[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v4 1/2] Avoid using EFI tables Xen may have clobbered



Memory of type EFI_CONVENTIONAL_MEMORY, EFI_LOADER_CODE, EFI_LOADER_DATA,
EFI_BOOT_SERVICES_CODE, and EFI_BOOT_SERVICES_DATA may be clobbered by
Xen before Linux gets to start using it.  Therefore, Linux under Xen
must not use EFI tables from such memory.  Most of the remaining EFI
memory types are not suitable for EFI tables, leaving only
EFI_ACPI_RECLAIM_MEMORY, EFI_RUNTIME_SERVICES_DATA, and
EFI_RUNTIME_SERVICES_CODE.  When running under Xen, Linux should only
use tables that are located in one of these types of memory.

This patch ensures this, and also adds a function
(xen_config_table_memory_region_max()) that will be used later to
replace the usage of the EFI memory map in esrt.c when running under
Xen.  This function can also be used in mokvar-table.c and efi-bgrt.c,
but I have not implemented this.

Signed-off-by: Demi Marie Obenour <demi@xxxxxxxxxxxxxxxxxxxxxx>
---
 drivers/firmware/efi/efi.c |  8 +++++---
 drivers/xen/efi.c          | 35 +++++++++++++++++++++++++++++++++++
 include/linux/efi.h        |  9 +++++++++
 3 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 
e4080ad96089abd7f84745dd8461c548bcbb7685..d344f3ff73d1c5ed0c67e3251a9502e66719741d
 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -574,7 +574,6 @@ int __init efi_config_parse_tables(const efi_config_table_t 
*config_tables,
        unsigned long table;
        int i;
 
-       pr_info("");
        for (i = 0; i < count; i++) {
                if (!IS_ENABLED(CONFIG_X86)) {
                        guid = &config_tables[i].guid;
@@ -585,7 +584,6 @@ int __init efi_config_parse_tables(const efi_config_table_t 
*config_tables,
 
                        if (IS_ENABLED(CONFIG_X86_32) &&
                            tbl64[i].table > U32_MAX) {
-                               pr_cont("\n");
                                pr_err("Table located above 4GB, disabling 
EFI.\n");
                                return -EINVAL;
                        }
@@ -594,10 +592,14 @@ int __init efi_config_parse_tables(const 
efi_config_table_t *config_tables,
                        table = tbl32[i].table;
                }
 
+#ifdef CONFIG_XEN_EFI
+               if (efi_enabled(EFI_PARAVIRT) && 
!xen_config_table_memory_region_max(table))
+                       continue;
+#endif
+
                if (!match_config_table(guid, table, common_tables) && 
arch_tables)
                        match_config_table(guid, table, arch_tables);
        }
-       pr_cont("\n");
        set_bit(EFI_CONFIG_TABLES, &efi.flags);
 
        if (efi_rng_seed != EFI_INVALID_TABLE_ADDR) {
diff --git a/drivers/xen/efi.c b/drivers/xen/efi.c
index 
d1ff2186ebb48a7c0981ecb6d4afcbbb25ffcea0..c2274ddfcc63304008ef0fd78fd9fa416f75d073
 100644
--- a/drivers/xen/efi.c
+++ b/drivers/xen/efi.c
@@ -28,6 +28,7 @@
 #include <xen/interface/platform.h>
 #include <xen/xen.h>
 #include <xen/xen-ops.h>
+#include <xen/page.h>
 
 #include <asm/page.h>
 
@@ -271,6 +272,40 @@ static void xen_efi_reset_system(int reset_type, 
efi_status_t status,
        }
 }
 
+__init u64 xen_config_table_memory_region_max(u64 addr)
+{
+       static_assert(XEN_PAGE_SHIFT == EFI_PAGE_SHIFT,
+                     "Mismatch between EFI_PAGE_SHIFT and XEN_PAGE_SHIFT");
+       struct xen_platform_op op = {
+               .cmd = XENPF_firmware_info,
+               .u.firmware_info = {
+                       .type = XEN_FW_EFI_INFO,
+                       .index = XEN_FW_EFI_MEM_INFO,
+                       .u.efi_info.mem.addr = addr,
+                       .u.efi_info.mem.size = U64_MAX - addr,
+               }
+       };
+       union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
+       int rc = HYPERVISOR_platform_op(&op);
+
+       if (rc) {
+               pr_warn("Failed to lookup header %llu in Xen memory map: error 
%d\n",
+                       (unsigned long long)addr, rc);
+               return 0;
+       }
+
+       switch (info->mem.type) {
+       case EFI_RUNTIME_SERVICES_CODE:
+       case EFI_RUNTIME_SERVICES_DATA:
+       case EFI_ACPI_RECLAIM_MEMORY:
+               return info->mem.addr + info->mem.size;
+       default:
+               pr_warn("Table %llu is in memory of type %d, ignoring it\n",
+                       (unsigned long long)addr, info->mem.type);
+               return 0;
+       }
+}
+
 /*
  * Set XEN EFI runtime services function pointers. Other fields of struct efi,
  * e.g. efi.systab, will be set like normal EFI.
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 
d2b84c2fec39f0268324d1a38a73ed67786973c9..fc81e4b984398cdb399e7886b2cae7f33bf91613
 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1324,4 +1324,13 @@ struct linux_efi_coco_secret_area {
 /* Header of a populated EFI secret area */
 #define EFI_SECRET_TABLE_HEADER_GUID   EFI_GUID(0x1e74f542, 0x71dd, 0x4d66,  
0x96, 0x3e, 0xef, 0x42, 0x87, 0xff, 0x17, 0x3b)
 
+#ifdef CONFIG_XEN_EFI
+/*
+ * Returns the end of the memory region containing the given config table,
+ * or 0 if the given address does not reside in memory that can validly
+ * contain EFI configuration tables.
+ */
+__init u64 xen_config_table_memory_region_max(u64 addr);
+#endif
+
 #endif /* _LINUX_EFI_H */
-- 
Sincerely,
Demi Marie Obenour (she/her/hers)
Invisible Things Lab




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.