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,