mirror of https://github.com/acidanthera/audk.git
1132 lines
31 KiB
C
1132 lines
31 KiB
C
/**@file
|
|
|
|
Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
Module Name:
|
|
|
|
WinNtBlockIo.c
|
|
|
|
Abstract:
|
|
|
|
Produce block IO abstractions for real devices on your PC using Win32 APIs.
|
|
The configuration of what devices to mount or emulate comes from NT
|
|
environment variables. The variables must be visible to the Microsoft*
|
|
Developer Studio for them to work.
|
|
|
|
<F>ixed - Fixed disk like a hard drive.
|
|
<R>emovable - Removable media like a floppy or CD-ROM.
|
|
Read <O>nly - Write protected device.
|
|
Read <W>rite - Read write device.
|
|
<block count> - Decimal number of blocks a device supports.
|
|
<block size> - Decimal number of bytes per block.
|
|
|
|
NT envirnonment variable contents. '<' and '>' are not part of the variable,
|
|
they are just used to make this help more readable. There should be no
|
|
spaces between the ';'. Extra spaces will break the variable. A '!' is
|
|
used to seperate multiple devices in a variable.
|
|
|
|
EFI_WIN_NT_VIRTUAL_DISKS =
|
|
<F | R><O | W>;<block count>;<block size>[!...]
|
|
|
|
EFI_WIN_NT_PHYSICAL_DISKS =
|
|
<drive letter>:<F | R><O | W>;<block count>;<block size>[!...]
|
|
|
|
Virtual Disks: These devices use a file to emulate a hard disk or removable
|
|
media device.
|
|
|
|
Thus a 20 MB emulated hard drive would look like:
|
|
EFI_WIN_NT_VIRTUAL_DISKS=FW;40960;512
|
|
|
|
A 1.44MB emulated floppy with a block size of 1024 would look like:
|
|
EFI_WIN_NT_VIRTUAL_DISKS=RW;1440;1024
|
|
|
|
Physical Disks: These devices use NT to open a real device in your system
|
|
|
|
Thus a 120 MB floppy would look like:
|
|
EFI_WIN_NT_PHYSICAL_DISKS=B:RW;245760;512
|
|
|
|
Thus a standard CD-ROM floppy would look like:
|
|
EFI_WIN_NT_PHYSICAL_DISKS=Z:RO;307200;2048
|
|
|
|
|
|
* Other names and brands may be claimed as the property of others.
|
|
|
|
**/
|
|
#include <Uefi.h>
|
|
#include <WinNtDxe.h>
|
|
#include <Protocol/WinNtThunk.h>
|
|
#include <Protocol/WinNtIo.h>
|
|
#include <Protocol/BlockIo.h>
|
|
#include <Protocol/ComponentName.h>
|
|
#include <Protocol/DriverBinding.h>
|
|
//
|
|
// The Library classes this module consumes
|
|
//
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/UefiDriverEntryPoint.h>
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
|
|
#include "WinNtBlockIo.h"
|
|
|
|
EFI_DRIVER_BINDING_PROTOCOL gWinNtBlockIoDriverBinding = {
|
|
WinNtBlockIoDriverBindingSupported,
|
|
WinNtBlockIoDriverBindingStart,
|
|
WinNtBlockIoDriverBindingStop,
|
|
0xa,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
/**
|
|
The user Entry Point for module WinNtBlockIo. The user code starts with this function.
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
@retval other Some error occurs when executing this entry point.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InitializeWinNtBlockIo(
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Install driver model protocol(s).
|
|
//
|
|
Status = EfiLibInstallAllDriverProtocols2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&gWinNtBlockIoDriverBinding,
|
|
ImageHandle,
|
|
&gWinNtBlockIoComponentName,
|
|
&gWinNtBlockIoComponentName2,
|
|
NULL,
|
|
NULL,
|
|
&gWinNtBlockIoDriverDiagnostics,
|
|
&gWinNtBlockIoDriverDiagnostics2
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtBlockIoDriverBindingSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: This - add argument and description to function comment
|
|
// TODO: Handle - add argument and description to function comment
|
|
// TODO: RemainingDevicePath - add argument and description to function comment
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_WIN_NT_IO_PROTOCOL *WinNtIo;
|
|
|
|
//
|
|
// Open the IO Abstraction(s) needed to perform the supported test
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
(VOID **) &WinNtIo,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Make sure the WinNtThunkProtocol is valid
|
|
//
|
|
Status = EFI_UNSUPPORTED;
|
|
if (WinNtIo->WinNtThunk->Signature == EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) {
|
|
|
|
//
|
|
// Check the GUID to see if this is a handle type the driver supports
|
|
//
|
|
if (CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtVirtualDisksGuid) ||
|
|
CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtPhysicalDisksGuid) ) {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Close the I/O Abstraction(s) used to perform the supported test
|
|
//
|
|
gBS->CloseProtocol (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Handle
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtBlockIoDriverBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: This - add argument and description to function comment
|
|
// TODO: Handle - add argument and description to function comment
|
|
// TODO: RemainingDevicePath - add argument and description to function comment
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_WIN_NT_IO_PROTOCOL *WinNtIo;
|
|
WIN_NT_RAW_DISK_DEVICE_TYPE DiskType;
|
|
UINT16 Buffer[FILENAME_BUFFER_SIZE];
|
|
CHAR16 *Str;
|
|
BOOLEAN RemovableMedia;
|
|
BOOLEAN WriteProtected;
|
|
UINTN NumberOfBlocks;
|
|
UINTN BlockSize;
|
|
|
|
//
|
|
// Grab the protocols we need
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
(VOID **) &WinNtIo,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Set DiskType
|
|
//
|
|
if (CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtVirtualDisksGuid)) {
|
|
DiskType = EfiWinNtVirtualDisks;
|
|
} else if (CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtPhysicalDisksGuid)) {
|
|
DiskType = EfiWinNtPhysicalDisks;
|
|
} else {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Done;
|
|
}
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
Str = WinNtIo->EnvString;
|
|
if (DiskType == EfiWinNtVirtualDisks) {
|
|
WinNtIo->WinNtThunk->SPrintf (
|
|
Buffer,
|
|
sizeof (Buffer),
|
|
L"Diskfile%d",
|
|
WinNtIo->InstanceNumber
|
|
);
|
|
} else {
|
|
if (*Str >= 'A' && *Str <= 'Z' || *Str >= 'a' && *Str <= 'z') {
|
|
WinNtIo->WinNtThunk->SPrintf (Buffer, sizeof (Buffer), L"\\\\.\\%c:", *Str);
|
|
} else {
|
|
WinNtIo->WinNtThunk->SPrintf (Buffer, sizeof (Buffer), L"\\\\.\\PHYSICALDRIVE%c", *Str);
|
|
}
|
|
|
|
Str++;
|
|
if (*Str != ':') {
|
|
Status = EFI_NOT_FOUND;
|
|
goto Done;
|
|
}
|
|
|
|
Str++;
|
|
}
|
|
|
|
if (*Str == 'R' || *Str == 'F') {
|
|
RemovableMedia = (BOOLEAN) (*Str == 'R');
|
|
Str++;
|
|
if (*Str == 'O' || *Str == 'W') {
|
|
WriteProtected = (BOOLEAN) (*Str == 'O');
|
|
Str = GetNextElementPastTerminator (Str, ';');
|
|
|
|
NumberOfBlocks = StrDecimalToUintn (Str);
|
|
if (NumberOfBlocks != 0) {
|
|
Str = GetNextElementPastTerminator (Str, ';');
|
|
BlockSize = StrDecimalToUintn (Str);
|
|
if (BlockSize != 0) {
|
|
//
|
|
// If we get here the variable is valid so do the work.
|
|
//
|
|
Status = WinNtBlockIoCreateMapping (
|
|
WinNtIo,
|
|
Handle,
|
|
Buffer,
|
|
WriteProtected,
|
|
RemovableMedia,
|
|
NumberOfBlocks,
|
|
BlockSize,
|
|
DiskType
|
|
);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->CloseProtocol (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Handle
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtBlockIoDriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Handle,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
This - TODO: add argument description
|
|
Handle - TODO: add argument description
|
|
NumberOfChildren - TODO: add argument description
|
|
ChildHandleBuffer - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_UNSUPPORTED - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
|
EFI_STATUS Status;
|
|
WIN_NT_BLOCK_IO_PRIVATE *Private;
|
|
|
|
//
|
|
// Get our context back
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
(VOID **) &BlockIo,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (BlockIo);
|
|
|
|
//
|
|
// BugBug: If we need to kick people off, we need to make Uninstall Close the handles.
|
|
// We could pass in our image handle or FLAG our open to be closed via
|
|
// Unistall (== to saying any CloseProtocol will close our open)
|
|
//
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
Private->EfiHandle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
&Private->BlockIo,
|
|
NULL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
Status = gBS->CloseProtocol (
|
|
Handle,
|
|
&gEfiWinNtIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Handle
|
|
);
|
|
|
|
//
|
|
// Shut down our device
|
|
//
|
|
Private->WinNtThunk->CloseHandle (Private->NtHandle);
|
|
|
|
//
|
|
// Free our instance data
|
|
//
|
|
FreeUnicodeStringTable (Private->ControllerNameTable);
|
|
|
|
FreePool (Private);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
|
|
Private = AllocatePool (sizeof (WIN_NT_BLOCK_IO_PRIVATE));
|
|
ASSERT (Private != NULL);
|
|
|
|
EfiInitializeLock (&Private->Lock, 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;
|
|
|
|
AddUnicodeString2 (
|
|
"eng",
|
|
gWinNtBlockIoComponentName.SupportedLanguages,
|
|
&Private->ControllerNameTable,
|
|
Private->Filename,
|
|
TRUE
|
|
);
|
|
AddUnicodeString2 (
|
|
"en",
|
|
gWinNtBlockIoComponentName2.SupportedLanguages,
|
|
&Private->ControllerNameTable,
|
|
Private->Filename,
|
|
FALSE
|
|
);
|
|
|
|
|
|
BlockIo = &Private->BlockIo;
|
|
BlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
|
|
BlockIo->Media = &Private->Media;
|
|
BlockIo->Media->BlockSize = (UINT32)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)) {
|
|
FreeUnicodeStringTable (Private->ControllerNameTable);
|
|
FreePool (Private);
|
|
}
|
|
|
|
DEBUG ((EFI_D_INIT, "BlockDevice added: %s\n", Filename));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
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,
|
|
(DWORD)Private->ReadMode,
|
|
(DWORD)Private->ShareMode,
|
|
NULL,
|
|
(DWORD)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, (UINT32)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, (UINT32)Private->BlockSize);
|
|
}
|
|
|
|
EndOfFile = MultU64x32 (Private->NumberOfBlocks, (UINT32)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;
|
|
}
|
|
|
|
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
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
WinNtBlockIoReadWriteCommon (
|
|
IN WIN_NT_BLOCK_IO_PRIVATE *Private,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA Lba,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer,
|
|
IN CHAR8 *CallerName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
Private - TODO: add argument description
|
|
MediaId - TODO: add argument description
|
|
Lba - TODO: add argument description
|
|
BufferSize - TODO: add argument description
|
|
Buffer - TODO: add argument description
|
|
CallerName - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
EFI_NO_MEDIA - TODO: Add description for return value
|
|
EFI_MEDIA_CHANGED - TODO: Add description for return value
|
|
EFI_INVALID_PARAMETER - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
EFI_BAD_BUFFER_SIZE - TODO: Add description for return value
|
|
EFI_INVALID_PARAMETER - TODO: Add description for return value
|
|
EFI_SUCCESS - TODO: Add description for return value
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BlockSize;
|
|
UINT64 LastBlock;
|
|
INT64 DistanceToMove;
|
|
UINT64 DistanceMoved;
|
|
|
|
if (Private->NtHandle == INVALID_HANDLE_VALUE) {
|
|
Status = WinNtBlockIoOpenDevice (Private);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (!Private->Media.MediaPresent) {
|
|
DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));
|
|
return EFI_NO_MEDIA;
|
|
}
|
|
|
|
if (Private->Media.MediaId != MediaId) {
|
|
return EFI_MEDIA_CHANGED;
|
|
}
|
|
|
|
if ((UINTN) Buffer % Private->Media.IoAlign != 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Verify buffer size
|
|
//
|
|
BlockSize = Private->BlockSize;
|
|
if (BufferSize == 0) {
|
|
DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if ((BufferSize % BlockSize) != 0) {
|
|
DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
}
|
|
|
|
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;
|
|
}
|
|
//
|
|
// Seek to End of File
|
|
//
|
|
DistanceToMove = MultU64x32 (Lba, (UINT32)BlockSize);
|
|
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;
|
|
}
|
|
|
|
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_SUCCESS - 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;
|
|
EFI_TPL OldTpl;
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
|
|
Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
Status = WinNtBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "WinNtReadBlocks");
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
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 ()));
|
|
Status = WinNtBlockIoError (Private);
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// If we wrote then media is present.
|
|
//
|
|
This->Media->MediaPresent = TRUE;
|
|
Status = EFI_SUCCESS;
|
|
|
|
Done:
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
}
|
|
|
|
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_SUCCESS - 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;
|
|
BOOL Locked;
|
|
EFI_STATUS Status;
|
|
EFI_TPL OldTpl;
|
|
UINTN BytesReturned;
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
|
|
Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
Status = WinNtBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "WinNtWriteBlocks");
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// According the Windows requirement, first need to lock the volume before
|
|
// write to it.
|
|
//
|
|
if (Private->DeviceType == EfiWinNtPhysicalDisks) {
|
|
Locked = Private->WinNtThunk->DeviceIoControl (Private->NtHandle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &BytesReturned, NULL);
|
|
if (Locked == 0) {
|
|
DEBUG ((EFI_D_INIT, "ReadBlocks: Lock volume failed. (%d)\n", Private->WinNtThunk->GetLastError ()));
|
|
Status = WinNtBlockIoError (Private);
|
|
goto Done;
|
|
}
|
|
} else {
|
|
Locked = 0;
|
|
}
|
|
Flag = Private->WinNtThunk->WriteFile (Private->NtHandle, Buffer, (DWORD) BufferSize, (LPDWORD) &BytesWritten, NULL);
|
|
if (Locked != 0) {
|
|
Private->WinNtThunk->DeviceIoControl (Private->NtHandle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &BytesReturned, NULL);
|
|
}
|
|
if (!Flag || (BytesWritten != BufferSize)) {
|
|
DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed. (%d)\n", Private->WinNtThunk->GetLastError ()));
|
|
Status = WinNtBlockIoError (Private);
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// If the write succeeded, we are not write protected and media is present.
|
|
//
|
|
This->Media->MediaPresent = TRUE;
|
|
This->Media->ReadOnly = FALSE;
|
|
Status = EFI_SUCCESS;
|
|
|
|
Done:
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
WinNtBlockIoFlushBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Flush the Block Device.
|
|
|
|
Arguments:
|
|
This - Protocol instance pointer.
|
|
|
|
Returns:
|
|
EFI_SUCCESS - 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;
|
|
}
|
|
|
|
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_SUCCESS - The device was reset.
|
|
EFI_DEVICE_ERROR - The device is not functioning properly and could
|
|
not be reset.
|
|
|
|
--*/
|
|
{
|
|
WIN_NT_BLOCK_IO_PRIVATE *Private;
|
|
EFI_TPL OldTpl;
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
|
|
Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
if (Private->NtHandle != INVALID_HANDLE_VALUE) {
|
|
Private->WinNtThunk->CloseHandle (Private->NtHandle);
|
|
Private->NtHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
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
|
|
|
|
--*/
|
|
// TODO: function comment is missing 'Routine Description:'
|
|
// TODO: function comment is missing 'Arguments:'
|
|
// TODO: function comment is missing 'Returns:'
|
|
// TODO: Private - add argument and description to function comment
|
|
// TODO: DistanceToMove - add argument and description to function comment
|
|
// TODO: NewFilePointer - add argument and description to function comment
|
|
// TODO: MoveMethod - add argument and description to function comment
|
|
{
|
|
EFI_STATUS Status;
|
|
LARGE_INTEGER LargeInt;
|
|
|
|
LargeInt.QuadPart = DistanceToMove;
|
|
Status = EFI_SUCCESS;
|
|
|
|
LargeInt.LowPart = Private->WinNtThunk->SetFilePointer (
|
|
Private->NtHandle,
|
|
LargeInt.LowPart,
|
|
&LargeInt.HighPart,
|
|
MoveMethod
|
|
);
|
|
|
|
if (LargeInt.LowPart == -1 && Private->WinNtThunk->GetLastError () != NO_ERROR) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (NewFilePointer != NULL) {
|
|
*NewFilePointer = LargeInt.QuadPart;
|
|
}
|
|
|
|
return Status;
|
|
}
|