Skip to content

Latest commit

 

History

History
167 lines (110 loc) · 7.57 KB

210625a_uefi.md

File metadata and controls

167 lines (110 loc) · 7.57 KB

UEFI 开发入门

UEFI最初由Intel开发用于其IA-64平台。作为传统BIOS的继任者,UEFI在各种现代计算机中得到了广泛应用。UEFI适用于各种类型的CPU,目前大部分基于x86_64的计算机以及近几年开始出现的基于ARM的服务器都广泛使用了UEFI

参考

UEFI原理与编程, 戴正华, 2015

0 UEFI 是什么

UEFI全称Unified Extensible Firmware Interface(统一可扩展固件接口),用于取代传统BIOS。UEFI只是一种标准,而具体实现由开源组织或公司提供,目前主要有Intel公司开源的TianoCore

1 UEFI 基本概念

1.1 UEFI 组成

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提供以下服务:

  1. 事件服务:是异步操作的基础。异步操作是并发执行的基础

  2. 内存管理:负责内存的分配或释放,以及管理内存的映射

  3. Protocol管理:提供安装/卸载Protocol的服务,以及注册Protocol通知函数(Protocol安装时被调用)

  4. Protocol使用类服务:包括了Protocol的打开与关闭,以及查找支持Protocol的控制器。比如读写一个PCI设备的寄存器,就会用到这些服务

  5. 驱动管理:包括了用于将驱动安装到控制器的connect服务,以及用于卸载的disconnect服务。比如网络驱动的加载,可以先将驱动Image加载到内存,再通过connect将驱动安装到设备

  6. Image管理:提供了加载、卸载、启动以及退出UEFI的驱动或应用程序的服务

  7. ExitBootService:用于结束BS

RT提供以下服务:

  1. 时间服务:用于读取或设定系统时间,或系统从睡眠状态唤醒的时间

  2. 读写UEFI系统变量:比如启动顺序等,这些变量会被保存(非易失,一般位于NVRAM)

  3. 虚拟内存服务:逻辑地址、物理地址的转换

  4. 其他:比如重启ResetSystem

1.2 UEFI 启动流程

UEFI的启动遵循UEFI的平台初始化标准。UEFI从启动到关机会经历7个不同的阶段

1.2.1 SEC:安全验证

Security Phase。之所以被称为安全阶段,是因为SEC是整个系统的可信任的基础。

SEC阶段主要有4个功能

  1. 接收处理系统启动以及重启信号:比如上电信号,重启信号,运行异常信号

  2. 初始化临时存储区域:将Cache初始化为RAM使用(no-eviction模式),这种技术被称为CAR(Cache As RAM)技术

  3. 作为可信任系统的基础:只有SEC可信任,之后的步骤才是可信任的

  4. 将参数传递给PEI:为PEI阶段做准备,将系统当前状态、可启动固件(Boot Firmware Volume)的地址以及大小、临时RAM的地址以及大小、栈的地址以及大小传递给PEI

SEC的执行流程分为两部分:其中临时RAM生效之前为Reset Vector阶段,在临时RAM生效之后调用SEC入口函数进入SEC功能区

Reset Vector执行流程有以下6步

  1. 进入固件入口

  2. 从16位实模式转为32位包含模式

  3. 定位固件中的BFV(Boot Firmware Volume)

  4. 定位BFV中的SEC映像

  5. 64位系统则从32位模式转为64位模式

  6. 调用SEC入口函数

SEC功能区一般会进行以下步骤

  1. 由于此时临时RAM已经可用,所以已经可以使用栈,先初始化栈,之后可以进行函数调用

  2. 初始化IDT、浮点寄存器等,并且将临时RAM地址、栈地址、BFV地址装入SecCoreDataEFI_SEC_PEI_HAND_OFF类型结构体)

  3. 最后调用PEI入口函数(在BFV中),同时传递SecCoreData给下一阶段PEI,将控制权转移给PEI

1.2.2 PEI:前期EFI初始化

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执行流程如下

  1. 首先入口调用PeiCore

  2. 根据SEC传入的的信息初始化PEI Core Services

  3. 调用PeiDispatcher执行PEIM

  4. 内存初始化后,再次进入PeiCore,此时使用的是初始化后的内存

  5. 获取DXE IPL PPI,调用其Entry服务(DxeLoadCore),执行DXE入口函数并将HOB传递给DXE

1.2.3 DXE:驱动执行环境

Driver Execution Environment。此时内存已经被初始化,是最重要的部分,绝大多数初始化都在此完成,原理和PEI类似

DXE同样分为内核派遣器两部分。在这里,DXE的每一个模块被称为驱动,通过Protocol进行通信,每个Protocol都有一个GUID。可以通过BootServicesOpenProtocol使用该Protocol提供的服务,Protocol可以根据GUID找到

DXE执行流程如下

  1. 调用DXE入口

  2. 根据PEI传入的HOB初始化系统服务

  3. 执行驱动

  4. DXE通过EFI_BDS_ARCH_PROTOCOL查找到BDS并且调用其入口函数进入BDS阶段

1.2.4 BDS:启动设备选择

Boot Device Selection。BDS本质也是一个DXE应用,用于执行启动策略

BDS主要有以下功能

  1. 初始化控制台设备

  2. 加载必要的设备驱动

  3. 根据设置加载执行启动项

BDS通过NVRAM配置,选项变量可以通过RT提供的GetVariable()SetVariable()配置。

使用过efibootmgr的应该知道BootOrder显示为BootXXXX,这就是一个变量

选中一个启动项以后就会调用Bootloader,系统进入TSL阶段

1.2.5 TSL:系统加载前期

Transient System Load。是Bootloader执行的第一阶段,此时Bootloader作为一个UEFI应用执行,资源仍然由UEFI内核控制。在ExitBootServices()被调用之后系统才会进入RT阶段

TSL阶段的功能已经非常强大,已经类似于一个微型的操作系统。UEFI Shell就是这个系统的Shell

1.2.6 RT:运行时

Run Time。此时系统资源从UEFI内核回收转交给Bootloader,系统控制权由Bootloader掌控,只有RT服务会留下来继续给Bootloader以及OS使用

1.2.7 AL:灾难恢复

After Life。在运行中出现错误后的错误处理以及灾难恢复机制

2 开发环境搭建

基于Linux