UEFI BIOS深度解析:现代固件架构的革命性突破

UEFI BIOS深度解析:现代固件架构的革命性突破

本文深入探讨UEFI(统一可扩展固件接口)的架构设计、核心概念和相比Legacy BIOS的革命性优势

目录


UEFI概述

什么是UEFI?

UEFI(Unified Extensible Firmware Interface,统一可扩展固件接口)定义了连接操作系统和硬件体系之间的标准接口。它是由UEFI论坛(UEFI Forum)制定的开放标准,旨在替代传统的Legacy BIOS。

UEFI的发展历程

时间 事件 意义
1998年 Intel提出EFI 1.0 最初的EFI规范
2005年 UEFI 2.0发布 统一标准,更名为UEFI
2006年 UEFI 2.1发布 增加安全启动支持
2011年 Windows 8要求UEFI 推动UEFI普及
2017年 UEFI 2.7发布 支持更多新特性

UEFI的设计目标

  1. 跨平台支持:支持x86、x64、ARM、MIPS等多种架构
  2. 模块化设计:驱动和应用程序可以动态加载
  3. 标准化接口:统一的API和协议规范
  4. 安全性:内置安全启动和可信链机制
  5. 易用性:支持图形界面和鼠标操作

UEFI核心概念

在UEFI构建的软件世界中,有一些基本概念必须熟悉,它们是理解UEFI的基础。

1. 启动管理器(Boot Manager)

定义: UEFI的应用程序和驱动可以在任何UEFI规范支持的设备和文件系统中加载,而决定加载顺序的就是启动管理器。

功能:

  • 通过全局的NVRAM变量来管理加载顺序
  • 可以配置启动选项
  • 增加启动选项或从启动列表中删除无效的选项
  • 支持多操作系统启动

NVRAM变量示例:

bash 复制代码
# 查看启动项
efibootmgr -v

# 输出示例:
# BootCurrent: 0001
# BootOrder: 0001,0002,0003
# Boot0001* Windows Boot Manager
# Boot0002  Linux Boot Manager
# Boot0003  UEFI Shell

2. UEFI Images(UEFI镜像)

定义: UEFI Images是UEFI规范定义的包含可执行代码的二进制程序文件。

类型:

  • UEFI应用程序.efi文件,独立运行的程序
  • UEFI驱动.efi文件,为硬件提供驱动支持

文件结构:

UEFI镜像采用PE32(Portable Executable 32)文件结构,这是Windows可执行文件的标准格式:

复制代码
PE32文件结构:
├── DOS Header (MZ)
├── PE Header
├── Section Headers
├── .text (代码段)
├── .data (数据段)
└── .reloc (重定位段)

优势:

  • 支持跨平台(x86、ARM等)
  • 标准化的加载机制
  • 支持代码签名验证

3. UEFI Services(UEFI服务)

定义: UEFI Service是平台调用接口的集合,允许UEFI程序和操作系统调用。

分类:

  • 启动服务(Boot Services,BS):在操作系统加载前可用
  • 运行时服务(Runtime Services,RS):操作系统运行期间也可用

服务提供者:

  • UEFI应用程序
  • UEFI驱动
  • UEFI OS Loader(操作系统加载器)

4. UEFI Protocol(UEFI协议)

定义: UEFI Protocol本质上是一种数据结构,它包含三个部分:

  1. 全局唯一标识符(GUID):128位唯一标识符
  2. 接口数据结构:定义协议的数据结构
  3. 服务:协议提供的函数接口

GUID格式:

复制代码
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
例如:EFI_BLOCK_IO_PROTOCOL_GUID
     {964e5b22-6459-11d2-8e39-00a0c969723b}

Protocol示例:

c 复制代码
// EFI_BLOCK_IO_PROTOCOL结构
typedef struct {
    UINT64              Revision;
    EFI_BLOCK_IO_MEDIA  *Media;
    EFI_BLOCK_RESET     Reset;
    EFI_BLOCK_READ      ReadBlocks;
    EFI_BLOCK_WRITE     WriteBlocks;
    EFI_BLOCK_FLUSH     FlushBlocks;
} EFI_BLOCK_IO_PROTOCOL;

5. UEFI系统表(UEFI System Table)

定义: 所有UEFI镜像都会接收到一个指向UEFI系统表的指针,通过此系统表可以访问固件提供的UEFI Protocol。

系统表结构:

c 复制代码
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;

UEFI软件架构

架构层次图

复制代码
┌─────────────────────────────────────────┐
│         操作系统 (OS)                    │
├─────────────────────────────────────────┤
│     UEFI OS Loader                      │
│     (操作系统加载器)                     │
├─────────────────────────────────────────┤
│     UEFI Applications                   │
│     (UEFI应用程序)                       │
├─────────────────────────────────────────┤
│     UEFI Drivers                        │
│     (UEFI驱动)                          │
├─────────────────────────────────────────┤
│     Boot Services (BS)                  │
│     (启动服务)                          │
├─────────────────────────────────────────┤
│     Runtime Services (RS)               │
│     (运行时服务)                        │
├─────────────────────────────────────────┤
│     UEFI Protocols                      │
│     (UEFI协议)                          │
├─────────────────────────────────────────┤
│     UEFI System Table                   │
│     (UEFI系统表)                        │
├─────────────────────────────────────────┤
│     Platform Hardware                   │
│     (平台硬件)                          │
└─────────────────────────────────────────┘

