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

如何使用GNU-EFI访问其他分区中的EFI可执行文件?

问题

我需要在磁盘中创建两个FAT16分区,并将一个EFI二进制文件放置在另一个FAT16分区中。最初我编写了一个基础的HelloWorld.efi应用(第二阶段),在第一阶段使用以下两个API来执行同一分区内的HelloWorld.efi:

efi_status = BS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID,
                (void **)&shim_li);

efi_status = BS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID,
                (void **) &drive);

目前我正尝试寻找访问另一分区中HelloWorld.efi的方法,使用上述API仅能访问同一分区内的文件,请问应该使用哪些API?

解决方案

要访问磁盘上的其他分区,需要先枚举磁盘的所有分区,再逐个验证并挂载目标分区的文件系统,核心步骤和API如下:

1. 获取磁盘的分区协议

从已加载的镜像中拿到磁盘设备句柄,再通过该句柄获取EFI_PARTITION_PROTOCOL——这个协议用于枚举磁盘上的所有分区:

// 从EFI_LOADED_IMAGE获取磁盘设备句柄
EFI_HANDLE disk_handle = shim_li->DeviceHandle;

// 获取分区协议
EFI_PARTITION_PROTOCOL *partition_proto;
efi_status = BS->HandleProtocol(disk_handle, &EFI_PARTITION_PROTOCOL_GUID, (void**)&partition_proto);
if (EFI_ERROR(efi_status)) {
    // 处理错误
    return efi_status;
}

2. 枚举所有分区

调用EFI_PARTITION_PROTOCOL的GetPartitionList方法,获取磁盘上所有分区的句柄列表:

EFI_HANDLE *partition_handles;
UINTN handle_count;
efi_status = partition_proto->GetPartitionList(
    partition_proto,
    FALSE,  // FALSE表示返回所有类型的分区
    &partition_handles,
    &handle_count
);
if (EFI_ERROR(efi_status)) {
    return efi_status;
}

3. 遍历分区并识别目标FAT16分区

对每个分区句柄尝试获取EFI_SIMPLE_FILE_SYSTEM_PROTOCOL,验证是否为可挂载的FAT分区。同时可以通过分区类型GUID(EFI_FAT16_FILE_SYSTEM_GUID)精准定位目标分区:

for (UINTN i = 0; i < handle_count; i++) {
    EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs_proto;
    efi_status = BS->HandleProtocol(
        partition_handles[i],
        &EFI_SIMPLE_FILE_SYSTEM_GUID,
        (void**)&fs_proto
    );
    if (EFI_ERROR(efi_status)) {
        continue;  // 跳过非文件系统分区
    }

    // 可选:验证分区是否为FAT16类型
    EFI_DEVICE_PATH_PROTOCOL *dev_path;
    efi_status = BS->HandleProtocol(
        partition_handles[i],
        &EFI_DEVICE_PATH_PROTOCOL_GUID,
        (void**)&dev_path
    );
    if (!EFI_ERROR(efi_status)) {
        // 遍历设备路径,找到分区类型节点
        while (!IsDevicePathEnd(dev_path)) {
            if (dev_path->Type == MEDIA_DEVICE_PATH && dev_path->SubType == MEDIA_HARDDRIVE_DP) {
                HARDDRIVE_DEVICE_PATH *hd_dev_path = (HARDDRIVE_DEVICE_PATH*)dev_path;
                if (CompareGuid(&hd_dev_path->PartitionTypeGuid, &EFI_FAT16_FILE_SYSTEM_GUID)) {
                    // 找到FAT16分区,开始挂载
                    break;
                }
            }
            dev_path = NextDevicePathNode(dev_path);
        }
    }

    // 挂载文件系统根目录
    EFI_FILE_PROTOCOL *root_dir;
    efi_status = fs_proto->OpenVolume(fs_proto, &root_dir);
    if (!EFI_ERROR(efi_status)) {
        // 访问目标分区内的HelloWorld.efi
        EFI_FILE_PROTOCOL *target_file;
        efi_status = root_dir->Open(
            root_dir,
            &target_file,
            L"HelloWorld.efi",
            EFI_FILE_MODE_READ,
            0
        );
        if (!EFI_ERROR(efi_status)) {
            // 成功打开文件,后续可加载执行
            target_file->Close(target_file);
        }
        root_dir->Close(root_dir);
    }
}

4. 释放资源

枚举完成后,释放分区句柄列表的内存:

BS->FreePool(partition_handles);

关键API总结

  • EFI_PARTITION_PROTOCOL:用于枚举磁盘上的所有分区
  • EFI_DEVICE_PATH_PROTOCOL:用于识别分区的类型(如FAT16)
  • 配合原有的EFI_SIMPLE_FILE_SYSTEM_PROTOCOL和EFI_FILE_PROTOCOL完成文件访问

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 18:55:42