Skip to content

Commit 12df216

Browse files
yu-chen-surfIngo Molnar
authored andcommitted
x86/boot/e820: Introduce the bootloader provided e820_table_firmware[] table
Add the real e820_tabel_firmware[] that will not be modified by the kernel or the EFI boot stub under any circumstance. In addition to that modify the code so that e820_table_firmwarep[] is exposed via sysfs to represent the real firmware memory layout, rather than exposing the e820_table_kexec[] table. This fixes a hibernation bug/warning, which uses e820_table_kexec[] to check RAM layout consistency across hibernation/resume: The suspend kernel: [ 0.000000] e820: update [mem 0x76671018-0x76679457] usable ==> usable The resume kernel: [ 0.000000] e820: update [mem 0x7666f018-0x76677457] usable ==> usable ... [ 15.752088] PM: Using 3 thread(s) for decompression. [ 15.752088] PM: Loading and decompressing image data (471870 pages)... [ 15.764971] Hibernate inconsistent memory map detected! [ 15.770833] PM: Image mismatch: architecture specific data Actually it is safe to restore these pages because E820_TYPE_RAM and E820_TYPE_RESERVED_KERN are treated the same during hibernation, so the original e820 table provided by the bootloader is used for hibernation MD5 fingerprint checking. The side effect is that, this newly introduced variable might increase the kernel size at compile time. Suggested-by: Ingo Molnar <[email protected]> Signed-off-by: Chen Yu <[email protected]> Cc: Dave Young <[email protected]> Cc: Len Brown <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Rafael J. Wysocki <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Xunlei Pang <[email protected]> Cc: [email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent a09bae0 commit 12df216

File tree

3 files changed

+29
-7
lines changed

3 files changed

+29
-7
lines changed

arch/x86/include/asm/e820/api.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
extern struct e820_table *e820_table;
77
extern struct e820_table *e820_table_kexec;
8+
extern struct e820_table *e820_table_firmware;
89

910
extern unsigned long pci_mem_start;
1011

arch/x86/kernel/e820.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,27 @@
2020
#include <asm/setup.h>
2121

2222
/*
23-
* We organize the E820 table into two main data structures:
23+
* We organize the E820 table into three main data structures:
2424
*
25-
* - 'e820_table_kexec': the original firmware version passed to us by the
26-
* bootloader - not modified by the kernel. We use this to:
25+
* - 'e820_table_firmware': the original firmware version passed to us by the
26+
* bootloader - not modified by the kernel. It is composed of two parts:
27+
* the first 128 E820 memory entries in boot_params.e820_table and the remaining
28+
* (if any) entries of the SETUP_E820_EXT nodes. We use this to:
2729
*
2830
* - inform the user about the firmware's notion of memory layout
2931
* via /sys/firmware/memmap
3032
*
3133
* - the hibernation code uses it to generate a kernel-independent MD5
3234
* fingerprint of the physical memory layout of a system.
3335
*
36+
* - 'e820_table_kexec': a slightly modified (by the kernel) firmware version
37+
* passed to us by the bootloader - the major difference between
38+
* e820_table_firmware[] and this one is that, the latter marks the setup_data
39+
* list created by the EFI boot stub as reserved, so that kexec can reuse the
40+
* setup_data information in the second kernel. Besides, e820_table_kexec[]
41+
* might also be modified by the kexec itself to fake a mptable.
42+
* We use this to:
43+
*
3444
* - kexec, which is a bootloader in disguise, uses the original E820
3545
* layout to pass to the kexec-ed kernel. This way the original kernel
3646
* can have a restricted E820 map while the kexec()-ed kexec-kernel
@@ -47,9 +57,11 @@
4757
*/
4858
static struct e820_table e820_table_init __initdata;
4959
static struct e820_table e820_table_kexec_init __initdata;
60+
static struct e820_table e820_table_firmware_init __initdata;
5061

5162
struct e820_table *e820_table __refdata = &e820_table_init;
5263
struct e820_table *e820_table_kexec __refdata = &e820_table_kexec_init;
64+
struct e820_table *e820_table_firmware __refdata = &e820_table_firmware_init;
5365

5466
/* For PCI or other memory-mapped resources */
5567
unsigned long pci_mem_start = 0xaeedbabe;
@@ -648,6 +660,12 @@ __init void e820__reallocate_tables(void)
648660
BUG_ON(!n);
649661
memcpy(n, e820_table_kexec, size);
650662
e820_table_kexec = n;
663+
664+
size = offsetof(struct e820_table, entries) + sizeof(struct e820_entry)*e820_table_firmware->nr_entries;
665+
n = kmalloc(size, GFP_KERNEL);
666+
BUG_ON(!n);
667+
memcpy(n, e820_table_firmware, size);
668+
e820_table_firmware = n;
651669
}
652670

653671
/*
@@ -670,6 +688,7 @@ void __init e820__memory_setup_extended(u64 phys_addr, u32 data_len)
670688
e820__update_table(e820_table);
671689

672690
memcpy(e820_table_kexec, e820_table, sizeof(*e820_table_kexec));
691+
memcpy(e820_table_firmware, e820_table, sizeof(*e820_table_firmware));
673692

674693
early_memunmap(sdata, data_len);
675694
pr_info("e820: extended physical RAM map:\n");
@@ -1064,8 +1083,9 @@ void __init e820__reserve_resources(void)
10641083
res++;
10651084
}
10661085

1067-
for (i = 0; i < e820_table_kexec->nr_entries; i++) {
1068-
struct e820_entry *entry = e820_table_kexec->entries + i;
1086+
/* Expose the bootloader-provided memory layout to the sysfs. */
1087+
for (i = 0; i < e820_table_firmware->nr_entries; i++) {
1088+
struct e820_entry *entry = e820_table_firmware->entries + i;
10691089

10701090
firmware_map_add_early(entry->addr, entry->addr + entry->size, e820_type_to_string(entry));
10711091
}
@@ -1178,6 +1198,7 @@ void __init e820__memory_setup(void)
11781198
who = x86_init.resources.memory_setup();
11791199

11801200
memcpy(e820_table_kexec, e820_table, sizeof(*e820_table_kexec));
1201+
memcpy(e820_table_firmware, e820_table, sizeof(*e820_table_firmware));
11811202

11821203
pr_info("e820: BIOS-provided physical RAM map:\n");
11831204
e820__print_table(who);

arch/x86/power/hibernate_64.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ static int get_e820_md5(struct e820_table *table, void *buf)
251251

252252
static void hibernation_e820_save(void *buf)
253253
{
254-
get_e820_md5(e820_table_kexec, buf);
254+
get_e820_md5(e820_table_firmware, buf);
255255
}
256256

257257
static bool hibernation_e820_mismatch(void *buf)
@@ -264,7 +264,7 @@ static bool hibernation_e820_mismatch(void *buf)
264264
if (!memcmp(result, buf, MD5_DIGEST_SIZE))
265265
return false;
266266

267-
ret = get_e820_md5(e820_table_kexec, result);
267+
ret = get_e820_md5(e820_table_firmware, result);
268268
if (ret)
269269
return true;
270270

0 commit comments

Comments
 (0)