feat: initial support for FFA_ABORT ABI to abort partition
This patch adds initial support for the newly introduced FFA_ABORT ABI.
It is invoked by partition, to enter aborted state, when it encounters
a fatal error.
Subsequent patches will add incremental support for handling this ABI by
partition manager.
Change-Id: I601a0bf4efd61f5008285b6712107795c65c0332
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/src/api.c b/src/api.c
index 816bf16..75f12f4 100644
--- a/src/api.c
+++ b/src/api.c
@@ -354,28 +354,39 @@
*/
struct vcpu *api_terminate_vm(struct vcpu *current)
{
- struct ffa_value ret = ffa_error(FFA_ABORTED);
- struct vcpu_locked current_locked;
struct vcpu *next;
- struct vm_locked vm_locked;
- dlog_notice("Terminating VM %#x vCPU %u\n", current->vm->id,
- vcpu_index(current));
-
- atomic_store_explicit(¤t->vm->aborting, true,
- memory_order_relaxed);
-
- vm_locked = vm_lock(current->vm);
- ffa_vm_free_resources(vm_locked);
- vm_unlock(&vm_locked);
-
- current_locked = vcpu_lock(current);
- next = api_switch_to_primary(current_locked, ret, VCPU_STATE_ABORTED);
- vcpu_unlock(¤t_locked);
+ ffa_partition_abort(current, &next);
return next;
}
+/**
+ * An execution context of a partition invokes FFA_ABORT ABI upon encountering
+ * a fatal error and enters ABORTED state. SPMC then takes necessary steps
+ * based on the abort action specified by the partition through its manifest.
+ */
+struct ffa_value api_ffa_abort(struct vcpu *current, struct vcpu **next,
+ struct ffa_value *args)
+{
+ assert(args != NULL);
+
+ if (ffa_is_vm_id(current->vm->id)) {
+ dlog_error("FFA_ABORT ABI not supported in NWd.\n");
+ return ffa_error(FFA_NOT_SUPPORTED);
+ }
+
+ if (args->arg1 != 0U || args->arg3 != 0U || args->arg4 != 0U ||
+ args->arg5 != 0U || args->arg6 != 0U || args->arg7 != 0U) {
+ dlog_error(
+ "Parameters passed through registers X1 and X3-X7 "
+ "must be zero\n");
+ return ffa_error(FFA_INVALID_PARAMETERS);
+ }
+
+ return ffa_partition_abort(current, next);
+}
+
/*
* Format the partition info descriptors according to the version supported
* by the endpoint and return the size of the array created.
@@ -2555,10 +2566,6 @@
}
return api_ffa_feature_success(0);
- /*
- * This function is restricted to the secure virtual FF-A instance (i.e.
- * only report success to SPs).
- */
case FFA_YIELD_32:
if (!vm_id_is_current_world(current->vm->id)) {
dlog_verbose(
@@ -2615,6 +2622,21 @@
FFA_FEATURES_MEM_RETRIEVE_REQ_HYPERVISOR_SUPPORT);
}
+ /*
+ * This function is restricted to the secure virtual FF-A instance (i.e.
+ * only report success to SPs).
+ */
+ case FFA_ABORT_32:
+ case FFA_ABORT_64:
+ if (ffa_is_vm_id(current->vm->id)) {
+ dlog_verbose(
+ "FFA_FEATURES: %s is only supported at secure "
+ "virtual FF-A instance\n",
+ ffa_func_name(FFA_YIELD_32));
+ return ffa_error(FFA_NOT_SUPPORTED);
+ }
+ return api_ffa_feature_success(0);
+
default:
return ffa_error(FFA_NOT_SUPPORTED);
}
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 56ca9e0..c0989cf 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -585,7 +585,10 @@
case FFA_ERROR_32:
*args = ffa_cpu_cycles_error_32(current, next, args->arg2);
return true;
-
+ case FFA_ABORT_32:
+ case FFA_ABORT_64:
+ *args = api_ffa_abort(current, next, args);
+ return true;
default:
return false;
}
@@ -1110,6 +1113,48 @@
return r;
}
+/**
+ * Aborts execution of a partition when a fatal error occurs on a vCPU and
+ * triggers the SPMC to reclaim all resources allocated to it.
+ */
+struct ffa_value ffa_partition_abort(struct vcpu *current, struct vcpu **next)
+{
+ struct vm_locked vm_locked;
+ struct ffa_value ret;
+ struct vcpu_locked current_locked;
+
+ dlog_notice("Aborting VM %#x vCPU %u\n", current->vm->id,
+ vcpu_index(current));
+
+ vm_locked = vm_lock(current->vm);
+
+ atomic_store_explicit(¤t->vm->aborting, true,
+ memory_order_relaxed);
+ current_locked = vcpu_lock(current);
+
+ /*
+ * A partition exection is in ABORTED state after it encounters a fatal
+ * error.
+ */
+ current->state = VCPU_STATE_ABORTED;
+
+ /*
+ * SPMC de-allocates and/or uninitializes all the resources allocated
+ * to the partition.
+ */
+ ffa_vm_free_resources(vm_locked);
+ vm_unlock(&vm_locked);
+
+ /*
+ * SPMC performs necessary operations based on the abort action for
+ * SP.
+ */
+ ret = ffa_cpu_cycles_abort(current_locked, next);
+ vcpu_unlock(¤t_locked);
+
+ return ret;
+}
+
struct vcpu *sync_lower_exception(uintreg_t esr, uintreg_t far)
{
struct vcpu *vcpu = current();
diff --git a/src/ffa/hypervisor/cpu_cycles.c b/src/ffa/hypervisor/cpu_cycles.c
index cf9f4bb..5ec1a45 100644
--- a/src/ffa/hypervisor/cpu_cycles.c
+++ b/src/ffa/hypervisor/cpu_cycles.c
@@ -10,6 +10,7 @@
#include "hf/api.h"
#include "hf/ffa/indirect_messaging.h"
+#include "hf/ffa/vm.h"
#include "hf/ffa_internal.h"
#include "hf/vcpu.h"
@@ -137,3 +138,14 @@
/* TODO: Interface not handled in hypervisor. */
return ffa_error(FFA_NOT_SUPPORTED);
}
+
+struct ffa_value ffa_cpu_cycles_abort(struct vcpu_locked *current_locked,
+ struct vcpu **next)
+{
+ struct ffa_value to_ret = ffa_error(FFA_ABORTED);
+
+ *next = api_switch_to_primary(*current_locked, to_ret,
+ VCPU_STATE_ABORTED);
+
+ return (struct ffa_value){.func = FFA_SUCCESS_32};
+}
diff --git a/src/ffa/spmc/cpu_cycles.c b/src/ffa/spmc/cpu_cycles.c
index 0b5809b..4516742 100644
--- a/src/ffa/spmc/cpu_cycles.c
+++ b/src/ffa/spmc/cpu_cycles.c
@@ -833,3 +833,18 @@
vm_unlock(&vm_locked);
return ret;
}
+
+struct ffa_value ffa_cpu_cycles_abort(struct vcpu_locked current_locked,
+ struct vcpu **next)
+{
+ struct ffa_value to_ret = ffa_error(FFA_ABORTED);
+ enum vcpu_state next_state = VCPU_STATE_ABORTED;
+
+ /*
+ * Relinquish control back to the NWd.
+ * TODO: Support for abort actions will be added in further patches.
+ */
+ *next = api_switch_to_primary(current_locked, to_ret, next_state);
+
+ return (struct ffa_value){.func = FFA_SUCCESS_32};
+}