diff options
-rw-r--r-- | sys/amd64/include/vmm.h | 3 | ||||
-rw-r--r-- | sys/amd64/vmm/io/vlapic.c | 101 | ||||
-rw-r--r-- | sys/amd64/vmm/io/vlapic.h | 10 | ||||
-rw-r--r-- | sys/amd64/vmm/vmm.c | 2 | ||||
-rw-r--r-- | sys/amd64/vmm/vmm_lapic.c | 11 | ||||
-rw-r--r-- | sys/amd64/vmm/x86.c | 2 | ||||
-rw-r--r-- | usr.sbin/bhyve/bhyverun.c | 28 |
7 files changed, 94 insertions, 63 deletions
diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h index 8b6933a..4dfb4fe 100644 --- a/sys/amd64/include/vmm.h +++ b/sys/amd64/include/vmm.h @@ -265,9 +265,8 @@ enum vm_cap_type { }; enum x2apic_state { - X2APIC_ENABLED, - X2APIC_AVAILABLE, X2APIC_DISABLED, + X2APIC_ENABLED, X2APIC_STATE_LAST }; diff --git a/sys/amd64/vmm/io/vlapic.c b/sys/amd64/vmm/io/vlapic.c index f855f73..d1f7234 100644 --- a/sys/amd64/vmm/io/vlapic.c +++ b/sys/amd64/vmm/io/vlapic.c @@ -1119,12 +1119,31 @@ vlapic_svr_write_handler(struct vlapic *vlapic) } int -vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data, bool *retu) +vlapic_read(struct vlapic *vlapic, int mmio_access, uint64_t offset, + uint64_t *data, bool *retu) { struct LAPIC *lapic = vlapic->apic_page; uint32_t *reg; int i; + /* Ignore MMIO accesses in x2APIC mode */ + if (x2apic(vlapic) && mmio_access) { + VLAPIC_CTR1(vlapic, "MMIO read from offset %#lx in x2APIC mode", + offset); + *data = 0; + goto done; + } + + if (!x2apic(vlapic) && !mmio_access) { + /* + * XXX Generate GP fault for MSR accesses in xAPIC mode + */ + VLAPIC_CTR1(vlapic, "x2APIC MSR read from offset %#lx in " + "xAPIC mode", offset); + *data = 0; + goto done; + } + if (offset > sizeof(*lapic)) { *data = 0; goto done; @@ -1221,7 +1240,8 @@ done: } int -vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data, bool *retu) +vlapic_write(struct vlapic *vlapic, int mmio_access, uint64_t offset, + uint64_t data, bool *retu) { struct LAPIC *lapic = vlapic->apic_page; uint32_t *regptr; @@ -1230,10 +1250,26 @@ vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data, bool *retu) KASSERT((offset & 0xf) == 0 && offset < PAGE_SIZE, ("vlapic_write: invalid offset %#lx", offset)); - VLAPIC_CTR2(vlapic, "vlapic write offset %#x, data %#lx", offset, data); + VLAPIC_CTR2(vlapic, "vlapic write offset %#lx, data %#lx", + offset, data); - if (offset > sizeof(*lapic)) { - return 0; + if (offset > sizeof(*lapic)) + return (0); + + /* Ignore MMIO accesses in x2APIC mode */ + if (x2apic(vlapic) && mmio_access) { + VLAPIC_CTR2(vlapic, "MMIO write of %#lx to offset %#lx " + "in x2APIC mode", data, offset); + return (0); + } + + /* + * XXX Generate GP fault for MSR accesses in xAPIC mode + */ + if (!x2apic(vlapic) && !mmio_access) { + VLAPIC_CTR2(vlapic, "x2APIC MSR write of %#lx to offset %#lx " + "in xAPIC mode", data, offset); + return (0); } retval = 0; @@ -1380,50 +1416,47 @@ vlapic_get_apicbase(struct vlapic *vlapic) return (vlapic->msr_apicbase); } -void +int vlapic_set_apicbase(struct vlapic *vlapic, uint64_t new) { - struct LAPIC *lapic; - enum x2apic_state state; - uint64_t old; - int err; - - err = vm_get_x2apic_state(vlapic->vm, vlapic->vcpuid, &state); - if (err) - panic("vlapic_set_apicbase: err %d fetching x2apic state", err); - if (state == X2APIC_DISABLED) - new &= ~APICBASE_X2APIC; - - old = vlapic->msr_apicbase; - vlapic->msr_apicbase = new; - - /* - * If the vlapic is switching between xAPIC and x2APIC modes then - * reset the mode-dependent registers. - */ - if ((old ^ new) & APICBASE_X2APIC) { - lapic = vlapic->apic_page; - lapic->id = vlapic_get_id(vlapic); - if (x2apic(vlapic)) { - lapic->ldr = x2apic_ldr(vlapic); - lapic->dfr = 0; - } else { - lapic->ldr = 0; - lapic->dfr = 0xffffffff; - } + if (vlapic->msr_apicbase != new) { + VLAPIC_CTR2(vlapic, "Changing APIC_BASE MSR from %#lx to %#lx " + "not supported", vlapic->msr_apicbase, new); + return (-1); } + + return (0); } void vlapic_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) { struct vlapic *vlapic; + struct LAPIC *lapic; vlapic = vm_lapic(vm, vcpuid); if (state == X2APIC_DISABLED) vlapic->msr_apicbase &= ~APICBASE_X2APIC; + else + vlapic->msr_apicbase |= APICBASE_X2APIC; + + /* + * Reset the local APIC registers whose values are mode-dependent. + * + * XXX this works because the APIC mode can be changed only at vcpu + * initialization time. + */ + lapic = vlapic->apic_page; + lapic->id = vlapic_get_id(vlapic); + if (x2apic(vlapic)) { + lapic->ldr = x2apic_ldr(vlapic); + lapic->dfr = 0; + } else { + lapic->ldr = 0; + lapic->dfr = 0xffffffff; + } } void diff --git a/sys/amd64/vmm/io/vlapic.h b/sys/amd64/vmm/io/vlapic.h index d2fc6d9..b215e57 100644 --- a/sys/amd64/vmm/io/vlapic.h +++ b/sys/amd64/vmm/io/vlapic.h @@ -32,10 +32,10 @@ struct vm; enum x2apic_state; -int vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data, - bool *retu); -int vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data, - bool *retu); +int vlapic_write(struct vlapic *vlapic, int mmio_access, uint64_t offset, + uint64_t data, bool *retu); +int vlapic_read(struct vlapic *vlapic, int mmio_access, uint64_t offset, + uint64_t *data, bool *retu); /* * Returns 0 if there is no eligible vector that can be delivered to the @@ -74,7 +74,7 @@ void vlapic_fire_cmci(struct vlapic *vlapic); int vlapic_trigger_lvt(struct vlapic *vlapic, int vector); uint64_t vlapic_get_apicbase(struct vlapic *vlapic); -void vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val); +int vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val); void vlapic_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state s); bool vlapic_enabled(struct vlapic *vlapic); diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c index 4ae6915..80ff5be 100644 --- a/sys/amd64/vmm/vmm.c +++ b/sys/amd64/vmm/vmm.c @@ -206,7 +206,7 @@ vcpu_init(struct vm *vm, uint32_t vcpu_id) vcpu->hostcpu = NOCPU; vcpu->vcpuid = vcpu_id; vcpu->vlapic = VLAPIC_INIT(vm->cookie, vcpu_id); - vm_set_x2apic_state(vm, vcpu_id, X2APIC_ENABLED); + vm_set_x2apic_state(vm, vcpu_id, X2APIC_DISABLED); vcpu->guest_xcr0 = XFEATURE_ENABLED_X87; vcpu->guestfpu = fpu_save_area_alloc(); fpu_save_area_reset(vcpu->guestfpu); diff --git a/sys/amd64/vmm/vmm_lapic.c b/sys/amd64/vmm/vmm_lapic.c index 47e04da..640c779 100644 --- a/sys/amd64/vmm/vmm_lapic.c +++ b/sys/amd64/vmm/vmm_lapic.c @@ -172,7 +172,7 @@ lapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval, bool *retu) error = 0; } else { offset = x2apic_msr_to_regoff(msr); - error = vlapic_read(vlapic, offset, rval, retu); + error = vlapic_read(vlapic, 0, offset, rval, retu); } return (error); @@ -188,11 +188,10 @@ lapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t val, bool *retu) vlapic = vm_lapic(vm, cpu); if (msr == MSR_APICBASE) { - vlapic_set_apicbase(vlapic, val); - error = 0; + error = vlapic_set_apicbase(vlapic, val); } else { offset = x2apic_msr_to_regoff(msr); - error = vlapic_write(vlapic, offset, val, retu); + error = vlapic_write(vlapic, 0, offset, val, retu); } return (error); @@ -216,7 +215,7 @@ lapic_mmio_write(void *vm, int cpu, uint64_t gpa, uint64_t wval, int size, return (EINVAL); vlapic = vm_lapic(vm, cpu); - error = vlapic_write(vlapic, off, wval, arg); + error = vlapic_write(vlapic, 1, off, wval, arg); return (error); } @@ -238,6 +237,6 @@ lapic_mmio_read(void *vm, int cpu, uint64_t gpa, uint64_t *rval, int size, return (EINVAL); vlapic = vm_lapic(vm, cpu); - error = vlapic_read(vlapic, off, rval, arg); + error = vlapic_read(vlapic, 1, off, rval, arg); return (error); } diff --git a/sys/amd64/vmm/x86.c b/sys/amd64/vmm/x86.c index 7ae32ec..d3a0248 100644 --- a/sys/amd64/vmm/x86.c +++ b/sys/amd64/vmm/x86.c @@ -149,6 +149,8 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id, if (x2apic_state != X2APIC_DISABLED) regs[2] |= CPUID2_X2APIC; + else + regs[2] &= ~CPUID2_X2APIC; /* * Only advertise CPUID2_XSAVE in the guest if diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c index c587aef..2218622 100644 --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -84,8 +84,9 @@ char *vmname; int guest_ncpus; static int pincpu = -1; -static int guest_vmexit_on_hlt, guest_vmexit_on_pause, disable_x2apic; +static int guest_vmexit_on_hlt, guest_vmexit_on_pause; static int virtio_msix = 1; +static int x2apic_mode = 0; /* default is xAPIC */ static int strictio; static int strictmsr = 1; @@ -126,7 +127,7 @@ usage(int code) fprintf(stderr, "Usage: %s [-aehwAHIPW] [-g <gdb port>] [-s <pci>]\n" " %*s [-c vcpus] [-p pincpu] [-m mem] [-l <lpc>] <vm>\n" - " -a: local apic is in XAPIC mode (default is X2APIC)\n" + " -a: local apic is in xAPIC mode (deprecated)\n" " -A: create an ACPI table\n" " -g: gdb port\n" " -c: # cpus (default 1)\n" @@ -139,7 +140,8 @@ usage(int code) " -s: <slot,driver,configinfo> PCI slot config\n" " -l: LPC device configuration\n" " -m: memory size in MB\n" - " -w: ignore unimplemented MSRs\n", + " -w: ignore unimplemented MSRs\n" + " -x: local apic is in x2APIC mode\n", progname, (int)strlen(progname), ""); exit(code); @@ -153,13 +155,6 @@ paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len) } int -fbsdrun_disable_x2apic(void) -{ - - return (disable_x2apic); -} - -int fbsdrun_vmexit_on_pause(void) { @@ -570,10 +565,10 @@ fbsdrun_set_capabilities(struct vmctx *ctx, int cpu) handler[VM_EXITCODE_PAUSE] = vmexit_pause; } - if (fbsdrun_disable_x2apic()) - err = vm_set_x2apic_state(ctx, cpu, X2APIC_DISABLED); - else + if (x2apic_mode) err = vm_set_x2apic_state(ctx, cpu, X2APIC_ENABLED); + else + err = vm_set_x2apic_state(ctx, cpu, X2APIC_DISABLED); if (err) { fprintf(stderr, "Unable to set x2apic state (%d)\n", err); @@ -598,10 +593,10 @@ main(int argc, char *argv[]) guest_ncpus = 1; memsize = 256 * MB; - while ((c = getopt(argc, argv, "abehwAHIPWp:g:c:s:m:l:")) != -1) { + while ((c = getopt(argc, argv, "abehwxAHIPWp:g:c:s:m:l:")) != -1) { switch (c) { case 'a': - disable_x2apic = 1; + x2apic_mode = 0; break; case 'A': acpi = 1; @@ -658,6 +653,9 @@ main(int argc, char *argv[]) case 'W': virtio_msix = 0; break; + case 'x': + x2apic_mode = 1; + break; case 'h': usage(0); default: |