From: Baoquan He <bhe@redhat.com>
To: bp@alien8.de, j-nomura@ce.jp.nec.com, kasong@redhat.com,
dyoung@redhat.com
Cc: fanc.fnst@cn.fujitsu.com, Baoquan He <bhe@redhat.com>,
x86@kernel.org, kexec@lists.infradead.org,
linux-kernel@vger.kernel.org, hpa@zytor.com, tglx@linutronix.de,
Borislav Petkov <bp@suse.de>
Subject: [PATCH v5 2/2] x86/boot: Use efi_setup_data for searching RSDP on kexec-ed kernels
Date: Wed, 24 Apr 2019 17:29:44 +0800 [thread overview]
Message-ID: <20190424092944.30481-3-bhe@redhat.com> (raw)
In-Reply-To: <20190424092944.30481-1-bhe@redhat.com>
From: Junichi Nomura <j-nomura@ce.jp.nec.com>
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 the EFI tables but that will
crash because the table address is virtual when the kernel was booted by
kexec (set_virtual_address_map() has run in the first kernel and cannot
be run again in the second kernel).
In the case of kexec, the physical address of EFI tables is provided via
efi_setup_data in boot_params, which is set up by kexec(1).
Factor out the table parsing code and use different pointers depending
on whether the kernel is booted by kexec or not.
[ bp: Massage. ]
Fixes: 3a63f70bf4c3a ("x86/boot: Early parse RSDP and save it in boot_params")
Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: Chao Fan <fanc.fnst@cn.fujitsu.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Dave Young <dyoung@redhat.com>
Link: https://lkml.kernel.org/r/20190408231011.GA5402@jeru.linux.bs1.fc.nec.co.jp
Signed-off-by: Baoquan He <bhe@redhat.com>
---
arch/x86/boot/compressed/acpi.c | 143 ++++++++++++++++++++++++--------
1 file changed, 107 insertions(+), 36 deletions(-)
diff --git a/arch/x86/boot/compressed/acpi.c b/arch/x86/boot/compressed/acpi.c
index 0ef4ad55b29b..8cecce1ac0cd 100644
--- a/arch/x86/boot/compressed/acpi.c
+++ b/arch/x86/boot/compressed/acpi.c
@@ -44,17 +44,109 @@ static acpi_physical_address get_acpi_rsdp(void)
return addr;
}
-/* Search EFI system tables for RSDP. */
-static acpi_physical_address efi_get_rsdp_addr(void)
+/*
+ * Search EFI system tables for RSDP. If both ACPI_20_TABLE_GUID and
+ * ACPI_TABLE_GUID are found, take the former, which has more features.
+ */
+static acpi_physical_address
+__efi_get_rsdp_addr(unsigned long config_tables, unsigned int nr_tables,
+ bool efi_64)
{
acpi_physical_address rsdp_addr = 0;
#ifdef CONFIG_EFI
- unsigned long systab, systab_tables, config_tables;
+ int i;
+
+ /* Get EFI tables from systab. */
+ for (i = 0; i < nr_tables; i++) {
+ acpi_physical_address table;
+ efi_guid_t guid;
+
+ if (efi_64) {
+ efi_config_table_64_t *tbl = (efi_config_table_64_t *) config_tables + i;
+
+ guid = tbl->guid;
+ table = tbl->table;
+
+ if (!IS_ENABLED(CONFIG_X86_64) && table >> 32) {
+ debug_putstr("Error getting RSDP address: EFI config table located above 4GB.\n");
+ return 0;
+ }
+ } else {
+ efi_config_table_32_t *tbl = (efi_config_table_32_t *) config_tables + i;
+
+ guid = tbl->guid;
+ table = tbl->table;
+ }
+
+ if (!(efi_guidcmp(guid, ACPI_TABLE_GUID)))
+ rsdp_addr = table;
+ else if (!(efi_guidcmp(guid, ACPI_20_TABLE_GUID)))
+ return table;
+ }
+#endif
+ return rsdp_addr;
+}
+
+/* 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;
+ char *sig;
+
+ 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;
+ }
+
+ ei = &boot_params->efi_info;
+ sig = (char *)&ei->efi_loader_signature;
+ if (strncmp(sig, EFI64_LOADER_SIGNATURE, 4)) {
+ debug_putstr("Wrong kexec EFI loader signature.\n");
+ return 0;
+ }
+
+ /* Get systab from boot params. */
+ systab = (efi_system_table_64_t *) (ei->efi_systab | ((__u64)ei->efi_systab_hi << 32));
+ if (!systab)
+ error("EFI system table not found in kexec boot_params.");
+
+ return __efi_get_rsdp_addr((unsigned long)esd->tables, systab->nr_tables, true);
+}
+#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
+ unsigned long systab, config_tables;
unsigned int nr_tables;
struct efi_info *ei;
bool efi_64;
- int size, i;
char *sig;
ei = &boot_params->efi_info;
@@ -88,49 +180,20 @@ static acpi_physical_address efi_get_rsdp_addr(void)
config_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;
nr_tables = stbl->nr_tables;
- size = sizeof(efi_config_table_32_t);
}
if (!config_tables)
error("EFI config tables not found.");
- /* Get EFI tables from systab. */
- for (i = 0; i < nr_tables; i++) {
- acpi_physical_address table;
- efi_guid_t guid;
-
- config_tables += size;
-
- if (efi_64) {
- efi_config_table_64_t *tbl = (efi_config_table_64_t *)config_tables;
-
- guid = tbl->guid;
- table = tbl->table;
-
- if (!IS_ENABLED(CONFIG_X86_64) && table >> 32) {
- debug_putstr("Error getting RSDP address: EFI config table located above 4GB.\n");
- return 0;
- }
- } else {
- efi_config_table_32_t *tbl = (efi_config_table_32_t *)config_tables;
-
- guid = tbl->guid;
- table = tbl->table;
- }
-
- if (!(efi_guidcmp(guid, ACPI_TABLE_GUID)))
- rsdp_addr = table;
- else if (!(efi_guidcmp(guid, ACPI_20_TABLE_GUID)))
- return table;
- }
+ return __efi_get_rsdp_addr(config_tables, nr_tables, efi_64);
+#else
+ return 0;
#endif
- return rsdp_addr;
}
static u8 compute_checksum(u8 *buffer, u32 length)
@@ -220,6 +283,14 @@ acpi_physical_address get_rsdp_addr(void)
if (!pa)
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();
--
2.17.2
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
WARNING: multiple messages have this Message-ID (diff)
From: Baoquan He <bhe@redhat.com>
To: bp@alien8.de, j-nomura@ce.jp.nec.com, kasong@redhat.com,
dyoung@redhat.com
Cc: linux-kernel@vger.kernel.org, tglx@linutronix.de,
fanc.fnst@cn.fujitsu.com, x86@kernel.org,
kexec@lists.infradead.org, hpa@zytor.com,
Borislav Petkov <bp@suse.de>, Baoquan He <bhe@redhat.com>
Subject: [PATCH v5 2/2] x86/boot: Use efi_setup_data for searching RSDP on kexec-ed kernels
Date: Wed, 24 Apr 2019 17:29:44 +0800 [thread overview]
Message-ID: <20190424092944.30481-3-bhe@redhat.com> (raw)
In-Reply-To: <20190424092944.30481-1-bhe@redhat.com>
From: Junichi Nomura <j-nomura@ce.jp.nec.com>
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 the EFI tables but that will
crash because the table address is virtual when the kernel was booted by
kexec (set_virtual_address_map() has run in the first kernel and cannot
be run again in the second kernel).
In the case of kexec, the physical address of EFI tables is provided via
efi_setup_data in boot_params, which is set up by kexec(1).
Factor out the table parsing code and use different pointers depending
on whether the kernel is booted by kexec or not.
[ bp: Massage. ]
Fixes: 3a63f70bf4c3a ("x86/boot: Early parse RSDP and save it in boot_params")
Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: Chao Fan <fanc.fnst@cn.fujitsu.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Dave Young <dyoung@redhat.com>
Link: https://lkml.kernel.org/r/20190408231011.GA5402@jeru.linux.bs1.fc.nec.co.jp
Signed-off-by: Baoquan He <bhe@redhat.com>
---
arch/x86/boot/compressed/acpi.c | 143 ++++++++++++++++++++++++--------
1 file changed, 107 insertions(+), 36 deletions(-)
diff --git a/arch/x86/boot/compressed/acpi.c b/arch/x86/boot/compressed/acpi.c
index 0ef4ad55b29b..8cecce1ac0cd 100644
--- a/arch/x86/boot/compressed/acpi.c
+++ b/arch/x86/boot/compressed/acpi.c
@@ -44,17 +44,109 @@ static acpi_physical_address get_acpi_rsdp(void)
return addr;
}
-/* Search EFI system tables for RSDP. */
-static acpi_physical_address efi_get_rsdp_addr(void)
+/*
+ * Search EFI system tables for RSDP. If both ACPI_20_TABLE_GUID and
+ * ACPI_TABLE_GUID are found, take the former, which has more features.
+ */
+static acpi_physical_address
+__efi_get_rsdp_addr(unsigned long config_tables, unsigned int nr_tables,
+ bool efi_64)
{
acpi_physical_address rsdp_addr = 0;
#ifdef CONFIG_EFI
- unsigned long systab, systab_tables, config_tables;
+ int i;
+
+ /* Get EFI tables from systab. */
+ for (i = 0; i < nr_tables; i++) {
+ acpi_physical_address table;
+ efi_guid_t guid;
+
+ if (efi_64) {
+ efi_config_table_64_t *tbl = (efi_config_table_64_t *) config_tables + i;
+
+ guid = tbl->guid;
+ table = tbl->table;
+
+ if (!IS_ENABLED(CONFIG_X86_64) && table >> 32) {
+ debug_putstr("Error getting RSDP address: EFI config table located above 4GB.\n");
+ return 0;
+ }
+ } else {
+ efi_config_table_32_t *tbl = (efi_config_table_32_t *) config_tables + i;
+
+ guid = tbl->guid;
+ table = tbl->table;
+ }
+
+ if (!(efi_guidcmp(guid, ACPI_TABLE_GUID)))
+ rsdp_addr = table;
+ else if (!(efi_guidcmp(guid, ACPI_20_TABLE_GUID)))
+ return table;
+ }
+#endif
+ return rsdp_addr;
+}
+
+/* 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;
+ char *sig;
+
+ 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;
+ }
+
+ ei = &boot_params->efi_info;
+ sig = (char *)&ei->efi_loader_signature;
+ if (strncmp(sig, EFI64_LOADER_SIGNATURE, 4)) {
+ debug_putstr("Wrong kexec EFI loader signature.\n");
+ return 0;
+ }
+
+ /* Get systab from boot params. */
+ systab = (efi_system_table_64_t *) (ei->efi_systab | ((__u64)ei->efi_systab_hi << 32));
+ if (!systab)
+ error("EFI system table not found in kexec boot_params.");
+
+ return __efi_get_rsdp_addr((unsigned long)esd->tables, systab->nr_tables, true);
+}
+#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
+ unsigned long systab, config_tables;
unsigned int nr_tables;
struct efi_info *ei;
bool efi_64;
- int size, i;
char *sig;
ei = &boot_params->efi_info;
@@ -88,49 +180,20 @@ static acpi_physical_address efi_get_rsdp_addr(void)
config_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;
nr_tables = stbl->nr_tables;
- size = sizeof(efi_config_table_32_t);
}
if (!config_tables)
error("EFI config tables not found.");
- /* Get EFI tables from systab. */
- for (i = 0; i < nr_tables; i++) {
- acpi_physical_address table;
- efi_guid_t guid;
-
- config_tables += size;
-
- if (efi_64) {
- efi_config_table_64_t *tbl = (efi_config_table_64_t *)config_tables;
-
- guid = tbl->guid;
- table = tbl->table;
-
- if (!IS_ENABLED(CONFIG_X86_64) && table >> 32) {
- debug_putstr("Error getting RSDP address: EFI config table located above 4GB.\n");
- return 0;
- }
- } else {
- efi_config_table_32_t *tbl = (efi_config_table_32_t *)config_tables;
-
- guid = tbl->guid;
- table = tbl->table;
- }
-
- if (!(efi_guidcmp(guid, ACPI_TABLE_GUID)))
- rsdp_addr = table;
- else if (!(efi_guidcmp(guid, ACPI_20_TABLE_GUID)))
- return table;
- }
+ return __efi_get_rsdp_addr(config_tables, nr_tables, efi_64);
+#else
+ return 0;
#endif
- return rsdp_addr;
}
static u8 compute_checksum(u8 *buffer, u32 length)
@@ -220,6 +283,14 @@ acpi_physical_address get_rsdp_addr(void)
if (!pa)
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();
--
2.17.2
next prev parent reply other threads:[~2019-04-24 9:30 UTC|newest]
Thread overview: 83+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-24 9:29 [PATCH v5 0/2] x86/boot: Use efi_setup_data for searching RSDP on kexec-ed kernel Baoquan He
2019-04-24 9:29 ` Baoquan He
2019-04-24 9:29 ` [PATCH v5 1/2] x86/kexec: Build identity mapping for EFI systab and ACPI tables Baoquan He
2019-04-24 9:29 ` Baoquan He
2019-04-27 16:11 ` Borislav Petkov
2019-04-27 16:11 ` Borislav Petkov
2019-04-28 5:41 ` Baoquan He
2019-04-28 5:41 ` Baoquan He
2019-04-29 12:50 ` Borislav Petkov
2019-04-29 12:50 ` Borislav Petkov
2019-04-29 0:23 ` [PATCH v6 " Baoquan He
2019-04-29 0:23 ` Baoquan He
2019-04-29 13:55 ` Borislav Petkov
2019-04-29 13:55 ` Borislav Petkov
2019-04-29 14:16 ` Baoquan He
2019-04-29 14:16 ` Baoquan He
2019-05-13 1:43 ` Baoquan He
2019-05-13 1:43 ` Baoquan He
2019-05-13 7:07 ` Borislav Petkov
2019-05-13 7:07 ` Borislav Petkov
2019-05-13 7:32 ` Baoquan He
2019-05-13 7:32 ` Baoquan He
2019-05-13 7:50 ` Borislav Petkov
2019-05-13 7:50 ` Borislav Petkov
2019-05-13 8:02 ` Baoquan He
2019-05-13 8:02 ` Baoquan He
2019-05-15 5:17 ` Junichi Nomura
2019-05-15 5:17 ` Junichi Nomura
2019-05-15 6:58 ` Borislav Petkov
2019-05-15 6:58 ` Borislav Petkov
2019-05-15 7:09 ` Junichi Nomura
2019-05-15 7:09 ` Junichi Nomura
2019-05-21 9:02 ` Kairui Song
2019-05-21 9:02 ` Kairui Song
2019-05-21 10:43 ` Junichi Nomura
2019-05-21 10:43 ` Junichi Nomura
2019-05-21 18:09 ` Borislav Petkov
2019-05-21 18:09 ` Borislav Petkov
2019-05-28 2:49 ` Kairui Song
2019-05-28 2:49 ` Kairui Song
2019-06-06 19:20 ` Borislav Petkov
2019-06-06 19:20 ` Borislav Petkov
2019-05-13 8:06 ` Baoquan He
2019-05-13 8:06 ` Baoquan He
2019-05-14 3:22 ` Dave Young
2019-05-14 3:22 ` Dave Young
2019-05-14 3:33 ` Baoquan He
2019-05-14 3:33 ` Baoquan He
2019-05-21 21:53 ` Dirk van der Merwe
2019-05-21 21:53 ` Dirk van der Merwe
2019-05-21 23:04 ` Borislav Petkov
2019-05-21 23:04 ` Borislav Petkov
2019-05-14 8:48 ` Dave Young
2019-05-14 8:48 ` Dave Young
2019-05-14 11:18 ` Kairui Song
2019-05-14 11:18 ` Kairui Song
2019-05-14 11:38 ` Peter Zijlstra
2019-05-14 11:38 ` Peter Zijlstra
2019-05-14 12:58 ` Dave Young
2019-05-14 12:58 ` Dave Young
2019-05-14 13:54 ` Peter Zijlstra
2019-05-14 13:54 ` Peter Zijlstra
2019-05-14 14:09 ` Ingo Molnar
2019-05-14 14:09 ` Ingo Molnar
2019-05-15 1:08 ` Dave Young
2019-05-15 1:08 ` Dave Young
2019-05-15 6:43 ` Junichi Nomura
2019-05-15 6:43 ` Junichi Nomura
2019-05-17 13:41 ` Borislav Petkov
2019-05-17 13:41 ` Borislav Petkov
2019-05-17 13:50 ` [PATCH] x86/boot: Call get_rsdp_addr() after console_init() Borislav Petkov
2019-05-17 13:50 ` Borislav Petkov
2019-05-21 9:28 ` Baoquan He
2019-05-21 9:28 ` Baoquan He
2019-06-06 19:22 ` [tip:x86/boot] x86/kexec: Add the EFI system tables and ACPI tables to the ident map tip-bot for Kairui Song
2019-04-24 9:29 ` Baoquan He [this message]
2019-04-24 9:29 ` [PATCH v5 2/2] x86/boot: Use efi_setup_data for searching RSDP on kexec-ed kernels Baoquan He
2019-04-24 9:33 ` Baoquan He
2019-04-24 9:33 ` Baoquan He
2019-04-24 9:38 ` [PATCH v5 0/2] x86/boot: Use efi_setup_data for searching RSDP on kexec-ed kernel Borislav Petkov
2019-04-24 9:38 ` Borislav Petkov
2019-04-24 10:00 ` Baoquan He
2019-04-24 10:00 ` Baoquan He
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190424092944.30481-3-bhe@redhat.com \
--to=bhe@redhat.com \
--cc=bp@alien8.de \
--cc=bp@suse.de \
--cc=dyoung@redhat.com \
--cc=fanc.fnst@cn.fujitsu.com \
--cc=hpa@zytor.com \
--cc=j-nomura@ce.jp.nec.com \
--cc=kasong@redhat.com \
--cc=kexec@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.