public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Ruiyu Ni <ruiyu.ni@intel.com>
To: edk2-devel@lists.01.org
Cc: Andrew Fish <afish@intel.com>, Hao A Wu <hao.a.wu@intel.com>
Subject: [PATCH 05/12] EmulatorPkg/Win: Add input/output support
Date: Thu, 23 Aug 2018 17:52:08 +0800	[thread overview]
Message-ID: <20180823095215.274248-6-ruiyu.ni@intel.com> (raw)
In-Reply-To: <20180823095215.274248-1-ruiyu.ni@intel.com>

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



  parent reply	other threads:[~2018-08-23  9:51 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` Ruiyu Ni [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180823095215.274248-6-ruiyu.ni@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox