十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从BIOS到UEFI:固件原理、安全启动与EDK2开发实战指南

从BIOS到UEFI:固件原理、安全启动与EDK2开发实战指南 1. 从 BIOS 到 UEFI一场持续三十年的固件革命如果你在过去十年里折腾过电脑装机、装双系统、或者研究过主板启动流程那么你大概率听过这几个词BIOS、UEFI、启动项、安全启动。而这两年随着 Windows 11 强制要求 UEFI 安全启动、Linux 发行版全面转向 EFI 引导以及开源固件社区coreboot、edk2、u-boot的持续活跃“固件”这个原本藏在操作系统背后的领域正在被越来越多人推到台前。我是从大学折腾黑苹果开始接触 UEFI 的。那时候为了搞定 Clover 引导把 BIOS 里里外外摸了个遍后来一发不可收拾开始研究 AMI BIOS 的结构、UEFI 规范的细节、EDK2 源码的编译流程。到现在我经手的固件相关项目少说也有几十个从简单的 BIOS 设置项调整到基于 EDK2 定制 UEFI 启动菜单再到给嵌入式 ARM 设备移植固件踩过的坑能写一本书。这篇文章我想把自己对 UEFI 和开源固件生态的理解完整梳理一遍。目标读者是两类人一是刚接触固件开发、想搞懂 BIOS 和 UEFI 到底怎么回事的开发者二是普通电脑用户想搞明白为什么新主板都叫 UEFI、为什么装系统总遇到磁盘布局错误、为什么安全启动能拦住一堆启动盘。无论你是哪一边这篇文章都能给你一个完整、接地气、能直接用的知识框架。先说结论UEFI 并不是 BIOS 的一个“美化版”而是从底层设计逻辑上与 BIOS 彻底分道扬镳的一套新体系。BIOS 是 1975 年诞生的老古董UEFI 是 Intel 在 1998 年启动的 EFI 项目的现代演进版。它们之间的关系与其说是升级不如说是换了一套操作系统。2. UEFI 核心机制深度拆解2.1 为什么说 UEFI 是一个“微型操作系统”理解 UEFI 最好的方式就是把它想象成一个微型操作系统。它有自己的驱动程序模型、协议接口、内存管理、甚至支持网络协议栈。我们平时在 BIOS 设置界面里看到的鼠标操作、图形化界面、截图功能本质上都是跑在 UEFI 固件这个“微型 OS”上的应用程序。UEFI 的启动流程通常分为七个阶段对应着 SEC安全验证、PEIEFI 前期初始化、DXE驱动执行环境、BDS启动设备选择、TSL操作系统加载前期、RT运行时、AL系统崩溃后。前几个阶段说白了就是“从最原始的代码一步步把硬件初始化到可以跑操作系统加载器的程度”。和传统 BIOS 相比UEFI 有三个核心优势可扩展性BIOS 的代码通常写在 ROM 里地址空间只有 1MB 的实模式访问范围扩展全靠后期打补丁。UEFI 运行在保护模式或长模式下可以直接访问全部内存驱动可以做成独立的 .efi 文件动态加载。模块化设计UEFI 固件由一堆独立的 PEIMPEI 模块和 DXE 驱动组成每个负责一个硬件设备的初始化。这种设计让固件厂商AMI、Insyde、Phoenix能灵活拼装不同模块来适配不同的主板。无关操作系统的引导方式传统 BIOS 引导必须靠主引导记录MBR里的引导代码UEFI 直接读取 FAT 分区里的 .efi 文件来加载操作系统不再依赖“引导扇区”那种脆弱机制。这最后一点直接影响了今天我们装系统的姿势。你在给 U 盘做启动盘时如果选错了 FAT32 和 NTFS就会出现“传统 BIOS 引导不支持 NTFS 上的 EFI 文件”这类错误本质上就是因为 UEFI 固件只认 FAT 格式下的引导文件路径。2.2 UEFI 安全启动到底在保护什么安全启动Secure Boot可以说是 UEFI 时代最让人又爱又恨的功能。Windows 11 强制开启它导致大量旧电脑和自制 Linux 启动盘翻车网上搜“uefi安全启动导致u盘装系统失败的解决方案”的热度一直居高不下。安全启动的原理说白了就是“数字签名信任链”。UEFI 固件内置了一组根证书Platform Key简称 PK固件只允许加载带有可信签名的引导程序。这个信任链从平台密钥到密钥交换密钥KEK、再到数据库db/dbx形成了一套完整的签名白名单和黑名单机制。装系统时遇到“无法验证此文件的数字签名”或者“Security Violation”这样的提示就是安全启动拦截了未经签名的引导加载器。这个时候有两条路可走关掉 Secure Boot进 BIOS找到 Boot 选项下的 Secure Boot改成 Disabled。这是最快的方法适合折腾 Linux 和黑苹果的用户。给引导程序签名如果你既想保留安全启动的保护又想用自定义引导可以通过 efitool 之类的工具自己生成密钥并加入 UEFI 数据库。不过操作复杂度陡增普通用户建议直接关掉。还有一个容易踩的坑很多新主板默认开启了 Secure Boot 的同时还开着 Windows 8/10 Whql 兼容模式。这时候你用 Rufus 刻录的 Ubuntu 启动盘可能直接连引导菜单都进不去。我一般建议在制作 Linux 启动盘时把分区表选成 GPT、文件系统用 FAT32同时进 BIOS 把 Secure Boot 关掉这样可以避免九成以上的启动问题。2.3 UEFI Shell 与固件级调试很多老玩家应该有印象以前 BIOS 时代有个 DOS 环境可以刷写 BIOS 文件、修改 DSDT 表现在 UEFI 时代对应的就是 UEFI Shell。UEFI Shell 是一个基于 EFI 字节码EBC的交互式命令行环境可以直接执行 .efi 文件、访问文件系统、查看内存映射、修改 UEFI 变量。像 UEFI Tool 0.28.0 这类工具本质上就是跑在 UEFI Shell 里的 ELTEFI 降级测试主程序。我给你举一个实际案例。之前帮朋友解决一台老联想笔记本的 BIOS 升级失败问题——机器开机直接黑屏风扇狂转。正常情况下我会建议返厂但我在拔掉电池后利用 BIOS Recovery 功能多数笔记本关机状态下按住 FnR 再开机或通过专用 U 盘恢复进入 UEFI Shell用内置脚本重新刷写备份的 BIOS 镜像硬是把砖救回来了。UEFI Shell 即使平时用不上我建议每个做固件开发的人都准备一个以防万一。在 Ubuntu 系统里安装 UEFI Shell 很简单用# apt install shell.efi或者在 EDK2 编译产物里直接拿 Shell.efi放进 FAT32 的 U 盘里就行。3. EDK2 现状与工程实践3.1 EDK2 到底是一个什么样的项目EDK2EFI Development Kit II是 TianoCore 社区维护的 UEFI 固件开发框架是目前几乎所有 Intel 平台 UEFI 固件的“母体原型”。甚至可以说市面上 90% 以上的 PC 主板 UEFI 固件底层源码基础都源自 EDK2只是被 AMI/Insyde 等厂商做了在 EDK2 之上的深度定制。EDK2 的源码结构非常有代表性。核心部分包括 MdePkg、MdeModulePkg、UefiCpuPkg 等基础包上面是各类平台的 Board Package如 Intel 的 MinPlatform 项目、ARM 平台的 ARM 移植分支。用 EDK2 写固件基本套路是搭建构建环境Windows 下用 Visual Studio Python NASMLinux 下用 GCC 工具链。配置目标平台通常通过修改 .dsc 文件来设置编译选项、包含的模块。编译生成固件镜像通常是一个 .fd 文件后续烧录到 SPI Flash 里。拿我去年做的一个小项目举例为了给一台老 Intel 工控机增加一个“网络启动优先”的默认启动项我没有直接去改 BIOS 设置里的顺序因为出厂固件锁死了选项而是拉了 EDK2 源码修改NetworkPkg的 BDS 优先级设置重新编译出固件后通过编程器烧录成功达到了目的。3.2 EDK2 开发环境的搭建与编译实操如果你自己动手试过编译 EDK2一定会对它的“重度依赖”有深刻体会。这里我分享一套在 Ubuntu 22.04 下实测稳定的流程# 1. 安装基础依赖 sudo apt install -y build-essential git uuid-dev nasm python3 python3-distutils # 2. 克隆源码注意用稳定 tagmaster 分支经常处于大改状态 git clone https://github.com/tianocore/edk2.git cd edk2 git checkout edk2-stable202311 # 3. 更新子模块这步是新手最大痛点网络差时建议多试几次 git submodule update --init --recursive # 4. 设置环境变量并编译模拟器版固件方便验证环境是否正常 make -C BaseTools source edksetup.sh build -p OvmfPkg/OvmfPkgX64.dsc -t GCC5 -b DEBUG # 5. 生成的固件在 Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd编译过程中最常掉的坑有三个子模块拉取失败EDK2 依赖一堆第三方库比如 brotli、openssl、lzma网络条件不好时git submodule update会卡死。解决办法是手动下载后放入对应目录或用代理这里指的是常规网络代理加速不是某种专有名词组合——总之用你能用的一切手段把代码完整拉下来。编译器版本不匹配老版本 EDK2 对 GCC 版本敏感比如 edk2-stable202008 用 GCC 9 编译没问题但 Ubuntu 22.04 默认是 GCC 11会报“unsupported option”。解决办法是装老版本 GCC或用最新稳定 tag。python3 权限问题BaseTools 有部分脚本是 Python 写的如果用虚拟环境或非 root 用户安装要确保python3在 PATH 里。编译完成后你会得到一个 OVMF.fd——这是一个跑在 QEMU 虚拟机里的 UEFI 固件镜像。你可以直接拿它来测试各种 EFI 应用不用冒真机变砖的风险。3.3 用 OVMF 在 QEMU 里模拟 UEFI 启动很多人做固件开发的第一步不是买开发板或刷真机而是先用 QEMU 模拟器把 UEFI 环境跑起来。OVMFOpen Virtual Machine Firmware是专门给 QEMU 用的 UEFI 固件它的好处是可以在不碰真实硬件的情况下测试 UEFI 应用程序、调试启动流程。最简单的试验方式sudo apt install qemu-system-x86 ovmf qemu-system-x86_64 -bios /usr/share/OVMF/OVMF_CODE.fd -hda fat:rw:./your_efi_dir这段话的意思是用 OVMF 固件启动虚拟机把你当前目录下所有文件模拟成一个 FAT 磁盘供给 UEFI 识别。如果你放了一个Shell.efi进这个目录虚拟机会直接进 UEFI Shell非常方便。我在这个环境里做过的试验包括写一个 HelloWorld.efi 打印内存映射表、用 UEFI 协议读取 ACPI 表、测试 Secure Boot 签名策略。成本极低出错也不怕强烈推荐初学者先玩这个环境再考虑真机。4. 开源固件生态全景不只是 EDK24.1 三大开源固件项目的分工与竞争提到开源固件不少人的第一反应是 coreboot第二反应才是 EDK2。实际上它们两个解决的问题不太一样再加上 U-Boot基本构成了当前开源固件生态的三足鼎立项目定位主要平台特点EDK2完整 UEFI 固件实现x86、ARM、RISC-V功能全模块大代码量大是工业界基准coreboot快速初始化固件前身 LinuxBIOSx86、ARM启动极快代码精简但默认不包含传统 BIOS 兼容层U-Boot引导加载器 轻量固件嵌入式平台ARM、MIPS、RISC-V部署广泛驱动丰富适合设备厂商定制coreboot 和 EDK2 不是替代关系更像“分工关系”。一个完整的 coreboot 构建往往在启动后期会加载一个名为UEFIPayload的东西这个 payload 就是 EDK2 编译出来的。也就是说一台装了 coreboot 的 Chromebook实际上底层早期初始化是 coreboot 在做到了 UEFI 协议提供阶段才切换到 EDK2。这种“双固件”方案在开源社区里非常普遍。而我个人看好 EDK2 的原因也很简单生态惯性。绝大多数 PC 主板厂商、服务器厂商、云厂商的固件都在 EDK2 基础上发展AMD 的 AGESA 初始化代码就是嵌在 EDK2 平台包里的。你想找一个完整的、对 PC 兼容性最好的开源 UEFI 实现EDK2 是唯一选择。4.2 从藏宝图到路线图固件供应链的现状固件供应链这个词听起来很专业其实本质就是“你的主板固件是从哪来的”。以最常见的消费级台式机主板为例它的 UEFI 固件通常是这么生成的Intel/AMD 发布 CPU 配套的 FSP固件支持包源码和二进制。AMI/Insyde 拿到主板厂商的需求在自家 BIOS 框架基础上集成 FSP做成一个半定制的固件基线。主板品牌方华硕、微星、技嘉等拿到 AMI/Insyde 的半成品加上自己的 logo、设置菜单、默认参数、Q-Flash 工具等等再编译成最终固件。用户通过 BIOS 自带升级工具或 U 盘升级写入 SPI Flash 芯片。这个链条里的薄弱环节在于绝大多数步骤是非开源的第三方和用户只能拿到最终成品。一旦固件有安全漏洞比如经典的联合漏洞合集普通用户几乎无力自查只能等待厂商推送更新。这也是开源固件社区这些年一直在呼吁“开放固件供应链”的原因。从国际上看Linux 基金会在推动LinuxBoot前身 NERF方向把 Linux 内核直接作为固件后续阶段用来替换 EDK2 的 DXE/BDS 部分。OpenBMC 则是在服务器 BMC 领域做了一套完整的开源管理固件。国内也有少数厂商在做 RISC-V 平台的固件开源尝试但整体生态还在起步期。4.3 为什么 UEFI 固件“刷机”比 BIOS 时代更危险在 BIOS 时代把固件文件写坏了顶多是 DOS 下重刷一遍到了 UEFI 时代SPI Flash 的分区布局更复杂包含的模块更多有 ME 固件、平台数据、UEFI 变量、恢复镜像等一不小心刷坏了轻则丢设置、重则板砖。我举一个真实案例。之前有个朋友让我帮他升级一块老主板的 BIOS 来支持新 CPU。结果刷写过程中断电重启后主板黑屏、风扇转一下停一下。最后我用编程器CH341A夹住 SPI Flash 芯片配合备份的固件镜像硬刷回来才救回来。这期间踩了无数坑芯片型号识别错误、擦除超时、校验不一致……每次失败我都在想如果厂商能在固件里默认带一个可用的恢复模块大家的折腾成本会低很多。再提一个和“编程器”相关的热词ch7511b在uefi环境下的刷写工具。这个其实是某些笔记本板载显示接口控制器的固件更新工具用 UEFI Shell 环境下的可执行程序来刷写。这类小工具的难点在于它依赖特定的 UEFI 协议、内存地址配置和芯片时序弄不好就把显示输出搞不见了。我的建议是非必要不碰专业的事情交给专业工具。5. 常见问题与排查技巧实录5.1 装系统时的 UEFI 相关报错先整理一份我从各个论坛和自己实践中收集的常见报错速查表报错/现象原因解决思路“UEFI 启动的 U 盘必须使用 FAT32”启动盘分区格式不对重建分区表为 GPT格式化 FAT32“无法安装 Windows 因为磁盘布局不受 UEFI 支持”磁盘是 MBR 分区表用 diskpart 转 GPT或使用支持 CSM 的启动方式“Security Violation”Secure Boot 拦截了未签名引导文件关闭 Secure Boot 或给引导器签名开机直接进 BIOS 设置界面启动项顺序不对或启动文件丢失检查 Boot Priority确认 EFI 引导是否正常升级 BIOS 后风扇狂转固件版本与 EC 固件不匹配或 BIOS 设置残留先清 CMOS再看是否需刷回旧版本这里重点讲一下磁盘布局不受 UEFI这个经典问题。现在很多 Windows ISO 是从微软官网直接下载的系统要求 GPT 分区并启用 UEFI 引导。如果你的磁盘还是老式 MBR 分区格式安装程序会直接拒绝继续。解决办法其实不复杂。如果磁盘是空的直接在PE 环境下用diskpart转成 GPTdiskpart list disk select disk 0 clean convert gpt exit注意clean会抹掉整块磁盘的数据操作前请务必备份。如果磁盘上有不想删的数据就得用第三方工具无损转换但风险较高我还是建议先备份再操作。5.2 老主板的 BIOS/UEFI 刷写经验对于老主板比如 H61、B75、H81 这些 LGA 1155/1150 时代的板子刷 BIOS 时需要特别小心。这些主板虽然也叫 UEFI多数是 UEFI 和 BIOS 混合模式但刷写流程和现代 UEFI 不太一样。我踩过的坑和总结的经验先备份再动手。现在很多工具支持直接读取 BIOS 芯片内容如 FPTFlash Programming Tool、编程器。哪怕用官方的刷新工具也试着在升级前先备份当前固件。一旦新固件出问题还可以回滚。不要在 Windows 图形界面里刷 BIOS。华硕的 EZ-Flash、微星的 M-Flash 都比 Windows 下的刷写工具靠谱。刷新过程中切记不可断电。Q-Flash 提示无法更新 BIOS 档案这个情况通常是因为 BIOS 文件放在 NTFS 分区或主板固件不兼容压缩格式。对策是把解压出来的.CAP/.BIN文件放到 FAT32 格式的 U 盘根目录文件名保持官方原样并确认格式和型号完全匹配。如果 BIOS 刷写失败变砖先试主板自带的 BIOS 恢复功能。华硕是按住 FnF8 或 ROG 主板的 USB BIOS FlashBack技嘉是插上 FAT32 U 盘后开机按住 CtrlHome微星多数系列也有双 BIOS 功能。实在不行再用编程器。5.3 UEFI 变量与 FAQ最后说一个问题人群较少的细分领域UEFI 变量。UEFI 变量是一组键值对存储在 SPI Flash 里用来保存启动配置、Secure Boot 数据库、厂商设置等。你可以通过uefiboot工具或者在 UEFI Shell 里用dmpstore命令查看它们。这些变量对系统启动和固件升级有直接影响。举个例子有次我帮人折腾一台 Windows 和 Linux 双启动的机器调了启动顺序后 Windows 无法进入原因是 UEFI BootOrder 变量被 Linux 的efibootmgr修改后出现了重复项。通过efibootmgr -o手动指定 BootOrder问题马上解决。如果以后遇到“默认启动项不对但设置界面里看不到”的情况可以考虑用编程器级别的工具直接读取变量区。注意修改 UEFI 变量有一定风险尤其是删除 Boot 变量可能导致某些主板无法启动操作系统。操作前务必备份全套变量信息。6. 基于个人经验的固件折腾建议写到这里我把自己多年折腾固件的核心心得总结成几条经验一、区分需求不要盲目追求新固件。很多人刷 BIOS 只是因为“新版本修复了几个 bug”但没有搞清楚新版本是否修复了你自己遇到的那个问题。一旦刷完发现风扇狂转、内存兼容性变差反而更难受。刷固件前先看看 release notes如果当前固件没有影响你的问题我建议不刷。二、尽量保留原始固件的备份。无论你是用官方工具升级还是想魔改安装选项张备份是能救命的。最简单的办法是在 DOS 下用 FPT 工具把整个 SPI Flash dump 下来。实在没有专业工具至少把当前固件版本号和设置界面截图留存方便排查。三、了解固件的“黑盒”部分保持敬畏。UEFI 固件里除了我们看到的设置界面还包含大量专有部分——比如 Intel ME/AMD PSP、板载控制器固件、电源管理代码。这些部分既不开源也几乎没有文档即使开源生态再发展短期内也无法完全替代。所以在做深度定制或魔改时一定要清楚边界不要碰到影响安全启动和信任根的模块。四、开源固件生态的方向是光明的但过程需要时间。从 x86 平台看LinuxBoot 和 OCP开放计算项目已经让部分服务器场景脱离了传统 UEFI 默认实现从 ARM/RISC-V 平台看U-Boot 和 EDK2 的移植分支也在快速成熟。如果你对固件开发感兴趣现在开始学 EDK2、coreboot 或 U-Boot 都是很好的切入点而且这些技能在芯片厂商、云厂商、嵌入式设备公司都有很大的需求空间。最后再分享一个小技巧我建议所有玩电脑的人都准备一个 FAT32 格式的 U 盘里面放 Universal 服务器固件恢复工具比如你手里那个 UEFI Tool 0.28.0、一个 UEFI Shell、还有自己平台的 BIOS 文件。平时不占什么空间关键时刻能救砖、能看启动日志、能刷固件。折腾固件这件事准备做得越充分心跳经历就会越少。
返回列表