summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--EmulatorPkg/Win/Host/WinBlockIo.c563
-rw-r--r--EmulatorPkg/Win/Host/WinHost.c1
-rw-r--r--EmulatorPkg/Win/Host/WinHost.h3
-rw-r--r--EmulatorPkg/Win/Host/WinHost.inf3
4 files changed, 570 insertions, 0 deletions
diff --git a/EmulatorPkg/Win/Host/WinBlockIo.c b/EmulatorPkg/Win/Host/WinBlockIo.c
new file mode 100644
index 0000000000..14491a6e90
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinBlockIo.c
@@ -0,0 +1,563 @@
+/**@file
+
+Copyright (c) 2004 - 2018, 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.
+
+**/
+
+#include "WinHost.h"
+
+#define WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE SIGNATURE_32 ('N', 'T', 'b', 'k')
+typedef struct {
+ UINTN Signature;
+
+ EMU_IO_THUNK_PROTOCOL *Thunk;
+
+ CHAR16 *FileName;
+ BOOLEAN Removable;
+ BOOLEAN Readonly;
+
+ HANDLE NtHandle;
+ UINTN BlockSize;
+
+ EFI_BLOCK_IO_MEDIA *Media;
+ EMU_BLOCK_IO_PROTOCOL EmuBlockIo;
+} WIN_NT_BLOCK_IO_PRIVATE;
+
+#define WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS(a) \
+ CR(a, WIN_NT_BLOCK_IO_PRIVATE, EmuBlockIo, WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE)
+
+
+EFI_STATUS
+WinNtBlockIoReset (
+ IN EMU_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+
+
+
+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;
+
+ LargeInt.QuadPart = DistanceToMove;
+ Status = EFI_SUCCESS;
+
+ LargeInt.LowPart = SetFilePointer (
+ Private->NtHandle,
+ LargeInt.LowPart,
+ &LargeInt.HighPart,
+ MoveMethod
+ );
+
+ if (LargeInt.LowPart == -1 && GetLastError () != NO_ERROR) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ if (NewFilePointer != NULL) {
+ *NewFilePointer = LargeInt.QuadPart;
+ }
+
+ return Status;
+}
+
+
+
+EFI_STATUS
+WinNtBlockIoOpenDevice (
+ IN WIN_NT_BLOCK_IO_PRIVATE *Private,
+ IN EFI_BLOCK_IO_MEDIA *Media
+ )
+{
+ EFI_STATUS Status;
+ UINT64 FileSize;
+
+ //
+ // If the device is already opened, close it
+ //
+ if (Private->NtHandle != INVALID_HANDLE_VALUE) {
+ WinNtBlockIoReset (&Private->EmuBlockIo, FALSE);
+ }
+
+ //
+ // Open the device
+ //
+ Private->NtHandle = CreateFile (
+ Private->FileName,
+ GENERIC_READ | (Private->Readonly ? 0 : GENERIC_WRITE),
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS, // Create if it doesn't exist
+ 0,
+ NULL
+ );
+
+ if (Private->NtHandle == INVALID_HANDLE_VALUE) {
+ DEBUG ((EFI_D_INFO, "OpenBlock: Could not open %S, %x\n", Private->FileName, GetLastError ()));
+ Media->MediaPresent = FALSE;
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+
+ //
+ // get the size of the file
+ //
+ Status = SetFilePointer64 (Private, 0, &FileSize, FILE_END);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "OpenBlock: Could not get filesize of %s\n", Private->FileName));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Media->LastBlock = DivU64x32 (FileSize, (UINT32)Private->BlockSize) - 1;
+
+ DEBUG ((EFI_D_INIT, "OpenBlock: opened %S\n", Private->FileName));
+ Status = EFI_SUCCESS;
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if (Private->NtHandle != INVALID_HANDLE_VALUE) {
+ WinNtBlockIoReset (&Private->EmuBlockIo, FALSE);
+ }
+ }
+
+ return Status;
+}
+
+
+EFI_STATUS
+EFIAPI
+WinNtBlockIoCreateMapping (
+ IN EMU_BLOCK_IO_PROTOCOL *This,
+ IN EFI_BLOCK_IO_MEDIA *Media
+ )
+{
+ WIN_NT_BLOCK_IO_PRIVATE *Private;
+
+ Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
+
+ Media->MediaId = 0;
+ Media->RemovableMedia = Private->Removable;
+ Media->MediaPresent = TRUE;
+ Media->LogicalPartition = FALSE;
+ Media->ReadOnly = Private->Readonly;
+ Media->WriteCaching = FALSE;
+ Media->IoAlign = 1;
+ Media->LastBlock = 0; // Filled in by OpenDevice
+ Media->BlockSize = Private->BlockSize;
+
+ // EFI_BLOCK_IO_PROTOCOL_REVISION2
+ Media->LowestAlignedLba = 0;
+ Media->LogicalBlocksPerPhysicalBlock = 0;
+
+
+ // EFI_BLOCK_IO_PROTOCOL_REVISION3
+ Media->OptimalTransferLengthGranularity = 0;
+
+ //
+ // Remember the Media pointer.
+ //
+ Private->Media = Media;
+ return WinNtBlockIoOpenDevice (Private, Media);
+}
+
+
+
+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_MEDIA *Media;
+ EFI_STATUS Status;
+
+ Media = Private->Media;
+
+ switch (GetLastError ()) {
+
+ case ERROR_NOT_READY:
+ Media->ReadOnly = FALSE;
+ Media->MediaPresent = FALSE;
+ Status = EFI_NO_MEDIA;
+ break;
+
+ case ERROR_WRONG_DISK:
+ Media->ReadOnly = FALSE;
+ Media->MediaPresent = TRUE;
+ Media->MediaId++;
+ Status = EFI_MEDIA_CHANGED;
+ break;
+
+ case ERROR_WRITE_PROTECT:
+ Media->ReadOnly = TRUE;
+ Status = EFI_WRITE_PROTECTED;
+ break;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ if (Status == EFI_NO_MEDIA || Status == EFI_MEDIA_CHANGED) {
+ WinNtBlockIoReset (&Private->EmuBlockIo, FALSE);
+ }
+
+ return Status;
+}
+
+
+EFI_STATUS
+WinNtSignalToken (
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN EFI_STATUS Status
+)
+{
+ if (Token != NULL) {
+ if (Token->Event != NULL) {
+ // Caller is responcible for signaling EFI Event
+ Token->TransactionStatus = Status;
+ return EFI_SUCCESS;
+ }
+ }
+ return Status;
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ This function reads the requested number of blocks from the device. All the
+ blocks are read, or an error is returned.
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
+ non-blocking I/O is being used, the Event associated with this request will
+ not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is
+ replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] Buffer A pointer to the destination buffer for the data. The
+ caller is responsible for either having implicit or
+ explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The read request was queued if Token->Event is
+ not NULL.The data was read correctly from the
+ device if the Token->Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+**/
+EFI_STATUS
+WinNtBlockIoReadBlocks (
+ IN EMU_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ WIN_NT_BLOCK_IO_PRIVATE *Private;
+ BOOL Flag;
+ EFI_STATUS Status;
+ DWORD BytesRead;
+ UINT64 DistanceToMove;
+ UINT64 DistanceMoved;
+
+ Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Seek to proper position
+ //
+ DistanceToMove = MultU64x32 (Lba, (UINT32)Private->BlockSize);
+ Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, FILE_BEGIN);
+
+ if (EFI_ERROR (Status) || (DistanceToMove != DistanceMoved)) {
+ DEBUG ((EFI_D_INIT, "ReadBlocks: SetFilePointer failed\n"));
+ return WinNtBlockIoError (Private->Media);
+ }
+
+ Flag = ReadFile (Private->NtHandle, Buffer, (DWORD)BufferSize, (LPDWORD)&BytesRead, NULL);
+ if (!Flag || (BytesRead != BufferSize)) {
+ return WinNtBlockIoError (Private->Media);
+ }
+
+ Private->Media->MediaPresent = TRUE;
+ return WinNtSignalToken (Token, EFI_SUCCESS);
+}
+
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ This function writes the requested number of blocks to the device. All blocks
+ are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
+ EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
+ being used, the Event associated with this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The write request was queued if Event is not NULL.
+ The data was written correctly to the device if
+ the Event is NULL.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+WinNtBlockIoWriteBlocks (
+ IN EMU_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ WIN_NT_BLOCK_IO_PRIVATE *Private;
+ UINTN BytesWritten;
+ BOOL Success;
+ EFI_STATUS Status;
+ UINT64 DistanceToMove;
+ UINT64 DistanceMoved;
+
+ Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Seek to proper position
+ //
+ DistanceToMove = MultU64x32 (Lba, (UINT32)Private->BlockSize);
+ Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, FILE_BEGIN);
+
+ if (EFI_ERROR (Status) || (DistanceToMove != DistanceMoved)) {
+ DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));
+ return WinNtBlockIoError (Private->Media);
+ }
+
+ Success = WriteFile (Private->NtHandle, Buffer, (DWORD)BufferSize, (LPDWORD)&BytesWritten, NULL);
+ if (!Success || (BytesWritten != BufferSize)) {
+ return WinNtBlockIoError (Private->Media);
+ }
+
+ //
+ // If the write succeeded, we are not write protected and media is present.
+ //
+ Private->Media->MediaPresent = TRUE;
+ Private->Media->ReadOnly = FALSE;
+ return WinNtSignalToken (Token, EFI_SUCCESS);
+}
+
+/**
+ Flush the Block Device.
+
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
+ is returned and non-blocking I/O is being used, the Event associated with
+ this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in,out] Token A pointer to the token associated with the transaction
+
+ @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
+ All outstanding data was written correctly to the
+ device if the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back
+ the data.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+WinNtBlockIoFlushBlocks (
+ IN EMU_BLOCK_IO_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ return WinNtSignalToken (Token, EFI_SUCCESS);
+}
+
+
+/**
+ Reset the block device hardware.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ExtendedVerification Indicates that the driver may perform a more
+ exhausive verfication operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+WinNtBlockIoReset (
+ IN EMU_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ WIN_NT_BLOCK_IO_PRIVATE *Private;
+
+ Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
+
+ if (Private->NtHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle (Private->NtHandle);
+ Private->NtHandle = INVALID_HANDLE_VALUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {
+ WinNtBlockIoReset,
+ WinNtBlockIoReadBlocks,
+ WinNtBlockIoWriteBlocks,
+ WinNtBlockIoFlushBlocks,
+ WinNtBlockIoCreateMapping
+};
+
+EFI_STATUS
+EFIAPI
+WinNtBlockIoThunkOpen (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ )
+{
+ WIN_NT_BLOCK_IO_PRIVATE *Private;
+ CHAR16 *Str;
+
+ Private = AllocatePool (sizeof (*Private));
+ if (Private == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Signature = WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE;
+ Private->Thunk = This;
+ CopyMem (&Private->EmuBlockIo, &gEmuBlockIoProtocol, sizeof (gEmuBlockIoProtocol));
+ Private->BlockSize = 512;
+ Private->NtHandle = INVALID_HANDLE_VALUE;
+
+ Private->FileName = AllocateCopyPool (StrSize (This->ConfigString), This->ConfigString);
+ if (Private->FileName == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Parse ConfigString
+ // <ConfigString> := <FileName> ':' [RF][OW] ':' <BlockSize>
+ //
+ Str = StrStr (Private->FileName, L":");
+ if (Str == NULL) {
+ Private->Removable = FALSE;
+ Private->Readonly = FALSE;
+ } else {
+ for (*Str++ = L'\0'; *Str != L'\0'; Str++) {
+ if (*Str == 'R' || *Str == 'F') {
+ Private->Removable = (BOOLEAN) (*Str == L'R');
+ }
+ if (*Str == 'O' || *Str == 'W') {
+ Private->Readonly = (BOOLEAN) (*Str == L'O');
+ }
+ if (*Str == ':') {
+ Private->BlockSize = wcstol (++Str, NULL, 0);
+ break;
+ }
+ }
+ }
+
+ This->Interface = &Private->EmuBlockIo;
+ This->Private = Private;
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+WinNtBlockIoThunkClose (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ )
+{
+ WIN_NT_BLOCK_IO_PRIVATE *Private;
+
+ Private = This->Private;
+
+ if (Private != NULL) {
+ if (Private->FileName != NULL) {
+ FreePool (Private->FileName);
+ }
+ FreePool (Private);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+EMU_IO_THUNK_PROTOCOL mWinNtBlockIoThunkIo = {
+ &gEmuBlockIoProtocolGuid,
+ NULL,
+ NULL,
+ 0,
+ WinNtBlockIoThunkOpen,
+ WinNtBlockIoThunkClose,
+ NULL
+};
+
+
diff --git a/EmulatorPkg/Win/Host/WinHost.c b/EmulatorPkg/Win/Host/WinHost.c
index 266ae59382..0cf02044c2 100644
--- a/EmulatorPkg/Win/Host/WinHost.c
+++ b/EmulatorPkg/Win/Host/WinHost.c
@@ -429,6 +429,7 @@ Returns:
//
AddThunkProtocol (&mWinNtWndThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
AddThunkProtocol (&mWinNtFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);
+ AddThunkProtocol (&mWinNtBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE);
//
// Allocate space for gSystemMemory Array
diff --git a/EmulatorPkg/Win/Host/WinHost.h b/EmulatorPkg/Win/Host/WinHost.h
index 3c7529fa91..6f1f1a2dd3 100644
--- a/EmulatorPkg/Win/Host/WinHost.h
+++ b/EmulatorPkg/Win/Host/WinHost.h
@@ -33,6 +33,8 @@ Abstract:
#include <Protocol/EmuThunk.h>
#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/EmuBlockIo.h>
+#include <Protocol/BlockIo.h>
#include <Library/BaseLib.h>
#include <Library/PeCoffLib.h>
@@ -203,4 +205,5 @@ SecInitializeThunk (
extern EMU_THUNK_PROTOCOL gEmuThunkProtocol;
extern EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo;
extern EMU_IO_THUNK_PROTOCOL mWinNtFileSystemThunkIo;
+extern EMU_IO_THUNK_PROTOCOL mWinNtBlockIoThunkIo;
#endif \ No newline at end of file
diff --git a/EmulatorPkg/Win/Host/WinHost.inf b/EmulatorPkg/Win/Host/WinHost.inf
index 358d000857..501edac15e 100644
--- a/EmulatorPkg/Win/Host/WinHost.inf
+++ b/EmulatorPkg/Win/Host/WinHost.inf
@@ -34,6 +34,7 @@
WinGopScreen.c
WinGop.h
WinFileSystem.c
+ WinBlockIo.c
WinThunk.c
WinHost.h
WinHost.c
@@ -62,6 +63,7 @@
[Protocols]
gEmuIoThunkProtocolGuid
gEmuGraphicsWindowProtocolGuid
+ gEmuBlockIoProtocolGuid
gEfiSimpleFileSystemProtocolGuid
[Guids]
@@ -76,6 +78,7 @@
gEmulatorPkgTokenSpaceGuid.PcdEmuFirmwareVolume
gEmulatorPkgTokenSpaceGuid.PcdEmuMemorySize
gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress
+ gEmulatorPkgTokenSpaceGuid.PcdEmuVirtualDisk
gEmulatorPkgTokenSpaceGuid.PcdEmuGop|L"GOP Window"
gEmulatorPkgTokenSpaceGuid.PcdEmuFileSystem
gEmulatorPkgTokenSpaceGuid.PcdPeiServicesTablePage