BIOS实战之读取文件

在UEFI shell下,BIOS的更新、EC的更新等都需要用到读取文件,从UEFI原理与编程中初步了解怎么读写,那么接下来就进入实践环节

先把后面需要的变量先定义好(便于理解):

  EFI_STATUS                      Status;
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *ptSFS;
  EFI_FILE_PROTOCOL               *ptRootFile;
  EFI_FILE_PROTOCOL               *ptFile;
  EFI_FILE_INFO                   *FileInfo;
  UINTN                           FileInfoSize;
  EFI_HANDLE                      *HandleBuffer;
  UINTN                           NumberOfHandles;
  UINTN                           Index;
  UINT8                           *Buffer;

  Status     = EFI_SUCCESS;
  ptRootFile = NULL;
  ptFile     = NULL;
  FileInfo   = NULL;
  HandleBuffer = NULL;	

1、首先通过使用gBS->LocateHandleBuffer找到所有支持FileSystemIo的设备

Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiSimpleFileSystemProtocolGuid,
                  NULL,
                  &NumberOfHandles,
                  &HandleBuffer
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }

2、对于每个支持FileSystemIo的设备,打开设备上的的SimpleFileSystemProtocol

for (Index = 0; Index < NumberOfHandles; Index ++) {
    Status = gBS->HandleProtocol(
               HandleBuffer[Index], 
               &gEfiSimpleFileSystemProtocolGuid, 
               (VOID **)&ptSFS
               );

3、通过SimpleFileSystemProtocol的OpenVolume,可以获得FAT文件系统上的根目录句柄,然后我们就可以根据这个句柄操作文件了,打开文件进行读写:

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;
};
 Status = ptRootFile->Open(
                   ptRootFile, 
                   &ptFile, 
                   FileName, 
                   EFI_FILE_MODE_READ, 
                   0
                   );

4、打开之后按理来说就可以读文件了,但是有个问题,你读的文件到底有多大,需要多大的缓存,这是一个未知数,因此在读文件之前,我们还需要先获取这个文件的一些信息,比如FileSize

