UEFI开发与调试---文件操作

存储器相关的Protocol有BlockIo,BlockIo2,DiskIo,DiskIo2。DiskIo/DiskIo2的实现分别依赖与BlockIo/BlockIo2,其中BlockIo,DiskIo提供了访问设备的阻塞函数,BlockIo2,DiskIo2提供异步函数。。它们的区别是BlockIo只能按照扇区为单位访问存储器,而DiskIo可以按照字节为单位访问。UEFI也会为每个分区生成对应的控制器,并且根据分区属性安装对应的BlockIo/BlockIo2/DiskIo/DiskIo2实例。

除了上面的Protocol之外,UEFI还提供了文件系统的支持,通常UEFI需要提供一个ESP(EFI System Partition)分区,在这个分区上提供启动文件。这就要求UEFI具有提取文件的功能,要达到此目的,UEFI必须要支持文件系统。ESP主要用来存放启动相关的文件,对文件系统的要求比较简单,所以FAT32即可满足要求,UEFI提供了对此文件系统的支持。

本文只以DiskIo作介绍说明,其他几种Protocol的操作方法类似。

DiskIo

操作DiskIo,需要首先需要查找对应的控制器Handler,然后OpenProtocol打开对应的服务,接下来才可以使用DiskIo的操作函数来操作存储器。
对应的Protocol提供的操作有:

typedef struct _EFI_DISK_IO_PROTOCOL EFI_DISK_IO_PROTOCOL;
///
/// This protocol is used to abstract Block I/O interfaces.
///
struct _EFI_DISK_IO_PROTOCOL {
  ///
  /// The revision to which the disk I/O interface adheres. All future
  /// revisions must be backwards compatible. If a future version is not
  /// backwards compatible, it is not the same GUID.
  ///
  UINT64          Revision;
  EFI_DISK_READ   ReadDisk;
  EFI_DISK_WRITE  WriteDisk;
};

使用实例:

  Status = gBS->OpenProtocol(HandleInfoList[0].Handle,
          &gEfiDiskIoProtocolGuid,
          (VOID **)&pDiskIo,
          gImageHandle,
          NULL,
          EFI_OPEN_PROTOCOL_GET_PROTOCOL
          );
  if (Status != EFI_SUCCESS) {
      DEBUG((EFI_D_ERROR, "%a(): Failed to get open protocol from partition. Reason: %r\n", __func__, Status));
      return Status;
  }

  Status = pDiskIo->ReadDisk(pDiskIo,
          MediaId,
          Offset,
          DataSize,
          (VOID *)Buffer);

FAT32文件系统

UEFI实现了一个EFI_SIMPLE_FILE_SYSTEM_PROTOCOL用来支持FAT32文件系统。它的定义如下:

typedef struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL;

typedef
EFI_STATUS
(EFIAPI *EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME)(
  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL    *This,
  OUT EFI_FILE_PROTOCOL                 **Root    //返回Root句柄
  );

struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL {
  ///
  /// The version of the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL. The version
  /// specified by this specification is 0x00010000. All future revisions
  /// must be backwards compatible.
  ///
  UINT64                                      Revision;
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME OpenVolume;
};

此Protocol中只有一个关键函数OpenVolume,主要功能是用来获取对应分区Root句柄,而Root句柄实际上也是一个Protocol,其中真正包含了文件操作,如下所示:

typedef struct _EFI_FILE_PROTOCOL         EFI_FILE_PROTOCOL;
typedef struct _EFI_FILE_PROTOCOL         *EFI_FILE_HANDLE;

 struct _EFI_FILE_PROTOCOL {
   ///
   /// The version of the EFI_FILE_PROTOCOL interface. The version specified 
   /// by this specification is EFI_FILE_PROTOCOL_LATEST_REVISION.
   /// Future versions are required to be backward compatible to version 1.0.
   ///
   UINT64                Revision;
   EFI_FILE_OPEN         Open;
   EFI_FILE_CLOSE        Close;
   EFI_FILE_DELETE       Delete;
   EFI_FILE_READ         Read;
   EFI_FILE_WRITE        Write;
   EFI_FILE_GET_POSITION GetPosition;
   EFI_FILE_SET_POSITION SetPosition;
   EFI_FILE_GET_INFO     GetInfo;
   EFI_FILE_SET_INFO     SetInfo;
   EFI_FILE_FLUSH        Flush;
   EFI_FILE_OPEN_EX      OpenEx;
   EFI_FILE_READ_EX      ReadEx;
   EFI_FILE_WRITE_EX     WriteEx;
   EFI_FILE_FLUSH_EX     FlushEx;
 };

实例:

EFI_STATUS TestOpen()
{
    EFI_STATUS  Status = 0;
    EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
    EFI_FILE_PROTOCOL *Root = 0;
    EFI_FILE_PROTOCOL *EfiDirectory = 0;

    Status = gBS->LocateProtocol(
            &gEfiSimpleFileSystemProtocolGuid,
            NULL,
            (VOID**)&SimpleFileSystem
    );
    if (EFI_ERROR(Status)) {
     //未找到EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
        return Status;
    }
    Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &Root);

    // 在根目录下生成efi目录
    Status = Root->Open(
            Root, 
            &EfiDirectory,
            (CHAR16*)L"efi",
            EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, //打开模式
            EFI_FILE_DIRECTORY
            );

    //在efi目录下生成readme.txt文件
    {
        EFI_FILE_PROTOCOL *ReadMe = 0;
        Status = EfiDirectory ->Open(
                EfiDirectory,    //This 指向目录\efi\ 
                &ReadMe,          //新文件的句柄   
                (CHAR16*)L"readme.txt",  //文件全路径为\efi\readme.txt
                EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,//创建并打开
                0  //生成普通文件,使用默认属性
                );
        Status = ReadMe -> Close(ReadMe);
    }
    Status = EfiDirectory->Close(EfiDirectory);
    return Status;
}

参考:《UEFI 原理与编程》–戴正华

你可能感兴趣的:(UEFI开发和调试)