第3章 UEFI固件初始化与ABL环境准备
ABL(Android Bootloader)作为一个UEFI应用程序在TSL(临时系统加载)阶段被调用。它依赖的运行时环境——CPU模式、内存映射、芯片组寄存器以及服务表指针——全部由前序的UEFI阶段(SEC→PEI→DXE→BDS)建立。本章拆解这些初始化的核心环节,并说明ABL如何通过EFI_SYSTEM_TABLE获取所需服务。
| 阶段 | 主要行为 | ABL依赖程度 |
|---|---|---|
| SEC (Security) | 设置临时栈、切换至保护模式 | 间接 – 提供基础CPU模式 |
| PEI (Pre-EFI Initialization) | 初始化内存控制器、CPU微码、Cache作为RAM | 高 – 内存拓扑必须正确 |
| DXE (Driver Execution Environment) | 枚举PCI、初始化芯片组寄存器、安装UEFI协议 | 高 – 服务表与Protocol可用 |
| BDS (Boot Device Selection) | 选择启动设备并调用Boot Manager | 触发 – BDS加载ABL.efi |
| TSL (Temporary System Load) | ABL在此阶段运行,使用Boot Services | 核心 – 所有内存/服务均就绪 |
3.1 CPU初始化
UEFI固件在SEC阶段将CPU从实模式切换至保护模式(或长模式),并建立初始GDT/IDT。PEI阶段会加载微码补丁、启用MTRR(内存类型范围寄存器)并设置页表。ABL启动时CPU已经处于64位长模式(AArch64或x64),OS装载器只需检查CR0、CR3即可确认状态。
; x64长模式检查(IA32_EFER.LME = 1)
mov ecx, 0xC0000080 ; MSR IA32_EFER
rdmsr
and eax, 0x100 ; LME bit
cmp eax, 0x100
jne .not_long_mode
ArmDisableInterrupts()或CPU_ARCH_DISABLE_INTERRUPT宏以确保安全环境。3.2 内存初始化
内存初始化分为两步:PEI阶段通过MCH(内存控制器中心)配置DIMM时序、DDR频率,并使用Cache-as-RAM (CAR)作为临时RAM;DXE阶段安装完整的全局内存映射。ABL依赖的服务表位于系统内存的高端区域,其物理地址在BDS阶段被写入UEFI_IMAGE_ENTRY_POINT参数。
// UEFI内存描述符结构 (EFI_MEMORY_DESCRIPTOR)
typedef struct {
UINT32 Type; // 0 = Reserved, 3 = BootServicesCode, ...
UINT32 Pad;
UINT64 PhysicalStart;
UINT64 VirtualStart;
UINT64 NumberOfPages;
UINT64 Attribute; // 缓存属性、预留位
} EFI_MEMORY_DESCRIPTOR;
ABL在BootServices->GetMemoryMap()中获取这个描述符列表,用于后续向Linux内核传递memmap参数。
3.3 芯片组初始化
芯片组初始化包括南桥(PCH)、北桥(系统代理)以及各种I/O控制器(SATA、USB、PCIe Root Complex)。DXE驱动会执行以下典型操作:
- PCI总线枚举 – 为每个设备分配总线号、内存/IO空间。
- ACPI表构建 – 在内存中填写MADT、FADT、DBG2等表。
- 寄存器锁定 – 例如
SPI_BAR、GPIO_BASE、BDF_TABLE。
ABL直接使用的芯片组资源包括:
// 通过UEFI Protocol访问GPIO或I2C
EFI_STATUS Status;
EFI_GPIO_PROTOCOL *Gpio;
Status = gBS->LocateProtocol(&gEfiGpioProtocolGuid, NULL, (VOID**)&Gpio);
if (EFI_ERROR(Status)) {
DEBUG((EFI_D_ERROR, "GPIO Protocol not found\n"));
return Status;
}
PLATFORM_PORT80寄存器。3.4 ABL依赖的UEFI服务表
ABL入口函数EfiMain的第一个参数是ImageHandle,第二个参数是EFI_SYSTEM_TABLE指针。系统表是ABL与UEFI固件交互的唯一入口。
// 精简版系统表定义
typedef struct {
EFI_TABLE_HEADER Hdr;
CHAR16 *FirmwareVendor;
UINT32 FirmwareRevision;
EFI_HANDLE ConsoleInHandle;
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
EFI_HANDLE ConsoleOutHandle;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
EFI_HANDLE StandardErrorHandle;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
EFI_RUNTIME_SERVICES *RuntimeServices;
EFI_BOOT_SERVICES *BootServices;
UINTN NumberOfTableEntries;
EFI_CONFIGURATION_TABLE *ConfigurationTable;
} EFI_SYSTEM_TABLE;
ABL主要使用BootServices(内存分配、协议定位、事件)和ConfigurationTable(获取ACPI表、设备树或SMBIOS)。
| 服务指针 | 典型用途 | ABL阶段 |
|---|---|---|
gBS->AllocatePages | 为大内核分配连续内存 | 加载内核前 |
gBS->LocateProtocol | 获取LoadFile2、PlatformInfo协议 | 初始化时 |
gRT->GetVariable | 读取Boot Args变量 | 配置解析 |
gST->ConfigurationTable | 获取设备树基址 | 传递FDT |
gBS->ExitBootServices()后不可再使用BootServices指针,必须提前将所有需要的数据复制到RuntimeServices内存中。上图展示了UEFI初始化阶段的流水线以及ABL在TSL阶段所能依赖的核心环境。所有初始化工作在DXE结束时已经完成,ABL通过系统表直接存取这些资源。