public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v2 0/2] OvmfPkg/IntelGvtGopDxe: Add Intel GVT-g GOP.
@ 2021-03-05  6:20 Colin Xu
  2021-03-05  6:20 ` [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation Colin Xu
  2021-03-05  6:20 ` [PATCH v2 2/2] OvmfPkg/IntelGvtGopDxe: Enable GVT-g GOP in OvmfPkg DSC & DFD Colin Xu
  0 siblings, 2 replies; 11+ messages in thread
From: Colin Xu @ 2021-03-05  6:20 UTC (permalink / raw)
  To: devel; +Cc: rebecca, colin.xu

This patch set add Intel GVT-g GOP DXE to OvmfPkg.

V2:
Program PIPESRC to match active H/V.

Colin Xu (2):
  OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation.
  OvmfPkg/IntelGvtGopDxe: Enable GVT-g GOP in OvmfPkg DSC & DFD.

 OvmfPkg/IntelGvtGopDxe/Common.h           |   45 +
 OvmfPkg/IntelGvtGopDxe/DebugHelper.h      |   20 +
 OvmfPkg/IntelGvtGopDxe/Display.c          | 1077 +++++++++++++++++++++
 OvmfPkg/IntelGvtGopDxe/Display.h          |  141 +++
 OvmfPkg/IntelGvtGopDxe/GopDriver.c        |  478 +++++++++
 OvmfPkg/IntelGvtGopDxe/GpuReg.c           |   91 ++
 OvmfPkg/IntelGvtGopDxe/GpuReg.h           |  175 ++++
 OvmfPkg/IntelGvtGopDxe/Gtt.c              |  162 ++++
 OvmfPkg/IntelGvtGopDxe/Gtt.h              |   51 +
 OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf |   59 ++
 OvmfPkg/IntelGvtGopDxe/VbeShim.asm        |  343 +++++++
 OvmfPkg/IntelGvtGopDxe/VbeShim.c          |  258 +++++
 OvmfPkg/IntelGvtGopDxe/VbeShim.h          |  912 +++++++++++++++++
 OvmfPkg/IntelGvtGopDxe/VbeShim.sh         |   81 ++
 OvmfPkg/IntelGvtGopDxe/VirtualGpu.c       |  400 ++++++++
 OvmfPkg/IntelGvtGopDxe/VirtualGpu.h       |   52 +
 OvmfPkg/OvmfPkgX64.dsc                    |    4 +
 OvmfPkg/OvmfPkgX64.fdf                    |    3 +
 18 files changed, 4352 insertions(+)
 create mode 100644 OvmfPkg/IntelGvtGopDxe/Common.h
 create mode 100644 OvmfPkg/IntelGvtGopDxe/DebugHelper.h
 create mode 100644 OvmfPkg/IntelGvtGopDxe/Display.c
 create mode 100644 OvmfPkg/IntelGvtGopDxe/Display.h
 create mode 100644 OvmfPkg/IntelGvtGopDxe/GopDriver.c
 create mode 100644 OvmfPkg/IntelGvtGopDxe/GpuReg.c
 create mode 100644 OvmfPkg/IntelGvtGopDxe/GpuReg.h
 create mode 100644 OvmfPkg/IntelGvtGopDxe/Gtt.c
 create mode 100644 OvmfPkg/IntelGvtGopDxe/Gtt.h
 create mode 100644 OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf
 create mode 100644 OvmfPkg/IntelGvtGopDxe/VbeShim.asm
 create mode 100644 OvmfPkg/IntelGvtGopDxe/VbeShim.c
 create mode 100644 OvmfPkg/IntelGvtGopDxe/VbeShim.h
 create mode 100755 OvmfPkg/IntelGvtGopDxe/VbeShim.sh
 create mode 100644 OvmfPkg/IntelGvtGopDxe/VirtualGpu.c
 create mode 100644 OvmfPkg/IntelGvtGopDxe/VirtualGpu.h

-- 
2.30.1


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

* [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation.
  2021-03-05  6:20 [PATCH v2 0/2] OvmfPkg/IntelGvtGopDxe: Add Intel GVT-g GOP Colin Xu
@ 2021-03-05  6:20 ` Colin Xu
  2021-03-05 13:19   ` [edk2-devel] " Laszlo Ersek
  2021-03-05  6:20 ` [PATCH v2 2/2] OvmfPkg/IntelGvtGopDxe: Enable GVT-g GOP in OvmfPkg DSC & DFD Colin Xu
  1 sibling, 1 reply; 11+ messages in thread
From: Colin Xu @ 2021-03-05  6:20 UTC (permalink / raw)
  To: devel; +Cc: rebecca, colin.xu

Intel GVT-g GOP DXE supports OVMF GOP output its frame buffer to vGPU
partitioned aperture mapped by GGTT, so that the GOP output can be
mediated to its backend for display (i.e. QEMU GTK display via dma-buf).

Unlike ACRN GVT-d integrating native GOP/VBT into it's OVMF, the GVT-g
GOP is an open-source implementation which follows Intel GVT-g framework
to interact with KVMGT in host kernel so that the GOP frame buffer
content can be processed properly.

With GVT-g GOP enabled OVMF, guest VM can output its framebuffer
content to KVMGT via GOP, with a proper backend support (i.e. QEMU GTK
display with dma-buf), the following content is now directly visible to
user unlike previosly need a second GPU:
- OVMF EFI Shell
- Bootloader (i.e. grub)
- OS installation progress. (before built-in GFX driver loaded)
- Pre GFX Driver display (i.e. Android/Linux boot splash or logo,
  Windows 8.1 boot progress/safe mode/recovery mode/BSOD/GPU-disabled
  desktop, etc.)

GVT-g GOP has below capabilites:
- Check GVT-g compatibility via PV info, only enable GVT-g GOP when it's
  compatible with KVMGT.
- R/W MMIO from BAR0.
- R/W Global GTT from BAR0.
- Reserve and program OpRegion address at ASLS location so that guest
  driver can decode GVT-g simluated VBT and enabled display properly.
- Reserve guest memory and map to BAR2 partitioned range with proper
  GGTT, so that KVMGT can access via proper guest GTT to host GGTT map.
- All supported EFI_GRAPHICS_OUTPUT_BLT_OPERATION from/to video memory.
- Enable/disable GOP content on PIPE_A, PLANE_PRIMARY with proper scaling.
- VBE Shim so that some OS can query non-empty mode info via INT10 call
  to enable the desktop when GPU is disabled.

V2:
Program PIPESRC to match active H/V.

Signed-off-by: Colin Xu <colin.xu@intel.com>
---
 OvmfPkg/IntelGvtGopDxe/Common.h           |   45 +
 OvmfPkg/IntelGvtGopDxe/DebugHelper.h      |   20 +
 OvmfPkg/IntelGvtGopDxe/Display.c          | 1077 +++++++++++++++++++++
 OvmfPkg/IntelGvtGopDxe/Display.h          |  141 +++
 OvmfPkg/IntelGvtGopDxe/GopDriver.c        |  478 +++++++++
 OvmfPkg/IntelGvtGopDxe/GpuReg.c           |   91 ++
 OvmfPkg/IntelGvtGopDxe/GpuReg.h           |  175 ++++
 OvmfPkg/IntelGvtGopDxe/Gtt.c              |  162 ++++
 OvmfPkg/IntelGvtGopDxe/Gtt.h              |   51 +
 OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf |   59 ++
 OvmfPkg/IntelGvtGopDxe/VbeShim.asm        |  343 +++++++
 OvmfPkg/IntelGvtGopDxe/VbeShim.c          |  258 +++++
 OvmfPkg/IntelGvtGopDxe/VbeShim.h          |  912 +++++++++++++++++
 OvmfPkg/IntelGvtGopDxe/VbeShim.sh         |   81 ++
 OvmfPkg/IntelGvtGopDxe/VirtualGpu.c       |  400 ++++++++
 OvmfPkg/IntelGvtGopDxe/VirtualGpu.h       |   52 +
 16 files changed, 4345 insertions(+)
 create mode 100644 OvmfPkg/IntelGvtGopDxe/Common.h
 create mode 100644 OvmfPkg/IntelGvtGopDxe/DebugHelper.h
 create mode 100644 OvmfPkg/IntelGvtGopDxe/Display.c
 create mode 100644 OvmfPkg/IntelGvtGopDxe/Display.h
 create mode 100644 OvmfPkg/IntelGvtGopDxe/GopDriver.c
 create mode 100644 OvmfPkg/IntelGvtGopDxe/GpuReg.c
 create mode 100644 OvmfPkg/IntelGvtGopDxe/GpuReg.h
 create mode 100644 OvmfPkg/IntelGvtGopDxe/Gtt.c
 create mode 100644 OvmfPkg/IntelGvtGopDxe/Gtt.h
 create mode 100644 OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf
 create mode 100644 OvmfPkg/IntelGvtGopDxe/VbeShim.asm
 create mode 100644 OvmfPkg/IntelGvtGopDxe/VbeShim.c
 create mode 100644 OvmfPkg/IntelGvtGopDxe/VbeShim.h
 create mode 100755 OvmfPkg/IntelGvtGopDxe/VbeShim.sh
 create mode 100644 OvmfPkg/IntelGvtGopDxe/VirtualGpu.c
 create mode 100644 OvmfPkg/IntelGvtGopDxe/VirtualGpu.h

diff --git a/OvmfPkg/IntelGvtGopDxe/Common.h b/OvmfPkg/IntelGvtGopDxe/Common.h
new file mode 100644
index 000000000000..cf30752eb8f3
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/Common.h
@@ -0,0 +1,45 @@
+/** @file
+  Component name for the QEMU video controller.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __COMMON_H_
+
+#include <Protocol/PciIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/GraphicsOutput.h>
+
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include "DebugHelper.h"
+
+#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
+
+typedef struct {
+  UINT64                       Signature;
+  EFI_HANDLE                   Handle;
+  EFI_PCI_IO_PROTOCOL          *PciIo;
+  UINT64                       OriginalPciAttr;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutputProtocol;
+  EFI_DEVICE_PATH_PROTOCOL     *GopDevPath;
+  VOID                         *VirtualGpu;
+} GVT_GOP_PRIVATE_DATA;
+
+#define GVT_GOP_MAGIC                     SIGNATURE_64('G','V','T','G','V','G','O','P')
+#define GVT_GOP_PRIVATE_DATA_FROM_THIS(a) CR(a, GVT_GOP_PRIVATE_DATA, GraphicsOutputProtocol, GVT_GOP_MAGIC)
+
+#define __COMMON_H_
+#endif //__COMMON_H_
diff --git a/OvmfPkg/IntelGvtGopDxe/DebugHelper.h b/OvmfPkg/IntelGvtGopDxe/DebugHelper.h
new file mode 100644
index 000000000000..75158d713ec3
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/DebugHelper.h
@@ -0,0 +1,20 @@
+/** @file
+  Component name for the QEMU video controller.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __DEBUGHELPER_H_
+#define __DEBUGHELPER_H_
+
+#include <Library/DebugLib.h>
+
+#define GVT_DEBUG(ErrLevel, Fmt, Args...) \
+  do { \
+    DEBUG ((ErrLevel, "GvtGop: "Fmt, ##Args));\
+  } while (FALSE)
+
+#endif //__DEBUGHELPER_H_
diff --git a/OvmfPkg/IntelGvtGopDxe/Display.c b/OvmfPkg/IntelGvtGopDxe/Display.c
new file mode 100644
index 000000000000..133de25ff03c
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/Display.c
@@ -0,0 +1,1077 @@
+/** @file
+  Component name for the QEMU video controller.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Common.h"
+#include "Display.h"
+#include "GpuReg.h"
+#include "Gtt.h"
+#include "VirtualGpu.h"
+
+EFI_STATUS
+IntelVirtualGpuDisplayInit (
+  IN OUT GVT_GOP_PRIVATE_DATA *Private
+  )
+{
+  EFI_STATUS                 Status = EFI_UNSUPPORTED;
+  PINTEL_VIRTUAL_GPU         VirtualGpu;
+  PINTEL_VIRTUAL_GPU_DISPLAY Display;
+  UINT32                     Val32;
+  UINTN                      Width, Height, ModeNumber;
+  EFI_TPL                    OriginalTPL;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
+  Display = &VirtualGpu->Display;
+
+  /*
+   * If PcdVideoHorizontalResolution or PcdVideoVerticalResolution is not set,
+   *   GOP will query the mode list reported to find the highest resolution.
+   *   Otherwise, check if the set PcdVideo*Resolution is defined.
+   *   If not supported, try 800x600 which is required by UEFI/EFI spec.
+   *   If still not supported, use the 1st mode in mode list.
+   * If there are multiple video devices, graphic console driver will set all
+   *   the video devices to the same mode.
+   * According to UEFI/EFI spec, in addition to platform design guide, on-board
+   *   graphics should support native mode of the display, plug-in graphics
+   *   should support 800x600x32 or 640x480x32.
+   * According to some OS requirement (i.e. UEFI requirment for Windows 10),
+   *   integrated displays should support panel native resolution and external
+   *   displays should support the maximum resolution of both GPU and display in
+   *   GOP. For alternate display output, it should support native or highest
+   *   compatible resolution, otherwise support an known mode to be compatible
+   *   with as many monitors as possible (640x480, 1024x768).
+   * Due to above requirement, use native resolution if PcdVideo*Resolution is
+   *   not defined. To reduce GGTT write overhead, also limit the maximum to
+   *   DISPLAY_WIDTH_MAX/DISPLAY_HEIGHT_MAX.
+   */
+
+  RegRead32 (Private, HTOTAL(PIPE_A), &Val32);
+  Display->HActive = (Val32 & 0xFFF) + 1;
+  RegRead32 (Private, VTOTAL(PIPE_A), &Val32);
+  Display->VActive = (Val32 & 0xFFF) + 1;
+
+  if (Display->HActive != 0 && Display->VActive != 0) {
+    Width = Display->HActive;
+    Height = Display->VActive;
+    if (Display->HActive > DISPLAY_WIDTH_MAX ||
+        Display->VActive > DISPLAY_HEIGHT_MAX) {
+      Width = DISPLAY_WIDTH_MAX;
+      Height = DISPLAY_HEIGHT_MAX;
+    }
+  } else {
+    Width = DISPLAY_WIDTH_DEFAULT;
+    Height = DISPLAY_HEIGHT_DEFAULT;
+  }
+
+  Display->Width = Width;
+  Display->Height = Height;
+  Display->Format = PixelBlueGreenRedReserved8BitPerColor;
+  Display->Bpp = 4;
+  Display->MaxMode = 1;
+
+  // Add default if defined
+  if (PcdGet32 (PcdVideoHorizontalResolution) != 0 &&
+      PcdGet32 (PcdVideoVerticalResolution) != 0 &&
+      PcdGet32 (PcdVideoHorizontalResolution) != Width &&
+      PcdGet32 (PcdVideoVerticalResolution) != Height) {
+      ++Display->MaxMode;
+  }
+
+  Display->CurrentMode = DISPLAY_MODE_INVALID;
+  Display->FrameBufferBltConfigure = NULL;
+  Display->FrameBufferBltConfigureSize = 0;
+
+  // Linear must start at 256K, stride align at 64
+  Display->WidthBytes = Display->Width * Display->Bpp;
+  Display->StrideBytes = ALIGN_VALUE (Display->WidthBytes, 64);
+  Display->FbSize = Display->StrideBytes * Display->Height;
+  Display->Pages = EFI_SIZE_TO_PAGES (Display->FbSize);
+
+  Display->FbGMAddr = VirtualGpu->GpuMemAddr + VirtualGpu->VisibleOffset;
+  Display->FbGMAddr = ALIGN_VALUE (Display->FbGMAddr, SIZE_256KB);
+
+  Status = gBS->AllocatePages (
+                AllocateAnyPages,
+                EfiReservedMemoryType,
+                Display->Pages,
+                &Display->FbPhysicalAddr
+                );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "AllocatePages failed for display FB, pages %d, size %lx, status %d\n",
+      Display->Pages, Display->FbSize, Status
+      );
+    return Status;
+  }
+
+  Status = UpdateGGTT (Private,
+             Display->FbGMAddr,
+             Display->FbPhysicalAddr,
+             Display->Pages
+             );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Fail to Update GGTT for display, status %d\n", Status
+      );
+    goto Done;
+  }
+
+  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+  Status = IntelVirtualGpuBltVideoFill (
+             Display,
+             (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION){{0, 0, 0, 0}},
+             (BLT_RECTANGLE){0, 0, Display->Width, Display->Height});
+  gBS->RestoreTPL (OriginalTPL);
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Fail to clear rectangle at [%d, %d] size %dx%d with color 0x%08x, status %d\n",
+      (BLT_RECTANGLE){0, 0, Display->Width, Display->Height}.X,
+      (BLT_RECTANGLE){0, 0, Display->Width, Display->Height}.Y,
+      (BLT_RECTANGLE){0, 0, Display->Width, Display->Height}.Width,
+      (BLT_RECTANGLE){0, 0, Display->Width, Display->Height}.Height,
+      (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION){{0, 0, 0, 0}}.Raw,
+      Status
+      );
+    goto Done;
+  }
+
+  Status = gBS->AllocatePool (
+                  EfiBootServicesData,
+                  sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * Display->MaxMode,
+                  (VOID **)&Display->ModeList
+                  );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "AllocatePool failed for display mode list, size %d, status %d\n",
+      sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * Display->MaxMode,
+      Status
+      );
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
+
+  for (ModeNumber = 0; ModeNumber < Display->MaxMode; ModeNumber++) {
+    Display->ModeList[ModeNumber].Version = 0;
+    Display->ModeList[ModeNumber].HorizontalResolution = Display->Width;
+    Display->ModeList[ModeNumber].VerticalResolution = Display->Height;
+    Display->ModeList[ModeNumber].PixelFormat = Display->Format;
+    Display->ModeList[ModeNumber].PixelsPerScanLine = Display->Width;
+  }
+  if (Display->MaxMode > 1) {
+    Display->ModeList[1].HorizontalResolution = PcdGet32 (PcdVideoHorizontalResolution);
+    Display->ModeList[1].VerticalResolution = PcdGet32 (PcdVideoVerticalResolution);
+    Display->ModeList[1].PixelsPerScanLine = PcdGet32 (PcdVideoHorizontalResolution);
+  }
+
+  Private->GraphicsOutputProtocol.QueryMode = IntelVirtualGpuQueryMode;
+  Private->GraphicsOutputProtocol.SetMode = IntelVirtualGpuSetMode;
+  Private->GraphicsOutputProtocol.Blt = IntelVirtualGpuBlt;
+  Private->GraphicsOutputProtocol.Mode->MaxMode = Display->MaxMode;
+  Private->GraphicsOutputProtocol.Mode->Mode = Display->CurrentMode;
+  Private->GraphicsOutputProtocol.Mode->SizeOfInfo =
+    sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * Display->MaxMode;
+
+  Status = gBS->AllocatePool (
+                  EfiBootServicesData,
+                  Private->GraphicsOutputProtocol.Mode->SizeOfInfo,
+                  (VOID **)&Private->GraphicsOutputProtocol.Mode->Info
+                  );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "AllocatePool failed for display mode info, size %d, status %d\n",
+      Private->GraphicsOutputProtocol.Mode->SizeOfInfo, Status
+      );
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
+
+  CopyMem (
+    Private->GraphicsOutputProtocol.Mode->Info,
+    Display->ModeList,
+    sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * Display->MaxMode
+    );
+
+  Private->GraphicsOutputProtocol.Mode->FrameBufferBase = Display->FbGMAddr;
+  Private->GraphicsOutputProtocol.Mode->FrameBufferSize = Display->FbSize;
+
+  InstallVbeShim (L"GVT-g VBIOS", Display->FbGMAddr);
+
+  GVT_DEBUG (EFI_D_INFO,
+    "modes %d, max %dx%d, OVMF default %dx%d\n",
+    Display->MaxMode,
+    Display->Width, Display->Height,
+    PcdGet32 (PcdVideoHorizontalResolution),
+    PcdGet32 (PcdVideoVerticalResolution)
+    );
+  for (ModeNumber = 0; ModeNumber < Display->MaxMode; ModeNumber++) {
+    GVT_DEBUG (EFI_D_INFO,
+      "  mode %d: %dx%d BGRX, stride %d\n",
+      ModeNumber,
+      Display->ModeList[ModeNumber].HorizontalResolution,
+      Display->ModeList[ModeNumber].VerticalResolution,
+      ALIGN_VALUE (Display->ModeList[ModeNumber].HorizontalResolution * Display->Bpp, 64)
+      );
+  }
+  GVT_DEBUG (EFI_D_INFO,
+    "FrameBuffer: GMADR %lx, PADDR %lx, size %lx, pages %d, INTERNAL_BLT %d\n",
+    Display->FbGMAddr, Display->FbPhysicalAddr, Display->FbSize, Display->Pages,
+    DISPLAY_USE_INTERNAL_BLT
+    );
+
+Done:
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+
+}
+
+EFI_STATUS
+IntelVirtualGpuDisplayClean (
+  IN OUT GVT_GOP_PRIVATE_DATA *Private
+  )
+{
+  EFI_STATUS                 Status = EFI_INVALID_PARAMETER;
+  PINTEL_VIRTUAL_GPU         VirtualGpu;
+  PINTEL_VIRTUAL_GPU_DISPLAY Display;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
+  Display = &VirtualGpu->Display;
+
+  if (Private->GraphicsOutputProtocol.Mode->Info) {
+    Status = gBS->FreePool (Private->GraphicsOutputProtocol.Mode->Info);
+    if (EFI_ERROR (Status)) {
+      GVT_DEBUG (EFI_D_ERROR,
+        "FreePool failed for display mode info, size %d, status %d\n",
+        Private->GraphicsOutputProtocol.Mode->SizeOfInfo, Status
+        );
+        goto Done;
+    }
+    Private->GraphicsOutputProtocol.Mode->SizeOfInfo = 0;
+    Private->GraphicsOutputProtocol.Mode->Info = NULL;
+  }
+  Private->GraphicsOutputProtocol.Mode->MaxMode = 0;
+  Private->GraphicsOutputProtocol.Mode->Mode = DISPLAY_MODE_INVALID;
+
+  if (Display->FbPhysicalAddr) {
+    Status = gBS->FreePages (Display->FbPhysicalAddr, Display->Pages);
+    if (EFI_ERROR (Status)) {
+      GVT_DEBUG (EFI_D_ERROR,
+        "FreePages failed for display FB, pages %d, size %lx, status %d\n",
+        Display->Pages, Display->FbSize, Status
+        );
+        goto Done;
+    }
+    Display->FbPhysicalAddr = 0;
+    Display->Pages = 0;
+    Display->FbSize = 0;
+  }
+
+  Status = EFI_SUCCESS;
+
+Done:
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+IntelVirtualGpuQueryMode (
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL         *This,
+  IN  UINT32                               ModeNumber,
+  OUT UINTN                                *SizeOfInfo,
+  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+  )
+{
+  EFI_STATUS                 Status = EFI_UNSUPPORTED;
+  GVT_GOP_PRIVATE_DATA       *GvtGopPrivate = NULL;
+  PINTEL_VIRTUAL_GPU         VirtualGpu;
+  PINTEL_VIRTUAL_GPU_DISPLAY Display;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  GvtGopPrivate = GVT_GOP_PRIVATE_DATA_FROM_THIS (This);
+  VirtualGpu = (PINTEL_VIRTUAL_GPU)GvtGopPrivate->VirtualGpu;
+  Display = &VirtualGpu->Display;
+
+  if (ModeNumber >= Display->MaxMode) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Invalid ModeNumber, request %d, max %d, status %d\n",
+      ModeNumber, Display->MaxMode, Status
+      );
+    Status = EFI_INVALID_PARAMETER;
+    goto Done;
+  }
+
+  Status = gBS->AllocatePool (
+                  EfiBootServicesData,
+                  sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
+                  (VOID **)Info
+                  );
+  if (EFI_ERROR (Status) || *Info == NULL) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "AllocatePool failed for queried mode info, size %d, status %d\n",
+      sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), Status
+      );
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
+
+  *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+  CopyMem (
+    *Info,
+    &Display->ModeList[ModeNumber],
+    sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
+    );
+
+  Status = EFI_SUCCESS;
+
+Done:
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+IntelVirtualGpuSetMode (
+  IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+  IN UINT32                       ModeNumber
+  )
+{
+  EFI_STATUS                          Status = EFI_UNSUPPORTED;
+  GVT_GOP_PRIVATE_DATA                *GvtGopPrivate = NULL;
+  PINTEL_VIRTUAL_GPU                  VirtualGpu;
+  PINTEL_VIRTUAL_GPU_DISPLAY          Display;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  GvtGopPrivate = GVT_GOP_PRIVATE_DATA_FROM_THIS (This);
+  VirtualGpu = (PINTEL_VIRTUAL_GPU)GvtGopPrivate->VirtualGpu;
+  Display = &VirtualGpu->Display;
+
+  if (ModeNumber >= Display->MaxMode) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Invalid ModeNumber, request %d, max %d, status %d\n",
+      ModeNumber, Display->MaxMode, Status
+      );
+    Status = EFI_INVALID_PARAMETER;
+    goto Done;
+  }
+
+#if (DISPLAY_USE_INTERNAL_BLT == 1)
+  Status = IntelVirtualGpuBltVideoFill (
+             Display,
+             (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION){{0, 0, 0, 0}},
+             (BLT_RECTANGLE){0, 0, This->Mode->Info->HorizontalResolution, This->Mode->Info->VerticalResolution});
+  if (EFI_ERROR (Status)) {
+      GVT_DEBUG (EFI_D_ERROR,
+        "IntelVirtualGpuBltVideoFill failed for mode %d, status %d\n",
+        ModeNumber,
+        Status
+        );
+    }
+#else
+  Status = FrameBufferBltConfigure (
+             (VOID*) (UINTN) This->Mode->FrameBufferBase,
+             This->Mode->Info,
+             Display->FrameBufferBltConfigure,
+             &Display->FrameBufferBltConfigureSize
+             );
+  if (Status == RETURN_BUFFER_TOO_SMALL) {
+    if (Display->FrameBufferBltConfigure != NULL) {
+      Status = gBS->FreePool (Display->FrameBufferBltConfigure);
+      if (EFI_ERROR (Status)) {
+        GVT_DEBUG (EFI_D_ERROR,
+          "FreePool failed for FrameBufferBltConfigure, status %d\n",
+          Status
+          );
+          goto Done;
+      }
+    }
+    Status = gBS->AllocatePool (
+                  EfiBootServicesData,
+                  Display->FrameBufferBltConfigureSize,
+                  (VOID **)&Display->FrameBufferBltConfigure
+                  );
+    if (EFI_ERROR (Status)) {
+      GVT_DEBUG (EFI_D_ERROR,
+        "AllocatePool failed for FrameBufferBltConfigure, size %d, status %d\n",
+        Display->FrameBufferBltConfigureSize,
+        Status
+        );
+      goto Done;
+    }
+
+    Status = FrameBufferBltConfigure (
+                (VOID*) (UINTN) This->Mode->FrameBufferBase,
+                This->Mode->Info,
+                Display->FrameBufferBltConfigure,
+                &Display->FrameBufferBltConfigureSize
+                );
+    if (EFI_ERROR (Status)) {
+      GVT_DEBUG (EFI_D_ERROR,
+        "FrameBufferBltConfigure failed for mode %d, status %d\n",
+        ModeNumber,
+        Status
+        );
+      goto Done;
+    }
+  }
+
+  Status = FrameBufferBlt (
+             Display->FrameBufferBltConfigure,
+             &(EFI_GRAPHICS_OUTPUT_BLT_PIXEL){0, 0, 0, 0},
+             EfiBltVideoFill,
+             0, 0,
+             0, 0,
+             This->Mode->Info->HorizontalResolution,
+             This->Mode->Info->VerticalResolution,
+             0
+             );
+  if (EFI_ERROR (Status)) {
+      GVT_DEBUG (EFI_D_ERROR,
+        "FrameBufferBlt BltOperation %d failed for mode %d, color 0x%08x, status %d\n",
+        EfiBltVideoFill,
+        ModeNumber,
+        (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION){{0, 0, 0, 0}}.Raw,
+        Status
+        );
+    }
+#endif
+
+  Status = IntelVirtualGpuEnableDisplay (
+             GvtGopPrivate,
+             ModeNumber,
+             FALSE
+             );
+
+  Status = IntelVirtualGpuEnableDisplay (
+             GvtGopPrivate,
+             ModeNumber,
+             TRUE
+             );
+
+  // Set current mode info in GOP
+  This->Mode->Mode = ModeNumber;
+  CopyMem (
+    This->Mode->Info,
+    &Display->ModeList[ModeNumber],
+    sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
+    );
+
+  GVT_DEBUG (EFI_D_INFO, "Set mode %d, %dx%d, status %d\n",
+    ModeNumber,
+    Display->ModeList[ModeNumber].HorizontalResolution,
+    Display->ModeList[ModeNumber].VerticalResolution,
+    Status
+    );
+
+Done:
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+IntelVirtualGpuBlt (
+  IN EFI_GRAPHICS_OUTPUT_PROTOCOL      *This,
+  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *BltBuffer, OPTIONAL
+  IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+  IN UINTN                             SourceX,
+  IN UINTN                             SourceY,
+  IN UINTN                             DestinationX,
+  IN UINTN                             DestinationY,
+  IN UINTN                             Width,
+  IN UINTN                             Height,
+  IN UINTN                             Delta OPTIONAL
+  )
+{
+  EFI_STATUS                 Status = EFI_UNSUPPORTED;
+  GVT_GOP_PRIVATE_DATA       *GvtGopPrivate = NULL;
+  PINTEL_VIRTUAL_GPU         VirtualGpu;
+  PINTEL_VIRTUAL_GPU_DISPLAY Display;
+  EFI_TPL                    OriginalTPL;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  GvtGopPrivate = GVT_GOP_PRIVATE_DATA_FROM_THIS (This);
+  VirtualGpu = (PINTEL_VIRTUAL_GPU)GvtGopPrivate->VirtualGpu;
+  Display = &VirtualGpu->Display;
+
+  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+#if (DISPLAY_USE_INTERNAL_BLT == 1)
+  switch (BltOperation) {
+  case EfiBltVideoFill:
+    Status = IntelVirtualGpuBltVideoFill (
+               Display,
+               (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION)(*BltBuffer),
+               (BLT_RECTANGLE){DestinationX, DestinationY, Width, Height});
+    RegWrite32 (GvtGopPrivate,
+      PLANE_SURF(PIPE_A, PLANE_PRIMARY),
+      Display->FbGMAddr
+      );
+    break;
+  case EfiBltVideoToBltBuffer:
+    Status = IntelVirtualGpuBltVideoToBuffer (
+               Display,
+               BltBuffer,
+               (BLT_RECTANGLE){SourceX, SourceY, Width, Height},
+               (BLT_RECTANGLE){DestinationX, DestinationY, Width, Height},
+               Delta
+               );
+    break;
+  case EfiBltBufferToVideo:
+    Status = IntelVirtualGpuBltVideoFromBuffer (
+               Display,
+               BltBuffer,
+               (BLT_RECTANGLE){SourceX, SourceY, Width, Height},
+               (BLT_RECTANGLE){DestinationX, DestinationY, Width, Height},
+               Delta
+               );
+    RegWrite32 (GvtGopPrivate,
+      PLANE_SURF(PIPE_A, PLANE_PRIMARY),
+      Display->FbGMAddr
+      );
+    break;
+  case EfiBltVideoToVideo:
+    Status = IntelVirtualGpuBltVideoToVideo (
+               Display,
+               (BLT_RECTANGLE){SourceX, SourceY, Width, Height},
+               (BLT_RECTANGLE){DestinationX, DestinationY, Width, Height}
+               );
+    RegWrite32 (GvtGopPrivate,
+      PLANE_SURF(PIPE_A, PLANE_PRIMARY),
+      Display->FbGMAddr
+      );
+    break;
+  default:
+    GVT_DEBUG (EFI_D_INFO, "Unsupported EFI_GRAPHICS_OUTPUT_BLT_OPERATION %d\n", BltOperation);
+    Status = EFI_UNSUPPORTED;
+    break;
+  }
+#else
+  switch (BltOperation) {
+  case EfiBltVideoToBltBuffer:
+  case EfiBltVideoFill:
+  case EfiBltBufferToVideo:
+  case EfiBltVideoToVideo:
+    Status = FrameBufferBlt (
+               Display->FrameBufferBltConfigure,
+               BltBuffer,
+               BltOperation,
+               SourceX,
+               SourceY,
+               DestinationX,
+               DestinationY,
+               Width,
+               Height,
+               Delta
+               );
+    if (BltOperation != EfiBltVideoToBltBuffer) {
+      RegWrite32 (GvtGopPrivate,
+        PLANE_SURF(PIPE_A, PLANE_PRIMARY),
+        Display->FbGMAddr
+        );
+    }
+    break;
+  default:
+    GVT_DEBUG (EFI_D_INFO, "Unsupported EFI_GRAPHICS_OUTPUT_BLT_OPERATION %d\n", BltOperation);
+    Status = EFI_UNSUPPORTED;
+    break;
+  }
+#endif
+
+  gBS->RestoreTPL (OriginalTPL);
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
+
+EFI_STATUS
+IntelVirtualGpuEnableDisplay (
+  IN OUT GVT_GOP_PRIVATE_DATA *Private,
+  IN     UINT32               ModeNumber,
+  IN     BOOLEAN              Enable
+  )
+{
+  EFI_STATUS                 Status = EFI_INVALID_PARAMETER;
+  PINTEL_VIRTUAL_GPU         VirtualGpu;
+  PINTEL_VIRTUAL_GPU_DISPLAY Display;
+  UINT32                     Width, Height, Val32;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
+  Display = &VirtualGpu->Display;
+
+  if (ModeNumber >= Display->MaxMode) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Invalid ModeNumber, request %d, max %d, status %d\n",
+      ModeNumber, Display->MaxMode, Status
+      );
+    Status = EFI_INVALID_PARAMETER;
+    goto Done;
+  }
+
+  Width = Display->ModeList[ModeNumber].HorizontalResolution;
+  Height = Display->ModeList[ModeNumber].VerticalResolution;
+
+  if (Enable) {
+    Display->CurrentMode = ModeNumber;
+
+    Val32 = (Display->HActive - 1) << 16;
+    Val32 |= Display->VActive;
+    RegWrite32 (Private, PIPESRC(PIPE_A), Val32);
+
+    RegRead32 (Private, PIPE_CONF(PIPE_A), &Val32);
+    Val32 |= PIPE_CONF_ENABLE;
+    RegWrite32 (Private, PIPE_CONF(PIPE_A), Val32);
+
+    Val32 = (Width - 1) & 0xFFF;
+    Val32 |= ((Height - 1) & 0xFFF) << 16;
+    RegWrite32 (Private, PLANE_SIZE(PIPE_A, PLANE_PRIMARY), Val32);
+    RegWrite32 (Private, PLANE_POS(PIPE_A, PLANE_PRIMARY), 0);
+
+    // Convert mode with to stride in chunks of 64 bytes as required by PLANE_STRIDE
+    Val32 = Display->ModeList[ModeNumber].HorizontalResolution * Display->Bpp;
+    Val32 = ALIGN_VALUE (Val32, 64);
+    Val32 = (Val32 / 64) & PLANE_STRIDE_MASK;
+    RegWrite32 (Private, PLANE_STRIDE(PIPE_A, PLANE_PRIMARY), Val32);
+
+    RegWrite32 (Private, PLANE_SURF(PIPE_A, PLANE_PRIMARY), Display->FbGMAddr);
+
+    // Stretch to fullscreen if current mode is smaller than H/V active.
+    if (Display->HActive != Width ||
+        Display->VActive != Height) {
+      RegWrite32 (Private, PS_WIN_POS(PIPE_A, 0), 0);
+      RegWrite32 (Private,
+        PS_WIN_SZ(PIPE_A, 0),
+        Display->HActive << 16 | Display->VActive
+        );
+      RegRead32 (Private, PS_CTRL(PIPE_A, 0), &Val32);
+      Val32 |= PS_CTRL_SCALER_EN;
+      Val32 &= ~PS_CTRL_SCALER_MODE_MASK;
+      Val32 |= PS_CTRL_SCALER_MODE_DYN;
+      Val32 &= ~PS_CTRL_SCALER_BINDING_MASK;
+      Val32 |= PS_CTRL_PLANE_SEL(PLANE_PRIMARY);
+      Val32 &= ~PS_CTRL_SCALER_FILTER_MASK;
+      Val32 |= PS_CTRL_SCALER_FILTER_MEDIUM;
+      RegWrite32 (Private, PS_CTRL(PIPE_A, 0), Val32);
+    }
+
+    RegRead32 (Private, PLANE_CTL(PIPE_A, PLANE_PRIMARY), &Val32);
+    Val32 |= PLANE_CTL_ENABLE;
+    Val32 &= ~PLANE_CTL_PIPE_GAMMA_ENABLE;
+    Val32 &= ~PLANE_CTL_FORMAT_MASK;
+    Val32 |= PLANE_CTL_FORMAT_XRGB_8888;
+    Val32 &= ~PLANE_CTL_PIPE_CSC_ENABLE;
+    Val32 &= ~PLANE_CTL_KEY_ENABLE_MASK;
+    Val32 &= ~PLANE_CTL_ORDER_RGBX;
+    if (Display->ModeList[ModeNumber].PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
+      Val32 |= PLANE_CTL_ORDER_RGBX;
+    }
+    Val32 &= ~PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
+    Val32 |= PLANE_CTL_PLANE_GAMMA_DISABLE;
+    Val32 &= ~PLANE_CTL_TILED_MASK;
+    Val32 |= PLANE_CTL_TILED_LINEAR;
+    Val32 &= ~PLANE_CTL_ASYNC_FLIP;
+    Val32 &= ~PLANE_CTL_ALPHA_MASK;
+    Val32 |= PLANE_CTL_ALPHA_DISABLE;
+    Val32 &= ~PLANE_CTL_ROTATE_MASK;
+    Val32 |= PLANE_CTL_ROTATE_0;
+    RegWrite32 (Private, PLANE_CTL(PIPE_A, PLANE_PRIMARY), Val32);
+  } else {
+    Display->CurrentMode = DISPLAY_MODE_INVALID;
+
+    RegRead32 (Private, PLANE_CTL(PIPE_A, PLANE_PRIMARY), &Val32);
+    Val32 &= ~PLANE_CTL_ENABLE;
+    RegWrite32 (Private, PLANE_CTL(PIPE_A, PLANE_PRIMARY), Val32);
+    RegWrite32 (Private, PLANE_SURF(PIPE_A, PLANE_PRIMARY), 0);
+
+    RegRead32 (Private, PS_CTRL(PIPE_A, 0), &Val32);
+    Val32 &= ~PS_CTRL_SCALER_EN;
+    RegWrite32 (Private, PS_CTRL(PIPE_A, 0), Val32);
+    RegWrite32 (Private, PS_WIN_POS(PIPE_A, 0), 0);
+    RegWrite32 (Private, PS_WIN_SZ(PIPE_A, 0), 0);
+
+    RegRead32 (Private, PIPE_CONF(PIPE_A), &Val32);
+    Val32 &= ~PIPE_CONF_ENABLE;
+    RegWrite32 (Private, PIPE_CONF(PIPE_A), Val32);
+  }
+
+  Status = EFI_SUCCESS;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: %a mode %dx%d 0x%x, scaling %a\n",
+    __FUNCTION__,
+    Enable ? "Enable" : "Disable",
+    Width,
+    Height,
+    Display->FbGMAddr,
+    (Display->HActive != Width ||
+     Display->VActive != Height) ? "On" : "Off");
+
+Done:
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
+
+EFI_STATUS
+IntelVirtualGpuNotifyDisplayReady (
+  IN GVT_GOP_PRIVATE_DATA *Private,
+  IN BOOLEAN              Ready
+  )
+{
+  return RegWrite32 (
+           Private,
+           vgtif_reg(display_ready),
+           Ready ? VGT_DRV_DISPLAY_READY : VGT_DRV_DISPLAY_NOT_READY
+           );
+}
+
+EFI_STATUS
+IntelVirtualGpuBltVideoFill (
+  IN PINTEL_VIRTUAL_GPU_DISPLAY          Display,
+  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION BltPixel,
+  IN BLT_RECTANGLE                       Destination
+  )
+{
+  EFI_STATUS Status = EFI_INVALID_PARAMETER;
+  VOID       *DestAddr;
+  UINTN      DestBytes, ModeStrideBytes, Line;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  if (Destination.Width == 0 || Destination.Height == 0) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "EfiBltVideoFill invalid destination rectangle [%d, %d] \n",
+      Destination.Width, Destination.Height
+      );
+    goto Done;
+  }
+
+  if ((Destination.X + Destination.Width > Display->Width) ||
+      (Destination.Y + Destination.Height > Display->Height)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "EfiBltVideoFill destination [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
+      Destination.X, Destination.Y,
+      Destination.X + Destination.Width, Destination.Y + Destination.Height,
+      Display->Width, Display->Height
+      );
+    goto Done;
+  }
+
+  if (Display->CurrentMode == DISPLAY_MODE_INVALID) {
+    ModeStrideBytes = Display->Width;
+  } else {
+    ModeStrideBytes = Display->ModeList[Display->CurrentMode].HorizontalResolution;
+  }
+  ModeStrideBytes = ALIGN_VALUE (ModeStrideBytes * Display->Bpp, 64);
+
+  if (Destination.Width * Display->Bpp == ModeStrideBytes) {
+    DestAddr = (UINT8*)Display->FbGMAddr + Destination.Y * ModeStrideBytes;
+    DestBytes = Destination.Width * Display->Bpp * Destination.Height;
+    SetMem32 ((VOID*)DestAddr, DestBytes, BltPixel.Raw);
+  } else {
+
+    for (Line = 0; Line < Destination.Height; Line++) {
+      DestAddr = (UINT8*)Display->FbGMAddr +
+        (Line + Destination.Y) * ModeStrideBytes +
+        Destination.X * Display->Bpp;
+      DestBytes = Destination.Width * Display->Bpp;
+
+      SetMem32 (DestAddr, DestBytes, BltPixel.Raw);
+    }
+  }
+
+  Status = EFI_SUCCESS;
+
+Done:
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
+
+EFI_STATUS
+IntelVirtualGpuBltVideoToBuffer (
+  IN PINTEL_VIRTUAL_GPU_DISPLAY    Display,
+  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
+  IN BLT_RECTANGLE                 Source,
+  IN BLT_RECTANGLE                 Destination,
+  IN UINTN                         Delta
+  )
+{
+  EFI_STATUS Status = EFI_INVALID_PARAMETER;
+  VOID       *SourceAddr, *DestAddr;
+  UINTN      DestStride, CopyBytes, ModeStrideBytes, Line;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  if (Source.Width == 0 || Source.Height == 0) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "EfiBltVideoToBltBuffer invalid source rectangle [%d, %d] \n",
+      Source.Width, Source.Height
+      );
+    goto Done;
+  }
+
+  if (Source.Width != Destination.Width ||
+      Source.Height != Destination.Height) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "EfiBltVideoToBltBuffer size mismatch: source %dx%d, destination %dx%d\n",
+      Source.Width, Source.Height, Destination.Width, Destination.Height
+      );
+    goto Done;
+  }
+
+  if ((Source.X + Source.Width > Display->Width) ||
+      (Source.Y + Source.Height > Display->Height)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "EfiBltVideoToBltBuffer source [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
+      Source.X, Source.Y,
+      Source.X + Source.Width, Source.Y + Source.Height,
+      Display->Width, Display->Height
+      );
+    goto Done;
+  }
+
+  if (Destination.X != 0 || Destination.Y != 0) {
+    DestStride = Delta;
+  } else {
+    DestStride = Destination.Width * Display->Bpp;
+  }
+
+  if (Display->CurrentMode == DISPLAY_MODE_INVALID) {
+    ModeStrideBytes = Display->Width;
+  } else {
+    ModeStrideBytes = Display->ModeList[Display->CurrentMode].HorizontalResolution;
+  }
+  ModeStrideBytes = ALIGN_VALUE (ModeStrideBytes * Display->Bpp, 64);
+
+  for (Line = 0; Line < Source.Height; Line++) {
+    SourceAddr = (UINT8*)Display->FbGMAddr +
+      (Source.Y + Line) * ModeStrideBytes +
+      Source.X * Display->Bpp;
+    DestAddr = (UINT8*)BltBuffer + (Destination.Y + Line) * DestStride;
+    DestAddr = (UINT8*)DestAddr + Destination.X * Display->Bpp;
+    CopyBytes = Source.Width * Display->Bpp;
+    CopyMem (DestAddr, SourceAddr, CopyBytes);
+  }
+
+  GVT_DEBUG (EFI_D_VERBOSE,
+    "EfiBltVideoToBltBuffer [%d, %d] >> [%d, %d] size [%d, %d] Delta %d\n",
+    Source.X, Source.Y,
+    Destination.X, Destination.Y,
+    Source.Width, Source.Height,
+    Delta
+    );
+
+  Status = EFI_SUCCESS;
+
+Done:
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
+
+EFI_STATUS
+IntelVirtualGpuBltVideoFromBuffer (
+  IN PINTEL_VIRTUAL_GPU_DISPLAY    Display,
+  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
+  IN BLT_RECTANGLE                 Source,
+  IN BLT_RECTANGLE                 Destination,
+  IN UINTN                         Delta
+  )
+{
+  EFI_STATUS Status = EFI_INVALID_PARAMETER;
+  VOID       *SourceAddr, *DestAddr;
+  UINTN      SourceStride, CopyBytes, ModeStrideBytes, Line;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  if (Source.Width == 0 || Source.Height == 0) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "EfiBltBufferToVideo invalid source rectangle [%d, %d] \n",
+      Source.Width, Source.Height
+      );
+    goto Done;
+  }
+
+  if (Source.Width != Destination.Width || Source.Height != Destination.Height) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "EfiBltBufferToVideo size mismatch: source %dx%d, destination %dx%d\n",
+      Source.Width, Source.Height, Destination.Width, Destination.Height
+      );
+    goto Done;
+  }
+
+  if ((Destination.X + Destination.Width > Display->Width) ||
+      (Destination.Y + Destination.Height > Display->Height)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "EfiBltBufferToVideo destination [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
+      Destination.X, Destination.Y,
+      Destination.X + Destination.Width, Destination.Y + Destination.Height,
+      Display->Width, Display->Height
+      );
+    goto Done;
+  }
+
+  if (Source.X != 0 || Source.Y != 0) {
+    SourceStride = Delta;
+  } else {
+    SourceStride = Source.Width * Display->Bpp;
+  }
+
+  if (Display->CurrentMode == DISPLAY_MODE_INVALID) {
+    ModeStrideBytes = Display->Width;
+  } else {
+    ModeStrideBytes = Display->ModeList[Display->CurrentMode].HorizontalResolution;
+  }
+  ModeStrideBytes = ALIGN_VALUE (ModeStrideBytes * Display->Bpp, 64);
+
+  for (Line = 0; Line < Source.Height; Line++) {
+    SourceAddr = (UINT8*)BltBuffer +
+      (Source.Y + Line) * SourceStride +
+      Source.X * Display->Bpp;
+    DestAddr = (UINT8*)Display->FbGMAddr +
+      (Destination.Y + Line) * ModeStrideBytes +
+      Destination.X * Display->Bpp;
+    CopyBytes = Source.Width * Display->Bpp;
+    CopyMem (DestAddr, SourceAddr, CopyBytes);
+  }
+
+  GVT_DEBUG (EFI_D_VERBOSE, "EfiBltBufferToVideo [%d, %d] >> [%d, %d] size [%d, %d] Delta %d\n",
+    Source.X, Source.Y,
+    Destination.X, Destination.Y,
+    Source.Width, Source.Height,
+    Delta
+    );
+
+  Status = EFI_SUCCESS;
+
+Done:
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
+
+EFI_STATUS
+IntelVirtualGpuBltVideoToVideo (
+  IN PINTEL_VIRTUAL_GPU_DISPLAY Display,
+  IN BLT_RECTANGLE              Source,
+  IN BLT_RECTANGLE              Destination
+  )
+{
+  EFI_STATUS Status = EFI_INVALID_PARAMETER;
+  VOID       *SourceAddr, *DestAddr;
+  UINTN      CopyBytes, ModeStrideBytes, Line;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  if (Source.Width == 0 || Source.Height == 0) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "EfiBltVideoToVideo invalid source rectangle [%d, %d] \n",
+      Source.Width, Source.Height
+      );
+    goto Done;
+  }
+
+  if (Source.Width != Destination.Width || Source.Height != Destination.Height) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "EfiBltVideoToVideo size mismatch: source %dx%d, destination %dx%d\n",
+      Source.Width, Source.Height, Destination.Width, Destination.Height
+      );
+    goto Done;
+  }
+
+  if ((Source.X + Source.Width > Display->Width) ||
+      (Source.Y + Source.Height > Display->Height)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "EfiBltVideoToVideo source [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
+      Source.X, Source.Y,
+      Source.X + Source.Width, Source.Y + Source.Height,
+      Display->Width, Display->Height
+      );
+    goto Done;
+  }
+
+  if ((Destination.X + Destination.Width > Display->Width) ||
+      (Destination.Y + Destination.Height > Display->Height)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "EfiBltVideoToVideo destination [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
+      Destination.X, Destination.Y,
+      Destination.X + Destination.Width, Destination.Y + Destination.Height,
+      Display->Width, Display->Height
+      );
+    goto Done;
+  }
+
+  if (Display->CurrentMode == DISPLAY_MODE_INVALID) {
+    ModeStrideBytes = Display->Width;
+  } else {
+    ModeStrideBytes = Display->ModeList[Display->CurrentMode].HorizontalResolution;
+  }
+  ModeStrideBytes = ALIGN_VALUE (ModeStrideBytes * Display->Bpp, 64);
+
+  for (Line = 0; Line < Source.Height; Line++) {
+    SourceAddr = (UINT8*)Display->FbGMAddr +
+      (Source.Y + Line) * ModeStrideBytes +
+      Source.X * Display->Bpp;
+    DestAddr = (UINT8*)Display->FbGMAddr +
+      (Destination.Y + Line)* ModeStrideBytes +
+      Destination.X * Display->Bpp;
+    CopyBytes = Source.Width * Display->Bpp;
+    //
+    // Overlap could corrupt source content:
+    // src <----|---->
+    // dst      <----|---->
+    //
+    if (DestAddr > SourceAddr && DestAddr < (SourceAddr + CopyBytes)) {
+      CopyMem (
+        SourceAddr + CopyBytes,
+        DestAddr,
+        SourceAddr + CopyBytes - DestAddr
+        );
+      CopyMem (DestAddr, SourceAddr, DestAddr - SourceAddr);
+    //
+    // Overlap won't corrupt source content:
+    // src      <----|---->
+    // dst <----|---->
+    //
+    // No overlap
+    // src <--------->
+    // dst                         <--------->
+    //
+    } else {
+      CopyMem (DestAddr, SourceAddr, CopyBytes);
+    }
+  }
+
+  Status = EFI_SUCCESS;
+
+Done:
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
diff --git a/OvmfPkg/IntelGvtGopDxe/Display.h b/OvmfPkg/IntelGvtGopDxe/Display.h
new file mode 100644
index 000000000000..19e4d64f3b12
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/Display.h
@@ -0,0 +1,141 @@
+/** @file
+  Component name for the QEMU video controller.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __DISPLAY_H_
+#define __DISPLAY_H_
+
+#include <Library/FrameBufferBltLib.h>
+
+typedef struct _BLT_RECTANGLE {
+  UINTN X;
+  UINTN Y;
+  UINTN Width;
+  UINTN Height;
+} BLT_RECTANGLE, *PBLT_RECTANGLE;
+
+#define DISPLAY_WIDTH_MAX      1920
+#define DISPLAY_HEIGHT_MAX     1080
+#define DISPLAY_WIDTH_DEFAULT  1024
+#define DISPLAY_HEIGHT_DEFAULT 768
+#define DISPLAY_MODE_INVALID   0xFFFF
+
+#define DISPLAY_USE_INTERNAL_BLT 1
+
+typedef struct _INTEL_VIRTUAL_GPU_DISPLAY {
+  UINTN                                HActive;
+  UINTN                                VActive;
+  UINTN                                Width;
+  UINTN                                Height;
+  UINTN                                WidthBytes;
+  UINTN                                StrideBytes;
+  EFI_GRAPHICS_PIXEL_FORMAT            Format;
+  UINTN                                Bpp;
+  UINTN                                MaxMode;
+  UINTN                                CurrentMode;
+  UINTN                                FbSize;
+  UINTN                                Pages;
+  EFI_PHYSICAL_ADDRESS                 FbGMAddr;
+  EFI_PHYSICAL_ADDRESS                 FbPhysicalAddr;
+  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeList;
+  FRAME_BUFFER_CONFIGURE               *FrameBufferBltConfigure;
+  UINTN                                FrameBufferBltConfigureSize;
+} INTEL_VIRTUAL_GPU_DISPLAY, *PINTEL_VIRTUAL_GPU_DISPLAY;
+
+EFI_STATUS
+IntelVirtualGpuDisplayInit (
+  IN OUT GVT_GOP_PRIVATE_DATA *Private
+  );
+
+EFI_STATUS
+IntelVirtualGpuDisplayClean (
+  IN OUT GVT_GOP_PRIVATE_DATA *Private
+  );
+
+EFI_STATUS
+EFIAPI
+IntelVirtualGpuQueryMode (
+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL         *This,
+  IN  UINT32                               ModeNumber,
+  OUT UINTN                                *SizeOfInfo,
+  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+  );
+
+EFI_STATUS
+EFIAPI
+IntelVirtualGpuSetMode (
+  IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+  IN UINT32                       ModeNumber
+  );
+
+EFI_STATUS
+EFIAPI
+IntelVirtualGpuBlt (
+  IN EFI_GRAPHICS_OUTPUT_PROTOCOL      *This,
+  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *BltBuffer,   OPTIONAL
+  IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+  IN UINTN                             SourceX,
+  IN UINTN                             SourceY,
+  IN UINTN                             DestinationX,
+  IN UINTN                             DestinationY,
+  IN UINTN                             Width,
+  IN UINTN                             Height,
+  IN UINTN                             Delta         OPTIONAL
+  );
+
+EFI_STATUS
+IntelVirtualGpuEnableDisplay (
+  IN OUT GVT_GOP_PRIVATE_DATA *Private,
+  IN     UINT32               ModeNumber,
+  IN     BOOLEAN              Enable
+  );
+
+EFI_STATUS
+IntelVirtualGpuNotifyDisplayReady (
+  IN GVT_GOP_PRIVATE_DATA *Private,
+  IN BOOLEAN              Ready
+  );
+
+EFI_STATUS
+IntelVirtualGpuBltVideoFill (
+  IN PINTEL_VIRTUAL_GPU_DISPLAY          Display,
+  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION BltPixel,
+  IN BLT_RECTANGLE                       Destination
+  );
+
+EFI_STATUS
+IntelVirtualGpuBltVideoToBuffer (
+  IN PINTEL_VIRTUAL_GPU_DISPLAY    Display,
+  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
+  IN BLT_RECTANGLE                 Source,
+  IN BLT_RECTANGLE                 Destination,
+  IN UINTN                         Delta
+  );
+
+EFI_STATUS
+IntelVirtualGpuBltVideoFromBuffer (
+  IN PINTEL_VIRTUAL_GPU_DISPLAY    Display,
+  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
+  IN BLT_RECTANGLE                 Source,
+  IN BLT_RECTANGLE                 Destination,
+  IN UINTN                         Delta
+  );
+
+EFI_STATUS
+IntelVirtualGpuBltVideoToVideo (
+  IN PINTEL_VIRTUAL_GPU_DISPLAY Display,
+  IN BLT_RECTANGLE              Source,
+  IN BLT_RECTANGLE              Destination
+  );
+VOID
+InstallVbeShim (
+  IN CONST CHAR16         *CardName,
+  IN EFI_PHYSICAL_ADDRESS FrameBufferBase
+  );
+
+#endif //__DISPLAY_H_
diff --git a/OvmfPkg/IntelGvtGopDxe/GopDriver.c b/OvmfPkg/IntelGvtGopDxe/GopDriver.c
new file mode 100644
index 000000000000..396e5cf4447c
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/GopDriver.c
@@ -0,0 +1,478 @@
+/** @file
+  Component name for the QEMU video controller.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Common.h"
+#include "VirtualGpu.h"
+
+EFI_STATUS
+EFIAPI
+GvtGopComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  );
+
+EFI_STATUS
+EFIAPI
+GvtGopComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  EFI_HANDLE                  ControllerHandle,
+  IN  EFI_HANDLE                  ChildHandle OPTIONAL,
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **ControllerName
+  );
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME_PROTOCOL gGvtGopDriverComponentName = {
+  GvtGopComponentNameGetDriverName,
+  GvtGopComponentNameGetControllerName,
+  "eng"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME2_PROTOCOL gGvtGopDriverComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GvtGopComponentNameGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GvtGopComponentNameGetControllerName,
+  "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_UNICODE_STRING_TABLE gGvtGopDriverNameTable[] = {
+  { "eng;en", L"Intel GVT-g GOP Driver" },
+  { NULL , NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_UNICODE_STRING_TABLE gGvtGopControllerNameTable[] = {
+  { "eng;en", L"Intel GVT-g Virtual GPU PCI Adapter" },
+  { NULL , NULL }
+};
+
+STATIC
+EFI_STATUS
+EFIAPI
+GvtGopBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
+  )
+{
+  EFI_STATUS          Status;
+  EFI_PCI_IO_PROTOCOL *PciIo;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **) &PciIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_VERBOSE,
+      "OpenProtocol gEfiPciIoProtocolGuid failed with %d\n", Status
+      );
+    goto Done;
+  }
+
+  Status = IntelVirtualGpuActive (PciIo);
+
+  gBS->CloseProtocol (
+        ControllerHandle,
+        &gEfiPciIoProtocolGuid,
+        This->DriverBindingHandle,
+        ControllerHandle
+        );
+
+Done:
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+  return Status;
+}
+
+
+STATIC
+EFI_STATUS
+EFIAPI
+GvtGopBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
+  )
+{
+  EFI_STATUS               Status;
+  EFI_TPL                  OriginalTPL;
+  GVT_GOP_PRIVATE_DATA     *GvtGopPrivate = NULL;
+  UINT64                   PciAttr;
+  EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+  ACPI_ADR_DEVICE_PATH     AcpiDeviceNode;
+  EFI_PCI_IO_PROTOCOL      *ChildPciIo;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  OriginalTPL = gBS->RaiseTPL (TPL_CALLBACK);
+
+  Status = gBS->AllocatePool (
+                  EfiBootServicesData,
+                  sizeof(GVT_GOP_PRIVATE_DATA),
+                  (VOID **)&GvtGopPrivate
+                  );
+  if (EFI_ERROR (Status) || GvtGopPrivate == NULL) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "AllocatePool failed for GVT_GOP_PRIVATE_DATA, size %d, status %d\n",
+      sizeof(GVT_GOP_PRIVATE_DATA), Status
+      );
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
+
+  ZeroMem (GvtGopPrivate, sizeof(GVT_GOP_PRIVATE_DATA));
+  GvtGopPrivate->Signature = GVT_GOP_MAGIC;
+
+  Status = gBS->AllocatePool (
+                  EfiBootServicesData,
+                  sizeof(INTEL_VIRTUAL_GPU),
+                  &GvtGopPrivate->VirtualGpu
+                  );
+  if (EFI_ERROR (Status) || GvtGopPrivate->VirtualGpu == NULL) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "AllocatePool failed for INTEL_VIRTUAL_GPU, size %d, status %d\n",
+      sizeof(INTEL_VIRTUAL_GPU), Status
+      );
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Free;
+  }
+  ZeroMem (GvtGopPrivate->VirtualGpu, sizeof(INTEL_VIRTUAL_GPU));
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **) &GvtGopPrivate->PciIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Can't open protocol gEfiPciIoProtocolGuid, status %d\n", Status
+      );
+    goto Free;
+  }
+
+  Status = GvtGopPrivate->PciIo->Attributes (
+                                   GvtGopPrivate->PciIo,
+                                   EfiPciIoAttributeOperationGet,
+                                   0,
+                                   &GvtGopPrivate->OriginalPciAttr
+                                   );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Failed EfiPciIoAttributeOperationGet, status %d\n", Status
+      );
+    goto Free;
+  }
+
+  PciAttr = EFI_PCI_DEVICE_ENABLE;
+  Status = GvtGopPrivate->PciIo->Attributes (
+                                   GvtGopPrivate->PciIo,
+                                   EfiPciIoAttributeOperationEnable,
+                                   PciAttr,
+                                   NULL);
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Failed EfiPciIoAttributeOperationEnable %llx, status %d\n", PciAttr,
+      Status
+      );
+    goto Free;
+  }
+
+  Status = IntelVirtualGpuInit (GvtGopPrivate);
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR, "Failed IntelVirtualGpuInit, status %d\n", Status);
+    goto Free;
+  }
+
+  Status = gBS->HandleProtocol (
+                  ControllerHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID **) &ParentDevicePath
+                  );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR, "Fail gEfiDevicePathProtocolGuid, status %d\n",
+      Status
+      );
+    goto Free;
+  }
+
+  ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
+  AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
+  AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
+  AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL, 0, 0);
+  SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
+  GvtGopPrivate->GopDevPath = AppendDevicePathNode (
+                                ParentDevicePath,
+                                (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
+                                );
+  if (GvtGopPrivate->GopDevPath == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    GVT_DEBUG (EFI_D_ERROR, "Fail AppendDevicePathNode, status %d\n", Status);
+    goto Free;
+  }
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &GvtGopPrivate->Handle,
+                  &gEfiDevicePathProtocolGuid,
+                  GvtGopPrivate->GopDevPath,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Can't install protocol gEfiDevicePathProtocolGuid, status %d\n",
+      Status
+      );
+    goto Free;
+  }
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &GvtGopPrivate->Handle,
+                  &gEfiGraphicsOutputProtocolGuid,
+                  &GvtGopPrivate->GraphicsOutputProtocol,
+                  NULL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Can't install protocol gEfiGraphicsOutputProtocolGuid, status %d\n",
+      Status
+      );
+    goto Free;
+  }
+
+  Status = gBS->OpenProtocol (
+                ControllerHandle,
+                &gEfiPciIoProtocolGuid,
+                (VOID **) &ChildPciIo,
+                This->DriverBindingHandle,
+                GvtGopPrivate->Handle,
+                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                );
+  if (EFI_ERROR (Status)) {
+    goto Free;
+  }
+
+  goto Done;
+
+Free:
+  if (GvtGopPrivate->PciIo) {
+    if (GvtGopPrivate->OriginalPciAttr) {
+      GvtGopPrivate->PciIo->Attributes (
+                              GvtGopPrivate->PciIo,
+                              EfiPciIoAttributeOperationEnable,
+                              GvtGopPrivate->OriginalPciAttr,
+                              NULL
+                              );
+    }
+    gBS->CloseProtocol (
+           ControllerHandle,
+           &gEfiPciIoProtocolGuid,
+           This->DriverBindingHandle,
+           ControllerHandle
+           );
+    GvtGopPrivate->PciIo = NULL;
+  }
+
+  if (GvtGopPrivate->VirtualGpu) {
+    gBS->FreePool (GvtGopPrivate->VirtualGpu);
+    GvtGopPrivate->VirtualGpu = NULL;
+  }
+
+  if (GvtGopPrivate) {
+    gBS->FreePool (GvtGopPrivate);
+  }
+
+  if (GvtGopPrivate->GopDevPath) {
+    FreePool (GvtGopPrivate->GopDevPath);
+    GvtGopPrivate->GopDevPath = NULL;
+  }
+
+Done:
+
+  gBS->RestoreTPL (OriginalTPL);
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
+
+
+STATIC
+EFI_STATUS
+EFIAPI
+GvtGopBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN  EFI_HANDLE                  ControllerHandle,
+  IN  UINTN                       NumberOfChildren,
+  IN  EFI_HANDLE                  *ChildHandleBuffer OPTIONAL
+  )
+{
+  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol;
+  EFI_STATUS                   Status;
+  GVT_GOP_PRIVATE_DATA         *GvtGopPrivate = NULL;
+
+  GVT_DEBUG (EFI_D_INFO, "%a: >>>\n", __FUNCTION__);
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiGraphicsOutputProtocolGuid,
+                  (VOID **)&GraphicsOutputProtocol,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_NOT_STARTED;
+    goto Done;
+  }
+
+  GvtGopPrivate = GVT_GOP_PRIVATE_DATA_FROM_THIS (GraphicsOutputProtocol);
+  if (!GvtGopPrivate) {
+    Status = EFI_NOT_STARTED;
+    GVT_DEBUG (EFI_D_ERROR,
+      "Intel GVT-g GOP isn't started, status %d\n", Status
+      );
+    goto Done;
+  }
+
+  gBS->UninstallMultipleProtocolInterfaces (
+         GvtGopPrivate->Handle,
+         &gEfiGraphicsOutputProtocolGuid,
+         &GvtGopPrivate->GraphicsOutputProtocol,
+         NULL
+         );
+
+  if (GvtGopPrivate->PciIo) {
+    gBS->CloseProtocol (
+           ControllerHandle,
+           &gEfiPciIoProtocolGuid,
+           This->DriverBindingHandle,
+           ControllerHandle
+           );
+    GvtGopPrivate->PciIo = NULL;
+  }
+
+  Status = IntelVirtualGpuClean (GvtGopPrivate);
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR, "Fail to clean virtual GPU, status %d\n", Status);
+    goto Done;
+  }
+
+  if (GvtGopPrivate->VirtualGpu) {
+    gBS->FreePool (GvtGopPrivate->VirtualGpu);
+    GvtGopPrivate->VirtualGpu = NULL;
+  }
+
+  if (GvtGopPrivate) {
+    gBS->FreePool (GvtGopPrivate);
+  }
+
+Done:
+
+  GVT_DEBUG (EFI_D_INFO, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
+
+STATIC EFI_DRIVER_BINDING_PROTOCOL gGvtGopDriverBinding = {
+  GvtGopBindingSupported,
+  GvtGopBindingStart,
+  GvtGopBindingStop,
+  0x10,
+  NULL,
+  NULL
+};
+
+EFI_STATUS
+EFIAPI
+GvtGopComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           gGvtGopDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gGvtGopDriverComponentName)
+           );
+}
+
+EFI_STATUS
+EFIAPI
+GvtGopComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  EFI_HANDLE                  ControllerHandle,
+  IN  EFI_HANDLE                  ChildHandle OPTIONAL,
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **ControllerName
+  )
+{
+  EFI_STATUS Status;
+
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = EfiTestManagedDevice (
+             ControllerHandle,
+             gGvtGopDriverBinding.DriverBindingHandle,
+             &gEfiPciIoProtocolGuid
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           gGvtGopControllerNameTable,
+           ControllerName,
+           (BOOLEAN)(This == &gGvtGopDriverComponentName)
+           );
+}
+
+EFI_STATUS
+EFIAPI
+GvtGopEntryPoint (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  EFI_STATUS Status;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle,
+             SystemTable,
+             &gGvtGopDriverBinding,
+             ImageHandle,
+             &gGvtGopDriverComponentName,
+             &gGvtGopDriverComponentName2);
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR, "Failed to install driver %d : %d\n", Status);
+  }
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
diff --git a/OvmfPkg/IntelGvtGopDxe/GpuReg.c b/OvmfPkg/IntelGvtGopDxe/GpuReg.c
new file mode 100644
index 000000000000..778c09d5198c
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/GpuReg.c
@@ -0,0 +1,91 @@
+/** @file
+  Component name for the QEMU video controller.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "GpuReg.h"
+
+EFI_STATUS
+RegRead32 (
+  IN  GVT_GOP_PRIVATE_DATA *Private,
+  IN  UINT32 Offset,
+  OUT UINT32 *ValuePtr
+  )
+{
+  EFI_STATUS Status = EFI_INVALID_PARAMETER;
+
+  if (Offset < MMIO_SIZE && ValuePtr != NULL) {
+    Status = Private->PciIo->Mem.Read (
+                          Private->PciIo,
+                          EfiPciIoWidthUint32,
+                          PCI_BAR_IDX0,
+                          Offset,
+                          1,
+                          ValuePtr
+                          );
+    if (EFI_ERROR (Status)) {
+      GVT_DEBUG (EFI_D_ERROR, "%a reg %x, value %x, status %d\n",
+        __FUNCTION__, Offset, *ValuePtr, Status
+        );
+    } else {
+      Status = EFI_SUCCESS;
+      GVT_DEBUG (EFI_D_VERBOSE, "%a reg %x, value %x, status %d\n",
+        __FUNCTION__, Offset, *ValuePtr, Status
+        );
+    }
+  } else {
+    Status = EFI_INVALID_PARAMETER;
+    GVT_DEBUG (EFI_D_ERROR,
+      "%a invalid reg %x or ValuePtr %p, status %d\n",
+      __FUNCTION__, Offset, ValuePtr, Status
+      );
+    goto Done;
+  }
+
+Done:
+  return Status;
+}
+
+EFI_STATUS
+RegWrite32 (
+  IN GVT_GOP_PRIVATE_DATA *Private,
+  IN UINT32 Offset,
+  IN UINT32 Value
+  )
+{
+  EFI_STATUS Status = EFI_INVALID_PARAMETER;
+
+  if (Offset < MMIO_SIZE) {
+    Status = Private->PciIo->Mem.Write (
+                          Private->PciIo,
+                          EfiPciIoWidthUint32,
+                          PCI_BAR_IDX0,
+                          Offset,
+                          1,
+                          &Value
+                          );
+    if (EFI_ERROR (Status)) {
+      GVT_DEBUG (EFI_D_ERROR, "%a reg %x, value %x, status %d\n",
+        __FUNCTION__, Offset, Value, Status
+        );
+    } else {
+      Status = EFI_SUCCESS;
+      GVT_DEBUG (EFI_D_VERBOSE, "%a reg %x, value %x, status %d\n",
+        __FUNCTION__, Offset, Value, Status
+        );
+    }
+  } else {
+    Status = EFI_INVALID_PARAMETER;
+    GVT_DEBUG (EFI_D_ERROR, "%a invalid reg %x, status %d\n",
+      __FUNCTION__, Offset, Status
+      );
+    goto Done;
+  }
+
+Done:
+  return Status;
+}
diff --git a/OvmfPkg/IntelGvtGopDxe/GpuReg.h b/OvmfPkg/IntelGvtGopDxe/GpuReg.h
new file mode 100644
index 000000000000..f46f4cef9cd4
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/GpuReg.h
@@ -0,0 +1,175 @@
+/** @file
+  Component name for the QEMU video controller.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __GPUREG_H_
+#define __GPUREG_H_
+
+#include "Common.h"
+
+#define MMIO_SIZE 0x200000
+
+#define VGT_PVINFO_PAGE 0x78000
+#define VGT_PVINFO_SIZE 0x1000
+
+#define VGT_MAGIC         0x4776544776544776ULL  /* 'vGTvGTvG' */
+#define VGT_VERSION_MAJOR 1
+#define VGT_VERSION_MINOR 0
+
+#define VGT_DRV_DISPLAY_NOT_READY 0
+#define VGT_DRV_DISPLAY_READY     1
+
+struct vgt_if {
+  UINT64 magic;    /* VGT_MAGIC */
+  UINT16 version_major;
+  UINT16 version_minor;
+  UINT32 vgt_id;    /* ID of vGT instance */
+  UINT32 vgt_caps;    /* VGT capabilities */
+  UINT32 rsv1[11];    /* pad to offset 0x40 */
+  /*
+   *  Data structure to describe the balooning info of resources.
+   *  Each VM can only have one portion of continuous area for now.
+   *  (May support scattered resource in future)
+   *  (starting from offset 0x40)
+   */
+  struct {
+    /* Aperture register balooning */
+    struct {
+      UINT32 base;
+      UINT32 size;
+    } mappable_gmadr;  /* aperture */
+    /* GMADR register balooning */
+    struct {
+      UINT32 base;
+      UINT32 size;
+    } nonmappable_gmadr;  /* non aperture */
+    /* allowed fence registers */
+    UINT32 fence_num;
+    UINT32 rsv2[3];
+  } avail_rs;    /* available/assigned resource */
+  UINT32 rsv3[0x200 - 24];  /* pad to half page */
+  /*
+   * The bottom half page is for response from Gfx driver to hypervisor.
+   */
+  UINT32 rsv4;
+  UINT32 display_ready;  /* ready for display owner switch */
+
+  UINT32 rsv5[4];
+
+  UINT32 g2v_notify;
+  UINT32 rsv6[5];
+
+  UINT32 cursor_x_hot;
+  UINT32 cursor_y_hot;
+
+  struct {
+    UINT32 lo;
+    UINT32 hi;
+  } pdp[4];
+
+  UINT32 execlist_context_descriptor_lo;
+  UINT32 execlist_context_descriptor_hi;
+
+  UINT32  rsv7[0x200 - 24];    /* pad to one page */
+} PACKED;
+
+#define vgtif_offset(x) (OFFSET_OF(struct vgt_if, x))
+#define vgtif_reg(x) (VGT_PVINFO_PAGE + vgtif_offset(x))
+
+typedef enum _GPU_DISPLAY_PIPE {
+  PIPE_INVALID = -1,
+  PIPE_A = 0,
+  PIPE_B,
+  PIPE_C,
+  PIPE_MAX = PIPE_C
+} GPU_DISPLAY_PIPE;
+
+typedef enum _GPU_DISPLAY_PLANE {
+  PLANE_PRIMARY = 0,
+  PLANE_SPRITE0,
+  PLANE_SPRITE1,
+  PLANE_MAX,
+} GPU_DISPLAY_PLANE;
+
+#define _TRANS_HTOTAL_A 0x60000
+#define _TRANS_VTOTAL_A 0x6000C
+#define _TRANS_REG_OFFSET(trans) (trans * 0x1000)
+
+#define _PS_WIN_POS_1_A 0x68170
+#define _PS_WIN_SZ_1_A 0x68174
+#define _PS_CTRL_1_A 0x68180
+#define _PS_REG_OFFSET(pipe, id) (pipe * 0x800 + id * 0x100)
+#define PS_WIN_POS(pipe, id) (_PS_WIN_POS_1_A + _PS_REG_OFFSET(pipe, id))
+#define PS_WIN_SZ(pipe, id) (_PS_WIN_SZ_1_A + _PS_REG_OFFSET(pipe, id))
+#define PS_CTRL(pipe, id) (_PS_CTRL_1_A + _PS_REG_OFFSET(pipe, id))
+#define   PS_CTRL_SCALER_EN (1 << 31)
+#define   PS_CTRL_SCALER_MODE_MASK (0x3 << 28)
+#define   PS_CTRL_SCALER_MODE_DYN  (0 << 28)
+#define   PS_CTRL_SCALER_MODE_HQ  (1 << 28)
+#define   PS_CTRL_SCALER_BINDING_MASK  (0x7 << 25)
+#define   PS_CTRL_SCALER_BINDING_PIPE  (0 << 25)
+#define   PS_CTRL_PLANE_SEL(plane) (((plane) + 1) << 25)
+#define   PS_CTRL_SCALER_FILTER_MASK         (3 << 23)
+#define   PS_CTRL_SCALER_FILTER_MEDIUM       (0 << 23)
+
+#define PIPE_REG_OFFSET(pipe) (pipe * 0x1000)
+#define _PIPE_CONF_A 0x70008
+#define   PIPE_CONF_ENABLE (1 << 31)
+#define _PIPE_SRCSZ_A 0x6001C
+#define PIPE_CONF(pipe) (_PIPE_CONF_A + PIPE_REG_OFFSET(pipe))
+#define PIPESRC(pipe) (_PIPE_SRCSZ_A + PIPE_REG_OFFSET(pipe))
+
+#define _PLANE_CTL_1_A 0x70180
+#define   PLANE_CTL_ENABLE (1 << 31)
+#define   PLANE_CTL_PIPE_GAMMA_ENABLE (1 << 30)
+#define   PLANE_CTL_FORMAT_MASK (0xF << 24)
+#define   PLANE_CTL_FORMAT_XRGB_8888 (0x4 << 24)
+#define   PLANE_CTL_PIPE_CSC_ENABLE (1 << 23)
+#define   PLANE_CTL_KEY_ENABLE_MASK (0x3 << 21)
+#define   PLANE_CTL_ORDER_RGBX (1 << 20)
+#define   PLANE_CTL_RENDER_DECOMPRESSION_ENABLE (1 << 15)
+#define   PLANE_CTL_PLANE_GAMMA_DISABLE (1 << 13)
+#define   PLANE_CTL_TILED_MASK (0x7 << 10)
+#define   PLANE_CTL_TILED_LINEAR (0 << 10)
+#define   PLANE_CTL_ASYNC_FLIP (1 << 9)
+#define   PLANE_CTL_ALPHA_MASK (0x3 << 4)
+#define   PLANE_CTL_ALPHA_DISABLE (0 << 4)
+#define   PLANE_CTL_ROTATE_MASK (0x3 << 0)
+#define   PLANE_CTL_ROTATE_0 (0x0 << 0)
+
+#define _PLANE_STRIDE_1_A 0x70188
+#define   PLANE_STRIDE_MASK 0x1FF
+#define _PLANE_POS_1_A  0x7018C
+#define _PLANE_SIZE_1_A 0x70190
+#define _PLANE_SURF_1_A 0x7019C
+#define _PLANE_REG_OFFSET(pipe, plane) (pipe * 0x1000 + plane * 0x100)
+
+#define HTOTAL(trans) (_TRANS_HTOTAL_A + _TRANS_REG_OFFSET(trans))
+#define VTOTAL(trans) (_TRANS_VTOTAL_A + _TRANS_REG_OFFSET(trans))
+
+#define PLANE_CTL(pipe, plane) (_PLANE_CTL_1_A + _PLANE_REG_OFFSET(pipe, plane))
+#define PLANE_STRIDE(pipe, plane) (_PLANE_STRIDE_1_A + _PLANE_REG_OFFSET(pipe, plane))
+#define PLANE_POS(pipe, plane) (_PLANE_POS_1_A + _PLANE_REG_OFFSET(pipe, plane))
+#define PLANE_SIZE(pipe, plane) (_PLANE_SIZE_1_A + _PLANE_REG_OFFSET(pipe, plane))
+#define PLANE_SURF(pipe, plane) (_PLANE_SURF_1_A + _PLANE_REG_OFFSET(pipe, plane))
+
+EFI_STATUS
+RegRead32 (
+  IN  GVT_GOP_PRIVATE_DATA *Private,
+  IN  UINT32 Offset,
+  OUT UINT32 *ValuePtr
+  );
+
+EFI_STATUS
+RegWrite32 (
+  IN GVT_GOP_PRIVATE_DATA *Private,
+  IN UINT32 Offset,
+  IN UINT32 Value
+  );
+
+#endif //__GPUREG_H_
diff --git a/OvmfPkg/IntelGvtGopDxe/Gtt.c b/OvmfPkg/IntelGvtGopDxe/Gtt.c
new file mode 100644
index 000000000000..12782eb5afaa
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/Gtt.c
@@ -0,0 +1,162 @@
+/** @file
+  Component name for the QEMU video controller.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Common.h"
+#include "Gtt.h"
+#include "VirtualGpu.h"
+
+EFI_STATUS
+GGTTGetEntry (
+  IN  GVT_GOP_PRIVATE_DATA *Private,
+  IN  UINT64 Index,
+  OUT GTT_PTE_ENTRY *Entry
+  )
+{
+  EFI_STATUS          Status = EFI_INVALID_PARAMETER;
+  EFI_PCI_IO_PROTOCOL *PciIo;
+  PINTEL_VIRTUAL_GPU  VirtualGpu;
+
+  if (Entry == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    GVT_DEBUG (EFI_D_ERROR,
+      "%a invalid GGTT entry ptr %p at Index %x, status %d\n",
+      __FUNCTION__, Entry, Index, Status
+      );
+    goto Done;
+  }
+
+  PciIo = Private->PciIo;
+  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
+
+  if (Index >= VirtualGpu->VisibleGGTTOffset &&
+       Index < VirtualGpu->VisibleGGTTOffset + VirtualGpu->VisibleGGTTSize) {
+    Status = PciIo->Mem.Read (
+                          PciIo,
+                          EfiPciIoWidthUint64,
+                          PCI_BAR_IDX0,
+                          GTT_OFFSET + Index * GTT_ENTRY_SIZE,
+                          1,
+                          Entry
+                          );
+    if (EFI_ERROR (Status)) {
+      Entry = 0;
+      GVT_DEBUG (EFI_D_ERROR,
+        "Failed to Get GGTT Entry index %lx, status %d\n", Index, Status
+        );
+    }
+  } else if (Index >= VirtualGpu->InvisibleGGTTOffset &&
+             Index < VirtualGpu->InvisibleGGTTOffset + VirtualGpu->InvisibleGGTTSize) {
+    Status = EFI_UNSUPPORTED;
+    GVT_DEBUG (EFI_D_ERROR,
+      "Skip get GGTT index %lx for invisible GMADR\n", Index
+      );
+  } else {
+    Status = EFI_OUT_OF_RESOURCES;
+    GVT_DEBUG (EFI_D_ERROR,
+      "Skip get GGTT index %lx out-of-range, balloon unsupported\n",
+      Index
+      );
+  }
+
+  GVT_DEBUG (EFI_D_VERBOSE, "Get GGTT Entry %lx at index %lx\n", *Entry, Index);
+
+Done:
+
+  return Status;
+}
+
+EFI_STATUS
+GGTTSetEntry (
+  IN GVT_GOP_PRIVATE_DATA *Private,
+  IN UINT64 Index,
+  IN GTT_PTE_ENTRY Entry
+  )
+{
+  EFI_STATUS          Status = EFI_INVALID_PARAMETER;
+  EFI_PCI_IO_PROTOCOL *PciIo;
+  PINTEL_VIRTUAL_GPU  VirtualGpu;
+
+  PciIo = Private->PciIo;
+  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
+
+  if (Index >= VirtualGpu->VisibleGGTTOffset &&
+      Index < VirtualGpu->VisibleGGTTOffset + VirtualGpu->VisibleGGTTSize) {
+    Status = PciIo->Mem.Write (
+                          PciIo,
+                          EfiPciIoWidthUint64,
+                          PCI_BAR_IDX0,
+                          GTT_OFFSET + Index * GTT_ENTRY_SIZE,
+                          1,
+                          &Entry
+                          );
+    if (EFI_ERROR (Status)) {
+      GVT_DEBUG (EFI_D_ERROR,
+        "Failed to Set GGTT Entry %lx at index %lx, status %d\n",
+        Entry, Index, Status
+        );
+    }
+  } else if (Index >= VirtualGpu->InvisibleGGTTOffset &&
+             Index < VirtualGpu->InvisibleGGTTOffset + VirtualGpu->InvisibleGGTTSize) {
+    Status = EFI_UNSUPPORTED;
+    GVT_DEBUG (EFI_D_ERROR,
+      "Skip set GGTT index %lx for invisible GMADR\n", Index
+      );
+  } else {
+    Status = EFI_OUT_OF_RESOURCES;
+    GVT_DEBUG (EFI_D_ERROR,
+      "Skip set GGTT index %lx out-of-range, balloon unsupported\n", Index
+      );
+  }
+
+  GVT_DEBUG (EFI_D_VERBOSE, "Set GGTT Entry %lx at index %lx\n", Entry, Index);
+
+  return Status;
+}
+
+EFI_STATUS
+UpdateGGTT (
+  IN GVT_GOP_PRIVATE_DATA *Private,
+  IN EFI_PHYSICAL_ADDRESS GMAddr,
+  IN EFI_PHYSICAL_ADDRESS SysAddr,
+  IN UINTN                Pages
+  )
+{
+  EFI_STATUS         Status = EFI_INVALID_PARAMETER;
+  PINTEL_VIRTUAL_GPU VirtualGpu;
+  UINTN              GttOffset, Index;
+  GTT_PTE_ENTRY      Entry;
+
+  if (!IS_ALIGNED(SysAddr, GTT_PAGE_SIZE)) {
+    Status = EFI_INVALID_PARAMETER;
+    GVT_DEBUG (EFI_D_ERROR,
+      "Failed to update GGTT GMADR %lx, SysAddr %lx isn't aligned to 0x%lx, status %d\n",
+      GMAddr, SysAddr, GTT_PAGE_SIZE, Status
+      );
+    goto Done;
+  }
+
+  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
+  GttOffset = (GMAddr - VirtualGpu->GpuMemAddr) >> GTT_PAGE_SHIFT;
+
+  GVT_DEBUG (EFI_D_VERBOSE,
+    "Update GGTT GMADR %lx, SysAddr %lx, Pages 0x%lx\n",
+    GMAddr, SysAddr, Pages
+    );
+  for (Index = 0; Index < Pages; Index++) {
+    Entry = SysAddr + Index * GTT_PAGE_SIZE;
+    Entry |= (GTT_PAGE_PRESENT | GTT_PAGE_READ_WRITE);
+    Entry |= (GTT_PAGE_PWT | GTT_PAGE_PCD);
+    GGTTSetEntry (Private, GttOffset + Index, Entry);
+  }
+
+  Status = EFI_SUCCESS;
+
+Done:
+  return Status;
+}
diff --git a/OvmfPkg/IntelGvtGopDxe/Gtt.h b/OvmfPkg/IntelGvtGopDxe/Gtt.h
new file mode 100644
index 000000000000..fc91b7a84a0a
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/Gtt.h
@@ -0,0 +1,51 @@
+/** @file
+  Component name for the QEMU video controller.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __GTT_H_
+#define __GTT_H_
+
+#include "Common.h"
+
+typedef UINT64 GTT_PTE_ENTRY;
+
+#define GTT_OFFSET          0x800000
+#define GTT_SIZE            0x800000
+#define GTT_ENTRY_SIZE      sizeof(GTT_PTE_ENTRY)
+#define GTT_ENTRY_NUM       (GTT_SIZE / GTT_ENTRY_SIZE)
+#define GTT_PAGE_SHIFT      12
+#define GTT_PAGE_SIZE       (1UL << GTT_PAGE_SHIFT)
+#define GTT_PAGE_MASK       (~(GTT_PAGE_SIZE-1))
+#define GTT_PAGE_PRESENT    0x01
+#define GTT_PAGE_READ_WRITE 0x02
+#define GTT_PAGE_PWT        0x08
+#define GTT_PAGE_PCD        0x10
+
+EFI_STATUS
+GGTTGetEntry (
+  IN  GVT_GOP_PRIVATE_DATA *Private,
+  IN  UINT64 Index,
+  OUT GTT_PTE_ENTRY *Entry
+  );
+
+EFI_STATUS
+GGTTSetEntry (
+  IN GVT_GOP_PRIVATE_DATA *Private,
+  IN UINT64 Index,
+  IN GTT_PTE_ENTRY Entry
+  );
+
+EFI_STATUS
+UpdateGGTT (
+  IN GVT_GOP_PRIVATE_DATA *Private,
+  IN EFI_PHYSICAL_ADDRESS GMAddr,
+  IN EFI_PHYSICAL_ADDRESS SysAddr,
+  IN UINTN                Pages
+  );
+
+#endif //__GTT_H_
diff --git a/OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf b/OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf
new file mode 100644
index 000000000000..c6e1751e1a22
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf
@@ -0,0 +1,59 @@
+## @file
+# Intel GVT-g Graphics Output Protocol driver
+#
+# Copyright (C) 2021 Intel Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = GvtGopDxe
+  FILE_GUID                      = 7c2a0c14-2a63-4d08-9c7f-d55691e1cedb
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 2.0
+  ENTRY_POINT                    = GvtGopEntryPoint
+
+[Sources]
+  Common.h
+  DebugHelper.h
+  Display.c
+  Display.h
+  GopDriver.c
+  GpuReg.c
+  GpuReg.h
+  Gtt.c
+  Gtt.h
+  VirtualGpu.h
+  VirtualGpu.c
+  VbeShim.c
+  VbeShim.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  FrameBufferBltLib
+  DebugLib
+  DevicePathLib
+  MemoryAllocationLib
+  PrintLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+  PcdLib
+  PciLib
+  QemuFwCfgLib
+
+[Protocols]
+  gEfiGraphicsOutputProtocolGuid
+  gEfiPciIoProtocolGuid
+  gEfiDevicePathProtocolGuid
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution
diff --git a/OvmfPkg/IntelGvtGopDxe/VbeShim.asm b/OvmfPkg/IntelGvtGopDxe/VbeShim.asm
new file mode 100644
index 000000000000..43a44362b794
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/VbeShim.asm
@@ -0,0 +1,343 @@
+;------------------------------------------------------------------------------
+; @file
+; A minimal Int10h stub that allows the Windows 2008 R2 SP1 UEFI guest's buggy,
+; default VGA driver to switch to 1024x768x32.
+;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; Copyright (C) 2020, Rebecca Cran <rebecca@bsdio.com>
+; Copyright (C) 2015, Nahanni Systems, Inc.
+; Copyright (C) 2014, Red Hat, Inc.
+; Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+;
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+; enable this macro for debug messages
+%define DEBUG
+
+%macro DebugLog 1
+%ifdef DEBUG
+  push       si
+  mov        si, %1
+  call       PrintStringSi
+  pop        si
+%endif
+%endmacro
+
+
+BITS 16
+ORG 0
+
+VbeInfo:
+TIMES 256 nop
+
+VbeModeInfo:
+VbeMode1:
+TIMES 50  nop
+VbeMode2:
+TIMES 50  nop
+VbeMode3:
+TIMES 50  nop
+VbeMode4:
+TIMES 50  nop
+TIMES 56  nop  ; filler for 256 bytes
+
+Handler:
+  cmp        ax, 0x4f00
+  je         GetInfo
+  cmp        ax, 0x4f01
+  je         GetModeInfo
+  cmp        ax, 0x4f02
+  je         SetMode
+  cmp        ax, 0x4f03
+  je         GetMode
+  cmp        ax, 0x4f10
+  je         GetPmCapabilities
+  cmp        ax, 0x4f15
+  je         ReadEdid
+  cmp        ah, 0x00
+  je         SetModeLegacy
+  DebugLog   StrUnkownFunction
+Hang:
+  jmp        Hang
+
+
+GetInfo:
+  push       es
+  push       di
+  push       ds
+  push       si
+  push       cx
+
+  DebugLog   StrEnterGetInfo
+
+  ; target (es:di) set on input
+  push       cs
+  pop        ds
+  mov        si, VbeInfo
+  ; source (ds:si) set now
+
+  mov        cx, 256
+  cld
+  rep movsb
+
+  pop        cx
+  pop        si
+  pop        ds
+  pop        di
+  pop        es
+  jmp        Success
+
+
+GetModeInfo:
+  push       es
+  push       di
+  push       ds
+  push       si
+  push       cx
+
+  DebugLog   StrEnterGetModeInfo
+
+  and        cx, ~0x4000 ; clear potentially set LFB bit in mode number
+
+  cmp        cx, 0x013f
+  je         gKnownMode1
+  cmp        cx, 0x0140
+  je         gKnownMode2
+  cmp        cx, 0x0141
+  je         gKnownMode3
+
+  DebugLog   StrUnkownMode
+  jmp        Hang
+gKnownMode1:
+  DebugLog   StrMode1
+  mov        si, VbeMode1
+  jmp        CopyModeInfo
+gKnownMode2:
+  DebugLog   StrMode2
+  mov        si, VbeMode2
+  jmp        CopyModeInfo
+gKnownMode3:
+  DebugLog   StrMode3
+  mov        si, VbeMode3
+  jmp        CopyModeInfo
+gKnownMode4:
+  DebugLog   StrMode4
+  mov        si, VbeMode4
+  jmp        CopyModeInfo
+
+CopyModeInfo:
+  ; target (es:di) set on input
+  push       cs
+  pop        ds
+  ;mov        si, VbeModeInfo
+  ; source (ds:si) set now
+
+  ;mov        cx, 256
+  mov        cx, 50
+  cld
+  rep movsb
+
+  pop        cx
+  pop        si
+  pop        ds
+  pop        di
+  pop        es
+  jmp        Success
+
+
+SetMode:
+  push       dx
+  push       ax
+
+  DebugLog   StrEnterSetMode
+
+  and        bx, ~0x4000 ; clear potentially set LFB bit in mode number
+  cmp        bx, 0x013f
+  je         KnownMode1
+  cmp        bx, 0x0140
+  je         KnownMode2
+  cmp        bx, 0x0141
+  je         KnownMode3
+  DebugLog   StrUnkownMode
+  jmp        Hang
+KnownMode1:
+  DebugLog   StrMode1
+  jmp        SetModeDone
+KnownMode2:
+  DebugLog   StrMode2
+  jmp        SetModeDone
+KnownMode3:
+  DebugLog   StrMode3
+  jmp        SetModeDone
+KnownMode4:
+  DebugLog   StrMode4
+
+SetModeDone:
+  mov        [CurMode], bl
+  mov        [CurMode+1], bh
+  pop        ax
+  pop        dx
+  jmp        Success
+
+
+GetMode:
+  DebugLog   StrEnterGetMode
+  mov        bl, [CurMode]
+  mov        bh, [CurMode+1]
+  jmp        Success
+
+
+GetPmCapabilities:
+  DebugLog   StrGetPmCapabilities
+  mov        bx, 0x0080
+  jmp        Success
+
+
+ReadEdid:
+  push       es
+  push       di
+  push       ds
+  push       si
+  push       cx
+
+  DebugLog   StrReadEdid
+
+  ; target (es:di) set on input
+  push       cs
+  pop        ds
+  mov        si, Edid
+  ; source (ds:si) set now
+
+  mov        cx, 128
+  cld
+  rep movsb
+
+  pop        cx
+  pop        si
+  pop        ds
+  pop        di
+  pop        es
+  jmp        Success
+
+
+SetModeLegacy:
+  DebugLog   StrEnterSetModeLegacy
+
+  cmp        al, 0x03
+  je         sKnownMode3
+  cmp        al, 0x12
+  je         sKnownMode4
+  DebugLog   StrUnkownMode
+  jmp        Hang
+sKnownMode3:
+  DebugLog   StrLegacyMode3
+  mov        al, 0 ; 0x30
+  jmp        SetModeLegacyDone
+sKnownMode4:
+  mov        al, 0 ;0x20
+SetModeLegacyDone:
+  DebugLog   StrExitSuccess
+  iret
+
+
+Success:
+  DebugLog   StrExitSuccess
+  mov        ax, 0x004f
+  iret
+
+
+Unsupported:
+  DebugLog   StrExitUnsupported
+  mov        ax, 0x024f
+  iret
+
+
+%ifdef DEBUG
+PrintStringSi:
+  pusha
+  push       ds ; save original
+  push       cs
+  pop        ds
+  mov        dx, 0x220             ; bhyve debug cons port
+  mov        ax, 0
+PrintStringSiLoop:
+  lodsb
+  cmp        al, 0
+  je         PrintStringSiDone
+  out        dx, al
+  jmp        PrintStringSiLoop
+PrintStringSiDone:
+  pop        ds ; restore original
+  popa
+  ret
+
+
+StrExitSuccess:
+  db 'vOk', 0x0d, 0x0a, 0
+
+StrExitUnsupported:
+  db 'vUnsupported', 0x0d, 0x0a, 0
+
+StrUnkownFunction:
+  db 'vUnknown Function', 0x0d, 0x0a, 0
+
+StrEnterGetInfo:
+  db 'vGetInfo', 0x0d, 0x0a, 0
+
+StrEnterGetModeInfo:
+  db 'vGetModeInfo', 0x0d, 0x0a, 0
+
+StrEnterGetMode:
+  db 'vGetMode', 0x0d, 0x0a, 0
+
+StrEnterSetMode:
+  db 'vSetMode', 0x0d, 0x0a, 0
+
+StrEnterSetModeLegacy:
+  db 'vSetModeLegacy', 0x0d, 0x0a, 0
+
+StrUnkownMode:
+  db 'vUnkown Mode', 0x0d, 0x0a, 0
+
+StrGetPmCapabilities:
+  db 'vGetPmCapabilities', 0x0d, 0x0a, 0
+
+StrReadEdid:
+  db 'vReadEdid', 0x0d, 0x0a, 0
+
+StrLegacyMode3:
+  db 'vLegacyMode3', 0x0d, 0x0a, 0
+
+
+StrMode1:
+  db 'mode_640x480x32', 0x0d, 0x0a, 0
+StrMode2:
+  db 'mode_800x600x32', 0x0d, 0x0a, 0
+StrMode3:
+  db 'mode_1024x768x32', 0x0d, 0x0a, 0
+StrMode4:
+  db 'mode_unused', 0x0d, 0x0a, 0
+%endif
+
+CurMode:
+  db 0x00, 0x00
+
+;
+; EDID stores monitor information. For now, just send back an null item.
+;
+Edid:
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
diff --git a/OvmfPkg/IntelGvtGopDxe/VbeShim.c b/OvmfPkg/IntelGvtGopDxe/VbeShim.c
new file mode 100644
index 000000000000..8063224d53b4
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/VbeShim.c
@@ -0,0 +1,258 @@
+/** @file
+  Install a fake VGABIOS service handler (real mode Int10h) for the buggy
+  Windows 2008 R2 SP1 UEFI guest.
+
+  The handler is never meant to be directly executed by a VCPU; it's there for
+  the internal real mode emulator of Windows 2008 R2 SP1.
+
+  The code is based on Ralf Brown's Interrupt List:
+  <http://www.cs.cmu.edu/~ralf/files.html>
+  <http://www.ctyme.com/rbrown.htm>
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  Copyright (C) 2020, Rebecca Cran <rebecca@bsdio.com>
+  Copyright (C) 2015, Nahanni Systems, Inc.
+  Copyright (C) 2014, Red Hat, Inc.
+  Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Common.h"
+#include <IndustryStandard/LegacyVgaBios.h>
+#include <Library/PciLib.h>
+#include <Library/PrintLib.h>
+#include "VbeShim.h"
+
+#pragma pack (1)
+typedef struct {
+  UINT16 Offset;
+  UINT16 Segment;
+} IVT_ENTRY;
+#pragma pack ()
+
+//
+// This string is displayed by Windows 2008 R2 SP1 in the Screen Resolution,
+// Advanced Settings dialog. It should be short.
+//
+STATIC CONST CHAR8 mProductRevision[] = "2.0";
+
+#define NUM_VBE_MODES 3
+STATIC CONST UINT16 vbeModeIds[] = {
+  0x13f,  // 640x480x32
+  0x140,  // 800x600x32
+  0x141   // 1024x768x32
+};
+
+// Modes can be toggled with bit-0
+#define VBE_MODE_ENABLED  0x00BB
+#define VBE_MODE_DISABLED 0x00BA
+
+STATIC VBE2_MODE_INFO vbeModes[] = {
+  { // 0x13f 640x480x32
+
+    // ModeAttr - BytesPerScanLine
+    VBE_MODE_DISABLED, 0x07, 0x00, 0x40, 0x40, 0xA000, 0x00, 0x0000, 640*4,
+    // Width, Height..., Vbe3
+    640, 480, 16, 8, 1, 32, 1, 0x06, 0, 0, 1,
+    // Masks
+    0x08, 0x10, 0x08, 0x08, 0x08, 0x00, 0x08, 0x18, 0x00,
+    // Framebuffer
+    0xdeadbeef, 0x0000, 0x0000
+  },
+  { // 0x140 800x600x32
+
+    // ModeAttr - BytesPerScanLine
+    VBE_MODE_DISABLED, 0x07, 0x00, 0x40, 0x40, 0xA000, 0x00, 0x0000, 800*4,
+    // Width, Height..., Vbe3
+    800, 600, 16, 8, 1, 32, 1, 0x06, 0, 0, 1,
+    // Masks
+    0x08, 0x10, 0x08, 0x08, 0x08, 0x00, 0x08, 0x18, 0x00,
+    // Framebuffer
+    0xdeadbeef, 0x0000, 0x0000
+  },
+  { // 0x141 1024x768x32
+
+    // ModeAttr - BytesPerScanLine
+    VBE_MODE_ENABLED, 0x07, 0x00, 0x40, 0x40, 0xA000, 0x00, 0x0000, 1024*4,
+    // Width, Height..., Vbe3
+    1024, 768, 16, 8, 1, 32, 1, 0x06, 0, 0, 1,
+    // Masks
+    0x08, 0x10, 0x08, 0x08, 0x08, 0x00, 0x08, 0x18, 0x00,
+    // Framebuffer
+    0xdeadbeef, 0x0000, 0x0000
+  }
+};
+
+/**
+  Install the VBE Info and VBE Mode Info structures, and the VBE service
+  handler routine in the C segment. Point the real-mode Int10h interrupt vector
+  to the handler. The only advertised mode is 1024x768x32.
+
+  @param[in] CardName         Name of the video card to be exposed in the
+                              Product Name field of the VBE Info structure.
+  @param[in] FrameBufferBase  Guest-physical base address of the video card's
+                              frame buffer.
+**/
+VOID
+InstallVbeShim (
+  IN CONST CHAR16         *CardName,
+  IN EFI_PHYSICAL_ADDRESS FrameBufferBase
+  )
+{
+  EFI_PHYSICAL_ADDRESS Segment0, SegmentC, SegmentF;
+  UINTN                Segment0Pages;
+  IVT_ENTRY            *Int0x10;
+  EFI_STATUS           Status;
+  UINTN                Pam1Address;
+  UINT8                Pam1;
+  UINTN                SegmentCPages;
+  VBE_INFO             *VbeInfoFull;
+  VBE_INFO_BASE        *VbeInfo;
+  UINT8                *Ptr;
+  UINTN                Printed;
+  VBE_MODE_INFO        *VbeModeInfo;
+  UINTN                i;
+
+  Segment0 = 0x00000;
+  SegmentC = 0xC0000;
+  SegmentF = 0xF0000;
+
+  //
+  // Attempt to cover the real mode IVT with an allocation. This is a UEFI
+  // driver, hence the arch protocols have been installed previously. Among
+  // those, the CPU arch protocol has configured the IDT, so we can overwrite
+  // the IVT used in real mode.
+  //
+  // The allocation request may fail, eg. if LegacyBiosDxe has already run.
+  //
+  Segment0Pages = 1;
+  Int0x10       = (IVT_ENTRY *)(UINTN)Segment0 + 0x10;
+  Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode,
+                  Segment0Pages, &Segment0);
+
+  if (EFI_ERROR (Status)) {
+    EFI_PHYSICAL_ADDRESS Handler;
+
+    //
+    // Check if a video BIOS handler has been installed previously -- we
+    // shouldn't override a real video BIOS with our shim, nor our own shim if
+    // it's already present.
+    //
+    Handler = (Int0x10->Segment << 4) + Int0x10->Offset;
+    if (Handler >= SegmentC && Handler < SegmentF) {
+      DEBUG ((DEBUG_VERBOSE, "%a: Video BIOS handler found at %04x:%04x\n",
+        __FUNCTION__, Int0x10->Segment, Int0x10->Offset));
+      return;
+    }
+
+    //
+    // Otherwise we'll overwrite the Int10h vector, even though we may not own
+    // the page at zero.
+    //
+    DEBUG ((DEBUG_VERBOSE, "%a: failed to allocate page at zero: %r\n",
+      __FUNCTION__, Status));
+  } else {
+    //
+    // We managed to allocate the page at zero. SVN r14218 guarantees that it
+    // is NUL-filled.
+    //
+    ASSERT (Int0x10->Segment == 0x0000);
+    ASSERT (Int0x10->Offset  == 0x0000);
+  }
+
+  //
+  // Put the shim in place first.
+  //
+  Pam1Address = PCI_LIB_ADDRESS (0, 0, 0, 0x5A);
+  //
+  // low nibble covers 0xC0000 to 0xC3FFF
+  // high nibble covers 0xC4000 to 0xC7FFF
+  // bit1 in each nibble is Write Enable
+  // bit0 in each nibble is Read Enable
+  //
+  Pam1 = PciRead8 (Pam1Address);
+  PciWrite8 (Pam1Address, Pam1 | (BIT1 | BIT0));
+
+  //
+  // We never added memory space durig PEI or DXE for the C segment, so we
+  // don't need to (and can't) allocate from there. Also, guest operating
+  // systems will see a hole in the UEFI memory map there.
+  //
+  SegmentCPages = 4;
+
+  ASSERT (sizeof gVbeShim <= EFI_PAGES_TO_SIZE (SegmentCPages));
+  CopyMem ((VOID *)(UINTN)SegmentC, gVbeShim, sizeof gVbeShim);
+
+  //
+  // Fill in the VBE INFO structure.
+  //
+  VbeInfoFull = (VBE_INFO *)(UINTN)SegmentC;
+  VbeInfo     = &VbeInfoFull->Base;
+  Ptr         = VbeInfoFull->Buffer;
+
+  CopyMem (VbeInfo->Signature, "VESA", 4);
+  VbeInfo->VesaVersion = 0x0200;
+
+  VbeInfo->OemNameAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
+  CopyMem (Ptr, "FBSD", 5);
+  Ptr += 5;
+
+  VbeInfo->Capabilities = BIT1 | BIT0; // DAC can be switched into 8-bit mode
+
+  VbeInfo->ModeListAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
+  for (i = 0; i < NUM_VBE_MODES; i ++) {
+     *(UINT16*)Ptr = vbeModeIds[i];  // mode number
+     Ptr += 2;
+  }
+  *(UINT16*)Ptr = 0xFFFF; // mode list terminator
+  Ptr += 2;
+
+  VbeInfo->VideoMem64K = (UINT16)((1024 * 768 * 4 + 65535) / 65536);
+  VbeInfo->OemSoftwareVersion = 0x0200;
+
+  VbeInfo->VendorNameAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
+  CopyMem (Ptr, "FBSD", 5);
+  Ptr += 5;
+
+  VbeInfo->ProductNameAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
+  Printed = AsciiSPrint ((CHAR8 *)Ptr,
+              sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer), "%s",
+              CardName);
+  Ptr += Printed + 1;
+
+  VbeInfo->ProductRevAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
+  CopyMem (Ptr, mProductRevision, sizeof mProductRevision);
+  Ptr += sizeof mProductRevision;
+
+  ASSERT (sizeof VbeInfoFull->Buffer >= Ptr - VbeInfoFull->Buffer);
+  ZeroMem (Ptr, sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer));
+
+  //
+  // Fill in the VBE MODE INFO structure list
+  //
+  VbeModeInfo = (VBE_MODE_INFO *)(VbeInfoFull + 1);
+  Ptr = (UINT8 *)VbeModeInfo;
+  for (i = 0; i < NUM_VBE_MODES; i++) {
+    vbeModes[i].LfbAddress = (UINT32)FrameBufferBase;
+    CopyMem (Ptr, &vbeModes[i], 0x32);
+    Ptr += 0x32;
+  }
+
+  ZeroMem (Ptr, 56);     // Clear remaining bytes
+
+  //
+  // Clear Write Enable (bit1), keep Read Enable (bit0) set
+  //
+  PciWrite8 (Pam1Address, (Pam1 & ~BIT1) | BIT0);
+
+  //
+  // Second, point the Int10h vector at the shim.
+  //
+  Int0x10->Segment = (UINT16) ((UINT32)SegmentC >> 4);
+  Int0x10->Offset  = (UINT16) ((UINTN) (VbeModeInfo + 1) - SegmentC);
+
+  DEBUG ((DEBUG_INFO, "%a: VBE shim installed to %x:%x\n",
+         __FUNCTION__, Int0x10->Segment, Int0x10->Offset));
+}
diff --git a/OvmfPkg/IntelGvtGopDxe/VbeShim.h b/OvmfPkg/IntelGvtGopDxe/VbeShim.h
new file mode 100644
index 000000000000..601b1465cbe5
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/VbeShim.h
@@ -0,0 +1,912 @@
+//
+// THIS FILE WAS GENERATED BY "VbeShim.sh". DO NOT EDIT.
+//
+#ifndef _VBE_SHIM_H_
+#define _VBE_SHIM_H_
+STATIC CONST UINT8 gVbeShim[] = {
+  /* 00000000 nop                            */  0x90,
+  /* 00000001 nop                            */  0x90,
+  /* 00000002 nop                            */  0x90,
+  /* 00000003 nop                            */  0x90,
+  /* 00000004 nop                            */  0x90,
+  /* 00000005 nop                            */  0x90,
+  /* 00000006 nop                            */  0x90,
+  /* 00000007 nop                            */  0x90,
+  /* 00000008 nop                            */  0x90,
+  /* 00000009 nop                            */  0x90,
+  /* 0000000A nop                            */  0x90,
+  /* 0000000B nop                            */  0x90,
+  /* 0000000C nop                            */  0x90,
+  /* 0000000D nop                            */  0x90,
+  /* 0000000E nop                            */  0x90,
+  /* 0000000F nop                            */  0x90,
+  /* 00000010 nop                            */  0x90,
+  /* 00000011 nop                            */  0x90,
+  /* 00000012 nop                            */  0x90,
+  /* 00000013 nop                            */  0x90,
+  /* 00000014 nop                            */  0x90,
+  /* 00000015 nop                            */  0x90,
+  /* 00000016 nop                            */  0x90,
+  /* 00000017 nop                            */  0x90,
+  /* 00000018 nop                            */  0x90,
+  /* 00000019 nop                            */  0x90,
+  /* 0000001A nop                            */  0x90,
+  /* 0000001B nop                            */  0x90,
+  /* 0000001C nop                            */  0x90,
+  /* 0000001D nop                            */  0x90,
+  /* 0000001E nop                            */  0x90,
+  /* 0000001F nop                            */  0x90,
+  /* 00000020 nop                            */  0x90,
+  /* 00000021 nop                            */  0x90,
+  /* 00000022 nop                            */  0x90,
+  /* 00000023 nop                            */  0x90,
+  /* 00000024 nop                            */  0x90,
+  /* 00000025 nop                            */  0x90,
+  /* 00000026 nop                            */  0x90,
+  /* 00000027 nop                            */  0x90,
+  /* 00000028 nop                            */  0x90,
+  /* 00000029 nop                            */  0x90,
+  /* 0000002A nop                            */  0x90,
+  /* 0000002B nop                            */  0x90,
+  /* 0000002C nop                            */  0x90,
+  /* 0000002D nop                            */  0x90,
+  /* 0000002E nop                            */  0x90,
+  /* 0000002F nop                            */  0x90,
+  /* 00000030 nop                            */  0x90,
+  /* 00000031 nop                            */  0x90,
+  /* 00000032 nop                            */  0x90,
+  /* 00000033 nop                            */  0x90,
+  /* 00000034 nop                            */  0x90,
+  /* 00000035 nop                            */  0x90,
+  /* 00000036 nop                            */  0x90,
+  /* 00000037 nop                            */  0x90,
+  /* 00000038 nop                            */  0x90,
+  /* 00000039 nop                            */  0x90,
+  /* 0000003A nop                            */  0x90,
+  /* 0000003B nop                            */  0x90,
+  /* 0000003C nop                            */  0x90,
+  /* 0000003D nop                            */  0x90,
+  /* 0000003E nop                            */  0x90,
+  /* 0000003F nop                            */  0x90,
+  /* 00000040 nop                            */  0x90,
+  /* 00000041 nop                            */  0x90,
+  /* 00000042 nop                            */  0x90,
+  /* 00000043 nop                            */  0x90,
+  /* 00000044 nop                            */  0x90,
+  /* 00000045 nop                            */  0x90,
+  /* 00000046 nop                            */  0x90,
+  /* 00000047 nop                            */  0x90,
+  /* 00000048 nop                            */  0x90,
+  /* 00000049 nop                            */  0x90,
+  /* 0000004A nop                            */  0x90,
+  /* 0000004B nop                            */  0x90,
+  /* 0000004C nop                            */  0x90,
+  /* 0000004D nop                            */  0x90,
+  /* 0000004E nop                            */  0x90,
+  /* 0000004F nop                            */  0x90,
+  /* 00000050 nop                            */  0x90,
+  /* 00000051 nop                            */  0x90,
+  /* 00000052 nop                            */  0x90,
+  /* 00000053 nop                            */  0x90,
+  /* 00000054 nop                            */  0x90,
+  /* 00000055 nop                            */  0x90,
+  /* 00000056 nop                            */  0x90,
+  /* 00000057 nop                            */  0x90,
+  /* 00000058 nop                            */  0x90,
+  /* 00000059 nop                            */  0x90,
+  /* 0000005A nop                            */  0x90,
+  /* 0000005B nop                            */  0x90,
+  /* 0000005C nop                            */  0x90,
+  /* 0000005D nop                            */  0x90,
+  /* 0000005E nop                            */  0x90,
+  /* 0000005F nop                            */  0x90,
+  /* 00000060 nop                            */  0x90,
+  /* 00000061 nop                            */  0x90,
+  /* 00000062 nop                            */  0x90,
+  /* 00000063 nop                            */  0x90,
+  /* 00000064 nop                            */  0x90,
+  /* 00000065 nop                            */  0x90,
+  /* 00000066 nop                            */  0x90,
+  /* 00000067 nop                            */  0x90,
+  /* 00000068 nop                            */  0x90,
+  /* 00000069 nop                            */  0x90,
+  /* 0000006A nop                            */  0x90,
+  /* 0000006B nop                            */  0x90,
+  /* 0000006C nop                            */  0x90,
+  /* 0000006D nop                            */  0x90,
+  /* 0000006E nop                            */  0x90,
+  /* 0000006F nop                            */  0x90,
+  /* 00000070 nop                            */  0x90,
+  /* 00000071 nop                            */  0x90,
+  /* 00000072 nop                            */  0x90,
+  /* 00000073 nop                            */  0x90,
+  /* 00000074 nop                            */  0x90,
+  /* 00000075 nop                            */  0x90,
+  /* 00000076 nop                            */  0x90,
+  /* 00000077 nop                            */  0x90,
+  /* 00000078 nop                            */  0x90,
+  /* 00000079 nop                            */  0x90,
+  /* 0000007A nop                            */  0x90,
+  /* 0000007B nop                            */  0x90,
+  /* 0000007C nop                            */  0x90,
+  /* 0000007D nop                            */  0x90,
+  /* 0000007E nop                            */  0x90,
+  /* 0000007F nop                            */  0x90,
+  /* 00000080 nop                            */  0x90,
+  /* 00000081 nop                            */  0x90,
+  /* 00000082 nop                            */  0x90,
+  /* 00000083 nop                            */  0x90,
+  /* 00000084 nop                            */  0x90,
+  /* 00000085 nop                            */  0x90,
+  /* 00000086 nop                            */  0x90,
+  /* 00000087 nop                            */  0x90,
+  /* 00000088 nop                            */  0x90,
+  /* 00000089 nop                            */  0x90,
+  /* 0000008A nop                            */  0x90,
+  /* 0000008B nop                            */  0x90,
+  /* 0000008C nop                            */  0x90,
+  /* 0000008D nop                            */  0x90,
+  /* 0000008E nop                            */  0x90,
+  /* 0000008F nop                            */  0x90,
+  /* 00000090 nop                            */  0x90,
+  /* 00000091 nop                            */  0x90,
+  /* 00000092 nop                            */  0x90,
+  /* 00000093 nop                            */  0x90,
+  /* 00000094 nop                            */  0x90,
+  /* 00000095 nop                            */  0x90,
+  /* 00000096 nop                            */  0x90,
+  /* 00000097 nop                            */  0x90,
+  /* 00000098 nop                            */  0x90,
+  /* 00000099 nop                            */  0x90,
+  /* 0000009A nop                            */  0x90,
+  /* 0000009B nop                            */  0x90,
+  /* 0000009C nop                            */  0x90,
+  /* 0000009D nop                            */  0x90,
+  /* 0000009E nop                            */  0x90,
+  /* 0000009F nop                            */  0x90,
+  /* 000000A0 nop                            */  0x90,
+  /* 000000A1 nop                            */  0x90,
+  /* 000000A2 nop                            */  0x90,
+  /* 000000A3 nop                            */  0x90,
+  /* 000000A4 nop                            */  0x90,
+  /* 000000A5 nop                            */  0x90,
+  /* 000000A6 nop                            */  0x90,
+  /* 000000A7 nop                            */  0x90,
+  /* 000000A8 nop                            */  0x90,
+  /* 000000A9 nop                            */  0x90,
+  /* 000000AA nop                            */  0x90,
+  /* 000000AB nop                            */  0x90,
+  /* 000000AC nop                            */  0x90,
+  /* 000000AD nop                            */  0x90,
+  /* 000000AE nop                            */  0x90,
+  /* 000000AF nop                            */  0x90,
+  /* 000000B0 nop                            */  0x90,
+  /* 000000B1 nop                            */  0x90,
+  /* 000000B2 nop                            */  0x90,
+  /* 000000B3 nop                            */  0x90,
+  /* 000000B4 nop                            */  0x90,
+  /* 000000B5 nop                            */  0x90,
+  /* 000000B6 nop                            */  0x90,
+  /* 000000B7 nop                            */  0x90,
+  /* 000000B8 nop                            */  0x90,
+  /* 000000B9 nop                            */  0x90,
+  /* 000000BA nop                            */  0x90,
+  /* 000000BB nop                            */  0x90,
+  /* 000000BC nop                            */  0x90,
+  /* 000000BD nop                            */  0x90,
+  /* 000000BE nop                            */  0x90,
+  /* 000000BF nop                            */  0x90,
+  /* 000000C0 nop                            */  0x90,
+  /* 000000C1 nop                            */  0x90,
+  /* 000000C2 nop                            */  0x90,
+  /* 000000C3 nop                            */  0x90,
+  /* 000000C4 nop                            */  0x90,
+  /* 000000C5 nop                            */  0x90,
+  /* 000000C6 nop                            */  0x90,
+  /* 000000C7 nop                            */  0x90,
+  /* 000000C8 nop                            */  0x90,
+  /* 000000C9 nop                            */  0x90,
+  /* 000000CA nop                            */  0x90,
+  /* 000000CB nop                            */  0x90,
+  /* 000000CC nop                            */  0x90,
+  /* 000000CD nop                            */  0x90,
+  /* 000000CE nop                            */  0x90,
+  /* 000000CF nop                            */  0x90,
+  /* 000000D0 nop                            */  0x90,
+  /* 000000D1 nop                            */  0x90,
+  /* 000000D2 nop                            */  0x90,
+  /* 000000D3 nop                            */  0x90,
+  /* 000000D4 nop                            */  0x90,
+  /* 000000D5 nop                            */  0x90,
+  /* 000000D6 nop                            */  0x90,
+  /* 000000D7 nop                            */  0x90,
+  /* 000000D8 nop                            */  0x90,
+  /* 000000D9 nop                            */  0x90,
+  /* 000000DA nop                            */  0x90,
+  /* 000000DB nop                            */  0x90,
+  /* 000000DC nop                            */  0x90,
+  /* 000000DD nop                            */  0x90,
+  /* 000000DE nop                            */  0x90,
+  /* 000000DF nop                            */  0x90,
+  /* 000000E0 nop                            */  0x90,
+  /* 000000E1 nop                            */  0x90,
+  /* 000000E2 nop                            */  0x90,
+  /* 000000E3 nop                            */  0x90,
+  /* 000000E4 nop                            */  0x90,
+  /* 000000E5 nop                            */  0x90,
+  /* 000000E6 nop                            */  0x90,
+  /* 000000E7 nop                            */  0x90,
+  /* 000000E8 nop                            */  0x90,
+  /* 000000E9 nop                            */  0x90,
+  /* 000000EA nop                            */  0x90,
+  /* 000000EB nop                            */  0x90,
+  /* 000000EC nop                            */  0x90,
+  /* 000000ED nop                            */  0x90,
+  /* 000000EE nop                            */  0x90,
+  /* 000000EF nop                            */  0x90,
+  /* 000000F0 nop                            */  0x90,
+  /* 000000F1 nop                            */  0x90,
+  /* 000000F2 nop                            */  0x90,
+  /* 000000F3 nop                            */  0x90,
+  /* 000000F4 nop                            */  0x90,
+  /* 000000F5 nop                            */  0x90,
+  /* 000000F6 nop                            */  0x90,
+  /* 000000F7 nop                            */  0x90,
+  /* 000000F8 nop                            */  0x90,
+  /* 000000F9 nop                            */  0x90,
+  /* 000000FA nop                            */  0x90,
+  /* 000000FB nop                            */  0x90,
+  /* 000000FC nop                            */  0x90,
+  /* 000000FD nop                            */  0x90,
+  /* 000000FE nop                            */  0x90,
+  /* 000000FF nop                            */  0x90,
+  /* 00000100 nop                            */  0x90,
+  /* 00000101 nop                            */  0x90,
+  /* 00000102 nop                            */  0x90,
+  /* 00000103 nop                            */  0x90,
+  /* 00000104 nop                            */  0x90,
+  /* 00000105 nop                            */  0x90,
+  /* 00000106 nop                            */  0x90,
+  /* 00000107 nop                            */  0x90,
+  /* 00000108 nop                            */  0x90,
+  /* 00000109 nop                            */  0x90,
+  /* 0000010A nop                            */  0x90,
+  /* 0000010B nop                            */  0x90,
+  /* 0000010C nop                            */  0x90,
+  /* 0000010D nop                            */  0x90,
+  /* 0000010E nop                            */  0x90,
+  /* 0000010F nop                            */  0x90,
+  /* 00000110 nop                            */  0x90,
+  /* 00000111 nop                            */  0x90,
+  /* 00000112 nop                            */  0x90,
+  /* 00000113 nop                            */  0x90,
+  /* 00000114 nop                            */  0x90,
+  /* 00000115 nop                            */  0x90,
+  /* 00000116 nop                            */  0x90,
+  /* 00000117 nop                            */  0x90,
+  /* 00000118 nop                            */  0x90,
+  /* 00000119 nop                            */  0x90,
+  /* 0000011A nop                            */  0x90,
+  /* 0000011B nop                            */  0x90,
+  /* 0000011C nop                            */  0x90,
+  /* 0000011D nop                            */  0x90,
+  /* 0000011E nop                            */  0x90,
+  /* 0000011F nop                            */  0x90,
+  /* 00000120 nop                            */  0x90,
+  /* 00000121 nop                            */  0x90,
+  /* 00000122 nop                            */  0x90,
+  /* 00000123 nop                            */  0x90,
+  /* 00000124 nop                            */  0x90,
+  /* 00000125 nop                            */  0x90,
+  /* 00000126 nop                            */  0x90,
+  /* 00000127 nop                            */  0x90,
+  /* 00000128 nop                            */  0x90,
+  /* 00000129 nop                            */  0x90,
+  /* 0000012A nop                            */  0x90,
+  /* 0000012B nop                            */  0x90,
+  /* 0000012C nop                            */  0x90,
+  /* 0000012D nop                            */  0x90,
+  /* 0000012E nop                            */  0x90,
+  /* 0000012F nop                            */  0x90,
+  /* 00000130 nop                            */  0x90,
+  /* 00000131 nop                            */  0x90,
+  /* 00000132 nop                            */  0x90,
+  /* 00000133 nop                            */  0x90,
+  /* 00000134 nop                            */  0x90,
+  /* 00000135 nop                            */  0x90,
+  /* 00000136 nop                            */  0x90,
+  /* 00000137 nop                            */  0x90,
+  /* 00000138 nop                            */  0x90,
+  /* 00000139 nop                            */  0x90,
+  /* 0000013A nop                            */  0x90,
+  /* 0000013B nop                            */  0x90,
+  /* 0000013C nop                            */  0x90,
+  /* 0000013D nop                            */  0x90,
+  /* 0000013E nop                            */  0x90,
+  /* 0000013F nop                            */  0x90,
+  /* 00000140 nop                            */  0x90,
+  /* 00000141 nop                            */  0x90,
+  /* 00000142 nop                            */  0x90,
+  /* 00000143 nop                            */  0x90,
+  /* 00000144 nop                            */  0x90,
+  /* 00000145 nop                            */  0x90,
+  /* 00000146 nop                            */  0x90,
+  /* 00000147 nop                            */  0x90,
+  /* 00000148 nop                            */  0x90,
+  /* 00000149 nop                            */  0x90,
+  /* 0000014A nop                            */  0x90,
+  /* 0000014B nop                            */  0x90,
+  /* 0000014C nop                            */  0x90,
+  /* 0000014D nop                            */  0x90,
+  /* 0000014E nop                            */  0x90,
+  /* 0000014F nop                            */  0x90,
+  /* 00000150 nop                            */  0x90,
+  /* 00000151 nop                            */  0x90,
+  /* 00000152 nop                            */  0x90,
+  /* 00000153 nop                            */  0x90,
+  /* 00000154 nop                            */  0x90,
+  /* 00000155 nop                            */  0x90,
+  /* 00000156 nop                            */  0x90,
+  /* 00000157 nop                            */  0x90,
+  /* 00000158 nop                            */  0x90,
+  /* 00000159 nop                            */  0x90,
+  /* 0000015A nop                            */  0x90,
+  /* 0000015B nop                            */  0x90,
+  /* 0000015C nop                            */  0x90,
+  /* 0000015D nop                            */  0x90,
+  /* 0000015E nop                            */  0x90,
+  /* 0000015F nop                            */  0x90,
+  /* 00000160 nop                            */  0x90,
+  /* 00000161 nop                            */  0x90,
+  /* 00000162 nop                            */  0x90,
+  /* 00000163 nop                            */  0x90,
+  /* 00000164 nop                            */  0x90,
+  /* 00000165 nop                            */  0x90,
+  /* 00000166 nop                            */  0x90,
+  /* 00000167 nop                            */  0x90,
+  /* 00000168 nop                            */  0x90,
+  /* 00000169 nop                            */  0x90,
+  /* 0000016A nop                            */  0x90,
+  /* 0000016B nop                            */  0x90,
+  /* 0000016C nop                            */  0x90,
+  /* 0000016D nop                            */  0x90,
+  /* 0000016E nop                            */  0x90,
+  /* 0000016F nop                            */  0x90,
+  /* 00000170 nop                            */  0x90,
+  /* 00000171 nop                            */  0x90,
+  /* 00000172 nop                            */  0x90,
+  /* 00000173 nop                            */  0x90,
+  /* 00000174 nop                            */  0x90,
+  /* 00000175 nop                            */  0x90,
+  /* 00000176 nop                            */  0x90,
+  /* 00000177 nop                            */  0x90,
+  /* 00000178 nop                            */  0x90,
+  /* 00000179 nop                            */  0x90,
+  /* 0000017A nop                            */  0x90,
+  /* 0000017B nop                            */  0x90,
+  /* 0000017C nop                            */  0x90,
+  /* 0000017D nop                            */  0x90,
+  /* 0000017E nop                            */  0x90,
+  /* 0000017F nop                            */  0x90,
+  /* 00000180 nop                            */  0x90,
+  /* 00000181 nop                            */  0x90,
+  /* 00000182 nop                            */  0x90,
+  /* 00000183 nop                            */  0x90,
+  /* 00000184 nop                            */  0x90,
+  /* 00000185 nop                            */  0x90,
+  /* 00000186 nop                            */  0x90,
+  /* 00000187 nop                            */  0x90,
+  /* 00000188 nop                            */  0x90,
+  /* 00000189 nop                            */  0x90,
+  /* 0000018A nop                            */  0x90,
+  /* 0000018B nop                            */  0x90,
+  /* 0000018C nop                            */  0x90,
+  /* 0000018D nop                            */  0x90,
+  /* 0000018E nop                            */  0x90,
+  /* 0000018F nop                            */  0x90,
+  /* 00000190 nop                            */  0x90,
+  /* 00000191 nop                            */  0x90,
+  /* 00000192 nop                            */  0x90,
+  /* 00000193 nop                            */  0x90,
+  /* 00000194 nop                            */  0x90,
+  /* 00000195 nop                            */  0x90,
+  /* 00000196 nop                            */  0x90,
+  /* 00000197 nop                            */  0x90,
+  /* 00000198 nop                            */  0x90,
+  /* 00000199 nop                            */  0x90,
+  /* 0000019A nop                            */  0x90,
+  /* 0000019B nop                            */  0x90,
+  /* 0000019C nop                            */  0x90,
+  /* 0000019D nop                            */  0x90,
+  /* 0000019E nop                            */  0x90,
+  /* 0000019F nop                            */  0x90,
+  /* 000001A0 nop                            */  0x90,
+  /* 000001A1 nop                            */  0x90,
+  /* 000001A2 nop                            */  0x90,
+  /* 000001A3 nop                            */  0x90,
+  /* 000001A4 nop                            */  0x90,
+  /* 000001A5 nop                            */  0x90,
+  /* 000001A6 nop                            */  0x90,
+  /* 000001A7 nop                            */  0x90,
+  /* 000001A8 nop                            */  0x90,
+  /* 000001A9 nop                            */  0x90,
+  /* 000001AA nop                            */  0x90,
+  /* 000001AB nop                            */  0x90,
+  /* 000001AC nop                            */  0x90,
+  /* 000001AD nop                            */  0x90,
+  /* 000001AE nop                            */  0x90,
+  /* 000001AF nop                            */  0x90,
+  /* 000001B0 nop                            */  0x90,
+  /* 000001B1 nop                            */  0x90,
+  /* 000001B2 nop                            */  0x90,
+  /* 000001B3 nop                            */  0x90,
+  /* 000001B4 nop                            */  0x90,
+  /* 000001B5 nop                            */  0x90,
+  /* 000001B6 nop                            */  0x90,
+  /* 000001B7 nop                            */  0x90,
+  /* 000001B8 nop                            */  0x90,
+  /* 000001B9 nop                            */  0x90,
+  /* 000001BA nop                            */  0x90,
+  /* 000001BB nop                            */  0x90,
+  /* 000001BC nop                            */  0x90,
+  /* 000001BD nop                            */  0x90,
+  /* 000001BE nop                            */  0x90,
+  /* 000001BF nop                            */  0x90,
+  /* 000001C0 nop                            */  0x90,
+  /* 000001C1 nop                            */  0x90,
+  /* 000001C2 nop                            */  0x90,
+  /* 000001C3 nop                            */  0x90,
+  /* 000001C4 nop                            */  0x90,
+  /* 000001C5 nop                            */  0x90,
+  /* 000001C6 nop                            */  0x90,
+  /* 000001C7 nop                            */  0x90,
+  /* 000001C8 nop                            */  0x90,
+  /* 000001C9 nop                            */  0x90,
+  /* 000001CA nop                            */  0x90,
+  /* 000001CB nop                            */  0x90,
+  /* 000001CC nop                            */  0x90,
+  /* 000001CD nop                            */  0x90,
+  /* 000001CE nop                            */  0x90,
+  /* 000001CF nop                            */  0x90,
+  /* 000001D0 nop                            */  0x90,
+  /* 000001D1 nop                            */  0x90,
+  /* 000001D2 nop                            */  0x90,
+  /* 000001D3 nop                            */  0x90,
+  /* 000001D4 nop                            */  0x90,
+  /* 000001D5 nop                            */  0x90,
+  /* 000001D6 nop                            */  0x90,
+  /* 000001D7 nop                            */  0x90,
+  /* 000001D8 nop                            */  0x90,
+  /* 000001D9 nop                            */  0x90,
+  /* 000001DA nop                            */  0x90,
+  /* 000001DB nop                            */  0x90,
+  /* 000001DC nop                            */  0x90,
+  /* 000001DD nop                            */  0x90,
+  /* 000001DE nop                            */  0x90,
+  /* 000001DF nop                            */  0x90,
+  /* 000001E0 nop                            */  0x90,
+  /* 000001E1 nop                            */  0x90,
+  /* 000001E2 nop                            */  0x90,
+  /* 000001E3 nop                            */  0x90,
+  /* 000001E4 nop                            */  0x90,
+  /* 000001E5 nop                            */  0x90,
+  /* 000001E6 nop                            */  0x90,
+  /* 000001E7 nop                            */  0x90,
+  /* 000001E8 nop                            */  0x90,
+  /* 000001E9 nop                            */  0x90,
+  /* 000001EA nop                            */  0x90,
+  /* 000001EB nop                            */  0x90,
+  /* 000001EC nop                            */  0x90,
+  /* 000001ED nop                            */  0x90,
+  /* 000001EE nop                            */  0x90,
+  /* 000001EF nop                            */  0x90,
+  /* 000001F0 nop                            */  0x90,
+  /* 000001F1 nop                            */  0x90,
+  /* 000001F2 nop                            */  0x90,
+  /* 000001F3 nop                            */  0x90,
+  /* 000001F4 nop                            */  0x90,
+  /* 000001F5 nop                            */  0x90,
+  /* 000001F6 nop                            */  0x90,
+  /* 000001F7 nop                            */  0x90,
+  /* 000001F8 nop                            */  0x90,
+  /* 000001F9 nop                            */  0x90,
+  /* 000001FA nop                            */  0x90,
+  /* 000001FB nop                            */  0x90,
+  /* 000001FC nop                            */  0x90,
+  /* 000001FD nop                            */  0x90,
+  /* 000001FE nop                            */  0x90,
+  /* 000001FF nop                            */  0x90,
+  /* 00000200 cmp ax,0x4f00                  */  0x3D, 0x00, 0x4F,
+  /* 00000203 jz 0x237                       */  0x74, 0x32,
+  /* 00000205 cmp ax,0x4f01                  */  0x3D, 0x01, 0x4F,
+  /* 00000208 jz 0x257                       */  0x74, 0x4D,
+  /* 0000020A cmp ax,0x4f02                  */  0x3D, 0x02, 0x4F,
+  /* 0000020D jz near 0x2c8                  */  0x0F, 0x84, 0xB7, 0x00,
+  /* 00000211 cmp ax,0x4f03                  */  0x3D, 0x03, 0x4F,
+  /* 00000214 jz near 0x325                  */  0x0F, 0x84, 0x0D, 0x01,
+  /* 00000218 cmp ax,0x4f10                  */  0x3D, 0x10, 0x4F,
+  /* 0000021B jz near 0x337                  */  0x0F, 0x84, 0x18, 0x01,
+  /* 0000021F cmp ax,0x4f15                  */  0x3D, 0x15, 0x4F,
+  /* 00000222 jz near 0x344                  */  0x0F, 0x84, 0x1E, 0x01,
+  /* 00000226 cmp ah,0x0                     */  0x80, 0xFC, 0x00,
+  /* 00000229 jz near 0x363                  */  0x0F, 0x84, 0x36, 0x01,
+  /* 0000022D push si                        */  0x56,
+  /* 0000022E mov si,0x3d7                   */  0xBE, 0xD7, 0x03,
+  /* 00000231 call 0x3ad                     */  0xE8, 0x79, 0x01,
+  /* 00000234 pop si                         */  0x5E,
+  /* 00000235 jmp short 0x235                */  0xEB, 0xFE,
+  /* 00000237 push es                        */  0x06,
+  /* 00000238 push di                        */  0x57,
+  /* 00000239 push ds                        */  0x1E,
+  /* 0000023A push si                        */  0x56,
+  /* 0000023B push cx                        */  0x51,
+  /* 0000023C push si                        */  0x56,
+  /* 0000023D mov si,0x3eb                   */  0xBE, 0xEB, 0x03,
+  /* 00000240 call 0x3ad                     */  0xE8, 0x6A, 0x01,
+  /* 00000243 pop si                         */  0x5E,
+  /* 00000244 push cs                        */  0x0E,
+  /* 00000245 pop ds                         */  0x1F,
+  /* 00000246 mov si,0x0                     */  0xBE, 0x00, 0x00,
+  /* 00000249 mov cx,0x100                   */  0xB9, 0x00, 0x01,
+  /* 0000024C cld                            */  0xFC,
+  /* 0000024D rep movsb                      */  0xF3, 0xA4,
+  /* 0000024F pop cx                         */  0x59,
+  /* 00000250 pop si                         */  0x5E,
+  /* 00000251 pop ds                         */  0x1F,
+  /* 00000252 pop di                         */  0x5F,
+  /* 00000253 pop es                         */  0x07,
+  /* 00000254 jmp 0x395                      */  0xE9, 0x3E, 0x01,
+  /* 00000257 push es                        */  0x06,
+  /* 00000258 push di                        */  0x57,
+  /* 00000259 push ds                        */  0x1E,
+  /* 0000025A push si                        */  0x56,
+  /* 0000025B push cx                        */  0x51,
+  /* 0000025C push si                        */  0x56,
+  /* 0000025D mov si,0x3f6                   */  0xBE, 0xF6, 0x03,
+  /* 00000260 call 0x3ad                     */  0xE8, 0x4A, 0x01,
+  /* 00000263 pop si                         */  0x5E,
+  /* 00000264 and cx,0xbfff                  */  0x81, 0xE1, 0xFF, 0xBF,
+  /* 00000268 cmp cx,0x13f                   */  0x81, 0xF9, 0x3F, 0x01,
+  /* 0000026C jz 0x284                       */  0x74, 0x16,
+  /* 0000026E cmp cx,0x140                   */  0x81, 0xF9, 0x40, 0x01,
+  /* 00000272 jz 0x291                       */  0x74, 0x1D,
+  /* 00000274 cmp cx,0x141                   */  0x81, 0xF9, 0x41, 0x01,
+  /* 00000278 jz 0x29e                       */  0x74, 0x24,
+  /* 0000027A push si                        */  0x56,
+  /* 0000027B mov si,0x42c                   */  0xBE, 0x2C, 0x04,
+  /* 0000027E call 0x3ad                     */  0xE8, 0x2C, 0x01,
+  /* 00000281 pop si                         */  0x5E,
+  /* 00000282 jmp short 0x235                */  0xEB, 0xB1,
+  /* 00000284 push si                        */  0x56,
+  /* 00000285 mov si,0x46b                   */  0xBE, 0x6B, 0x04,
+  /* 00000288 call 0x3ad                     */  0xE8, 0x22, 0x01,
+  /* 0000028B pop si                         */  0x5E,
+  /* 0000028C mov si,0x100                   */  0xBE, 0x00, 0x01,
+  /* 0000028F jmp short 0x2b8                */  0xEB, 0x27,
+  /* 00000291 push si                        */  0x56,
+  /* 00000292 mov si,0x47d                   */  0xBE, 0x7D, 0x04,
+  /* 00000295 call 0x3ad                     */  0xE8, 0x15, 0x01,
+  /* 00000298 pop si                         */  0x5E,
+  /* 00000299 mov si,0x132                   */  0xBE, 0x32, 0x01,
+  /* 0000029C jmp short 0x2b8                */  0xEB, 0x1A,
+  /* 0000029E push si                        */  0x56,
+  /* 0000029F mov si,0x48f                   */  0xBE, 0x8F, 0x04,
+  /* 000002A2 call 0x3ad                     */  0xE8, 0x08, 0x01,
+  /* 000002A5 pop si                         */  0x5E,
+  /* 000002A6 mov si,0x164                   */  0xBE, 0x64, 0x01,
+  /* 000002A9 jmp short 0x2b8                */  0xEB, 0x0D,
+  /* 000002AB push si                        */  0x56,
+  /* 000002AC mov si,0x4a2                   */  0xBE, 0xA2, 0x04,
+  /* 000002AF call 0x3ad                     */  0xE8, 0xFB, 0x00,
+  /* 000002B2 pop si                         */  0x5E,
+  /* 000002B3 mov si,0x196                   */  0xBE, 0x96, 0x01,
+  /* 000002B6 jmp short 0x2b8                */  0xEB, 0x00,
+  /* 000002B8 push cs                        */  0x0E,
+  /* 000002B9 pop ds                         */  0x1F,
+  /* 000002BA mov cx,0x32                    */  0xB9, 0x32, 0x00,
+  /* 000002BD cld                            */  0xFC,
+  /* 000002BE rep movsb                      */  0xF3, 0xA4,
+  /* 000002C0 pop cx                         */  0x59,
+  /* 000002C1 pop si                         */  0x5E,
+  /* 000002C2 pop ds                         */  0x1F,
+  /* 000002C3 pop di                         */  0x5F,
+  /* 000002C4 pop es                         */  0x07,
+  /* 000002C5 jmp 0x395                      */  0xE9, 0xCD, 0x00,
+  /* 000002C8 push dx                        */  0x52,
+  /* 000002C9 push ax                        */  0x50,
+  /* 000002CA push si                        */  0x56,
+  /* 000002CB mov si,0x410                   */  0xBE, 0x10, 0x04,
+  /* 000002CE call 0x3ad                     */  0xE8, 0xDC, 0x00,
+  /* 000002D1 pop si                         */  0x5E,
+  /* 000002D2 and bx,0xbfff                  */  0x81, 0xE3, 0xFF, 0xBF,
+  /* 000002D6 cmp bx,0x13f                   */  0x81, 0xFB, 0x3F, 0x01,
+  /* 000002DA jz 0x2f3                       */  0x74, 0x17,
+  /* 000002DC cmp bx,0x140                   */  0x81, 0xFB, 0x40, 0x01,
+  /* 000002E0 jz 0x2fd                       */  0x74, 0x1B,
+  /* 000002E2 cmp bx,0x141                   */  0x81, 0xFB, 0x41, 0x01,
+  /* 000002E6 jz 0x307                       */  0x74, 0x1F,
+  /* 000002E8 push si                        */  0x56,
+  /* 000002E9 mov si,0x42c                   */  0xBE, 0x2C, 0x04,
+  /* 000002EC call 0x3ad                     */  0xE8, 0xBE, 0x00,
+  /* 000002EF pop si                         */  0x5E,
+  /* 000002F0 jmp 0x235                      */  0xE9, 0x42, 0xFF,
+  /* 000002F3 push si                        */  0x56,
+  /* 000002F4 mov si,0x46b                   */  0xBE, 0x6B, 0x04,
+  /* 000002F7 call 0x3ad                     */  0xE8, 0xB3, 0x00,
+  /* 000002FA pop si                         */  0x5E,
+  /* 000002FB jmp short 0x319                */  0xEB, 0x1C,
+  /* 000002FD push si                        */  0x56,
+  /* 000002FE mov si,0x47d                   */  0xBE, 0x7D, 0x04,
+  /* 00000301 call 0x3ad                     */  0xE8, 0xA9, 0x00,
+  /* 00000304 pop si                         */  0x5E,
+  /* 00000305 jmp short 0x319                */  0xEB, 0x12,
+  /* 00000307 push si                        */  0x56,
+  /* 00000308 mov si,0x48f                   */  0xBE, 0x8F, 0x04,
+  /* 0000030B call 0x3ad                     */  0xE8, 0x9F, 0x00,
+  /* 0000030E pop si                         */  0x5E,
+  /* 0000030F jmp short 0x319                */  0xEB, 0x08,
+  /* 00000311 push si                        */  0x56,
+  /* 00000312 mov si,0x4a2                   */  0xBE, 0xA2, 0x04,
+  /* 00000315 call 0x3ad                     */  0xE8, 0x95, 0x00,
+  /* 00000318 pop si                         */  0x5E,
+  /* 00000319 mov [0x4b0],bl                 */  0x88, 0x1E, 0xB0, 0x04,
+  /* 0000031D mov [0x4b1],bh                 */  0x88, 0x3E, 0xB1, 0x04,
+  /* 00000321 pop ax                         */  0x58,
+  /* 00000322 pop dx                         */  0x5A,
+  /* 00000323 jmp short 0x395                */  0xEB, 0x70,
+  /* 00000325 push si                        */  0x56,
+  /* 00000326 mov si,0x405                   */  0xBE, 0x05, 0x04,
+  /* 00000329 call 0x3ad                     */  0xE8, 0x81, 0x00,
+  /* 0000032C pop si                         */  0x5E,
+  /* 0000032D mov bl,[0x4b0]                 */  0x8A, 0x1E, 0xB0, 0x04,
+  /* 00000331 mov bh,[0x4b1]                 */  0x8A, 0x3E, 0xB1, 0x04,
+  /* 00000335 jmp short 0x395                */  0xEB, 0x5E,
+  /* 00000337 push si                        */  0x56,
+  /* 00000338 mov si,0x43b                   */  0xBE, 0x3B, 0x04,
+  /* 0000033B call 0x3ad                     */  0xE8, 0x6F, 0x00,
+  /* 0000033E pop si                         */  0x5E,
+  /* 0000033F mov bx,0x80                    */  0xBB, 0x80, 0x00,
+  /* 00000342 jmp short 0x395                */  0xEB, 0x51,
+  /* 00000344 push es                        */  0x06,
+  /* 00000345 push di                        */  0x57,
+  /* 00000346 push ds                        */  0x1E,
+  /* 00000347 push si                        */  0x56,
+  /* 00000348 push cx                        */  0x51,
+  /* 00000349 push si                        */  0x56,
+  /* 0000034A mov si,0x450                   */  0xBE, 0x50, 0x04,
+  /* 0000034D call 0x3ad                     */  0xE8, 0x5D, 0x00,
+  /* 00000350 pop si                         */  0x5E,
+  /* 00000351 push cs                        */  0x0E,
+  /* 00000352 pop ds                         */  0x1F,
+  /* 00000353 mov si,0x4b2                   */  0xBE, 0xB2, 0x04,
+  /* 00000356 mov cx,0x80                    */  0xB9, 0x80, 0x00,
+  /* 00000359 cld                            */  0xFC,
+  /* 0000035A rep movsb                      */  0xF3, 0xA4,
+  /* 0000035C pop cx                         */  0x59,
+  /* 0000035D pop si                         */  0x5E,
+  /* 0000035E pop ds                         */  0x1F,
+  /* 0000035F pop di                         */  0x5F,
+  /* 00000360 pop es                         */  0x07,
+  /* 00000361 jmp short 0x395                */  0xEB, 0x32,
+  /* 00000363 push si                        */  0x56,
+  /* 00000364 mov si,0x41b                   */  0xBE, 0x1B, 0x04,
+  /* 00000367 call 0x3ad                     */  0xE8, 0x43, 0x00,
+  /* 0000036A pop si                         */  0x5E,
+  /* 0000036B cmp al,0x3                     */  0x3C, 0x03,
+  /* 0000036D jz 0x37e                       */  0x74, 0x0F,
+  /* 0000036F cmp al,0x12                    */  0x3C, 0x12,
+  /* 00000371 jz 0x38a                       */  0x74, 0x17,
+  /* 00000373 push si                        */  0x56,
+  /* 00000374 mov si,0x42c                   */  0xBE, 0x2C, 0x04,
+  /* 00000377 call 0x3ad                     */  0xE8, 0x33, 0x00,
+  /* 0000037A pop si                         */  0x5E,
+  /* 0000037B jmp 0x235                      */  0xE9, 0xB7, 0xFE,
+  /* 0000037E push si                        */  0x56,
+  /* 0000037F mov si,0x45c                   */  0xBE, 0x5C, 0x04,
+  /* 00000382 call 0x3ad                     */  0xE8, 0x28, 0x00,
+  /* 00000385 pop si                         */  0x5E,
+  /* 00000386 mov al,0x0                     */  0xB0, 0x00,
+  /* 00000388 jmp short 0x38c                */  0xEB, 0x02,
+  /* 0000038A mov al,0x0                     */  0xB0, 0x00,
+  /* 0000038C push si                        */  0x56,
+  /* 0000038D mov si,0x3c2                   */  0xBE, 0xC2, 0x03,
+  /* 00000390 call 0x3ad                     */  0xE8, 0x1A, 0x00,
+  /* 00000393 pop si                         */  0x5E,
+  /* 00000394 iret                           */  0xCF,
+  /* 00000395 push si                        */  0x56,
+  /* 00000396 mov si,0x3c2                   */  0xBE, 0xC2, 0x03,
+  /* 00000399 call 0x3ad                     */  0xE8, 0x11, 0x00,
+  /* 0000039C pop si                         */  0x5E,
+  /* 0000039D mov ax,0x4f                    */  0xB8, 0x4F, 0x00,
+  /* 000003A0 iret                           */  0xCF,
+  /* 000003A1 push si                        */  0x56,
+  /* 000003A2 mov si,0x3c8                   */  0xBE, 0xC8, 0x03,
+  /* 000003A5 call 0x3ad                     */  0xE8, 0x05, 0x00,
+  /* 000003A8 pop si                         */  0x5E,
+  /* 000003A9 mov ax,0x24f                   */  0xB8, 0x4F, 0x02,
+  /* 000003AC iret                           */  0xCF,
+  /* 000003AD pusha                          */  0x60,
+  /* 000003AE push ds                        */  0x1E,
+  /* 000003AF push cs                        */  0x0E,
+  /* 000003B0 pop ds                         */  0x1F,
+  /* 000003B1 mov dx,0x220                   */  0xBA, 0x20, 0x02,
+  /* 000003B4 mov ax,0x0                     */  0xB8, 0x00, 0x00,
+  /* 000003B7 lodsb                          */  0xAC,
+  /* 000003B8 cmp al,0x0                     */  0x3C, 0x00,
+  /* 000003BA jz 0x3bf                       */  0x74, 0x03,
+  /* 000003BC out dx,al                      */  0xEE,
+  /* 000003BD jmp short 0x3b7                */  0xEB, 0xF8,
+  /* 000003BF pop ds                         */  0x1F,
+  /* 000003C0 popa                           */  0x61,
+  /* 000003C1 ret                            */  0xC3,
+  /* 000003C2 jna 0x413                      */  0x76, 0x4F,
+  /* 000003C4 imul cx,[di],byte +0xa         */  0x6B, 0x0D, 0x0A,
+  /* 000003C7 add [bp+0x55],dh               */  0x00, 0x76, 0x55,
+  /* 000003CA outsb                          */  0x6E,
+  /* 000003CB jnc 0x442                      */  0x73, 0x75,
+  /* 000003CD jo 0x43f                       */  0x70, 0x70,
+  /* 000003CF outsw                          */  0x6F,
+  /* 000003D0 jc 0x446                       */  0x72, 0x74,
+  /* 000003D2 fs or ax,0xa                   */  0x65, 0x64, 0x0D, 0x0A, 0x00,
+  /* 000003D7 jna 0x42e                      */  0x76, 0x55,
+  /* 000003D9 outsb                          */  0x6E,
+  /* 000003DA imul bp,[bp+0x6f],byte +0x77   */  0x6B, 0x6E, 0x6F, 0x77,
+  /* 000003DE outsb                          */  0x6E,
+  /* 000003DF and [bp+0x75],al               */  0x20, 0x46, 0x75,
+  /* 000003E2 outsb                          */  0x6E,
+  /* 000003E3 arpl [si+0x69],si              */  0x63, 0x74, 0x69,
+  /* 000003E6 outsw                          */  0x6F,
+  /* 000003E7 outsb                          */  0x6E,
+  /* 000003E8 or ax,0xa                      */  0x0D, 0x0A, 0x00,
+  /* 000003EB jna 0x434                      */  0x76, 0x47,
+  /* 000003ED gs jz 0x439                    */  0x65, 0x74, 0x49,
+  /* 000003F0 outsb                          */  0x6E,
+  /* 000003F1 outsd                          */  0x66, 0x6F,
+  /* 000003F3 or ax,0xa                      */  0x0D, 0x0A, 0x00,
+  /* 000003F6 jna 0x43f                      */  0x76, 0x47,
+  /* 000003F8 gs jz 0x448                    */  0x65, 0x74, 0x4D,
+  /* 000003FB outsw                          */  0x6F,
+  /* 000003FC gs dec cx                      */  0x64, 0x65, 0x49,
+  /* 000003FF outsb                          */  0x6E,
+  /* 00000400 outsd                          */  0x66, 0x6F,
+  /* 00000402 or ax,0xa                      */  0x0D, 0x0A, 0x00,
+  /* 00000405 jna 0x44e                      */  0x76, 0x47,
+  /* 00000407 gs jz 0x457                    */  0x65, 0x74, 0x4D,
+  /* 0000040A outsw                          */  0x6F,
+  /* 0000040B gs or ax,0xa                   */  0x64, 0x65, 0x0D, 0x0A, 0x00,
+  /* 00000410 jna 0x465                      */  0x76, 0x53,
+  /* 00000412 gs jz 0x462                    */  0x65, 0x74, 0x4D,
+  /* 00000415 outsw                          */  0x6F,
+  /* 00000416 gs or ax,0xa                   */  0x64, 0x65, 0x0D, 0x0A, 0x00,
+  /* 0000041B jna 0x470                      */  0x76, 0x53,
+  /* 0000041D gs jz 0x46d                    */  0x65, 0x74, 0x4D,
+  /* 00000420 outsw                          */  0x6F,
+  /* 00000421 gs dec sp                      */  0x64, 0x65, 0x4C,
+  /* 00000424 gs a32 popa                    */  0x65, 0x67, 0x61,
+  /* 00000427 arpl [bx+di+0xd],di            */  0x63, 0x79, 0x0D,
+  /* 0000042A or al,[bx+si]                  */  0x0A, 0x00,
+  /* 0000042C jna 0x483                      */  0x76, 0x55,
+  /* 0000042E outsb                          */  0x6E,
+  /* 0000042F imul bp,[bx+0x77],byte +0x6e   */  0x6B, 0x6F, 0x77, 0x6E,
+  /* 00000433 and [di+0x6f],cl               */  0x20, 0x4D, 0x6F,
+  /* 00000436 gs or ax,0xa                   */  0x64, 0x65, 0x0D, 0x0A, 0x00,
+  /* 0000043B jna 0x484                      */  0x76, 0x47,
+  /* 0000043D gs jz 0x490                    */  0x65, 0x74, 0x50,
+  /* 00000440 insw                           */  0x6D,
+  /* 00000441 inc bx                         */  0x43,
+  /* 00000442 popa                           */  0x61,
+  /* 00000443 jo 0x4a6                       */  0x70, 0x61,
+  /* 00000445 bound bp,[bx+di+0x6c]          */  0x62, 0x69, 0x6C,
+  /* 00000448 imul si,[si+0x69],word 0x7365  */  0x69, 0x74, 0x69, 0x65, 0x73,
+  /* 0000044D or ax,0xa                      */  0x0D, 0x0A, 0x00,
+  /* 00000450 jna 0x4a4                      */  0x76, 0x52,
+  /* 00000452 gs popa                        */  0x65, 0x61,
+  /* 00000454 fs inc bp                      */  0x64, 0x45,
+  /* 00000456 imul sp,[fs:si+0xd],word 0xa   */  0x64, 0x69, 0x64, 0x0D, 0x0A, 0x00,
+  /* 0000045C jna 0x4aa                      */  0x76, 0x4C,
+  /* 0000045E gs a32 popa                    */  0x65, 0x67, 0x61,
+  /* 00000461 arpl [bx+di+0x4d],di           */  0x63, 0x79, 0x4D,
+  /* 00000464 outsw                          */  0x6F,
+  /* 00000465 xor cx,[gs:di]                 */  0x64, 0x65, 0x33, 0x0D,
+  /* 00000469 or al,[bx+si]                  */  0x0A, 0x00,
+  /* 0000046B insw                           */  0x6D,
+  /* 0000046C outsw                          */  0x6F,
+  /* 0000046D gs pop di                      */  0x64, 0x65, 0x5F,
+  /* 00000470 ss xor al,0x30                 */  0x36, 0x34, 0x30,
+  /* 00000473 js 0x4a9                       */  0x78, 0x34,
+  /* 00000475 cmp [bx+si],dh                 */  0x38, 0x30,
+  /* 00000477 js 0x4ac                       */  0x78, 0x33,
+  /* 00000479 xor cl,[di]                    */  0x32, 0x0D,
+  /* 0000047B or al,[bx+si]                  */  0x0A, 0x00,
+  /* 0000047D insw                           */  0x6D,
+  /* 0000047E outsw                          */  0x6F,
+  /* 0000047F gs pop di                      */  0x64, 0x65, 0x5F,
+  /* 00000482 cmp [bx+si],dh                 */  0x38, 0x30,
+  /* 00000484 xor [bx+si+0x36],bh            */  0x30, 0x78, 0x36,
+  /* 00000487 xor [bx+si],dh                 */  0x30, 0x30,
+  /* 00000489 js 0x4be                       */  0x78, 0x33,
+  /* 0000048B xor cl,[di]                    */  0x32, 0x0D,
+  /* 0000048D or al,[bx+si]                  */  0x0A, 0x00,
+  /* 0000048F insw                           */  0x6D,
+  /* 00000490 outsw                          */  0x6F,
+  /* 00000491 gs pop di                      */  0x64, 0x65, 0x5F,
+  /* 00000494 xor [bx+si],si                 */  0x31, 0x30,
+  /* 00000496 xor dh,[si]                    */  0x32, 0x34,
+  /* 00000498 js 0x4d1                       */  0x78, 0x37,
+  /* 0000049A cmp [ss:bx+si+0x33],bh         */  0x36, 0x38, 0x78, 0x33,
+  /* 0000049E xor cl,[di]                    */  0x32, 0x0D,
+  /* 000004A0 or al,[bx+si]                  */  0x0A, 0x00,
+  /* 000004A2 insw                           */  0x6D,
+  /* 000004A3 outsw                          */  0x6F,
+  /* 000004A4 gs pop di                      */  0x64, 0x65, 0x5F,
+  /* 000004A7 jnz 0x517                      */  0x75, 0x6E,
+  /* 000004A9 jnz 0x51e                      */  0x75, 0x73,
+  /* 000004AB fs or ax,0xa                   */  0x65, 0x64, 0x0D, 0x0A, 0x00,
+  /* 000004B0 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004B2 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004B4 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004B6 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004B8 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004BA add [bx+si],al                 */  0x00, 0x00,
+  /* 000004BC add [bx+si],al                 */  0x00, 0x00,
+  /* 000004BE add [bx+si],al                 */  0x00, 0x00,
+  /* 000004C0 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004C2 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004C4 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004C6 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004C8 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004CA add [bx+si],al                 */  0x00, 0x00,
+  /* 000004CC add [bx+si],al                 */  0x00, 0x00,
+  /* 000004CE add [bx+si],al                 */  0x00, 0x00,
+  /* 000004D0 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004D2 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004D4 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004D6 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004D8 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004DA add [bx+si],al                 */  0x00, 0x00,
+  /* 000004DC add [bx+si],al                 */  0x00, 0x00,
+  /* 000004DE add [bx+si],al                 */  0x00, 0x00,
+  /* 000004E0 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004E2 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004E4 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004E6 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004E8 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004EA add [bx+si],al                 */  0x00, 0x00,
+  /* 000004EC add [bx+si],al                 */  0x00, 0x00,
+  /* 000004EE add [bx+si],al                 */  0x00, 0x00,
+  /* 000004F0 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004F2 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004F4 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004F6 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004F8 add [bx+si],al                 */  0x00, 0x00,
+  /* 000004FA add [bx+si],al                 */  0x00, 0x00,
+  /* 000004FC add [bx+si],al                 */  0x00, 0x00,
+  /* 000004FE add [bx+si],al                 */  0x00, 0x00,
+  /* 00000500 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000502 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000504 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000506 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000508 add [bx+si],al                 */  0x00, 0x00,
+  /* 0000050A add [bx+si],al                 */  0x00, 0x00,
+  /* 0000050C add [bx+si],al                 */  0x00, 0x00,
+  /* 0000050E add [bx+si],al                 */  0x00, 0x00,
+  /* 00000510 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000512 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000514 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000516 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000518 add [bx+si],al                 */  0x00, 0x00,
+  /* 0000051A add [bx+si],al                 */  0x00, 0x00,
+  /* 0000051C add [bx+si],al                 */  0x00, 0x00,
+  /* 0000051E add [bx+si],al                 */  0x00, 0x00,
+  /* 00000520 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000522 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000524 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000526 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000528 add [bx+si],al                 */  0x00, 0x00,
+  /* 0000052A add [bx+si],al                 */  0x00, 0x00,
+  /* 0000052C add [bx+si],al                 */  0x00, 0x00,
+  /* 0000052E add [bx+si],al                 */  0x00, 0x00,
+  /* 00000530 add [bx+si],al                 */  0x00, 0x00,
+  /* 00000532 add [bx+si],al                 */  0x00, 0x00,
+};
+#endif
diff --git a/OvmfPkg/IntelGvtGopDxe/VbeShim.sh b/OvmfPkg/IntelGvtGopDxe/VbeShim.sh
new file mode 100755
index 000000000000..4f61e5220b01
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/VbeShim.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+###
+# @file
+# Shell script to assemble and dump the fake Int10h handler from NASM source to
+# a C array.
+#
+# Copyright (C) 2021, Intel Corporation. All rights reserved.<BR>
+# Copyright (C) 2020, Rebecca Cran <rebecca@bsdio.com>
+# Copyright (C) 2014, Red Hat, Inc.
+# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+###
+
+set -e -u
+
+STEM=$(dirname -- "$0")/$(basename -- "$0" .sh)
+
+#
+# Install exit handler -- remove temporary files.
+#
+exit_handler()
+{
+  rm -f -- "$STEM".bin "$STEM".disasm "$STEM".offsets "$STEM".insns \
+      "$STEM".bytes
+}
+trap exit_handler EXIT
+
+#
+# Assemble the source file.
+#
+nasm -o "$STEM".bin "$STEM".asm
+
+#
+# Disassemble it, in order to get a binary dump associated with the source.
+# (ndisasm doesn't recognize the "--" end-of-options delimiter.)
+#
+ndisasm "$STEM".bin >"$STEM".disasm
+
+#
+# Create three files, each with one column of the disassembly.
+#
+# The first column contains the offsets, and it starts the comment.
+#
+cut -c 1-8 -- "$STEM".disasm \
+| sed -e 's,^,  /* ,' >"$STEM".offsets
+
+#
+# The second column contains the assembly-language instructions, and it closes
+# the comment. We first pad it to 30 characters.
+#
+cut -c 29- -- "$STEM".disasm \
+| sed -e 's,$,                              ,' \
+      -e 's,^\(.\{30\}\).*$,\1 */,' >"$STEM".insns
+
+#
+# The third column contains the bytes corresponding to the instruction,
+# represented as C integer constants. First strip trailing whitespace from the
+# middle column of the input disassembly, then process pairs of nibbles.
+#
+cut -c 11-28 -- "$STEM".disasm \
+| sed -e 's, \+$,,' -e 's/\(..\)/ 0x\1,/g' | sed 's/0x  ,//g' >"$STEM".bytes
+
+#
+# Write the output file, recombining the columns. The output should have CRLF
+# line endings.
+#
+{
+  printf '//\n'
+  printf '// THIS FILE WAS GENERATED BY "%s". DO NOT EDIT.\n' \
+      "$(basename -- "$0")"
+  printf '//\n'
+  printf '#ifndef _VBE_SHIM_H_\n'
+  printf '#define _VBE_SHIM_H_\n'
+  printf 'STATIC CONST UINT8 gVbeShim[] = {\n'
+  paste -d ' ' -- "$STEM".offsets "$STEM".insns "$STEM".bytes
+  printf '};\n'
+  printf '#endif\n'
+} \
+| unix2dos >"$STEM".h
diff --git a/OvmfPkg/IntelGvtGopDxe/VirtualGpu.c b/OvmfPkg/IntelGvtGopDxe/VirtualGpu.c
new file mode 100644
index 000000000000..dc2c23706c8b
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/VirtualGpu.c
@@ -0,0 +1,400 @@
+/** @file
+  Component name for the QEMU video controller.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Common.h"
+#include "VirtualGpu.h"
+#include "GpuReg.h"
+#include "Gtt.h"
+#include "Display.h"
+#include <Library/QemuFwCfgLib.h>
+
+EFI_STATUS
+IntelVirtualGpuActive (
+  IN EFI_PCI_IO_PROTOCOL *PciIo
+  )
+{
+  EFI_STATUS Status = EFI_UNSUPPORTED;
+  PCI_TYPE00 PciHdr = {0};
+  UINT64     Magic = 0;
+  UINT32     Version = 0;
+  UINT16     VerMajor = 0, VerMinor = 0;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        0,
+                        sizeof (PciHdr) / sizeof (UINT32),
+                        &PciHdr
+                        );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Can't read PCI config header, status %d\n", Status
+      );
+    Status = EFI_UNSUPPORTED;
+    goto Done;
+  }
+
+  if (!IS_PCI_DISPLAY (&PciHdr) || PciHdr.Hdr.VendorId != 0x8086) {
+    GVT_DEBUG (EFI_D_VERBOSE,
+      "Skip non Intel PCI Display [%04x:%04x] class:%x\n",
+      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, PciHdr.Hdr.ClassCode[2]
+      );
+    Status = EFI_UNSUPPORTED;
+    goto Done;
+  }
+
+  Status = PciIo->Mem.Read (
+                        PciIo,
+                        EfiPciIoWidthUint64,
+                        PCI_BAR_IDX0,
+                        vgtif_reg(magic),
+                        1,
+                        &Magic
+                        );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Can't read GVT magic from [%04x:%04x], status %d\n",
+      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, Status
+      );
+    Status = EFI_UNSUPPORTED;
+    goto Done;
+  }
+
+  if (Magic != VGT_MAGIC) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Read magic from [%04x:%04x], get %x expect %x\n",
+      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, Magic, VGT_MAGIC
+      );
+    Status = EFI_UNSUPPORTED;
+    goto Done;
+  }
+
+  Status = PciIo->Mem.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_BAR_IDX0,
+                        vgtif_reg(version_major),
+                        1,
+                        &Version
+                        );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Can't read GVT version from [%04x:%04x], status %d\n",
+      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, Status
+      );
+    Status = EFI_UNSUPPORTED;
+    goto Done;
+  }
+
+  VerMajor = Version & 0xFFFF;
+  VerMinor = (Version & 0xFFFF) >> 16;
+  if (VerMajor < VGT_VERSION_MAJOR) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Check VGT interface version of [%04x:%04x], got %x.%x, expect %x.*\n",
+      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId,
+      VerMajor, VerMinor, VGT_VERSION_MAJOR
+      );
+    Status = EFI_UNSUPPORTED;
+    goto Done;
+  }
+
+  GVT_DEBUG (EFI_D_INFO,
+    "Intel GVT-g virtual GPU [%04x:%04x] detected, version %x.%x\n",
+    PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, VerMajor, VerMinor
+    );
+  Status = EFI_SUCCESS;
+
+Done:
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
+
+EFI_STATUS
+IntelVirtualGpuInit (
+  IN OUT GVT_GOP_PRIVATE_DATA *Private
+  )
+{
+  EFI_STATUS           Status = EFI_UNSUPPORTED;
+  EFI_PCI_IO_PROTOCOL  *PciIo;
+  PINTEL_VIRTUAL_GPU   VirtualGpu;
+  FIRMWARE_CONFIG_ITEM FwCfgItem;
+  UINTN                FwCfgSize;
+  UINT8                Val8;
+  UINT64               Val64;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  PciIo = Private->PciIo;
+  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint16,
+                        PCI_VENDOR_ID_OFFSET,
+                        1,
+                        &VirtualGpu->VendorId
+                        );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Can't read PCI_VENDOR_ID_OFFSET, status %d\n", Status
+      );
+    goto Done;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint16,
+                        PCI_DEVICE_ID_OFFSET,
+                        1,
+                        &VirtualGpu->DeviceId
+                        );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Can't read PCI_DEVICE_ID_OFFSET, status %d\n", Status
+      );
+    goto Done;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint64,
+                        PCI_BASE_ADDRESSREG_OFFSET + PCI_BAR_IDX2 * 4,
+                        1,
+                        &Val64
+                        );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR, "Can't get GMADR from BAR2, status %d\n", Status);
+    goto Done;
+  }
+
+  if (Val64 & 0x1) {
+    Status = EFI_OUT_OF_RESOURCES;
+    GVT_DEBUG (EFI_D_ERROR, "BAR2 isn't memory space, status %d\n", Status);
+    goto Done;
+  }
+
+  switch (Val64 >> 1 & 0x3) {
+  case 0:
+    VirtualGpu->GpuMemAddr = Val64 & 0xFFFFFFF0;
+    GVT_DEBUG (EFI_D_VERBOSE, "BAR2 has 32-bit access space\n");
+    break;
+  case 2:
+    VirtualGpu->GpuMemAddr = Val64 & ~0xF;
+    GVT_DEBUG (EFI_D_VERBOSE, "BAR2 has 64-bit access space\n");
+    break;
+  default:
+    Status = EFI_OUT_OF_RESOURCES;
+    GVT_DEBUG (EFI_D_ERROR,
+      "BAR2 has unknown access space, status %d\n", Status
+      );
+    goto Done;
+    break;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint8,
+                        PCI_REG_MSAC,
+                        1,
+                        &Val8
+                        );
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Can't get MSAC from %x, status %d\n", PCI_REG_MSAC, Status
+      );
+    goto Done;
+  }
+
+  Val8 &= 0x1F;
+  if (Val8 & 0x10) {
+    VirtualGpu->GpuMemSizeM = 4096;
+  } else {
+    Val8 &= 0xF;
+    if (Val8 & 0x8) {
+      VirtualGpu->GpuMemSizeM = 2048;
+    } else {
+      Val8 &= 0x7;
+      if (Val8 & 0x4) {
+        VirtualGpu->GpuMemSizeM = 1024;
+      } else {
+        Val8 &= 0x3;
+        if (Val8 & 0x2) {
+          VirtualGpu->GpuMemSizeM = 512;
+        } else {
+          if (Val8 & 0x1) {
+            VirtualGpu->GpuMemSizeM = 256;
+          } else {
+            VirtualGpu->GpuMemSizeM = 128;
+          }
+        }
+      }
+    }
+  }
+
+  Status = QemuFwCfgFindFile ("etc/igd-opregion", &FwCfgItem, &FwCfgSize);
+  if (Status == EFI_SUCCESS && FwCfgSize == OPREGION_SIZE) {
+    // OpRegion must sit below 4 GB
+    VirtualGpu->OpRegion = SIZE_4GB - 1;
+    Status = gBS->AllocatePages (
+                AllocateMaxAddress,
+                EfiReservedMemoryType,
+                EFI_SIZE_TO_PAGES (OPREGION_SIZE),
+                &VirtualGpu->OpRegion
+                );
+    if (EFI_ERROR (Status)) {
+      GVT_DEBUG (EFI_D_ERROR,
+        "Fail to allocate %d pages size %lx for OpRegion, status %d\n",
+        EFI_SIZE_TO_PAGES (OPREGION_SIZE), OPREGION_SIZE, Status
+        );
+      goto Done;
+    }
+    QemuFwCfgSelectItem (FwCfgItem);
+    QemuFwCfgReadBytes (FwCfgSize, (VOID*)VirtualGpu->OpRegion);
+    Status = PciIo->Pci.Write (
+                          PciIo,
+                          EfiPciIoWidthUint32,
+                          PCI_REG_ASLS,
+                          1,
+                          (UINT32*)&VirtualGpu->OpRegion
+                          );
+    if (EFI_ERROR (Status)) {
+      GVT_DEBUG (EFI_D_ERROR,
+        "Fail to write OpRegion %p to PCI config offset 0x%x, status %d\n",
+        VirtualGpu->OpRegion, PCI_REG_ASLS, Status
+        );
+      goto Done;
+    } else {
+      GVT_DEBUG (EFI_D_INFO,
+        "OpRegion %p is set to PCI config offset 0x%x\n",
+        VirtualGpu->OpRegion, PCI_REG_ASLS
+        );
+    }
+  } else {
+    GVT_DEBUG (EFI_D_VERBOSE,
+      "Not igd-opregion found in QEMU firmware config\n"
+      );
+  }
+
+  RegRead32 (Private,
+    vgtif_reg(avail_rs.mappable_gmadr.base), &VirtualGpu->VisibleOffset);
+  RegRead32 (Private,
+    vgtif_reg(avail_rs.mappable_gmadr.size), &VirtualGpu->VisibleSize);
+  RegRead32 (Private,
+    vgtif_reg(avail_rs.nonmappable_gmadr.base), &VirtualGpu->InvisibleOffset);
+  RegRead32 (Private,
+    vgtif_reg(avail_rs.nonmappable_gmadr.size), &VirtualGpu->InvisibleSize);
+  VirtualGpu->VisibleGGTTOffset = VirtualGpu->VisibleOffset >> GTT_PAGE_SHIFT;
+  VirtualGpu->VisibleGGTTSize = VirtualGpu->VisibleSize >> GTT_PAGE_SHIFT;
+  VirtualGpu->InvisibleGGTTOffset = VirtualGpu->InvisibleOffset >> GTT_PAGE_SHIFT;
+  VirtualGpu->InvisibleGGTTSize = VirtualGpu->InvisibleSize >> GTT_PAGE_SHIFT;
+
+  GVT_DEBUG (
+    EFI_D_INFO,
+    "GMADR [0x%lx - 0x%lx], size %d MB\n",
+    VirtualGpu->GpuMemAddr,
+    VirtualGpu->GpuMemAddr + VirtualGpu->GpuMemSizeM * 0x100000,
+    VirtualGpu->GpuMemSizeM
+    );
+  GVT_DEBUG (
+    EFI_D_INFO,
+    "visible offset [0x%x - 0x%x] size %d KB, GGTT range [%x - %x]\n",
+    VirtualGpu->VisibleOffset,
+    VirtualGpu->VisibleOffset + VirtualGpu->VisibleSize,
+    VirtualGpu->VisibleSize / 0x400,
+    VirtualGpu->VisibleGGTTOffset,
+    VirtualGpu->VisibleGGTTOffset + VirtualGpu->VisibleGGTTSize
+    );
+  GVT_DEBUG (
+    EFI_D_INFO,
+    "invisible offset [0x%x - 0x%x] size %d KB, GGTT range [%x - %x]\n",
+    VirtualGpu->InvisibleOffset,
+    VirtualGpu->InvisibleOffset + VirtualGpu->InvisibleSize,
+    VirtualGpu->InvisibleSize / 0x400,
+    VirtualGpu->InvisibleGGTTOffset,
+    VirtualGpu->InvisibleGGTTOffset + VirtualGpu->InvisibleGGTTSize
+    );
+
+  Status = IntelVirtualGpuDisplayInit (Private);
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Fail to initialize display, status %d\n", Status
+      );
+    goto Done;
+  }
+
+  Status = IntelVirtualGpuSetMode (&Private->GraphicsOutputProtocol, 0);
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Fail to set init display mode, status %d\n", Status
+      );
+    goto Done;
+  }
+
+  Status = IntelVirtualGpuNotifyDisplayReady (Private, TRUE);
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR,
+      "Fail to notify display ready, status %d\n", Status
+      );
+    goto Done;
+  }
+
+  // Flush all reg after DisplayReady
+  Status = IntelVirtualGpuEnableDisplay (
+             Private,
+             0,
+             TRUE
+             );
+
+Done:
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
+
+EFI_STATUS
+IntelVirtualGpuClean (
+  IN OUT GVT_GOP_PRIVATE_DATA *Private
+  )
+{
+  EFI_STATUS         Status = EFI_INVALID_PARAMETER;
+  PINTEL_VIRTUAL_GPU VirtualGpu;
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
+
+  Status = IntelVirtualGpuDisplayClean (Private);
+  if (EFI_ERROR (Status)) {
+    GVT_DEBUG (EFI_D_ERROR, "Fail to clean display, status %d\n", Status);
+    goto Done;
+  }
+
+  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
+  if (VirtualGpu->OpRegion) {
+    Status = gBS->FreePages (
+                    VirtualGpu->OpRegion,
+                    EFI_SIZE_TO_PAGES (OPREGION_SIZE)
+                    );
+    if (EFI_ERROR (Status)) {
+      GVT_DEBUG (EFI_D_ERROR,
+        "FreePages failed for OpRegion, pages %d, size %d, status %d\n",
+        EFI_SIZE_TO_PAGES (OPREGION_SIZE), OPREGION_SIZE, Status
+        );
+        goto Done;
+    }
+    Status = EFI_SUCCESS;
+  }
+
+Done:
+
+  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
+
+  return Status;
+}
diff --git a/OvmfPkg/IntelGvtGopDxe/VirtualGpu.h b/OvmfPkg/IntelGvtGopDxe/VirtualGpu.h
new file mode 100644
index 000000000000..60d80eadb3ac
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/VirtualGpu.h
@@ -0,0 +1,52 @@
+/** @file
+  Component name for the QEMU video controller.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VIRTUALGPU_H_
+#define __VIRTUALGPU_H_
+
+#include <Display.h>
+
+#define PCI_REG_MSAC 0x62
+#define PCI_REG_ASLS 0xFC
+
+#define OPREGION_SIZE SIZE_8KB
+
+typedef struct _INTEL_VIRTUAL_GPU {
+  UINT16                    VendorId;
+  UINT16                    DeviceId;
+  EFI_PHYSICAL_ADDRESS      OpRegion;
+  EFI_PHYSICAL_ADDRESS      GpuMemAddr;
+  UINT32                    GpuMemSizeM;
+  UINT32                    VisibleOffset;
+  UINT32                    VisibleSize;
+  UINT32                    VisibleGGTTOffset;
+  UINT32                    VisibleGGTTSize;
+  UINT32                    InvisibleOffset;
+  UINT32                    InvisibleSize;
+  UINT32                    InvisibleGGTTOffset;
+  UINT32                    InvisibleGGTTSize;
+  INTEL_VIRTUAL_GPU_DISPLAY Display;
+} INTEL_VIRTUAL_GPU, *PINTEL_VIRTUAL_GPU;
+
+EFI_STATUS
+IntelVirtualGpuActive (
+  IN EFI_PCI_IO_PROTOCOL *PciIo
+  );
+
+EFI_STATUS
+IntelVirtualGpuInit (
+  IN OUT GVT_GOP_PRIVATE_DATA *Private
+  );
+
+EFI_STATUS
+IntelVirtualGpuClean (
+  IN OUT GVT_GOP_PRIVATE_DATA *Private
+  );
+
+#endif //__VIRTUALGPU_H_
-- 
2.30.1


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

* [PATCH v2 2/2] OvmfPkg/IntelGvtGopDxe: Enable GVT-g GOP in OvmfPkg DSC & DFD.
  2021-03-05  6:20 [PATCH v2 0/2] OvmfPkg/IntelGvtGopDxe: Add Intel GVT-g GOP Colin Xu
  2021-03-05  6:20 ` [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation Colin Xu
@ 2021-03-05  6:20 ` Colin Xu
  1 sibling, 0 replies; 11+ messages in thread
From: Colin Xu @ 2021-03-05  6:20 UTC (permalink / raw)
  To: devel; +Cc: rebecca, colin.xu

Intel GVT-g is already enabled by default in upstream kernel.

V2:
Refresh.

Signed-off-by: Colin Xu <colin.xu@intel.com>
---
 OvmfPkg/OvmfPkgX64.dsc | 4 ++++
 OvmfPkg/OvmfPkgX64.fdf | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index fabb8b2f29e4..971fd262151b 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -52,6 +52,7 @@
   DEFINE PVSCSI_ENABLE           = TRUE
   DEFINE MPT_SCSI_ENABLE         = TRUE
   DEFINE LSI_SCSI_ENABLE         = FALSE
+  DEFINE INTEL_GVT_KVMGT_ENABLE  = TRUE
 
   #
   # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to
@@ -808,6 +809,9 @@
 !endif
 !if $(LSI_SCSI_ENABLE) == TRUE
   OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
+!endif
+!if $(INTEL_GVT_KVMGT_ENABLE) == TRUE
+  OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf
 !endif
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
   MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index d519f8532822..6d0bcf3fcd31 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -252,6 +252,9 @@ INF  OvmfPkg/MptScsiDxe/MptScsiDxe.inf
 !if $(LSI_SCSI_ENABLE) == TRUE
 INF  OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
 !endif
+!if $(INTEL_GVT_KVMGT_ENABLE) == TRUE
+INF  OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf
+!endif
 
 !if $(SECURE_BOOT_ENABLE) == TRUE
   INF  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
-- 
2.30.1


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

* Re: [edk2-devel] [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation.
  2021-03-05  6:20 ` [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation Colin Xu
@ 2021-03-05 13:19   ` Laszlo Ersek
  2021-03-12  3:57     ` Colin Xu
  2021-03-12  4:42     ` Rebecca Cran
  0 siblings, 2 replies; 11+ messages in thread
From: Laszlo Ersek @ 2021-03-05 13:19 UTC (permalink / raw)
  To: devel, colin.xu; +Cc: rebecca, Gerd Hoffmann, Alex Williamson

Adding Gerd and Alex; some comments below (near the end of the patch --
keeping full context for Gerd's and Alex's sake):

On 03/05/21 07:20, Colin Xu wrote:
> Intel GVT-g GOP DXE supports OVMF GOP output its frame buffer to vGPU
> partitioned aperture mapped by GGTT, so that the GOP output can be
> mediated to its backend for display (i.e. QEMU GTK display via dma-buf).
> 
> Unlike ACRN GVT-d integrating native GOP/VBT into it's OVMF, the GVT-g
> GOP is an open-source implementation which follows Intel GVT-g framework
> to interact with KVMGT in host kernel so that the GOP frame buffer
> content can be processed properly.
> 
> With GVT-g GOP enabled OVMF, guest VM can output its framebuffer
> content to KVMGT via GOP, with a proper backend support (i.e. QEMU GTK
> display with dma-buf), the following content is now directly visible to
> user unlike previosly need a second GPU:
> - OVMF EFI Shell
> - Bootloader (i.e. grub)
> - OS installation progress. (before built-in GFX driver loaded)
> - Pre GFX Driver display (i.e. Android/Linux boot splash or logo,
>   Windows 8.1 boot progress/safe mode/recovery mode/BSOD/GPU-disabled
>   desktop, etc.)
> 
> GVT-g GOP has below capabilites:
> - Check GVT-g compatibility via PV info, only enable GVT-g GOP when it's
>   compatible with KVMGT.
> - R/W MMIO from BAR0.
> - R/W Global GTT from BAR0.
> - Reserve and program OpRegion address at ASLS location so that guest
>   driver can decode GVT-g simluated VBT and enabled display properly.
> - Reserve guest memory and map to BAR2 partitioned range with proper
>   GGTT, so that KVMGT can access via proper guest GTT to host GGTT map.
> - All supported EFI_GRAPHICS_OUTPUT_BLT_OPERATION from/to video memory.
> - Enable/disable GOP content on PIPE_A, PLANE_PRIMARY with proper scaling.
> - VBE Shim so that some OS can query non-empty mode info via INT10 call
>   to enable the desktop when GPU is disabled.
> 
> V2:
> Program PIPESRC to match active H/V.
> 
> Signed-off-by: Colin Xu <colin.xu@intel.com>
> ---
>  OvmfPkg/IntelGvtGopDxe/Common.h           |   45 +
>  OvmfPkg/IntelGvtGopDxe/DebugHelper.h      |   20 +
>  OvmfPkg/IntelGvtGopDxe/Display.c          | 1077 +++++++++++++++++++++
>  OvmfPkg/IntelGvtGopDxe/Display.h          |  141 +++
>  OvmfPkg/IntelGvtGopDxe/GopDriver.c        |  478 +++++++++
>  OvmfPkg/IntelGvtGopDxe/GpuReg.c           |   91 ++
>  OvmfPkg/IntelGvtGopDxe/GpuReg.h           |  175 ++++
>  OvmfPkg/IntelGvtGopDxe/Gtt.c              |  162 ++++
>  OvmfPkg/IntelGvtGopDxe/Gtt.h              |   51 +
>  OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf |   59 ++
>  OvmfPkg/IntelGvtGopDxe/VbeShim.asm        |  343 +++++++
>  OvmfPkg/IntelGvtGopDxe/VbeShim.c          |  258 +++++
>  OvmfPkg/IntelGvtGopDxe/VbeShim.h          |  912 +++++++++++++++++
>  OvmfPkg/IntelGvtGopDxe/VbeShim.sh         |   81 ++
>  OvmfPkg/IntelGvtGopDxe/VirtualGpu.c       |  400 ++++++++
>  OvmfPkg/IntelGvtGopDxe/VirtualGpu.h       |   52 +
>  16 files changed, 4345 insertions(+)
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/Common.h
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/DebugHelper.h
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/Display.c
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/Display.h
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/GopDriver.c
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/GpuReg.c
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/GpuReg.h
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/Gtt.c
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/Gtt.h
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/VbeShim.asm
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/VbeShim.c
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/VbeShim.h
>  create mode 100755 OvmfPkg/IntelGvtGopDxe/VbeShim.sh
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/VirtualGpu.c
>  create mode 100644 OvmfPkg/IntelGvtGopDxe/VirtualGpu.h
> 
> diff --git a/OvmfPkg/IntelGvtGopDxe/Common.h b/OvmfPkg/IntelGvtGopDxe/Common.h
> new file mode 100644
> index 000000000000..cf30752eb8f3
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/Common.h
> @@ -0,0 +1,45 @@
> +/** @file
> +  Component name for the QEMU video controller.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __COMMON_H_
> +
> +#include <Protocol/PciIo.h>
> +#include <Protocol/DevicePath.h>
> +#include <Protocol/GraphicsOutput.h>
> +
> +#include <Library/BaseLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/DevicePathLib.h>
> +
> +#include <IndustryStandard/Pci.h>
> +
> +#include "DebugHelper.h"
> +
> +#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
> +
> +typedef struct {
> +  UINT64                       Signature;
> +  EFI_HANDLE                   Handle;
> +  EFI_PCI_IO_PROTOCOL          *PciIo;
> +  UINT64                       OriginalPciAttr;
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutputProtocol;
> +  EFI_DEVICE_PATH_PROTOCOL     *GopDevPath;
> +  VOID                         *VirtualGpu;
> +} GVT_GOP_PRIVATE_DATA;
> +
> +#define GVT_GOP_MAGIC                     SIGNATURE_64('G','V','T','G','V','G','O','P')
> +#define GVT_GOP_PRIVATE_DATA_FROM_THIS(a) CR(a, GVT_GOP_PRIVATE_DATA, GraphicsOutputProtocol, GVT_GOP_MAGIC)
> +
> +#define __COMMON_H_
> +#endif //__COMMON_H_
> diff --git a/OvmfPkg/IntelGvtGopDxe/DebugHelper.h b/OvmfPkg/IntelGvtGopDxe/DebugHelper.h
> new file mode 100644
> index 000000000000..75158d713ec3
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/DebugHelper.h
> @@ -0,0 +1,20 @@
> +/** @file
> +  Component name for the QEMU video controller.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __DEBUGHELPER_H_
> +#define __DEBUGHELPER_H_
> +
> +#include <Library/DebugLib.h>
> +
> +#define GVT_DEBUG(ErrLevel, Fmt, Args...) \
> +  do { \
> +    DEBUG ((ErrLevel, "GvtGop: "Fmt, ##Args));\
> +  } while (FALSE)
> +
> +#endif //__DEBUGHELPER_H_
> diff --git a/OvmfPkg/IntelGvtGopDxe/Display.c b/OvmfPkg/IntelGvtGopDxe/Display.c
> new file mode 100644
> index 000000000000..133de25ff03c
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/Display.c
> @@ -0,0 +1,1077 @@
> +/** @file
> +  Component name for the QEMU video controller.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Common.h"
> +#include "Display.h"
> +#include "GpuReg.h"
> +#include "Gtt.h"
> +#include "VirtualGpu.h"
> +
> +EFI_STATUS
> +IntelVirtualGpuDisplayInit (
> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
> +  )
> +{
> +  EFI_STATUS                 Status = EFI_UNSUPPORTED;
> +  PINTEL_VIRTUAL_GPU         VirtualGpu;
> +  PINTEL_VIRTUAL_GPU_DISPLAY Display;
> +  UINT32                     Val32;
> +  UINTN                      Width, Height, ModeNumber;
> +  EFI_TPL                    OriginalTPL;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
> +  Display = &VirtualGpu->Display;
> +
> +  /*
> +   * If PcdVideoHorizontalResolution or PcdVideoVerticalResolution is not set,
> +   *   GOP will query the mode list reported to find the highest resolution.
> +   *   Otherwise, check if the set PcdVideo*Resolution is defined.
> +   *   If not supported, try 800x600 which is required by UEFI/EFI spec.
> +   *   If still not supported, use the 1st mode in mode list.
> +   * If there are multiple video devices, graphic console driver will set all
> +   *   the video devices to the same mode.
> +   * According to UEFI/EFI spec, in addition to platform design guide, on-board
> +   *   graphics should support native mode of the display, plug-in graphics
> +   *   should support 800x600x32 or 640x480x32.
> +   * According to some OS requirement (i.e. UEFI requirment for Windows 10),
> +   *   integrated displays should support panel native resolution and external
> +   *   displays should support the maximum resolution of both GPU and display in
> +   *   GOP. For alternate display output, it should support native or highest
> +   *   compatible resolution, otherwise support an known mode to be compatible
> +   *   with as many monitors as possible (640x480, 1024x768).
> +   * Due to above requirement, use native resolution if PcdVideo*Resolution is
> +   *   not defined. To reduce GGTT write overhead, also limit the maximum to
> +   *   DISPLAY_WIDTH_MAX/DISPLAY_HEIGHT_MAX.
> +   */
> +
> +  RegRead32 (Private, HTOTAL(PIPE_A), &Val32);
> +  Display->HActive = (Val32 & 0xFFF) + 1;
> +  RegRead32 (Private, VTOTAL(PIPE_A), &Val32);
> +  Display->VActive = (Val32 & 0xFFF) + 1;
> +
> +  if (Display->HActive != 0 && Display->VActive != 0) {
> +    Width = Display->HActive;
> +    Height = Display->VActive;
> +    if (Display->HActive > DISPLAY_WIDTH_MAX ||
> +        Display->VActive > DISPLAY_HEIGHT_MAX) {
> +      Width = DISPLAY_WIDTH_MAX;
> +      Height = DISPLAY_HEIGHT_MAX;
> +    }
> +  } else {
> +    Width = DISPLAY_WIDTH_DEFAULT;
> +    Height = DISPLAY_HEIGHT_DEFAULT;
> +  }
> +
> +  Display->Width = Width;
> +  Display->Height = Height;
> +  Display->Format = PixelBlueGreenRedReserved8BitPerColor;
> +  Display->Bpp = 4;
> +  Display->MaxMode = 1;
> +
> +  // Add default if defined
> +  if (PcdGet32 (PcdVideoHorizontalResolution) != 0 &&
> +      PcdGet32 (PcdVideoVerticalResolution) != 0 &&
> +      PcdGet32 (PcdVideoHorizontalResolution) != Width &&
> +      PcdGet32 (PcdVideoVerticalResolution) != Height) {
> +      ++Display->MaxMode;
> +  }
> +
> +  Display->CurrentMode = DISPLAY_MODE_INVALID;
> +  Display->FrameBufferBltConfigure = NULL;
> +  Display->FrameBufferBltConfigureSize = 0;
> +
> +  // Linear must start at 256K, stride align at 64
> +  Display->WidthBytes = Display->Width * Display->Bpp;
> +  Display->StrideBytes = ALIGN_VALUE (Display->WidthBytes, 64);
> +  Display->FbSize = Display->StrideBytes * Display->Height;
> +  Display->Pages = EFI_SIZE_TO_PAGES (Display->FbSize);
> +
> +  Display->FbGMAddr = VirtualGpu->GpuMemAddr + VirtualGpu->VisibleOffset;
> +  Display->FbGMAddr = ALIGN_VALUE (Display->FbGMAddr, SIZE_256KB);
> +
> +  Status = gBS->AllocatePages (
> +                AllocateAnyPages,
> +                EfiReservedMemoryType,
> +                Display->Pages,
> +                &Display->FbPhysicalAddr
> +                );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "AllocatePages failed for display FB, pages %d, size %lx, status %d\n",
> +      Display->Pages, Display->FbSize, Status
> +      );
> +    return Status;
> +  }
> +
> +  Status = UpdateGGTT (Private,
> +             Display->FbGMAddr,
> +             Display->FbPhysicalAddr,
> +             Display->Pages
> +             );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Fail to Update GGTT for display, status %d\n", Status
> +      );
> +    goto Done;
> +  }
> +
> +  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
> +  Status = IntelVirtualGpuBltVideoFill (
> +             Display,
> +             (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION){{0, 0, 0, 0}},
> +             (BLT_RECTANGLE){0, 0, Display->Width, Display->Height});
> +  gBS->RestoreTPL (OriginalTPL);
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Fail to clear rectangle at [%d, %d] size %dx%d with color 0x%08x, status %d\n",
> +      (BLT_RECTANGLE){0, 0, Display->Width, Display->Height}.X,
> +      (BLT_RECTANGLE){0, 0, Display->Width, Display->Height}.Y,
> +      (BLT_RECTANGLE){0, 0, Display->Width, Display->Height}.Width,
> +      (BLT_RECTANGLE){0, 0, Display->Width, Display->Height}.Height,
> +      (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION){{0, 0, 0, 0}}.Raw,
> +      Status
> +      );
> +    goto Done;
> +  }
> +
> +  Status = gBS->AllocatePool (
> +                  EfiBootServicesData,
> +                  sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * Display->MaxMode,
> +                  (VOID **)&Display->ModeList
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "AllocatePool failed for display mode list, size %d, status %d\n",
> +      sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * Display->MaxMode,
> +      Status
> +      );
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto Done;
> +  }
> +
> +  for (ModeNumber = 0; ModeNumber < Display->MaxMode; ModeNumber++) {
> +    Display->ModeList[ModeNumber].Version = 0;
> +    Display->ModeList[ModeNumber].HorizontalResolution = Display->Width;
> +    Display->ModeList[ModeNumber].VerticalResolution = Display->Height;
> +    Display->ModeList[ModeNumber].PixelFormat = Display->Format;
> +    Display->ModeList[ModeNumber].PixelsPerScanLine = Display->Width;
> +  }
> +  if (Display->MaxMode > 1) {
> +    Display->ModeList[1].HorizontalResolution = PcdGet32 (PcdVideoHorizontalResolution);
> +    Display->ModeList[1].VerticalResolution = PcdGet32 (PcdVideoVerticalResolution);
> +    Display->ModeList[1].PixelsPerScanLine = PcdGet32 (PcdVideoHorizontalResolution);
> +  }
> +
> +  Private->GraphicsOutputProtocol.QueryMode = IntelVirtualGpuQueryMode;
> +  Private->GraphicsOutputProtocol.SetMode = IntelVirtualGpuSetMode;
> +  Private->GraphicsOutputProtocol.Blt = IntelVirtualGpuBlt;
> +  Private->GraphicsOutputProtocol.Mode->MaxMode = Display->MaxMode;
> +  Private->GraphicsOutputProtocol.Mode->Mode = Display->CurrentMode;
> +  Private->GraphicsOutputProtocol.Mode->SizeOfInfo =
> +    sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * Display->MaxMode;
> +
> +  Status = gBS->AllocatePool (
> +                  EfiBootServicesData,
> +                  Private->GraphicsOutputProtocol.Mode->SizeOfInfo,
> +                  (VOID **)&Private->GraphicsOutputProtocol.Mode->Info
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "AllocatePool failed for display mode info, size %d, status %d\n",
> +      Private->GraphicsOutputProtocol.Mode->SizeOfInfo, Status
> +      );
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto Done;
> +  }
> +
> +  CopyMem (
> +    Private->GraphicsOutputProtocol.Mode->Info,
> +    Display->ModeList,
> +    sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * Display->MaxMode
> +    );
> +
> +  Private->GraphicsOutputProtocol.Mode->FrameBufferBase = Display->FbGMAddr;
> +  Private->GraphicsOutputProtocol.Mode->FrameBufferSize = Display->FbSize;
> +
> +  InstallVbeShim (L"GVT-g VBIOS", Display->FbGMAddr);
> +
> +  GVT_DEBUG (EFI_D_INFO,
> +    "modes %d, max %dx%d, OVMF default %dx%d\n",
> +    Display->MaxMode,
> +    Display->Width, Display->Height,
> +    PcdGet32 (PcdVideoHorizontalResolution),
> +    PcdGet32 (PcdVideoVerticalResolution)
> +    );
> +  for (ModeNumber = 0; ModeNumber < Display->MaxMode; ModeNumber++) {
> +    GVT_DEBUG (EFI_D_INFO,
> +      "  mode %d: %dx%d BGRX, stride %d\n",
> +      ModeNumber,
> +      Display->ModeList[ModeNumber].HorizontalResolution,
> +      Display->ModeList[ModeNumber].VerticalResolution,
> +      ALIGN_VALUE (Display->ModeList[ModeNumber].HorizontalResolution * Display->Bpp, 64)
> +      );
> +  }
> +  GVT_DEBUG (EFI_D_INFO,
> +    "FrameBuffer: GMADR %lx, PADDR %lx, size %lx, pages %d, INTERNAL_BLT %d\n",
> +    Display->FbGMAddr, Display->FbPhysicalAddr, Display->FbSize, Display->Pages,
> +    DISPLAY_USE_INTERNAL_BLT
> +    );
> +
> +Done:
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +
> +}
> +
> +EFI_STATUS
> +IntelVirtualGpuDisplayClean (
> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
> +  )
> +{
> +  EFI_STATUS                 Status = EFI_INVALID_PARAMETER;
> +  PINTEL_VIRTUAL_GPU         VirtualGpu;
> +  PINTEL_VIRTUAL_GPU_DISPLAY Display;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
> +  Display = &VirtualGpu->Display;
> +
> +  if (Private->GraphicsOutputProtocol.Mode->Info) {
> +    Status = gBS->FreePool (Private->GraphicsOutputProtocol.Mode->Info);
> +    if (EFI_ERROR (Status)) {
> +      GVT_DEBUG (EFI_D_ERROR,
> +        "FreePool failed for display mode info, size %d, status %d\n",
> +        Private->GraphicsOutputProtocol.Mode->SizeOfInfo, Status
> +        );
> +        goto Done;
> +    }
> +    Private->GraphicsOutputProtocol.Mode->SizeOfInfo = 0;
> +    Private->GraphicsOutputProtocol.Mode->Info = NULL;
> +  }
> +  Private->GraphicsOutputProtocol.Mode->MaxMode = 0;
> +  Private->GraphicsOutputProtocol.Mode->Mode = DISPLAY_MODE_INVALID;
> +
> +  if (Display->FbPhysicalAddr) {
> +    Status = gBS->FreePages (Display->FbPhysicalAddr, Display->Pages);
> +    if (EFI_ERROR (Status)) {
> +      GVT_DEBUG (EFI_D_ERROR,
> +        "FreePages failed for display FB, pages %d, size %lx, status %d\n",
> +        Display->Pages, Display->FbSize, Status
> +        );
> +        goto Done;
> +    }
> +    Display->FbPhysicalAddr = 0;
> +    Display->Pages = 0;
> +    Display->FbSize = 0;
> +  }
> +
> +  Status = EFI_SUCCESS;
> +
> +Done:
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +IntelVirtualGpuQueryMode (
> +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL         *This,
> +  IN  UINT32                               ModeNumber,
> +  OUT UINTN                                *SizeOfInfo,
> +  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
> +  )
> +{
> +  EFI_STATUS                 Status = EFI_UNSUPPORTED;
> +  GVT_GOP_PRIVATE_DATA       *GvtGopPrivate = NULL;
> +  PINTEL_VIRTUAL_GPU         VirtualGpu;
> +  PINTEL_VIRTUAL_GPU_DISPLAY Display;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  GvtGopPrivate = GVT_GOP_PRIVATE_DATA_FROM_THIS (This);
> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)GvtGopPrivate->VirtualGpu;
> +  Display = &VirtualGpu->Display;
> +
> +  if (ModeNumber >= Display->MaxMode) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Invalid ModeNumber, request %d, max %d, status %d\n",
> +      ModeNumber, Display->MaxMode, Status
> +      );
> +    Status = EFI_INVALID_PARAMETER;
> +    goto Done;
> +  }
> +
> +  Status = gBS->AllocatePool (
> +                  EfiBootServicesData,
> +                  sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
> +                  (VOID **)Info
> +                  );
> +  if (EFI_ERROR (Status) || *Info == NULL) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "AllocatePool failed for queried mode info, size %d, status %d\n",
> +      sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), Status
> +      );
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto Done;
> +  }
> +
> +  *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> +  CopyMem (
> +    *Info,
> +    &Display->ModeList[ModeNumber],
> +    sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
> +    );
> +
> +  Status = EFI_SUCCESS;
> +
> +Done:
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +IntelVirtualGpuSetMode (
> +  IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
> +  IN UINT32                       ModeNumber
> +  )
> +{
> +  EFI_STATUS                          Status = EFI_UNSUPPORTED;
> +  GVT_GOP_PRIVATE_DATA                *GvtGopPrivate = NULL;
> +  PINTEL_VIRTUAL_GPU                  VirtualGpu;
> +  PINTEL_VIRTUAL_GPU_DISPLAY          Display;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  GvtGopPrivate = GVT_GOP_PRIVATE_DATA_FROM_THIS (This);
> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)GvtGopPrivate->VirtualGpu;
> +  Display = &VirtualGpu->Display;
> +
> +  if (ModeNumber >= Display->MaxMode) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Invalid ModeNumber, request %d, max %d, status %d\n",
> +      ModeNumber, Display->MaxMode, Status
> +      );
> +    Status = EFI_INVALID_PARAMETER;
> +    goto Done;
> +  }
> +
> +#if (DISPLAY_USE_INTERNAL_BLT == 1)
> +  Status = IntelVirtualGpuBltVideoFill (
> +             Display,
> +             (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION){{0, 0, 0, 0}},
> +             (BLT_RECTANGLE){0, 0, This->Mode->Info->HorizontalResolution, This->Mode->Info->VerticalResolution});
> +  if (EFI_ERROR (Status)) {
> +      GVT_DEBUG (EFI_D_ERROR,
> +        "IntelVirtualGpuBltVideoFill failed for mode %d, status %d\n",
> +        ModeNumber,
> +        Status
> +        );
> +    }
> +#else
> +  Status = FrameBufferBltConfigure (
> +             (VOID*) (UINTN) This->Mode->FrameBufferBase,
> +             This->Mode->Info,
> +             Display->FrameBufferBltConfigure,
> +             &Display->FrameBufferBltConfigureSize
> +             );
> +  if (Status == RETURN_BUFFER_TOO_SMALL) {
> +    if (Display->FrameBufferBltConfigure != NULL) {
> +      Status = gBS->FreePool (Display->FrameBufferBltConfigure);
> +      if (EFI_ERROR (Status)) {
> +        GVT_DEBUG (EFI_D_ERROR,
> +          "FreePool failed for FrameBufferBltConfigure, status %d\n",
> +          Status
> +          );
> +          goto Done;
> +      }
> +    }
> +    Status = gBS->AllocatePool (
> +                  EfiBootServicesData,
> +                  Display->FrameBufferBltConfigureSize,
> +                  (VOID **)&Display->FrameBufferBltConfigure
> +                  );
> +    if (EFI_ERROR (Status)) {
> +      GVT_DEBUG (EFI_D_ERROR,
> +        "AllocatePool failed for FrameBufferBltConfigure, size %d, status %d\n",
> +        Display->FrameBufferBltConfigureSize,
> +        Status
> +        );
> +      goto Done;
> +    }
> +
> +    Status = FrameBufferBltConfigure (
> +                (VOID*) (UINTN) This->Mode->FrameBufferBase,
> +                This->Mode->Info,
> +                Display->FrameBufferBltConfigure,
> +                &Display->FrameBufferBltConfigureSize
> +                );
> +    if (EFI_ERROR (Status)) {
> +      GVT_DEBUG (EFI_D_ERROR,
> +        "FrameBufferBltConfigure failed for mode %d, status %d\n",
> +        ModeNumber,
> +        Status
> +        );
> +      goto Done;
> +    }
> +  }
> +
> +  Status = FrameBufferBlt (
> +             Display->FrameBufferBltConfigure,
> +             &(EFI_GRAPHICS_OUTPUT_BLT_PIXEL){0, 0, 0, 0},
> +             EfiBltVideoFill,
> +             0, 0,
> +             0, 0,
> +             This->Mode->Info->HorizontalResolution,
> +             This->Mode->Info->VerticalResolution,
> +             0
> +             );
> +  if (EFI_ERROR (Status)) {
> +      GVT_DEBUG (EFI_D_ERROR,
> +        "FrameBufferBlt BltOperation %d failed for mode %d, color 0x%08x, status %d\n",
> +        EfiBltVideoFill,
> +        ModeNumber,
> +        (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION){{0, 0, 0, 0}}.Raw,
> +        Status
> +        );
> +    }
> +#endif
> +
> +  Status = IntelVirtualGpuEnableDisplay (
> +             GvtGopPrivate,
> +             ModeNumber,
> +             FALSE
> +             );
> +
> +  Status = IntelVirtualGpuEnableDisplay (
> +             GvtGopPrivate,
> +             ModeNumber,
> +             TRUE
> +             );
> +
> +  // Set current mode info in GOP
> +  This->Mode->Mode = ModeNumber;
> +  CopyMem (
> +    This->Mode->Info,
> +    &Display->ModeList[ModeNumber],
> +    sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
> +    );
> +
> +  GVT_DEBUG (EFI_D_INFO, "Set mode %d, %dx%d, status %d\n",
> +    ModeNumber,
> +    Display->ModeList[ModeNumber].HorizontalResolution,
> +    Display->ModeList[ModeNumber].VerticalResolution,
> +    Status
> +    );
> +
> +Done:
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +IntelVirtualGpuBlt (
> +  IN EFI_GRAPHICS_OUTPUT_PROTOCOL      *This,
> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *BltBuffer, OPTIONAL
> +  IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> +  IN UINTN                             SourceX,
> +  IN UINTN                             SourceY,
> +  IN UINTN                             DestinationX,
> +  IN UINTN                             DestinationY,
> +  IN UINTN                             Width,
> +  IN UINTN                             Height,
> +  IN UINTN                             Delta OPTIONAL
> +  )
> +{
> +  EFI_STATUS                 Status = EFI_UNSUPPORTED;
> +  GVT_GOP_PRIVATE_DATA       *GvtGopPrivate = NULL;
> +  PINTEL_VIRTUAL_GPU         VirtualGpu;
> +  PINTEL_VIRTUAL_GPU_DISPLAY Display;
> +  EFI_TPL                    OriginalTPL;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  GvtGopPrivate = GVT_GOP_PRIVATE_DATA_FROM_THIS (This);
> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)GvtGopPrivate->VirtualGpu;
> +  Display = &VirtualGpu->Display;
> +
> +  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
> +
> +#if (DISPLAY_USE_INTERNAL_BLT == 1)
> +  switch (BltOperation) {
> +  case EfiBltVideoFill:
> +    Status = IntelVirtualGpuBltVideoFill (
> +               Display,
> +               (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION)(*BltBuffer),
> +               (BLT_RECTANGLE){DestinationX, DestinationY, Width, Height});
> +    RegWrite32 (GvtGopPrivate,
> +      PLANE_SURF(PIPE_A, PLANE_PRIMARY),
> +      Display->FbGMAddr
> +      );
> +    break;
> +  case EfiBltVideoToBltBuffer:
> +    Status = IntelVirtualGpuBltVideoToBuffer (
> +               Display,
> +               BltBuffer,
> +               (BLT_RECTANGLE){SourceX, SourceY, Width, Height},
> +               (BLT_RECTANGLE){DestinationX, DestinationY, Width, Height},
> +               Delta
> +               );
> +    break;
> +  case EfiBltBufferToVideo:
> +    Status = IntelVirtualGpuBltVideoFromBuffer (
> +               Display,
> +               BltBuffer,
> +               (BLT_RECTANGLE){SourceX, SourceY, Width, Height},
> +               (BLT_RECTANGLE){DestinationX, DestinationY, Width, Height},
> +               Delta
> +               );
> +    RegWrite32 (GvtGopPrivate,
> +      PLANE_SURF(PIPE_A, PLANE_PRIMARY),
> +      Display->FbGMAddr
> +      );
> +    break;
> +  case EfiBltVideoToVideo:
> +    Status = IntelVirtualGpuBltVideoToVideo (
> +               Display,
> +               (BLT_RECTANGLE){SourceX, SourceY, Width, Height},
> +               (BLT_RECTANGLE){DestinationX, DestinationY, Width, Height}
> +               );
> +    RegWrite32 (GvtGopPrivate,
> +      PLANE_SURF(PIPE_A, PLANE_PRIMARY),
> +      Display->FbGMAddr
> +      );
> +    break;
> +  default:
> +    GVT_DEBUG (EFI_D_INFO, "Unsupported EFI_GRAPHICS_OUTPUT_BLT_OPERATION %d\n", BltOperation);
> +    Status = EFI_UNSUPPORTED;
> +    break;
> +  }
> +#else
> +  switch (BltOperation) {
> +  case EfiBltVideoToBltBuffer:
> +  case EfiBltVideoFill:
> +  case EfiBltBufferToVideo:
> +  case EfiBltVideoToVideo:
> +    Status = FrameBufferBlt (
> +               Display->FrameBufferBltConfigure,
> +               BltBuffer,
> +               BltOperation,
> +               SourceX,
> +               SourceY,
> +               DestinationX,
> +               DestinationY,
> +               Width,
> +               Height,
> +               Delta
> +               );
> +    if (BltOperation != EfiBltVideoToBltBuffer) {
> +      RegWrite32 (GvtGopPrivate,
> +        PLANE_SURF(PIPE_A, PLANE_PRIMARY),
> +        Display->FbGMAddr
> +        );
> +    }
> +    break;
> +  default:
> +    GVT_DEBUG (EFI_D_INFO, "Unsupported EFI_GRAPHICS_OUTPUT_BLT_OPERATION %d\n", BltOperation);
> +    Status = EFI_UNSUPPORTED;
> +    break;
> +  }
> +#endif
> +
> +  gBS->RestoreTPL (OriginalTPL);
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +IntelVirtualGpuEnableDisplay (
> +  IN OUT GVT_GOP_PRIVATE_DATA *Private,
> +  IN     UINT32               ModeNumber,
> +  IN     BOOLEAN              Enable
> +  )
> +{
> +  EFI_STATUS                 Status = EFI_INVALID_PARAMETER;
> +  PINTEL_VIRTUAL_GPU         VirtualGpu;
> +  PINTEL_VIRTUAL_GPU_DISPLAY Display;
> +  UINT32                     Width, Height, Val32;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
> +  Display = &VirtualGpu->Display;
> +
> +  if (ModeNumber >= Display->MaxMode) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Invalid ModeNumber, request %d, max %d, status %d\n",
> +      ModeNumber, Display->MaxMode, Status
> +      );
> +    Status = EFI_INVALID_PARAMETER;
> +    goto Done;
> +  }
> +
> +  Width = Display->ModeList[ModeNumber].HorizontalResolution;
> +  Height = Display->ModeList[ModeNumber].VerticalResolution;
> +
> +  if (Enable) {
> +    Display->CurrentMode = ModeNumber;
> +
> +    Val32 = (Display->HActive - 1) << 16;
> +    Val32 |= Display->VActive;
> +    RegWrite32 (Private, PIPESRC(PIPE_A), Val32);
> +
> +    RegRead32 (Private, PIPE_CONF(PIPE_A), &Val32);
> +    Val32 |= PIPE_CONF_ENABLE;
> +    RegWrite32 (Private, PIPE_CONF(PIPE_A), Val32);
> +
> +    Val32 = (Width - 1) & 0xFFF;
> +    Val32 |= ((Height - 1) & 0xFFF) << 16;
> +    RegWrite32 (Private, PLANE_SIZE(PIPE_A, PLANE_PRIMARY), Val32);
> +    RegWrite32 (Private, PLANE_POS(PIPE_A, PLANE_PRIMARY), 0);
> +
> +    // Convert mode with to stride in chunks of 64 bytes as required by PLANE_STRIDE
> +    Val32 = Display->ModeList[ModeNumber].HorizontalResolution * Display->Bpp;
> +    Val32 = ALIGN_VALUE (Val32, 64);
> +    Val32 = (Val32 / 64) & PLANE_STRIDE_MASK;
> +    RegWrite32 (Private, PLANE_STRIDE(PIPE_A, PLANE_PRIMARY), Val32);
> +
> +    RegWrite32 (Private, PLANE_SURF(PIPE_A, PLANE_PRIMARY), Display->FbGMAddr);
> +
> +    // Stretch to fullscreen if current mode is smaller than H/V active.
> +    if (Display->HActive != Width ||
> +        Display->VActive != Height) {
> +      RegWrite32 (Private, PS_WIN_POS(PIPE_A, 0), 0);
> +      RegWrite32 (Private,
> +        PS_WIN_SZ(PIPE_A, 0),
> +        Display->HActive << 16 | Display->VActive
> +        );
> +      RegRead32 (Private, PS_CTRL(PIPE_A, 0), &Val32);
> +      Val32 |= PS_CTRL_SCALER_EN;
> +      Val32 &= ~PS_CTRL_SCALER_MODE_MASK;
> +      Val32 |= PS_CTRL_SCALER_MODE_DYN;
> +      Val32 &= ~PS_CTRL_SCALER_BINDING_MASK;
> +      Val32 |= PS_CTRL_PLANE_SEL(PLANE_PRIMARY);
> +      Val32 &= ~PS_CTRL_SCALER_FILTER_MASK;
> +      Val32 |= PS_CTRL_SCALER_FILTER_MEDIUM;
> +      RegWrite32 (Private, PS_CTRL(PIPE_A, 0), Val32);
> +    }
> +
> +    RegRead32 (Private, PLANE_CTL(PIPE_A, PLANE_PRIMARY), &Val32);
> +    Val32 |= PLANE_CTL_ENABLE;
> +    Val32 &= ~PLANE_CTL_PIPE_GAMMA_ENABLE;
> +    Val32 &= ~PLANE_CTL_FORMAT_MASK;
> +    Val32 |= PLANE_CTL_FORMAT_XRGB_8888;
> +    Val32 &= ~PLANE_CTL_PIPE_CSC_ENABLE;
> +    Val32 &= ~PLANE_CTL_KEY_ENABLE_MASK;
> +    Val32 &= ~PLANE_CTL_ORDER_RGBX;
> +    if (Display->ModeList[ModeNumber].PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
> +      Val32 |= PLANE_CTL_ORDER_RGBX;
> +    }
> +    Val32 &= ~PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
> +    Val32 |= PLANE_CTL_PLANE_GAMMA_DISABLE;
> +    Val32 &= ~PLANE_CTL_TILED_MASK;
> +    Val32 |= PLANE_CTL_TILED_LINEAR;
> +    Val32 &= ~PLANE_CTL_ASYNC_FLIP;
> +    Val32 &= ~PLANE_CTL_ALPHA_MASK;
> +    Val32 |= PLANE_CTL_ALPHA_DISABLE;
> +    Val32 &= ~PLANE_CTL_ROTATE_MASK;
> +    Val32 |= PLANE_CTL_ROTATE_0;
> +    RegWrite32 (Private, PLANE_CTL(PIPE_A, PLANE_PRIMARY), Val32);
> +  } else {
> +    Display->CurrentMode = DISPLAY_MODE_INVALID;
> +
> +    RegRead32 (Private, PLANE_CTL(PIPE_A, PLANE_PRIMARY), &Val32);
> +    Val32 &= ~PLANE_CTL_ENABLE;
> +    RegWrite32 (Private, PLANE_CTL(PIPE_A, PLANE_PRIMARY), Val32);
> +    RegWrite32 (Private, PLANE_SURF(PIPE_A, PLANE_PRIMARY), 0);
> +
> +    RegRead32 (Private, PS_CTRL(PIPE_A, 0), &Val32);
> +    Val32 &= ~PS_CTRL_SCALER_EN;
> +    RegWrite32 (Private, PS_CTRL(PIPE_A, 0), Val32);
> +    RegWrite32 (Private, PS_WIN_POS(PIPE_A, 0), 0);
> +    RegWrite32 (Private, PS_WIN_SZ(PIPE_A, 0), 0);
> +
> +    RegRead32 (Private, PIPE_CONF(PIPE_A), &Val32);
> +    Val32 &= ~PIPE_CONF_ENABLE;
> +    RegWrite32 (Private, PIPE_CONF(PIPE_A), Val32);
> +  }
> +
> +  Status = EFI_SUCCESS;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: %a mode %dx%d 0x%x, scaling %a\n",
> +    __FUNCTION__,
> +    Enable ? "Enable" : "Disable",
> +    Width,
> +    Height,
> +    Display->FbGMAddr,
> +    (Display->HActive != Width ||
> +     Display->VActive != Height) ? "On" : "Off");
> +
> +Done:
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +IntelVirtualGpuNotifyDisplayReady (
> +  IN GVT_GOP_PRIVATE_DATA *Private,
> +  IN BOOLEAN              Ready
> +  )
> +{
> +  return RegWrite32 (
> +           Private,
> +           vgtif_reg(display_ready),
> +           Ready ? VGT_DRV_DISPLAY_READY : VGT_DRV_DISPLAY_NOT_READY
> +           );
> +}
> +
> +EFI_STATUS
> +IntelVirtualGpuBltVideoFill (
> +  IN PINTEL_VIRTUAL_GPU_DISPLAY          Display,
> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION BltPixel,
> +  IN BLT_RECTANGLE                       Destination
> +  )
> +{
> +  EFI_STATUS Status = EFI_INVALID_PARAMETER;
> +  VOID       *DestAddr;
> +  UINTN      DestBytes, ModeStrideBytes, Line;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  if (Destination.Width == 0 || Destination.Height == 0) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "EfiBltVideoFill invalid destination rectangle [%d, %d] \n",
> +      Destination.Width, Destination.Height
> +      );
> +    goto Done;
> +  }
> +
> +  if ((Destination.X + Destination.Width > Display->Width) ||
> +      (Destination.Y + Destination.Height > Display->Height)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "EfiBltVideoFill destination [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
> +      Destination.X, Destination.Y,
> +      Destination.X + Destination.Width, Destination.Y + Destination.Height,
> +      Display->Width, Display->Height
> +      );
> +    goto Done;
> +  }
> +
> +  if (Display->CurrentMode == DISPLAY_MODE_INVALID) {
> +    ModeStrideBytes = Display->Width;
> +  } else {
> +    ModeStrideBytes = Display->ModeList[Display->CurrentMode].HorizontalResolution;
> +  }
> +  ModeStrideBytes = ALIGN_VALUE (ModeStrideBytes * Display->Bpp, 64);
> +
> +  if (Destination.Width * Display->Bpp == ModeStrideBytes) {
> +    DestAddr = (UINT8*)Display->FbGMAddr + Destination.Y * ModeStrideBytes;
> +    DestBytes = Destination.Width * Display->Bpp * Destination.Height;
> +    SetMem32 ((VOID*)DestAddr, DestBytes, BltPixel.Raw);
> +  } else {
> +
> +    for (Line = 0; Line < Destination.Height; Line++) {
> +      DestAddr = (UINT8*)Display->FbGMAddr +
> +        (Line + Destination.Y) * ModeStrideBytes +
> +        Destination.X * Display->Bpp;
> +      DestBytes = Destination.Width * Display->Bpp;
> +
> +      SetMem32 (DestAddr, DestBytes, BltPixel.Raw);
> +    }
> +  }
> +
> +  Status = EFI_SUCCESS;
> +
> +Done:
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +IntelVirtualGpuBltVideoToBuffer (
> +  IN PINTEL_VIRTUAL_GPU_DISPLAY    Display,
> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
> +  IN BLT_RECTANGLE                 Source,
> +  IN BLT_RECTANGLE                 Destination,
> +  IN UINTN                         Delta
> +  )
> +{
> +  EFI_STATUS Status = EFI_INVALID_PARAMETER;
> +  VOID       *SourceAddr, *DestAddr;
> +  UINTN      DestStride, CopyBytes, ModeStrideBytes, Line;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  if (Source.Width == 0 || Source.Height == 0) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "EfiBltVideoToBltBuffer invalid source rectangle [%d, %d] \n",
> +      Source.Width, Source.Height
> +      );
> +    goto Done;
> +  }
> +
> +  if (Source.Width != Destination.Width ||
> +      Source.Height != Destination.Height) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "EfiBltVideoToBltBuffer size mismatch: source %dx%d, destination %dx%d\n",
> +      Source.Width, Source.Height, Destination.Width, Destination.Height
> +      );
> +    goto Done;
> +  }
> +
> +  if ((Source.X + Source.Width > Display->Width) ||
> +      (Source.Y + Source.Height > Display->Height)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "EfiBltVideoToBltBuffer source [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
> +      Source.X, Source.Y,
> +      Source.X + Source.Width, Source.Y + Source.Height,
> +      Display->Width, Display->Height
> +      );
> +    goto Done;
> +  }
> +
> +  if (Destination.X != 0 || Destination.Y != 0) {
> +    DestStride = Delta;
> +  } else {
> +    DestStride = Destination.Width * Display->Bpp;
> +  }
> +
> +  if (Display->CurrentMode == DISPLAY_MODE_INVALID) {
> +    ModeStrideBytes = Display->Width;
> +  } else {
> +    ModeStrideBytes = Display->ModeList[Display->CurrentMode].HorizontalResolution;
> +  }
> +  ModeStrideBytes = ALIGN_VALUE (ModeStrideBytes * Display->Bpp, 64);
> +
> +  for (Line = 0; Line < Source.Height; Line++) {
> +    SourceAddr = (UINT8*)Display->FbGMAddr +
> +      (Source.Y + Line) * ModeStrideBytes +
> +      Source.X * Display->Bpp;
> +    DestAddr = (UINT8*)BltBuffer + (Destination.Y + Line) * DestStride;
> +    DestAddr = (UINT8*)DestAddr + Destination.X * Display->Bpp;
> +    CopyBytes = Source.Width * Display->Bpp;
> +    CopyMem (DestAddr, SourceAddr, CopyBytes);
> +  }
> +
> +  GVT_DEBUG (EFI_D_VERBOSE,
> +    "EfiBltVideoToBltBuffer [%d, %d] >> [%d, %d] size [%d, %d] Delta %d\n",
> +    Source.X, Source.Y,
> +    Destination.X, Destination.Y,
> +    Source.Width, Source.Height,
> +    Delta
> +    );
> +
> +  Status = EFI_SUCCESS;
> +
> +Done:
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +IntelVirtualGpuBltVideoFromBuffer (
> +  IN PINTEL_VIRTUAL_GPU_DISPLAY    Display,
> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
> +  IN BLT_RECTANGLE                 Source,
> +  IN BLT_RECTANGLE                 Destination,
> +  IN UINTN                         Delta
> +  )
> +{
> +  EFI_STATUS Status = EFI_INVALID_PARAMETER;
> +  VOID       *SourceAddr, *DestAddr;
> +  UINTN      SourceStride, CopyBytes, ModeStrideBytes, Line;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  if (Source.Width == 0 || Source.Height == 0) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "EfiBltBufferToVideo invalid source rectangle [%d, %d] \n",
> +      Source.Width, Source.Height
> +      );
> +    goto Done;
> +  }
> +
> +  if (Source.Width != Destination.Width || Source.Height != Destination.Height) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "EfiBltBufferToVideo size mismatch: source %dx%d, destination %dx%d\n",
> +      Source.Width, Source.Height, Destination.Width, Destination.Height
> +      );
> +    goto Done;
> +  }
> +
> +  if ((Destination.X + Destination.Width > Display->Width) ||
> +      (Destination.Y + Destination.Height > Display->Height)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "EfiBltBufferToVideo destination [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
> +      Destination.X, Destination.Y,
> +      Destination.X + Destination.Width, Destination.Y + Destination.Height,
> +      Display->Width, Display->Height
> +      );
> +    goto Done;
> +  }
> +
> +  if (Source.X != 0 || Source.Y != 0) {
> +    SourceStride = Delta;
> +  } else {
> +    SourceStride = Source.Width * Display->Bpp;
> +  }
> +
> +  if (Display->CurrentMode == DISPLAY_MODE_INVALID) {
> +    ModeStrideBytes = Display->Width;
> +  } else {
> +    ModeStrideBytes = Display->ModeList[Display->CurrentMode].HorizontalResolution;
> +  }
> +  ModeStrideBytes = ALIGN_VALUE (ModeStrideBytes * Display->Bpp, 64);
> +
> +  for (Line = 0; Line < Source.Height; Line++) {
> +    SourceAddr = (UINT8*)BltBuffer +
> +      (Source.Y + Line) * SourceStride +
> +      Source.X * Display->Bpp;
> +    DestAddr = (UINT8*)Display->FbGMAddr +
> +      (Destination.Y + Line) * ModeStrideBytes +
> +      Destination.X * Display->Bpp;
> +    CopyBytes = Source.Width * Display->Bpp;
> +    CopyMem (DestAddr, SourceAddr, CopyBytes);
> +  }
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "EfiBltBufferToVideo [%d, %d] >> [%d, %d] size [%d, %d] Delta %d\n",
> +    Source.X, Source.Y,
> +    Destination.X, Destination.Y,
> +    Source.Width, Source.Height,
> +    Delta
> +    );
> +
> +  Status = EFI_SUCCESS;
> +
> +Done:
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +IntelVirtualGpuBltVideoToVideo (
> +  IN PINTEL_VIRTUAL_GPU_DISPLAY Display,
> +  IN BLT_RECTANGLE              Source,
> +  IN BLT_RECTANGLE              Destination
> +  )
> +{
> +  EFI_STATUS Status = EFI_INVALID_PARAMETER;
> +  VOID       *SourceAddr, *DestAddr;
> +  UINTN      CopyBytes, ModeStrideBytes, Line;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  if (Source.Width == 0 || Source.Height == 0) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "EfiBltVideoToVideo invalid source rectangle [%d, %d] \n",
> +      Source.Width, Source.Height
> +      );
> +    goto Done;
> +  }
> +
> +  if (Source.Width != Destination.Width || Source.Height != Destination.Height) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "EfiBltVideoToVideo size mismatch: source %dx%d, destination %dx%d\n",
> +      Source.Width, Source.Height, Destination.Width, Destination.Height
> +      );
> +    goto Done;
> +  }
> +
> +  if ((Source.X + Source.Width > Display->Width) ||
> +      (Source.Y + Source.Height > Display->Height)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "EfiBltVideoToVideo source [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
> +      Source.X, Source.Y,
> +      Source.X + Source.Width, Source.Y + Source.Height,
> +      Display->Width, Display->Height
> +      );
> +    goto Done;
> +  }
> +
> +  if ((Destination.X + Destination.Width > Display->Width) ||
> +      (Destination.Y + Destination.Height > Display->Height)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "EfiBltVideoToVideo destination [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
> +      Destination.X, Destination.Y,
> +      Destination.X + Destination.Width, Destination.Y + Destination.Height,
> +      Display->Width, Display->Height
> +      );
> +    goto Done;
> +  }
> +
> +  if (Display->CurrentMode == DISPLAY_MODE_INVALID) {
> +    ModeStrideBytes = Display->Width;
> +  } else {
> +    ModeStrideBytes = Display->ModeList[Display->CurrentMode].HorizontalResolution;
> +  }
> +  ModeStrideBytes = ALIGN_VALUE (ModeStrideBytes * Display->Bpp, 64);
> +
> +  for (Line = 0; Line < Source.Height; Line++) {
> +    SourceAddr = (UINT8*)Display->FbGMAddr +
> +      (Source.Y + Line) * ModeStrideBytes +
> +      Source.X * Display->Bpp;
> +    DestAddr = (UINT8*)Display->FbGMAddr +
> +      (Destination.Y + Line)* ModeStrideBytes +
> +      Destination.X * Display->Bpp;
> +    CopyBytes = Source.Width * Display->Bpp;
> +    //
> +    // Overlap could corrupt source content:
> +    // src <----|---->
> +    // dst      <----|---->
> +    //
> +    if (DestAddr > SourceAddr && DestAddr < (SourceAddr + CopyBytes)) {
> +      CopyMem (
> +        SourceAddr + CopyBytes,
> +        DestAddr,
> +        SourceAddr + CopyBytes - DestAddr
> +        );
> +      CopyMem (DestAddr, SourceAddr, DestAddr - SourceAddr);
> +    //
> +    // Overlap won't corrupt source content:
> +    // src      <----|---->
> +    // dst <----|---->
> +    //
> +    // No overlap
> +    // src <--------->
> +    // dst                         <--------->
> +    //
> +    } else {
> +      CopyMem (DestAddr, SourceAddr, CopyBytes);
> +    }
> +  }
> +
> +  Status = EFI_SUCCESS;
> +
> +Done:
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> diff --git a/OvmfPkg/IntelGvtGopDxe/Display.h b/OvmfPkg/IntelGvtGopDxe/Display.h
> new file mode 100644
> index 000000000000..19e4d64f3b12
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/Display.h
> @@ -0,0 +1,141 @@
> +/** @file
> +  Component name for the QEMU video controller.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __DISPLAY_H_
> +#define __DISPLAY_H_
> +
> +#include <Library/FrameBufferBltLib.h>
> +
> +typedef struct _BLT_RECTANGLE {
> +  UINTN X;
> +  UINTN Y;
> +  UINTN Width;
> +  UINTN Height;
> +} BLT_RECTANGLE, *PBLT_RECTANGLE;
> +
> +#define DISPLAY_WIDTH_MAX      1920
> +#define DISPLAY_HEIGHT_MAX     1080
> +#define DISPLAY_WIDTH_DEFAULT  1024
> +#define DISPLAY_HEIGHT_DEFAULT 768
> +#define DISPLAY_MODE_INVALID   0xFFFF
> +
> +#define DISPLAY_USE_INTERNAL_BLT 1
> +
> +typedef struct _INTEL_VIRTUAL_GPU_DISPLAY {
> +  UINTN                                HActive;
> +  UINTN                                VActive;
> +  UINTN                                Width;
> +  UINTN                                Height;
> +  UINTN                                WidthBytes;
> +  UINTN                                StrideBytes;
> +  EFI_GRAPHICS_PIXEL_FORMAT            Format;
> +  UINTN                                Bpp;
> +  UINTN                                MaxMode;
> +  UINTN                                CurrentMode;
> +  UINTN                                FbSize;
> +  UINTN                                Pages;
> +  EFI_PHYSICAL_ADDRESS                 FbGMAddr;
> +  EFI_PHYSICAL_ADDRESS                 FbPhysicalAddr;
> +  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeList;
> +  FRAME_BUFFER_CONFIGURE               *FrameBufferBltConfigure;
> +  UINTN                                FrameBufferBltConfigureSize;
> +} INTEL_VIRTUAL_GPU_DISPLAY, *PINTEL_VIRTUAL_GPU_DISPLAY;
> +
> +EFI_STATUS
> +IntelVirtualGpuDisplayInit (
> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
> +  );
> +
> +EFI_STATUS
> +IntelVirtualGpuDisplayClean (
> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +IntelVirtualGpuQueryMode (
> +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL         *This,
> +  IN  UINT32                               ModeNumber,
> +  OUT UINTN                                *SizeOfInfo,
> +  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +IntelVirtualGpuSetMode (
> +  IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
> +  IN UINT32                       ModeNumber
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +IntelVirtualGpuBlt (
> +  IN EFI_GRAPHICS_OUTPUT_PROTOCOL      *This,
> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *BltBuffer,   OPTIONAL
> +  IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> +  IN UINTN                             SourceX,
> +  IN UINTN                             SourceY,
> +  IN UINTN                             DestinationX,
> +  IN UINTN                             DestinationY,
> +  IN UINTN                             Width,
> +  IN UINTN                             Height,
> +  IN UINTN                             Delta         OPTIONAL
> +  );
> +
> +EFI_STATUS
> +IntelVirtualGpuEnableDisplay (
> +  IN OUT GVT_GOP_PRIVATE_DATA *Private,
> +  IN     UINT32               ModeNumber,
> +  IN     BOOLEAN              Enable
> +  );
> +
> +EFI_STATUS
> +IntelVirtualGpuNotifyDisplayReady (
> +  IN GVT_GOP_PRIVATE_DATA *Private,
> +  IN BOOLEAN              Ready
> +  );
> +
> +EFI_STATUS
> +IntelVirtualGpuBltVideoFill (
> +  IN PINTEL_VIRTUAL_GPU_DISPLAY          Display,
> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION BltPixel,
> +  IN BLT_RECTANGLE                       Destination
> +  );
> +
> +EFI_STATUS
> +IntelVirtualGpuBltVideoToBuffer (
> +  IN PINTEL_VIRTUAL_GPU_DISPLAY    Display,
> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
> +  IN BLT_RECTANGLE                 Source,
> +  IN BLT_RECTANGLE                 Destination,
> +  IN UINTN                         Delta
> +  );
> +
> +EFI_STATUS
> +IntelVirtualGpuBltVideoFromBuffer (
> +  IN PINTEL_VIRTUAL_GPU_DISPLAY    Display,
> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
> +  IN BLT_RECTANGLE                 Source,
> +  IN BLT_RECTANGLE                 Destination,
> +  IN UINTN                         Delta
> +  );
> +
> +EFI_STATUS
> +IntelVirtualGpuBltVideoToVideo (
> +  IN PINTEL_VIRTUAL_GPU_DISPLAY Display,
> +  IN BLT_RECTANGLE              Source,
> +  IN BLT_RECTANGLE              Destination
> +  );
> +VOID
> +InstallVbeShim (
> +  IN CONST CHAR16         *CardName,
> +  IN EFI_PHYSICAL_ADDRESS FrameBufferBase
> +  );
> +
> +#endif //__DISPLAY_H_
> diff --git a/OvmfPkg/IntelGvtGopDxe/GopDriver.c b/OvmfPkg/IntelGvtGopDxe/GopDriver.c
> new file mode 100644
> index 000000000000..396e5cf4447c
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/GopDriver.c
> @@ -0,0 +1,478 @@
> +/** @file
> +  Component name for the QEMU video controller.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Common.h"
> +#include "VirtualGpu.h"
> +
> +EFI_STATUS
> +EFIAPI
> +GvtGopComponentNameGetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> +  IN  CHAR8                        *Language,
> +  OUT CHAR16                       **DriverName
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +GvtGopComponentNameGetControllerName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> +  IN  EFI_HANDLE                  ControllerHandle,
> +  IN  EFI_HANDLE                  ChildHandle OPTIONAL,
> +  IN  CHAR8                       *Language,
> +  OUT CHAR16                      **ControllerName
> +  );
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED
> +EFI_COMPONENT_NAME_PROTOCOL gGvtGopDriverComponentName = {
> +  GvtGopComponentNameGetDriverName,
> +  GvtGopComponentNameGetControllerName,
> +  "eng"
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED
> +EFI_COMPONENT_NAME2_PROTOCOL gGvtGopDriverComponentName2 = {
> +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GvtGopComponentNameGetDriverName,
> +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GvtGopComponentNameGetControllerName,
> +  "en"
> +};
> +
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED
> +EFI_UNICODE_STRING_TABLE gGvtGopDriverNameTable[] = {
> +  { "eng;en", L"Intel GVT-g GOP Driver" },
> +  { NULL , NULL }
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED
> +EFI_UNICODE_STRING_TABLE gGvtGopControllerNameTable[] = {
> +  { "eng;en", L"Intel GVT-g Virtual GPU PCI Adapter" },
> +  { NULL , NULL }
> +};
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GvtGopBindingSupported (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  ControllerHandle,
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
> +  )
> +{
> +  EFI_STATUS          Status;
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  Status = gBS->OpenProtocol (
> +                  ControllerHandle,
> +                  &gEfiPciIoProtocolGuid,
> +                  (VOID **) &PciIo,
> +                  This->DriverBindingHandle,
> +                  ControllerHandle,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_VERBOSE,
> +      "OpenProtocol gEfiPciIoProtocolGuid failed with %d\n", Status
> +      );
> +    goto Done;
> +  }
> +
> +  Status = IntelVirtualGpuActive (PciIo);
> +
> +  gBS->CloseProtocol (
> +        ControllerHandle,
> +        &gEfiPciIoProtocolGuid,
> +        This->DriverBindingHandle,
> +        ControllerHandle
> +        );
> +
> +Done:
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +  return Status;
> +}
> +
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GvtGopBindingStart (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  ControllerHandle,
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
> +  )
> +{
> +  EFI_STATUS               Status;
> +  EFI_TPL                  OriginalTPL;
> +  GVT_GOP_PRIVATE_DATA     *GvtGopPrivate = NULL;
> +  UINT64                   PciAttr;
> +  EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
> +  ACPI_ADR_DEVICE_PATH     AcpiDeviceNode;
> +  EFI_PCI_IO_PROTOCOL      *ChildPciIo;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  OriginalTPL = gBS->RaiseTPL (TPL_CALLBACK);
> +
> +  Status = gBS->AllocatePool (
> +                  EfiBootServicesData,
> +                  sizeof(GVT_GOP_PRIVATE_DATA),
> +                  (VOID **)&GvtGopPrivate
> +                  );
> +  if (EFI_ERROR (Status) || GvtGopPrivate == NULL) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "AllocatePool failed for GVT_GOP_PRIVATE_DATA, size %d, status %d\n",
> +      sizeof(GVT_GOP_PRIVATE_DATA), Status
> +      );
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto Done;
> +  }
> +
> +  ZeroMem (GvtGopPrivate, sizeof(GVT_GOP_PRIVATE_DATA));
> +  GvtGopPrivate->Signature = GVT_GOP_MAGIC;
> +
> +  Status = gBS->AllocatePool (
> +                  EfiBootServicesData,
> +                  sizeof(INTEL_VIRTUAL_GPU),
> +                  &GvtGopPrivate->VirtualGpu
> +                  );
> +  if (EFI_ERROR (Status) || GvtGopPrivate->VirtualGpu == NULL) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "AllocatePool failed for INTEL_VIRTUAL_GPU, size %d, status %d\n",
> +      sizeof(INTEL_VIRTUAL_GPU), Status
> +      );
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto Free;
> +  }
> +  ZeroMem (GvtGopPrivate->VirtualGpu, sizeof(INTEL_VIRTUAL_GPU));
> +
> +  Status = gBS->OpenProtocol (
> +                  ControllerHandle,
> +                  &gEfiPciIoProtocolGuid,
> +                  (VOID **) &GvtGopPrivate->PciIo,
> +                  This->DriverBindingHandle,
> +                  ControllerHandle,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Can't open protocol gEfiPciIoProtocolGuid, status %d\n", Status
> +      );
> +    goto Free;
> +  }
> +
> +  Status = GvtGopPrivate->PciIo->Attributes (
> +                                   GvtGopPrivate->PciIo,
> +                                   EfiPciIoAttributeOperationGet,
> +                                   0,
> +                                   &GvtGopPrivate->OriginalPciAttr
> +                                   );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Failed EfiPciIoAttributeOperationGet, status %d\n", Status
> +      );
> +    goto Free;
> +  }
> +
> +  PciAttr = EFI_PCI_DEVICE_ENABLE;
> +  Status = GvtGopPrivate->PciIo->Attributes (
> +                                   GvtGopPrivate->PciIo,
> +                                   EfiPciIoAttributeOperationEnable,
> +                                   PciAttr,
> +                                   NULL);
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Failed EfiPciIoAttributeOperationEnable %llx, status %d\n", PciAttr,
> +      Status
> +      );
> +    goto Free;
> +  }
> +
> +  Status = IntelVirtualGpuInit (GvtGopPrivate);
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR, "Failed IntelVirtualGpuInit, status %d\n", Status);
> +    goto Free;
> +  }
> +
> +  Status = gBS->HandleProtocol (
> +                  ControllerHandle,
> +                  &gEfiDevicePathProtocolGuid,
> +                  (VOID **) &ParentDevicePath
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR, "Fail gEfiDevicePathProtocolGuid, status %d\n",
> +      Status
> +      );
> +    goto Free;
> +  }
> +
> +  ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
> +  AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
> +  AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
> +  AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL, 0, 0);
> +  SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
> +  GvtGopPrivate->GopDevPath = AppendDevicePathNode (
> +                                ParentDevicePath,
> +                                (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
> +                                );
> +  if (GvtGopPrivate->GopDevPath == NULL) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    GVT_DEBUG (EFI_D_ERROR, "Fail AppendDevicePathNode, status %d\n", Status);
> +    goto Free;
> +  }
> +
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                  &GvtGopPrivate->Handle,
> +                  &gEfiDevicePathProtocolGuid,
> +                  GvtGopPrivate->GopDevPath,
> +                  NULL
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Can't install protocol gEfiDevicePathProtocolGuid, status %d\n",
> +      Status
> +      );
> +    goto Free;
> +  }
> +
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                  &GvtGopPrivate->Handle,
> +                  &gEfiGraphicsOutputProtocolGuid,
> +                  &GvtGopPrivate->GraphicsOutputProtocol,
> +                  NULL
> +                  );
> +
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Can't install protocol gEfiGraphicsOutputProtocolGuid, status %d\n",
> +      Status
> +      );
> +    goto Free;
> +  }
> +
> +  Status = gBS->OpenProtocol (
> +                ControllerHandle,
> +                &gEfiPciIoProtocolGuid,
> +                (VOID **) &ChildPciIo,
> +                This->DriverBindingHandle,
> +                GvtGopPrivate->Handle,
> +                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
> +                );
> +  if (EFI_ERROR (Status)) {
> +    goto Free;
> +  }
> +
> +  goto Done;
> +
> +Free:
> +  if (GvtGopPrivate->PciIo) {
> +    if (GvtGopPrivate->OriginalPciAttr) {
> +      GvtGopPrivate->PciIo->Attributes (
> +                              GvtGopPrivate->PciIo,
> +                              EfiPciIoAttributeOperationEnable,
> +                              GvtGopPrivate->OriginalPciAttr,
> +                              NULL
> +                              );
> +    }
> +    gBS->CloseProtocol (
> +           ControllerHandle,
> +           &gEfiPciIoProtocolGuid,
> +           This->DriverBindingHandle,
> +           ControllerHandle
> +           );
> +    GvtGopPrivate->PciIo = NULL;
> +  }
> +
> +  if (GvtGopPrivate->VirtualGpu) {
> +    gBS->FreePool (GvtGopPrivate->VirtualGpu);
> +    GvtGopPrivate->VirtualGpu = NULL;
> +  }
> +
> +  if (GvtGopPrivate) {
> +    gBS->FreePool (GvtGopPrivate);
> +  }
> +
> +  if (GvtGopPrivate->GopDevPath) {
> +    FreePool (GvtGopPrivate->GopDevPath);
> +    GvtGopPrivate->GopDevPath = NULL;
> +  }
> +
> +Done:
> +
> +  gBS->RestoreTPL (OriginalTPL);
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +GvtGopBindingStop (
> +  IN  EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN  EFI_HANDLE                  ControllerHandle,
> +  IN  UINTN                       NumberOfChildren,
> +  IN  EFI_HANDLE                  *ChildHandleBuffer OPTIONAL
> +  )
> +{
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol;
> +  EFI_STATUS                   Status;
> +  GVT_GOP_PRIVATE_DATA         *GvtGopPrivate = NULL;
> +
> +  GVT_DEBUG (EFI_D_INFO, "%a: >>>\n", __FUNCTION__);
> +
> +  Status = gBS->OpenProtocol (
> +                  ControllerHandle,
> +                  &gEfiGraphicsOutputProtocolGuid,
> +                  (VOID **)&GraphicsOutputProtocol,
> +                  This->DriverBindingHandle,
> +                  ControllerHandle,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    Status = EFI_NOT_STARTED;
> +    goto Done;
> +  }
> +
> +  GvtGopPrivate = GVT_GOP_PRIVATE_DATA_FROM_THIS (GraphicsOutputProtocol);
> +  if (!GvtGopPrivate) {
> +    Status = EFI_NOT_STARTED;
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Intel GVT-g GOP isn't started, status %d\n", Status
> +      );
> +    goto Done;
> +  }
> +
> +  gBS->UninstallMultipleProtocolInterfaces (
> +         GvtGopPrivate->Handle,
> +         &gEfiGraphicsOutputProtocolGuid,
> +         &GvtGopPrivate->GraphicsOutputProtocol,
> +         NULL
> +         );
> +
> +  if (GvtGopPrivate->PciIo) {
> +    gBS->CloseProtocol (
> +           ControllerHandle,
> +           &gEfiPciIoProtocolGuid,
> +           This->DriverBindingHandle,
> +           ControllerHandle
> +           );
> +    GvtGopPrivate->PciIo = NULL;
> +  }
> +
> +  Status = IntelVirtualGpuClean (GvtGopPrivate);
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR, "Fail to clean virtual GPU, status %d\n", Status);
> +    goto Done;
> +  }
> +
> +  if (GvtGopPrivate->VirtualGpu) {
> +    gBS->FreePool (GvtGopPrivate->VirtualGpu);
> +    GvtGopPrivate->VirtualGpu = NULL;
> +  }
> +
> +  if (GvtGopPrivate) {
> +    gBS->FreePool (GvtGopPrivate);
> +  }
> +
> +Done:
> +
> +  GVT_DEBUG (EFI_D_INFO, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +STATIC EFI_DRIVER_BINDING_PROTOCOL gGvtGopDriverBinding = {
> +  GvtGopBindingSupported,
> +  GvtGopBindingStart,
> +  GvtGopBindingStop,
> +  0x10,
> +  NULL,
> +  NULL
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +GvtGopComponentNameGetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> +  IN  CHAR8                        *Language,
> +  OUT CHAR16                       **DriverName
> +  )
> +{
> +  return LookupUnicodeString2 (
> +           Language,
> +           This->SupportedLanguages,
> +           gGvtGopDriverNameTable,
> +           DriverName,
> +           (BOOLEAN)(This == &gGvtGopDriverComponentName)
> +           );
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +GvtGopComponentNameGetControllerName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> +  IN  EFI_HANDLE                  ControllerHandle,
> +  IN  EFI_HANDLE                  ChildHandle OPTIONAL,
> +  IN  CHAR8                       *Language,
> +  OUT CHAR16                      **ControllerName
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  if (ChildHandle != NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Status = EfiTestManagedDevice (
> +             ControllerHandle,
> +             gGvtGopDriverBinding.DriverBindingHandle,
> +             &gEfiPciIoProtocolGuid
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  return LookupUnicodeString2 (
> +           Language,
> +           This->SupportedLanguages,
> +           gGvtGopControllerNameTable,
> +           ControllerName,
> +           (BOOLEAN)(This == &gGvtGopDriverComponentName)
> +           );
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +GvtGopEntryPoint (
> +  IN EFI_HANDLE       ImageHandle,
> +  IN EFI_SYSTEM_TABLE *SystemTable
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  Status = EfiLibInstallDriverBindingComponentName2 (
> +             ImageHandle,
> +             SystemTable,
> +             &gGvtGopDriverBinding,
> +             ImageHandle,
> +             &gGvtGopDriverComponentName,
> +             &gGvtGopDriverComponentName2);
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR, "Failed to install driver %d : %d\n", Status);
> +  }
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> diff --git a/OvmfPkg/IntelGvtGopDxe/GpuReg.c b/OvmfPkg/IntelGvtGopDxe/GpuReg.c
> new file mode 100644
> index 000000000000..778c09d5198c
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/GpuReg.c
> @@ -0,0 +1,91 @@
> +/** @file
> +  Component name for the QEMU video controller.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "GpuReg.h"
> +
> +EFI_STATUS
> +RegRead32 (
> +  IN  GVT_GOP_PRIVATE_DATA *Private,
> +  IN  UINT32 Offset,
> +  OUT UINT32 *ValuePtr
> +  )
> +{
> +  EFI_STATUS Status = EFI_INVALID_PARAMETER;
> +
> +  if (Offset < MMIO_SIZE && ValuePtr != NULL) {
> +    Status = Private->PciIo->Mem.Read (
> +                          Private->PciIo,
> +                          EfiPciIoWidthUint32,
> +                          PCI_BAR_IDX0,
> +                          Offset,
> +                          1,
> +                          ValuePtr
> +                          );
> +    if (EFI_ERROR (Status)) {
> +      GVT_DEBUG (EFI_D_ERROR, "%a reg %x, value %x, status %d\n",
> +        __FUNCTION__, Offset, *ValuePtr, Status
> +        );
> +    } else {
> +      Status = EFI_SUCCESS;
> +      GVT_DEBUG (EFI_D_VERBOSE, "%a reg %x, value %x, status %d\n",
> +        __FUNCTION__, Offset, *ValuePtr, Status
> +        );
> +    }
> +  } else {
> +    Status = EFI_INVALID_PARAMETER;
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "%a invalid reg %x or ValuePtr %p, status %d\n",
> +      __FUNCTION__, Offset, ValuePtr, Status
> +      );
> +    goto Done;
> +  }
> +
> +Done:
> +  return Status;
> +}
> +
> +EFI_STATUS
> +RegWrite32 (
> +  IN GVT_GOP_PRIVATE_DATA *Private,
> +  IN UINT32 Offset,
> +  IN UINT32 Value
> +  )
> +{
> +  EFI_STATUS Status = EFI_INVALID_PARAMETER;
> +
> +  if (Offset < MMIO_SIZE) {
> +    Status = Private->PciIo->Mem.Write (
> +                          Private->PciIo,
> +                          EfiPciIoWidthUint32,
> +                          PCI_BAR_IDX0,
> +                          Offset,
> +                          1,
> +                          &Value
> +                          );
> +    if (EFI_ERROR (Status)) {
> +      GVT_DEBUG (EFI_D_ERROR, "%a reg %x, value %x, status %d\n",
> +        __FUNCTION__, Offset, Value, Status
> +        );
> +    } else {
> +      Status = EFI_SUCCESS;
> +      GVT_DEBUG (EFI_D_VERBOSE, "%a reg %x, value %x, status %d\n",
> +        __FUNCTION__, Offset, Value, Status
> +        );
> +    }
> +  } else {
> +    Status = EFI_INVALID_PARAMETER;
> +    GVT_DEBUG (EFI_D_ERROR, "%a invalid reg %x, status %d\n",
> +      __FUNCTION__, Offset, Status
> +      );
> +    goto Done;
> +  }
> +
> +Done:
> +  return Status;
> +}
> diff --git a/OvmfPkg/IntelGvtGopDxe/GpuReg.h b/OvmfPkg/IntelGvtGopDxe/GpuReg.h
> new file mode 100644
> index 000000000000..f46f4cef9cd4
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/GpuReg.h
> @@ -0,0 +1,175 @@
> +/** @file
> +  Component name for the QEMU video controller.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __GPUREG_H_
> +#define __GPUREG_H_
> +
> +#include "Common.h"
> +
> +#define MMIO_SIZE 0x200000
> +
> +#define VGT_PVINFO_PAGE 0x78000
> +#define VGT_PVINFO_SIZE 0x1000
> +
> +#define VGT_MAGIC         0x4776544776544776ULL  /* 'vGTvGTvG' */
> +#define VGT_VERSION_MAJOR 1
> +#define VGT_VERSION_MINOR 0
> +
> +#define VGT_DRV_DISPLAY_NOT_READY 0
> +#define VGT_DRV_DISPLAY_READY     1
> +
> +struct vgt_if {
> +  UINT64 magic;    /* VGT_MAGIC */
> +  UINT16 version_major;
> +  UINT16 version_minor;
> +  UINT32 vgt_id;    /* ID of vGT instance */
> +  UINT32 vgt_caps;    /* VGT capabilities */
> +  UINT32 rsv1[11];    /* pad to offset 0x40 */
> +  /*
> +   *  Data structure to describe the balooning info of resources.
> +   *  Each VM can only have one portion of continuous area for now.
> +   *  (May support scattered resource in future)
> +   *  (starting from offset 0x40)
> +   */
> +  struct {
> +    /* Aperture register balooning */
> +    struct {
> +      UINT32 base;
> +      UINT32 size;
> +    } mappable_gmadr;  /* aperture */
> +    /* GMADR register balooning */
> +    struct {
> +      UINT32 base;
> +      UINT32 size;
> +    } nonmappable_gmadr;  /* non aperture */
> +    /* allowed fence registers */
> +    UINT32 fence_num;
> +    UINT32 rsv2[3];
> +  } avail_rs;    /* available/assigned resource */
> +  UINT32 rsv3[0x200 - 24];  /* pad to half page */
> +  /*
> +   * The bottom half page is for response from Gfx driver to hypervisor.
> +   */
> +  UINT32 rsv4;
> +  UINT32 display_ready;  /* ready for display owner switch */
> +
> +  UINT32 rsv5[4];
> +
> +  UINT32 g2v_notify;
> +  UINT32 rsv6[5];
> +
> +  UINT32 cursor_x_hot;
> +  UINT32 cursor_y_hot;
> +
> +  struct {
> +    UINT32 lo;
> +    UINT32 hi;
> +  } pdp[4];
> +
> +  UINT32 execlist_context_descriptor_lo;
> +  UINT32 execlist_context_descriptor_hi;
> +
> +  UINT32  rsv7[0x200 - 24];    /* pad to one page */
> +} PACKED;
> +
> +#define vgtif_offset(x) (OFFSET_OF(struct vgt_if, x))
> +#define vgtif_reg(x) (VGT_PVINFO_PAGE + vgtif_offset(x))
> +
> +typedef enum _GPU_DISPLAY_PIPE {
> +  PIPE_INVALID = -1,
> +  PIPE_A = 0,
> +  PIPE_B,
> +  PIPE_C,
> +  PIPE_MAX = PIPE_C
> +} GPU_DISPLAY_PIPE;
> +
> +typedef enum _GPU_DISPLAY_PLANE {
> +  PLANE_PRIMARY = 0,
> +  PLANE_SPRITE0,
> +  PLANE_SPRITE1,
> +  PLANE_MAX,
> +} GPU_DISPLAY_PLANE;
> +
> +#define _TRANS_HTOTAL_A 0x60000
> +#define _TRANS_VTOTAL_A 0x6000C
> +#define _TRANS_REG_OFFSET(trans) (trans * 0x1000)
> +
> +#define _PS_WIN_POS_1_A 0x68170
> +#define _PS_WIN_SZ_1_A 0x68174
> +#define _PS_CTRL_1_A 0x68180
> +#define _PS_REG_OFFSET(pipe, id) (pipe * 0x800 + id * 0x100)
> +#define PS_WIN_POS(pipe, id) (_PS_WIN_POS_1_A + _PS_REG_OFFSET(pipe, id))
> +#define PS_WIN_SZ(pipe, id) (_PS_WIN_SZ_1_A + _PS_REG_OFFSET(pipe, id))
> +#define PS_CTRL(pipe, id) (_PS_CTRL_1_A + _PS_REG_OFFSET(pipe, id))
> +#define   PS_CTRL_SCALER_EN (1 << 31)
> +#define   PS_CTRL_SCALER_MODE_MASK (0x3 << 28)
> +#define   PS_CTRL_SCALER_MODE_DYN  (0 << 28)
> +#define   PS_CTRL_SCALER_MODE_HQ  (1 << 28)
> +#define   PS_CTRL_SCALER_BINDING_MASK  (0x7 << 25)
> +#define   PS_CTRL_SCALER_BINDING_PIPE  (0 << 25)
> +#define   PS_CTRL_PLANE_SEL(plane) (((plane) + 1) << 25)
> +#define   PS_CTRL_SCALER_FILTER_MASK         (3 << 23)
> +#define   PS_CTRL_SCALER_FILTER_MEDIUM       (0 << 23)
> +
> +#define PIPE_REG_OFFSET(pipe) (pipe * 0x1000)
> +#define _PIPE_CONF_A 0x70008
> +#define   PIPE_CONF_ENABLE (1 << 31)
> +#define _PIPE_SRCSZ_A 0x6001C
> +#define PIPE_CONF(pipe) (_PIPE_CONF_A + PIPE_REG_OFFSET(pipe))
> +#define PIPESRC(pipe) (_PIPE_SRCSZ_A + PIPE_REG_OFFSET(pipe))
> +
> +#define _PLANE_CTL_1_A 0x70180
> +#define   PLANE_CTL_ENABLE (1 << 31)
> +#define   PLANE_CTL_PIPE_GAMMA_ENABLE (1 << 30)
> +#define   PLANE_CTL_FORMAT_MASK (0xF << 24)
> +#define   PLANE_CTL_FORMAT_XRGB_8888 (0x4 << 24)
> +#define   PLANE_CTL_PIPE_CSC_ENABLE (1 << 23)
> +#define   PLANE_CTL_KEY_ENABLE_MASK (0x3 << 21)
> +#define   PLANE_CTL_ORDER_RGBX (1 << 20)
> +#define   PLANE_CTL_RENDER_DECOMPRESSION_ENABLE (1 << 15)
> +#define   PLANE_CTL_PLANE_GAMMA_DISABLE (1 << 13)
> +#define   PLANE_CTL_TILED_MASK (0x7 << 10)
> +#define   PLANE_CTL_TILED_LINEAR (0 << 10)
> +#define   PLANE_CTL_ASYNC_FLIP (1 << 9)
> +#define   PLANE_CTL_ALPHA_MASK (0x3 << 4)
> +#define   PLANE_CTL_ALPHA_DISABLE (0 << 4)
> +#define   PLANE_CTL_ROTATE_MASK (0x3 << 0)
> +#define   PLANE_CTL_ROTATE_0 (0x0 << 0)
> +
> +#define _PLANE_STRIDE_1_A 0x70188
> +#define   PLANE_STRIDE_MASK 0x1FF
> +#define _PLANE_POS_1_A  0x7018C
> +#define _PLANE_SIZE_1_A 0x70190
> +#define _PLANE_SURF_1_A 0x7019C
> +#define _PLANE_REG_OFFSET(pipe, plane) (pipe * 0x1000 + plane * 0x100)
> +
> +#define HTOTAL(trans) (_TRANS_HTOTAL_A + _TRANS_REG_OFFSET(trans))
> +#define VTOTAL(trans) (_TRANS_VTOTAL_A + _TRANS_REG_OFFSET(trans))
> +
> +#define PLANE_CTL(pipe, plane) (_PLANE_CTL_1_A + _PLANE_REG_OFFSET(pipe, plane))
> +#define PLANE_STRIDE(pipe, plane) (_PLANE_STRIDE_1_A + _PLANE_REG_OFFSET(pipe, plane))
> +#define PLANE_POS(pipe, plane) (_PLANE_POS_1_A + _PLANE_REG_OFFSET(pipe, plane))
> +#define PLANE_SIZE(pipe, plane) (_PLANE_SIZE_1_A + _PLANE_REG_OFFSET(pipe, plane))
> +#define PLANE_SURF(pipe, plane) (_PLANE_SURF_1_A + _PLANE_REG_OFFSET(pipe, plane))
> +
> +EFI_STATUS
> +RegRead32 (
> +  IN  GVT_GOP_PRIVATE_DATA *Private,
> +  IN  UINT32 Offset,
> +  OUT UINT32 *ValuePtr
> +  );
> +
> +EFI_STATUS
> +RegWrite32 (
> +  IN GVT_GOP_PRIVATE_DATA *Private,
> +  IN UINT32 Offset,
> +  IN UINT32 Value
> +  );
> +
> +#endif //__GPUREG_H_
> diff --git a/OvmfPkg/IntelGvtGopDxe/Gtt.c b/OvmfPkg/IntelGvtGopDxe/Gtt.c
> new file mode 100644
> index 000000000000..12782eb5afaa
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/Gtt.c
> @@ -0,0 +1,162 @@
> +/** @file
> +  Component name for the QEMU video controller.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Common.h"
> +#include "Gtt.h"
> +#include "VirtualGpu.h"
> +
> +EFI_STATUS
> +GGTTGetEntry (
> +  IN  GVT_GOP_PRIVATE_DATA *Private,
> +  IN  UINT64 Index,
> +  OUT GTT_PTE_ENTRY *Entry
> +  )
> +{
> +  EFI_STATUS          Status = EFI_INVALID_PARAMETER;
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  PINTEL_VIRTUAL_GPU  VirtualGpu;
> +
> +  if (Entry == NULL) {
> +    Status = EFI_INVALID_PARAMETER;
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "%a invalid GGTT entry ptr %p at Index %x, status %d\n",
> +      __FUNCTION__, Entry, Index, Status
> +      );
> +    goto Done;
> +  }
> +
> +  PciIo = Private->PciIo;
> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
> +
> +  if (Index >= VirtualGpu->VisibleGGTTOffset &&
> +       Index < VirtualGpu->VisibleGGTTOffset + VirtualGpu->VisibleGGTTSize) {
> +    Status = PciIo->Mem.Read (
> +                          PciIo,
> +                          EfiPciIoWidthUint64,
> +                          PCI_BAR_IDX0,
> +                          GTT_OFFSET + Index * GTT_ENTRY_SIZE,
> +                          1,
> +                          Entry
> +                          );
> +    if (EFI_ERROR (Status)) {
> +      Entry = 0;
> +      GVT_DEBUG (EFI_D_ERROR,
> +        "Failed to Get GGTT Entry index %lx, status %d\n", Index, Status
> +        );
> +    }
> +  } else if (Index >= VirtualGpu->InvisibleGGTTOffset &&
> +             Index < VirtualGpu->InvisibleGGTTOffset + VirtualGpu->InvisibleGGTTSize) {
> +    Status = EFI_UNSUPPORTED;
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Skip get GGTT index %lx for invisible GMADR\n", Index
> +      );
> +  } else {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Skip get GGTT index %lx out-of-range, balloon unsupported\n",
> +      Index
> +      );
> +  }
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "Get GGTT Entry %lx at index %lx\n", *Entry, Index);
> +
> +Done:
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +GGTTSetEntry (
> +  IN GVT_GOP_PRIVATE_DATA *Private,
> +  IN UINT64 Index,
> +  IN GTT_PTE_ENTRY Entry
> +  )
> +{
> +  EFI_STATUS          Status = EFI_INVALID_PARAMETER;
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  PINTEL_VIRTUAL_GPU  VirtualGpu;
> +
> +  PciIo = Private->PciIo;
> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
> +
> +  if (Index >= VirtualGpu->VisibleGGTTOffset &&
> +      Index < VirtualGpu->VisibleGGTTOffset + VirtualGpu->VisibleGGTTSize) {
> +    Status = PciIo->Mem.Write (
> +                          PciIo,
> +                          EfiPciIoWidthUint64,
> +                          PCI_BAR_IDX0,
> +                          GTT_OFFSET + Index * GTT_ENTRY_SIZE,
> +                          1,
> +                          &Entry
> +                          );
> +    if (EFI_ERROR (Status)) {
> +      GVT_DEBUG (EFI_D_ERROR,
> +        "Failed to Set GGTT Entry %lx at index %lx, status %d\n",
> +        Entry, Index, Status
> +        );
> +    }
> +  } else if (Index >= VirtualGpu->InvisibleGGTTOffset &&
> +             Index < VirtualGpu->InvisibleGGTTOffset + VirtualGpu->InvisibleGGTTSize) {
> +    Status = EFI_UNSUPPORTED;
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Skip set GGTT index %lx for invisible GMADR\n", Index
> +      );
> +  } else {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Skip set GGTT index %lx out-of-range, balloon unsupported\n", Index
> +      );
> +  }
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "Set GGTT Entry %lx at index %lx\n", Entry, Index);
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +UpdateGGTT (
> +  IN GVT_GOP_PRIVATE_DATA *Private,
> +  IN EFI_PHYSICAL_ADDRESS GMAddr,
> +  IN EFI_PHYSICAL_ADDRESS SysAddr,
> +  IN UINTN                Pages
> +  )
> +{
> +  EFI_STATUS         Status = EFI_INVALID_PARAMETER;
> +  PINTEL_VIRTUAL_GPU VirtualGpu;
> +  UINTN              GttOffset, Index;
> +  GTT_PTE_ENTRY      Entry;
> +
> +  if (!IS_ALIGNED(SysAddr, GTT_PAGE_SIZE)) {
> +    Status = EFI_INVALID_PARAMETER;
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Failed to update GGTT GMADR %lx, SysAddr %lx isn't aligned to 0x%lx, status %d\n",
> +      GMAddr, SysAddr, GTT_PAGE_SIZE, Status
> +      );
> +    goto Done;
> +  }
> +
> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
> +  GttOffset = (GMAddr - VirtualGpu->GpuMemAddr) >> GTT_PAGE_SHIFT;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE,
> +    "Update GGTT GMADR %lx, SysAddr %lx, Pages 0x%lx\n",
> +    GMAddr, SysAddr, Pages
> +    );
> +  for (Index = 0; Index < Pages; Index++) {
> +    Entry = SysAddr + Index * GTT_PAGE_SIZE;
> +    Entry |= (GTT_PAGE_PRESENT | GTT_PAGE_READ_WRITE);
> +    Entry |= (GTT_PAGE_PWT | GTT_PAGE_PCD);
> +    GGTTSetEntry (Private, GttOffset + Index, Entry);
> +  }
> +
> +  Status = EFI_SUCCESS;
> +
> +Done:
> +  return Status;
> +}
> diff --git a/OvmfPkg/IntelGvtGopDxe/Gtt.h b/OvmfPkg/IntelGvtGopDxe/Gtt.h
> new file mode 100644
> index 000000000000..fc91b7a84a0a
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/Gtt.h
> @@ -0,0 +1,51 @@
> +/** @file
> +  Component name for the QEMU video controller.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __GTT_H_
> +#define __GTT_H_
> +
> +#include "Common.h"
> +
> +typedef UINT64 GTT_PTE_ENTRY;
> +
> +#define GTT_OFFSET          0x800000
> +#define GTT_SIZE            0x800000
> +#define GTT_ENTRY_SIZE      sizeof(GTT_PTE_ENTRY)
> +#define GTT_ENTRY_NUM       (GTT_SIZE / GTT_ENTRY_SIZE)
> +#define GTT_PAGE_SHIFT      12
> +#define GTT_PAGE_SIZE       (1UL << GTT_PAGE_SHIFT)
> +#define GTT_PAGE_MASK       (~(GTT_PAGE_SIZE-1))
> +#define GTT_PAGE_PRESENT    0x01
> +#define GTT_PAGE_READ_WRITE 0x02
> +#define GTT_PAGE_PWT        0x08
> +#define GTT_PAGE_PCD        0x10
> +
> +EFI_STATUS
> +GGTTGetEntry (
> +  IN  GVT_GOP_PRIVATE_DATA *Private,
> +  IN  UINT64 Index,
> +  OUT GTT_PTE_ENTRY *Entry
> +  );
> +
> +EFI_STATUS
> +GGTTSetEntry (
> +  IN GVT_GOP_PRIVATE_DATA *Private,
> +  IN UINT64 Index,
> +  IN GTT_PTE_ENTRY Entry
> +  );
> +
> +EFI_STATUS
> +UpdateGGTT (
> +  IN GVT_GOP_PRIVATE_DATA *Private,
> +  IN EFI_PHYSICAL_ADDRESS GMAddr,
> +  IN EFI_PHYSICAL_ADDRESS SysAddr,
> +  IN UINTN                Pages
> +  );
> +
> +#endif //__GTT_H_
> diff --git a/OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf b/OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf
> new file mode 100644
> index 000000000000..c6e1751e1a22
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf
> @@ -0,0 +1,59 @@
> +## @file
> +# Intel GVT-g Graphics Output Protocol driver
> +#
> +# Copyright (C) 2021 Intel Corporation. All rights reserved.
> +#
> +# SPDX-License-Identifier: BSD-2-Clause
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = GvtGopDxe
> +  FILE_GUID                      = 7c2a0c14-2a63-4d08-9c7f-d55691e1cedb
> +  MODULE_TYPE                    = UEFI_DRIVER
> +  VERSION_STRING                 = 2.0
> +  ENTRY_POINT                    = GvtGopEntryPoint
> +
> +[Sources]
> +  Common.h
> +  DebugHelper.h
> +  Display.c
> +  Display.h
> +  GopDriver.c
> +  GpuReg.c
> +  GpuReg.h
> +  Gtt.c
> +  Gtt.h
> +  VirtualGpu.h
> +  VirtualGpu.c
> +  VbeShim.c
> +  VbeShim.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  OvmfPkg/OvmfPkg.dec
> +
> +[LibraryClasses]
> +  BaseMemoryLib
> +  FrameBufferBltLib
> +  DebugLib
> +  DevicePathLib
> +  MemoryAllocationLib
> +  PrintLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  UefiLib
> +  PcdLib
> +  PciLib
> +  QemuFwCfgLib
> +
> +[Protocols]
> +  gEfiGraphicsOutputProtocolGuid
> +  gEfiPciIoProtocolGuid
> +  gEfiDevicePathProtocolGuid
> +
> +[Pcd]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution
> diff --git a/OvmfPkg/IntelGvtGopDxe/VbeShim.asm b/OvmfPkg/IntelGvtGopDxe/VbeShim.asm
> new file mode 100644
> index 000000000000..43a44362b794
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/VbeShim.asm
> @@ -0,0 +1,343 @@
> +;------------------------------------------------------------------------------
> +; @file
> +; A minimal Int10h stub that allows the Windows 2008 R2 SP1 UEFI guest's buggy,
> +; default VGA driver to switch to 1024x768x32.
> +;
> +; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +; Copyright (C) 2020, Rebecca Cran <rebecca@bsdio.com>
> +; Copyright (C) 2015, Nahanni Systems, Inc.
> +; Copyright (C) 2014, Red Hat, Inc.
> +; Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
> +;
> +; SPDX-License-Identifier: BSD-2-Clause-Patent
> +;
> +;------------------------------------------------------------------------------
> +
> +; enable this macro for debug messages
> +%define DEBUG
> +
> +%macro DebugLog 1
> +%ifdef DEBUG
> +  push       si
> +  mov        si, %1
> +  call       PrintStringSi
> +  pop        si
> +%endif
> +%endmacro
> +
> +
> +BITS 16
> +ORG 0
> +
> +VbeInfo:
> +TIMES 256 nop
> +
> +VbeModeInfo:
> +VbeMode1:
> +TIMES 50  nop
> +VbeMode2:
> +TIMES 50  nop
> +VbeMode3:
> +TIMES 50  nop
> +VbeMode4:
> +TIMES 50  nop
> +TIMES 56  nop  ; filler for 256 bytes
> +
> +Handler:
> +  cmp        ax, 0x4f00
> +  je         GetInfo
> +  cmp        ax, 0x4f01
> +  je         GetModeInfo
> +  cmp        ax, 0x4f02
> +  je         SetMode
> +  cmp        ax, 0x4f03
> +  je         GetMode
> +  cmp        ax, 0x4f10
> +  je         GetPmCapabilities
> +  cmp        ax, 0x4f15
> +  je         ReadEdid
> +  cmp        ah, 0x00
> +  je         SetModeLegacy
> +  DebugLog   StrUnkownFunction
> +Hang:
> +  jmp        Hang
> +
> +
> +GetInfo:
> +  push       es
> +  push       di
> +  push       ds
> +  push       si
> +  push       cx
> +
> +  DebugLog   StrEnterGetInfo
> +
> +  ; target (es:di) set on input
> +  push       cs
> +  pop        ds
> +  mov        si, VbeInfo
> +  ; source (ds:si) set now
> +
> +  mov        cx, 256
> +  cld
> +  rep movsb
> +
> +  pop        cx
> +  pop        si
> +  pop        ds
> +  pop        di
> +  pop        es
> +  jmp        Success
> +
> +
> +GetModeInfo:
> +  push       es
> +  push       di
> +  push       ds
> +  push       si
> +  push       cx
> +
> +  DebugLog   StrEnterGetModeInfo
> +
> +  and        cx, ~0x4000 ; clear potentially set LFB bit in mode number
> +
> +  cmp        cx, 0x013f
> +  je         gKnownMode1
> +  cmp        cx, 0x0140
> +  je         gKnownMode2
> +  cmp        cx, 0x0141
> +  je         gKnownMode3
> +
> +  DebugLog   StrUnkownMode
> +  jmp        Hang
> +gKnownMode1:
> +  DebugLog   StrMode1
> +  mov        si, VbeMode1
> +  jmp        CopyModeInfo
> +gKnownMode2:
> +  DebugLog   StrMode2
> +  mov        si, VbeMode2
> +  jmp        CopyModeInfo
> +gKnownMode3:
> +  DebugLog   StrMode3
> +  mov        si, VbeMode3
> +  jmp        CopyModeInfo
> +gKnownMode4:
> +  DebugLog   StrMode4
> +  mov        si, VbeMode4
> +  jmp        CopyModeInfo
> +
> +CopyModeInfo:
> +  ; target (es:di) set on input
> +  push       cs
> +  pop        ds
> +  ;mov        si, VbeModeInfo
> +  ; source (ds:si) set now
> +
> +  ;mov        cx, 256
> +  mov        cx, 50
> +  cld
> +  rep movsb
> +
> +  pop        cx
> +  pop        si
> +  pop        ds
> +  pop        di
> +  pop        es
> +  jmp        Success
> +
> +
> +SetMode:
> +  push       dx
> +  push       ax
> +
> +  DebugLog   StrEnterSetMode
> +
> +  and        bx, ~0x4000 ; clear potentially set LFB bit in mode number
> +  cmp        bx, 0x013f
> +  je         KnownMode1
> +  cmp        bx, 0x0140
> +  je         KnownMode2
> +  cmp        bx, 0x0141
> +  je         KnownMode3
> +  DebugLog   StrUnkownMode
> +  jmp        Hang
> +KnownMode1:
> +  DebugLog   StrMode1
> +  jmp        SetModeDone
> +KnownMode2:
> +  DebugLog   StrMode2
> +  jmp        SetModeDone
> +KnownMode3:
> +  DebugLog   StrMode3
> +  jmp        SetModeDone
> +KnownMode4:
> +  DebugLog   StrMode4
> +
> +SetModeDone:
> +  mov        [CurMode], bl
> +  mov        [CurMode+1], bh
> +  pop        ax
> +  pop        dx
> +  jmp        Success
> +
> +
> +GetMode:
> +  DebugLog   StrEnterGetMode
> +  mov        bl, [CurMode]
> +  mov        bh, [CurMode+1]
> +  jmp        Success
> +
> +
> +GetPmCapabilities:
> +  DebugLog   StrGetPmCapabilities
> +  mov        bx, 0x0080
> +  jmp        Success
> +
> +
> +ReadEdid:
> +  push       es
> +  push       di
> +  push       ds
> +  push       si
> +  push       cx
> +
> +  DebugLog   StrReadEdid
> +
> +  ; target (es:di) set on input
> +  push       cs
> +  pop        ds
> +  mov        si, Edid
> +  ; source (ds:si) set now
> +
> +  mov        cx, 128
> +  cld
> +  rep movsb
> +
> +  pop        cx
> +  pop        si
> +  pop        ds
> +  pop        di
> +  pop        es
> +  jmp        Success
> +
> +
> +SetModeLegacy:
> +  DebugLog   StrEnterSetModeLegacy
> +
> +  cmp        al, 0x03
> +  je         sKnownMode3
> +  cmp        al, 0x12
> +  je         sKnownMode4
> +  DebugLog   StrUnkownMode
> +  jmp        Hang
> +sKnownMode3:
> +  DebugLog   StrLegacyMode3
> +  mov        al, 0 ; 0x30
> +  jmp        SetModeLegacyDone
> +sKnownMode4:
> +  mov        al, 0 ;0x20
> +SetModeLegacyDone:
> +  DebugLog   StrExitSuccess
> +  iret
> +
> +
> +Success:
> +  DebugLog   StrExitSuccess
> +  mov        ax, 0x004f
> +  iret
> +
> +
> +Unsupported:
> +  DebugLog   StrExitUnsupported
> +  mov        ax, 0x024f
> +  iret
> +
> +
> +%ifdef DEBUG
> +PrintStringSi:
> +  pusha
> +  push       ds ; save original
> +  push       cs
> +  pop        ds
> +  mov        dx, 0x220             ; bhyve debug cons port
> +  mov        ax, 0
> +PrintStringSiLoop:
> +  lodsb
> +  cmp        al, 0
> +  je         PrintStringSiDone
> +  out        dx, al
> +  jmp        PrintStringSiLoop
> +PrintStringSiDone:
> +  pop        ds ; restore original
> +  popa
> +  ret
> +
> +
> +StrExitSuccess:
> +  db 'vOk', 0x0d, 0x0a, 0
> +
> +StrExitUnsupported:
> +  db 'vUnsupported', 0x0d, 0x0a, 0
> +
> +StrUnkownFunction:
> +  db 'vUnknown Function', 0x0d, 0x0a, 0
> +
> +StrEnterGetInfo:
> +  db 'vGetInfo', 0x0d, 0x0a, 0
> +
> +StrEnterGetModeInfo:
> +  db 'vGetModeInfo', 0x0d, 0x0a, 0
> +
> +StrEnterGetMode:
> +  db 'vGetMode', 0x0d, 0x0a, 0
> +
> +StrEnterSetMode:
> +  db 'vSetMode', 0x0d, 0x0a, 0
> +
> +StrEnterSetModeLegacy:
> +  db 'vSetModeLegacy', 0x0d, 0x0a, 0
> +
> +StrUnkownMode:
> +  db 'vUnkown Mode', 0x0d, 0x0a, 0
> +
> +StrGetPmCapabilities:
> +  db 'vGetPmCapabilities', 0x0d, 0x0a, 0
> +
> +StrReadEdid:
> +  db 'vReadEdid', 0x0d, 0x0a, 0
> +
> +StrLegacyMode3:
> +  db 'vLegacyMode3', 0x0d, 0x0a, 0
> +
> +
> +StrMode1:
> +  db 'mode_640x480x32', 0x0d, 0x0a, 0
> +StrMode2:
> +  db 'mode_800x600x32', 0x0d, 0x0a, 0
> +StrMode3:
> +  db 'mode_1024x768x32', 0x0d, 0x0a, 0
> +StrMode4:
> +  db 'mode_unused', 0x0d, 0x0a, 0
> +%endif
> +
> +CurMode:
> +  db 0x00, 0x00
> +
> +;
> +; EDID stores monitor information. For now, just send back an null item.
> +;
> +Edid:
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> diff --git a/OvmfPkg/IntelGvtGopDxe/VbeShim.c b/OvmfPkg/IntelGvtGopDxe/VbeShim.c
> new file mode 100644
> index 000000000000..8063224d53b4
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/VbeShim.c
> @@ -0,0 +1,258 @@
> +/** @file
> +  Install a fake VGABIOS service handler (real mode Int10h) for the buggy
> +  Windows 2008 R2 SP1 UEFI guest.
> +
> +  The handler is never meant to be directly executed by a VCPU; it's there for
> +  the internal real mode emulator of Windows 2008 R2 SP1.
> +
> +  The code is based on Ralf Brown's Interrupt List:
> +  <http://www.cs.cmu.edu/~ralf/files.html>
> +  <http://www.ctyme.com/rbrown.htm>
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +  Copyright (C) 2020, Rebecca Cran <rebecca@bsdio.com>
> +  Copyright (C) 2015, Nahanni Systems, Inc.
> +  Copyright (C) 2014, Red Hat, Inc.
> +  Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Common.h"
> +#include <IndustryStandard/LegacyVgaBios.h>
> +#include <Library/PciLib.h>
> +#include <Library/PrintLib.h>
> +#include "VbeShim.h"
> +
> +#pragma pack (1)
> +typedef struct {
> +  UINT16 Offset;
> +  UINT16 Segment;
> +} IVT_ENTRY;
> +#pragma pack ()
> +
> +//
> +// This string is displayed by Windows 2008 R2 SP1 in the Screen Resolution,
> +// Advanced Settings dialog. It should be short.
> +//
> +STATIC CONST CHAR8 mProductRevision[] = "2.0";
> +
> +#define NUM_VBE_MODES 3
> +STATIC CONST UINT16 vbeModeIds[] = {
> +  0x13f,  // 640x480x32
> +  0x140,  // 800x600x32
> +  0x141   // 1024x768x32
> +};
> +
> +// Modes can be toggled with bit-0
> +#define VBE_MODE_ENABLED  0x00BB
> +#define VBE_MODE_DISABLED 0x00BA
> +
> +STATIC VBE2_MODE_INFO vbeModes[] = {
> +  { // 0x13f 640x480x32
> +
> +    // ModeAttr - BytesPerScanLine
> +    VBE_MODE_DISABLED, 0x07, 0x00, 0x40, 0x40, 0xA000, 0x00, 0x0000, 640*4,
> +    // Width, Height..., Vbe3
> +    640, 480, 16, 8, 1, 32, 1, 0x06, 0, 0, 1,
> +    // Masks
> +    0x08, 0x10, 0x08, 0x08, 0x08, 0x00, 0x08, 0x18, 0x00,
> +    // Framebuffer
> +    0xdeadbeef, 0x0000, 0x0000
> +  },
> +  { // 0x140 800x600x32
> +
> +    // ModeAttr - BytesPerScanLine
> +    VBE_MODE_DISABLED, 0x07, 0x00, 0x40, 0x40, 0xA000, 0x00, 0x0000, 800*4,
> +    // Width, Height..., Vbe3
> +    800, 600, 16, 8, 1, 32, 1, 0x06, 0, 0, 1,
> +    // Masks
> +    0x08, 0x10, 0x08, 0x08, 0x08, 0x00, 0x08, 0x18, 0x00,
> +    // Framebuffer
> +    0xdeadbeef, 0x0000, 0x0000
> +  },
> +  { // 0x141 1024x768x32
> +
> +    // ModeAttr - BytesPerScanLine
> +    VBE_MODE_ENABLED, 0x07, 0x00, 0x40, 0x40, 0xA000, 0x00, 0x0000, 1024*4,
> +    // Width, Height..., Vbe3
> +    1024, 768, 16, 8, 1, 32, 1, 0x06, 0, 0, 1,
> +    // Masks
> +    0x08, 0x10, 0x08, 0x08, 0x08, 0x00, 0x08, 0x18, 0x00,
> +    // Framebuffer
> +    0xdeadbeef, 0x0000, 0x0000
> +  }
> +};
> +
> +/**
> +  Install the VBE Info and VBE Mode Info structures, and the VBE service
> +  handler routine in the C segment. Point the real-mode Int10h interrupt vector
> +  to the handler. The only advertised mode is 1024x768x32.
> +
> +  @param[in] CardName         Name of the video card to be exposed in the
> +                              Product Name field of the VBE Info structure.
> +  @param[in] FrameBufferBase  Guest-physical base address of the video card's
> +                              frame buffer.
> +**/
> +VOID
> +InstallVbeShim (
> +  IN CONST CHAR16         *CardName,
> +  IN EFI_PHYSICAL_ADDRESS FrameBufferBase
> +  )
> +{
> +  EFI_PHYSICAL_ADDRESS Segment0, SegmentC, SegmentF;
> +  UINTN                Segment0Pages;
> +  IVT_ENTRY            *Int0x10;
> +  EFI_STATUS           Status;
> +  UINTN                Pam1Address;
> +  UINT8                Pam1;
> +  UINTN                SegmentCPages;
> +  VBE_INFO             *VbeInfoFull;
> +  VBE_INFO_BASE        *VbeInfo;
> +  UINT8                *Ptr;
> +  UINTN                Printed;
> +  VBE_MODE_INFO        *VbeModeInfo;
> +  UINTN                i;
> +
> +  Segment0 = 0x00000;
> +  SegmentC = 0xC0000;
> +  SegmentF = 0xF0000;
> +
> +  //
> +  // Attempt to cover the real mode IVT with an allocation. This is a UEFI
> +  // driver, hence the arch protocols have been installed previously. Among
> +  // those, the CPU arch protocol has configured the IDT, so we can overwrite
> +  // the IVT used in real mode.
> +  //
> +  // The allocation request may fail, eg. if LegacyBiosDxe has already run.
> +  //
> +  Segment0Pages = 1;
> +  Int0x10       = (IVT_ENTRY *)(UINTN)Segment0 + 0x10;
> +  Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode,
> +                  Segment0Pages, &Segment0);
> +
> +  if (EFI_ERROR (Status)) {
> +    EFI_PHYSICAL_ADDRESS Handler;
> +
> +    //
> +    // Check if a video BIOS handler has been installed previously -- we
> +    // shouldn't override a real video BIOS with our shim, nor our own shim if
> +    // it's already present.
> +    //
> +    Handler = (Int0x10->Segment << 4) + Int0x10->Offset;
> +    if (Handler >= SegmentC && Handler < SegmentF) {
> +      DEBUG ((DEBUG_VERBOSE, "%a: Video BIOS handler found at %04x:%04x\n",
> +        __FUNCTION__, Int0x10->Segment, Int0x10->Offset));
> +      return;
> +    }
> +
> +    //
> +    // Otherwise we'll overwrite the Int10h vector, even though we may not own
> +    // the page at zero.
> +    //
> +    DEBUG ((DEBUG_VERBOSE, "%a: failed to allocate page at zero: %r\n",
> +      __FUNCTION__, Status));
> +  } else {
> +    //
> +    // We managed to allocate the page at zero. SVN r14218 guarantees that it
> +    // is NUL-filled.
> +    //
> +    ASSERT (Int0x10->Segment == 0x0000);
> +    ASSERT (Int0x10->Offset  == 0x0000);
> +  }
> +
> +  //
> +  // Put the shim in place first.
> +  //
> +  Pam1Address = PCI_LIB_ADDRESS (0, 0, 0, 0x5A);
> +  //
> +  // low nibble covers 0xC0000 to 0xC3FFF
> +  // high nibble covers 0xC4000 to 0xC7FFF
> +  // bit1 in each nibble is Write Enable
> +  // bit0 in each nibble is Read Enable
> +  //
> +  Pam1 = PciRead8 (Pam1Address);
> +  PciWrite8 (Pam1Address, Pam1 | (BIT1 | BIT0));
> +
> +  //
> +  // We never added memory space durig PEI or DXE for the C segment, so we
> +  // don't need to (and can't) allocate from there. Also, guest operating
> +  // systems will see a hole in the UEFI memory map there.
> +  //
> +  SegmentCPages = 4;
> +
> +  ASSERT (sizeof gVbeShim <= EFI_PAGES_TO_SIZE (SegmentCPages));
> +  CopyMem ((VOID *)(UINTN)SegmentC, gVbeShim, sizeof gVbeShim);
> +
> +  //
> +  // Fill in the VBE INFO structure.
> +  //
> +  VbeInfoFull = (VBE_INFO *)(UINTN)SegmentC;
> +  VbeInfo     = &VbeInfoFull->Base;
> +  Ptr         = VbeInfoFull->Buffer;
> +
> +  CopyMem (VbeInfo->Signature, "VESA", 4);
> +  VbeInfo->VesaVersion = 0x0200;
> +
> +  VbeInfo->OemNameAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
> +  CopyMem (Ptr, "FBSD", 5);
> +  Ptr += 5;
> +
> +  VbeInfo->Capabilities = BIT1 | BIT0; // DAC can be switched into 8-bit mode
> +
> +  VbeInfo->ModeListAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
> +  for (i = 0; i < NUM_VBE_MODES; i ++) {
> +     *(UINT16*)Ptr = vbeModeIds[i];  // mode number
> +     Ptr += 2;
> +  }
> +  *(UINT16*)Ptr = 0xFFFF; // mode list terminator
> +  Ptr += 2;
> +
> +  VbeInfo->VideoMem64K = (UINT16)((1024 * 768 * 4 + 65535) / 65536);
> +  VbeInfo->OemSoftwareVersion = 0x0200;
> +
> +  VbeInfo->VendorNameAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
> +  CopyMem (Ptr, "FBSD", 5);
> +  Ptr += 5;
> +
> +  VbeInfo->ProductNameAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
> +  Printed = AsciiSPrint ((CHAR8 *)Ptr,
> +              sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer), "%s",
> +              CardName);
> +  Ptr += Printed + 1;
> +
> +  VbeInfo->ProductRevAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
> +  CopyMem (Ptr, mProductRevision, sizeof mProductRevision);
> +  Ptr += sizeof mProductRevision;
> +
> +  ASSERT (sizeof VbeInfoFull->Buffer >= Ptr - VbeInfoFull->Buffer);
> +  ZeroMem (Ptr, sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer));
> +
> +  //
> +  // Fill in the VBE MODE INFO structure list
> +  //
> +  VbeModeInfo = (VBE_MODE_INFO *)(VbeInfoFull + 1);
> +  Ptr = (UINT8 *)VbeModeInfo;
> +  for (i = 0; i < NUM_VBE_MODES; i++) {
> +    vbeModes[i].LfbAddress = (UINT32)FrameBufferBase;
> +    CopyMem (Ptr, &vbeModes[i], 0x32);
> +    Ptr += 0x32;
> +  }
> +
> +  ZeroMem (Ptr, 56);     // Clear remaining bytes
> +
> +  //
> +  // Clear Write Enable (bit1), keep Read Enable (bit0) set
> +  //
> +  PciWrite8 (Pam1Address, (Pam1 & ~BIT1) | BIT0);
> +
> +  //
> +  // Second, point the Int10h vector at the shim.
> +  //
> +  Int0x10->Segment = (UINT16) ((UINT32)SegmentC >> 4);
> +  Int0x10->Offset  = (UINT16) ((UINTN) (VbeModeInfo + 1) - SegmentC);
> +
> +  DEBUG ((DEBUG_INFO, "%a: VBE shim installed to %x:%x\n",
> +         __FUNCTION__, Int0x10->Segment, Int0x10->Offset));
> +}
> diff --git a/OvmfPkg/IntelGvtGopDxe/VbeShim.h b/OvmfPkg/IntelGvtGopDxe/VbeShim.h
> new file mode 100644
> index 000000000000..601b1465cbe5
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/VbeShim.h
> @@ -0,0 +1,912 @@
> +//
> +// THIS FILE WAS GENERATED BY "VbeShim.sh". DO NOT EDIT.
> +//
> +#ifndef _VBE_SHIM_H_
> +#define _VBE_SHIM_H_
> +STATIC CONST UINT8 gVbeShim[] = {
> +  /* 00000000 nop                            */  0x90,
> +  /* 00000001 nop                            */  0x90,
> +  /* 00000002 nop                            */  0x90,
> +  /* 00000003 nop                            */  0x90,
> +  /* 00000004 nop                            */  0x90,
> +  /* 00000005 nop                            */  0x90,
> +  /* 00000006 nop                            */  0x90,
> +  /* 00000007 nop                            */  0x90,
> +  /* 00000008 nop                            */  0x90,
> +  /* 00000009 nop                            */  0x90,
> +  /* 0000000A nop                            */  0x90,
> +  /* 0000000B nop                            */  0x90,
> +  /* 0000000C nop                            */  0x90,
> +  /* 0000000D nop                            */  0x90,
> +  /* 0000000E nop                            */  0x90,
> +  /* 0000000F nop                            */  0x90,
> +  /* 00000010 nop                            */  0x90,
> +  /* 00000011 nop                            */  0x90,
> +  /* 00000012 nop                            */  0x90,
> +  /* 00000013 nop                            */  0x90,
> +  /* 00000014 nop                            */  0x90,
> +  /* 00000015 nop                            */  0x90,
> +  /* 00000016 nop                            */  0x90,
> +  /* 00000017 nop                            */  0x90,
> +  /* 00000018 nop                            */  0x90,
> +  /* 00000019 nop                            */  0x90,
> +  /* 0000001A nop                            */  0x90,
> +  /* 0000001B nop                            */  0x90,
> +  /* 0000001C nop                            */  0x90,
> +  /* 0000001D nop                            */  0x90,
> +  /* 0000001E nop                            */  0x90,
> +  /* 0000001F nop                            */  0x90,
> +  /* 00000020 nop                            */  0x90,
> +  /* 00000021 nop                            */  0x90,
> +  /* 00000022 nop                            */  0x90,
> +  /* 00000023 nop                            */  0x90,
> +  /* 00000024 nop                            */  0x90,
> +  /* 00000025 nop                            */  0x90,
> +  /* 00000026 nop                            */  0x90,
> +  /* 00000027 nop                            */  0x90,
> +  /* 00000028 nop                            */  0x90,
> +  /* 00000029 nop                            */  0x90,
> +  /* 0000002A nop                            */  0x90,
> +  /* 0000002B nop                            */  0x90,
> +  /* 0000002C nop                            */  0x90,
> +  /* 0000002D nop                            */  0x90,
> +  /* 0000002E nop                            */  0x90,
> +  /* 0000002F nop                            */  0x90,
> +  /* 00000030 nop                            */  0x90,
> +  /* 00000031 nop                            */  0x90,
> +  /* 00000032 nop                            */  0x90,
> +  /* 00000033 nop                            */  0x90,
> +  /* 00000034 nop                            */  0x90,
> +  /* 00000035 nop                            */  0x90,
> +  /* 00000036 nop                            */  0x90,
> +  /* 00000037 nop                            */  0x90,
> +  /* 00000038 nop                            */  0x90,
> +  /* 00000039 nop                            */  0x90,
> +  /* 0000003A nop                            */  0x90,
> +  /* 0000003B nop                            */  0x90,
> +  /* 0000003C nop                            */  0x90,
> +  /* 0000003D nop                            */  0x90,
> +  /* 0000003E nop                            */  0x90,
> +  /* 0000003F nop                            */  0x90,
> +  /* 00000040 nop                            */  0x90,
> +  /* 00000041 nop                            */  0x90,
> +  /* 00000042 nop                            */  0x90,
> +  /* 00000043 nop                            */  0x90,
> +  /* 00000044 nop                            */  0x90,
> +  /* 00000045 nop                            */  0x90,
> +  /* 00000046 nop                            */  0x90,
> +  /* 00000047 nop                            */  0x90,
> +  /* 00000048 nop                            */  0x90,
> +  /* 00000049 nop                            */  0x90,
> +  /* 0000004A nop                            */  0x90,
> +  /* 0000004B nop                            */  0x90,
> +  /* 0000004C nop                            */  0x90,
> +  /* 0000004D nop                            */  0x90,
> +  /* 0000004E nop                            */  0x90,
> +  /* 0000004F nop                            */  0x90,
> +  /* 00000050 nop                            */  0x90,
> +  /* 00000051 nop                            */  0x90,
> +  /* 00000052 nop                            */  0x90,
> +  /* 00000053 nop                            */  0x90,
> +  /* 00000054 nop                            */  0x90,
> +  /* 00000055 nop                            */  0x90,
> +  /* 00000056 nop                            */  0x90,
> +  /* 00000057 nop                            */  0x90,
> +  /* 00000058 nop                            */  0x90,
> +  /* 00000059 nop                            */  0x90,
> +  /* 0000005A nop                            */  0x90,
> +  /* 0000005B nop                            */  0x90,
> +  /* 0000005C nop                            */  0x90,
> +  /* 0000005D nop                            */  0x90,
> +  /* 0000005E nop                            */  0x90,
> +  /* 0000005F nop                            */  0x90,
> +  /* 00000060 nop                            */  0x90,
> +  /* 00000061 nop                            */  0x90,
> +  /* 00000062 nop                            */  0x90,
> +  /* 00000063 nop                            */  0x90,
> +  /* 00000064 nop                            */  0x90,
> +  /* 00000065 nop                            */  0x90,
> +  /* 00000066 nop                            */  0x90,
> +  /* 00000067 nop                            */  0x90,
> +  /* 00000068 nop                            */  0x90,
> +  /* 00000069 nop                            */  0x90,
> +  /* 0000006A nop                            */  0x90,
> +  /* 0000006B nop                            */  0x90,
> +  /* 0000006C nop                            */  0x90,
> +  /* 0000006D nop                            */  0x90,
> +  /* 0000006E nop                            */  0x90,
> +  /* 0000006F nop                            */  0x90,
> +  /* 00000070 nop                            */  0x90,
> +  /* 00000071 nop                            */  0x90,
> +  /* 00000072 nop                            */  0x90,
> +  /* 00000073 nop                            */  0x90,
> +  /* 00000074 nop                            */  0x90,
> +  /* 00000075 nop                            */  0x90,
> +  /* 00000076 nop                            */  0x90,
> +  /* 00000077 nop                            */  0x90,
> +  /* 00000078 nop                            */  0x90,
> +  /* 00000079 nop                            */  0x90,
> +  /* 0000007A nop                            */  0x90,
> +  /* 0000007B nop                            */  0x90,
> +  /* 0000007C nop                            */  0x90,
> +  /* 0000007D nop                            */  0x90,
> +  /* 0000007E nop                            */  0x90,
> +  /* 0000007F nop                            */  0x90,
> +  /* 00000080 nop                            */  0x90,
> +  /* 00000081 nop                            */  0x90,
> +  /* 00000082 nop                            */  0x90,
> +  /* 00000083 nop                            */  0x90,
> +  /* 00000084 nop                            */  0x90,
> +  /* 00000085 nop                            */  0x90,
> +  /* 00000086 nop                            */  0x90,
> +  /* 00000087 nop                            */  0x90,
> +  /* 00000088 nop                            */  0x90,
> +  /* 00000089 nop                            */  0x90,
> +  /* 0000008A nop                            */  0x90,
> +  /* 0000008B nop                            */  0x90,
> +  /* 0000008C nop                            */  0x90,
> +  /* 0000008D nop                            */  0x90,
> +  /* 0000008E nop                            */  0x90,
> +  /* 0000008F nop                            */  0x90,
> +  /* 00000090 nop                            */  0x90,
> +  /* 00000091 nop                            */  0x90,
> +  /* 00000092 nop                            */  0x90,
> +  /* 00000093 nop                            */  0x90,
> +  /* 00000094 nop                            */  0x90,
> +  /* 00000095 nop                            */  0x90,
> +  /* 00000096 nop                            */  0x90,
> +  /* 00000097 nop                            */  0x90,
> +  /* 00000098 nop                            */  0x90,
> +  /* 00000099 nop                            */  0x90,
> +  /* 0000009A nop                            */  0x90,
> +  /* 0000009B nop                            */  0x90,
> +  /* 0000009C nop                            */  0x90,
> +  /* 0000009D nop                            */  0x90,
> +  /* 0000009E nop                            */  0x90,
> +  /* 0000009F nop                            */  0x90,
> +  /* 000000A0 nop                            */  0x90,
> +  /* 000000A1 nop                            */  0x90,
> +  /* 000000A2 nop                            */  0x90,
> +  /* 000000A3 nop                            */  0x90,
> +  /* 000000A4 nop                            */  0x90,
> +  /* 000000A5 nop                            */  0x90,
> +  /* 000000A6 nop                            */  0x90,
> +  /* 000000A7 nop                            */  0x90,
> +  /* 000000A8 nop                            */  0x90,
> +  /* 000000A9 nop                            */  0x90,
> +  /* 000000AA nop                            */  0x90,
> +  /* 000000AB nop                            */  0x90,
> +  /* 000000AC nop                            */  0x90,
> +  /* 000000AD nop                            */  0x90,
> +  /* 000000AE nop                            */  0x90,
> +  /* 000000AF nop                            */  0x90,
> +  /* 000000B0 nop                            */  0x90,
> +  /* 000000B1 nop                            */  0x90,
> +  /* 000000B2 nop                            */  0x90,
> +  /* 000000B3 nop                            */  0x90,
> +  /* 000000B4 nop                            */  0x90,
> +  /* 000000B5 nop                            */  0x90,
> +  /* 000000B6 nop                            */  0x90,
> +  /* 000000B7 nop                            */  0x90,
> +  /* 000000B8 nop                            */  0x90,
> +  /* 000000B9 nop                            */  0x90,
> +  /* 000000BA nop                            */  0x90,
> +  /* 000000BB nop                            */  0x90,
> +  /* 000000BC nop                            */  0x90,
> +  /* 000000BD nop                            */  0x90,
> +  /* 000000BE nop                            */  0x90,
> +  /* 000000BF nop                            */  0x90,
> +  /* 000000C0 nop                            */  0x90,
> +  /* 000000C1 nop                            */  0x90,
> +  /* 000000C2 nop                            */  0x90,
> +  /* 000000C3 nop                            */  0x90,
> +  /* 000000C4 nop                            */  0x90,
> +  /* 000000C5 nop                            */  0x90,
> +  /* 000000C6 nop                            */  0x90,
> +  /* 000000C7 nop                            */  0x90,
> +  /* 000000C8 nop                            */  0x90,
> +  /* 000000C9 nop                            */  0x90,
> +  /* 000000CA nop                            */  0x90,
> +  /* 000000CB nop                            */  0x90,
> +  /* 000000CC nop                            */  0x90,
> +  /* 000000CD nop                            */  0x90,
> +  /* 000000CE nop                            */  0x90,
> +  /* 000000CF nop                            */  0x90,
> +  /* 000000D0 nop                            */  0x90,
> +  /* 000000D1 nop                            */  0x90,
> +  /* 000000D2 nop                            */  0x90,
> +  /* 000000D3 nop                            */  0x90,
> +  /* 000000D4 nop                            */  0x90,
> +  /* 000000D5 nop                            */  0x90,
> +  /* 000000D6 nop                            */  0x90,
> +  /* 000000D7 nop                            */  0x90,
> +  /* 000000D8 nop                            */  0x90,
> +  /* 000000D9 nop                            */  0x90,
> +  /* 000000DA nop                            */  0x90,
> +  /* 000000DB nop                            */  0x90,
> +  /* 000000DC nop                            */  0x90,
> +  /* 000000DD nop                            */  0x90,
> +  /* 000000DE nop                            */  0x90,
> +  /* 000000DF nop                            */  0x90,
> +  /* 000000E0 nop                            */  0x90,
> +  /* 000000E1 nop                            */  0x90,
> +  /* 000000E2 nop                            */  0x90,
> +  /* 000000E3 nop                            */  0x90,
> +  /* 000000E4 nop                            */  0x90,
> +  /* 000000E5 nop                            */  0x90,
> +  /* 000000E6 nop                            */  0x90,
> +  /* 000000E7 nop                            */  0x90,
> +  /* 000000E8 nop                            */  0x90,
> +  /* 000000E9 nop                            */  0x90,
> +  /* 000000EA nop                            */  0x90,
> +  /* 000000EB nop                            */  0x90,
> +  /* 000000EC nop                            */  0x90,
> +  /* 000000ED nop                            */  0x90,
> +  /* 000000EE nop                            */  0x90,
> +  /* 000000EF nop                            */  0x90,
> +  /* 000000F0 nop                            */  0x90,
> +  /* 000000F1 nop                            */  0x90,
> +  /* 000000F2 nop                            */  0x90,
> +  /* 000000F3 nop                            */  0x90,
> +  /* 000000F4 nop                            */  0x90,
> +  /* 000000F5 nop                            */  0x90,
> +  /* 000000F6 nop                            */  0x90,
> +  /* 000000F7 nop                            */  0x90,
> +  /* 000000F8 nop                            */  0x90,
> +  /* 000000F9 nop                            */  0x90,
> +  /* 000000FA nop                            */  0x90,
> +  /* 000000FB nop                            */  0x90,
> +  /* 000000FC nop                            */  0x90,
> +  /* 000000FD nop                            */  0x90,
> +  /* 000000FE nop                            */  0x90,
> +  /* 000000FF nop                            */  0x90,
> +  /* 00000100 nop                            */  0x90,
> +  /* 00000101 nop                            */  0x90,
> +  /* 00000102 nop                            */  0x90,
> +  /* 00000103 nop                            */  0x90,
> +  /* 00000104 nop                            */  0x90,
> +  /* 00000105 nop                            */  0x90,
> +  /* 00000106 nop                            */  0x90,
> +  /* 00000107 nop                            */  0x90,
> +  /* 00000108 nop                            */  0x90,
> +  /* 00000109 nop                            */  0x90,
> +  /* 0000010A nop                            */  0x90,
> +  /* 0000010B nop                            */  0x90,
> +  /* 0000010C nop                            */  0x90,
> +  /* 0000010D nop                            */  0x90,
> +  /* 0000010E nop                            */  0x90,
> +  /* 0000010F nop                            */  0x90,
> +  /* 00000110 nop                            */  0x90,
> +  /* 00000111 nop                            */  0x90,
> +  /* 00000112 nop                            */  0x90,
> +  /* 00000113 nop                            */  0x90,
> +  /* 00000114 nop                            */  0x90,
> +  /* 00000115 nop                            */  0x90,
> +  /* 00000116 nop                            */  0x90,
> +  /* 00000117 nop                            */  0x90,
> +  /* 00000118 nop                            */  0x90,
> +  /* 00000119 nop                            */  0x90,
> +  /* 0000011A nop                            */  0x90,
> +  /* 0000011B nop                            */  0x90,
> +  /* 0000011C nop                            */  0x90,
> +  /* 0000011D nop                            */  0x90,
> +  /* 0000011E nop                            */  0x90,
> +  /* 0000011F nop                            */  0x90,
> +  /* 00000120 nop                            */  0x90,
> +  /* 00000121 nop                            */  0x90,
> +  /* 00000122 nop                            */  0x90,
> +  /* 00000123 nop                            */  0x90,
> +  /* 00000124 nop                            */  0x90,
> +  /* 00000125 nop                            */  0x90,
> +  /* 00000126 nop                            */  0x90,
> +  /* 00000127 nop                            */  0x90,
> +  /* 00000128 nop                            */  0x90,
> +  /* 00000129 nop                            */  0x90,
> +  /* 0000012A nop                            */  0x90,
> +  /* 0000012B nop                            */  0x90,
> +  /* 0000012C nop                            */  0x90,
> +  /* 0000012D nop                            */  0x90,
> +  /* 0000012E nop                            */  0x90,
> +  /* 0000012F nop                            */  0x90,
> +  /* 00000130 nop                            */  0x90,
> +  /* 00000131 nop                            */  0x90,
> +  /* 00000132 nop                            */  0x90,
> +  /* 00000133 nop                            */  0x90,
> +  /* 00000134 nop                            */  0x90,
> +  /* 00000135 nop                            */  0x90,
> +  /* 00000136 nop                            */  0x90,
> +  /* 00000137 nop                            */  0x90,
> +  /* 00000138 nop                            */  0x90,
> +  /* 00000139 nop                            */  0x90,
> +  /* 0000013A nop                            */  0x90,
> +  /* 0000013B nop                            */  0x90,
> +  /* 0000013C nop                            */  0x90,
> +  /* 0000013D nop                            */  0x90,
> +  /* 0000013E nop                            */  0x90,
> +  /* 0000013F nop                            */  0x90,
> +  /* 00000140 nop                            */  0x90,
> +  /* 00000141 nop                            */  0x90,
> +  /* 00000142 nop                            */  0x90,
> +  /* 00000143 nop                            */  0x90,
> +  /* 00000144 nop                            */  0x90,
> +  /* 00000145 nop                            */  0x90,
> +  /* 00000146 nop                            */  0x90,
> +  /* 00000147 nop                            */  0x90,
> +  /* 00000148 nop                            */  0x90,
> +  /* 00000149 nop                            */  0x90,
> +  /* 0000014A nop                            */  0x90,
> +  /* 0000014B nop                            */  0x90,
> +  /* 0000014C nop                            */  0x90,
> +  /* 0000014D nop                            */  0x90,
> +  /* 0000014E nop                            */  0x90,
> +  /* 0000014F nop                            */  0x90,
> +  /* 00000150 nop                            */  0x90,
> +  /* 00000151 nop                            */  0x90,
> +  /* 00000152 nop                            */  0x90,
> +  /* 00000153 nop                            */  0x90,
> +  /* 00000154 nop                            */  0x90,
> +  /* 00000155 nop                            */  0x90,
> +  /* 00000156 nop                            */  0x90,
> +  /* 00000157 nop                            */  0x90,
> +  /* 00000158 nop                            */  0x90,
> +  /* 00000159 nop                            */  0x90,
> +  /* 0000015A nop                            */  0x90,
> +  /* 0000015B nop                            */  0x90,
> +  /* 0000015C nop                            */  0x90,
> +  /* 0000015D nop                            */  0x90,
> +  /* 0000015E nop                            */  0x90,
> +  /* 0000015F nop                            */  0x90,
> +  /* 00000160 nop                            */  0x90,
> +  /* 00000161 nop                            */  0x90,
> +  /* 00000162 nop                            */  0x90,
> +  /* 00000163 nop                            */  0x90,
> +  /* 00000164 nop                            */  0x90,
> +  /* 00000165 nop                            */  0x90,
> +  /* 00000166 nop                            */  0x90,
> +  /* 00000167 nop                            */  0x90,
> +  /* 00000168 nop                            */  0x90,
> +  /* 00000169 nop                            */  0x90,
> +  /* 0000016A nop                            */  0x90,
> +  /* 0000016B nop                            */  0x90,
> +  /* 0000016C nop                            */  0x90,
> +  /* 0000016D nop                            */  0x90,
> +  /* 0000016E nop                            */  0x90,
> +  /* 0000016F nop                            */  0x90,
> +  /* 00000170 nop                            */  0x90,
> +  /* 00000171 nop                            */  0x90,
> +  /* 00000172 nop                            */  0x90,
> +  /* 00000173 nop                            */  0x90,
> +  /* 00000174 nop                            */  0x90,
> +  /* 00000175 nop                            */  0x90,
> +  /* 00000176 nop                            */  0x90,
> +  /* 00000177 nop                            */  0x90,
> +  /* 00000178 nop                            */  0x90,
> +  /* 00000179 nop                            */  0x90,
> +  /* 0000017A nop                            */  0x90,
> +  /* 0000017B nop                            */  0x90,
> +  /* 0000017C nop                            */  0x90,
> +  /* 0000017D nop                            */  0x90,
> +  /* 0000017E nop                            */  0x90,
> +  /* 0000017F nop                            */  0x90,
> +  /* 00000180 nop                            */  0x90,
> +  /* 00000181 nop                            */  0x90,
> +  /* 00000182 nop                            */  0x90,
> +  /* 00000183 nop                            */  0x90,
> +  /* 00000184 nop                            */  0x90,
> +  /* 00000185 nop                            */  0x90,
> +  /* 00000186 nop                            */  0x90,
> +  /* 00000187 nop                            */  0x90,
> +  /* 00000188 nop                            */  0x90,
> +  /* 00000189 nop                            */  0x90,
> +  /* 0000018A nop                            */  0x90,
> +  /* 0000018B nop                            */  0x90,
> +  /* 0000018C nop                            */  0x90,
> +  /* 0000018D nop                            */  0x90,
> +  /* 0000018E nop                            */  0x90,
> +  /* 0000018F nop                            */  0x90,
> +  /* 00000190 nop                            */  0x90,
> +  /* 00000191 nop                            */  0x90,
> +  /* 00000192 nop                            */  0x90,
> +  /* 00000193 nop                            */  0x90,
> +  /* 00000194 nop                            */  0x90,
> +  /* 00000195 nop                            */  0x90,
> +  /* 00000196 nop                            */  0x90,
> +  /* 00000197 nop                            */  0x90,
> +  /* 00000198 nop                            */  0x90,
> +  /* 00000199 nop                            */  0x90,
> +  /* 0000019A nop                            */  0x90,
> +  /* 0000019B nop                            */  0x90,
> +  /* 0000019C nop                            */  0x90,
> +  /* 0000019D nop                            */  0x90,
> +  /* 0000019E nop                            */  0x90,
> +  /* 0000019F nop                            */  0x90,
> +  /* 000001A0 nop                            */  0x90,
> +  /* 000001A1 nop                            */  0x90,
> +  /* 000001A2 nop                            */  0x90,
> +  /* 000001A3 nop                            */  0x90,
> +  /* 000001A4 nop                            */  0x90,
> +  /* 000001A5 nop                            */  0x90,
> +  /* 000001A6 nop                            */  0x90,
> +  /* 000001A7 nop                            */  0x90,
> +  /* 000001A8 nop                            */  0x90,
> +  /* 000001A9 nop                            */  0x90,
> +  /* 000001AA nop                            */  0x90,
> +  /* 000001AB nop                            */  0x90,
> +  /* 000001AC nop                            */  0x90,
> +  /* 000001AD nop                            */  0x90,
> +  /* 000001AE nop                            */  0x90,
> +  /* 000001AF nop                            */  0x90,
> +  /* 000001B0 nop                            */  0x90,
> +  /* 000001B1 nop                            */  0x90,
> +  /* 000001B2 nop                            */  0x90,
> +  /* 000001B3 nop                            */  0x90,
> +  /* 000001B4 nop                            */  0x90,
> +  /* 000001B5 nop                            */  0x90,
> +  /* 000001B6 nop                            */  0x90,
> +  /* 000001B7 nop                            */  0x90,
> +  /* 000001B8 nop                            */  0x90,
> +  /* 000001B9 nop                            */  0x90,
> +  /* 000001BA nop                            */  0x90,
> +  /* 000001BB nop                            */  0x90,
> +  /* 000001BC nop                            */  0x90,
> +  /* 000001BD nop                            */  0x90,
> +  /* 000001BE nop                            */  0x90,
> +  /* 000001BF nop                            */  0x90,
> +  /* 000001C0 nop                            */  0x90,
> +  /* 000001C1 nop                            */  0x90,
> +  /* 000001C2 nop                            */  0x90,
> +  /* 000001C3 nop                            */  0x90,
> +  /* 000001C4 nop                            */  0x90,
> +  /* 000001C5 nop                            */  0x90,
> +  /* 000001C6 nop                            */  0x90,
> +  /* 000001C7 nop                            */  0x90,
> +  /* 000001C8 nop                            */  0x90,
> +  /* 000001C9 nop                            */  0x90,
> +  /* 000001CA nop                            */  0x90,
> +  /* 000001CB nop                            */  0x90,
> +  /* 000001CC nop                            */  0x90,
> +  /* 000001CD nop                            */  0x90,
> +  /* 000001CE nop                            */  0x90,
> +  /* 000001CF nop                            */  0x90,
> +  /* 000001D0 nop                            */  0x90,
> +  /* 000001D1 nop                            */  0x90,
> +  /* 000001D2 nop                            */  0x90,
> +  /* 000001D3 nop                            */  0x90,
> +  /* 000001D4 nop                            */  0x90,
> +  /* 000001D5 nop                            */  0x90,
> +  /* 000001D6 nop                            */  0x90,
> +  /* 000001D7 nop                            */  0x90,
> +  /* 000001D8 nop                            */  0x90,
> +  /* 000001D9 nop                            */  0x90,
> +  /* 000001DA nop                            */  0x90,
> +  /* 000001DB nop                            */  0x90,
> +  /* 000001DC nop                            */  0x90,
> +  /* 000001DD nop                            */  0x90,
> +  /* 000001DE nop                            */  0x90,
> +  /* 000001DF nop                            */  0x90,
> +  /* 000001E0 nop                            */  0x90,
> +  /* 000001E1 nop                            */  0x90,
> +  /* 000001E2 nop                            */  0x90,
> +  /* 000001E3 nop                            */  0x90,
> +  /* 000001E4 nop                            */  0x90,
> +  /* 000001E5 nop                            */  0x90,
> +  /* 000001E6 nop                            */  0x90,
> +  /* 000001E7 nop                            */  0x90,
> +  /* 000001E8 nop                            */  0x90,
> +  /* 000001E9 nop                            */  0x90,
> +  /* 000001EA nop                            */  0x90,
> +  /* 000001EB nop                            */  0x90,
> +  /* 000001EC nop                            */  0x90,
> +  /* 000001ED nop                            */  0x90,
> +  /* 000001EE nop                            */  0x90,
> +  /* 000001EF nop                            */  0x90,
> +  /* 000001F0 nop                            */  0x90,
> +  /* 000001F1 nop                            */  0x90,
> +  /* 000001F2 nop                            */  0x90,
> +  /* 000001F3 nop                            */  0x90,
> +  /* 000001F4 nop                            */  0x90,
> +  /* 000001F5 nop                            */  0x90,
> +  /* 000001F6 nop                            */  0x90,
> +  /* 000001F7 nop                            */  0x90,
> +  /* 000001F8 nop                            */  0x90,
> +  /* 000001F9 nop                            */  0x90,
> +  /* 000001FA nop                            */  0x90,
> +  /* 000001FB nop                            */  0x90,
> +  /* 000001FC nop                            */  0x90,
> +  /* 000001FD nop                            */  0x90,
> +  /* 000001FE nop                            */  0x90,
> +  /* 000001FF nop                            */  0x90,
> +  /* 00000200 cmp ax,0x4f00                  */  0x3D, 0x00, 0x4F,
> +  /* 00000203 jz 0x237                       */  0x74, 0x32,
> +  /* 00000205 cmp ax,0x4f01                  */  0x3D, 0x01, 0x4F,
> +  /* 00000208 jz 0x257                       */  0x74, 0x4D,
> +  /* 0000020A cmp ax,0x4f02                  */  0x3D, 0x02, 0x4F,
> +  /* 0000020D jz near 0x2c8                  */  0x0F, 0x84, 0xB7, 0x00,
> +  /* 00000211 cmp ax,0x4f03                  */  0x3D, 0x03, 0x4F,
> +  /* 00000214 jz near 0x325                  */  0x0F, 0x84, 0x0D, 0x01,
> +  /* 00000218 cmp ax,0x4f10                  */  0x3D, 0x10, 0x4F,
> +  /* 0000021B jz near 0x337                  */  0x0F, 0x84, 0x18, 0x01,
> +  /* 0000021F cmp ax,0x4f15                  */  0x3D, 0x15, 0x4F,
> +  /* 00000222 jz near 0x344                  */  0x0F, 0x84, 0x1E, 0x01,
> +  /* 00000226 cmp ah,0x0                     */  0x80, 0xFC, 0x00,
> +  /* 00000229 jz near 0x363                  */  0x0F, 0x84, 0x36, 0x01,
> +  /* 0000022D push si                        */  0x56,
> +  /* 0000022E mov si,0x3d7                   */  0xBE, 0xD7, 0x03,
> +  /* 00000231 call 0x3ad                     */  0xE8, 0x79, 0x01,
> +  /* 00000234 pop si                         */  0x5E,
> +  /* 00000235 jmp short 0x235                */  0xEB, 0xFE,
> +  /* 00000237 push es                        */  0x06,
> +  /* 00000238 push di                        */  0x57,
> +  /* 00000239 push ds                        */  0x1E,
> +  /* 0000023A push si                        */  0x56,
> +  /* 0000023B push cx                        */  0x51,
> +  /* 0000023C push si                        */  0x56,
> +  /* 0000023D mov si,0x3eb                   */  0xBE, 0xEB, 0x03,
> +  /* 00000240 call 0x3ad                     */  0xE8, 0x6A, 0x01,
> +  /* 00000243 pop si                         */  0x5E,
> +  /* 00000244 push cs                        */  0x0E,
> +  /* 00000245 pop ds                         */  0x1F,
> +  /* 00000246 mov si,0x0                     */  0xBE, 0x00, 0x00,
> +  /* 00000249 mov cx,0x100                   */  0xB9, 0x00, 0x01,
> +  /* 0000024C cld                            */  0xFC,
> +  /* 0000024D rep movsb                      */  0xF3, 0xA4,
> +  /* 0000024F pop cx                         */  0x59,
> +  /* 00000250 pop si                         */  0x5E,
> +  /* 00000251 pop ds                         */  0x1F,
> +  /* 00000252 pop di                         */  0x5F,
> +  /* 00000253 pop es                         */  0x07,
> +  /* 00000254 jmp 0x395                      */  0xE9, 0x3E, 0x01,
> +  /* 00000257 push es                        */  0x06,
> +  /* 00000258 push di                        */  0x57,
> +  /* 00000259 push ds                        */  0x1E,
> +  /* 0000025A push si                        */  0x56,
> +  /* 0000025B push cx                        */  0x51,
> +  /* 0000025C push si                        */  0x56,
> +  /* 0000025D mov si,0x3f6                   */  0xBE, 0xF6, 0x03,
> +  /* 00000260 call 0x3ad                     */  0xE8, 0x4A, 0x01,
> +  /* 00000263 pop si                         */  0x5E,
> +  /* 00000264 and cx,0xbfff                  */  0x81, 0xE1, 0xFF, 0xBF,
> +  /* 00000268 cmp cx,0x13f                   */  0x81, 0xF9, 0x3F, 0x01,
> +  /* 0000026C jz 0x284                       */  0x74, 0x16,
> +  /* 0000026E cmp cx,0x140                   */  0x81, 0xF9, 0x40, 0x01,
> +  /* 00000272 jz 0x291                       */  0x74, 0x1D,
> +  /* 00000274 cmp cx,0x141                   */  0x81, 0xF9, 0x41, 0x01,
> +  /* 00000278 jz 0x29e                       */  0x74, 0x24,
> +  /* 0000027A push si                        */  0x56,
> +  /* 0000027B mov si,0x42c                   */  0xBE, 0x2C, 0x04,
> +  /* 0000027E call 0x3ad                     */  0xE8, 0x2C, 0x01,
> +  /* 00000281 pop si                         */  0x5E,
> +  /* 00000282 jmp short 0x235                */  0xEB, 0xB1,
> +  /* 00000284 push si                        */  0x56,
> +  /* 00000285 mov si,0x46b                   */  0xBE, 0x6B, 0x04,
> +  /* 00000288 call 0x3ad                     */  0xE8, 0x22, 0x01,
> +  /* 0000028B pop si                         */  0x5E,
> +  /* 0000028C mov si,0x100                   */  0xBE, 0x00, 0x01,
> +  /* 0000028F jmp short 0x2b8                */  0xEB, 0x27,
> +  /* 00000291 push si                        */  0x56,
> +  /* 00000292 mov si,0x47d                   */  0xBE, 0x7D, 0x04,
> +  /* 00000295 call 0x3ad                     */  0xE8, 0x15, 0x01,
> +  /* 00000298 pop si                         */  0x5E,
> +  /* 00000299 mov si,0x132                   */  0xBE, 0x32, 0x01,
> +  /* 0000029C jmp short 0x2b8                */  0xEB, 0x1A,
> +  /* 0000029E push si                        */  0x56,
> +  /* 0000029F mov si,0x48f                   */  0xBE, 0x8F, 0x04,
> +  /* 000002A2 call 0x3ad                     */  0xE8, 0x08, 0x01,
> +  /* 000002A5 pop si                         */  0x5E,
> +  /* 000002A6 mov si,0x164                   */  0xBE, 0x64, 0x01,
> +  /* 000002A9 jmp short 0x2b8                */  0xEB, 0x0D,
> +  /* 000002AB push si                        */  0x56,
> +  /* 000002AC mov si,0x4a2                   */  0xBE, 0xA2, 0x04,
> +  /* 000002AF call 0x3ad                     */  0xE8, 0xFB, 0x00,
> +  /* 000002B2 pop si                         */  0x5E,
> +  /* 000002B3 mov si,0x196                   */  0xBE, 0x96, 0x01,
> +  /* 000002B6 jmp short 0x2b8                */  0xEB, 0x00,
> +  /* 000002B8 push cs                        */  0x0E,
> +  /* 000002B9 pop ds                         */  0x1F,
> +  /* 000002BA mov cx,0x32                    */  0xB9, 0x32, 0x00,
> +  /* 000002BD cld                            */  0xFC,
> +  /* 000002BE rep movsb                      */  0xF3, 0xA4,
> +  /* 000002C0 pop cx                         */  0x59,
> +  /* 000002C1 pop si                         */  0x5E,
> +  /* 000002C2 pop ds                         */  0x1F,
> +  /* 000002C3 pop di                         */  0x5F,
> +  /* 000002C4 pop es                         */  0x07,
> +  /* 000002C5 jmp 0x395                      */  0xE9, 0xCD, 0x00,
> +  /* 000002C8 push dx                        */  0x52,
> +  /* 000002C9 push ax                        */  0x50,
> +  /* 000002CA push si                        */  0x56,
> +  /* 000002CB mov si,0x410                   */  0xBE, 0x10, 0x04,
> +  /* 000002CE call 0x3ad                     */  0xE8, 0xDC, 0x00,
> +  /* 000002D1 pop si                         */  0x5E,
> +  /* 000002D2 and bx,0xbfff                  */  0x81, 0xE3, 0xFF, 0xBF,
> +  /* 000002D6 cmp bx,0x13f                   */  0x81, 0xFB, 0x3F, 0x01,
> +  /* 000002DA jz 0x2f3                       */  0x74, 0x17,
> +  /* 000002DC cmp bx,0x140                   */  0x81, 0xFB, 0x40, 0x01,
> +  /* 000002E0 jz 0x2fd                       */  0x74, 0x1B,
> +  /* 000002E2 cmp bx,0x141                   */  0x81, 0xFB, 0x41, 0x01,
> +  /* 000002E6 jz 0x307                       */  0x74, 0x1F,
> +  /* 000002E8 push si                        */  0x56,
> +  /* 000002E9 mov si,0x42c                   */  0xBE, 0x2C, 0x04,
> +  /* 000002EC call 0x3ad                     */  0xE8, 0xBE, 0x00,
> +  /* 000002EF pop si                         */  0x5E,
> +  /* 000002F0 jmp 0x235                      */  0xE9, 0x42, 0xFF,
> +  /* 000002F3 push si                        */  0x56,
> +  /* 000002F4 mov si,0x46b                   */  0xBE, 0x6B, 0x04,
> +  /* 000002F7 call 0x3ad                     */  0xE8, 0xB3, 0x00,
> +  /* 000002FA pop si                         */  0x5E,
> +  /* 000002FB jmp short 0x319                */  0xEB, 0x1C,
> +  /* 000002FD push si                        */  0x56,
> +  /* 000002FE mov si,0x47d                   */  0xBE, 0x7D, 0x04,
> +  /* 00000301 call 0x3ad                     */  0xE8, 0xA9, 0x00,
> +  /* 00000304 pop si                         */  0x5E,
> +  /* 00000305 jmp short 0x319                */  0xEB, 0x12,
> +  /* 00000307 push si                        */  0x56,
> +  /* 00000308 mov si,0x48f                   */  0xBE, 0x8F, 0x04,
> +  /* 0000030B call 0x3ad                     */  0xE8, 0x9F, 0x00,
> +  /* 0000030E pop si                         */  0x5E,
> +  /* 0000030F jmp short 0x319                */  0xEB, 0x08,
> +  /* 00000311 push si                        */  0x56,
> +  /* 00000312 mov si,0x4a2                   */  0xBE, 0xA2, 0x04,
> +  /* 00000315 call 0x3ad                     */  0xE8, 0x95, 0x00,
> +  /* 00000318 pop si                         */  0x5E,
> +  /* 00000319 mov [0x4b0],bl                 */  0x88, 0x1E, 0xB0, 0x04,
> +  /* 0000031D mov [0x4b1],bh                 */  0x88, 0x3E, 0xB1, 0x04,
> +  /* 00000321 pop ax                         */  0x58,
> +  /* 00000322 pop dx                         */  0x5A,
> +  /* 00000323 jmp short 0x395                */  0xEB, 0x70,
> +  /* 00000325 push si                        */  0x56,
> +  /* 00000326 mov si,0x405                   */  0xBE, 0x05, 0x04,
> +  /* 00000329 call 0x3ad                     */  0xE8, 0x81, 0x00,
> +  /* 0000032C pop si                         */  0x5E,
> +  /* 0000032D mov bl,[0x4b0]                 */  0x8A, 0x1E, 0xB0, 0x04,
> +  /* 00000331 mov bh,[0x4b1]                 */  0x8A, 0x3E, 0xB1, 0x04,
> +  /* 00000335 jmp short 0x395                */  0xEB, 0x5E,
> +  /* 00000337 push si                        */  0x56,
> +  /* 00000338 mov si,0x43b                   */  0xBE, 0x3B, 0x04,
> +  /* 0000033B call 0x3ad                     */  0xE8, 0x6F, 0x00,
> +  /* 0000033E pop si                         */  0x5E,
> +  /* 0000033F mov bx,0x80                    */  0xBB, 0x80, 0x00,
> +  /* 00000342 jmp short 0x395                */  0xEB, 0x51,
> +  /* 00000344 push es                        */  0x06,
> +  /* 00000345 push di                        */  0x57,
> +  /* 00000346 push ds                        */  0x1E,
> +  /* 00000347 push si                        */  0x56,
> +  /* 00000348 push cx                        */  0x51,
> +  /* 00000349 push si                        */  0x56,
> +  /* 0000034A mov si,0x450                   */  0xBE, 0x50, 0x04,
> +  /* 0000034D call 0x3ad                     */  0xE8, 0x5D, 0x00,
> +  /* 00000350 pop si                         */  0x5E,
> +  /* 00000351 push cs                        */  0x0E,
> +  /* 00000352 pop ds                         */  0x1F,
> +  /* 00000353 mov si,0x4b2                   */  0xBE, 0xB2, 0x04,
> +  /* 00000356 mov cx,0x80                    */  0xB9, 0x80, 0x00,
> +  /* 00000359 cld                            */  0xFC,
> +  /* 0000035A rep movsb                      */  0xF3, 0xA4,
> +  /* 0000035C pop cx                         */  0x59,
> +  /* 0000035D pop si                         */  0x5E,
> +  /* 0000035E pop ds                         */  0x1F,
> +  /* 0000035F pop di                         */  0x5F,
> +  /* 00000360 pop es                         */  0x07,
> +  /* 00000361 jmp short 0x395                */  0xEB, 0x32,
> +  /* 00000363 push si                        */  0x56,
> +  /* 00000364 mov si,0x41b                   */  0xBE, 0x1B, 0x04,
> +  /* 00000367 call 0x3ad                     */  0xE8, 0x43, 0x00,
> +  /* 0000036A pop si                         */  0x5E,
> +  /* 0000036B cmp al,0x3                     */  0x3C, 0x03,
> +  /* 0000036D jz 0x37e                       */  0x74, 0x0F,
> +  /* 0000036F cmp al,0x12                    */  0x3C, 0x12,
> +  /* 00000371 jz 0x38a                       */  0x74, 0x17,
> +  /* 00000373 push si                        */  0x56,
> +  /* 00000374 mov si,0x42c                   */  0xBE, 0x2C, 0x04,
> +  /* 00000377 call 0x3ad                     */  0xE8, 0x33, 0x00,
> +  /* 0000037A pop si                         */  0x5E,
> +  /* 0000037B jmp 0x235                      */  0xE9, 0xB7, 0xFE,
> +  /* 0000037E push si                        */  0x56,
> +  /* 0000037F mov si,0x45c                   */  0xBE, 0x5C, 0x04,
> +  /* 00000382 call 0x3ad                     */  0xE8, 0x28, 0x00,
> +  /* 00000385 pop si                         */  0x5E,
> +  /* 00000386 mov al,0x0                     */  0xB0, 0x00,
> +  /* 00000388 jmp short 0x38c                */  0xEB, 0x02,
> +  /* 0000038A mov al,0x0                     */  0xB0, 0x00,
> +  /* 0000038C push si                        */  0x56,
> +  /* 0000038D mov si,0x3c2                   */  0xBE, 0xC2, 0x03,
> +  /* 00000390 call 0x3ad                     */  0xE8, 0x1A, 0x00,
> +  /* 00000393 pop si                         */  0x5E,
> +  /* 00000394 iret                           */  0xCF,
> +  /* 00000395 push si                        */  0x56,
> +  /* 00000396 mov si,0x3c2                   */  0xBE, 0xC2, 0x03,
> +  /* 00000399 call 0x3ad                     */  0xE8, 0x11, 0x00,
> +  /* 0000039C pop si                         */  0x5E,
> +  /* 0000039D mov ax,0x4f                    */  0xB8, 0x4F, 0x00,
> +  /* 000003A0 iret                           */  0xCF,
> +  /* 000003A1 push si                        */  0x56,
> +  /* 000003A2 mov si,0x3c8                   */  0xBE, 0xC8, 0x03,
> +  /* 000003A5 call 0x3ad                     */  0xE8, 0x05, 0x00,
> +  /* 000003A8 pop si                         */  0x5E,
> +  /* 000003A9 mov ax,0x24f                   */  0xB8, 0x4F, 0x02,
> +  /* 000003AC iret                           */  0xCF,
> +  /* 000003AD pusha                          */  0x60,
> +  /* 000003AE push ds                        */  0x1E,
> +  /* 000003AF push cs                        */  0x0E,
> +  /* 000003B0 pop ds                         */  0x1F,
> +  /* 000003B1 mov dx,0x220                   */  0xBA, 0x20, 0x02,
> +  /* 000003B4 mov ax,0x0                     */  0xB8, 0x00, 0x00,
> +  /* 000003B7 lodsb                          */  0xAC,
> +  /* 000003B8 cmp al,0x0                     */  0x3C, 0x00,
> +  /* 000003BA jz 0x3bf                       */  0x74, 0x03,
> +  /* 000003BC out dx,al                      */  0xEE,
> +  /* 000003BD jmp short 0x3b7                */  0xEB, 0xF8,
> +  /* 000003BF pop ds                         */  0x1F,
> +  /* 000003C0 popa                           */  0x61,
> +  /* 000003C1 ret                            */  0xC3,
> +  /* 000003C2 jna 0x413                      */  0x76, 0x4F,
> +  /* 000003C4 imul cx,[di],byte +0xa         */  0x6B, 0x0D, 0x0A,
> +  /* 000003C7 add [bp+0x55],dh               */  0x00, 0x76, 0x55,
> +  /* 000003CA outsb                          */  0x6E,
> +  /* 000003CB jnc 0x442                      */  0x73, 0x75,
> +  /* 000003CD jo 0x43f                       */  0x70, 0x70,
> +  /* 000003CF outsw                          */  0x6F,
> +  /* 000003D0 jc 0x446                       */  0x72, 0x74,
> +  /* 000003D2 fs or ax,0xa                   */  0x65, 0x64, 0x0D, 0x0A, 0x00,
> +  /* 000003D7 jna 0x42e                      */  0x76, 0x55,
> +  /* 000003D9 outsb                          */  0x6E,
> +  /* 000003DA imul bp,[bp+0x6f],byte +0x77   */  0x6B, 0x6E, 0x6F, 0x77,
> +  /* 000003DE outsb                          */  0x6E,
> +  /* 000003DF and [bp+0x75],al               */  0x20, 0x46, 0x75,
> +  /* 000003E2 outsb                          */  0x6E,
> +  /* 000003E3 arpl [si+0x69],si              */  0x63, 0x74, 0x69,
> +  /* 000003E6 outsw                          */  0x6F,
> +  /* 000003E7 outsb                          */  0x6E,
> +  /* 000003E8 or ax,0xa                      */  0x0D, 0x0A, 0x00,
> +  /* 000003EB jna 0x434                      */  0x76, 0x47,
> +  /* 000003ED gs jz 0x439                    */  0x65, 0x74, 0x49,
> +  /* 000003F0 outsb                          */  0x6E,
> +  /* 000003F1 outsd                          */  0x66, 0x6F,
> +  /* 000003F3 or ax,0xa                      */  0x0D, 0x0A, 0x00,
> +  /* 000003F6 jna 0x43f                      */  0x76, 0x47,
> +  /* 000003F8 gs jz 0x448                    */  0x65, 0x74, 0x4D,
> +  /* 000003FB outsw                          */  0x6F,
> +  /* 000003FC gs dec cx                      */  0x64, 0x65, 0x49,
> +  /* 000003FF outsb                          */  0x6E,
> +  /* 00000400 outsd                          */  0x66, 0x6F,
> +  /* 00000402 or ax,0xa                      */  0x0D, 0x0A, 0x00,
> +  /* 00000405 jna 0x44e                      */  0x76, 0x47,
> +  /* 00000407 gs jz 0x457                    */  0x65, 0x74, 0x4D,
> +  /* 0000040A outsw                          */  0x6F,
> +  /* 0000040B gs or ax,0xa                   */  0x64, 0x65, 0x0D, 0x0A, 0x00,
> +  /* 00000410 jna 0x465                      */  0x76, 0x53,
> +  /* 00000412 gs jz 0x462                    */  0x65, 0x74, 0x4D,
> +  /* 00000415 outsw                          */  0x6F,
> +  /* 00000416 gs or ax,0xa                   */  0x64, 0x65, 0x0D, 0x0A, 0x00,
> +  /* 0000041B jna 0x470                      */  0x76, 0x53,
> +  /* 0000041D gs jz 0x46d                    */  0x65, 0x74, 0x4D,
> +  /* 00000420 outsw                          */  0x6F,
> +  /* 00000421 gs dec sp                      */  0x64, 0x65, 0x4C,
> +  /* 00000424 gs a32 popa                    */  0x65, 0x67, 0x61,
> +  /* 00000427 arpl [bx+di+0xd],di            */  0x63, 0x79, 0x0D,
> +  /* 0000042A or al,[bx+si]                  */  0x0A, 0x00,
> +  /* 0000042C jna 0x483                      */  0x76, 0x55,
> +  /* 0000042E outsb                          */  0x6E,
> +  /* 0000042F imul bp,[bx+0x77],byte +0x6e   */  0x6B, 0x6F, 0x77, 0x6E,
> +  /* 00000433 and [di+0x6f],cl               */  0x20, 0x4D, 0x6F,
> +  /* 00000436 gs or ax,0xa                   */  0x64, 0x65, 0x0D, 0x0A, 0x00,
> +  /* 0000043B jna 0x484                      */  0x76, 0x47,
> +  /* 0000043D gs jz 0x490                    */  0x65, 0x74, 0x50,
> +  /* 00000440 insw                           */  0x6D,
> +  /* 00000441 inc bx                         */  0x43,
> +  /* 00000442 popa                           */  0x61,
> +  /* 00000443 jo 0x4a6                       */  0x70, 0x61,
> +  /* 00000445 bound bp,[bx+di+0x6c]          */  0x62, 0x69, 0x6C,
> +  /* 00000448 imul si,[si+0x69],word 0x7365  */  0x69, 0x74, 0x69, 0x65, 0x73,
> +  /* 0000044D or ax,0xa                      */  0x0D, 0x0A, 0x00,
> +  /* 00000450 jna 0x4a4                      */  0x76, 0x52,
> +  /* 00000452 gs popa                        */  0x65, 0x61,
> +  /* 00000454 fs inc bp                      */  0x64, 0x45,
> +  /* 00000456 imul sp,[fs:si+0xd],word 0xa   */  0x64, 0x69, 0x64, 0x0D, 0x0A, 0x00,
> +  /* 0000045C jna 0x4aa                      */  0x76, 0x4C,
> +  /* 0000045E gs a32 popa                    */  0x65, 0x67, 0x61,
> +  /* 00000461 arpl [bx+di+0x4d],di           */  0x63, 0x79, 0x4D,
> +  /* 00000464 outsw                          */  0x6F,
> +  /* 00000465 xor cx,[gs:di]                 */  0x64, 0x65, 0x33, 0x0D,
> +  /* 00000469 or al,[bx+si]                  */  0x0A, 0x00,
> +  /* 0000046B insw                           */  0x6D,
> +  /* 0000046C outsw                          */  0x6F,
> +  /* 0000046D gs pop di                      */  0x64, 0x65, 0x5F,
> +  /* 00000470 ss xor al,0x30                 */  0x36, 0x34, 0x30,
> +  /* 00000473 js 0x4a9                       */  0x78, 0x34,
> +  /* 00000475 cmp [bx+si],dh                 */  0x38, 0x30,
> +  /* 00000477 js 0x4ac                       */  0x78, 0x33,
> +  /* 00000479 xor cl,[di]                    */  0x32, 0x0D,
> +  /* 0000047B or al,[bx+si]                  */  0x0A, 0x00,
> +  /* 0000047D insw                           */  0x6D,
> +  /* 0000047E outsw                          */  0x6F,
> +  /* 0000047F gs pop di                      */  0x64, 0x65, 0x5F,
> +  /* 00000482 cmp [bx+si],dh                 */  0x38, 0x30,
> +  /* 00000484 xor [bx+si+0x36],bh            */  0x30, 0x78, 0x36,
> +  /* 00000487 xor [bx+si],dh                 */  0x30, 0x30,
> +  /* 00000489 js 0x4be                       */  0x78, 0x33,
> +  /* 0000048B xor cl,[di]                    */  0x32, 0x0D,
> +  /* 0000048D or al,[bx+si]                  */  0x0A, 0x00,
> +  /* 0000048F insw                           */  0x6D,
> +  /* 00000490 outsw                          */  0x6F,
> +  /* 00000491 gs pop di                      */  0x64, 0x65, 0x5F,
> +  /* 00000494 xor [bx+si],si                 */  0x31, 0x30,
> +  /* 00000496 xor dh,[si]                    */  0x32, 0x34,
> +  /* 00000498 js 0x4d1                       */  0x78, 0x37,
> +  /* 0000049A cmp [ss:bx+si+0x33],bh         */  0x36, 0x38, 0x78, 0x33,
> +  /* 0000049E xor cl,[di]                    */  0x32, 0x0D,
> +  /* 000004A0 or al,[bx+si]                  */  0x0A, 0x00,
> +  /* 000004A2 insw                           */  0x6D,
> +  /* 000004A3 outsw                          */  0x6F,
> +  /* 000004A4 gs pop di                      */  0x64, 0x65, 0x5F,
> +  /* 000004A7 jnz 0x517                      */  0x75, 0x6E,
> +  /* 000004A9 jnz 0x51e                      */  0x75, 0x73,
> +  /* 000004AB fs or ax,0xa                   */  0x65, 0x64, 0x0D, 0x0A, 0x00,
> +  /* 000004B0 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004B2 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004B4 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004B6 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004B8 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004BA add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004BC add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004BE add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004C0 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004C2 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004C4 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004C6 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004C8 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004CA add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004CC add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004CE add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004D0 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004D2 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004D4 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004D6 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004D8 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004DA add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004DC add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004DE add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004E0 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004E2 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004E4 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004E6 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004E8 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004EA add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004EC add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004EE add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004F0 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004F2 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004F4 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004F6 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004F8 add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004FA add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004FC add [bx+si],al                 */  0x00, 0x00,
> +  /* 000004FE add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000500 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000502 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000504 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000506 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000508 add [bx+si],al                 */  0x00, 0x00,
> +  /* 0000050A add [bx+si],al                 */  0x00, 0x00,
> +  /* 0000050C add [bx+si],al                 */  0x00, 0x00,
> +  /* 0000050E add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000510 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000512 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000514 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000516 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000518 add [bx+si],al                 */  0x00, 0x00,
> +  /* 0000051A add [bx+si],al                 */  0x00, 0x00,
> +  /* 0000051C add [bx+si],al                 */  0x00, 0x00,
> +  /* 0000051E add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000520 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000522 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000524 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000526 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000528 add [bx+si],al                 */  0x00, 0x00,
> +  /* 0000052A add [bx+si],al                 */  0x00, 0x00,
> +  /* 0000052C add [bx+si],al                 */  0x00, 0x00,
> +  /* 0000052E add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000530 add [bx+si],al                 */  0x00, 0x00,
> +  /* 00000532 add [bx+si],al                 */  0x00, 0x00,
> +};
> +#endif
> diff --git a/OvmfPkg/IntelGvtGopDxe/VbeShim.sh b/OvmfPkg/IntelGvtGopDxe/VbeShim.sh
> new file mode 100755
> index 000000000000..4f61e5220b01
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/VbeShim.sh
> @@ -0,0 +1,81 @@
> +#!/bin/sh
> +###
> +# @file
> +# Shell script to assemble and dump the fake Int10h handler from NASM source to
> +# a C array.
> +#
> +# Copyright (C) 2021, Intel Corporation. All rights reserved.<BR>
> +# Copyright (C) 2020, Rebecca Cran <rebecca@bsdio.com>
> +# Copyright (C) 2014, Red Hat, Inc.
> +# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +###
> +
> +set -e -u
> +
> +STEM=$(dirname -- "$0")/$(basename -- "$0" .sh)
> +
> +#
> +# Install exit handler -- remove temporary files.
> +#
> +exit_handler()
> +{
> +  rm -f -- "$STEM".bin "$STEM".disasm "$STEM".offsets "$STEM".insns \
> +      "$STEM".bytes
> +}
> +trap exit_handler EXIT
> +
> +#
> +# Assemble the source file.
> +#
> +nasm -o "$STEM".bin "$STEM".asm
> +
> +#
> +# Disassemble it, in order to get a binary dump associated with the source.
> +# (ndisasm doesn't recognize the "--" end-of-options delimiter.)
> +#
> +ndisasm "$STEM".bin >"$STEM".disasm
> +
> +#
> +# Create three files, each with one column of the disassembly.
> +#
> +# The first column contains the offsets, and it starts the comment.
> +#
> +cut -c 1-8 -- "$STEM".disasm \
> +| sed -e 's,^,  /* ,' >"$STEM".offsets
> +
> +#
> +# The second column contains the assembly-language instructions, and it closes
> +# the comment. We first pad it to 30 characters.
> +#
> +cut -c 29- -- "$STEM".disasm \
> +| sed -e 's,$,                              ,' \
> +      -e 's,^\(.\{30\}\).*$,\1 */,' >"$STEM".insns
> +
> +#
> +# The third column contains the bytes corresponding to the instruction,
> +# represented as C integer constants. First strip trailing whitespace from the
> +# middle column of the input disassembly, then process pairs of nibbles.
> +#
> +cut -c 11-28 -- "$STEM".disasm \
> +| sed -e 's, \+$,,' -e 's/\(..\)/ 0x\1,/g' | sed 's/0x  ,//g' >"$STEM".bytes
> +
> +#
> +# Write the output file, recombining the columns. The output should have CRLF
> +# line endings.
> +#
> +{
> +  printf '//\n'
> +  printf '// THIS FILE WAS GENERATED BY "%s". DO NOT EDIT.\n' \
> +      "$(basename -- "$0")"
> +  printf '//\n'
> +  printf '#ifndef _VBE_SHIM_H_\n'
> +  printf '#define _VBE_SHIM_H_\n'
> +  printf 'STATIC CONST UINT8 gVbeShim[] = {\n'
> +  paste -d ' ' -- "$STEM".offsets "$STEM".insns "$STEM".bytes
> +  printf '};\n'
> +  printf '#endif\n'
> +} \
> +| unix2dos >"$STEM".h
> diff --git a/OvmfPkg/IntelGvtGopDxe/VirtualGpu.c b/OvmfPkg/IntelGvtGopDxe/VirtualGpu.c
> new file mode 100644
> index 000000000000..dc2c23706c8b
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/VirtualGpu.c
> @@ -0,0 +1,400 @@
> +/** @file
> +  Component name for the QEMU video controller.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "Common.h"
> +#include "VirtualGpu.h"
> +#include "GpuReg.h"
> +#include "Gtt.h"
> +#include "Display.h"
> +#include <Library/QemuFwCfgLib.h>
> +
> +EFI_STATUS
> +IntelVirtualGpuActive (
> +  IN EFI_PCI_IO_PROTOCOL *PciIo
> +  )
> +{
> +  EFI_STATUS Status = EFI_UNSUPPORTED;
> +  PCI_TYPE00 PciHdr = {0};
> +  UINT64     Magic = 0;
> +  UINT32     Version = 0;
> +  UINT16     VerMajor = 0, VerMinor = 0;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  Status = PciIo->Pci.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint32,
> +                        0,
> +                        sizeof (PciHdr) / sizeof (UINT32),
> +                        &PciHdr
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Can't read PCI config header, status %d\n", Status
> +      );
> +    Status = EFI_UNSUPPORTED;
> +    goto Done;
> +  }
> +
> +  if (!IS_PCI_DISPLAY (&PciHdr) || PciHdr.Hdr.VendorId != 0x8086) {
> +    GVT_DEBUG (EFI_D_VERBOSE,
> +      "Skip non Intel PCI Display [%04x:%04x] class:%x\n",
> +      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, PciHdr.Hdr.ClassCode[2]
> +      );
> +    Status = EFI_UNSUPPORTED;
> +    goto Done;
> +  }
> +
> +  Status = PciIo->Mem.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint64,
> +                        PCI_BAR_IDX0,
> +                        vgtif_reg(magic),
> +                        1,
> +                        &Magic
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Can't read GVT magic from [%04x:%04x], status %d\n",
> +      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, Status
> +      );
> +    Status = EFI_UNSUPPORTED;
> +    goto Done;
> +  }
> +
> +  if (Magic != VGT_MAGIC) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Read magic from [%04x:%04x], get %x expect %x\n",
> +      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, Magic, VGT_MAGIC
> +      );
> +    Status = EFI_UNSUPPORTED;
> +    goto Done;
> +  }
> +
> +  Status = PciIo->Mem.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint32,
> +                        PCI_BAR_IDX0,
> +                        vgtif_reg(version_major),
> +                        1,
> +                        &Version
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Can't read GVT version from [%04x:%04x], status %d\n",
> +      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, Status
> +      );
> +    Status = EFI_UNSUPPORTED;
> +    goto Done;
> +  }
> +
> +  VerMajor = Version & 0xFFFF;
> +  VerMinor = (Version & 0xFFFF) >> 16;
> +  if (VerMajor < VGT_VERSION_MAJOR) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Check VGT interface version of [%04x:%04x], got %x.%x, expect %x.*\n",
> +      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId,
> +      VerMajor, VerMinor, VGT_VERSION_MAJOR
> +      );
> +    Status = EFI_UNSUPPORTED;
> +    goto Done;
> +  }
> +
> +  GVT_DEBUG (EFI_D_INFO,
> +    "Intel GVT-g virtual GPU [%04x:%04x] detected, version %x.%x\n",
> +    PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, VerMajor, VerMinor
> +    );
> +  Status = EFI_SUCCESS;
> +
> +Done:
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +IntelVirtualGpuInit (
> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
> +  )
> +{
> +  EFI_STATUS           Status = EFI_UNSUPPORTED;
> +  EFI_PCI_IO_PROTOCOL  *PciIo;
> +  PINTEL_VIRTUAL_GPU   VirtualGpu;
> +  FIRMWARE_CONFIG_ITEM FwCfgItem;
> +  UINTN                FwCfgSize;
> +  UINT8                Val8;
> +  UINT64               Val64;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  PciIo = Private->PciIo;
> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
> +  Status = PciIo->Pci.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint16,
> +                        PCI_VENDOR_ID_OFFSET,
> +                        1,
> +                        &VirtualGpu->VendorId
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Can't read PCI_VENDOR_ID_OFFSET, status %d\n", Status
> +      );
> +    goto Done;
> +  }
> +
> +  Status = PciIo->Pci.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint16,
> +                        PCI_DEVICE_ID_OFFSET,
> +                        1,
> +                        &VirtualGpu->DeviceId
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Can't read PCI_DEVICE_ID_OFFSET, status %d\n", Status
> +      );
> +    goto Done;
> +  }
> +
> +  Status = PciIo->Pci.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint64,
> +                        PCI_BASE_ADDRESSREG_OFFSET + PCI_BAR_IDX2 * 4,
> +                        1,
> +                        &Val64
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR, "Can't get GMADR from BAR2, status %d\n", Status);
> +    goto Done;
> +  }
> +
> +  if (Val64 & 0x1) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    GVT_DEBUG (EFI_D_ERROR, "BAR2 isn't memory space, status %d\n", Status);
> +    goto Done;
> +  }
> +
> +  switch (Val64 >> 1 & 0x3) {
> +  case 0:
> +    VirtualGpu->GpuMemAddr = Val64 & 0xFFFFFFF0;
> +    GVT_DEBUG (EFI_D_VERBOSE, "BAR2 has 32-bit access space\n");
> +    break;
> +  case 2:
> +    VirtualGpu->GpuMemAddr = Val64 & ~0xF;
> +    GVT_DEBUG (EFI_D_VERBOSE, "BAR2 has 64-bit access space\n");
> +    break;
> +  default:
> +    Status = EFI_OUT_OF_RESOURCES;
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "BAR2 has unknown access space, status %d\n", Status
> +      );
> +    goto Done;
> +    break;
> +  }
> +
> +  Status = PciIo->Pci.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint8,
> +                        PCI_REG_MSAC,
> +                        1,
> +                        &Val8
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Can't get MSAC from %x, status %d\n", PCI_REG_MSAC, Status
> +      );
> +    goto Done;
> +  }
> +
> +  Val8 &= 0x1F;
> +  if (Val8 & 0x10) {
> +    VirtualGpu->GpuMemSizeM = 4096;
> +  } else {
> +    Val8 &= 0xF;
> +    if (Val8 & 0x8) {
> +      VirtualGpu->GpuMemSizeM = 2048;
> +    } else {
> +      Val8 &= 0x7;
> +      if (Val8 & 0x4) {
> +        VirtualGpu->GpuMemSizeM = 1024;
> +      } else {
> +        Val8 &= 0x3;
> +        if (Val8 & 0x2) {
> +          VirtualGpu->GpuMemSizeM = 512;
> +        } else {
> +          if (Val8 & 0x1) {
> +            VirtualGpu->GpuMemSizeM = 256;
> +          } else {
> +            VirtualGpu->GpuMemSizeM = 128;
> +          }
> +        }
> +      }
> +    }
> +  }
> +
> +  Status = QemuFwCfgFindFile ("etc/igd-opregion", &FwCfgItem, &FwCfgSize);

(1) This feature still relies on "etc/igd-opregion".

And so, while this driver "poses" as a UEFI_DRIVER module for a PCI
device, it remains a platform driver.

That's still a deal-breaker -- please refer to
<https://bugzilla.tianocore.org/show_bug.cgi?id=935>, specifically
comment 15.

Has there been any improvement regarding the requirement that the
opregion come from QEMU via fw_cfg, for the Windows guest driver's sake?

(I really wish you had first asked about this feature, before authoring
a driver with 4000+ lines!)


(2) If the fw_cfg file in question is not found, the patch simply
ignores it. We log a debug message about it (not even an error message),
but then proceed with the rest of the code as if everything was OK.

Is that intentional?


(3) There's a whole lot of style issues in the code, and I absolutely
don't see myself identifying every single one of those for you, in a
4000+ line driver.

(EFI_D_xxx macro usage, line wrapping issues with multi-line function
calls, comment style problems, an assumption of varargs support with
function-like macros on all edk2 toolchains, building the driver only
for X64, ...)


I'd much prefer if you maintained this driver outside of OvmfPkg
(perhaps somewhere in edk2-platforms, possibly under
Drivers/OptionRomPkg/), and then, given a UEFI driver binary, you passed
it to QEMU via the device's ROM BAR, per
<https://bugzilla.tianocore.org/show_bug.cgi?id=935#c17>.


I'd be *somewhat* open to accepting this driver into OvmfPkg if:

- you formally assume on-going reviewership for the driver
(Maintainers.txt),

- you set the feature test macro in the DSC files to FALSE by default,

- you fix all the style issues with the help of other Intel contributors,

- you explicitly document somewhere that the fw_cfg access is a design
bug in a UEFI driver (especially for an assigned device) -- it remains a
platform driver, contrary to the semblance, for the sake of the arguably
broken Windows guest driver,

- you make the driver 32-bit clean and include it in the IA32 and
IA32X64 DSC files too.


I won't even mention how unreviewable a "patch bomb" like this is; such
a driver should be constructed (erected) gradually over 10-20 patches at
the minimum, isolating the UEFI driver model code from the device
initialization from the various GOP member functions. I won't mention
that because I don't intend to review this driver in depth anyway.

I might be willing to accept it as an optional (disabled by default)
"code dump", as long as you ensure the bare minimum of edk2 style and
build requirements, and take full responsibility for the driver in the
future.

... Honestly, the fact that you never asked about this feature on any
edk2 list, and that you (apparently) never searched the TianoCore
bugzilla tracker for potentially related BZs (such as #935), doesn't
really boost my confidence in this feature.

Laszlo

> +  if (Status == EFI_SUCCESS && FwCfgSize == OPREGION_SIZE) {
> +    // OpRegion must sit below 4 GB
> +    VirtualGpu->OpRegion = SIZE_4GB - 1;
> +    Status = gBS->AllocatePages (
> +                AllocateMaxAddress,
> +                EfiReservedMemoryType,
> +                EFI_SIZE_TO_PAGES (OPREGION_SIZE),
> +                &VirtualGpu->OpRegion
> +                );
> +    if (EFI_ERROR (Status)) {
> +      GVT_DEBUG (EFI_D_ERROR,
> +        "Fail to allocate %d pages size %lx for OpRegion, status %d\n",
> +        EFI_SIZE_TO_PAGES (OPREGION_SIZE), OPREGION_SIZE, Status
> +        );
> +      goto Done;
> +    }
> +    QemuFwCfgSelectItem (FwCfgItem);
> +    QemuFwCfgReadBytes (FwCfgSize, (VOID*)VirtualGpu->OpRegion);
> +    Status = PciIo->Pci.Write (
> +                          PciIo,
> +                          EfiPciIoWidthUint32,
> +                          PCI_REG_ASLS,
> +                          1,
> +                          (UINT32*)&VirtualGpu->OpRegion
> +                          );
> +    if (EFI_ERROR (Status)) {
> +      GVT_DEBUG (EFI_D_ERROR,
> +        "Fail to write OpRegion %p to PCI config offset 0x%x, status %d\n",
> +        VirtualGpu->OpRegion, PCI_REG_ASLS, Status
> +        );
> +      goto Done;
> +    } else {
> +      GVT_DEBUG (EFI_D_INFO,
> +        "OpRegion %p is set to PCI config offset 0x%x\n",
> +        VirtualGpu->OpRegion, PCI_REG_ASLS
> +        );
> +    }
> +  } else {
> +    GVT_DEBUG (EFI_D_VERBOSE,
> +      "Not igd-opregion found in QEMU firmware config\n"
> +      );
> +  }
> +
> +  RegRead32 (Private,
> +    vgtif_reg(avail_rs.mappable_gmadr.base), &VirtualGpu->VisibleOffset);
> +  RegRead32 (Private,
> +    vgtif_reg(avail_rs.mappable_gmadr.size), &VirtualGpu->VisibleSize);
> +  RegRead32 (Private,
> +    vgtif_reg(avail_rs.nonmappable_gmadr.base), &VirtualGpu->InvisibleOffset);
> +  RegRead32 (Private,
> +    vgtif_reg(avail_rs.nonmappable_gmadr.size), &VirtualGpu->InvisibleSize);
> +  VirtualGpu->VisibleGGTTOffset = VirtualGpu->VisibleOffset >> GTT_PAGE_SHIFT;
> +  VirtualGpu->VisibleGGTTSize = VirtualGpu->VisibleSize >> GTT_PAGE_SHIFT;
> +  VirtualGpu->InvisibleGGTTOffset = VirtualGpu->InvisibleOffset >> GTT_PAGE_SHIFT;
> +  VirtualGpu->InvisibleGGTTSize = VirtualGpu->InvisibleSize >> GTT_PAGE_SHIFT;
> +
> +  GVT_DEBUG (
> +    EFI_D_INFO,
> +    "GMADR [0x%lx - 0x%lx], size %d MB\n",
> +    VirtualGpu->GpuMemAddr,
> +    VirtualGpu->GpuMemAddr + VirtualGpu->GpuMemSizeM * 0x100000,
> +    VirtualGpu->GpuMemSizeM
> +    );
> +  GVT_DEBUG (
> +    EFI_D_INFO,
> +    "visible offset [0x%x - 0x%x] size %d KB, GGTT range [%x - %x]\n",
> +    VirtualGpu->VisibleOffset,
> +    VirtualGpu->VisibleOffset + VirtualGpu->VisibleSize,
> +    VirtualGpu->VisibleSize / 0x400,
> +    VirtualGpu->VisibleGGTTOffset,
> +    VirtualGpu->VisibleGGTTOffset + VirtualGpu->VisibleGGTTSize
> +    );
> +  GVT_DEBUG (
> +    EFI_D_INFO,
> +    "invisible offset [0x%x - 0x%x] size %d KB, GGTT range [%x - %x]\n",
> +    VirtualGpu->InvisibleOffset,
> +    VirtualGpu->InvisibleOffset + VirtualGpu->InvisibleSize,
> +    VirtualGpu->InvisibleSize / 0x400,
> +    VirtualGpu->InvisibleGGTTOffset,
> +    VirtualGpu->InvisibleGGTTOffset + VirtualGpu->InvisibleGGTTSize
> +    );
> +
> +  Status = IntelVirtualGpuDisplayInit (Private);
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Fail to initialize display, status %d\n", Status
> +      );
> +    goto Done;
> +  }
> +
> +  Status = IntelVirtualGpuSetMode (&Private->GraphicsOutputProtocol, 0);
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Fail to set init display mode, status %d\n", Status
> +      );
> +    goto Done;
> +  }
> +
> +  Status = IntelVirtualGpuNotifyDisplayReady (Private, TRUE);
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR,
> +      "Fail to notify display ready, status %d\n", Status
> +      );
> +    goto Done;
> +  }
> +
> +  // Flush all reg after DisplayReady
> +  Status = IntelVirtualGpuEnableDisplay (
> +             Private,
> +             0,
> +             TRUE
> +             );
> +
> +Done:
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> +
> +EFI_STATUS
> +IntelVirtualGpuClean (
> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
> +  )
> +{
> +  EFI_STATUS         Status = EFI_INVALID_PARAMETER;
> +  PINTEL_VIRTUAL_GPU VirtualGpu;
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
> +
> +  Status = IntelVirtualGpuDisplayClean (Private);
> +  if (EFI_ERROR (Status)) {
> +    GVT_DEBUG (EFI_D_ERROR, "Fail to clean display, status %d\n", Status);
> +    goto Done;
> +  }
> +
> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
> +  if (VirtualGpu->OpRegion) {
> +    Status = gBS->FreePages (
> +                    VirtualGpu->OpRegion,
> +                    EFI_SIZE_TO_PAGES (OPREGION_SIZE)
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      GVT_DEBUG (EFI_D_ERROR,
> +        "FreePages failed for OpRegion, pages %d, size %d, status %d\n",
> +        EFI_SIZE_TO_PAGES (OPREGION_SIZE), OPREGION_SIZE, Status
> +        );
> +        goto Done;
> +    }
> +    Status = EFI_SUCCESS;
> +  }
> +
> +Done:
> +
> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
> +
> +  return Status;
> +}
> diff --git a/OvmfPkg/IntelGvtGopDxe/VirtualGpu.h b/OvmfPkg/IntelGvtGopDxe/VirtualGpu.h
> new file mode 100644
> index 000000000000..60d80eadb3ac
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/VirtualGpu.h
> @@ -0,0 +1,52 @@
> +/** @file
> +  Component name for the QEMU video controller.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __VIRTUALGPU_H_
> +#define __VIRTUALGPU_H_
> +
> +#include <Display.h>
> +
> +#define PCI_REG_MSAC 0x62
> +#define PCI_REG_ASLS 0xFC
> +
> +#define OPREGION_SIZE SIZE_8KB
> +
> +typedef struct _INTEL_VIRTUAL_GPU {
> +  UINT16                    VendorId;
> +  UINT16                    DeviceId;
> +  EFI_PHYSICAL_ADDRESS      OpRegion;
> +  EFI_PHYSICAL_ADDRESS      GpuMemAddr;
> +  UINT32                    GpuMemSizeM;
> +  UINT32                    VisibleOffset;
> +  UINT32                    VisibleSize;
> +  UINT32                    VisibleGGTTOffset;
> +  UINT32                    VisibleGGTTSize;
> +  UINT32                    InvisibleOffset;
> +  UINT32                    InvisibleSize;
> +  UINT32                    InvisibleGGTTOffset;
> +  UINT32                    InvisibleGGTTSize;
> +  INTEL_VIRTUAL_GPU_DISPLAY Display;
> +} INTEL_VIRTUAL_GPU, *PINTEL_VIRTUAL_GPU;
> +
> +EFI_STATUS
> +IntelVirtualGpuActive (
> +  IN EFI_PCI_IO_PROTOCOL *PciIo
> +  );
> +
> +EFI_STATUS
> +IntelVirtualGpuInit (
> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
> +  );
> +
> +EFI_STATUS
> +IntelVirtualGpuClean (
> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
> +  );
> +
> +#endif //__VIRTUALGPU_H_
> 


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

* Re: [edk2-devel] [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation.
  2021-03-05 13:19   ` [edk2-devel] " Laszlo Ersek
@ 2021-03-12  3:57     ` Colin Xu
  2021-03-12 12:35       ` Gerd Hoffmann
  2021-03-12  4:42     ` Rebecca Cran
  1 sibling, 1 reply; 11+ messages in thread
From: Colin Xu @ 2021-03-12  3:57 UTC (permalink / raw)
  To: devel, lersek, kraxel, alex.williamson; +Cc: colin.xu, rebecca, zhenyuw



--
Best Regards,
Colin Xu

On Fri, 5 Mar 2021, Laszlo Ersek wrote:
Thanks a lot for your comment, Laszlo! See my reply also end of the 
patch.
Hi Gerd, Alex, would you mind share your thoughts as well?

> Adding Gerd and Alex; some comments below (near the end of the patch --
> keeping full context for Gerd's and Alex's sake):
>
> On 03/05/21 07:20, Colin Xu wrote:
>> Intel GVT-g GOP DXE supports OVMF GOP output its frame buffer to vGPU
>> partitioned aperture mapped by GGTT, so that the GOP output can be
>> mediated to its backend for display (i.e. QEMU GTK display via dma-buf).
>>
>> Unlike ACRN GVT-d integrating native GOP/VBT into it's OVMF, the GVT-g
>> GOP is an open-source implementation which follows Intel GVT-g framework
>> to interact with KVMGT in host kernel so that the GOP frame buffer
>> content can be processed properly.
>>
>> With GVT-g GOP enabled OVMF, guest VM can output its framebuffer
>> content to KVMGT via GOP, with a proper backend support (i.e. QEMU GTK
>> display with dma-buf), the following content is now directly visible to
>> user unlike previosly need a second GPU:
>> - OVMF EFI Shell
>> - Bootloader (i.e. grub)
>> - OS installation progress. (before built-in GFX driver loaded)
>> - Pre GFX Driver display (i.e. Android/Linux boot splash or logo,
>>   Windows 8.1 boot progress/safe mode/recovery mode/BSOD/GPU-disabled
>>   desktop, etc.)
>>
>> GVT-g GOP has below capabilites:
>> - Check GVT-g compatibility via PV info, only enable GVT-g GOP when it's
>>   compatible with KVMGT.
>> - R/W MMIO from BAR0.
>> - R/W Global GTT from BAR0.
>> - Reserve and program OpRegion address at ASLS location so that guest
>>   driver can decode GVT-g simluated VBT and enabled display properly.
>> - Reserve guest memory and map to BAR2 partitioned range with proper
>>   GGTT, so that KVMGT can access via proper guest GTT to host GGTT map.
>> - All supported EFI_GRAPHICS_OUTPUT_BLT_OPERATION from/to video memory.
>> - Enable/disable GOP content on PIPE_A, PLANE_PRIMARY with proper scaling.
>> - VBE Shim so that some OS can query non-empty mode info via INT10 call
>>   to enable the desktop when GPU is disabled.
>>
>> V2:
>> Program PIPESRC to match active H/V.
>>
>> Signed-off-by: Colin Xu <colin.xu@intel.com>
>> ---
>>  OvmfPkg/IntelGvtGopDxe/Common.h           |   45 +
>>  OvmfPkg/IntelGvtGopDxe/DebugHelper.h      |   20 +
>>  OvmfPkg/IntelGvtGopDxe/Display.c          | 1077 +++++++++++++++++++++
>>  OvmfPkg/IntelGvtGopDxe/Display.h          |  141 +++
>>  OvmfPkg/IntelGvtGopDxe/GopDriver.c        |  478 +++++++++
>>  OvmfPkg/IntelGvtGopDxe/GpuReg.c           |   91 ++
>>  OvmfPkg/IntelGvtGopDxe/GpuReg.h           |  175 ++++
>>  OvmfPkg/IntelGvtGopDxe/Gtt.c              |  162 ++++
>>  OvmfPkg/IntelGvtGopDxe/Gtt.h              |   51 +
>>  OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf |   59 ++
>>  OvmfPkg/IntelGvtGopDxe/VbeShim.asm        |  343 +++++++
>>  OvmfPkg/IntelGvtGopDxe/VbeShim.c          |  258 +++++
>>  OvmfPkg/IntelGvtGopDxe/VbeShim.h          |  912 +++++++++++++++++
>>  OvmfPkg/IntelGvtGopDxe/VbeShim.sh         |   81 ++
>>  OvmfPkg/IntelGvtGopDxe/VirtualGpu.c       |  400 ++++++++
>>  OvmfPkg/IntelGvtGopDxe/VirtualGpu.h       |   52 +
>>  16 files changed, 4345 insertions(+)
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/Common.h
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/DebugHelper.h
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/Display.c
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/Display.h
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/GopDriver.c
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/GpuReg.c
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/GpuReg.h
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/Gtt.c
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/Gtt.h
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/VbeShim.asm
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/VbeShim.c
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/VbeShim.h
>>  create mode 100755 OvmfPkg/IntelGvtGopDxe/VbeShim.sh
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/VirtualGpu.c
>>  create mode 100644 OvmfPkg/IntelGvtGopDxe/VirtualGpu.h
>>
>> diff --git a/OvmfPkg/IntelGvtGopDxe/Common.h b/OvmfPkg/IntelGvtGopDxe/Common.h
>> new file mode 100644
>> index 000000000000..cf30752eb8f3
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/Common.h
>> @@ -0,0 +1,45 @@
>> +/** @file
>> +  Component name for the QEMU video controller.
>> +
>> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef __COMMON_H_
>> +
>> +#include <Protocol/PciIo.h>
>> +#include <Protocol/DevicePath.h>
>> +#include <Protocol/GraphicsOutput.h>
>> +
>> +#include <Library/BaseLib.h>
>> +#include <Library/PcdLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Library/UefiDriverEntryPoint.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/DevicePathLib.h>
>> +
>> +#include <IndustryStandard/Pci.h>
>> +
>> +#include "DebugHelper.h"
>> +
>> +#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0)
>> +
>> +typedef struct {
>> +  UINT64                       Signature;
>> +  EFI_HANDLE                   Handle;
>> +  EFI_PCI_IO_PROTOCOL          *PciIo;
>> +  UINT64                       OriginalPciAttr;
>> +  EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutputProtocol;
>> +  EFI_DEVICE_PATH_PROTOCOL     *GopDevPath;
>> +  VOID                         *VirtualGpu;
>> +} GVT_GOP_PRIVATE_DATA;
>> +
>> +#define GVT_GOP_MAGIC                     SIGNATURE_64('G','V','T','G','V','G','O','P')
>> +#define GVT_GOP_PRIVATE_DATA_FROM_THIS(a) CR(a, GVT_GOP_PRIVATE_DATA, GraphicsOutputProtocol, GVT_GOP_MAGIC)
>> +
>> +#define __COMMON_H_
>> +#endif //__COMMON_H_
>> diff --git a/OvmfPkg/IntelGvtGopDxe/DebugHelper.h b/OvmfPkg/IntelGvtGopDxe/DebugHelper.h
>> new file mode 100644
>> index 000000000000..75158d713ec3
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/DebugHelper.h
>> @@ -0,0 +1,20 @@
>> +/** @file
>> +  Component name for the QEMU video controller.
>> +
>> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef __DEBUGHELPER_H_
>> +#define __DEBUGHELPER_H_
>> +
>> +#include <Library/DebugLib.h>
>> +
>> +#define GVT_DEBUG(ErrLevel, Fmt, Args...) \
>> +  do { \
>> +    DEBUG ((ErrLevel, "GvtGop: "Fmt, ##Args));\
>> +  } while (FALSE)
>> +
>> +#endif //__DEBUGHELPER_H_
>> diff --git a/OvmfPkg/IntelGvtGopDxe/Display.c b/OvmfPkg/IntelGvtGopDxe/Display.c
>> new file mode 100644
>> index 000000000000..133de25ff03c
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/Display.c
>> @@ -0,0 +1,1077 @@
>> +/** @file
>> +  Component name for the QEMU video controller.
>> +
>> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include "Common.h"
>> +#include "Display.h"
>> +#include "GpuReg.h"
>> +#include "Gtt.h"
>> +#include "VirtualGpu.h"
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuDisplayInit (
>> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
>> +  )
>> +{
>> +  EFI_STATUS                 Status = EFI_UNSUPPORTED;
>> +  PINTEL_VIRTUAL_GPU         VirtualGpu;
>> +  PINTEL_VIRTUAL_GPU_DISPLAY Display;
>> +  UINT32                     Val32;
>> +  UINTN                      Width, Height, ModeNumber;
>> +  EFI_TPL                    OriginalTPL;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
>> +  Display = &VirtualGpu->Display;
>> +
>> +  /*
>> +   * If PcdVideoHorizontalResolution or PcdVideoVerticalResolution is not set,
>> +   *   GOP will query the mode list reported to find the highest resolution.
>> +   *   Otherwise, check if the set PcdVideo*Resolution is defined.
>> +   *   If not supported, try 800x600 which is required by UEFI/EFI spec.
>> +   *   If still not supported, use the 1st mode in mode list.
>> +   * If there are multiple video devices, graphic console driver will set all
>> +   *   the video devices to the same mode.
>> +   * According to UEFI/EFI spec, in addition to platform design guide, on-board
>> +   *   graphics should support native mode of the display, plug-in graphics
>> +   *   should support 800x600x32 or 640x480x32.
>> +   * According to some OS requirement (i.e. UEFI requirment for Windows 10),
>> +   *   integrated displays should support panel native resolution and external
>> +   *   displays should support the maximum resolution of both GPU and display in
>> +   *   GOP. For alternate display output, it should support native or highest
>> +   *   compatible resolution, otherwise support an known mode to be compatible
>> +   *   with as many monitors as possible (640x480, 1024x768).
>> +   * Due to above requirement, use native resolution if PcdVideo*Resolution is
>> +   *   not defined. To reduce GGTT write overhead, also limit the maximum to
>> +   *   DISPLAY_WIDTH_MAX/DISPLAY_HEIGHT_MAX.
>> +   */
>> +
>> +  RegRead32 (Private, HTOTAL(PIPE_A), &Val32);
>> +  Display->HActive = (Val32 & 0xFFF) + 1;
>> +  RegRead32 (Private, VTOTAL(PIPE_A), &Val32);
>> +  Display->VActive = (Val32 & 0xFFF) + 1;
>> +
>> +  if (Display->HActive != 0 && Display->VActive != 0) {
>> +    Width = Display->HActive;
>> +    Height = Display->VActive;
>> +    if (Display->HActive > DISPLAY_WIDTH_MAX ||
>> +        Display->VActive > DISPLAY_HEIGHT_MAX) {
>> +      Width = DISPLAY_WIDTH_MAX;
>> +      Height = DISPLAY_HEIGHT_MAX;
>> +    }
>> +  } else {
>> +    Width = DISPLAY_WIDTH_DEFAULT;
>> +    Height = DISPLAY_HEIGHT_DEFAULT;
>> +  }
>> +
>> +  Display->Width = Width;
>> +  Display->Height = Height;
>> +  Display->Format = PixelBlueGreenRedReserved8BitPerColor;
>> +  Display->Bpp = 4;
>> +  Display->MaxMode = 1;
>> +
>> +  // Add default if defined
>> +  if (PcdGet32 (PcdVideoHorizontalResolution) != 0 &&
>> +      PcdGet32 (PcdVideoVerticalResolution) != 0 &&
>> +      PcdGet32 (PcdVideoHorizontalResolution) != Width &&
>> +      PcdGet32 (PcdVideoVerticalResolution) != Height) {
>> +      ++Display->MaxMode;
>> +  }
>> +
>> +  Display->CurrentMode = DISPLAY_MODE_INVALID;
>> +  Display->FrameBufferBltConfigure = NULL;
>> +  Display->FrameBufferBltConfigureSize = 0;
>> +
>> +  // Linear must start at 256K, stride align at 64
>> +  Display->WidthBytes = Display->Width * Display->Bpp;
>> +  Display->StrideBytes = ALIGN_VALUE (Display->WidthBytes, 64);
>> +  Display->FbSize = Display->StrideBytes * Display->Height;
>> +  Display->Pages = EFI_SIZE_TO_PAGES (Display->FbSize);
>> +
>> +  Display->FbGMAddr = VirtualGpu->GpuMemAddr + VirtualGpu->VisibleOffset;
>> +  Display->FbGMAddr = ALIGN_VALUE (Display->FbGMAddr, SIZE_256KB);
>> +
>> +  Status = gBS->AllocatePages (
>> +                AllocateAnyPages,
>> +                EfiReservedMemoryType,
>> +                Display->Pages,
>> +                &Display->FbPhysicalAddr
>> +                );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "AllocatePages failed for display FB, pages %d, size %lx, status %d\n",
>> +      Display->Pages, Display->FbSize, Status
>> +      );
>> +    return Status;
>> +  }
>> +
>> +  Status = UpdateGGTT (Private,
>> +             Display->FbGMAddr,
>> +             Display->FbPhysicalAddr,
>> +             Display->Pages
>> +             );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Fail to Update GGTT for display, status %d\n", Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
>> +  Status = IntelVirtualGpuBltVideoFill (
>> +             Display,
>> +             (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION){{0, 0, 0, 0}},
>> +             (BLT_RECTANGLE){0, 0, Display->Width, Display->Height});
>> +  gBS->RestoreTPL (OriginalTPL);
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Fail to clear rectangle at [%d, %d] size %dx%d with color 0x%08x, status %d\n",
>> +      (BLT_RECTANGLE){0, 0, Display->Width, Display->Height}.X,
>> +      (BLT_RECTANGLE){0, 0, Display->Width, Display->Height}.Y,
>> +      (BLT_RECTANGLE){0, 0, Display->Width, Display->Height}.Width,
>> +      (BLT_RECTANGLE){0, 0, Display->Width, Display->Height}.Height,
>> +      (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION){{0, 0, 0, 0}}.Raw,
>> +      Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  Status = gBS->AllocatePool (
>> +                  EfiBootServicesData,
>> +                  sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * Display->MaxMode,
>> +                  (VOID **)&Display->ModeList
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "AllocatePool failed for display mode list, size %d, status %d\n",
>> +      sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * Display->MaxMode,
>> +      Status
>> +      );
>> +    Status = EFI_OUT_OF_RESOURCES;
>> +    goto Done;
>> +  }
>> +
>> +  for (ModeNumber = 0; ModeNumber < Display->MaxMode; ModeNumber++) {
>> +    Display->ModeList[ModeNumber].Version = 0;
>> +    Display->ModeList[ModeNumber].HorizontalResolution = Display->Width;
>> +    Display->ModeList[ModeNumber].VerticalResolution = Display->Height;
>> +    Display->ModeList[ModeNumber].PixelFormat = Display->Format;
>> +    Display->ModeList[ModeNumber].PixelsPerScanLine = Display->Width;
>> +  }
>> +  if (Display->MaxMode > 1) {
>> +    Display->ModeList[1].HorizontalResolution = PcdGet32 (PcdVideoHorizontalResolution);
>> +    Display->ModeList[1].VerticalResolution = PcdGet32 (PcdVideoVerticalResolution);
>> +    Display->ModeList[1].PixelsPerScanLine = PcdGet32 (PcdVideoHorizontalResolution);
>> +  }
>> +
>> +  Private->GraphicsOutputProtocol.QueryMode = IntelVirtualGpuQueryMode;
>> +  Private->GraphicsOutputProtocol.SetMode = IntelVirtualGpuSetMode;
>> +  Private->GraphicsOutputProtocol.Blt = IntelVirtualGpuBlt;
>> +  Private->GraphicsOutputProtocol.Mode->MaxMode = Display->MaxMode;
>> +  Private->GraphicsOutputProtocol.Mode->Mode = Display->CurrentMode;
>> +  Private->GraphicsOutputProtocol.Mode->SizeOfInfo =
>> +    sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * Display->MaxMode;
>> +
>> +  Status = gBS->AllocatePool (
>> +                  EfiBootServicesData,
>> +                  Private->GraphicsOutputProtocol.Mode->SizeOfInfo,
>> +                  (VOID **)&Private->GraphicsOutputProtocol.Mode->Info
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "AllocatePool failed for display mode info, size %d, status %d\n",
>> +      Private->GraphicsOutputProtocol.Mode->SizeOfInfo, Status
>> +      );
>> +    Status = EFI_OUT_OF_RESOURCES;
>> +    goto Done;
>> +  }
>> +
>> +  CopyMem (
>> +    Private->GraphicsOutputProtocol.Mode->Info,
>> +    Display->ModeList,
>> +    sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * Display->MaxMode
>> +    );
>> +
>> +  Private->GraphicsOutputProtocol.Mode->FrameBufferBase = Display->FbGMAddr;
>> +  Private->GraphicsOutputProtocol.Mode->FrameBufferSize = Display->FbSize;
>> +
>> +  InstallVbeShim (L"GVT-g VBIOS", Display->FbGMAddr);
>> +
>> +  GVT_DEBUG (EFI_D_INFO,
>> +    "modes %d, max %dx%d, OVMF default %dx%d\n",
>> +    Display->MaxMode,
>> +    Display->Width, Display->Height,
>> +    PcdGet32 (PcdVideoHorizontalResolution),
>> +    PcdGet32 (PcdVideoVerticalResolution)
>> +    );
>> +  for (ModeNumber = 0; ModeNumber < Display->MaxMode; ModeNumber++) {
>> +    GVT_DEBUG (EFI_D_INFO,
>> +      "  mode %d: %dx%d BGRX, stride %d\n",
>> +      ModeNumber,
>> +      Display->ModeList[ModeNumber].HorizontalResolution,
>> +      Display->ModeList[ModeNumber].VerticalResolution,
>> +      ALIGN_VALUE (Display->ModeList[ModeNumber].HorizontalResolution * Display->Bpp, 64)
>> +      );
>> +  }
>> +  GVT_DEBUG (EFI_D_INFO,
>> +    "FrameBuffer: GMADR %lx, PADDR %lx, size %lx, pages %d, INTERNAL_BLT %d\n",
>> +    Display->FbGMAddr, Display->FbPhysicalAddr, Display->FbSize, Display->Pages,
>> +    DISPLAY_USE_INTERNAL_BLT
>> +    );
>> +
>> +Done:
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +
>> +}
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuDisplayClean (
>> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
>> +  )
>> +{
>> +  EFI_STATUS                 Status = EFI_INVALID_PARAMETER;
>> +  PINTEL_VIRTUAL_GPU         VirtualGpu;
>> +  PINTEL_VIRTUAL_GPU_DISPLAY Display;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
>> +  Display = &VirtualGpu->Display;
>> +
>> +  if (Private->GraphicsOutputProtocol.Mode->Info) {
>> +    Status = gBS->FreePool (Private->GraphicsOutputProtocol.Mode->Info);
>> +    if (EFI_ERROR (Status)) {
>> +      GVT_DEBUG (EFI_D_ERROR,
>> +        "FreePool failed for display mode info, size %d, status %d\n",
>> +        Private->GraphicsOutputProtocol.Mode->SizeOfInfo, Status
>> +        );
>> +        goto Done;
>> +    }
>> +    Private->GraphicsOutputProtocol.Mode->SizeOfInfo = 0;
>> +    Private->GraphicsOutputProtocol.Mode->Info = NULL;
>> +  }
>> +  Private->GraphicsOutputProtocol.Mode->MaxMode = 0;
>> +  Private->GraphicsOutputProtocol.Mode->Mode = DISPLAY_MODE_INVALID;
>> +
>> +  if (Display->FbPhysicalAddr) {
>> +    Status = gBS->FreePages (Display->FbPhysicalAddr, Display->Pages);
>> +    if (EFI_ERROR (Status)) {
>> +      GVT_DEBUG (EFI_D_ERROR,
>> +        "FreePages failed for display FB, pages %d, size %lx, status %d\n",
>> +        Display->Pages, Display->FbSize, Status
>> +        );
>> +        goto Done;
>> +    }
>> +    Display->FbPhysicalAddr = 0;
>> +    Display->Pages = 0;
>> +    Display->FbSize = 0;
>> +  }
>> +
>> +  Status = EFI_SUCCESS;
>> +
>> +Done:
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +IntelVirtualGpuQueryMode (
>> +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL         *This,
>> +  IN  UINT32                               ModeNumber,
>> +  OUT UINTN                                *SizeOfInfo,
>> +  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
>> +  )
>> +{
>> +  EFI_STATUS                 Status = EFI_UNSUPPORTED;
>> +  GVT_GOP_PRIVATE_DATA       *GvtGopPrivate = NULL;
>> +  PINTEL_VIRTUAL_GPU         VirtualGpu;
>> +  PINTEL_VIRTUAL_GPU_DISPLAY Display;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  GvtGopPrivate = GVT_GOP_PRIVATE_DATA_FROM_THIS (This);
>> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)GvtGopPrivate->VirtualGpu;
>> +  Display = &VirtualGpu->Display;
>> +
>> +  if (ModeNumber >= Display->MaxMode) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Invalid ModeNumber, request %d, max %d, status %d\n",
>> +      ModeNumber, Display->MaxMode, Status
>> +      );
>> +    Status = EFI_INVALID_PARAMETER;
>> +    goto Done;
>> +  }
>> +
>> +  Status = gBS->AllocatePool (
>> +                  EfiBootServicesData,
>> +                  sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
>> +                  (VOID **)Info
>> +                  );
>> +  if (EFI_ERROR (Status) || *Info == NULL) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "AllocatePool failed for queried mode info, size %d, status %d\n",
>> +      sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), Status
>> +      );
>> +    Status = EFI_OUT_OF_RESOURCES;
>> +    goto Done;
>> +  }
>> +
>> +  *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
>> +  CopyMem (
>> +    *Info,
>> +    &Display->ModeList[ModeNumber],
>> +    sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
>> +    );
>> +
>> +  Status = EFI_SUCCESS;
>> +
>> +Done:
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +IntelVirtualGpuSetMode (
>> +  IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
>> +  IN UINT32                       ModeNumber
>> +  )
>> +{
>> +  EFI_STATUS                          Status = EFI_UNSUPPORTED;
>> +  GVT_GOP_PRIVATE_DATA                *GvtGopPrivate = NULL;
>> +  PINTEL_VIRTUAL_GPU                  VirtualGpu;
>> +  PINTEL_VIRTUAL_GPU_DISPLAY          Display;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  GvtGopPrivate = GVT_GOP_PRIVATE_DATA_FROM_THIS (This);
>> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)GvtGopPrivate->VirtualGpu;
>> +  Display = &VirtualGpu->Display;
>> +
>> +  if (ModeNumber >= Display->MaxMode) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Invalid ModeNumber, request %d, max %d, status %d\n",
>> +      ModeNumber, Display->MaxMode, Status
>> +      );
>> +    Status = EFI_INVALID_PARAMETER;
>> +    goto Done;
>> +  }
>> +
>> +#if (DISPLAY_USE_INTERNAL_BLT == 1)
>> +  Status = IntelVirtualGpuBltVideoFill (
>> +             Display,
>> +             (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION){{0, 0, 0, 0}},
>> +             (BLT_RECTANGLE){0, 0, This->Mode->Info->HorizontalResolution, This->Mode->Info->VerticalResolution});
>> +  if (EFI_ERROR (Status)) {
>> +      GVT_DEBUG (EFI_D_ERROR,
>> +        "IntelVirtualGpuBltVideoFill failed for mode %d, status %d\n",
>> +        ModeNumber,
>> +        Status
>> +        );
>> +    }
>> +#else
>> +  Status = FrameBufferBltConfigure (
>> +             (VOID*) (UINTN) This->Mode->FrameBufferBase,
>> +             This->Mode->Info,
>> +             Display->FrameBufferBltConfigure,
>> +             &Display->FrameBufferBltConfigureSize
>> +             );
>> +  if (Status == RETURN_BUFFER_TOO_SMALL) {
>> +    if (Display->FrameBufferBltConfigure != NULL) {
>> +      Status = gBS->FreePool (Display->FrameBufferBltConfigure);
>> +      if (EFI_ERROR (Status)) {
>> +        GVT_DEBUG (EFI_D_ERROR,
>> +          "FreePool failed for FrameBufferBltConfigure, status %d\n",
>> +          Status
>> +          );
>> +          goto Done;
>> +      }
>> +    }
>> +    Status = gBS->AllocatePool (
>> +                  EfiBootServicesData,
>> +                  Display->FrameBufferBltConfigureSize,
>> +                  (VOID **)&Display->FrameBufferBltConfigure
>> +                  );
>> +    if (EFI_ERROR (Status)) {
>> +      GVT_DEBUG (EFI_D_ERROR,
>> +        "AllocatePool failed for FrameBufferBltConfigure, size %d, status %d\n",
>> +        Display->FrameBufferBltConfigureSize,
>> +        Status
>> +        );
>> +      goto Done;
>> +    }
>> +
>> +    Status = FrameBufferBltConfigure (
>> +                (VOID*) (UINTN) This->Mode->FrameBufferBase,
>> +                This->Mode->Info,
>> +                Display->FrameBufferBltConfigure,
>> +                &Display->FrameBufferBltConfigureSize
>> +                );
>> +    if (EFI_ERROR (Status)) {
>> +      GVT_DEBUG (EFI_D_ERROR,
>> +        "FrameBufferBltConfigure failed for mode %d, status %d\n",
>> +        ModeNumber,
>> +        Status
>> +        );
>> +      goto Done;
>> +    }
>> +  }
>> +
>> +  Status = FrameBufferBlt (
>> +             Display->FrameBufferBltConfigure,
>> +             &(EFI_GRAPHICS_OUTPUT_BLT_PIXEL){0, 0, 0, 0},
>> +             EfiBltVideoFill,
>> +             0, 0,
>> +             0, 0,
>> +             This->Mode->Info->HorizontalResolution,
>> +             This->Mode->Info->VerticalResolution,
>> +             0
>> +             );
>> +  if (EFI_ERROR (Status)) {
>> +      GVT_DEBUG (EFI_D_ERROR,
>> +        "FrameBufferBlt BltOperation %d failed for mode %d, color 0x%08x, status %d\n",
>> +        EfiBltVideoFill,
>> +        ModeNumber,
>> +        (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION){{0, 0, 0, 0}}.Raw,
>> +        Status
>> +        );
>> +    }
>> +#endif
>> +
>> +  Status = IntelVirtualGpuEnableDisplay (
>> +             GvtGopPrivate,
>> +             ModeNumber,
>> +             FALSE
>> +             );
>> +
>> +  Status = IntelVirtualGpuEnableDisplay (
>> +             GvtGopPrivate,
>> +             ModeNumber,
>> +             TRUE
>> +             );
>> +
>> +  // Set current mode info in GOP
>> +  This->Mode->Mode = ModeNumber;
>> +  CopyMem (
>> +    This->Mode->Info,
>> +    &Display->ModeList[ModeNumber],
>> +    sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
>> +    );
>> +
>> +  GVT_DEBUG (EFI_D_INFO, "Set mode %d, %dx%d, status %d\n",
>> +    ModeNumber,
>> +    Display->ModeList[ModeNumber].HorizontalResolution,
>> +    Display->ModeList[ModeNumber].VerticalResolution,
>> +    Status
>> +    );
>> +
>> +Done:
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +IntelVirtualGpuBlt (
>> +  IN EFI_GRAPHICS_OUTPUT_PROTOCOL      *This,
>> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *BltBuffer, OPTIONAL
>> +  IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
>> +  IN UINTN                             SourceX,
>> +  IN UINTN                             SourceY,
>> +  IN UINTN                             DestinationX,
>> +  IN UINTN                             DestinationY,
>> +  IN UINTN                             Width,
>> +  IN UINTN                             Height,
>> +  IN UINTN                             Delta OPTIONAL
>> +  )
>> +{
>> +  EFI_STATUS                 Status = EFI_UNSUPPORTED;
>> +  GVT_GOP_PRIVATE_DATA       *GvtGopPrivate = NULL;
>> +  PINTEL_VIRTUAL_GPU         VirtualGpu;
>> +  PINTEL_VIRTUAL_GPU_DISPLAY Display;
>> +  EFI_TPL                    OriginalTPL;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  GvtGopPrivate = GVT_GOP_PRIVATE_DATA_FROM_THIS (This);
>> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)GvtGopPrivate->VirtualGpu;
>> +  Display = &VirtualGpu->Display;
>> +
>> +  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
>> +
>> +#if (DISPLAY_USE_INTERNAL_BLT == 1)
>> +  switch (BltOperation) {
>> +  case EfiBltVideoFill:
>> +    Status = IntelVirtualGpuBltVideoFill (
>> +               Display,
>> +               (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION)(*BltBuffer),
>> +               (BLT_RECTANGLE){DestinationX, DestinationY, Width, Height});
>> +    RegWrite32 (GvtGopPrivate,
>> +      PLANE_SURF(PIPE_A, PLANE_PRIMARY),
>> +      Display->FbGMAddr
>> +      );
>> +    break;
>> +  case EfiBltVideoToBltBuffer:
>> +    Status = IntelVirtualGpuBltVideoToBuffer (
>> +               Display,
>> +               BltBuffer,
>> +               (BLT_RECTANGLE){SourceX, SourceY, Width, Height},
>> +               (BLT_RECTANGLE){DestinationX, DestinationY, Width, Height},
>> +               Delta
>> +               );
>> +    break;
>> +  case EfiBltBufferToVideo:
>> +    Status = IntelVirtualGpuBltVideoFromBuffer (
>> +               Display,
>> +               BltBuffer,
>> +               (BLT_RECTANGLE){SourceX, SourceY, Width, Height},
>> +               (BLT_RECTANGLE){DestinationX, DestinationY, Width, Height},
>> +               Delta
>> +               );
>> +    RegWrite32 (GvtGopPrivate,
>> +      PLANE_SURF(PIPE_A, PLANE_PRIMARY),
>> +      Display->FbGMAddr
>> +      );
>> +    break;
>> +  case EfiBltVideoToVideo:
>> +    Status = IntelVirtualGpuBltVideoToVideo (
>> +               Display,
>> +               (BLT_RECTANGLE){SourceX, SourceY, Width, Height},
>> +               (BLT_RECTANGLE){DestinationX, DestinationY, Width, Height}
>> +               );
>> +    RegWrite32 (GvtGopPrivate,
>> +      PLANE_SURF(PIPE_A, PLANE_PRIMARY),
>> +      Display->FbGMAddr
>> +      );
>> +    break;
>> +  default:
>> +    GVT_DEBUG (EFI_D_INFO, "Unsupported EFI_GRAPHICS_OUTPUT_BLT_OPERATION %d\n", BltOperation);
>> +    Status = EFI_UNSUPPORTED;
>> +    break;
>> +  }
>> +#else
>> +  switch (BltOperation) {
>> +  case EfiBltVideoToBltBuffer:
>> +  case EfiBltVideoFill:
>> +  case EfiBltBufferToVideo:
>> +  case EfiBltVideoToVideo:
>> +    Status = FrameBufferBlt (
>> +               Display->FrameBufferBltConfigure,
>> +               BltBuffer,
>> +               BltOperation,
>> +               SourceX,
>> +               SourceY,
>> +               DestinationX,
>> +               DestinationY,
>> +               Width,
>> +               Height,
>> +               Delta
>> +               );
>> +    if (BltOperation != EfiBltVideoToBltBuffer) {
>> +      RegWrite32 (GvtGopPrivate,
>> +        PLANE_SURF(PIPE_A, PLANE_PRIMARY),
>> +        Display->FbGMAddr
>> +        );
>> +    }
>> +    break;
>> +  default:
>> +    GVT_DEBUG (EFI_D_INFO, "Unsupported EFI_GRAPHICS_OUTPUT_BLT_OPERATION %d\n", BltOperation);
>> +    Status = EFI_UNSUPPORTED;
>> +    break;
>> +  }
>> +#endif
>> +
>> +  gBS->RestoreTPL (OriginalTPL);
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuEnableDisplay (
>> +  IN OUT GVT_GOP_PRIVATE_DATA *Private,
>> +  IN     UINT32               ModeNumber,
>> +  IN     BOOLEAN              Enable
>> +  )
>> +{
>> +  EFI_STATUS                 Status = EFI_INVALID_PARAMETER;
>> +  PINTEL_VIRTUAL_GPU         VirtualGpu;
>> +  PINTEL_VIRTUAL_GPU_DISPLAY Display;
>> +  UINT32                     Width, Height, Val32;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
>> +  Display = &VirtualGpu->Display;
>> +
>> +  if (ModeNumber >= Display->MaxMode) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Invalid ModeNumber, request %d, max %d, status %d\n",
>> +      ModeNumber, Display->MaxMode, Status
>> +      );
>> +    Status = EFI_INVALID_PARAMETER;
>> +    goto Done;
>> +  }
>> +
>> +  Width = Display->ModeList[ModeNumber].HorizontalResolution;
>> +  Height = Display->ModeList[ModeNumber].VerticalResolution;
>> +
>> +  if (Enable) {
>> +    Display->CurrentMode = ModeNumber;
>> +
>> +    Val32 = (Display->HActive - 1) << 16;
>> +    Val32 |= Display->VActive;
>> +    RegWrite32 (Private, PIPESRC(PIPE_A), Val32);
>> +
>> +    RegRead32 (Private, PIPE_CONF(PIPE_A), &Val32);
>> +    Val32 |= PIPE_CONF_ENABLE;
>> +    RegWrite32 (Private, PIPE_CONF(PIPE_A), Val32);
>> +
>> +    Val32 = (Width - 1) & 0xFFF;
>> +    Val32 |= ((Height - 1) & 0xFFF) << 16;
>> +    RegWrite32 (Private, PLANE_SIZE(PIPE_A, PLANE_PRIMARY), Val32);
>> +    RegWrite32 (Private, PLANE_POS(PIPE_A, PLANE_PRIMARY), 0);
>> +
>> +    // Convert mode with to stride in chunks of 64 bytes as required by PLANE_STRIDE
>> +    Val32 = Display->ModeList[ModeNumber].HorizontalResolution * Display->Bpp;
>> +    Val32 = ALIGN_VALUE (Val32, 64);
>> +    Val32 = (Val32 / 64) & PLANE_STRIDE_MASK;
>> +    RegWrite32 (Private, PLANE_STRIDE(PIPE_A, PLANE_PRIMARY), Val32);
>> +
>> +    RegWrite32 (Private, PLANE_SURF(PIPE_A, PLANE_PRIMARY), Display->FbGMAddr);
>> +
>> +    // Stretch to fullscreen if current mode is smaller than H/V active.
>> +    if (Display->HActive != Width ||
>> +        Display->VActive != Height) {
>> +      RegWrite32 (Private, PS_WIN_POS(PIPE_A, 0), 0);
>> +      RegWrite32 (Private,
>> +        PS_WIN_SZ(PIPE_A, 0),
>> +        Display->HActive << 16 | Display->VActive
>> +        );
>> +      RegRead32 (Private, PS_CTRL(PIPE_A, 0), &Val32);
>> +      Val32 |= PS_CTRL_SCALER_EN;
>> +      Val32 &= ~PS_CTRL_SCALER_MODE_MASK;
>> +      Val32 |= PS_CTRL_SCALER_MODE_DYN;
>> +      Val32 &= ~PS_CTRL_SCALER_BINDING_MASK;
>> +      Val32 |= PS_CTRL_PLANE_SEL(PLANE_PRIMARY);
>> +      Val32 &= ~PS_CTRL_SCALER_FILTER_MASK;
>> +      Val32 |= PS_CTRL_SCALER_FILTER_MEDIUM;
>> +      RegWrite32 (Private, PS_CTRL(PIPE_A, 0), Val32);
>> +    }
>> +
>> +    RegRead32 (Private, PLANE_CTL(PIPE_A, PLANE_PRIMARY), &Val32);
>> +    Val32 |= PLANE_CTL_ENABLE;
>> +    Val32 &= ~PLANE_CTL_PIPE_GAMMA_ENABLE;
>> +    Val32 &= ~PLANE_CTL_FORMAT_MASK;
>> +    Val32 |= PLANE_CTL_FORMAT_XRGB_8888;
>> +    Val32 &= ~PLANE_CTL_PIPE_CSC_ENABLE;
>> +    Val32 &= ~PLANE_CTL_KEY_ENABLE_MASK;
>> +    Val32 &= ~PLANE_CTL_ORDER_RGBX;
>> +    if (Display->ModeList[ModeNumber].PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
>> +      Val32 |= PLANE_CTL_ORDER_RGBX;
>> +    }
>> +    Val32 &= ~PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
>> +    Val32 |= PLANE_CTL_PLANE_GAMMA_DISABLE;
>> +    Val32 &= ~PLANE_CTL_TILED_MASK;
>> +    Val32 |= PLANE_CTL_TILED_LINEAR;
>> +    Val32 &= ~PLANE_CTL_ASYNC_FLIP;
>> +    Val32 &= ~PLANE_CTL_ALPHA_MASK;
>> +    Val32 |= PLANE_CTL_ALPHA_DISABLE;
>> +    Val32 &= ~PLANE_CTL_ROTATE_MASK;
>> +    Val32 |= PLANE_CTL_ROTATE_0;
>> +    RegWrite32 (Private, PLANE_CTL(PIPE_A, PLANE_PRIMARY), Val32);
>> +  } else {
>> +    Display->CurrentMode = DISPLAY_MODE_INVALID;
>> +
>> +    RegRead32 (Private, PLANE_CTL(PIPE_A, PLANE_PRIMARY), &Val32);
>> +    Val32 &= ~PLANE_CTL_ENABLE;
>> +    RegWrite32 (Private, PLANE_CTL(PIPE_A, PLANE_PRIMARY), Val32);
>> +    RegWrite32 (Private, PLANE_SURF(PIPE_A, PLANE_PRIMARY), 0);
>> +
>> +    RegRead32 (Private, PS_CTRL(PIPE_A, 0), &Val32);
>> +    Val32 &= ~PS_CTRL_SCALER_EN;
>> +    RegWrite32 (Private, PS_CTRL(PIPE_A, 0), Val32);
>> +    RegWrite32 (Private, PS_WIN_POS(PIPE_A, 0), 0);
>> +    RegWrite32 (Private, PS_WIN_SZ(PIPE_A, 0), 0);
>> +
>> +    RegRead32 (Private, PIPE_CONF(PIPE_A), &Val32);
>> +    Val32 &= ~PIPE_CONF_ENABLE;
>> +    RegWrite32 (Private, PIPE_CONF(PIPE_A), Val32);
>> +  }
>> +
>> +  Status = EFI_SUCCESS;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: %a mode %dx%d 0x%x, scaling %a\n",
>> +    __FUNCTION__,
>> +    Enable ? "Enable" : "Disable",
>> +    Width,
>> +    Height,
>> +    Display->FbGMAddr,
>> +    (Display->HActive != Width ||
>> +     Display->VActive != Height) ? "On" : "Off");
>> +
>> +Done:
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuNotifyDisplayReady (
>> +  IN GVT_GOP_PRIVATE_DATA *Private,
>> +  IN BOOLEAN              Ready
>> +  )
>> +{
>> +  return RegWrite32 (
>> +           Private,
>> +           vgtif_reg(display_ready),
>> +           Ready ? VGT_DRV_DISPLAY_READY : VGT_DRV_DISPLAY_NOT_READY
>> +           );
>> +}
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuBltVideoFill (
>> +  IN PINTEL_VIRTUAL_GPU_DISPLAY          Display,
>> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION BltPixel,
>> +  IN BLT_RECTANGLE                       Destination
>> +  )
>> +{
>> +  EFI_STATUS Status = EFI_INVALID_PARAMETER;
>> +  VOID       *DestAddr;
>> +  UINTN      DestBytes, ModeStrideBytes, Line;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  if (Destination.Width == 0 || Destination.Height == 0) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "EfiBltVideoFill invalid destination rectangle [%d, %d] \n",
>> +      Destination.Width, Destination.Height
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  if ((Destination.X + Destination.Width > Display->Width) ||
>> +      (Destination.Y + Destination.Height > Display->Height)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "EfiBltVideoFill destination [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
>> +      Destination.X, Destination.Y,
>> +      Destination.X + Destination.Width, Destination.Y + Destination.Height,
>> +      Display->Width, Display->Height
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  if (Display->CurrentMode == DISPLAY_MODE_INVALID) {
>> +    ModeStrideBytes = Display->Width;
>> +  } else {
>> +    ModeStrideBytes = Display->ModeList[Display->CurrentMode].HorizontalResolution;
>> +  }
>> +  ModeStrideBytes = ALIGN_VALUE (ModeStrideBytes * Display->Bpp, 64);
>> +
>> +  if (Destination.Width * Display->Bpp == ModeStrideBytes) {
>> +    DestAddr = (UINT8*)Display->FbGMAddr + Destination.Y * ModeStrideBytes;
>> +    DestBytes = Destination.Width * Display->Bpp * Destination.Height;
>> +    SetMem32 ((VOID*)DestAddr, DestBytes, BltPixel.Raw);
>> +  } else {
>> +
>> +    for (Line = 0; Line < Destination.Height; Line++) {
>> +      DestAddr = (UINT8*)Display->FbGMAddr +
>> +        (Line + Destination.Y) * ModeStrideBytes +
>> +        Destination.X * Display->Bpp;
>> +      DestBytes = Destination.Width * Display->Bpp;
>> +
>> +      SetMem32 (DestAddr, DestBytes, BltPixel.Raw);
>> +    }
>> +  }
>> +
>> +  Status = EFI_SUCCESS;
>> +
>> +Done:
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuBltVideoToBuffer (
>> +  IN PINTEL_VIRTUAL_GPU_DISPLAY    Display,
>> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
>> +  IN BLT_RECTANGLE                 Source,
>> +  IN BLT_RECTANGLE                 Destination,
>> +  IN UINTN                         Delta
>> +  )
>> +{
>> +  EFI_STATUS Status = EFI_INVALID_PARAMETER;
>> +  VOID       *SourceAddr, *DestAddr;
>> +  UINTN      DestStride, CopyBytes, ModeStrideBytes, Line;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  if (Source.Width == 0 || Source.Height == 0) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "EfiBltVideoToBltBuffer invalid source rectangle [%d, %d] \n",
>> +      Source.Width, Source.Height
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  if (Source.Width != Destination.Width ||
>> +      Source.Height != Destination.Height) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "EfiBltVideoToBltBuffer size mismatch: source %dx%d, destination %dx%d\n",
>> +      Source.Width, Source.Height, Destination.Width, Destination.Height
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  if ((Source.X + Source.Width > Display->Width) ||
>> +      (Source.Y + Source.Height > Display->Height)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "EfiBltVideoToBltBuffer source [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
>> +      Source.X, Source.Y,
>> +      Source.X + Source.Width, Source.Y + Source.Height,
>> +      Display->Width, Display->Height
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  if (Destination.X != 0 || Destination.Y != 0) {
>> +    DestStride = Delta;
>> +  } else {
>> +    DestStride = Destination.Width * Display->Bpp;
>> +  }
>> +
>> +  if (Display->CurrentMode == DISPLAY_MODE_INVALID) {
>> +    ModeStrideBytes = Display->Width;
>> +  } else {
>> +    ModeStrideBytes = Display->ModeList[Display->CurrentMode].HorizontalResolution;
>> +  }
>> +  ModeStrideBytes = ALIGN_VALUE (ModeStrideBytes * Display->Bpp, 64);
>> +
>> +  for (Line = 0; Line < Source.Height; Line++) {
>> +    SourceAddr = (UINT8*)Display->FbGMAddr +
>> +      (Source.Y + Line) * ModeStrideBytes +
>> +      Source.X * Display->Bpp;
>> +    DestAddr = (UINT8*)BltBuffer + (Destination.Y + Line) * DestStride;
>> +    DestAddr = (UINT8*)DestAddr + Destination.X * Display->Bpp;
>> +    CopyBytes = Source.Width * Display->Bpp;
>> +    CopyMem (DestAddr, SourceAddr, CopyBytes);
>> +  }
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE,
>> +    "EfiBltVideoToBltBuffer [%d, %d] >> [%d, %d] size [%d, %d] Delta %d\n",
>> +    Source.X, Source.Y,
>> +    Destination.X, Destination.Y,
>> +    Source.Width, Source.Height,
>> +    Delta
>> +    );
>> +
>> +  Status = EFI_SUCCESS;
>> +
>> +Done:
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuBltVideoFromBuffer (
>> +  IN PINTEL_VIRTUAL_GPU_DISPLAY    Display,
>> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
>> +  IN BLT_RECTANGLE                 Source,
>> +  IN BLT_RECTANGLE                 Destination,
>> +  IN UINTN                         Delta
>> +  )
>> +{
>> +  EFI_STATUS Status = EFI_INVALID_PARAMETER;
>> +  VOID       *SourceAddr, *DestAddr;
>> +  UINTN      SourceStride, CopyBytes, ModeStrideBytes, Line;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  if (Source.Width == 0 || Source.Height == 0) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "EfiBltBufferToVideo invalid source rectangle [%d, %d] \n",
>> +      Source.Width, Source.Height
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  if (Source.Width != Destination.Width || Source.Height != Destination.Height) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "EfiBltBufferToVideo size mismatch: source %dx%d, destination %dx%d\n",
>> +      Source.Width, Source.Height, Destination.Width, Destination.Height
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  if ((Destination.X + Destination.Width > Display->Width) ||
>> +      (Destination.Y + Destination.Height > Display->Height)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "EfiBltBufferToVideo destination [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
>> +      Destination.X, Destination.Y,
>> +      Destination.X + Destination.Width, Destination.Y + Destination.Height,
>> +      Display->Width, Display->Height
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  if (Source.X != 0 || Source.Y != 0) {
>> +    SourceStride = Delta;
>> +  } else {
>> +    SourceStride = Source.Width * Display->Bpp;
>> +  }
>> +
>> +  if (Display->CurrentMode == DISPLAY_MODE_INVALID) {
>> +    ModeStrideBytes = Display->Width;
>> +  } else {
>> +    ModeStrideBytes = Display->ModeList[Display->CurrentMode].HorizontalResolution;
>> +  }
>> +  ModeStrideBytes = ALIGN_VALUE (ModeStrideBytes * Display->Bpp, 64);
>> +
>> +  for (Line = 0; Line < Source.Height; Line++) {
>> +    SourceAddr = (UINT8*)BltBuffer +
>> +      (Source.Y + Line) * SourceStride +
>> +      Source.X * Display->Bpp;
>> +    DestAddr = (UINT8*)Display->FbGMAddr +
>> +      (Destination.Y + Line) * ModeStrideBytes +
>> +      Destination.X * Display->Bpp;
>> +    CopyBytes = Source.Width * Display->Bpp;
>> +    CopyMem (DestAddr, SourceAddr, CopyBytes);
>> +  }
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "EfiBltBufferToVideo [%d, %d] >> [%d, %d] size [%d, %d] Delta %d\n",
>> +    Source.X, Source.Y,
>> +    Destination.X, Destination.Y,
>> +    Source.Width, Source.Height,
>> +    Delta
>> +    );
>> +
>> +  Status = EFI_SUCCESS;
>> +
>> +Done:
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuBltVideoToVideo (
>> +  IN PINTEL_VIRTUAL_GPU_DISPLAY Display,
>> +  IN BLT_RECTANGLE              Source,
>> +  IN BLT_RECTANGLE              Destination
>> +  )
>> +{
>> +  EFI_STATUS Status = EFI_INVALID_PARAMETER;
>> +  VOID       *SourceAddr, *DestAddr;
>> +  UINTN      CopyBytes, ModeStrideBytes, Line;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  if (Source.Width == 0 || Source.Height == 0) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "EfiBltVideoToVideo invalid source rectangle [%d, %d] \n",
>> +      Source.Width, Source.Height
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  if (Source.Width != Destination.Width || Source.Height != Destination.Height) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "EfiBltVideoToVideo size mismatch: source %dx%d, destination %dx%d\n",
>> +      Source.Width, Source.Height, Destination.Width, Destination.Height
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  if ((Source.X + Source.Width > Display->Width) ||
>> +      (Source.Y + Source.Height > Display->Height)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "EfiBltVideoToVideo source [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
>> +      Source.X, Source.Y,
>> +      Source.X + Source.Width, Source.Y + Source.Height,
>> +      Display->Width, Display->Height
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  if ((Destination.X + Destination.Width > Display->Width) ||
>> +      (Destination.Y + Destination.Height > Display->Height)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "EfiBltVideoToVideo destination [%d, %d] to [%d, %d] ouf of range [%d, %d]\n",
>> +      Destination.X, Destination.Y,
>> +      Destination.X + Destination.Width, Destination.Y + Destination.Height,
>> +      Display->Width, Display->Height
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  if (Display->CurrentMode == DISPLAY_MODE_INVALID) {
>> +    ModeStrideBytes = Display->Width;
>> +  } else {
>> +    ModeStrideBytes = Display->ModeList[Display->CurrentMode].HorizontalResolution;
>> +  }
>> +  ModeStrideBytes = ALIGN_VALUE (ModeStrideBytes * Display->Bpp, 64);
>> +
>> +  for (Line = 0; Line < Source.Height; Line++) {
>> +    SourceAddr = (UINT8*)Display->FbGMAddr +
>> +      (Source.Y + Line) * ModeStrideBytes +
>> +      Source.X * Display->Bpp;
>> +    DestAddr = (UINT8*)Display->FbGMAddr +
>> +      (Destination.Y + Line)* ModeStrideBytes +
>> +      Destination.X * Display->Bpp;
>> +    CopyBytes = Source.Width * Display->Bpp;
>> +    //
>> +    // Overlap could corrupt source content:
>> +    // src <----|---->
>> +    // dst      <----|---->
>> +    //
>> +    if (DestAddr > SourceAddr && DestAddr < (SourceAddr + CopyBytes)) {
>> +      CopyMem (
>> +        SourceAddr + CopyBytes,
>> +        DestAddr,
>> +        SourceAddr + CopyBytes - DestAddr
>> +        );
>> +      CopyMem (DestAddr, SourceAddr, DestAddr - SourceAddr);
>> +    //
>> +    // Overlap won't corrupt source content:
>> +    // src      <----|---->
>> +    // dst <----|---->
>> +    //
>> +    // No overlap
>> +    // src <--------->
>> +    // dst                         <--------->
>> +    //
>> +    } else {
>> +      CopyMem (DestAddr, SourceAddr, CopyBytes);
>> +    }
>> +  }
>> +
>> +  Status = EFI_SUCCESS;
>> +
>> +Done:
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> diff --git a/OvmfPkg/IntelGvtGopDxe/Display.h b/OvmfPkg/IntelGvtGopDxe/Display.h
>> new file mode 100644
>> index 000000000000..19e4d64f3b12
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/Display.h
>> @@ -0,0 +1,141 @@
>> +/** @file
>> +  Component name for the QEMU video controller.
>> +
>> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef __DISPLAY_H_
>> +#define __DISPLAY_H_
>> +
>> +#include <Library/FrameBufferBltLib.h>
>> +
>> +typedef struct _BLT_RECTANGLE {
>> +  UINTN X;
>> +  UINTN Y;
>> +  UINTN Width;
>> +  UINTN Height;
>> +} BLT_RECTANGLE, *PBLT_RECTANGLE;
>> +
>> +#define DISPLAY_WIDTH_MAX      1920
>> +#define DISPLAY_HEIGHT_MAX     1080
>> +#define DISPLAY_WIDTH_DEFAULT  1024
>> +#define DISPLAY_HEIGHT_DEFAULT 768
>> +#define DISPLAY_MODE_INVALID   0xFFFF
>> +
>> +#define DISPLAY_USE_INTERNAL_BLT 1
>> +
>> +typedef struct _INTEL_VIRTUAL_GPU_DISPLAY {
>> +  UINTN                                HActive;
>> +  UINTN                                VActive;
>> +  UINTN                                Width;
>> +  UINTN                                Height;
>> +  UINTN                                WidthBytes;
>> +  UINTN                                StrideBytes;
>> +  EFI_GRAPHICS_PIXEL_FORMAT            Format;
>> +  UINTN                                Bpp;
>> +  UINTN                                MaxMode;
>> +  UINTN                                CurrentMode;
>> +  UINTN                                FbSize;
>> +  UINTN                                Pages;
>> +  EFI_PHYSICAL_ADDRESS                 FbGMAddr;
>> +  EFI_PHYSICAL_ADDRESS                 FbPhysicalAddr;
>> +  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeList;
>> +  FRAME_BUFFER_CONFIGURE               *FrameBufferBltConfigure;
>> +  UINTN                                FrameBufferBltConfigureSize;
>> +} INTEL_VIRTUAL_GPU_DISPLAY, *PINTEL_VIRTUAL_GPU_DISPLAY;
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuDisplayInit (
>> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
>> +  );
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuDisplayClean (
>> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
>> +  );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +IntelVirtualGpuQueryMode (
>> +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL         *This,
>> +  IN  UINT32                               ModeNumber,
>> +  OUT UINTN                                *SizeOfInfo,
>> +  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
>> +  );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +IntelVirtualGpuSetMode (
>> +  IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
>> +  IN UINT32                       ModeNumber
>> +  );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +IntelVirtualGpuBlt (
>> +  IN EFI_GRAPHICS_OUTPUT_PROTOCOL      *This,
>> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *BltBuffer,   OPTIONAL
>> +  IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
>> +  IN UINTN                             SourceX,
>> +  IN UINTN                             SourceY,
>> +  IN UINTN                             DestinationX,
>> +  IN UINTN                             DestinationY,
>> +  IN UINTN                             Width,
>> +  IN UINTN                             Height,
>> +  IN UINTN                             Delta         OPTIONAL
>> +  );
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuEnableDisplay (
>> +  IN OUT GVT_GOP_PRIVATE_DATA *Private,
>> +  IN     UINT32               ModeNumber,
>> +  IN     BOOLEAN              Enable
>> +  );
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuNotifyDisplayReady (
>> +  IN GVT_GOP_PRIVATE_DATA *Private,
>> +  IN BOOLEAN              Ready
>> +  );
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuBltVideoFill (
>> +  IN PINTEL_VIRTUAL_GPU_DISPLAY          Display,
>> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION BltPixel,
>> +  IN BLT_RECTANGLE                       Destination
>> +  );
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuBltVideoToBuffer (
>> +  IN PINTEL_VIRTUAL_GPU_DISPLAY    Display,
>> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
>> +  IN BLT_RECTANGLE                 Source,
>> +  IN BLT_RECTANGLE                 Destination,
>> +  IN UINTN                         Delta
>> +  );
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuBltVideoFromBuffer (
>> +  IN PINTEL_VIRTUAL_GPU_DISPLAY    Display,
>> +  IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
>> +  IN BLT_RECTANGLE                 Source,
>> +  IN BLT_RECTANGLE                 Destination,
>> +  IN UINTN                         Delta
>> +  );
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuBltVideoToVideo (
>> +  IN PINTEL_VIRTUAL_GPU_DISPLAY Display,
>> +  IN BLT_RECTANGLE              Source,
>> +  IN BLT_RECTANGLE              Destination
>> +  );
>> +VOID
>> +InstallVbeShim (
>> +  IN CONST CHAR16         *CardName,
>> +  IN EFI_PHYSICAL_ADDRESS FrameBufferBase
>> +  );
>> +
>> +#endif //__DISPLAY_H_
>> diff --git a/OvmfPkg/IntelGvtGopDxe/GopDriver.c b/OvmfPkg/IntelGvtGopDxe/GopDriver.c
>> new file mode 100644
>> index 000000000000..396e5cf4447c
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/GopDriver.c
>> @@ -0,0 +1,478 @@
>> +/** @file
>> +  Component name for the QEMU video controller.
>> +
>> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include "Common.h"
>> +#include "VirtualGpu.h"
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GvtGopComponentNameGetDriverName (
>> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
>> +  IN  CHAR8                        *Language,
>> +  OUT CHAR16                       **DriverName
>> +  );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GvtGopComponentNameGetControllerName (
>> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
>> +  IN  EFI_HANDLE                  ControllerHandle,
>> +  IN  EFI_HANDLE                  ChildHandle OPTIONAL,
>> +  IN  CHAR8                       *Language,
>> +  OUT CHAR16                      **ControllerName
>> +  );
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED
>> +EFI_COMPONENT_NAME_PROTOCOL gGvtGopDriverComponentName = {
>> +  GvtGopComponentNameGetDriverName,
>> +  GvtGopComponentNameGetControllerName,
>> +  "eng"
>> +};
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED
>> +EFI_COMPONENT_NAME2_PROTOCOL gGvtGopDriverComponentName2 = {
>> +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GvtGopComponentNameGetDriverName,
>> +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GvtGopComponentNameGetControllerName,
>> +  "en"
>> +};
>> +
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED
>> +EFI_UNICODE_STRING_TABLE gGvtGopDriverNameTable[] = {
>> +  { "eng;en", L"Intel GVT-g GOP Driver" },
>> +  { NULL , NULL }
>> +};
>> +
>> +GLOBAL_REMOVE_IF_UNREFERENCED
>> +EFI_UNICODE_STRING_TABLE gGvtGopControllerNameTable[] = {
>> +  { "eng;en", L"Intel GVT-g Virtual GPU PCI Adapter" },
>> +  { NULL , NULL }
>> +};
>> +
>> +STATIC
>> +EFI_STATUS
>> +EFIAPI
>> +GvtGopBindingSupported (
>> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> +  IN EFI_HANDLE                  ControllerHandle,
>> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
>> +  )
>> +{
>> +  EFI_STATUS          Status;
>> +  EFI_PCI_IO_PROTOCOL *PciIo;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  Status = gBS->OpenProtocol (
>> +                  ControllerHandle,
>> +                  &gEfiPciIoProtocolGuid,
>> +                  (VOID **) &PciIo,
>> +                  This->DriverBindingHandle,
>> +                  ControllerHandle,
>> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_VERBOSE,
>> +      "OpenProtocol gEfiPciIoProtocolGuid failed with %d\n", Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  Status = IntelVirtualGpuActive (PciIo);
>> +
>> +  gBS->CloseProtocol (
>> +        ControllerHandle,
>> +        &gEfiPciIoProtocolGuid,
>> +        This->DriverBindingHandle,
>> +        ControllerHandle
>> +        );
>> +
>> +Done:
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +  return Status;
>> +}
>> +
>> +
>> +STATIC
>> +EFI_STATUS
>> +EFIAPI
>> +GvtGopBindingStart (
>> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
>> +  IN EFI_HANDLE                  ControllerHandle,
>> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
>> +  )
>> +{
>> +  EFI_STATUS               Status;
>> +  EFI_TPL                  OriginalTPL;
>> +  GVT_GOP_PRIVATE_DATA     *GvtGopPrivate = NULL;
>> +  UINT64                   PciAttr;
>> +  EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
>> +  ACPI_ADR_DEVICE_PATH     AcpiDeviceNode;
>> +  EFI_PCI_IO_PROTOCOL      *ChildPciIo;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  OriginalTPL = gBS->RaiseTPL (TPL_CALLBACK);
>> +
>> +  Status = gBS->AllocatePool (
>> +                  EfiBootServicesData,
>> +                  sizeof(GVT_GOP_PRIVATE_DATA),
>> +                  (VOID **)&GvtGopPrivate
>> +                  );
>> +  if (EFI_ERROR (Status) || GvtGopPrivate == NULL) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "AllocatePool failed for GVT_GOP_PRIVATE_DATA, size %d, status %d\n",
>> +      sizeof(GVT_GOP_PRIVATE_DATA), Status
>> +      );
>> +    Status = EFI_OUT_OF_RESOURCES;
>> +    goto Done;
>> +  }
>> +
>> +  ZeroMem (GvtGopPrivate, sizeof(GVT_GOP_PRIVATE_DATA));
>> +  GvtGopPrivate->Signature = GVT_GOP_MAGIC;
>> +
>> +  Status = gBS->AllocatePool (
>> +                  EfiBootServicesData,
>> +                  sizeof(INTEL_VIRTUAL_GPU),
>> +                  &GvtGopPrivate->VirtualGpu
>> +                  );
>> +  if (EFI_ERROR (Status) || GvtGopPrivate->VirtualGpu == NULL) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "AllocatePool failed for INTEL_VIRTUAL_GPU, size %d, status %d\n",
>> +      sizeof(INTEL_VIRTUAL_GPU), Status
>> +      );
>> +    Status = EFI_OUT_OF_RESOURCES;
>> +    goto Free;
>> +  }
>> +  ZeroMem (GvtGopPrivate->VirtualGpu, sizeof(INTEL_VIRTUAL_GPU));
>> +
>> +  Status = gBS->OpenProtocol (
>> +                  ControllerHandle,
>> +                  &gEfiPciIoProtocolGuid,
>> +                  (VOID **) &GvtGopPrivate->PciIo,
>> +                  This->DriverBindingHandle,
>> +                  ControllerHandle,
>> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Can't open protocol gEfiPciIoProtocolGuid, status %d\n", Status
>> +      );
>> +    goto Free;
>> +  }
>> +
>> +  Status = GvtGopPrivate->PciIo->Attributes (
>> +                                   GvtGopPrivate->PciIo,
>> +                                   EfiPciIoAttributeOperationGet,
>> +                                   0,
>> +                                   &GvtGopPrivate->OriginalPciAttr
>> +                                   );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Failed EfiPciIoAttributeOperationGet, status %d\n", Status
>> +      );
>> +    goto Free;
>> +  }
>> +
>> +  PciAttr = EFI_PCI_DEVICE_ENABLE;
>> +  Status = GvtGopPrivate->PciIo->Attributes (
>> +                                   GvtGopPrivate->PciIo,
>> +                                   EfiPciIoAttributeOperationEnable,
>> +                                   PciAttr,
>> +                                   NULL);
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Failed EfiPciIoAttributeOperationEnable %llx, status %d\n", PciAttr,
>> +      Status
>> +      );
>> +    goto Free;
>> +  }
>> +
>> +  Status = IntelVirtualGpuInit (GvtGopPrivate);
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR, "Failed IntelVirtualGpuInit, status %d\n", Status);
>> +    goto Free;
>> +  }
>> +
>> +  Status = gBS->HandleProtocol (
>> +                  ControllerHandle,
>> +                  &gEfiDevicePathProtocolGuid,
>> +                  (VOID **) &ParentDevicePath
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR, "Fail gEfiDevicePathProtocolGuid, status %d\n",
>> +      Status
>> +      );
>> +    goto Free;
>> +  }
>> +
>> +  ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
>> +  AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
>> +  AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
>> +  AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL, 0, 0);
>> +  SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
>> +  GvtGopPrivate->GopDevPath = AppendDevicePathNode (
>> +                                ParentDevicePath,
>> +                                (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
>> +                                );
>> +  if (GvtGopPrivate->GopDevPath == NULL) {
>> +    Status = EFI_OUT_OF_RESOURCES;
>> +    GVT_DEBUG (EFI_D_ERROR, "Fail AppendDevicePathNode, status %d\n", Status);
>> +    goto Free;
>> +  }
>> +
>> +  Status = gBS->InstallMultipleProtocolInterfaces (
>> +                  &GvtGopPrivate->Handle,
>> +                  &gEfiDevicePathProtocolGuid,
>> +                  GvtGopPrivate->GopDevPath,
>> +                  NULL
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Can't install protocol gEfiDevicePathProtocolGuid, status %d\n",
>> +      Status
>> +      );
>> +    goto Free;
>> +  }
>> +
>> +  Status = gBS->InstallMultipleProtocolInterfaces (
>> +                  &GvtGopPrivate->Handle,
>> +                  &gEfiGraphicsOutputProtocolGuid,
>> +                  &GvtGopPrivate->GraphicsOutputProtocol,
>> +                  NULL
>> +                  );
>> +
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Can't install protocol gEfiGraphicsOutputProtocolGuid, status %d\n",
>> +      Status
>> +      );
>> +    goto Free;
>> +  }
>> +
>> +  Status = gBS->OpenProtocol (
>> +                ControllerHandle,
>> +                &gEfiPciIoProtocolGuid,
>> +                (VOID **) &ChildPciIo,
>> +                This->DriverBindingHandle,
>> +                GvtGopPrivate->Handle,
>> +                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
>> +                );
>> +  if (EFI_ERROR (Status)) {
>> +    goto Free;
>> +  }
>> +
>> +  goto Done;
>> +
>> +Free:
>> +  if (GvtGopPrivate->PciIo) {
>> +    if (GvtGopPrivate->OriginalPciAttr) {
>> +      GvtGopPrivate->PciIo->Attributes (
>> +                              GvtGopPrivate->PciIo,
>> +                              EfiPciIoAttributeOperationEnable,
>> +                              GvtGopPrivate->OriginalPciAttr,
>> +                              NULL
>> +                              );
>> +    }
>> +    gBS->CloseProtocol (
>> +           ControllerHandle,
>> +           &gEfiPciIoProtocolGuid,
>> +           This->DriverBindingHandle,
>> +           ControllerHandle
>> +           );
>> +    GvtGopPrivate->PciIo = NULL;
>> +  }
>> +
>> +  if (GvtGopPrivate->VirtualGpu) {
>> +    gBS->FreePool (GvtGopPrivate->VirtualGpu);
>> +    GvtGopPrivate->VirtualGpu = NULL;
>> +  }
>> +
>> +  if (GvtGopPrivate) {
>> +    gBS->FreePool (GvtGopPrivate);
>> +  }
>> +
>> +  if (GvtGopPrivate->GopDevPath) {
>> +    FreePool (GvtGopPrivate->GopDevPath);
>> +    GvtGopPrivate->GopDevPath = NULL;
>> +  }
>> +
>> +Done:
>> +
>> +  gBS->RestoreTPL (OriginalTPL);
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> +
>> +
>> +STATIC
>> +EFI_STATUS
>> +EFIAPI
>> +GvtGopBindingStop (
>> +  IN  EFI_DRIVER_BINDING_PROTOCOL *This,
>> +  IN  EFI_HANDLE                  ControllerHandle,
>> +  IN  UINTN                       NumberOfChildren,
>> +  IN  EFI_HANDLE                  *ChildHandleBuffer OPTIONAL
>> +  )
>> +{
>> +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol;
>> +  EFI_STATUS                   Status;
>> +  GVT_GOP_PRIVATE_DATA         *GvtGopPrivate = NULL;
>> +
>> +  GVT_DEBUG (EFI_D_INFO, "%a: >>>\n", __FUNCTION__);
>> +
>> +  Status = gBS->OpenProtocol (
>> +                  ControllerHandle,
>> +                  &gEfiGraphicsOutputProtocolGuid,
>> +                  (VOID **)&GraphicsOutputProtocol,
>> +                  This->DriverBindingHandle,
>> +                  ControllerHandle,
>> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    Status = EFI_NOT_STARTED;
>> +    goto Done;
>> +  }
>> +
>> +  GvtGopPrivate = GVT_GOP_PRIVATE_DATA_FROM_THIS (GraphicsOutputProtocol);
>> +  if (!GvtGopPrivate) {
>> +    Status = EFI_NOT_STARTED;
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Intel GVT-g GOP isn't started, status %d\n", Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  gBS->UninstallMultipleProtocolInterfaces (
>> +         GvtGopPrivate->Handle,
>> +         &gEfiGraphicsOutputProtocolGuid,
>> +         &GvtGopPrivate->GraphicsOutputProtocol,
>> +         NULL
>> +         );
>> +
>> +  if (GvtGopPrivate->PciIo) {
>> +    gBS->CloseProtocol (
>> +           ControllerHandle,
>> +           &gEfiPciIoProtocolGuid,
>> +           This->DriverBindingHandle,
>> +           ControllerHandle
>> +           );
>> +    GvtGopPrivate->PciIo = NULL;
>> +  }
>> +
>> +  Status = IntelVirtualGpuClean (GvtGopPrivate);
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR, "Fail to clean virtual GPU, status %d\n", Status);
>> +    goto Done;
>> +  }
>> +
>> +  if (GvtGopPrivate->VirtualGpu) {
>> +    gBS->FreePool (GvtGopPrivate->VirtualGpu);
>> +    GvtGopPrivate->VirtualGpu = NULL;
>> +  }
>> +
>> +  if (GvtGopPrivate) {
>> +    gBS->FreePool (GvtGopPrivate);
>> +  }
>> +
>> +Done:
>> +
>> +  GVT_DEBUG (EFI_D_INFO, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> +
>> +STATIC EFI_DRIVER_BINDING_PROTOCOL gGvtGopDriverBinding = {
>> +  GvtGopBindingSupported,
>> +  GvtGopBindingStart,
>> +  GvtGopBindingStop,
>> +  0x10,
>> +  NULL,
>> +  NULL
>> +};
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GvtGopComponentNameGetDriverName (
>> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
>> +  IN  CHAR8                        *Language,
>> +  OUT CHAR16                       **DriverName
>> +  )
>> +{
>> +  return LookupUnicodeString2 (
>> +           Language,
>> +           This->SupportedLanguages,
>> +           gGvtGopDriverNameTable,
>> +           DriverName,
>> +           (BOOLEAN)(This == &gGvtGopDriverComponentName)
>> +           );
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GvtGopComponentNameGetControllerName (
>> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
>> +  IN  EFI_HANDLE                  ControllerHandle,
>> +  IN  EFI_HANDLE                  ChildHandle OPTIONAL,
>> +  IN  CHAR8                       *Language,
>> +  OUT CHAR16                      **ControllerName
>> +  )
>> +{
>> +  EFI_STATUS Status;
>> +
>> +  if (ChildHandle != NULL) {
>> +    return EFI_UNSUPPORTED;
>> +  }
>> +
>> +  Status = EfiTestManagedDevice (
>> +             ControllerHandle,
>> +             gGvtGopDriverBinding.DriverBindingHandle,
>> +             &gEfiPciIoProtocolGuid
>> +             );
>> +  if (EFI_ERROR (Status)) {
>> +    return Status;
>> +  }
>> +
>> +  return LookupUnicodeString2 (
>> +           Language,
>> +           This->SupportedLanguages,
>> +           gGvtGopControllerNameTable,
>> +           ControllerName,
>> +           (BOOLEAN)(This == &gGvtGopDriverComponentName)
>> +           );
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +GvtGopEntryPoint (
>> +  IN EFI_HANDLE       ImageHandle,
>> +  IN EFI_SYSTEM_TABLE *SystemTable
>> +  )
>> +{
>> +  EFI_STATUS Status;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  Status = EfiLibInstallDriverBindingComponentName2 (
>> +             ImageHandle,
>> +             SystemTable,
>> +             &gGvtGopDriverBinding,
>> +             ImageHandle,
>> +             &gGvtGopDriverComponentName,
>> +             &gGvtGopDriverComponentName2);
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR, "Failed to install driver %d : %d\n", Status);
>> +  }
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> diff --git a/OvmfPkg/IntelGvtGopDxe/GpuReg.c b/OvmfPkg/IntelGvtGopDxe/GpuReg.c
>> new file mode 100644
>> index 000000000000..778c09d5198c
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/GpuReg.c
>> @@ -0,0 +1,91 @@
>> +/** @file
>> +  Component name for the QEMU video controller.
>> +
>> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include "GpuReg.h"
>> +
>> +EFI_STATUS
>> +RegRead32 (
>> +  IN  GVT_GOP_PRIVATE_DATA *Private,
>> +  IN  UINT32 Offset,
>> +  OUT UINT32 *ValuePtr
>> +  )
>> +{
>> +  EFI_STATUS Status = EFI_INVALID_PARAMETER;
>> +
>> +  if (Offset < MMIO_SIZE && ValuePtr != NULL) {
>> +    Status = Private->PciIo->Mem.Read (
>> +                          Private->PciIo,
>> +                          EfiPciIoWidthUint32,
>> +                          PCI_BAR_IDX0,
>> +                          Offset,
>> +                          1,
>> +                          ValuePtr
>> +                          );
>> +    if (EFI_ERROR (Status)) {
>> +      GVT_DEBUG (EFI_D_ERROR, "%a reg %x, value %x, status %d\n",
>> +        __FUNCTION__, Offset, *ValuePtr, Status
>> +        );
>> +    } else {
>> +      Status = EFI_SUCCESS;
>> +      GVT_DEBUG (EFI_D_VERBOSE, "%a reg %x, value %x, status %d\n",
>> +        __FUNCTION__, Offset, *ValuePtr, Status
>> +        );
>> +    }
>> +  } else {
>> +    Status = EFI_INVALID_PARAMETER;
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "%a invalid reg %x or ValuePtr %p, status %d\n",
>> +      __FUNCTION__, Offset, ValuePtr, Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +Done:
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +RegWrite32 (
>> +  IN GVT_GOP_PRIVATE_DATA *Private,
>> +  IN UINT32 Offset,
>> +  IN UINT32 Value
>> +  )
>> +{
>> +  EFI_STATUS Status = EFI_INVALID_PARAMETER;
>> +
>> +  if (Offset < MMIO_SIZE) {
>> +    Status = Private->PciIo->Mem.Write (
>> +                          Private->PciIo,
>> +                          EfiPciIoWidthUint32,
>> +                          PCI_BAR_IDX0,
>> +                          Offset,
>> +                          1,
>> +                          &Value
>> +                          );
>> +    if (EFI_ERROR (Status)) {
>> +      GVT_DEBUG (EFI_D_ERROR, "%a reg %x, value %x, status %d\n",
>> +        __FUNCTION__, Offset, Value, Status
>> +        );
>> +    } else {
>> +      Status = EFI_SUCCESS;
>> +      GVT_DEBUG (EFI_D_VERBOSE, "%a reg %x, value %x, status %d\n",
>> +        __FUNCTION__, Offset, Value, Status
>> +        );
>> +    }
>> +  } else {
>> +    Status = EFI_INVALID_PARAMETER;
>> +    GVT_DEBUG (EFI_D_ERROR, "%a invalid reg %x, status %d\n",
>> +      __FUNCTION__, Offset, Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +Done:
>> +  return Status;
>> +}
>> diff --git a/OvmfPkg/IntelGvtGopDxe/GpuReg.h b/OvmfPkg/IntelGvtGopDxe/GpuReg.h
>> new file mode 100644
>> index 000000000000..f46f4cef9cd4
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/GpuReg.h
>> @@ -0,0 +1,175 @@
>> +/** @file
>> +  Component name for the QEMU video controller.
>> +
>> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef __GPUREG_H_
>> +#define __GPUREG_H_
>> +
>> +#include "Common.h"
>> +
>> +#define MMIO_SIZE 0x200000
>> +
>> +#define VGT_PVINFO_PAGE 0x78000
>> +#define VGT_PVINFO_SIZE 0x1000
>> +
>> +#define VGT_MAGIC         0x4776544776544776ULL  /* 'vGTvGTvG' */
>> +#define VGT_VERSION_MAJOR 1
>> +#define VGT_VERSION_MINOR 0
>> +
>> +#define VGT_DRV_DISPLAY_NOT_READY 0
>> +#define VGT_DRV_DISPLAY_READY     1
>> +
>> +struct vgt_if {
>> +  UINT64 magic;    /* VGT_MAGIC */
>> +  UINT16 version_major;
>> +  UINT16 version_minor;
>> +  UINT32 vgt_id;    /* ID of vGT instance */
>> +  UINT32 vgt_caps;    /* VGT capabilities */
>> +  UINT32 rsv1[11];    /* pad to offset 0x40 */
>> +  /*
>> +   *  Data structure to describe the balooning info of resources.
>> +   *  Each VM can only have one portion of continuous area for now.
>> +   *  (May support scattered resource in future)
>> +   *  (starting from offset 0x40)
>> +   */
>> +  struct {
>> +    /* Aperture register balooning */
>> +    struct {
>> +      UINT32 base;
>> +      UINT32 size;
>> +    } mappable_gmadr;  /* aperture */
>> +    /* GMADR register balooning */
>> +    struct {
>> +      UINT32 base;
>> +      UINT32 size;
>> +    } nonmappable_gmadr;  /* non aperture */
>> +    /* allowed fence registers */
>> +    UINT32 fence_num;
>> +    UINT32 rsv2[3];
>> +  } avail_rs;    /* available/assigned resource */
>> +  UINT32 rsv3[0x200 - 24];  /* pad to half page */
>> +  /*
>> +   * The bottom half page is for response from Gfx driver to hypervisor.
>> +   */
>> +  UINT32 rsv4;
>> +  UINT32 display_ready;  /* ready for display owner switch */
>> +
>> +  UINT32 rsv5[4];
>> +
>> +  UINT32 g2v_notify;
>> +  UINT32 rsv6[5];
>> +
>> +  UINT32 cursor_x_hot;
>> +  UINT32 cursor_y_hot;
>> +
>> +  struct {
>> +    UINT32 lo;
>> +    UINT32 hi;
>> +  } pdp[4];
>> +
>> +  UINT32 execlist_context_descriptor_lo;
>> +  UINT32 execlist_context_descriptor_hi;
>> +
>> +  UINT32  rsv7[0x200 - 24];    /* pad to one page */
>> +} PACKED;
>> +
>> +#define vgtif_offset(x) (OFFSET_OF(struct vgt_if, x))
>> +#define vgtif_reg(x) (VGT_PVINFO_PAGE + vgtif_offset(x))
>> +
>> +typedef enum _GPU_DISPLAY_PIPE {
>> +  PIPE_INVALID = -1,
>> +  PIPE_A = 0,
>> +  PIPE_B,
>> +  PIPE_C,
>> +  PIPE_MAX = PIPE_C
>> +} GPU_DISPLAY_PIPE;
>> +
>> +typedef enum _GPU_DISPLAY_PLANE {
>> +  PLANE_PRIMARY = 0,
>> +  PLANE_SPRITE0,
>> +  PLANE_SPRITE1,
>> +  PLANE_MAX,
>> +} GPU_DISPLAY_PLANE;
>> +
>> +#define _TRANS_HTOTAL_A 0x60000
>> +#define _TRANS_VTOTAL_A 0x6000C
>> +#define _TRANS_REG_OFFSET(trans) (trans * 0x1000)
>> +
>> +#define _PS_WIN_POS_1_A 0x68170
>> +#define _PS_WIN_SZ_1_A 0x68174
>> +#define _PS_CTRL_1_A 0x68180
>> +#define _PS_REG_OFFSET(pipe, id) (pipe * 0x800 + id * 0x100)
>> +#define PS_WIN_POS(pipe, id) (_PS_WIN_POS_1_A + _PS_REG_OFFSET(pipe, id))
>> +#define PS_WIN_SZ(pipe, id) (_PS_WIN_SZ_1_A + _PS_REG_OFFSET(pipe, id))
>> +#define PS_CTRL(pipe, id) (_PS_CTRL_1_A + _PS_REG_OFFSET(pipe, id))
>> +#define   PS_CTRL_SCALER_EN (1 << 31)
>> +#define   PS_CTRL_SCALER_MODE_MASK (0x3 << 28)
>> +#define   PS_CTRL_SCALER_MODE_DYN  (0 << 28)
>> +#define   PS_CTRL_SCALER_MODE_HQ  (1 << 28)
>> +#define   PS_CTRL_SCALER_BINDING_MASK  (0x7 << 25)
>> +#define   PS_CTRL_SCALER_BINDING_PIPE  (0 << 25)
>> +#define   PS_CTRL_PLANE_SEL(plane) (((plane) + 1) << 25)
>> +#define   PS_CTRL_SCALER_FILTER_MASK         (3 << 23)
>> +#define   PS_CTRL_SCALER_FILTER_MEDIUM       (0 << 23)
>> +
>> +#define PIPE_REG_OFFSET(pipe) (pipe * 0x1000)
>> +#define _PIPE_CONF_A 0x70008
>> +#define   PIPE_CONF_ENABLE (1 << 31)
>> +#define _PIPE_SRCSZ_A 0x6001C
>> +#define PIPE_CONF(pipe) (_PIPE_CONF_A + PIPE_REG_OFFSET(pipe))
>> +#define PIPESRC(pipe) (_PIPE_SRCSZ_A + PIPE_REG_OFFSET(pipe))
>> +
>> +#define _PLANE_CTL_1_A 0x70180
>> +#define   PLANE_CTL_ENABLE (1 << 31)
>> +#define   PLANE_CTL_PIPE_GAMMA_ENABLE (1 << 30)
>> +#define   PLANE_CTL_FORMAT_MASK (0xF << 24)
>> +#define   PLANE_CTL_FORMAT_XRGB_8888 (0x4 << 24)
>> +#define   PLANE_CTL_PIPE_CSC_ENABLE (1 << 23)
>> +#define   PLANE_CTL_KEY_ENABLE_MASK (0x3 << 21)
>> +#define   PLANE_CTL_ORDER_RGBX (1 << 20)
>> +#define   PLANE_CTL_RENDER_DECOMPRESSION_ENABLE (1 << 15)
>> +#define   PLANE_CTL_PLANE_GAMMA_DISABLE (1 << 13)
>> +#define   PLANE_CTL_TILED_MASK (0x7 << 10)
>> +#define   PLANE_CTL_TILED_LINEAR (0 << 10)
>> +#define   PLANE_CTL_ASYNC_FLIP (1 << 9)
>> +#define   PLANE_CTL_ALPHA_MASK (0x3 << 4)
>> +#define   PLANE_CTL_ALPHA_DISABLE (0 << 4)
>> +#define   PLANE_CTL_ROTATE_MASK (0x3 << 0)
>> +#define   PLANE_CTL_ROTATE_0 (0x0 << 0)
>> +
>> +#define _PLANE_STRIDE_1_A 0x70188
>> +#define   PLANE_STRIDE_MASK 0x1FF
>> +#define _PLANE_POS_1_A  0x7018C
>> +#define _PLANE_SIZE_1_A 0x70190
>> +#define _PLANE_SURF_1_A 0x7019C
>> +#define _PLANE_REG_OFFSET(pipe, plane) (pipe * 0x1000 + plane * 0x100)
>> +
>> +#define HTOTAL(trans) (_TRANS_HTOTAL_A + _TRANS_REG_OFFSET(trans))
>> +#define VTOTAL(trans) (_TRANS_VTOTAL_A + _TRANS_REG_OFFSET(trans))
>> +
>> +#define PLANE_CTL(pipe, plane) (_PLANE_CTL_1_A + _PLANE_REG_OFFSET(pipe, plane))
>> +#define PLANE_STRIDE(pipe, plane) (_PLANE_STRIDE_1_A + _PLANE_REG_OFFSET(pipe, plane))
>> +#define PLANE_POS(pipe, plane) (_PLANE_POS_1_A + _PLANE_REG_OFFSET(pipe, plane))
>> +#define PLANE_SIZE(pipe, plane) (_PLANE_SIZE_1_A + _PLANE_REG_OFFSET(pipe, plane))
>> +#define PLANE_SURF(pipe, plane) (_PLANE_SURF_1_A + _PLANE_REG_OFFSET(pipe, plane))
>> +
>> +EFI_STATUS
>> +RegRead32 (
>> +  IN  GVT_GOP_PRIVATE_DATA *Private,
>> +  IN  UINT32 Offset,
>> +  OUT UINT32 *ValuePtr
>> +  );
>> +
>> +EFI_STATUS
>> +RegWrite32 (
>> +  IN GVT_GOP_PRIVATE_DATA *Private,
>> +  IN UINT32 Offset,
>> +  IN UINT32 Value
>> +  );
>> +
>> +#endif //__GPUREG_H_
>> diff --git a/OvmfPkg/IntelGvtGopDxe/Gtt.c b/OvmfPkg/IntelGvtGopDxe/Gtt.c
>> new file mode 100644
>> index 000000000000..12782eb5afaa
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/Gtt.c
>> @@ -0,0 +1,162 @@
>> +/** @file
>> +  Component name for the QEMU video controller.
>> +
>> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include "Common.h"
>> +#include "Gtt.h"
>> +#include "VirtualGpu.h"
>> +
>> +EFI_STATUS
>> +GGTTGetEntry (
>> +  IN  GVT_GOP_PRIVATE_DATA *Private,
>> +  IN  UINT64 Index,
>> +  OUT GTT_PTE_ENTRY *Entry
>> +  )
>> +{
>> +  EFI_STATUS          Status = EFI_INVALID_PARAMETER;
>> +  EFI_PCI_IO_PROTOCOL *PciIo;
>> +  PINTEL_VIRTUAL_GPU  VirtualGpu;
>> +
>> +  if (Entry == NULL) {
>> +    Status = EFI_INVALID_PARAMETER;
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "%a invalid GGTT entry ptr %p at Index %x, status %d\n",
>> +      __FUNCTION__, Entry, Index, Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  PciIo = Private->PciIo;
>> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
>> +
>> +  if (Index >= VirtualGpu->VisibleGGTTOffset &&
>> +       Index < VirtualGpu->VisibleGGTTOffset + VirtualGpu->VisibleGGTTSize) {
>> +    Status = PciIo->Mem.Read (
>> +                          PciIo,
>> +                          EfiPciIoWidthUint64,
>> +                          PCI_BAR_IDX0,
>> +                          GTT_OFFSET + Index * GTT_ENTRY_SIZE,
>> +                          1,
>> +                          Entry
>> +                          );
>> +    if (EFI_ERROR (Status)) {
>> +      Entry = 0;
>> +      GVT_DEBUG (EFI_D_ERROR,
>> +        "Failed to Get GGTT Entry index %lx, status %d\n", Index, Status
>> +        );
>> +    }
>> +  } else if (Index >= VirtualGpu->InvisibleGGTTOffset &&
>> +             Index < VirtualGpu->InvisibleGGTTOffset + VirtualGpu->InvisibleGGTTSize) {
>> +    Status = EFI_UNSUPPORTED;
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Skip get GGTT index %lx for invisible GMADR\n", Index
>> +      );
>> +  } else {
>> +    Status = EFI_OUT_OF_RESOURCES;
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Skip get GGTT index %lx out-of-range, balloon unsupported\n",
>> +      Index
>> +      );
>> +  }
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "Get GGTT Entry %lx at index %lx\n", *Entry, Index);
>> +
>> +Done:
>> +
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +GGTTSetEntry (
>> +  IN GVT_GOP_PRIVATE_DATA *Private,
>> +  IN UINT64 Index,
>> +  IN GTT_PTE_ENTRY Entry
>> +  )
>> +{
>> +  EFI_STATUS          Status = EFI_INVALID_PARAMETER;
>> +  EFI_PCI_IO_PROTOCOL *PciIo;
>> +  PINTEL_VIRTUAL_GPU  VirtualGpu;
>> +
>> +  PciIo = Private->PciIo;
>> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
>> +
>> +  if (Index >= VirtualGpu->VisibleGGTTOffset &&
>> +      Index < VirtualGpu->VisibleGGTTOffset + VirtualGpu->VisibleGGTTSize) {
>> +    Status = PciIo->Mem.Write (
>> +                          PciIo,
>> +                          EfiPciIoWidthUint64,
>> +                          PCI_BAR_IDX0,
>> +                          GTT_OFFSET + Index * GTT_ENTRY_SIZE,
>> +                          1,
>> +                          &Entry
>> +                          );
>> +    if (EFI_ERROR (Status)) {
>> +      GVT_DEBUG (EFI_D_ERROR,
>> +        "Failed to Set GGTT Entry %lx at index %lx, status %d\n",
>> +        Entry, Index, Status
>> +        );
>> +    }
>> +  } else if (Index >= VirtualGpu->InvisibleGGTTOffset &&
>> +             Index < VirtualGpu->InvisibleGGTTOffset + VirtualGpu->InvisibleGGTTSize) {
>> +    Status = EFI_UNSUPPORTED;
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Skip set GGTT index %lx for invisible GMADR\n", Index
>> +      );
>> +  } else {
>> +    Status = EFI_OUT_OF_RESOURCES;
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Skip set GGTT index %lx out-of-range, balloon unsupported\n", Index
>> +      );
>> +  }
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "Set GGTT Entry %lx at index %lx\n", Entry, Index);
>> +
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +UpdateGGTT (
>> +  IN GVT_GOP_PRIVATE_DATA *Private,
>> +  IN EFI_PHYSICAL_ADDRESS GMAddr,
>> +  IN EFI_PHYSICAL_ADDRESS SysAddr,
>> +  IN UINTN                Pages
>> +  )
>> +{
>> +  EFI_STATUS         Status = EFI_INVALID_PARAMETER;
>> +  PINTEL_VIRTUAL_GPU VirtualGpu;
>> +  UINTN              GttOffset, Index;
>> +  GTT_PTE_ENTRY      Entry;
>> +
>> +  if (!IS_ALIGNED(SysAddr, GTT_PAGE_SIZE)) {
>> +    Status = EFI_INVALID_PARAMETER;
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Failed to update GGTT GMADR %lx, SysAddr %lx isn't aligned to 0x%lx, status %d\n",
>> +      GMAddr, SysAddr, GTT_PAGE_SIZE, Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
>> +  GttOffset = (GMAddr - VirtualGpu->GpuMemAddr) >> GTT_PAGE_SHIFT;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE,
>> +    "Update GGTT GMADR %lx, SysAddr %lx, Pages 0x%lx\n",
>> +    GMAddr, SysAddr, Pages
>> +    );
>> +  for (Index = 0; Index < Pages; Index++) {
>> +    Entry = SysAddr + Index * GTT_PAGE_SIZE;
>> +    Entry |= (GTT_PAGE_PRESENT | GTT_PAGE_READ_WRITE);
>> +    Entry |= (GTT_PAGE_PWT | GTT_PAGE_PCD);
>> +    GGTTSetEntry (Private, GttOffset + Index, Entry);
>> +  }
>> +
>> +  Status = EFI_SUCCESS;
>> +
>> +Done:
>> +  return Status;
>> +}
>> diff --git a/OvmfPkg/IntelGvtGopDxe/Gtt.h b/OvmfPkg/IntelGvtGopDxe/Gtt.h
>> new file mode 100644
>> index 000000000000..fc91b7a84a0a
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/Gtt.h
>> @@ -0,0 +1,51 @@
>> +/** @file
>> +  Component name for the QEMU video controller.
>> +
>> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef __GTT_H_
>> +#define __GTT_H_
>> +
>> +#include "Common.h"
>> +
>> +typedef UINT64 GTT_PTE_ENTRY;
>> +
>> +#define GTT_OFFSET          0x800000
>> +#define GTT_SIZE            0x800000
>> +#define GTT_ENTRY_SIZE      sizeof(GTT_PTE_ENTRY)
>> +#define GTT_ENTRY_NUM       (GTT_SIZE / GTT_ENTRY_SIZE)
>> +#define GTT_PAGE_SHIFT      12
>> +#define GTT_PAGE_SIZE       (1UL << GTT_PAGE_SHIFT)
>> +#define GTT_PAGE_MASK       (~(GTT_PAGE_SIZE-1))
>> +#define GTT_PAGE_PRESENT    0x01
>> +#define GTT_PAGE_READ_WRITE 0x02
>> +#define GTT_PAGE_PWT        0x08
>> +#define GTT_PAGE_PCD        0x10
>> +
>> +EFI_STATUS
>> +GGTTGetEntry (
>> +  IN  GVT_GOP_PRIVATE_DATA *Private,
>> +  IN  UINT64 Index,
>> +  OUT GTT_PTE_ENTRY *Entry
>> +  );
>> +
>> +EFI_STATUS
>> +GGTTSetEntry (
>> +  IN GVT_GOP_PRIVATE_DATA *Private,
>> +  IN UINT64 Index,
>> +  IN GTT_PTE_ENTRY Entry
>> +  );
>> +
>> +EFI_STATUS
>> +UpdateGGTT (
>> +  IN GVT_GOP_PRIVATE_DATA *Private,
>> +  IN EFI_PHYSICAL_ADDRESS GMAddr,
>> +  IN EFI_PHYSICAL_ADDRESS SysAddr,
>> +  IN UINTN                Pages
>> +  );
>> +
>> +#endif //__GTT_H_
>> diff --git a/OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf b/OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf
>> new file mode 100644
>> index 000000000000..c6e1751e1a22
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/IntelGvtGopDxe.inf
>> @@ -0,0 +1,59 @@
>> +## @file
>> +# Intel GVT-g Graphics Output Protocol driver
>> +#
>> +# Copyright (C) 2021 Intel Corporation. All rights reserved.
>> +#
>> +# SPDX-License-Identifier: BSD-2-Clause
>> +#
>> +##
>> +
>> +[Defines]
>> +  INF_VERSION                    = 0x00010005
>> +  BASE_NAME                      = GvtGopDxe
>> +  FILE_GUID                      = 7c2a0c14-2a63-4d08-9c7f-d55691e1cedb
>> +  MODULE_TYPE                    = UEFI_DRIVER
>> +  VERSION_STRING                 = 2.0
>> +  ENTRY_POINT                    = GvtGopEntryPoint
>> +
>> +[Sources]
>> +  Common.h
>> +  DebugHelper.h
>> +  Display.c
>> +  Display.h
>> +  GopDriver.c
>> +  GpuReg.c
>> +  GpuReg.h
>> +  Gtt.c
>> +  Gtt.h
>> +  VirtualGpu.h
>> +  VirtualGpu.c
>> +  VbeShim.c
>> +  VbeShim.h
>> +
>> +[Packages]
>> +  MdePkg/MdePkg.dec
>> +  MdeModulePkg/MdeModulePkg.dec
>> +  OvmfPkg/OvmfPkg.dec
>> +
>> +[LibraryClasses]
>> +  BaseMemoryLib
>> +  FrameBufferBltLib
>> +  DebugLib
>> +  DevicePathLib
>> +  MemoryAllocationLib
>> +  PrintLib
>> +  UefiBootServicesTableLib
>> +  UefiDriverEntryPoint
>> +  UefiLib
>> +  PcdLib
>> +  PciLib
>> +  QemuFwCfgLib
>> +
>> +[Protocols]
>> +  gEfiGraphicsOutputProtocolGuid
>> +  gEfiPciIoProtocolGuid
>> +  gEfiDevicePathProtocolGuid
>> +
>> +[Pcd]
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution
>> diff --git a/OvmfPkg/IntelGvtGopDxe/VbeShim.asm b/OvmfPkg/IntelGvtGopDxe/VbeShim.asm
>> new file mode 100644
>> index 000000000000..43a44362b794
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/VbeShim.asm
>> @@ -0,0 +1,343 @@
>> +;------------------------------------------------------------------------------
>> +; @file
>> +; A minimal Int10h stub that allows the Windows 2008 R2 SP1 UEFI guest's buggy,
>> +; default VGA driver to switch to 1024x768x32.
>> +;
>> +; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +; Copyright (C) 2020, Rebecca Cran <rebecca@bsdio.com>
>> +; Copyright (C) 2015, Nahanni Systems, Inc.
>> +; Copyright (C) 2014, Red Hat, Inc.
>> +; Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
>> +;
>> +; SPDX-License-Identifier: BSD-2-Clause-Patent
>> +;
>> +;------------------------------------------------------------------------------
>> +
>> +; enable this macro for debug messages
>> +%define DEBUG
>> +
>> +%macro DebugLog 1
>> +%ifdef DEBUG
>> +  push       si
>> +  mov        si, %1
>> +  call       PrintStringSi
>> +  pop        si
>> +%endif
>> +%endmacro
>> +
>> +
>> +BITS 16
>> +ORG 0
>> +
>> +VbeInfo:
>> +TIMES 256 nop
>> +
>> +VbeModeInfo:
>> +VbeMode1:
>> +TIMES 50  nop
>> +VbeMode2:
>> +TIMES 50  nop
>> +VbeMode3:
>> +TIMES 50  nop
>> +VbeMode4:
>> +TIMES 50  nop
>> +TIMES 56  nop  ; filler for 256 bytes
>> +
>> +Handler:
>> +  cmp        ax, 0x4f00
>> +  je         GetInfo
>> +  cmp        ax, 0x4f01
>> +  je         GetModeInfo
>> +  cmp        ax, 0x4f02
>> +  je         SetMode
>> +  cmp        ax, 0x4f03
>> +  je         GetMode
>> +  cmp        ax, 0x4f10
>> +  je         GetPmCapabilities
>> +  cmp        ax, 0x4f15
>> +  je         ReadEdid
>> +  cmp        ah, 0x00
>> +  je         SetModeLegacy
>> +  DebugLog   StrUnkownFunction
>> +Hang:
>> +  jmp        Hang
>> +
>> +
>> +GetInfo:
>> +  push       es
>> +  push       di
>> +  push       ds
>> +  push       si
>> +  push       cx
>> +
>> +  DebugLog   StrEnterGetInfo
>> +
>> +  ; target (es:di) set on input
>> +  push       cs
>> +  pop        ds
>> +  mov        si, VbeInfo
>> +  ; source (ds:si) set now
>> +
>> +  mov        cx, 256
>> +  cld
>> +  rep movsb
>> +
>> +  pop        cx
>> +  pop        si
>> +  pop        ds
>> +  pop        di
>> +  pop        es
>> +  jmp        Success
>> +
>> +
>> +GetModeInfo:
>> +  push       es
>> +  push       di
>> +  push       ds
>> +  push       si
>> +  push       cx
>> +
>> +  DebugLog   StrEnterGetModeInfo
>> +
>> +  and        cx, ~0x4000 ; clear potentially set LFB bit in mode number
>> +
>> +  cmp        cx, 0x013f
>> +  je         gKnownMode1
>> +  cmp        cx, 0x0140
>> +  je         gKnownMode2
>> +  cmp        cx, 0x0141
>> +  je         gKnownMode3
>> +
>> +  DebugLog   StrUnkownMode
>> +  jmp        Hang
>> +gKnownMode1:
>> +  DebugLog   StrMode1
>> +  mov        si, VbeMode1
>> +  jmp        CopyModeInfo
>> +gKnownMode2:
>> +  DebugLog   StrMode2
>> +  mov        si, VbeMode2
>> +  jmp        CopyModeInfo
>> +gKnownMode3:
>> +  DebugLog   StrMode3
>> +  mov        si, VbeMode3
>> +  jmp        CopyModeInfo
>> +gKnownMode4:
>> +  DebugLog   StrMode4
>> +  mov        si, VbeMode4
>> +  jmp        CopyModeInfo
>> +
>> +CopyModeInfo:
>> +  ; target (es:di) set on input
>> +  push       cs
>> +  pop        ds
>> +  ;mov        si, VbeModeInfo
>> +  ; source (ds:si) set now
>> +
>> +  ;mov        cx, 256
>> +  mov        cx, 50
>> +  cld
>> +  rep movsb
>> +
>> +  pop        cx
>> +  pop        si
>> +  pop        ds
>> +  pop        di
>> +  pop        es
>> +  jmp        Success
>> +
>> +
>> +SetMode:
>> +  push       dx
>> +  push       ax
>> +
>> +  DebugLog   StrEnterSetMode
>> +
>> +  and        bx, ~0x4000 ; clear potentially set LFB bit in mode number
>> +  cmp        bx, 0x013f
>> +  je         KnownMode1
>> +  cmp        bx, 0x0140
>> +  je         KnownMode2
>> +  cmp        bx, 0x0141
>> +  je         KnownMode3
>> +  DebugLog   StrUnkownMode
>> +  jmp        Hang
>> +KnownMode1:
>> +  DebugLog   StrMode1
>> +  jmp        SetModeDone
>> +KnownMode2:
>> +  DebugLog   StrMode2
>> +  jmp        SetModeDone
>> +KnownMode3:
>> +  DebugLog   StrMode3
>> +  jmp        SetModeDone
>> +KnownMode4:
>> +  DebugLog   StrMode4
>> +
>> +SetModeDone:
>> +  mov        [CurMode], bl
>> +  mov        [CurMode+1], bh
>> +  pop        ax
>> +  pop        dx
>> +  jmp        Success
>> +
>> +
>> +GetMode:
>> +  DebugLog   StrEnterGetMode
>> +  mov        bl, [CurMode]
>> +  mov        bh, [CurMode+1]
>> +  jmp        Success
>> +
>> +
>> +GetPmCapabilities:
>> +  DebugLog   StrGetPmCapabilities
>> +  mov        bx, 0x0080
>> +  jmp        Success
>> +
>> +
>> +ReadEdid:
>> +  push       es
>> +  push       di
>> +  push       ds
>> +  push       si
>> +  push       cx
>> +
>> +  DebugLog   StrReadEdid
>> +
>> +  ; target (es:di) set on input
>> +  push       cs
>> +  pop        ds
>> +  mov        si, Edid
>> +  ; source (ds:si) set now
>> +
>> +  mov        cx, 128
>> +  cld
>> +  rep movsb
>> +
>> +  pop        cx
>> +  pop        si
>> +  pop        ds
>> +  pop        di
>> +  pop        es
>> +  jmp        Success
>> +
>> +
>> +SetModeLegacy:
>> +  DebugLog   StrEnterSetModeLegacy
>> +
>> +  cmp        al, 0x03
>> +  je         sKnownMode3
>> +  cmp        al, 0x12
>> +  je         sKnownMode4
>> +  DebugLog   StrUnkownMode
>> +  jmp        Hang
>> +sKnownMode3:
>> +  DebugLog   StrLegacyMode3
>> +  mov        al, 0 ; 0x30
>> +  jmp        SetModeLegacyDone
>> +sKnownMode4:
>> +  mov        al, 0 ;0x20
>> +SetModeLegacyDone:
>> +  DebugLog   StrExitSuccess
>> +  iret
>> +
>> +
>> +Success:
>> +  DebugLog   StrExitSuccess
>> +  mov        ax, 0x004f
>> +  iret
>> +
>> +
>> +Unsupported:
>> +  DebugLog   StrExitUnsupported
>> +  mov        ax, 0x024f
>> +  iret
>> +
>> +
>> +%ifdef DEBUG
>> +PrintStringSi:
>> +  pusha
>> +  push       ds ; save original
>> +  push       cs
>> +  pop        ds
>> +  mov        dx, 0x220             ; bhyve debug cons port
>> +  mov        ax, 0
>> +PrintStringSiLoop:
>> +  lodsb
>> +  cmp        al, 0
>> +  je         PrintStringSiDone
>> +  out        dx, al
>> +  jmp        PrintStringSiLoop
>> +PrintStringSiDone:
>> +  pop        ds ; restore original
>> +  popa
>> +  ret
>> +
>> +
>> +StrExitSuccess:
>> +  db 'vOk', 0x0d, 0x0a, 0
>> +
>> +StrExitUnsupported:
>> +  db 'vUnsupported', 0x0d, 0x0a, 0
>> +
>> +StrUnkownFunction:
>> +  db 'vUnknown Function', 0x0d, 0x0a, 0
>> +
>> +StrEnterGetInfo:
>> +  db 'vGetInfo', 0x0d, 0x0a, 0
>> +
>> +StrEnterGetModeInfo:
>> +  db 'vGetModeInfo', 0x0d, 0x0a, 0
>> +
>> +StrEnterGetMode:
>> +  db 'vGetMode', 0x0d, 0x0a, 0
>> +
>> +StrEnterSetMode:
>> +  db 'vSetMode', 0x0d, 0x0a, 0
>> +
>> +StrEnterSetModeLegacy:
>> +  db 'vSetModeLegacy', 0x0d, 0x0a, 0
>> +
>> +StrUnkownMode:
>> +  db 'vUnkown Mode', 0x0d, 0x0a, 0
>> +
>> +StrGetPmCapabilities:
>> +  db 'vGetPmCapabilities', 0x0d, 0x0a, 0
>> +
>> +StrReadEdid:
>> +  db 'vReadEdid', 0x0d, 0x0a, 0
>> +
>> +StrLegacyMode3:
>> +  db 'vLegacyMode3', 0x0d, 0x0a, 0
>> +
>> +
>> +StrMode1:
>> +  db 'mode_640x480x32', 0x0d, 0x0a, 0
>> +StrMode2:
>> +  db 'mode_800x600x32', 0x0d, 0x0a, 0
>> +StrMode3:
>> +  db 'mode_1024x768x32', 0x0d, 0x0a, 0
>> +StrMode4:
>> +  db 'mode_unused', 0x0d, 0x0a, 0
>> +%endif
>> +
>> +CurMode:
>> +  db 0x00, 0x00
>> +
>> +;
>> +; EDID stores monitor information. For now, just send back an null item.
>> +;
>> +Edid:
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +  db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> diff --git a/OvmfPkg/IntelGvtGopDxe/VbeShim.c b/OvmfPkg/IntelGvtGopDxe/VbeShim.c
>> new file mode 100644
>> index 000000000000..8063224d53b4
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/VbeShim.c
>> @@ -0,0 +1,258 @@
>> +/** @file
>> +  Install a fake VGABIOS service handler (real mode Int10h) for the buggy
>> +  Windows 2008 R2 SP1 UEFI guest.
>> +
>> +  The handler is never meant to be directly executed by a VCPU; it's there for
>> +  the internal real mode emulator of Windows 2008 R2 SP1.
>> +
>> +  The code is based on Ralf Brown's Interrupt List:
>> +  <http://www.cs.cmu.edu/~ralf/files.html>
>> +  <http://www.ctyme.com/rbrown.htm>
>> +
>> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +  Copyright (C) 2020, Rebecca Cran <rebecca@bsdio.com>
>> +  Copyright (C) 2015, Nahanni Systems, Inc.
>> +  Copyright (C) 2014, Red Hat, Inc.
>> +  Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include "Common.h"
>> +#include <IndustryStandard/LegacyVgaBios.h>
>> +#include <Library/PciLib.h>
>> +#include <Library/PrintLib.h>
>> +#include "VbeShim.h"
>> +
>> +#pragma pack (1)
>> +typedef struct {
>> +  UINT16 Offset;
>> +  UINT16 Segment;
>> +} IVT_ENTRY;
>> +#pragma pack ()
>> +
>> +//
>> +// This string is displayed by Windows 2008 R2 SP1 in the Screen Resolution,
>> +// Advanced Settings dialog. It should be short.
>> +//
>> +STATIC CONST CHAR8 mProductRevision[] = "2.0";
>> +
>> +#define NUM_VBE_MODES 3
>> +STATIC CONST UINT16 vbeModeIds[] = {
>> +  0x13f,  // 640x480x32
>> +  0x140,  // 800x600x32
>> +  0x141   // 1024x768x32
>> +};
>> +
>> +// Modes can be toggled with bit-0
>> +#define VBE_MODE_ENABLED  0x00BB
>> +#define VBE_MODE_DISABLED 0x00BA
>> +
>> +STATIC VBE2_MODE_INFO vbeModes[] = {
>> +  { // 0x13f 640x480x32
>> +
>> +    // ModeAttr - BytesPerScanLine
>> +    VBE_MODE_DISABLED, 0x07, 0x00, 0x40, 0x40, 0xA000, 0x00, 0x0000, 640*4,
>> +    // Width, Height..., Vbe3
>> +    640, 480, 16, 8, 1, 32, 1, 0x06, 0, 0, 1,
>> +    // Masks
>> +    0x08, 0x10, 0x08, 0x08, 0x08, 0x00, 0x08, 0x18, 0x00,
>> +    // Framebuffer
>> +    0xdeadbeef, 0x0000, 0x0000
>> +  },
>> +  { // 0x140 800x600x32
>> +
>> +    // ModeAttr - BytesPerScanLine
>> +    VBE_MODE_DISABLED, 0x07, 0x00, 0x40, 0x40, 0xA000, 0x00, 0x0000, 800*4,
>> +    // Width, Height..., Vbe3
>> +    800, 600, 16, 8, 1, 32, 1, 0x06, 0, 0, 1,
>> +    // Masks
>> +    0x08, 0x10, 0x08, 0x08, 0x08, 0x00, 0x08, 0x18, 0x00,
>> +    // Framebuffer
>> +    0xdeadbeef, 0x0000, 0x0000
>> +  },
>> +  { // 0x141 1024x768x32
>> +
>> +    // ModeAttr - BytesPerScanLine
>> +    VBE_MODE_ENABLED, 0x07, 0x00, 0x40, 0x40, 0xA000, 0x00, 0x0000, 1024*4,
>> +    // Width, Height..., Vbe3
>> +    1024, 768, 16, 8, 1, 32, 1, 0x06, 0, 0, 1,
>> +    // Masks
>> +    0x08, 0x10, 0x08, 0x08, 0x08, 0x00, 0x08, 0x18, 0x00,
>> +    // Framebuffer
>> +    0xdeadbeef, 0x0000, 0x0000
>> +  }
>> +};
>> +
>> +/**
>> +  Install the VBE Info and VBE Mode Info structures, and the VBE service
>> +  handler routine in the C segment. Point the real-mode Int10h interrupt vector
>> +  to the handler. The only advertised mode is 1024x768x32.
>> +
>> +  @param[in] CardName         Name of the video card to be exposed in the
>> +                              Product Name field of the VBE Info structure.
>> +  @param[in] FrameBufferBase  Guest-physical base address of the video card's
>> +                              frame buffer.
>> +**/
>> +VOID
>> +InstallVbeShim (
>> +  IN CONST CHAR16         *CardName,
>> +  IN EFI_PHYSICAL_ADDRESS FrameBufferBase
>> +  )
>> +{
>> +  EFI_PHYSICAL_ADDRESS Segment0, SegmentC, SegmentF;
>> +  UINTN                Segment0Pages;
>> +  IVT_ENTRY            *Int0x10;
>> +  EFI_STATUS           Status;
>> +  UINTN                Pam1Address;
>> +  UINT8                Pam1;
>> +  UINTN                SegmentCPages;
>> +  VBE_INFO             *VbeInfoFull;
>> +  VBE_INFO_BASE        *VbeInfo;
>> +  UINT8                *Ptr;
>> +  UINTN                Printed;
>> +  VBE_MODE_INFO        *VbeModeInfo;
>> +  UINTN                i;
>> +
>> +  Segment0 = 0x00000;
>> +  SegmentC = 0xC0000;
>> +  SegmentF = 0xF0000;
>> +
>> +  //
>> +  // Attempt to cover the real mode IVT with an allocation. This is a UEFI
>> +  // driver, hence the arch protocols have been installed previously. Among
>> +  // those, the CPU arch protocol has configured the IDT, so we can overwrite
>> +  // the IVT used in real mode.
>> +  //
>> +  // The allocation request may fail, eg. if LegacyBiosDxe has already run.
>> +  //
>> +  Segment0Pages = 1;
>> +  Int0x10       = (IVT_ENTRY *)(UINTN)Segment0 + 0x10;
>> +  Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode,
>> +                  Segment0Pages, &Segment0);
>> +
>> +  if (EFI_ERROR (Status)) {
>> +    EFI_PHYSICAL_ADDRESS Handler;
>> +
>> +    //
>> +    // Check if a video BIOS handler has been installed previously -- we
>> +    // shouldn't override a real video BIOS with our shim, nor our own shim if
>> +    // it's already present.
>> +    //
>> +    Handler = (Int0x10->Segment << 4) + Int0x10->Offset;
>> +    if (Handler >= SegmentC && Handler < SegmentF) {
>> +      DEBUG ((DEBUG_VERBOSE, "%a: Video BIOS handler found at %04x:%04x\n",
>> +        __FUNCTION__, Int0x10->Segment, Int0x10->Offset));
>> +      return;
>> +    }
>> +
>> +    //
>> +    // Otherwise we'll overwrite the Int10h vector, even though we may not own
>> +    // the page at zero.
>> +    //
>> +    DEBUG ((DEBUG_VERBOSE, "%a: failed to allocate page at zero: %r\n",
>> +      __FUNCTION__, Status));
>> +  } else {
>> +    //
>> +    // We managed to allocate the page at zero. SVN r14218 guarantees that it
>> +    // is NUL-filled.
>> +    //
>> +    ASSERT (Int0x10->Segment == 0x0000);
>> +    ASSERT (Int0x10->Offset  == 0x0000);
>> +  }
>> +
>> +  //
>> +  // Put the shim in place first.
>> +  //
>> +  Pam1Address = PCI_LIB_ADDRESS (0, 0, 0, 0x5A);
>> +  //
>> +  // low nibble covers 0xC0000 to 0xC3FFF
>> +  // high nibble covers 0xC4000 to 0xC7FFF
>> +  // bit1 in each nibble is Write Enable
>> +  // bit0 in each nibble is Read Enable
>> +  //
>> +  Pam1 = PciRead8 (Pam1Address);
>> +  PciWrite8 (Pam1Address, Pam1 | (BIT1 | BIT0));
>> +
>> +  //
>> +  // We never added memory space durig PEI or DXE for the C segment, so we
>> +  // don't need to (and can't) allocate from there. Also, guest operating
>> +  // systems will see a hole in the UEFI memory map there.
>> +  //
>> +  SegmentCPages = 4;
>> +
>> +  ASSERT (sizeof gVbeShim <= EFI_PAGES_TO_SIZE (SegmentCPages));
>> +  CopyMem ((VOID *)(UINTN)SegmentC, gVbeShim, sizeof gVbeShim);
>> +
>> +  //
>> +  // Fill in the VBE INFO structure.
>> +  //
>> +  VbeInfoFull = (VBE_INFO *)(UINTN)SegmentC;
>> +  VbeInfo     = &VbeInfoFull->Base;
>> +  Ptr         = VbeInfoFull->Buffer;
>> +
>> +  CopyMem (VbeInfo->Signature, "VESA", 4);
>> +  VbeInfo->VesaVersion = 0x0200;
>> +
>> +  VbeInfo->OemNameAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
>> +  CopyMem (Ptr, "FBSD", 5);
>> +  Ptr += 5;
>> +
>> +  VbeInfo->Capabilities = BIT1 | BIT0; // DAC can be switched into 8-bit mode
>> +
>> +  VbeInfo->ModeListAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
>> +  for (i = 0; i < NUM_VBE_MODES; i ++) {
>> +     *(UINT16*)Ptr = vbeModeIds[i];  // mode number
>> +     Ptr += 2;
>> +  }
>> +  *(UINT16*)Ptr = 0xFFFF; // mode list terminator
>> +  Ptr += 2;
>> +
>> +  VbeInfo->VideoMem64K = (UINT16)((1024 * 768 * 4 + 65535) / 65536);
>> +  VbeInfo->OemSoftwareVersion = 0x0200;
>> +
>> +  VbeInfo->VendorNameAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
>> +  CopyMem (Ptr, "FBSD", 5);
>> +  Ptr += 5;
>> +
>> +  VbeInfo->ProductNameAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
>> +  Printed = AsciiSPrint ((CHAR8 *)Ptr,
>> +              sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer), "%s",
>> +              CardName);
>> +  Ptr += Printed + 1;
>> +
>> +  VbeInfo->ProductRevAddress = (UINT32)SegmentC << 12 | (UINT16)((UINTN)Ptr-SegmentC);
>> +  CopyMem (Ptr, mProductRevision, sizeof mProductRevision);
>> +  Ptr += sizeof mProductRevision;
>> +
>> +  ASSERT (sizeof VbeInfoFull->Buffer >= Ptr - VbeInfoFull->Buffer);
>> +  ZeroMem (Ptr, sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer));
>> +
>> +  //
>> +  // Fill in the VBE MODE INFO structure list
>> +  //
>> +  VbeModeInfo = (VBE_MODE_INFO *)(VbeInfoFull + 1);
>> +  Ptr = (UINT8 *)VbeModeInfo;
>> +  for (i = 0; i < NUM_VBE_MODES; i++) {
>> +    vbeModes[i].LfbAddress = (UINT32)FrameBufferBase;
>> +    CopyMem (Ptr, &vbeModes[i], 0x32);
>> +    Ptr += 0x32;
>> +  }
>> +
>> +  ZeroMem (Ptr, 56);     // Clear remaining bytes
>> +
>> +  //
>> +  // Clear Write Enable (bit1), keep Read Enable (bit0) set
>> +  //
>> +  PciWrite8 (Pam1Address, (Pam1 & ~BIT1) | BIT0);
>> +
>> +  //
>> +  // Second, point the Int10h vector at the shim.
>> +  //
>> +  Int0x10->Segment = (UINT16) ((UINT32)SegmentC >> 4);
>> +  Int0x10->Offset  = (UINT16) ((UINTN) (VbeModeInfo + 1) - SegmentC);
>> +
>> +  DEBUG ((DEBUG_INFO, "%a: VBE shim installed to %x:%x\n",
>> +         __FUNCTION__, Int0x10->Segment, Int0x10->Offset));
>> +}
>> diff --git a/OvmfPkg/IntelGvtGopDxe/VbeShim.h b/OvmfPkg/IntelGvtGopDxe/VbeShim.h
>> new file mode 100644
>> index 000000000000..601b1465cbe5
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/VbeShim.h
>> @@ -0,0 +1,912 @@
>> +//
>> +// THIS FILE WAS GENERATED BY "VbeShim.sh". DO NOT EDIT.
>> +//
>> +#ifndef _VBE_SHIM_H_
>> +#define _VBE_SHIM_H_
>> +STATIC CONST UINT8 gVbeShim[] = {
>> +  /* 00000000 nop                            */  0x90,
>> +  /* 00000001 nop                            */  0x90,
>> +  /* 00000002 nop                            */  0x90,
>> +  /* 00000003 nop                            */  0x90,
>> +  /* 00000004 nop                            */  0x90,
>> +  /* 00000005 nop                            */  0x90,
>> +  /* 00000006 nop                            */  0x90,
>> +  /* 00000007 nop                            */  0x90,
>> +  /* 00000008 nop                            */  0x90,
>> +  /* 00000009 nop                            */  0x90,
>> +  /* 0000000A nop                            */  0x90,
>> +  /* 0000000B nop                            */  0x90,
>> +  /* 0000000C nop                            */  0x90,
>> +  /* 0000000D nop                            */  0x90,
>> +  /* 0000000E nop                            */  0x90,
>> +  /* 0000000F nop                            */  0x90,
>> +  /* 00000010 nop                            */  0x90,
>> +  /* 00000011 nop                            */  0x90,
>> +  /* 00000012 nop                            */  0x90,
>> +  /* 00000013 nop                            */  0x90,
>> +  /* 00000014 nop                            */  0x90,
>> +  /* 00000015 nop                            */  0x90,
>> +  /* 00000016 nop                            */  0x90,
>> +  /* 00000017 nop                            */  0x90,
>> +  /* 00000018 nop                            */  0x90,
>> +  /* 00000019 nop                            */  0x90,
>> +  /* 0000001A nop                            */  0x90,
>> +  /* 0000001B nop                            */  0x90,
>> +  /* 0000001C nop                            */  0x90,
>> +  /* 0000001D nop                            */  0x90,
>> +  /* 0000001E nop                            */  0x90,
>> +  /* 0000001F nop                            */  0x90,
>> +  /* 00000020 nop                            */  0x90,
>> +  /* 00000021 nop                            */  0x90,
>> +  /* 00000022 nop                            */  0x90,
>> +  /* 00000023 nop                            */  0x90,
>> +  /* 00000024 nop                            */  0x90,
>> +  /* 00000025 nop                            */  0x90,
>> +  /* 00000026 nop                            */  0x90,
>> +  /* 00000027 nop                            */  0x90,
>> +  /* 00000028 nop                            */  0x90,
>> +  /* 00000029 nop                            */  0x90,
>> +  /* 0000002A nop                            */  0x90,
>> +  /* 0000002B nop                            */  0x90,
>> +  /* 0000002C nop                            */  0x90,
>> +  /* 0000002D nop                            */  0x90,
>> +  /* 0000002E nop                            */  0x90,
>> +  /* 0000002F nop                            */  0x90,
>> +  /* 00000030 nop                            */  0x90,
>> +  /* 00000031 nop                            */  0x90,
>> +  /* 00000032 nop                            */  0x90,
>> +  /* 00000033 nop                            */  0x90,
>> +  /* 00000034 nop                            */  0x90,
>> +  /* 00000035 nop                            */  0x90,
>> +  /* 00000036 nop                            */  0x90,
>> +  /* 00000037 nop                            */  0x90,
>> +  /* 00000038 nop                            */  0x90,
>> +  /* 00000039 nop                            */  0x90,
>> +  /* 0000003A nop                            */  0x90,
>> +  /* 0000003B nop                            */  0x90,
>> +  /* 0000003C nop                            */  0x90,
>> +  /* 0000003D nop                            */  0x90,
>> +  /* 0000003E nop                            */  0x90,
>> +  /* 0000003F nop                            */  0x90,
>> +  /* 00000040 nop                            */  0x90,
>> +  /* 00000041 nop                            */  0x90,
>> +  /* 00000042 nop                            */  0x90,
>> +  /* 00000043 nop                            */  0x90,
>> +  /* 00000044 nop                            */  0x90,
>> +  /* 00000045 nop                            */  0x90,
>> +  /* 00000046 nop                            */  0x90,
>> +  /* 00000047 nop                            */  0x90,
>> +  /* 00000048 nop                            */  0x90,
>> +  /* 00000049 nop                            */  0x90,
>> +  /* 0000004A nop                            */  0x90,
>> +  /* 0000004B nop                            */  0x90,
>> +  /* 0000004C nop                            */  0x90,
>> +  /* 0000004D nop                            */  0x90,
>> +  /* 0000004E nop                            */  0x90,
>> +  /* 0000004F nop                            */  0x90,
>> +  /* 00000050 nop                            */  0x90,
>> +  /* 00000051 nop                            */  0x90,
>> +  /* 00000052 nop                            */  0x90,
>> +  /* 00000053 nop                            */  0x90,
>> +  /* 00000054 nop                            */  0x90,
>> +  /* 00000055 nop                            */  0x90,
>> +  /* 00000056 nop                            */  0x90,
>> +  /* 00000057 nop                            */  0x90,
>> +  /* 00000058 nop                            */  0x90,
>> +  /* 00000059 nop                            */  0x90,
>> +  /* 0000005A nop                            */  0x90,
>> +  /* 0000005B nop                            */  0x90,
>> +  /* 0000005C nop                            */  0x90,
>> +  /* 0000005D nop                            */  0x90,
>> +  /* 0000005E nop                            */  0x90,
>> +  /* 0000005F nop                            */  0x90,
>> +  /* 00000060 nop                            */  0x90,
>> +  /* 00000061 nop                            */  0x90,
>> +  /* 00000062 nop                            */  0x90,
>> +  /* 00000063 nop                            */  0x90,
>> +  /* 00000064 nop                            */  0x90,
>> +  /* 00000065 nop                            */  0x90,
>> +  /* 00000066 nop                            */  0x90,
>> +  /* 00000067 nop                            */  0x90,
>> +  /* 00000068 nop                            */  0x90,
>> +  /* 00000069 nop                            */  0x90,
>> +  /* 0000006A nop                            */  0x90,
>> +  /* 0000006B nop                            */  0x90,
>> +  /* 0000006C nop                            */  0x90,
>> +  /* 0000006D nop                            */  0x90,
>> +  /* 0000006E nop                            */  0x90,
>> +  /* 0000006F nop                            */  0x90,
>> +  /* 00000070 nop                            */  0x90,
>> +  /* 00000071 nop                            */  0x90,
>> +  /* 00000072 nop                            */  0x90,
>> +  /* 00000073 nop                            */  0x90,
>> +  /* 00000074 nop                            */  0x90,
>> +  /* 00000075 nop                            */  0x90,
>> +  /* 00000076 nop                            */  0x90,
>> +  /* 00000077 nop                            */  0x90,
>> +  /* 00000078 nop                            */  0x90,
>> +  /* 00000079 nop                            */  0x90,
>> +  /* 0000007A nop                            */  0x90,
>> +  /* 0000007B nop                            */  0x90,
>> +  /* 0000007C nop                            */  0x90,
>> +  /* 0000007D nop                            */  0x90,
>> +  /* 0000007E nop                            */  0x90,
>> +  /* 0000007F nop                            */  0x90,
>> +  /* 00000080 nop                            */  0x90,
>> +  /* 00000081 nop                            */  0x90,
>> +  /* 00000082 nop                            */  0x90,
>> +  /* 00000083 nop                            */  0x90,
>> +  /* 00000084 nop                            */  0x90,
>> +  /* 00000085 nop                            */  0x90,
>> +  /* 00000086 nop                            */  0x90,
>> +  /* 00000087 nop                            */  0x90,
>> +  /* 00000088 nop                            */  0x90,
>> +  /* 00000089 nop                            */  0x90,
>> +  /* 0000008A nop                            */  0x90,
>> +  /* 0000008B nop                            */  0x90,
>> +  /* 0000008C nop                            */  0x90,
>> +  /* 0000008D nop                            */  0x90,
>> +  /* 0000008E nop                            */  0x90,
>> +  /* 0000008F nop                            */  0x90,
>> +  /* 00000090 nop                            */  0x90,
>> +  /* 00000091 nop                            */  0x90,
>> +  /* 00000092 nop                            */  0x90,
>> +  /* 00000093 nop                            */  0x90,
>> +  /* 00000094 nop                            */  0x90,
>> +  /* 00000095 nop                            */  0x90,
>> +  /* 00000096 nop                            */  0x90,
>> +  /* 00000097 nop                            */  0x90,
>> +  /* 00000098 nop                            */  0x90,
>> +  /* 00000099 nop                            */  0x90,
>> +  /* 0000009A nop                            */  0x90,
>> +  /* 0000009B nop                            */  0x90,
>> +  /* 0000009C nop                            */  0x90,
>> +  /* 0000009D nop                            */  0x90,
>> +  /* 0000009E nop                            */  0x90,
>> +  /* 0000009F nop                            */  0x90,
>> +  /* 000000A0 nop                            */  0x90,
>> +  /* 000000A1 nop                            */  0x90,
>> +  /* 000000A2 nop                            */  0x90,
>> +  /* 000000A3 nop                            */  0x90,
>> +  /* 000000A4 nop                            */  0x90,
>> +  /* 000000A5 nop                            */  0x90,
>> +  /* 000000A6 nop                            */  0x90,
>> +  /* 000000A7 nop                            */  0x90,
>> +  /* 000000A8 nop                            */  0x90,
>> +  /* 000000A9 nop                            */  0x90,
>> +  /* 000000AA nop                            */  0x90,
>> +  /* 000000AB nop                            */  0x90,
>> +  /* 000000AC nop                            */  0x90,
>> +  /* 000000AD nop                            */  0x90,
>> +  /* 000000AE nop                            */  0x90,
>> +  /* 000000AF nop                            */  0x90,
>> +  /* 000000B0 nop                            */  0x90,
>> +  /* 000000B1 nop                            */  0x90,
>> +  /* 000000B2 nop                            */  0x90,
>> +  /* 000000B3 nop                            */  0x90,
>> +  /* 000000B4 nop                            */  0x90,
>> +  /* 000000B5 nop                            */  0x90,
>> +  /* 000000B6 nop                            */  0x90,
>> +  /* 000000B7 nop                            */  0x90,
>> +  /* 000000B8 nop                            */  0x90,
>> +  /* 000000B9 nop                            */  0x90,
>> +  /* 000000BA nop                            */  0x90,
>> +  /* 000000BB nop                            */  0x90,
>> +  /* 000000BC nop                            */  0x90,
>> +  /* 000000BD nop                            */  0x90,
>> +  /* 000000BE nop                            */  0x90,
>> +  /* 000000BF nop                            */  0x90,
>> +  /* 000000C0 nop                            */  0x90,
>> +  /* 000000C1 nop                            */  0x90,
>> +  /* 000000C2 nop                            */  0x90,
>> +  /* 000000C3 nop                            */  0x90,
>> +  /* 000000C4 nop                            */  0x90,
>> +  /* 000000C5 nop                            */  0x90,
>> +  /* 000000C6 nop                            */  0x90,
>> +  /* 000000C7 nop                            */  0x90,
>> +  /* 000000C8 nop                            */  0x90,
>> +  /* 000000C9 nop                            */  0x90,
>> +  /* 000000CA nop                            */  0x90,
>> +  /* 000000CB nop                            */  0x90,
>> +  /* 000000CC nop                            */  0x90,
>> +  /* 000000CD nop                            */  0x90,
>> +  /* 000000CE nop                            */  0x90,
>> +  /* 000000CF nop                            */  0x90,
>> +  /* 000000D0 nop                            */  0x90,
>> +  /* 000000D1 nop                            */  0x90,
>> +  /* 000000D2 nop                            */  0x90,
>> +  /* 000000D3 nop                            */  0x90,
>> +  /* 000000D4 nop                            */  0x90,
>> +  /* 000000D5 nop                            */  0x90,
>> +  /* 000000D6 nop                            */  0x90,
>> +  /* 000000D7 nop                            */  0x90,
>> +  /* 000000D8 nop                            */  0x90,
>> +  /* 000000D9 nop                            */  0x90,
>> +  /* 000000DA nop                            */  0x90,
>> +  /* 000000DB nop                            */  0x90,
>> +  /* 000000DC nop                            */  0x90,
>> +  /* 000000DD nop                            */  0x90,
>> +  /* 000000DE nop                            */  0x90,
>> +  /* 000000DF nop                            */  0x90,
>> +  /* 000000E0 nop                            */  0x90,
>> +  /* 000000E1 nop                            */  0x90,
>> +  /* 000000E2 nop                            */  0x90,
>> +  /* 000000E3 nop                            */  0x90,
>> +  /* 000000E4 nop                            */  0x90,
>> +  /* 000000E5 nop                            */  0x90,
>> +  /* 000000E6 nop                            */  0x90,
>> +  /* 000000E7 nop                            */  0x90,
>> +  /* 000000E8 nop                            */  0x90,
>> +  /* 000000E9 nop                            */  0x90,
>> +  /* 000000EA nop                            */  0x90,
>> +  /* 000000EB nop                            */  0x90,
>> +  /* 000000EC nop                            */  0x90,
>> +  /* 000000ED nop                            */  0x90,
>> +  /* 000000EE nop                            */  0x90,
>> +  /* 000000EF nop                            */  0x90,
>> +  /* 000000F0 nop                            */  0x90,
>> +  /* 000000F1 nop                            */  0x90,
>> +  /* 000000F2 nop                            */  0x90,
>> +  /* 000000F3 nop                            */  0x90,
>> +  /* 000000F4 nop                            */  0x90,
>> +  /* 000000F5 nop                            */  0x90,
>> +  /* 000000F6 nop                            */  0x90,
>> +  /* 000000F7 nop                            */  0x90,
>> +  /* 000000F8 nop                            */  0x90,
>> +  /* 000000F9 nop                            */  0x90,
>> +  /* 000000FA nop                            */  0x90,
>> +  /* 000000FB nop                            */  0x90,
>> +  /* 000000FC nop                            */  0x90,
>> +  /* 000000FD nop                            */  0x90,
>> +  /* 000000FE nop                            */  0x90,
>> +  /* 000000FF nop                            */  0x90,
>> +  /* 00000100 nop                            */  0x90,
>> +  /* 00000101 nop                            */  0x90,
>> +  /* 00000102 nop                            */  0x90,
>> +  /* 00000103 nop                            */  0x90,
>> +  /* 00000104 nop                            */  0x90,
>> +  /* 00000105 nop                            */  0x90,
>> +  /* 00000106 nop                            */  0x90,
>> +  /* 00000107 nop                            */  0x90,
>> +  /* 00000108 nop                            */  0x90,
>> +  /* 00000109 nop                            */  0x90,
>> +  /* 0000010A nop                            */  0x90,
>> +  /* 0000010B nop                            */  0x90,
>> +  /* 0000010C nop                            */  0x90,
>> +  /* 0000010D nop                            */  0x90,
>> +  /* 0000010E nop                            */  0x90,
>> +  /* 0000010F nop                            */  0x90,
>> +  /* 00000110 nop                            */  0x90,
>> +  /* 00000111 nop                            */  0x90,
>> +  /* 00000112 nop                            */  0x90,
>> +  /* 00000113 nop                            */  0x90,
>> +  /* 00000114 nop                            */  0x90,
>> +  /* 00000115 nop                            */  0x90,
>> +  /* 00000116 nop                            */  0x90,
>> +  /* 00000117 nop                            */  0x90,
>> +  /* 00000118 nop                            */  0x90,
>> +  /* 00000119 nop                            */  0x90,
>> +  /* 0000011A nop                            */  0x90,
>> +  /* 0000011B nop                            */  0x90,
>> +  /* 0000011C nop                            */  0x90,
>> +  /* 0000011D nop                            */  0x90,
>> +  /* 0000011E nop                            */  0x90,
>> +  /* 0000011F nop                            */  0x90,
>> +  /* 00000120 nop                            */  0x90,
>> +  /* 00000121 nop                            */  0x90,
>> +  /* 00000122 nop                            */  0x90,
>> +  /* 00000123 nop                            */  0x90,
>> +  /* 00000124 nop                            */  0x90,
>> +  /* 00000125 nop                            */  0x90,
>> +  /* 00000126 nop                            */  0x90,
>> +  /* 00000127 nop                            */  0x90,
>> +  /* 00000128 nop                            */  0x90,
>> +  /* 00000129 nop                            */  0x90,
>> +  /* 0000012A nop                            */  0x90,
>> +  /* 0000012B nop                            */  0x90,
>> +  /* 0000012C nop                            */  0x90,
>> +  /* 0000012D nop                            */  0x90,
>> +  /* 0000012E nop                            */  0x90,
>> +  /* 0000012F nop                            */  0x90,
>> +  /* 00000130 nop                            */  0x90,
>> +  /* 00000131 nop                            */  0x90,
>> +  /* 00000132 nop                            */  0x90,
>> +  /* 00000133 nop                            */  0x90,
>> +  /* 00000134 nop                            */  0x90,
>> +  /* 00000135 nop                            */  0x90,
>> +  /* 00000136 nop                            */  0x90,
>> +  /* 00000137 nop                            */  0x90,
>> +  /* 00000138 nop                            */  0x90,
>> +  /* 00000139 nop                            */  0x90,
>> +  /* 0000013A nop                            */  0x90,
>> +  /* 0000013B nop                            */  0x90,
>> +  /* 0000013C nop                            */  0x90,
>> +  /* 0000013D nop                            */  0x90,
>> +  /* 0000013E nop                            */  0x90,
>> +  /* 0000013F nop                            */  0x90,
>> +  /* 00000140 nop                            */  0x90,
>> +  /* 00000141 nop                            */  0x90,
>> +  /* 00000142 nop                            */  0x90,
>> +  /* 00000143 nop                            */  0x90,
>> +  /* 00000144 nop                            */  0x90,
>> +  /* 00000145 nop                            */  0x90,
>> +  /* 00000146 nop                            */  0x90,
>> +  /* 00000147 nop                            */  0x90,
>> +  /* 00000148 nop                            */  0x90,
>> +  /* 00000149 nop                            */  0x90,
>> +  /* 0000014A nop                            */  0x90,
>> +  /* 0000014B nop                            */  0x90,
>> +  /* 0000014C nop                            */  0x90,
>> +  /* 0000014D nop                            */  0x90,
>> +  /* 0000014E nop                            */  0x90,
>> +  /* 0000014F nop                            */  0x90,
>> +  /* 00000150 nop                            */  0x90,
>> +  /* 00000151 nop                            */  0x90,
>> +  /* 00000152 nop                            */  0x90,
>> +  /* 00000153 nop                            */  0x90,
>> +  /* 00000154 nop                            */  0x90,
>> +  /* 00000155 nop                            */  0x90,
>> +  /* 00000156 nop                            */  0x90,
>> +  /* 00000157 nop                            */  0x90,
>> +  /* 00000158 nop                            */  0x90,
>> +  /* 00000159 nop                            */  0x90,
>> +  /* 0000015A nop                            */  0x90,
>> +  /* 0000015B nop                            */  0x90,
>> +  /* 0000015C nop                            */  0x90,
>> +  /* 0000015D nop                            */  0x90,
>> +  /* 0000015E nop                            */  0x90,
>> +  /* 0000015F nop                            */  0x90,
>> +  /* 00000160 nop                            */  0x90,
>> +  /* 00000161 nop                            */  0x90,
>> +  /* 00000162 nop                            */  0x90,
>> +  /* 00000163 nop                            */  0x90,
>> +  /* 00000164 nop                            */  0x90,
>> +  /* 00000165 nop                            */  0x90,
>> +  /* 00000166 nop                            */  0x90,
>> +  /* 00000167 nop                            */  0x90,
>> +  /* 00000168 nop                            */  0x90,
>> +  /* 00000169 nop                            */  0x90,
>> +  /* 0000016A nop                            */  0x90,
>> +  /* 0000016B nop                            */  0x90,
>> +  /* 0000016C nop                            */  0x90,
>> +  /* 0000016D nop                            */  0x90,
>> +  /* 0000016E nop                            */  0x90,
>> +  /* 0000016F nop                            */  0x90,
>> +  /* 00000170 nop                            */  0x90,
>> +  /* 00000171 nop                            */  0x90,
>> +  /* 00000172 nop                            */  0x90,
>> +  /* 00000173 nop                            */  0x90,
>> +  /* 00000174 nop                            */  0x90,
>> +  /* 00000175 nop                            */  0x90,
>> +  /* 00000176 nop                            */  0x90,
>> +  /* 00000177 nop                            */  0x90,
>> +  /* 00000178 nop                            */  0x90,
>> +  /* 00000179 nop                            */  0x90,
>> +  /* 0000017A nop                            */  0x90,
>> +  /* 0000017B nop                            */  0x90,
>> +  /* 0000017C nop                            */  0x90,
>> +  /* 0000017D nop                            */  0x90,
>> +  /* 0000017E nop                            */  0x90,
>> +  /* 0000017F nop                            */  0x90,
>> +  /* 00000180 nop                            */  0x90,
>> +  /* 00000181 nop                            */  0x90,
>> +  /* 00000182 nop                            */  0x90,
>> +  /* 00000183 nop                            */  0x90,
>> +  /* 00000184 nop                            */  0x90,
>> +  /* 00000185 nop                            */  0x90,
>> +  /* 00000186 nop                            */  0x90,
>> +  /* 00000187 nop                            */  0x90,
>> +  /* 00000188 nop                            */  0x90,
>> +  /* 00000189 nop                            */  0x90,
>> +  /* 0000018A nop                            */  0x90,
>> +  /* 0000018B nop                            */  0x90,
>> +  /* 0000018C nop                            */  0x90,
>> +  /* 0000018D nop                            */  0x90,
>> +  /* 0000018E nop                            */  0x90,
>> +  /* 0000018F nop                            */  0x90,
>> +  /* 00000190 nop                            */  0x90,
>> +  /* 00000191 nop                            */  0x90,
>> +  /* 00000192 nop                            */  0x90,
>> +  /* 00000193 nop                            */  0x90,
>> +  /* 00000194 nop                            */  0x90,
>> +  /* 00000195 nop                            */  0x90,
>> +  /* 00000196 nop                            */  0x90,
>> +  /* 00000197 nop                            */  0x90,
>> +  /* 00000198 nop                            */  0x90,
>> +  /* 00000199 nop                            */  0x90,
>> +  /* 0000019A nop                            */  0x90,
>> +  /* 0000019B nop                            */  0x90,
>> +  /* 0000019C nop                            */  0x90,
>> +  /* 0000019D nop                            */  0x90,
>> +  /* 0000019E nop                            */  0x90,
>> +  /* 0000019F nop                            */  0x90,
>> +  /* 000001A0 nop                            */  0x90,
>> +  /* 000001A1 nop                            */  0x90,
>> +  /* 000001A2 nop                            */  0x90,
>> +  /* 000001A3 nop                            */  0x90,
>> +  /* 000001A4 nop                            */  0x90,
>> +  /* 000001A5 nop                            */  0x90,
>> +  /* 000001A6 nop                            */  0x90,
>> +  /* 000001A7 nop                            */  0x90,
>> +  /* 000001A8 nop                            */  0x90,
>> +  /* 000001A9 nop                            */  0x90,
>> +  /* 000001AA nop                            */  0x90,
>> +  /* 000001AB nop                            */  0x90,
>> +  /* 000001AC nop                            */  0x90,
>> +  /* 000001AD nop                            */  0x90,
>> +  /* 000001AE nop                            */  0x90,
>> +  /* 000001AF nop                            */  0x90,
>> +  /* 000001B0 nop                            */  0x90,
>> +  /* 000001B1 nop                            */  0x90,
>> +  /* 000001B2 nop                            */  0x90,
>> +  /* 000001B3 nop                            */  0x90,
>> +  /* 000001B4 nop                            */  0x90,
>> +  /* 000001B5 nop                            */  0x90,
>> +  /* 000001B6 nop                            */  0x90,
>> +  /* 000001B7 nop                            */  0x90,
>> +  /* 000001B8 nop                            */  0x90,
>> +  /* 000001B9 nop                            */  0x90,
>> +  /* 000001BA nop                            */  0x90,
>> +  /* 000001BB nop                            */  0x90,
>> +  /* 000001BC nop                            */  0x90,
>> +  /* 000001BD nop                            */  0x90,
>> +  /* 000001BE nop                            */  0x90,
>> +  /* 000001BF nop                            */  0x90,
>> +  /* 000001C0 nop                            */  0x90,
>> +  /* 000001C1 nop                            */  0x90,
>> +  /* 000001C2 nop                            */  0x90,
>> +  /* 000001C3 nop                            */  0x90,
>> +  /* 000001C4 nop                            */  0x90,
>> +  /* 000001C5 nop                            */  0x90,
>> +  /* 000001C6 nop                            */  0x90,
>> +  /* 000001C7 nop                            */  0x90,
>> +  /* 000001C8 nop                            */  0x90,
>> +  /* 000001C9 nop                            */  0x90,
>> +  /* 000001CA nop                            */  0x90,
>> +  /* 000001CB nop                            */  0x90,
>> +  /* 000001CC nop                            */  0x90,
>> +  /* 000001CD nop                            */  0x90,
>> +  /* 000001CE nop                            */  0x90,
>> +  /* 000001CF nop                            */  0x90,
>> +  /* 000001D0 nop                            */  0x90,
>> +  /* 000001D1 nop                            */  0x90,
>> +  /* 000001D2 nop                            */  0x90,
>> +  /* 000001D3 nop                            */  0x90,
>> +  /* 000001D4 nop                            */  0x90,
>> +  /* 000001D5 nop                            */  0x90,
>> +  /* 000001D6 nop                            */  0x90,
>> +  /* 000001D7 nop                            */  0x90,
>> +  /* 000001D8 nop                            */  0x90,
>> +  /* 000001D9 nop                            */  0x90,
>> +  /* 000001DA nop                            */  0x90,
>> +  /* 000001DB nop                            */  0x90,
>> +  /* 000001DC nop                            */  0x90,
>> +  /* 000001DD nop                            */  0x90,
>> +  /* 000001DE nop                            */  0x90,
>> +  /* 000001DF nop                            */  0x90,
>> +  /* 000001E0 nop                            */  0x90,
>> +  /* 000001E1 nop                            */  0x90,
>> +  /* 000001E2 nop                            */  0x90,
>> +  /* 000001E3 nop                            */  0x90,
>> +  /* 000001E4 nop                            */  0x90,
>> +  /* 000001E5 nop                            */  0x90,
>> +  /* 000001E6 nop                            */  0x90,
>> +  /* 000001E7 nop                            */  0x90,
>> +  /* 000001E8 nop                            */  0x90,
>> +  /* 000001E9 nop                            */  0x90,
>> +  /* 000001EA nop                            */  0x90,
>> +  /* 000001EB nop                            */  0x90,
>> +  /* 000001EC nop                            */  0x90,
>> +  /* 000001ED nop                            */  0x90,
>> +  /* 000001EE nop                            */  0x90,
>> +  /* 000001EF nop                            */  0x90,
>> +  /* 000001F0 nop                            */  0x90,
>> +  /* 000001F1 nop                            */  0x90,
>> +  /* 000001F2 nop                            */  0x90,
>> +  /* 000001F3 nop                            */  0x90,
>> +  /* 000001F4 nop                            */  0x90,
>> +  /* 000001F5 nop                            */  0x90,
>> +  /* 000001F6 nop                            */  0x90,
>> +  /* 000001F7 nop                            */  0x90,
>> +  /* 000001F8 nop                            */  0x90,
>> +  /* 000001F9 nop                            */  0x90,
>> +  /* 000001FA nop                            */  0x90,
>> +  /* 000001FB nop                            */  0x90,
>> +  /* 000001FC nop                            */  0x90,
>> +  /* 000001FD nop                            */  0x90,
>> +  /* 000001FE nop                            */  0x90,
>> +  /* 000001FF nop                            */  0x90,
>> +  /* 00000200 cmp ax,0x4f00                  */  0x3D, 0x00, 0x4F,
>> +  /* 00000203 jz 0x237                       */  0x74, 0x32,
>> +  /* 00000205 cmp ax,0x4f01                  */  0x3D, 0x01, 0x4F,
>> +  /* 00000208 jz 0x257                       */  0x74, 0x4D,
>> +  /* 0000020A cmp ax,0x4f02                  */  0x3D, 0x02, 0x4F,
>> +  /* 0000020D jz near 0x2c8                  */  0x0F, 0x84, 0xB7, 0x00,
>> +  /* 00000211 cmp ax,0x4f03                  */  0x3D, 0x03, 0x4F,
>> +  /* 00000214 jz near 0x325                  */  0x0F, 0x84, 0x0D, 0x01,
>> +  /* 00000218 cmp ax,0x4f10                  */  0x3D, 0x10, 0x4F,
>> +  /* 0000021B jz near 0x337                  */  0x0F, 0x84, 0x18, 0x01,
>> +  /* 0000021F cmp ax,0x4f15                  */  0x3D, 0x15, 0x4F,
>> +  /* 00000222 jz near 0x344                  */  0x0F, 0x84, 0x1E, 0x01,
>> +  /* 00000226 cmp ah,0x0                     */  0x80, 0xFC, 0x00,
>> +  /* 00000229 jz near 0x363                  */  0x0F, 0x84, 0x36, 0x01,
>> +  /* 0000022D push si                        */  0x56,
>> +  /* 0000022E mov si,0x3d7                   */  0xBE, 0xD7, 0x03,
>> +  /* 00000231 call 0x3ad                     */  0xE8, 0x79, 0x01,
>> +  /* 00000234 pop si                         */  0x5E,
>> +  /* 00000235 jmp short 0x235                */  0xEB, 0xFE,
>> +  /* 00000237 push es                        */  0x06,
>> +  /* 00000238 push di                        */  0x57,
>> +  /* 00000239 push ds                        */  0x1E,
>> +  /* 0000023A push si                        */  0x56,
>> +  /* 0000023B push cx                        */  0x51,
>> +  /* 0000023C push si                        */  0x56,
>> +  /* 0000023D mov si,0x3eb                   */  0xBE, 0xEB, 0x03,
>> +  /* 00000240 call 0x3ad                     */  0xE8, 0x6A, 0x01,
>> +  /* 00000243 pop si                         */  0x5E,
>> +  /* 00000244 push cs                        */  0x0E,
>> +  /* 00000245 pop ds                         */  0x1F,
>> +  /* 00000246 mov si,0x0                     */  0xBE, 0x00, 0x00,
>> +  /* 00000249 mov cx,0x100                   */  0xB9, 0x00, 0x01,
>> +  /* 0000024C cld                            */  0xFC,
>> +  /* 0000024D rep movsb                      */  0xF3, 0xA4,
>> +  /* 0000024F pop cx                         */  0x59,
>> +  /* 00000250 pop si                         */  0x5E,
>> +  /* 00000251 pop ds                         */  0x1F,
>> +  /* 00000252 pop di                         */  0x5F,
>> +  /* 00000253 pop es                         */  0x07,
>> +  /* 00000254 jmp 0x395                      */  0xE9, 0x3E, 0x01,
>> +  /* 00000257 push es                        */  0x06,
>> +  /* 00000258 push di                        */  0x57,
>> +  /* 00000259 push ds                        */  0x1E,
>> +  /* 0000025A push si                        */  0x56,
>> +  /* 0000025B push cx                        */  0x51,
>> +  /* 0000025C push si                        */  0x56,
>> +  /* 0000025D mov si,0x3f6                   */  0xBE, 0xF6, 0x03,
>> +  /* 00000260 call 0x3ad                     */  0xE8, 0x4A, 0x01,
>> +  /* 00000263 pop si                         */  0x5E,
>> +  /* 00000264 and cx,0xbfff                  */  0x81, 0xE1, 0xFF, 0xBF,
>> +  /* 00000268 cmp cx,0x13f                   */  0x81, 0xF9, 0x3F, 0x01,
>> +  /* 0000026C jz 0x284                       */  0x74, 0x16,
>> +  /* 0000026E cmp cx,0x140                   */  0x81, 0xF9, 0x40, 0x01,
>> +  /* 00000272 jz 0x291                       */  0x74, 0x1D,
>> +  /* 00000274 cmp cx,0x141                   */  0x81, 0xF9, 0x41, 0x01,
>> +  /* 00000278 jz 0x29e                       */  0x74, 0x24,
>> +  /* 0000027A push si                        */  0x56,
>> +  /* 0000027B mov si,0x42c                   */  0xBE, 0x2C, 0x04,
>> +  /* 0000027E call 0x3ad                     */  0xE8, 0x2C, 0x01,
>> +  /* 00000281 pop si                         */  0x5E,
>> +  /* 00000282 jmp short 0x235                */  0xEB, 0xB1,
>> +  /* 00000284 push si                        */  0x56,
>> +  /* 00000285 mov si,0x46b                   */  0xBE, 0x6B, 0x04,
>> +  /* 00000288 call 0x3ad                     */  0xE8, 0x22, 0x01,
>> +  /* 0000028B pop si                         */  0x5E,
>> +  /* 0000028C mov si,0x100                   */  0xBE, 0x00, 0x01,
>> +  /* 0000028F jmp short 0x2b8                */  0xEB, 0x27,
>> +  /* 00000291 push si                        */  0x56,
>> +  /* 00000292 mov si,0x47d                   */  0xBE, 0x7D, 0x04,
>> +  /* 00000295 call 0x3ad                     */  0xE8, 0x15, 0x01,
>> +  /* 00000298 pop si                         */  0x5E,
>> +  /* 00000299 mov si,0x132                   */  0xBE, 0x32, 0x01,
>> +  /* 0000029C jmp short 0x2b8                */  0xEB, 0x1A,
>> +  /* 0000029E push si                        */  0x56,
>> +  /* 0000029F mov si,0x48f                   */  0xBE, 0x8F, 0x04,
>> +  /* 000002A2 call 0x3ad                     */  0xE8, 0x08, 0x01,
>> +  /* 000002A5 pop si                         */  0x5E,
>> +  /* 000002A6 mov si,0x164                   */  0xBE, 0x64, 0x01,
>> +  /* 000002A9 jmp short 0x2b8                */  0xEB, 0x0D,
>> +  /* 000002AB push si                        */  0x56,
>> +  /* 000002AC mov si,0x4a2                   */  0xBE, 0xA2, 0x04,
>> +  /* 000002AF call 0x3ad                     */  0xE8, 0xFB, 0x00,
>> +  /* 000002B2 pop si                         */  0x5E,
>> +  /* 000002B3 mov si,0x196                   */  0xBE, 0x96, 0x01,
>> +  /* 000002B6 jmp short 0x2b8                */  0xEB, 0x00,
>> +  /* 000002B8 push cs                        */  0x0E,
>> +  /* 000002B9 pop ds                         */  0x1F,
>> +  /* 000002BA mov cx,0x32                    */  0xB9, 0x32, 0x00,
>> +  /* 000002BD cld                            */  0xFC,
>> +  /* 000002BE rep movsb                      */  0xF3, 0xA4,
>> +  /* 000002C0 pop cx                         */  0x59,
>> +  /* 000002C1 pop si                         */  0x5E,
>> +  /* 000002C2 pop ds                         */  0x1F,
>> +  /* 000002C3 pop di                         */  0x5F,
>> +  /* 000002C4 pop es                         */  0x07,
>> +  /* 000002C5 jmp 0x395                      */  0xE9, 0xCD, 0x00,
>> +  /* 000002C8 push dx                        */  0x52,
>> +  /* 000002C9 push ax                        */  0x50,
>> +  /* 000002CA push si                        */  0x56,
>> +  /* 000002CB mov si,0x410                   */  0xBE, 0x10, 0x04,
>> +  /* 000002CE call 0x3ad                     */  0xE8, 0xDC, 0x00,
>> +  /* 000002D1 pop si                         */  0x5E,
>> +  /* 000002D2 and bx,0xbfff                  */  0x81, 0xE3, 0xFF, 0xBF,
>> +  /* 000002D6 cmp bx,0x13f                   */  0x81, 0xFB, 0x3F, 0x01,
>> +  /* 000002DA jz 0x2f3                       */  0x74, 0x17,
>> +  /* 000002DC cmp bx,0x140                   */  0x81, 0xFB, 0x40, 0x01,
>> +  /* 000002E0 jz 0x2fd                       */  0x74, 0x1B,
>> +  /* 000002E2 cmp bx,0x141                   */  0x81, 0xFB, 0x41, 0x01,
>> +  /* 000002E6 jz 0x307                       */  0x74, 0x1F,
>> +  /* 000002E8 push si                        */  0x56,
>> +  /* 000002E9 mov si,0x42c                   */  0xBE, 0x2C, 0x04,
>> +  /* 000002EC call 0x3ad                     */  0xE8, 0xBE, 0x00,
>> +  /* 000002EF pop si                         */  0x5E,
>> +  /* 000002F0 jmp 0x235                      */  0xE9, 0x42, 0xFF,
>> +  /* 000002F3 push si                        */  0x56,
>> +  /* 000002F4 mov si,0x46b                   */  0xBE, 0x6B, 0x04,
>> +  /* 000002F7 call 0x3ad                     */  0xE8, 0xB3, 0x00,
>> +  /* 000002FA pop si                         */  0x5E,
>> +  /* 000002FB jmp short 0x319                */  0xEB, 0x1C,
>> +  /* 000002FD push si                        */  0x56,
>> +  /* 000002FE mov si,0x47d                   */  0xBE, 0x7D, 0x04,
>> +  /* 00000301 call 0x3ad                     */  0xE8, 0xA9, 0x00,
>> +  /* 00000304 pop si                         */  0x5E,
>> +  /* 00000305 jmp short 0x319                */  0xEB, 0x12,
>> +  /* 00000307 push si                        */  0x56,
>> +  /* 00000308 mov si,0x48f                   */  0xBE, 0x8F, 0x04,
>> +  /* 0000030B call 0x3ad                     */  0xE8, 0x9F, 0x00,
>> +  /* 0000030E pop si                         */  0x5E,
>> +  /* 0000030F jmp short 0x319                */  0xEB, 0x08,
>> +  /* 00000311 push si                        */  0x56,
>> +  /* 00000312 mov si,0x4a2                   */  0xBE, 0xA2, 0x04,
>> +  /* 00000315 call 0x3ad                     */  0xE8, 0x95, 0x00,
>> +  /* 00000318 pop si                         */  0x5E,
>> +  /* 00000319 mov [0x4b0],bl                 */  0x88, 0x1E, 0xB0, 0x04,
>> +  /* 0000031D mov [0x4b1],bh                 */  0x88, 0x3E, 0xB1, 0x04,
>> +  /* 00000321 pop ax                         */  0x58,
>> +  /* 00000322 pop dx                         */  0x5A,
>> +  /* 00000323 jmp short 0x395                */  0xEB, 0x70,
>> +  /* 00000325 push si                        */  0x56,
>> +  /* 00000326 mov si,0x405                   */  0xBE, 0x05, 0x04,
>> +  /* 00000329 call 0x3ad                     */  0xE8, 0x81, 0x00,
>> +  /* 0000032C pop si                         */  0x5E,
>> +  /* 0000032D mov bl,[0x4b0]                 */  0x8A, 0x1E, 0xB0, 0x04,
>> +  /* 00000331 mov bh,[0x4b1]                 */  0x8A, 0x3E, 0xB1, 0x04,
>> +  /* 00000335 jmp short 0x395                */  0xEB, 0x5E,
>> +  /* 00000337 push si                        */  0x56,
>> +  /* 00000338 mov si,0x43b                   */  0xBE, 0x3B, 0x04,
>> +  /* 0000033B call 0x3ad                     */  0xE8, 0x6F, 0x00,
>> +  /* 0000033E pop si                         */  0x5E,
>> +  /* 0000033F mov bx,0x80                    */  0xBB, 0x80, 0x00,
>> +  /* 00000342 jmp short 0x395                */  0xEB, 0x51,
>> +  /* 00000344 push es                        */  0x06,
>> +  /* 00000345 push di                        */  0x57,
>> +  /* 00000346 push ds                        */  0x1E,
>> +  /* 00000347 push si                        */  0x56,
>> +  /* 00000348 push cx                        */  0x51,
>> +  /* 00000349 push si                        */  0x56,
>> +  /* 0000034A mov si,0x450                   */  0xBE, 0x50, 0x04,
>> +  /* 0000034D call 0x3ad                     */  0xE8, 0x5D, 0x00,
>> +  /* 00000350 pop si                         */  0x5E,
>> +  /* 00000351 push cs                        */  0x0E,
>> +  /* 00000352 pop ds                         */  0x1F,
>> +  /* 00000353 mov si,0x4b2                   */  0xBE, 0xB2, 0x04,
>> +  /* 00000356 mov cx,0x80                    */  0xB9, 0x80, 0x00,
>> +  /* 00000359 cld                            */  0xFC,
>> +  /* 0000035A rep movsb                      */  0xF3, 0xA4,
>> +  /* 0000035C pop cx                         */  0x59,
>> +  /* 0000035D pop si                         */  0x5E,
>> +  /* 0000035E pop ds                         */  0x1F,
>> +  /* 0000035F pop di                         */  0x5F,
>> +  /* 00000360 pop es                         */  0x07,
>> +  /* 00000361 jmp short 0x395                */  0xEB, 0x32,
>> +  /* 00000363 push si                        */  0x56,
>> +  /* 00000364 mov si,0x41b                   */  0xBE, 0x1B, 0x04,
>> +  /* 00000367 call 0x3ad                     */  0xE8, 0x43, 0x00,
>> +  /* 0000036A pop si                         */  0x5E,
>> +  /* 0000036B cmp al,0x3                     */  0x3C, 0x03,
>> +  /* 0000036D jz 0x37e                       */  0x74, 0x0F,
>> +  /* 0000036F cmp al,0x12                    */  0x3C, 0x12,
>> +  /* 00000371 jz 0x38a                       */  0x74, 0x17,
>> +  /* 00000373 push si                        */  0x56,
>> +  /* 00000374 mov si,0x42c                   */  0xBE, 0x2C, 0x04,
>> +  /* 00000377 call 0x3ad                     */  0xE8, 0x33, 0x00,
>> +  /* 0000037A pop si                         */  0x5E,
>> +  /* 0000037B jmp 0x235                      */  0xE9, 0xB7, 0xFE,
>> +  /* 0000037E push si                        */  0x56,
>> +  /* 0000037F mov si,0x45c                   */  0xBE, 0x5C, 0x04,
>> +  /* 00000382 call 0x3ad                     */  0xE8, 0x28, 0x00,
>> +  /* 00000385 pop si                         */  0x5E,
>> +  /* 00000386 mov al,0x0                     */  0xB0, 0x00,
>> +  /* 00000388 jmp short 0x38c                */  0xEB, 0x02,
>> +  /* 0000038A mov al,0x0                     */  0xB0, 0x00,
>> +  /* 0000038C push si                        */  0x56,
>> +  /* 0000038D mov si,0x3c2                   */  0xBE, 0xC2, 0x03,
>> +  /* 00000390 call 0x3ad                     */  0xE8, 0x1A, 0x00,
>> +  /* 00000393 pop si                         */  0x5E,
>> +  /* 00000394 iret                           */  0xCF,
>> +  /* 00000395 push si                        */  0x56,
>> +  /* 00000396 mov si,0x3c2                   */  0xBE, 0xC2, 0x03,
>> +  /* 00000399 call 0x3ad                     */  0xE8, 0x11, 0x00,
>> +  /* 0000039C pop si                         */  0x5E,
>> +  /* 0000039D mov ax,0x4f                    */  0xB8, 0x4F, 0x00,
>> +  /* 000003A0 iret                           */  0xCF,
>> +  /* 000003A1 push si                        */  0x56,
>> +  /* 000003A2 mov si,0x3c8                   */  0xBE, 0xC8, 0x03,
>> +  /* 000003A5 call 0x3ad                     */  0xE8, 0x05, 0x00,
>> +  /* 000003A8 pop si                         */  0x5E,
>> +  /* 000003A9 mov ax,0x24f                   */  0xB8, 0x4F, 0x02,
>> +  /* 000003AC iret                           */  0xCF,
>> +  /* 000003AD pusha                          */  0x60,
>> +  /* 000003AE push ds                        */  0x1E,
>> +  /* 000003AF push cs                        */  0x0E,
>> +  /* 000003B0 pop ds                         */  0x1F,
>> +  /* 000003B1 mov dx,0x220                   */  0xBA, 0x20, 0x02,
>> +  /* 000003B4 mov ax,0x0                     */  0xB8, 0x00, 0x00,
>> +  /* 000003B7 lodsb                          */  0xAC,
>> +  /* 000003B8 cmp al,0x0                     */  0x3C, 0x00,
>> +  /* 000003BA jz 0x3bf                       */  0x74, 0x03,
>> +  /* 000003BC out dx,al                      */  0xEE,
>> +  /* 000003BD jmp short 0x3b7                */  0xEB, 0xF8,
>> +  /* 000003BF pop ds                         */  0x1F,
>> +  /* 000003C0 popa                           */  0x61,
>> +  /* 000003C1 ret                            */  0xC3,
>> +  /* 000003C2 jna 0x413                      */  0x76, 0x4F,
>> +  /* 000003C4 imul cx,[di],byte +0xa         */  0x6B, 0x0D, 0x0A,
>> +  /* 000003C7 add [bp+0x55],dh               */  0x00, 0x76, 0x55,
>> +  /* 000003CA outsb                          */  0x6E,
>> +  /* 000003CB jnc 0x442                      */  0x73, 0x75,
>> +  /* 000003CD jo 0x43f                       */  0x70, 0x70,
>> +  /* 000003CF outsw                          */  0x6F,
>> +  /* 000003D0 jc 0x446                       */  0x72, 0x74,
>> +  /* 000003D2 fs or ax,0xa                   */  0x65, 0x64, 0x0D, 0x0A, 0x00,
>> +  /* 000003D7 jna 0x42e                      */  0x76, 0x55,
>> +  /* 000003D9 outsb                          */  0x6E,
>> +  /* 000003DA imul bp,[bp+0x6f],byte +0x77   */  0x6B, 0x6E, 0x6F, 0x77,
>> +  /* 000003DE outsb                          */  0x6E,
>> +  /* 000003DF and [bp+0x75],al               */  0x20, 0x46, 0x75,
>> +  /* 000003E2 outsb                          */  0x6E,
>> +  /* 000003E3 arpl [si+0x69],si              */  0x63, 0x74, 0x69,
>> +  /* 000003E6 outsw                          */  0x6F,
>> +  /* 000003E7 outsb                          */  0x6E,
>> +  /* 000003E8 or ax,0xa                      */  0x0D, 0x0A, 0x00,
>> +  /* 000003EB jna 0x434                      */  0x76, 0x47,
>> +  /* 000003ED gs jz 0x439                    */  0x65, 0x74, 0x49,
>> +  /* 000003F0 outsb                          */  0x6E,
>> +  /* 000003F1 outsd                          */  0x66, 0x6F,
>> +  /* 000003F3 or ax,0xa                      */  0x0D, 0x0A, 0x00,
>> +  /* 000003F6 jna 0x43f                      */  0x76, 0x47,
>> +  /* 000003F8 gs jz 0x448                    */  0x65, 0x74, 0x4D,
>> +  /* 000003FB outsw                          */  0x6F,
>> +  /* 000003FC gs dec cx                      */  0x64, 0x65, 0x49,
>> +  /* 000003FF outsb                          */  0x6E,
>> +  /* 00000400 outsd                          */  0x66, 0x6F,
>> +  /* 00000402 or ax,0xa                      */  0x0D, 0x0A, 0x00,
>> +  /* 00000405 jna 0x44e                      */  0x76, 0x47,
>> +  /* 00000407 gs jz 0x457                    */  0x65, 0x74, 0x4D,
>> +  /* 0000040A outsw                          */  0x6F,
>> +  /* 0000040B gs or ax,0xa                   */  0x64, 0x65, 0x0D, 0x0A, 0x00,
>> +  /* 00000410 jna 0x465                      */  0x76, 0x53,
>> +  /* 00000412 gs jz 0x462                    */  0x65, 0x74, 0x4D,
>> +  /* 00000415 outsw                          */  0x6F,
>> +  /* 00000416 gs or ax,0xa                   */  0x64, 0x65, 0x0D, 0x0A, 0x00,
>> +  /* 0000041B jna 0x470                      */  0x76, 0x53,
>> +  /* 0000041D gs jz 0x46d                    */  0x65, 0x74, 0x4D,
>> +  /* 00000420 outsw                          */  0x6F,
>> +  /* 00000421 gs dec sp                      */  0x64, 0x65, 0x4C,
>> +  /* 00000424 gs a32 popa                    */  0x65, 0x67, 0x61,
>> +  /* 00000427 arpl [bx+di+0xd],di            */  0x63, 0x79, 0x0D,
>> +  /* 0000042A or al,[bx+si]                  */  0x0A, 0x00,
>> +  /* 0000042C jna 0x483                      */  0x76, 0x55,
>> +  /* 0000042E outsb                          */  0x6E,
>> +  /* 0000042F imul bp,[bx+0x77],byte +0x6e   */  0x6B, 0x6F, 0x77, 0x6E,
>> +  /* 00000433 and [di+0x6f],cl               */  0x20, 0x4D, 0x6F,
>> +  /* 00000436 gs or ax,0xa                   */  0x64, 0x65, 0x0D, 0x0A, 0x00,
>> +  /* 0000043B jna 0x484                      */  0x76, 0x47,
>> +  /* 0000043D gs jz 0x490                    */  0x65, 0x74, 0x50,
>> +  /* 00000440 insw                           */  0x6D,
>> +  /* 00000441 inc bx                         */  0x43,
>> +  /* 00000442 popa                           */  0x61,
>> +  /* 00000443 jo 0x4a6                       */  0x70, 0x61,
>> +  /* 00000445 bound bp,[bx+di+0x6c]          */  0x62, 0x69, 0x6C,
>> +  /* 00000448 imul si,[si+0x69],word 0x7365  */  0x69, 0x74, 0x69, 0x65, 0x73,
>> +  /* 0000044D or ax,0xa                      */  0x0D, 0x0A, 0x00,
>> +  /* 00000450 jna 0x4a4                      */  0x76, 0x52,
>> +  /* 00000452 gs popa                        */  0x65, 0x61,
>> +  /* 00000454 fs inc bp                      */  0x64, 0x45,
>> +  /* 00000456 imul sp,[fs:si+0xd],word 0xa   */  0x64, 0x69, 0x64, 0x0D, 0x0A, 0x00,
>> +  /* 0000045C jna 0x4aa                      */  0x76, 0x4C,
>> +  /* 0000045E gs a32 popa                    */  0x65, 0x67, 0x61,
>> +  /* 00000461 arpl [bx+di+0x4d],di           */  0x63, 0x79, 0x4D,
>> +  /* 00000464 outsw                          */  0x6F,
>> +  /* 00000465 xor cx,[gs:di]                 */  0x64, 0x65, 0x33, 0x0D,
>> +  /* 00000469 or al,[bx+si]                  */  0x0A, 0x00,
>> +  /* 0000046B insw                           */  0x6D,
>> +  /* 0000046C outsw                          */  0x6F,
>> +  /* 0000046D gs pop di                      */  0x64, 0x65, 0x5F,
>> +  /* 00000470 ss xor al,0x30                 */  0x36, 0x34, 0x30,
>> +  /* 00000473 js 0x4a9                       */  0x78, 0x34,
>> +  /* 00000475 cmp [bx+si],dh                 */  0x38, 0x30,
>> +  /* 00000477 js 0x4ac                       */  0x78, 0x33,
>> +  /* 00000479 xor cl,[di]                    */  0x32, 0x0D,
>> +  /* 0000047B or al,[bx+si]                  */  0x0A, 0x00,
>> +  /* 0000047D insw                           */  0x6D,
>> +  /* 0000047E outsw                          */  0x6F,
>> +  /* 0000047F gs pop di                      */  0x64, 0x65, 0x5F,
>> +  /* 00000482 cmp [bx+si],dh                 */  0x38, 0x30,
>> +  /* 00000484 xor [bx+si+0x36],bh            */  0x30, 0x78, 0x36,
>> +  /* 00000487 xor [bx+si],dh                 */  0x30, 0x30,
>> +  /* 00000489 js 0x4be                       */  0x78, 0x33,
>> +  /* 0000048B xor cl,[di]                    */  0x32, 0x0D,
>> +  /* 0000048D or al,[bx+si]                  */  0x0A, 0x00,
>> +  /* 0000048F insw                           */  0x6D,
>> +  /* 00000490 outsw                          */  0x6F,
>> +  /* 00000491 gs pop di                      */  0x64, 0x65, 0x5F,
>> +  /* 00000494 xor [bx+si],si                 */  0x31, 0x30,
>> +  /* 00000496 xor dh,[si]                    */  0x32, 0x34,
>> +  /* 00000498 js 0x4d1                       */  0x78, 0x37,
>> +  /* 0000049A cmp [ss:bx+si+0x33],bh         */  0x36, 0x38, 0x78, 0x33,
>> +  /* 0000049E xor cl,[di]                    */  0x32, 0x0D,
>> +  /* 000004A0 or al,[bx+si]                  */  0x0A, 0x00,
>> +  /* 000004A2 insw                           */  0x6D,
>> +  /* 000004A3 outsw                          */  0x6F,
>> +  /* 000004A4 gs pop di                      */  0x64, 0x65, 0x5F,
>> +  /* 000004A7 jnz 0x517                      */  0x75, 0x6E,
>> +  /* 000004A9 jnz 0x51e                      */  0x75, 0x73,
>> +  /* 000004AB fs or ax,0xa                   */  0x65, 0x64, 0x0D, 0x0A, 0x00,
>> +  /* 000004B0 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004B2 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004B4 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004B6 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004B8 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004BA add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004BC add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004BE add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004C0 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004C2 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004C4 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004C6 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004C8 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004CA add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004CC add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004CE add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004D0 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004D2 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004D4 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004D6 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004D8 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004DA add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004DC add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004DE add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004E0 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004E2 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004E4 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004E6 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004E8 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004EA add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004EC add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004EE add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004F0 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004F2 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004F4 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004F6 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004F8 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004FA add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004FC add [bx+si],al                 */  0x00, 0x00,
>> +  /* 000004FE add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000500 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000502 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000504 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000506 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000508 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 0000050A add [bx+si],al                 */  0x00, 0x00,
>> +  /* 0000050C add [bx+si],al                 */  0x00, 0x00,
>> +  /* 0000050E add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000510 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000512 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000514 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000516 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000518 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 0000051A add [bx+si],al                 */  0x00, 0x00,
>> +  /* 0000051C add [bx+si],al                 */  0x00, 0x00,
>> +  /* 0000051E add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000520 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000522 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000524 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000526 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000528 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 0000052A add [bx+si],al                 */  0x00, 0x00,
>> +  /* 0000052C add [bx+si],al                 */  0x00, 0x00,
>> +  /* 0000052E add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000530 add [bx+si],al                 */  0x00, 0x00,
>> +  /* 00000532 add [bx+si],al                 */  0x00, 0x00,
>> +};
>> +#endif
>> diff --git a/OvmfPkg/IntelGvtGopDxe/VbeShim.sh b/OvmfPkg/IntelGvtGopDxe/VbeShim.sh
>> new file mode 100755
>> index 000000000000..4f61e5220b01
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/VbeShim.sh
>> @@ -0,0 +1,81 @@
>> +#!/bin/sh
>> +###
>> +# @file
>> +# Shell script to assemble and dump the fake Int10h handler from NASM source to
>> +# a C array.
>> +#
>> +# Copyright (C) 2021, Intel Corporation. All rights reserved.<BR>
>> +# Copyright (C) 2020, Rebecca Cran <rebecca@bsdio.com>
>> +# Copyright (C) 2014, Red Hat, Inc.
>> +# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
>> +#
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +###
>> +
>> +set -e -u
>> +
>> +STEM=$(dirname -- "$0")/$(basename -- "$0" .sh)
>> +
>> +#
>> +# Install exit handler -- remove temporary files.
>> +#
>> +exit_handler()
>> +{
>> +  rm -f -- "$STEM".bin "$STEM".disasm "$STEM".offsets "$STEM".insns \
>> +      "$STEM".bytes
>> +}
>> +trap exit_handler EXIT
>> +
>> +#
>> +# Assemble the source file.
>> +#
>> +nasm -o "$STEM".bin "$STEM".asm
>> +
>> +#
>> +# Disassemble it, in order to get a binary dump associated with the source.
>> +# (ndisasm doesn't recognize the "--" end-of-options delimiter.)
>> +#
>> +ndisasm "$STEM".bin >"$STEM".disasm
>> +
>> +#
>> +# Create three files, each with one column of the disassembly.
>> +#
>> +# The first column contains the offsets, and it starts the comment.
>> +#
>> +cut -c 1-8 -- "$STEM".disasm \
>> +| sed -e 's,^,  /* ,' >"$STEM".offsets
>> +
>> +#
>> +# The second column contains the assembly-language instructions, and it closes
>> +# the comment. We first pad it to 30 characters.
>> +#
>> +cut -c 29- -- "$STEM".disasm \
>> +| sed -e 's,$,                              ,' \
>> +      -e 's,^\(.\{30\}\).*$,\1 */,' >"$STEM".insns
>> +
>> +#
>> +# The third column contains the bytes corresponding to the instruction,
>> +# represented as C integer constants. First strip trailing whitespace from the
>> +# middle column of the input disassembly, then process pairs of nibbles.
>> +#
>> +cut -c 11-28 -- "$STEM".disasm \
>> +| sed -e 's, \+$,,' -e 's/\(..\)/ 0x\1,/g' | sed 's/0x  ,//g' >"$STEM".bytes
>> +
>> +#
>> +# Write the output file, recombining the columns. The output should have CRLF
>> +# line endings.
>> +#
>> +{
>> +  printf '//\n'
>> +  printf '// THIS FILE WAS GENERATED BY "%s". DO NOT EDIT.\n' \
>> +      "$(basename -- "$0")"
>> +  printf '//\n'
>> +  printf '#ifndef _VBE_SHIM_H_\n'
>> +  printf '#define _VBE_SHIM_H_\n'
>> +  printf 'STATIC CONST UINT8 gVbeShim[] = {\n'
>> +  paste -d ' ' -- "$STEM".offsets "$STEM".insns "$STEM".bytes
>> +  printf '};\n'
>> +  printf '#endif\n'
>> +} \
>> +| unix2dos >"$STEM".h
>> diff --git a/OvmfPkg/IntelGvtGopDxe/VirtualGpu.c b/OvmfPkg/IntelGvtGopDxe/VirtualGpu.c
>> new file mode 100644
>> index 000000000000..dc2c23706c8b
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/VirtualGpu.c
>> @@ -0,0 +1,400 @@
>> +/** @file
>> +  Component name for the QEMU video controller.
>> +
>> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include "Common.h"
>> +#include "VirtualGpu.h"
>> +#include "GpuReg.h"
>> +#include "Gtt.h"
>> +#include "Display.h"
>> +#include <Library/QemuFwCfgLib.h>
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuActive (
>> +  IN EFI_PCI_IO_PROTOCOL *PciIo
>> +  )
>> +{
>> +  EFI_STATUS Status = EFI_UNSUPPORTED;
>> +  PCI_TYPE00 PciHdr = {0};
>> +  UINT64     Magic = 0;
>> +  UINT32     Version = 0;
>> +  UINT16     VerMajor = 0, VerMinor = 0;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  Status = PciIo->Pci.Read (
>> +                        PciIo,
>> +                        EfiPciIoWidthUint32,
>> +                        0,
>> +                        sizeof (PciHdr) / sizeof (UINT32),
>> +                        &PciHdr
>> +                        );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Can't read PCI config header, status %d\n", Status
>> +      );
>> +    Status = EFI_UNSUPPORTED;
>> +    goto Done;
>> +  }
>> +
>> +  if (!IS_PCI_DISPLAY (&PciHdr) || PciHdr.Hdr.VendorId != 0x8086) {
>> +    GVT_DEBUG (EFI_D_VERBOSE,
>> +      "Skip non Intel PCI Display [%04x:%04x] class:%x\n",
>> +      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, PciHdr.Hdr.ClassCode[2]
>> +      );
>> +    Status = EFI_UNSUPPORTED;
>> +    goto Done;
>> +  }
>> +
>> +  Status = PciIo->Mem.Read (
>> +                        PciIo,
>> +                        EfiPciIoWidthUint64,
>> +                        PCI_BAR_IDX0,
>> +                        vgtif_reg(magic),
>> +                        1,
>> +                        &Magic
>> +                        );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Can't read GVT magic from [%04x:%04x], status %d\n",
>> +      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, Status
>> +      );
>> +    Status = EFI_UNSUPPORTED;
>> +    goto Done;
>> +  }
>> +
>> +  if (Magic != VGT_MAGIC) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Read magic from [%04x:%04x], get %x expect %x\n",
>> +      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, Magic, VGT_MAGIC
>> +      );
>> +    Status = EFI_UNSUPPORTED;
>> +    goto Done;
>> +  }
>> +
>> +  Status = PciIo->Mem.Read (
>> +                        PciIo,
>> +                        EfiPciIoWidthUint32,
>> +                        PCI_BAR_IDX0,
>> +                        vgtif_reg(version_major),
>> +                        1,
>> +                        &Version
>> +                        );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Can't read GVT version from [%04x:%04x], status %d\n",
>> +      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, Status
>> +      );
>> +    Status = EFI_UNSUPPORTED;
>> +    goto Done;
>> +  }
>> +
>> +  VerMajor = Version & 0xFFFF;
>> +  VerMinor = (Version & 0xFFFF) >> 16;
>> +  if (VerMajor < VGT_VERSION_MAJOR) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Check VGT interface version of [%04x:%04x], got %x.%x, expect %x.*\n",
>> +      PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId,
>> +      VerMajor, VerMinor, VGT_VERSION_MAJOR
>> +      );
>> +    Status = EFI_UNSUPPORTED;
>> +    goto Done;
>> +  }
>> +
>> +  GVT_DEBUG (EFI_D_INFO,
>> +    "Intel GVT-g virtual GPU [%04x:%04x] detected, version %x.%x\n",
>> +    PciHdr.Hdr.VendorId, PciHdr.Hdr.DeviceId, VerMajor, VerMinor
>> +    );
>> +  Status = EFI_SUCCESS;
>> +
>> +Done:
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuInit (
>> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
>> +  )
>> +{
>> +  EFI_STATUS           Status = EFI_UNSUPPORTED;
>> +  EFI_PCI_IO_PROTOCOL  *PciIo;
>> +  PINTEL_VIRTUAL_GPU   VirtualGpu;
>> +  FIRMWARE_CONFIG_ITEM FwCfgItem;
>> +  UINTN                FwCfgSize;
>> +  UINT8                Val8;
>> +  UINT64               Val64;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  PciIo = Private->PciIo;
>> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
>> +  Status = PciIo->Pci.Read (
>> +                        PciIo,
>> +                        EfiPciIoWidthUint16,
>> +                        PCI_VENDOR_ID_OFFSET,
>> +                        1,
>> +                        &VirtualGpu->VendorId
>> +                        );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Can't read PCI_VENDOR_ID_OFFSET, status %d\n", Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  Status = PciIo->Pci.Read (
>> +                        PciIo,
>> +                        EfiPciIoWidthUint16,
>> +                        PCI_DEVICE_ID_OFFSET,
>> +                        1,
>> +                        &VirtualGpu->DeviceId
>> +                        );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Can't read PCI_DEVICE_ID_OFFSET, status %d\n", Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  Status = PciIo->Pci.Read (
>> +                        PciIo,
>> +                        EfiPciIoWidthUint64,
>> +                        PCI_BASE_ADDRESSREG_OFFSET + PCI_BAR_IDX2 * 4,
>> +                        1,
>> +                        &Val64
>> +                        );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR, "Can't get GMADR from BAR2, status %d\n", Status);
>> +    goto Done;
>> +  }
>> +
>> +  if (Val64 & 0x1) {
>> +    Status = EFI_OUT_OF_RESOURCES;
>> +    GVT_DEBUG (EFI_D_ERROR, "BAR2 isn't memory space, status %d\n", Status);
>> +    goto Done;
>> +  }
>> +
>> +  switch (Val64 >> 1 & 0x3) {
>> +  case 0:
>> +    VirtualGpu->GpuMemAddr = Val64 & 0xFFFFFFF0;
>> +    GVT_DEBUG (EFI_D_VERBOSE, "BAR2 has 32-bit access space\n");
>> +    break;
>> +  case 2:
>> +    VirtualGpu->GpuMemAddr = Val64 & ~0xF;
>> +    GVT_DEBUG (EFI_D_VERBOSE, "BAR2 has 64-bit access space\n");
>> +    break;
>> +  default:
>> +    Status = EFI_OUT_OF_RESOURCES;
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "BAR2 has unknown access space, status %d\n", Status
>> +      );
>> +    goto Done;
>> +    break;
>> +  }
>> +
>> +  Status = PciIo->Pci.Read (
>> +                        PciIo,
>> +                        EfiPciIoWidthUint8,
>> +                        PCI_REG_MSAC,
>> +                        1,
>> +                        &Val8
>> +                        );
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Can't get MSAC from %x, status %d\n", PCI_REG_MSAC, Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  Val8 &= 0x1F;
>> +  if (Val8 & 0x10) {
>> +    VirtualGpu->GpuMemSizeM = 4096;
>> +  } else {
>> +    Val8 &= 0xF;
>> +    if (Val8 & 0x8) {
>> +      VirtualGpu->GpuMemSizeM = 2048;
>> +    } else {
>> +      Val8 &= 0x7;
>> +      if (Val8 & 0x4) {
>> +        VirtualGpu->GpuMemSizeM = 1024;
>> +      } else {
>> +        Val8 &= 0x3;
>> +        if (Val8 & 0x2) {
>> +          VirtualGpu->GpuMemSizeM = 512;
>> +        } else {
>> +          if (Val8 & 0x1) {
>> +            VirtualGpu->GpuMemSizeM = 256;
>> +          } else {
>> +            VirtualGpu->GpuMemSizeM = 128;
>> +          }
>> +        }
>> +      }
>> +    }
>> +  }
>> +
>> +  Status = QemuFwCfgFindFile ("etc/igd-opregion", &FwCfgItem, &FwCfgSize);
>
> (1) This feature still relies on "etc/igd-opregion".
>
> And so, while this driver "poses" as a UEFI_DRIVER module for a PCI
> device, it remains a platform driver.
>
> That's still a deal-breaker -- please refer to
> <https://bugzilla.tianocore.org/show_bug.cgi?id=935>, specifically
> comment 15.
>
> Has there been any improvement regarding the requirement that the
> opregion come from QEMU via fw_cfg, for the Windows guest driver's sake?
>
> (I really wish you had first asked about this feature, before authoring
> a driver with 4000+ lines!)
>
Sorry for the confusion. Yes I understand the history in the case of IGD 
passthrough. Maybe it's better if I've added an RFC in the subject. I'm 
not intended to sell the patch directly, instead to have a patch first so 
that have more details to receive valuable comments. Either UEFI_DRIVER or 
platform driver should follow OVMF requirement for sure, there is no 
doubt for that.
The current igd-opregion indeed block us finding better solution to get 
rid of it due to the dependency of guest driver implementation. So for 
this part there is nothing can do but follow the driver behavior.

However there is still use case to boot a UEFI guest with only one 
GPU (Intel GVT-g vGPU) but there is no screen output duing non-OS stage, 
this is the exact problem this patch tries to resolve.

Unlike the patch you mentioned, the majority of this patch consists of two 
parts: GOP and mdev device emulation. I thought feedback on them are still 
valuable, thus sent out as a single patch first.

> (2) If the fw_cfg file in question is not found, the patch simply
> ignores it. We log a debug message about it (not even an error message),
> but then proceed with the rest of the code as if everything was OK.
>
> Is that intentional?

It's absolutely OK doing in this way. etc/igd-opregion is indeed not clear 
for OVMF. Assume future guest driver decouple itself with igd-opregion, 
which some guest driver doesn't rely on it already, the intention of this 
patch is to have a common solution for Intel GVT-g vGPU.

Again the intention is not push the patch into EDK2, but RFC and find out 
accepable part into upstream, either EDK2 or EDK2-platform. Sorry for 
not making it clear at first time.

>
> (3) There's a whole lot of style issues in the code, and I absolutely
> don't see myself identifying every single one of those for you, in a
> 4000+ line driver.
>
> (EFI_D_xxx macro usage, line wrapping issues with multi-line function
> calls, comment style problems, an assumption of varargs support with
> function-like macros on all edk2 toolchains, building the driver only
> for X64, ...)
>
Style issues are mainly due to I looked all around EDK2 and found 
different components have very different styles so just follow what I saw. 
I'll review them again and make sure there are fixed. I'll also double 
check and make sure all other compling toolchains won't be broken.
It'll be great if you cound suggest a good-style reference so that I can 
strictly follow it.

>
> I'd much prefer if you maintained this driver outside of OvmfPkg
> (perhaps somewhere in edk2-platforms, possibly under
> Drivers/OptionRomPkg/), and then, given a UEFI driver binary, you passed
> it to QEMU via the device's ROM BAR, per
> <https://bugzilla.tianocore.org/show_bug.cgi?id=935#c17>.
>
>
This is acceptable. In device pass through case, UEFI driver passed as ROM 
BAR are commonly used so it can meet the using scenario.

> I'd be *somewhat* open to accepting this driver into OvmfPkg if:
>
> - you formally assume on-going reviewership for the driver
> (Maintainers.txt),
>
Since it's tight to Intel GVT-g, I'll discuss with GVT-g maintainer and 
keep a on-going reviewship in the list so that it can be actively 
mainained as GVT-g.
> - you set the feature test macro in the DSC files to FALSE by default,
>
Consider it done. It won't be a problem.
> - you fix all the style issues with the help of other Intel contributors,
>
I'll revise and update.
> - you explicitly document somewhere that the fw_cfg access is a design
> bug in a UEFI driver (especially for an assigned device) -- it remains a
> platform driver, contrary to the semblance, for the sake of the arguably
> broken Windows guest driver,
>
Sure.
> - you make the driver 32-bit clean and include it in the IA32 and
> IA32X64 DSC files too.
>
Sure.
>
> I won't even mention how unreviewable a "patch bomb" like this is; such
> a driver should be constructed (erected) gradually over 10-20 patches at
> the minimum, isolating the UEFI driver model code from the device
> initialization from the various GOP member functions. I won't mention
> that because I don't intend to review this driver in depth anyway.
>
Not be a problem. I'll find a way to split the patch to a reviewable 
series.

> I might be willing to accept it as an optional (disabled by default)
> "code dump", as long as you ensure the bare minimum of edk2 style and
> build requirements, and take full responsibility for the driver in the
> future.
>

> ... Honestly, the fact that you never asked about this feature on any
> edk2 list, and that you (apparently) never searched the TianoCore
> bugzilla tracker for potentially related BZs (such as #935), doesn't
> really boost my confidence in this feature.
>
It's my negligence. I do realized the existence of #935, which is always 
referenced in some down-upstream project. The situation here is we have a 
user experience problem at first and need resolve it asap so the off-tree
patch is crafted first. Then we are looking for re-using the 
implemenation in up-stream so that it can benefits more open source users. 
Since the draft patch is done, it feels like reasonly to send to community 
as an opening so that experts can direclty suggest an acceptable way to 
re-use some of the implmentation to craft an upstream version. 
igd-opregion is a dirty part but is not the foundation or dependency of 
this GOP driver.


In summary if my understanding is correct, this driver is closer to a 
platform driver (due to it's dependecy to vfio) than a full simulated 
device driver. Maybe there is tiny chance it can be accepted in OvmfPkg, 
but Drivers/OptionRomPkg is the more proper place it should sit.

I'll send the revised version to Drivers/OptionRomPkg with all review 
comments (now & future) considered. igd-opregion maybe completely removed 
from the driver, or could be kept in code but disabled by default, the 
reason and explanation will be documented somewhere in case some very 
specific sceaniro requires.


"There's always a first step in everything". Please accept my apollogy if 
this first step had an impact on the technical discussion. As developer I 
payed more attention to the implemenation and re-usability, but could lack 
big picture thinking and overall considerations. Thus your and other 
maintainers' comments are very valuable to drive to the right direction.

> Laszlo
>
>> +  if (Status == EFI_SUCCESS && FwCfgSize == OPREGION_SIZE) {
>> +    // OpRegion must sit below 4 GB
>> +    VirtualGpu->OpRegion = SIZE_4GB - 1;
>> +    Status = gBS->AllocatePages (
>> +                AllocateMaxAddress,
>> +                EfiReservedMemoryType,
>> +                EFI_SIZE_TO_PAGES (OPREGION_SIZE),
>> +                &VirtualGpu->OpRegion
>> +                );
>> +    if (EFI_ERROR (Status)) {
>> +      GVT_DEBUG (EFI_D_ERROR,
>> +        "Fail to allocate %d pages size %lx for OpRegion, status %d\n",
>> +        EFI_SIZE_TO_PAGES (OPREGION_SIZE), OPREGION_SIZE, Status
>> +        );
>> +      goto Done;
>> +    }
>> +    QemuFwCfgSelectItem (FwCfgItem);
>> +    QemuFwCfgReadBytes (FwCfgSize, (VOID*)VirtualGpu->OpRegion);
>> +    Status = PciIo->Pci.Write (
>> +                          PciIo,
>> +                          EfiPciIoWidthUint32,
>> +                          PCI_REG_ASLS,
>> +                          1,
>> +                          (UINT32*)&VirtualGpu->OpRegion
>> +                          );
>> +    if (EFI_ERROR (Status)) {
>> +      GVT_DEBUG (EFI_D_ERROR,
>> +        "Fail to write OpRegion %p to PCI config offset 0x%x, status %d\n",
>> +        VirtualGpu->OpRegion, PCI_REG_ASLS, Status
>> +        );
>> +      goto Done;
>> +    } else {
>> +      GVT_DEBUG (EFI_D_INFO,
>> +        "OpRegion %p is set to PCI config offset 0x%x\n",
>> +        VirtualGpu->OpRegion, PCI_REG_ASLS
>> +        );
>> +    }
>> +  } else {
>> +    GVT_DEBUG (EFI_D_VERBOSE,
>> +      "Not igd-opregion found in QEMU firmware config\n"
>> +      );
>> +  }
>> +
>> +  RegRead32 (Private,
>> +    vgtif_reg(avail_rs.mappable_gmadr.base), &VirtualGpu->VisibleOffset);
>> +  RegRead32 (Private,
>> +    vgtif_reg(avail_rs.mappable_gmadr.size), &VirtualGpu->VisibleSize);
>> +  RegRead32 (Private,
>> +    vgtif_reg(avail_rs.nonmappable_gmadr.base), &VirtualGpu->InvisibleOffset);
>> +  RegRead32 (Private,
>> +    vgtif_reg(avail_rs.nonmappable_gmadr.size), &VirtualGpu->InvisibleSize);
>> +  VirtualGpu->VisibleGGTTOffset = VirtualGpu->VisibleOffset >> GTT_PAGE_SHIFT;
>> +  VirtualGpu->VisibleGGTTSize = VirtualGpu->VisibleSize >> GTT_PAGE_SHIFT;
>> +  VirtualGpu->InvisibleGGTTOffset = VirtualGpu->InvisibleOffset >> GTT_PAGE_SHIFT;
>> +  VirtualGpu->InvisibleGGTTSize = VirtualGpu->InvisibleSize >> GTT_PAGE_SHIFT;
>> +
>> +  GVT_DEBUG (
>> +    EFI_D_INFO,
>> +    "GMADR [0x%lx - 0x%lx], size %d MB\n",
>> +    VirtualGpu->GpuMemAddr,
>> +    VirtualGpu->GpuMemAddr + VirtualGpu->GpuMemSizeM * 0x100000,
>> +    VirtualGpu->GpuMemSizeM
>> +    );
>> +  GVT_DEBUG (
>> +    EFI_D_INFO,
>> +    "visible offset [0x%x - 0x%x] size %d KB, GGTT range [%x - %x]\n",
>> +    VirtualGpu->VisibleOffset,
>> +    VirtualGpu->VisibleOffset + VirtualGpu->VisibleSize,
>> +    VirtualGpu->VisibleSize / 0x400,
>> +    VirtualGpu->VisibleGGTTOffset,
>> +    VirtualGpu->VisibleGGTTOffset + VirtualGpu->VisibleGGTTSize
>> +    );
>> +  GVT_DEBUG (
>> +    EFI_D_INFO,
>> +    "invisible offset [0x%x - 0x%x] size %d KB, GGTT range [%x - %x]\n",
>> +    VirtualGpu->InvisibleOffset,
>> +    VirtualGpu->InvisibleOffset + VirtualGpu->InvisibleSize,
>> +    VirtualGpu->InvisibleSize / 0x400,
>> +    VirtualGpu->InvisibleGGTTOffset,
>> +    VirtualGpu->InvisibleGGTTOffset + VirtualGpu->InvisibleGGTTSize
>> +    );
>> +
>> +  Status = IntelVirtualGpuDisplayInit (Private);
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Fail to initialize display, status %d\n", Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  Status = IntelVirtualGpuSetMode (&Private->GraphicsOutputProtocol, 0);
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Fail to set init display mode, status %d\n", Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  Status = IntelVirtualGpuNotifyDisplayReady (Private, TRUE);
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR,
>> +      "Fail to notify display ready, status %d\n", Status
>> +      );
>> +    goto Done;
>> +  }
>> +
>> +  // Flush all reg after DisplayReady
>> +  Status = IntelVirtualGpuEnableDisplay (
>> +             Private,
>> +             0,
>> +             TRUE
>> +             );
>> +
>> +Done:
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuClean (
>> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
>> +  )
>> +{
>> +  EFI_STATUS         Status = EFI_INVALID_PARAMETER;
>> +  PINTEL_VIRTUAL_GPU VirtualGpu;
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: >>>\n", __FUNCTION__);
>> +
>> +  Status = IntelVirtualGpuDisplayClean (Private);
>> +  if (EFI_ERROR (Status)) {
>> +    GVT_DEBUG (EFI_D_ERROR, "Fail to clean display, status %d\n", Status);
>> +    goto Done;
>> +  }
>> +
>> +  VirtualGpu = (PINTEL_VIRTUAL_GPU)Private->VirtualGpu;
>> +  if (VirtualGpu->OpRegion) {
>> +    Status = gBS->FreePages (
>> +                    VirtualGpu->OpRegion,
>> +                    EFI_SIZE_TO_PAGES (OPREGION_SIZE)
>> +                    );
>> +    if (EFI_ERROR (Status)) {
>> +      GVT_DEBUG (EFI_D_ERROR,
>> +        "FreePages failed for OpRegion, pages %d, size %d, status %d\n",
>> +        EFI_SIZE_TO_PAGES (OPREGION_SIZE), OPREGION_SIZE, Status
>> +        );
>> +        goto Done;
>> +    }
>> +    Status = EFI_SUCCESS;
>> +  }
>> +
>> +Done:
>> +
>> +  GVT_DEBUG (EFI_D_VERBOSE, "%a: <<<\n", __FUNCTION__);
>> +
>> +  return Status;
>> +}
>> diff --git a/OvmfPkg/IntelGvtGopDxe/VirtualGpu.h b/OvmfPkg/IntelGvtGopDxe/VirtualGpu.h
>> new file mode 100644
>> index 000000000000..60d80eadb3ac
>> --- /dev/null
>> +++ b/OvmfPkg/IntelGvtGopDxe/VirtualGpu.h
>> @@ -0,0 +1,52 @@
>> +/** @file
>> +  Component name for the QEMU video controller.
>> +
>> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef __VIRTUALGPU_H_
>> +#define __VIRTUALGPU_H_
>> +
>> +#include <Display.h>
>> +
>> +#define PCI_REG_MSAC 0x62
>> +#define PCI_REG_ASLS 0xFC
>> +
>> +#define OPREGION_SIZE SIZE_8KB
>> +
>> +typedef struct _INTEL_VIRTUAL_GPU {
>> +  UINT16                    VendorId;
>> +  UINT16                    DeviceId;
>> +  EFI_PHYSICAL_ADDRESS      OpRegion;
>> +  EFI_PHYSICAL_ADDRESS      GpuMemAddr;
>> +  UINT32                    GpuMemSizeM;
>> +  UINT32                    VisibleOffset;
>> +  UINT32                    VisibleSize;
>> +  UINT32                    VisibleGGTTOffset;
>> +  UINT32                    VisibleGGTTSize;
>> +  UINT32                    InvisibleOffset;
>> +  UINT32                    InvisibleSize;
>> +  UINT32                    InvisibleGGTTOffset;
>> +  UINT32                    InvisibleGGTTSize;
>> +  INTEL_VIRTUAL_GPU_DISPLAY Display;
>> +} INTEL_VIRTUAL_GPU, *PINTEL_VIRTUAL_GPU;
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuActive (
>> +  IN EFI_PCI_IO_PROTOCOL *PciIo
>> +  );
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuInit (
>> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
>> +  );
>> +
>> +EFI_STATUS
>> +IntelVirtualGpuClean (
>> +  IN OUT GVT_GOP_PRIVATE_DATA *Private
>> +  );
>> +
>> +#endif //__VIRTUALGPU_H_
>>
>
>
>
> 
>
>
>

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

* Re: [edk2-devel] [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation.
  2021-03-05 13:19   ` [edk2-devel] " Laszlo Ersek
  2021-03-12  3:57     ` Colin Xu
@ 2021-03-12  4:42     ` Rebecca Cran
  2021-03-12  4:55       ` Colin Xu
  1 sibling, 1 reply; 11+ messages in thread
From: Rebecca Cran @ 2021-03-12  4:42 UTC (permalink / raw)
  To: devel, lersek, colin.xu; +Cc: Gerd Hoffmann, Alex Williamson

On 3/5/2021 6:19 AM, Laszlo Ersek wrote:

> (3) There's a whole lot of style issues in the code, and I absolutely
> don't see myself identifying every single one of those for you, in a
> 4000+ line driver.
>
> (EFI_D_xxx macro usage, line wrapping issues with multi-line function
> calls, comment style problems, an assumption of varargs support with
> function-like macros on all edk2 toolchains, building the driver only
> for X64, ...)

The other style issue I noticed was the leading double underscores in 
the include guards - e.g.:

diff --git a/OvmfPkg/IntelGvtGopDxe/Common.h b/OvmfPkg/IntelGvtGopDxe/Common.h
new file mode 100644
index 000000000000..cf30752eb8f3
--- /dev/null
+++ b/OvmfPkg/IntelGvtGopDxe/Common.h
@@ -0,0 +1,45 @@
+/** @file
+  Component name for the QEMU video controller.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __COMMON_H_

-- 
Rebecca Cran



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

* Re: [edk2-devel] [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation.
  2021-03-12  4:42     ` Rebecca Cran
@ 2021-03-12  4:55       ` Colin Xu
  0 siblings, 0 replies; 11+ messages in thread
From: Colin Xu @ 2021-03-12  4:55 UTC (permalink / raw)
  To: devel, rebecca; +Cc: lersek, colin.xu, Gerd Hoffmann, Alex Williamson



On Fri, 12 Mar 2021, Rebecca Cran wrote:

> On 3/5/2021 6:19 AM, Laszlo Ersek wrote:
>
>> (3) There's a whole lot of style issues in the code, and I absolutely
>> don't see myself identifying every single one of those for you, in a
>> 4000+ line driver.
>> 
>> (EFI_D_xxx macro usage, line wrapping issues with multi-line function
>> calls, comment style problems, an assumption of varargs support with
>> function-like macros on all edk2 toolchains, building the driver only
>> for X64, ...)
>
> The other style issue I noticed was the leading double underscores in the 
> include guards - e.g.:
>
Thanks Rebecca. I'll fix them.

Best Regards,
Colin

> diff --git a/OvmfPkg/IntelGvtGopDxe/Common.h 
> b/OvmfPkg/IntelGvtGopDxe/Common.h
> new file mode 100644
> index 000000000000..cf30752eb8f3
> --- /dev/null
> +++ b/OvmfPkg/IntelGvtGopDxe/Common.h
> @@ -0,0 +1,45 @@
> +/** @file
> +  Component name for the QEMU video controller.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __COMMON_H_
>
> -- 
> Rebecca Cran
>
>
>
>
> 
>
>
>

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

* Re: [edk2-devel] [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation.
  2021-03-12  3:57     ` Colin Xu
@ 2021-03-12 12:35       ` Gerd Hoffmann
  2021-03-19  2:08         ` Colin Xu
  0 siblings, 1 reply; 11+ messages in thread
From: Gerd Hoffmann @ 2021-03-12 12:35 UTC (permalink / raw)
  To: Colin Xu; +Cc: devel, lersek, alex.williamson, rebecca, zhenyuw

  Hi,

> Thanks a lot for your comment, Laszlo! See my reply also end of the patch.
> Hi Gerd, Alex, would you mind share your thoughts as well?

> > (2) If the fw_cfg file in question is not found, the patch simply
> > ignores it. We log a debug message about it (not even an error message),
> > but then proceed with the rest of the code as if everything was OK.
> > 
> > Is that intentional?
> 
> It's absolutely OK doing in this way. etc/igd-opregion is indeed not clear
> for OVMF. Assume future guest driver decouple itself with igd-opregion,
> which some guest driver doesn't rely on it already, the intention of this
> patch is to have a common solution for Intel GVT-g vGPU.

For reference, on seabios the opregion workflow looks like this:

  (1) i915 gvt kernel driver generates opregion content.
  (2) opregion is exported as special vfio region.
  (3) qemu copies over the content to etc/igd-opregion fw_cfg file.
  (4) seabios loads etc/igd-opregion, stores it in ram, writes the
      address to a register.
  (5) guest os driver reads the register to find the opregion.

So, first question is how dynamic is the opregion content?

On physical hardware it clearly is, it carries information on how
outputs are wired to physical DVI / HDMI / DP plugs and for laptops how
to drive the lvds panel built in.  For virtual hardware this is fixed
and a simple "all outputs are displayport".

What else is in there?  Anything which might need changes when the gvt
driver is updated?  Given that some guest drivers do not depend on the
opregion I assume this is not the case.

So I'm wondering whenever there is a good reason in the first place to
generate the opregion in the i915 gvt kernel driver.  Is it an option to
generate the opregion in this IntelGvtGopDxe driver instead?  That would
clearly be the easiest solution.

Failing that we should at least take fw_cfg out of the loop.  It is just
a middle man here and not needed at all.  As discussed before the pci
rom bar can do the job instead.  That will remove any platform
dependencies from the driver, it only need to talk to the device itself
then.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation.
  2021-03-12 12:35       ` Gerd Hoffmann
@ 2021-03-19  2:08         ` Colin Xu
  2021-03-19  9:06           ` kraxel
  0 siblings, 1 reply; 11+ messages in thread
From: Colin Xu @ 2021-03-19  2:08 UTC (permalink / raw)
  To: Gerd Hoffmann, zhenyuw
  Cc: Colin Xu, devel, lersek, alex.williamson, rebecca, zhenyuw

On Fri, 12 Mar 2021, Gerd Hoffmann wrote:

>  Hi,
>
>> Thanks a lot for your comment, Laszlo! See my reply also end of the patch.
>> Hi Gerd, Alex, would you mind share your thoughts as well?
>
>>> (2) If the fw_cfg file in question is not found, the patch simply
>>> ignores it. We log a debug message about it (not even an error message),
>>> but then proceed with the rest of the code as if everything was OK.
>>>
>>> Is that intentional?
>>
>> It's absolutely OK doing in this way. etc/igd-opregion is indeed not clear
>> for OVMF. Assume future guest driver decouple itself with igd-opregion,
>> which some guest driver doesn't rely on it already, the intention of this
>> patch is to have a common solution for Intel GVT-g vGPU.
>
> For reference, on seabios the opregion workflow looks like this:
>
>  (1) i915 gvt kernel driver generates opregion content.
>  (2) opregion is exported as special vfio region.
>  (3) qemu copies over the content to etc/igd-opregion fw_cfg file.
>  (4) seabios loads etc/igd-opregion, stores it in ram, writes the
>      address to a register.
>  (5) guest os driver reads the register to find the opregion.
>
> So, first question is how dynamic is the opregion content?
>
> On physical hardware it clearly is, it carries information on how
> outputs are wired to physical DVI / HDMI / DP plugs and for laptops how
> to drive the lvds panel built in.  For virtual hardware this is fixed
> and a simple "all outputs are displayport".
>
> What else is in there?  Anything which might need changes when the gvt
> driver is updated?  Given that some guest drivers do not depend on the
> opregion I assume this is not the case.
>
> So I'm wondering whenever there is a good reason in the first place to
> generate the opregion in the i915 gvt kernel driver.  Is it an option to
> generate the opregion in this IntelGvtGopDxe driver instead?  That would
> clearly be the easiest solution.
>
It's absolutely true that generating opregion in IntelGvtGopDxe could be 
an option. I thought the reason that i915/gvt generating the opregion is 
due to the design that how to emulate a GPU in a layered hierarchy. On 
physical hardware, OpRegion is part of firmware, loaded and comsumed 
by GPU SW stack. Firmware itself is always platform specific. So the most 
close virtualization is let gvt virtualize GPU HW, and firmware virtualize 
opregion.

However in QEMU world, it looks like those non-simulated device related 
opreations are left to other component as most as possible, like VFIO 
region, so that QEMU itself could force less on physical device specific 
operations but handle the common logic. In this opregion case, QEMU and 
seabios only copies the raw data, but the contents are left to gvt to fill 
so that gvt could fill different data in different cases. Otherwise any 
change requires SEABIOS update, instead of dyncamilly filled by gvt.

One benefit OVMF overcomes SEABIOS is that IntelGvtGopDxe can be loaded
as a standalone driver. So it maybe possible that in OVMF case, both gvt 
and IntelGvtGopDxe can act part of Intel vGPU virtualization component. 
However the behavior of gvt+seabios and gvt+ovmf will be inconsistent. May 
need update gvt logic so that if IntelGvtGopDxe generate opregion, gvt can 
still update it before any opregion consumer using it. Then, loading 
fw_cfg can be dropped without preventing guest OS driver find it.

I'm adding gvt maintainer here for more comments.

> Failing that we should at least take fw_cfg out of the loop.  It is just
> a middle man here and not needed at all.  As discussed before the pci
> rom bar can do the job instead.  That will remove any platform
> dependencies from the driver, it only need to talk to the device itself
> then.
>
> take care,
>  Gerd
>
>

--
Best Regards,
Colin Xu

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

* Re: [edk2-devel] [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation.
  2021-03-19  2:08         ` Colin Xu
@ 2021-03-19  9:06           ` kraxel
  2021-03-26  7:37             ` Colin Xu
  0 siblings, 1 reply; 11+ messages in thread
From: kraxel @ 2021-03-19  9:06 UTC (permalink / raw)
  To: Colin Xu; +Cc: zhenyuw, devel, lersek, alex.williamson, rebecca

  Hi,

> operations but handle the common logic. In this opregion case, QEMU and
> seabios only copies the raw data, but the contents are left to gvt to fill
> so that gvt could fill different data in different cases.

Yes, gvt could do that.

The big question is: does that actually happen?  When looking at
drivers/gpu/drm/i915/gvt/opregion.c it seems the opregion is pretty
static.

Are there plausible reasons for that capability being needed in the
future?

> Otherwise any change requires SEABIOS update, instead of dyncamilly
> filled by gvt.

That clearly isn't an option.

> One benefit OVMF overcomes SEABIOS is that IntelGvtGopDxe can be loaded
> as a standalone driver.

Well, seabios allows standalone drivers too.  It's called vgabios ;)

> So it maybe possible that in OVMF case, both gvt and
> IntelGvtGopDxe can act part of Intel vGPU virtualization component. However
> the behavior of gvt+seabios and gvt+ovmf will be inconsistent.

Well, in case the opregion is not static there is still the option to
use the pci rom bar instead of fw_cfg to deliver the opregion content
to the guest.

> May need
> update gvt logic so that if IntelGvtGopDxe generate opregion, gvt can still
> update it before any opregion consumer using it.

Hmm.  Can gvt trap pci config space writes?  IIRC pci config space is
simply yet another vfio region, so that should be possible.  gvt could
update the opregion then when the firmware updates the opregion address.

If that actually works there is little reason for IntelGvtGopDxe (and
seabios) to fill the opregion in the first place though.  We could
change the opregion initialization protocol to something like this:

  (1) firmware allocates memory for the opregion
  (2) firmware fills signature and size
  (3) firmware writes opregion address to pci config space
  (4) gvt goes fill opregion at the given address in guest memory.

Maybe it would be better to reserve a paravirtual mmio register for that
purpose to make the whole thing a bit more robust.

> Then, loading fw_cfg can be
> dropped without preventing guest OS driver find it.

I guess we have to keep that for a while for backward compatibility
reasons.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation.
  2021-03-19  9:06           ` kraxel
@ 2021-03-26  7:37             ` Colin Xu
  0 siblings, 0 replies; 11+ messages in thread
From: Colin Xu @ 2021-03-26  7:37 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: Colin Xu, zhenyuw, devel, lersek, alex.williamson, rebecca

On Fri, 19 Mar 2021, Gerd Hoffmann wrote:

>  Hi,
>
>> operations but handle the common logic. In this opregion case, QEMU and
>> seabios only copies the raw data, but the contents are left to gvt to fill
>> so that gvt could fill different data in different cases.
>
> Yes, gvt could do that.
>
> The big question is: does that actually happen?  When looking at
> drivers/gpu/drm/i915/gvt/opregion.c it seems the opregion is pretty
> static.
>
> Are there plausible reasons for that capability being needed in the
> future?
>
The current situation is static indeed. However there are still two cases 
requires run-time adjustment.
1) Current opregion/vbt has fixed display mappings, and many virtual GPU 
registers' value are inherited from host. However host opregion/vbt is 
platform specific. So if guest driver (like i915) do some strict sanity 
check it will found some display registers are incorrect. The proper way 
is that gvt generate vbt based on the virutal display type it emulated, 
and initialze related vREGs by following VESA and Intel specs.
2) Some downstream project may use physical display as an output, thus 
also need generate VBT based on host opregion/vbt.

>> Otherwise any change requires SEABIOS update, instead of dyncamilly
>> filled by gvt.
>
> That clearly isn't an option.
>
Yes, so based on such reason, gvt should still be able to update it 
dynamically even ovmf/seabios can generate the initial value.
>> One benefit OVMF overcomes SEABIOS is that IntelGvtGopDxe can be loaded
>> as a standalone driver.
>
> Well, seabios allows standalone drivers too.  It's called vgabios ;)
>
Like ATI VGABIOS in seabios repo. Unfortunately Intel hasn't implemented 
yet.
>> So it maybe possible that in OVMF case, both gvt and
>> IntelGvtGopDxe can act part of Intel vGPU virtualization component. However
>> the behavior of gvt+seabios and gvt+ovmf will be inconsistent.
>
> Well, in case the opregion is not static there is still the option to
> use the pci rom bar instead of fw_cfg to deliver the opregion content
> to the guest.
>
>> May need
>> update gvt logic so that if IntelGvtGopDxe generate opregion, gvt can still
>> update it before any opregion consumer using it.
>
> Hmm.  Can gvt trap pci config space writes?  IIRC pci config space is
> simply yet another vfio region, so that should be possible.  gvt could
> update the opregion then when the firmware updates the opregion address.
>
> If that actually works there is little reason for IntelGvtGopDxe (and
> seabios) to fill the opregion in the first place though.  We could
> change the opregion initialization protocol to something like this:
>
>  (1) firmware allocates memory for the opregion
>  (2) firmware fills signature and size
>  (3) firmware writes opregion address to pci config space
>  (4) gvt goes fill opregion at the given address in guest memory.
>
> Maybe it would be better to reserve a paravirtual mmio register for that
> purpose to make the whole thing a bit more robust.
>
Yes gvt can trap PCI cfg read/write, the suggested protocol is exact the 
same as I'm considering. Let me refine this big patch to smaller ones and 
send out again. Thanks very much!

>> Then, loading fw_cfg can be
>> dropped without preventing guest OS driver find it.
>
> I guess we have to keep that for a while for backward compatibility
> reasons.
Sure. That will be the correct way.
>
> take care,
>  Gerd
>
>

--
Best Regards,
Colin Xu

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

end of thread, other threads:[~2021-03-26  7:37 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-03-05  6:20 [PATCH v2 0/2] OvmfPkg/IntelGvtGopDxe: Add Intel GVT-g GOP Colin Xu
2021-03-05  6:20 ` [PATCH v2 1/2] OvmfPkg/IntelGvtGopDxe: Intel GVT-g GOP Implementation Colin Xu
2021-03-05 13:19   ` [edk2-devel] " Laszlo Ersek
2021-03-12  3:57     ` Colin Xu
2021-03-12 12:35       ` Gerd Hoffmann
2021-03-19  2:08         ` Colin Xu
2021-03-19  9:06           ` kraxel
2021-03-26  7:37             ` Colin Xu
2021-03-12  4:42     ` Rebecca Cran
2021-03-12  4:55       ` Colin Xu
2021-03-05  6:20 ` [PATCH v2 2/2] OvmfPkg/IntelGvtGopDxe: Enable GVT-g GOP in OvmfPkg DSC & DFD Colin Xu

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