diff --git a/sys/x86/xen/hvm.c b/sys/x86/xen/hvm.c index 1b98ab61e42..f8c886ec0fa 100644 --- a/sys/x86/xen/hvm.c +++ b/sys/x86/xen/hvm.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include @@ -63,13 +64,6 @@ __FBSDID("$FreeBSD$"); /*--------------------------- Forward Declarations ---------------------------*/ static void xen_hvm_cpu_init(void); -/*-------------------------------- Local Types -------------------------------*/ -enum xen_hvm_init_type { - XEN_HVM_INIT_COLD, - XEN_HVM_INIT_CANCELLED_SUSPEND, - XEN_HVM_INIT_RESUME -}; - /*-------------------------------- Global Data -------------------------------*/ enum xen_domain_type xen_domain_type = XEN_NATIVE; @@ -119,50 +113,66 @@ xen_hvm_cpuid_base(void) return (0); } +static void +hypervisor_quirks(unsigned int major, unsigned int minor) +{ +#ifdef SMP + if (((major < 4) || (major == 4 && minor <= 5)) && + msix_disable_migration == -1) { + /* + * Xen hypervisors prior to 4.6.0 do not properly + * handle updates to enabled MSI-X table entries, + * so disable MSI-X interrupt migration in that + * case. + */ + if (bootverbose) + printf( +"Disabling MSI-X interrupt migration due to Xen hypervisor bug.\n" +"Set machdep.msix_disable_migration=0 to forcefully enable it.\n"); + msix_disable_migration = 1; + } +#endif +} + +static void +hypervisor_version(void) +{ + uint32_t regs[4]; + int major, minor; + + do_cpuid(cpuid_base + 1, regs); + + major = regs[0] >> 16; + minor = regs[0] & 0xffff; + printf("XEN: Hypervisor version %d.%d detected.\n", major, minor); + + hypervisor_quirks(major, minor); +} + /* * Allocate and fill in the hypcall page. */ -static int +int xen_hvm_init_hypercall_stubs(enum xen_hvm_init_type init_type) { uint32_t regs[4]; - if (xen_pv_domain()) { - /* hypercall page is already set in the PV case */ - return (0); + if (xen_domain() && init_type == XEN_HVM_INIT_LATE) { + /* + * If the domain type is already set we can assume that the + * hypercall page has been populated too, so just print the + * version (and apply any quirks) and exit. + */ + hypervisor_version(); + return 0; } cpuid_base = xen_hvm_cpuid_base(); if (cpuid_base == 0) return (ENXIO); - if (init_type == XEN_HVM_INIT_COLD) { - int major, minor; - - do_cpuid(cpuid_base + 1, regs); - - major = regs[0] >> 16; - minor = regs[0] & 0xffff; - printf("XEN: Hypervisor version %d.%d detected.\n", major, - minor); - -#ifdef SMP - if (((major < 4) || (major == 4 && minor <= 5)) && - msix_disable_migration == -1) { - /* - * Xen hypervisors prior to 4.6.0 do not properly - * handle updates to enabled MSI-X table entries, - * so disable MSI-X interrupt migration in that - * case. - */ - if (bootverbose) - printf( -"Disabling MSI-X interrupt migration due to Xen hypervisor bug.\n" -"Set machdep.msix_disable_migration=0 to forcefully enable it.\n"); - msix_disable_migration = 1; - } -#endif - } + if (init_type == XEN_HVM_INIT_LATE) + hypervisor_version(); /* * Find the hypercall pages. @@ -171,7 +181,9 @@ xen_hvm_init_hypercall_stubs(enum xen_hvm_init_type init_type) if (regs[0] != 1) return (EINVAL); - wrmsr(regs[1], vtophys(&hypercall_page)); + wrmsr(regs[1], (init_type == XEN_HVM_INIT_EARLY) + ? ((vm_paddr_t)&hypercall_page - KERNBASE) + : vtophys(&hypercall_page)); return (0); } @@ -307,7 +319,7 @@ xen_hvm_init(enum xen_hvm_init_type init_type) error = xen_hvm_init_hypercall_stubs(init_type); switch (init_type) { - case XEN_HVM_INIT_COLD: + case XEN_HVM_INIT_LATE: if (error != 0) return; @@ -371,7 +383,7 @@ xen_hvm_resume(bool suspend_cancelled) static void xen_hvm_sysinit(void *arg __unused) { - xen_hvm_init(XEN_HVM_INIT_COLD); + xen_hvm_init(XEN_HVM_INIT_LATE); } SYSINIT(xen_hvm_init, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, xen_hvm_sysinit, NULL); diff --git a/sys/xen/hvm.h b/sys/xen/hvm.h index 07d3d7b269c..055ba4ffe75 100644 --- a/sys/xen/hvm.h +++ b/sys/xen/hvm.h @@ -91,6 +91,14 @@ enum { (((uint64_t)HVM_CB_TYPE_VECTOR << HVM_CB_TYPE_SHIFT) \ | (((vector) & HVM_CB_GSI_GSI_MASK) << HVM_CB_GSI_GSI_SHIFT)) +enum xen_hvm_init_type { + XEN_HVM_INIT_EARLY, + XEN_HVM_INIT_LATE, + XEN_HVM_INIT_CANCELLED_SUSPEND, + XEN_HVM_INIT_RESUME, +}; + +int xen_hvm_init_hypercall_stubs(enum xen_hvm_init_type); void xen_hvm_set_callback(device_t); void xen_hvm_suspend(void); void xen_hvm_resume(bool suspend_cancelled);