diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h --- a/sys/amd64/include/vmm.h +++ b/sys/amd64/include/vmm.h @@ -322,6 +322,7 @@ typedef void (*vm_rendezvous_func_t)(struct vcpu *vcpu, void *arg); int vm_smp_rendezvous(struct vcpu *vcpu, cpuset_t dest, vm_rendezvous_func_t func, void *arg); +void vm_handle_rendezvous_from_lock_all(struct vm *vm, int maxi); cpuset_t vm_active_cpus(struct vm *vm); cpuset_t vm_debug_cpus(struct vm *vm); diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c --- a/sys/amd64/vmm/vmm.c +++ b/sys/amd64/vmm/vmm.c @@ -181,6 +181,7 @@ cpuset_t rendezvous_done_cpus; /* (x) [r] rendezvous finished */ void *rendezvous_arg; /* (x) [r] rendezvous func/arg */ vm_rendezvous_func_t rendezvous_func; + int rendezvous_vcpu_req; struct mtx rendezvous_mtx; /* (o) rendezvous lock */ struct mem_map mem_maps[VM_MAX_MEMMAPS]; /* (i) [m+v] guest address space */ struct mem_seg mem_segs[VM_MAX_MEMSEGS]; /* (o) [m+v] guest memory regions */ @@ -1411,7 +1412,7 @@ } static int -vm_handle_rendezvous(struct vcpu *vcpu) +vm_handle_rendezvous_locked(struct vcpu *vcpu, bool wait) { struct vm *vm = vcpu->vm; struct thread *td; @@ -1420,7 +1421,6 @@ error = 0; vcpuid = vcpu->vcpuid; td = curthread; - mtx_lock(&vm->rendezvous_mtx); while (vm->rendezvous_func != NULL) { /* 'rendezvous_req_cpus' must be a subset of 'active_cpus' */ CPU_AND(&vm->rendezvous_req_cpus, &vm->rendezvous_req_cpus, &vm->active_cpus); @@ -1438,21 +1438,56 @@ wakeup(&vm->rendezvous_func); break; } - VMM_CTR0(vcpu, "Wait for rendezvous completion"); - mtx_sleep(&vm->rendezvous_func, &vm->rendezvous_mtx, 0, - "vmrndv", hz); - if (td_ast_pending(td, TDA_SUSPEND)) { - mtx_unlock(&vm->rendezvous_mtx); - error = thread_check_susp(td, true); - if (error != 0) - return (error); - mtx_lock(&vm->rendezvous_mtx); + if (wait) { + VMM_CTR0(vcpu, "Wait for rendezvous completion"); + mtx_sleep(&vm->rendezvous_func, &vm->rendezvous_mtx, 0, + "vmrndv", hz); + if (td_ast_pending(td, TDA_SUSPEND)) { + mtx_unlock(&vm->rendezvous_mtx); + error = thread_check_susp(td, true); + if (error != 0) + return (error); + mtx_lock(&vm->rendezvous_mtx); + } } } - mtx_unlock(&vm->rendezvous_mtx); return (0); } +static int +vm_handle_rendezvous(struct vcpu *vcpu) +{ + struct vm *vm; + int res; + + vm = vcpu->vm; + mtx_lock(&vm->rendezvous_mtx); + res = vm_handle_rendezvous_locked(vcpu, true); + mtx_unlock(&vm->rendezvous_mtx); + return (res); +} + +/* + * Handle rendezvous request for all vcpus frozen by the caller. + */ +void +vm_handle_rendezvous_from_lock_all(struct vm *vm, int maxi) +{ + struct vcpu *vcpu; + int i; + + if (vm->rendezvous_func == NULL) + return; + + mtx_lock(&vm->rendezvous_mtx); + for (i = 0; vm->rendezvous_func != NULL && i < maxi; i++) { + vcpu = vm_vcpu(vm, i); + if (vcpu != NULL && vcpu->vcpuid != vm->rendezvous_vcpu_req) + vm_handle_rendezvous_locked(vcpu, false); + } + mtx_unlock(&vm->rendezvous_mtx); +} + /* * Emulate a guest 'hlt' by sleeping until the vcpu is ready to run. */ @@ -2646,6 +2681,7 @@ CPU_ZERO(&vm->rendezvous_done_cpus); vm->rendezvous_arg = arg; vm->rendezvous_func = func; + vm->rendezvous_vcpu_req = vcpu->vcpuid; mtx_unlock(&vm->rendezvous_mtx); /* diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c --- a/sys/amd64/vmm/vmm_dev.c +++ b/sys/amd64/vmm/vmm_dev.c @@ -147,14 +147,17 @@ static int vcpu_lock_all(struct vmmdev_softc *sc) { + struct vm *vm; struct vcpu *vcpu; int error; uint16_t i, j, maxcpus; - vm_slock_vcpus(sc->vm); - maxcpus = vm_get_maxcpus(sc->vm); + vm = sc->vm; + vm_slock_vcpus(vm); + maxcpus = vm_get_maxcpus(vm); for (i = 0; i < maxcpus; i++) { - vcpu = vm_vcpu(sc->vm, i); + vm_handle_rendezvous_from_lock_all(vm, i); + vcpu = vm_vcpu(vm, i); if (vcpu == NULL) continue; error = vcpu_lock_one(vcpu); @@ -164,12 +167,12 @@ if (error) { for (j = 0; j < i; j++) { - vcpu = vm_vcpu(sc->vm, j); + vcpu = vm_vcpu(vm, j); if (vcpu == NULL) continue; vcpu_unlock_one(sc, j, vcpu); } - vm_unlock_vcpus(sc->vm); + vm_unlock_vcpus(vm); } return (error);