git: a8ea1540640f - main - x86: Distinguish Xen from non-Xen PVH boots
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 18 Oct 2022 06:03:15 UTC
The branch main has been updated by cperciva: URL: https://cgit.FreeBSD.org/src/commit/?id=a8ea1540640f154844f12a0b24d0e272b6e39ca9 commit a8ea1540640f154844f12a0b24d0e272b6e39ca9 Author: Colin Percival <cperciva@FreeBSD.org> AuthorDate: 2022-07-13 00:46:04 +0000 Commit: Colin Percival <cperciva@FreeBSD.org> CommitDate: 2022-10-18 06:02:22 +0000 x86: Distinguish Xen from non-Xen PVH boots The PVH boot protocol, introduced by Xen, is now used by some non-Xen platforms (e.g. the Firecracker VM) as well. In order to accommodate these, we use CPUID to detect Xen and only perform Xen-specific setup when running on that platform. The "isxen" function duplicates some work done by identcpu.c later in the boot process; but we need it here since this is the very first C code which runs when PVH booting (even before hammer_time). In many places the existing code had xc_printf(...); HYPERVISOR_shutdown(SHUTDOWN_crash); making use of Xen functionality to print a message and shut down; in the places where this idiom can be reached in the non-xen case, we replace it idiom with a CRASH(...) macro which calls those in the Xen case and halts in the non-Xen case. Reviewed by: royger Sponsored by: https://www.patreon.com/cperciva Differential Revision: https://reviews.freebsd.org/D35801 --- sys/x86/xen/pv.c | 92 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 24 deletions(-) diff --git a/sys/x86/xen/pv.c b/sys/x86/xen/pv.c index 845c2d7222eb..b81423a1be88 100644 --- a/sys/x86/xen/pv.c +++ b/sys/x86/xen/pv.c @@ -76,6 +76,7 @@ __FBSDID("$FreeBSD$"); #include <xen/xenstore/xenstorevar.h> #include <xen/xen_pv.h> +#include <contrib/xen/arch-x86/cpuid.h> #include <contrib/xen/arch-x86/hvm/start_info.h> #include <contrib/xen/vcpu.h> @@ -117,6 +118,44 @@ static struct hvm_start_info *start_info; /*-------------------------------- Xen PV init -------------------------------*/ +static int +isxen(void) +{ + static int xen = -1; + uint32_t base; + u_int regs[4]; + + if (xen != -1) + return (xen); + + /* + * The full code for identifying which hypervisor we're running under + * is in sys/x86/x86/identcpu.c and runs later in the boot process; + * this is sufficient to distinguish Xen PVH booting from non-Xen PVH + * and skip some very early Xen-specific code in the non-Xen case. + */ + xen = 0; + for (base = 0x40000000; base < 0x40010000; base += 0x100) { + do_cpuid(base, regs); + if (regs[1] == XEN_CPUID_SIGNATURE_EBX && + regs[2] == XEN_CPUID_SIGNATURE_ECX && + regs[3] == XEN_CPUID_SIGNATURE_EDX) { + xen = 1; + break; + } + } + return (xen); +} + +#define CRASH(...) do { \ + if (isxen()) { \ + xc_printf(__VA_ARGS__); \ + HYPERVISOR_shutdown(SHUTDOWN_crash); \ + } else { \ + halt(); \ + } \ +} while (0) + uint64_t hammer_time_xen(vm_paddr_t start_info_paddr) { @@ -126,21 +165,21 @@ hammer_time_xen(vm_paddr_t start_info_paddr) char *kenv; int rc; - xen_domain_type = XEN_HVM_DOMAIN; - vm_guest = VM_GUEST_XEN; - - rc = xen_hvm_init_hypercall_stubs(XEN_HVM_INIT_EARLY); - if (rc) { - xc_printf("ERROR: failed to initialize hypercall page: %d\n", - rc); - HYPERVISOR_shutdown(SHUTDOWN_crash); + if (isxen()) { + xen_domain_type = XEN_HVM_DOMAIN; + vm_guest = VM_GUEST_XEN; + rc = xen_hvm_init_hypercall_stubs(XEN_HVM_INIT_EARLY); + if (rc) { + xc_printf("ERROR: failed to initialize hypercall page: %d\n", + rc); + HYPERVISOR_shutdown(SHUTDOWN_crash); + } } start_info = (struct hvm_start_info *)(start_info_paddr + KERNBASE); if (start_info->magic != XEN_HVM_START_MAGIC_VALUE) { - xc_printf("Unknown magic value in start_info struct: %#x\n", + CRASH("Unknown magic value in start_info struct: %#x\n", start_info->magic); - HYPERVISOR_shutdown(SHUTDOWN_crash); } /* @@ -164,9 +203,8 @@ hammer_time_xen(vm_paddr_t start_info_paddr) unsigned int i; if (start_info->nr_modules == 0) { - xc_printf( + CRASH( "ERROR: modlist_paddr != 0 but nr_modules == 0\n"); - HYPERVISOR_shutdown(SHUTDOWN_crash); } mod = (struct hvm_modlist_entry *) (start_info->modlist_paddr + KERNBASE); @@ -175,16 +213,18 @@ hammer_time_xen(vm_paddr_t start_info_paddr) PAGE_SIZE), physfree); } - xatp.domid = DOMID_SELF; - xatp.idx = 0; - xatp.space = XENMAPSPACE_shared_info; - xatp.gpfn = atop(physfree); - if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) { - xc_printf("ERROR: failed to setup shared_info page\n"); - HYPERVISOR_shutdown(SHUTDOWN_crash); + if (isxen()) { + xatp.domid = DOMID_SELF; + xatp.idx = 0; + xatp.space = XENMAPSPACE_shared_info; + xatp.gpfn = atop(physfree); + if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) { + xc_printf("ERROR: failed to setup shared_info page\n"); + HYPERVISOR_shutdown(SHUTDOWN_crash); + } + HYPERVISOR_shared_info = (shared_info_t *)(physfree + KERNBASE); + physfree += PAGE_SIZE; } - HYPERVISOR_shared_info = (shared_info_t *)(physfree + KERNBASE); - physfree += PAGE_SIZE; /* * Init a static kenv using a free page. The contents will be filled @@ -245,7 +285,7 @@ xen_pvh_set_env(char *env, bool (*filter)(const char *)) value = option; option = strsep(&value, "="); - if (kern_setenv(option, value) != 0) + if (kern_setenv(option, value) != 0 && isxen()) xc_printf("unable to add kenv %s=%s\n", option, value); option = value + strlen(value) + 1; } @@ -269,7 +309,8 @@ xen_pvh_parse_symtab(void) if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || ehdr->e_version > 1) { - xc_printf("Unable to load ELF symtab: invalid symbol table\n"); + if (isxen()) + xc_printf("Unable to load ELF symtab: invalid symbol table\n"); return; } @@ -289,7 +330,7 @@ xen_pvh_parse_symtab(void) break; } - if (ksymtab == 0 || kstrtab == 0) + if ((ksymtab == 0 || kstrtab == 0) && isxen()) xc_printf( "Unable to load ELF symtab: could not find symtab or strtab\n"); } @@ -432,6 +473,9 @@ xen_pvh_parse_memmap(caddr_t kmdp, vm_paddr_t *physmap, int *physmap_idx) u_int32_t size; int rc; + /* We should only reach here if we're running under Xen. */ + KASSERT(isxen(), ("xen_pvh_parse_memmap reached when !Xen")); + /* Fetch the E820 map from Xen */ memmap.nr_entries = MAX_E820_ENTRIES; set_xen_guest_handle(memmap.buffer, xen_smap);