public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Reserve EBDA region
@ 2019-12-20  0:57 Gan Shun Lim
  0 siblings, 0 replies; only message in thread
From: Gan Shun Lim @ 2019-12-20  0:57 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, Gan Shun Lim

When we boot LinuxBoot-style (as a UEFI binary), sometimes UEFI does
not correctly mark the EBDA region as reserved. We reserve it in all
e820 maps to ensure both the Linuxboot kernel and the future kexec-ed
kernel do not corrupt it. This patch also adds a LinuxBoot config that
selects the RESERVE_EBDA automatically.

Signed-off-by: Gan Shun Lim <ganshun@google.com>
---
 arch/x86/Kconfig                | 23 ++++++++++++++++++++
 arch/x86/include/asm/e820/api.h |  1 +
 arch/x86/kernel/e820.c          | 38 +++++++++++++++++++++++++++++++++
 arch/x86/kernel/setup.c         |  4 ++++
 4 files changed, 66 insertions(+)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 5e89499536606..bf3bd0381df70 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2467,6 +2467,29 @@ config MODIFY_LDT_SYSCALL
 
 source "kernel/livepatch/Kconfig"
 
+config LINUXBOOT
+	bool "LinuxBoot"
+	select KEXEC_CORE
+	select KEXEC
+	select KEXEC_FILE
+	select EFI
+	select EFI_STUB
+	select RESERVE_EBDA
+	help
+	  Include code to handle booting directly out of firmware.
+	  On EFI systems, this means booting with the EFI boot stub
+	  as an EFI application, embedded in the firmware image. LinuxBoot
+	  should then kexec the actual runtime operating system, and is not
+	  meant to keep running.
+
+config RESERVE_EBDA
+	bool "Reserve the EBDA on boot"
+	help
+	  The Extended BIOS Data Area can be left unreserved when booting
+	  LinuxBoot as an EFI application. This unconditionally marks the
+	  area as reserved for both current and kexec-ed kernels so that
+	  it's not accidently corrupted on kexec.
+
 endmenu
 
 config ARCH_HAS_ADD_PAGES
diff --git a/arch/x86/include/asm/e820/api.h b/arch/x86/include/asm/e820/api.h
index e8f58ddd06d97..57c6bc2f78fda 100644
--- a/arch/x86/include/asm/e820/api.h
+++ b/arch/x86/include/asm/e820/api.h
@@ -29,6 +29,7 @@ extern u64  e820__memblock_alloc_reserved(u64 size, u64 align);
 extern void e820__memblock_setup(void);
 
 extern void e820__reserve_setup_data(void);
+extern void e820__reserve_ebda(void);
 extern void e820__finish_early_params(void);
 extern void e820__reserve_resources(void);
 extern void e820__reserve_resources_late(void);
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index c5399e80c59c5..8401d3fd9b945 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -18,6 +18,7 @@
 #include <linux/memory_hotplug.h>
 
 #include <asm/e820/api.h>
+#include <asm/bios_ebda.h>
 #include <asm/setup.h>
 
 /*
@@ -523,6 +524,14 @@ static u64 __init e820__range_update_kexec(u64 start, u64 size, enum e820_type o
 	return __e820__range_update(e820_table_kexec, start, size, old_type, new_type);
 }
 
+static u64 __init e820__range_update_firmware(u64 start, u64 size,
+					      enum e820_type old_type,
+					      enum e820_type  new_type)
+{
+	return __e820__range_update(e820_table_firmware, start, size,
+				    old_type, new_type);
+}
+
 /* Remove a range of memory from the E820 table: */
 u64 __init e820__range_remove(u64 start, u64 size, enum e820_type old_type, bool check_type)
 {
@@ -1022,6 +1031,35 @@ void __init e820__reserve_setup_data(void)
 	e820__print_table("reserve setup_data");
 }
 
+void __init e820__reserve_ebda(void)
+{
+	unsigned long address;
+	unsigned long start_page, new_length;
+	size_t length;
+
+	address = get_bios_ebda();
+	if (!address) {
+		pr_info("BIOS EBDA non-existent.\n");
+		return;
+	}
+	length = get_bios_ebda_length();
+	start_page = ALIGN_DOWN(address, PAGE_SIZE);
+	new_length = PAGE_ALIGN(address + length) - start_page;
+	pr_info("BIOS EBDA structure found at phys 0x%lx, length 0x%x\n",
+		address, (unsigned int)length);
+	pr_info("Reserving EBDA Page aligned starting at 0x%lx, length 0x%lx\n",
+		start_page, new_length);
+	// Reserve page aligned because memremap doesn't allow us to access
+	// mixed pages.
+	e820__range_update(start_page, new_length, E820_TYPE_RAM,
+			   E820_TYPE_RESERVED);
+	// reserve only the actual ebda region to pass on.
+	e820__range_update_kexec(address, length, E820_TYPE_RAM,
+				 E820_TYPE_RESERVED);
+	e820__range_update_firmware(address, length, E820_TYPE_RAM,
+				    E820_TYPE_RESERVED);
+}
+
 /*
  * Called after parse_early_param(), after early parameters (such as mem=)
  * have been processed, in which case we already have an E820 table filled in
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index cedfe2077a69b..06226d8222d13 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1036,6 +1036,10 @@ void __init setup_arch(char **cmdline_p)
 		setup_clear_cpu_cap(X86_FEATURE_APIC);
 	}
 
+#ifdef CONFIG_LINUXBOOT_RESERVE_EBDA
+	/* update the e820_saved too */
+	e820__reserve_ebda();
+#endif
 	e820__reserve_setup_data();
 	e820__finish_early_params();
 
-- 
2.24.1.735.g03f4e72817-goog


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2019-12-20  0:57 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-12-20  0:57 [PATCH] Reserve EBDA region Gan Shun Lim

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox