diff options
author | Kairui Song <kasong@redhat.com> | 2019-05-24 14:23:19 +0800 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2019-05-31 11:26:04 +0200 |
commit | cedeee0a30075030632a18e419419371ddf3fca3 (patch) | |
tree | 7a3e4dcf3deb8aa1cc718d908912d945a39d211f /kexec/arch/i386/kexec-x86-common.c | |
parent | 402351390f31b2db0768eef4ced375d00bff9e17 (diff) |
x86: Introduce helpers for getting RSDP address
On x86 RSDP is fundamental for booting the machine. When second kernel
is incapable of parsing the RSDP address (eg. kexec next kernel on an EFI
system with EFI service disabled), kexec should prepare the RSDP address
for second kernel.
Introduce helpers for getting RSDP from multiple sources, including boot
params and EFI firmware.
For legacy BIOS interface, there is no better way to find the RSDP address
rather than scanning the memory region and search for it, and this will
always be done by the kernel as a fallback, so this is no need to try to
get the RSDP address for that case.
Signed-off-by: Kairui Song <kasong@redhat.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'kexec/arch/i386/kexec-x86-common.c')
-rw-r--r-- | kexec/arch/i386/kexec-x86-common.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/kexec/arch/i386/kexec-x86-common.c b/kexec/arch/i386/kexec-x86-common.c index de99758..5c55ec8 100644 --- a/kexec/arch/i386/kexec-x86-common.c +++ b/kexec/arch/i386/kexec-x86-common.c @@ -39,6 +39,7 @@ #include "../../firmware_memmap.h" #include "../../crashdump.h" #include "kexec-x86.h" +#include "x86-linux-setup.h" #include "../../kexec-xen.h" /* Used below but not present in (older?) xenctrl.h */ @@ -392,4 +393,46 @@ int get_memory_ranges(struct memory_range **range, int *ranges, return ret; } +static uint64_t bootparam_get_acpi_rsdp(void) { + uint64_t acpi_rsdp = 0; + off_t offset = offsetof(struct x86_linux_param_header, acpi_rsdp_addr); + if (get_bootparam(&acpi_rsdp, offset, sizeof(acpi_rsdp))) + return 0; + + return acpi_rsdp; +} + +static uint64_t efi_get_acpi_rsdp(void) { + FILE *fp; + char line[MAX_LINE], *s; + uint64_t acpi_rsdp = 0; + + fp = fopen("/sys/firmware/efi/systab", "r"); + if (!fp) + return acpi_rsdp; + + while(fgets(line, sizeof(line), fp) != 0) { + /* ACPI20= always goes before ACPI= */ + if ((strstr(line, "ACPI20=")) || (strstr(line, "ACPI="))) { + s = strchr(line, '=') + 1; + sscanf(s, "0x%lx", &acpi_rsdp); + break; + } + } + fclose(fp); + + return acpi_rsdp; +} + +uint64_t get_acpi_rsdp(void) +{ + uint64_t acpi_rsdp = 0; + + acpi_rsdp = bootparam_get_acpi_rsdp(); + + if (!acpi_rsdp) + acpi_rsdp = efi_get_acpi_rsdp(); + + return acpi_rsdp; +} |