public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH 00/12] Add WinHost support in EmulatorPkg
@ 2018-08-23  9:52 Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 01/12] EmulatorPkg/ThunkProtocolList: Fix VS build failure Ruiyu Ni
                   ` (12 more replies)
  0 siblings, 13 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1112

The patch sets add WinHost support (Nt32) in EmulatorPkg.
3 EmulatorPkg common issues were found and fixed.
Other 9 patches are to step-by-step enable the WinHost.

Ruiyu Ni (12):
  EmulatorPkg/ThunkProtocolList: Fix VS build failure
  EmulatorPkg/Win: Add Windows host support
  EmulatorPkg/Win: Enable source level debugging
  EmulatorPkg/Win: Enable native OS console as firmware console
  EmulatorPkg/Win: Add input/output support
  EmulatorPkg/Win: Add timer and interrupt support
  EmulatorPkg/Win: Add RTC support
  EmulatorPkg/Win: Add SimpleFileSystem support
  EmulatorPkg/Win: Add BlockIo support
  EmulatorPkg/PlatformBds: Signal EndOfDxe in platform BDS
  EmulatorPkg/EmuFileSystem: Fix a bug that causes Close() assertion
  EmulatorPkg/DSC: Remove FS mapping to EDK Shell bin directory

 .../EmuSimpleFileSystemDxe/EmuSimpleFileSystem.c   |   33 +-
 EmulatorPkg/EmulatorPkg.dsc                        |   17 +-
 EmulatorPkg/Library/EmuBdsLib/BdsPlatform.c        |    4 +-
 EmulatorPkg/Library/EmuBdsLib/BdsPlatform.h        |    4 +-
 EmulatorPkg/Library/EmuBdsLib/EmuBdsLib.inf        |    5 +-
 .../Library/ThunkProtocolList/ThunkProtocolList.c  |    4 +-
 EmulatorPkg/Win/Host/WinBlockIo.c                  |  563 +++++
 EmulatorPkg/Win/Host/WinFileSystem.c               | 2409 ++++++++++++++++++++
 EmulatorPkg/Win/Host/WinGop.h                      |  204 ++
 EmulatorPkg/Win/Host/WinGopInput.c                 |  417 ++++
 EmulatorPkg/Win/Host/WinGopScreen.c                |  872 +++++++
 EmulatorPkg/Win/Host/WinHost.c                     |  947 ++++++++
 EmulatorPkg/Win/Host/WinHost.h                     |  209 ++
 EmulatorPkg/Win/Host/WinHost.inf                   |  107 +
 EmulatorPkg/Win/Host/WinInclude.h                  |   75 +
 EmulatorPkg/Win/Host/WinMemoryAllocationLib.c      |  178 ++
 EmulatorPkg/Win/Host/WinThunk.c                    |  577 +++++
 17 files changed, 6614 insertions(+), 11 deletions(-)
 create mode 100644 EmulatorPkg/Win/Host/WinBlockIo.c
 create mode 100644 EmulatorPkg/Win/Host/WinFileSystem.c
 create mode 100644 EmulatorPkg/Win/Host/WinGop.h
 create mode 100644 EmulatorPkg/Win/Host/WinGopInput.c
 create mode 100644 EmulatorPkg/Win/Host/WinGopScreen.c
 create mode 100644 EmulatorPkg/Win/Host/WinHost.c
 create mode 100644 EmulatorPkg/Win/Host/WinHost.h
 create mode 100644 EmulatorPkg/Win/Host/WinHost.inf
 create mode 100644 EmulatorPkg/Win/Host/WinInclude.h
 create mode 100644 EmulatorPkg/Win/Host/WinMemoryAllocationLib.c
 create mode 100644 EmulatorPkg/Win/Host/WinThunk.c

-- 
2.16.1.windows.1



^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 01/12] EmulatorPkg/ThunkProtocolList: Fix VS build failure
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
@ 2018-08-23  9:52 ` Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 02/12] EmulatorPkg/Win: Add Windows host support Ruiyu Ni
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel; +Cc: Andrdw Fish, Hao A Wu

VS compiler complains converting UINTN to UINT16 causes data lost.
Add typecast to fix the build failure.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Andrdw Fish <afish@apple.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
---
 EmulatorPkg/Library/ThunkProtocolList/ThunkProtocolList.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/EmulatorPkg/Library/ThunkProtocolList/ThunkProtocolList.c b/EmulatorPkg/Library/ThunkProtocolList/ThunkProtocolList.c
index b2daa2bef5..9fa9e25e94 100644
--- a/EmulatorPkg/Library/ThunkProtocolList/ThunkProtocolList.c
+++ b/EmulatorPkg/Library/ThunkProtocolList/ThunkProtocolList.c
@@ -2,7 +2,7 @@
   Emulator Thunk to abstract OS services from pure EFI code
 
   Copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
