拓冰建站拓冰建站
首页 / 资讯中心 / 正文

从BIOS到UEFI:EDK2开源固件生态与开发实战解析

做固件方向这些年隔三差五就会有人拿同一类问题来问我老电脑开机卡在LOGO是不是BIOS坏了服务器不支持UEFI引导怎么办EDK2编译出来的固件能直接刷到主板上吗这些问题看似零散背后却是一条越来越重要的主线——你每天开机那一两秒里运行的“BIOS”早就不再是三十年前那个16位实模式小程序了。今天几乎所有x86主板、一大批ARM设备跑的都是UEFI固件而其中相当一部分底层实现都源自同一个开源项目EDK2。这篇文章我想用这几年做固件开发的视角把从传统BIOS到UEFI、再到EDK2和整个开源固件生态的脉络串起来聊一遍。不管你是想搞明白“为什么UEFI引导U盘非得用FAT32”还是准备入门固件开发、想看看EDK2编译到底是什么流程这篇都能给你一个可以直接落地参考的底稿。1. 别再叫它BIOS了固件世界的两次换代1.1 传统BIOS是怎么一步步走到尽头的很多人习惯把所有主板固件都叫“BIOS”这本身没什么问题但从技术上较真传统BIOS和今天的UEFI固件完全是两代人。传统BIOS的历史可以追溯到1981年IBM PC时代它的核心思路是把最基础的硬件初始化、中断服务、磁盘读写封装成一套固件例程。从它出生起就有几个绕不开的硬伤第一它活在16位实模式下地址空间被限制在1MB内操作系统的引导最终只能靠一条简单的int 13h磁盘中断搞定第二它依赖MBR分区表主分区最多4个启动盘超过2TB就开始出各种幺蛾子第三它的驱动模型基本是“一次性买卖”BIOS结束后系统就再也用不到它也没有标准的安全验证机制。后来厂商们在传统BIOS上打了各种补丁包括加入ACPI、SMBIOS、DMI甚至是漂亮的图形界面但底子还是那套实模式框架。真正让它退出历史舞台的是Intel在90年代末为安腾处理器提出EFI规范再到2005年UEFI论坛成立、UEFI 2.x规范逐步完善。UEFI不是给BIOS换个皮而是把整个固件层重写成了类似“微型操作系统”的架构。1.2 UEFI到底改了什么从启动协议到微型运行时我第一次接触UEFI规范时最直观的感受是这玩意本质上不是BIOS而是一套运行在硬件之上的接口标准是“固件与操作系统之间的协议”。UEFI的关键组件包括系统表System Table、启动服务Boot Services、运行时服务Runtime Services、协议Protocol和驱动模型。它用PE/COFF格式承载扩展程序用Protocol的方式定义接口启动时规范要求在硬盘的EFI系统分区ESP里找EFI\BOOT\BOOTX64.EFI之类的引导文件。相比MBRUEFI几乎总是配GPT分区表支持超大容量硬盘和更多分区。再加上Secure Boot和TPM固件层第一次有了真正意义上的信任链验证。这里有个经常被误解的点UEFI设置界面只是它的一小部分。UEFI规范本身定义的是从复位向量到操作系统加载器之间的一整套环境包括内存管理、事件、协议、驱动架构、网络栈、甚至命令行Shell。它在开机时把自己初始化成一个小型运行时再把控制权交给OS然后留一部分Runtime Services常驻内存供OS调用。这也是为什么现在的固件能支持鼠标操作、网络引导、图形输出还能跑各种诊断工具传统BIOS根本做不到这些。所以当你再听到“BIOS”心里要清楚大多数消费级主板上的所谓“BIOS”其实已经是UEFI固件只是界面里还留了个CSM兼容模块用来伪装成传统BIOS引导老系统。2. EDK2开源固件的事实标准2.1 TianoCore与EDK2的来龙去脉说到UEFI的具体实现绕不开TianoCore。这是Intel发起的开源固件项目核心代码库叫EDK2全称EFI Development Kit II。最初只有x86代码现在已经扩展到ARM、ARM64、RISC-V等架构成为整个开源固件生态里最基础也最活跃的一棵树。EDK2的代码仓库归属TianoCore组织里面除了主仓edk2还有edk2-platforms各种SoC和开发板的平台包、edk2-staging实验性代码、edk2-libcUEFI环境下的C库等。主仓里的核心包包括MdePkg基础类型和接口定义、MdeModulePkg核心模块、SecurityPkg安全与Secure Boot、NetworkPkg网络栈、ShellPkgUEFI Shell、OvmfPkg虚拟化固件等等。EDK2的迭代节奏通常以UDKUEFI Development Kit为里程碑比如UDK2018、UDK2022、UDK202405。圈内人平常说的“更新到最新EDK2”往往指的就是跟住master分支或某个UDK版本。它与商业固件的关系就像Linux内核与发行版一样——你拿到的最终固件几乎都是某家厂商基于EDK2改出来的。2.2 固件源码是怎么变成芯片上的二进制我见过很多新人第一次拉EDK2源码时直接懵掉因为它不像普通应用工程那样一个Makefile就能构建。EDK2用了一套自己的描述体系核心是四个文件类型.dsc描述整个平台构建哪些模块.dec声明包内的Protocol、PPI、PCD和库类.inf描述单个模块的编译信息.fdf描述最终Flash镜像的布局。从源码到固件的链路大致是先构建BaseTools工具链然后执行edksetup.sh初始化环境再调用build命令根据.dsc把模块编译成FFS文件最后通过GenFds等工具打包成完整的固件镜像。比如编译一个OVMF虚拟化UEFI固件的常规操作是git clone https://github.com/tianocore/edk2.git cd edk2 git submodule update --init make -C BaseTools . edksetup.sh build -p OvmfPkg/OvmfPkgX64.dsc -a X64 -b RELEASE -t GCC5等到构建完成Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd和OVMF_VARS.fd就是可以拿到QEMU里跑的固件镜像。这里有个很关键的概念叫PCDPlatform Configuration Database它相当于固件里的“可配置开关”同一个模块可以在编译期或运行期通过PCD切换功能。Protocol则类似C里的接口模块之间不直接依赖具体实现而是通过Protocol握手通信。理解了PCD、Protocol和PPIPEI阶段的Protocol你基本就拿到了阅读EDK2代码的钥匙。2.3 EDK2和你在主板上看到的“BIOS”还差多远你从主板官网下载的固件和EDK2仓库里的源码并不是一回事。商业固件通常是在EDK2或者类似框架的基础上叠加了厂商自研的Setup页面、平台驱动、CPU微码、显卡GOP驱动、RAID OptionROM、管理引擎固件等再打包成一个很大的二进制镜像。所以你能说“我下载的固件是开源的”吗很难。像AMI Aptio、Insyde H2O、Phoenix SecureCore这些商业固件虽然核心框架里有EDK2的影子但最终交付物里大量二进制仍然闭源。这也解释了为什么“开源固件”和“开源EDK2”是两个层次的话题——EDK2本身是开源的但消费级主板上的最终固件往往是开源框架闭源组件的混合体。真正想上手EDK2开发建议不要一上来就去研究某个主板固件包而是先在QEMU里把OVMF跑起来改一改它的PCD、加一个自己的DXE驱动感受一下固件开发的编译和调试循环远比对着几百兆的FD文件瞎猜要靠谱得多。3. 开源固件生态格局TianoCore之外还有谁3.1 coreboot万物皆可快速启动EDK2不是唯一的选择。coreboot前身叫LinuxBIOS是另一条重要的技术路线它的理念和EDK2正好相反EDK2倾向于打造一个功能完整、抽象层丰富的微型OS式固件而coreboot追求最小化初始化把硬件带起来之后直接跳转到一个payload负载程序由payload负责引导操作系统。coreboot的特点一是启动速度快很多Chromebook、瘦客户机、服务器主板用coreboot能把开机到系统的时间压到几秒二是代码简洁、可审计性高安全研究员和云厂商比较喜欢它。但它也有代价支持的硬件范围比EDK2窄得多如果你用的是一块非常规主板很可能需要自己移植代码。coreboot的payload可以是SeaBIOS用来兼容传统BIOS引导、也可以是UEFI固件直接把EDK2编译成payload加载这叫corebootUEFI组合方案、更可以是LinuxBoot。这就带出了第三条路线。3.2 LinuxBoot与Slim Bootloader把Linux塞进固件LinuxBoot的思路很激进与其在固件层重复造轮子不如直接把Linux内核作为固件的一部分用它来做硬件初始化和引导。这样固件里跑的是真正的Linux内核驱动、真正的文件系统和网络栈启动速度飞快而且能复用整个Linux生态的安全性维护。LinuxBoot在大型数据中心的服务器上有不少落地案例典型架构是“coreboot初始化少量硬件 LinuxBoot作为payload u-root或initramfs把内核加载到内存”。它把固件里的闭源组件尽量压缩用Linux驱动代替厂商OptionROM这让运维人员可以直接在固件阶段做诊断、网络加载镜像甚至跑脚本。Intel还搞了一个Slim Bootloader面向边缘计算和物联网设备特点是高度可裁剪、通过配置脚本生成固件、镜像可以做到很小。嵌入式领域里U-Boot也实现了CONFIG_EFI_LOADER可以在U-Boot之上提供UEFI API让GRUB和systemd-boot这些EFI应用直接跑起来。再加上RISC-V生态里的OpenSBI、rust-sbi整个开源固件的版图已经非常多元。3.3 OVMF藏在虚拟机里的UEFI如果你没条件碰物理机又想要一个可以随便折腾的UEFI环境OVMF是最好的入口。OVMF是EDK2里的OvmfPkg专门面向QEMU/KVM虚拟机提供UEFI固件。它支持Secure Boot、UEFI Shell、VirtIO驱动、ACPI和SMBIOS等几乎把完整UEFI体验搬进了虚拟机。启动一台带UEFI固件的QEMU虚拟机最简命令类似qemu-system-x86_64 \ -machine q35 \ -drive ifpflash,formatraw,readonlyon,fileOVMF_CODE.fd \ -drive ifpflash,formatraw,fileOVMF_VARS.fd \ -m 2048 \ -cdrom some.isoOVMF_CODE.fd是只读的代码区OVMF_VARS.fd是存放变量的存储区这种分离设计和真实主板上的写保护机制是一个思路。很多虚拟化平台默认给虚拟机提供的就是SeaBIOS传统BIOS想实验UEFI启动方式、测试安全启动装一个OVMF就能搞定这也是理解物理机UEFI引导最安全的方式。4. 日常UEFI实操从启动盘到Shell急救4.1 3分钟判断电脑是UEFI还是Legacy启动实操问题往往比理论更困扰人第一个高频问题就是我这台机器到底是用UEFI还是传统BIOS引导的Windows下最简单的方法是运行msinfo32在系统信息里看“BIOS模式”这一项显示“UEFI”就是UEFI启动显示“传统”就是Legacy。Linux下可以用一行命令判断[ -d /sys/firmware/efi ] echo UEFI mode || echo Legacy BIOS mode如果启动时能看见图形化鼠标界面、只显示厂商Logo而不是蓝底白字的设置页基本能确定是UEFI。另一个辅助信号是磁盘分区表UEFI启动一般对应GPT分区盘上会有一个几百MB的EFI系统分区传统启动则大概率是MBR分区表。用lsblk -o NAME,PARTTYPENAME看一下有没有EFI System分区心里就有数了。还有种特殊情况是启动U盘时遇到error: bios/legacy boot of uefi-only media这类报错意思是安装介质明确要求UEFI方式但你的启动项配置成了Legacy。解决思路很简单确认安装盘是用UEFI方式制作的同时在固件里关闭CSM、或选择带UEFI前缀的启动项。4.2 UEFI引导U盘FAT32还是NTFS这个问题的标准答案是无脑FAT32原因在于UEFI规范对ESP分区的要求就是FAT/FAT32文件系统。固件里的FAT驱动是不能省的基础组件但NTFS驱动、exFAT驱动在大多数固件里并没有内置即使有也可能因为实现不完整而翻车。但有个实际矛盾Windows安装镜像里的install.wim经常超过4GB而FAT32单文件上限正好是4GB。这时候我常用的做法是准备一个双分区U盘第一个小分区格式化成FAT32专门放EFI引导文件和boot.wim第二个分区用NTFS或exFAT放完整镜像。另一个更省事的方案是直接上Ventoy它会创建兼容性最好的多分区布局在启动时模拟出固件需要的FAT环境Windows和Linux镜像丢进去都能引导。更老的机型不支持从FAT32的U盘UEFI启动时还会有各种奇葩表现比如启动项认不到盘。这时候先进UEFI Shell用map -r看设备映射如果再不行就检查U盘分区是不是MBR格式、有没有激活标志。很多所谓“固件不识盘”其实是分区表类型不对。4.3 老主板没有NVMe引导怎么办现在还能看到不少老主板固件里没有NVMe驱动模块导致NVMe固态硬盘可以当数据盘但没法从它启动系统。这种情况圈内俗称“魔改BIOS”做法是用UEFITool之类的工具打开原厂固件镜像提取或注入NVMe驱动模块再刷回去。原理不复杂UEFI是通过Protocol发现设备固件里缺了NvmeDxe驱动启动管理器就看不到NVMe盘。你可以从别的固件里提取NVMe模块用MMTool或UEFITool把它插入到同平台的固件卷里。但我要泼一盆冷水跨平台注入、Flash布局不匹配、固件卷空间不足任何一个坑都可能导致刷黑。更稳妥的替代方案是用Clover四叶草或OpenCore这类引导器把它们写到一个小U盘或老硬盘的EFI分区里作为“引导代理”再由它们加载NVMe驱动并引导系统。这种方式不动原厂固件风险低得多也是我处理老本子“电容键盘卡BIOS”“NVMe不识别”时优先推荐的思路。真正要动固件本身的魔改操作务必确保有编程器、有原厂备份、并且愿意承担变砖风险。4.4 UEFI Shell固件自带的命令行急救室UEFI Shell是UEFI环境里特别实用的工具相当于一个跑在固件层的命令行终端。很多主板固件里有内置Shell也可以把Shell.efi放到U盘的EFI目录下从固件启动菜单里直接加载。入门级操作包括map -r ls fs0:\EFI bcfg boot dump -v dmpstore -d ver memmapmap -r重新扫描设备映射bcfg boot dump能查看当前固件启动项dmpstore可以浏览UEFI变量这在排查“启动项丢失”“Linux更新后Windows引导消失”的时候非常有用。比如想查看某个UEFI启动项的完整路径直接bcfg boot dump -v一清二楚清理多余启动变量也有对应的bcfg子命令。不过要提醒一点UEFI Shell再强也做不到随意读写整个SPI Flash芯片。很多刷BIOS工具其实是厂商自己的Shell命令行程序或者需要配合flashrom之类的工具在OS层操作。指望Shell万能备份固件不如老老实实用flashrom加编程器。5. 固件排障现场那些折腾人的问题5.1 磁盘时有时无固件层与系统层的错位我收到过很多类似的问题BIOS固件里明明能看到硬盘PE启动盘却认不出来或者硬盘状态显示unconfigured good但系统里就是找不到盘。先解释unconfigured good这个状态它常见于SAS/RAID控制器场景。磁盘本身物理是好的但没有被加入任何虚拟磁盘VD或直通配置所以控制器层不会把它的盘符暴露给系统。解决思路是进入RAID控制器配置界面把盘做成阵列或直通passthrough这和主板BIOS本身关系不大。PE看不到盘则是另一类问题。如果固件设置了SATA为RAID模式比如Intel RSTPE里没有IRST驱动就会丢失所有盘固件以UEFI模式启动但PE是Legacy引导的也会导致GPT磁盘在传统中断路径下不识别。常用的排查顺序是先确认启动模式统一再把SATA模式改AHCI试试最后往PE里注入AHCI/NVMe驱动。很多时候不是硬盘坏了而是固件和引导环境之间没对齐。5.2 Recovery Mode果奔先别急着拆芯片有块主板开机直接提示warning BIOS recovery mode has...很多人第一反应是BIOS芯片坏了马上拆机找编程器。其实Recovery Mode是固件的一种自保护机制说明引导模块检测到异常正在尝试从备份区或外接介质恢复。我的建议是先冷静让机器把恢复流程走完。如果它试图从U盘的固件文件恢复你需要准备一个存有官方固件文件的FAT32 U盘按厂商指定的命名放到根目录或特定目录。反复卡在Recovery Mode也不一定是芯片挂了CMOS电池没电、内存接触不良、电源供电不稳都可能触发固件保护。等确认外设、内存、电源都没问题之后再考虑刷写路线。这一步千万别手滑选了别人改过的魔改固件先恢复原厂默认再说。很多“什么固件都刷不进去”的故障最后发现是SPI Flash写保护位被置位或者主板上有硬件写保护跳线根本轮不到拆芯片。5.3 设置存不住、密码忘不掉CMOS/EC/安全芯片那些事“BIOS设置保存不了”“断电就恢复默认”这类问题绝大多数是CMOS电池没电了。主板上的RTC电池负责在断电后维持CMOS存储和时钟一旦没电固件配置丢失是必然的。换电池是最便宜的排查手段别一上来就怀疑固件损坏。但笔记本上还有一层更隐蔽的存在——ECEmbedded Controller嵌入式控制器。EC负责键盘矩阵、电源管理、风扇控制也是笔记本固件启动流程里最早工作的部件之一。很多人问“BIOS和EC通信是什么”简单说EC通过特定的I/O端口和ACPI事件机制与固件及操作系统交互EC固件和BIOS固件经常放在同一个Flash芯片的不同区域。笔记本清CMOS不是拔颗电池那么简单有时需要拆后盖、断开内置电池、长按电源键放电甚至把RTC插头拔掉等几分钟才能让EC和PCH的状态彻底复位。顺带说一句BIOS密码这类密码一般存在RTC或安全芯片里CMOS放电有时能清掉但遇到独立安全芯片的方案就很难绕过。网络上那些标榜“密码破解工具”的东西效果非常有限而且安全隐患很大。忘记密码的正路是联系厂商售后或走官方解锁流程不是相信旁门左道。5.4 固件备份与差分升级动手前先留后路做固件改动之前备份是唯一保命手段。最通用的方案是flashromsudo flashrom -p internal -r backup.rom如果只是备份某部分区域可以按IFDFlash Descriptor分区来指定比如只读BIOS区域、ME区域等。备份出的镜像用UEFITool打开能看到固件卷FV、模块FFS、PE32/PE32镜像这也是提取NVMe模块、分析固件差异的基本操作。UEFITool 0.28.0是目前用得比较多的一版图形界面和命令行都有适合做这类静态分析。固件升级则不一定要整片重写。现代UEFI固件支持Capsule Update机制操作系统把新固件打包成Capsule运行时调用UpdateCapsule服务写入。Linux下用fwupd配合LVFS就能实现这类无感升级。嵌入式设备的固件差分升级有更成熟的A/B分区方案例如RAUC、SWUpdate通过bsdiff之类的工具生成补丁包网络不好也能可靠升级。备份固件时要特别留意一个隐私问题固件镜像里往往包含BIOS Descriptor、GigE MAC地址、UUID、平台证书等本机唯一信息。直接丢到公开论坛求分析等于把机器的身份信息送出去。打码、脱敏、只提取必要模块是基本的自我保护。6. 魔改BIOS与固件安全几句大实话6.1 为什么我不建议刷别人的“魔改版”每次讨论NVMe模块注入、解锁隐藏设置、改启动Logo总会有人问“XX大魔改BIOS下载地址有吗”。我的态度很明确玩可以但不要拿别人改好的固件直接刷进自己主板。原因有二。第一固件没有可靠的签名验证前闭源魔改二进制里到底加了什么你根本无从知晓。有人可能只是改了Logo有人可能塞了后门这不是危言耸听固件层的恶意代码一旦运行优先级比操作系统还高普通杀毒软件根本管不到。第二魔改固件往往基于某个特定BIOS版本和你的主板Rev、内存颗粒、CPU微码、外围芯片未必匹配。别人刷了能开机你刷了可能就是变砖送修。如果你确实需要某个功能优先考虑合法方案官方发布了带NVMe的新BIOS就升级官方版官方不支持就用Clover这类引导代理只是想清理老机器干脆降级用回传统BIOS模式。如果一定要动固件请先备份原厂固件、确认编程器到手、再挑一块不重要的板子练手。一个连原厂固件都没备份过的人是没有资格刷魔改版的。6.2 开源固件未来的方向其实和你有关聊完风险再往远看一点。固件正在从“不可见、不可改、不可审计”的黑盒慢慢走向“可见、可改、可审计”的开源生态。EDK2、coreboot、LinuxBoot、OVMF这些项目让越来越多人有能力理解底层启动流程也让服务器和数据中心有机会把固件纳入统一的安全管理。对我个人来说这股趋势最大的价值不是“人人都能改BIOS”而是“出了问题你知道去哪里查”。以前主板固件黑屏只能怀疑“BIOS坏了”现在你可以用UEFITool分析镜像、用flashrom读完整芯片、用UEFI Shell检查启动项甚至自己改几行EDK2代码编一个OVMF跑起来。这种掌控感是任何一层应用开发都给不了的。如果你也想入门我的建议是先别碰物理机刷写装好QEMU把OVMF编译一遍再尝试往固件里加一个打印Hello World的DXE驱动。把这一步走通你对UEFI、EDK2和整个固件生态的理解就已经超过绝大多数只会按Del进设置页的玩家了。我自己也是从这个起点开始的这条路一点都不神秘缺的只是一次动手。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门