aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Deprez <olivier.deprez@arm.com>2020-06-09 18:28:45 +0200
committerOlivier Deprez <olivier.deprez@arm.com>2020-09-18 15:37:47 +0200
commitf33a6c77faec155eefb24af029ae5f305b658250 (patch)
treed6ac38342ee4f774159003776f16efba64340157
parent2688624aaff9ae02ea9fd714c224adc8b837db12 (diff)
downloadhafnium-f33a6c77faec155eefb24af029ae5f305b658250.tar.gz
FF-A: implement a handler loop for SPMC
When an FF-A ABI is invoked from a partition (virtual FF-A instance) it enters a handler loop calling ffa_handler such that it can either handle the FF-A request and resume current or next partition or forward the call to the normal world. When the SPMC is resumed from normal world it can process a fresh FF-A request from normal world. This permits receiving FF-A requests in the SPMC and possibly return straight to the NWd through SPMD without necessarily resuming a partition. Change-Id: Ib00efca90a5419290bd6c9153a6d1c343e8919bb Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
-rw-r--r--src/arch/aarch64/hypervisor/handler.c116
1 files changed, 96 insertions, 20 deletions
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 6c0135607..10caf4051 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -12,6 +12,7 @@
#include "hf/arch/init.h"
#include "hf/arch/mmu.h"
#include "hf/arch/plat/smc.h"
+#include "hf/arch/tee.h"
#include "hf/api.h"
#include "hf/check.h"
@@ -315,7 +316,16 @@ static void smc_forwarder(const struct vm *vm, struct ffa_value *args)
*args = ret;
}
-static bool ffa_handler(struct ffa_value *args, struct vcpu **next)
+/**
+ * In the normal world, ffa_handler is always called from the virtual FF-A
+ * instance (from a VM). In the secure world, ffa_handler may be called from
+ * virtual (a secure partition) or physical FF-A instance (from the normal
+ * world). The function returns true when the call is handled. The *next
+ * pointer is updated to the next vCPU to run or NULL when the call originated
+ * from the virtual FF-A instance and has to be forwarded down to EL3.
+ */
+static bool ffa_handler(struct ffa_value *args, struct vcpu *current,
+ struct vcpu **next)
{
uint32_t func = args->func & ~SMCCC_CONVENTION_MASK;
@@ -332,87 +342,145 @@ static bool ffa_handler(struct ffa_value *args, struct vcpu **next)
ffa_uuid_init(args->arg1, args->arg2, args->arg3, args->arg4,
&uuid);
- *args = api_ffa_partition_info_get(current(), &uuid);
+ *args = api_ffa_partition_info_get(current, &uuid);
return true;
}
case FFA_ID_GET_32:
- *args = api_ffa_id_get(current());
+ *args = api_ffa_id_get(current);
return true;
case FFA_FEATURES_32:
*args = api_ffa_features(args->arg1);
return true;
case FFA_RX_RELEASE_32:
- *args = api_ffa_rx_release(current(), next);
+ *args = api_ffa_rx_release(current, next);
return true;
case FFA_RXTX_MAP_32:
*args = api_ffa_rxtx_map(ipa_init(args->arg1),
ipa_init(args->arg2), args->arg3,
- current(), next);
+ current, next);
return true;
case FFA_YIELD_32:
- *args = api_yield(current(), next);
+ *args = api_yield(current, next);
return true;
case FFA_MSG_SEND_32:
*args = api_ffa_msg_send(
ffa_msg_send_sender(*args),
ffa_msg_send_receiver(*args), ffa_msg_send_size(*args),
- ffa_msg_send_attributes(*args), current(), next);
+ ffa_msg_send_attributes(*args), current, next);
return true;
case FFA_MSG_WAIT_32:
- *args = api_ffa_msg_recv(true, current(), next);
+ *args = api_ffa_msg_recv(true, current, next);
return true;
case FFA_MSG_POLL_32:
- *args = api_ffa_msg_recv(false, current(), next);
+ *args = api_ffa_msg_recv(false, current, next);
return true;
case FFA_RUN_32:
*args = api_ffa_run(ffa_vm_id(*args), ffa_vcpu_index(*args),
- current(), next);
+ current, next);
return true;
case FFA_MEM_DONATE_32:
case FFA_MEM_LEND_32:
case FFA_MEM_SHARE_32:
*args = api_ffa_mem_send(func, args->arg1, args->arg2,
ipa_init(args->arg3), args->arg4,
- current());
+ current);
return true;
case FFA_MEM_RETRIEVE_REQ_32:
*args = api_ffa_mem_retrieve_req(args->arg1, args->arg2,
ipa_init(args->arg3),
- args->arg4, current());
+ args->arg4, current);
return true;
case FFA_MEM_RELINQUISH_32:
- *args = api_ffa_mem_relinquish(current());
+ *args = api_ffa_mem_relinquish(current);
return true;
case FFA_MEM_RECLAIM_32:
*args = api_ffa_mem_reclaim(
ffa_assemble_handle(args->arg1, args->arg2), args->arg3,
- current());
+ current);
return true;
case FFA_MEM_FRAG_RX_32:
*args = api_ffa_mem_frag_rx(ffa_frag_handle(*args), args->arg3,
(args->arg4 >> 16) & 0xffff,
- current());
+ current);
return true;
case FFA_MEM_FRAG_TX_32:
*args = api_ffa_mem_frag_tx(ffa_frag_handle(*args), args->arg3,
(args->arg4 >> 16) & 0xffff,
- current());
+ current);
return true;
case FFA_MSG_SEND_DIRECT_REQ_32:
*args = api_ffa_msg_send_direct_req(
ffa_msg_send_sender(*args),
- ffa_msg_send_receiver(*args), *args, current(), next);
+ ffa_msg_send_receiver(*args), *args, current, next);
return true;
case FFA_MSG_SEND_DIRECT_RESP_32:
*args = api_ffa_msg_send_direct_resp(
ffa_msg_send_sender(*args),
- ffa_msg_send_receiver(*args), *args, current(), next);
+ ffa_msg_send_receiver(*args), *args, current, next);
return true;
}
return false;
}
+#if SECURE_WORLD == 1
+
+static struct vcpu *get_other_world_vcpu(struct vcpu *current)
+{
+ struct vm *vm = vm_find(HF_OTHER_WORLD_ID);
+ ffa_vcpu_index_t current_cpu_index = cpu_index(current->cpu);
+
+ return vm_get_vcpu(vm, current_cpu_index);
+}
+
+/**
+ * Initially called from virtual FF-A instance (smc_handler and hvc_handler).
+ * Handles an FF-A function from a secure partition, and if necessary returns
+ * to the normal world and handles one or more FF-A functions from the normal
+ * world. Returns when it is ready to run a secure partition again.
+ */
+static bool ffa_handler_loop(struct ffa_value *ret, struct vcpu **next)
+{
+ struct vcpu *ffa_next = current();
+ struct vcpu *other_world_vcpu = get_other_world_vcpu(current());
+ bool handled = false;
+
+ /* The FF-A call originates from a partition in current world. */
+ handled = ffa_handler(ret, current(), &ffa_next);
+
+ while (handled) {
+ if (ffa_next != NULL) {
+ /*
+ * The FF-A call was handled and ffa_next is not null
+ * which means this vCPU can be resumed.
+ */
+ if (ffa_next != current()) {
+ *next = ffa_next;
+ }
+
+ /* Resume current or next EL1 partition. */
+ return true;
+ }
+
+ /*
+ * The FF-A call is handled and ffa_next is null which hints
+ * the result shall be passed to the other world.
+ */
+ *ret = smc_forward(ret->func, ret->arg1, ret->arg2, ret->arg3,
+ ret->arg4, ret->arg5, ret->arg6, ret->arg7);
+
+ /*
+ * Returned from EL3 thus next FF-A call is from
+ * physical FF-A instance.
+ */
+ handled = ffa_handler(ret, other_world_vcpu, &ffa_next);
+ }
+
+ return false;
+}
+
+#endif
+
/**
* Set or clear VI bit according to pending interrupts.
*/
@@ -464,7 +532,11 @@ static struct vcpu *smc_handler(struct vcpu *vcpu)
return next;
}
- if (ffa_handler(&args, &next)) {
+#if SECURE_WORLD == 1
+ if (ffa_handler_loop(&args, &next)) {
+#else
+ if (ffa_handler(&args, current(), &next)) {
+#endif
arch_regs_set_retval(&vcpu->regs, args);
update_vi(next);
return next;
@@ -645,7 +717,11 @@ struct vcpu *hvc_handler(struct vcpu *vcpu)
return next;
}
- if (ffa_handler(&args, &next)) {
+#if SECURE_WORLD == 1
+ if (ffa_handler_loop(&args, &next)) {
+#else
+ if (ffa_handler(&args, current(), &next)) {
+#endif
arch_regs_set_retval(&vcpu->regs, args);
update_vi(next);
return next;