ESP

UEFI 是相比于 BIOS 更加先进的固件,它不再局限于寻找 MBR ,而是可以直接加载外存上的 EFI 文件(这些文件往往就是bootloader)。

UEFI 有专门的 ESP (EFI System Partion) 来存储启动相关的文件和数据,这在 Linux 上就是 /boot/ 目录,如果用 lsblk -f 去查看,就可以看到相关显示,会发现这个分区的文件系统是 FAT ,这主要是为了提高跨平台兼容性。

在 ESP 中存放着:

  • bootloader: 如 Grub
  • 内核镜像:比如说 /boot/vmlinuz-linux
  • bootloader 的配置文件等

Boot Flow

UEFI 的启动流程如下图所示:

SEC

使用汇编,因为没有栈,所以无法使用 C 语言。

在这个阶段它将 Cache 初始化为临时内存,因为没有内存就没有栈,就无法使用 C 语言,工程的可维护性就会变差。

而内存并不能轻易初始化,所以我们会选择用 Cache 先当作内存,但是也需要一定的特殊配置。

PEI

在 PEI 阶段我们会对内存进行初始化,并进行一些其他简单的平台初始化任务(比如说 GPIO, Serial)。

PEI 会真正初始化内存,而原本内存的数据在 cache 中,这时候就需要重新执行一遍 PEI 阶段,将数据从 cache 搬运到内存中。

PEI 就开始引入模块化的设计,具体而言就是,存在一个 PEI Core 用于调度多个模块,PEI 阶段的模块被称为 PEIM 。调度使用的是在同一上下文顺序调度(要检查依赖关系),依赖函数指针。模块间通信的接口被称为 PPI 。

DXE

在 DXE 阶段我们拥有了完整的内存,可以执行更加复杂的功能了(如网络,解码)。

正因为功能更加复杂了,所以我们需要更加复杂的协调机制。在 DXE 中我们同样采取“Core + Module”的方式,不过我们这次 enable 了 time interupt ,所以可以支持一些 Device Notify 。

DXE 和 PEI 的对比如下:

BDS

在这个阶段我们选择要在哪个外存上 boot 操作系统。

TSL

这可能是一个可选的阶段,我们进入这个阶段,一般是因为 OS 启动不了了,这个阶段是一个紧急救援阶段。

System Manage Mode

这是一个比 ring-0 权限还高的处理模式,而且对 OS 完全透明(避免了恶意的 OS)。主要用于处理一些和硬件密切相关的任务。

它实现了一组 handler ,当发生 SMI (SM Interupt)的时候,会选择一个 handler 进行执行。它执行在一片特殊的内存 SMRAM 中,这片内存对 OS 完全不可见。

UEFI System Class

根据 OS 对 UEFI 的适配程度(过去这些 OS 适配 BIOS),UEFI 将其分为 4 个 class ,如下所示: