winntblockio.c

来自「Next BIOS Source code : Extensible Firmw」· C语言 代码 · 共 1,018 行 · 第 1/2 页

C
1,018
字号
{
  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);
//    gBS->ReinstallProtocolInterface (Private->EfiHandle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
    EfiAcquireLock (&Private->Lock);
  }

  //
  // get the size of the file
  //
  //FileSizeLow = Private->WinNtThunk->SetFilePointer (Private->NtHandle, 0, NULL, FILE_END);
  Status = SetFilePointer64 (Private, 0, &FileSize, FILE_END);
  
  if (EFI_ERROR(Status)) {
    FileSize = DriverLibMultU64x32 (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 = DriverLibDivU64x32 (FileSize, Private->BlockSize, NULL);
  }
  EndOfFile = DriverLibMultU64x32 (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
    //
    //Private->WinNtThunk->SetFilePointer (Private->NtHandle, 0, NULL, FILE_BEGIN);
    SetFilePointer64 (Private, 0, NULL, FILE_BEGIN);
    Private->WinNtThunk->SetEndOfFile (Private->NtHandle);

    //
    // then set it to the needed file size (OS will zero fill it)
    //
    //Private->WinNtThunk->SetFilePointer (Private->NtHandle, EndOfFile, NULL, FILE_BEGIN);
    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
  )
{
  EFI_BLOCK_IO_PROTOCOL   *BlockIo;
  EFI_STATUS              Status;
  BOOLEAN                 ReinstallBlockIoFlag;

  BlockIo = &Private->BlockIo;

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

  case ERROR_NOT_READY:
    BlockIo->Media->ReadOnly = FALSE;
    BlockIo->Media->MediaPresent = FALSE;
    ReinstallBlockIoFlag = FALSE;
    Status = EFI_DEVICE_ERROR;
    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
          );
  }
  return Status;
}

STATIC
EFI_STATUS
WinNtBlockIoReadWriteCommon (
  IN  WIN_NT_BLOCK_IO_PRIVATE     *Private,
  IN UINT32                 MediaId,
  IN EFI_LBA      Lba,
  IN UINTN        BufferSize,
  IN VOID         *Buffer,
  IN BOOLEAN      Write,
  IN CHAR8        *CallerName 
  )
{
  EFI_STATUS  Status;
  EFI_BLOCK_IO_MEDIA      *Media;
  UINTN       BlockSize;
  UINT64      LastBlock;
  INT64       DistanceToMove;
  UINT64       DistanceMoved;

  if (Private->NtHandle == INVALID_HANDLE_VALUE) {
    Status = WinNtBlockIoOpenDevice (Private);
    if (EFI_ERROR(Status)) {
      return Status;
    }
  }

  Media = Private->BlockIo.Media;

  if (!(Media->MediaPresent)) {
    Status = EFI_NO_MEDIA;
  }    
  
  if (MediaId != Media->MediaId) {
    Status = EFI_MEDIA_CHANGED;
  }

  if (Write) {
    if (Media->ReadOnly) {
      return EFI_WRITE_PROTECTED;
    }
  }

  //
  // Verify buffer size
  //
  BlockSize = Private->BlockSize;

  LastBlock = Lba + (BufferSize/BlockSize) - 1;
  if (LastBlock > Private->LastBlock) {
    DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));
    return EFI_INVALID_PARAMETER;
  }

  if ((BufferSize % BlockSize) != 0) {
    DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));
    return EFI_BAD_BUFFER_SIZE;
  }

  if (Buffer == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (BufferSize == 0) {
    DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));
    return EFI_SUCCESS;
  }

  //
  // Seek to End of File
  //
  DistanceToMove = DriverLibMultU64x32 (Lba, BlockSize);
  //DistanceMoved = Private->WinNtThunk->SetFilePointer (Private->NtHandle, DistanceToMove, NULL, FILE_BEGIN);
  Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, FILE_BEGIN);
  
  if (EFI_ERROR(Status)) {
    DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));
    return WinNtBlockIoError (Private);
  }

  return EFI_SUCCESS;
}


