You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从UEFI引导加载程序调用独立EFI文件的入口点

自研UEFI引导加载器调用同盘EFI文件的设备路径实现指引

核心逻辑

要调用LoadImage和StartImage,核心是手动构造EFI设备路径链——这是UEFI用来定位存储设备和文件的结构化数据,由多个节点链式拼接而成,最后以结束节点收尾。你需要实现两个关键节点:定位虚拟硬盘分区的媒体节点,以及定位目标EFI文件的文件路径节点。

分步实现

1. 设备路径节点基础结构

所有设备路径节点都包含统一头部,后续紧跟节点特定数据:

typedef struct {
  UINT8  Type;       // 设备类型:媒体设备=0x01,结束节点=0x7F
  UINT8  SubType;    // 子类型:硬盘分区=0x01,文件路径=0x04,结束节点=0xFF
  UINT16 Length;     // 整个节点的字节长度(含头部)
} EFI_DEVICE_PATH_PROTOCOL;

2. 构造硬盘分区媒体节点

这个节点用来定位你的虚拟硬盘上的EFI系统分区:

typedef struct {
  EFI_DEVICE_PATH_PROTOCOL Header;
  UINT32                   PartitionNumber;  // 分区号(从1开始,通常EFI分区是1)
  UINT64                   PartitionStart;   // 可选,填0让UEFI自动识别
  UINT64                   PartitionSize;    // 可选,填0让UEFI自动识别
  UINT8                    Signature[16];    // GPT分区GUID/MBR分区签名(前4字节)
  UINT8                    SignatureType;    // 0x01=MBR,0x02=GPT
} MEDIA_HARDDRIVE_DEVICE_PATH;
  • 头部填充:Type=0x01,SubType=0x01,Length=sizeof(MEDIA_HARDDRIVE_DEVICE_PATH)
  • 分区信息:根据你的虚拟硬盘分区类型(MBR/GPT)填充Signature和SignatureType,PartitionNumber填对应分区号

3. 构造文件路径节点

这个节点用来指定分区内的目标EFI文件路径(UTF-16编码):

typedef struct {
  EFI_DEVICE_PATH_PROTOCOL Header;
  CHAR16                   PathName[];       // 宽字符路径,比如L"\\EFI\\BOOT\\test.efi"
} MEDIA_FILEPATH_DEVICE_PATH;
  • 头部填充:Type=0x01,SubType=0x04,Length=sizeof(EFI_DEVICE_PATH_PROTOCOL) + (wcslen(PathName)+1)*2(要包含末尾的空字符)
  • 路径要求:必须是UEFI支持的UTF-16宽字符串,路径分隔符用\

4. 拼接设备路径链

将三个部分按顺序拼接在连续内存中:

  • 先通过gBS->AllocatePool分配足够内存,总长度=媒体节点长度 + 文件节点长度 + 4(结束节点长度)
  • 依次复制媒体节点、文件节点,最后添加结束节点(Type=0x7F,SubType=0xFF,Length=4)

5. 调用UEFI服务加载启动EFI文件

构造好设备路径后,直接调用标准UEFI服务:

EFI_STATUS status;
EFI_HANDLE image_handle;
EFI_DEVICE_PATH_PROTOCOL *device_path = /* 你构造的设备路径 */;

// 加载镜像
status = gBS->LoadImage(
  FALSE,
  gImageHandle,
  device_path,
  NULL,
  0,
  &image_handle
);

// 启动镜像
if (!EFI_ERROR(status)) {
  status = gBS->StartImage(image_handle, NULL, NULL);
}

关键注意事项

  • 内存管理:用gBS->AllocatePool分配设备路径内存,使用完后用gBS->FreePool释放
  • 编码正确性:必须使用UTF-16宽字符串,C语言中L""前缀的字符串直接满足要求
  • 节点长度准确:每个节点的Length字段必须精确计算,否则UEFI会无法解析设备路径
  • 分区信息获取:如果不知道分区号或GUID,可以遍历系统中的EFI_BLOCK_IO_PROTOCOL设备,自行读取解析分区表

内容的提问来源于stack exchange,提问作者DSMOS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 14:43:22