diff --git a/OvmfPkg/XenPlatformPei/Platform.h b/OvmfPkg/XenPlatformPei/Platform.h
index db9a62572f..7661f4a8de 100644
--- a/OvmfPkg/XenPlatformPei/Platform.h
+++ b/OvmfPkg/XenPlatformPei/Platform.h
@@ -44,6 +44,13 @@ AddReservedMemoryBaseSizeHob (
   BOOLEAN                     Cacheable
   );
 
+VOID
+AddReservedMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit,
+  BOOLEAN                     Cacheable
+  );
+
 VOID
 AddressWidthInitialization (
   VOID
@@ -114,6 +121,12 @@ XenPublishRamRegions (
   VOID
   );
 
+EFI_STATUS
+XenGetE820Map (
+  EFI_E820_ENTRY64 **Entries,
+  UINT32 *Count
+  );
+
 extern EFI_BOOT_MODE mBootMode;
 
 extern UINT8 mPhysMemAddressWidth;
diff --git a/OvmfPkg/XenPlatformPei/MemDetect.c b/OvmfPkg/XenPlatformPei/MemDetect.c
index cf95f9c474..1f81eee407 100644
--- a/OvmfPkg/XenPlatformPei/MemDetect.c
+++ b/OvmfPkg/XenPlatformPei/MemDetect.c
@@ -96,6 +96,45 @@ Q35TsegMbytesInitialization (
   mQ35TsegMbytes = ExtendedTsegMbytes;
 }
 
+STATIC
+UINT64
+GetHighestSystemMemoryAddress (
+  BOOLEAN       Below4gb
+  )
+{
+  EFI_E820_ENTRY64    *E820Map;
+  UINT32              E820EntriesCount;
+  EFI_E820_ENTRY64    *Entry;
+  EFI_STATUS          Status;
+  UINT32              Loop;
+  UINT64              HighestAddress;
+  UINT64              EntryEnd;
+
+  HighestAddress = 0;
+
+  Status = XenGetE820Map (&E820Map, &E820EntriesCount);
+  ASSERT_EFI_ERROR (Status);
+
+  for (Loop = 0; Loop < E820EntriesCount; Loop++) {
+    Entry = E820Map + Loop;
+    EntryEnd = Entry->BaseAddr + Entry->Length;
+
+    if (Entry->Type == EfiAcpiAddressRangeMemory &&
+        EntryEnd > HighestAddress) {
+
+      if (Below4gb && (EntryEnd <= BASE_4GB)) {
+        HighestAddress = EntryEnd;
+      } else if (!Below4gb && (EntryEnd >= BASE_4GB)) {
+        HighestAddress = EntryEnd;
+      }
+    }
+  }
+
+  //
+  // Round down the end address.
+  //
+  return HighestAddress & ~(UINT64)EFI_PAGE_MASK;
+}
 
 UINT32
 GetSystemMemorySizeBelow4gb (
@@ -105,6 +144,19 @@ GetSystemMemorySizeBelow4gb (
   UINT8 Cmos0x34;
   UINT8 Cmos0x35;
 
+  //
+  // In PVH case, there is no CMOS, we have to calculate the memory size
+  // from parsing the E820
+  //
+  if (XenPvhDetected ()) {
+    UINT64  HighestAddress;
+
+    HighestAddress = GetHighestSystemMemoryAddress (TRUE);
+    ASSERT (HighestAddress > 0 && HighestAddress <= BASE_4GB);
+
+    return HighestAddress;
+  }
+
   //
   // CMOS 0x34/0x35 specifies the system memory above 16 MB.
   // * CMOS(0x35) is the high byte
@@ -129,6 +181,23 @@ GetSystemMemorySizeAbove4gb (
   UINT32 Size;
   UINTN  CmosIndex;
 
+  //
+  // In PVH case, there is no CMOS, we have to calculate the memory size
+  // from parsing the E820
+  //
+  if (XenPvhDetected ()) {
+    UINT64  HighestAddress;
+
+    HighestAddress = GetHighestSystemMemoryAddress (FALSE);
+    ASSERT (HighestAddress == 0 || HighestAddress >= BASE_4GB);
+
+    if (HighestAddress >= BASE_4GB) {
+      HighestAddress -= BASE_4GB;
+    }
+
+    return HighestAddress;
+  }
+
   //
   // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
   // * CMOS(0x5d) is the most significant size byte
diff --git a/OvmfPkg/XenPlatformPei/Platform.c b/OvmfPkg/XenPlatformPei/Platform.c
index 6aaafc3ee9..2f42ca6ccd 100644
--- a/OvmfPkg/XenPlatformPei/Platform.c
+++ b/OvmfPkg/XenPlatformPei/Platform.c
@@ -102,6 +102,17 @@ AddReservedMemoryBaseSizeHob (
     );
 }
 
+VOID
+AddReservedMemoryRangeHob (
+  EFI_PHYSICAL_ADDRESS        MemoryBase,
+  EFI_PHYSICAL_ADDRESS        MemoryLimit,
+  BOOLEAN                     Cacheable
+  )
+{
+  AddReservedMemoryBaseSizeHob (MemoryBase,
+    (UINT64)(MemoryLimit - MemoryBase), Cacheable);
+}
+
 VOID
 AddIoMemoryRangeHob (
   EFI_PHYSICAL_ADDRESS        MemoryBase,
diff --git a/OvmfPkg/XenPlatformPei/Xen.c b/OvmfPkg/XenPlatformPei/Xen.c
index a21d657357..182e96cc5b 100644
--- a/OvmfPkg/XenPlatformPei/Xen.c
+++ b/OvmfPkg/XenPlatformPei/Xen.c
@@ -276,9 +276,12 @@ XenPublishRamRegions (
   VOID
   )
 {
-  EFI_E820_ENTRY64  *E820Map;
-  UINT32            E820EntriesCount;
-  EFI_STATUS        Status;
+  EFI_E820_ENTRY64      *E820Map;
+  UINT32                E820EntriesCount;
+  EFI_STATUS            Status;
+  EFI_E820_ENTRY64      *Entry;
+  UINTN                 Index;
+  EFI_PHYSICAL_ADDRESS  LocalApic;
 
   DEBUG ((DEBUG_INFO, "Using memory map provided by Xen\n"));
 
@@ -287,26 +290,47 @@ XenPublishRamRegions (
   //
   E820EntriesCount = 0;
   Status = XenGetE820Map (&E820Map, &E820EntriesCount);
-
   ASSERT_EFI_ERROR (Status);
 
-  if (E820EntriesCount > 0) {
-    EFI_E820_ENTRY64 *Entry;
-    UINT32 Loop;
-
-    for (Loop = 0; Loop < E820EntriesCount; Loop++) {
-      Entry = E820Map + Loop;
-
-      //
-      // Only care about RAM
-      //
-      if (Entry->Type != EfiAcpiAddressRangeMemory) {
-        continue;
+  LocalApic = PcdGet32(PcdCpuLocalApicBaseAddress);
+  AddIoMemoryBaseSizeHob (LocalApic, SIZE_1MB);
+
+  for (Index = 0; Index < E820EntriesCount; Index++) {
+    UINT64 Base;
+    UINT64 End;
+
+    Entry = &E820Map[Index];
+
+    //
+    // Round up the start address, and round down the end address.
+    //
+    Base = ALIGN_VALUE (Entry->BaseAddr, (UINT64)EFI_PAGE_SIZE);
+    End = (Entry->BaseAddr + Entry->Length) & ~(UINT64)EFI_PAGE_MASK;
+
+    switch (Entry->Type) {
+    case EfiAcpiAddressRangeMemory:
+      AddMemoryRangeHob (Base, End);
+      break;
+    case EfiAcpiAddressRangeACPI:
+      AddReservedMemoryRangeHob (Base, End, FALSE);
+      break;
+    case EfiAcpiAddressRangeReserved:
+      if (Base < LocalApic && LocalApic < End) {
+        //
+        // hvmloader marks a range that overlaps with the local APIC memory
+        // mapped region as reserved, but CpuDxe wants it as mapped IO. We
+        // have already added it as mapped IO, so skip it here.
+        //
+        AddReservedMemoryRangeHob (Base, LocalApic, FALSE);
+        if (End > (LocalApic + SIZE_1MB)) {
+          AddReservedMemoryRangeHob (LocalApic + SIZE_1MB, End, FALSE);
+        }
+      } else {
+        AddReservedMemoryRangeHob (Base, End, FALSE);
       }
-
-      AddMemoryBaseSizeHob (Entry->BaseAddr, Entry->Length);
-
-      MtrrSetMemoryAttribute (Entry->BaseAddr, Entry->Length, CacheWriteBack);
+      break;
+    default:
+      break;
     }
   }
 }
@@ -326,12 +350,6 @@ InitializeXen (
 {
   RETURN_STATUS PcdStatus;
 
-  //
-  // Reserve away HVMLOADER reserved memory [0xFC000000,0xFD000000).
-  // This needs to match HVMLOADER RESERVED_MEMBASE/RESERVED_MEMSIZE.
-  //
-  AddReservedMemoryBaseSizeHob (0xFC000000, 0x1000000, FALSE);
-
   PcdStatus = PcdSetBoolS (PcdPciDisableBusEnumeration, TRUE);
   ASSERT_RETURN_ERROR (PcdStatus);
 