STATIC
EFI_STATUS
EFIAPI
WinNtBlockIoReadBlocks (
  IN EFI_BLOCK_IO_PROTOCOL  *This,
  IN UINT32                 MediaId,
  IN EFI_LBA                Lba,
  IN UINTN                  BufferSize,
  OUT VOID                  *Buffer
  )
/*++

  Routine Description:
    Read BufferSize bytes from Lba into Buffer.

  Arguments:
    This       - Protocol instance pointer.
    MediaId    - Id of the media, changes every time the media is replaced.
    Lba        - The starting Logical Block Address to read from
    BufferSize - Size of Buffer, must be a multiple of device block size.
    Buffer     - Buffer containing read data

  Returns:
    EFI_SUCCES            - The data was read correctly from the device.
    EFI_DEVICE_ERROR      - The device reported an error while performing the read.
    EFI_NO_MEDIA          - There is no media in the device.
    EFI_MEDIA_CHANGED     - The MediaId does not matched the current device.
    EFI_BAD_BUFFER_SIZE   - The Buffer was not a multiple of the block size of the 
                            device.
    EFI_INVALID_PARAMETER - The read request contains device addresses that are not 
                            valid for the device.

--*/
{
  WIN_NT_BLOCK_IO_PRIVATE *Private;
  BOOL                    Flag;
  EFI_STATUS              Status;
  DWORD                   BytesRead;

  Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS(This);

  Status = WinNtBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, FALSE, "WinNtReadBlocks");
  if (EFI_ERROR(Status)) {
    return Status;
  }

  Flag = Private->WinNtThunk->ReadFile (Private->NtHandle, Buffer, (DWORD)BufferSize, (LPDWORD)&BytesRead, NULL);
  if (!Flag || (BytesRead != BufferSize)) {
    DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed. (%d)\n", Private->WinNtThunk->GetLastError()));
    return WinNtBlockIoError (Private);
  }

  //
  // If we wrote then media is present.
  //
  This->Media->MediaPresent = TRUE;
  return EFI_SUCCESS;
}



STATIC
EFI_STATUS
EFIAPI
WinNtBlockIoWriteBlocks (
  IN EFI_BLOCK_IO_PROTOCOL  *This,
  IN UINT32                 MediaId,
  IN EFI_LBA                Lba,
  IN UINTN                  BufferSize,
  IN VOID                   *Buffer
  )
/*++

  Routine Description:
    Write BufferSize bytes from Lba into Buffer.

  Arguments:
    This       - Protocol instance pointer.
    MediaId    - Id of the media, changes every time the media is replaced.
    Lba        - The starting Logical Block Address to read from
    BufferSize - Size of Buffer, must be a multiple of device block size.
    Buffer     - Buffer containing read data

  Returns:
    EFI_SUCCES            - The data was written correctly to the device.
    EFI_WRITE_PROTECTED   - The device can not be written to.
    EFI_DEVICE_ERROR      - The device reported an error while performing the write.
    EFI_NO_MEDIA          - There is no media in the device.
    EFI_MEDIA_CHNAGED     - The MediaId does not matched the current device.
    EFI_BAD_BUFFER_SIZE   - The Buffer was not a multiple of the block size of the 
                            device.
    EFI_INVALID_PARAMETER - The write request contains a LBA that is not 
                            valid for the device.

--*/
{
  WIN_NT_BLOCK_IO_PRIVATE *Private;
  UINTN                   BytesWritten;
  BOOL                    Flag;
  EFI_STATUS              Status;
    
  Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS(This);
  
  Status = WinNtBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, TRUE, "WinNtWriteBlocks");
  if (EFI_ERROR(Status)) {
    return Status;
  }

  Flag = Private->WinNtThunk->WriteFile (Private->NtHandle, Buffer, (DWORD)BufferSize, (LPDWORD)&BytesWritten, NULL);
  if (!Flag || (BytesWritten != BufferSize)) {
    DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed. (%d)\n", Private->WinNtThunk->GetLastError()));
    return WinNtBlockIoError (Private);
  }

  //
  // If the write succeeded, we are not write protected and media is present.
  //
  This->Media->MediaPresent = TRUE;
  This->Media->ReadOnly = FALSE;
  return EFI_SUCCESS;
}


STATIC
EFI_STATUS
EFIAPI
WinNtBlockIoFlushBlocks(
  IN EFI_BLOCK_IO_PROTOCOL  *This
  )
/*++

  Routine Description:
    Flush the Block Device.

  Arguments:
    This             - Protocol instance pointer.

  Returns:
    EFI_SUCCES       - All outstanding data was written to the device
    EFI_DEVICE_ERROR - The device reported an error while writting back the data
    EFI_NO_MEDIA     - There is no media in the device.

--*/
{
  return EFI_SUCCESS;
}


STATIC
EFI_STATUS
EFIAPI
WinNtBlockIoResetBlock(
  IN EFI_BLOCK_IO_PROTOCOL  *This,
  IN BOOLEAN                ExtendedVerification
  )
/*++

  Routine Description:
    Reset the Block Device.

  Arguments:
    This                 - Protocol instance pointer.
    ExtendedVerification - Driver may perform diagnostics on reset.

  Returns:
    EFI_SUCCES            - The device was reset.
    EFI_DEVICE_ERROR      - The device is not functioning properly and could 
                            not be reset.

--*/
{
  WIN_NT_BLOCK_IO_PRIVATE *Private;
    
  Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS(This);

  Private->WinNtThunk->CloseHandle (Private->NtHandle);
  Private->NtHandle = INVALID_HANDLE_VALUE;
    
  return EFI_SUCCESS;
}


UINTN
Atoi (
  CHAR16  *String
  )
/*++

Routine Description:

  Convert a unicode string to a UINTN

Arguments:

  String - Unicode string.

Returns: 

  UINTN of the number represented by String.  

--*/
{
  UINTN   Number;
  CHAR16  *Str;

  //
  // skip preceeding white space
  //
  Str = String;
  while ((*Str) && (*Str == ' ')) {
    Str++;
  }

  //
  // Convert ot a Number
  //
  Number = 0;
  while (*Str != '\0') {
      if ((*Str >= '0') && (*Str <= '9')) {
          Number = (Number * 10) + *Str - '0';
      } else {
          break;
      }
      Str++;
  }

  return Number;
}


EFI_STATUS
SetFilePointer64 (
  IN  WIN_NT_BLOCK_IO_PRIVATE   *Private,
  IN  INT64                     DistanceToMove,
  OUT UINT64                     *NewFilePointer,
  IN  DWORD                     MoveMethod
  )
/*++

This function extends the capability of SetFilePointer to accept 64 bit parameters

--*/
{
  EFI_STATUS      Status;
  LARGE_INTEGER   LargeInt;
  UINT32          ErrorCode;

  LargeInt.QuadPart = DistanceToMove;
  Status = EFI_SUCCESS;
  
  LargeInt.LowPart = Private->WinNtThunk->SetFilePointer(Private->NtHandle, 
                                          LargeInt.LowPart,
                                          &LargeInt.HighPart,
                                          MoveMethod
                                          );
  
  if (LargeInt.LowPart == -1 &&
      (ErrorCode = Private->WinNtThunk->GetLastError()) != NO_ERROR)
  {
    Status = EFI_INVALID_PARAMETER;
  }
  
  if (NewFilePointer != NULL)
  {
    *NewFilePointer = LargeInt.QuadPart;
  }

  return Status;  
}

⌨️ 快捷键说明

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