feat: reclaim all resources from an aborted SP

Once any execution context of an SP is aborted, all the resources of
the SP are reclaimed by SPMC. This patch creates a placeholder
function to this effect which can be populated with necessary actions
such as disabling all interrupts belonging to the SP.

Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Change-Id: Ia4c2913ad0aeda21770052ca748d41734cafd8b4
diff --git a/src/api.c b/src/api.c
index 210c604..843b8dc 100644
--- a/src/api.c
+++ b/src/api.c
@@ -385,6 +385,7 @@
 	struct ffa_value ret = ffa_error(FFA_ABORTED);
 	struct vcpu_locked current_locked;
 	struct vcpu *next;
+	struct vm_locked vm_locked;
 
 	dlog_notice("Aborting VM %#x vCPU %u\n", current->vm->id,
 		    vcpu_index(current));
@@ -399,7 +400,9 @@
 	atomic_store_explicit(&current->vm->aborting, true,
 			      memory_order_relaxed);
 
-	/* TODO: free resources once all vCPUs abort. */
+	vm_locked = vm_lock(current->vm);
+	plat_ffa_free_vm_resources(vm_locked);
+	vm_unlock(&vm_locked);
 
 	current_locked = vcpu_lock(current);
 	next = api_switch_to_primary(current_locked, ret, VCPU_STATE_ABORTED);
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index 0e300c8..b1c34c5 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -639,3 +639,8 @@
 	(void)current;
 	return -1;
 }
+
+void plat_ffa_free_vm_resources(struct vm_locked vm_locked)
+{
+	(void)vm_locked;
+}
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index c80458d..a3d2ce5 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -2233,3 +2233,8 @@
 
 	return waiting_vm->id;
 }
+
+void plat_ffa_free_vm_resources(struct vm_locked vm_locked)
+{
+	(void)vm_locked;
+}
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index a3d379a..7f52efd 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -1323,6 +1323,25 @@
 	return 0;
 }
 
+static void plat_ffa_disable_vm_interrupts(struct vm_locked vm_locked)
+{
+	uint32_t core_pos = arch_find_core_pos();
+
+	/* Gracefully disable interrupts. */
+	dlog_verbose("Interrupts belonging to SP %x disabled\n",
+		     vm_locked.vm->id);
+
+	for (uint32_t i = 0; i < HF_NUM_INTIDS; i++) {
+		struct interrupt_descriptor int_desc;
+
+		int_desc = vm_locked.vm->interrupt_desc[i];
+		if (!int_desc.valid) {
+			break;
+		}
+		plat_interrupts_disable(int_desc.interrupt_id, core_pos);
+	}
+}
+
 static struct vcpu *plat_ffa_find_target_vcpu(struct vcpu *current,
 					      uint32_t interrupt_id)
 {
@@ -2709,9 +2728,11 @@
 				   uint32_t error_code)
 {
 	struct vcpu_locked current_locked;
+	struct vm_locked vm_locked;
 	enum partition_runtime_model rt_model;
 	struct ffa_value ret = (struct ffa_value){.func = FFA_INTERRUPT_32};
 
+	vm_locked = vm_lock(current->vm);
 	current_locked = vcpu_lock(current);
 	rt_model = current_locked.vcpu->rt_model;
 
@@ -2722,6 +2743,8 @@
 		atomic_store_explicit(&current->vm->aborting, true,
 				      memory_order_relaxed);
 
+		plat_ffa_free_vm_resources(vm_locked);
+
 		if (sp_boot_next(current_locked, next)) {
 			goto out;
 		}
@@ -2741,6 +2764,7 @@
 	ret = ffa_error(FFA_NOT_SUPPORTED);
 out:
 	vcpu_unlock(&current_locked);
+	vm_unlock(&vm_locked);
 	return ret;
 }
 
@@ -2855,3 +2879,14 @@
 
 	return ret;
 }
+
+/**
+ * Reclaim all resources belonging to VM in aborted state.
+ */
+void plat_ffa_free_vm_resources(struct vm_locked vm_locked)
+{
+	/*
+	 * Gracefully disable all interrupts belonging to SP.
+	 */
+	plat_ffa_disable_vm_interrupts(vm_locked);
+}
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index 4e2fedd..a7a30b6 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -668,3 +668,8 @@
 {
 	return false;
 }
+
+void plat_ffa_free_vm_resources(struct vm_locked vm_locked)
+{
+	(void)vm_locked;
+}