[PATCH 1/2][RFC] x86/boot/e820: Introduce e820_table_ori to represent the real original e820 layout

From: Chen Yu
Date: Sat Jun 17 2017 - 01:22:11 EST

Currently we try to have e820_table_firmware to represent the
original firmware memory layout passed to us by the bootloader,
however it is not the case, the e820_table_firmware might still
be modified by linux:
1. During bootup, the efi boot stub might allocate memory via
efi service for the PCI device information structure, then
later e820_reserve_setup_data() reserved these dynamically
allocated structures(AKA, setup_data) in e820_table_firmware
2. The kexec might also modify the e820_table_firmware.

This brings problem to the memory layout checking logic during
hibernation, because in theory that code expects to get input
from the original memory layout passed by the BIOS, otherwise
we get a force-positive failure.

So introduce a new variable e820_table_ori to record the original
BIOS provided memory layout, which is composed of two parts:
the BIOS-provided physical RAM map and extended physical RAM map.

Cc: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Cc: Rafael J. Wysocki <rafael@xxxxxxxxxx>
Cc: Len Brown <lenb@xxxxxxxxxx>
Cc: Ying Huang <ying.huang@xxxxxxxxx>
Cc: x86@xxxxxxxxxx
Signed-off-by: Chen Yu <yu.c.chen@xxxxxxxxx>
arch/x86/include/asm/e820/api.h | 1 +
arch/x86/kernel/e820.c | 24 ++++++++++++++++++++----
2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/e820/api.h b/arch/x86/include/asm/e820/api.h
index 8e0f8b8..d30114b 100644
--- a/arch/x86/include/asm/e820/api.h
+++ b/arch/x86/include/asm/e820/api.h
@@ -5,6 +5,7 @@

extern struct e820_table *e820_table;
extern struct e820_table *e820_table_firmware;
+extern struct e820_table *e820_table_ori;

extern unsigned long pci_mem_start;

diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index d78a586..29dcb4c 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -20,7 +20,7 @@
#include <asm/setup.h>

- * We organize the E820 table into two main data structures:
+ * We organize the E820 table into three main data structures:
* - 'e820_table_firmware': the original firmware version passed to us by the
* bootloader - not modified by the kernel. We use this to:
@@ -28,14 +28,18 @@
* - inform the user about the firmware's notion of memory layout
* via /sys/firmware/memmap
- * - the hibernation code uses it to generate a kernel-independent MD5
- * fingerprint of the physical memory layout of a system.
- *
* - kexec, which is a bootloader in disguise, uses the original E820
* layout to pass to the kexec-ed kernel. This way the original kernel
* can have a restricted E820 map while the kexec()-ed kexec-kernel
* can have access to full memory - etc.
+ * - 'e820_table_ori': the original firmware version passed to us by the
+ * bootloader - not modified by the kernel or the efi boot stub.
+ * We use this to:
+ *
+ * - the hibernation code uses it to generate a kernel-independent MD5
+ * fingerprint of the physical memory layout of a system.
+ *
* - 'e820_table': this is the main E820 table that is massaged by the
* low level x86 platform code, or modified by boot parameters, before
* passed on to higher level MM layers.
@@ -47,9 +51,11 @@
static struct e820_table e820_table_init __initdata;
static struct e820_table e820_table_firmware_init __initdata;
+static struct e820_table e820_table_ori_init __initdata;

struct e820_table *e820_table __refdata = &e820_table_init;
struct e820_table *e820_table_firmware __refdata = &e820_table_firmware_init;
+struct e820_table *e820_table_ori __refdata = &e820_table_ori_init;

/* For PCI or other memory-mapped resources */
unsigned long pci_mem_start = 0xaeedbabe;
@@ -648,6 +654,12 @@ __init void e820__reallocate_tables(void)
memcpy(n, e820_table_firmware, size);
e820_table_firmware = n;
+ size = offsetof(struct e820_table, entries) + sizeof(struct e820_entry)*e820_table_ori->nr_entries;
+ n = kmalloc(size, GFP_KERNEL);
+ BUG_ON(!n);
+ memcpy(n, e820_table_ori, size);
+ e820_table_ori = n;

@@ -669,6 +681,9 @@ void __init e820__memory_setup_extended(u64 phys_addr, u32 data_len)
__append_e820_table(extmap, entries);

+ /* Update the original table if there's any extended memory. */
+ memcpy(e820_table_ori, e820_table, sizeof(*e820_table_ori));
early_memunmap(sdata, data_len);
pr_info("e820: extended physical RAM map:\n");
@@ -1176,6 +1191,7 @@ void __init e820__memory_setup(void)
who = x86_init.resources.memory_setup();

memcpy(e820_table_firmware, e820_table, sizeof(*e820_table_firmware));
+ memcpy(e820_table_ori, e820_table, sizeof(*e820_table_ori));

pr_info("e820: BIOS-provided physical RAM map:\n");