【UEFI 开源系列第一篇】什么是 UEFI?

进迭开源uefi代码仓库: Bianbu Linux/edk2-platforms

【UEFI 开源系列第一篇】什么是 UEFI?

UEFI是什么?

UEFI(Unified Extensible Firmware Interface,统一可扩展固件接口) 是一种现代化的启动系统接口,取代了传统的 BIOS,在 x86 和 ARM 架构上已经广泛使用。

传统的BIOS

传统的BIOS,指的是一种在计算机启动时初始化硬件并加载操作系统引导程序的标准接口。即主要负责开机时检测硬件功能和引导操作系统启动。

传统BIOS启动过程:计算机开机时,硬件被设置为开始执行BIOS,BIOS负责初始化硬件,引导加载程序,然后引导加载程序负责加载并启动操作系统。BIOS存储在可擦除可编程只读存储器,既然BIOS如此完善,为什么我们需要UEFI呢?

1, BIOS负责识别主引导记录(MBR)初始化的硬盘,mbr位于磁盘第一个扇区(512字节),包含引导代码(446字节),分区表(64字节),标识符:ox55aa(2字节),分区表每个条目16字节,所以最多只能四个分区。且MBR分区表最大支持2TB磁盘,扩展分区容易出错。BIOS无法直接识别文件系统,引导加载程序自行实现文件系统驱动。

2, BIOS是16位汇编语言代码,1M内存寻址,中断执行,所以如果使用BIOS启动,开机时是再16位实模式下访问,那么它能直接访问的内存只有1MB。需要进行复杂的切换才能进入操作系统。

3, BIOS启动时需要依次检测硬件,无法并行初始化设备,无法验证操作系统加载器(grub等)的完整性。

BIOS的这些限制,推动了UEFI的诞生。

UEFI优势

更快的启动速度

并行化检测和初始化硬件设备,获得更快的启动速度

直接加载efi应用程序,无需依赖MBR/VBR的多阶段引导

内置文件系统启动,可直接读取磁盘文件,不需要引导加载程序

支持大容量磁盘与GPT分区

GPT支持128个主分区,支持64位寻址

安全启动

可验证引导加载程序(.efi)的数字签名

更好的兼容与扩展性

模块化设计,采用驱动模型(如EFI_DRIVER),可动态加载硬件驱动

内置网络协议栈,支持http、https,tftp引导

UEFI允许从任意FAT32分区加载efi程序

UEFI核心组件

BOOT SERVICE

在操作系统加载前启动,启动服务在操作系统加载完成后会被终止,操作系统接管系统资源,启动服务提供以下服务:

1, 对内存进行管理,分配和释放内存,支持不同类型的物理内存(如常规内存和保留内存)。

2, 利用timer来创建和管理事件,支持异步操作和定时器功能。

3, 安装、卸载和查找协议(Protocol),用于驱动程序和应用程序之间的通信。

4, 加载和启动操作系统内核或其他可执行镜像。

5, 提供对硬件设备的访问和控制。

RUNTIME SERVICE

在操作系统运行期间提供一系列关键功能,包括时间管理、变量服务和系统重置等。与启动服务不同,运行时服务在操作系统加载完成后仍然可用,为操作系统和应用程序提供与固件的交互接口。

时间管理: 获取和设置系统时间。

变量服务: 读写 UEFI 变量(如启动顺序、硬件配置等)。UEFI 变量通常用于存储系统配置信息,例如:启动顺序(BootOrder):定义系统的启动设备顺序。硬件配置:存储硬件相关的设置(如网络配置、安全设置等)。

系统重置: 支持系统重启或关机(RISC-V架构下,系统重启和关机通过openSBI实现)。

虚拟内存管理 在操作系统运行期间管理虚拟内存映射。

OS LOADER

OS Loader(操作系统加载器) 是 UEFI 启动流程的一部分,依赖于 UEFI 的启动服务(Boot Services)和运行时服务(Runtime Services),从启动设备(如硬盘、光盘或网络)加载操作系统内核,并为其准备执行环境,将控制权从 UEFI 固件转移到操作系统。

Windows的os loader是bootmgfw.efi,负责:

加载Windows内核

准备 Windows 启动环境

