整理参考自:知乎 TrustZero:一文搞懂UEFI
BIOS
当我们提到BIOS时,根据上下文的不同,它可能代表不同的含义:
- BIOS标准:这是一个广泛的概念,指的是一种在计算机启动时初始化硬件并加载操作系统引导程序的标准接口。
- 具体的BIOS实现——即特定于主板的固件:
- 这是由主板制造商编写或授权的代码。
- 当计算机开机时,硬件被设置为开始执行BIOS。这是CPU需要知道的全部内容,即CPU不需要了解驱动器、文件系统或操作系统。BIOS负责初始化硬件,加载引导加载程序(如GRUB或Windows Boot Manager),然后引导加载程序负责加载并启动操作系统。
简而言之,BIOS是计算机启动过程中的一个重要环节,它负责在操作系统加载之前初始化硬件,并为操作系统的启动提供必要的环境。而UEFI(统一可扩展固件接口)是BIOS的现代替代品,提供了更多的功能和更好的安全性。
BIOS 标准
BIOS 标准定义了以下内容:
- 一个硬编码的内存位置,计算机在开机时 CPU 将从该位置开始执行 BIOS 代码。
- 磁盘位置,操作系统制造商可以在这些位置放置其引导加载程序以启动其操作系统。
- APIs:
- 从硬盘和软盘读写数据(因此不是所有程序都需要直接处理 IDE / SATA 等总线)
- 读取键盘按键 => BIOS 是一个硬件抽象层。
但 BIOS API 使用并不多,因为:
- 开发人员与操作系统的硬件抽象API进行交互,甚至操作系统本身也不使用太多的BIOS API(因为它们直接控制硬件以获得更高级别的访问权限,这样就很不安全了)
- 即使在DOS时代,应用程序开发人员也可能使用DOS API进行抽象,而不是直接使用BIOS。
BIOS 实现
BIOS的实现是特定于主板的
局限性: 由于引导加载程序大小的限制,大多数操作系统不得不使用复杂的链式启动过程。
启动过程
CPU 复位后从一个特定的内存位置(x86: 0xFFFFFFF0, RISC-V: 厂商规定)开始执行代码,这个内存位置由主板的 BIOS 代码 ROM 提供支持。
对于硬盘来说,存在一个引导扇区 / 主引导记录(MBR),它包含引导加载程序,并且其大小限制实际上是 440 字节,因此仅凭这个大小的引导加载程序无法加载现代操作系统。加载操作系统至少意味着引导加载程序必须从磁盘读取内核(Linux / Windows等)并将其控制权交给它。
通常, MBR 中的引导加载程序会将控制权传递给 active partition 的引导加载程序(VBR, 卷引导记录),但它也有相同的大小限制。
为了让引导加载程序从磁盘读取内核, 它必须知道如何遍历文件系统以访问内核。 因此,引导加载程序会从文件系统的根目录读取并链式加载一个“第二阶段”——一个可以更大、因此可以包含更复杂代码的文件。
windows
在Windows中,这个第二阶段过去被称为 NTLDR (NT加载程序),位于 C 盘的根目录下
引导加载程序组件分布在各个地方。有三个不同的特定于 Windows 的位置用于开始加载实际的内核。
Linux
Linux(链式GRUB)的情况也大致相同
UEFI
UEFI 文档: https://uefi.org/specs/UEFI/2.10/index.html
EFI (Extensible Firmware Interface,可扩展固件接口) 是现代计算机系统中用来替代传统 BIOS 的一种新标准。
UEFI: 统一可扩展固件接口(Unified Extensible Firmware Interface)
与 BIOS 的区别
与 BIOS 执行相同的任务,但有一个 基本区别:它将所有关于初始化和启动的数据存储在 .efi 文件中,而不是存储在固件上
这个 .efi 文件存储在硬盘上一个名为 EFI 系统分区(EFI System Partition, ESP)的特殊分区中。这个 ESP 分区还包含引导加载程序。
UEFI 被设计用来克服旧版 BIOS 的许多限制,包括:
- UEFI 支持高达 8 ZB 的驱动器大小,而 BIOS 仅支持 2TB
- UEFI 启动更快
- UEFI 具有独立的驱动程序支持,而 BIOS 的驱动程序支持存储在 ROM 中,因此更新 BIOS 固件有点困难
- UEFI 提供类似“安全启动”(Secure Boot)的安全功能,防止计算机从未经授权/未签名的应用程序启动
- 有助于防止 rootkit
- 也会妨碍双系统启动,因为它将其他操作系统视为未签名的应用程序
- BIOS 允许在不更改任何设置的情况下运行多个操作系统。从现代的角度来看,这可能是一个安全问题,但对用户来说没有麻烦。
- UEFI 以 32 位或 64 位模式运行,而 BIOS 以 16 位模式运行。
- UEFI 能够提供 GUI, 允许使用鼠标进行导航,而 BIOS 仅允许使用键盘进行导航。
- 如果操作系统以 16 位模式运行,使用 BIOS 不需要编写与硬件交互的代码。它可以直接使用 BIOS 提供的 API.否则,如果操作系统切换到 32 位或 64 位模式,则需要提供自己的与硬件交互的子程序。
由于 UEFI 自身相对于 BIOS 存在一些限制,所以也提供了传统模式(Legacy mode)。在该模式下,可以像拥有 BIOS 固件一样运行所有内容
UEFI 架构
UEFI 启动过程
- cpu reset 后启动 UEFI 固件并启动加电自检(POST)
- 检查硬件组件的完整性
- POST 成功完成后,UEFI 固件会查找可启动设备
- 在 UEFI 系统中,固件与 UEFI 启动管理器交互, 启动管理器会查阅 UEFI 启动变量
- UEFI 启动管理器: 一个负责加载操作系统的软件
- UEFI 启动变量: 包含有关可用启动选项及其优先级的信息,存储在非易失性存储器中,用户或系统管理员可以对其进行修改以自定义启动配置
- UEFI 固件在启动管理器的帮助下,定位 SSD 上 EFI 系统分区(ESP)中存储的 UEFI 引导加载程序
- UEFI 引导加载程序是一个小程序,它了解文件系统并知道如何将操作系统内核加载到内存中
- 一旦 UEFI 引导加载程序加载了操作系统内核,控制权便转移给操作系统,并向用户呈现用户界面
EFI 系统分区
通常是一个采用 FAT32 格式化的分区,最小空间为 100MB
该分区包含 EFI 应用程序,这些应用程序通常位于自己的目录中。可能包含多个 EFI 应用程序,因为可能安装了多个操作系统。
EFI 变量
存储在主板的 NVRAM 中
- 每台电脑的主板上都有自己的EFI变量。这些变量里可能包含了一些特定的设置或参数,是启动操作系统时必需的
重要变量:
- 默认启动项 (BootCurrent)
对于 Linux 系统来说,有一个特别的 EFI 应用程序: EFI stub, 它可以直接从 EFI 环境启动 Linux 内核,而不需要传统的引导加载程序(如 GRUB )。此时 EFI 变量里就会包含 Linux 内核启动时需要的命令行参数,比如指定根文件系统所在的分区。而如果使用 GRUB 这样的引导加载程序,这些参数就会写在 GRUB 的配置文件中
EFI 变量可以从操作系统内部直接修改