Merge changes from topic "mp/cpu_off_broadcast"

* changes:
  test: deny prohibited ABIs while handling CPU_OFF psci msg
  feat: add build flag to control support for CPU_OFF psci msg
  feat(cactus): receive psci msg through direct req framework msg
diff --git a/Makefile b/Makefile
index 4936ff7..29b0f3b 100644
--- a/Makefile
+++ b/Makefile
@@ -171,6 +171,7 @@
 $(eval $(call assert_boolean,ENABLE_REALM_PAYLOAD_TESTS))
 $(eval $(call assert_boolean,TRANSFER_LIST))
 $(eval $(call assert_boolean,SPMC_AT_EL3))
+$(eval $(call assert_boolean,CACTUS_PWR_MGMT_SUPPORT))
 
 ################################################################################
 # Process build options
@@ -199,6 +200,7 @@
 $(eval $(call add_define,TFTF_DEFINES,TRANSFER_LIST))
 $(eval $(call add_define,TFTF_DEFINES,PLAT_AMU_GROUP1_COUNTERS_MASK))
 $(eval $(call add_define,TFTF_DEFINES,SPMC_AT_EL3))
+$(eval $(call add_define,TFTF_DEFINES,CACTUS_PWR_MGMT_SUPPORT))
 
 ################################################################################
 
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 08343e3..3f62958 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -155,6 +155,14 @@
 - ``SPMC_AT_EL3``: This flag is required to match the feature set of Cactus SP that
    are implemented in TF-A EL3 SPMC. Default value is 0.
 
+-  ``CACTUS_PWR_MGMT_SUPPORT``: If a Cactus SP subscribes to receiving power
+   management framework message through its partition manifest, this flag
+   controls whether the SP supports handling the aforementioned message. This
+   option can take either 0 (unsupported) or 1 (supported). Default value is 1.
+
+   Note that a value of 0 is particularly useful in stress testing of power
+   management handling by the SPMC.
+
 Realm payload specific Build Options
 ------------------------------------
 
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..67fd393 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,7 +960,12 @@
 					    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_yield(void);
 struct ffa_value ffa_version(uint32_t input_version);
 struct ffa_value ffa_id_get(void);
 struct ffa_value ffa_spm_id_get(void);
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 3a7f8bf..337c6a6 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -59,3 +59,10 @@
 # This flag is required to match the feature set of Cactus SP that are
 # implemented in TF-A EL3 SPMC.
 SPMC_AT_EL3		:= 0
+
+# If a Cactus SP subscribes to receiving power management framework message
+# through its partition manifest, this flag controls whether the SP supports
+# handling the aforementioned message. This option can take either 0
+# (unsupported) or 1 (supported). Default value is 1. Note that a value of 0 is
+# particularly useful in stress testing of power management handling by the SPMC.
+CACTUS_PWR_MGMT_SUPPORT	:= 1
diff --git a/spm/cactus/cactus.mk b/spm/cactus/cactus.mk
index 7d39221..34565f0 100644
--- a/spm/cactus/cactus.mk
+++ b/spm/cactus/cactus.mk
@@ -100,6 +100,7 @@
 $(eval $(call add_define,CACTUS_DEFINES,PLAT_${PLAT}))
 $(eval $(call add_define,CACTUS_DEFINES,PLAT_XLAT_TABLES_DYNAMIC))
 $(eval $(call add_define,CACTUS_DEFINES,SPMC_AT_EL3))
+$(eval $(call add_define,CACTUS_DEFINES,CACTUS_PWR_MGMT_SUPPORT))
 
 $(CACTUS_DTB) : $(BUILD_PLAT)/cactus $(BUILD_PLAT)/cactus/cactus.elf
 $(CACTUS_DTB) : $(CACTUS_DTS)
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..aba3124 100644
--- a/spm/cactus/cactus_tests/cactus_message_loop.c
+++ b/spm/cactus/cactus_tests/cactus_message_loop.c
@@ -11,7 +11,9 @@
 #include <ffa_helpers.h>
 #include <events.h>
 #include <platform.h>
+#include <sp_helpers.h>
 #include <spm_helpers.h>
+#include <psci.h>
 
 /**
  * Counter of the number of handled requests, for each CPU. The number of
@@ -99,3 +101,87 @@
 				 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;
+
+#if CACTUS_PWR_MGMT_SUPPORT == 1
+	uint32_t framework_msg = ffa_get_framework_msg(args);
+	uint32_t psci_function = args.arg3;
+	struct ffa_value ret;
+
+	/*
+	 * 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;
+
+	/*
+	 * FF-A spec states that SPs are prohibited from invoking Direct
+	 * request, FFA_RUN and FFA_YIELD interfaces while handling power
+	 * management framework message. Make the Cactus SP intentionally
+	 * invoke prohibited interfaces and attest that SPMC should deny such
+	 * invocations.
+	 */
+	ret = cactus_success_resp(destination_id, source_id, status_code);
+
+	/* Non-framework direct response must be denied. */
+	EXPECT(ffa_func_id(ret), FFA_ERROR);
+	EXPECT(ffa_error_code(ret), FFA_ERROR_DENIED);
+
+	ret = cactus_echo_send_cmd(destination_id, SP_ID(4), 0x9999);
+
+	/* Direct request message must be denied. */
+	EXPECT(ffa_func_id(ret), FFA_ERROR);
+	EXPECT(ffa_error_code(ret), FFA_ERROR_DENIED);
+
+	ret = ffa_run(SP_ID(4), 0);
+
+	/* FFA_RUN invocation must be denied. */
+	EXPECT(ffa_func_id(ret), FFA_ERROR);
+	EXPECT(ffa_error_code(ret), FFA_ERROR_DENIED);
+
+	ret = ffa_yield();
+
+	/* FFA_YIELD invocation must be denied. */
+	EXPECT(ffa_func_id(ret), FFA_ERROR);
+	EXPECT(ffa_error_code(ret), FFA_ERROR_DENIED);
+
+	/*
+	 * 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:
+#else
+	status_code = PSCI_E_DENIED;
+#endif
+	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..3dc7036 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -142,6 +142,29 @@
 	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);
+}
+
+struct ffa_value ffa_yield(void)
+{
+	struct ffa_value args = {
+		.fid = FFA_MSG_YIELD,
+	};
+
+	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,