diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index d0335853ff52fa8b581e3c842ec43685f1a7e7c5..fc1d579f212bb1b797588454f1aad911f3c75604 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -27,7 +28,22 @@ #include #include +/* + * The e820 map is the map that gets modified e.g. with command line parameters + * and that is also registered with modifications in the kernel resource tree + * with the iomem_resource as parent. + * + * The e820_saved is directly saved after the BIOS-provided memory map is + * copied. It doesn't get modified afterwards. It's registered for the + * /sys/firmware/memmap interface. + * + * That memory map is not modified and is used as base for kexec. The kexec'd + * kernel should get the same memory map as the firmware provides. Then the + * user can e.g. boot the original kernel with mem=1G while still booting the + * next kernel with full memory. + */ struct e820map e820; +struct e820map e820_saved; /* For PCI or other memory-mapped resources */ unsigned long pci_mem_start = 0xaeedbabe; @@ -1198,6 +1214,17 @@ void __init finish_e820_parsing(void) } } +static inline const char *e820_type_to_string(int e820_type) +{ + switch (e820_type) { + case E820_RESERVED_KERN: + case E820_RAM: return "System RAM"; + case E820_ACPI: return "ACPI Tables"; + case E820_NVS: return "ACPI Non-volatile Storage"; + default: return "reserved"; + } +} + /* * Mark e820 reserved areas as busy for the resource manager. */ @@ -1209,13 +1236,6 @@ void __init e820_reserve_resources(void) res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map); for (i = 0; i < e820.nr_map; i++) { - switch (e820.map[i].type) { - case E820_RESERVED_KERN: - case E820_RAM: res->name = "System RAM"; break; - case E820_ACPI: res->name = "ACPI Tables"; break; - case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; - default: res->name = "reserved"; - } end = e820.map[i].addr + e820.map[i].size - 1; #ifndef CONFIG_RESOURCES_64BIT if (end > 0x100000000ULL) { @@ -1223,6 +1243,7 @@ void __init e820_reserve_resources(void) continue; } #endif + res->name = e820_type_to_string(e820.map[i].type); res->start = e820.map[i].addr; res->end = end; @@ -1230,6 +1251,13 @@ void __init e820_reserve_resources(void) insert_resource(&iomem_resource, res); res++; } + + for (i = 0; i < e820_saved.nr_map; i++) { + struct e820entry *entry = &e820_saved.map[i]; + firmware_map_add_early(entry->addr, + entry->addr + entry->size - 1, + e820_type_to_string(entry->type)); + } } char *__init default_machine_specific_memory_setup(void) @@ -1266,6 +1294,8 @@ char *__init default_machine_specific_memory_setup(void) e820_add_region(HIGH_MEMORY, mem_size << 10, E820_RAM); } + memcpy(&e820_saved, &e820, sizeof(struct e820map)); + /* In case someone cares... */ return who; } diff --git a/include/asm-x86/e820.h b/include/asm-x86/e820.h index 4b26604b3c1951ddb70ae064714321fd6f1e86a7..a20d0a7f589221330a3fa24a356a1e58b26b76f5 100644 --- a/include/asm-x86/e820.h +++ b/include/asm-x86/e820.h @@ -59,7 +59,9 @@ struct e820map { struct e820entry map[E820_X_MAX]; }; +/* see comment in arch/x86/kernel/e820.c */ extern struct e820map e820; +extern struct e820map e820_saved; extern int e820_any_mapped(u64 start, u64 end, unsigned type); extern int e820_all_mapped(u64 start, u64 end, unsigned type);