架构特点

图1-2 UEFI软件架构

UEFI为操作系统启动和启动前的运行状态提供了一个标准的环境,规范中详细规定了系统的控制权如何从启动前环境传递到操作系统。它所规定的与平台信息相关的启动服务(BS)和运行时服务(RT),都是与平台架构相分离的,即独立于平台上的抽象接口。这就是为什么发展到现在,UEFI可以支持X86、ARM、MIPS等各种CPU架构的原因。

服务生命周期

对Option ROM开发者来说:

复制代码
┌─────────────────────────────────────────┐
│  Option ROM执行前                       │
│  ✓ Boot Services可用                   │
│  ✓ Runtime Services可用                │
├─────────────────────────────────────────┤
│  OS Loader加载后                        │
│  ✓ Boot Services可用                   │
│  ✓ Runtime Services可用                │
├─────────────────────────────────────────┤
│  ExitBootServices()调用后               │
│  ✗ Boot Services销毁                  │
│  ✓ Runtime Services保留                │
└─────────────────────────────────────────┘

关键点:

  • Option ROM运行于操作系统加载器执行前,启动服务和运行时服务都可以使用
  • 从操作系统加载器被加载,到操作系统加载器执行ExitBootServices()前的这段时间,是从UEFI环境向操作系统过渡的阶段,启动服务和运行时服务也同样可以使用
  • 在操作系统加载器执行ExitBootServices()之后,启动服务就完成了使命,其占用的资源会被回收,计算机系统进入UEFI Runtime阶段
  • 此后,就只能使用运行时服务了,启动服务已经从系统中销毁

UEFI服务详解

启动服务(Boot Services)

启动服务提供的服务包括如下几项:

1. Event(事件)服务

功能: 允许程序进行异步操作,这是UEFI得以执行并发操作的基础。

事件类型:

  • 定时器事件:基于时间的触发
  • 等待事件:等待某个条件满足
  • 通知函数:事件触发时调用的回调函数

示例代码:

c 复制代码
EFI_EVENT TimerEvent;

// 创建定时器事件
gBS->CreateEvent(
    EVT_TIMER,
    TPL_CALLBACK,
    NULL,
    NULL,
    &TimerEvent
);

// 设置定时器(10秒)
gBS->SetTimer(TimerEvent, TimerRelative, 10000000);

// 等待事件
gBS->WaitForEvent(1, &TimerEvent, NULL);
2. Timer(定时器)服务

功能: 配合Event提供定时器功能。

定时器类型:

  • TimerCancel:取消定时器
  • TimerPeriodic:周期性定时器
  • TimerRelative:相对时间定时器
  • TimerAbsolute:绝对时间定时器
3. 内存管理

功能: 提供内存的分配和释放服务,管理系统的内存映射。

内存类型:

类型 说明
EfiLoaderCode 加载器代码
EfiLoaderData 加载器数据
EfiBootServicesCode 启动服务代码
EfiBootServicesData 启动服务数据
EfiRuntimeServicesCode 运行时服务代码
EfiRuntimeServicesData 运行时服务数据
EfiConventionalMemory 常规内存
EfiUnusableMemory 不可用内存
EfiACPIReclaimMemory ACPI回收内存
EfiACPIMemoryNVS ACPI非易失性内存
EfiMemoryMappedIO 内存映射IO
EfiMemoryMappedIOPortSpace 内存映射IO端口空间
EfiPalCode PAL代码

内存分配示例:

c 复制代码
EFI_PHYSICAL_ADDRESS Memory;
UINTN Pages = 10; // 分配10页(4KB/页)

// 分配内存
EFI_STATUS Status = gBS->AllocatePages(
    AllocateAnyPages,
    EfiBootServicesData,
    Pages,
    &Memory
);

// 使用内存...

// 释放内存
gBS->FreePages(Memory, Pages);
4. Protocol服务

功能: 提供安装和卸载Protocol的服务,以及查找、打开和关闭Protocol的服务。

主要函数:

  • InstallProtocolInterface():安装协议接口
  • UninstallProtocolInterface():卸载协议接口
  • LocateProtocol():定位协议
  • OpenProtocol():打开协议
  • CloseProtocol():关闭协议

示例:

c 复制代码
EFI_BLOCK_IO_PROTOCOL *BlockIo;

// 定位Block IO协议
EFI_STATUS Status = gBS->LocateProtocol(
    &gEfiBlockIoProtocolGuid,
    NULL,
    (VOID **)&BlockIo
);

if (EFI_ERROR(Status)) {
    // 处理错误
}
5. Image服务

功能: 提供加载、卸载、启动和退出UEFI应用程序和驱动的服务。

主要函数:

  • LoadImage():加载镜像
  • StartImage():启动镜像
  • Exit():退出镜像
  • UnloadImage():卸载镜像
6. 其他服务

包括设置看门狗定时器、延时、计算CRC校验值等,随着UEFI标准的发展,这类功能也在不断增加。

运行时服务(Runtime Services)

运行时服务提供的服务包括如下几项:

1. 系统变量服务

功能: 读取或者设置系统变量,比如设定启动项顺序。