typedef struct {
  ///
  /// The size of the EFI_FILE_INFO structure, including the Null-terminated FileName string.
  ///
  UINT64    Size;
  ///
  /// The size of the file in bytes.
  ///
  UINT64    FileSize;
  ///
  /// PhysicalSize The amount of physical space the file consumes on the file system volume.
  ///
  UINT64    PhysicalSize;
  ///
  /// The time the file was created.
  ///
  EFI_TIME  CreateTime;
  ///
  /// The time when the file was last accessed.
  ///
  EFI_TIME  LastAccessTime;
  ///
  /// The time when the file's contents were last modified.
  ///
  EFI_TIME  ModificationTime;
  ///
  /// The attribute bits for the file.
  ///
  UINT64    Attribute;
  ///
  /// The Null-terminated name of the file.
  ///
  CHAR16    FileName[1];
} EFI_FILE_INFO;

 

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;
};
Status = ptFile->GetInfo (
                       ptFile,
                       &gEfiFileInfoGuid,
                       &FileInfoSize,
                       FileInfo
                       );
    if(Status == EFI_BUFFER_TOO_SMALL){
      FileInfo = AllocateZeroPool(FileInfoSize);
      if(FileInfo == NULL){
        Status = EFI_OUT_OF_RESOURCES;
      } else {
        Status = ptFile->GetInfo(
                           ptFile,
                           &gEfiFileInfoGuid,
                           &FileInfoSize,
                           FileInfo
                           );

最后就是真正的读取文件

Buffer = AllocateZeroPool((UINTN)FileInfo->FileSize);

Status = ptFile->Read(ptFile, &FileInfo->FileSize, Buffer);

整体流程如下:

EFI_STATUS 
ReadFileInFS (
  IN      CHAR16  *FileName,
  OUT     UINT8   **FileData,
  IN OUT  UINTN   *BufferSize
  )
{
  EFI_STATUS                      Status;
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *ptSFS;
  EFI_FILE_PROTOCOL               *ptRootFile;
  EFI_FILE_PROTOCOL               *ptFile;
  EFI_FILE_INFO                   *FileInfo;
  UINTN                           FileInfoSize;
  EFI_HANDLE                      *HandleBuffer;
  UINTN                           NumberOfHandles;
  UINTN                           Index;
  UINT8                           *Buffer;

  Status     = EFI_SUCCESS;
  ptRootFile = NULL;
  ptFile     = NULL;
  FileInfo   = NULL;
  HandleBuffer = NULL;	

  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiSimpleFileSystemProtocolGuid,
                  NULL,
                  &NumberOfHandles,
                  &HandleBuffer
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  for (Index = 0; Index < NumberOfHandles; Index ++) {
    Status = gBS->HandleProtocol(
               HandleBuffer[Index], 
               &gEfiSimpleFileSystemProtocolGuid, 
               (VOID **)&ptSFS
               );
    if (!EFI_ERROR (Status)) {
      Status = ptSFS->OpenVolume(ptSFS, &ptRootFile);
      if (!EFI_ERROR (Status)) {
        Status = ptRootFile->Open(
                   ptRootFile, 
                   &ptFile, 
                   FileName, 
                   EFI_FILE_MODE_READ, 
                   0
                   );
        if (!EFI_ERROR (Status)) {
          break;
        } else {
          if (ptRootFile != NULL){
            ptRootFile->Close(ptRootFile);
            ptRootFile = NULL;						
          }
        }
      }
    }
  }

  if (HandleBuffer != NULL) {
    FreePool(HandleBuffer);
    HandleBuffer = NULL;
  }

  if (!EFI_ERROR (Status)) {
    FileInfo = NULL;
    FileInfoSize = 0;
    Status = ptFile->GetInfo (
                       ptFile,
                       &gEfiFileInfoGuid,
                       &FileInfoSize,
                       FileInfo
                       );
    if(Status == EFI_BUFFER_TOO_SMALL){
      FileInfo = AllocateZeroPool(FileInfoSize);
      if(FileInfo == NULL){
        Status = EFI_OUT_OF_RESOURCES;
      } else {
        Status = ptFile->GetInfo(
                           ptFile,
                           &gEfiFileInfoGuid,
                           &FileInfoSize,
                           FileInfo
                           );
      }
    }
  }
  if (EFI_ERROR (Status)) {
    goto ProcExit;
  }

  if(FileInfo->Attribute & EFI_FILE_DIRECTORY){
    Status = EFI_INVALID_PARAMETER;
    goto ProcExit;
  }

  Buffer = AllocateZeroPool((UINTN)FileInfo->FileSize);
  if (Buffer == NULL) {
    goto ProcExit;
  }

  Status = ptFile->Read(ptFile, &FileInfo->FileSize, Buffer);
  if (EFI_ERROR (Status)) {
    FreePool (Buffer);
    goto ProcExit;
  }
  *FileData = Buffer;
  *BufferSize = FileInfo->FileSize;

ProcExit:
  if (ptFile != NULL){
    ptFile->Close(ptFile);
  }  
  if (ptRootFile != NULL){
    ptRootFile->Close(ptRootFile);
  }
  if (FileInfo != NULL) {
    FreePool (FileInfo);
  }

  return Status;
}

在APP中,只要加入这个函数,就能读取文件,我们可以读取BIOS文件,EC文件,图片文件等等。但是这个函数有个缺点,比如我编译了一个DisplayBmpTest.efi,运行显示bmp图片,那么这个图片与DisplayBmpTest.efi必须在根目录,不能在子目录,如果在子目录,必须添加路径,比如在根目录,我直接使用DisplayBmpTest.efi Tianocore.bmp就ok了,但是在子目录,就需要运行DisplayBmpTest.efi  \xxx\xxx\Tianocore.bmp,那么怎么样才能在子目录运行DisplayBmpTest.efi Tianocore.bmp就可以呢,那么我们就需要通过代码将这个路径找出来,ok,下一节接着找路径。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值