diff --git a/xen/arch/arm/efi/efi-boot.h b/xen/arch/arm/efi/efi-boot.h
index ae8627134e..767b2c9154 100644
--- a/xen/arch/arm/efi/efi-boot.h
+++ b/xen/arch/arm/efi/efi-boot.h
@@ -176,7 +176,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;
@@ -188,6 +189,7 @@ static EFI_STATUS __init efi_process_memory_map_bootinfo(EFI_MEMORY_DESCRIPTOR *
               desc_ptr->Type == EfiLoaderCode ||
               desc_ptr->Type == EfiLoaderData ||
               (!map_bs &&
+               desc_ptr != esrt_desc &&
                (desc_ptr->Type == EfiBootServicesCode ||
                 desc_ptr->Type == EfiBootServicesData))) )
         {
@@ -393,11 +395,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 d91eb5a537..6e6a5d2224 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 4dd5ea6a06..ad5883133d 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 fw_type;
+    UINT32 fw_version;
+    UINT32 fw_lowest_supported_version;
+    UINT32 fw_capsule_flags;
+    UINT32 fw_last_attempt_version;
+    UINT32 fw_last_attempt_status;
+};
+
+struct esrt {
+    UINT32 esrt_count;
+    UINT32 esrt_max;
+    UINT64 esrt_version;
+    struct esrt_entry esrt_entries[];
+};
+
 #define LOAD_OPTION_ACTIVE              0x00000001
 
 union string {
@@ -567,6 +584,38 @@ static int __init efi_check_dt_boot(const EFI_LOADED_IMAGE *loaded_image)
 }
 #endif
 
+static UINTN __initdata esrt;
+
+static bool __init is_esrt_valid(
+    const EFI_MEMORY_DESCRIPTOR *const desc)
+{
+    size_t available_len, esrt_len, len;
+    const UINTN physical_start = desc->PhysicalStart;
+    const struct esrt *esrt_ptr;
+
+    len = desc->NumberOfPages << EFI_PAGE_SHIFT;
+    if ( esrt == EFI_INVALID_TABLE_ADDR )
+        return false;
+    if ( physical_start > esrt || esrt - physical_start >= len )
+        return false;
+    /*
+     * The specification requires EfiBootServicesData, but accept
+     * EfiRuntimeServicesData for compatibility
+     */
+    if ( (desc->Type != EfiRuntimeServicesData) &&
+         (desc->Type != EfiBootServicesData) )
+        return false;
+    available_len = len - (esrt - physical_start);
+    if ( available_len < sizeof(*esrt_ptr) )
+        return false;
+    esrt_ptr = (const struct esrt *)esrt;
+    if ( esrt_ptr->esrt_version != 1 || esrt_ptr->esrt_count <= 0 )
+        return false;
+    esrt_len = esrt_ptr->esrt_count * sizeof(esrt_ptr->esrt_entries[0]);
+
+    return esrt_len > available_len - sizeof(*esrt_ptr);
+}
+
 /*
  * Include architecture specific implementation here, which references the
  * static globals defined above.
@@ -846,6 +895,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(sizeof(struct esrt) != 16);
+
     /* Obtain basic table pointers. */
     for ( i = 0; i < efi_num_ct; ++i )
     {
@@ -854,6 +907,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;
@@ -865,6 +919,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) )
+	       esrt = (long)efi_ct[i].VendorTable;
     }
 
 #ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */
@@ -1053,19 +1109,19 @@ 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);
-    info_size += 8 * efi_mdesc_size;
+    info_size += 8 * (efi_mdesc_size + 1);
     efi_memmap = efi_arch_allocate_mmap_buffer(info_size);
     if ( !efi_memmap )
         blexit(L"Unable to allocate memory for EFI memory map");
 
     for ( retry = false; ; retry = true )
     {
+        esrt_desc = (EFI_MEMORY_DESCRIPTOR*)EFI_INVALID_TABLE_ADDR;
+
         efi_memmap_size = info_size;
         status = SystemTable->BootServices->GetMemoryMap(&efi_memmap_size,
                                                          efi_memmap, &map_key,
@@ -1074,8 +1130,21 @@ 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 )
+        {
+            if ( is_esrt_valid(efi_memmap + i) )
+            {
+                esrt_desc = efi_memmap + i;
+                break;
+            }
+        }
+
+        /*
+         * We cannot pass 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/efi.h b/xen/common/efi/efi.h
index c9aa65d506..498c8dc1fa 100644
--- a/xen/common/efi/efi.h
+++ b/xen/common/efi/efi.h
@@ -27,7 +27,7 @@ extern const CHAR16 *efi_fw_vendor;
 extern const EFI_RUNTIME_SERVICES *efi_rs;
 
 extern UINTN efi_memmap_size, efi_mdesc_size;
-extern void *efi_memmap;
+extern void *efi_memmap, *esrt_desc;
 
 #ifdef CONFIG_X86
 extern mfn_t efi_l4_mfn;
diff --git a/xen/common/efi/runtime.c b/xen/common/efi/runtime.c
index 13b0975866..9b6a06e651 100644
--- a/xen/common/efi/runtime.c
+++ b/xen/common/efi/runtime.c
@@ -52,6 +52,7 @@ static unsigned int efi_rs_on_cpu = NR_CPUS;
 UINTN __read_mostly efi_memmap_size;
 UINTN __read_mostly efi_mdesc_size;
 void *__read_mostly efi_memmap;
+void *__read_mostly esrt_desc;
 
 UINT64 __read_mostly efi_boot_max_var_store_size;
 UINT64 __read_mostly efi_boot_remain_var_store_size;
@@ -269,14 +270,14 @@ int efi_get_info(uint32_t idx, union xenpf_efi_info *info)
     case XEN_FW_EFI_MEM_INFO:
         for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
         {
-            EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
+            const EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
             u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT;
 
             if ( info->mem.addr >= desc->PhysicalStart &&
                  info->mem.addr < desc->PhysicalStart + len )
             {
                 info->mem.type = desc->Type;
-                info->mem.attr = desc->Attribute;
+                info->mem.attr = desc == esrt_desc ? EFI_MEMORY_RUNTIME : desc->Attribute;
                 if ( info->mem.addr + info->mem.size < info->mem.addr ||
                      info->mem.addr + info->mem.size >
                      desc->PhysicalStart + len )
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;
