目录
UEFI编程基础
UEFI(Unified Extensible Firmware Interface)是一种替代传统BIOS的新标准,提供了更强大的功能和更好的扩展性。本文将详细介绍UEFI编程的基础知识,包括其架构、主要概念、开发工具和编程示例。
1. UEFI概述
1.1 什么是UEFI?
- 定义:UEFI 是一种标准化的固件接口,用于在操作系统启动之前初始化和配置硬件。
- 特点:
- 模块化设计:UEFI 采用模块化设计,每个模块负责特定的功能。
- 高级安全特性:支持安全启动(Secure Boot),防止未经授权的引导加载程序运行。
- 丰富的用户界面:提供图形化的用户界面,方便用户进行设置和配置。
- 更好的兼容性和扩展性:支持多种硬件平台和操作系统。
- 大容量存储支持:支持大于2TB的硬盘分区。
1.2 UEFI与传统BIOS的区别
- 架构:UEFI 采用模块化设计,而传统BIOS是基于中断的服务调用。
- 安全性:UEFI 支持安全启动,而传统BIOS没有类似的安全机制。
- 用户界面:UEFI 提供图形化的用户界面,而传统BIOS通常是文本界面。
- 扩展性:UEFI 支持更多的硬件平台和操作系统,而传统BIOS的扩展性较差。
2. UEFI架构
2.1 主要组件
- UEFI系统表(System Table):
- 包含系统的基本信息和函数指针,如内存映射、时间服务等。
- 协议(Protocols):
- 定义了一组接口,用于提供特定的功能和服务。
- 库类(Library Classes):
- 提供常用的功能和工具,如字符串处理、内存管理等。
- 平台初始化(Platform Initialization, PI):
- 描述了UEFI固件的初始化过程,包括PEI(Pre-EFI Initialization)、DXE(Driver Execution Environment)和SMM(System Management Mode)阶段。
2.2 启动流程
- 硬件初始化:
- PEI阶段:初始化CPU、内存等基本硬件。
- DXE阶段:加载和初始化驱动程序,构建运行时环境。
- 自检(POST):
- 执行Power-On Self-Test,检测硬件是否正常工作。
- 加载引导程序:
- 查找并加载操作系统的引导扇区,将控制权交给操作系统。
- 提供底层接口:
- 为操作系统提供访问和控制硬件的底层接口。
3. 开发工具
3.1 Visual Studio
- 下载和安装:
- 访问 Visual Studio 下载页面,下载并安装最新版本的Visual Studio。
- 确保选择C++开发工具。
3.2 EDK II
- 克隆仓库:
- 打开命令行终端,导航到一个合适的目录,然后克隆EDK II仓库。 sh
深色版本
git clone https://github.com/tianocore/edk2.git cd edk2
- 打开命令行终端,导航到一个合适的目录,然后克隆EDK II仓库。 sh
- 安装依赖项:
- Windows: sh
深色版本
.\edksetup.bat Rebuild python -m pip install --upgrade pip python -m pip install --user -r tools/edk2-pytool-extras/requirements.txt
- Linux: sh
深色版本
./edksetup.sh Rebuild sudo apt-get update sudo apt-get install -y build-essential uuid-dev iasl git nasm python3 python3-distutils python3 -m pip install --user -r tools/edk2-pytool-extras/requirements.txt
- Windows: sh
4. 编写第一个UEFI应用程序
4.1 创建项目目录
- 在EDK II目录下创建一个新的项目目录: sh
深色版本
mkdir MyHelloWorld cd MyHelloWorld
4.2 创建项目文件
4.2.1 创建.inf
文件
- 创建一个名为
MyHelloWorld.inf
的文件,内容如下: ini深色版本
[Defines] INF_VERSION = 0x00010005 BASE_NAME = MyHelloWorld FILE_GUID = 12345678-1234-1234-1234-1234567890AB MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 1.0 UEFI_SPECIFICATION_VERSION = 0x00020000 PI_SPECIFICATION_VERSION = 0x0001000C LIBRARY_CLASS = UefiApplication|DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER DXE_DRIVER UEFI_APPLICATION CONSTRUCTOR = MyHelloWorldConstructor [Sources] MyHelloWorld.c [Packages] MdePkg/MdePkg.dec Uefi/Uefi.dec [LibraryClasses] UefiLib UefiApplicationEntryPoint [Protocols] [Guids] [Ppis] [FeaturePcds] [FixedPcds] [DynamicExPcds] [DynamicPcds] [UserExtensions]
4.2.2 创建.c
文件
- 创建一个名为
MyHelloWorld.c
的文件,内容如下: c深色版本
#include <Uefi.h> #include <Library/UefiLib.h> #include <Library/UefiApplicationEntryPoint.h> EFI_STATUS EFIAPI UefiMain ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { // 输出 "Hello, World!" Print(L"Hello, World!\n"); // 等待用户按键 EFI_STATUS Status; EFI_INPUT_KEY Key; Status = SystemTable->ConIn->ReadKeyStroke(SystemTable->ConIn, &Key); if (EFI_ERROR(Status)) { Print(L"Failed to read key stroke\n"); } return EFI_SUCCESS; }
4.3 创建构建脚本
4.3.1 创建build.sh
脚本
- 创建一个名为
build.sh
的文件,内容如下: sh深色版本
#!/bin/bash # 设置工作目录 WORKSPACE=$(pwd)/.. export WORKSPACE # 设置目标平台 TARGET=DEBUG TOOLCHAIN=VS2019 ARCHITECTURE=X64 # 构建项目 build -t $TOOLCHAIN -p MyHelloWorld/MyHelloWorld.dsc -b $TARGET -a $ARCHITECTURE -D EFI_SOURCE -D USE_DEBUG_AGENT
4.3.2 创建.dsc
文件
- 创建一个名为
MyHelloWorld.dsc
的文件,内容如下: ini深色版本
[Defines] PLATFORM_NAME = MyHelloWorld PLATFORM_GUID = 12345678-1234-1234-1234-1234567890AB PLATFORM_VERSION = 1.0 DSC_SPECIFICATION = 0x00010020 OUTPUT_DIRECTORY = Build/MyHelloWorld/DEBUG_VS2019/X64 SUPPORTED_ARCHITECTURES = X64 FIRMWARE_TYPE = UEFI_APPLICATION FW_TYPE = UEFI_APPLICATION [BuildOptions] [LibraryClasses] UefiLib UefiApplicationEntryPoint [PcdsFixedAtBuild] [PcdsPatchableInModule] [PcdsDynamicDefault] [PcdsDynamicVpd] [PcdsDynamicExDefault] [PcdsDynamicExVpd] [PcdsFeatureFlag] [FeaturePcds] [FixedPcds] [DynamicExPcds] [DynamicPcds] [Components] MyHelloWorld/MyHelloWorld.inf
5. 编译和测试应用程序
5.1 编译项目
- 打开命令行终端,导航到
MyHelloWorld
目录: sh深色版本
cd C:\path\to\edk2\MyHelloWorld
- 运行构建脚本: sh
深色版本
./build.sh
5.2 测试应用程序
-
安装QEMU:
- Windows:
- 下载并安装QEMU。
- 链接: QEMU 下载页面
- 将QEMU的路径添加到系统环境变量中,例如
C:\Program Files\QEMU
.
- 下载并安装QEMU。
- Linux: sh
深色版本
sudo apt-get install qemu
- Windows:
-
使用QEMU测试应用程序:
- 导航到构建输出目录: sh
深色版本
cd Build/MyHelloWorld/DEBUG_VS2019/X64
- 运行QEMU并加载你的UEFI应用程序: sh
深色版本
qemu-system-x86_64 -bios OVMF.fd -drive format=raw,file=fv/MyHelloWorld.efi,if=none,id=myapp -device isa-debugcon,iobase=0x402,irq=0 -global isa-debugcon.iobase=0x402
- 导航到构建输出目录: sh
6. 常用库和函数
6.1 UEFI系统表
- 定义:包含系统的基本信息和函数指针。
- 使用示例: c
深色版本
EFI_SYSTEM_TABLE *SystemTable; SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello, World!\n");
6.2 UEFI库类
-
常用库类:
- UefiLib:提供字符串处理、内存管理等基本功能。
- UefiApplicationEntryPoint:提供UEFI应用程序的入口点函数。
- BaseLib:提供基本的数据类型和数学运算。
- DebugLib:提供调试信息输出功能。
-
使用示例:
c深色版本
#include <Library/UefiLib.h> #include <Library/UefiApplicationEntryPoint.h> EFI_STATUS EFIAPI UefiMain ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { // 输出 "Hello, World!" Print(L"Hello, World!\n"); // 等待用户按键 EFI_STATUS Status; EFI_INPUT_KEY Key; Status = SystemTable->ConIn->ReadKeyStroke(SystemTable->ConIn, &Key); if (EFI_ERROR(Status)) { Print(L"Failed to read key stroke\n"); } return EFI_SUCCESS; }
7. 进一步学习资源
-
官方文档:
-
书籍:
- 《UEFI Internals》:Michael D. Kinney, Jordan R. Hubbard
- 《Writing Device Drivers for the Intel Platform》:各种技术专家
-
在线资源: