Handle VMs misbehaving.

If a VM accesses memory it is not allowed to or otherwise triggers and
unhandled exception it will be aborted such that none of the vCPUs can
be run again.

The VM remains unchanged from the point of view of other VMs other than
it will not make any further progress.

Change-Id: I352e1c714f1e4b1b43185269f92e7fa41e09a4db
diff --git a/src/api.c b/src/api.c
index 1161230..9506532 100644
--- a/src/api.c
+++ b/src/api.c
@@ -121,6 +121,32 @@
 }
 
 /**
+ * Aborts the vCPU and triggers it's VM to abort fully.
+ */
+struct vcpu *api_abort(struct vcpu *current)
+{
+	struct hf_vcpu_run_return ret = {
+		.code = HF_VCPU_RUN_ABORTED,
+	};
+
+	dlog("Aborting VM %u vCPU %u\n", current->vm->id, vcpu_index(current));
+
+	if (current->vm->id == HF_PRIMARY_VM_ID) {
+		/* TODO: what to do when the primary aborts? */
+		for (;;) {
+			/* Do nothing. */
+		}
+	}
+
+	atomic_store_explicit(&current->vm->aborting, true,
+			      memory_order_relaxed);
+
+	/* TODO: free resources once all vCPUs abort. */
+
+	return api_switch_to_primary(current, ret, vcpu_state_aborted);
+}
+
+/**
  * Returns the ID of the VM.
  */
 int64_t api_vm_get_id(const struct vcpu *current)
@@ -194,12 +220,23 @@
  * Prepares the vcpu to run by updating its state and fetching whether a return
  * value needs to be forced onto the vCPU.
  */
-static bool api_vcpu_prepare_run(const struct vcpu *current, struct vcpu *vcpu,
+static bool api_vcpu_prepare_run(struct vcpu *current, struct vcpu *vcpu,
 				 struct retval_state *vcpu_retval)
 {
 	bool ret;
 
 	sl_lock(&vcpu->lock);
+
+	if (atomic_load_explicit(&vcpu->vm->aborting, memory_order_relaxed)) {
+		if (vcpu->state != vcpu_state_aborted) {
+			dlog("Aborting VM %u vCPU %u\n", current->vm->id,
+			     vcpu_index(current));
+			vcpu->state = vcpu_state_aborted;
+		}
+		ret = false;
+		goto out;
+	}
+
 	if (vcpu->state != vcpu_state_ready) {
 		ret = false;
 		goto out;
@@ -242,8 +279,7 @@
  * Runs the given vcpu of the given vm.
  */
 struct hf_vcpu_run_return api_vcpu_run(uint32_t vm_id, uint32_t vcpu_idx,
-				       const struct vcpu *current,
-				       struct vcpu **next)
+				       struct vcpu *current, struct vcpu **next)
 {
 	struct vm *vm;
 	struct vcpu *vcpu;