feat(indirect message): add FFA_MSG_SEND2 support
FF-A v1.1 indirect message FFA_MSG_SEND2 support, allowing indirect
messaging between any endpoint (VM and SP).
When one of the endpoints is an SP, the SPMC is responsible for message
delivery to the receiver, potentially in the other world.
In order to allow cross world communication the SPMC is aware of VM
mailboxes and the Hypervisor forwards the FFA_MSG_SEND2 message to the
SPMC when the receiver is an SP.
Change-Id: Iba9b3d299b051ed3b105cb9e2b63e65fd4f662ce
Signed-off-by: Federico Recanati <federico.recanati@arm.com>
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index fc3c324..13ab1eb 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -516,6 +516,10 @@
ffa_msg_send_attributes(*args),
current, next);
return true;
+ case FFA_MSG_SEND2_32:
+ *args = api_ffa_msg_send2(ffa_sender(*args),
+ ffa_msg_send2_flags(*args), current);
+ return true;
case FFA_MSG_WAIT_32:
*args = api_ffa_msg_wait(current, next, args);
return true;
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index ecf7075..d3d9264 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -129,6 +129,25 @@
return false;
}
+bool plat_ffa_is_indirect_msg_supported(struct vm_locked sender_locked,
+ struct vm_locked receiver_locked)
+{
+ (void)sender_locked;
+ (void)receiver_locked;
+
+ return false;
+}
+
+bool plat_ffa_msg_send2_forward(ffa_vm_id_t receiver_vm_id,
+ ffa_vm_id_t sender_vm_id, struct ffa_value *ret)
+{
+ (void)receiver_vm_id;
+ (void)sender_vm_id;
+ (void)ret;
+
+ return false;
+}
+
ffa_memory_handle_t plat_ffa_memory_handle_make(uint64_t index)
{
return index | FFA_MEMORY_HANDLE_ALLOCATOR_HYPERVISOR;
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index 25c0e95..1ae5089 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -243,6 +243,43 @@
return false;
}
+bool plat_ffa_is_indirect_msg_supported(struct vm_locked sender_locked,
+ struct vm_locked receiver_locked)
+{
+ (void)sender_locked;
+ (void)receiver_locked;
+
+ /*
+ * Hypervisor is only for testing purposes, always allow indirect
+ * messages from VM.
+ */
+ return true;
+}
+
+bool plat_ffa_msg_send2_forward(ffa_vm_id_t receiver_vm_id,
+ ffa_vm_id_t sender_vm_id, struct ffa_value *ret)
+{
+ /* FFA_MSG_SEND2 is forwarded to SPMC when the receiver is an SP. */
+ if (!vm_id_is_current_world(receiver_vm_id)) {
+ /*
+ * Set the sender in arg1 to allow the SPMC to retrieve
+ * VM's TX buffer to copy in SP's RX buffer.
+ */
+ *ret = arch_other_world_call((struct ffa_value){
+ .func = FFA_MSG_SEND2_32, .arg1 = sender_vm_id << 16});
+ if (ffa_func_id(*ret) != FFA_SUCCESS_32) {
+ dlog_verbose(
+ "Failed forwarding FFA_MSG_SEND2_32 to the "
+ "SPMC, got error (%d).\n",
+ ret->arg2);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
ffa_memory_handle_t plat_ffa_memory_handle_make(uint64_t index)
{
return index | FFA_MEMORY_HANDLE_ALLOCATOR_HYPERVISOR;
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index d8eaeec..baa6e77 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -349,6 +349,55 @@
return false;
}
+/**
+ * Check that sender and receiver support indirect messages, in accordance
+ * to their configurations in the respective partition's FF-A manifest.
+ * Note: check is done at virtual FF-A instance only.
+ */
+bool plat_ffa_is_indirect_msg_supported(struct vm_locked sender_locked,
+ struct vm_locked receiver_locked)
+{
+ struct vm *sender_vm = sender_locked.vm;
+ struct vm *receiver_vm = receiver_locked.vm;
+
+ /*
+ * SPMC doesn't have information about VMs' configuration hence can't
+ * check if they are allowed to send indirect messages, but it's not a
+ * security threat.
+ */
+ if (vm_id_is_current_world(sender_vm->id)) {
+ if (!vm_supports_messaging_method(sender_vm,
+ FFA_PARTITION_INDIRECT_MSG)) {
+ dlog_verbose("VM %#x can't send indirect messages.\n",
+ sender_vm->id);
+ return false;
+ }
+ }
+
+ if (vm_id_is_current_world(receiver_vm->id)) {
+ if (!vm_supports_messaging_method(receiver_vm,
+ FFA_PARTITION_INDIRECT_MSG)) {
+ dlog_verbose(
+ "VM %#x can't receive indirect messages.\n",
+ receiver_vm->id);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool plat_ffa_msg_send2_forward(ffa_vm_id_t receiver_vm_id,
+ ffa_vm_id_t sender_vm_id, struct ffa_value *ret)
+{
+ /* SPMC never needs to forward a FFA_MSG_SEND2, it always handles it. */
+ (void)receiver_vm_id;
+ (void)sender_vm_id;
+ (void)ret;
+
+ return false;
+}
+
bool plat_ffa_is_notifications_create_valid(struct vcpu *current,
ffa_vm_id_t vm_id)
{
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index a18b34d..9eb3686 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -99,6 +99,25 @@
return false;
}
+bool plat_ffa_is_indirect_msg_supported(struct vm_locked sender_locked,
+ struct vm_locked receiver_locked)
+{
+ (void)sender_locked;
+ (void)receiver_locked;
+
+ return false;
+}
+
+bool plat_ffa_msg_send2_forward(ffa_vm_id_t receiver_vm_id,
+ ffa_vm_id_t sender_vm_id, struct ffa_value *ret)
+{
+ (void)receiver_vm_id;
+ (void)sender_vm_id;
+ (void)ret;
+
+ return false;
+}
+
ffa_memory_handle_t plat_ffa_memory_handle_make(uint64_t index)
{
return index;