-  Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD License
@@ -82,7 +82,7 @@ AddThunkProtocol (
     Private->EmuBusDriver       = EmuBusDriver;
 
     CopyMem (&Private->Data, ThunkIo, sizeof (EMU_IO_THUNK_PROTOCOL));
-    Private->Data.Instance      = Instance++;
+    Private->Data.Instance      = (UINT16)Instance++;
     Private->Data.ConfigString  = StartString;
 
     InsertTailList (&mThunkList, &Private->Link);
-- 
2.16.1.windows.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 02/12] EmulatorPkg/Win: Add Windows host support
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 01/12] EmulatorPkg/ThunkProtocolList: Fix VS build failure Ruiyu Ni
@ 2018-08-23  9:52 ` Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 03/12] EmulatorPkg/Win: Enable source level debugging Ruiyu Ni
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Andrew Fish

This is the initial patch to make it boot to early DXE
phase without display (only debug message).

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Hao Wu <hao.a.wu@intel.com>
Cc: Andrew Fish <afish@apple.com>
---
 EmulatorPkg/EmulatorPkg.dsc                   |   7 +
 EmulatorPkg/Win/Host/WinHost.c                | 940 ++++++++++++++++++++++++++
 EmulatorPkg/Win/Host/WinHost.h                | 200 ++++++
 EmulatorPkg/Win/Host/WinHost.inf              |  88 +++
 EmulatorPkg/Win/Host/WinInclude.h             |  75 ++
 EmulatorPkg/Win/Host/WinMemoryAllocationLib.c | 178 +++++
 EmulatorPkg/Win/Host/WinThunk.c               | 228 +++++++
 7 files changed, 1716 insertions(+)
 create mode 100644 EmulatorPkg/Win/Host/WinHost.c
 create mode 100644 EmulatorPkg/Win/Host/WinHost.h
 create mode 100644 EmulatorPkg/Win/Host/WinHost.inf
 create mode 100644 EmulatorPkg/Win/Host/WinInclude.h
 create mode 100644 EmulatorPkg/Win/Host/WinMemoryAllocationLib.c
 create mode 100644 EmulatorPkg/Win/Host/WinThunk.c

diff --git a/EmulatorPkg/EmulatorPkg.dsc b/EmulatorPkg/EmulatorPkg.dsc
index ef56a86a32..8afeaf5fa3 100644
--- a/EmulatorPkg/EmulatorPkg.dsc
+++ b/EmulatorPkg/EmulatorPkg.dsc
@@ -251,6 +251,13 @@ [Components]
   EmulatorPkg/Unix/Host/Host.inf
 !endif
 
+!ifdef $(WIN_SEC_BUILD)
+  ##
+  #  Emulator, OS WIN application
+  ##
+  EmulatorPkg/Win/Host/WinHost.inf
+!endif
+
 !ifndef $(SKIP_MAIN_BUILD)
   #
   # Generic SEC
diff --git a/EmulatorPkg/Win/Host/WinHost.c b/EmulatorPkg/Win/Host/WinHost.c
new file mode 100644
index 0000000000..22399f18b9
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinHost.c
@@ -0,0 +1,940 @@
+/**@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 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include "WinHost.h"
+
+#ifndef SE_TIME_ZONE_NAME
+#define SE_TIME_ZONE_NAME                 TEXT("SeTimeZonePrivilege")
+#endif
+
+//
+// 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 seperate memory rantes.
+//  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 it's 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 occured 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  INTN  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;
+  UINT32                ProcessAffinityMask;
+  UINT32                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 ("\nEDK II WIN Host Emulation Environment from http://www.tianocore.org/edk2/\n");
+
+  //
+  // Determine the first thread available to this process.
+  //
+  if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask)) {
+    LowBit = (INT32)LowBitSet32 (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);
+
+  //
+  // 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", 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", FirmwareVolumesStr);
+    exit (1);
+  }
+  //
+  // Setup Boot Mode.
+  //
+  SecPrint ("  BootMode 0x%02x\n", 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");
+    exit (1);
+  }
+  SetMemN (TemporaryRam, TemporaryRamSize, PcdGet32 (PcdInitValueInTempStack));
+
+  SecPrint ("  OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n",
+    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", 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");
+    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", FileName, Status);
+      exit (1);
+    }
+
+    SecPrint ("  FD loaded from %S\n", 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");
+  }
+  //
+  // 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");
+
+  //
+  // 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");
+  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 transfered 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)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;
+}
+
+
+VOID
+EFIAPI
+PeCoffLoaderRelocateImageExtraAction (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
+  )
+{
+  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 usw 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 bellow.
+  //
+
+  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)) {
+      ImageContext->EntryPoint  = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;
+      SecPrint ("LoadLibraryEx (%S,\n               NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName);
+    } else {
+      SecPrint ("WARNING: No source level debug %S. \n", DllFileName);
+    }
+
+    free (DllFileName);
+  }
+}
+
+VOID
+EFIAPI
+PeCoffLoaderUnloadImageExtraAction (
+  IN PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
+)
+{
+  ASSERT (ImageContext != NULL);
+}
+
+
+VOID
+_ModuleEntryPoint (
+  VOID
+  )
+{
+}
diff --git a/EmulatorPkg/Win/Host/WinHost.h b/EmulatorPkg/Win/Host/WinHost.h
new file mode 100644
index 0000000000..c73ba17e74
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinHost.h
@@ -0,0 +1,200 @@
+/**@file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+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 <Ppi/EmuThunk.h>
+#include <Protocol/EmuThunk.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>
+
+
+#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 transfered 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;
+#endif
\ No newline at end of file
diff --git a/EmulatorPkg/Win/Host/WinHost.inf b/EmulatorPkg/Win/Host/WinHost.inf
new file mode 100644
index 0000000000..544e775c49
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinHost.inf
@@ -0,0 +1,88 @@
+## @file
+# Entry Point of Win Emulator
+#
+# Main executable file of Win Emulator that loads Sec core after initialization finished.
+# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+# Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution. The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[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
+  WinThunk.c
+  WinHost.h
+  WinHost.c
+  WinInclude.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  EmulatorPkg/EmulatorPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  PcdLib
+  PrintLib
+  BaseMemoryLib
+  BaseLib
+  PeCoffLib
+  ThunkPpiList
+  ThunkProtocolList
+  PpiListLib
+  PeiServicesLib
+
+[Ppis]
+  gEmuThunkPpiGuid
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
+
+  gEmulatorPkgTokenSpaceGuid.PcdEmuBootMode
+  gEmulatorPkgTokenSpaceGuid.PcdEmuFirmwareVolume
+  gEmulatorPkgTokenSpaceGuid.PcdEmuMemorySize
+  gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress
+  gEmulatorPkgTokenSpaceGuid.PcdPeiServicesTablePage
+
+[BuildOptions]
+       *_*_*_DLINK_FLAGS            == /out:"$(BIN_DIR)\$(BASE_NAME).exe" /base:0x10000000 /pdb:"$(BIN_DIR)\$(BASE_NAME).pdb"
+      :*_*_*_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
+       *_*_*_PP_FLAGS               == /nologo /E /TC /FIAutoGen.h
+
+  MSFT:*_*_IA32_DLINK_FLAGS          = /LIBPATH:"$(VCINSTALLDIR)\Lib" /LIBPATH:"$(VCINSTALLDIR)\PlatformSdk\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
+  MSFT:*_VS2015_IA32_DLINK_FLAGS     = /LIBPATH:"$(VCINSTALLDIR)\Lib" /LIBPATH:"$(VCINSTALLDIR)\PlatformSdk\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:"$(VCINSTALLDIR)\Lib" /LIBPATH:"$(VCINSTALLDIR)\PlatformSdk\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:*_*_IA32_ASM_FLAGS           == /nologo /W3 /WX /c /coff /Cx /Zd /W0 /Zi
+  MSFT:*_*_IA32_ASMLINK_FLAGS       == /link /nologo /tiny
+
+  MSFT:*_*_X64_DLINK_FLAGS           = /LIBPATH:"$(VCINSTALLDIR)\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 Gdi32.lib User32.lib Winmm.lib Advapi32.lib
+  MSFT:*_VS2015_X64_DLINK_FLAGS      = /LIBPATH:"$(VCINSTALLDIR)\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:"$(VCINSTALLDIR)\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:*_*_X64_ASM_FLAGS            == /nologo /W3 /WX /c /Cx /Zd /W0 /Zi
+  MSFT:*_*_X64_ASMLINK_FLAGS        == /link /nologo
+
+  INTEL:*_*_IA32_DLINK_FLAGS         = /LIBPATH:"C:\Program Files\Intel\Compiler\C++\9.1\IA32\Lib" /LIBPATH:"$(VCINSTALLDIR)\Lib" /LIBPATH:"$(VCINSTALLDIR)\PlatformSdk\Lib" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:I386 /LTCG Kernel32.lib MSVCRTD.lib Gdi32.lib User32.lib Winmm.lib
+  INTEL:*_*_IA32_ASM_FLAGS          == /nologo /W3 /WX /c /coff /Cx /Zd /W0 /Zi
+  INTEL:*_*_IA32_ASMLINK_FLAGS      == /link /nologo /tiny
diff --git a/EmulatorPkg/Win/Host/WinInclude.h b/EmulatorPkg/Win/Host/WinInclude.h
new file mode 100644
index 0000000000..ae90b1ed30
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinInclude.h
@@ -0,0 +1,75 @@
+/**@file
+  Public include file for the WinNt Library
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#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"
+
+#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/EmulatorPkg/Win/Host/WinMemoryAllocationLib.c b/EmulatorPkg/Win/Host/WinMemoryAllocationLib.c
new file mode 100644
index 0000000000..0c7e7ff508
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinMemoryAllocationLib.c
@@ -0,0 +1,178 @@
+/*++ @file
+
+  Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <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/EmulatorPkg/Win/Host/WinThunk.c b/EmulatorPkg/Win/Host/WinThunk.c
new file mode 100644
index 0000000000..5ec5d439d4
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinThunk.c
@@ -0,0 +1,228 @@
+/**@file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+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
+  )
+{
+  return 0;
+}
+
+
+EFI_STATUS
+SecConfigStdIn (
+  VOID
+  )
+{
+  return EFI_SUCCESS;
+}
+
+UINTN
+SecWriteStdOut (
+  IN UINT8     *Buffer,
+  IN UINTN     NumberOfBytes
+  )
+{
+  return 0;
+}
+
+BOOLEAN
+SecPollStdIn (
+  VOID
+  )
+{
+  return FALSE;
+}
+
+UINTN
+SecReadStdIn (
+  IN UINT8     *Buffer,
+  IN UINTN     NumberOfBytes
+  )
+{
+  return 0;
+}
+
+
+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;
+}
+
+VOID
+SecSetTimer (
+  IN  UINT64                  TimerPeriod,
+  IN  EMU_SET_TIMER_CALLBACK  Callback
+)
+{
+}
+
+VOID
+SecInitializeThunk (
+  VOID
+)
+{
+}
+
+VOID
+SecEnableInterrupt (
+  VOID
+  )
+{
+}
+
+
+VOID
+SecDisableInterrupt (
+  VOID
+  )
+{
+}
+
+
+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
+  )
+{
+}
+
+EFI_STATUS
+SecSetTime (
+  IN  EFI_TIME               *Time
+)
+{
+  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)
+
-- 
2.16.1.windows.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 03/12] EmulatorPkg/Win: Enable source level debugging
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 01/12] EmulatorPkg/ThunkProtocolList: Fix VS build failure Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 02/12] EmulatorPkg/Win: Add Windows host support Ruiyu Ni
@ 2018-08-23  9:52 ` Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 04/12] EmulatorPkg/Win: Enable native OS console as firmware console Ruiyu Ni
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel; +Cc: Andrew Fish, Hao A Wu

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Andrew Fish <afish@apple.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
---
 EmulatorPkg/EmulatorPkg.dsc | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/EmulatorPkg/EmulatorPkg.dsc b/EmulatorPkg/EmulatorPkg.dsc
