UEFI最初由Intel开发用于其IA-64平台。作为传统BIOS的继任者,UEFI在各种现代计算机中得到了广泛应用。UEFI适用于各种类型的CPU,目前大部分基于x86_64的计算机以及近几年开始出现的基于ARM的服务器都广泛使用了UEFI
UEFI原理与编程, 戴正华, 2015
UEFI全称Unified Extensible Firmware Interface(统一可扩展固件接口),用于取代传统BIOS。UEFI只是一种标准,而具体实现由开源组织或公司提供,目前主要有Intel公司开源的TianoCore
UEFI提供的接口分为启动服务(Boot Services, BS)以及运行时服务(Runtime Sercice, RT)。
从操作系统的Bootloader(比如GRUB)被加载,到Bootloader执行ExitBootServices()
,这个过程被称为TSL(Transient System Load),在这个过程中Bootloader可以通过BS或RT使用UEFI提供的服务,将计算机的资源转移到自己手中
Bootloader只是UEFI中的一个应用程序,一般的操作系统都会提供一个Bootloader放在ESP分区,为.efi
后缀
当Bootloader掌握所有资源之后,BS就会被结束并且资源会被回收。接下来进入Runtime阶段,此时只有RT会继续提供服务
TSL阶段的系统资源通过BS管理。BS提供以下服务:
事件服务:是异步操作的基础。异步操作是并发执行的基础
内存管理:负责内存的分配或释放,以及管理内存的映射
Protocol管理:提供安装/卸载Protocol的服务,以及注册Protocol通知函数(Protocol安装时被调用)
Protocol使用类服务:包括了Protocol的打开与关闭,以及查找支持Protocol的控制器。比如读写一个PCI设备的寄存器,就会用到这些服务
驱动管理:包括了用于将驱动安装到控制器的
connect
服务,以及用于卸载的disconnect
服务。比如网络驱动的加载,可以先将驱动Image加载到内存,再通过connect
将驱动安装到设备Image管理:提供了加载、卸载、启动以及退出UEFI的驱动或应用程序的服务
ExitBootService:用于结束BS
而RT提供以下服务:
时间服务:用于读取或设定系统时间,或系统从睡眠状态唤醒的时间
读写UEFI系统变量:比如启动顺序等,这些变量会被保存(非易失,一般位于NVRAM)
虚拟内存服务:逻辑地址、物理地址的转换
其他:比如重启
ResetSystem
等
UEFI的启动遵循UEFI的平台初始化标准。UEFI从启动到关机会经历7个不同的阶段
Security Phase。之所以被称为安全阶段,是因为SEC是整个系统的可信任的基础。
SEC阶段主要有4个功能
接收处理系统启动以及重启信号:比如上电信号,重启信号,运行异常信号
初始化临时存储区域:将Cache初始化为RAM使用(no-eviction模式),这种技术被称为CAR(Cache As RAM)技术
作为可信任系统的基础:只有SEC可信任,之后的步骤才是可信任的
将参数传递给PEI:为PEI阶段做准备,将系统当前状态、可启动固件(Boot Firmware Volume)的地址以及大小、临时RAM的地址以及大小、栈的地址以及大小传递给PEI
SEC的执行流程分为两部分:其中临时RAM生效之前为Reset Vector阶段,在临时RAM生效之后调用SEC入口函数进入SEC功能区
Reset Vector执行流程有以下6步
进入固件入口
从16位实模式转为32位包含模式
定位固件中的BFV(Boot Firmware Volume)
定位BFV中的SEC映像
64位系统则从32位模式转为64位模式
调用SEC入口函数
SEC功能区一般会进行以下步骤
由于此时临时RAM已经可用,所以已经可以使用栈,先初始化栈,之后可以进行函数调用
初始化IDT、浮点寄存器等,并且将临时RAM地址、栈地址、BFV地址装入
SecCoreData
(EFI_SEC_PEI_HAND_OFF
类型结构体)最后调用PEI入口函数(在BFV中),同时传递
SecCoreData
给下一阶段PEI,将控制权转移给PEI
Pre-EFI Initialization。PEI为下一步的DXE做准备,会对内存进行初始化,同时将信息构成HOB(Handoff Block)传递给PEI
PEI的执行流程同样分为两部分:PEI内核(PEI Foundation)以及PEIM(PEI Module)派遣器,PEI内核负责PEI基础服务,PEI阶段初始化工作主要由PEIM完成,PEIM为独立模块,而派遣器就是负责找出这些PEIM并按顺序执行。PEI本身其实也是一个PEIM。PEIM载入临时内存以后生成PEI Image,可以调用_ModuleEntryPoint
进入
PEIM都有自己的入口函数。PEIM的入口处会传入一个PeiServices
,通过这个指针可以调用PEI阶段的系统服务,以及访问PEI内核。PEIM之间通过PPI通信。每个PPI都是一个结构体,并且都有一个GUID,可以通过PEI服务中的LocatePpi
获取对应GUID的PPI
PEI执行流程如下
首先入口调用
PeiCore
根据SEC传入的的信息初始化PEI Core Services
调用
PeiDispatcher
执行PEIM内存初始化后,再次进入
PeiCore
,此时使用的是初始化后的内存获取DXE IPL PPI,调用其Entry服务(
DxeLoadCore
),执行DXE入口函数并将HOB传递给DXE
Driver Execution Environment。此时内存已经被初始化,是最重要的部分,绝大多数初始化都在此完成,原理和PEI类似
DXE同样分为内核与派遣器两部分。在这里,DXE的每一个模块被称为驱动,通过Protocol进行通信,每个Protocol都有一个GUID。可以通过BootServices
的OpenProtocol
使用该Protocol提供的服务,Protocol可以根据GUID找到
DXE执行流程如下
调用DXE入口
根据PEI传入的HOB初始化系统服务
执行驱动
DXE通过
EFI_BDS_ARCH_PROTOCOL
查找到BDS并且调用其入口函数进入BDS阶段
Boot Device Selection。BDS本质也是一个DXE应用,用于执行启动策略
BDS主要有以下功能
初始化控制台设备
加载必要的设备驱动
根据设置加载执行启动项
BDS通过NVRAM配置,选项变量可以通过RT提供的GetVariable()
和SetVariable()
配置。
使用过
efibootmgr
的应该知道BootOrder显示为BootXXXX,这就是一个变量
选中一个启动项以后就会调用Bootloader,系统进入TSL阶段
Transient System Load。是Bootloader执行的第一阶段,此时Bootloader作为一个UEFI应用执行,资源仍然由UEFI内核控制。在ExitBootServices()
被调用之后系统才会进入RT阶段
TSL阶段的功能已经非常强大,已经类似于一个微型的操作系统。UEFI Shell就是这个系统的Shell
Run Time。此时系统资源从UEFI内核回收转交给Bootloader,系统控制权由Bootloader掌控,只有RT服务会留下来继续给Bootloader以及OS使用
After Life。在运行中出现错误后的错误处理以及灾难恢复机制
基于Linux