Skip to content

Commit

Permalink
Fix non-deterministic delays when accessing a vcpu that was in "runni…
Browse files Browse the repository at this point in the history
…ng" 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.

MFC after:      2 weeks
  • Loading branch information
neel authored and neel committed May 28, 2015
1 parent 67b3bbe commit 3f2b4fc
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 35 deletions.
26 changes: 20 additions & 6 deletions sys/amd64/include/vmm.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,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)(int ipinum);
typedef int (*vmm_cleanup_func_t)(void);
typedef void (*vmm_resume_func_t)(void);
typedef void * (*vmi_init_func_t)(struct vm *vm, struct pmap *pmap);
typedef int (*vmi_run_func_t)(void *vmi, int vcpu, register_t rip,
struct pmap *pmap, void *rendezvous_cookie,
void *suspend_cookie);
struct pmap *pmap, struct vm_eventinfo *info);
typedef void (*vmi_cleanup_func_t)(void *vmi);
typedef int (*vmi_get_register_t)(void *vmi, int vcpu, int num,
uint64_t *retval);
Expand Down Expand Up @@ -208,6 +213,7 @@ 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_astpending(struct vm *vm, int vcpuid, uint64_t rip);
void vm_exit_reqidle(struct vm *vm, int vcpuid, uint64_t rip);

#ifdef _SYS__CPUSET_H_
/*
Expand All @@ -232,17 +238,24 @@ cpuset_t vm_suspended_cpus(struct vm *vm);
#endif /* _SYS__CPUSET_H_ */

static __inline int
vcpu_rendezvous_pending(void *rendezvous_cookie)
vcpu_rendezvous_pending(struct vm_eventinfo *info)
{

return (*((uintptr_t *)(info->rptr)) != 0);
}

static __inline int
vcpu_suspended(struct vm_eventinfo *info)
{

return (*(uintptr_t *)rendezvous_cookie != 0);
return (*info->sptr);
}

static __inline int
vcpu_suspended(void *suspend_cookie)
vcpu_reqidle(struct vm_eventinfo *info)
{

return (*(int *)suspend_cookie);
return (*info->iptr);
}

/*
Expand Down Expand Up @@ -506,6 +519,7 @@ enum vm_exitcode {
VM_EXITCODE_MONITOR,
VM_EXITCODE_MWAIT,
VM_EXITCODE_SVM,
VM_EXITCODE_REQIDLE,
VM_EXITCODE_MAX
};

Expand Down
12 changes: 9 additions & 3 deletions sys/amd64/vmm/amd/svm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1900,7 +1900,7 @@ enable_gintr(void)
*/
static int
svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap,
void *rend_cookie, void *suspended_cookie)
struct vm_eventinfo *evinfo)
{
struct svm_regctx *gctx;
struct svm_softc *svm_sc;
Expand Down Expand Up @@ -1975,18 +1975,24 @@ svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap,
*/
disable_gintr();

if (vcpu_suspended(suspended_cookie)) {
if (vcpu_suspended(evinfo)) {
enable_gintr();
vm_exit_suspended(vm, vcpu, state->rip);
break;
}

if (vcpu_rendezvous_pending(rend_cookie)) {
if (vcpu_rendezvous_pending(evinfo)) {
enable_gintr();
vm_exit_rendezvous(vm, vcpu, state->rip);
break;
}

if (vcpu_reqidle(evinfo)) {
enable_gintr();
vm_exit_reqidle(vm, vcpu, state->rip);
break;
}

/* We are asked to give the cpu by scheduler. */
if (vcpu_should_yield(vm, vcpu)) {
enable_gintr();
Expand Down
12 changes: 9 additions & 3 deletions sys/amd64/vmm/intel/vmx.c
Original file line number Diff line number Diff line change
Expand Up @@ -2554,7 +2554,7 @@ vmx_exit_handle_nmi(struct vmx *vmx, int vcpuid, struct vm_exit *vmexit)

static int
vmx_run(void *arg, int vcpu, register_t rip, pmap_t pmap,
void *rendezvous_cookie, void *suspend_cookie)
struct vm_eventinfo *evinfo)
{
int rc, handled, launched;
struct vmx *vmx;
Expand Down Expand Up @@ -2623,18 +2623,24 @@ vmx_run(void *arg, int vcpu, register_t rip, pmap_t pmap,
* vmx_inject_interrupts() can suspend the vcpu due to a
* triple fault.
*/
if (vcpu_suspended(suspend_cookie)) {
if (vcpu_suspended(evinfo)) {
enable_intr();
vm_exit_suspended(vmx->vm, vcpu, rip);
break;
}

if (vcpu_rendezvous_pending(rendezvous_cookie)) {
if (vcpu_rendezvous_pending(evinfo)) {
enable_intr();
vm_exit_rendezvous(vmx->vm, vcpu, rip);
break;
}

if (vcpu_reqidle(evinfo)) {
enable_intr();
vm_exit_reqidle(vmx->vm, vcpu, rip);
break;
}

if (vcpu_should_yield(vm, vcpu)) {
enable_intr();
vm_exit_astpending(vmx->vm, vcpu, rip);
Expand Down

0 comments on commit 3f2b4fc

Please sign in to comment.