diff options
author | Mark Johnston <markj@FreeBSD.org> | 2024-04-29 14:19:27 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2024-04-29 14:19:27 +0000 |
commit | 1ee7a8fa58c3fe7161683f2a7d2e37dc5c672b46 (patch) | |
tree | 216469e159985220709de5ac85292d530dda31d3 | |
parent | 390e44988aeaa824a9ea4f0e352f9a252093c170 (diff) | |
download | src-1ee7a8fa58c3fe7161683f2a7d2e37dc5c672b46.tar.gz src-1ee7a8fa58c3fe7161683f2a7d2e37dc5c672b46.zip |
-rw-r--r-- | sys/arm64/vmm/vmm.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/sys/arm64/vmm/vmm.c b/sys/arm64/vmm/vmm.c index 2685e5869b4f..a2cc63448f19 100644 --- a/sys/arm64/vmm/vmm.c +++ b/sys/arm64/vmm/vmm.c @@ -1716,6 +1716,54 @@ vm_handle_paging(struct vcpu *vcpu, bool *retu) return (0); } +static int +vm_handle_suspend(struct vcpu *vcpu, bool *retu) +{ + struct vm *vm = vcpu->vm; + int error, i; + struct thread *td; + + error = 0; + td = curthread; + + CPU_SET_ATOMIC(vcpu->vcpuid, &vm->suspended_cpus); + + /* + * Wait until all 'active_cpus' have suspended themselves. + * + * Since a VM may be suspended at any time including when one or + * more vcpus are doing a rendezvous we need to call the rendezvous + * handler while we are waiting to prevent a deadlock. + */ + vcpu_lock(vcpu); + while (error == 0) { + if (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) + break; + + vcpu_require_state_locked(vcpu, VCPU_SLEEPING); + msleep_spin(vcpu, &vcpu->mtx, "vmsusp", hz); + vcpu_require_state_locked(vcpu, VCPU_FROZEN); + if (td_ast_pending(td, TDA_SUSPEND)) { + vcpu_unlock(vcpu); + error = thread_check_susp(td, false); + vcpu_lock(vcpu); + } + } + vcpu_unlock(vcpu); + + /* + * Wakeup the other sleeping vcpus and return to userspace. + */ + for (i = 0; i < vm->maxcpus; i++) { + if (CPU_ISSET(i, &vm->suspended_cpus)) { + vcpu_notify_event(vm_vcpu(vm, i)); + } + } + + *retu = true; + return (error); +} + int vm_run(struct vcpu *vcpu) { @@ -1788,6 +1836,11 @@ restart: error = vm_handle_paging(vcpu, &retu); break; + case VM_EXITCODE_SUSPENDED: + vcpu->nextpc = vme->pc; + error = vm_handle_suspend(vcpu, &retu); + break; + default: /* Handle in userland */ vcpu->nextpc = vme->pc; |