kdump voided the whole original e820 map and half way made it up via memmap= options passed via kdump boot params again. But this is conceptionally wrong. The whole original memory ranges which are declared reserved, ACPI data/nvs or however are not usable must stay the same and get honored by the kdump kernel. Therefore memmap=kdump_reserve_usable gets introduced. kdump passes this one and originally usable memory gets converted by the kernel to the Linux kernel specific kdump reserved e820 type. kdump passes the usable memory ranges where the kdump kernel resides in via memmap=x at y parameter(s). This preserves all e820 information and the kdump kernel can look it up and be sure it is valid. It also cleans up unnecessary memmap= boot parameter passing of reserved memory areas via kexec-tools. This information is already passed via boot structures. This also fixes mmconf (extended PCI config access) and possibly other kernel parts which rely on remapped memory to be in reserved or ACPI (data/nvs) declared e820 memory areas. Signed-off-by: Thomas Renninger <trenn at suse.de> --- Documentation/kernel-parameters.txt | 9 +++++++++ arch/x86/kernel/e820.c | 22 ++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index da0e077..f38375a 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1518,6 +1518,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. BIOS output or other requirements. See the memmap=nn at ss option description. + memmap=kdump_reserve_usable + [KNL,X86] Convert usable memory areas into a special + Linux kernel specific kdump reserved type. + Usable memory areas the kdump kernel resides in have + to be passed via memmap=X at Y parameters which overrides + these areas again to be usable. + This boot parameter is intended for kdump usage. + Passing exactmap overrules kdump_reserve_usable. + memmap=nn[KMG]@ss[KMG] [KNL] Force usage of a specific region of memory Region of memory to be used, from ss to ss+nn. diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 7c6a72e..9c00bfa 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -839,6 +839,7 @@ static int __init parse_memopt(char *p) early_param("mem", parse_memopt); static bool __initdata exactmap_parsed; +static bool __initdata kdump_res_parsed; static int __init parse_memmap_one(char *p) { @@ -848,7 +849,8 @@ static int __init parse_memmap_one(char *p) if (!p) return -EINVAL; - if (!strncmp(p, "exactmap", 8)) { + if (!strncmp(p, "exactmap", 8) || + !strncmp(p, "kdump_reserve_usable", 20)) { if (exactmap_parsed) return 0; @@ -861,7 +863,13 @@ static int __init parse_memmap_one(char *p) */ saved_max_pfn = e820_end_of_ram_pfn(); #endif - e820.nr_map = 0; + if (!strncmp(p, "kdump_reserve_usable", 20)) { + /* remove all old E820_RAM ranges */ + e820_update_range(0, ULLONG_MAX, E820_RAM, + E820_RESERVED_KDUMP); + kdump_res_parsed = true; + } else + e820.nr_map = 0; userdef = 1; return 0; } @@ -874,6 +882,11 @@ static int __init parse_memmap_one(char *p) userdef = 1; if (*p == '@') { start_at = memparse(p+1, &p); + if (kdump_res_parsed) { + /* Remove old reserved so new ram could take over. */ + e820_remove_range(start_at, mem_size, + E820_RESERVED_KDUMP, 0); + } e820_add_region(start_at, mem_size, E820_RAM); } else if (*p == '#') { start_at = memparse(p+1, &p); @@ -893,6 +906,11 @@ static int __init parse_memmap_opt(char *str) p = strstr(p, "exactmap"); if (p) parse_memmap_one("exactmap"); + else { + p = strstr(boot_command_line, "kdump_reserve_usable"); + if (p) + parse_memmap_one("kdump_reserve_usable"); + } while (str) { char *k = strchr(str, ',');