diff --git a/MdePkg/Include/Uefi/UefiBaseType.h b/MdePkg/Include/Uefi/UefiBaseType.h
index 45e2aa63bb..084c52cd0f 100644
--- a/MdePkg/Include/Uefi/UefiBaseType.h
+++ b/MdePkg/Include/Uefi/UefiBaseType.h
@@ -53,6 +53,8 @@ typedef UINT64                    EFI_PHYSICAL_ADDRESS;
 ///
 typedef UINT64                    EFI_VIRTUAL_ADDRESS;
 
+#define NUMERIC_VALUE_AS_POINTER(Type, Value)   ((Type *) ((UINTN)(Value)))
+
 ///
 /// EFI Time Abstraction:
 ///  Year:       1900 - 9999
diff --git a/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.c b/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.c
index 9ccdb4d91c..e7de6937da 100644
--- a/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.c
+++ b/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.c
@@ -245,6 +245,16 @@ InstallAcpiTables (
 {
   EFI_STATUS Status;
 
+  Status = InstallBhyveTables (AcpiTable);
+  if (!EFI_ERROR (Status)) {
+    return EFI_SUCCESS;
+  }
+  if (Status != EFI_NOT_FOUND) {
+    DEBUG ((DEBUG_INFO, "%a: unable to install bhyve's ACPI tables (%r)\n",
+      __FUNCTION__, Status));
+    return Status;
+  }
+
   Status = InstallOvmfFvTables (AcpiTable);
 
   return Status;
diff --git a/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.h b/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.h
index 994ee2c7cd..1a99838e8e 100644
--- a/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.h
+++ b/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatform.h
@@ -46,6 +46,12 @@ BhyveInstallAcpiTable(
   OUT  UINTN                         *TableKey
   );
 
+EFI_STATUS
+EFIAPI
+InstallBhyveTables (
+  IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol
+  );
+
 EFI_STATUS
 EFIAPI
 InstallXenTables (
diff --git a/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatformDxe.inf b/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatformDxe.inf
index 595fd055f9..a2efa3feb1 100644
--- a/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatformDxe.inf
+++ b/OvmfPkg/Bhyve/AcpiPlatformDxe/AcpiPlatformDxe.inf
@@ -37,12 +37,12 @@
 [LibraryClasses]
   BaseLib
   BaseMemoryLib
-  BhyveFwCtlLib
   DebugLib
   DxeServicesTableLib
   MemoryAllocationLib
   OrderedCollectionLib
   PcdLib
+  QemuFwCfgLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
   UefiLib
diff --git a/OvmfPkg/Bhyve/AcpiPlatformDxe/Bhyve.c b/OvmfPkg/Bhyve/AcpiPlatformDxe/Bhyve.c
index 01ee894746..e2c543516a 100644
--- a/OvmfPkg/Bhyve/AcpiPlatformDxe/Bhyve.c
+++ b/OvmfPkg/Bhyve/AcpiPlatformDxe/Bhyve.c
@@ -9,8 +9,55 @@
 #include "AcpiPlatform.h"
 
 #include <Library/BaseMemoryLib.h>
-#include <Library/BhyveFwCtlLib.h>
 #include <Library/MemoryAllocationLib.h>
+#include <Library/QemuFwCfgLib.h>             // QemuFwCfgFindFile()
+
+#define BHYVE_ACPI_PHYSICAL_ADDRESS   ((UINTN)0x000F2400)
+#define BHYVE_BIOS_PHYSICAL_END       ((UINTN)0x00100000)
+
+#pragma pack (1)
+
+typedef struct
+{
+  EFI_ACPI_DESCRIPTION_HEADER   Header;
+  UINT64                        Tables[0];
+} EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE;
+
+#pragma pack ()
+
+STATIC
+EFI_STATUS
+EFIAPI
+BhyveGetCpuCount (
+  OUT UINT32 *CpuCount
+  )
+{
+  EFI_STATUS Status;
+  FIRMWARE_CONFIG_ITEM Item;
+  UINTN Size;
+
+  if (!QemuFwCfgIsAvailable ()) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Get index of FW_CFG file
+  //
+  Status = QemuFwCfgFindFile ("opt/bhyve/hw.ncpu", &Item, &Size);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  } else if (Size != sizeof (*CpuCount)) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  //
+  // Get data of FW_CFG file
+  //
+  QemuFwCfgSelectItem (Item);
+  QemuFwCfgReadBytes (Size, CpuCount);
+
+  return EFI_SUCCESS;
+}
 
 STATIC
 EFI_STATUS
@@ -23,7 +70,6 @@ BhyveInstallAcpiMadtTable (
   )
 {
   UINT32                                              CpuCount;
-  UINTN                                               cSize;
   UINTN                                               NewBufferSize;
   EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
   EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE         *LocalApic;
@@ -36,9 +82,8 @@ BhyveInstallAcpiMadtTable (
   ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
 
   // Query the host for the number of vCPUs
-  CpuCount = 0;
-  cSize = sizeof(CpuCount);
-  if (BhyveFwCtlGet ("hw.ncpu", &CpuCount, &cSize) == RETURN_SUCCESS) {
+  Status = BhyveGetCpuCount (&CpuCount);
+  if (!EFI_ERROR (Status)) {
     DEBUG ((DEBUG_INFO, "Retrieved CpuCount %d\n", CpuCount));
     ASSERT (CpuCount >= 1);
   } else {
@@ -130,3 +175,231 @@ BhyveInstallAcpiTable (
            TableKey
            );
 }
+
+/**
+  Get the address of bhyve's ACPI Root System Description Pointer (RSDP).
+
+  @param  RsdpPtr             Return pointer to RSDP.
+
+  @return EFI_SUCCESS         Bhyve's RSDP successfully found.
+  @return EFI_NOT_FOUND       Couldn't find bhyve's RSDP.
+  @return EFI_UNSUPPORTED     Revision is lower than 2.
+  @return EFI_PROTOCOL_ERROR  Invalid RSDP found.
+
+**/
+EFI_STATUS
+EFIAPI
+BhyveGetAcpiRsdp (
+  OUT   EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER   **RsdpPtr
+  )
+{
+  UINTN                                         RsdpAddress;
+  EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *Rsdp;
+
+  if (RsdpPtr == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Detect the RSDP
+  //
+  for (RsdpAddress = BHYVE_ACPI_PHYSICAL_ADDRESS;
+       RsdpAddress < BHYVE_BIOS_PHYSICAL_END;
+       RsdpAddress += 0x10) {
+    Rsdp = NUMERIC_VALUE_AS_POINTER (
+             EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER,
+             RsdpAddress
+             );
+    if (Rsdp->Signature != EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE) {
+      continue;
+    }
+    if (Rsdp->Revision < 2) {
+      DEBUG ((DEBUG_INFO, "%a: unsupported RSDP found\n", __FUNCTION__));
+      return EFI_UNSUPPORTED;
+    }
+
+    //
+    // For ACPI 1.0/2.0/3.0 the checksum of first 20 bytes should be 0.
+    // For ACPI 2.0/3.0 the checksum of the entire table should be 0.
+    //
+    UINT8 Sum = CalculateCheckSum8 (
+            (CONST UINT8 *)Rsdp,
+            sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER)
+            );
+    if (Sum != 0) {
+      DEBUG ((DEBUG_INFO, "%a: RSDP header checksum not valid: 0x%02x\n",
+        __FUNCTION__, Sum));
+      return EFI_PROTOCOL_ERROR;
+    }
+    Sum = CalculateCheckSum8 (
+            (CONST UINT8 *)Rsdp,
+            sizeof (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER)
+            );
+    if (Sum != 0) {
+      DEBUG ((DEBUG_INFO, "%a: RSDP table checksum not valid: 0x%02x\n",
+        __FUNCTION__, Sum));
+      return EFI_PROTOCOL_ERROR;
+    }
+
+    //
+    // RSDP was found and is valid
+    //
+    *RsdpPtr = Rsdp;
+
+    return EFI_SUCCESS;
+  }
+
+  DEBUG ((DEBUG_INFO, "%a: RSDP not found\n", __FUNCTION__));
+  return EFI_NOT_FOUND;
+}
+
+/**
+  Get bhyve's ACPI tables from the RSDP. And install bhyve's ACPI tables
+  into the RSDT/XSDT using InstallAcpiTable.
+
+  @param  AcpiProtocol        Protocol instance pointer.
+
+  @return EFI_SUCCESS         All tables were successfully inserted.
+  @return EFI_UNSUPPORTED     Bhyve's ACPI tables doesn't include a XSDT.
+  @return EFI_PROTOCOL_ERROR  Invalid XSDT found.
+
+  @return                     Error codes propagated from underlying functions.
+**/
+EFI_STATUS
+EFIAPI
+InstallBhyveTables (
+  IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol
+  )
+{
+  EFI_STATUS                                      Status;
+  UINTN                                           TableHandle;
+  EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER    *Rsdp;
+  EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE    *Facs;
+  EFI_ACPI_DESCRIPTION_HEADER                     *Dsdt;
+
+  Rsdp = NULL;
+  Facs = NULL;
+  Dsdt = NULL;
+
+  //
+  // Try to find bhyve ACPI tables
+  //
+  Status = BhyveGetAcpiRsdp (&Rsdp);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "%a: can't get RSDP (%r)\n", __FUNCTION__, Status));
+    return Status;
+  }
+
+  //
+  // Bhyve should always provide a XSDT
+  //
+  EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE * CONST Xsdt =
+    NUMERIC_VALUE_AS_POINTER (
+      EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE,
+      Rsdp->XsdtAddress
+      );
+  if (Xsdt == NULL) {
+    DEBUG ((DEBUG_INFO, "%a: XSDT not found\n", __FUNCTION__));
+    return EFI_UNSUPPORTED;
+  }
+  if (Xsdt->Header.Length < sizeof (EFI_ACPI_DESCRIPTION_HEADER)) {
+    DEBUG ((DEBUG_INFO, "%a: invalid XSDT length\n", __FUNCTION__));
+    return EFI_PROTOCOL_ERROR;
+  }
+
+  //
+  // Install ACPI tables
+  //
+  CONST UINTN NumberOfTableEntries =
+    (Xsdt->Header.Length - sizeof (Xsdt->Header)) / sizeof (UINT64);
+  for (UINTN Index = 0; Index < NumberOfTableEntries; Index++) {
+    EFI_ACPI_DESCRIPTION_HEADER * CONST CurrentTable =
+      NUMERIC_VALUE_AS_POINTER (
+        EFI_ACPI_DESCRIPTION_HEADER,
+        Xsdt->Tables[Index]
+        );
+    Status = AcpiProtocol->InstallAcpiTable (
+                             AcpiProtocol,
+                             CurrentTable,
+                             CurrentTable->Length,
+                             &TableHandle
+                             );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_INFO, "%a: failed to install ACPI table %c%c%c%c (%r)\n",
+        __FUNCTION__,
+        NUMERIC_VALUE_AS_POINTER (UINT8, CurrentTable->Signature)[0],
+        NUMERIC_VALUE_AS_POINTER (UINT8, CurrentTable->Signature)[1],
+        NUMERIC_VALUE_AS_POINTER (UINT8, CurrentTable->Signature)[2],
+        NUMERIC_VALUE_AS_POINTER (UINT8, CurrentTable->Signature)[3],
+        Status));
+      return Status;
+    }
+
+    if (CurrentTable->Signature == EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
+      EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE * CONST Fadt =
+        (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE * CONST)CurrentTable;
+      if (Fadt->XFirmwareCtrl) {
+        Facs = NUMERIC_VALUE_AS_POINTER (
+                 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE,
+                 Fadt->XFirmwareCtrl
+                 );
+      } else {
+        Facs = NUMERIC_VALUE_AS_POINTER (
+                 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE,
+                 Fadt->FirmwareCtrl
+                 );
+      }
+      if (Fadt->XDsdt) {
+        Dsdt = NUMERIC_VALUE_AS_POINTER (
+                 EFI_ACPI_DESCRIPTION_HEADER,
+                 Fadt->XDsdt
+                 );
+      } else {
+        Dsdt = NUMERIC_VALUE_AS_POINTER (
+                 EFI_ACPI_DESCRIPTION_HEADER,
+                 Fadt->Dsdt
+                 );
+      }
+    }
+  }
+
+  //
+  // Install FACS
+  //
+  if (Facs != NULL) {
+    Status = AcpiProtocol->InstallAcpiTable (
+                             AcpiProtocol,
+                             Facs,
+                             Facs->Length,
+                             &TableHandle
+                             );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_INFO, "%a: failed to install FACS (%r)\n", __FUNCTION__,
+        Status));
+      return Status;
+    }
+  }
+
+  //
+  // Install DSDT
+  // If it's not found, something bad happened. Don't continue execution.
+  //
+  if (Dsdt == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to find DSDT\n", __FUNCTION__));
+    CpuDeadLoop ();
+  }
+
+  Status = AcpiProtocol->InstallAcpiTable (
+                           AcpiProtocol,
+                           Dsdt,
+                           Dsdt->Length,
+                           &TableHandle
+                           );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "%a: failed to install DSDT (%r)\n", __FUNCTION__,
+      Status));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc
index d8fe607d1c..53f061eeb3 100644
--- a/OvmfPkg/Bhyve/BhyveX64.dsc
+++ b/OvmfPkg/Bhyve/BhyveX64.dsc
@@ -163,9 +163,7 @@
   SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
   UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
   SerializeVariablesLib|OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.inf
