From: Juergen Gross <jgross@suse.com>
Date: Wed, 10 Oct 2018 08:14:55 +0200
Subject: x86/boot: Add ACPI RSDP address to setup_header
Origin: https://git.kernel.org/linus/ae7e1238e68f2a472a125673ab506d49158c1889

Xen PVH guests receive the address of the RSDP table from Xen. In order
to support booting a Xen PVH guest via Grub2 using the standard x86
boot entry we need a way for Grub2 to pass the RSDP address to the
kernel.

For this purpose expand the struct setup_header to hold the physical
address of the RSDP address. Being zero means it isn't specified and
has to be located the legacy way (searching through low memory or
EBDA).

While documenting the new setup_header layout and protocol version
2.14 add the missing documentation of protocol version 2.13.

There are Grub2 versions in several distros with a downstream patch
violating the boot protocol by writing past the end of setup_header.
This requires another update of the boot protocol to enable the kernel
to distinguish between a specified RSDP address and one filled with
garbage by such a broken Grub2.

From protocol 2.14 on Grub2 will write the version it is supporting
(but never a higher value than found to be supported by the kernel)
ored with 0x8000 to the version field of setup_header. This enables
the kernel to know up to which field Grub2 has written information
to. All fields after that are supposed to be clobbered.

Signed-off-by: Juergen Gross <jgross@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: boris.ostrovsky@oracle.com
Cc: bp@alien8.de
Cc: corbet@lwn.net
Cc: linux-doc@vger.kernel.org
Cc: xen-devel@lists.xenproject.org
Link: http://lkml.kernel.org/r/20181010061456.22238-3-jgross@suse.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
 Documentation/x86/boot.txt            | 32 ++++++++++++++++++++++++++-
 arch/x86/boot/header.S                |  6 ++++-
 arch/x86/include/asm/x86_init.h       |  2 ++
 arch/x86/include/uapi/asm/bootparam.h |  4 ++++
 arch/x86/kernel/head32.c              |  1 +
 arch/x86/kernel/head64.c              |  2 ++
 arch/x86/kernel/setup.c               | 17 ++++++++++++++
 7 files changed, 62 insertions(+), 2 deletions(-)

Index: linux/Documentation/x86/boot.txt
===================================================================
--- linux.orig/Documentation/x86/boot.txt
+++ linux/Documentation/x86/boot.txt
@@ -61,6 +61,18 @@ Protocol 2.12:	(Kernel 3.8) Added the xl
 	 	to struct boot_params for loading bzImage and ramdisk
 		above 4G in 64bit.
 
+Protocol 2.13:	(Kernel 3.14) Support 32- and 64-bit flags being set in
+		xloadflags to support booting a 64-bit kernel from 32-bit
+		EFI
+
+Protocol 2.14:	(Kernel 4.20) Added acpi_rsdp_addr holding the physical
+		address of the ACPI RSDP table.
+		The bootloader updates version with:
+		0x8000 | min(kernel-version, bootloader-version)
+		kernel-version being the protocol version supported by
+		the kernel and bootloader-version the protocol version
+		supported by the bootloader.
+
 **** MEMORY LAYOUT
 
 The traditional memory map for the kernel loader, used for Image or
@@ -197,6 +209,7 @@ Offset	Proto	Name		Meaning
 0258/8	2.10+	pref_address	Preferred loading address
 0260/4	2.10+	init_size	Linear memory required during initialization
 0264/4	2.11+	handover_offset	Offset of handover entry point
+0268/8	2.14+	acpi_rsdp_addr	Physical address of RSDP table
 
 (1) For backwards compatibility, if the setup_sects field contains 0, the
     real value is 4.
@@ -309,7 +322,7 @@ Protocol:	2.00+
   Contains the magic number "HdrS" (0x53726448).
 
 Field name:	version
-Type:		read
+Type:		modify
 Offset/size:	0x206/2
 Protocol:	2.00+
 
@@ -317,6 +330,12 @@ Protocol:	2.00+
   e.g. 0x0204 for version 2.04, and 0x0a11 for a hypothetical version
   10.17.
 
+  Up to protocol version 2.13 this information is only read by the
+  bootloader. From protocol version 2.14 onwards the bootloader will
+  write the used protocol version or-ed with 0x8000 to the field. The
+  used protocol version will be the minimum of the supported protocol
+  versions of the bootloader and the kernel.
+
 Field name:	realmode_swtch
 Type:		modify (optional)
 Offset/size:	0x208/4
@@ -744,6 +763,17 @@ Offset/size:	0x264/4
 
   See EFI HANDOVER PROTOCOL below for more details.
 
+Field name:	acpi_rsdp_addr
+Type:		write
+Offset/size:	0x268/8
+Protocol:	2.14+
+
+  This field can be set by the boot loader to tell the kernel the
+  physical address of the ACPI RSDP table.
+
+  A value of 0 indicates the kernel should fall back to the standard
+  methods to locate the RSDP.
+
 
 **** THE IMAGE CHECKSUM
 
Index: linux/arch/x86/boot/header.S
===================================================================
--- linux.orig/arch/x86/boot/header.S
+++ linux/arch/x86/boot/header.S
@@ -300,7 +300,7 @@ _start:
 	# Part 2 of the header, from the old setup.S
 
 		.ascii	"HdrS"		# header signature
-		.word	0x020d		# header version number (>= 0x0105)
+		.word	0x020e		# header version number (>= 0x0105)
 					# or else old loadlin-1.5 will fail)
 		.globl realmode_swtch
 realmode_swtch:	.word	0, 0		# default_switch, SETUPSEG
@@ -558,6 +558,10 @@ pref_address:		.quad LOAD_PHYSICAL_ADDR
 init_size:		.long INIT_SIZE		# kernel initialization size
 handover_offset:	.long 0			# Filled in by build.c
 
+acpi_rsdp_addr:		.quad 0			# 64-bit physical pointer to the
+						# ACPI RSDP table, added with
+						# version 2.14
+
 # End of setup header #####################################################
 
 	.section ".entrytext", "ax"
Index: linux/arch/x86/include/asm/x86_init.h
===================================================================
--- linux.orig/arch/x86/include/asm/x86_init.h
+++ linux/arch/x86/include/asm/x86_init.h
@@ -303,4 +303,6 @@ extern void x86_init_noop(void);
 extern void x86_init_uint_noop(unsigned int unused);
 extern bool x86_pnpbios_disabled(void);
 
+void x86_verify_bootdata_version(void);
+
 #endif
Index: linux/arch/x86/include/uapi/asm/bootparam.h
===================================================================
--- linux.orig/arch/x86/include/uapi/asm/bootparam.h
+++ linux/arch/x86/include/uapi/asm/bootparam.h
@@ -16,6 +16,9 @@
 #define RAMDISK_PROMPT_FLAG		0x8000
 #define RAMDISK_LOAD_FLAG		0x4000
 
+/* version flags */
+#define VERSION_WRITTEN	0x8000
+
 /* loadflags */
 #define LOADED_HIGH	(1<<0)
 #define KASLR_FLAG	(1<<1)
@@ -86,6 +89,7 @@ struct setup_header {
 	__u64	pref_address;
 	__u32	init_size;
 	__u32	handover_offset;
+	__u64	acpi_rsdp_addr;
 } __attribute__((packed));
 
 struct sys_desc_table {
Index: linux/arch/x86/kernel/head32.c
===================================================================
--- linux.orig/arch/x86/kernel/head32.c
+++ linux/arch/x86/kernel/head32.c
@@ -37,6 +37,7 @@ asmlinkage __visible void __init i386_st
 	cr4_init_shadow();
 
 	sanitize_boot_params(&boot_params);
+	x86_verify_bootdata_version();
 
 	x86_early_init_platform_quirks();
 
Index: linux/arch/x86/kernel/head64.c
===================================================================
--- linux.orig/arch/x86/kernel/head64.c
+++ linux/arch/x86/kernel/head64.c
@@ -477,6 +477,8 @@ void __init x86_64_start_reservations(ch
 	if (!boot_params.hdr.version)
 		copy_bootdata(__va(real_mode_data));
 
+	x86_verify_bootdata_version();
+
 	x86_early_init_platform_quirks();
 
 	switch (boot_params.hdr.hardware_subarch) {
Index: linux/arch/x86/kernel/setup.c
===================================================================
--- linux.orig/arch/x86/kernel/setup.c
+++ linux/arch/x86/kernel/setup.c
@@ -1281,6 +1281,23 @@ void __init setup_arch(char **cmdline_p)
 	unwind_init();
 }
 
+/*
+ * From boot protocol 2.14 onwards we expect the bootloader to set the
+ * version to "0x8000 | <used version>". In case we find a version >= 2.14
+ * without the 0x8000 we assume the boot loader supports 2.13 only and
+ * reset the version accordingly. The 0x8000 flag is removed in any case.
+ */
+void __init x86_verify_bootdata_version(void)
+{
+	if (boot_params.hdr.version & VERSION_WRITTEN)
+		boot_params.hdr.version &= ~VERSION_WRITTEN;
+	else if (boot_params.hdr.version >= 0x020e)
+		boot_params.hdr.version = 0x020d;
+
+	if (boot_params.hdr.version < 0x020e)
+		boot_params.hdr.acpi_rsdp_addr = 0;
+}
+
 #ifdef CONFIG_X86_32
 
 static struct resource video_ram_resource = {
