UEFI基础服务——记录

发布时间:2026/9/13 7:52:06

UEFI基础服务——记录 学习戴正华大佬的《UEFI原理与编程》第5章记录如下。UEFI 的核心任务是为 OS 准备好软硬件运行环境。它向上暴露的接口分两种启动服务Boot Services和运行时服务Runtime Services统称为 UEFI 服务。任何 UEFI 应用或驱动都是通过系统表拿到这两个服务表的指针。5.1 系统表5.1.1 概述系统表是整个 UEFI 编程的入口。它本质上是一个全局结构体在 DXE 阶段被初始化也就是说 SEC、PEI 阶段用不了只有到了 DXE 及以后才能访问。每个 .efi 文件Image被加载到内存后UEFI 固件会调用它的入口函数并把系统表指针传进去。入口函数的签名typedef EFI_STATUS(EFIAPI *EFI_IMAGE_ENTRY_POINT) ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable );Image 和 ImageHandle 的区别Image 是加载到内存后的可执行程序实体一个数据结构ImageHandle 是这个 Image 的句柄——可以理解为 Image 的身份证用来唯一标识这个 Image。驱动/应用之间的交互比如 Protocol 的安装和查找都是通过 Handle 来关联的。具体调用链.efi 文件加载后形成 Image 对象_ModuleEntryPoint的地址被填到Image-EntryPoint然后固件执行Image-EntryPoint(ImageHandle, SystemTable)最终进入 .inf 里指定的模块入口函数。5.1.2 系统表的结构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;几点理解1表头 EFI_TABLE_HEADERUEFI 里所有表都用EFI_TABLE_HEADER开头启动服务表、运行时服务表都是。这个 Header 里有 64 位 Signature跟 GUID 类似的思路用于标识表的类型、版本号、整表大小、CRC32 校验值。CRC32 是这样算的先把 CRC32 字段清零算整表的 CRC再填回去。如果表被篡改或者损坏校验就对不上。2控制台系统表提供了 3 套控制台ConIn键盘、ConOut屏幕、StdErr屏幕。每套包含一个设备句柄和一个对应的 Protocol。有了这些UEFI 应用不用关心底层硬件细节直接调 Protocol 的函数就行。3配置表ConfigurationTable是一个数组每一项是一对GUID 数据指针。ACPI 表、SMBIOS 表、设备树等等都挂在这上面。OS Loader 通过它获取硬件信息交给内核这个设计很巧妙——用 GUID 做索引随意扩展不用改系统表结构。5.2 启动服务启动服务表在 DXE 阶段初始化通过gST-BootServices或gBS访问。它提供的服务覆盖了 UEFI 应用在启动阶段ExitBootServices 之前几乎所有需求共 8 类。注虽然也叫表但它不像系统表那样存数据——启动服务表里基本都是函数指针。5.2.1 八类服务概览类别说明典型使用场景事件服务事件、定时器、任务优先级TPL创建回调事件、设置定时器内存管理分配/释放内存页或池驱动分配缓冲区Protocol 管理安装/卸载 Protocol、注册通知驱动提供 ProtocolProtocol 使用查找/打开/关闭 Protocol应用调用驱动服务驱动管理Connect/Disconnect 控制器加载驱动到设备Image 服务加载/卸载/启动 .efi 文件OS Loader 加载内核ExitBootServices结束启动服务移交控制权OS Loader 接管系统其他CopyMem、SetMem、CRC32、Stall 等通用工具操作启动服务表的结构体非常大100 行但理清分类后其实很好记。额外提几点TPL任务优先级RaiseTPL/RestoreTPL 用来在关键区域提升优先级防止其他事件打断。跟中断屏蔽的思路类似但用的是软件优先级。事件UEFI 的事件模型支持多种类型通知事件、定时器事件等。CreateEvent 的时候可以指定回调函数和触发条件核心是异步通知机制。Protocol 函数的历史包袱InstallProtocolInterface和ReinstallProtocolInterface是早期版本遗留下来的新代码应该用InstallMultipleProtocolInterfaces它一次可以安装多个 Protocol而且会在失败时自动回滚。5.2.2 内存管理服务详解内存管理服务分三组1AllocatePool / FreePool —— 按字节分配最常用的内存分配方式类似 C 的 malloc/free。必须成对调用。CHAR16 *Buffer NULL; gBS-AllocatePool(EfiBootServicesCode, 1024, (VOID**)Buffer); gBS-FreePool(Buffer);内存类型是关键参数。AllocatePool第一个参数指定内存类型这决定了内存在 ExitBootServices 之后的命运EfiBootServicesCode/EfiBootServicesDataExitBootServices 后固件回收。用于 UEFI 驱动和应用自身。EfiLoaderCode/EfiLoaderData由 OS Loader 和 OS 决定是否回收。用于存放交给内核的数据比如内存映射表。EfiACPIReclaimMemoryACPI 表初始化完成后回收。EfiRuntimeServicesCode/EfiRuntimeServicesData等ExitBootServices 后保留给运行时服务继续用。理解这个很重要——如果你在 Boot Service 里分配了一块EfiBootServicesData内存想在 RT 阶段继续用那就会挂掉因为这块内存已经被回收了。2AllocatePages / FreePages —— 按物理页分配当你需要整页内存或者不想分配跨页时用这个。驱动开发中很常见因为有些硬件 DMA 要求物理连续而且 DMA 缓冲区通常以页为单位。EFI_PHYSICAL_ADDRESS pages 0; // 0 表示让固件自己选地址 gBS-AllocatePages(AllocateAnyPages, EfiBootServicesCode, 3, pages); // 拿到的是物理地址操作内存前要转成指针 CHAR16 *Str (CHAR16*)pages; gBS-FreePages(pages, 3);重要AllocatePages返回的是物理地址EFI_PHYSICAL_ADDRESS不是指针。在 32 位 UEFI 上如果物理内存超过 4GBAllocateAnyPages可能分配到 4G 以上的物理地址32 位指针够不着——这时候要用AllocateMaxAddress限制允许分配的最大物理地址。Type参数的三种分配方式AllocateAnyPages任意地址AllocateMaxAddress分配的页面物理地址不能超过传入值AllocateAddress强制分配到指定物理地址3GetMemoryMap —— 获取系统内存布局这是 ExitBootServices 之前必须调用的服务。它返回整个系统的内存映射表每个条目EFI_MEMORY_DESCRIPTOR描述了一块内存的类型、物理地址、虚拟地址、页数和属性。调用有个经典的两步走模式先传个 0 大小的 Buffer 让固件告诉你需要多大分配好再调一次。MapKey是当前内存映射的版本标识ExitBootServices 时要传这个 Key防止内存映射在你获取之后被修改如果 Key 变了说明驱动对内存做了操作就得重新获取。5.2.3 启动服务的生命周期总结gBS从 DXE 初始化开始可用到gBS-ExitBootServices()成功后结束。ExitBootServices 执行后被回收的启动服务表中除EFI_TABLE_HEADER外的所有函数指针都失效ConIn、ConOut、StdErr相关的控制台设备/Protocol 失效EfiBootServicesCode和EfiBootServicesData类型的内存被回收保留的gRT—— 运行时服务继续可用ConfigurationTable—— 配置表保留ACPI、SMBIOS 等 HW 信息FirmwareVendor和FirmwareRevision字符串调试技巧在 ExitBootServices 前后分别看gST的地址和其成员地址可以确认哪些区域被释放了。书中提到可以用asm int 3打调试断点来观察。MapKey的坑如果第一次 GetMemoryMap 拿到 MapKey 后在调用 ExitBootServices 之前又有代码调了分配/释放内存MapKey 就对不上了ExitBootServices 会失败。正确的做法是检测到失败后重新 GetMemoryMap 再调。5.3 运行时服务运行时服务同样在 DXE 阶段初始化但它的生命周期比启动服务长得多——一直到操作系统运行期间都存活给 OS 提供底层服务。gRT提供了 4 类服务类别说明时间服务读写硬件 RTC、唤醒定时器虚拟内存SetVirtualAddressMap、ConvertPointer变量服务读写 UEFI 变量Get/Set Variable其他ResetSystem重启、Capsule 更新、查询变量信息5.3.1 时间服务GetTime / SetTime直接操作 RTC 硬件。时间结构体包含年月日时分秒纳秒和时区。注意几个细节EFI_TIME有两个 Padding 字节Pad1、Pad2这是为了字节对齐TimeZone-1440 到 1440单位分钟UTC 时区是 0。还有一个特殊值 2047 表示时区未知Daylight夏令时标志Nanosecond字段精度看起来很高但实际受限于 RTC 硬件精度EFI_TIME_CAPABILITIES描述时钟硬件能力Resolution时钟每秒脉冲数Accuracy精度单位 ppm百万分之一SetsToZero是否在设置时间时清零亚秒计数器GetWakeupTime / SetWakeupTime操作系统用这个实现定时开机——比如笔记本在 AC 状态下设置唤醒时间关机后 RTC 到时触发上电。5.3.2 变量服务UEFI 变量是运行在 Flash 上的键值存储用 (GUID Name) 作为唯一标识。OS 装好后的启动项、Secure Boot 密钥、固件设置都存成变量。核心三个接口GetVariable读取变量SetVariable写入变量可以附加属性如 Non-Volatile、BootService、Runtime、Authenticated Write 等GetNextVariableName遍历所有变量5.3.3 虚拟内存服务这两个接口只能在 ExitBootServices 之后调用。由于 OS 启用分页后物理地址就不能直接用了所以 RT 阶段要先把运行时服务使用的物理地址映射到虚拟地址。调用流程SetVirtualAddressMap传入内存映射表物理地址→虚拟地址的映射固件内部遍历并更新。然后ConvertPointer用于将某个指针的指向从物理地址改为虚拟地址——注意它转换的是指针的指针。小结UEFI 的这套服务设计其实很清晰系统表 导航中心从这里拿到一切启动服务 DXE 到 OS Loader 期间的工具箱内存管理 Protocol 操作 Image 加载功能最强运行时服务 OS 运行后还能用的精简接口时间 变量 复位理解生命周期这个概念特别重要什么内存在什么时候分配、什么时候回收什么服务在什么时候可用。
延伸阅读

更多相关文章

2026/9/10 22:27:13

Android渗透测试环境搭建:Kali Linux与MSFvenom实战指南

1. 项目概述:为什么需要搭建Android渗透测试环境?如果你对移动安全感兴趣,或者想验证自己开发的Android应用是否存在安全隐患,那么亲手搭建一个本地的渗透测试环境是必经之路。这就像木匠需要自己的工具箱,厨师需要自己…

2026/9/12 20:31:22

Windows C盘深度清理工具:安全释放磁盘空间与系统优化指南

如果你还在为 C 盘爆红、系统卡顿而烦恼,每次手动清理又担心误删系统文件,那么今天介绍的这个工具可能会彻底改变你的电脑维护方式。这不是又一个普通的清理软件,而是一个专门针对 Windows 系统深层垃圾设计的“外科手术式”清理方案。很多人…

2026/9/12 20:03:12

【大纲利器】专业级AI写作辅助软件:研究框架、文献综述一键搭建

每到开题季,无数本硕学子都会陷入同款困境:选题无思路、研究框架逻辑混乱、翻阅上百篇文献仍写不出合格综述、参考文献格式反复出错、熬夜搭建结构却被导师全盘打回。传统手工梳理文献、徒手搭建研究框架的模式耗时耗力,稍有疏漏就会延误开题…

