UEFI_Shell_App_原理详解
2026/6/13 12:25:24 网站建设 项目流程

UEFI Shell App 原理详解

UEFI Shell App 是什么

UEFI Shell App 本质上是一个运行在 UEFI 环境里的.efi可执行程序。

它和 Windows 下的.exe很像,只不过运行环境不是 Windows,而是 BIOS/UEFI 固件提供的一套服务。

电脑刚开机时,操作系统还没有启动。这个阶段由 UEFI 固件控制。

UEFI 固件可以运行一种特殊程序:

.efi

例如:

BOOTX64.EFI Shell.efi BiosDumpApp.efi

这些.efi文件就是 UEFI 程序。

UEFI Shell App 是其中一种类型:

MODULE_TYPE = UEFI_APPLICATION

它可以在 UEFI Shell 里运行,也可以被 BIOS/UEFI 固件直接启动。

它运行在哪里

普通程序运行在操作系统上。

例如 Windows 程序:

Windows 程序 -> 依赖 Windows API -> 访问文件用 CreateFile -> 打印用 printf 或 Windows 控制台 API

UEFI Shell App 运行在操作系统启动之前:

UEFI Shell App -> 依赖 UEFI Boot Services -> 依赖 UEFI Runtime Services -> 打印用 ConOut 或 Print() -> 读变量用 GetVariable()

所以它不能调用 Windows API,也不能使用普通main()作为入口。

入口函数

普通 C 程序入口通常是:

intmain()

UEFI App 的入口通常是:

EFI_STATUS EFIAPIUefiMain(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE*SystemTable)

其中:

ImageHandle

表示当前这个 EFI 程序本身。

SystemTable

是 UEFI 固件交给程序的总入口,里面有各种服务表。

最重要的是:

SystemTable->BootServices SystemTable->RuntimeServices SystemTable->ConOut SystemTable->ConIn

在 EDKII 中通常用全局变量简写:

gBS// Boot ServicesgRT// Runtime ServicesgST// System Table

Boot Services 是什么

Boot Services 是 UEFI 在操作系统启动前提供的一组服务。

它可以用来:

  • 找设备
  • 找 handle
  • 找 protocol
  • 分配内存
  • 打开 protocol
  • 等待事件
  • 加载 EFI 程序
  • 启动 EFI 程序

打印 protocol 时用到的就是 Boot Services:

gBS->LocateHandleBuffer(...)gBS->ProtocolsPerHandle(...)

含义是:

找出系统里所有 UEFI handle 再查看每个 handle 上挂了哪些 protocol

Boot Services 只在操作系统启动前可靠可用。操作系统一旦调用ExitBootServices(),很多 Boot Services 就不能再用了。

Runtime Services 是什么

Runtime Services 是 UEFI 提供的另一组服务。

它们在操作系统启动后理论上也可能继续存在。

常见功能包括:

  • 读写 UEFI variable
  • 获取时间
  • 设置时间
  • 重启或关机

打印 variable 和 boot option 时用到的是:

gRT->GetNextVariableName(...)gRT->GetVariable(...)

也就是:

枚举所有 UEFI variable 读取每个 variable 的内容

BIOS 启动项,比如BootOrderBoot0000,也是 UEFI variable。

Protocol 是什么

UEFI 中很多功能都用 Protocol 表示。

可以把 Protocol 理解成:

UEFI 里的接口

例如,一个磁盘设备可能支持:

BlockIoProtocol DiskIoProtocol DevicePathProtocol SimpleFileSystemProtocol

一个键盘设备可能支持:

SimpleTextInputProtocol SimpleTextInputExProtocol

一个文件系统可能支持:

SimpleFileSystemProtocol

每个 Protocol 都有一个 GUID 作为唯一标识。

所以打印 protocol 本质上是在问固件:

现在系统里有哪些对象? 每个对象支持哪些 UEFI 接口?

Handle 是什么

UEFI 里的 Handle 可以理解成:

一个设备、一个驱动、一个控制器,或者一个抽象对象的句柄

Protocol 通常安装在 Handle 上。

关系大概是:

Handle A -> Protocol 1 -> Protocol 2 -> Protocol 3 Handle B -> Protocol 4 -> Protocol 5

所以枚举 protocol 的标准方式是:

先找所有 handle 再看每个 handle 上有哪些 protocol

Variable 是什么

UEFI Variable 是固件保存配置的键值数据。

它由三部分共同标识:

  • 变量名
  • Vendor GUID
  • 属性

常见变量包括:

BootOrder Boot0000 SecureBoot SetupMode PK KEK db dbx