Linux的os loader是grub,负责:

加载 Linux 内核(vmlinuz)和ramdisk(initrd)

支持多操作系统启动

提供命令行界面,用于调试和配置

ACPI

ACPI(Advanced Configuration and Power Interface,高级配置与电源接口)用于定义操作系统与硬件之间的电源管理和硬件配置接口。ACPI 提供了一种标准化的方式,使操作系统能够管理硬件资源、控制电源状态,并支持即插即用功能。其不仅定义了电源管理功能,还提供了硬件资源的描述和配置接口。

ACPI表

ACPI 表是 ACPI 的核心数据结构,用于描述硬件资源和电源管理信息。ACPI 表通常在 UEFI 的 DXE(Driver Execution Environment)阶段生成,并由 UEFI 传递给操作系统。ACPI table以二进制格式存储,操作系统通过解析这些表获取硬件信息。

SMBIOS

SMBIOS(System Management BIOS) 是由 DMTF(分布式管理任务组)制定的一项标准,旨在为操作系统和管理工具提供系统硬件信息的标准化接口。通过一种结构化的方式,将系统的硬件配置、固件版本、主板信息等数据传递给操作系统或管理工具。SMBIOS 数据表由UEFI生成,存储在系统内存中,操作系统可以通过system table访问这些数据。

操作系统或管理工具可以通过以下方式访问 SMBIOS 表:

System table: kernel下通过EFI_SYSTEM_TABLE获取EFI_CONFIGURATION_TABLE,进而定位SMBIOS表的地址

操作系统: 用户可以通过工具(如 dmidecode)查询 SMBIOS 数据,获取系统的硬件信息。

系统管理工具: IPMI、Redfish标准中使用 SMBIOS 数据监控硬件状态、诊断故障和管理系统资源。

UEFI启动

UEFI 包含六个主要的启动步骤,这些步骤在平台的启动和初始化过程中都扮演着至关重要的角色。所有这些步骤加在一起,我们通常称之为“平台初始化”(Platform Initialization,简称 PI)。

安全阶段(SEC)

这是UEFI启动流程的首要阶段,主要用于:初始化一个临时的内存存储区域,作为系统信任链的起点,并向Pre-EFI初始化(PEI)阶段提供必要的信息。这个信任链的起点确保了在平台初始化(PI)过程中执行的任何代码都经过加密验证(即数字签名),从而建立一个“安全启动”的环境。

Pre-EFI初始化阶段(PEI)

这是启动流程的第二阶段,它仅利用CPU当前的资源来调度Pre-EFI初始化模块(PEIM)。这些模块负责执行关键的启动操作初始化,如内存初始化,同时也允许将控制权传递给驱动程序执行环境(DXE)。

驱动程序执行环境(DXE)

在DXE阶段,系统的大部分初始化工作都会发生。在PEI阶段,DXE操作所需的内存已经被分配和初始化。当控制权传递给DXE时,DXE调度器会被激活。调度器负责加载和执行硬件驱动程序、运行时服务和任何操作系统启动所需的启动服务。

启动设备选择(BDS)

一旦DXE调度器完成了所有DXE驱动程序的执行,控制权就会传递给BDS。这个阶段负责初始化控制台设备和任何剩余的必需设备。然后,它会加载并执行选定的启动项,为瞬态系统加载(TSL)阶段做准备。

瞬态系统加载(TSL)

在这个阶段,PI流程处于启动设备选择和将控制权移交给主操作系统之间的过渡阶段。此时,可能会调用一个应用程序(如UEFI shell),或者(更常见的是)运行一个引导加载程序来准备最终的操作系统环境。引导加载程序通常负责通过调用ExitBootServices()来终止UEFI启动服务。但是,操作系统本身也可以执行这一操作,比如带有CONFIG_EFI_STUB的Linux内核。

运行时(RT)

这是最后的阶段,也是操作系统接管系统的时刻。尽管此时UEFI的启动服务已经不再可用,但UEFI的运行时服务仍然保留给操作系统使用,例如用于查询和写入NVRAM中的变量。

下一篇预告

敬请期待:【UEFI 开源系列第二篇】UEFI 在 SpacemiT K1 上的解决方案