]> git.baikalelectronics.ru Git - kernel.git/commitdiff
x86/compressed/acpi: Move EFI kexec handling into common code
authorMichael Roth <michael.roth@amd.com>
Thu, 24 Feb 2022 16:56:08 +0000 (10:56 -0600)
committerBorislav Petkov <bp@suse.de>
Wed, 6 Apr 2022 15:07:24 +0000 (17:07 +0200)
Future patches for SEV-SNP-validated CPUID will also require early
parsing of the EFI configuration. Incrementally move the related code
into a set of helpers that can be re-used for that purpose.

In this instance, the current acpi.c kexec handling is mainly used to
get the alternative EFI config table address provided by kexec via a
setup_data entry of type SETUP_EFI. If not present, the code then falls
back to normal EFI config table address provided by EFI system table.
This would need to be done by all call-sites attempting to access the
EFI config table, so just have efi_get_conf_table() handle that
automatically.

Signed-off-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://lore.kernel.org/r/20220307213356.2797205-29-brijesh.singh@amd.com
arch/x86/boot/compressed/acpi.c
arch/x86/boot/compressed/efi.c

index b0c1dffc551087aa6ac6f5f34af53dff13025451..64b172dabd5caf34d7e7c7661a391959a3faef79 100644 (file)
@@ -47,57 +47,6 @@ __efi_get_rsdp_addr(unsigned long cfg_tbl_pa, unsigned int cfg_tbl_len)
        return 0;
 }
 
-/* EFI/kexec support is 64-bit only. */
-#ifdef CONFIG_X86_64
-static struct efi_setup_data *get_kexec_setup_data_addr(void)
-{
-       struct setup_data *data;
-       u64 pa_data;
-
-       pa_data = boot_params->hdr.setup_data;
-       while (pa_data) {
-               data = (struct setup_data *)pa_data;
-               if (data->type == SETUP_EFI)
-                       return (struct efi_setup_data *)(pa_data + sizeof(struct setup_data));
-
-               pa_data = data->next;
-       }
-       return NULL;
-}
-
-static acpi_physical_address kexec_get_rsdp_addr(void)
-{
-       efi_system_table_64_t *systab;
-       struct efi_setup_data *esd;
-       struct efi_info *ei;
-       enum efi_type et;
-
-       esd = (struct efi_setup_data *)get_kexec_setup_data_addr();
-       if (!esd)
-               return 0;
-
-       if (!esd->tables) {
-               debug_putstr("Wrong kexec SETUP_EFI data.\n");
-               return 0;
-       }
-
-       et = efi_get_type(boot_params);
-       if (et != EFI_TYPE_64) {
-               debug_putstr("Unexpected kexec EFI environment (expected 64-bit EFI).\n");
-               return 0;
-       }
-
-       /* Get systab from boot params. */
-       systab = (efi_system_table_64_t *)efi_get_system_table(boot_params);
-       if (!systab)
-               error("EFI system table not found in kexec boot_params.");
-
-       return __efi_get_rsdp_addr((unsigned long)esd->tables, systab->nr_tables);
-}
-#else
-static acpi_physical_address kexec_get_rsdp_addr(void) { return 0; }
-#endif /* CONFIG_X86_64 */
-
 static acpi_physical_address efi_get_rsdp_addr(void)
 {
 #ifdef CONFIG_EFI
@@ -210,14 +159,6 @@ acpi_physical_address get_rsdp_addr(void)
 
        pa = boot_params->acpi_rsdp_addr;
 
-       /*
-        * Try to get EFI data from setup_data. This can happen when we're a
-        * kexec'ed kernel and kexec(1) has passed all the required EFI info to
-        * us.
-        */
-       if (!pa)
-               pa = kexec_get_rsdp_addr();
-
        if (!pa)
                pa = efi_get_rsdp_addr();
 
index 4d363dfc2b33490917acb215e6de693ed06d7975..09fa3b5d70b8ff27e1c3b00a21789a449dd39b83 100644 (file)
@@ -78,6 +78,46 @@ unsigned long efi_get_system_table(struct boot_params *bp)
        return sys_tbl_pa;
 }
 
+/*
+ * EFI config table address changes to virtual address after boot, which may
+ * not be accessible for the kexec'd kernel. To address this, kexec provides
+ * the initial physical address via a struct setup_data entry, which is
+ * checked for here, along with some sanity checks.
+ */
+static struct efi_setup_data *get_kexec_setup_data(struct boot_params *bp,
+                                                  enum efi_type et)
+{
+#ifdef CONFIG_X86_64
+       struct efi_setup_data *esd = NULL;
+       struct setup_data *data;
+       u64 pa_data;
+
+       pa_data = bp->hdr.setup_data;
+       while (pa_data) {
+               data = (struct setup_data *)pa_data;
+               if (data->type == SETUP_EFI) {
+                       esd = (struct efi_setup_data *)(pa_data + sizeof(struct setup_data));
+                       break;
+               }
+
+               pa_data = data->next;
+       }
+
+       /*
+        * Original ACPI code falls back to attempting normal EFI boot in these
+        * cases, so maintain existing behavior by indicating non-kexec
+        * environment to the caller, but print them for debugging.
+        */
+       if (esd && !esd->tables) {
+               debug_putstr("kexec EFI environment missing valid configuration table.\n");
+               return NULL;
+       }
+
+       return esd;
+#endif
+       return NULL;
+}
+
 /**
  * efi_get_conf_table - Given a pointer to boot_params, locate and return the physical
  *                      address of EFI configuration table.
@@ -106,8 +146,12 @@ int efi_get_conf_table(struct boot_params *bp, unsigned long *cfg_tbl_pa,
        et = efi_get_type(bp);
        if (et == EFI_TYPE_64) {
                efi_system_table_64_t *stbl = (efi_system_table_64_t *)sys_tbl_pa;
+               struct efi_setup_data *esd;
 
-               *cfg_tbl_pa = stbl->tables;
+               /* kexec provides an alternative EFI conf table, check for it. */
+               esd = get_kexec_setup_data(bp, et);
+
+               *cfg_tbl_pa = esd ? esd->tables : stbl->tables;
                *cfg_tbl_len = stbl->nr_tables;
        } else if (et == EFI_TYPE_32) {
                efi_system_table_32_t *stbl = (efi_system_table_32_t *)sys_tbl_pa;