变量命名空间:

  • EFI_GLOBAL_VARIABLE:全局变量
  • EFI_IMAGE_SECURITY_DATABASE_GUID:安全数据库
  • 厂商自定义GUID:厂商特定变量

常用工具:

bash 复制代码
# Linux下的efibootmgr工具
efibootmgr -v                    # 查看启动项
efibootmgr -o 0001,0002,0003    # 设置启动顺序
efibootmgr -c -L "Linux" -l /vmlinuz  # 创建启动项
2. 时间服务

功能: 提供读取和设定系统时间的功能,也提供了读取和设定定时唤醒系统的功能。

时间结构:

c 复制代码
typedef struct {
    UINT16 Year;        // 1900 - 9999
    UINT8  Month;       // 1 - 12
    UINT8  Day;         // 1 - 31
    UINT8  Hour;        // 0 - 23
    UINT8  Minute;      // 0 - 59
    UINT8  Second;      // 0 - 59
    UINT8  Pad1;
    UINT32 Nanosecond;  // 0 - 999999999
    INT16  TimeZone;    // -1440 to 1440 or 2047
    UINT8  Daylight;
    UINT8  Pad2;
} EFI_TIME;
3. 内存虚拟地址服务

功能: 提供将内存的物理地址转换为虚拟地址的服务。

4. 其他服务

包括重启系统、更新BIOS(Capsules服务)、交换操作系统与BIOS的数据等各种服务。


UEFI vs Legacy BIOS对比

全面对比表

特性 Legacy BIOS UEFI BIOS
运行模式 实模式(16位) 保护模式(32/64位)
可寻址内存 1MB 4GB+(取决于架构)
开发语言 主要使用汇编 C/C++/Python
代码大小 受ROM限制(通常<8MB) 可存储在硬盘分区
启动速度 较慢 较快(并行初始化)
图形界面 文本模式 支持高分辨率GUI
鼠标支持 不支持 支持
安全启动 不支持 支持(Secure Boot)
GPT分区 不支持 原生支持
大硬盘支持 限制2TB 支持超大容量
网络启动 有限支持 完整支持
驱动加载 静态链接 动态加载
模块化 优秀
跨平台 x86/x64 x86/x64/ARM/MIPS等
代码签名 不支持 支持
远程管理 不支持 支持

启动时间对比

复制代码
Legacy BIOS启动流程:
上电 → POST → 硬件初始化 → 加载OS
时间:通常 30-60秒

UEFI启动流程:
上电 → SEC → PEI → DXE → BDS → TSL → OS
时间:通常 10-20秒(并行初始化)

内存使用对比

Legacy BIOS内存布局:

复制代码
0x00000 - 0x9FFFF: 可用内存(640KB)
0xA0000 - 0xBFFFF: 视频内存
0xC0000 - 0xEFFFF: ROM扩展区
0xF0000 - 0xFFFFF: 系统BIOS

UEFI内存布局:

复制代码
0x00000000 - 0x0009FFFF: 传统内存(可选)
0x000A0000 - 0x000FFFFF: 传统视频内存
0x00100000 - 0xFFFFFFFF: UEFI可用内存(4GB)
(64位系统可访问更大地址空间)

UEFI的优势

UEFI在发展过程中,打败其他新的BIOS架构,尤其是取代Legacy BIOS,得益于以下几大优势。

1. 开发效率高

技术栈对比:

方面 Legacy BIOS UEFI
主要语言 汇编 C/C++
辅助语言 Python(工具链)
代码复用 困难 容易
库支持 丰富(libjpeg等)
调试工具 有限 完善

优势:

  • 相比于Legacy BIOS采用汇编语言开发,UEFI采用了C语言、Python语言加少量汇编语言的混合模式编写,其中以C语言为主
  • 实际上,UEFI的应用程序和驱动可以使用C++编写
  • 它屏蔽了大量的底层硬件细节,为程序员提供了非常统一的调用接口
  • 能很方便地在多种CPU架构间编写代码
  • 很多代码可以重复使用,也可以直接使用大量的C语言库,比如libjpeg等,极大地提高了编程效率

代码示例对比:

Legacy BIOS(汇编):

assembly 复制代码
; 显示字符 'A'
MOV AH, 0Eh        ; 功能号
MOV AL, 'A'        ; 字符
MOV BH, 0          ; 页号
INT 10h            ; 调用BIOS中断

UEFI(C语言):

c 复制代码
// 显示字符串
EFI_STATUS Status;
Status = gST->ConOut->OutputString(
    gST->ConOut,
    L"Hello, UEFI!\n"
);

2. 突破了ROM的容量限制

存储方式对比:

特性 Legacy BIOS UEFI
存储位置 Flash ROM Flash ROM + 硬盘分区
容量限制 通常<8MB 几乎无限制
文件系统 不支持 支持(FAT32等)
可执行程序 受限 丰富

优势:

  • UEFI可以解析文件系统,可以将硬盘的某个区域变为自己的存储空间
  • 这样不但保证了充足的容量,而且可以直接执行一些常用的程序
  • 比如操作系统的多引导、系统备份和恢复等
  • 由于不受限于容量,UEFI可以吸取现代操作系统的设计理念,将功能分层化,不断添加各类新的功能,以满足未来计算机的发展

EFI系统分区(ESP):

