winntblockio.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,122 行 · 第 1/3 页

C
1,122
字号
    // Shut down our device
    //
    Private->WinNtThunk->CloseHandle (Private->NtHandle);

    //
    // Free our instance data
    //
    EfiLibFreeUnicodeStringTable (Private->ControllerNameTable);

    gBS->FreePool (Private);
  }

  return Status;
}

STATIC
CHAR16 *
GetNextElementPastTerminator (
  IN  CHAR16  *EnvironmentVariable,
  IN  CHAR16  Terminator
  )
/*++

Routine Description:

  Worker function to parse environment variables.

Arguments:
  EnvironmentVariable - Envirnment variable to parse.

  Terminator          - Terminator to parse for.

Returns: 

  Pointer to next eliment past the first occurence of Terminator or the '\0'
  at the end of the string.

--*/
{
  CHAR16  *Ptr;

  for (Ptr = EnvironmentVariable; *Ptr != '\0'; Ptr++) {
    if (*Ptr == Terminator) {
      Ptr++;
      break;
    }
  }

  return Ptr;
}

STATIC
EFI_STATUS
WinNtBlockIoCreateMapping (
  IN EFI_WIN_NT_IO_PROTOCOL             *WinNtIo,
  IN EFI_HANDLE                         EfiDeviceHandle,
  IN CHAR16                             *Filename,
  IN BOOLEAN                            ReadOnly,
  IN BOOLEAN                            RemovableMedia,
  IN UINTN                              NumberOfBlocks,
  IN UINTN                              BlockSize,
  IN WIN_NT_RAW_DISK_DEVICE_TYPE        DeviceType
  )
/*++

Routine Description:

  TODO: Add function description

Arguments:

  WinNtIo         - TODO: add argument description
  EfiDeviceHandle - TODO: add argument description
  Filename        - TODO: add argument description
  ReadOnly        - TODO: add argument description
  RemovableMedia  - TODO: add argument description
  NumberOfBlocks  - TODO: add argument description
  BlockSize       - TODO: add argument description
  DeviceType      - TODO: add argument description

Returns:

  TODO: add return values

--*/
{
  EFI_STATUS              Status;
  EFI_BLOCK_IO_PROTOCOL   *BlockIo;
  WIN_NT_BLOCK_IO_PRIVATE *Private;
  UINTN                   Index;

  WinNtIo->WinNtThunk->SetErrorMode (SEM_FAILCRITICALERRORS);

  Status = gBS->AllocatePool (
                  EfiBootServicesData,
                  sizeof (WIN_NT_BLOCK_IO_PRIVATE),
                  &Private
                  );
  ASSERT_EFI_ERROR (Status);

  EfiInitializeLock (&Private->Lock, EFI_TPL_NOTIFY);

  Private->WinNtThunk = WinNtIo->WinNtThunk;

  Private->Signature  = WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE;
  Private->LastBlock  = NumberOfBlocks - 1;
  Private->BlockSize  = BlockSize;

  for (Index = 0; Filename[Index] != 0; Index++) {
    Private->Filename[Index] = Filename[Index];
  }

  Private->Filename[Index]      = 0;

  Private->ReadMode             = GENERIC_READ | (ReadOnly ? 0 : GENERIC_WRITE);
  Private->ShareMode            = FILE_SHARE_READ | FILE_SHARE_WRITE;

  Private->NumberOfBlocks       = NumberOfBlocks;
  Private->DeviceType           = DeviceType;
  Private->NtHandle             = INVALID_HANDLE_VALUE;

  Private->ControllerNameTable  = NULL;

  EfiLibAddUnicodeString (
    "eng",
    gWinNtBlockIoComponentName.SupportedLanguages,
    &Private->ControllerNameTable,
    Private->Filename
    );

  BlockIo = &Private->BlockIo;
  BlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
  BlockIo->Media = &Private->Media;
  BlockIo->Media->BlockSize = Private->BlockSize;
  BlockIo->Media->LastBlock = Private->NumberOfBlocks - 1;
  BlockIo->Media->MediaId = 0;;

  BlockIo->Reset = WinNtBlockIoResetBlock;
  BlockIo->ReadBlocks = WinNtBlockIoReadBlocks;
  BlockIo->WriteBlocks = WinNtBlockIoWriteBlocks;
  BlockIo->FlushBlocks = WinNtBlockIoFlushBlocks;

  BlockIo->Media->ReadOnly = ReadOnly;
  BlockIo->Media->RemovableMedia = RemovableMedia;
  BlockIo->Media->LogicalPartition = FALSE;
  BlockIo->Media->MediaPresent = TRUE;
  BlockIo->Media->WriteCaching = FALSE;

  if (DeviceType == EfiWinNtVirtualDisks) {
    BlockIo->Media->IoAlign = 1;

    //
    // Create a file to use for a virtual disk even if it does not exist.
    //
    Private->OpenMode = OPEN_ALWAYS;
  } else if (DeviceType == EfiWinNtPhysicalDisks) {
    //
    // Physical disk and floppy devices require 4 byte alignment.
    //
    BlockIo->Media->IoAlign = 4;

    //
    // You can only open a physical device if it exists.
    //
    Private->OpenMode = OPEN_EXISTING;
  } else {
    ASSERT (FALSE);
  }

  Private->EfiHandle  = EfiDeviceHandle;
  Status              = WinNtBlockIoOpenDevice (Private);
  if (!EFI_ERROR (Status)) {

    Status = gBS->InstallMultipleProtocolInterfaces (
                    &Private->EfiHandle,
                    &gEfiBlockIoProtocolGuid,
                    &Private->BlockIo,
                    NULL
                    );
    if (EFI_ERROR (Status)) {
      EfiLibFreeUnicodeStringTable (Private->ControllerNameTable);
      gBS->FreePool (Private);
    }

    DEBUG ((EFI_D_INIT, "BlockDevice added: %s\n", Filename));
  }

  return Status;
}

