svn commit: r259205 - in head/sys/amd64/vmm: . intel io
Neel Natu
neel at FreeBSD.org
Tue Dec 10 22:56:53 UTC 2013
Author: neel
Date: Tue Dec 10 22:56:51 2013
New Revision: 259205
URL: http://svnweb.freebsd.org/changeset/base/259205
Log:
Fix x2apic support in bhyve.
When the guest is bringing up the APs in the x2APIC mode a write to the
ICR register will now trigger a return to userspace with an exitcode of
VM_EXITCODE_SPINUP_AP. This gets SMP guests working again with x2APIC.
Change the vlapic timer lock to be a spinlock because the vlapic can be
accessed from within a critical section (vm run loop) when guest is using
x2apic mode.
Reviewed by: grehan@
Modified:
head/sys/amd64/vmm/intel/vmx.c
head/sys/amd64/vmm/io/vlapic.c
head/sys/amd64/vmm/io/vlapic.h
head/sys/amd64/vmm/vmm.c
head/sys/amd64/vmm/vmm_lapic.c
head/sys/amd64/vmm/vmm_lapic.h
head/sys/amd64/vmm/vmm_msr.c
head/sys/amd64/vmm/vmm_msr.h
Modified: head/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- head/sys/amd64/vmm/intel/vmx.c Tue Dec 10 22:55:22 2013 (r259204)
+++ head/sys/amd64/vmm/intel/vmx.c Tue Dec 10 22:56:51 2013 (r259205)
@@ -1337,6 +1337,7 @@ vmx_exit_process(struct vmx *vmx, int vc
struct vmxctx *vmxctx;
uint32_t eax, ecx, edx, idtvec_info, idtvec_err, reason;
uint64_t qual, gpa, rflags;
+ bool retu;
handled = 0;
vmcs = &vmx->vmcs[vcpu];
@@ -1382,27 +1383,39 @@ vmx_exit_process(struct vmx *vmx, int vc
break;
case EXIT_REASON_RDMSR:
vmm_stat_incr(vmx->vm, vcpu, VMEXIT_RDMSR, 1);
+ retu = false;
ecx = vmxctx->guest_rcx;
- error = emulate_rdmsr(vmx->vm, vcpu, ecx);
+ error = emulate_rdmsr(vmx->vm, vcpu, ecx, &retu);
if (error) {
vmexit->exitcode = VM_EXITCODE_RDMSR;
vmexit->u.msr.code = ecx;
- } else
+ } else if (!retu) {
handled = 1;
+ } else {
+ /* Return to userspace with a valid exitcode */
+ KASSERT(vmexit->exitcode != VM_EXITCODE_BOGUS,
+ ("emulate_wrmsr retu with bogus exitcode"));
+ }
break;
case EXIT_REASON_WRMSR:
vmm_stat_incr(vmx->vm, vcpu, VMEXIT_WRMSR, 1);
+ retu = false;
eax = vmxctx->guest_rax;
ecx = vmxctx->guest_rcx;
edx = vmxctx->guest_rdx;
error = emulate_wrmsr(vmx->vm, vcpu, ecx,
- (uint64_t)edx << 32 | eax);
+ (uint64_t)edx << 32 | eax, &retu);
if (error) {
vmexit->exitcode = VM_EXITCODE_WRMSR;
vmexit->u.msr.code = ecx;
vmexit->u.msr.wval = (uint64_t)edx << 32 | eax;
- } else
+ } else if (!retu) {
handled = 1;
+ } else {
+ /* Return to userspace with a valid exitcode */
+ KASSERT(vmexit->exitcode != VM_EXITCODE_BOGUS,
+ ("emulate_wrmsr retu with bogus exitcode"));
+ }
break;
case EXIT_REASON_HLT:
vmm_stat_incr(vmx->vm, vcpu, VMEXIT_HLT, 1);
Modified: head/sys/amd64/vmm/io/vlapic.c
==============================================================================
--- head/sys/amd64/vmm/io/vlapic.c Tue Dec 10 22:55:22 2013 (r259204)
+++ head/sys/amd64/vmm/io/vlapic.c Tue Dec 10 22:56:51 2013 (r259205)
@@ -139,8 +139,8 @@ struct vlapic {
* Note that the vlapic_callout_handler() does not write to any of these
* registers so they can be safely read from the vcpu context without locking.
*/
-#define VLAPIC_TIMER_LOCK(vlapic) mtx_lock(&((vlapic)->timer_mtx))
-#define VLAPIC_TIMER_UNLOCK(vlapic) mtx_unlock(&((vlapic)->timer_mtx))
+#define VLAPIC_TIMER_LOCK(vlapic) mtx_lock_spin(&((vlapic)->timer_mtx))
+#define VLAPIC_TIMER_UNLOCK(vlapic) mtx_unlock_spin(&((vlapic)->timer_mtx))
#define VLAPIC_TIMER_LOCKED(vlapic) mtx_owned(&((vlapic)->timer_mtx))
#define VLAPIC_BUS_FREQ tsc_freq
@@ -613,7 +613,7 @@ vlapic_set_icr_timer(struct vlapic *vlap
static VMM_STAT_ARRAY(IPIS_SENT, VM_MAXCPU, "ipis sent to vcpu");
static int
-lapic_process_icr(struct vlapic *vlapic, uint64_t icrval)
+lapic_process_icr(struct vlapic *vlapic, uint64_t icrval, bool *retu)
{
int i;
cpuset_t dmask;
@@ -688,17 +688,18 @@ lapic_process_icr(struct vlapic *vlapic,
if (vlapic2->boot_state != BS_SIPI)
return (0);
- vmexit = vm_exitinfo(vlapic->vm, vlapic->vcpuid);
- vmexit->exitcode = VM_EXITCODE_SPINUP_AP;
- vmexit->u.spinup_ap.vcpu = dest;
- vmexit->u.spinup_ap.rip = vec << PAGE_SHIFT;
-
/*
* XXX this assumes that the startup IPI always succeeds
*/
vlapic2->boot_state = BS_RUNNING;
vm_activate_cpu(vlapic2->vm, dest);
+ *retu = true;
+ vmexit = vm_exitinfo(vlapic->vm, vlapic->vcpuid);
+ vmexit->exitcode = VM_EXITCODE_SPINUP_AP;
+ vmexit->u.spinup_ap.vcpu = dest;
+ vmexit->u.spinup_ap.rip = vec << PAGE_SHIFT;
+
return (0);
}
}
@@ -804,7 +805,7 @@ lapic_set_svr(struct vlapic *vlapic, uin
}
int
-vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data)
+vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data, bool *retu)
{
struct LAPIC *lapic = &vlapic->apic;
uint32_t *reg;
@@ -895,7 +896,7 @@ done:
}
int
-vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data)
+vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data, bool *retu)
{
struct LAPIC *lapic = &vlapic->apic;
int retval;
@@ -931,7 +932,7 @@ vlapic_write(struct vlapic *vlapic, uint
data &= 0xffffffff;
data |= (uint64_t)lapic->icr_hi << 32;
}
- retval = lapic_process_icr(vlapic, data);
+ retval = lapic_process_icr(vlapic, data, retu);
break;
case APIC_OFFSET_ICR_HI:
if (!x2apic(vlapic)) {
@@ -978,7 +979,14 @@ vlapic_init(struct vm *vm, int vcpuid)
vlapic->vm = vm;
vlapic->vcpuid = vcpuid;
- mtx_init(&vlapic->timer_mtx, "vlapic timer mtx", NULL, MTX_DEF);
+ /*
+ * If the vlapic is configured in x2apic mode then it will be
+ * accessed in the critical section via the MSR emulation code.
+ *
+ * Therefore the timer mutex must be a spinlock because blockable
+ * mutexes cannot be acquired in a critical section.
+ */
+ mtx_init(&vlapic->timer_mtx, "vlapic timer mtx", NULL, MTX_SPIN);
callout_init(&vlapic->callout, 1);
vlapic->msr_apicbase = DEFAULT_APIC_BASE | APICBASE_ENABLED;
Modified: head/sys/amd64/vmm/io/vlapic.h
==============================================================================
--- head/sys/amd64/vmm/io/vlapic.h Tue Dec 10 22:55:22 2013 (r259204)
+++ head/sys/amd64/vmm/io/vlapic.h Tue Dec 10 22:56:51 2013 (r259205)
@@ -90,8 +90,10 @@ enum x2apic_state;
struct vlapic *vlapic_init(struct vm *vm, int vcpuid);
void vlapic_cleanup(struct vlapic *vlapic);
-int vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data);
-int vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data);
+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_pending_intr(struct vlapic *vlapic);
void vlapic_intr_accepted(struct vlapic *vlapic, int vector);
void vlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level);
Modified: head/sys/amd64/vmm/vmm.c
==============================================================================
--- head/sys/amd64/vmm/vmm.c Tue Dec 10 22:55:22 2013 (r259204)
+++ head/sys/amd64/vmm/vmm.c Tue Dec 10 22:56:51 2013 (r259205)
@@ -860,8 +860,7 @@ vcpu_require_state_locked(struct vcpu *v
* Emulate a guest 'hlt' by sleeping until the vcpu is ready to run.
*/
static int
-vm_handle_hlt(struct vm *vm, int vcpuid, boolean_t intr_disabled,
- boolean_t *retu)
+vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu)
{
struct vm_exit *vmexit;
struct vcpu *vcpu;
@@ -894,7 +893,7 @@ vm_handle_hlt(struct vm *vm, int vcpuid,
* Spindown the vcpu if the apic is disabled and it
* had entered the halted state.
*/
- *retu = TRUE;
+ *retu = true;
vmexit = vm_exitinfo(vm, vcpuid);
vmexit->exitcode = VM_EXITCODE_SPINDOWN_CPU;
VCPU_CTR0(vm, vcpuid, "spinning down cpu");
@@ -908,7 +907,7 @@ vm_handle_hlt(struct vm *vm, int vcpuid,
}
static int
-vm_handle_paging(struct vm *vm, int vcpuid, boolean_t *retu)
+vm_handle_paging(struct vm *vm, int vcpuid, bool *retu)
{
int rv, ftype;
struct vm_map *map;
@@ -946,7 +945,7 @@ done:
}
static int
-vm_handle_inst_emul(struct vm *vm, int vcpuid, boolean_t *retu)
+vm_handle_inst_emul(struct vm *vm, int vcpuid, bool *retu)
{
struct vie *vie;
struct vcpu *vcpu;
@@ -987,15 +986,12 @@ vm_handle_inst_emul(struct vm *vm, int v
mread = vhpet_mmio_read;
mwrite = vhpet_mmio_write;
} else {
- *retu = TRUE;
+ *retu = true;
return (0);
}
- error = vmm_emulate_instruction(vm, vcpuid, gpa, vie, mread, mwrite, 0);
-
- /* return to userland to spin up the AP */
- if (error == 0 && vme->exitcode == VM_EXITCODE_SPINUP_AP)
- *retu = TRUE;
+ error = vmm_emulate_instruction(vm, vcpuid, gpa, vie, mread, mwrite,
+ retu);
return (error);
}
@@ -1008,7 +1004,7 @@ vm_run(struct vm *vm, struct vm_run *vmr
struct pcb *pcb;
uint64_t tscval, rip;
struct vm_exit *vme;
- boolean_t retu, intr_disabled;
+ bool retu, intr_disabled;
pmap_t pmap;
vcpuid = vmrun->cpuid;
@@ -1048,13 +1044,10 @@ restart:
critical_exit();
if (error == 0) {
- retu = FALSE;
+ retu = false;
switch (vme->exitcode) {
case VM_EXITCODE_HLT:
- if ((vme->u.hlt.rflags & PSL_I) == 0)
- intr_disabled = TRUE;
- else
- intr_disabled = FALSE;
+ intr_disabled = ((vme->u.hlt.rflags & PSL_I) == 0);
error = vm_handle_hlt(vm, vcpuid, intr_disabled, &retu);
break;
case VM_EXITCODE_PAGING:
@@ -1064,12 +1057,12 @@ restart:
error = vm_handle_inst_emul(vm, vcpuid, &retu);
break;
default:
- retu = TRUE; /* handled in userland */
+ retu = true; /* handled in userland */
break;
}
}
- if (error == 0 && retu == FALSE) {
+ if (error == 0 && retu == false) {
rip = vme->rip + vme->inst_length;
goto restart;
}
Modified: head/sys/amd64/vmm/vmm_lapic.c
==============================================================================
--- head/sys/amd64/vmm/vmm_lapic.c Tue Dec 10 22:55:22 2013 (r259204)
+++ head/sys/amd64/vmm/vmm_lapic.c Tue Dec 10 22:56:51 2013 (r259205)
@@ -107,7 +107,7 @@ lapic_msr(u_int msr)
}
int
-lapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval)
+lapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval, bool *retu)
{
int error;
u_int offset;
@@ -120,14 +120,14 @@ lapic_rdmsr(struct vm *vm, int cpu, u_in
error = 0;
} else {
offset = x2apic_msr_to_regoff(msr);
- error = vlapic_read(vlapic, offset, rval);
+ error = vlapic_read(vlapic, offset, rval, retu);
}
return (error);
}
int
-lapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t val)
+lapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t val, bool *retu)
{
int error;
u_int offset;
@@ -140,7 +140,7 @@ lapic_wrmsr(struct vm *vm, int cpu, u_in
error = 0;
} else {
offset = x2apic_msr_to_regoff(msr);
- error = vlapic_write(vlapic, offset, val);
+ error = vlapic_write(vlapic, offset, val, retu);
}
return (error);
@@ -164,7 +164,7 @@ lapic_mmio_write(void *vm, int cpu, uint
return (EINVAL);
vlapic = vm_lapic(vm, cpu);
- error = vlapic_write(vlapic, off, wval);
+ error = vlapic_write(vlapic, off, wval, arg);
return (error);
}
@@ -186,6 +186,6 @@ lapic_mmio_read(void *vm, int cpu, uint6
return (EINVAL);
vlapic = vm_lapic(vm, cpu);
- error = vlapic_read(vlapic, off, rval);
+ error = vlapic_read(vlapic, off, rval, arg);
return (error);
}
Modified: head/sys/amd64/vmm/vmm_lapic.h
==============================================================================
--- head/sys/amd64/vmm/vmm_lapic.h Tue Dec 10 22:55:22 2013 (r259204)
+++ head/sys/amd64/vmm/vmm_lapic.h Tue Dec 10 22:56:51 2013 (r259205)
@@ -32,8 +32,10 @@
struct vm;
boolean_t lapic_msr(u_int num);
-int lapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval);
-int lapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t wval);
+int lapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval,
+ bool *retu);
+int lapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t wval,
+ bool *retu);
int lapic_mmio_read(void *vm, int cpu, uint64_t gpa,
uint64_t *rval, int size, void *arg);
Modified: head/sys/amd64/vmm/vmm_msr.c
==============================================================================
--- head/sys/amd64/vmm/vmm_msr.c Tue Dec 10 22:55:22 2013 (r259204)
+++ head/sys/amd64/vmm/vmm_msr.c Tue Dec 10 22:56:51 2013 (r259205)
@@ -154,13 +154,13 @@ msr_num_to_idx(u_int num)
}
int
-emulate_wrmsr(struct vm *vm, int cpu, u_int num, uint64_t val)
+emulate_wrmsr(struct vm *vm, int cpu, u_int num, uint64_t val, bool *retu)
{
int idx;
uint64_t *guest_msrs;
if (lapic_msr(num))
- return (lapic_wrmsr(vm, cpu, num, val));
+ return (lapic_wrmsr(vm, cpu, num, val, retu));
idx = msr_num_to_idx(num);
if (idx < 0 || invalid_msr(idx))
@@ -181,14 +181,14 @@ emulate_wrmsr(struct vm *vm, int cpu, u_
}
int
-emulate_rdmsr(struct vm *vm, int cpu, u_int num)
+emulate_rdmsr(struct vm *vm, int cpu, u_int num, bool *retu)
{
int error, idx;
uint32_t eax, edx;
uint64_t result, *guest_msrs;
if (lapic_msr(num)) {
- error = lapic_rdmsr(vm, cpu, num, &result);
+ error = lapic_rdmsr(vm, cpu, num, &result, retu);
goto done;
}
Modified: head/sys/amd64/vmm/vmm_msr.h
==============================================================================
--- head/sys/amd64/vmm/vmm_msr.h Tue Dec 10 22:55:22 2013 (r259204)
+++ head/sys/amd64/vmm/vmm_msr.h Tue Dec 10 22:56:51 2013 (r259205)
@@ -33,8 +33,9 @@
struct vm;
void vmm_msr_init(void);
-int emulate_wrmsr(struct vm *vm, int vcpu, u_int msr, uint64_t val);
-int emulate_rdmsr(struct vm *vm, int vcpu, u_int msr);
+int emulate_wrmsr(struct vm *vm, int vcpu, u_int msr, uint64_t val,
+ bool *retu);
+int emulate_rdmsr(struct vm *vm, int vcpu, u_int msr, bool *retu);
void guest_msrs_init(struct vm *vm, int cpu);
void guest_msr_valid(int msr);
void restore_host_msrs(struct vm *vm, int cpu);
More information about the svn-src-head
mailing list