index 8afeaf5fa3..67812f754b 100644
--- a/EmulatorPkg/EmulatorPkg.dsc
+++ b/EmulatorPkg/EmulatorPkg.dsc
@@ -420,3 +420,11 @@ [Components]
 
 !endif
 
+[BuildOptions]
+  MSFT:DEBUG_*_*_CC_FLAGS = /Od /Oy-
+  MSFT:NOOPT_*_*_CC_FLAGS = /Od /Oy-
+
+  MSFT:*_*_*_DLINK_FLAGS     = /ALIGN:4096 /FILEALIGN:4096 /SUBSYSTEM:CONSOLE
+  MSFT:DEBUG_*_*_DLINK_FLAGS = /EXPORT:InitializeDriver=$(IMAGE_ENTRY_POINT) /BASE:0x10000
+  MSFT:NOOPT_*_*_DLINK_FLAGS = /EXPORT:InitializeDriver=$(IMAGE_ENTRY_POINT) /BASE:0x10000
+
-- 
2.16.1.windows.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 04/12] EmulatorPkg/Win: Enable native OS console as firmware console
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
                   ` (2 preceding siblings ...)
  2018-08-23  9:52 ` [PATCH 03/12] EmulatorPkg/Win: Enable source level debugging Ruiyu Ni
@ 2018-08-23  9:52 ` Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 05/12] EmulatorPkg/Win: Add input/output support Ruiyu Ni
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao A Wu, Andrew Fish

The patch implements Stdin/Stdout/Stderr access so that
the native OS console (cmd.exe) can be used as the firmware
console and debug message can also be routed to it.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Andrew Fish <afish@apple.com>
---
 EmulatorPkg/Win/Host/WinThunk.c | 109 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 105 insertions(+), 4 deletions(-)

diff --git a/EmulatorPkg/Win/Host/WinThunk.c b/EmulatorPkg/Win/Host/WinThunk.c
index 5ec5d439d4..69a61258f3 100644
--- a/EmulatorPkg/Win/Host/WinThunk.c
+++ b/EmulatorPkg/Win/Host/WinThunk.c
@@ -42,7 +42,19 @@ SecWriteStdErr (
   IN UINTN     NumberOfBytes
   )
 {
-  return 0;
+  BOOL  Success;
+  DWORD CharCount;
+
+  CharCount = (DWORD)NumberOfBytes;
+  Success = WriteFile (
+    GetStdHandle (STD_ERROR_HANDLE),
+    Buffer,
+    CharCount,
+    &CharCount,
+    NULL
+    );
+
+  return Success ? CharCount : 0;
 }
 
 
@@ -51,7 +63,32 @@ SecConfigStdIn (
   VOID
   )
 {
-  return EFI_SUCCESS;
+  BOOL     Success;
+  DWORD    Mode;
+
+  Success = GetConsoleMode (GetStdHandle (STD_INPUT_HANDLE), &Mode);
+  if (Success) {
+    //
+    // Disable buffer (line input), echo, mouse, window
+    //
+    Success = SetConsoleMode (
+                GetStdHandle (STD_INPUT_HANDLE),
+                Mode | ENABLE_VIRTUAL_TERMINAL_INPUT & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT)
+                );
+  }
+  if (Success) {
+    //
+    // Enable terminal mode
+    //
+    Success = GetConsoleMode (GetStdHandle (STD_OUTPUT_HANDLE), &Mode);
+    if (Success) {
+      Success = SetConsoleMode (
+        GetStdHandle (STD_OUTPUT_HANDLE),
+        Mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN
+      );
+    }
+  }
+  return Success ? EFI_SUCCESS : EFI_DEVICE_ERROR;
 }
 
 UINTN
@@ -60,7 +97,19 @@ SecWriteStdOut (
   IN UINTN     NumberOfBytes
   )
 {
-  return 0;
+  BOOL  Success;
+  DWORD CharCount;
+
+  CharCount = (DWORD)NumberOfBytes;
+  Success = WriteFile (
+    GetStdHandle (STD_OUTPUT_HANDLE),
+    Buffer,
+    CharCount,
+    &CharCount,
+    NULL
+    );
+
+  return Success ? CharCount : 0;
 }
 
 BOOLEAN
@@ -68,6 +117,38 @@ 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;
 }
 
@@ -77,7 +158,27 @@ SecReadStdIn (
   IN UINTN     NumberOfBytes
   )
 {
-  return 0;
+  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;
 }
 
 
-- 
2.16.1.windows.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 05/12] EmulatorPkg/Win: Add input/output support
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
                   ` (3 preceding siblings ...)
  2018-08-23  9:52 ` [PATCH 04/12] EmulatorPkg/Win: Enable native OS console as firmware console Ruiyu Ni
@ 2018-08-23  9:52 ` Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 06/12] EmulatorPkg/Win: Add timer and interrupt support Ruiyu Ni
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel; +Cc: Andrew Fish, Hao A Wu

The patch adds GOP and SimpleTextIn[Ex] support.
Now firmware can boot to UI and Shell but timer doesn't work.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Andrew Fish <afish@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
---
 EmulatorPkg/Win/Host/WinGop.h       | 204 +++++++++
 EmulatorPkg/Win/Host/WinGopInput.c  | 417 +++++++++++++++++
 EmulatorPkg/Win/Host/WinGopScreen.c | 872 ++++++++++++++++++++++++++++++++++++
 EmulatorPkg/Win/Host/WinHost.c      |   5 +
 EmulatorPkg/Win/Host/WinHost.h      |   1 +
 EmulatorPkg/Win/Host/WinHost.inf    |   7 +
 6 files changed, 1506 insertions(+)
 create mode 100644 EmulatorPkg/Win/Host/WinGop.h
 create mode 100644 EmulatorPkg/Win/Host/WinGopInput.c
 create mode 100644 EmulatorPkg/Win/Host/WinGopScreen.c

