From 938445ea34fbdbcdf824e5bd72902e8b7b306214 Mon Sep 17 00:00:00 2001 From: Camilo Aguilar Date: Fri, 8 Jan 2016 15:17:04 -0500 Subject: [PATCH] Fix non-deterministic delays when accessing a vcpu in "running" or "sleeping" state. This is done by forcing the vcpu to transition to "idle" by returning to userspace with an exit code of VM_EXITCODE_REQIDLE. Ported from bhyve. Authored by @neelnatu --- include/xhyve/vmm/vmm.h | 25 +++++-- include/xhyve/vmm/vmm_common.h | 1 + include/xhyve/vmm/vmm_ktr.h | 20 +++--- include/xhyve/vmm/vmm_stat.h | 7 +- src/vmm/intel/vmx.c | 20 +++--- src/vmm/vmm.c | 126 +++++++++++++++++++++++++-------- src/vmm/vmm_stat.c | 1 + src/xhyve.c | 14 +++- 8 files changed, 157 insertions(+), 57 deletions(-) diff --git a/include/xhyve/vmm/vmm.h b/include/xhyve/vmm/vmm.h index 7b72e8a..61022c3 100644 --- a/include/xhyve/vmm/vmm.h +++ b/include/xhyve/vmm/vmm.h @@ -62,12 +62,18 @@ struct vm_object; struct vm_guest_paging; struct pmap; +struct vm_eventinfo { + void *rptr; /* rendezvous cookie */ + int *sptr; /* suspend cookie */ + int *iptr; /* reqidle cookie */ +}; + typedef int (*vmm_init_func_t)(void); typedef int (*vmm_cleanup_func_t)(void); typedef void *(*vmi_vm_init_func_t)(struct vm *vm); typedef int (*vmi_vcpu_init_func_t)(void *vmi, int vcpu); typedef int (*vmi_run_func_t)(void *vmi, int vcpu, register_t rip, - void *rendezvous_cookie, void *suspend_cookie); + struct vm_eventinfo *info); typedef void (*vmi_vm_cleanup_func_t)(void *vmi); typedef void (*vmi_vcpu_cleanup_func_t)(void *vmi, int vcpu); typedef int (*vmi_get_register_t)(void *vmi, int vcpu, int num, @@ -145,6 +151,7 @@ int vm_activate_cpu(struct vm *vm, int vcpu); struct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid); void vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip); void vm_exit_rendezvous(struct vm *vm, int vcpuid, uint64_t rip); +void vm_exit_reqidle(struct vm *vm, int vcpuid, uint64_t rip); /* * Rendezvous all vcpus specified in 'dest' and execute 'func(arg)'. @@ -167,17 +174,21 @@ cpuset_t vm_active_cpus(struct vm *vm); cpuset_t vm_suspended_cpus(struct vm *vm); static __inline int -vcpu_rendezvous_pending(void *rendezvous_cookie) +vcpu_rendezvous_pending(struct vm_eventinfo *info) { - - return (*(uintptr_t *)rendezvous_cookie != 0); + return (*((uintptr_t *)(info->rptr)) != 0); } static __inline int -vcpu_suspended(void *suspend_cookie) +vcpu_suspended(struct vm_eventinfo *info) { + return (*info->sptr); +} - return (*(int *)suspend_cookie); +static __inline int +vcpu_reqidle(struct vm_eventinfo *info) +{ + return (*info->iptr); } enum vcpu_state { @@ -256,7 +267,7 @@ struct vm_copyinfo { /* * Set up 'copyinfo[]' to copy to/from guest linear address space starting * at 'gla' and 'len' bytes long. The 'prot' should be set to PROT_READ for - * a copyin or PROT_WRITE for a copyout. + * a copyin or PROT_WRITE for a copyout. * * retval is_fault Intepretation * 0 0 Success diff --git a/include/xhyve/vmm/vmm_common.h b/include/xhyve/vmm/vmm_common.h index f5c5326..1df6bf7 100644 --- a/include/xhyve/vmm/vmm_common.h +++ b/include/xhyve/vmm/vmm_common.h @@ -143,6 +143,7 @@ enum vm_exitcode { VM_EXITCODE_INOUT, VM_EXITCODE_VMX, VM_EXITCODE_BOGUS, + VM_EXITCODE_REQIDLE, VM_EXITCODE_RDMSR, VM_EXITCODE_WRMSR, VM_EXITCODE_HLT, diff --git a/include/xhyve/vmm/vmm_ktr.h b/include/xhyve/vmm/vmm_ktr.h index acfe5b6..293909e 100644 --- a/include/xhyve/vmm/vmm_ktr.h +++ b/include/xhyve/vmm/vmm_ktr.h @@ -41,32 +41,32 @@ struct vm; extern const char *vm_name(struct vm *vm); #define VCPU_CTR0(vm, vcpuid, format) \ -vmmtrace("vm %s[%d]: " format "\n", vm_name((vm)), (vcpuid)) +vmmtrace("vm %s[%d]: " format "\r\n", vm_name((vm)), (vcpuid)) #define VCPU_CTR1(vm, vcpuid, format, p1) \ -vmmtrace("vm %s[%d]: " format "\n", vm_name((vm)), (vcpuid), (p1)) +vmmtrace("vm %s[%d]: " format "\r\n", vm_name((vm)), (vcpuid), (p1)) #define VCPU_CTR2(vm, vcpuid, format, p1, p2) \ -vmmtrace("vm %s[%d]: " format "\n", vm_name((vm)), (vcpuid), (p1), (p2)) +vmmtrace("vm %s[%d]: " format "\r\n", vm_name((vm)), (vcpuid), (p1), (p2)) #define VCPU_CTR3(vm, vcpuid, format, p1, p2, p3) \ -vmmtrace("vm %s[%d]: " format "\n", vm_name((vm)), (vcpuid), (p1), (p2), (p3)) +vmmtrace("vm %s[%d]: " format "\r\n", vm_name((vm)), (vcpuid), (p1), (p2), (p3)) #define VCPU_CTR4(vm, vcpuid, format, p1, p2, p3, p4) \ -vmmtrace("vm %s[%d]: " format "\n", vm_name((vm)), (vcpuid), \ +vmmtrace("vm %s[%d]: " format "\r\n", vm_name((vm)), (vcpuid), \ (p1), (p2), (p3), (p4)) #define VM_CTR0(vm, format) \ -vmmtrace("vm %s: " format "\n", vm_name((vm))) +vmmtrace("vm %s: " format "\r\n", vm_name((vm))) #define VM_CTR1(vm, format, p1) \ -vmmtrace("vm %s: " format "\n", vm_name((vm)), (p1)) +vmmtrace("vm %s: " format "\r\n", vm_name((vm)), (p1)) #define VM_CTR2(vm, format, p1, p2) \ -vmmtrace("vm %s: " format "\n", vm_name((vm)), (p1), (p2)) +vmmtrace("vm %s: " format "\r\n", vm_name((vm)), (p1), (p2)) #define VM_CTR3(vm, format, p1, p2, p3) \ -vmmtrace("vm %s: " format "\n", vm_name((vm)), (p1), (p2), (p3)) +vmmtrace("vm %s: " format "\r\n", vm_name((vm)), (p1), (p2), (p3)) #define VM_CTR4(vm, format, p1, p2, p3, p4) \ -vmmtrace("vm %s: " format "\n", vm_name((vm)), (p1), (p2), (p3), (p4)) +vmmtrace("vm %s: " format "\r\n", vm_name((vm)), (p1), (p2), (p3), (p4)) diff --git a/include/xhyve/vmm/vmm_stat.h b/include/xhyve/vmm/vmm_stat.h index dbd1dc9..442de5c 100644 --- a/include/xhyve/vmm/vmm_stat.h +++ b/include/xhyve/vmm/vmm_stat.h @@ -101,7 +101,7 @@ vmm_stat_array_incr(struct vm *vm, int vcpu, struct vmm_stat_type *vst, { #ifdef XHYVE_CONFIG_STATS uint64_t *stats; - + stats = vcpu_stats(vm, vcpu); if (vst->index >= 0 && statidx < vst->nelems) @@ -121,7 +121,7 @@ vmm_stat_array_set(struct vm *vm, int vcpu, struct vmm_stat_type *vst, { #ifdef XHYVE_CONFIG_STATS uint64_t *stats; - + stats = vcpu_stats(vm, vcpu); if (vst->index >= 0 && statidx < vst->nelems) @@ -134,7 +134,7 @@ vmm_stat_array_set(struct vm *vm, int vcpu, struct vmm_stat_type *vst, (void) val; #endif } - + static void __inline vmm_stat_incr(struct vm *vm, int vcpu, struct vmm_stat_type *vst, uint64_t x) { @@ -183,3 +183,4 @@ VMM_STAT_DECLARE(VMEXIT_ASTPENDING); VMM_STAT_DECLARE(VMEXIT_USERSPACE); VMM_STAT_DECLARE(VMEXIT_RENDEZVOUS); VMM_STAT_DECLARE(VMEXIT_EXCEPTION); +VMM_STAT_DECLARE(VMEXIT_REQIDLE); diff --git a/src/vmm/intel/vmx.c b/src/vmm/intel/vmx.c index f4f2bb0..4b7eabb 100644 --- a/src/vmm/intel/vmx.c +++ b/src/vmm/intel/vmx.c @@ -415,7 +415,7 @@ exit_reason_to_str(int reason) // for (i = 0; i < 8; i++) // error += guest_msr_ro(vmx, MSR_APIC_TMR0 + i); - + // for (i = 0; i < 8; i++) // error += guest_msr_ro(vmx, MSR_APIC_IRR0 + i); @@ -670,7 +670,7 @@ vmx_handle_cpuid(struct vm *vm, int vcpuid) { uint32_t eax, ebx, ecx, edx; int error; - + eax = (uint32_t) reg_read(vcpuid, HV_X86_RAX); ebx = (uint32_t) reg_read(vcpuid, HV_X86_RBX); ecx = (uint32_t) reg_read(vcpuid, HV_X86_RCX); @@ -2129,8 +2129,7 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) } static int -vmx_run(void *arg, int vcpu, register_t rip, void *rendezvous_cookie, - void *suspend_cookie) +vmx_run(void *arg, int vcpu, register_t rip, struct vm_eventinfo *evinfo) { int handled; struct vmx *vmx; @@ -2161,16 +2160,21 @@ vmx_run(void *arg, int vcpu, register_t rip, void *rendezvous_cookie, * vmx_inject_interrupts() can suspend the vcpu due to a * triple fault. */ - if (vcpu_suspended(suspend_cookie)) { + if (vcpu_suspended(evinfo)) { vm_exit_suspended(vmx->vm, vcpu, ((uint64_t) rip)); break; } - if (vcpu_rendezvous_pending(rendezvous_cookie)) { + if (vcpu_rendezvous_pending(evinfo)) { vm_exit_rendezvous(vmx->vm, vcpu, ((uint64_t) rip)); break; } + if (vcpu_reqidle(evinfo)) { + vm_exit_reqidle(vmx->vm, vcpu, ((uint64_t) rip)); + break; + } + vmx_run_trace(vmx, vcpu); hvr = hv_vcpu_run((hv_vcpuid_t) vcpu); /* Collect some information for VM exit processing */ @@ -2382,7 +2386,7 @@ vmx_setreg(void *arg, int vcpu, int reg, uint64_t val) if (shadow > 0) { /* * Store the unmodified value in the shadow - */ + */ error = vmcs_setreg(vcpu, VMCS_IDENT(shadow), val); } @@ -2698,7 +2702,7 @@ vmx_vlapic_init(void *arg, int vcpuid) struct vmx *vmx; struct vlapic *vlapic; struct vlapic_vtx *vlapic_vtx; - + vmx = arg; vlapic = malloc(sizeof(struct vlapic_vtx)); diff --git a/src/vmm/vmm.c b/src/vmm/vmm.c index bf25c3b..01b66fe 100644 --- a/src/vmm/vmm.c +++ b/src/vmm/vmm.c @@ -75,6 +75,7 @@ struct vcpu { pthread_mutex_t vcpu_sleep_mtx; pthread_cond_t vcpu_sleep_cnd; enum vcpu_state state; /* (o) vcpu state */ + int reqidle; /* (i) request vcpu to idle */ struct vlapic *vlapic; /* (i) APIC device model */ enum x2apic_state x2apic_state; /* (i) APIC mode */ uint64_t exitintinfo; /* (i) events pending at VM exit */ @@ -144,8 +145,8 @@ static struct vmm_ops *ops; (*ops->vm_init)(vmi) #define VCPU_INIT(vmi, vcpu) \ (*ops->vcpu_init)(vmi, vcpu) -#define VMRUN(vmi, vcpu, rip, rptr, sptr) \ - (*ops->vmrun)(vmi, vcpu, rip, rptr, sptr) +#define VMRUN(vmi, vcpu, rip, evinfo) \ + (*ops->vmrun)(vmi, vcpu, rip, evinfo) #define VM_CLEANUP(vmi) \ (*ops->vm_cleanup)(vmi) #define VCPU_CLEANUP(vmi, vcpu) \ @@ -179,6 +180,24 @@ static struct vmm_ops *ops; static int halt_detection_enabled = 1; static int trace_guest_exceptions = 0; +static void vcpu_notify_event_locked(struct vcpu *vcpu, int vcpuid, bool lapic_intr); + +static const char * +vcpu_state2str(enum vcpu_state state) +{ + switch (state) { + case VCPU_IDLE: + return ("idle"); + case VCPU_FROZEN: + return ("frozen"); + case VCPU_RUNNING: + return ("running"); + case VCPU_SLEEPING: + return ("sleeping"); + } + return ("unknown"); +} + static void vcpu_cleanup(struct vm *vm, int i, bool destroy) { @@ -186,7 +205,7 @@ vcpu_cleanup(struct vm *vm, int i, bool destroy) VLAPIC_CLEANUP(vm->cookie, vcpu->vlapic); if (destroy) { - vmm_stat_free(vcpu->stats); + vmm_stat_free(vcpu->stats); } } @@ -197,7 +216,7 @@ vcpu_init(struct vm *vm, int vcpu_id, bool create) KASSERT(vcpu_id >= 0 && vcpu_id < VM_MAXCPU, ("vcpu_init: invalid vcpu %d", vcpu_id)); - + vcpu = &vm->vcpu[vcpu_id]; if (create) { @@ -212,6 +231,7 @@ vcpu_init(struct vm *vm, int vcpu_id, bool create) vcpu->vlapic = VLAPIC_INIT(vm->cookie, vcpu_id); vm_set_x2apic_state(vm, vcpu_id, X2APIC_DISABLED); + vcpu->reqidle = 0; vcpu->exitintinfo = 0; vcpu->nmi_pending = 0; vcpu->extint_pending = 0; @@ -263,7 +283,7 @@ vmm_init(void) error = vmm_mem_init(); if (error) return (error); - + ops = &vmm_ops_intel; error = VMM_INIT(); @@ -437,7 +457,7 @@ vm_malloc(struct vm *vm, uint64_t gpa, size_t len) if ((gpa & XHYVE_PAGE_MASK) || (len & XHYVE_PAGE_MASK) || len == 0) return (EINVAL); - + available = allocated = 0; g = gpa; while (g < gpa + len) { @@ -629,10 +649,13 @@ vm_set_seg_desc(struct vm *vm, int vcpu, int reg, // static VMM_STAT(VCPU_IDLE_TICKS, "number of ticks vcpu was idle"); static int -vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate, - bool from_idle) +vcpu_set_state_locked(struct vm *vm, int vcpuid, enum vcpu_state newstate, + bool from_idle) { + struct vcpu *vcpu; int error; + vcpu = &vm->vcpu[vcpuid]; + const struct timespec ts = {.tv_sec = 1, .tv_nsec = 0}; /* 1 second */ /* @@ -642,11 +665,17 @@ vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate, */ if (from_idle) { while (vcpu->state != VCPU_IDLE) { + + pthread_mutex_lock(&vcpu->state_sleep_mtx); vcpu_unlock(vcpu); pthread_cond_timedwait_relative_np(&vcpu->state_sleep_cnd, &vcpu->state_sleep_mtx, &ts); vcpu_lock(vcpu); + vcpu->reqidle = 1; + vcpu_notify_event_locked(vcpu, vcpuid, false); + VCPU_CTR1(vm, vcpuid, "vcpu state change from %s to " + "idle requested", vcpu_state2str(vcpu->state)); pthread_mutex_unlock(&vcpu->state_sleep_mtx); //msleep_spin(&vcpu->state, &vcpu->mtx, "vmstat", hz); } @@ -675,6 +704,9 @@ vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate, if (error) return (EBUSY); + VCPU_CTR2(vm, vcpuid, "vcpu state changed from %s to %s", + vcpu_state2str(vcpu->state), vcpu_state2str(newstate)); + vcpu->state = newstate; if (newstate == VCPU_IDLE) @@ -694,11 +726,11 @@ vcpu_require_state(struct vm *vm, int vcpuid, enum vcpu_state newstate) } static void -vcpu_require_state_locked(struct vcpu *vcpu, enum vcpu_state newstate) +vcpu_require_state_locked(struct vm *vm, int vcpuid, enum vcpu_state newstate) { int error; - if ((error = vcpu_set_state_locked(vcpu, newstate, false)) != 0) + if ((error = vcpu_set_state_locked(vm, vcpuid, newstate, false)) != 0) xhyve_abort("Error %d setting state to %d", error, newstate); } @@ -787,7 +819,7 @@ vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled) * vcpu returned from VMRUN() and before it acquired the * vcpu lock above. */ - if (vm->rendezvous_func != NULL || vm->suspend) + if (vm->rendezvous_func != NULL || vm->suspend || vcpu->reqidle) break; if (vm_nmi_pending(vm, vcpuid)) break; @@ -820,7 +852,7 @@ vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled) } //t = ticks; - vcpu_require_state_locked(vcpu, VCPU_SLEEPING); + vcpu_require_state_locked(vm, vcpuid, VCPU_SLEEPING); /* * XXX msleep_spin() cannot be interrupted by signals so * wake up periodically to check pending signals. @@ -832,7 +864,7 @@ vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled) vcpu_lock(vcpu); pthread_mutex_unlock(&vcpu->vcpu_sleep_mtx); //msleep_spin(vcpu, &vcpu->mtx, wmesg, hz); - vcpu_require_state_locked(vcpu, VCPU_FROZEN); + vcpu_require_state_locked(vm, vcpuid, VCPU_FROZEN); //vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t); } @@ -906,7 +938,7 @@ vm_handle_inst_emul(struct vm *vm, int vcpuid, bool *retu) vme->inst_length = vie->num_processed; vcpu->nextrip += vie->num_processed; } - + /* return to userland unless this is an in-kernel emulated device */ if (gpa >= DEFAULT_APIC_BASE && gpa < DEFAULT_APIC_BASE + XHYVE_PAGE_SIZE) { mread = lapic_mmio_read; @@ -956,7 +988,7 @@ vm_handle_suspend(struct vm *vm, int vcpuid, bool *retu) if (vm->rendezvous_func == NULL) { VCPU_CTR0(vm, vcpuid, "Sleeping during suspend"); - vcpu_require_state_locked(vcpu, VCPU_SLEEPING); + vcpu_require_state_locked(vm, vcpuid, VCPU_SLEEPING); pthread_mutex_lock(&vcpu->vcpu_sleep_mtx); vcpu_unlock(vcpu); @@ -966,7 +998,7 @@ vm_handle_suspend(struct vm *vm, int vcpuid, bool *retu) pthread_mutex_unlock(&vcpu->vcpu_sleep_mtx); //msleep_spin(vcpu, &vcpu->mtx, "vmsusp", hz); - vcpu_require_state_locked(vcpu, VCPU_FROZEN); + vcpu_require_state_locked(vm, vcpuid, VCPU_FROZEN); } else { VCPU_CTR0(vm, vcpuid, "Rendezvous during suspend"); vcpu_unlock(vcpu); @@ -989,6 +1021,19 @@ vm_handle_suspend(struct vm *vm, int vcpuid, bool *retu) return (0); } +static int +vm_handle_reqidle(struct vm *vm, int vcpuid, bool *retu) +{ + struct vcpu *vcpu = &vm->vcpu[vcpuid]; + + vcpu_lock(vcpu); + KASSERT(vcpu->reqidle, ("invalid vcpu reqidle %d", vcpu->reqidle)); + vcpu->reqidle = 0; + vcpu_unlock(vcpu); + *retu = true; + return (0); +} + int vm_suspend(struct vm *vm, enum vm_suspend_how how) { @@ -1031,6 +1076,20 @@ vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip) vmexit->u.suspended.how = (enum vm_suspend_how) vm->suspend; } + +void +vm_exit_reqidle(struct vm *vm, int vcpuid, uint64_t rip) +{ + struct vm_exit *vmexit; + + vmexit = vm_exitinfo(vm, vcpuid); + vmexit->rip = rip; + vmexit->inst_length = 0; + vmexit->exitcode = VM_EXITCODE_REQIDLE; + vmm_stat_incr(vm, vcpuid, VMEXIT_REQIDLE, 1); +} + + void vm_exit_rendezvous(struct vm *vm, int vcpuid, uint64_t rip) { @@ -1050,12 +1109,12 @@ void pittest(struct vm *thevm); int vm_run(struct vm *vm, int vcpuid, struct vm_exit *vm_exit) { + struct vm_eventinfo evinfo; int error; struct vcpu *vcpu; // uint64_t tscval; struct vm_exit *vme; bool retu, intr_disabled; - void *rptr, *sptr; if (vcpuid < 0 || vcpuid >= VM_MAXCPU) return (EINVAL); @@ -1066,17 +1125,18 @@ vm_run(struct vm *vm, int vcpuid, struct vm_exit *vm_exit) if (CPU_ISSET(((unsigned) vcpuid), &vm->suspended_cpus)) return (EINVAL); - rptr = &vm->rendezvous_func; - sptr = &vm->suspend; vcpu = &vm->vcpu[vcpuid]; vme = &vcpu->exitinfo; + evinfo.rptr = &vm->rendezvous_func; + evinfo.sptr = &vm->suspend; + evinfo.iptr = &vcpu->reqidle; retu = false; restart: // tscval = rdtsc(); vcpu_require_state(vm, vcpuid, VCPU_RUNNING); - error = VMRUN(vm->cookie, vcpuid, (register_t) vcpu->nextrip, rptr, sptr); + error = VMRUN(vm->cookie, vcpuid, (register_t) vcpu->nextrip, &evinfo); vcpu_require_state(vm, vcpuid, VCPU_FROZEN); @@ -1086,6 +1146,9 @@ vm_run(struct vm *vm, int vcpuid, struct vm_exit *vm_exit) retu = false; vcpu->nextrip = vme->rip + ((unsigned) vme->inst_length); switch (((int) (vme->exitcode))) { + case VM_EXITCODE_REQIDLE: + error = vm_handle_reqidle(vm, vcpuid, &retu); + break; case VM_EXITCODE_SUSPENDED: error = vm_handle_suspend(vm, vcpuid, &retu); break; @@ -1124,6 +1187,8 @@ vm_run(struct vm *vm, int vcpuid, struct vm_exit *vm_exit) if (error == 0 && retu == false) goto restart; + VCPU_CTR2(vm, vcpuid, "retu %d/%d", error, vme->exitcode); + /* copy the exit information (FIXME: zero copy) */ bcopy(vme, vm_exit, sizeof(struct vm_exit)); return (error); @@ -1600,7 +1665,7 @@ vcpu_set_state(struct vm *vm, int vcpuid, enum vcpu_state newstate, vcpu = &vm->vcpu[vcpuid]; vcpu_lock(vcpu); - error = vcpu_set_state_locked(vcpu, newstate, from_idle); + error = vcpu_set_state_locked(vm, vcpuid, newstate, from_idle); vcpu_unlock(vcpu); return (error); } @@ -1693,13 +1758,9 @@ vm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) * - If the vcpu is running on a different host_cpu then an IPI will be directed * to the host_cpu to cause the vcpu to trap into the hypervisor. */ -void -vcpu_notify_event(struct vm *vm, int vcpuid, UNUSED bool lapic_intr) +static void +vcpu_notify_event_locked(struct vcpu *vcpu, int vcpuid, UNUSED bool lapic_intr) { - struct vcpu *vcpu; - - vcpu = &vm->vcpu[vcpuid]; - vcpu_lock(vcpu); if (vcpu->state == VCPU_RUNNING) { VCPU_INTERRUPT(vcpuid); /* FIXME */ @@ -1723,6 +1784,15 @@ vcpu_notify_event(struct vm *vm, int vcpuid, UNUSED bool lapic_intr) pthread_cond_signal(&vcpu->vcpu_sleep_cnd); //wakeup_one(vcpu); } +} + +void +vcpu_notify_event(struct vm *vm, int vcpuid, bool lapic_intr) +{ + struct vcpu *vcpu = &vm->vcpu[vcpuid]; + + vcpu_lock(vcpu); + vcpu_notify_event_locked(vcpu, vcpuid, lapic_intr); vcpu_unlock(vcpu); } @@ -1879,7 +1949,7 @@ vm_copyin(UNUSED struct vm *vm, UNUSED int vcpuid, struct vm_copyinfo *copyinfo, { char *dst; int idx; - + dst = kaddr; idx = 0; while (len > 0) { diff --git a/src/vmm/vmm_stat.c b/src/vmm/vmm_stat.c index bb52097..8a37cbb 100644 --- a/src/vmm/vmm_stat.c +++ b/src/vmm/vmm_stat.c @@ -151,6 +151,7 @@ VMM_STAT(VMEXIT_NESTED_FAULT, "vm exits due to nested page fault"); VMM_STAT(VMEXIT_INST_EMUL, "vm exits for instruction emulation"); VMM_STAT(VMEXIT_UNKNOWN, "number of vm exits for unknown reason"); VMM_STAT(VMEXIT_ASTPENDING, "number of times astpending at exit"); +VMM_STAT(VMEXIT_REQIDLE, "number of times idle requested at exit"); VMM_STAT(VMEXIT_USERSPACE, "number of vm exits handled in userspace"); VMM_STAT(VMEXIT_RENDEZVOUS, "number of times rendezvous pending at exit"); VMM_STAT(VMEXIT_EXCEPTION, "number of vm exits due to exceptions"); diff --git a/src/xhyve.c b/src/xhyve.c index 224a74b..20dbecc 100644 --- a/src/xhyve.c +++ b/src/xhyve.c @@ -101,7 +101,7 @@ static struct vm_exit vmexit[VM_MAXCPU]; static struct bhyvestats { uint64_t vmexit_bogus; - uint64_t vmexit_bogus_switch; + uint64_t vmexit_reqidle; uint64_t vmexit_hlt; uint64_t vmexit_pause; uint64_t vmexit_mtrap; @@ -433,6 +433,17 @@ vmexit_bogus(struct vm_exit *vme, UNUSED int *pvcpu) return (VMEXIT_CONTINUE); } +static int +vmexit_reqidle(struct vm_exit *vme, UNUSED int *pvcpu) +{ + + assert(vme->inst_length == 0); + + stats.vmexit_reqidle++; + + return (VMEXIT_CONTINUE); +} + static int vmexit_hlt(UNUSED struct vm_exit *vme, UNUSED int *pvcpu) { @@ -539,6 +550,7 @@ static vmexit_handler_t handler[VM_EXITCODE_MAX] = { [VM_EXITCODE_INOUT_STR] = vmexit_inout, [VM_EXITCODE_VMX] = vmexit_vmx, [VM_EXITCODE_BOGUS] = vmexit_bogus, + [VM_EXITCODE_REQIDLE] = vmexit_reqidle, [VM_EXITCODE_RDMSR] = vmexit_rdmsr, [VM_EXITCODE_WRMSR] = vmexit_wrmsr, [VM_EXITCODE_MTRAP] = vmexit_mtrap,