xen: allow very early initialization of the hypercall page

Allow the hypercall page to be initialized very early, even before
vtophys is functional. Also make the function global so it can be
called by other files.

This will be needed in order to perform the early bringup on PVHv2
guests.

Sponsored by: Citrix Systems R&D
This commit is contained in:
Roger Pau Monné 2018-07-19 08:13:41 +00:00
parent 3653af112f
commit 07c2711fbf
2 changed files with 61 additions and 41 deletions

View File

@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_param.h>
#include <dev/pci/pcivar.h>
@ -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);

View File

@ -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);