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); +bool vm_handle_rendezvous_help_one(struct vcpu *vcpu); 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 @@ -302,6 +302,7 @@ static void vm_free_memmap(struct vm *vm, int ident); static bool sysmem_mapping(struct vm *vm, struct mem_map *mm); static void vcpu_notify_event_locked(struct vcpu *vcpu, bool lapic_intr); +static int vm_handle_rendezvous(struct vcpu *vcpu); /* * Upper limit on vm_maxcpu. Limited by use of uint16_t types for CPU @@ -1335,6 +1336,13 @@ */ if (from_idle) { while (vcpu->state != VCPU_IDLE) { + if (vcpu->vm->rendezvous_func != NULL) { + VMM_CTR0(vcpu, "Rendezvous during set state"); + vcpu_unlock(vcpu); + error = vm_handle_rendezvous(vcpu); + vcpu_lock(vcpu); + continue; + } vcpu->reqidle = 1; vcpu_notify_event_locked(vcpu, false); VMM_CTR1(vcpu, "vcpu state change from %s to " @@ -1410,6 +1418,24 @@ panic("Error %d setting state to %d", error, newstate); } +bool +vm_handle_rendezvous_help_one(struct vcpu *vcpu) +{ + struct vm *vm = vcpu->vm; + int vcpuid; + bool res; + + if (vm->rendezvous_func == NULL) + return (false); + mtx_lock(&vm->rendezvous_mtx); + vcpuid = vcpu->vcpuid; + res = vm->rendezvous_func != NULL && + CPU_ISSET(vcpuid, &vm->rendezvous_req_cpus) && + !CPU_ISSET(vcpuid, &vm->rendezvous_done_cpus); + mtx_unlock(&vm->rendezvous_mtx); + return (res); +} + static int vm_handle_rendezvous(struct vcpu *vcpu) { 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 @@ -151,9 +151,17 @@ int error; uint16_t i, j, maxcpus; +again: + error = 0; vm_slock_vcpus(sc->vm); maxcpus = vm_get_maxcpus(sc->vm); for (i = 0; i < maxcpus; i++) { + for (j = 0; j < i; j++) { + if (vm_handle_rendezvous_help_one(vm_vcpu(sc->vm, j))) { + error = EJUSTRETURN; + break; + } + } vcpu = vm_vcpu(sc->vm, i); if (vcpu == NULL) continue; @@ -171,6 +179,8 @@ } vm_unlock_vcpus(sc->vm); } + if (error == EJUSTRETURN) + goto again; return (error); }