feat(cactus): receive psci msg through direct req framework msg

Cactus receives PSCI CPU_OFF power management operation message
through framework direct request message and it will respond back
with framework direct message if all conditions are met.

Cactus SP1 and SP2 explicitly subscribe to CPU_OFF power management
message through their respective manifests.

Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Change-Id: I790a8698d238e29847e376b4fa9447a6241ef17e
diff --git a/include/runtime_services/cactus_message_loop.h b/include/runtime_services/cactus_message_loop.h
index 4d963ac..a13f42f 100644
--- a/include/runtime_services/cactus_message_loop.h
+++ b/include/runtime_services/cactus_message_loop.h
@@ -42,3 +42,5 @@
 
 bool cactus_handle_cmd(struct ffa_value *cmd_args, struct ffa_value *ret,
 		       struct mailbox_buffers *mb);
+
+struct ffa_value cactus_handle_framework_msg(struct ffa_value args);
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index 0a63e96..24a7e38 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -349,6 +349,33 @@
 	return (args.arg2 >> 48) & 0xFFFFU;
 }
 
+/**
+ * FF-A Framework message helpers
+ */
+#define FFA_FRAMEWORK_MSG_BIT (1U << 31)
+
+#define FFA_FRAMEWORK_MSG_MASK 0xFFU
+
+#define FFA_FRAMEWORK_MSG_PSCI_REQ 0U
+#define FFA_FRAMEWORK_MSG_PSCI_RESP 2U
+
+static inline uint32_t ffa_framework_msg_flags(struct ffa_value args)
+{
+	return (uint32_t)args.arg2;
+}
+
+static inline bool ffa_is_framework_msg(struct ffa_value args)
+{
+	return (ffa_func_id(args) == FFA_MSG_SEND_DIRECT_REQ_SMC32 ||
+		ffa_func_id(args) == FFA_MSG_SEND_DIRECT_REQ_SMC64) &&
+		((ffa_framework_msg_flags(args) & FFA_FRAMEWORK_MSG_BIT) != 0);
+}
+
+static inline uint32_t ffa_get_framework_msg(struct ffa_value args)
+{
+	return ffa_framework_msg_flags(args) & FFA_FRAMEWORK_MSG_MASK;
+}
+
 typedef uint64_t ffa_notification_bitmap_t;
 
 /**
@@ -933,6 +960,10 @@
 					    uint32_t arg1, uint32_t arg2,
 					    uint32_t arg3, uint32_t arg4);
 
+struct ffa_value ffa_framework_msg_send_direct_resp(ffa_id_t source_id,
+					    ffa_id_t dest_id, uint32_t msg,
+					    uint32_t status_code);
+
 struct ffa_value ffa_run(uint32_t dest_id, uint32_t vcpu_id);
 struct ffa_value ffa_version(uint32_t input_version);
 struct ffa_value ffa_id_get(void);
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index 8554709..4a28862 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -102,6 +102,11 @@
 			continue;
 		}
 
+		if (ffa_is_framework_msg(ffa_ret)) {
+			ffa_ret = cactus_handle_framework_msg(ffa_ret);
+			continue;
+		}
+
 		destination = ffa_dir_msg_dest(ffa_ret);
 		if (destination != vm_id) {
 			ERROR("%s(%u) invalid vm id 0x%x\n",
diff --git a/spm/cactus/cactus_tests/cactus_message_loop.c b/spm/cactus/cactus_tests/cactus_message_loop.c
index c0abf2b..9a8e9a1 100644
--- a/spm/cactus/cactus_tests/cactus_message_loop.c
+++ b/spm/cactus/cactus_tests/cactus_message_loop.c
@@ -12,6 +12,7 @@
 #include <events.h>
 #include <platform.h>
 #include <spm_helpers.h>
+#include <psci.h>
 
 /**
  * Counter of the number of handled requests, for each CPU. The number of
@@ -99,3 +100,49 @@
 				 CACTUS_ERROR_UNHANDLED);
 	return true;
 }
+
+struct ffa_value cactus_handle_framework_msg(struct ffa_value args)
+{
+	ffa_id_t source_id = ffa_dir_msg_source(args);
+	ffa_id_t destination_id = ffa_dir_msg_dest(args);
+	uint32_t status_code;
+	uint32_t framework_msg = ffa_get_framework_msg(args);
+	uint32_t psci_function = args.arg3;
+
+	/*
+	 * As of now, Cactus supports receiving only PSCI power management
+	 * request as framework message.
+	 */
+	if (framework_msg != FFA_FRAMEWORK_MSG_PSCI_REQ) {
+		ERROR("Unsupported framework message received by SP:%x\n",
+					destination_id);
+		status_code = PSCI_E_DENIED;
+		goto out;
+	}
+
+	/* Cactus only supports receiving CPU_OFF PSCI function as message. */
+	if (psci_function != SMC_PSCI_CPU_OFF) {
+		ERROR("Unsupported PSCI function(%x) received by SP:%x through "
+			"framework message\n", psci_function, destination_id);
+		status_code = PSCI_E_DENIED;
+		goto out;
+	}
+
+	/* Only SPMC can send the PSCI framework message. */
+	if (source_id != SPMC_ID) {
+		ERROR("Framework message source illegal %x\n", source_id);
+		status_code = PSCI_E_DENIED;
+		goto out;
+	}
+
+	status_code = PSCI_E_SUCCESS;
+	/*
+	 * Return successful status for PSCI power management request through
+	 * direct response Framework message.
+	 */
+	VERBOSE("PSCI power management request handled successfully by SP:%x\n",
+							destination_id);
+out:
+	return ffa_framework_msg_send_direct_resp(destination_id, source_id,
+				FFA_FRAMEWORK_MSG_PSCI_RESP, status_code);
+}
diff --git a/spm/cactus/plat/arm/fvp/fdts/cactus-secondary.dts b/spm/cactus/plat/arm/fvp/fdts/cactus-secondary.dts
index 0f6c23d..a8130c6 100644
--- a/spm/cactus/plat/arm/fvp/fdts/cactus-secondary.dts
+++ b/spm/cactus/plat/arm/fvp/fdts/cactus-secondary.dts
@@ -30,6 +30,7 @@
 	messaging-method = <3>; /* Direct messaging only */
 	ns-interrupts-action = <2>; /* Non secure interrupts are signaled. */
 	notification-support; /* Support receipt of notifications. */
+	power-management-messages = <1>; /* Support CPU_OFF power management message. */
 
 	rx_tx-info {
 		compatible = "arm,ffa-manifest-rx_tx-buffer";
diff --git a/spm/cactus/plat/arm/fvp/fdts/cactus.dts b/spm/cactus/plat/arm/fvp/fdts/cactus.dts
index 4d95069..03a7d17 100644
--- a/spm/cactus/plat/arm/fvp/fdts/cactus.dts
+++ b/spm/cactus/plat/arm/fvp/fdts/cactus.dts
@@ -30,6 +30,7 @@
 	messaging-method = <7>; /* Indirect Messaging and direct messaging. */
 	ns-interrupts-action = <1>; /* Managed exit is supported */
 	notification-support; /* Support receipt of notifications. */
+	power-management-messages = <1>; /* Support CPU_OFF power management message. */
 
 	/* Boot protocol */
 	gp-register-num = <0>;
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index e0388db..1d128ab 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -142,6 +142,20 @@
 	return ffa_service_call(&args);
 }
 
+struct ffa_value ffa_framework_msg_send_direct_resp(ffa_id_t source_id,
+					    ffa_id_t dest_id, uint32_t msg,
+					    uint32_t status_code)
+{
+	struct ffa_value args = {
+		.fid = FFA_MSG_SEND_DIRECT_RESP_SMC32,
+		.arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
+		.arg2 = ((uint32_t)(1 << 31)) | (msg & 0xFF),
+		.arg3 = status_code,
+	};
+
+	return ffa_service_call(&args);
+}
+
 void ffa_memory_region_init_header(struct ffa_memory_region *memory_region,
 				   ffa_id_t sender,
 				   ffa_memory_attributes_t attributes,