2026/9/13 15:52:50

OpenCode工具链:AI驱动的智能开发实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 15:52:50

提示词工程实战:10个技巧稳定提升AI输出质量

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 15:52:50

1Panel服务离线迁移实战:Docker镜像与数据完整搬迁至Ubuntu 22.04

接手过一次“把 1Panel 管理的所有服务迁移到一台离线 Ubuntu 22.04 新服务器”之后,你会发现这类迁移根本不是“拷贝文件、跑起来”这么简单。尤其目标机器在隔离内网里,没有外网、不能在线拉镜像,连 Docker 和 1Panel 本身都得想办法离线装…

2026/9/13 15:52:50

经典层合板理论ABD矩阵计算:MATLAB实现与验证

简介:MATLAB程序包「20190301ABD」提供经典层合板理论(CLPT)下的ABD矩阵计算工具。面向材料科学与工程、复合材料结构分析领域的工程师与研究人员,仅需输入叠层顺序、纤维角度及材料属性,即可计算A、B、D矩阵等关键刚度…

2026/9/13 15:47:49

交通标志识别工业级方案:YOLOv5s轻量化+双路径分类

简介:这是一套面向高校计算机、人工智能等专业学生的交通标志智能检测与识别毕业设计项目,基于Python实现端到端图像识别流程,覆盖数据预处理、模型训练、推理部署等核心环节,适用于课程设计、综合实验及毕设实践。资源包共298个文…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/13 11:18:28

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码