diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index 487bada64d..af92ce3ed2 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -196,6 +196,7 @@ [LibraryClasses]
   OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf
   XenHypercallLib|OvmfPkg/Library/XenHypercallLib/XenHypercallLib.inf
   XenPlatformLib|OvmfPkg/Library/XenPlatformLib/XenPlatformLib.inf
+  XenIoMmioLib|OvmfPkg/Library/XenIoMmioLib/XenIoMmioLib.inf
 
   Tcg2PhysicalPresenceLib|OvmfPkg/Library/Tcg2PhysicalPresenceLibNull/DxeTcg2PhysicalPresenceLib.inf
 
@@ -583,6 +584,7 @@ [Components]
       NULL|OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf
 !endif
   }
+  OvmfPkg/XenIoPvhDxe/XenIoPvhDxe.inf
   OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
   OvmfPkg/XenBusDxe/XenBusDxe.inf
   OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
diff --git a/OvmfPkg/OvmfXen.fdf b/OvmfPkg/OvmfXen.fdf
index 5c1a925d6a..517a492f14 100644
--- a/OvmfPkg/OvmfXen.fdf
+++ b/OvmfPkg/OvmfXen.fdf
@@ -309,6 +309,7 @@ [FV.DXEFV]
 INF  MdeModulePkg/Universal/Metronome/Metronome.inf
 INF  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
 
+INF  OvmfPkg/XenIoPvhDxe/XenIoPvhDxe.inf
 INF  OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
 INF  OvmfPkg/XenBusDxe/XenBusDxe.inf
 INF  OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
diff --git a/OvmfPkg/XenIoPvhDxe/XenIoPvhDxe.inf b/OvmfPkg/XenIoPvhDxe/XenIoPvhDxe.inf
new file mode 100644
index 0000000000..a093d48fde
--- /dev/null
+++ b/OvmfPkg/XenIoPvhDxe/XenIoPvhDxe.inf
@@ -0,0 +1,34 @@
+## @file
+#  Driver for the XenIo protocol
+#
+#  Copyright (c) 2019, Citrix Systems, Inc.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION               = 0x00010005
+  BASE_NAME                 = XenIoPvhDxe
+  FILE_GUID                 = 7a567cc4-0e75-4d7a-a305-c3db109b53ad
+  MODULE_TYPE               = DXE_DRIVER
+  VERSION_STRING            = 1.0
+  ENTRY_POINT               = InitializeXenIoPvhDxe
+
+[Packages]
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[Sources]
+  XenIoPvhDxe.c
+
+[LibraryClasses]
+  DebugLib
+  MemoryAllocationLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  XenIoMmioLib
+  XenPlatformLib
+
+[Depex]
+  TRUE
diff --git a/OvmfPkg/XenIoPvhDxe/XenIoPvhDxe.c b/OvmfPkg/XenIoPvhDxe/XenIoPvhDxe.c
new file mode 100644
index 0000000000..88a394bf91
--- /dev/null
+++ b/OvmfPkg/XenIoPvhDxe/XenIoPvhDxe.c
@@ -0,0 +1,108 @@
+/** @file
+
+  Driver for the XenIo protocol
+
+  This driver simply allocate space for the grant tables.
+
+  Copyright (c) 2019, Citrix Systems, Inc.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/XenIoMmioLib.h>
+#include <Library/XenPlatformLib.h>
+
+typedef struct {
+  EFI_HANDLE    XenIoHandle;
+  EFI_EVENT     ExitBootEvent;
+  VOID          *Allocation;
+} XEN_IO_PVH_STATE;
+
+//
+// Value should be the same as NR_GRANT_FRAMES in XenBusDxe
+//
+#define XEN_GRANT_FRAMES 4
+
+STATIC
+VOID
+EFIAPI
+XenIoPvhDxeNotifyExitBoot (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  XEN_IO_PVH_STATE *State;
+  EFI_STATUS Status;
+
+  State = Context;
+
+  gBS->CloseEvent(&State->ExitBootEvent);
+  Status = XenIoMmioUninstall(State->XenIoHandle);
+  if (Status == EFI_SUCCESS) {
+    //
+    // Only free the reserved space for grant table if no driver is using it.
+    //
+    FreePages (State->Allocation, XEN_GRANT_FRAMES);
+  }
+  FreePool (State);
+}
+
+EFI_STATUS
+EFIAPI
+InitializeXenIoPvhDxe (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  VOID *Allocation;
+  EFI_STATUS Status;
+  XEN_IO_PVH_STATE *State;
+
+  State = NULL;
+  Allocation = NULL;
+
+  if (! XenPvhDetected ()) {
+    return EFI_UNSUPPORTED;
+  }
+
+  State = AllocatePool (sizeof (*State));
+  if (State == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Error;
+  }
+
+  Allocation = AllocateReservedPages (XEN_GRANT_FRAMES);
+  if (Allocation == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Error;
+  }
+
+  State->XenIoHandle = NULL;
+  Status = XenIoMmioInstall (&State->XenIoHandle, (UINTN) Allocation);
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+
+  State->Allocation = Allocation;
+  Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
+                  XenIoPvhDxeNotifyExitBoot, State, &State->ExitBootEvent);
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+
+Error:
+  if (State != NULL && State->XenIoHandle != NULL) {
+    XenIoMmioUninstall(State->XenIoHandle);
+  }
+  if (Allocation != NULL) {
+    FreePages (Allocation, XEN_GRANT_FRAMES);
+  }
+  if (State != NULL) {
+    FreePool (State);
+  }
+  return Status;
+}