复制代码
GPT分区表:
├── EFI System Partition (ESP)
│   ├── \EFI\Boot\bootx64.efi
│   ├── \EFI\Microsoft\Boot\bootmgfw.efi
│   └── \EFI\Linux\grubx64.efi
├── Windows分区
├── Linux分区
└── 数据分区

3. 可扩展性好

模块化设计:

  • UEFI采用模块化的设计,驱动可以动态加载
  • 可以非常方便地添加对新硬件的支持
  • UEFI的每个驱动,均有唯一的GUID标识
  • 使得UEFI系统的升级变得安全而简单

应用场景:

  • 各种备份和诊断功能,都可以在UEFI下实现
  • 配合UEFI提供的网络功能,可以远程对主板进行故障诊断
  • 或者进行BIOS更新

驱动加载示例:

c 复制代码
// 动态加载驱动
EFI_HANDLE ImageHandle;
EFI_STATUS Status;

Status = gBS->LoadImage(
    FALSE,
    gImageHandle,
    DevicePath,
    NULL,
    0,
    &ImageHandle
);

if (!EFI_ERROR(Status)) {
    gBS->StartImage(ImageHandle, NULL, NULL);
}

4. 系统性能高

运行模式对比:

特性 Legacy BIOS UEFI
CPU模式 16位实模式 32/64位保护模式
内存访问 受限(1MB) 完整访问
并行处理 不支持 支持(异步操作)
CPU利用率

优势:

  • Legacy BIOS运行于16位实模式,而UEFI是直接运行于保护模式下的,可以充分利用CPU和内存
  • UEFI提供了异步操作机制,这类似于操作系统下的多进程模式
  • 可充分提高CPU的利用率,减少等待时间

性能提升:

复制代码
启动时间对比:
Legacy BIOS: 30-60秒
UEFI:        10-20秒(提升50-70%)

硬件初始化:
Legacy BIOS: 串行初始化
UEFI:        并行初始化(多核CPU优势)

5. 安全性高

安全机制对比:

安全特性 Legacy BIOS UEFI
代码签名 不支持 支持
安全启动 不支持 支持(Secure Boot)
可信链 完整可信链
恶意软件防护

Secure Boot流程:

复制代码
1. 主板出厂时内置可信公钥(CA证书)
   ↓
2. UEFI固件验证启动加载器签名
   ↓
3. 启动加载器验证内核签名
   ↓
4. 内核验证驱动签名
   ↓
5. 形成完整的可信链

优势:

  • UEFI建立了完整的可信链机制
  • 主板出厂时,可以内置一些可靠的公钥
  • 这些公钥一般由比较权威的CA机构发布,比如VeriSign等
  • 当系统的安全启动功能打开后,UEFI在执行应用程序和驱动前,会检测应用程序和驱动的证书
  • 只有证书被内置公钥认证通过,应用程序和驱动才能被执行
  • UEFI的安全机制提高了操作系统启动过程的安全性,能有效阻止恶意软件

6. 易用性好

用户界面对比:

特性 Legacy BIOS UEFI
显示模式 文本模式(80x25) 高分辨率图形
颜色支持 16色 真彩色
鼠标支持 不支持 支持
界面类型 命令行 GUI图形界面
多语言 有限 完整支持

优势:

  • 从UEFI的设计可以看出,它实际上是一个简化了的操作系统
  • 它支持高分辨率的彩色显示,可以运行GUI(图形用户界面)
  • 支持鼠标的使用
  • 这使得开发人员可以构建非常友好的用户交互界面
  • 用户能更容易、更方便地调节各种参数

UEFI Setup界面特点:

  • 图形化菜单
  • 鼠标操作
  • 实时预览
  • 多语言支持
  • 搜索功能
  • 帮助提示

总结

UEFI作为现代计算机固件的标准,相比Legacy BIOS在多个方面实现了革命性的突破:

  1. 开发效率:从汇编到C/C++,大幅提升开发效率
  2. 存储容量:突破ROM限制,支持文件系统
  3. 扩展性:模块化设计,动态加载驱动
  4. 性能:保护模式运行,并行初始化
  5. 安全性:完整的可信链和安全启动机制
  6. 易用性:图形界面,鼠标操作

这些优势使得UEFI成为现代计算机固件的标准选择,为未来的计算机发展奠定了坚实的基础。在下一篇文章中,我们将深入探讨UEFI的启动过程和开发环境搭建。


参考资料

  • UEFI Specification 2.7+
  • 《UEFI编程实践》- 罗冰
  • Intel Platform Initialization Specification
  • TianoCore EDK II Documentation

本文基于《UEFI编程实践》读书笔记整理,旨在帮助读者深入理解UEFI的架构设计和优势。

UEFI BIOS深度解析:现代固件架构的革命性突破

本文深入探讨UEFI(统一可扩展固件接口)的架构设计、核心概念和相比Legacy BIOS的革命性优势

目录


UEFI概述

什么是UEFI?

UEFI(Unified Extensible Firmware Interface,统一可扩展固件接口)定义了连接操作系统和硬件体系之间的标准接口。它是由UEFI论坛(UEFI Forum)制定的开放标准,旨在替代传统的Legacy BIOS。

UEFI的发展历程

时间 事件 意义
1998年 Intel提出EFI 1.0 最初的EFI规范
2005年 UEFI 2.0发布 统一标准,更名为UEFI
2006年 UEFI 2.1发布 增加安全启动支持
2011年 Windows 8要求UEFI 推动UEFI普及
2017年 UEFI 2.7发布 支持更多新特性

UEFI的设计目标

  1. 跨平台支持:支持x86、x64、ARM、MIPS等多种架构
  2. 模块化设计:驱动和应用程序可以动态加载
  3. 标准化接口:统一的API和协议规范
  4. 安全性:内置安全启动和可信链机制
  5. 易用性:支持图形界面和鼠标操作

UEFI核心概念

在UEFI构建的软件世界中,有一些基本概念必须熟悉,它们是理解UEFI的基础。

1. 启动管理器(Boot Manager)

定义: UEFI的应用程序和驱动可以在任何UEFI规范支持的设备和文件系统中加载,而决定加载顺序的就是启动管理器。

功能:

  • 通过全局的NVRAM变量来管理加载顺序
  • 可以配置启动选项
  • 增加启动选项或从启动列表中删除无效的选项
  • 支持多操作系统启动

NVRAM变量示例:

bash 复制代码
# 查看启动项
efibootmgr -v

# 输出示例:
# BootCurrent: 0001
# BootOrder: 0001,0002,0003
# Boot0001* Windows Boot Manager
# Boot0002  Linux Boot Manager
# Boot0003  UEFI Shell

2. UEFI Images(UEFI镜像)

定义: UEFI Images是UEFI规范定义的包含可执行代码的二进制程序文件。

类型:

  • UEFI应用程序.efi文件,独立运行的程序
  • UEFI驱动.efi文件,为硬件提供驱动支持

文件结构:

UEFI镜像采用PE32(Portable Executable 32)文件结构,这是Windows可执行文件的标准格式:

复制代码
PE32文件结构:
├── DOS Header (MZ)
├── PE Header
├── Section Headers
├── .text (代码段)
├── .data (数据段)
└── .reloc (重定位段)

优势:

  • 支持跨平台(x86、ARM等)
  • 标准化的加载机制
  • 支持代码签名验证

3. UEFI Services(UEFI服务)

定义: UEFI Service是平台调用接口的集合,允许UEFI程序和操作系统调用。

分类:

  • 启动服务(Boot Services,BS):在操作系统加载前可用
  • 运行时服务(Runtime Services,RS):操作系统运行期间也可用

服务提供者:

  • UEFI应用程序
  • UEFI驱动
  • UEFI OS Loader(操作系统加载器)

4. UEFI Protocol(UEFI协议)

定义: UEFI Protocol本质上是一种数据结构,它包含三个部分:

  1. 全局唯一标识符(GUID):128位唯一标识符
  2. 接口数据结构:定义协议的数据结构
  3. 服务:协议提供的函数接口

GUID格式:

复制代码
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
例如:EFI_BLOCK_IO_PROTOCOL_GUID
     {964e5b22-6459-11d2-8e39-00a0c969723b}

Protocol示例:

c 复制代码
// EFI_BLOCK_IO_PROTOCOL结构
typedef struct {
    UINT64              Revision;
    EFI_BLOCK_IO_MEDIA  *Media;
    EFI_BLOCK_RESET     Reset;
    EFI_BLOCK_READ      ReadBlocks;
    EFI_BLOCK_WRITE     WriteBlocks;
    EFI_BLOCK_FLUSH     FlushBlocks;
} EFI_BLOCK_IO_PROTOCOL;

5. UEFI系统表(UEFI System Table)

定义: 所有UEFI镜像都会接收到一个指向UEFI系统表的指针,通过此系统表可以访问固件提供的UEFI Protocol。

系统表结构:

c 复制代码
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;

UEFI软件架构

架构层次图

复制代码
┌─────────────────────────────────────────┐
│         操作系统 (OS)                    │
├─────────────────────────────────────────┤
│     UEFI OS Loader                      │
│     (操作系统加载器)                     │
├─────────────────────────────────────────┤
│     UEFI Applications                   │
│     (UEFI应用程序)                       │
├─────────────────────────────────────────┤
│     UEFI Drivers                        │
│     (UEFI驱动)                          │
├─────────────────────────────────────────┤
│     Boot Services (BS)                  │
│     (启动服务)                          │
├─────────────────────────────────────────┤
│     Runtime Services (RS)               │
│     (运行时服务)                        │
├─────────────────────────────────────────┤
│     UEFI Protocols                      │
│     (UEFI协议)                          │
├─────────────────────────────────────────┤
│     UEFI System Table                   │
│     (UEFI系统表)                        │
├─────────────────────────────────────────┤
│     Platform Hardware                   │
│     (平台硬件)                          │
└─────────────────────────────────────────┘

架构特点

图1-2 UEFI软件架构

UEFI为操作系统启动和启动前的运行状态提供了一个标准的环境,规范中详细规定了系统的控制权如何从启动前环境传递到操作系统。它所规定的与平台信息相关的启动服务(BS)和运行时服务(RT),都是与平台架构相分离的,即独立于平台上的抽象接口。这就是为什么发展到现在,UEFI可以支持X86、ARM、MIPS等各种CPU架构的原因。

服务生命周期

对Option ROM开发者来说:

