aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2024-04-29 14:19:27 +0000
committerMark Johnston <markj@FreeBSD.org>2024-04-29 14:19:27 +0000
commit1ee7a8fa58c3fe7161683f2a7d2e37dc5c672b46 (patch)
tree216469e159985220709de5ac85292d530dda31d3
parent390e44988aeaa824a9ea4f0e352f9a252093c170 (diff)
downloadsrc-1ee7a8fa58c3fe7161683f2a7d2e37dc5c672b46.tar.gz
src-1ee7a8fa58c3fe7161683f2a7d2e37dc5c672b46.zip
-rw-r--r--sys/arm64/vmm/vmm.c53
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;