变量可能保存在主板 NVRAM 中,断电后仍然存在。

变量有属性,例如:

NV = 非易失,断电保存 BS = Boot Services 阶段可访问 RT = Runtime 阶段可访问

程序枚举 variable 的过程是:

GetNextVariableName() -> 得到下一个变量名和 Vendor GUID GetVariable() -> 读取这个变量的属性、大小、内容

Boot Option 是什么

BIOS 启动菜单里的每个启动项,通常就是一个 UEFI Variable。

名字格式是:

Boot0000 Boot0001 Boot0002

启动顺序存在:

BootOrder

例如:

BootOrder = 0001, 0000, 0002

意思是:

先尝试 Boot0001 再尝试 Boot0000 再尝试 Boot0002

每个Boot####变量内部是一个EFI_LOAD_OPTION结构,里面有:

  • 启动项属性
  • 显示名称
  • 设备路径
  • 可选参数

所以程序解析Boot####后,可以打印:

  • 启动项名称
  • 是否 active
  • 对应设备路径
  • 是否在 BootOrder 中

Shell App 如何打印

在 UEFI Shell App 中,不能用普通 Windows 控制台。

EDKII 提供:

Print(L"hello\n");

它最终会调用 UEFI 的控制台输出:

gST->ConOut->OutputString()

所以屏幕上看到的文字,是 UEFI 固件自己的文本输出服务显示出来的。

Shell App 如何读写文件

UEFI 中读写文件一般通过:

SimpleFileSystemProtocol EFI_FILE_PROTOCOL

程序保存bios_dump.txt时,流程大概是:

1. 通过 ImageHandle 找到当前程序是从哪个设备启动的 2. 打开这个设备上的 SimpleFileSystemProtocol 3. 打开文件系统根目录 4. 创建或打开 bios_dump.txt 5. 把输出写进去

所以日志会保存到启动它的那个 U 盘上。

Shell App 和 UEFI Shell 的关系

名字里有 Shell App,容易误会。

实际上:

UEFI Shell

是一个类似命令行的 EFI 程序。

UEFI Shell App

是可以在 UEFI Shell 里运行的应用程序。

关系类似:

Windows cmd.exe -> 可以运行 app.exe UEFI Shell.efi -> 可以运行 BiosDumpApp.efi

.efi程序不一定必须通过 Shell 运行。

如果它被放到:

\EFI\BOOT\BOOTX64.EFI

固件也可以直接启动它。

当前实现就是这种方式:

BIOS/UEFI 固件直接启动 BiosDumpApp

EDKII 的作用

EDKII 是开发 UEFI 程序的开源框架。

它提供:

  • 头文件
  • 库函数
  • 协议定义
  • GUID 定义
  • 构建系统
  • 示例代码

程序中使用了这些头文件和库:

#include<Uefi.h>#include<Library/UefiLib.h>#include<Library/UefiBootServicesTableLib.h>#include<Library/UefiRuntimeServicesTableLib.h>

这些让代码可以方便地访问:

gBS gRT gST Print() AllocatePool() ConvertDevicePathToText()

INF 文件是什么

BiosDumpApp.inf是模块描述文件。

它告诉 EDKII:

  • 这个模块叫什么
  • 是什么类型
  • 入口函数是什么
  • 有哪些源码
  • 依赖哪些库
  • 用到了哪些 GUID 或 Protocol

例如:

MODULE_TYPE = UEFI_APPLICATION ENTRY_POINT = UefiMain

意思是:

这是一个 UEFI 应用程序 入口函数是 UefiMain

DSC 文件是什么

UefiBiosDumpShellAppPkg.dsc是平台或工程描述文件。

它告诉 EDKII:

  • 要编译哪些模块
  • 每种 LibraryClass 使用哪个具体库实现
  • 目标架构是什么
  • 输出目录是什么

简单说:

INF 描述单个程序 DSC 描述整个构建工程

最终程序执行链

最终执行链如下:

开机 -> UEFI 固件初始化硬件 -> 用户选择 U 盘 UEFI 启动 -> 固件读取 FAT32 文件系统 -> 固件寻找 \EFI\BOOT\BOOTX64.EFI -> 固件加载 BOOTX64.EFI 到内存 -> 固件调用 UefiMain() -> 程序使用 gBS 枚举 protocol -> 程序使用 gRT 枚举 variable -> 程序解析 BootOrder / Boot#### -> 程序把结果显示到屏幕 -> 程序把结果写入 bios_dump.txt -> 程序等待按键退出

这就是 UEFI Shell App 的核心原理。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询