复制代码
┌─────────────────────────────────────────┐
│  Option ROM执行前                       │
│  ✓ Boot Services可用                   │
│  ✓ Runtime Services可用                │
├─────────────────────────────────────────┤
│  OS Loader加载后                        │
│  ✓ Boot Services可用                   │
│  ✓ Runtime Services可用                │
├─────────────────────────────────────────┤
│  ExitBootServices()调用后               │
│  ✗ Boot Services销毁                  │
│  ✓ Runtime Services保留                │
└─────────────────────────────────────────┘

关键点:

  • Option ROM运行于操作系统加载器执行前,启动服务和运行时服务都可以使用
  • 从操作系统加载器被加载,到操作系统加载器执行ExitBootServices()前的这段时间,是从UEFI环境向操作系统过渡的阶段,启动服务和运行时服务也同样可以使用
  • 在操作系统加载器执行ExitBootServices()之后,启动服务就完成了使命,其占用的资源会被回收,计算机系统进入UEFI Runtime阶段
  • 此后,就只能使用运行时服务了,启动服务已经从系统中销毁

UEFI服务详解

启动服务(Boot Services)

启动服务提供的服务包括如下几项:

1. Event(事件)服务

功能: 允许程序进行异步操作,这是UEFI得以执行并发操作的基础。

事件类型:

  • 定时器事件:基于时间的触发
  • 等待事件:等待某个条件满足
  • 通知函数:事件触发时调用的回调函数

示例代码:

c 复制代码
EFI_EVENT TimerEvent;

// 创建定时器事件
gBS->CreateEvent(
    EVT_TIMER,
    TPL_CALLBACK,
    NULL,
    NULL,
    &TimerEvent
);

// 设置定时器(10秒)
gBS->SetTimer(TimerEvent, TimerRelative, 10000000);

// 等待事件
gBS->WaitForEvent(1, &TimerEvent, NULL);
2. Timer(定时器)服务

功能: 配合Event提供定时器功能。

定时器类型:

  • TimerCancel:取消定时器
  • TimerPeriodic:周期性定时器
  • TimerRelative:相对时间定时器
  • TimerAbsolute:绝对时间定时器
3. 内存管理

功能: 提供内存的分配和释放服务,管理系统的内存映射。

内存类型:

类型 说明
EfiLoaderCode 加载器代码
EfiLoaderData 加载器数据
EfiBootServicesCode 启动服务代码
EfiBootServicesData 启动服务数据
EfiRuntimeServicesCode 运行时服务代码
EfiRuntimeServicesData 运行时服务数据
EfiConventionalMemory 常规内存
EfiUnusableMemory 不可用内存
EfiACPIReclaimMemory ACPI回收内存
EfiACPIMemoryNVS ACPI非易失性内存
EfiMemoryMappedIO 内存映射IO
EfiMemoryMappedIOPortSpace 内存映射IO端口空间
EfiPalCode PAL代码

内存分配示例:

c 复制代码
EFI_PHYSICAL_ADDRESS Memory;
UINTN Pages = 10; // 分配10页(4KB/页)

// 分配内存
EFI_STATUS Status = gBS->AllocatePages(
    AllocateAnyPages,
    EfiBootServicesData,
    Pages,
    &Memory
);

// 使用内存...

// 释放内存
gBS->FreePages(Memory, Pages);
4. Protocol服务

功能: 提供安装和卸载Protocol的服务,以及查找、打开和关闭Protocol的服务。

主要函数:

  • InstallProtocolInterface():安装协议接口
  • UninstallProtocolInterface():卸载协议接口
  • LocateProtocol():定位协议
  • OpenProtocol():打开协议
  • CloseProtocol():关闭协议

示例:

c 复制代码
EFI_BLOCK_IO_PROTOCOL *BlockIo;

// 定位Block IO协议
EFI_STATUS Status = gBS->LocateProtocol(
    &gEfiBlockIoProtocolGuid,
    NULL,
    (VOID **)&BlockIo
);

if (EFI_ERROR(Status)) {
    // 处理错误
}
5. Image服务

功能: 提供加载、卸载、启动和退出UEFI应用程序和驱动的服务。

主要函数:

  • LoadImage():加载镜像
  • StartImage():启动镜像
  • Exit():退出镜像
  • UnloadImage():卸载镜像
6. 其他服务

包括设置看门狗定时器、延时、计算CRC校验值等,随着UEFI标准的发展,这类功能也在不断增加。

运行时服务(Runtime Services)

运行时服务提供的服务包括如下几项:

1. 系统变量服务

功能: 读取或者设置系统变量,比如设定启动项顺序。

变量命名空间:

  • EFI_GLOBAL_VARIABLE:全局变量
  • EFI_IMAGE_SECURITY_DATABASE_GUID:安全数据库
  • 厂商自定义GUID:厂商特定变量

常用工具:

bash 复制代码
# Linux下的efibootmgr工具
efibootmgr -v                    # 查看启动项
efibootmgr -o 0001,0002,0003    # 设置启动顺序
efibootmgr -c -L "Linux" -l /vmlinuz  # 创建启动项
2. 时间服务

功能: 提供读取和设定系统时间的功能,也提供了读取和设定定时唤醒系统的功能。

时间结构:

