diff --git a/xen/arch/arm/efi/efi-boot.h b/xen/arch/arm/efi/efi-boot.h
index cf9c37153f..d8de478022 100644
--- a/xen/arch/arm/efi/efi-boot.h
+++ b/xen/arch/arm/efi/efi-boot.h
@@ -142,7 +142,8 @@ static bool __init meminfo_add_bank(struct meminfo *mem,
 
 static EFI_STATUS __init efi_process_memory_map_bootinfo(EFI_MEMORY_DESCRIPTOR *map,
                                                 UINTN mmap_size,
-                                                UINTN desc_size)
+                                                UINTN desc_size,
+                                                const EFI_MEMORY_DESCRIPTOR *const esrt_desc)
 {
     int Index;
     EFI_MEMORY_DESCRIPTOR *desc_ptr = map;
@@ -154,6 +155,7 @@ static EFI_STATUS __init efi_process_memory_map_bootinfo(EFI_MEMORY_DESCRIPTOR *
               desc_ptr->Type == EfiLoaderCode ||
               desc_ptr->Type == EfiLoaderData ||
               (!map_bs &&
+               desc != esrt_desc &&
                (desc_ptr->Type == EfiBootServicesCode ||
                 desc_ptr->Type == EfiBootServicesData))) )
         {
@@ -359,11 +361,12 @@ static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable,
                                                void *map,
                                                UINTN map_size,
                                                UINTN desc_size,
-                                               UINT32 desc_ver)
+                                               UINT32 desc_ver,
+                                               const EFI_MEMORY_DESCRIPTOR *const esrt_desc)
 {
     EFI_STATUS status;
 
-    status = efi_process_memory_map_bootinfo(map, map_size, desc_size);
+    status = efi_process_memory_map_bootinfo(map, map_size, desc_size, esrt_desc);
     if ( EFI_ERROR(status) )
         blexit(L"EFI memory map processing failed");
 
diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h
index fb217031ff..f381855368 100644
--- a/xen/arch/x86/efi/efi-boot.h
+++ b/xen/arch/x86/efi/efi-boot.h
@@ -154,7 +154,8 @@ static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable,
                                                void *map,
                                                UINTN map_size,
                                                UINTN desc_size,
-                                               UINT32 desc_ver)
+                                               UINT32 desc_ver,
+                                               const EFI_MEMORY_DESCRIPTOR *const esrt_desc)
 {
     struct e820entry *e;
     unsigned int i;
@@ -171,7 +172,7 @@ static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable,
         {
         case EfiBootServicesCode:
         case EfiBootServicesData:
-            if ( map_bs )
+            if ( map_bs || desc == esrt_desc )
             {
         default:
                 type = E820_RESERVED;
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c
index 758f9d74d2..0603172074 100644
--- a/xen/common/efi/boot.c
+++ b/xen/common/efi/boot.c
@@ -93,6 +93,23 @@ typedef struct _EFI_LOAD_OPTION {
     CHAR16 Description[];
 } EFI_LOAD_OPTION;
 
+struct esrt_entry {
+    EFI_GUID fw_class;
+    uint32_t fw_type;
+    uint32_t fw_version;
+    uint32_t fw_lowest_supported_version;
+    uint32_t fw_capsule_flags;
+    uint32_t fw_last_attempt_version;
+    uint32_t fw_last_attempt_status;
+};
+
+struct esrt {
+    uint32_t esrt_count;
+    uint32_t esrt_max;
+    uint64_t esrt_version;
+    struct esrt_entry esrt_entries[];
+};
+
 #define LOAD_OPTION_ACTIVE              0x00000001
 
 union string {
@@ -166,6 +183,41 @@ static void __init PrintErr(const CHAR16 *s)
     StdErr->OutputString(StdErr, (CHAR16 *)s );
 }
 
+enum esrt_status {
+    ESRT_NOTFOUND = 0,
+    ESRT_GOOD,
+    ESRT_BAD,
+};
+
+static enum esrt_status __init is_esrt_valid(
+    const EFI_MEMORY_DESCRIPTOR *const desc) {
+    size_t available_len, esrt_len, len;
+    const uintptr_t physical_start = desc->PhysicalStart;
+    const uintptr_t esrt = efi.esrt;
+    const struct esrt *esrt_ptr;
+
+    len = desc->NumberOfPages << EFI_PAGE_SHIFT;
+    if ( esrt == EFI_INVALID_TABLE_ADDR )
+        return ESRT_BAD;
+    if ( physical_start > esrt || esrt - physical_start >= len )
+        return ESRT_NOTFOUND;
+    if ( ! ( desc->Attribute & EFI_MEMORY_RUNTIME ) &&
+           ( desc->Type != EfiRuntimeServicesData ) &&
+           ( desc->Type != EfiBootServicesData ) )
+        return ESRT_BAD;
+    available_len = len - (esrt - physical_start);
+    if ( available_len < offsetof(struct esrt, esrt_entries) )
+        return ESRT_BAD;
+    esrt_ptr = (const struct esrt *) esrt;
+    if ( esrt_ptr->esrt_count <= 0 ||
+         __builtin_mul_overflow(esrt_ptr->esrt_count,
+                                sizeof(struct esrt_entry),
+                                &esrt_len) ||
+         esrt_len > available_len - offsetof(struct esrt, esrt_entries) )
+        return ESRT_BAD;
+    return ESRT_GOOD;
+}
+
 /*
  * Include architecture specific implementation here, which references the
  * static globals defined above.
@@ -835,6 +887,10 @@ static void __init efi_tables(void)
 {
     unsigned int i;
 
+    BUILD_BUG_ON(sizeof(struct esrt_entry) != 40);
+    BUILD_BUG_ON(_Alignof(struct esrt_entry) != 4);
+    BUILD_BUG_ON(offsetof(struct esrt, esrt_entries) != 16);
+
     /* Obtain basic table pointers. */
     for ( i = 0; i < efi_num_ct; ++i )
     {
@@ -843,6 +899,7 @@ static void __init efi_tables(void)
         static EFI_GUID __initdata mps_guid = MPS_TABLE_GUID;
         static EFI_GUID __initdata smbios_guid = SMBIOS_TABLE_GUID;
         static EFI_GUID __initdata smbios3_guid = SMBIOS3_TABLE_GUID;
+        static EFI_GUID __initdata esrt_guid = ESRT_GUID;
 
         if ( match_guid(&acpi2_guid, &efi_ct[i].VendorGuid) )
 	       efi.acpi20 = (long)efi_ct[i].VendorTable;
@@ -854,6 +911,8 @@ static void __init efi_tables(void)
 	       efi.smbios = (long)efi_ct[i].VendorTable;
         if ( match_guid(&smbios3_guid, &efi_ct[i].VendorGuid) )
 	       efi.smbios3 = (long)efi_ct[i].VendorTable;
+        if ( match_guid(&esrt_guid, &efi_ct[i].VendorGuid) )
+	       efi.esrt = (long)efi_ct[i].VendorTable;
     }
 
 #ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */
@@ -1042,9 +1101,7 @@ static void __init efi_exit_boot(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *Syste
     EFI_STATUS status;
     UINTN info_size = 0, map_key;
     bool retry;
-#ifdef CONFIG_EFI_SET_VIRTUAL_ADDRESS_MAP
     unsigned int i;
-#endif
 
     efi_bs->GetMemoryMap(&info_size, NULL, &map_key,
                          &efi_mdesc_size, &mdesc_ver);
@@ -1055,6 +1112,10 @@ static void __init efi_exit_boot(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *Syste
 
     for ( retry = false; ; retry = true )
     {
+        enum esrt_status esrt_status = ESRT_NOTFOUND;
+        const EFI_MEMORY_DESCRIPTOR *esrt_desc =
+            (const EFI_MEMORY_DESCRIPTOR*) EFI_INVALID_TABLE_ADDR;
+
         efi_memmap_size = info_size;
         status = SystemTable->BootServices->GetMemoryMap(&efi_memmap_size,
                                                          efi_memmap, &map_key,
@@ -1063,8 +1124,31 @@ static void __init efi_exit_boot(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *Syste
         if ( EFI_ERROR(status) )
             PrintErrMesg(L"Cannot obtain memory map", status);
 
+        for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
+        {
+            EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
+            switch ( is_esrt_valid(desc) )
+            {
+            case ESRT_NOTFOUND:
+                break;
+            case ESRT_GOOD:
+                esrt_status = ESRT_GOOD;
+                esrt_desc = desc;
+                break;
+            case ESRT_BAD:
+                esrt_status = ESRT_BAD;
+                break;
+            }
+        }
+        if ( esrt_status != ESRT_GOOD )
+            efi.esrt = EFI_INVALID_TABLE_ADDR;
+
+        /*
+         * We cannot pass efi.esrt because we need to explicitly compare the
+         * descriptor pointers for equality.
+         */
         efi_arch_process_memory_map(SystemTable, efi_memmap, efi_memmap_size,
-                                    efi_mdesc_size, mdesc_ver);
+                                    efi_mdesc_size, mdesc_ver, esrt_desc);
 
         efi_arch_pre_exit_boot();
 
diff --git a/xen/common/efi/runtime.c b/xen/common/efi/runtime.c
index 375b94229e..8ae086feaa 100644
--- a/xen/common/efi/runtime.c
+++ b/xen/common/efi/runtime.c
@@ -68,6 +68,7 @@ struct efi __read_mostly efi = {
 	.mps    = EFI_INVALID_TABLE_ADDR,
 	.smbios = EFI_INVALID_TABLE_ADDR,
 	.smbios3 = EFI_INVALID_TABLE_ADDR,
+	.esrt   = EFI_INVALID_TABLE_ADDR,
 };
 
 const struct efi_pci_rom *__read_mostly efi_pci_roms;
diff --git a/xen/include/efi/efiapi.h b/xen/include/efi/efiapi.h
index a616d1238a..42ef3e1c8c 100644
--- a/xen/include/efi/efiapi.h
+++ b/xen/include/efi/efiapi.h
@@ -882,6 +882,9 @@ typedef struct _EFI_BOOT_SERVICES {
 #define SAL_SYSTEM_TABLE_GUID    \
     { 0xeb9d2d32, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }
 
+#define ESRT_GUID    \
+    { 0xb122a263, 0x3661, 0x4f68, {0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80} }
+
 
 typedef struct _EFI_CONFIGURATION_TABLE {
     EFI_GUID                VendorGuid;
diff --git a/xen/include/xen/efi.h b/xen/include/xen/efi.h
index 94a7e547f9..bb149fbfb9 100644
--- a/xen/include/xen/efi.h
+++ b/xen/include/xen/efi.h
@@ -19,6 +19,7 @@ struct efi {
     unsigned long acpi20;       /* ACPI table (ACPI 2.0) */
     unsigned long smbios;       /* SM BIOS table */
     unsigned long smbios3;      /* SMBIOS v3 table */
+    unsigned long esrt;         /* EFI System Reference Table */
 };
 
 extern struct efi efi;
