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;
}

编译与运行

  1. 将上述代码保存为OpenRoot.c,并创建对应的.inf文件(需声明gEfiSimpleFileSystemProtocolGuid依赖)。
  2. 在EDK2环境中执行build命令生成EFI可执行文件。
  3. 在UEFI Shell中运行生成的.efi文件。

验证方法

运行程序后观察:

  • 若返回EFI_SUCCESS(即Shell无错误提示),说明OpenVolume()调用成功,根目录句柄已获取。
  • 可在Done标签前临时添加调试输出(如Print(L"Root opened successfully\n"))确认执行路径。
  • 若返回错误码,检查SimpleFs是否为有效协议实例,以及设备是否已挂载文件系统。

通过条件:程序无错误返回,且能通过RootDir句柄继续执行后续文件操作(如调用RootDir->Open()打开具体文件)。