c 复制代码
typedef struct {
    UINT16 Year;        // 1900 - 9999
    UINT8  Month;       // 1 - 12
    UINT8  Day;         // 1 - 31
    UINT8  Hour;        // 0 - 23
    UINT8  Minute;      // 0 - 59
    UINT8  Second;      // 0 - 59
    UINT8  Pad1;
    UINT32 Nanosecond;  // 0 - 999999999
    INT16  TimeZone;    // -1440 to 1440 or 2047
    UINT8  Daylight;
    UINT8  Pad2;
} EFI_TIME;
3. 内存虚拟地址服务

功能: 提供将内存的物理地址转换为虚拟地址的服务。

4. 其他服务

包括重启系统、更新BIOS(Capsules服务)、交换操作系统与BIOS的数据等各种服务。


UEFI vs Legacy BIOS对比

全面对比表

特性 Legacy BIOS UEFI BIOS
运行模式 实模式(16位) 保护模式(32/64位)
可寻址内存 1MB 4GB+(取决于架构)
开发语言 主要使用汇编 C/C++/Python
代码大小 受ROM限制(通常<8MB) 可存储在硬盘分区
启动速度 较慢 较快(并行初始化)
图形界面 文本模式 支持高分辨率GUI
鼠标支持 不支持 支持
安全启动 不支持 支持(Secure Boot)
GPT分区 不支持 原生支持
大硬盘支持 限制2TB 支持超大容量
网络启动 有限支持 完整支持
驱动加载 静态链接 动态加载
模块化 优秀
跨平台 x86/x64 x86/x64/ARM/MIPS等
代码签名 不支持 支持
远程管理 不支持 支持

启动时间对比

复制代码
Legacy BIOS启动流程:
上电 → POST → 硬件初始化 → 加载OS
时间:通常 30-60秒

UEFI启动流程:
上电 → SEC → PEI → DXE → BDS → TSL → OS
时间:通常 10-20秒(并行初始化)

内存使用对比

Legacy BIOS内存布局:

复制代码
0x00000 - 0x9FFFF: 可用内存(640KB)
0xA0000 - 0xBFFFF: 视频内存
0xC0000 - 0xEFFFF: ROM扩展区
0xF0000 - 0xFFFFF: 系统BIOS

UEFI内存布局:

复制代码
0x00000000 - 0x0009FFFF: 传统内存(可选)
0x000A0000 - 0x000FFFFF: 传统视频内存
0x00100000 - 0xFFFFFFFF: UEFI可用内存(4GB)
(64位系统可访问更大地址空间)

UEFI的优势

UEFI在发展过程中,打败其他新的BIOS架构,尤其是取代Legacy BIOS,得益于以下几大优势。

1. 开发效率高

技术栈对比:

方面 Legacy BIOS UEFI
主要语言 汇编 C/C++
辅助语言 Python(工具链)
代码复用 困难 容易
库支持 丰富(libjpeg等)
调试工具 有限 完善

优势:

  • 相比于Legacy BIOS采用汇编语言开发,UEFI采用了C语言、Python语言加少量汇编语言的混合模式编写,其中以C语言为主
  • 实际上,UEFI的应用程序和驱动可以使用C++编写
  • 它屏蔽了大量的底层硬件细节,为程序员提供了非常统一的调用接口
  • 能很方便地在多种CPU架构间编写代码
  • 很多代码可以重复使用,也可以直接使用大量的C语言库,比如libjpeg等,极大地提高了编程效率

代码示例对比:

Legacy BIOS(汇编):

assembly 复制代码
; 显示字符 'A'
MOV AH, 0Eh        ; 功能号
MOV AL, 'A'        ; 字符
MOV BH, 0          ; 页号
INT 10h            ; 调用BIOS中断

UEFI(C语言):

c 复制代码
// 显示字符串
EFI_STATUS Status;
Status = gST->ConOut->OutputString(
    gST->ConOut,
    L"Hello, UEFI!\n"
);

2. 突破了ROM的容量限制

存储方式对比:

特性 Legacy BIOS UEFI
存储位置 Flash ROM Flash ROM + 硬盘分区
容量限制 通常<8MB 几乎无限制
文件系统 不支持 支持(FAT32等)
可执行程序 受限 丰富

优势:

  • UEFI可以解析文件系统,可以将硬盘的某个区域变为自己的存储空间
  • 这样不但保证了充足的容量,而且可以直接执行一些常用的程序
  • 比如操作系统的多引导、系统备份和恢复等
  • 由于不受限于容量,UEFI可以吸取现代操作系统的设计理念,将功能分层化,不断添加各类新的功能,以满足未来计算机的发展

EFI系统分区(ESP):

复制代码
GPT分区表:
├── EFI System Partition (ESP)
│   ├── \EFI\Boot\bootx64.efi
│   ├── \EFI\Microsoft\Boot\bootmgfw.efi
│   └── \EFI\Linux\grubx64.efi
├── Windows分区
├── Linux分区
└── 数据分区

3. 可扩展性好

模块化设计:

  • UEFI采用模块化的设计,驱动可以动态加载
  • 可以非常方便地添加对新硬件的支持
  • UEFI的每个驱动,均有唯一的GUID标识
  • 使得UEFI系统的升级变得安全而简单

