aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/EmulatorPkg/Win
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/EmulatorPkg/Win')
-rw-r--r--roms/edk2/EmulatorPkg/Win/Host/WinBlockIo.c557
-rw-r--r--roms/edk2/EmulatorPkg/Win/Host/WinFileSystem.c2445
-rw-r--r--roms/edk2/EmulatorPkg/Win/Host/WinGop.h204
-rw-r--r--roms/edk2/EmulatorPkg/Win/Host/WinGopInput.c447
-rw-r--r--roms/edk2/EmulatorPkg/Win/Host/WinGopScreen.c827
-rw-r--r--roms/edk2/EmulatorPkg/Win/Host/WinHost.c1097
-rw-r--r--roms/edk2/EmulatorPkg/Win/Host/WinHost.h208
-rw-r--r--roms/edk2/EmulatorPkg/Win/Host/WinHost.inf110
-rw-r--r--roms/edk2/EmulatorPkg/Win/Host/WinInclude.h70
-rw-r--r--roms/edk2/EmulatorPkg/Win/Host/WinMemoryAllocationLib.c172
-rw-r--r--roms/edk2/EmulatorPkg/Win/Host/WinPacketFilter.c1135
-rw-r--r--roms/edk2/EmulatorPkg/Win/Host/WinThunk.c580
-rw-r--r--roms/edk2/EmulatorPkg/Win/VS2017/BuildVS.bat3
-rw-r--r--roms/edk2/EmulatorPkg/Win/VS2017/Win.sln25
-rw-r--r--roms/edk2/EmulatorPkg/Win/VS2017/Win.vcxproj120
-rw-r--r--roms/edk2/EmulatorPkg/Win/VS2017/Win.vcxproj.filters50
-rw-r--r--roms/edk2/EmulatorPkg/Win/VS2017/Win.vcxproj.user13
17 files changed, 8063 insertions, 0 deletions
diff --git a/roms/edk2/EmulatorPkg/Win/Host/WinBlockIo.c b/roms/edk2/EmulatorPkg/Win/Host/WinBlockIo.c
new file mode 100644
index 000000000..715d0c26c
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/Host/WinBlockIo.c
@@ -0,0 +1,557 @@
+/**@file
+
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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;
+ UINT32 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_CHANGED The MediaId does not match 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 writing 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/roms/edk2/EmulatorPkg/Win/Host/WinFileSystem.c b/roms/edk2/EmulatorPkg/Win/Host/WinFileSystem.c
new file mode 100644
index 000000000..f6b06b1c9
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/Host/WinFileSystem.c
@@ -0,0 +1,2445 @@
+/*++ @file
+ Support OS native directory access.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "WinHost.h"
+
+
+#define WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE SIGNATURE_32 ('N', 'T', 'f', 's')
+
+typedef struct {
+ UINTN Signature;
+ EMU_IO_THUNK_PROTOCOL *Thunk;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFileSystem;
+ CHAR16 *FilePath;
+ CHAR16 *VolumeLabel;
+} WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE;
+
+#define WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE, \
+ SimpleFileSystem, \
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \
+ )
+
+
+#define WIN_NT_EFI_FILE_PRIVATE_SIGNATURE SIGNATURE_32 ('l', 'o', 'f', 's')
+
+typedef struct {
+ UINTN Signature;
+ EMU_IO_THUNK_PROTOCOL *Thunk;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
+ EFI_FILE_PROTOCOL EfiFile;
+ HANDLE LHandle;
+ HANDLE DirHandle;
+ BOOLEAN IsRootDirectory;
+ BOOLEAN IsDirectoryPath;
+ BOOLEAN IsOpenedByRead;
+ CHAR16 *FilePath;
+ WCHAR *FileName;
+ BOOLEAN IsValidFindBuf;
+ WIN32_FIND_DATA FindBuf;
+} WIN_NT_EFI_FILE_PRIVATE;
+
+#define WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ WIN_NT_EFI_FILE_PRIVATE, \
+ EfiFile, \
+ WIN_NT_EFI_FILE_PRIVATE_SIGNATURE \
+ )
+
+extern EFI_FILE_PROTOCOL gWinNtFileProtocol;
+extern EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gWinNtFileSystemProtocol;
+
+EFI_STATUS
+WinNtFileGetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+EFI_STATUS
+WinNtFileSetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+
+
+CHAR16 *
+EfiStrChr (
+ IN CHAR16 *Str,
+ IN CHAR16 Chr
+)
+/*++
+
+Routine Description:
+
+ Locate the first occurance of a character in a string.
+
+Arguments:
+
+ Str - Pointer to NULL terminated unicode string.
+ Chr - Character to locate.
+
+Returns:
+
+ If Str is NULL, then NULL is returned.
+ If Chr is not contained in Str, then NULL is returned.
+ If Chr is contained in Str, then a pointer to the first occurance of Chr in Str is returned.
+
+--*/
+{
+ if (Str == NULL) {
+ return Str;
+ }
+
+ while (*Str != '\0' && *Str != Chr) {
+ ++Str;
+ }
+
+ return (*Str == Chr) ? Str : NULL;
+}
+
+
+
+BOOLEAN
+IsZero (
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ if (Buffer == NULL || Length == 0) {
+ return FALSE;
+ }
+
+ if (*(UINT8 *) Buffer != 0) {
+ return FALSE;
+ }
+
+ if (Length > 1) {
+ if (!CompareMem (Buffer, (UINT8 *) Buffer + 1, Length - 1)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+VOID
+CutPrefix (
+ IN CHAR16 *Str,
+ IN UINTN Count
+ )
+{
+ CHAR16 *Pointer;
+
+ if (StrLen (Str) < Count) {
+ ASSERT (0);
+ }
+
+ if (Count != 0) {
+ for (Pointer = Str; *(Pointer + Count); Pointer++) {
+ *Pointer = *(Pointer + Count);
+ }
+
+ *Pointer = *(Pointer + Count);
+ }
+}
+/**
+ Open the root directory on a volume.
+
+ @param This Protocol instance pointer.
+ @param Root Returns an Open file handle for the root directory
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_UNSUPPORTED This volume does not support the file system.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
+
+**/
+EFI_STATUS
+WinNtOpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **Root
+ )
+{
+ EFI_STATUS Status;
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;
+ CHAR16 *TempFileName;
+ UINTN Size;
+
+ if (This == NULL || Root == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ 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;
+ }
+
+ StrCpyS (PrivateFile->FilePath,
+ StrSize (Private->FilePath) / sizeof (CHAR16),
+ Private->FilePath
+ );
+ StrCpyS (PrivateFile->FileName,
+ StrSize (Private->FilePath) / sizeof (CHAR16),
+ PrivateFile->FilePath
+ );
+ PrivateFile->Signature = WIN_NT_EFI_FILE_PRIVATE_SIGNATURE;
+ PrivateFile->Thunk = Private->Thunk;
+ PrivateFile->SimpleFileSystem = This;
+ PrivateFile->IsRootDirectory = TRUE;
+ PrivateFile->IsDirectoryPath = TRUE;
+ PrivateFile->IsOpenedByRead = TRUE;
+ CopyMem (&PrivateFile->EfiFile, &gWinNtFileProtocol, sizeof (gWinNtFileProtocol));
+ PrivateFile->IsValidFindBuf = FALSE;
+
+ //
+ // Set DirHandle
+ //
+ PrivateFile->DirHandle = 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"\\*");
+ TempFileName = AllocatePool (Size);
+ if (TempFileName == NULL) {
+ goto Done;
+ }
+ StrCpyS (TempFileName, Size / sizeof (CHAR16), PrivateFile->FilePath);
+ StrCatS (TempFileName, Size / sizeof (CHAR16), L"\\*");
+
+ PrivateFile->LHandle = 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);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Count the number of Leading Dot in FileNameToken.
+
+ @param FileNameToken A string representing a token in the path name.
+
+ @return UINTN The number of leading dot in the name.
+
+**/
+UINTN
+CountLeadingDots (
+ IN CONST CHAR16 * FileNameToken
+)
+{
+ UINTN Num;
+
+ Num = 0;
+ while (*FileNameToken == L'.') {
+ Num++;
+ FileNameToken++;
+ }
+
+ return Num;
+}
+
+
+BOOLEAN
+IsFileNameTokenValid (
+ IN CONST CHAR16 * FileNameToken
+)
+{
+ UINTN Num;
+ if (StrStr (FileNameToken, L"/") != NULL) {
+ //
+ // No L'/' in file name.
+ //
+ return FALSE;
+ } else {
+ //
+ // If Token has all dot, the number should not exceed 2
+ //
+ Num = CountLeadingDots (FileNameToken);
+
+ if (Num == StrLen (FileNameToken)) {
+ //
+ // If the FileNameToken only contains a number of L'.'.
+ //
+ if (Num > 2) {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Return the first string token found in the indirect pointer a String named by FileName.
+
+ On input, FileName is a indirect pointer pointing to a String.
+ On output, FileName is a updated to point to the next character after the first
+ found L"\" or NULL if there is no L"\" found.
+
+ @param FileName A indirect pointer pointing to a FileName.
+
+ @return Token The first string token found before a L"\".
+
+**/
+CHAR16 *
+GetNextFileNameToken (
+ IN OUT CONST CHAR16 ** FileName
+)
+{
+ CHAR16 *SlashPos;
+ CHAR16 *Token;
+ UINTN Offset;
+ ASSERT (**FileName != L'\\');
+ ASSERT (**FileName != L'\0');
+
+ SlashPos = StrStr (*FileName, L"\\");
+ if (SlashPos == NULL) {
+ Token = AllocateCopyPool (StrSize (*FileName), *FileName);
+ *FileName = NULL;
+ } else {
+ Offset = SlashPos - *FileName;
+ Token = AllocateZeroPool ((Offset + 1) * sizeof (CHAR16));
+ StrnCpyS (Token, Offset + 1, *FileName, Offset);
+ //
+ // Point *FileName to the next character after L'\'.
+ //
+ *FileName = *FileName + Offset + 1;
+ //
+ // If *FileName is an empty string, then set *FileName to NULL
+ //
+ if (**FileName == L'\0') {
+ *FileName = NULL;
+ }
+ }
+
+ return Token;
+}
+
+
+/**
+ Check if a FileName contains only Valid Characters.
+
+ If FileName contains only a single L'\', return TRUE.
+ If FileName contains two adjacent L'\', return FALSE.
+ If FileName conatins L'/' , return FALSE.
+ If FileName contains more than two dots separated with other FileName characters
+ by L'\', return FALSE. For example, L'.\...\filename.txt' is invalid path name. But L'..TwoDots\filename.txt' is valid path name.
+
+ @param FileName The File Name String to check.
+
+ @return TRUE FileName only contains valid characters.
+ @return FALSE FileName contains at least one invalid character.
+
+**/
+
+BOOLEAN
+IsFileNameValid (
+ IN CONST CHAR16 *FileName
+ )
+{
+ CHAR16 *Token;
+ BOOLEAN Valid;
+
+ //
+ // If FileName is just L'\', then it is a valid pathname.
+ //
+ if (StrCmp (FileName, L"\\") == 0) {
+ return TRUE;
+ }
+ //
+ // We don't support two or more adjacent L'\'.
+ //
+ if (StrStr (FileName, L"\\\\") != NULL) {
+ return FALSE;
+ }
+
+ //
+ // Is FileName has a leading L"\", skip to next character.
+ //
+ if (FileName [0] == L'\\') {
+ FileName++;
+ }
+
+ do {
+ Token = GetNextFileNameToken (&FileName);
+ Valid = IsFileNameTokenValid (Token);
+ FreePool (Token);
+
+ if (!Valid)
+ return FALSE;
+ } while (FileName != NULL);
+
+ return TRUE;
+}
+
+
+/**
+ Opens a new file relative to the source file's location.
+
+ @param This The protocol instance pointer.
+ @param NewHandle Returns File Handle for FileName.
+ @param FileName Null terminated string. "\", ".", and ".." are supported.
+ @param OpenMode Open mode for file.
+ @param Attributes Only used for EFI_FILE_MODE_CREATE.
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_NOT_FOUND The specified file could not be found on the device.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_MEDIA_CHANGED The media has changed.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+WinNtFileOpen (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+{
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;
+ WIN_NT_EFI_FILE_PRIVATE *NewPrivateFile;
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
+ EFI_STATUS Status;
+ CHAR16 *RealFileName;
+ CHAR16 *TempFileName;
+ CHAR16 *ParseFileName;
+ CHAR16 *GuardPointer;
+ CHAR16 TempChar;
+ DWORD LastError;
+ UINTN Count;
+ BOOLEAN LoopFinish;
+ UINTN InfoSize;
+ EFI_FILE_INFO *Info;
+ UINTN Size;
+
+
+ //
+ // Init local variables
+ //
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+ PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
+ NewPrivateFile = NULL;
+
+ //
+ // Allocate buffer for FileName as the passed in FileName may be read only
+ //
+ TempFileName = AllocatePool (StrSize (FileName));
+ if (TempFileName == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StrCpyS (TempFileName, StrSize (FileName) / sizeof (CHAR16), FileName);
+ FileName = TempFileName;
+
+ if (FileName[StrLen (FileName) - 1] == L'\\') {
+ FileName[StrLen (FileName) - 1] = 0;
+ }
+
+ //
+ // If file name does not equal to "." or ".." and not trailed with "\..",
+ // then we trim the leading/trailing blanks and trailing dots
+ //
+ if (StrCmp (FileName, L".") != 0 && StrCmp (FileName, L"..") != 0 &&
+ ((StrLen (FileName) >= 3) ? (StrCmp (&FileName[StrLen (FileName) - 3], L"\\..") != 0) : TRUE)) {
+ //
+ // Trim leading blanks
+ //
+ Count = 0;
+ for (TempFileName = FileName;
+ *TempFileName != 0 && *TempFileName == L' ';
+ TempFileName++) {
+ Count++;
+ }
+ CutPrefix (FileName, Count);
+ //
+ // Trim trailing blanks
+ //
+ for (TempFileName = FileName + StrLen (FileName) - 1;
+ TempFileName >= FileName && (*TempFileName == L' ');
+ TempFileName--) {
+ ;
+ }
+ *(TempFileName + 1) = 0;
+ }
+
+ //
+ // Attempt to open the file
+ //
+ NewPrivateFile = AllocatePool (sizeof (WIN_NT_EFI_FILE_PRIVATE));
+ if (NewPrivateFile == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ CopyMem (NewPrivateFile, PrivateFile, sizeof (WIN_NT_EFI_FILE_PRIVATE));
+
+ NewPrivateFile->FilePath = AllocatePool (StrSize (PrivateFile->FileName));
+ if (NewPrivateFile->FilePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ if (PrivateFile->IsDirectoryPath) {
+ StrCpyS (
+ NewPrivateFile->FilePath,
+ StrSize (PrivateFile->FileName) / sizeof (CHAR16),
+ PrivateFile->FileName
+ );
+ } else {
+ StrCpyS (
+ NewPrivateFile->FilePath,
+ StrSize (PrivateFile->FileName) / sizeof (CHAR16),
+ PrivateFile->FilePath
+ );
+ }
+
+ Size = StrSize (NewPrivateFile->FilePath);
+ Size += StrSize (L"\\");
+ Size += StrSize (FileName);
+ NewPrivateFile->FileName = AllocatePool (Size);
+ if (NewPrivateFile->FileName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ if (*FileName == L'\\') {
+ StrCpyS (NewPrivateFile->FileName, Size / sizeof (CHAR16), PrivateRoot->FilePath);
+ StrCatS (NewPrivateFile->FileName, Size / sizeof (CHAR16), L"\\");
+ StrCatS (NewPrivateFile->FileName, Size / sizeof (CHAR16), FileName + 1);
+ } else {
+ StrCpyS (NewPrivateFile->FileName, Size / sizeof (CHAR16), NewPrivateFile->FilePath);
+ if (StrCmp (FileName, L"") != 0) {
+ //
+ // In case the filename becomes empty, especially after trimming dots and blanks
+ //
+ StrCatS (NewPrivateFile->FileName, Size / sizeof (CHAR16), L"\\");
+ StrCatS (NewPrivateFile->FileName, Size / sizeof (CHAR16), FileName);
+ }
+ }
+
+ if (!IsFileNameValid (NewPrivateFile->FileName)) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Get rid of . and .., except leading . or ..
+ //
+
+ //
+ // GuardPointer protect simplefilesystem root path not be destroyed
+ //
+ GuardPointer = NewPrivateFile->FileName + StrLen (PrivateRoot->FilePath);
+
+ LoopFinish = FALSE;
+
+ while (!LoopFinish) {
+
+ LoopFinish = TRUE;
+
+ for (ParseFileName = GuardPointer; *ParseFileName; ParseFileName++) {
+ if (*ParseFileName == L'.' &&
+ (*(ParseFileName + 1) == 0 || *(ParseFileName + 1) == L'\\') &&
+ *(ParseFileName - 1) == L'\\'
+ ) {
+
+ //
+ // cut \.
+ //
+ CutPrefix (ParseFileName - 1, 2);
+ LoopFinish = FALSE;
+ break;
+ }
+
+ if (*ParseFileName == L'.' &&
+ *(ParseFileName + 1) == L'.' &&
+ (*(ParseFileName + 2) == 0 || *(ParseFileName + 2) == L'\\') &&
+ *(ParseFileName - 1) == L'\\'
+ ) {
+
+ ParseFileName--;
+ Count = 3;
+
+ while (ParseFileName != GuardPointer) {
+ ParseFileName--;
+ Count++;
+ if (*ParseFileName == L'\\') {
+ break;
+ }
+ }
+
+ //
+ // cut \.. and its left directory
+ //
+ CutPrefix (ParseFileName, Count);
+ LoopFinish = FALSE;
+ break;
+ }
+ }
+ }
+
+ RealFileName = NewPrivateFile->FileName;
+ while (EfiStrChr (RealFileName, L'\\') != NULL) {
+ RealFileName = EfiStrChr (RealFileName, L'\\') + 1;
+ }
+
+ TempChar = 0;
+ if (RealFileName != NewPrivateFile->FileName) {
+ TempChar = *(RealFileName - 1);
+ *(RealFileName - 1) = 0;
+ }
+
+ FreePool (NewPrivateFile->FilePath);
+ NewPrivateFile->FilePath = NULL;
+ NewPrivateFile->FilePath = AllocatePool (StrSize (NewPrivateFile->FileName));
+ if (NewPrivateFile->FilePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ StrCpyS (
+ NewPrivateFile->FilePath,
+ StrSize (NewPrivateFile->FileName) / sizeof (CHAR16),
+ NewPrivateFile->FileName
+ );
+ if (TempChar != 0) {
+ *(RealFileName - 1) = TempChar;
+ }
+
+ NewPrivateFile->IsRootDirectory = FALSE;
+
+ //
+ // Test whether file or directory
+ //
+ if (OpenMode & EFI_FILE_MODE_CREATE) {
+ if (Attributes & EFI_FILE_DIRECTORY) {
+ NewPrivateFile->IsDirectoryPath = TRUE;
+ } else {
+ NewPrivateFile->IsDirectoryPath = FALSE;
+ }
+ } else {
+ NewPrivateFile->LHandle = CreateFile (
+ NewPrivateFile->FileName,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+
+ if (NewPrivateFile->LHandle != INVALID_HANDLE_VALUE) {
+ NewPrivateFile->IsDirectoryPath = FALSE;
+ CloseHandle (NewPrivateFile->LHandle);
+ } else {
+ NewPrivateFile->IsDirectoryPath = TRUE;
+ }
+
+ NewPrivateFile->LHandle = INVALID_HANDLE_VALUE;
+ }
+
+ if (OpenMode & EFI_FILE_MODE_WRITE) {
+ NewPrivateFile->IsOpenedByRead = FALSE;
+ } else {
+ NewPrivateFile->IsOpenedByRead = TRUE;
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // deal with directory
+ //
+ if (NewPrivateFile->IsDirectoryPath) {
+
+ Size = StrSize (NewPrivateFile->FileName);
+ Size += StrSize (L"\\*");
+ TempFileName = AllocatePool (Size);
+ if (TempFileName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ StrCpyS (TempFileName, Size / sizeof (CHAR16), NewPrivateFile->FileName);
+
+ if ((OpenMode & EFI_FILE_MODE_CREATE)) {
+ //
+ // Create a directory
+ //
+ if (!CreateDirectory (TempFileName, NULL)) {
+
+ LastError = GetLastError ();
+ if (LastError != ERROR_ALREADY_EXISTS) {
+ FreePool (TempFileName);
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ }
+ }
+
+ NewPrivateFile->DirHandle = CreateFile (
+ TempFileName,
+ NewPrivateFile->IsOpenedByRead ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE),
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL
+ );
+
+ if (NewPrivateFile->DirHandle == INVALID_HANDLE_VALUE) {
+
+ NewPrivateFile->DirHandle = CreateFile (
+ TempFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL
+ );
+
+ if (NewPrivateFile->DirHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle (NewPrivateFile->DirHandle);
+ NewPrivateFile->DirHandle = INVALID_HANDLE_VALUE;
+ Status = EFI_ACCESS_DENIED;
+ } else {
+ Status = EFI_NOT_FOUND;
+ }
+
+ FreePool (TempFileName);
+ goto Done;
+ }
+
+ //
+ // Find the first file under it
+ //
+ StrCatS (TempFileName, Size / sizeof (CHAR16), L"\\*");
+ NewPrivateFile->LHandle = FindFirstFile (TempFileName, &NewPrivateFile->FindBuf);
+ FreePool (TempFileName);
+
+ if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) {
+ NewPrivateFile->IsValidFindBuf = FALSE;
+ } else {
+ NewPrivateFile->IsValidFindBuf = TRUE;
+ }
+ } else {
+ //
+ // deal with file
+ //
+ if (!NewPrivateFile->IsOpenedByRead) {
+ NewPrivateFile->LHandle = CreateFile (
+ NewPrivateFile->FileName,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ (OpenMode & EFI_FILE_MODE_CREATE) ? OPEN_ALWAYS : OPEN_EXISTING,
+ 0,
+ NULL
+ );
+
+ if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) {
+ NewPrivateFile->LHandle = CreateFile (
+ NewPrivateFile->FileName,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+
+ if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) {
+ Status = EFI_NOT_FOUND;
+ } else {
+ Status = EFI_ACCESS_DENIED;
+ CloseHandle (NewPrivateFile->LHandle);
+ NewPrivateFile->LHandle = INVALID_HANDLE_VALUE;
+ }
+ }
+ } else {
+ NewPrivateFile->LHandle = CreateFile (
+ NewPrivateFile->FileName,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+
+ if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) {
+ Status = EFI_NOT_FOUND;
+ }
+ }
+ }
+
+ if ((OpenMode & EFI_FILE_MODE_CREATE) && Status == EFI_SUCCESS) {
+ //
+ // Set the attribute
+ //
+ InfoSize = 0;
+ Info = NULL;
+
+ Status = WinNtFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ Info = AllocatePool (InfoSize);
+ if (Info == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = WinNtFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info);
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Info);
+ goto Done;
+ }
+
+ Info->Attribute = Attributes;
+
+ WinNtFileSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info);
+ FreePool (Info);
+ }
+
+Done:
+ FreePool (FileName);
+
+ if (EFI_ERROR (Status)) {
+ if (NewPrivateFile) {
+ if (NewPrivateFile->FileName) {
+ FreePool (NewPrivateFile->FileName);
+ }
+
+ if (NewPrivateFile->FilePath) {
+ FreePool (NewPrivateFile->FilePath);
+ }
+
+ FreePool (NewPrivateFile);
+ }
+ } else {
+ *NewHandle = &NewPrivateFile->EfiFile;
+ if (StrCmp (NewPrivateFile->FileName, PrivateRoot->FilePath) == 0) {
+ NewPrivateFile->IsRootDirectory = TRUE;
+ }
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Close the file handle
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The device was opened.
+
+**/
+EFI_STATUS
+WinNtFileClose (
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;
+
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+ if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) {
+ if (PrivateFile->IsDirectoryPath) {
+ FindClose (PrivateFile->LHandle);
+ } else {
+ CloseHandle (PrivateFile->LHandle);
+ }
+
+ PrivateFile->LHandle = INVALID_HANDLE_VALUE;
+ }
+
+ if (PrivateFile->IsDirectoryPath && PrivateFile->DirHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle (PrivateFile->DirHandle);
+ PrivateFile->DirHandle = INVALID_HANDLE_VALUE;
+ }
+
+ if (PrivateFile->FileName) {
+ FreePool (PrivateFile->FileName);
+ }
+
+ if (PrivateFile->FilePath) {
+ FreePool (PrivateFile->FilePath);
+ }
+
+ FreePool (PrivateFile);
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Close and delete the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
+
+**/
+EFI_STATUS
+WinNtFileDelete (
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;
+
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+ Status = EFI_WARN_DELETE_FAILURE;
+
+ if (PrivateFile->IsDirectoryPath) {
+ if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) {
+ FindClose (PrivateFile->LHandle);
+ }
+
+ if (PrivateFile->DirHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle (PrivateFile->DirHandle);
+ PrivateFile->DirHandle = INVALID_HANDLE_VALUE;
+ }
+
+ if (RemoveDirectory (PrivateFile->FileName)) {
+ Status = EFI_SUCCESS;
+ }
+ } else {
+ CloseHandle (PrivateFile->LHandle);
+ PrivateFile->LHandle = INVALID_HANDLE_VALUE;
+
+ if (!PrivateFile->IsOpenedByRead) {
+ if (DeleteFile (PrivateFile->FileName)) {
+ Status = EFI_SUCCESS;
+ }
+ }
+ }
+
+ FreePool (PrivateFile->FileName);
+ FreePool (PrivateFile->FilePath);
+ FreePool (PrivateFile);
+
+ return Status;
+}
+
+VOID
+WinNtSystemTimeToEfiTime (
+ IN SYSTEMTIME *SystemTime,
+ IN TIME_ZONE_INFORMATION *TimeZone,
+ OUT EFI_TIME *Time
+)
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SystemTime - TODO: add argument description
+ TimeZone - TODO: add argument description
+ Time - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ Time->Year = (UINT16)SystemTime->wYear;
+ Time->Month = (UINT8)SystemTime->wMonth;
+ Time->Day = (UINT8)SystemTime->wDay;
+ Time->Hour = (UINT8)SystemTime->wHour;
+ Time->Minute = (UINT8)SystemTime->wMinute;
+ Time->Second = (UINT8)SystemTime->wSecond;
+ Time->Nanosecond = (UINT32)SystemTime->wMilliseconds * 1000000;
+ Time->TimeZone = (INT16)TimeZone->Bias;
+
+ if (TimeZone->StandardDate.wMonth) {
+ Time->Daylight = EFI_TIME_ADJUST_DAYLIGHT;
+ }
+}
+
+/**
+ Convert the FileTime to EfiTime.
+
+ @param PrivateFile Pointer to WIN_NT_EFI_FILE_PRIVATE.
+ @param TimeZone Pointer to the current time zone.
+ @param FileTime Pointer to file time.
+ @param EfiTime Pointer to EFI time.
+**/
+VOID
+WinNtFileTimeToEfiTime (
+ IN CONST WIN_NT_EFI_FILE_PRIVATE *PrivateFile,
+ IN TIME_ZONE_INFORMATION *TimeZone,
+ IN CONST FILETIME *FileTime,
+ OUT EFI_TIME *EfiTime
+)
+{
+ FILETIME TempFileTime;
+ SYSTEMTIME SystemTime;
+
+ FileTimeToLocalFileTime (FileTime, &TempFileTime);
+ FileTimeToSystemTime (&TempFileTime, &SystemTime);
+ WinNtSystemTimeToEfiTime (&SystemTime, TimeZone, EfiTime);
+}
+
+
+/**
+ Read data from the file.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input size of buffer, on output amount of data in buffer.
+ @param Buffer The buffer in which data is read.
+
+ @retval EFI_SUCCESS Data was read.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
+
+**/
+EFI_STATUS
+WinNtFileRead (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_STATUS Status;
+ UINTN Size;
+ UINTN NameSize;
+ UINTN ResultSize;
+ UINTN Index;
+ EFI_FILE_INFO *Info;
+ WCHAR *pw;
+ TIME_ZONE_INFORMATION TimeZone;
+ EFI_FILE_INFO *FileInfo;
+ UINT64 Pos;
+ UINT64 FileSize;
+ UINTN FileInfoSize;
+
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+ if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ if (!PrivateFile->IsDirectoryPath) {
+
+ if (This->GetPosition (This, &Pos) != EFI_SUCCESS) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ FileInfoSize = SIZE_OF_EFI_FILE_SYSTEM_INFO;
+ FileInfo = AllocatePool (FileInfoSize);
+
+ Status = This->GetInfo (
+ This,
+ &gEfiFileInfoGuid,
+ &FileInfoSize,
+ FileInfo
+ );
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (FileInfo);
+ FileInfo = AllocatePool (FileInfoSize);
+ Status = This->GetInfo (
+ This,
+ &gEfiFileInfoGuid,
+ &FileInfoSize,
+ FileInfo
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ FileSize = FileInfo->FileSize;
+
+ FreePool (FileInfo);
+
+ if (Pos >= FileSize) {
+ *BufferSize = 0;
+ if (Pos == FileSize) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ }
+
+ Status = ReadFile (
+ PrivateFile->LHandle,
+ Buffer,
+ (DWORD)*BufferSize,
+ (LPDWORD)BufferSize,
+ NULL
+ ) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // Read on a directory. Perform a find next
+ //
+ if (!PrivateFile->IsValidFindBuf) {
+ *BufferSize = 0;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ Size = SIZE_OF_EFI_FILE_INFO;
+
+ NameSize = StrSize (PrivateFile->FindBuf.cFileName);
+
+ ResultSize = Size + NameSize;
+
+ Status = EFI_BUFFER_TOO_SMALL;
+
+ if (*BufferSize >= ResultSize) {
+ Status = EFI_SUCCESS;
+
+ Info = Buffer;
+ ZeroMem (Info, ResultSize);
+
+ Info->Size = ResultSize;
+
+ GetTimeZoneInformation (&TimeZone);
+ WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &PrivateFile->FindBuf.ftCreationTime, &Info->CreateTime);
+ WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &PrivateFile->FindBuf.ftLastAccessTime, &Info->LastAccessTime);
+ WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &PrivateFile->FindBuf.ftLastWriteTime, &Info->ModificationTime);
+
+ Info->FileSize = PrivateFile->FindBuf.nFileSizeLow;
+
+ Info->PhysicalSize = PrivateFile->FindBuf.nFileSizeLow;
+
+ if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {
+ Info->Attribute |= EFI_FILE_ARCHIVE;
+ }
+
+ if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
+ Info->Attribute |= EFI_FILE_HIDDEN;
+ }
+
+ if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
+ Info->Attribute |= EFI_FILE_SYSTEM;
+ }
+
+ if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+ Info->Attribute |= EFI_FILE_READ_ONLY;
+ }
+
+ if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ Info->Attribute |= EFI_FILE_DIRECTORY;
+ }
+
+ NameSize = NameSize / sizeof (WCHAR);
+
+ pw = (WCHAR *)(((CHAR8 *)Buffer) + Size);
+
+ for (Index = 0; Index < NameSize; Index++) {
+ pw[Index] = PrivateFile->FindBuf.cFileName[Index];
+ }
+
+ if (FindNextFile (PrivateFile->LHandle, &PrivateFile->FindBuf)) {
+ PrivateFile->IsValidFindBuf = TRUE;
+ } else {
+ PrivateFile->IsValidFindBuf = FALSE;
+ }
+ }
+
+ *BufferSize = ResultSize;
+
+Done:
+ return Status;
+}
+
+
+
+/**
+ Write data to a file.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input size of buffer, on output amount of data in buffer.
+ @param Buffer The buffer in which data to write.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+WinNtFileWrite (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_STATUS Status;
+
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+ if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ if (PrivateFile->IsDirectoryPath) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (PrivateFile->IsOpenedByRead) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ Status = WriteFile (
+ PrivateFile->LHandle,
+ Buffer,
+ (DWORD)*BufferSize,
+ (LPDWORD)BufferSize,
+ NULL
+ ) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+
+Done:
+ return Status;
+
+ //
+ // bugbug: need to access windows error reporting
+ //
+}
+
+
+
+/**
+ Set a files current position
+
+ @param This Protocol instance pointer.
+ @param Position Byte position from the start of the file.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
+
+**/
+EFI_STATUS
+WinNtFileSetPossition (
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 Position
+ )
+{
+ EFI_STATUS Status;
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;
+ UINT32 PosLow;
+ UINT32 PosHigh;
+ CHAR16 *FileName;
+ UINTN Size;
+
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+ if (PrivateFile->IsDirectoryPath) {
+ if (Position != 0) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Size = StrSize (PrivateFile->FileName);
+ Size += StrSize (L"\\*");
+ FileName = AllocatePool (Size);
+ if (FileName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ StrCpyS (FileName, Size / sizeof (CHAR16), PrivateFile->FileName);
+ StrCatS (FileName, Size / sizeof (CHAR16), L"\\*");
+
+ if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) {
+ FindClose (PrivateFile->LHandle);
+ }
+
+ PrivateFile->LHandle = FindFirstFile (FileName, &PrivateFile->FindBuf);
+
+ if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {
+ PrivateFile->IsValidFindBuf = FALSE;
+ } else {
+ PrivateFile->IsValidFindBuf = TRUE;
+ }
+
+ FreePool (FileName);
+
+ Status = (PrivateFile->LHandle == INVALID_HANDLE_VALUE) ? EFI_DEVICE_ERROR : EFI_SUCCESS;
+ } else {
+ if (Position == (UINT64)-1) {
+ PosLow = SetFilePointer (PrivateFile->LHandle, (ULONG)0, NULL, FILE_END);
+ } else {
+ PosHigh = (UINT32)RShiftU64 (Position, 32);
+
+ PosLow = SetFilePointer (PrivateFile->LHandle, (ULONG)Position, (PLONG)&PosHigh, FILE_BEGIN);
+ }
+
+ Status = (PosLow == 0xFFFFFFFF) ? EFI_DEVICE_ERROR : EFI_SUCCESS;
+ }
+
+Done:
+ return Status;
+}
+
+
+
+/**
+ Get a file's current position
+
+ @param This Protocol instance pointer.
+ @param Position Byte position from the start of the file.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
+
+**/
+EFI_STATUS
+WinNtFileGetPossition (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 *Position
+ )
+{
+ EFI_STATUS Status;
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;
+ INT32 PositionHigh;
+ UINT64 PosHigh64;
+
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+ PositionHigh = 0;
+ PosHigh64 = 0;
+
+ if (PrivateFile->IsDirectoryPath) {
+
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+
+ } else {
+
+ PositionHigh = 0;
+ *Position = SetFilePointer (
+ PrivateFile->LHandle,
+ 0,
+ (PLONG)&PositionHigh,
+ FILE_CURRENT
+ );
+
+ Status = *Position == 0xffffffff ? EFI_DEVICE_ERROR : EFI_SUCCESS;
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ PosHigh64 = PositionHigh;
+ *Position += LShiftU64 (PosHigh64, 32);
+ }
+
+Done:
+ return Status;
+}
+
+
+EFI_STATUS
+WinNtSimpleFileSystemFileInfo (
+ IN WIN_NT_EFI_FILE_PRIVATE *PrivateFile,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+)
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PrivateFile - TODO: add argument description
+ BufferSize - TODO: add argument description
+ Buffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ UINTN NameSize;
+ UINTN ResultSize;
+ EFI_FILE_INFO *Info;
+ BY_HANDLE_FILE_INFORMATION FileInfo;
+ CHAR16 *RealFileName;
+ CHAR16 *TempPointer;
+ TIME_ZONE_INFORMATION TimeZone;
+
+ Size = SIZE_OF_EFI_FILE_INFO;
+
+ RealFileName = PrivateFile->FileName;
+ TempPointer = RealFileName;
+ while (*TempPointer) {
+ if (*TempPointer == '\\') {
+ RealFileName = TempPointer + 1;
+ }
+
+ TempPointer++;
+ }
+ NameSize = StrSize (RealFileName);
+
+ ResultSize = Size + NameSize;
+
+ Status = EFI_BUFFER_TOO_SMALL;
+ if (*BufferSize >= ResultSize) {
+ Status = EFI_SUCCESS;
+
+ Info = Buffer;
+ ZeroMem (Info, ResultSize);
+
+ Info->Size = ResultSize;
+ GetFileInformationByHandle (
+ PrivateFile->IsDirectoryPath ? PrivateFile->DirHandle : PrivateFile->LHandle,
+ &FileInfo
+ );
+ Info->FileSize = FileInfo.nFileSizeLow;
+ Info->PhysicalSize = Info->FileSize;
+
+ GetTimeZoneInformation (&TimeZone);
+ WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &FileInfo.ftCreationTime, &Info->CreateTime);
+ WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &FileInfo.ftLastAccessTime, &Info->LastAccessTime);
+ WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &FileInfo.ftLastWriteTime, &Info->ModificationTime);
+
+ if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {
+ Info->Attribute |= EFI_FILE_ARCHIVE;
+ }
+
+ if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
+ Info->Attribute |= EFI_FILE_HIDDEN;
+ }
+
+ if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+ Info->Attribute |= EFI_FILE_READ_ONLY;
+ }
+
+ if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
+ Info->Attribute |= EFI_FILE_SYSTEM;
+ }
+
+ if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ Info->Attribute |= EFI_FILE_DIRECTORY;
+ }
+
+ if (PrivateFile->IsDirectoryPath) {
+ Info->Attribute |= EFI_FILE_DIRECTORY;
+ }
+
+ if (PrivateFile->IsRootDirectory) {
+ *((CHAR8 *)Buffer + Size) = 0;
+ } else {
+ CopyMem ((CHAR8 *)Buffer + Size, RealFileName, NameSize);
+ }
+ }
+
+ *BufferSize = ResultSize;
+ return Status;
+}
+
+/**
+ Get information about a file.
+
+ @param This Protocol instance pointer.
+ @param InformationType Type of information to return in Buffer.
+ @param BufferSize On input size of buffer, on output amount of data in buffer.
+ @param Buffer The buffer to return data.
+
+ @retval EFI_SUCCESS Data was returned.
+ @retval EFI_UNSUPPORTED InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
+
+**/
+EFI_STATUS
+WinNtFileGetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_FILE_SYSTEM_INFO *FileSystemInfoBuffer;
+ UINT32 SectorsPerCluster;
+ UINT32 BytesPerSector;
+ UINT32 FreeClusters;
+ UINT32 TotalClusters;
+ UINT32 BytesPerCluster;
+ CHAR16 *DriveName;
+ BOOLEAN DriveNameFound;
+ BOOL NtStatus;
+ UINTN Index;
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
+
+ if (This == NULL || InformationType == NULL || BufferSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+ PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
+
+ Status = EFI_UNSUPPORTED;
+
+ if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
+ Status = WinNtSimpleFileSystemFileInfo (PrivateFile, BufferSize, Buffer);
+ }
+
+ if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
+ if (*BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) {
+ *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ FileSystemInfoBuffer = (EFI_FILE_SYSTEM_INFO *)Buffer;
+ FileSystemInfoBuffer->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
+ FileSystemInfoBuffer->ReadOnly = FALSE;
+
+ //
+ // Try to get the drive name
+ //
+ DriveNameFound = FALSE;
+ DriveName = AllocatePool (StrSize (PrivateFile->FilePath) + 1);
+ if (DriveName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ StrCpyS (
+ DriveName,
+ (StrSize (PrivateFile->FilePath) + 1) / sizeof (CHAR16),
+ PrivateFile->FilePath
+ );
+ for (Index = 0; DriveName[Index] != 0 && DriveName[Index] != ':'; Index++) {
+ ;
+ }
+
+ if (DriveName[Index] == ':') {
+ DriveName[Index + 1] = '\\';
+ DriveName[Index + 2] = 0;
+ DriveNameFound = TRUE;
+ } else if (DriveName[0] == '\\' && DriveName[1] == '\\') {
+ for (Index = 2; DriveName[Index] != 0 && DriveName[Index] != '\\'; Index++) {
+ ;
+ }
+
+ if (DriveName[Index] == '\\') {
+ DriveNameFound = TRUE;
+ for (Index++; DriveName[Index] != 0 && DriveName[Index] != '\\'; Index++) {
+ ;
+ }
+
+ DriveName[Index] = '\\';
+ DriveName[Index + 1] = 0;
+ }
+ }
+
+ //
+ // Try GetDiskFreeSpace first
+ //
+ NtStatus = GetDiskFreeSpace (
+ DriveNameFound ? DriveName : NULL,
+ (LPDWORD)&SectorsPerCluster,
+ (LPDWORD)&BytesPerSector,
+ (LPDWORD)&FreeClusters,
+ (LPDWORD)&TotalClusters
+ );
+ if (DriveName) {
+ FreePool (DriveName);
+ }
+
+ if (NtStatus) {
+ //
+ // Succeeded
+ //
+ BytesPerCluster = BytesPerSector * SectorsPerCluster;
+ FileSystemInfoBuffer->VolumeSize = MultU64x32 (TotalClusters, BytesPerCluster);
+ FileSystemInfoBuffer->FreeSpace = MultU64x32 (FreeClusters, BytesPerCluster);
+ FileSystemInfoBuffer->BlockSize = BytesPerCluster;
+
+ } else {
+ //
+ // try GetDiskFreeSpaceEx then
+ //
+ FileSystemInfoBuffer->BlockSize = 0;
+ NtStatus = GetDiskFreeSpaceEx (
+ PrivateFile->FilePath,
+ (PULARGE_INTEGER)(&FileSystemInfoBuffer->FreeSpace),
+ (PULARGE_INTEGER)(&FileSystemInfoBuffer->VolumeSize),
+ NULL
+ );
+ if (!NtStatus) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ }
+
+ StrCpyS (
+ (CHAR16 *)FileSystemInfoBuffer->VolumeLabel,
+ (*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_INFO) / sizeof (CHAR16),
+ PrivateRoot->VolumeLabel
+ );
+ *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel);
+ Status = EFI_SUCCESS;
+ }
+
+ if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+ if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) {
+ *BufferSize = StrSize (PrivateRoot->VolumeLabel);
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ StrCpyS (
+ (CHAR16 *)Buffer,
+ *BufferSize / sizeof (CHAR16),
+ PrivateRoot->VolumeLabel
+ );
+ *BufferSize = StrSize (PrivateRoot->VolumeLabel);
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ return Status;
+}
+
+
+/**
+ Set information about a file
+
+ @param File Protocol instance pointer.
+ @param InformationType Type of information in Buffer.
+ @param BufferSize Size of buffer.
+ @param Buffer The data to write.
+
+ @retval EFI_SUCCESS Data was returned.
+ @retval EFI_UNSUPPORTED InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+
+**/
+EFI_STATUS
+WinNtFileSetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot;
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_FILE_INFO *OldFileInfo;
+ EFI_FILE_INFO *NewFileInfo;
+ EFI_STATUS Status;
+ UINTN OldInfoSize;
+ INTN NtStatus;
+ UINT32 NewAttr;
+ UINT32 OldAttr;
+ CHAR16 *OldFileName;
+ CHAR16 *NewFileName;
+ CHAR16 *TempFileName;
+ CHAR16 *CharPointer;
+ BOOLEAN AttrChangeFlag;
+ BOOLEAN NameChangeFlag;
+ BOOLEAN SizeChangeFlag;
+ BOOLEAN TimeChangeFlag;
+ UINT64 CurPos;
+ SYSTEMTIME NewCreationSystemTime;
+ SYSTEMTIME NewLastAccessSystemTime;
+ SYSTEMTIME NewLastWriteSystemTime;
+ FILETIME NewCreationFileTime;
+ FILETIME NewLastAccessFileTime;
+ FILETIME NewLastWriteFileTime;
+ WIN32_FIND_DATA FindBuf;
+ EFI_FILE_SYSTEM_INFO *NewFileSystemInfo;
+ UINTN Size;
+
+ //
+ // Initialise locals.
+ //
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+ PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem);
+
+ Status = EFI_UNSUPPORTED;
+ OldFileInfo = NewFileInfo = NULL;
+ OldFileName = NewFileName = NULL;
+ AttrChangeFlag = NameChangeFlag = SizeChangeFlag = TimeChangeFlag = FALSE;
+
+ //
+ // Set file system information.
+ //
+ if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
+ NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
+ if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (NewFileSystemInfo->VolumeLabel)) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+
+
+ FreePool (PrivateRoot->VolumeLabel);
+ PrivateRoot->VolumeLabel = AllocatePool (StrSize (NewFileSystemInfo->VolumeLabel));
+ if (PrivateRoot->VolumeLabel == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ StrCpyS (
+ PrivateRoot->VolumeLabel,
+ StrSize (NewFileSystemInfo->VolumeLabel) / sizeof (CHAR16),
+ NewFileSystemInfo->VolumeLabel
+ );
+
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ //
+ // Set volume label information.
+ //
+ if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+ if (BufferSize < StrSize (PrivateRoot->VolumeLabel)) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+
+ StrCpyS (
+ PrivateRoot->VolumeLabel,
+ StrSize (PrivateRoot->VolumeLabel) / sizeof (CHAR16),
+ (CHAR16 *)Buffer
+ );
+
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ if (!CompareGuid (InformationType, &gEfiFileInfoGuid)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (BufferSize < SIZE_OF_EFI_FILE_INFO) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+
+ //
+ // Set file/directory information.
+ //
+
+ //
+ // Check for invalid set file information parameters.
+ //
+ NewFileInfo = (EFI_FILE_INFO *)Buffer;
+
+ if ((NewFileInfo->Size <= SIZE_OF_EFI_FILE_INFO) ||
+ (NewFileInfo->Attribute &~(EFI_FILE_VALID_ATTR)) ||
+ (sizeof (UINTN) == 4 && NewFileInfo->Size > 0xFFFFFFFF)
+ ) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // bugbug: - This is not safe. We need something like EfiStrMaxSize()
+ // that would have an additional parameter that would be the size
+ // of the string array just in case there are no NULL characters in
+ // the string array.
+ //
+ //
+ // Get current file information so we can determine what kind
+ // of change request this is.
+ //
+ OldInfoSize = 0;
+ Status = WinNtSimpleFileSystemFileInfo (PrivateFile, &OldInfoSize, NULL);
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ OldFileInfo = AllocatePool (OldInfoSize);
+ if (OldFileInfo == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = WinNtSimpleFileSystemFileInfo (PrivateFile, &OldInfoSize, OldFileInfo);
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ OldFileName = AllocatePool (StrSize (PrivateFile->FileName));
+ if (OldFileName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ StrCpyS (
+ OldFileName,
+ StrSize (PrivateFile->FileName) / sizeof (CHAR16),
+ PrivateFile->FileName
+ );
+
+ //
+ // Make full pathname from new filename and rootpath.
+ //
+ if (NewFileInfo->FileName[0] == '\\') {
+ Size = StrSize (PrivateRoot->FilePath);
+ Size += StrSize (L"\\");
+ Size += StrSize (NewFileInfo->FileName);
+ NewFileName = AllocatePool (Size);
+ if (NewFileName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ StrCpyS (NewFileName, Size / sizeof (CHAR16), PrivateRoot->FilePath);
+ StrCatS (NewFileName, Size / sizeof (CHAR16), L"\\");
+ StrCatS (NewFileName, Size / sizeof (CHAR16), NewFileInfo->FileName + 1);
+ } else {
+ Size = StrSize (PrivateFile->FilePath);
+ Size += StrSize (L"\\");
+ Size += StrSize (NewFileInfo->FileName);
+ NewFileName = AllocatePool (Size);
+ if (NewFileName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ StrCpyS (NewFileName, Size / sizeof (CHAR16), PrivateFile->FilePath);
+ StrCatS (NewFileName, Size / sizeof (CHAR16), L"\\");
+ StrCatS (NewFileName, Size / sizeof (CHAR16), NewFileInfo->FileName);
+ }
+
+ //
+ // Is there an attribute change request?
+ //
+ if (NewFileInfo->Attribute != OldFileInfo->Attribute) {
+ if ((NewFileInfo->Attribute & EFI_FILE_DIRECTORY) != (OldFileInfo->Attribute & EFI_FILE_DIRECTORY)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ AttrChangeFlag = TRUE;
+ }
+
+ //
+ // Is there a name change request?
+ // bugbug: - Need EfiStrCaseCmp()
+ //
+ if (StrCmp (NewFileInfo->FileName, OldFileInfo->FileName)) {
+ NameChangeFlag = TRUE;
+ }
+
+ //
+ // Is there a size change request?
+ //
+ if (NewFileInfo->FileSize != OldFileInfo->FileSize) {
+ SizeChangeFlag = TRUE;
+ }
+
+ //
+ // Is there a time stamp change request?
+ //
+ if (!IsZero (&NewFileInfo->CreateTime, sizeof (EFI_TIME)) &&
+ CompareMem (&NewFileInfo->CreateTime, &OldFileInfo->CreateTime, sizeof (EFI_TIME))
+ ) {
+ TimeChangeFlag = TRUE;
+ } else if (!IsZero (&NewFileInfo->LastAccessTime, sizeof (EFI_TIME)) &&
+ CompareMem (&NewFileInfo->LastAccessTime, &OldFileInfo->LastAccessTime, sizeof (EFI_TIME))
+ ) {
+ TimeChangeFlag = TRUE;
+ } else if (!IsZero (&NewFileInfo->ModificationTime, sizeof (EFI_TIME)) &&
+ CompareMem (&NewFileInfo->ModificationTime, &OldFileInfo->ModificationTime, sizeof (EFI_TIME))
+ ) {
+ TimeChangeFlag = TRUE;
+ }
+
+ //
+ // All done if there are no change requests being made.
+ //
+ if (!(AttrChangeFlag || NameChangeFlag || SizeChangeFlag || TimeChangeFlag)) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ //
+ // Set file or directory information.
+ //
+ OldAttr = GetFileAttributes (OldFileName);
+
+ //
+ // Name change.
+ //
+ if (NameChangeFlag) {
+ //
+ // Close the handles first
+ //
+ if (PrivateFile->IsOpenedByRead) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ for (CharPointer = NewFileName; *CharPointer != 0 && *CharPointer != L'/'; CharPointer++) {
+ }
+
+ if (*CharPointer != 0) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) {
+ if (PrivateFile->IsDirectoryPath) {
+ FindClose (PrivateFile->LHandle);
+ } else {
+ CloseHandle (PrivateFile->LHandle);
+ PrivateFile->LHandle = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ if (PrivateFile->IsDirectoryPath && PrivateFile->DirHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle (PrivateFile->DirHandle);
+ PrivateFile->DirHandle = INVALID_HANDLE_VALUE;
+ }
+
+ NtStatus = MoveFile (OldFileName, NewFileName);
+
+ if (NtStatus) {
+ //
+ // modify file name
+ //
+ FreePool (PrivateFile->FileName);
+
+ PrivateFile->FileName = AllocatePool (StrSize (NewFileName));
+ if (PrivateFile->FileName == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ StrCpyS (PrivateFile->FileName, StrSize (NewFileName) / sizeof (CHAR16), NewFileName);
+
+ Size = StrSize (NewFileName);
+ Size += StrSize (L"\\*");
+ TempFileName = AllocatePool (Size);
+
+ StrCpyS (TempFileName, Size / sizeof (CHAR16), NewFileName);
+
+ if (!PrivateFile->IsDirectoryPath) {
+ PrivateFile->LHandle = CreateFile (
+ TempFileName,
+ PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+
+ FreePool (TempFileName);
+
+ //
+ // Flush buffers just in case
+ //
+ if (FlushFileBuffers (PrivateFile->LHandle) == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ } else {
+ PrivateFile->DirHandle = CreateFile (
+ TempFileName,
+ PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL
+ );
+
+ StrCatS (TempFileName, Size / sizeof (CHAR16), L"\\*");
+ PrivateFile->LHandle = FindFirstFile (TempFileName, &FindBuf);
+
+ FreePool (TempFileName);
+ }
+ } else {
+ Status = EFI_ACCESS_DENIED;
+ Reopen:;
+
+ NtStatus = SetFileAttributes (OldFileName, OldAttr);
+
+ if (!NtStatus) {
+ goto Done;
+ }
+
+ Size = StrSize (OldFileName);
+ Size += StrSize (L"\\*");
+ TempFileName = AllocatePool (Size);
+
+ StrCpyS (TempFileName, Size / sizeof (CHAR16), OldFileName);
+
+ if (!PrivateFile->IsDirectoryPath) {
+ PrivateFile->LHandle = CreateFile (
+ TempFileName,
+ PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+ } else {
+ PrivateFile->DirHandle = CreateFile (
+ TempFileName,
+ PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL
+ );
+
+ StrCatS (TempFileName, Size / sizeof (CHAR16), L"\\*");
+ PrivateFile->LHandle = FindFirstFile (TempFileName, &FindBuf);
+ }
+
+ FreePool (TempFileName);
+
+ goto Done;
+
+ }
+ }
+
+ //
+ // Size change
+ //
+ if (SizeChangeFlag) {
+ if (PrivateFile->IsDirectoryPath) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ if (PrivateFile->IsOpenedByRead || OldFileInfo->Attribute & EFI_FILE_READ_ONLY) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ Status = This->GetPosition (This, &CurPos);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = This->SetPosition (This, NewFileInfo->FileSize);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (SetEndOfFile (PrivateFile->LHandle) == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ Status = This->SetPosition (This, CurPos);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // Time change
+ //
+ if (TimeChangeFlag) {
+
+ NewCreationSystemTime.wYear = NewFileInfo->CreateTime.Year;
+ NewCreationSystemTime.wMonth = NewFileInfo->CreateTime.Month;
+ NewCreationSystemTime.wDay = NewFileInfo->CreateTime.Day;
+ NewCreationSystemTime.wHour = NewFileInfo->CreateTime.Hour;
+ NewCreationSystemTime.wMinute = NewFileInfo->CreateTime.Minute;
+ NewCreationSystemTime.wSecond = NewFileInfo->CreateTime.Second;
+ NewCreationSystemTime.wMilliseconds = 0;
+
+ if (!SystemTimeToFileTime (
+ &NewCreationSystemTime,
+ &NewCreationFileTime
+ )) {
+ goto Done;
+ }
+
+ if (!LocalFileTimeToFileTime (
+ &NewCreationFileTime,
+ &NewCreationFileTime
+ )) {
+ goto Done;
+ }
+
+ NewLastAccessSystemTime.wYear = NewFileInfo->LastAccessTime.Year;
+ NewLastAccessSystemTime.wMonth = NewFileInfo->LastAccessTime.Month;
+ NewLastAccessSystemTime.wDay = NewFileInfo->LastAccessTime.Day;
+ NewLastAccessSystemTime.wHour = NewFileInfo->LastAccessTime.Hour;
+ NewLastAccessSystemTime.wMinute = NewFileInfo->LastAccessTime.Minute;
+ NewLastAccessSystemTime.wSecond = NewFileInfo->LastAccessTime.Second;
+ NewLastAccessSystemTime.wMilliseconds = 0;
+
+ if (!SystemTimeToFileTime (
+ &NewLastAccessSystemTime,
+ &NewLastAccessFileTime
+ )) {
+ goto Done;
+ }
+
+ if (!LocalFileTimeToFileTime (
+ &NewLastAccessFileTime,
+ &NewLastAccessFileTime
+ )) {
+ goto Done;
+ }
+
+ NewLastWriteSystemTime.wYear = NewFileInfo->ModificationTime.Year;
+ NewLastWriteSystemTime.wMonth = NewFileInfo->ModificationTime.Month;
+ NewLastWriteSystemTime.wDay = NewFileInfo->ModificationTime.Day;
+ NewLastWriteSystemTime.wHour = NewFileInfo->ModificationTime.Hour;
+ NewLastWriteSystemTime.wMinute = NewFileInfo->ModificationTime.Minute;
+ NewLastWriteSystemTime.wSecond = NewFileInfo->ModificationTime.Second;
+ NewLastWriteSystemTime.wMilliseconds = 0;
+
+ if (!SystemTimeToFileTime (
+ &NewLastWriteSystemTime,
+ &NewLastWriteFileTime
+ )) {
+ goto Done;
+ }
+
+ if (!LocalFileTimeToFileTime (
+ &NewLastWriteFileTime,
+ &NewLastWriteFileTime
+ )) {
+ goto Done;
+ }
+
+ if (!SetFileTime (
+ PrivateFile->IsDirectoryPath ? PrivateFile->DirHandle : PrivateFile->LHandle,
+ &NewCreationFileTime,
+ &NewLastAccessFileTime,
+ &NewLastWriteFileTime
+ )) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ }
+
+ //
+ // No matter about AttrChangeFlag, Attribute must be set.
+ // Because operation before may cause attribute change.
+ //
+ NewAttr = OldAttr;
+
+ if (NewFileInfo->Attribute & EFI_FILE_ARCHIVE) {
+ NewAttr |= FILE_ATTRIBUTE_ARCHIVE;
+ } else {
+ NewAttr &= ~FILE_ATTRIBUTE_ARCHIVE;
+ }
+
+ if (NewFileInfo->Attribute & EFI_FILE_HIDDEN) {
+ NewAttr |= FILE_ATTRIBUTE_HIDDEN;
+ } else {
+ NewAttr &= ~FILE_ATTRIBUTE_HIDDEN;
+ }
+
+ if (NewFileInfo->Attribute & EFI_FILE_SYSTEM) {
+ NewAttr |= FILE_ATTRIBUTE_SYSTEM;
+ } else {
+ NewAttr &= ~FILE_ATTRIBUTE_SYSTEM;
+ }
+
+ if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) {
+ NewAttr |= FILE_ATTRIBUTE_READONLY;
+ } else {
+ NewAttr &= ~FILE_ATTRIBUTE_READONLY;
+ }
+
+ NtStatus = SetFileAttributes (NewFileName, NewAttr);
+
+ if (!NtStatus) {
+ Status = EFI_DEVICE_ERROR;
+ goto Reopen;
+ }
+
+Done:
+ if (OldFileInfo != NULL) {
+ FreePool (OldFileInfo);
+ }
+
+ if (OldFileName != NULL) {
+ FreePool (OldFileName);
+ }
+
+ if (NewFileName != NULL) {
+ FreePool (NewFileName);
+ }
+
+ return Status;
+}
+
+
+/**
+ Flush data back for the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+WinNtFileFlush (
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ BY_HANDLE_FILE_INFORMATION FileInfo;
+ WIN_NT_EFI_FILE_PRIVATE *PrivateFile;
+ EFI_STATUS Status;
+
+ PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+ if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ if (PrivateFile->IsDirectoryPath) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ if (PrivateFile->IsOpenedByRead) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ GetFileInformationByHandle (PrivateFile->LHandle, &FileInfo);
+
+ if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+
+ Status = FlushFileBuffers (PrivateFile->LHandle) ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+
+Done:
+ return Status;
+ //
+ // bugbug: - Use Windows error reporting.
+ //
+
+}
+
+
+
+EFI_STATUS
+WinNtFileSystmeThunkOpen (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ )
+{
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
+
+ Private = AllocateZeroPool (sizeof (*Private));
+ if (Private == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->FilePath = AllocateCopyPool (StrSize (This->ConfigString), This->ConfigString);
+ if (Private->FilePath == NULL) {
+ FreePool (Private);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->VolumeLabel = AllocateCopyPool (StrSize (L"EFI_EMULATED"), L"EFI_EMULATED");
+ if (Private->VolumeLabel == NULL) {
+ FreePool (Private->FilePath);
+ FreePool (Private);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Signature = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE;
+ Private->Thunk = This;
+ CopyMem (&Private->SimpleFileSystem, &gWinNtFileSystemProtocol, sizeof (Private->SimpleFileSystem));
+
+ This->Interface = &Private->SimpleFileSystem;
+ This->Private = Private;
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+WinNtFileSystmeThunkClose (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ )
+{
+ WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private;
+
+ Private = This->Private;
+ ASSERT (Private != NULL);
+
+ if (Private->VolumeLabel != NULL) {
+ FreePool (Private->VolumeLabel);
+ }
+ if (Private->FilePath != NULL) {
+ FreePool (Private->FilePath);
+ }
+ FreePool (Private);
+ return EFI_SUCCESS;
+}
+
+
+EFI_FILE_PROTOCOL gWinNtFileProtocol = {
+ EFI_FILE_REVISION,
+ WinNtFileOpen,
+ WinNtFileClose,
+ WinNtFileDelete,
+ WinNtFileRead,
+ WinNtFileWrite,
+ WinNtFileGetPossition,
+ WinNtFileSetPossition,
+ WinNtFileGetInfo,
+ WinNtFileSetInfo,
+ WinNtFileFlush
+};
+
+EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gWinNtFileSystemProtocol = {
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
+ WinNtOpenVolume
+};
+
+
+EMU_IO_THUNK_PROTOCOL mWinNtFileSystemThunkIo = {
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ NULL,
+ 0,
+ WinNtFileSystmeThunkOpen,
+ WinNtFileSystmeThunkClose,
+ NULL
+};
+
+
diff --git a/roms/edk2/EmulatorPkg/Win/Host/WinGop.h b/roms/edk2/EmulatorPkg/Win/Host/WinGop.h
new file mode 100644
index 000000000..7a8f01a37
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/Host/WinGop.h
@@ -0,0 +1,204 @@
+/** @file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ WinGop.h
+
+Abstract:
+
+ Private data for the Gop driver that is bound to the WinNt Thunk protocol
+
+
+**/
+
+#ifndef _WIN_GOP_H_
+#define _WIN_GOP_H_
+
+
+#include "WinHost.h"
+
+#include <Protocol/EmuIoThunk.h>
+#include <Protocol/EmuGraphicsWindow.h>
+#include <Protocol/SimplePointer.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Library/FrameBufferBltLib.h>
+
+//
+// WM_SYSKEYDOWN/WM_SYSKEYUP Notification
+// lParam
+// bit 24: Specifies whether the key is an extended key,
+// such as the right-hand ALT and CTRL keys that appear on
+// an enhanced 101- or 102-key keyboard.
+// The value is 1 if it is an extended key; otherwise, it is 0.
+// bit 29:Specifies the context code.
+// The value is 1 if the ALT key is down while the key is pressed/released;
+// it is 0 if the WM_SYSKEYDOWN message is posted to the active window
+// because no window has the keyboard focus.
+#define GOP_EXTENDED_KEY (0x1 << 24)
+#define GOP_ALT_KEY_PRESSED (0x1 << 29)
+
+#define KEYBOARD_TIMER_INTERVAL 200000 // 0.02s
+
+#define MAX_Q 256
+
+typedef struct {
+ UINTN Front;
+ UINTN Rear;
+ EFI_KEY_DATA Q[MAX_Q];
+ CRITICAL_SECTION Cs;
+} GOP_QUEUE_FIXED;
+
+#define WIN_NT_GOP_CLASS_NAME L"WinNtGopWindow"
+
+
+typedef struct {
+ UINT64 Signature;
+ EMU_GRAPHICS_WINDOW_PROTOCOL GraphicsWindowIo;
+
+ //
+ // GOP Private Data knowing when to start hardware
+ //
+ BOOLEAN HardwareNeedsStarting;
+
+ CHAR16 *WindowName;
+ CHAR16 Buffer[160];
+
+ HANDLE ThreadInited; // Semaphore
+ HANDLE ThreadHandle; // Thread
+ DWORD ThreadId;
+
+ HWND WindowHandle;
+ WNDCLASSEX WindowsClass;
+
+ UINT32 Width;
+ UINT32 Height;
+ //
+ // This screen is used to redraw the screen when windows events happen. It's
+ // updated in the main thread and displayed in the windows thread.
+ //
+ BITMAPV4HEADER *VirtualScreenInfo;
+
+ FRAME_BUFFER_CONFIGURE *FrameBufferConfigure;
+
+ //
+ // Keyboard Queue used by Simple Text In.
+ // QueueForRead: WinProc thread adds, and main thread removes.
+ //
+ GOP_QUEUE_FIXED QueueForRead;
+
+ EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeRegisterdKeyCallback;
+ EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakRegisterdKeyCallback;
+ VOID *RegisterdKeyCallbackContext;
+
+ EFI_KEY_STATE KeyState;
+ BOOLEAN LeftShift;
+ BOOLEAN RightShift;
+ BOOLEAN LeftAlt;
+ BOOLEAN RightAlt;
+ BOOLEAN LeftCtrl;
+ BOOLEAN RightCtrl;
+ BOOLEAN LeftLogo;
+ BOOLEAN RightLogo;
+ BOOLEAN Menu;
+ BOOLEAN SysReq;
+ BOOLEAN NumLock;
+ BOOLEAN ScrollLock;
+ BOOLEAN CapsLock;
+ BOOLEAN IsPartialKeySupport;
+ INT32 PointerPreviousX;
+ INT32 PointerPreviousY;
+ BOOLEAN PointerStateChanged;
+ EFI_SIMPLE_POINTER_STATE PointerState;
+} GRAPHICS_PRIVATE_DATA;
+#define GRAPHICS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('g', 'f', 'x', 'd')
+#define GRAPHICS_PRIVATE_DATA_FROM_THIS(a) \
+ CR(a, GRAPHICS_PRIVATE_DATA, GraphicsWindowIo, GRAPHICS_PRIVATE_DATA_SIGNATURE)
+
+
+//
+// Gop Hardware abstraction internal worker functions
+//
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param Key TODO: add argument description
+
+ @return TODO: add return values
+
+**/
+EFI_STATUS
+GopPrivateAddKey (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN EFI_INPUT_KEY Key
+ );
+
+EFI_STATUS
+EFIAPI
+WinNtWndGetKey (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_KEY_DATA *KeyData
+ );
+
+EFI_STATUS
+EFIAPI
+WinNtWndCheckKey (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo
+ );
+
+EFI_STATUS
+EFIAPI
+WinNtWndKeySetState (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ );
+
+EFI_STATUS
+EFIAPI
+WinNtWndRegisterKeyNotify (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeCallBack,
+ IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakCallBack,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+EFIAPI
+WinNtWndCheckPointer (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo
+ );
+
+EFI_STATUS
+EFIAPI
+WinNtWndGetPointerState (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_SIMPLE_POINTER_STATE *State
+ );
+EFI_STATUS
+GopPrivateCreateQ (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN GOP_QUEUE_FIXED *Queue
+ );
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateDestroyQ (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN GOP_QUEUE_FIXED *Queue
+ );
+#endif
+
diff --git a/roms/edk2/EmulatorPkg/Win/Host/WinGopInput.c b/roms/edk2/EmulatorPkg/Win/Host/WinGopInput.c
new file mode 100644
index 000000000..6ae7aa4c3
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/Host/WinGopInput.c
@@ -0,0 +1,447 @@
+/** @file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ WinGopInput.c
+
+Abstract:
+
+ This file produces the Simple Text In for an Gop window.
+
+ This stuff is linked at the hip to the Window, since the window
+ processing is done in a thread kicked off in WinNtGopImplementation.c
+
+ Since the window information is processed in an other thread we need
+ a keyboard Queue to pass data about. The Simple Text In code just
+ takes data off the Queue. The WinProc message loop takes keyboard input
+ and places it in the Queue.
+
+
+**/
+
+
+#include "WinGop.h"
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateCreateQ (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN GOP_QUEUE_FIXED *Queue
+ )
+{
+ InitializeCriticalSection (&Queue->Cs);
+ Queue->Front = 0;
+ Queue->Rear = 0;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateDestroyQ (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN GOP_QUEUE_FIXED *Queue
+ )
+{
+ Queue->Front = 0;
+ Queue->Rear = 0;
+ DeleteCriticalSection (&Queue->Cs);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param Key TODO: add argument description
+
+ @retval EFI_NOT_READY TODO: Add description for return value
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateAddQ (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN GOP_QUEUE_FIXED *Queue,
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ EnterCriticalSection (&Queue->Cs);
+
+ if ((Queue->Rear + 1) % MAX_Q == Queue->Front) {
+ LeaveCriticalSection (&Queue->Cs);
+ return EFI_NOT_READY;
+ }
+
+ CopyMem (&Queue->Q[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
+ Queue->Rear = (Queue->Rear + 1) % MAX_Q;
+
+ LeaveCriticalSection (&Queue->Cs);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param Key TODO: add argument description
+
+ @retval EFI_NOT_READY TODO: Add description for return value
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateDeleteQ (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN GOP_QUEUE_FIXED *Queue,
+ OUT EFI_KEY_DATA *Key
+ )
+{
+ EnterCriticalSection (&Queue->Cs);
+
+ if (Queue->Front == Queue->Rear) {
+ LeaveCriticalSection (&Queue->Cs);
+ return EFI_NOT_READY;
+ }
+
+ CopyMem (Key, &Queue->Q[Queue->Front], sizeof (EFI_KEY_DATA));
+ Queue->Front = (Queue->Front + 1) % MAX_Q;
+
+ if (Key->Key.ScanCode == SCAN_NULL && Key->Key.UnicodeChar == CHAR_NULL) {
+ if (!Private->IsPartialKeySupport) {
+ //
+ // If partial keystrok is not enabled, don't return the partial keystroke.
+ //
+ LeaveCriticalSection (&Queue->Cs);
+ ZeroMem (Key, sizeof (EFI_KEY_DATA));
+ return EFI_NOT_READY;
+ }
+ }
+ LeaveCriticalSection (&Queue->Cs);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ @retval EFI_NOT_READY TODO: Add description for return value
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateCheckQ (
+ IN GOP_QUEUE_FIXED *Queue
+ )
+{
+ if (Queue->Front == Queue->Rear) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the key state.
+
+ @param Private The GOP_PRIVATE_DATA instance.
+ @param KeyState A pointer to receive the key state information.
+**/
+VOID
+InitializeKeyState (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN EFI_KEY_STATE *KeyState
+ )
+{
+ KeyState->KeyShiftState = EFI_SHIFT_STATE_VALID;
+ KeyState->KeyToggleState = EFI_TOGGLE_STATE_VALID;
+
+ //
+ // Record Key shift state and toggle state
+ //
+ if (Private->LeftCtrl) {
+ KeyState->KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
+ }
+ if (Private->RightCtrl) {
+ KeyState->KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
+ }
+ if (Private->LeftAlt) {
+ KeyState->KeyShiftState |= EFI_LEFT_ALT_PRESSED;
+ }
+ if (Private->RightAlt) {
+ KeyState->KeyShiftState |= EFI_RIGHT_ALT_PRESSED;
+ }
+ if (Private->LeftShift) {
+ KeyState->KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
+ }
+ if (Private->RightShift) {
+ KeyState->KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
+ }
+ if (Private->LeftLogo) {
+ KeyState->KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
+ }
+ if (Private->RightLogo) {
+ KeyState->KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;
+ }
+ if (Private->Menu) {
+ KeyState->KeyShiftState |= EFI_MENU_KEY_PRESSED;
+ }
+ if (Private->SysReq) {
+ KeyState->KeyShiftState |= EFI_SYS_REQ_PRESSED;
+ }
+ if (Private->CapsLock) {
+ KeyState->KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
+ }
+ if (Private->NumLock) {
+ KeyState->KeyToggleState |= EFI_NUM_LOCK_ACTIVE;
+ }
+ if (Private->ScrollLock) {
+ KeyState->KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;
+ }
+ if (Private->IsPartialKeySupport) {
+ KeyState->KeyToggleState |= EFI_KEY_STATE_EXPOSED;
+ }
+}
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param Key TODO: add argument description
+
+ @retval EFI_NOT_READY TODO: Add description for return value
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateAddKey (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN EFI_INPUT_KEY Key
+ )
+{
+ EFI_KEY_DATA KeyData;
+
+ KeyData.Key = Key;
+ InitializeKeyState (Private, &KeyData.KeyState);
+
+ //
+ // Convert Ctrl+[1-26] to Ctrl+[A-Z]
+ //
+ if ((Private->LeftCtrl || Private->RightCtrl) &&
+ (KeyData.Key.UnicodeChar >= 1) && (KeyData.Key.UnicodeChar <= 26)
+ ) {
+ if ((Private->LeftShift || Private->RightShift) == Private->CapsLock) {
+ KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'a' - 1);
+ } else {
+ KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'A' - 1);
+ }
+ }
+
+ //
+ // Unmask the Shift bit for printable char
+ //
+ if (((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) ||
+ ((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z'))
+ ) {
+ KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);
+ }
+
+ GopPrivateAddQ (Private, &Private->QueueForRead, &KeyData);
+ if (Private->MakeRegisterdKeyCallback != NULL) {
+ Private->MakeRegisterdKeyCallback (Private->RegisterdKeyCallbackContext, &KeyData);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+WinNtWndCheckKey (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo
+ )
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+ return GopPrivateCheckQ (&Private->QueueForRead);
+
+}
+EFI_STATUS
+EFIAPI
+WinNtWndGetKey (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_KEY_DATA *KeyData
+ )
+/*++
+
+ Routine Description:
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existence of a keystroke via WaitForEvent () call.
+
+ Arguments:
+ Private - The private structure of WinNt Gop device.
+ KeyData - A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ Returns:
+ EFI_SUCCESS - The keystroke information was returned.
+ EFI_NOT_READY - There was no keystroke data available.
+ EFI_DEVICE_ERROR - The keystroke information was not returned due to
+ hardware errors.
+ EFI_INVALID_PARAMETER - KeyData is NULL.
+
+--*/
+{
+ EFI_STATUS Status;
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+ ZeroMem (&KeyData->Key, sizeof (KeyData->Key));
+ InitializeKeyState (Private, &KeyData->KeyState);
+
+ Status = GopPrivateCheckQ (&Private->QueueForRead);
+ if (!EFI_ERROR (Status)) {
+ //
+ // If a Key press exists try and read it.
+ //
+ Status = GopPrivateDeleteQ (Private, &Private->QueueForRead, KeyData);
+ if (!EFI_ERROR (Status)) {
+ //
+ // If partial keystroke is not enabled, check whether it is value key. If not return
+ // EFI_NOT_READY.
+ //
+ if (!Private->IsPartialKeySupport) {
+ if (KeyData->Key.ScanCode == SCAN_NULL && KeyData->Key.UnicodeChar == CHAR_NULL) {
+ Status = EFI_NOT_READY;
+ }
+ }
+ }
+ }
+
+ return Status;
+
+}
+
+EFI_STATUS
+EFIAPI
+WinNtWndKeySetState (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ )
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+ Private->ScrollLock = FALSE;
+ Private->NumLock = FALSE;
+ Private->CapsLock = FALSE;
+ Private->IsPartialKeySupport = FALSE;
+
+ if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
+ Private->ScrollLock = TRUE;
+ }
+ if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
+ Private->NumLock = TRUE;
+ }
+ if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
+ Private->CapsLock = TRUE;
+ }
+ if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
+ Private->IsPartialKeySupport = TRUE;
+ }
+ Private->KeyState.KeyToggleState = *KeyToggleState;
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+WinNtWndRegisterKeyNotify (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeCallBack,
+ IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakCallBack,
+ IN VOID *Context
+ )
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+ Private->MakeRegisterdKeyCallback = MakeCallBack;
+ Private->BreakRegisterdKeyCallback = BreakCallBack;
+ Private->RegisterdKeyCallbackContext = Context;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+WinNtWndCheckPointer (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo
+ )
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+ if (!Private->PointerStateChanged) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+WinNtWndGetPointerState (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_SIMPLE_POINTER_STATE *State
+ )
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+ if (!Private->PointerStateChanged) {
+ return EFI_NOT_READY;
+ }
+
+ State->RelativeMovementX = Private->PointerState.RelativeMovementX;
+ State->RelativeMovementY = Private->PointerState.RelativeMovementY;
+ State->RelativeMovementZ = Private->PointerState.RelativeMovementZ;
+ State->LeftButton = Private->PointerState.LeftButton;
+ State->RightButton = Private->PointerState.RightButton;
+
+ Private->PointerState.RelativeMovementX = 0;
+ Private->PointerState.RelativeMovementY = 0;
+ Private->PointerState.RelativeMovementZ = 0;
+
+ Private->PointerStateChanged = FALSE;
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/EmulatorPkg/Win/Host/WinGopScreen.c b/roms/edk2/EmulatorPkg/Win/Host/WinGopScreen.c
new file mode 100644
index 000000000..74011e225
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/Host/WinGopScreen.c
@@ -0,0 +1,827 @@
+/** @file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ WinGopScreen.c
+
+Abstract:
+
+ This file produces the graphics abstration of GOP. It is called by
+ WinNtGopDriver.c file which deals with the UEFI 2.0 driver model.
+ This file just does graphics.
+
+
+**/
+
+#include "WinGop.h"
+
+DWORD mTlsIndex = TLS_OUT_OF_INDEXES;
+DWORD mTlsIndexUseCount = 0; // lets us know when we can free mTlsIndex.
+
+BOOLEAN
+WinNtGopConvertParamToEfiKeyShiftState (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN WPARAM *wParam,
+ IN LPARAM *lParam,
+ IN BOOLEAN Flag
+ )
+{
+ switch (*wParam) {
+ //
+ // BUGBUG: Only GetAsyncKeyState() and GetKeyState() can distinguish
+ // left and right Ctrl, and Shift key.
+ // Neither of the two is defined in EFI_WIN_NT_THUNK_PROTOCOL.
+ // Therefor, we can not set the correct Shift state here.
+ //
+ case VK_SHIFT:
+ if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
+ Private->RightShift = Flag;
+ } else {
+ Private->LeftShift = Flag;
+ }
+ return TRUE;
+
+ case VK_LSHIFT:
+ Private->LeftShift = Flag;
+ return TRUE;
+
+ case VK_RSHIFT:
+ Private->RightShift = Flag;
+ return TRUE;
+
+ case VK_CONTROL:
+ if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
+ Private->RightCtrl= Flag;
+ } else {
+ Private->LeftCtrl = Flag;
+ }
+ return TRUE;
+
+ case VK_LCONTROL:
+ Private->LeftCtrl = Flag;
+ return TRUE;
+
+ case VK_RCONTROL:
+ Private->RightCtrl = Flag;
+ return TRUE;
+
+ case VK_LWIN:
+ Private->LeftLogo = Flag;
+ return TRUE;
+
+ case VK_RWIN:
+ Private->RightLogo = Flag;
+ return TRUE;
+
+ case VK_APPS:
+ Private->Menu = Flag;
+ return TRUE;
+ //
+ // BUGBUG: PrintScreen/SysRq can not trigger WM_KEYDOWN message,
+ // so SySReq shift state is not supported here.
+ //
+ case VK_PRINT:
+ Private->SysReq = Flag;
+ return TRUE;
+ //
+ // For Alt Keystroke.
+ //
+ case VK_MENU:
+ if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
+ Private->RightAlt = Flag;
+ } else {
+ Private->LeftAlt = Flag;
+ }
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+BOOLEAN
+WinNtGopConvertParamToEfiKey (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN WPARAM *wParam,
+ IN LPARAM *lParam,
+ IN EFI_INPUT_KEY *Key
+ )
+{
+ BOOLEAN Flag;
+ Flag = FALSE;
+ switch (*wParam) {
+ case VK_HOME: Key->ScanCode = SCAN_HOME; Flag = TRUE; break;
+ case VK_END: Key->ScanCode = SCAN_END; Flag = TRUE; break;
+ case VK_LEFT: Key->ScanCode = SCAN_LEFT; Flag = TRUE; break;
+ case VK_RIGHT: Key->ScanCode = SCAN_RIGHT; Flag = TRUE; break;
+ case VK_UP: Key->ScanCode = SCAN_UP; Flag = TRUE; break;
+ case VK_DOWN: Key->ScanCode = SCAN_DOWN; Flag = TRUE; break;
+ case VK_DELETE: Key->ScanCode = SCAN_DELETE; Flag = TRUE; break;
+ case VK_INSERT: Key->ScanCode = SCAN_INSERT; Flag = TRUE; break;
+ case VK_PRIOR: Key->ScanCode = SCAN_PAGE_UP; Flag = TRUE; break;
+ case VK_NEXT: Key->ScanCode = SCAN_PAGE_DOWN; Flag = TRUE; break;
+ case VK_ESCAPE: Key->ScanCode = SCAN_ESC; Flag = TRUE; break;
+
+ case VK_F1: Key->ScanCode = SCAN_F1; Flag = TRUE; break;
+ case VK_F2: Key->ScanCode = SCAN_F2; Flag = TRUE; break;
+ case VK_F3: Key->ScanCode = SCAN_F3; Flag = TRUE; break;
+ case VK_F4: Key->ScanCode = SCAN_F4; Flag = TRUE; break;
+ case VK_F5: Key->ScanCode = SCAN_F5; Flag = TRUE; break;
+ case VK_F6: Key->ScanCode = SCAN_F6; Flag = TRUE; break;
+ case VK_F7: Key->ScanCode = SCAN_F7; Flag = TRUE; break;
+ case VK_F8: Key->ScanCode = SCAN_F8; Flag = TRUE; break;
+ case VK_F9: Key->ScanCode = SCAN_F9; Flag = TRUE; break;
+ case VK_F11: Key->ScanCode = SCAN_F11; Flag = TRUE; break;
+ case VK_F12: Key->ScanCode = SCAN_F12; Flag = TRUE; break;
+
+ case VK_F13: Key->ScanCode = SCAN_F13; Flag = TRUE; break;
+ case VK_F14: Key->ScanCode = SCAN_F14; Flag = TRUE; break;
+ case VK_F15: Key->ScanCode = SCAN_F15; Flag = TRUE; break;
+ case VK_F16: Key->ScanCode = SCAN_F16; Flag = TRUE; break;
+ case VK_F17: Key->ScanCode = SCAN_F17; Flag = TRUE; break;
+ case VK_F18: Key->ScanCode = SCAN_F18; Flag = TRUE; break;
+ case VK_F19: Key->ScanCode = SCAN_F19; Flag = TRUE; break;
+ case VK_F20: Key->ScanCode = SCAN_F20; Flag = TRUE; break;
+ case VK_F21: Key->ScanCode = SCAN_F21; Flag = TRUE; break;
+ case VK_F22: Key->ScanCode = SCAN_F22; Flag = TRUE; break;
+ case VK_F23: Key->ScanCode = SCAN_F23; Flag = TRUE; break;
+ case VK_F24: Key->ScanCode = SCAN_F24; Flag = TRUE; break;
+ case VK_PAUSE: Key->ScanCode = SCAN_PAUSE; Flag = TRUE; break;
+
+ //
+ // Set toggle state
+ //
+ case VK_NUMLOCK:
+ Private->NumLock = (BOOLEAN)(!Private->NumLock);
+ Flag = TRUE;
+ break;
+ case VK_SCROLL:
+ Private->ScrollLock = (BOOLEAN)(!Private->ScrollLock);
+ Flag = TRUE;
+ break;
+ case VK_CAPITAL:
+ Private->CapsLock = (BOOLEAN)(!Private->CapsLock);
+ Flag = TRUE;
+ break;
+ }
+
+ return (WinNtGopConvertParamToEfiKeyShiftState (Private, wParam, lParam, TRUE)) == TRUE ? TRUE : Flag;
+}
+
+
+//
+// GOP Protocol Member Functions
+//
+
+/**
+ Change the resolution and resize of the window
+**/
+EFI_STATUS
+EFIAPI
+WinNtWndSize (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN UINT32 Width,
+ IN UINT32 Height
+)
+{
+ RETURN_STATUS RStatus;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION Info;
+ GRAPHICS_PRIVATE_DATA *Private;
+ RECT Rect;
+ BITMAPV4HEADER *VirtualScreenInfo;
+ FRAME_BUFFER_CONFIGURE *FrameBufferConfigure;
+ UINTN FrameBufferConfigureSize;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+ //
+ // Allocate DIB frame buffer directly from NT for performance enhancement
+ // This buffer is the virtual screen/frame buffer.
+ //
+ VirtualScreenInfo = HeapAlloc (
+ GetProcessHeap (),
+ HEAP_ZERO_MEMORY,
+ Width * Height * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER)
+ );
+ if (VirtualScreenInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Update the virtual screen info data structure
+ // Use negative Height to make sure screen/buffer are using the same coordinate.
+ //
+ VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);
+ VirtualScreenInfo->bV4Width = Width;
+ VirtualScreenInfo->bV4Height = -(LONG)Height;
+ VirtualScreenInfo->bV4Planes = 1;
+ VirtualScreenInfo->bV4BitCount = 32;
+ //
+ // uncompressed
+ //
+ VirtualScreenInfo->bV4V4Compression = BI_RGB;
+
+ Info.HorizontalResolution = Width;
+ Info.VerticalResolution = Height;
+ Info.PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
+ Info.PixelsPerScanLine = Width;
+ FrameBufferConfigureSize = 0;
+ RStatus = FrameBufferBltConfigure (VirtualScreenInfo + 1, &Info, NULL, &FrameBufferConfigureSize);
+ ASSERT (RStatus == EFI_BUFFER_TOO_SMALL);
+ FrameBufferConfigure = AllocatePool (FrameBufferConfigureSize);
+ if (FrameBufferConfigure == NULL) {
+ HeapFree (GetProcessHeap (), 0, VirtualScreenInfo);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ RStatus = FrameBufferBltConfigure (VirtualScreenInfo + 1, &Info, FrameBufferConfigure, &FrameBufferConfigureSize);
+ ASSERT_RETURN_ERROR (RStatus);
+
+
+ if (Private->FrameBufferConfigure != NULL) {
+ FreePool (Private->FrameBufferConfigure);
+ }
+ Private->FrameBufferConfigure = FrameBufferConfigure;
+
+ //
+ // Free the old buffer. We do not save the content of the old buffer since the
+ // screen is to be cleared anyway. Clearing the screen is required by the EFI spec.
+ // See UEFI spec -EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode()
+ //
+ if (Private->VirtualScreenInfo != NULL) {
+ HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);
+ }
+ Private->VirtualScreenInfo = VirtualScreenInfo;
+
+ Private->Width = Width;
+ Private->Height = Height;
+
+ //
+ // Use the AdjuctWindowRect fuction to calculate the real width and height
+ // of the new window including the border and caption
+ //
+ Rect.left = 0;
+ Rect.top = 0;
+ Rect.right = Width;
+ Rect.bottom = Height;
+
+ AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);
+
+ Width = Rect.right - Rect.left;
+ Height = Rect.bottom - Rect.top;
+
+ //
+ // Retrieve the original window position information
+ //
+ GetWindowRect (Private->WindowHandle, &Rect);
+
+ //
+ // Adjust the window size
+ //
+ MoveWindow (Private->WindowHandle, Rect.left, Rect.top, (INT32)Width, (INT32)Height, TRUE);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Blt pixels from the rectangle (Width X Height) formed by the BltBuffer
+ onto the graphics screen starting a location (X, Y). (0, 0) is defined as
+ the upper left hand side of the screen. (X, Y) can be outside of the
+ current screen geometry and the BltBuffer will be cliped when it is
+ displayed. X and Y can be negative or positive. If Width or Height is
+ bigger than the current video screen the image will be clipped.
+
+ @param This Protocol instance pointer.
+ @param X X location on graphics screen.
+ @param Y Y location on the graphics screen.
+ @param Width Width of BltBuffer.
+ @param Height Height of BltBuffer
+ @param BltOperation Operation to perform on BltBuffer and video memory
+ @param BltBuffer Buffer containing data to blt into video buffer.
+ This buffer has a size of
+ Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ @param SourceX If the BltOperation is a EfiCopyBlt this is the
+ source of the copy. For other BLT operations this
+ argument is not used.
+ @param SourceX If the BltOperation is a EfiCopyBlt this is the
+ source of the copy. For other BLT operations this
+ argument is not used.
+
+ @retval EFI_SUCCESS The palette is updated with PaletteArray.
+ @retval EFI_INVALID_PARAMETER BltOperation is not valid.
+ @retval EFI_DEVICE_ERROR A hardware error occurred writing to the video
+ buffer.
+
+**/
+// TODO: SourceY - add argument and description to function comment
+// TODO: DestinationX - add argument and description to function comment
+// TODO: DestinationY - add argument and description to function comment
+// TODO: Delta - add argument and description to function comment
+EFI_STATUS
+WinNtWndBlt (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
+ IN EFI_UGA_BLT_OPERATION BltOperation,
+ IN EMU_GRAPHICS_WINDOWS__BLT_ARGS *Args
+)
+{
+ RETURN_STATUS RStatus;
+ GRAPHICS_PRIVATE_DATA *Private;
+ RECT Rect;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+ RStatus = FrameBufferBlt (
+ Private->FrameBufferConfigure,
+ BltBuffer,
+ BltOperation,
+ Args->SourceX, Args->SourceY,
+ Args->DestinationX, Args->DestinationY,
+ Args->Width, Args->Height,
+ Args->Delta
+ );
+ if (RETURN_ERROR (RStatus)) {
+ return (EFI_STATUS)RStatus;
+ }
+
+ if (BltOperation != EfiBltVideoToBltBuffer) {
+ //
+ // Mark the area we just blted as Invalid so WM_PAINT will update.
+ //
+ Rect.left = (LONG)Args->DestinationX;
+ Rect.top = (LONG)Args->DestinationY;
+ Rect.right = (LONG)(Args->DestinationX + Args->Width);
+ Rect.bottom = (LONG)(Args->DestinationY + Args->Height);
+ InvalidateRect (Private->WindowHandle, &Rect, FALSE);
+
+ //
+ // Send the WM_PAINT message to the thread that is drawing the window. We
+ // are in the main thread and the window drawing is in a child thread.
+ // There is a child thread per window. We have no CriticalSection or Mutex
+ // since we write the data and the other thread displays the data. While
+ // we may miss some data for a short period of time this is no different than
+ // a write combining on writes to a frame buffer.
+ //
+
+ UpdateWindow (Private->WindowHandle);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Win32 Windows event handler.
+
+ See Win32 Book
+
+ @return See Win32 Book
+
+**/
+// TODO: hwnd - add argument and description to function comment
+// TODO: iMsg - add argument and description to function comment
+// TODO: wParam - add argument and description to function comment
+// TODO: lParam - add argument and description to function comment
+LRESULT
+CALLBACK
+WinNtGopThreadWindowProc (
+ IN HWND hwnd,
+ IN UINT iMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+ HDC Handle;
+ PAINTSTRUCT PaintStruct;
+ LPARAM Index;
+ EFI_INPUT_KEY Key;
+ BOOLEAN AltIsPress;
+ INT32 PosX;
+ INT32 PosY;
+
+ //
+ // Use mTlsIndex global to get a Thread Local Storage version of Private.
+ // This works since each Gop protocol has a unique Private data instance and
+ // a unique thread.
+ //
+ AltIsPress = FALSE;
+ Private = TlsGetValue (mTlsIndex);
+ ASSERT (NULL != Private);
+
+ switch (iMsg) {
+ case WM_PAINT:
+ Handle = BeginPaint (hwnd, &PaintStruct);
+
+ SetDIBitsToDevice (
+ Handle, // Destination Device Context
+ 0, // Destination X - 0
+ 0, // Destination Y - 0
+ Private->Width, // Width
+ Private->Height, // Height
+ 0, // Source X
+ 0, // Source Y
+ 0, // DIB Start Scan Line
+ Private->Height, // Number of scan lines
+ Private->VirtualScreenInfo + 1, // Address of array of DIB bits
+ (BITMAPINFO *) Private->VirtualScreenInfo, // Address of structure with bitmap info
+ DIB_RGB_COLORS // RGB or palette indexes
+ );
+
+ EndPaint (hwnd, &PaintStruct);
+ return 0;
+
+ //
+ // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case
+ // WM_SYSKEYDOWN is posted when F10 is pressed or
+ // holds down ALT key and then presses another key.
+ //
+ case WM_SYSKEYDOWN:
+
+ Key.ScanCode = 0;
+ Key.UnicodeChar = CHAR_NULL;
+ switch (wParam) {
+ case VK_F10:
+ Key.ScanCode = SCAN_F10;
+ Key.UnicodeChar = CHAR_NULL;
+ GopPrivateAddKey (Private, Key);
+ return 0;
+ }
+
+ //
+ // If ALT or ALT + modifier key is pressed.
+ //
+ if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {
+ if (Key.ScanCode != 0){
+ //
+ // If ALT is pressed with other ScanCode.
+ // Always revers the left Alt for simple.
+ //
+ Private->LeftAlt = TRUE;
+ }
+ GopPrivateAddKey (Private, Key);
+ //
+ // When Alt is released there is no windoes message, so
+ // clean it after using it.
+ //
+ Private->RightAlt = FALSE;
+ Private->LeftAlt = FALSE;
+ return 0;
+ }
+ AltIsPress = TRUE;
+
+ case WM_CHAR:
+ //
+ // The ESC key also generate WM_CHAR.
+ //
+ if (wParam == 0x1B) {
+ return 0;
+ }
+
+ if (AltIsPress == TRUE) {
+ //
+ // If AltIsPress is true that means the Alt key is pressed.
+ //
+ Private->LeftAlt = TRUE;
+ }
+ for (Index = 0; Index < (lParam & 0xffff); Index++) {
+ if (wParam != 0) {
+ Key.UnicodeChar = (CHAR16) wParam;
+ Key.ScanCode = SCAN_NULL;
+ GopPrivateAddKey (Private, Key);
+ }
+ }
+ if (AltIsPress == TRUE) {
+ //
+ // When Alt is released there is no windoes message, so
+ // clean it after using it.
+ //
+ Private->LeftAlt = FALSE;
+ Private->RightAlt = FALSE;
+ }
+ return 0;
+
+ case WM_SYSKEYUP:
+ //
+ // ALT is pressed with another key released
+ //
+ WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);
+ return 0;
+
+ case WM_KEYDOWN:
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = CHAR_NULL;
+ //
+ // A value key press will cause a WM_KEYDOWN first, then cause a WM_CHAR
+ // So if there is no modifier key updated, skip the WM_KEYDOWN even.
+ //
+ if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {
+ //
+ // Support the partial keystroke, add all keydown event into the queue.
+ //
+ GopPrivateAddKey (Private, Key);
+ }
+ return 0;
+
+ case WM_KEYUP:
+ WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);
+ return 0;
+
+ case WM_MOUSEMOVE:
+ PosX = GET_X_LPARAM (lParam);
+ PosY = GET_Y_LPARAM (lParam);
+
+ if (Private->PointerPreviousX != PosX) {
+ Private->PointerState.RelativeMovementX += (PosX - Private->PointerPreviousX);
+ Private->PointerPreviousX = PosX;
+ Private->PointerStateChanged = TRUE;
+ }
+
+ if (Private->PointerPreviousY != PosY) {
+ Private->PointerState.RelativeMovementY += (PosY - Private->PointerPreviousY);
+ Private->PointerPreviousY = PosY;
+ Private->PointerStateChanged = TRUE;
+ }
+
+ Private->PointerState.RelativeMovementZ = 0;
+ return 0;
+
+ case WM_LBUTTONDOWN:
+ Private->PointerState.LeftButton = TRUE;
+ Private->PointerStateChanged = TRUE;
+ return 0;
+
+ case WM_LBUTTONUP:
+ Private->PointerState.LeftButton = FALSE;
+ Private->PointerStateChanged = TRUE;
+ return 0;
+
+ case WM_RBUTTONDOWN:
+ Private->PointerState.RightButton = TRUE;
+ Private->PointerStateChanged = TRUE;
+ return 0;
+
+ case WM_RBUTTONUP:
+ Private->PointerState.RightButton = FALSE;
+ Private->PointerStateChanged = TRUE;
+ return 0;
+
+ case WM_CLOSE:
+ //
+ // This close message is issued by user, core is not aware of this,
+ // so don't release the window display resource, just hide the window.
+ //
+ ShowWindow (Private->WindowHandle, SW_HIDE);
+ return 0;
+
+ case WM_DESTROY:
+ DestroyWindow (hwnd);
+ PostQuitMessage (0);
+
+ HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);
+
+ ExitThread (0);
+
+ default:
+ break;
+ };
+
+ return DefWindowProc (hwnd, iMsg, wParam, lParam);
+}
+
+
+/**
+ This thread simulates the end of WinMain () application. Each Window needs
+ to process its events. The messages are dispatched to
+ WinNtGopThreadWindowProc ().
+ Be very careful since WinNtGopThreadWinMain () and WinNtGopThreadWindowProc ()
+ are running in a separate thread. We have to do this to process the events.
+
+ @param lpParameter Handle of window to manage.
+
+ @return if a WM_QUIT message is returned exit.
+
+**/
+DWORD
+WINAPI
+WinNtGopThreadWinMain (
+ LPVOID lpParameter
+ )
+{
+ MSG Message;
+ GRAPHICS_PRIVATE_DATA *Private;
+ RECT Rect;
+
+ Private = (GRAPHICS_PRIVATE_DATA *) lpParameter;
+ ASSERT (NULL != Private);
+
+ //
+ // Since each thread has unique private data, save the private data in Thread
+ // Local Storage slot. Then the shared global mTlsIndex can be used to get
+ // thread specific context.
+ //
+ TlsSetValue (mTlsIndex, Private);
+
+ Private->ThreadId = GetCurrentThreadId ();
+
+ Private->WindowsClass.cbSize = sizeof (WNDCLASSEX);
+ Private->WindowsClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+ Private->WindowsClass.lpfnWndProc = WinNtGopThreadWindowProc;
+ Private->WindowsClass.cbClsExtra = 0;
+ Private->WindowsClass.cbWndExtra = 0;
+ Private->WindowsClass.hInstance = NULL;
+ Private->WindowsClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
+ Private->WindowsClass.hCursor = LoadCursor (NULL, IDC_ARROW);
+ Private->WindowsClass.hbrBackground = (HBRUSH)(UINTN)COLOR_WINDOW;
+ Private->WindowsClass.lpszMenuName = NULL;
+ Private->WindowsClass.lpszClassName = WIN_NT_GOP_CLASS_NAME;
+ Private->WindowsClass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
+
+ //
+ // Use 100 x 100 as initial Window size.
+ //
+ Private->Width = 100;
+ Private->Height = 100;
+
+
+ //
+ // This call will fail after the first time, but thats O.K. since we only need
+ // WIN_NT_GOP_CLASS_NAME to exist to create the window.
+ //
+ RegisterClassEx (&Private->WindowsClass);
+
+ //
+ // Setting Rect values to allow for the AdjustWindowRect to provide
+ // us the correct sizes for the client area when doing the CreateWindowEx
+ //
+ Rect.top = 0;
+ Rect.bottom = Private->Height;
+ Rect.left = 0;
+ Rect.right = Private->Width;
+
+ AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);
+
+ Private->WindowHandle = CreateWindowEx (
+ 0,
+ WIN_NT_GOP_CLASS_NAME,
+ Private->WindowName,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ Rect.right - Rect.left,
+ Rect.bottom - Rect.top,
+ NULL,
+ NULL,
+ NULL,
+ (VOID **)&Private
+ );
+
+ //
+ // The reset of this thread is the standard windows program. We need a separate
+ // thread since we must process the message loop to make windows act like
+ // windows.
+ //
+
+ ShowWindow (Private->WindowHandle, SW_SHOW);
+ UpdateWindow (Private->WindowHandle);
+
+ //
+ // Let the main thread get some work done
+ //
+ ReleaseSemaphore (Private->ThreadInited, 1, NULL);
+
+ //
+ // This is the message loop that all Windows programs need.
+ //
+ while (GetMessage (&Message, Private->WindowHandle, 0, 0)) {
+ TranslateMessage (&Message);
+ DispatchMessage (&Message);
+ }
+
+ return (DWORD)Message.wParam;
+}
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param HorizontalResolution TODO: add argument description
+ @param VerticalResolution TODO: add argument description
+ @param ColorDepth TODO: add argument description
+ @param RefreshRate TODO: add argument description
+
+ @return TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+WinNtGraphicsWindowOpen (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ )
+{
+ DWORD NewThreadId;
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = AllocateZeroPool (sizeof (*Private));
+
+ GopPrivateCreateQ (Private, &Private->QueueForRead);
+
+ Private->GraphicsWindowIo.Size = WinNtWndSize;
+ Private->GraphicsWindowIo.CheckKey = WinNtWndCheckKey;
+ Private->GraphicsWindowIo.GetKey = WinNtWndGetKey;
+ Private->GraphicsWindowIo.KeySetState = WinNtWndKeySetState;
+ Private->GraphicsWindowIo.RegisterKeyNotify = WinNtWndRegisterKeyNotify;
+ Private->GraphicsWindowIo.Blt = WinNtWndBlt;
+ Private->GraphicsWindowIo.CheckPointer = WinNtWndCheckPointer;
+ Private->GraphicsWindowIo.GetPointerState = WinNtWndGetPointerState;
+
+ Private->WindowName = This->ConfigString;
+ //
+ // Initialize a Thread Local Storge variable slot. We use TLS to get the
+ // correct Private data instance into the windows thread.
+ //
+ if (mTlsIndex == TLS_OUT_OF_INDEXES) {
+ ASSERT (0 == mTlsIndexUseCount);
+ mTlsIndex = TlsAlloc ();
+ }
+
+ //
+ // always increase the use count!
+ //
+ mTlsIndexUseCount++;
+
+ Private->ThreadInited = CreateSemaphore (NULL, 0, 1, NULL);
+ Private->ThreadHandle = CreateThread (
+ NULL,
+ 0,
+ WinNtGopThreadWinMain,
+ (VOID *) Private,
+ 0,
+ &NewThreadId
+ );
+
+ //
+ // The other thread has entered the windows message loop so we can
+ // continue our initialization.
+ //
+ WaitForSingleObject (Private->ThreadInited, INFINITE);
+ CloseHandle (Private->ThreadInited);
+
+ This->Private = Private;
+ This->Interface = &Private->GraphicsWindowIo;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+WinNtGraphicsWindowClose (
+ IN EMU_IO_THUNK_PROTOCOL *This
+)
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = (GRAPHICS_PRIVATE_DATA *)This->Private;
+
+ //
+ // BugBug: Shutdown GOP Hardware and any child devices.
+ //
+ SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0);
+ CloseHandle (Private->ThreadHandle);
+
+ mTlsIndexUseCount--;
+
+ //
+ // The callback function for another window could still be called,
+ // so we need to make sure there are no more users of mTlsIndex.
+ //
+ if (0 == mTlsIndexUseCount) {
+ ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex);
+
+ TlsFree (mTlsIndex);
+ mTlsIndex = TLS_OUT_OF_INDEXES;
+
+ UnregisterClass (
+ Private->WindowsClass.lpszClassName,
+ Private->WindowsClass.hInstance
+ );
+ }
+
+
+ GopPrivateDestroyQ (Private, &Private->QueueForRead);
+ return EFI_SUCCESS;
+}
+
+
+EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo = {
+ &gEmuGraphicsWindowProtocolGuid,
+ NULL,
+ NULL,
+ 0,
+ WinNtGraphicsWindowOpen,
+ WinNtGraphicsWindowClose,
+ NULL
+};
diff --git a/roms/edk2/EmulatorPkg/Win/Host/WinHost.c b/roms/edk2/EmulatorPkg/Win/Host/WinHost.c
new file mode 100644
index 000000000..0838c56dd
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/Host/WinHost.c
@@ -0,0 +1,1097 @@
+/**@file
+ WinNt emulator of pre-SEC phase. It's really a Win32 application, but this is
+ Ok since all the other modules for NT32 are NOT Win32 applications.
+
+ This program gets NT32 PCD setting and figures out what the memory layout
+ will be, how may FD's will be loaded and also what the boot mode is.
+
+ This code produces 128 K of temporary memory for the SEC stack by directly
+ allocate memory space with ReadWrite and Execute attribute.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016-2020 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "WinHost.h"
+
+#ifndef SE_TIME_ZONE_NAME
+#define SE_TIME_ZONE_NAME TEXT("SeTimeZonePrivilege")
+#endif
+
+//
+// The growth size for array of module handle entries
+//
+#define MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE 0x100
+
+//
+// Module handle entry structure
+//
+typedef struct {
+ CHAR8 *PdbPointer;
+ VOID *ModHandle;
+} PDB_NAME_TO_MOD_HANDLE;
+
+//
+// An Array to hold the module handles
+//
+PDB_NAME_TO_MOD_HANDLE *mPdbNameModHandleArray = NULL;
+UINTN mPdbNameModHandleArraySize = 0;
+
+//
+// Default information about where the FD is located.
+// This array gets filled in with information from PcdWinNtFirmwareVolume
+// The number of array elements is allocated base on parsing
+// PcdWinNtFirmwareVolume and the memory is never freed.
+//
+UINTN gFdInfoCount = 0;
+NT_FD_INFO *gFdInfo;
+
+//
+// Array that supports separate memory ranges.
+// The memory ranges are set by PcdWinNtMemorySizeForSecMain.
+// The number of array elements is allocated base on parsing
+// PcdWinNtMemorySizeForSecMain value and the memory is never freed.
+//
+UINTN gSystemMemoryCount = 0;
+NT_SYSTEM_MEMORY *gSystemMemory;
+
+/*++
+
+Routine Description:
+ This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
+ It allows discontinuous memory regions to be supported by the emulator.
+ It uses gSystemMemory[] and gSystemMemoryCount that were created by
+ parsing the host environment variable EFI_MEMORY_SIZE.
+ The size comes from the varaible and the address comes from the call to
+ UnixOpenFile.
+
+Arguments:
+ Index - Which memory region to use
+ MemoryBase - Return Base address of memory region
+ MemorySize - Return size in bytes of the memory region
+
+Returns:
+ EFI_SUCCESS - If memory region was mapped
+ EFI_UNSUPPORTED - If Index is not supported
+
+**/
+EFI_STATUS
+WinPeiAutoScan (
+ IN UINTN Index,
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
+ OUT UINT64 *MemorySize
+ )
+{
+ if (Index >= gSystemMemoryCount) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Allocate enough memory space for emulator
+ //
+ gSystemMemory[Index].Memory = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (gSystemMemory[Index].Size), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if (gSystemMemory[Index].Memory == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *MemoryBase = gSystemMemory[Index].Memory;
+ *MemorySize = gSystemMemory[Index].Size;
+
+ return EFI_SUCCESS;
+}
+
+/*++
+
+Routine Description:
+ Return the FD Size and base address. Since the FD is loaded from a
+ file into host memory only the SEC will know its address.
+
+Arguments:
+ Index - Which FD, starts at zero.
+ FdSize - Size of the FD in bytes
+ FdBase - Start address of the FD. Assume it points to an FV Header
+ FixUp - Difference between actual FD address and build address
+
+Returns:
+ EFI_SUCCESS - Return the Base address and size of the FV
+ EFI_UNSUPPORTED - Index does nto map to an FD in the system
+
+**/
+EFI_STATUS
+WinFdAddress (
+ IN UINTN Index,
+ IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
+ IN OUT UINT64 *FdSize,
+ IN OUT EFI_PHYSICAL_ADDRESS *FixUp
+ )
+{
+ if (Index >= gFdInfoCount) {
+ return EFI_UNSUPPORTED;
+ }
+
+
+ *FdBase = (EFI_PHYSICAL_ADDRESS)(UINTN)gFdInfo[Index].Address;
+ *FdSize = (UINT64)gFdInfo[Index].Size;
+ *FixUp = 0;
+
+ if (*FdBase == 0 && *FdSize == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Index == 0) {
+ //
+ // FD 0 has XIP code and well known PCD values
+ // If the memory buffer could not be allocated at the FD build address
+ // the Fixup is the difference.
+ //
+ *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/*++
+
+Routine Description:
+ Since the SEC is the only Unix program in stack it must export
+ an interface to do POSIX calls. gUnix is initialized in UnixThunk.c.
+
+Arguments:
+ InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
+ InterfaceBase - Address of the gUnix global
+
+Returns:
+ EFI_SUCCESS - Data returned
+
+**/
+VOID *
+WinThunk (
+ VOID
+ )
+{
+ return &gEmuThunkProtocol;
+}
+
+
+EMU_THUNK_PPI mSecEmuThunkPpi = {
+ WinPeiAutoScan,
+ WinFdAddress,
+ WinThunk
+};
+
+VOID
+SecPrint (
+ CHAR8 *Format,
+ ...
+ )
+{
+ va_list Marker;
+ UINTN CharCount;
+ CHAR8 Buffer[0x1000];
+
+ va_start (Marker, Format);
+
+ _vsnprintf (Buffer, sizeof (Buffer), Format, Marker);
+
+ va_end (Marker);
+
+ CharCount = strlen (Buffer);
+ WriteFile (
+ GetStdHandle (STD_OUTPUT_HANDLE),
+ Buffer,
+ (DWORD)CharCount,
+ (LPDWORD)&CharCount,
+ NULL
+ );
+}
+
+/*++
+
+Routine Description:
+ Check to see if an address range is in the EFI GCD memory map.
+
+ This is all of GCD for system memory passed to DXE Core. FV
+ mapping and other device mapped into system memory are not
+ inlcuded in the check.
+
+Arguments:
+ Index - Which memory region to use
+ MemoryBase - Return Base address of memory region
+ MemorySize - Return size in bytes of the memory region
+
+Returns:
+ TRUE - Address is in the EFI GCD memory map
+ FALSE - Address is NOT in memory map
+
+**/
+BOOLEAN
+EfiSystemMemoryRange (
+ IN VOID *MemoryAddress
+ )
+{
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS MemoryBase;
+
+ MemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
+ for (Index = 0; Index < gSystemMemoryCount; Index++) {
+ if ((MemoryBase >= gSystemMemory[Index].Memory) &&
+ (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)) ) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+EFI_STATUS
+WinNtOpenFile (
+ IN CHAR16 *FileName, OPTIONAL
+ IN UINT32 MapSize,
+ IN DWORD CreationDisposition,
+ IN OUT VOID **BaseAddress,
+ OUT UINTN *Length
+ )
+/*++
+
+Routine Description:
+ Opens and memory maps a file using WinNt services. If *BaseAddress is non zero
+ the process will try and allocate the memory starting at BaseAddress.
+
+Arguments:
+ FileName - The name of the file to open and map
+ MapSize - The amount of the file to map in bytes
+ CreationDisposition - The flags to pass to CreateFile(). Use to create new files for
+ memory emulation, and exiting files for firmware volume emulation
+ BaseAddress - The base address of the mapped file in the user address space.
+ If *BaseAddress is 0, the new memory region is used.
+ If *BaseAddress is not 0, the request memory region is used for
+ the mapping of the file into the process space.
+ Length - The size of the mapped region in bytes
+
+Returns:
+ EFI_SUCCESS - The file was opened and mapped.
+ EFI_NOT_FOUND - FileName was not found in the current directory
+ EFI_DEVICE_ERROR - An error occurred attempting to map the opened file
+
+--*/
+{
+ HANDLE NtFileHandle;
+ HANDLE NtMapHandle;
+ VOID *VirtualAddress;
+ UINTN FileSize;
+
+ //
+ // Use Win API to open/create a file
+ //
+ NtFileHandle = INVALID_HANDLE_VALUE;
+ if (FileName != NULL) {
+ NtFileHandle = CreateFile (
+ FileName,
+ GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
+ FILE_SHARE_READ,
+ NULL,
+ CreationDisposition,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+ if (NtFileHandle == INVALID_HANDLE_VALUE) {
+ return EFI_NOT_FOUND;
+ }
+ }
+ //
+ // Map the open file into a memory range
+ //
+ NtMapHandle = CreateFileMapping (
+ NtFileHandle,
+ NULL,
+ PAGE_EXECUTE_READWRITE,
+ 0,
+ MapSize,
+ NULL
+ );
+ if (NtMapHandle == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Get the virtual address (address in the emulator) of the mapped file
+ //
+ VirtualAddress = MapViewOfFileEx (
+ NtMapHandle,
+ FILE_MAP_EXECUTE | FILE_MAP_ALL_ACCESS,
+ 0,
+ 0,
+ MapSize,
+ *BaseAddress
+ );
+ if (VirtualAddress == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (MapSize == 0) {
+ //
+ // Seek to the end of the file to figure out the true file size.
+ //
+ FileSize = SetFilePointer (
+ NtFileHandle,
+ 0,
+ NULL,
+ FILE_END
+ );
+ if (FileSize == -1) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ *Length = FileSize;
+ } else {
+ *Length = MapSize;
+ }
+
+ *BaseAddress = VirtualAddress;
+
+ return EFI_SUCCESS;
+}
+
+INTN
+EFIAPI
+main (
+ IN INT Argc,
+ IN CHAR8 **Argv,
+ IN CHAR8 **Envp
+ )
+/*++
+
+Routine Description:
+ Main entry point to SEC for WinNt. This is a Windows program
+
+Arguments:
+ Argc - Number of command line arguments
+ Argv - Array of command line argument strings
+ Envp - Array of environment variable strings
+
+Returns:
+ 0 - Normal exit
+ 1 - Abnormal exit
+
+--*/
+{
+ EFI_STATUS Status;
+ HANDLE Token;
+ TOKEN_PRIVILEGES TokenPrivileges;
+ VOID *TemporaryRam;
+ UINT32 TemporaryRamSize;
+ VOID *EmuMagicPage;
+ UINTN Index;
+ UINTN Index1;
+ CHAR16 *FileName;
+ CHAR16 *FileNamePtr;
+ BOOLEAN Done;
+ EFI_PEI_FILE_HANDLE FileHandle;
+ VOID *SecFile;
+ CHAR16 *MemorySizeStr;
+ CHAR16 *FirmwareVolumesStr;
+ UINTN ProcessAffinityMask;
+ UINTN SystemAffinityMask;
+ INT32 LowBit;
+
+ //
+ // Enable the privilege so that RTC driver can successfully run SetTime()
+ //
+ OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &Token);
+ if (LookupPrivilegeValue(NULL, SE_TIME_ZONE_NAME, &TokenPrivileges.Privileges[0].Luid)) {
+ TokenPrivileges.PrivilegeCount = 1;
+ TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ AdjustTokenPrivileges(Token, FALSE, &TokenPrivileges, 0, (PTOKEN_PRIVILEGES) NULL, 0);
+ }
+
+ MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize);
+ FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume);
+
+ SecPrint ("\n\rEDK II WIN Host Emulation Environment from http://www.tianocore.org/edk2/\n\r");
+
+ //
+ // Determine the first thread available to this process.
+ //
+ if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask)) {
+ LowBit = (INT32)LowBitSet32 ((UINT32)ProcessAffinityMask);
+ if (LowBit != -1) {
+ //
+ // Force the system to bind the process to a single thread to work
+ // around odd semaphore type crashes.
+ //
+ SetProcessAffinityMask (GetCurrentProcess (), (INTN)(BIT0 << LowBit));
+ }
+ }
+
+ //
+ // Make some Windows calls to Set the process to the highest priority in the
+ // idle class. We need this to have good performance.
+ //
+ SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS);
+ SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
+
+ SecInitializeThunk ();
+ //
+ // PPIs pased into PEI_CORE
+ //
+ AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);
+
+ //
+ // Emulator Bus Driver Thunks
+ //
+ AddThunkProtocol (&mWinNtWndThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
+ AddThunkProtocol (&mWinNtFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);
+ AddThunkProtocol (&mWinNtBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE);
+ AddThunkProtocol (&mWinNtSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE);
+
+ //
+ // Allocate space for gSystemMemory Array
+ //
+ gSystemMemoryCount = CountSeparatorsInString (MemorySizeStr, '!') + 1;
+ gSystemMemory = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));
+ if (gSystemMemory == NULL) {
+ SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n\r", MemorySizeStr);
+ exit (1);
+ }
+
+ //
+ // Allocate space for gSystemMemory Array
+ //
+ gFdInfoCount = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1;
+ gFdInfo = calloc (gFdInfoCount, sizeof (NT_FD_INFO));
+ if (gFdInfo == NULL) {
+ SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n\r", FirmwareVolumesStr);
+ exit (1);
+ }
+ //
+ // Setup Boot Mode.
+ //
+ SecPrint (" BootMode 0x%02x\n\r", PcdGet32 (PcdEmuBootMode));
+
+ //
+ // Allocate 128K memory to emulate temp memory for PEI.
+ // on a real platform this would be SRAM, or using the cache as RAM.
+ // Set TemporaryRam to zero so WinNtOpenFile will allocate a new mapping
+ //
+ TemporaryRamSize = TEMPORARY_RAM_SIZE;
+ TemporaryRam = VirtualAlloc (NULL, (SIZE_T) (TemporaryRamSize), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if (TemporaryRam == NULL) {
+ SecPrint ("ERROR : Can not allocate enough space for SecStack\n\r");
+ exit (1);
+ }
+ SetMem32 (TemporaryRam, TemporaryRamSize, PcdGet32 (PcdInitValueInTempStack));
+
+ SecPrint (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n\r",
+ TemporaryRamSize / SIZE_1KB,
+ TemporaryRam
+ );
+
+ //
+ // If enabled use the magic page to communicate between modules
+ // This replaces the PI PeiServicesTable pointer mechanism that
+ // deos not work in the emulator. It also allows the removal of
+ // writable globals from SEC, PEI_CORE (libraries), PEIMs
+ //
+ EmuMagicPage = (VOID *)(UINTN)(FixedPcdGet64 (PcdPeiServicesTablePage) & MAX_UINTN);
+ if (EmuMagicPage != NULL) {
+ UINT64 Size;
+ Status = WinNtOpenFile (
+ NULL,
+ SIZE_4KB,
+ 0,
+ &EmuMagicPage,
+ &Size
+ );
+ if (EFI_ERROR (Status)) {
+ SecPrint ("ERROR : Could not allocate PeiServicesTablePage @ %p\n\r", EmuMagicPage);
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Open All the firmware volumes and remember the info in the gFdInfo global
+ // Meanwhile, find the SEC Core.
+ //
+ FileNamePtr = AllocateCopyPool (StrSize (FirmwareVolumesStr), FirmwareVolumesStr);
+ if (FileNamePtr == NULL) {
+ SecPrint ("ERROR : Can not allocate memory for firmware volume string\n\r");
+ exit (1);
+ }
+
+ for (Done = FALSE, Index = 0, SecFile = NULL; !Done; Index++) {
+ FileName = FileNamePtr;
+ for (Index1 = 0; (FileNamePtr[Index1] != '!') && (FileNamePtr[Index1] != 0); Index1++)
+ ;
+ if (FileNamePtr[Index1] == 0) {
+ Done = TRUE;
+ } else {
+ FileNamePtr[Index1] = '\0';
+ FileNamePtr = &FileNamePtr[Index1 + 1];
+ }
+
+ //
+ // Open the FD and remember where it got mapped into our processes address space
+ //
+ Status = WinNtOpenFile (
+ FileName,
+ 0,
+ OPEN_EXISTING,
+ &gFdInfo[Index].Address,
+ &gFdInfo[Index].Size
+ );
+ if (EFI_ERROR (Status)) {
+ SecPrint ("ERROR : Can not open Firmware Device File %S (0x%X). Exiting.\n\r", FileName, Status);
+ exit (1);
+ }
+
+ SecPrint (" FD loaded from %S", FileName);
+
+ if (SecFile == NULL) {
+ //
+ // Assume the beginning of the FD is an FV and look for the SEC Core.
+ // Load the first one we find.
+ //
+ FileHandle = NULL;
+ Status = PeiServicesFfsFindNextFile (
+ EFI_FV_FILETYPE_SECURITY_CORE,
+ (EFI_PEI_FV_HANDLE)gFdInfo[Index].Address,
+ &FileHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
+ if (!EFI_ERROR (Status)) {
+ SecPrint (" contains SEC Core");
+ }
+ }
+ }
+
+ SecPrint ("\n\r");
+ }
+ //
+ // Calculate memory regions and store the information in the gSystemMemory
+ // global for later use. The autosizing code will use this data to
+ // map this memory into the SEC process memory space.
+ //
+ for (Index = 0, Done = FALSE; !Done; Index++) {
+ //
+ // Save the size of the memory and make a Unicode filename SystemMemory00, ...
+ //
+ gSystemMemory[Index].Size = _wtoi (MemorySizeStr) * SIZE_1MB;
+
+ //
+ // Find the next region
+ //
+ for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++)
+ ;
+ if (MemorySizeStr[Index1] == 0) {
+ Done = TRUE;
+ }
+
+ MemorySizeStr = MemorySizeStr + Index1 + 1;
+ }
+
+ SecPrint ("\n\r");
+
+ //
+ // Hand off to SEC Core
+ //
+ SecLoadSecCore ((UINTN)TemporaryRam, TemporaryRamSize, gFdInfo[0].Address, gFdInfo[0].Size, SecFile);
+
+ //
+ // If we get here, then the SEC Core returned. This is an error as SEC should
+ // always hand off to PEI Core and then on to DXE Core.
+ //
+ SecPrint ("ERROR : SEC returned\n\r");
+ exit (1);
+}
+
+VOID
+SecLoadSecCore (
+ IN UINTN TemporaryRam,
+ IN UINTN TemporaryRamSize,
+ IN VOID *BootFirmwareVolumeBase,
+ IN UINTN BootFirmwareVolumeSize,
+ IN VOID *SecCorePe32File
+ )
+/*++
+
+Routine Description:
+ This is the service to load the SEC Core from the Firmware Volume
+
+Arguments:
+ TemporaryRam - Memory to use for SEC.
+ TemporaryRamSize - Size of Memory to use for SEC
+ BootFirmwareVolumeBase - Start of the Boot FV
+ SecCorePe32File - SEC Core PE32
+
+Returns:
+ Success means control is transferred and thus we should never return
+
+--*/
+{
+ EFI_STATUS Status;
+ VOID *TopOfStack;
+ VOID *SecCoreEntryPoint;
+ EFI_SEC_PEI_HAND_OFF *SecCoreData;
+ UINTN SecStackSize;
+
+ //
+ // Compute Top Of Memory for Stack and PEI Core Allocations
+ //
+ SecStackSize = TemporaryRamSize >> 1;
+
+ //
+ // |-----------| <---- TemporaryRamBase + TemporaryRamSize
+ // | Heap |
+ // | |
+ // |-----------| <---- StackBase / PeiTemporaryMemoryBase
+ // | |
+ // | Stack |
+ // |-----------| <---- TemporaryRamBase
+ //
+ TopOfStack = (VOID *)(TemporaryRam + SecStackSize);
+
+ //
+ // Reservet space for storing PeiCore's parament in stack.
+ //
+ TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
+ TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
+
+ //
+ // Bind this information into the SEC hand-off state
+ //
+ SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN)TopOfStack;
+ SecCoreData->DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
+ SecCoreData->BootFirmwareVolumeBase = BootFirmwareVolumeBase;
+ SecCoreData->BootFirmwareVolumeSize = BootFirmwareVolumeSize;
+ SecCoreData->TemporaryRamBase = (VOID*)TemporaryRam;
+ SecCoreData->TemporaryRamSize = TemporaryRamSize;
+ SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
+ SecCoreData->StackSize = SecStackSize;
+ SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + SecStackSize);
+ SecCoreData->PeiTemporaryRamSize = TemporaryRamSize - SecStackSize;
+
+ //
+ // Load the PEI Core from a Firmware Volume
+ //
+ Status = SecPeCoffGetEntryPoint (
+ SecCorePe32File,
+ &SecCoreEntryPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Transfer control to the SEC Core
+ //
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)SecCoreEntryPoint,
+ SecCoreData,
+ GetThunkPpiList (),
+ TopOfStack
+ );
+ //
+ // If we get here, then the SEC Core returned. This is an error
+ //
+ return ;
+}
+
+RETURN_STATUS
+EFIAPI
+SecPeCoffGetEntryPoint (
+ IN VOID *Pe32Data,
+ IN OUT VOID **EntryPoint
+ )
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = Pe32Data;
+
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;
+
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Allocate space in NT (not emulator) memory with ReadWrite and Execute attribute.
+ // Extra space is for alignment
+ //
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if (ImageContext.ImageAddress == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Align buffer on section boundary
+ //
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+ ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
+
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SecImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
+
+Arguments:
+ FileHandle - The handle to the PE/COFF file
+ FileOffset - The offset, in bytes, into the file to read
+ ReadSize - The number of bytes to read from the file starting at FileOffset
+ Buffer - A pointer to the buffer to read the data into.
+
+Returns:
+ EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+--*/
+{
+ CHAR8 *Destination8;
+ CHAR8 *Source8;
+ UINTN Length;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
+ Length = *ReadSize;
+ while (Length--) {
+ *(Destination8++) = *(Source8++);
+ }
+
+ return EFI_SUCCESS;
+}
+
+CHAR16 *
+AsciiToUnicode (
+ IN CHAR8 *Ascii,
+ IN UINTN *StrLen OPTIONAL
+ )
+/*++
+
+Routine Description:
+ Convert the passed in Ascii string to Unicode.
+ Optionally return the length of the strings.
+
+Arguments:
+ Ascii - Ascii string to convert
+ StrLen - Length of string
+
+Returns:
+ Pointer to malloc'ed Unicode version of Ascii
+
+--*/
+{
+ UINTN Index;
+ CHAR16 *Unicode;
+
+ //
+ // Allocate a buffer for unicode string
+ //
+ for (Index = 0; Ascii[Index] != '\0'; Index++)
+ ;
+ Unicode = malloc ((Index + 1) * sizeof (CHAR16));
+ if (Unicode == NULL) {
+ return NULL;
+ }
+
+ for (Index = 0; Ascii[Index] != '\0'; Index++) {
+ Unicode[Index] = (CHAR16) Ascii[Index];
+ }
+
+ Unicode[Index] = '\0';
+
+ if (StrLen != NULL) {
+ *StrLen = Index;
+ }
+
+ return Unicode;
+}
+
+UINTN
+CountSeparatorsInString (
+ IN CONST CHAR16 *String,
+ IN CHAR16 Separator
+ )
+/*++
+
+Routine Description:
+ Count the number of separators in String
+
+Arguments:
+ String - String to process
+ Separator - Item to count
+
+Returns:
+ Number of Separator in String
+
+--*/
+{
+ UINTN Count;
+
+ for (Count = 0; *String != '\0'; String++) {
+ if (*String == Separator) {
+ Count++;
+ }
+ }
+
+ return Count;
+}
+
+/**
+ Store the ModHandle in an array indexed by the Pdb File name.
+ The ModHandle is needed to unload the image.
+ @param ImageContext - Input data returned from PE Laoder Library. Used to find the
+ .PDB file name of the PE Image.
+ @param ModHandle - Returned from LoadLibraryEx() and stored for call to
+ FreeLibrary().
+ @return return EFI_SUCCESS when ModHandle was stored.
+--*/
+EFI_STATUS
+AddModHandle (
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ IN VOID *ModHandle
+ )
+
+{
+ UINTN Index;
+ PDB_NAME_TO_MOD_HANDLE *Array;
+ UINTN PreviousSize;
+ PDB_NAME_TO_MOD_HANDLE *TempArray;
+ HANDLE Handle;
+ UINTN Size;
+
+ //
+ // Return EFI_ALREADY_STARTED if this DLL has already been loaded
+ //
+ Array = mPdbNameModHandleArray;
+ for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
+ if (Array->PdbPointer != NULL && Array->ModHandle == ModHandle) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ Array = mPdbNameModHandleArray;
+ for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
+ if (Array->PdbPointer == NULL) {
+ //
+ // Make a copy of the stirng and store the ModHandle
+ //
+ Handle = GetProcessHeap ();
+ Size = AsciiStrLen (ImageContext->PdbPointer) + 1;
+ Array->PdbPointer = HeapAlloc ( Handle, HEAP_ZERO_MEMORY, Size);
+ ASSERT (Array->PdbPointer != NULL);
+
+ AsciiStrCpyS (Array->PdbPointer, Size, ImageContext->PdbPointer);
+ Array->ModHandle = ModHandle;
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // No free space in mPdbNameModHandleArray so grow it by
+ // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires.
+ //
+ PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE);
+ mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE;
+ //
+ // re-allocate a new buffer and copy the old values to the new locaiton.
+ //
+ TempArray = HeapAlloc (GetProcessHeap (),
+ HEAP_ZERO_MEMORY,
+ mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE)
+ );
+
+ CopyMem ((VOID *) (UINTN) TempArray, (VOID *) (UINTN)mPdbNameModHandleArray, PreviousSize);
+
+ HeapFree (GetProcessHeap (), 0, mPdbNameModHandleArray);
+
+ mPdbNameModHandleArray = TempArray;
+ if (mPdbNameModHandleArray == NULL) {
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return AddModHandle (ImageContext, ModHandle);
+}
+
+/**
+ Return the ModHandle and delete the entry in the array.
+ @param ImageContext - Input data returned from PE Laoder Library. Used to find the
+ .PDB file name of the PE Image.
+ @return
+ ModHandle - ModHandle assoicated with ImageContext is returned
+ NULL - No ModHandle associated with ImageContext
+**/
+VOID *
+RemoveModHandle (
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ UINTN Index;
+ PDB_NAME_TO_MOD_HANDLE *Array;
+
+ if (ImageContext->PdbPointer == NULL) {
+ //
+ // If no PDB pointer there is no ModHandle so return NULL
+ //
+ return NULL;
+ }
+
+ Array = mPdbNameModHandleArray;
+ for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
+ if ((Array->PdbPointer != NULL) && (AsciiStrCmp(Array->PdbPointer, ImageContext->PdbPointer) == 0)) {
+ //
+ // If you find a match return it and delete the entry
+ //
+ HeapFree (GetProcessHeap (), 0, Array->PdbPointer);
+ Array->PdbPointer = NULL;
+ return Array->ModHandle;
+ }
+ }
+
+ return NULL;
+}
+
+VOID
+EFIAPI
+PeCoffLoaderRelocateImageExtraAction (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ EFI_STATUS Status;
+ VOID *DllEntryPoint;
+ CHAR16 *DllFileName;
+ HMODULE Library;
+ UINTN Index;
+
+ ASSERT (ImageContext != NULL);
+ //
+ // If we load our own PE COFF images the Windows debugger can not source
+ // level debug our code. If a valid PDB pointer exists use it to load
+ // the *.dll file as a library using Windows* APIs. This allows
+ // source level debug. The image is still loaded and relocated
+ // in the Framework memory space like on a real system (by the code above),
+ // but the entry point points into the DLL loaded by the code below.
+ //
+
+ DllEntryPoint = NULL;
+
+ //
+ // Load the DLL if it's not an EBC image.
+ //
+ if ((ImageContext->PdbPointer != NULL) &&
+ (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {
+ //
+ // Convert filename from ASCII to Unicode
+ //
+ DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);
+
+ //
+ // Check that we have a valid filename
+ //
+ if (Index < 5 || DllFileName[Index - 4] != '.') {
+ free (DllFileName);
+
+ //
+ // Never return an error if PeCoffLoaderRelocateImage() succeeded.
+ // The image will run, but we just can't source level debug. If we
+ // return an error the image will not run.
+ //
+ return;
+ }
+ //
+ // Replace .PDB with .DLL on the filename
+ //
+ DllFileName[Index - 3] = 'D';
+ DllFileName[Index - 2] = 'L';
+ DllFileName[Index - 1] = 'L';
+
+ //
+ // Load the .DLL file into the user process's address space for source
+ // level debug
+ //
+ Library = LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);
+ if (Library != NULL) {
+ //
+ // InitializeDriver is the entry point we put in all our EFI DLL's. The
+ // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() suppresses the
+ // normal DLL entry point of DllMain, and prevents other modules that are
+ // referenced in side the DllFileName from being loaded. There is no error
+ // checking as the we can point to the PE32 image loaded by Tiano. This
+ // step is only needed for source level debugging
+ //
+ DllEntryPoint = (VOID *) (UINTN) GetProcAddress (Library, "InitializeDriver");
+
+ }
+
+ if ((Library != NULL) && (DllEntryPoint != NULL)) {
+ Status = AddModHandle (ImageContext, Library);
+ if (Status == EFI_ALREADY_STARTED) {
+ //
+ // If the DLL has already been loaded before, then this instance of the DLL can not be debugged.
+ //
+ ImageContext->PdbPointer = NULL;
+ SecPrint ("WARNING: DLL already loaded. No source level debug %S.\n\r", DllFileName);
+ } else {
+ //
+ // This DLL is not already loaded, so source level debugging is supported.
+ //
+ ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;
+ SecPrint ("LoadLibraryEx (\n\r %S,\n\r NULL, DONT_RESOLVE_DLL_REFERENCES)\n\r", DllFileName);
+ }
+ } else {
+ SecPrint ("WARNING: No source level debug %S. \n\r", DllFileName);
+ }
+
+ free (DllFileName);
+ }
+}
+
+VOID
+EFIAPI
+PeCoffLoaderUnloadImageExtraAction (
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+)
+{
+ VOID *ModHandle;
+
+ ASSERT (ImageContext != NULL);
+
+ ModHandle = RemoveModHandle (ImageContext);
+ if (ModHandle != NULL) {
+ FreeLibrary (ModHandle);
+ SecPrint ("FreeLibrary (\n\r %s)\n\r", ImageContext->PdbPointer);
+ } else {
+ SecPrint ("WARNING: Unload image without source level debug\n\r");
+ }
+}
+
+VOID
+_ModuleEntryPoint (
+ VOID
+ )
+{
+}
diff --git a/roms/edk2/EmulatorPkg/Win/Host/WinHost.h b/roms/edk2/EmulatorPkg/Win/Host/WinHost.h
new file mode 100644
index 000000000..b36fea254
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/Host/WinHost.h
@@ -0,0 +1,208 @@
+/**@file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+Module Name:
+ WinHost.h
+
+Abstract:
+ Include file for Windows Host
+
+**/
+#ifndef _HOST_H_
+#define _HOST_H_
+
+#include <stdio.h>
+#include <time.h>
+#include "WinInclude.h"
+
+#include <PiPei.h>
+#include <IndustryStandard/PeImage.h>
+#include <Guid/FileInfo.h>
+#include <Guid/FileSystemInfo.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Ppi/EmuThunk.h>
+#include <Protocol/EmuThunk.h>
+#include <Protocol/SimpleFileSystem.h>
+
+#include <Protocol/EmuBlockIo.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/EmuSnp.h>
+
+#include <Library/BaseLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ThunkPpiList.h>
+#include <Library/ThunkProtocolList.h>
+#include <Library/PcdLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <Library/NetLib.h>
+
+
+#define TEMPORARY_RAM_SIZE 0x20000
+
+typedef struct {
+ VOID *Address;
+ UINTN Size;
+} NT_FD_INFO;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINT64 Size;
+} NT_SYSTEM_MEMORY;
+
+RETURN_STATUS
+EFIAPI
+SecPeCoffGetEntryPoint (
+ IN VOID *Pe32Data,
+ IN OUT VOID **EntryPoint
+);
+
+VOID
+SecLoadSecCore (
+ IN UINTN TemporaryRam,
+ IN UINTN TemporaryRamSize,
+ IN VOID *BootFirmwareVolumeBase,
+ IN UINTN BootFirmwareVolumeSize,
+ IN VOID *SecCorePe32File
+)
+/*++
+
+Routine Description:
+ This is the service to load the SEC Core from the Firmware Volume
+
+Arguments:
+ TemporaryRam - Memory to use for SEC.
+ TemporaryRamSize - Size of Memory to use for SEC
+ BootFirmwareVolumeBase - Start of the Boot FV
+ SecCorePe32File - SEC Core PE32
+
+Returns:
+ Success means control is transferred and thus we should never return
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SecWinNtFdAddress (
+ IN UINTN Index,
+ IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
+ IN OUT UINT64 *FdSize
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ Index - TODO: add argument description
+ FdBase - TODO: add argument description
+ FdSize - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+
+EFI_STATUS
+EFIAPI
+SecImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ FileHandle - TODO: add argument description
+ FileOffset - TODO: add argument description
+ ReadSize - TODO: add argument description
+ Buffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+CHAR16 *
+AsciiToUnicode (
+ IN CHAR8 *Ascii,
+ IN UINTN *StrLen OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ Ascii - TODO: add argument description
+ StrLen - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+UINTN
+CountSeparatorsInString (
+ IN CONST CHAR16 *String,
+ IN CHAR16 Separator
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ String - TODO: add argument description
+ Separator - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+EfiSystemMemoryRange (
+ IN VOID *MemoryAddress
+ );
+VOID
+SecInitializeThunk (
+ VOID
+);
+extern EMU_THUNK_PROTOCOL gEmuThunkProtocol;
+extern EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo;
+extern EMU_IO_THUNK_PROTOCOL mWinNtFileSystemThunkIo;
+extern EMU_IO_THUNK_PROTOCOL mWinNtBlockIoThunkIo;
+extern EMU_IO_THUNK_PROTOCOL mWinNtSnpThunkIo;
+
+#endif
diff --git a/roms/edk2/EmulatorPkg/Win/Host/WinHost.inf b/roms/edk2/EmulatorPkg/Win/Host/WinHost.inf
new file mode 100644
index 000000000..4d2ce1962
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/Host/WinHost.inf
@@ -0,0 +1,110 @@
+## @file
+# Entry Point of Win Emulator
+#
+# Main executable file of Win Emulator that loads Sec core after initialization finished.
+# Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.<BR>
+# Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
+# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = WinHost
+ FILE_GUID = 62E8F833-2B0A-4C19-A966-63C180588BE7
+ MODULE_TYPE = USER_DEFINED
+ VERSION_STRING = 1.0
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ WinMemoryAllocationLib.c
+ WinGopInput.c
+ WinGopScreen.c
+ WinGop.h
+ WinFileSystem.c
+ WinBlockIo.c
+ WinThunk.c
+ WinHost.h
+ WinHost.c
+ WinPacketFilter.c
+ WinInclude.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ NetworkPkg/NetworkPkg.dec
+ EmulatorPkg/EmulatorPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ PcdLib
+ PrintLib
+ BaseMemoryLib
+ BaseLib
+ PeCoffLib
+ ThunkPpiList
+ ThunkProtocolList
+ PpiListLib
+ PeiServicesLib
+ FrameBufferBltLib
+
+[Ppis]
+ gEmuThunkPpiGuid
+
+[Protocols]
+ gEmuIoThunkProtocolGuid
+ gEmuGraphicsWindowProtocolGuid
+ gEmuBlockIoProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+ gEmuSnpProtocolGuid
+
+[Guids]
+ gEfiFileSystemVolumeLabelInfoIdGuid # SOMETIMES_CONSUMED
+ gEfiFileInfoGuid # SOMETIMES_CONSUMED
+ gEfiFileSystemInfoGuid # SOMETIMES_CONSUMED
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
+
+ gEmulatorPkgTokenSpaceGuid.PcdEmuBootMode
+ gEmulatorPkgTokenSpaceGuid.PcdEmuFirmwareVolume
+ gEmulatorPkgTokenSpaceGuid.PcdEmuMemorySize
+ gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress
+ gEmulatorPkgTokenSpaceGuid.PcdEmuVirtualDisk
+ gEmulatorPkgTokenSpaceGuid.PcdEmuGop|L"GOP Window"
+ gEmulatorPkgTokenSpaceGuid.PcdEmuFileSystem
+ gEmulatorPkgTokenSpaceGuid.PcdPeiServicesTablePage
+ gEmulatorPkgTokenSpaceGuid.PcdEmuNetworkInterface|L"0"
+
+[BuildOptions]
+ MSFT:*_*_*_DLINK_FLAGS == /out:"$(BIN_DIR)\$(BASE_NAME).exe" /base:0x10000000 /pdb:"$(BIN_DIR)\$(BASE_NAME).pdb"
+ MSFT:*_*_*_CC_FLAGS == /nologo /W4 /WX /Gy /c /D UNICODE /Od /Oy- /FIAutoGen.h /EHs-c- /GF /Gs8192 /Zi /Gm /D _CRT_SECURE_NO_WARNINGS /D _CRT_SECURE_NO_DEPRECATE
+ MSFT:*_*_*_PP_FLAGS == /nologo /E /TC /FIAutoGen.h
+
+ MSFT:*_VS2015_IA32_DLINK_FLAGS = /LIBPATH:"%VS2015_PREFIX%Lib" /LIBPATH:"%VS2015_PREFIX%VC\Lib" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:I386 /LTCG Kernel32.lib MSVCRTD.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib vcruntimed.lib ucrtd.lib
+ MSFT:*_VS2015x86_IA32_DLINK_FLAGS = /LIBPATH:"%VS2015_PREFIX%Lib" /LIBPATH:"%VS2015_PREFIX%VC\Lib" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:I386 /LTCG Kernel32.lib MSVCRTD.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib vcruntimed.lib ucrtd.lib
+ MSFT:*_VS2017_IA32_DLINK_FLAGS = /LIBPATH:"%VCToolsInstallDir%lib\x86" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:I386 /LTCG Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib
+ MSFT:*_VS2019_IA32_DLINK_FLAGS = /LIBPATH:"%VCToolsInstallDir%lib\x86" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:I386 /LTCG Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib
+ MSFT:*_*_IA32_ASM_FLAGS == /nologo /W3 /WX /c /coff /Cx /Zd /W0 /Zi
+ MSFT:*_*_IA32_ASMLINK_FLAGS == /link /nologo /tiny
+
+ MSFT:*_VS2015_X64_DLINK_FLAGS = /LIBPATH:"%VS2015_PREFIX%VC\Lib\AMD64" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:AMD64 /LTCG Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib
+ MSFT:*_VS2015x86_X64_DLINK_FLAGS = /LIBPATH:"%VS2015_PREFIX%VC\Lib\AMD64" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:AMD64 /LTCG Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib
+ MSFT:*_VS2017_X64_DLINK_FLAGS = /LIBPATH:"%VCToolsInstallDir%lib\x64" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:AMD64 /LTCG Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib
+ MSFT:*_VS2019_X64_DLINK_FLAGS = /LIBPATH:"%VCToolsInstallDir%lib\x64" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:AMD64 /LTCG Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib
+ MSFT:*_*_X64_ASM_FLAGS == /nologo /W3 /WX /c /Cx /Zd /W0 /Zi
+ MSFT:*_*_X64_ASMLINK_FLAGS == /link /nologo
+
+ GCC:*_CLANGPDB_X64_DLINK_FLAGS == /out:"$(BIN_DIR)\$(BASE_NAME).exe" /base:0x10000000 /pdb:"$(BIN_DIR)\$(BASE_NAME).pdb" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x64" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x64" /LIBPATH:"%VCToolsInstallDir%lib\x64" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /OPT:REF /DEBUG /MACHINE:AMD64 Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib /lldmap /EXPORT:InitializeDriver=_ModuleEntryPoint
+ GCC:*_CLANGPDB_X64_CC_FLAGS == -m64 -g -fshort-wchar -fno-strict-aliasing -Wall -c -include AutoGen.h -D _CRT_SECURE_NO_WARNINGS -Wnonportable-include-path -D UNICODE -D _CRT_SECURE_NO_DEPRECATE
+
+ GCC:*_CLANGPDB_IA32_DLINK_FLAGS == /out:"$(BIN_DIR)\$(BASE_NAME).exe" /base:0x10000000 /pdb:"$(BIN_DIR)\$(BASE_NAME).pdb" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86" /LIBPATH:"%VCToolsInstallDir%ib\x86" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /OPT:REF /DEBUG /MACHINE:I386 Kernel32.lib MSVCRTD.lib vcruntimed.lib ucrtd.lib Gdi32.lib User32.lib Winmm.lib Advapi32.lib /lldmap /EXPORT:InitializeDriver=_ModuleEntryPoint
+ GCC:*_CLANGPDB_IA32_CC_FLAGS == -m32 -g -fshort-wchar -fno-strict-aliasing -Wall -c -include AutoGen.h -D _CRT_SECURE_NO_WARNINGS -Wnonportable-include-path -D UNICODE -D _CRT_SECURE_NO_DEPRECATE
diff --git a/roms/edk2/EmulatorPkg/Win/Host/WinInclude.h b/roms/edk2/EmulatorPkg/Win/Host/WinInclude.h
new file mode 100644
index 000000000..8a9ae7d74
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/Host/WinInclude.h
@@ -0,0 +1,70 @@
+/**@file
+ Public include file for the WinNt Library
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __WIN_NT_INCLUDE_H__
+#define __WIN_NT_INCLUDE_H__
+
+//
+// Win32 include files do not compile clean with /W4, so we use the warning
+// pragma to suppress the warnings for Win32 only. This way our code can stil
+// compile at /W4 (highest warning level) with /WX (warnings cause build
+// errors).
+//
+#pragma warning(disable : 4115)
+#pragma warning(disable : 4201)
+#pragma warning(disable : 4028)
+#pragma warning(disable : 4133)
+
+#define GUID _WINNT_DUP_GUID_____
+#define _LIST_ENTRY _WINNT_DUP_LIST_ENTRY_FORWARD
+#define LIST_ENTRY _WINNT_DUP_LIST_ENTRY
+#if defined (MDE_CPU_IA32) && (_MSC_VER < 1800)
+#define InterlockedIncrement _WINNT_DUP_InterlockedIncrement
+#define InterlockedDecrement _WINNT_DUP_InterlockedDecrement
+#define InterlockedCompareExchange64 _WINNT_DUP_InterlockedCompareExchange64
+#endif
+#undef UNALIGNED
+#undef CONST
+#undef VOID
+#undef DEBUG_EVENT
+
+// WQBugBug: This typedef is to make "windows.h" buildable.
+// It should be removed after the root cause why
+// size_t is undefined when go into the line below is found.
+#if defined (MDE_CPU_IA32)
+typedef UINT32 size_t ;
+#endif
+
+#include "windows.h"
+#include "windowsx.h"
+
+#undef GUID
+#undef _LIST_ENTRY
+#undef LIST_ENTRY
+#undef InterlockedIncrement
+#undef InterlockedDecrement
+#undef InterlockedCompareExchange64
+#undef InterlockedCompareExchangePointer
+#undef CreateEventEx
+
+#define VOID void
+
+//
+// Prevent collisions with Windows API name macros that deal with Unicode/Not issues
+//
+#undef LoadImage
+#undef CreateEvent
+#undef FAR
+
+//
+// Set the warnings back on as the EFI code must be /W4.
+//
+#pragma warning(default : 4115)
+#pragma warning(default : 4201)
+
+
+#endif
diff --git a/roms/edk2/EmulatorPkg/Win/Host/WinMemoryAllocationLib.c b/roms/edk2/EmulatorPkg/Win/Host/WinMemoryAllocationLib.c
new file mode 100644
index 000000000..a29ebddd1
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/Host/WinMemoryAllocationLib.c
@@ -0,0 +1,172 @@
+/*++ @file
+
+ Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <stdlib.h>
+
+/**
+ Allocates a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePool (
+ IN UINTN AllocationSize
+ )
+{
+ return (VOID*) malloc (AllocationSize);
+}
+
+
+/**
+ Allocates and zeros a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+
+ Buffer = AllocatePool (AllocationSize);
+ if (Buffer == NULL) {
+ return NULL;
+ }
+
+ ZeroMem (Buffer, AllocationSize);
+
+ return Buffer;
+}
+
+
+/**
+ Reallocates a buffer of type EfiBootServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = AllocatePool (NewSize);
+ if (NewBuffer == NULL) {
+ return NULL;
+ }
+
+ if (OldBuffer != NULL) {
+ if (OldSize > 0) {
+ CopyMem (NewBuffer, OldBuffer, OldSize);
+ }
+
+ FreePool (OldBuffer);
+ }
+
+ return NewBuffer;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *Memory;
+
+ Memory = AllocatePool (AllocationSize);
+ if (Memory != NULL) {
+ Memory = CopyMem (Memory, Buffer, AllocationSize);
+ }
+ return Memory;
+}
+
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer Pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+ IN VOID *Buffer
+ )
+{
+ free ((void *) Buffer);
+}
+
diff --git a/roms/edk2/EmulatorPkg/Win/Host/WinPacketFilter.c b/roms/edk2/EmulatorPkg/Win/Host/WinPacketFilter.c
new file mode 100644
index 000000000..0b751f97e
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/Host/WinPacketFilter.c
@@ -0,0 +1,1135 @@
+/**@file
+ Windows Packet Filter implementation of the EMU_SNP_PROTOCOL that allows the
+ emulator to get on real networks.
+
+Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2011, Apple Inc. All rights reserved.
+(C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "WinHost.h"
+
+#define NETWORK_LIBRARY_NAME_U L"SnpNt32Io.dll"
+#define NETWORK_LIBRARY_INITIALIZE "SnpInitialize"
+#define NETWORK_LIBRARY_FINALIZE "SnpFinalize"
+#define NETWORK_LIBRARY_SET_RCV_FILTER "SnpSetReceiveFilter"
+#define NETWORK_LIBRARY_RECEIVE "SnpReceive"
+#define NETWORK_LIBRARY_TRANSMIT "SnpTransmit"
+
+#pragma pack(1)
+typedef struct _NT_NET_INTERFACE_INFO {
+ UINT32 InterfaceIndex;
+ EFI_MAC_ADDRESS MacAddr;
+} NT_NET_INTERFACE_INFO;
+#pragma pack()
+
+#define NET_ETHER_HEADER_SIZE 14
+#define MAX_INTERFACE_INFO_NUMBER 16
+#define SNP_MAX_TX_BUFFER_NUM 65536
+#define SNP_TX_BUFFER_INCREASEMENT 32
+#define DEFAULT_SELECTED_NIC_INDEX 0
+
+//
+// Functions in Net Library
+//
+typedef
+INT32
+(*NT_NET_INITIALIZE) (
+ IN OUT UINT32 *InterfaceCount,
+ IN OUT NT_NET_INTERFACE_INFO * InterfaceInfoBuffer
+ );
+
+typedef
+INT32
+(*NT_NET_FINALIZE) (
+ VOID
+ );
+
+typedef
+INT32
+(*NT_NET_SET_RECEIVE_FILTER) (
+ IN UINT32 Index,
+ IN UINT32 EnableFilter,
+ IN UINT32 MCastFilterCnt,
+ IN EFI_MAC_ADDRESS * MCastFilter
+ );
+
+typedef
+INT32
+(*NT_NET_RECEIVE) (
+ IN UINT32 Index,
+ IN OUT UINT32 *BufferSize,
+ OUT VOID *Buffer
+ );
+
+typedef
+INT32
+(*NT_NET_TRANSMIT) (
+ IN UINT32 Index,
+ IN UINT32 HeaderSize,
+ IN UINT32 BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS * SrcAddr,
+ IN EFI_MAC_ADDRESS * DestAddr,
+ IN UINT16 *Protocol
+ );
+
+typedef struct _NT_NET_UTILITY_TABLE {
+ NT_NET_INITIALIZE Initialize;
+ NT_NET_FINALIZE Finalize;
+ NT_NET_SET_RECEIVE_FILTER SetReceiveFilter;
+ NT_NET_RECEIVE Receive;
+ NT_NET_TRANSMIT Transmit;
+} NT_NET_UTILITY_TABLE;
+
+//
+// Instance data for each fake SNP instance
+//
+#define WIN_NT_INSTANCE_SIGNATURE SIGNATURE_32 ('N', 'T', 'I', 'S')
+
+typedef struct {
+ UINT32 Signature;
+
+ //
+ // Array of the recycled transmit buffer address.
+ //
+ UINT64 *RecycledTxBuf;
+
+ //
+ // Current number of recycled buffer pointers in RecycledTxBuf.
+ //
+ UINT32 RecycledTxBufCount;
+
+ //
+ // The maximum number of recycled buffer pointers in RecycledTxBuf.
+ //
+ UINT32 MaxRecycledTxBuf;
+ EFI_SIMPLE_NETWORK_MODE Mode;
+ NT_NET_INTERFACE_INFO InterfaceInfo;
+} WIN_NT_INSTANCE_DATA;
+
+//
+// Instance data for each SNP private instance
+//
+#define WIN_NT_SIMPLE_NETWORK_PRIVATE_SIGNATURE SIGNATURE_32 ('N', 'T', 's', 'n')
+
+typedef struct {
+ UINTN Signature;
+ EMU_IO_THUNK_PROTOCOL *Thunk;
+ EMU_SNP_PROTOCOL EmuSnp;
+ EFI_SIMPLE_NETWORK_MODE *Mode;
+ HMODULE NetworkLibraryHandle;
+ NT_NET_UTILITY_TABLE NtNetUtilityTable;
+ WIN_NT_INSTANCE_DATA Instance;
+} WIN_NT_SNP_PRIVATE;
+
+#define WIN_NT_SNP_PRIVATE_DATA_FROM_THIS(a) \
+ CR(a, WIN_NT_SNP_PRIVATE, EmuSnp, WIN_NT_SIMPLE_NETWORK_PRIVATE_SIGNATURE)
+
+
+/**
+ Register storage for SNP Mode.
+
+ @param This Protocol instance pointer.
+ @param Mode SimpleNetworkProtocol Mode structure passed into driver.
+
+ @retval EFI_SUCCESS The network interface was started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+
+**/
+EFI_STATUS
+WinNtSnpCreateMapping (
+ IN EMU_SNP_PROTOCOL *This,
+ IN EFI_SIMPLE_NETWORK_MODE *Mode
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ Private->Mode = Mode;
+
+ //
+ // Set the broadcast address.
+ //
+ CopyMem (&Mode->BroadcastAddress, &Private->Instance.Mode.BroadcastAddress, sizeof (EFI_MAC_ADDRESS));
+ //
+ // Set the MAC address.
+ //
+ CopyMem (&Mode->CurrentAddress, &Private->Instance.Mode.CurrentAddress, sizeof (EFI_MAC_ADDRESS));
+ CopyMem (&Mode->PermanentAddress, &Private->Instance.Mode.PermanentAddress, sizeof (EFI_MAC_ADDRESS));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Changes the state of a network interface from "stopped" to "started".
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was started.
+ @retval EFI_ALREADY_STARTED The network interface is already in the started state.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpStart (
+ IN EMU_SNP_PROTOCOL *This
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ switch (Private->Mode->State) {
+ case EfiSimpleNetworkStopped:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ case EfiSimpleNetworkInitialized:
+ return EFI_ALREADY_STARTED;
+ break;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ break;
+ }
+
+ Private->Mode->State = EfiSimpleNetworkStarted;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Changes the state of a network interface from "started" to "stopped".
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was stopped.
+ @retval EFI_ALREADY_STARTED The network interface is already in the stopped state.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpStop (
+ IN EMU_SNP_PROTOCOL *This
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ switch ( Private->Mode->State ) {
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+ break;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ break;
+ }
+
+ Private->Mode->State = EfiSimpleNetworkStopped;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets a network adapter and allocates the transmit and receive buffers
+ required by the network interface; optionally, also requests allocation
+ of additional transmit and receive buffers.
+
+ @param This The protocol instance pointer.
+ @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space
+ that the driver should allocate for the network interface.
+ Some network interfaces will not be able to use the extra
+ buffer, and the caller will not know if it is actually
+ being used.
+ @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space
+ that the driver should allocate for the network interface.
+ Some network interfaces will not be able to use the extra
+ buffer, and the caller will not know if it is actually
+ being used.
+
+ @retval EFI_SUCCESS The network interface was initialized.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and
+ receive buffers.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpInitialize (
+ IN EMU_SNP_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ switch ( Private->Mode->State ) {
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+ break;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ break;
+ }
+
+ Private->Mode->MCastFilterCount = 0;
+ Private->Mode->ReceiveFilterSetting = 0;
+ ZeroMem (Private->Mode->MCastFilter, sizeof (Private->Mode->MCastFilter));
+
+ Private->Mode->State = EfiSimpleNetworkInitialized;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets a network adapter and re-initializes it with the parameters that were
+ provided in the previous call to Initialize().
+
+ @param This The protocol instance pointer.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The network interface was reset.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpReset (
+ IN EMU_SNP_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ switch ( Private->Mode->State ) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+ break;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets a network adapter and leaves it in a state that is safe for
+ another driver to initialize.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was shutdown.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpShutdown (
+ IN EMU_SNP_PROTOCOL *This
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ switch ( Private->Mode->State ) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+ break;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ break;
+ }
+
+ Private->Mode->State = EfiSimpleNetworkStarted;
+
+ Private->Mode->ReceiveFilterSetting = 0;
+ Private->Mode->MCastFilterCount = 0;
+ ZeroMem (Private->Mode->MCastFilter, sizeof (Private->Mode->MCastFilter));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Manages the multicast receive filters of a network interface.
+
+ @param This The protocol instance pointer.
+ @param Enable A bit mask of receive filters to enable on the network interface.
+ @param Disable A bit mask of receive filters to disable on the network interface.
+ @param ResetMCastFilter Set to TRUE to reset the contents of the multicast receive
+ filters on the network interface to their default values.
+ @param McastFilterCnt Number of multicast HW MAC addresses in the new
+ MCastFilter list. This value must be less than or equal to
+ the MCastFilterCnt field of EMU_SNP_MODE. This
+ field is optional if ResetMCastFilter is TRUE.
+ @param MCastFilter A pointer to a list of new multicast receive filter HW MAC
+ addresses. This list will replace any existing multicast
+ HW MAC address list. This field is optional if
+ ResetMCastFilter is TRUE.
+
+ @retval EFI_SUCCESS The multicast receive filter list was updated.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpReceiveFilters (
+ IN EMU_SNP_PROTOCOL *This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt OPTIONAL,
+ IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+ INT32 ReturnValue;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ ReturnValue = Private->NtNetUtilityTable.SetReceiveFilter (
+ Private->Instance.InterfaceInfo.InterfaceIndex,
+ Enable,
+ (UINT32)MCastFilterCnt,
+ MCastFilter
+ );
+
+ if (ReturnValue <= 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Modifies or resets the current station address, if supported.
+
+ @param This The protocol instance pointer.
+ @param Reset Flag used to reset the station address to the network interfaces
+ permanent address.
+ @param New The new station address to be used for the network interface.
+
+ @retval EFI_SUCCESS The network interfaces station address was updated.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpStationAddress (
+ IN EMU_SNP_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS *New OPTIONAL
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Resets or collects the statistics on a network interface.
+
+ @param This Protocol instance pointer.
+ @param Reset Set to TRUE to reset the statistics for the network interface.
+ @param StatisticsSize On input the size, in bytes, of StatisticsTable. On
+ output the size, in bytes, of the resulting table of
+ statistics.
+ @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
+ contains the statistics.
+
+ @retval EFI_SUCCESS The statistics were collected from the network interface.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer
+ size needed to hold the statistics is returned in
+ StatisticsSize.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpStatistics (
+ IN EMU_SNP_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize OPTIONAL,
+ OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Converts a multicast IP address to a multicast HW MAC address.
+
+ @param This The protocol instance pointer.
+ @param IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. Set
+ to FALSE if the multicast IP address is IPv4 [RFC 791].
+ @param IP The multicast IP address that is to be converted to a multicast
+ HW MAC address.
+ @param MAC The multicast HW MAC address that is to be generated from IP.
+
+ @retval EFI_SUCCESS The multicast IP address was mapped to the multicast
+ HW MAC address.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer
+ size needed to hold the statistics is returned in
+ StatisticsSize.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpMCastIpToMac (
+ IN EMU_SNP_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Performs read and write operations on the NVRAM device attached to a
+ network interface.
+
+ @param This The protocol instance pointer.
+ @param ReadWrite TRUE for read operations, FALSE for write operations.
+ @param Offset Byte offset in the NVRAM device at which to start the read or
+ write operation. This must be a multiple of NvRamAccessSize and
+ less than NvRamSize.
+ @param BufferSize The number of bytes to read or write from the NVRAM device.
+ This must also be a multiple of NvramAccessSize.
+ @param Buffer A pointer to the data buffer.
+
+ @retval EFI_SUCCESS The NVRAM access was performed.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpNvData (
+ IN EMU_SNP_PROTOCOL *This,
+ IN BOOLEAN ReadWrite,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Reads the current interrupt status and recycled transmit buffer status from
+ a network interface.
+
+ @param This The protocol instance pointer.
+ @param InterruptStatus A pointer to the bit mask of the currently active interrupts
+ If this is NULL, the interrupt status will not be read from
+ the device. If this is not NULL, the interrupt status will
+ be read from the device. When the interrupt status is read,
+ it will also be cleared. Clearing the transmit interrupt
+ does not empty the recycled transmit buffer array.
+ @param TxBuf Recycled transmit buffer address. The network interface will
+ not transmit if its internal recycled transmit buffer array
+ is full. Reading the transmit buffer does not clear the
+ transmit interrupt. If this is NULL, then the transmit buffer
+ status will not be read. If there are no transmit buffers to
+ recycle and TxBuf is not NULL, * TxBuf will be set to NULL.
+
+ @retval EFI_SUCCESS The status of the network interface was retrieved.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpGetStatus (
+ IN EMU_SNP_PROTOCOL *This,
+ OUT UINT32 *InterruptStatus OPTIONAL,
+ OUT VOID **TxBuf OPTIONAL
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ if (TxBuf != NULL) {
+ if (Private->Instance.RecycledTxBufCount != 0) {
+ Private->Instance.RecycledTxBufCount --;
+ *((UINT8 **) TxBuf) = (UINT8 *) (UINTN)Private->Instance.RecycledTxBuf[Private->Instance.RecycledTxBufCount];
+ } else {
+ *((UINT8 **) TxBuf) = NULL;
+ }
+ }
+
+ if (InterruptStatus != NULL) {
+ *InterruptStatus = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Places a packet in the transmit queue of a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header to be filled in by
+ the Transmit() function. If HeaderSize is non-zero, then it
+ must be equal to This->Mode->MediaHeaderSize and the DestAddr
+ and Protocol parameters must not be NULL.
+ @param BufferSize The size, in bytes, of the entire packet (media header and
+ data) to be transmitted through the network interface.
+ @param Buffer A pointer to the packet (media header followed by data) to be
+ transmitted. This parameter cannot be NULL. If HeaderSize is zero,
+ then the media header in Buffer must already be filled in by the
+ caller. If HeaderSize is non-zero, then the media header will be
+ filled in by the Transmit() function.
+ @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter
+ is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then
+ This->Mode->CurrentAddress is used for the source HW MAC address.
+ @param DestAddr The destination HW MAC address. If HeaderSize is zero, then this
+ parameter is ignored.
+ @param Protocol The type of header to build. If HeaderSize is zero, then this
+ parameter is ignored. See RFC 1700, section "Ether Types", for
+ examples.
+
+ @retval EFI_SUCCESS The packet was placed on the transmit queue.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpTransmit (
+ IN EMU_SNP_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ IN UINT16 *Protocol OPTIONAL
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+ INT32 ReturnValue;
+ UINT64 *Tmp;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ if ((HeaderSize != 0) && (SrcAddr == NULL)) {
+ SrcAddr = &Private->Instance.Mode.CurrentAddress;
+ }
+
+ ReturnValue = Private->NtNetUtilityTable.Transmit (
+ Private->Instance.InterfaceInfo.InterfaceIndex,
+ (UINT32)HeaderSize,
+ (UINT32)BufferSize,
+ Buffer,
+ SrcAddr,
+ DestAddr,
+ Protocol
+ );
+
+ if (ReturnValue < 0) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ if ((Private->Instance.MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT) >= SNP_MAX_TX_BUFFER_NUM) {
+ return EFI_NOT_READY;
+ }
+
+ if (Private->Instance.RecycledTxBufCount < Private->Instance.MaxRecycledTxBuf) {
+ Private->Instance.RecycledTxBuf[Private->Instance.RecycledTxBufCount] = (UINT64) Buffer;
+ Private->Instance.RecycledTxBufCount ++;
+ } else {
+ Tmp = malloc (sizeof (UINT64) * (Private->Instance.MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT));
+ if (Tmp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ CopyMem (Tmp, Private->Instance.RecycledTxBuf, sizeof (UINT64) * Private->Instance.RecycledTxBufCount);
+ free (Private->Instance.RecycledTxBuf);
+ Private->Instance.RecycledTxBuf = Tmp;
+ Private->Instance.MaxRecycledTxBuf += SNP_TX_BUFFER_INCREASEMENT;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Receives a packet from a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header received on the network
+ interface. If this parameter is NULL, then the media header size
+ will not be returned.
+ @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
+ bytes, of the packet that was received on the network interface.
+ @param Buffer A pointer to the data buffer to receive both the media header and
+ the data.
+ @param SrcAddr The source HW MAC address. If this parameter is NULL, the
+ HW MAC source address will not be extracted from the media
+ header.
+ @param DestAddr The destination HW MAC address. If this parameter is NULL,
+ the HW MAC destination address will not be extracted from the
+ media header.
+ @param Protocol The media header type. If this parameter is NULL, then the
+ protocol will not be extracted from the media header. See
+ RFC 1700 section "Ether Types" for examples.
+
+ @retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has
+ been updated to the number of bytes received.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit
+ request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+WinNtSnpReceive (
+ IN EMU_SNP_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ OUT UINT16 *Protocol OPTIONAL
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+ INT32 ReturnValue;
+ UINTN BufSize;
+
+ Private = WIN_NT_SNP_PRIVATE_DATA_FROM_THIS (This);
+
+ BufSize = *BufferSize;
+
+ ASSERT (Private->NtNetUtilityTable.Receive != NULL);
+
+ ReturnValue = Private->NtNetUtilityTable.Receive (
+ Private->Instance.InterfaceInfo.InterfaceIndex,
+ BufferSize,
+ Buffer
+ );
+
+ if (ReturnValue < 0) {
+ if (ReturnValue == -100) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ return EFI_DEVICE_ERROR;
+ } else if (ReturnValue == 0) {
+ return EFI_NOT_READY;
+ }
+
+ if (HeaderSize != NULL) {
+ *HeaderSize = 14;
+ }
+
+ if (SrcAddr != NULL) {
+ ZeroMem (SrcAddr, sizeof (EFI_MAC_ADDRESS));
+ CopyMem (SrcAddr, ((UINT8 *) Buffer) + 6, 6);
+ }
+
+ if (DestAddr != NULL) {
+ ZeroMem (DestAddr, sizeof (EFI_MAC_ADDRESS));
+ CopyMem (DestAddr, ((UINT8 *) Buffer), 6);
+ }
+
+ if (Protocol != NULL) {
+ *Protocol = NTOHS (*((UINT16 *) (((UINT8 *) Buffer) + 12)));
+ }
+
+ return (*BufferSize <= BufSize) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
+}
+
+/**
+ Initialize the snpnt32 driver instance.
+
+ @param Instance Pointer to the instance context data.
+ @param NetInfo Pointer to the interface info.
+
+ @retval EFI_SUCCESS The driver instance is initialized.
+ @retval other Initialization errors.
+
+**/
+EFI_STATUS
+WinNtInitializeInstanceData (
+ IN OUT WIN_NT_INSTANCE_DATA *Instance,
+ IN NT_NET_INTERFACE_INFO *NetInfo
+ )
+{
+ if (Instance == NULL || NetInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (Instance, sizeof (WIN_NT_INSTANCE_DATA));
+
+ Instance->Signature = WIN_NT_INSTANCE_SIGNATURE;
+ Instance->RecycledTxBufCount = 0;
+ Instance->MaxRecycledTxBuf = 32;
+ Instance->Mode.State = EfiSimpleNetworkInitialized;
+ Instance->Mode.HwAddressSize = NET_ETHER_ADDR_LEN;
+ Instance->Mode.MediaHeaderSize = NET_ETHER_HEADER_SIZE;
+ Instance->Mode.MaxPacketSize = 1500;
+ Instance->Mode.MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;
+ Instance->Mode.IfType = NET_IFTYPE_ETHERNET;
+ Instance->Mode.MediaPresentSupported = TRUE;
+ Instance->Mode.MediaPresent = TRUE;
+
+ //
+ // Allocate the RecycledTxBuf.
+ //
+ Instance->RecycledTxBuf = malloc (sizeof (UINT64) * Instance->MaxRecycledTxBuf);
+ if (Instance->RecycledTxBuf == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Set the interface information.
+ //
+ CopyMem (&Instance->InterfaceInfo, NetInfo, sizeof (Instance->InterfaceInfo));
+
+
+ //
+ // Set broadcast address
+ //
+ SetMem (&Instance->Mode.BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF);
+
+ //
+ // Copy Current/PermanentAddress MAC address
+ //
+ CopyMem (&Instance->Mode.CurrentAddress, &Instance->InterfaceInfo.MacAddr, sizeof(Instance->Mode.CurrentAddress));
+ CopyMem (&Instance->Mode.PermanentAddress, &Instance->InterfaceInfo.MacAddr, sizeof(Instance->Mode.PermanentAddress));
+
+ //
+ // Since the fake SNP is based on a real NIC, to avoid conflict with the host
+ // NIC network stack, we use a different MAC address.
+ // So just change the last byte of the MAC address for the real NIC.
+ //
+ Instance->Mode.CurrentAddress.Addr[NET_ETHER_ADDR_LEN - 1]++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the net utility data.
+
+ @param This Pointer to the private data.
+ @param ActiveInstance The active network interface.
+
+ @retval EFI_SUCCESS The global data is initialized.
+ @retval EFI_NOT_FOUND The required DLL is not found.
+ @retval EFI_DEVICE_ERROR Error initialize network utility library.
+ @retval other Other errors.
+
+**/
+EFI_STATUS
+WintNtInitializeNetUtilityData (
+ IN OUT WIN_NT_SNP_PRIVATE *Private,
+ IN UINT8 ActiveInstance
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *DllFileNameU;
+ INT32 ReturnValue;
+ BOOLEAN NetUtilityLibInitDone;
+ NT_NET_INTERFACE_INFO NetInterfaceInfoBuffer[MAX_INTERFACE_INFO_NUMBER];
+ UINT32 InterfaceCount;
+ UINT8 ActiveInterfaceIndex;
+
+ if (Private == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NetUtilityLibInitDone = FALSE;
+ InterfaceCount = MAX_INTERFACE_INFO_NUMBER;
+ DllFileNameU = NETWORK_LIBRARY_NAME_U;
+
+ //
+ // Load network utility library
+ //
+ Private->NetworkLibraryHandle = LoadLibraryEx (DllFileNameU, NULL, 0);
+ if (NULL == Private->NetworkLibraryHandle) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private->NtNetUtilityTable.Initialize = (NT_NET_INITIALIZE) GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_INITIALIZE);
+ if (NULL == Private->NtNetUtilityTable.Initialize) {
+ Status = EFI_NOT_FOUND;
+ goto ErrorReturn;
+ }
+
+ Private->NtNetUtilityTable.Finalize = (NT_NET_FINALIZE) GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_FINALIZE);
+ if (NULL == Private->NtNetUtilityTable.Finalize) {
+ Status = EFI_NOT_FOUND;
+ goto ErrorReturn;
+ }
+
+ Private->NtNetUtilityTable.SetReceiveFilter = (NT_NET_SET_RECEIVE_FILTER) GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_SET_RCV_FILTER);
+ if (NULL == Private->NtNetUtilityTable.SetReceiveFilter) {
+ Status = EFI_NOT_FOUND;
+ goto ErrorReturn;
+ }
+
+ Private->NtNetUtilityTable.Receive = (NT_NET_RECEIVE) GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_RECEIVE);
+ if (NULL == Private->NtNetUtilityTable.Receive) {
+ Status = EFI_NOT_FOUND;
+ goto ErrorReturn;
+ }
+
+ Private->NtNetUtilityTable.Transmit = (NT_NET_TRANSMIT) GetProcAddress (Private->NetworkLibraryHandle, NETWORK_LIBRARY_TRANSMIT);
+ if (NULL == Private->NtNetUtilityTable.Transmit) {
+ Status = EFI_NOT_FOUND;
+ goto ErrorReturn;
+ }
+
+ //
+ // Initialize the network utility library
+ // And enumerate the interfaces in emulator host
+ //
+ ReturnValue = Private->NtNetUtilityTable.Initialize (&InterfaceCount, &NetInterfaceInfoBuffer[0]);
+ if (ReturnValue <= 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto ErrorReturn;
+ }
+
+ NetUtilityLibInitDone = TRUE;
+
+ if (InterfaceCount == 0) {
+ Status = EFI_NOT_FOUND;
+ goto ErrorReturn;
+ }
+
+ DEBUG ((DEBUG_INFO, "%a, total %d interface(s) found\n", __FUNCTION__, InterfaceCount));
+ //
+ // Active interface index is set to first interface if given instance does
+ // not exist.
+ //
+ ActiveInterfaceIndex = (ActiveInstance >= InterfaceCount ? DEFAULT_SELECTED_NIC_INDEX : ActiveInstance);
+
+ //
+ // Initialize instance
+ //
+ Status = WinNtInitializeInstanceData (&Private->Instance, &NetInterfaceInfoBuffer[ActiveInterfaceIndex]);
+ if (EFI_ERROR (Status)) {
+ goto ErrorReturn;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorReturn:
+
+ if (Private->Instance.RecycledTxBuf != NULL) {
+ free (Private->Instance.RecycledTxBuf);
+ }
+
+ if (NetUtilityLibInitDone) {
+ if (Private->NtNetUtilityTable.Finalize != NULL) {
+ Private->NtNetUtilityTable.Finalize ();
+ Private->NtNetUtilityTable.Finalize = NULL;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Release the net utility data.
+
+ @param This Pointer to the private data.
+
+ @retval EFI_SUCCESS The global data is released.
+ @retval other Other errors.
+
+**/
+EFI_STATUS
+WintNtReleaseNetUtilityData (
+ IN OUT WIN_NT_SNP_PRIVATE *Private
+ )
+{
+ if (Private == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Private->Instance.RecycledTxBuf != NULL) {
+ free (Private->Instance.RecycledTxBuf);
+ }
+
+ if (Private->NtNetUtilityTable.Finalize != NULL) {
+ Private->NtNetUtilityTable.Finalize ();
+ }
+
+ FreeLibrary (Private->NetworkLibraryHandle);
+
+ return EFI_SUCCESS;
+}
+
+EMU_SNP_PROTOCOL mWinNtSnpProtocol = {
+ WinNtSnpCreateMapping,
+ WinNtSnpStart,
+ WinNtSnpStop,
+ WinNtSnpInitialize,
+ WinNtSnpReset,
+ WinNtSnpShutdown,
+ WinNtSnpReceiveFilters,
+ WinNtSnpStationAddress,
+ WinNtSnpStatistics,
+ WinNtSnpMCastIpToMac,
+ WinNtSnpNvData,
+ WinNtSnpGetStatus,
+ WinNtSnpTransmit,
+ WinNtSnpReceive
+};
+
+/**
+ Open SNP thunk protocol.
+
+ @param This Pointer to the thunk protocol instance.
+
+ @retval EFI_SUCCESS SNP thunk protocol is opened successfully.
+ @retval EFI_UNSUPPORTED This is not SNP thunk protocol.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory.
+ @retval other Other errors.
+
+**/
+EFI_STATUS
+WinNtSnpThunkOpen (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+ UINT8 HostInterfaceIndex;
+
+ HostInterfaceIndex = 0;
+
+ if (This->Private != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (!CompareGuid (This->Protocol, &gEmuSnpProtocolGuid)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Private = malloc (sizeof (WIN_NT_SNP_PRIVATE));
+ if (Private == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Signature = WIN_NT_SIMPLE_NETWORK_PRIVATE_SIGNATURE;
+ Private->Thunk = This;
+ CopyMem (&Private->EmuSnp, &mWinNtSnpProtocol, sizeof (mWinNtSnpProtocol));
+
+ This->Interface = &Private->EmuSnp;
+ This->Private = Private;
+
+ if (This->ConfigString != NULL && This->ConfigString[0] != '\0') {
+ HostInterfaceIndex = (UINT8)StrDecimalToUintn (This->ConfigString);
+ }
+
+ return WintNtInitializeNetUtilityData (Private, HostInterfaceIndex);
+}
+
+/**
+ Close SNP thunk protocol.
+
+ @param This Pointer to the thunk protocol instance.
+
+ @retval EFI_SUCCESS SNP thunk protocol is closed successfully.
+ @retval EFI_UNSUPPORTED This is not SNP thunk protocol.
+ @retval other Other errors.
+
+**/
+EFI_STATUS
+WinNtSnpThunkClose (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ )
+{
+ WIN_NT_SNP_PRIVATE *Private;
+
+ if (!CompareGuid (This->Protocol, &gEmuSnpProtocolGuid)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Private = This->Private;
+ WintNtReleaseNetUtilityData (Private);
+ free (Private);
+
+ return EFI_SUCCESS;
+}
+
+EMU_IO_THUNK_PROTOCOL mWinNtSnpThunkIo = {
+ &gEmuSnpProtocolGuid,
+ NULL,
+ NULL,
+ 0,
+ WinNtSnpThunkOpen,
+ WinNtSnpThunkClose,
+ NULL
+};
diff --git a/roms/edk2/EmulatorPkg/Win/Host/WinThunk.c b/roms/edk2/EmulatorPkg/Win/Host/WinThunk.c
new file mode 100644
index 000000000..a77be2a64
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/Host/WinThunk.c
@@ -0,0 +1,580 @@
+/**@file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ WinNtThunk.c
+
+Abstract:
+
+ Since the SEC is the only windows program in our emulation we
+ must use a Tiano mechanism to export Win32 APIs to other modules.
+ This is the role of the EFI_WIN_NT_THUNK_PROTOCOL.
+
+ The mWinNtThunkTable exists so that a change to EFI_WIN_NT_THUNK_PROTOCOL
+ will cause an error in initializing the array if all the member functions
+ are not added. It looks like adding a element to end and not initializing
+ it may cause the table to be initaliized with the members at the end being
+ set to zero. This is bad as jumping to zero will case the NT32 to crash.
+
+ All the member functions in mWinNtThunkTable are Win32
+ API calls, so please reference Microsoft documentation.
+
+
+ gWinNt is a a public exported global that contains the initialized
+ data.
+
+**/
+
+#include "WinHost.h"
+
+UINTN
+SecWriteStdErr (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ BOOL Success;
+ DWORD CharCount;
+
+ CharCount = (DWORD)NumberOfBytes;
+ Success = WriteFile (
+ GetStdHandle (STD_ERROR_HANDLE),
+ Buffer,
+ CharCount,
+ &CharCount,
+ NULL
+ );
+
+ return Success ? CharCount : 0;
+}
+
+
+EFI_STATUS
+SecConfigStdIn (
+ VOID
+ )
+{
+ BOOL Success;
+ DWORD Mode;
+
+ Success = GetConsoleMode (GetStdHandle (STD_INPUT_HANDLE), &Mode);
+ if (Success) {
+ //
+ // Disable buffer (line input), echo, mouse, window
+ //
+ Mode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
+
+#if defined(NTDDI_VERSION) && defined (NTDDI_WIN10_TH2) && (NTDDI_VERSION > NTDDI_WIN10_TH2)
+ //
+ // Enable virtual terminal input for Win10 above TH2
+ //
+ Mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
+#endif
+
+ Success = SetConsoleMode (GetStdHandle (STD_INPUT_HANDLE), Mode);
+ }
+
+#if defined(NTDDI_VERSION) && defined (NTDDI_WIN10_TH2) && (NTDDI_VERSION > NTDDI_WIN10_TH2)
+ //
+ // Enable terminal mode for Win10 above TH2
+ //
+ if (Success) {
+ Success = GetConsoleMode (GetStdHandle (STD_OUTPUT_HANDLE), &Mode);
+ if (Success) {
+ Success = SetConsoleMode (
+ GetStdHandle (STD_OUTPUT_HANDLE),
+ Mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN
+ );
+ }
+ }
+#endif
+ return Success ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+}
+
+UINTN
+SecWriteStdOut (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ BOOL Success;
+ DWORD CharCount;
+
+ CharCount = (DWORD)NumberOfBytes;
+ Success = WriteFile (
+ GetStdHandle (STD_OUTPUT_HANDLE),
+ Buffer,
+ CharCount,
+ &CharCount,
+ NULL
+ );
+
+ return Success ? CharCount : 0;
+}
+
+BOOLEAN
+SecPollStdIn (
+ VOID
+ )
+{
+ BOOL Success;
+ INPUT_RECORD Record;
+ DWORD RecordNum;
+
+ do {
+ Success = GetNumberOfConsoleInputEvents (GetStdHandle (STD_INPUT_HANDLE), &RecordNum);
+ if (!Success || (RecordNum == 0)) {
+ break;
+ }
+ Success = PeekConsoleInput (
+ GetStdHandle (STD_INPUT_HANDLE),
+ &Record,
+ 1,
+ &RecordNum
+ );
+ if (Success && (RecordNum == 1)) {
+ if (Record.EventType == KEY_EVENT && Record.Event.KeyEvent.bKeyDown) {
+ return TRUE;
+ } else {
+ //
+ // Consume the non-key event.
+ //
+ Success = ReadConsoleInput (
+ GetStdHandle (STD_INPUT_HANDLE),
+ &Record,
+ 1,
+ &RecordNum
+ );
+ }
+ }
+ } while (Success);
+
+ return FALSE;
+}
+
+UINTN
+SecReadStdIn (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ BOOL Success;
+ INPUT_RECORD Record;
+ DWORD RecordNum;
+ UINTN BytesReturn;
+
+ if (!SecPollStdIn ()) {
+ return 0;
+ }
+ Success = ReadConsoleInput (
+ GetStdHandle (STD_INPUT_HANDLE),
+ &Record,
+ 1,
+ &RecordNum
+ );
+ ASSERT (Success && (RecordNum == 1) && (Record.EventType == KEY_EVENT) && (Record.Event.KeyEvent.bKeyDown));
+ NumberOfBytes = MIN (Record.Event.KeyEvent.wRepeatCount, NumberOfBytes);
+ BytesReturn = NumberOfBytes;
+ while (NumberOfBytes-- != 0) {
+ Buffer[NumberOfBytes] = Record.Event.KeyEvent.uChar.AsciiChar;
+ }
+ return BytesReturn;
+}
+
+
+VOID *
+SecAlloc (
+ IN UINTN Size
+ )
+{
+ return malloc ((size_t)Size);
+}
+
+BOOLEAN
+SecFree (
+ IN VOID *Ptr
+ )
+{
+ if (EfiSystemMemoryRange (Ptr)) {
+ // If an address range is in the EFI memory map it was alloced via EFI.
+ // So don't free those ranges and let the caller know.
+ return FALSE;
+ }
+
+ free (Ptr);
+ return TRUE;
+}
+
+
+
+//
+// Define a global that we can use to shut down the NT timer thread when
+// the timer is canceled.
+//
+BOOLEAN mCancelTimerThread = FALSE;
+
+//
+// The notification function to call on every timer interrupt
+//
+EMU_SET_TIMER_CALLBACK *mTimerNotifyFunction = NULL;
+
+//
+// The thread handle for this driver
+//
+HANDLE mNtMainThreadHandle;
+
+//
+// The timer value from the last timer interrupt
+//
+UINT32 mNtLastTick;
+
+//
+// Critical section used to update varibles shared between the main thread and
+// the timer interrupt thread.
+//
+CRITICAL_SECTION mNtCriticalSection;
+
+//
+// Worker Functions
+//
+UINT mMMTimerThreadID = 0;
+
+volatile BOOLEAN mInterruptEnabled = FALSE;
+
+VOID
+CALLBACK
+MMTimerThread (
+ UINT wTimerID,
+ UINT msg,
+ DWORD dwUser,
+ DWORD dw1,
+ DWORD dw2
+)
+{
+ UINT32 CurrentTick;
+ UINT32 Delta;
+
+ if (!mCancelTimerThread) {
+
+ //
+ // Suspend the main thread until we are done.
+ // Enter the critical section before suspending
+ // and leave the critical section after resuming
+ // to avoid deadlock between main and timer thread.
+ //
+ EnterCriticalSection (&mNtCriticalSection);
+ SuspendThread (mNtMainThreadHandle);
+
+ //
+ // If the timer thread is being canceled, then bail immediately.
+ // We check again here because there's a small window of time from when
+ // this thread was kicked off and when we suspended the main thread above.
+ //
+ if (mCancelTimerThread) {
+ ResumeThread (mNtMainThreadHandle);
+ LeaveCriticalSection (&mNtCriticalSection);
+ timeKillEvent (wTimerID);
+ mMMTimerThreadID = 0;
+ return;
+ }
+
+ while (!mInterruptEnabled) {
+ //
+ // Resume the main thread
+ //
+ ResumeThread (mNtMainThreadHandle);
+ LeaveCriticalSection (&mNtCriticalSection);
+
+ //
+ // Wait for interrupts to be enabled.
+ //
+ while (!mInterruptEnabled) {
+ Sleep (1);
+ }
+
+ //
+ // Suspend the main thread until we are done
+ //
+ EnterCriticalSection (&mNtCriticalSection);
+ SuspendThread (mNtMainThreadHandle);
+ }
+
+ //
+ // Get the current system tick
+ //
+ CurrentTick = GetTickCount ();
+ Delta = CurrentTick - mNtLastTick;
+ mNtLastTick = CurrentTick;
+
+ //
+ // If delay was more then 1 second, ignore it (probably debugging case)
+ //
+ if (Delta < 1000) {
+
+ //
+ // Only invoke the callback function if a Non-NULL handler has been
+ // registered. Assume all other handlers are legal.
+ //
+ if (mTimerNotifyFunction != NULL) {
+ mTimerNotifyFunction (Delta);
+ }
+ }
+
+ //
+ // Resume the main thread
+ //
+ ResumeThread (mNtMainThreadHandle);
+ LeaveCriticalSection (&mNtCriticalSection);
+ } else {
+ timeKillEvent (wTimerID);
+ mMMTimerThreadID = 0;
+ }
+
+}
+
+VOID
+SecSetTimer (
+ IN UINT64 TimerPeriod,
+ IN EMU_SET_TIMER_CALLBACK Callback
+)
+{
+ //
+// If TimerPeriod is 0, then the timer thread should be canceled
+//
+ if (TimerPeriod == 0) {
+ //
+ // Cancel the timer thread
+ //
+ EnterCriticalSection (&mNtCriticalSection);
+
+ mCancelTimerThread = TRUE;
+
+ LeaveCriticalSection (&mNtCriticalSection);
+
+ //
+ // Wait for the timer thread to exit
+ //
+
+ if (mMMTimerThreadID != 0) {
+ timeKillEvent (mMMTimerThreadID);
+ mMMTimerThreadID = 0;
+ }
+ } else {
+ //
+ // If the TimerPeriod is valid, then create and/or adjust the period of the timer thread
+ //
+ EnterCriticalSection (&mNtCriticalSection);
+
+ mCancelTimerThread = FALSE;
+
+ LeaveCriticalSection (&mNtCriticalSection);
+
+ //
+ // Get the starting tick location if we are just starting the timer thread
+ //
+ mNtLastTick = GetTickCount ();
+
+ if (mMMTimerThreadID) {
+ timeKillEvent (mMMTimerThreadID);
+ }
+
+ SetThreadPriority (
+ GetCurrentThread (),
+ THREAD_PRIORITY_HIGHEST
+ );
+
+ mMMTimerThreadID = timeSetEvent (
+ (UINT)TimerPeriod,
+ 0,
+ MMTimerThread,
+ (DWORD_PTR)NULL,
+ TIME_PERIODIC | TIME_KILL_SYNCHRONOUS | TIME_CALLBACK_FUNCTION
+ );
+ }
+ mTimerNotifyFunction = Callback;
+}
+
+VOID
+SecInitializeThunk (
+ VOID
+)
+{
+ InitializeCriticalSection (&mNtCriticalSection);
+
+ DuplicateHandle (
+ GetCurrentProcess (),
+ GetCurrentThread (),
+ GetCurrentProcess (),
+ &mNtMainThreadHandle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS
+ );
+}
+
+VOID
+SecEnableInterrupt (
+ VOID
+ )
+{
+ mInterruptEnabled = TRUE;
+}
+
+
+VOID
+SecDisableInterrupt (
+ VOID
+ )
+{
+ mInterruptEnabled = FALSE;
+}
+
+
+UINT64
+SecQueryPerformanceFrequency (
+ VOID
+ )
+{
+ // Hard code to nanoseconds
+ return 1000000000ULL;
+}
+
+UINT64
+SecQueryPerformanceCounter (
+ VOID
+ )
+{
+ return 0;
+}
+
+
+
+VOID
+SecSleep (
+ IN UINT64 Nanoseconds
+ )
+{
+ Sleep ((DWORD)DivU64x32 (Nanoseconds, 1000000));
+}
+
+
+VOID
+SecCpuSleep (
+ VOID
+ )
+{
+ Sleep (1);
+}
+
+
+VOID
+SecExit (
+ UINTN Status
+ )
+{
+ exit ((int)Status);
+}
+
+
+VOID
+SecGetTime (
+ OUT EFI_TIME *Time,
+ OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
+ )
+{
+ SYSTEMTIME SystemTime;
+ TIME_ZONE_INFORMATION TimeZone;
+
+ GetLocalTime (&SystemTime);
+ GetTimeZoneInformation (&TimeZone);
+
+ Time->Year = (UINT16)SystemTime.wYear;
+ Time->Month = (UINT8)SystemTime.wMonth;
+ Time->Day = (UINT8)SystemTime.wDay;
+ Time->Hour = (UINT8)SystemTime.wHour;
+ Time->Minute = (UINT8)SystemTime.wMinute;
+ Time->Second = (UINT8)SystemTime.wSecond;
+ Time->Nanosecond = (UINT32)(SystemTime.wMilliseconds * 1000000);
+ Time->TimeZone = (INT16)TimeZone.Bias;
+
+ if (Capabilities != NULL) {
+ Capabilities->Resolution = 1;
+ Capabilities->Accuracy = 50000000;
+ Capabilities->SetsToZero = FALSE;
+ }
+
+ Time->Daylight = 0;
+ if (TimeZone.StandardDate.wMonth) {
+ Time->Daylight = (UINT8)TimeZone.StandardDate.wMonth;
+ }
+}
+
+EFI_STATUS
+SecSetTime (
+ IN EFI_TIME *Time
+ )
+{
+ TIME_ZONE_INFORMATION TimeZone;
+ SYSTEMTIME SystemTime;
+ BOOL Flag;
+
+ //
+ // Set Daylight savings time information and Time Zone
+ //
+ GetTimeZoneInformation (&TimeZone);
+ TimeZone.StandardDate.wMonth = Time->Daylight;
+ TimeZone.Bias = Time->TimeZone;
+ Flag = SetTimeZoneInformation (&TimeZone);
+ if (!Flag) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ SystemTime.wYear = Time->Year;
+ SystemTime.wMonth = Time->Month;
+ SystemTime.wDay = Time->Day;
+ SystemTime.wHour = Time->Hour;
+ SystemTime.wMinute = Time->Minute;
+ SystemTime.wSecond = Time->Second;
+ SystemTime.wMilliseconds = (INT16)(Time->Nanosecond / 1000000);
+
+ Flag = SetLocalTime (&SystemTime);
+
+ if (!Flag) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+EMU_THUNK_PROTOCOL gEmuThunkProtocol = {
+ SecWriteStdErr,
+ SecConfigStdIn,
+ SecWriteStdOut,
+ SecReadStdIn,
+ SecPollStdIn,
+ SecAlloc,
+ NULL,
+ SecFree,
+ SecPeCoffGetEntryPoint,
+ PeCoffLoaderRelocateImageExtraAction,
+ PeCoffLoaderUnloadImageExtraAction,
+ SecEnableInterrupt,
+ SecDisableInterrupt,
+ SecQueryPerformanceFrequency,
+ SecQueryPerformanceCounter,
+ SecSleep,
+ SecCpuSleep,
+ SecExit,
+ SecGetTime,
+ SecSetTime,
+ SecSetTimer,
+ GetNextThunkProtocol
+};
+
+
+#pragma warning(default : 4996)
+#pragma warning(default : 4232)
+
diff --git a/roms/edk2/EmulatorPkg/Win/VS2017/BuildVS.bat b/roms/edk2/EmulatorPkg/Win/VS2017/BuildVS.bat
new file mode 100644
index 000000000..6fcf40cc0
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/VS2017/BuildVS.bat
@@ -0,0 +1,3 @@
+cd ../../../
+@call edksetup.bat
+build -p EmulatorPkg\EmulatorPkg.dsc -t VS2017 %*
diff --git a/roms/edk2/EmulatorPkg/Win/VS2017/Win.sln b/roms/edk2/EmulatorPkg/Win/VS2017/Win.sln
new file mode 100644
index 000000000..397c5d9b8
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/VS2017/Win.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28010.2003
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Win", "Win.vcxproj", "{B4E1783F-FD72-4214-B0F7-69271BAD5DDF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B4E1783F-FD72-4214-B0F7-69271BAD5DDF}.Debug|x64.ActiveCfg = Debug|x64
+ {B4E1783F-FD72-4214-B0F7-69271BAD5DDF}.Debug|x64.Build.0 = Debug|x64
+ {B4E1783F-FD72-4214-B0F7-69271BAD5DDF}.Debug|x86.ActiveCfg = Debug|Win32
+ {B4E1783F-FD72-4214-B0F7-69271BAD5DDF}.Debug|x86.Build.0 = Debug|Win32
+ {B4E1783F-FD72-4214-B0F7-69271BAD5DDF}.Release|x64.ActiveCfg = Release|x64
+ {B4E1783F-FD72-4214-B0F7-69271BAD5DDF}.Release|x64.Build.0 = Release|x64
+ {B4E1783F-FD72-4214-B0F7-69271BAD5DDF}.Release|x86.ActiveCfg = Release|Win32
+ {B4E1783F-FD72-4214-B0F7-69271BAD5DDF}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+EndGlobal
diff --git a/roms/edk2/EmulatorPkg/Win/VS2017/Win.vcxproj b/roms/edk2/EmulatorPkg/Win/VS2017/Win.vcxproj
new file mode 100644
index 000000000..0f574a8e7
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/VS2017/Win.vcxproj
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>15.0</VCProjectVersion>
+ <ProjectGuid>{B4E1783F-FD72-4214-B0F7-69271BAD5DDF}</ProjectGuid>
+ <Keyword>MakeFileProj</Keyword>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <NMakeBuildCommandLine>BuildVS.bat -a IA32</NMakeBuildCommandLine>
+ <NMakeReBuildCommandLine>BuildVS.bat -a IA32 all</NMakeReBuildCommandLine>
+ <NMakeCleanCommandLine>BuildVS.bat -a IA32 clean</NMakeCleanCommandLine>
+ <OutDir>..\..\..\Build\EmulatorIA32\DEBUG_VS2017\</OutDir>
+ <IntDir>..\..\..\Build\EmulatorIA32\DEBUG_VS2017\</IntDir>
+ <IncludePath>..\..\..\MdePkg\Include;..\..\..\MdePkg\Include\Ia32;..\..\..\MdeModulePkg\Include;..\..\..\EmulatorPkg\Include;$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <NMakeBuildCommandLine>BuildVS.bat -a IA32 -b RELEASE</NMakeBuildCommandLine>
+ <NMakePreprocessorDefinitions>
+ </NMakePreprocessorDefinitions>
+ <NMakeReBuildCommandLine>BuildVS.bat -a IA32 -b RELEASE all</NMakeReBuildCommandLine>
+ <NMakeCleanCommandLine>BuildVS.bat -a IA32 -b RELEASE clean</NMakeCleanCommandLine>
+ <OutDir>..\..\..\Build\EmulatorIA32\DEBUG_VS2017\</OutDir>
+ <IntDir>..\..\..\Build\EmulatorIA32\DEBUG_VS2017\</IntDir>
+ <IncludePath>..\..\..\MdePkg\Include;..\..\..\MdePkg\Include\Ia32;..\..\..\MdeModulePkg\Include;..\..\..\EmulatorPkg\Include;$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <NMakeBuildCommandLine>BuildVS.bat -a X64</NMakeBuildCommandLine>
+ <NMakeReBuildCommandLine>BuildVS.bat -a X64 all</NMakeReBuildCommandLine>
+ <NMakeCleanCommandLine>BuildVS.bat -a X64 clean</NMakeCleanCommandLine>
+ <OutDir>..\..\..\Build\EmulatorX64\DEBUG_VS2017\</OutDir>
+ <IntDir>..\..\..\Build\EmulatorX64\DEBUG_VS2017\</IntDir>
+ <IncludePath>..\..\..\MdePkg\Include;..\..\..\MdePkg\Include\X64;..\..\..\MdeModulePkg\Include;..\..\..\EmulatorPkg\Include;$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <NMakeBuildCommandLine>BuildVS.bat -a X64 -b RELEASE</NMakeBuildCommandLine>
+ <NMakeReBuildCommandLine>BuildVS.bat -a X64 -b RELEASE all</NMakeReBuildCommandLine>
+ <NMakeCleanCommandLine>BuildVS.bat -a X64 -b RELEASE clean</NMakeCleanCommandLine>
+ <OutDir>..\..\Build\EmulatorX64\DEBUG_VS2017\</OutDir>
+ <IntDir>..\..\Build\EmulatorX64\DEBUG_VS2017\</IntDir>
+ <IncludePath>..\..\..\MdePkg\Include;..\..\..\MdePkg\Include\X64;..\..\..\MdeModulePkg\Include;..\..\..\EmulatorPkg\Include;$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <ItemGroup>
+ <ClCompile Include="..\Host\WinBlockIo.c" />
+ <ClCompile Include="..\Host\WinFileSystem.c" />
+ <ClCompile Include="..\Host\WinGopInput.c" />
+ <ClCompile Include="..\Host\WinGopScreen.c" />
+ <ClCompile Include="..\Host\WinHost.c" />
+ <ClCompile Include="..\Host\WinMemoryAllocationLib.c" />
+ <ClCompile Include="..\Host\WinThunk.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\Host\WinGop.h" />
+ <ClInclude Include="..\Host\WinHost.h" />
+ <ClInclude Include="..\Host\WinInclude.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\Host\WinHost.inf" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/roms/edk2/EmulatorPkg/Win/VS2017/Win.vcxproj.filters b/roms/edk2/EmulatorPkg/Win/VS2017/Win.vcxproj.filters
new file mode 100644
index 000000000..3e176597b
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/VS2017/Win.vcxproj.filters
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="host\WinBlockIo.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="host\WinFileSystem.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="host\WinGopInput.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="host\WinGopScreen.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="host\WinHost.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="host\WinMemoryAllocationLib.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="host\WinThunk.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="host\WinGop.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="host\WinHost.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="host\WinInclude.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Host\WinHost.inf" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/roms/edk2/EmulatorPkg/Win/VS2017/Win.vcxproj.user b/roms/edk2/EmulatorPkg/Win/VS2017/Win.vcxproj.user
new file mode 100644
index 000000000..7ccf83f13
--- /dev/null
+++ b/roms/edk2/EmulatorPkg/Win/VS2017/Win.vcxproj.user
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LocalDebuggerCommand>WinHost.exe</LocalDebuggerCommand>
+ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+ <LocalDebuggerWorkingDirectory>$(ProjectDir)..\..\..\Build\EmulatorIA32\DEBUG_VS2017\IA32\</LocalDebuggerWorkingDirectory>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LocalDebuggerCommand>WinHost.exe</LocalDebuggerCommand>
+ <LocalDebuggerWorkingDirectory>$(ProjectDir)..\..\..\Build\EmulatorX64\DEBUG_VS2017\X64\</LocalDebuggerWorkingDirectory>
+ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+ </PropertyGroup>
+</Project> \ No newline at end of file