-  QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibNull.inf
-  QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/BaseQemuFwCfgS3LibNull.inf
-  BhyveFwCtlLib|OvmfPkg/Library/BhyveFwCtlLib/BhyveFwCtlLib.inf
+  QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf
   VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
   MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
   LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
@@ -284,6 +282,7 @@
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
   PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
+  QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
 
   MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
 
@@ -354,6 +353,7 @@
 !endif
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.inf
+  QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
 
 [LibraryClasses.common.UEFI_APPLICATION]
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
@@ -416,7 +416,6 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
 
 [PcdsFixedAtBuild]
-  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial|FALSE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|TRUE
   gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1
@@ -622,10 +621,11 @@
   UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
   UefiCpuPkg/CpuDxe/CpuDxe.inf
   PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.inf
+  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
   OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
   MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
     <LibraryClasses>
-      PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLibScan/PciHostBridgeLibScan.inf
+      PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
       PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf
       NULL|OvmfPkg/Library/PlatformHasIoMmuLib/PlatformHasIoMmuLib.inf
   }
@@ -660,6 +660,7 @@
   OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
   OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
   OvmfPkg/VirtioRngDxe/VirtioRng.inf
+  OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.inf
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
   MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
   MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
diff --git a/OvmfPkg/Bhyve/BhyveX64.fdf b/OvmfPkg/Bhyve/BhyveX64.fdf
index b3b4d44cef..20d9aa7e6c 100644
--- a/OvmfPkg/Bhyve/BhyveX64.fdf
+++ b/OvmfPkg/Bhyve/BhyveX64.fdf
@@ -205,6 +205,7 @@ INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
 INF  UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
 INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
 INF  PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.inf
+INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
 INF  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
 INF  MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
@@ -217,6 +218,7 @@ INF  OvmfPkg/Virtio10Dxe/Virtio10.inf
 INF  OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
 INF  OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
 INF  OvmfPkg/VirtioRngDxe/VirtioRng.inf
+INF  OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.inf
 
 !if $(SECURE_BOOT_ENABLE) == TRUE
   INF  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
diff --git a/OvmfPkg/Bhyve/PlatformPei/MemDetect.c b/OvmfPkg/Bhyve/PlatformPei/MemDetect.c
index 1b556be69c..80ac24a813 100644
--- a/OvmfPkg/Bhyve/PlatformPei/MemDetect.c
+++ b/OvmfPkg/Bhyve/PlatformPei/MemDetect.c
@@ -30,6 +30,7 @@ Module Name:
 #include <Library/PcdLib.h>
 #include <Library/PciLib.h>
 #include <Library/PeimEntryPoint.h>
+#include <Library/QemuFwCfgLib.h>
 #include <Library/ResourcePublicationLib.h>
 #include <Library/MtrrLib.h>
 
@@ -352,6 +353,9 @@ PublishPeiMemory (
   VOID
   )
 {
+  EFI_E820_ENTRY64            E820Entry;
+  FIRMWARE_CONFIG_ITEM        Item;
+  UINTN                       ItemSize;
   EFI_STATUS                  Status;
   EFI_PHYSICAL_ADDRESS        MemoryBase;
   UINT64                      MemorySize;
@@ -407,6 +411,78 @@ PublishPeiMemory (
     }
   }
 