应用场景:

  • 各种备份和诊断功能,都可以在UEFI下实现
  • 配合UEFI提供的网络功能,可以远程对主板进行故障诊断
  • 或者进行BIOS更新

驱动加载示例:

c 复制代码
// 动态加载驱动
EFI_HANDLE ImageHandle;
EFI_STATUS Status;

Status = gBS->LoadImage(
    FALSE,
    gImageHandle,
    DevicePath,
    NULL,
    0,
    &ImageHandle
);

if (!EFI_ERROR(Status)) {
    gBS->StartImage(ImageHandle, NULL, NULL);
}

4. 系统性能高

运行模式对比:

特性 Legacy BIOS UEFI
CPU模式 16位实模式 32/64位保护模式
内存访问 受限(1MB) 完整访问
并行处理 不支持 支持(异步操作)
CPU利用率

优势:

  • Legacy BIOS运行于16位实模式,而UEFI是直接运行于保护模式下的,可以充分利用CPU和内存
  • UEFI提供了异步操作机制,这类似于操作系统下的多进程模式
  • 可充分提高CPU的利用率,减少等待时间

性能提升:

复制代码
启动时间对比:
Legacy BIOS: 30-60秒
UEFI:        10-20秒(提升50-70%)

硬件初始化:
Legacy BIOS: 串行初始化
UEFI:        并行初始化(多核CPU优势)

5. 安全性高

安全机制对比:

安全特性 Legacy BIOS UEFI
代码签名 不支持 支持
安全启动 不支持 支持(Secure Boot)
可信链 完整可信链
恶意软件防护

Secure Boot流程:

复制代码
1. 主板出厂时内置可信公钥(CA证书)
   ↓
2. UEFI固件验证启动加载器签名
   ↓
3. 启动加载器验证内核签名
   ↓
4. 内核验证驱动签名
   ↓
5. 形成完整的可信链

优势:

  • UEFI建立了完整的可信链机制
  • 主板出厂时,可以内置一些可靠的公钥
  • 这些公钥一般由比较权威的CA机构发布,比如VeriSign等
  • 当系统的安全启动功能打开后,UEFI在执行应用程序和驱动前,会检测应用程序和驱动的证书
  • 只有证书被内置公钥认证通过,应用程序和驱动才能被执行
  • UEFI的安全机制提高了操作系统启动过程的安全性,能有效阻止恶意软件

6. 易用性好

用户界面对比:

特性 Legacy BIOS UEFI
显示模式 文本模式(80x25) 高分辨率图形
颜色支持 16色 真彩色
鼠标支持 不支持 支持
界面类型 命令行 GUI图形界面
多语言 有限 完整支持

优势:

  • 从UEFI的设计可以看出,它实际上是一个简化了的操作系统
  • 它支持高分辨率的彩色显示,可以运行GUI(图形用户界面)
  • 支持鼠标的使用
  • 这使得开发人员可以构建非常友好的用户交互界面
  • 用户能更容易、更方便地调节各种参数

UEFI Setup界面特点:

  • 图形化菜单
  • 鼠标操作
  • 实时预览
  • 多语言支持
  • 搜索功能
  • 帮助提示

总结

UEFI作为现代计算机固件的标准,相比Legacy BIOS在多个方面实现了革命性的突破:

  1. 开发效率:从汇编到C/C++,大幅提升开发效率
  2. 存储容量:突破ROM限制,支持文件系统
  3. 扩展性:模块化设计,动态加载驱动
  4. 性能:保护模式运行,并行初始化
  5. 安全性:完整的可信链和安全启动机制
  6. 易用性:图形界面,鼠标操作

这些优势使得UEFI成为现代计算机固件的标准选择,为未来的计算机发展奠定了坚实的基础。在下一篇文章中,我们将深入探讨UEFI的启动过程和开发环境搭建。


参考资料

  • UEFI Specification 2.7+
  • 《UEFI编程实践》- 罗冰
  • Intel Platform Initialization Specification
  • TianoCore EDK II Documentation

本文基于《UEFI编程实践》读书笔记整理,旨在帮助读者深入理解UEFI的架构设计和优势。

相关推荐
智慧化智能化数字化方案2 小时前
架构进阶——解读45页数据治理能力提升转项目培训-数据架构【附全文阅读】
架构·数据架构·数据治理能力·企业it治理·企业架构规划
没逻辑2 小时前
Gopher 带你学 Serverless 架构:从服务器运维到按需计算的范式转变
架构
heartbeat..2 小时前
介绍一下软件开发中常见的几种的架构模式
java·架构·开发
狗哥哥3 小时前
Pinia Store 平滑迁移:用代理模式实现零风险重构
前端·架构
wshzd3 小时前
LLM之Agent(三十八)|AI Agents(七):Multi-Agent架构
人工智能·架构
颜颜yan_3 小时前
跨越x86与ARM:openEuler全架构算力实战评测
java·arm开发·架构
狗哥哥3 小时前
我是如何治理一个混乱的 Pinia 状态管理系统的
前端·vue.js·架构
weixin_307779134 小时前
采用Amazon SES解决电商邮件延迟:以最小化运维实现最大效率的方案选择
运维·云原生·架构·云计算·aws
GOTXX4 小时前
智能计算新纪元:openEuler的AI原生架构深度实践与全维度性能验证
架构·ai-native