STATIC
EFI_STATUS
WinNtBlockIoOpenDevice (
  WIN_NT_BLOCK_IO_PRIVATE                 *Private
  )
/*++

Routine Description:

  TODO: Add function description

Arguments:

  Private - TODO: add argument description

Returns:

  TODO: add return values

--*/
{
  EFI_STATUS            Status;
  UINT64                FileSize;
  UINT64                EndOfFile;
  EFI_BLOCK_IO_PROTOCOL *BlockIo;

  BlockIo = &Private->BlockIo;
  EfiAcquireLock (&Private->Lock);

  //
  // If the device is already opened, close it
  //
  if (Private->NtHandle != INVALID_HANDLE_VALUE) {
    BlockIo->Reset (BlockIo, FALSE);
  }

  //
  // Open the device
  //
  Private->NtHandle = Private->WinNtThunk->CreateFile (
                                            Private->Filename,
                                            Private->ReadMode,
                                            Private->ShareMode,
                                            NULL,
                                            Private->OpenMode,
                                            0,
                                            NULL
                                            );

  Status = Private->WinNtThunk->GetLastError ();

  if (Private->NtHandle == INVALID_HANDLE_VALUE) {
    DEBUG ((EFI_D_INFO, "PlOpenBlock: Could not open %s, %x\n", Private->Filename, Private->WinNtThunk->GetLastError ()));
    BlockIo->Media->MediaPresent  = FALSE;
    Status                        = EFI_NO_MEDIA;
    goto Done;
  }

  if (!BlockIo->Media->MediaPresent) {
    //
    // BugBug: try to emulate if a CD appears - notify drivers to check it out
    //
    BlockIo->Media->MediaPresent = TRUE;
    EfiReleaseLock (&Private->Lock);
    EfiAcquireLock (&Private->Lock);
  }

  //
  // get the size of the file
  //
  Status = SetFilePointer64 (Private, 0, &FileSize, FILE_END);

  if (EFI_ERROR (Status)) {
    FileSize = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);
    if (Private->DeviceType == EfiWinNtVirtualDisks) {
      DEBUG ((EFI_D_ERROR, "PlOpenBlock: Could not get filesize of %s\n", Private->Filename));
      Status = EFI_UNSUPPORTED;
      goto Done;
    }
  }

  if (Private->NumberOfBlocks == 0) {
    Private->NumberOfBlocks = DivU64x32 (FileSize, Private->BlockSize, NULL);
  }

  EndOfFile = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);

  if (FileSize != EndOfFile) {
    //
    // file is not the proper size, change it
    //
    DEBUG ((EFI_D_INIT, "PlOpenBlock: Initializing block device: %hs\n", Private->Filename));

    //
    // first set it to 0
    //
    SetFilePointer64 (Private, 0, NULL, FILE_BEGIN);
    Private->WinNtThunk->SetEndOfFile (Private->NtHandle);

    //
    // then set it to the needed file size (OS will zero fill it)
    //
    SetFilePointer64 (Private, EndOfFile, NULL, FILE_BEGIN);
    Private->WinNtThunk->SetEndOfFile (Private->NtHandle);
  }

  DEBUG ((EFI_D_INIT, "%HPlOpenBlock: opened %s%N\n", Private->Filename));
  Status = EFI_SUCCESS;

Done:
  if (EFI_ERROR (Status)) {
    if (Private->NtHandle != INVALID_HANDLE_VALUE) {
      BlockIo->Reset (BlockIo, FALSE);
    }
  }

  EfiReleaseLock (&Private->Lock);
  return Status;
}

STATIC
EFI_STATUS
WinNtBlockIoError (
  IN WIN_NT_BLOCK_IO_PRIVATE      *Private
  )
/*++

Routine Description:

  TODO: Add function description

Arguments:

  Private - TODO: add argument description

Returns:

  TODO: add return values

--*/
{
  EFI_BLOCK_IO_PROTOCOL *BlockIo;
  EFI_STATUS            Status;
  BOOLEAN               ReinstallBlockIoFlag;

  BlockIo = &Private->BlockIo;

  switch (Private->WinNtThunk->GetLastError ()) {

  case ERROR_NOT_READY:
    Status                        = EFI_NO_MEDIA;
    BlockIo->Media->ReadOnly      = FALSE;
    BlockIo->Media->MediaPresent  = FALSE;
    ReinstallBlockIoFlag          = FALSE;
    break;

  case ERROR_WRONG_DISK:
    BlockIo->Media->ReadOnly      = FALSE;
    BlockIo->Media->MediaPresent  = TRUE;
    BlockIo->Media->MediaId += 1;
    ReinstallBlockIoFlag  = TRUE;
    Status                = EFI_MEDIA_CHANGED;
    break;

  case ERROR_WRITE_PROTECT:
    BlockIo->Media->ReadOnly  = TRUE;
    ReinstallBlockIoFlag      = FALSE;
    Status                    = EFI_WRITE_PROTECTED;
    break;

  default:
    ReinstallBlockIoFlag  = FALSE;
    Status                = EFI_DEVICE_ERROR;
    break;
  }

  if (ReinstallBlockIoFlag) {
    BlockIo->Reset (BlockIo, FALSE);

    gBS->ReinstallProtocolInterface (
          Private->EfiHandle,
          &gEfiBlockIoProtocolGuid,
          BlockIo,
          BlockIo

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?