文章目录
- 此书的背景
- UEFI运行时
- DXE基础
- CPU架构协议
- PCI协议
- UEFI驱动的初始化
- 串口DXE驱动示例
《Beyond BIOS》首先介绍一个简单的UEFI应用程序模块,用于展示UEFI应用程序的行为。作者为Waldo。该模块名为“InitializeHelloApplication”,它接受两个参数:ImageHandle和SystemTable。在程序中,首先向ConsoleOut设备发送一条消息,然后等待用户按下任意键,最后退出应用程序并返回EFI_SUCCESS状态。要执行该UEFI应用程序,可以在UEFI Shell命令行中输入程序名。假设hello.efi在UEFI Shell环境的搜索路径中,可以通过示例Shell> hello来运行该应用程序。该应用程序在用户按下任意键后返回UEFI Shell提示符。本文还提供了一些注释和说明,以帮助读者更好地理解程序的作用和功能。通过这个简单的UEFI应用程序模块,读者可以了解UEFI应用程序的基本结构和行为,以及如何使用UEFI API进行简单的输入输出和操作系统的加载。
此书的背景
主要介绍了从硬件到软件的飞跃如何带来一段无政府状态和崩溃的时期,特别是在发达国家。这一版还概述了从可扩展固件接口(EFI)到统一可扩展固件接口(UEFI)的演变,以及从英特尔框架规范到UEFI平台初始化(PI)规范的转变。注意,在规范的标题中省略了“Framework”一词。此外,这一章还讨论了UEFI PI规范如何成为行业标准,以及UEFI PI规范如何帮助行业成员更好地实现系统启动和运行。
- 该书第二版的出版是经过了时间的考验,因为自从第一版问世以来,技术进步已经取得了巨大的进步。
- 对于UEFI和GPT等术语的解释和说明,以便读者更好地理解这些技术在现代计算机系统中的重要性和应用。
- 该书的目标仍然是帮助读者理解这些新技术,以及它们在构建现代计算机系统中的角色和作用。
- 作者对读者的感谢和认可,以及对支持和鼓励他完成这本书的人的感谢。
UEFI运行时
UEFI Runtime是UEFI(统一可扩展固件接口)规范中的一部分,它定义了在系统引导过程中,固件将控制权交给操作系统后,依然能提供给操作系统运行时使用的服务。这些服务包括系统配置信息、各种UEFI服务和函数等。
在系统引导过程中,当UEFI将控制权交给操作系统后,会继续运行一些服务,这就是UEFI Runtime。这些服务主要运行在固件和操作系统之间,为操作系统提供必要的支持和功能。
具体来说,UEFI Runtime主要提供以下服务:
- 系统配置信息:UEFI Runtime提供了一种方式,让操作系统可以获取系统的配置信息,如处理器、内存、硬盘等硬件信息,以及启动参数等。
- UEFI服务:UEFI Runtime还提供了一些UEFI服务,如内存管理、文件系统、网络服务等。这些服务可以帮助操作系统更好地运行和管理系统资源。
- 运行时函数:UEFI Runtime还提供了一些运行时函数,如重启、关机等操作。这些函数可以在操作系统的运行过程中被调用,以便进行一些系统级别的操作。
需要注意的是,UEFI Runtime并不是一个完整的操作系统,它只是提供了一些必要的服务和函数,以便操作系统可以更好地运行和管理系统资源。
DXE基础
DXE指的是平台初始化驱动执行环境,它在UEFI(统一可扩展固件接口)的预引导阶段和PEI(Pre-EFI Initialization)阶段之间起着关键的作用。DXE的主要功能是将平台硬件映射到各种硬件平台上,以便在UEFI服务可用之前执行。
在DXE阶段,一些重要的组件包括DXE核心、DXE调度程序和DXE驱动程序。DXE核心提供了一个执行环境,它负责将PEI的核心服务映射到各种硬件平台上。DXE调度程序负责在DXE服务中调度和执行各种服务。DXE驱动程序则负责与硬件交互,以便在UEFI服务可用之前执行。
此外,DXE还包括一些重要的协议,例如ACPI(高级配置和电源接口)编辑协议和SIO(系统输入输出)协议。ACPI编辑协议用于编辑和读取ACPI表,这些表描述了系统的硬件配置和电源管理设置。SIO协议则提供了与系统输入/输出设备的通信功能。
在DXE阶段还有一些重要的概念,例如BDS(Boot Device Selection)阶段。BDS阶段是在UEFI服务可用之前执行的,它负责选择启动设备并加载启动设备上的引导加载程序。
总之,DXE是UEFI固件的一个重要组成部分,它提供了一个执行环境,将平台硬件映射到各种硬件平台上,以便在UEFI服务可用之前执行。它还包括一些重要的组件和协议,以提供必要的服务和与硬件交互的功能。
CPU架构协议
主要介绍了UEFI的定义、重要概念和协议、系统管理模式的更新、设备驱动模型的交互作用以及安全功能等内容。
- 介绍了Unified Extensible Firmware Interface (UEFI)的定义和作用。UEFI是一种描述平台硬件接口的规范,它允许在预操作系统阶段进行一些操作,如加载驱动、运行诊断等。
- 描述了UEFI中的一些重要概念和协议,如Multiprocessor Protocol、Itanium E-SAL and MCA support、Report-status code listener、SMBIOS protocol、ACPI editing protocol、SIO protocol等。
- 介绍了UEFI在系统管理模式的更新,包括对SMM协议和基础设施的抽象化处理,以及将各种CPU和芯片组的实现从更通用的组件中分离出来。
- 描述了UEFI在设备驱动模型中的交互作用,包括如何配置基础设施和使用配置基础设施等。
介绍了UEFI的安全功能,如Trusted Platform Module (TPM)和Measured Boot等。
PCI协议
- PCI I/O Protocol:这是一种由PCI总线驱动程序为每个PCI设备安装的协议实例。每个PCI I/O协议实例都配备了针对该PCI设备独特的数据值,包括UEFI选项ROM(OpROM)图像的位置和大小。
- Driver Model Interactions:介绍了如何使用配置基础设施来管理驱动程序模型之间的交互。
- Provisioning the Platform:介绍了如何使用配置基础设施来配置和启动平台组件,以及如何使用UEFI Secure Boot和UEFI Executable Verification等机制来确保平台的安全性和可信性。
UEFI驱动的初始化
UEFI驱动的初始化在UEFI固件加载后开始,主要在UEFI的SEC(安全验证)阶段进行。在这个阶段,计算机系统加电后进入SEC阶段,执行以下四种任务:
- 对计算机系统的基本硬件进行安全验证。
- 对计算机系统的固件进行加载。
- 初始化固件所需要的硬件设备。
- 执行其他必要的初始化操作。
在SEC阶段结束后,PEI(EFI前期初始化)阶段开始,这个阶段主要进行硬件的初始化工作。然后是DXE(驱动执行环境)阶段,在这个阶段,UEFI驱动程序被加载并准备运行。BDS(启动设备选择)阶段和TSL(操作系统加载前期)阶段是操作系统加载器作为UEFI应用程序运行的阶段。最后是RT(Run Time)阶段和AL(系统灾难恢复期)阶段。RT阶段包括操作系统加载器后期和操作系统运行期,当系统硬件或操作系统出现严重错误不能继续正常运行时,固件会尝试修复错误,这时系统进入AL期。但PI规范和UEFI规范都没有规定AL期的行为。
串口DXE驱动示例
DXE驱动的一般开发过程如下:
- 确定需要开发的DXE驱动的用途和功能,例如用于初始化某个硬件设备或提供某个特定的服务。
- 了解DXE驱动的架构和规范,包括UEFI规范和相关的协议,例如ACPI编辑协议和SIO协议等。
- 编写DXE驱动的代码,包括驱动程序的入口点、服务处理函数、回调函数等。
- 编译DXE驱动的代码,生成可执行文件。
- 将可执行文件加载到UEFI固件中,并测试DXE驱动的功能和稳定性。
下面是一个示例:
#include <Protocol/SimpleFilesystem.h>
#include <Protocol/SerialPort.h>
#include <Protocol/DevicePath.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h> // 串口DXE驱动程序入口点
EFI_STATUS
EFIAPI
SerialDxeInitialize(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
{ // 获取串口设备路径 EFI_DEVICE_PATH_PROTOCOL *DevicePath; DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ImageHandle; // 获取串口参数 UINTN BaudRate = 9600; UINTN DataBits = 8; UINTN Parity = 0; UINTN StopBits = 1; // 初始化串口 EFI_STATUS Status; Status = gBS->LocateProtocol(&gEfiSerialPortProtocolGuid, NULL, (VOID **)&SerialPort); if (EFI_ERROR(Status)) { return Status; } Status = SerialPort->Initialize(SerialPort, BaudRate, DataBits, Parity, StopBits); if (EFI_ERROR(Status)) { return Status; } // 打开串口并测试连接是否正常 Status = SerialPort->Open(SerialPort, DevicePath); if (EFI_ERROR(Status)) { return Status; } CHAR16 Buffer[10]; Status = SerialPort->Read(SerialPort, Buffer, sizeof(Buffer)); if (EFI_ERROR(Status)) { return Status; } // 返回成功状态码 return EFI_SUCCESS;
}
INF文件配置:
[Defines]
INF_VERSION =0x00010005
BASE_NAME = SerialDxe
FILE_GUID = 0x12345678-0x1234-0x1234-0x1234-0x123456789abc
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = SerialDxeInitialize
- INF_VERSION:INF文件的版本号,这里设置为0x00010005。
- BASE_NAME:驱动程序的名称,这里设置为SerialDxe。
- FILE_GUID:驱动程序的GUID,这里随意设置了一个值。
- MODULE_TYPE:驱动程序的类型,这里设置为DXE_DRIVER。
- VERSION_STRING:驱动程序的版本号,这里设置为1.0。
- ENTRY_POINT:驱动程序的入口点函数,这里设置为SerialDxeInitialize。