+  //
+  // Bhyve uses an E820 table to reserve certain kinds of memory like Graphics
+  // Stolen Memory. These reserved memory regions could overlap with the PEI
+  // core memory which leads to undefined behaviour. Check the E820 table for
+  // a memory region starting at or below MemoryBase which is equal or larger
+  // than MemorySize.
+  //
+  if (!EFI_ERROR (QemuFwCfgFindFile("etc/e820", &Item, &ItemSize))) {
+    //
+    // Set a new base address based on E820 table.
+    //
+
+    EFI_PHYSICAL_ADDRESS  MaxAddress;
+    UINT64                EntryEnd;
+    UINT64                EndAddr;
+
+    if (ItemSize % sizeof (E820Entry) != 0) {
+      DEBUG ((DEBUG_INFO, "%a: invalid E820 size\n", __FUNCTION__));
+      return EFI_PROTOCOL_ERROR;
+    }
+
+    QemuFwCfgSelectItem(Item);
+
+    MaxAddress = MemoryBase + MemorySize;
+    MemoryBase = 0;
+
+    for (UINTN i = 0; i < ItemSize; i += sizeof (E820Entry)) {
+
+      QemuFwCfgReadBytes (sizeof (E820Entry), &E820Entry);
+
+      if (E820Entry.BaseAddr > MaxAddress) {
+        //
+        // E820 is always sorted in ascending order. For that reason, BaseAddr
+        // will always be larger than MaxAddress for the following entries.
+        //
+        break;
+      } else if (E820Entry.Type != EfiAcpiAddressRangeMemory) {
+        continue;
+      }
+
+      //
+      // Since MemoryBase should be at top of the memory, calculate the end
+      // address of the entry. Additionally, MemoryBase and MemorySize are page
+      // aligned. For that reason, page align EntryEnd too.
+      //
+      EntryEnd = (E820Entry.BaseAddr + E820Entry.Length) & ~EFI_PAGE_MASK;
+      if (E820Entry.BaseAddr > EntryEnd) {
+        //
+        // Either BaseAddr + Length overflows or the entry is smaller than a
+        // page. In both cases, we can't use it.
+        //
+        continue;
+      }
+
+      EndAddr = MIN (EntryEnd, MaxAddress);
+      if (EndAddr - E820Entry.BaseAddr < MemorySize) {
+        //
+        // E820 entry is too small for the Pei core memory.
+        //
+        continue;
+      }
+
+      MemoryBase = EndAddr - MemorySize;
+    }
+
+    if (MemoryBase == 0) {
+      DEBUG ((DEBUG_ERROR, "%a: Unable to find suitable PeiCore address\n",
+        __FUNCTION__));
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+
   //
   // Publish this memory to the PEI Core
   //
diff --git a/OvmfPkg/Bhyve/PlatformPei/Platform.c b/OvmfPkg/Bhyve/PlatformPei/Platform.c
index c23b906733..788198e70e 100644
--- a/OvmfPkg/Bhyve/PlatformPei/Platform.c
+++ b/OvmfPkg/Bhyve/PlatformPei/Platform.c
@@ -27,6 +27,7 @@
 #include <Library/PciLib.h>
 #include <Library/PeimEntryPoint.h>
 #include <Library/PeiServicesLib.h>
+#include <Library/QemuFwCfgLib.h>
 #include <Library/ResourcePublicationLib.h>
 #include <Guid/MemoryTypeInformation.h>
 #include <Ppi/MasterBootMode.h>
@@ -487,6 +488,110 @@ DebugDumpCmos (
 }
 
 
+STATIC
+EFI_STATUS
+E820ReserveMemory (
+  VOID
+  )
+{
+  EFI_E820_ENTRY64      E820Entry;
+  FIRMWARE_CONFIG_ITEM  Item;
+  UINTN                 Size;
+  EFI_STATUS            Status;
+
+  Status = QemuFwCfgFindFile ("etc/e820", &Item, &Size);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "%a: E820 not found: %r\n", __FUNCTION__, Status));
+    return Status;
+  }
+
+  if (Size % sizeof (E820Entry) != 0) {
+    DEBUG ((DEBUG_INFO, "%a: invalid E820 size\n", __FUNCTION__));
+    return EFI_PROTOCOL_ERROR;
+  }
+
+  QemuFwCfgSelectItem (Item);
+  for (UINTN i = 0; i < Size; i += sizeof (E820Entry)) {
+    UINT64  Base;
+    UINT64  End;
+
+    QemuFwCfgReadBytes (sizeof (E820Entry), &E820Entry);
+
+    DEBUG_CODE (
+      CHAR8 *E820TypeName;
+      switch (E820Entry.Type) {
+      case EfiAcpiAddressRangeMemory:
+        E820TypeName = "RAM     ";
+        break;
+      case EfiAcpiAddressRangeReserved:
+        E820TypeName = "Reserved";
+        break;
+      case EfiAcpiAddressRangeACPI:
+        E820TypeName = "ACPI    ";
+        break;
+      case EfiAcpiAddressRangeNVS:
+        E820TypeName = "NVS     ";
+        break;
+      default:
+        E820TypeName = "Unknown ";
+        break;
+      }
+      DEBUG ((DEBUG_INFO, "E820 entry [ %16lx, %16lx] (%a)\n",
+        E820Entry.BaseAddr, E820Entry.BaseAddr + E820Entry.Length,
+        E820TypeName));
+    );
+
+    //
+    // Round down base and round up length to page boundary
+    //
+    Base = E820Entry.BaseAddr & ~(UINT64)EFI_PAGE_MASK;
+    End = ALIGN_VALUE (
+            E820Entry.BaseAddr + E820Entry.Length,
+            (UINT64)EFI_PAGE_SIZE
+            );
+
+    switch (E820Entry.Type) {
+    case EfiAcpiAddressRangeReserved:
+      BuildMemoryAllocationHob (
+        Base,
+        End - Base,
+        EfiReservedMemoryType
+        );
+      break;
+
+    case  EfiAcpiAddressRangeACPI:
+      BuildMemoryAllocationHob (
+        Base,
+        End - Base,
+        EfiACPIReclaimMemory
+        );
+      break;
+
+    case EfiAcpiAddressRangeNVS:
+      BuildMemoryAllocationHob (
+        Base,
+        End - Base,
+        EfiACPIMemoryNVS
+        );
+      break;
+
+    case EfiAcpiAddressRangeMemory:
+      //
+      // EfiAcpiAddressRangeMemory is usable. Do not build an Allocation HOB.
+      //
+      break;
+
+    default:
+      DEBUG ((DEBUG_ERROR, "%a: Unknown E820 type %d\n", __FUNCTION__,
+        E820Entry.Type));
+      return EFI_PROTOCOL_ERROR;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+
 VOID
 S3Verification (
   VOID
@@ -563,6 +668,10 @@ InitializePlatform (
   IN CONST EFI_PEI_SERVICES     **PeiServices
   )
 {
+  EFI_STATUS            Status;
+  FIRMWARE_CONFIG_ITEM  Item;
+  UINTN                 Size;
+
   DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
 
   //
@@ -575,6 +684,16 @@ InitializePlatform (
 
   DebugDumpCmos ();
 
+  //
+  // If an E820 table exists, Memory should be reserved by E820.
+  //
+  if (!EFI_ERROR (QemuFwCfgFindFile("etc/e820", &Item, &Size))) {
+    Status = E820ReserveMemory ();
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
   BootModeInitialization ();
   AddressWidthInitialization ();
   MaxCpuCountInitialization ();
diff --git a/OvmfPkg/Bhyve/PlatformPei/PlatformPei.inf b/OvmfPkg/Bhyve/PlatformPei/PlatformPei.inf
index 739d63098b..557a8f890e 100644
--- a/OvmfPkg/Bhyve/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/Bhyve/PlatformPei/PlatformPei.inf
@@ -59,6 +59,7 @@
   PeiServicesLib
   PeiServicesTablePointerLib
   PcdLib
+  QemuFwCfgLib
   ResourcePublicationLib
 
 [Pcd]
diff --git a/OvmfPkg/Include/IndustryStandard/IgdOpRegion.h b/OvmfPkg/Include/IndustryStandard/IgdOpRegion.h
new file mode 100644
index 0000000000..4e9180c86b
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/IgdOpRegion.h
@@ -0,0 +1,181 @@
+/** @file
+  IGD OpRegion definition from Intel Integrated Graphics Device OpRegion
+  Specification.
+
+  https://01.org/sites/default/files/documentation/skl_opregion_rev0p5.pdf
+
+  @note Fixed bug in the spec Mailbox3 - RM31 size from 0x45(69) to 0x46(70)
+
+  Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef _IGD_OPREGION_H_
+#define _IGD_OPREGION_H_
+
+#define IGD_OPREGION_HEADER_SIGN "IntelGraphicsMem"
+#define IGD_OPREGION_HEADER_MBOX1 BIT0
+#define IGD_OPREGION_HEADER_MBOX2 BIT1
+#define IGD_OPREGION_HEADER_MBOX3 BIT2
+#define IGD_OPREGION_HEADER_MBOX4 BIT3
+#define IGD_OPREGION_HEADER_MBOX5 BIT4
+
+#define IGD_OPREGION_VBT_SIZE_6K (6 * SIZE_1KB)
+
+/**
+  OpRegion structures:
+  Sub-structures define the different parts of the OpRegion followed by the
+  main structure representing the entire OpRegion.
+
+  @note These structures are packed to 1 byte offsets because the exact
+  data location is required by the supporting design specification due to
+  the fact that the data is used by ASL and Graphics driver code compiled
+  separately.
+**/
+#pragma pack(1)
+///
+/// OpRegion Mailbox 0 Header structure. The OpRegion Header is used to
+/// identify a block of memory as the graphics driver OpRegion.
+/// Offset 0x0, Size 0x100
+///
+typedef struct {
+  CHAR8  SIGN[0x10];    ///< Offset 0x00 OpRegion Signature
+  UINT32 SIZE;          ///< Offset 0x10 OpRegion Size
+  UINT32 OVER;          ///< Offset 0x14 OpRegion Structure Version
+  UINT8  SVER[0x20];    ///< Offset 0x18 System BIOS Build Version
+  UINT8  VVER[0x10];    ///< Offset 0x38 Video BIOS Build Version
+  UINT8  GVER[0x10];    ///< Offset 0x48 Graphic Driver Build Version
+  UINT32 MBOX;          ///< Offset 0x58 Supported Mailboxes
+  UINT32 DMOD;          ///< Offset 0x5C Driver Model
+  UINT32 PCON;          ///< Offset 0x60 Platform Configuration
+  CHAR16 DVER[0x10];    ///< Offset 0x64 GOP Version
+  UINT8  RM01[0x7C];    ///< Offset 0x84 Reserved Must be zero
+} IGD_OPREGION_HEADER;
+
+///
+/// OpRegion Mailbox 1 - Public ACPI Methods
+/// Offset 0x100, Size 0x100
+///
+typedef struct {
+  UINT32 DRDY;          ///< Offset 0x100 Driver Readiness
+  UINT32 CSTS;          ///< Offset 0x104 Status
+  UINT32 CEVT;          ///< Offset 0x108 Current Event
+  UINT8  RM11[0x14];    ///< Offset 0x10C Reserved Must be Zero
+  UINT32 DIDL[8];       ///< Offset 0x120 Supported Display Devices ID List
+  UINT32 CPDL[8];       ///< Offset 0x140 Currently Attached Display Devices List
+  UINT32 CADL[8];       ///< Offset 0x160 Currently Active Display Devices List
+  UINT32 NADL[8];       ///< Offset 0x180 Next Active Devices List
+  UINT32 ASLP;          ///< Offset 0x1A0 ASL Sleep Time Out
+  UINT32 TIDX;          ///< Offset 0x1A4 Toggle Table Index
+  UINT32 CHPD;          ///< Offset 0x1A8 Current Hotplug Enable Indicator
+  UINT32 CLID;          ///< Offset 0x1AC Current Lid State Indicator
+  UINT32 CDCK;          ///< Offset 0x1B0 Current Docking State Indicator
+  UINT32 SXSW;          ///< Offset 0x1B4 Display Switch Notification on Sx State Resume
+  UINT32 EVTS;          ///< Offset 0x1B8 Events supported by ASL
+  UINT32 CNOT;          ///< Offset 0x1BC Current OS Notification
+  UINT32 NRDY;          ///< Offset 0x1C0 Driver Status
+  UINT8  DID2[0x1C];    ///< Offset 0x1C4 Extended Supported Devices ID List (DOD)
+  UINT8  CPD2[0x1C];    ///< Offset 0x1E0 Extended Attached Display Devices List
+  UINT8  RM12[4];       ///< Offset 0x1FC - 0x1FF Reserved Must be zero
+} IGD_OPREGION_MBOX1;
+
+///
+/// OpRegion Mailbox 2 - Software SCI Interface
+/// Offset 0x200, Size 0x100
+///
+typedef struct {
+  UINT32 SCIC;          ///< Offset 0x200 Software SCI Command / Status / Data
+  UINT32 PARM;          ///< Offset 0x204 Software SCI Parameters
+  UINT32 DSLP;          ///< Offset 0x208 Driver Sleep Time Out
+  UINT8  RM21[0xF4];    ///< Offset 0x20C - 0x2FF Reserved Must be zero
+} IGD_OPREGION_MBOX2;
+
+///
+/// OpRegion Mailbox 3 - BIOS/Driver Notification - ASLE Support
+/// Offset 0x300, Size 0x100
+///
+typedef struct {
+  UINT32 ARDY;          ///< Offset 0x300 Driver Readiness
+  UINT32 ASLC;          ///< Offset 0x304 ASLE Interrupt Command / Status
+  UINT32 TCHE;          ///< Offset 0x308 Technology Enabled Indicator
+  UINT32 ALSI;          ///< Offset 0x30C Current ALS Luminance Reading
+  UINT32 BCLP;          ///< Offset 0x310 Requested Backlight Brightness
+  UINT32 PFIT;          ///< Offset 0x314 Panel Fitting State or Request
+  UINT32 CBLV;          ///< Offset 0x318 Current Brightness Level
+  UINT16 BCLM[0x14];    ///< Offset 0x31C Backlight Brightness Levels Duty Cycle Mapping Table
+  UINT32 CPFM;          ///< Offset 0x344 Current Panel Fitting Mode
+  UINT32 EPFM;          ///< Offset 0x348 Enabled Panel Fitting Modes
+  UINT8  PLUT[0x4A];    ///< Offset 0x34C Panel Look Up Table & Identifier
+  UINT32 PFMB;          ///< Offset 0x396 PWM Frequency and Minimum Brightness
+  UINT32 CCDV;          ///< Offset 0x39A Color Correction Default Values
+  UINT32 PCFT;          ///< Offset 0x39E Power Conservation Features
+  UINT32 SROT;          ///< Offset 0x3A2 Supported Rotation Angles
+  UINT32 IUER;          ///< Offset 0x3A6 Intel Ultrabook(TM) Event Register
+  UINT64 FDSS;          ///< Offset 0x3AA DSS Buffer address allocated for IFFS feature
+  UINT32 FDSP;          ///< Offset 0x3B2 Size of DSS buffer
+  UINT32 STAT;          ///< Offset 0x3B6 State Indicator
+  UINT64 RVDA;          ///< Offset 0x3BA Absolute/Relative Address of Raw VBT Data from OpRegion Base
+  UINT32 RVDS;          ///< Offset 0x3C2 Raw VBT Data Size
+  UINT8  RSVD3[0x3A];   ///< Offset 0x3C6 - 0x3FF  Reserved Must be zero. Bug in spec 0x45(69)
+} IGD_OPREGION_MBOX3;
+
+///
+/// OpRegion Mailbox 4 - VBT Video BIOS Table
+/// Offset 0x400, Size 0x1800
+///
+typedef struct {
+  UINT8  RVBT[IGD_OPREGION_VBT_SIZE_6K];  ///< Offset 0x400 - 0x1BFF Raw VBT Data
+} IGD_OPREGION_MBOX4;
+
+///
+/// OpRegion Mailbox 5 - BIOS/Driver Notification - Data storage BIOS to Driver data sync
+/// Offset 0x1C00, Size 0x400
+///
+typedef struct {
+  UINT32 PHED;          ///< Offset 0x1C00 Panel Header
+  UINT8  BDDC[0x100];   ///< Offset 0x1C04 Panel EDID (DDC data)
+  UINT8  RM51[0x2FC];   ///< Offset 0x1D04 - 0x1FFF Reserved Must be zero
+} IGD_OPREGION_MBOX5;
+
+///
+/// IGD OpRegion Structure
+///
+typedef struct {
+  IGD_OPREGION_HEADER Header; ///< OpRegion header (Offset 0x0, Size 0x100)
+  IGD_OPREGION_MBOX1  MBox1;  ///< Mailbox 1: Public ACPI Methods (Offset 0x100, Size 0x100)
+  IGD_OPREGION_MBOX2  MBox2;  ///< Mailbox 2: Software SCI Interface (Offset 0x200, Size 0x100)
+  IGD_OPREGION_MBOX3  MBox3;  ///< Mailbox 3: BIOS to Driver Notification (Offset 0x300, Size 0x100)
+  IGD_OPREGION_MBOX4  MBox4;  ///< Mailbox 4: Video BIOS Table (VBT) (Offset 0x400, Size 0x1800)
+  IGD_OPREGION_MBOX5  MBox5;  ///< Mailbox 5: BIOS to Driver Notification Extension (Offset 0x1C00, Size 0x400)
+} IGD_OPREGION_STRUCTURE;
+
+///
+/// VBT Header Structure
+///
+typedef struct {
+  UINT8  Product_String[20];
+  UINT16 Version;
+  UINT16 Header_Size;
+  UINT16 Table_Size;
+  UINT8  Checksum;
+  UINT8  Reserved1;
+  UINT32 Bios_Data_Offset;
+  UINT32 Aim_Data_Offset[4];
+} VBT_HEADER;
+
+typedef struct {
+  UINT8  BDB_Signature[16];
+  UINT16 BDB_Version;
+  UINT16 BDB_Header_Size;
+  UINT16 BDB_Size;
+} VBT_BIOS_DATA_HEADER;
+
+#pragma pack()
+
+#endif
diff --git a/OvmfPkg/Include/Protocol/PlatformGopPolicy.h b/OvmfPkg/Include/Protocol/PlatformGopPolicy.h
new file mode 100644
index 0000000000..9c3a9a07c8
--- /dev/null
+++ b/OvmfPkg/Include/Protocol/PlatformGopPolicy.h
@@ -0,0 +1,68 @@
+/*++
+
+Copyright (c)  1999  - 2019, Intel Corporation. All rights reserved
+
+  This program and the accompanying materials are licensed and made available under
+  the terms and conditions of the BSD License that accompanies this distribution.
+  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php.
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+--*/
+
+/** @file
+**/
+
+#ifndef _PLATFORM_GOP_POLICY_PROTOCOL_H_
+#define _PLATFORM_GOP_POLICY_PROTOCOL_H_
+
+#define EFI_PLATFORM_GOP_POLICY_PROTOCOL_GUID \
+  { 0xec2e931b, 0x3281, 0x48a5, 0x81, 0x7, 0xdf, 0x8a, 0x8b, 0xed, 0x3c, 0x5d }
+
+#define PLATFORM_GOP_POLICY_PROTOCOL_REVISION_01 0x01
+#define PLATFORM_GOP_POLICY_PROTOCOL_REVISION_02 x0222
+
+#pragma pack(1)
+
+typedef enum {
+  LidClosed,
+  LidOpen,
+  LidStatusMax
+} LID_STATUS;
+
+typedef enum {
+  Docked,
+  UnDocked,
+  DockStatusMax
+} DOCK_STATUS;
+
+typedef
+EFI_STATUS
+(EFIAPI *GET_PLATFORM_LID_STATUS) (
+   OUT LID_STATUS *CurrentLidStatus
+);
+
+typedef
+EFI_STATUS
+(EFIAPI *GET_VBT_DATA) (
+   OUT EFI_PHYSICAL_ADDRESS *VbtAddress,
+   OUT UINT32 *VbtSize
+);
+
+#pragma pack()
+
+typedef struct _PLATFORM_GOP_POLICY_PROTOCOL {
+  UINT32                             Revision;
+  GET_PLATFORM_LID_STATUS            GetPlatformLidStatus;
+  GET_VBT_DATA                       GetVbtData;
+} PLATFORM_GOP_POLICY_PROTOCOL;
+
+//
+// Extern the GUID for protocol users.
+//
+extern EFI_GUID  gPlatformGOPPolicyGuid;
+
+#endif
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 340d83f794..b4bc2355e8 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -148,6 +148,7 @@
   gEfiLegacyInterruptProtocolGuid       = {0x31ce593d, 0x108a, 0x485d, {0xad, 0xb2, 0x78, 0xf2, 0x1f, 0x29, 0x66, 0xbe}}
   gEfiVgaMiniPortProtocolGuid           = {0xc7735a2f, 0x88f5, 0x4882, {0xae, 0x63, 0xfa, 0xac, 0x8c, 0x8b, 0x86, 0xb3}}
   gOvmfLoadedX86LinuxKernelProtocolGuid = {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}}
+  gPlatformGOPPolicyGuid                = {0xec2e931b, 0x3281, 0x48a5, {0x81, 0x07, 0xdf, 0x8a, 0x8b, 0xed, 0x3c, 0x5d}}
 
 [PcdsFixedAtBuild]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase|0x0|UINT32|0
diff --git a/OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.c b/OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.c
new file mode 100644
index 0000000000..ebff16b795
--- /dev/null
+++ b/OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.c
@@ -0,0 +1,295 @@
+/** @file
+  Platform GOP Policy
+
+  GOP drivers calls GetVbtData to get the Video BIOS Table of the Intel Graphics
+  Device.
+
+  Copyright (C) 1999 - 2019, Intel Corporation. All rights reserved
+  Copyright (C) 2021, Beckhoff Automation GmbH & Co. KG. All rights reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available under
+  the terms and conditions of the BSD License that accompanies this distribution.
+  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php.
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+**/
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/PlatformGopPolicy.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PciLib.h>
+
+#include <IndustryStandard/IgdOpRegion.h>
+#include <IndustryStandard/Pci22.h>
+
+//
+// IGD is always located at 0:2.0
+//
+#define IGD_PCI_BUS 0
+#define IGD_PCI_SLOT 2
+#define IGD_PCI_FUNC 0
+
+#define IGD_PCI_ASLS_OFFSET 0xFC
+
+#define IGD_PCI_VENDOR_ID 0x8086
+
+PLATFORM_GOP_POLICY_PROTOCOL  mPlatformGOPPolicy;
+VBT_HEADER *mVbt;
+
+/**
+  The function returns the Platform Lid Status. IBV/OEM can customize this code
+  for their specific policy action.
+
+  @param[out] CurrentLidStatus  Current LID Status.
+
+  @retval EFI_UNSUPPORTED       Function isn't implemented yet.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPlatformLidStatus (
+   OUT LID_STATUS *CurrentLidStatus
+)
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  The function returns the Video Bios Table size and address.
+
+  @param[out] VbtAddress  Physical Address of Video BIOS Table
+
+  @param[out] VbtSize     Size of Video BIOS Table
+
+  @retval EFI_STATUS      Successfully returned Video BIOS Table address and
+                          size.
+
+**/
+
+EFI_STATUS
+EFIAPI
+GetVbtData (
+   OUT EFI_PHYSICAL_ADDRESS *VbtAddress,
+   OUT UINT32 *VbtSize
+)
+{
+  EFI_STATUS Status;
+  IGD_OPREGION_STRUCTURE *OpRegion;
+  VBT_HEADER *Vbt;
+  UINT8 CheckSum = 0;
+  UINT16 VersionMajor;
+  UINT16 VersionMinor;
+  UINT32 VbtSizeMax = 0;
+  UINT16 VendorId;
+  UINT32 ClassCode;
+
+  //
+  // Check if vendor is Intel
+  //
+  VendorId = PciRead16 (
+               PCI_LIB_ADDRESS (
+                 IGD_PCI_BUS,
+                 IGD_PCI_SLOT,
+                 IGD_PCI_FUNC,
+                 PCI_VENDOR_ID_OFFSET
+               )
+             );
+  if (VendorId == 0xFFFF) {
+    return EFI_NOT_FOUND;
+  } else if (VendorId != IGD_PCI_VENDOR_ID) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Check if class is display device
+  //
+  ClassCode = PciRead32 (
+                PCI_LIB_ADDRESS (
+                  IGD_PCI_BUS,
+                  IGD_PCI_SLOT,
+                  IGD_PCI_FUNC,
+                  PCI_CLASSCODE_OFFSET & ~0x3
+                )
+              );
+  if (((ClassCode >> 24) & 0xFF) != PCI_CLASS_DISPLAY ||
+      ((ClassCode >> 16) & 0xFF) != PCI_CLASS_DISPLAY_VGA ||
+      ((ClassCode >>  8) & 0xFF) != PCI_IF_VGA_VGA) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Get OpRegion.
+  //
+  OpRegion = (IGD_OPREGION_STRUCTURE *)(UINTN)PciRead32 (
+                                         PCI_LIB_ADDRESS (
+                                           0,
+                                           2,
+                                           0,
+                                           IGD_PCI_ASLS_OFFSET
+                                           )
+                                        );
+  if (OpRegion == NULL) {
+      DEBUG ((EFI_D_ERROR, "%a: Failed to get OpRegion address\n",
+        __FUNCTION__));
+  }
+
+  //
+  // Check if Intel Graphics Device has an OpRegion.
+  //
+  if (!OpRegion) {
+    DEBUG ((EFI_D_ERROR, "%a: No OpRegion found\n", __FUNCTION__));
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Check OpRegion signature.
+  //
+  if (CompareMem (OpRegion->Header.SIGN, IGD_OPREGION_HEADER_SIGN, sizeof (OpRegion->Header.SIGN)) != 0) {
+    DEBUG ((EFI_D_ERROR, "%a: Invalid OpRegion signature (%a), expected %a\n",
+      __FUNCTION__, OpRegion->Header.SIGN, IGD_OPREGION_HEADER_SIGN));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  VersionMajor = OpRegion->Header.OVER >> 24;
+  VersionMinor = OpRegion->Header.OVER >> 16 & 0xFF;
+
+  //
+  // Only OpRegion v2.0 and higher is supported.
+  //
+  if (VersionMajor < 2) {
+    DEBUG ((EFI_D_ERROR, "%a: Unsupported OpRegion version %d.%d\n", __FUNCTION__,
+      VersionMajor, VersionMinor));
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // If the size of the Video BIOS Table larger then 6K, the Video BIOS Table is
+  // stored outside the OpRegion. In that case, the address and size of the
+  // Video BIOS Table are stored in MailBox3 (RVDA and RVDS). When OpRegion v2.0
+  // is used, RVDA is a physical address. In a virtual environment this physical
+  // address is invalid. For that reason, we do not support a Video BIOS Table
+  // which is larger than 6K for OpRegion v2.0.
+  //
+  if (VersionMajor == 2 &&
+      VersionMinor == 0 &&
+      OpRegion->MBox3.RVDA &&
+      OpRegion->MBox3.RVDS) {
+    DEBUG ((EFI_D_ERROR,
+      "%a: VBT larger than 6K is unsupported for OpRegion v2.0\n",
+      __FUNCTION__));
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Get Video BIOS Table size.
+  //
+  VbtSizeMax = IGD_OPREGION_VBT_SIZE_6K;
+  if (OpRegion->MBox3.RVDA && OpRegion->MBox3.RVDS) {
+    Vbt = (VBT_HEADER *)((UINT8 *)OpRegion + OpRegion->MBox3.RVDA);
+    VbtSizeMax = *VbtSize;
+  } else {
+    Vbt = (VBT_HEADER *)&OpRegion->MBox4;
+    VbtSizeMax = IGD_OPREGION_VBT_SIZE_6K;
+  }
+
+  //
+  // Free old Video BIOS Table.
+  //
+  if (mVbt) {
+    Status = gBS->FreePages (
+                    (EFI_PHYSICAL_ADDRESS)mVbt,
+                    EFI_SIZE_TO_PAGES (VbtSizeMax)
+                    );
+  }
+
+  //
+  // Allocate Video BIOS Table.
+  //
+  mVbt = (VBT_HEADER *)(SIZE_4GB - 1);
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  EfiReservedMemoryType,
+                  EFI_SIZE_TO_PAGES (VbtSizeMax),
+                  (EFI_PHYSICAL_ADDRESS *)&mVbt
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR,
+      "%a: AllocatePages failed for VBT size 0x%x status %d\n", __FUNCTION__,
+      VbtSizeMax, Status));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Copy Video BIOS Table to allocated space.
+  //
+  ZeroMem ((VOID*)mVbt, VbtSizeMax);
+  CopyMem((VOID*)mVbt, (VOID*)Vbt, Vbt->Table_Size);
+
+  //
+  // Fix checksum.
+  //
+  for (UINT32 i = 0; i < mVbt->Table_Size; i++) {
+    CheckSum = (CheckSum + ((UINT8*)mVbt)[i]) & 0xFF;
+  }
+  mVbt->Checksum += (0x100 - CheckSum);
+
+  //
+  // Return Video BIOS Table address and size.
+  //
+  *VbtAddress = (EFI_PHYSICAL_ADDRESS)mVbt;
+  *VbtSize = mVbt->Table_Size;
+  DEBUG ((DEBUG_INFO, "%a: VBT Version %d size 0x%x\n", __FUNCTION__,
+    ((VBT_BIOS_DATA_HEADER*)((VOID *)mVbt + mVbt->Bios_Data_Offset))->BDB_Version,
+    mVbt->Table_Size));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Entry point for the Platform GOP Policy Driver.
+
+  @param[in] ImageHandle  Image handle of this driver.
+
+  @param[in] SystemTable  Global system service table.
+
+  @retval EFI_SUCCESS     Initialization complete.
+
+  @return                 Error codes propagated from underlying functions.
+**/
+
+EFI_STATUS
+EFIAPI
+PlatformGOPPolicyEntryPoint (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+
+{
+  EFI_STATUS  Status;
+
+  gBS = SystemTable->BootServices;
+
+  mPlatformGOPPolicy.Revision = PLATFORM_GOP_POLICY_PROTOCOL_REVISION_01;
+  mPlatformGOPPolicy.GetPlatformLidStatus = GetPlatformLidStatus;
+  mPlatformGOPPolicy.GetVbtData = GetVbtData;
+
+  //
+  // Install protocol to allow access to this Policy.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &ImageHandle,
+                  &gPlatformGOPPolicyGuid,
+                  &mPlatformGOPPolicy,
+                  NULL
+                  );
+
+  return Status;
+}
diff --git a/OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.inf b/OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.inf
new file mode 100644
index 0000000000..8bf6f60f8f
--- /dev/null
+++ b/OvmfPkg/PlatformGopPolicy/PlatformGopPolicy.inf
@@ -0,0 +1,52 @@
+## @file
+#  Platform GOP Policy
+#
+#  GOP drivers calls GetVbtData to get the Video BIOS Table of the Intel Graphics
+#  Device.
+#
+# Copyright (c) 1999 - 2019, Intel Corporation. All rights reserved
+# Copyrigth (C) 2021, Beckhoff Automation GmbH & Co. KG. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available under
+# the terms and conditions of the BSD License that accompanies this distribution.
+# The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+##
+
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = PlatformGOPPolicy
+  FILE_GUID                      = 9737D7CA-D869-45e5-A5EF-75D9438688DE
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = PlatformGOPPolicyEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32
+#
+
+[Sources.common]
+  PlatformGopPolicy.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  UefiDriverEntryPoint
+  UefiRuntimeServicesTableLib
+  PciLib
+
+[Protocols]
+  gPlatformGOPPolicyGuid
+
+[Depex]
+  TRUE
