FF-A: SPMC direct messaging interface.
Adaptation of direct messaging interface to the SPMC.
Change-Id: Ic27d19908d2071be57483a76da61c7f948b86bdb
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/src/api.c b/src/api.c
index bdf60d3..a514bf6 100644
--- a/src/api.c
+++ b/src/api.c
@@ -123,6 +123,34 @@
}
/**
+ * Choose next vCPU to run to be the counterpart vCPU in the other
+ * world (run the normal world if currently running in the secure
+ * world). Set current vCPU state to the given vcpu_state parameter.
+ * Set FF-A return values to the target vCPU in the other world.
+ *
+ * Called in context of a direct message response from a secure
+ * partition to a VM.
+ */
+static struct vcpu *api_switch_to_other_world(struct vcpu *current,
+ struct ffa_value other_world_ret,
+ enum vcpu_state vcpu_state)
+{
+ struct vcpu *next = vcpu_get_other_world_counterpart(current);
+
+ CHECK(next != NULL);
+
+ /* Set the return value for the other world's VM. */
+ arch_regs_set_retval(&next->regs, other_world_ret);
+
+ /* Set the current vCPU state. */
+ sl_lock(¤t->lock);
+ current->state = vcpu_state;
+ sl_unlock(¤t->lock);
+
+ return next;
+}
+
+/**
* Checks whether the given `to` VM's mailbox is currently busy, and optionally
* registers the `from` VM to be notified when it becomes available.
*/
@@ -1601,26 +1629,15 @@
struct vcpu **next)
{
struct ffa_value ret = (struct ffa_value){.func = FFA_INTERRUPT_32};
- ffa_vm_id_t current_vm_id = current->vm->id;
struct vm *receiver_vm;
struct vcpu *receiver_vcpu;
struct two_vcpu_locked vcpus_locked;
- /* Only allow primary VM to send direct message requests. */
- if (current_vm_id != HF_PRIMARY_VM_ID) {
+ if (!arch_other_world_is_direct_request_valid(current, sender_vm_id,
+ receiver_vm_id)) {
return ffa_error(FFA_NOT_SUPPORTED);
}
- /* Prevent sender_vm_id spoofing. */
- if (current_vm_id != sender_vm_id) {
- return ffa_error(FFA_INVALID_PARAMETERS);
- }
-
- /* Prevent a VM from sending messages to itself. */
- if (current_vm_id == receiver_vm_id) {
- return ffa_error(FFA_INVALID_PARAMETERS);
- }
-
receiver_vm = vm_find(receiver_vm_id);
if (receiver_vm == NULL) {
return ffa_error(FFA_INVALID_PARAMETERS);
@@ -1696,7 +1713,7 @@
receiver_vcpu->cpu = current->cpu;
receiver_vcpu->state = VCPU_STATE_RUNNING;
receiver_vcpu->regs_available = false;
- receiver_vcpu->direct_request_origin_vm_id = current_vm_id;
+ receiver_vcpu->direct_request_origin_vm_id = sender_vm_id;
arch_regs_set_retval(&receiver_vcpu->regs, (struct ffa_value){
.func = args.func,
@@ -1735,61 +1752,67 @@
struct vcpu *current,
struct vcpu **next)
{
- ffa_vm_id_t current_vm_id = current->vm->id;
- struct vcpu_locked vcpu_locked;
+ struct vcpu_locked current_locked;
- /* Only allow secondary VMs to send direct message responses. */
- if (current_vm_id == HF_PRIMARY_VM_ID) {
+ if (!arch_other_world_is_direct_response_valid(current, sender_vm_id,
+ receiver_vm_id)) {
return ffa_error(FFA_NOT_SUPPORTED);
}
- /* Prevent sender_vm_id spoofing. */
- if (current_vm_id != sender_vm_id) {
- return ffa_error(FFA_INVALID_PARAMETERS);
- }
-
- /* Prevent a VM from sending messages to itself. */
- if (current_vm_id == receiver_vm_id) {
- return ffa_error(FFA_INVALID_PARAMETERS);
- }
-
- vcpu_locked = vcpu_lock(current);
+ current_locked = vcpu_lock(current);
/*
* Ensure the terminating FFA_MSG_SEND_DIRECT_REQ had a
* defined originator.
*/
- if (!is_ffa_direct_msg_request_ongoing(vcpu_locked)) {
+ if (!is_ffa_direct_msg_request_ongoing(current_locked)) {
/*
* Sending direct response but direct request origin vCPU is
* not set.
*/
- vcpu_unlock(&vcpu_locked);
+ vcpu_unlock(¤t_locked);
return ffa_error(FFA_DENIED);
}
if (current->direct_request_origin_vm_id != receiver_vm_id) {
- vcpu_unlock(&vcpu_locked);
+ vcpu_unlock(¤t_locked);
return ffa_error(FFA_DENIED);
}
/* Clear direct request origin for the caller. */
current->direct_request_origin_vm_id = HF_INVALID_VM_ID;
- vcpu_unlock(&vcpu_locked);
+ vcpu_unlock(¤t_locked);
- *next = api_switch_to_primary(current,
- (struct ffa_value){
- .func = args.func,
- .arg1 = args.arg1,
- .arg2 = 0,
- .arg3 = args.arg3,
- .arg4 = args.arg4,
- .arg5 = args.arg5,
- .arg6 = args.arg6,
- .arg7 = args.arg7,
- },
- VCPU_STATE_BLOCKED_MAILBOX);
+ if (!vm_id_is_current_world(receiver_vm_id)) {
+ *next = api_switch_to_other_world(current,
+ (struct ffa_value){
+ .func = args.func,
+ .arg1 = args.arg1,
+ .arg2 = 0,
+ .arg3 = args.arg3,
+ .arg4 = args.arg4,
+ .arg5 = args.arg5,
+ .arg6 = args.arg6,
+ .arg7 = args.arg7,
+ },
+ VCPU_STATE_BLOCKED_MAILBOX);
+ } else if (receiver_vm_id == HF_PRIMARY_VM_ID) {
+ *next = api_switch_to_primary(current,
+ (struct ffa_value){
+ .func = args.func,
+ .arg1 = args.arg1,
+ .arg2 = 0,
+ .arg3 = args.arg3,
+ .arg4 = args.arg4,
+ .arg5 = args.arg5,
+ .arg6 = args.arg6,
+ .arg7 = args.arg7,
+ },
+ VCPU_STATE_BLOCKED_MAILBOX);
+ } else {
+ panic("Invalid direct message response invocation");
+ }
return (struct ffa_value){.func = FFA_INTERRUPT_32};
}
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 624899e..4d3a462 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -427,14 +427,6 @@
#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);
-}
-
/**
* Called to switch to the other world and handle FF-A calls from it. Returns
* when it is ready to run a secure partition again.
@@ -539,7 +531,8 @@
arch_regs_set_retval(&vcpu->regs, args);
#if SECURE_WORLD == 1
- struct vcpu *other_world_vcpu = get_other_world_vcpu(current());
+ struct vcpu *other_world_vcpu =
+ vcpu_get_other_world_counterpart(current());
if (*next == other_world_vcpu) {
/*
diff --git a/src/arch/aarch64/hypervisor/other_world.c b/src/arch/aarch64/hypervisor/other_world.c
index 39b5752..8868873 100644
--- a/src/arch/aarch64/hypervisor/other_world.c
+++ b/src/arch/aarch64/hypervisor/other_world.c
@@ -107,6 +107,77 @@
#endif
}
+/**
+ * Check validity of a FF-A direct message request.
+ */
+bool arch_other_world_is_direct_request_valid(struct vcpu *current,
+ ffa_vm_id_t sender_vm_id,
+ ffa_vm_id_t receiver_vm_id)
+{
+ ffa_vm_id_t current_vm_id = current->vm->id;
+
+#if SECURE_WORLD == 1
+
+ /*
+ * The normal world can send direct message requests
+ * via the Hypervisor to any SP.
+ */
+ return sender_vm_id != receiver_vm_id &&
+ current_vm_id == HF_HYPERVISOR_VM_ID &&
+ vm_id_is_current_world(receiver_vm_id) &&
+ !vm_id_is_current_world(sender_vm_id);
+
+#else
+
+ /*
+ * The primary VM can send direct message request to
+ * any other VM (but itself) or SP, but can't spoof
+ * a different sender.
+ */
+ return sender_vm_id != receiver_vm_id &&
+ sender_vm_id == current_vm_id &&
+ current_vm_id == HF_PRIMARY_VM_ID;
+
+#endif
+
+ return false;
+}
+
+/**
+ * Check validity of a FF-A direct message response.
+ */
+bool arch_other_world_is_direct_response_valid(struct vcpu *current,
+ ffa_vm_id_t sender_vm_id,
+ ffa_vm_id_t receiver_vm_id)
+{
+ ffa_vm_id_t current_vm_id = current->vm->id;
+
+#if SECURE_WORLD == 1
+
+ /*
+ * Direct message responses emitted from a SP
+ * target a VM in NWd.
+ */
+ return sender_vm_id != receiver_vm_id &&
+ sender_vm_id == current_vm_id &&
+ vm_id_is_current_world(sender_vm_id) &&
+ !vm_id_is_current_world(receiver_vm_id);
+
+#else
+
+ /*
+ * Secondary VMs can send direct message responses to
+ * the PVM, but can't spoof a different sender.
+ */
+ return sender_vm_id != receiver_vm_id &&
+ sender_vm_id == current_vm_id &&
+ receiver_vm_id == HF_PRIMARY_VM_ID;
+
+#endif
+
+ return false;
+}
+
struct ffa_value arch_other_world_call(struct ffa_value args)
{
return smc_ffa_call(args);
diff --git a/src/arch/fake/hypervisor/other_world.c b/src/arch/fake/hypervisor/other_world.c
index 57df952..c41e1d6 100644
--- a/src/arch/fake/hypervisor/other_world.c
+++ b/src/arch/fake/hypervisor/other_world.c
@@ -17,3 +17,25 @@
dlog_error("Attempted to call TEE function %#x\n", args.func);
return ffa_error(FFA_NOT_SUPPORTED);
}
+
+bool arch_other_world_is_direct_request_valid(struct vcpu *current,
+ ffa_vm_id_t sender_vm_id,
+ ffa_vm_id_t receiver_vm_id)
+{
+ (void)current;
+ (void)sender_vm_id;
+ (void)receiver_vm_id;
+
+ return true;
+}
+
+bool arch_other_world_is_direct_response_valid(struct vcpu *current,
+ ffa_vm_id_t sender_vm_id,
+ ffa_vm_id_t receiver_vm_id)
+{
+ (void)current;
+ (void)sender_vm_id;
+ (void)receiver_vm_id;
+
+ return true;
+}
diff --git a/src/manifest.c b/src/manifest.c
index 273d445..60b0fa3 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -617,7 +617,8 @@
ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
}
- if (vm->sp.messaging_method != INDIRECT_MESSAGING) {
+ if (vm->sp.messaging_method != INDIRECT_MESSAGING &&
+ vm->sp.messaging_method != DIRECT_MESSAGING) {
dlog_error("Messaging method %s: %x\n", error_string,
vm->sp.messaging_method);
ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
diff --git a/src/vcpu.c b/src/vcpu.c
index 7f1746f..1e4d777 100644
--- a/src/vcpu.c
+++ b/src/vcpu.c
@@ -181,3 +181,15 @@
return resume;
}
+
+/**
+ * Return the vCPU corresponding to the other world vCPU whose index
+ * matches current vCPU index.
+ */
+struct vcpu *vcpu_get_other_world_counterpart(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);
+}