[PATCH v2] x86/boot: Use EFI setup data if provided

From: Junichi Nomura
Date: Mon Mar 25 2019 - 04:28:59 EST


On 3/25/19 3:59 PM, Dave Young wrote:
> On 03/25/19 at 06:47am, Junichi Nomura wrote:
>> On 3/25/19 3:19 PM, Dave Young wrote:
>>> On 03/25/19 at 02:01pm, Dave Young wrote:
>>> I think normally people do not see this bug, because kernel will set the
>>> rsdp in boot_params->acpi_rsdp_addr. Maybe you are testing with
>>
>> I think it's only done for file-based kexec interface.
>
> Saw Kairui's another reply, yes, kexec-tools need a patch to fill the
> value as well then.
>
> I would vote for a repost of your old patch with some #ifdef

Thanks for comments, Dave, Kairui and Baoquan.

The problem for me is it's a regression in v5.1-rc1, that breaks
existing setup. If early parsing of RSDP is required only for newly
supported configuration, I'm fine such configuration requires
new tools or new options.

This is the 1st version plus #ifdef around the EFI code.
Build tested both with and without CONFIG_EFI to see no warnings.

[PATCH v2] x86/boot: Use EFI setup data if provided

Commit 3a63f70bf4c3a ("x86/boot: Early parse RSDP and save it in
boot_params") broke kexec boot on EFI systems. efi_get_rsdp_addr()
in the early parsing code tries to search RSDP from EFI table but
whose address is virtual.

Since kexec(1) provides physical address of config_table via boot_params,
efi_get_rsdp_addr() should look for setup_data in the same way as
efi_systab_init() in arch/x86/platform/efi/efi.c does.

Fixes: 3a63f70bf4c3a ("x86/boot: Early parse RSDP and save it in boot_params")
Signed-off-by: Jun'ichi Nomura <j-nomura@xxxxxxxxxxxxx>
Acked-by: Dave Young <dyoung@xxxxxxxxxx>
Cc: Chao Fan <fanc.fnst@xxxxxxxxxxxxxx>
Cc: Borislav Petkov <bp@xxxxxxx>

diff --git a/arch/x86/boot/compressed/acpi.c b/arch/x86/boot/compressed/acpi.c
--- a/arch/x86/boot/compressed/acpi.c
+++ b/arch/x86/boot/compressed/acpi.c
@@ -44,6 +44,24 @@ static acpi_physical_address get_acpi_rsdp(void)
return addr;
}

+#ifdef CONFIG_EFI
+static unsigned long efi_get_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 pa_data + sizeof(struct setup_data);
+ pa_data = data->next;
+ }
+
+ return 0;
+}
+#endif
+
/* Search EFI system tables for RSDP. */
static acpi_physical_address efi_get_rsdp_addr(void)
{
@@ -53,10 +71,12 @@ static acpi_physical_address efi_get_rsdp_addr(void)
unsigned long systab, systab_tables, config_tables;
unsigned int nr_tables;
struct efi_info *ei;
+ struct efi_setup_data *esd;
bool efi_64;
int size, i;
char *sig;

+ esd = (struct efi_setup_data *) efi_get_setup_data_addr();
ei = &boot_params->efi_info;
sig = (char *)&ei->efi_loader_signature;

@@ -86,13 +106,13 @@ static acpi_physical_address efi_get_rsdp_addr(void)
if (efi_64) {
efi_system_table_64_t *stbl = (efi_system_table_64_t *)systab;

- config_tables = stbl->tables;
+ config_tables = esd ? esd->tables : stbl->tables;
nr_tables = stbl->nr_tables;
size = sizeof(efi_config_table_64_t);
} else {
efi_system_table_32_t *stbl = (efi_system_table_32_t *)systab;

- config_tables = stbl->tables;
+ config_tables = esd ? esd->tables : stbl->tables;
nr_tables = stbl->nr_tables;
size = sizeof(efi_config_table_32_t);
}