diff --git a/EmulatorPkg/Win/Host/WinGop.h b/EmulatorPkg/Win/Host/WinGop.h
new file mode 100644
index 0000000000..32ae6b03af
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinGop.h
@@ -0,0 +1,204 @@
+/** @file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+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/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/GraphicsOutput.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 scree when windows events happen. It's
+  // updated in the main thread and displayed in the windows thread.
+  //
+  BITMAPV4HEADER                *VirtualScreenInfo;
+  RGBQUAD                       *VirtualScreen;
+
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FillLine;
+
+  //
+  // 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;
+} 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
\ No newline at end of file
diff --git a/EmulatorPkg/Win/Host/WinGopInput.c b/EmulatorPkg/Win/Host/WinGopInput.c
new file mode 100644
index 0000000000..7223f6a185
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinGopInput.c
@@ -0,0 +1,417 @@
+/** @file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+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 existance 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 availiable.
+    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->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);
+
+  return EFI_NOT_READY;
+}
+
+
+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);
+
+  return EFI_NOT_READY;
+}
\ No newline at end of file
diff --git a/EmulatorPkg/Win/Host/WinGopScreen.c b/EmulatorPkg/Win/Host/WinGopScreen.c
new file mode 100644
index 0000000000..2ca51d23d0
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinGopScreen.c
@@ -0,0 +1,872 @@
+/** @file
+
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+    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
+)
+{
+  UINT32                            Size;
+  GRAPHICS_PRIVATE_DATA             *Private;
+  RECT                              Rect;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *NewFillLine;
+
+  Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+  Private->Width  = Width;
+  Private->Height = Height;
+
+
+  //
+  // 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);
+  }
+
+  //
+  // Allocate DIB frame buffer directly from NT for performance enhancement
+  // This buffer is the virtual screen/frame buffer. This buffer is not the
+  // same a a frame buffer. The first row of this buffer will be the bottom
+  // line of the image. This is an artifact of the way we draw to the screen.
+  //
+  Size = Private->Width * Private->Height * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER);
+  Private->VirtualScreenInfo = HeapAlloc (
+    GetProcessHeap (),
+    HEAP_ZERO_MEMORY,
+    Size
+  );
+
+  //
+  // Update the virtual screen info data structure
+  //
+  Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);
+  Private->VirtualScreenInfo->bV4Width = Private->Width;
+  Private->VirtualScreenInfo->bV4Height = Private->Height;
+  Private->VirtualScreenInfo->bV4Planes = 1;
+  Private->VirtualScreenInfo->bV4BitCount = 32;
+  //
+  // uncompressed
+  //
+  Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;
+
+  //
+  // The rest of the allocated memory block is the virtual screen buffer
+  //
+  Private->VirtualScreen = (RGBQUAD *)(Private->VirtualScreenInfo + 1);
+
+  //
+  // 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 = Private->Width;
+  Rect.bottom = Private->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);
+
+  NewFillLine = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Private->Width);
+  if (NewFillLine == NULL) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (Private->FillLine != NULL) {
+    FreePool (Private->FillLine);
+  }
+
+  Private->FillLine = NewFillLine;
+  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                 Hight 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 occured writting 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
+)
+{
+  GRAPHICS_PRIVATE_DATA         *Private;
+  UINTN                         DstY;
+  UINTN                         SrcY;
+  RGBQUAD                       *VScreen;
+  RGBQUAD                       *VScreenSrc;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+  UINTN                         Index;
+  RECT                          Rect;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FillPixel;
+  UINT32                        VerticalResolution;
+  UINT32                        HorizontalResolution;
+
+  Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+  //
+  // We need to fill the Virtual Screen buffer with the blt data.
+  // The virtual screen is upside down, as the first row is the bootom row of
+  // the image.
+  //
+  VerticalResolution = Private->VirtualScreenInfo->bV4Height;
+  HorizontalResolution = Private->VirtualScreenInfo->bV4Width;
+  if (BltOperation == EfiBltVideoToBltBuffer) {
+
+    for (SrcY = Args->SourceY, DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); SrcY++, DstY++) {
+      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Args->Delta) + Args->DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+      VScreen = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + Args->SourceX];
+      CopyMem (Blt, VScreen, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Args->Width);
+    }
+  } else {
+    if (BltOperation == EfiBltVideoFill) {
+      FillPixel = BltBuffer;
+      for (Index = 0; Index < Args->Width; Index++) {
+        Private->FillLine[Index] = *FillPixel;
+      }
+    }
+
+    for (Index = 0; Index < Args->Height; Index++) {
+      if (Args->DestinationY <= Args->SourceY) {
+        SrcY  = Args->SourceY + Index;
+        DstY  = Args->DestinationY + Index;
+      } else {
+        SrcY  = Args->SourceY + Args->Height - Index - 1;
+        DstY  = Args->DestinationY + Args->Height - Index - 1;
+      }
+
+      VScreen = &Private->VirtualScreen[(VerticalResolution - DstY - 1) * HorizontalResolution + Args->DestinationX];
+      switch (BltOperation) {
+      case EfiBltBufferToVideo:
+        Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Args->Delta) + Args->SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+        CopyMem (VScreen, Blt, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+        break;
+
+      case EfiBltVideoToVideo:
+        VScreenSrc = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + Args->SourceX];
+        CopyMem (VScreen, VScreenSrc, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+        break;
+
+      case EfiBltVideoFill:
+        CopyMem (VScreen, Private->FillLine, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+        break;
+      }
+    }
+  }
+
+  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;
+  UINTN                 Size;
+  HDC                   Handle;
+  PAINTSTRUCT           PaintStruct;
+  LPARAM                Index;
+  EFI_INPUT_KEY         Key;
+  BOOLEAN               AltIsPress;
+
+  //
+  // BugBug - if there are two instances of this DLL in memory (such as is
+  // the case for ERM), the correct instance of this function may not be called.
+  // This also means that the address of the mTlsIndex value will be wrong, and
+  // the value may be wrong too.
+  //
+
+
+  //
+  // 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_CREATE:
+    Size = Private->Width * Private->Height * sizeof (RGBQUAD);
+
+    //
+    // Allocate DIB frame buffer directly from NT for performance enhancement
+    // This buffer is the virtual screen/frame buffer. This buffer is not the
+    // same a a frame buffer. The first fow of this buffer will be the bottom
+    // line of the image. This is an artifact of the way we draw to the screen.
+    //
+    Private->VirtualScreenInfo = HeapAlloc (
+                                   GetProcessHeap (),
+                                   HEAP_ZERO_MEMORY,
+                                   Size
+                                   );
+
+    Private->VirtualScreenInfo->bV4Size           = sizeof (BITMAPV4HEADER);
+    Private->VirtualScreenInfo->bV4Width          = Private->Width;
+    Private->VirtualScreenInfo->bV4Height         = Private->Height;
+    Private->VirtualScreenInfo->bV4Planes         = 1;
+    Private->VirtualScreenInfo->bV4BitCount       = 32;
+    //
+    // uncompressed
+    //
+    Private->VirtualScreenInfo->bV4V4Compression  = BI_RGB;
+    Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1);
+    return 0;
+
+  case WM_PAINT:
+    //
+    // I have not found a way to convert hwnd into a Private context. So for
+    // now we use this API to convert hwnd to Private data.
+    //
+
+    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->VirtualScreen,                     // 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_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 () aplication. Each Winow nededs
+  to process it's events. The messages are dispatched to
+  WinNtGopThreadWindowProc ().
+  Be very careful sine WinNtGopThreadWinMain () and WinNtGopThreadWindowProc ()
+  are running in a seperate 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.
+  //
+  // Note: Multiple instances of this DLL will use the same instance of this
+  // Class, including the callback function, unless the Class is unregistered and
+  // successfully registered again.
+  //
+  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 winows program. We need a sperate
+  // 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/EmulatorPkg/Win/Host/WinHost.c b/EmulatorPkg/Win/Host/WinHost.c
index 22399f18b9..f8d21d26d9 100644
--- a/EmulatorPkg/Win/Host/WinHost.c
+++ b/EmulatorPkg/Win/Host/WinHost.c
@@ -424,6 +424,11 @@ Returns:
   //
   AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);
 
+  //
+  // Emulator Bus Driver Thunks
+  //
+  AddThunkProtocol (&mWinNtWndThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
+
   //
   // Allocate space for gSystemMemory Array
   //
diff --git a/EmulatorPkg/Win/Host/WinHost.h b/EmulatorPkg/Win/Host/WinHost.h
index c73ba17e74..3dc6a7e641 100644
--- a/EmulatorPkg/Win/Host/WinHost.h
+++ b/EmulatorPkg/Win/Host/WinHost.h
@@ -197,4 +197,5 @@ SecInitializeThunk (
   VOID
 );
 extern EMU_THUNK_PROTOCOL    gEmuThunkProtocol;
+extern EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo;
 #endif
\ No newline at end of file
diff --git a/EmulatorPkg/Win/Host/WinHost.inf b/EmulatorPkg/Win/Host/WinHost.inf
index 544e775c49..b62791bcfa 100644
--- a/EmulatorPkg/Win/Host/WinHost.inf
+++ b/EmulatorPkg/Win/Host/WinHost.inf
@@ -30,6 +30,9 @@ [Defines]
 
 [Sources]
   WinMemoryAllocationLib.c
+  WinGopInput.c
+  WinGopScreen.c
+  WinGop.h
   WinThunk.c
   WinHost.h
   WinHost.c
@@ -55,6 +58,9 @@ [LibraryClasses]
 [Ppis]
   gEmuThunkPpiGuid
 
+[Protocols]
+  gEmuIoThunkProtocolGuid
+  gEmuGraphicsWindowProtocolGuid
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
 
@@ -62,6 +68,7 @@ [Pcd]
   gEmulatorPkgTokenSpaceGuid.PcdEmuFirmwareVolume
   gEmulatorPkgTokenSpaceGuid.PcdEmuMemorySize
   gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress
+  gEmulatorPkgTokenSpaceGuid.PcdEmuGop|L"GOP Window"
   gEmulatorPkgTokenSpaceGuid.PcdPeiServicesTablePage
 
 [BuildOptions]
-- 
2.16.1.windows.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 06/12] EmulatorPkg/Win: Add timer and interrupt support
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
                   ` (4 preceding siblings ...)
  2018-08-23  9:52 ` [PATCH 05/12] EmulatorPkg/Win: Add input/output support Ruiyu Ni
@ 2018-08-23  9:52 ` Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 07/12] EmulatorPkg/Win: Add RTC support Ruiyu Ni
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Andrew Fish

Now the firmware can boot to Shell and count down 5 seconds to
command prompt.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Hao Wu <hao.a.wu@intel.com>
Cc: Andrew Fish <afish@intel.com>
---
 EmulatorPkg/Win/Host/WinThunk.c | 194 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 194 insertions(+)

diff --git a/EmulatorPkg/Win/Host/WinThunk.c b/EmulatorPkg/Win/Host/WinThunk.c
index 69a61258f3..ffe71aef9a 100644
--- a/EmulatorPkg/Win/Host/WinThunk.c
+++ b/EmulatorPkg/Win/Host/WinThunk.c
@@ -205,12 +205,193 @@ SecFree (
   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
@@ -218,6 +399,17 @@ SecInitializeThunk (
   VOID
 )
 {
+  InitializeCriticalSection (&mNtCriticalSection);
+
+  DuplicateHandle (
+    GetCurrentProcess (),
+    GetCurrentThread (),
+    GetCurrentProcess (),
+    &mNtMainThreadHandle,
+    0,
+    FALSE,
+    DUPLICATE_SAME_ACCESS
+  );
 }
 
 VOID
@@ -225,6 +417,7 @@ SecEnableInterrupt (
   VOID
   )
 {
+  mInterruptEnabled = TRUE;
 }
 
 
@@ -233,6 +426,7 @@ SecDisableInterrupt (
   VOID
   )
 {
+  mInterruptEnabled = FALSE;
 }
 
 
-- 
2.16.1.windows.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 07/12] EmulatorPkg/Win: Add RTC support
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
                   ` (5 preceding siblings ...)
  2018-08-23  9:52 ` [PATCH 06/12] EmulatorPkg/Win: Add timer and interrupt support Ruiyu Ni
@ 2018-08-23  9:52 ` Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 08/12] EmulatorPkg/Win: Add SimpleFileSystem support Ruiyu Ni
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Andrew Fish

Now firmware can display the time correctly.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Hao Wu <hao.a.wu@intel.com>
Cc: Andrew Fish <afish@intel.com>
---
 EmulatorPkg/Win/Host/WinThunk.c | 58 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 56 insertions(+), 2 deletions(-)

diff --git a/EmulatorPkg/Win/Host/WinThunk.c b/EmulatorPkg/Win/Host/WinThunk.c
index ffe71aef9a..306fe75ecd 100644
--- a/EmulatorPkg/Win/Host/WinThunk.c
+++ b/EmulatorPkg/Win/Host/WinThunk.c
@@ -482,14 +482,68 @@ SecGetTime (
   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
-)
+  )
 {
-  return EFI_SUCCESS;
+  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 = {
-- 
2.16.1.windows.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 08/12] EmulatorPkg/Win: Add SimpleFileSystem support
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
                   ` (6 preceding siblings ...)
  2018-08-23  9:52 ` [PATCH 07/12] EmulatorPkg/Win: Add RTC support Ruiyu Ni
@ 2018-08-23  9:52 ` Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 09/12] EmulatorPkg/Win: Add BlockIo support Ruiyu Ni
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Andrew Fish

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Hao Wu <hao.a.wu@intel.com>
Cc: Andrew Fish <afish@intel.com>
---
 EmulatorPkg/Win/Host/WinFileSystem.c | 2409 ++++++++++++++++++++++++++++++++++
 EmulatorPkg/Win/Host/WinHost.c       |    1 +
 EmulatorPkg/Win/Host/WinHost.h       |    5 +
 EmulatorPkg/Win/Host/WinHost.inf     |    9 +
 4 files changed, 2424 insertions(+)
 create mode 100644 EmulatorPkg/Win/Host/WinFileSystem.c

diff --git a/EmulatorPkg/Win/Host/WinFileSystem.c b/EmulatorPkg/Win/Host/WinFileSystem.c
new file mode 100644
index 0000000000..0d43ddaae3
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinFileSystem.c
@@ -0,0 +1,2409 @@
+/*++ @file
+  Support OS native directory access.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+#include "WinHost.h"
+
+
+#define WIN_NT_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;
+  }
+
+  StrCpy (PrivateFile->FilePath, Private->FilePath);
+  StrCpy (PrivateFile->FileName, 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;
+  }
+  StrCpy (TempFileName, PrivateFile->FilePath);
+  StrCat (TempFileName, 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));
+    StrnCpy (Token, *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 FielName contains more than two dots seperated 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;
+  }
+  StrCpy (TempFileName, 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) {
+    StrCpy (NewPrivateFile->FilePath, PrivateFile->FileName);
+  } else {
+    StrCpy (NewPrivateFile->FilePath, 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'\\') {
+    StrCpy (NewPrivateFile->FileName, PrivateRoot->FilePath);
+    StrCat (NewPrivateFile->FileName, L"\\");
+    StrCat (NewPrivateFile->FileName, FileName + 1);
+  } else {
+    StrCpy (NewPrivateFile->FileName, NewPrivateFile->FilePath);
+    if (StrCmp (FileName, L"") != 0) {
+      //
+      // In case the filename becomes empty, especially after trimming dots and blanks
+      //
+      StrCat (NewPrivateFile->FileName, L"\\");
+      StrCat (NewPrivateFile->FileName, 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;
+  }
+
+  StrCpy (NewPrivateFile->FilePath, 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;
+    }
+
+    StrCpy (TempFileName, 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
+    //
+    StrCat (TempFileName, 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;
+    }
+
+    StrCpy (FileName, PrivateFile->FileName);
+    StrCat (FileName, 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;
+    }
+
+    StrCpy (DriveName, 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;
+      }
+    }
+
+    StrCpy ((CHAR16 *)FileSystemInfoBuffer->VolumeLabel, 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;
+    }
+
+    StrCpy ((CHAR16 *)Buffer, 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;
+    }
+
+    StrCpy (PrivateRoot->VolumeLabel, 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;
+    }
+
+    StrCpy (PrivateRoot->VolumeLabel, (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;
+  }
+
+  StrCpy (OldFileName, 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;
+    }
+
+    StrCpy (NewFileName, PrivateRoot->FilePath);
+    StrCat (NewFileName, L"\\");
+    StrCat (NewFileName, 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;
+    }
+
+    StrCpy (NewFileName, PrivateFile->FilePath);
+    StrCat (NewFileName, L"\\");
+    StrCat (NewFileName, 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;
+      }
+
+      StrCpy (PrivateFile->FileName, NewFileName);
+
+      Size = StrSize (NewFileName);
+      Size += StrSize (L"\\*");
+      TempFileName = AllocatePool (Size);
+
+      StrCpy (TempFileName, 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
+        );
+
+        StrCat (TempFileName, 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);
+
+      StrCpy (TempFileName, 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
+        );
+
+        StrCat (TempFileName, 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/EmulatorPkg/Win/Host/WinHost.c b/EmulatorPkg/Win/Host/WinHost.c
index f8d21d26d9..266ae59382 100644
--- a/EmulatorPkg/Win/Host/WinHost.c
+++ b/EmulatorPkg/Win/Host/WinHost.c
@@ -428,6 +428,7 @@ Returns:
   // Emulator Bus Driver Thunks
   //
   AddThunkProtocol (&mWinNtWndThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
+  AddThunkProtocol (&mWinNtFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);
 
   //
   // Allocate space for gSystemMemory Array
diff --git a/EmulatorPkg/Win/Host/WinHost.h b/EmulatorPkg/Win/Host/WinHost.h
index 3dc6a7e641..3c7529fa91 100644
--- a/EmulatorPkg/Win/Host/WinHost.h
+++ b/EmulatorPkg/Win/Host/WinHost.h
@@ -26,8 +26,12 @@ Abstract:
 
 #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 <Library/BaseLib.h>
@@ -198,4 +202,5 @@ SecInitializeThunk (
 );
 extern EMU_THUNK_PROTOCOL    gEmuThunkProtocol;
 extern EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo;
+extern EMU_IO_THUNK_PROTOCOL mWinNtFileSystemThunkIo;
 #endif
\ No newline at end of file
diff --git a/EmulatorPkg/Win/Host/WinHost.inf b/EmulatorPkg/Win/Host/WinHost.inf
index b62791bcfa..358d000857 100644
--- a/EmulatorPkg/Win/Host/WinHost.inf
+++ b/EmulatorPkg/Win/Host/WinHost.inf
@@ -33,6 +33,7 @@ [Sources]
   WinGopInput.c
   WinGopScreen.c
   WinGop.h
+  WinFileSystem.c
   WinThunk.c
   WinHost.h
   WinHost.c
@@ -61,6 +62,13 @@ [Ppis]
 [Protocols]
   gEmuIoThunkProtocolGuid
   gEmuGraphicsWindowProtocolGuid
+  gEfiSimpleFileSystemProtocolGuid
+
+[Guids]
+  gEfiFileSystemVolumeLabelInfoIdGuid           # SOMETIMES_CONSUMED
+  gEfiFileInfoGuid                              # SOMETIMES_CONSUMED
+  gEfiFileSystemInfoGuid                        # SOMETIMES_CONSUMED
+
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
 
@@ -69,6 +77,7 @@ [Pcd]
   gEmulatorPkgTokenSpaceGuid.PcdEmuMemorySize
   gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress
   gEmulatorPkgTokenSpaceGuid.PcdEmuGop|L"GOP Window"
+  gEmulatorPkgTokenSpaceGuid.PcdEmuFileSystem
   gEmulatorPkgTokenSpaceGuid.PcdPeiServicesTablePage
 
 [BuildOptions]
-- 
2.16.1.windows.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 09/12] EmulatorPkg/Win: Add BlockIo support
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
                   ` (7 preceding siblings ...)
  2018-08-23  9:52 ` [PATCH 08/12] EmulatorPkg/Win: Add SimpleFileSystem support Ruiyu Ni
@ 2018-08-23  9:52 ` Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 10/12] EmulatorPkg/PlatformBds: Signal EndOfDxe in platform BDS Ruiyu Ni
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Andrew Fish

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Hao Wu <hao.a.wu@intel.com>
Cc: Andrew Fish <afish@intel.com>
---
 EmulatorPkg/Win/Host/WinBlockIo.c | 563 ++++++++++++++++++++++++++++++++++++++
 EmulatorPkg/Win/Host/WinHost.c    |   1 +
 EmulatorPkg/Win/Host/WinHost.h    |   3 +
 EmulatorPkg/Win/Host/WinHost.inf  |   3 +
 4 files changed, 570 insertions(+)
 create mode 100644 EmulatorPkg/Win/Host/WinBlockIo.c

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



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 10/12] EmulatorPkg/PlatformBds: Signal EndOfDxe in platform BDS
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
                   ` (8 preceding siblings ...)
  2018-08-23  9:52 ` [PATCH 09/12] EmulatorPkg/Win: Add BlockIo support Ruiyu Ni
@ 2018-08-23  9:52 ` Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 11/12] EmulatorPkg/EmuFileSystem: Fix a bug that causes Close() assertion Ruiyu Ni
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Andrew Fish

Without signal of EndOfDxe, the 3rd party code (.efi from non-flash
storage) cannot run. It's forbidden by
8be37a5cee700777ca8e8e8a34cc2225b21931a7
*MdeModulePkg/SecurityStubDxe: Defer 3rd party image before EndOfDxe

The patch enables running of SCT from internal shell.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Hao Wu <hao.a.wu@intel.com>
Cc: Andrew Fish <afish@intel.com>
---
 EmulatorPkg/Library/EmuBdsLib/BdsPlatform.c | 4 +++-
 EmulatorPkg/Library/EmuBdsLib/BdsPlatform.h | 4 +++-
 EmulatorPkg/Library/EmuBdsLib/EmuBdsLib.inf | 5 +++--
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/EmulatorPkg/Library/EmuBdsLib/BdsPlatform.c b/EmulatorPkg/Library/EmuBdsLib/BdsPlatform.c
index 3580d36779..75fba847f4 100644
--- a/EmulatorPkg/Library/EmuBdsLib/BdsPlatform.c
+++ b/EmulatorPkg/Library/EmuBdsLib/BdsPlatform.c
@@ -1,6 +1,6 @@
 /*++ @file
 
-Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 Portions copyright (c) 2011, Apple Inc. All rights reserved.
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
@@ -77,6 +77,8 @@ Returns:
 **/
 {
   SetupVariableInit ();
+
+  EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
 }
 
 EFI_STATUS
diff --git a/EmulatorPkg/Library/EmuBdsLib/BdsPlatform.h b/EmulatorPkg/Library/EmuBdsLib/BdsPlatform.h
index a099fecda0..5ececd4bed 100644
--- a/EmulatorPkg/Library/EmuBdsLib/BdsPlatform.h
+++ b/EmulatorPkg/Library/EmuBdsLib/BdsPlatform.h
@@ -1,6 +1,6 @@
 /*++ @file
 
-Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 Portions copyright (c) 2011, Apple Inc. All rights reserved.
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
@@ -18,6 +18,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <PiDxe.h>
 
 #include <Guid/EmuSystemConfig.h>
+#include <Guid/EventGroup.h>
 #include <Protocol/EmuThunk.h>
 #include <Protocol/EmuIoThunk.h>
 #include <Protocol/EmuGraphicsWindow.h>
@@ -32,6 +33,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Library/GenericBdsLib.h>
 #include <Library/PlatformBdsLib.h>
 #include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
 
 
 extern BDS_CONSOLE_CONNECT_ENTRY  gPlatformConsole[];
diff --git a/EmulatorPkg/Library/EmuBdsLib/EmuBdsLib.inf b/EmulatorPkg/Library/EmuBdsLib/EmuBdsLib.inf
index 526a159b96..755c50c789 100644
--- a/EmulatorPkg/Library/EmuBdsLib/EmuBdsLib.inf
+++ b/EmulatorPkg/Library/EmuBdsLib/EmuBdsLib.inf
@@ -2,7 +2,7 @@
 # Platfrom BDS driver
 #
 # Do platform action customized by IBV/OEM.
-# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 # Portions copyright (c) 2011, Apple Inc. All rights reserved.
 #
 #  This program and the accompanying materials
@@ -51,10 +51,11 @@ [LibraryClasses]
   PcdLib
   GenericBdsLib
   DevicePathLib
-
+  UefiLib
 
 [Guids]
   gEmuSystemConfigGuid
+  gEfiEndOfDxeEventGroupGuid
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow
-- 
2.16.1.windows.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 11/12] EmulatorPkg/EmuFileSystem: Fix a bug that causes Close() assertion
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
                   ` (9 preceding siblings ...)
  2018-08-23  9:52 ` [PATCH 10/12] EmulatorPkg/PlatformBds: Signal EndOfDxe in platform BDS Ruiyu Ni
@ 2018-08-23  9:52 ` Ruiyu Ni
  2018-08-23  9:52 ` [PATCH 12/12] EmulatorPkg/DSC: Remove FS mapping to EDK Shell bin directory Ruiyu Ni
  2018-08-23  9:56 ` [PATCH 00/12] Add WinHost support in EmulatorPkg Ni, Ruiyu
  12 siblings, 0 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Andrew Fish

The root cause is when a file is opened through File.Open(), the
private data for the File is not allocated, so when later
when File.Close() is called, the signature check in CR() causes
the assertion.

The private data for the File is allocated properly when the file
is opened from FS.OpenVolume().

The patch also fixes a minor issue that wrongly assigns
revision number to File.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Hao Wu <hao.a.wu@intel.com>
Cc: Andrew Fish <afish@intel.com>
---
 .../EmuSimpleFileSystemDxe/EmuSimpleFileSystem.c   | 33 +++++++++++++++++++---
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/EmulatorPkg/EmuSimpleFileSystemDxe/EmuSimpleFileSystem.c b/EmulatorPkg/EmuSimpleFileSystemDxe/EmuSimpleFileSystem.c
index 4709f7a46f..b5e19bb840 100644
--- a/EmulatorPkg/EmuSimpleFileSystemDxe/EmuSimpleFileSystem.c
+++ b/EmulatorPkg/EmuSimpleFileSystemDxe/EmuSimpleFileSystem.c
@@ -4,7 +4,7 @@
   environment variables. The variables must be visible to the Microsoft*
   Developer Studio for them to work.
 
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 Portions copyright (c) 2011, Apple Inc. All rights reserved.
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
@@ -51,7 +51,10 @@ EmuSimpleFileSystemOpen (
   IN  UINT64              Attributes
   )
 {
+  EFI_STATUS                        Status;
+  EFI_TPL                           OldTpl;
   EMU_EFI_FILE_PRIVATE              *PrivateFile;
+  EMU_EFI_FILE_PRIVATE              *NewPrivateFile;
 
   //
   // Check for obvious invalid parameters.
@@ -81,9 +84,29 @@ EmuSimpleFileSystemOpen (
     return EFI_INVALID_PARAMETER;
   }
 
-  PrivateFile     = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+  PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This);
+
+  NewPrivateFile = AllocateCopyPool (sizeof (EMU_EFI_FILE_PRIVATE), PrivateFile);
+  if (NewPrivateFile == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
+
 
-  return PrivateFile->Io->Open (PrivateFile->Io, NewHandle, FileName, OpenMode, Attributes);
+  Status = PrivateFile->Io->Open (PrivateFile->Io, &NewPrivateFile->Io, FileName, OpenMode, Attributes);
+  if (!EFI_ERROR (Status)) {
+    *NewHandle = &NewPrivateFile->EfiFile;
+  } else {
+    *NewHandle = NULL;
+    FreePool (NewPrivateFile);
+  }
+
+Done:
+  gBS->RestoreTPL (OldTpl);
+
+  return Status;
 }
 
 
@@ -508,7 +531,9 @@ EmuSimpleFileSystemOpenVolume (
   PrivateFile->Signature            = EMU_EFI_FILE_PRIVATE_SIGNATURE;
   PrivateFile->IoThunk              = Private->IoThunk;
   PrivateFile->SimpleFileSystem     = This;
-  PrivateFile->EfiFile.Revision     = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
+
+  ZeroMem (&PrivateFile->EfiFile, sizeof (PrivateFile->EfiFile));
+  PrivateFile->EfiFile.Revision     = EFI_FILE_PROTOCOL_REVISION;
   PrivateFile->EfiFile.Open         = EmuSimpleFileSystemOpen;
   PrivateFile->EfiFile.Close        = EmuSimpleFileSystemClose;
   PrivateFile->EfiFile.Delete       = EmuSimpleFileSystemDelete;
-- 
2.16.1.windows.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 12/12] EmulatorPkg/DSC: Remove FS mapping to EDK Shell bin directory
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
                   ` (10 preceding siblings ...)
  2018-08-23  9:52 ` [PATCH 11/12] EmulatorPkg/EmuFileSystem: Fix a bug that causes Close() assertion Ruiyu Ni
@ 2018-08-23  9:52 ` Ruiyu Ni
  2018-08-23  9:56 ` [PATCH 00/12] Add WinHost support in EmulatorPkg Ni, Ruiyu
  12 siblings, 0 replies; 14+ messages in thread
From: Ruiyu Ni @ 2018-08-23  9:52 UTC (permalink / raw)
  To: edk2-devel; +Cc: Hao Wu, Andrew Fish

The EDK Shell is end of line so the FS mapping to old EDK
Shell bin directory is better to be removed.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Hao Wu <hao.a.wu@intel.com>
Cc: Andrew Fish <afish@intel.com>
---
 EmulatorPkg/EmulatorPkg.dsc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/EmulatorPkg/EmulatorPkg.dsc b/EmulatorPkg/EmulatorPkg.dsc
index 67812f754b..9f9f7d318d 100644
--- a/EmulatorPkg/EmulatorPkg.dsc
+++ b/EmulatorPkg/EmulatorPkg.dsc
@@ -223,7 +223,7 @@ [PcdsFixedAtBuild]
   # For a CD-ROM/DVD use L"diag.dmg:RO:2048"
   gEmulatorPkgTokenSpaceGuid.PcdEmuVirtualDisk|L"disk.dmg:FW"
   gEmulatorPkgTokenSpaceGuid.PcdEmuGop|L"GOP Window"
-  gEmulatorPkgTokenSpaceGuid.PcdEmuFileSystem|L".!../../../../EdkShellBinPkg/Bin"
+  gEmulatorPkgTokenSpaceGuid.PcdEmuFileSystem|L"."
   gEmulatorPkgTokenSpaceGuid.PcdEmuSerialPort|L"/dev/ttyS0"
   gEmulatorPkgTokenSpaceGuid.PcdEmuNetworkInterface|L"en0"
 
-- 
2.16.1.windows.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 00/12] Add WinHost support in EmulatorPkg
  2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
                   ` (11 preceding siblings ...)
  2018-08-23  9:52 ` [PATCH 12/12] EmulatorPkg/DSC: Remove FS mapping to EDK Shell bin directory Ruiyu Ni
@ 2018-08-23  9:56 ` Ni, Ruiyu
  12 siblings, 0 replies; 14+ messages in thread
From: Ni, Ruiyu @ 2018-08-23  9:56 UTC (permalink / raw)
  To: Ni, Ruiyu, edk2-devel@lists.01.org

Hello,
Please ignore this patch sets.
I used the wrong mail address.

Thanks/Ray

> -----Original Message-----
> From: edk2-devel <edk2-devel-bounces@lists.01.org> On Behalf Of Ruiyu Ni
> Sent: Thursday, August 23, 2018 5:52 PM
> To: edk2-devel@lists.01.org
> Subject: [edk2] [PATCH 00/12] Add WinHost support in EmulatorPkg
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1112
> 
> The patch sets add WinHost support (Nt32) in EmulatorPkg.
> 3 EmulatorPkg common issues were found and fixed.
> Other 9 patches are to step-by-step enable the WinHost.
> 
> Ruiyu Ni (12):
>   EmulatorPkg/ThunkProtocolList: Fix VS build failure
>   EmulatorPkg/Win: Add Windows host support
>   EmulatorPkg/Win: Enable source level debugging
>   EmulatorPkg/Win: Enable native OS console as firmware console
>   EmulatorPkg/Win: Add input/output support
>   EmulatorPkg/Win: Add timer and interrupt support
>   EmulatorPkg/Win: Add RTC support
>   EmulatorPkg/Win: Add SimpleFileSystem support
>   EmulatorPkg/Win: Add BlockIo support
>   EmulatorPkg/PlatformBds: Signal EndOfDxe in platform BDS
>   EmulatorPkg/EmuFileSystem: Fix a bug that causes Close() assertion
>   EmulatorPkg/DSC: Remove FS mapping to EDK Shell bin directory
> 
>  .../EmuSimpleFileSystemDxe/EmuSimpleFileSystem.c   |   33 +-
>  EmulatorPkg/EmulatorPkg.dsc                        |   17 +-
>  EmulatorPkg/Library/EmuBdsLib/BdsPlatform.c        |    4 +-
>  EmulatorPkg/Library/EmuBdsLib/BdsPlatform.h        |    4 +-
>  EmulatorPkg/Library/EmuBdsLib/EmuBdsLib.inf        |    5 +-
>  .../Library/ThunkProtocolList/ThunkProtocolList.c  |    4 +-
>  EmulatorPkg/Win/Host/WinBlockIo.c                  |  563 +++++
>  EmulatorPkg/Win/Host/WinFileSystem.c               | 2409
> ++++++++++++++++++++
>  EmulatorPkg/Win/Host/WinGop.h                      |  204 ++
>  EmulatorPkg/Win/Host/WinGopInput.c                 |  417 ++++
>  EmulatorPkg/Win/Host/WinGopScreen.c                |  872 +++++++
>  EmulatorPkg/Win/Host/WinHost.c                     |  947 ++++++++
>  EmulatorPkg/Win/Host/WinHost.h                     |  209 ++
>  EmulatorPkg/Win/Host/WinHost.inf                   |  107 +
>  EmulatorPkg/Win/Host/WinInclude.h                  |   75 +
>  EmulatorPkg/Win/Host/WinMemoryAllocationLib.c      |  178 ++
>  EmulatorPkg/Win/Host/WinThunk.c                    |  577 +++++
>  17 files changed, 6614 insertions(+), 11 deletions(-)  create mode 100644
> EmulatorPkg/Win/Host/WinBlockIo.c  create mode 100644
> EmulatorPkg/Win/Host/WinFileSystem.c
>  create mode 100644 EmulatorPkg/Win/Host/WinGop.h  create mode 100644
> EmulatorPkg/Win/Host/WinGopInput.c
>  create mode 100644 EmulatorPkg/Win/Host/WinGopScreen.c
>  create mode 100644 EmulatorPkg/Win/Host/WinHost.c  create mode 100644
> EmulatorPkg/Win/Host/WinHost.h  create mode 100644
> EmulatorPkg/Win/Host/WinHost.inf  create mode 100644
> EmulatorPkg/Win/Host/WinInclude.h  create mode 100644
> EmulatorPkg/Win/Host/WinMemoryAllocationLib.c
>  create mode 100644 EmulatorPkg/Win/Host/WinThunk.c
> 
> --
> 2.16.1.windows.1
> 
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2018-08-23  9:56 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
2018-08-23  9:52 ` [PATCH 01/12] EmulatorPkg/ThunkProtocolList: Fix VS build failure Ruiyu Ni
2018-08-23  9:52 ` [PATCH 02/12] EmulatorPkg/Win: Add Windows host support Ruiyu Ni
2018-08-23  9:52 ` [PATCH 03/12] EmulatorPkg/Win: Enable source level debugging Ruiyu Ni
2018-08-23  9:52 ` [PATCH 04/12] EmulatorPkg/Win: Enable native OS console as firmware console Ruiyu Ni
2018-08-23  9:52 ` [PATCH 05/12] EmulatorPkg/Win: Add input/output support Ruiyu Ni
2018-08-23  9:52 ` [PATCH 06/12] EmulatorPkg/Win: Add timer and interrupt support Ruiyu Ni
2018-08-23  9:52 ` [PATCH 07/12] EmulatorPkg/Win: Add RTC support Ruiyu Ni
2018-08-23  9:52 ` [PATCH 08/12] EmulatorPkg/Win: Add SimpleFileSystem support Ruiyu Ni
2018-08-23  9:52 ` [PATCH 09/12] EmulatorPkg/Win: Add BlockIo support Ruiyu Ni
2018-08-23  9:52 ` [PATCH 10/12] EmulatorPkg/PlatformBds: Signal EndOfDxe in platform BDS Ruiyu Ni
2018-08-23  9:52 ` [PATCH 11/12] EmulatorPkg/EmuFileSystem: Fix a bug that causes Close() assertion Ruiyu Ni
2018-08-23  9:52 ` [PATCH 12/12] EmulatorPkg/DSC: Remove FS mapping to EDK Shell bin directory Ruiyu Ni
2018-08-23  9:56 ` [PATCH 00/12] Add WinHost support in EmulatorPkg Ni, Ruiyu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox