git: 1b5e5ff68c2b - main - xen/pvh: fix initialization of environment

From: Roger Pau Monné <royger_at_FreeBSD.org>
Date: Fri, 02 Aug 2024 10:42:55 UTC
The branch main has been updated by royger:

URL: https://cgit.FreeBSD.org/src/commit/?id=1b5e5ff68c2bafae55a5adab42f22039bbbce59c

commit 1b5e5ff68c2bafae55a5adab42f22039bbbce59c
Author:     Roger Pau Monné <royger@FreeBSD.org>
AuthorDate: 2024-07-18 08:14:28 +0000
Commit:     Roger Pau Monné <royger@FreeBSD.org>
CommitDate: 2024-08-02 10:41:52 +0000

    xen/pvh: fix initialization of environment
    
    Xen PVH entry point requires to modify the environment provided by the boot
    loader, so that the ACPI RSDP is re-written to use the Xen generated RSDP
    instead of the native one.
    
    The current logic in the PVH entry point reserves a single page (4K) in order
    to copy the contents of the environment passed from the boot loader, so that
    the bootloader provided "acpi.rsdp" is dropped and a Xen specific one is added
    afterwards.
    
    This however doesn't scale well, as it's possible for the environment to be
    bigger than 4K.  Bumping the buffer, or attempting to peek at the size of the
    metadata all seem to just add more complexity to a sensitive path.  Instead
    introduce a new ACPI hook that allows setting the RSDP address directly, and
    use it from the PVH entry point to set the position of the Xen generated RSDP.
    
    This allows to reduce the logic in the PVH metadata processing, as there's no
    need to parse and filter the bootloader provided environment.
    
    Note that modifying the environment blob in-place is likely to not work.  The
    RSDP address is provided as a string, it's possible the new RSDP location is
    higher than the current one, and the string with the new location would overrun
    the space used by the previous one.
    
    Sponsored by: Cloud Software Group
    PR: 277200
    MFC: 3 days
    Reviewed by: markj kib
    Differential revision: https://reviews.freebsd.org/D46089
---
 sys/x86/acpica/OsdEnvironment.c  | 12 +++++--
 sys/x86/include/acpica_machdep.h |  2 ++
 sys/x86/xen/pv.c                 | 74 +++++++---------------------------------
 3 files changed, 25 insertions(+), 63 deletions(-)

diff --git a/sys/x86/acpica/OsdEnvironment.c b/sys/x86/acpica/OsdEnvironment.c
index c9dd3d0560cc..55954f8336fa 100644
--- a/sys/x86/acpica/OsdEnvironment.c
+++ b/sys/x86/acpica/OsdEnvironment.c
@@ -77,14 +77,22 @@ acpi_get_root_from_memory(void)
 	return (0);
 }
 
+void
+acpi_set_root(vm_paddr_t addr)
+{
+
+	KASSERT(acpi_root_phys == 0, ("ACPI root pointer already set"));
+	acpi_root_phys = addr;
+}
+
 ACPI_PHYSICAL_ADDRESS
 AcpiOsGetRootPointer(void)
 {
 
 	if (acpi_root_phys == 0) {
-		acpi_root_phys = acpi_get_root_from_loader();
+		acpi_set_root(acpi_get_root_from_loader());
 		if (acpi_root_phys == 0)
-			acpi_root_phys = acpi_get_root_from_memory();
+			acpi_set_root(acpi_get_root_from_memory());
 	}
 
 	return (acpi_root_phys);
diff --git a/sys/x86/include/acpica_machdep.h b/sys/x86/include/acpica_machdep.h
index b4811e4bd30c..2592b47ae1c1 100644
--- a/sys/x86/include/acpica_machdep.h
+++ b/sys/x86/include/acpica_machdep.h
@@ -84,6 +84,8 @@ void	madt_parse_interrupt_values(void *entry,
 extern int madt_found_sci_override;
 extern int (*apei_nmi)(void);
 
+void	acpi_set_root(vm_paddr_t addr);
+
 #endif /* _KERNEL */
 
 #endif /* __ACPICA_MACHDEP_H__ */
diff --git a/sys/x86/xen/pv.c b/sys/x86/xen/pv.c
index 0e6492b124b8..388543d64254 100644
--- a/sys/x86/xen/pv.c
+++ b/sys/x86/xen/pv.c
@@ -60,6 +60,7 @@
 
 #include <machine/_inttypes.h>
 #include <machine/intr_machdep.h>
+#include <x86/acpica_machdep.h>
 #include <x86/apicvar.h>
 #include <x86/init.h>
 #include <machine/pc/bios.h>
@@ -157,7 +158,6 @@ hammer_time_xen(vm_paddr_t start_info_paddr)
 {
 	struct hvm_modlist_entry *mod;
 	uint64_t physfree;
-	char *kenv;
 
 	start_info = (struct hvm_start_info *)(start_info_paddr + KERNBASE);
 	if (start_info->magic != XEN_HVM_START_MAGIC_VALUE) {
@@ -196,15 +196,6 @@ hammer_time_xen(vm_paddr_t start_info_paddr)
 			    PAGE_SIZE), physfree);
 	}
 
-	/*
-	 * Init a static kenv using a free page. The contents will be filled
-	 * from the parse_preload_data hook.
-	 */
-	kenv = (void *)(physfree + KERNBASE);
-	physfree += PAGE_SIZE;
-	bzero_early(kenv, PAGE_SIZE);
-	init_static_kenv(kenv, PAGE_SIZE);
-
 	/* Set the hooks for early functions that diverge from bare metal */
 	init_ops = xen_pvh_init_ops;
 	hvm_start_flags = start_info->flags;
@@ -215,52 +206,6 @@ hammer_time_xen(vm_paddr_t start_info_paddr)
 
 /*-------------------------------- PV specific -------------------------------*/
 
-/*
- * When booted as a PVH guest FreeBSD needs to avoid using the RSDP address
- * hint provided by the loader because it points to the native set of ACPI
- * tables instead of the ones crafted by Xen. The acpi.rsdp env variable is
- * removed from kenv if present, and a new acpi.rsdp is added to kenv that
- * points to the address of the Xen crafted RSDP.
- */
-static bool reject_option(const char *option)
-{
-	static const char *reject[] = {
-		"acpi.rsdp",
-	};
-	unsigned int i;
-
-	for (i = 0; i < nitems(reject); i++)
-		if (strncmp(option, reject[i], strlen(reject[i])) == 0)
-			return (true);
-
-	return (false);
-}
-
-static void
-xen_pvh_set_env(char *env, bool (*filter)(const char *))
-{
-	char *option;
-
-	if (env == NULL)
-		return;
-
-	option = env;
-	while (*option != 0) {
-		char *value;
-
-		if (filter != NULL && filter(option)) {
-			option += strlen(option) + 1;
-			continue;
-		}
-
-		value = option;
-		option = strsep(&value, "=");
-		if (kern_setenv(option, value) != 0 && isxen())
-			xc_printf("unable to add kenv %s=%s\n", option, value);
-		option = value + strlen(value) + 1;
-	}
-}
-
 #ifdef DDB
 /*
  * The way Xen loads the symtab is different from the native boot loader,
@@ -313,7 +258,6 @@ xen_pvh_parse_preload_data(uint64_t modulep)
 	vm_ooffset_t off;
 	vm_paddr_t metadata;
 	char *envp;
-	char acpi_rsdp[19];
 
 	TSENTER();
 	if (start_info->modlist_paddr != 0) {
@@ -379,13 +323,18 @@ xen_pvh_parse_preload_data(uint64_t modulep)
 		envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
 		if (envp != NULL)
 			envp += off;
-		xen_pvh_set_env(envp, reject_option);
+		init_static_kenv(envp, 0);
 
 		if (MD_FETCH(kmdp, MODINFOMD_EFI_MAP, void *) != NULL)
 		    strlcpy(bootmethod, "UEFI", sizeof(bootmethod));
 		else
 		    strlcpy(bootmethod, "BIOS", sizeof(bootmethod));
 	} else {
+		static char kenv_buffer[PAGE_SIZE];
+
+		/* Provide a static kenv so the command line can be parsed. */
+		init_static_kenv(kenv_buffer, sizeof(kenv_buffer));
+
 		/* Parse the extra boot information given by Xen */
 		if (start_info->cmdline_paddr != 0)
 			boot_parse_cmdline_delim(
@@ -397,9 +346,12 @@ xen_pvh_parse_preload_data(uint64_t modulep)
 
 	boothowto |= boot_env_to_howto();
 
-	snprintf(acpi_rsdp, sizeof(acpi_rsdp), "%#" PRIx64,
-	    start_info->rsdp_paddr);
-	kern_setenv("acpi.rsdp", acpi_rsdp);
+	/*
+	 * When booted as a PVH guest FreeBSD must not use the RSDP address
+	 * hint provided by the loader because it points to the native set of
+	 * ACPI tables instead of the ones crafted by Xen.
+	 */
+	acpi_set_root(start_info->rsdp_paddr);
 
 #ifdef DDB
 	xen_pvh_parse_symtab();