2. 打开根目录
任务目标
本案例演示如何在UEFI应用中通过EFI_SIMPLE_FILE_SYSTEM_PROTOCOL的OpenVolume()函数获取文件系统根目录的EFI_FILE_PROTOCOL句柄,为后续文件读写操作建立基础。
核心概念
UEFI固件通过EFI_SIMPLE_FILE_SYSTEM_PROTOCOL暴露文件系统服务。要访问文件,首先必须调用其OpenVolume()成员函数获得根目录的EFI_FILE_PROTOCOL接口——所有文件操作(打开、读取、创建等)都从该根目录句柄开始。
必要依赖
- EDK2开发环境(含标准UEFI头文件)
- 一个已加载的
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL实例(通常通过LocateHandleBuffer+HandleProtocol获得,或由Shell/加载器传入)
关键完整代码
#include <Uefi.h>
#include <Protocol/SimpleFileSystem.h>
#include <Protocol/File.h>
EFI_STATUS
OpenRootDirectory (
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs,
OUT EFI_FILE_PROTOCOL **RootDir
)
{
if (SimpleFs == NULL || RootDir == NULL) {
return EFI_INVALID_PARAMETER;
}
// 调用 OpenVolume 获取根目录句柄
return SimpleFs->OpenVolume (SimpleFs, RootDir);
}
// 使用示例:假设已通过某种方式获得 SimpleFs
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer = NULL;
UINTN HandleCount = 0;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs = NULL;
EFI_FILE_PROTOCOL *RootDir = NULL;
// 1. 定位系统中所有 SimpleFileSystem 实例
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiSimpleFileSystemProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status) || HandleCount == 0) {
return EFI_NOT_FOUND;
}
// 2. 取第一个实例(实际应用中可能需要遍历选择特定设备)
Status = gBS->HandleProtocol (
HandleBuffer[0],
&gEfiSimpleFileSystemProtocolGuid,
(VOID **)&SimpleFs
);
if (EFI_ERROR (Status)) {
goto Done;
}
// 3. 打开根目录
Status = OpenRootDirectory (SimpleFs, &RootDir);
if (EFI_ERROR (Status)) {
goto Done;
}
// 此时 RootDir 即为根目录句柄,可继续执行文件操作
// ...(本案例仅演示打开根目录)
Done:
if (RootDir != NULL) {
RootDir->Close (RootDir);
}
if (HandleBuffer != NULL) {
FreePool (HandleBuffer);
}
return Status;
}
编译与运行
- 将上述代码保存为
OpenRoot.c,并创建对应的.inf文件(需声明gEfiSimpleFileSystemProtocolGuid依赖)。 - 在EDK2环境中执行
build命令生成EFI可执行文件。 - 在UEFI Shell中运行生成的
.efi文件。
验证方法
运行程序后观察:
- 若返回
EFI_SUCCESS(即Shell无错误提示),说明OpenVolume()调用成功,根目录句柄已获取。 - 可在
Done标签前临时添加调试输出(如Print(L"Root opened successfully\n"))确认执行路径。 - 若返回错误码,检查
SimpleFs是否为有效协议实例,以及设备是否已挂载文件系统。
通过条件:程序无错误返回,且能通过RootDir句柄继续执行后续文件操作(如调用RootDir->Open()打开具体文件)。