feat(ff-a): handle forwarded FFA_VERSION from SPMD

The SPMD must forward calls to FFA_VERSION to the SPMC so that the
ff-a version of the callee can be saved for later use. Since the
return value of FFA_VERSION is not wrapped in a FF-A call we must
forward the call using a direct message request from the SPMD to
the SPMC. W2 of this request is used to identify the function
that should handle the message. Update the spmd_handler function
to choose the appropriate function to handle the message based on
W2 for both PSCI and FFA_VERSION.

Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: Ibf55f33130242303dd19f500f55abed5f06dbbef
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index bf5d530..94a0c5b 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -56,6 +56,15 @@
  */
 #define CLIENT_ID_MASK UINT64_C(0xffff)
 
+/*
+ * Target function IDs for framework messages from the SPMD.
+ */
+#define SPMD_FWK_MSG_BIT UINT64_C(1 << 31)
+#define SPMD_FWK_MSG_FUNC_MASK UINT64_C(0xFF)
+#define SPMD_FWK_MSG_PSCI UINT8_C(0)
+#define SPMD_FWK_MSG_FFA_VERSION_REQ UINT8_C(0x8)
+#define SPMD_FWK_MSG_FFA_VERSION_RESP UINT8_C(0x9)
+
 /**
  * Returns a reference to the currently executing vCPU.
  */
@@ -367,39 +376,67 @@
 	ffa_vm_id_t sender = ffa_sender(*args);
 	ffa_vm_id_t receiver = ffa_receiver(*args);
 	ffa_vm_id_t current_vm_id = current->vm->id;
+	uint32_t fwk_msg = ffa_fwk_msg(*args);
+	uint8_t fwk_msg_func_id = fwk_msg & SPMD_FWK_MSG_FUNC_MASK;
 
 	/*
-	 * Check if direct message request is originating from the SPMD and
-	 * directed to the SPMC.
+	 * Check if direct message request is originating from the SPMD,
+	 * directed to the SPMC and the message is a framework message.
 	 */
 	if (!(sender == HF_SPMD_VM_ID && receiver == HF_SPMC_VM_ID &&
-	      current_vm_id == HF_OTHER_WORLD_ID)) {
+	      current_vm_id == HF_OTHER_WORLD_ID) ||
+	    (fwk_msg & SPMD_FWK_MSG_BIT) == 0) {
 		return false;
 	}
 
-	switch (args->arg3) {
-	case PSCI_CPU_OFF: {
-		struct vm *vm = vm_get_first_boot();
-		struct vcpu *vcpu = vm_get_vcpu(vm, vcpu_index(current));
+	switch (fwk_msg_func_id) {
+	case SPMD_FWK_MSG_PSCI: {
+		switch (args->arg3) {
+		case PSCI_CPU_OFF: {
+			struct vm *vm = vm_get_first_boot();
+			struct vcpu *vcpu =
+				vm_get_vcpu(vm, vcpu_index(current));
 
-		/*
-		 * TODO: the PM event reached the SPMC. In a later iteration,
-		 * the PM event can be passed to the SP by resuming it.
-		 */
+			/*
+			 * TODO: the PM event reached the SPMC. In a later
+			 * iteration, the PM event can be passed to the SP by
+			 * resuming it.
+			 */
+			*args = (struct ffa_value){
+				.func = FFA_MSG_SEND_DIRECT_RESP_32,
+				.arg1 = ((uint64_t)HF_SPMC_VM_ID << 16) |
+					HF_SPMD_VM_ID,
+				.arg2 = 0U};
+
+			dlog_verbose("%s cpu off notification cpuid %#x\n",
+				     __func__, vcpu->cpu->id);
+			cpu_off(vcpu->cpu);
+			break;
+		}
+		default:
+			dlog_verbose("%s PSCI message not handled %#x\n",
+				     __func__, args->arg3);
+			return false;
+		}
+	}
+	case SPMD_FWK_MSG_FFA_VERSION_REQ: {
+		struct ffa_value ret = api_ffa_version(current, args->arg3);
 		*args = (struct ffa_value){
 			.func = FFA_MSG_SEND_DIRECT_RESP_32,
 			.arg1 = ((uint64_t)HF_SPMC_VM_ID << 16) | HF_SPMD_VM_ID,
-			.arg2 = 0U};
-
-		dlog_verbose("%s cpu off notification cpuid %#x\n", __func__,
-			     vcpu->cpu->id);
-		cpu_off(vcpu->cpu);
+			/* Set bit 31 since this is a framework message. */
+			.arg2 = SPMD_FWK_MSG_BIT |
+				SPMD_FWK_MSG_FFA_VERSION_RESP,
+			.arg3 = ret.func};
 		break;
 	}
 	default:
-		dlog_verbose("%s message not handled %#x\n", __func__,
-			     args->arg3);
-		return false;
+		dlog_verbose("%s message not handled %#x\n", __func__, fwk_msg);
+		*args = (struct ffa_value){
+			.func = FFA_MSG_SEND_DIRECT_RESP_32,
+			.arg1 = ((uint64_t)HF_SPMC_VM_ID << 16) | HF_SPMD_VM_ID,
+			/* Set bit 31 since this is a framework message. */
+			.arg2 = SPMD_FWK_MSG_BIT | fwk_msg_func_id};
 	}
 
 	return true;