Step to UEFI (164)NT32 环境下的OpenFile研究

根据之前的研究,UDK中带的 NT32 模拟环境里面的很多操作都是直接和 Windows API挂钩来实现的。最近查看了一下 NT32 下面的 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL 的实现。具体代码可以在\Nt32Pkg\WinNtSimpleFileSystemDxe\WinNtSimpleFileSystem.c 下面看到。

首先,在 WinNtSimpleFileSystem.c 中有下面这样的代码:

  Private->SimpleFileSystem.OpenVolume  = WinNtSimpleFileSystemOpenVolume;

 

这样,当我们调用EFI_SIMPLE_FILE_SYSTEM_PROTOCOL OpenVolume 的时候,实际工作的是WinNtSimpleFileSystemOpenVolume 的代码。此外,还有下面这样的代码,都是用Windows API 来替换 Protocol 中的操作。

  PrivateFile->EfiFile.Open         = WinNtSimpleFileSystemOpen;
  PrivateFile->EfiFile.Close        = WinNtSimpleFileSystemClose;
  PrivateFile->EfiFile.Delete       = WinNtSimpleFileSystemDelete;
  PrivateFile->EfiFile.Read         = WinNtSimpleFileSystemRead;
  PrivateFile->EfiFile.Write        = WinNtSimpleFileSystemWrite;
  PrivateFile->EfiFile.GetPosition  = WinNtSimpleFileSystemGetPosition;
  PrivateFile->EfiFile.SetPosition  = WinNtSimpleFileSystemSetPosition;
  PrivateFile->EfiFile.GetInfo      = WinNtSimpleFileSystemGetInfo;
  PrivateFile->EfiFile.SetInfo      = WinNtSimpleFileSystemSetInfo;
  PrivateFile->EfiFile.Flush        = WinNtSimpleFileSystemFlush;
  PrivateFile->IsValidFindBuf       = FALSE;

 

通过这样的赋值,当我们在NT32 模拟环境中调用打开读取等等Protocol 的函数时,实际上是用Windows 对应的API来完成实际操作的。
为了证明这一点,可以在上面的函数中插入输出 Debug 信息的代码【参考1】,比如:修改 WinNTSimpleFileSystemOpenVolume() 代码,插入Debug 信息:

/*++

Routine Description:

  Open the root directory on a volume.

Arguments:

  This  - A pointer to the volume to open.

  Root  - A pointer to storage for the returned opened file handle of the root directory.

Returns:

  EFI_SUCCESS           - The volume was opened.

  EFI_UNSUPPORTED       - The volume does not support the requested file system type.

  EFI_NO_MEDIA          - The device has no media.

  EFI_DEVICE_ERROR      - The device reported an error.

  EFI_VOLUME_CORRUPTED  - The file system structures are corrupted.

  EFI_ACCESS_DENIED     - The service denied access to the file.

  EFI_OUT_OF_RESOURCES  - The file volume could not be opened due to lack of resources.

  EFI_MEDIA_CHANGED     - The device has new media or the media is no longer supported.

--*/
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
{
  EFI_STATUS                        Status;
  WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
  WIN_NT_EFI_FILE_PRIVATE           *PrivateFile;
  EFI_TPL                           OldTpl;
  CHAR16                            *TempFileName;
  UINTN                             Size;

  //LABZ_Start
  DEBUG ((EFI_D_INFO, "www.lab-z.com\n"));
  //LABZ_End
  
  if (This == NULL || Root == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);

  Private     = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This);

  PrivateFile = AllocatePool (sizeof (WIN_NT_EFI_FILE_PRIVATE));
  if (PrivateFile == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

  PrivateFile->FileName = AllocatePool (StrSize (Private->FilePath));
  if (PrivateFile->FileName == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

  PrivateFile->FilePath = AllocatePool (StrSize (Private->FilePath));
  if (PrivateFile->FilePath == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

  StrCpy (PrivateFile->FilePath, Private->FilePath);
  StrCpy (PrivateFile->FileName, PrivateFile->FilePath);
  PrivateFile->Signature            = WIN_NT_EFI_FILE_PRIVATE_SIGNATURE;
  PrivateFile->WinNtThunk           = Private->WinNtThunk;
  PrivateFile->SimpleFileSystem     = This;
  PrivateFile->IsRootDirectory      = TRUE;
  PrivateFile->IsDirectoryPath      = TRUE;
  PrivateFile->IsOpenedByRead       = TRUE;
  PrivateFile->EfiFile.Revision     = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
  PrivateFile->EfiFile.Open         = WinNtSimpleFileSystemOpen;
  PrivateFile->EfiFile.Close        = WinNtSimpleFileSystemClose;
  PrivateFile->EfiFile.Delete       = WinNtSimpleFileSystemDelete;
  PrivateFile->EfiFile.Read         = WinNtSimpleFileSystemRead;
  PrivateFile->EfiFile.Write        = WinNtSimpleFileSystemWrite;
  PrivateFile->EfiFile.GetPosition  = WinNtSimpleFileSystemGetPosition;
  PrivateFile->EfiFile.SetPosition  = WinNtSimpleFileSystemSetPosition;
  PrivateFile->EfiFile.GetInfo      = WinNtSimpleFileSystemGetInfo;
  PrivateFile->EfiFile.SetInfo      = WinNtSimpleFileSystemSetInfo;
  PrivateFile->EfiFile.Flush        = WinNtSimpleFileSystemFlush;
  PrivateFile->IsValidFindBuf       = FALSE;

  //
  // Set DirHandle
  //
  PrivateFile->DirHandle = PrivateFile->WinNtThunk->CreateFile (
                                                      PrivateFile->FilePath,
                                                      GENERIC_READ,
                                                      FILE_SHARE_READ | FILE_SHARE_WRITE,
                                                      NULL,
                                                      OPEN_EXISTING,
                                                      FILE_FLAG_BACKUP_SEMANTICS,
                                                      NULL
                                                      );

  if (PrivateFile->DirHandle == INVALID_HANDLE_VALUE) {
    Status = EFI_NOT_FOUND;
    goto Done;
  }

  //
  // Find the first file under it
  //
  Size  = StrSize (PrivateFile->FilePath);
  Size += StrSize (L"\\*");
  Status = gBS->AllocatePool (
                  EfiBootServicesData,
                  Size,
                  (VOID **)&TempFileName
                  );
  if (EFI_ERROR (Status)) {
    goto Done;
  }
  StrCpy (TempFileName, PrivateFile->FilePath);
  StrCat (TempFileName, L"\\*");

  PrivateFile->LHandle = PrivateFile->WinNtThunk->FindFirstFile (TempFileName, &PrivateFile->FindBuf);
  FreePool (TempFileName);

  if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {
    PrivateFile->IsValidFindBuf = FALSE;
  } else {
    PrivateFile->IsValidFindBuf = TRUE;
  }
  *Root = &PrivateFile->EfiFile;

  Status = EFI_SUCCESS;

Done:

  if (EFI_ERROR (Status)) {
    if (PrivateFile) {
      if (PrivateFile->FileName) {
        FreePool (PrivateFile->FileName);
      }

      if (PrivateFile->FilePath) {
        FreePool (PrivateFile->FilePath);
      }

      FreePool (PrivateFile);
    }
  }

  gBS->RestoreTPL (OldTpl);

  return Status;
}

 

之后在启动的过程中就能够看到如下的 Debug 信息:

参考:
1. https://www.lab-z.com/stu130nt32/ NT32 模拟器中的 Debug Message 输出

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注