aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChen Yu <yu.c.chen@intel.com>2017-07-02 13:07:32 -0400
committerIngo Molnar <mingo@kernel.org>2017-07-05 04:09:02 -0400
commit12df216c61c89e31e27e74146115a9728880ca6f (patch)
tree7d6796254039017f002e28577fc83dd1f5eab09e
parenta09bae0f8aa08d4d76d0ebece26062a49ec51ac9 (diff)
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 <mingo@redhat.com> Signed-off-by: Chen Yu <yu.c.chen@intel.com> Cc: Dave Young <dyoung@redhat.com> Cc: Len Brown <lenb@kernel.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Xunlei Pang <xlpang@redhat.com> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/e820/api.h1
-rw-r--r--arch/x86/kernel/e820.c31
-rw-r--r--arch/x86/power/hibernate_64.c4
3 files changed, 29 insertions, 7 deletions
diff --git a/arch/x86/include/asm/e820/api.h b/arch/x86/include/asm/e820/api.h
index a688095421ab..a504adc661a4 100644
--- a/arch/x86/include/asm/e820/api.h
+++ b/arch/x86/include/asm/e820/api.h
@@ -5,6 +5,7 @@
5 5
6extern struct e820_table *e820_table; 6extern struct e820_table *e820_table;
7extern struct e820_table *e820_table_kexec; 7extern struct e820_table *e820_table_kexec;
8extern struct e820_table *e820_table_firmware;
8 9
9extern unsigned long pci_mem_start; 10extern unsigned long pci_mem_start;
10 11
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 591019031e23..532da61d605c 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -20,10 +20,12 @@
20#include <asm/setup.h> 20#include <asm/setup.h>
21 21
22/* 22/*
23 * We organize the E820 table into two main data structures: 23 * We organize the E820 table into three main data structures:
24 * 24 *
25 * - 'e820_table_kexec': the original firmware version passed to us by the 25 * - 'e820_table_firmware': the original firmware version passed to us by the
26 * bootloader - not modified by the kernel. We use this to: 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:
27 * 29 *
28 * - inform the user about the firmware's notion of memory layout 30 * - inform the user about the firmware's notion of memory layout
29 * via /sys/firmware/memmap 31 * via /sys/firmware/memmap
@@ -31,6 +33,14 @@
31 * - the hibernation code uses it to generate a kernel-independent MD5 33 * - the hibernation code uses it to generate a kernel-independent MD5
32 * fingerprint of the physical memory layout of a system. 34 * fingerprint of the physical memory layout of a system.
33 * 35 *
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 *
34 * - kexec, which is a bootloader in disguise, uses the original E820 44 * - kexec, which is a bootloader in disguise, uses the original E820
35 * layout to pass to the kexec-ed kernel. This way the original kernel 45 * layout to pass to the kexec-ed kernel. This way the original kernel
36 * can have a restricted E820 map while the kexec()-ed kexec-kernel 46 * can have a restricted E820 map while the kexec()-ed kexec-kernel
@@ -47,9 +57,11 @@
47 */ 57 */
48static struct e820_table e820_table_init __initdata; 58static struct e820_table e820_table_init __initdata;
49static struct e820_table e820_table_kexec_init __initdata; 59static struct e820_table e820_table_kexec_init __initdata;
60static struct e820_table e820_table_firmware_init __initdata;
50 61
51struct e820_table *e820_table __refdata = &e820_table_init; 62struct e820_table *e820_table __refdata = &e820_table_init;
52struct e820_table *e820_table_kexec __refdata = &e820_table_kexec_init; 63struct e820_table *e820_table_kexec __refdata = &e820_table_kexec_init;
64struct e820_table *e820_table_firmware __refdata = &e820_table_firmware_init;
53 65
54/* For PCI or other memory-mapped resources */ 66/* For PCI or other memory-mapped resources */
55unsigned long pci_mem_start = 0xaeedbabe; 67unsigned long pci_mem_start = 0xaeedbabe;
@@ -648,6 +660,12 @@ __init void e820__reallocate_tables(void)
648 BUG_ON(!n); 660 BUG_ON(!n);
649 memcpy(n, e820_table_kexec, size); 661 memcpy(n, e820_table_kexec, size);
650 e820_table_kexec = n; 662 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;
651} 669}
652 670
653/* 671/*
@@ -670,6 +688,7 @@ void __init e820__memory_setup_extended(u64 phys_addr, u32 data_len)
670 e820__update_table(e820_table); 688 e820__update_table(e820_table);
671 689
672 memcpy(e820_table_kexec, e820_table, sizeof(*e820_table_kexec)); 690 memcpy(e820_table_kexec, e820_table, sizeof(*e820_table_kexec));
691 memcpy(e820_table_firmware, e820_table, sizeof(*e820_table_firmware));
673 692
674 early_memunmap(sdata, data_len); 693 early_memunmap(sdata, data_len);
675 pr_info("e820: extended physical RAM map:\n"); 694 pr_info("e820: extended physical RAM map:\n");
@@ -1064,8 +1083,9 @@ void __init e820__reserve_resources(void)
1064 res++; 1083 res++;
1065 } 1084 }
1066 1085
1067 for (i = 0; i < e820_table_kexec->nr_entries; i++) { 1086 /* Expose the bootloader-provided memory layout to the sysfs. */
1068 struct e820_entry *entry = e820_table_kexec->entries + i; 1087 for (i = 0; i < e820_table_firmware->nr_entries; i++) {
1088 struct e820_entry *entry = e820_table_firmware->entries + i;
1069 1089
1070 firmware_map_add_early(entry->addr, entry->addr + entry->size, e820_type_to_string(entry)); 1090 firmware_map_add_early(entry->addr, entry->addr + entry->size, e820_type_to_string(entry));
1071 } 1091 }
@@ -1178,6 +1198,7 @@ void __init e820__memory_setup(void)
1178 who = x86_init.resources.memory_setup(); 1198 who = x86_init.resources.memory_setup();
1179 1199
1180 memcpy(e820_table_kexec, e820_table, sizeof(*e820_table_kexec)); 1200 memcpy(e820_table_kexec, e820_table, sizeof(*e820_table_kexec));
1201 memcpy(e820_table_firmware, e820_table, sizeof(*e820_table_firmware));
1181 1202
1182 pr_info("e820: BIOS-provided physical RAM map:\n"); 1203 pr_info("e820: BIOS-provided physical RAM map:\n");
1183 e820__print_table(who); 1204 e820__print_table(who);
diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c
index 3ba161a08d6e..e3e62c8a8e70 100644
--- a/arch/x86/power/hibernate_64.c
+++ b/arch/x86/power/hibernate_64.c
@@ -251,7 +251,7 @@ static int get_e820_md5(struct e820_table *table, void *buf)
251 251
252static void hibernation_e820_save(void *buf) 252static void hibernation_e820_save(void *buf)
253{ 253{
254 get_e820_md5(e820_table_kexec, buf); 254 get_e820_md5(e820_table_firmware, buf);
255} 255}
256 256
257static bool hibernation_e820_mismatch(void *buf) 257static bool hibernation_e820_mismatch(void *buf)
@@ -264,7 +264,7 @@ static bool hibernation_e820_mismatch(void *buf)
264 if (!memcmp(result, buf, MD5_DIGEST_SIZE)) 264 if (!memcmp(result, buf, MD5_DIGEST_SIZE))
265 return false; 265 return false;
266 266
267 ret = get_e820_md5(e820_table_kexec, result); 267 ret = get_e820_md5(e820_table_firmware, result);
268 if (ret) 268 if (ret)
269 return true; 269 return true;
270 270