Merge "fix(fwu): invalidate the data cache for NS_BL1U and NS_BL2U images"
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index 332f1d8..9031b34 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -10,6 +10,7 @@
#include <arch_features.h>
#include <ffa_svc.h>
#include <plat_topology.h>
+#include <events.h>
#include <psci.h>
#include <spm_common.h>
#include <tftf_lib.h>
@@ -341,4 +342,14 @@
uint32_t ffa_version_minor, const struct ffa_uuid *ffa_uuids,
size_t ffa_uuids_size);
+/**
+ * Turn on all cpus to execute a test in all.
+ * - 'cpu_on_handler' should have the code containing the test.
+ * - 'cpu_booted' is used for notifying which cores the test has been executed.
+ * This should be used in the test executed by cpu_on_handler at the end of
+ * processing to make sure it complies with this function's implementation.
+ */
+test_result_t spm_run_multi_core_test(uintptr_t cpu_on_handler,
+ event_t *cpu_booted);
+
#endif /* __TEST_HELPERS_H__ */
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 85e8cd8..4350fbd 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -145,6 +145,11 @@
#define ID_AA64PFR0_CSV2_SHIFT U(56)
#define ID_AA64PFR0_CSV2_MASK ULL(0xf)
#define ID_AA64PFR0_CSV2_LENGTH U(4)
+#define ID_AA64PFR0_FEAT_RME_SHIFT U(52)
+#define ID_AA64PFR0_FEAT_RME_MASK ULL(0xf)
+#define ID_AA64PFR0_FEAT_RME_LENGTH U(4)
+#define ID_AA64PFR0_FEAT_RME_NOT_SUPPORTED U(0)
+#define ID_AA64PFR0_FEAT_RME_V1 U(1)
/* ID_AA64DFR0_EL1.PMS definitions (for ARMv8.2+) */
#define ID_AA64DFR0_PMS_SHIFT U(32)
diff --git a/include/lib/aarch64/arch_features.h b/include/lib/aarch64/arch_features.h
index edc40f0..1002936 100644
--- a/include/lib/aarch64/arch_features.h
+++ b/include/lib/aarch64/arch_features.h
@@ -125,4 +125,15 @@
ID_AA64DFR0_TRACEVER_SUPPORTED;
}
+static inline unsigned int get_armv9_2_feat_rme_support(void)
+{
+ /*
+ * Return the RME version, zero if not supported. This function can be
+ * used as both an integer value for the RME version or compared to zero
+ * to detect RME presence.
+ */
+ return (unsigned int)(read_id_aa64pfr0_el1() >>
+ ID_AA64PFR0_FEAT_RME_SHIFT) & ID_AA64PFR0_FEAT_RME_MASK;
+}
+
#endif /* ARCH_FEATURES_H */
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index eba1c9e..b25b6a1 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -70,6 +70,9 @@
#define FFA_NOTIFICATIONS_FLAG_PER_VCPU UINT32_C(0x1 << 0)
+/** Flag to delay Schedule Receiver Interrupt. */
+#define FFA_NOTIFICATIONS_FLAG_DELAY_SRI UINT32_C(0x1 << 1)
+
#define FFA_NOTIFICATIONS_FLAGS_VCPU_ID(id) UINT32_C((id & 0xFFFF) << 16)
#define FFA_NOTIFICATIONS_FLAG_BITMAP_SP UINT32_C(0x1 << 0)
@@ -93,6 +96,38 @@
return FFA_NOTIFICATIONS_BITMAP(val.ret4, val.ret5);
}
+/*
+ * FFA_NOTIFICATION_INFO_GET is a SMC64 interface.
+ * The following macros are defined for SMC64 implementation.
+ */
+#define FFA_NOTIFICATIONS_INFO_GET_MAX_IDS 20U
+
+#define FFA_NOTIFICATIONS_INFO_GET_FLAG_MORE_PENDING UINT64_C(0x1)
+
+#define FFA_NOTIFICATIONS_LISTS_COUNT_SHIFT 0x7U
+#define FFA_NOTIFICATIONS_LISTS_COUNT_MASK 0x1FU
+#define FFA_NOTIFICATIONS_LIST_SHIFT(l) (2 * (l - 1) + 12)
+#define FFA_NOTIFICATIONS_LIST_SIZE_MASK 0x3U
+
+static inline uint32_t ffa_notifications_info_get_lists_count(
+ smc_ret_values ret)
+{
+ return (uint32_t)(ret.ret2 >> FFA_NOTIFICATIONS_LISTS_COUNT_SHIFT)
+ & FFA_NOTIFICATIONS_LISTS_COUNT_MASK;
+}
+
+static inline uint32_t ffa_notifications_info_get_list_size(
+ smc_ret_values ret, uint32_t list)
+{
+ return (uint32_t)(ret.ret2 >> FFA_NOTIFICATIONS_LIST_SHIFT(list)) &
+ FFA_NOTIFICATIONS_LIST_SIZE_MASK;
+}
+
+static inline bool ffa_notifications_info_get_more_pending(smc_ret_values ret)
+{
+ return (ret.ret2 & FFA_NOTIFICATIONS_INFO_GET_FLAG_MORE_PENDING) != 0U;
+}
+
enum ffa_data_access {
FFA_DATA_ACCESS_NOT_SPECIFIED,
FFA_DATA_ACCESS_RO,
@@ -473,6 +508,7 @@
ffa_notification_bitmap_t bitmap);
smc_ret_values ffa_notification_get(ffa_id_t receiver, uint32_t vcpu_id,
uint32_t flags);
+smc_ret_values ffa_notification_info_get(void);
#endif /* __ASSEMBLY__ */
#endif /* FFA_HELPERS_H */
diff --git a/include/runtime_services/ffa_svc.h b/include/runtime_services/ffa_svc.h
index df19f98..4a62a79 100644
--- a/include/runtime_services/ffa_svc.h
+++ b/include/runtime_services/ffa_svc.h
@@ -12,13 +12,15 @@
#include <uuid.h>
/* FFA error codes. */
-#define FFA_ERROR_NOT_SUPPORTED -1
+#define FFA_ERROR_NOT_SUPPORTED -1
#define FFA_ERROR_INVALID_PARAMETER -2
#define FFA_ERROR_NO_MEMORY -3
#define FFA_ERROR_BUSY -4
#define FFA_ERROR_INTERRUPTED -5
#define FFA_ERROR_DENIED -6
-#define FFA_ERROR_RETRY -7
+#define FFA_ERROR_RETRY -7
+#define FFA_ERROR_ABORTED -8
+#define FFA_ERROR_NO_DATA -9
/* The macros below are used to identify FFA calls from the SMC function ID */
#define FFA_FNUM_MIN_VALUE U(0x60)
@@ -135,6 +137,8 @@
#define FFA_NOTIFICATION_UNBIND FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_UNBIND)
#define FFA_NOTIFICATION_SET FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_SET)
#define FFA_NOTIFICATION_GET FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_GET)
+#define FFA_NOTIFICATION_INFO_GET \
+ FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_INFO_GET)
#define FFA_SPM_ID_GET FFA_FID(SMC_32, FFA_FNUM_SPM_ID_GET)
/* FFA SMC64 FIDs */
@@ -151,7 +155,8 @@
FFA_FID(SMC_64, FFA_FNUM_MEM_RETRIEVE_REQ)
#define FFA_SECONDARY_EP_REGISTER_SMC64 \
FFA_FID(SMC_64, FFA_FNUM_SECONDARY_EP_REGISTER)
-
+#define FFA_NOTIFICATION_INFO_GET_SMC64 \
+ FFA_FID(SMC_64, FFA_FNUM_NOTIFICATION_INFO_GET)
/*
* Reserve a special value for traffic targeted to the Hypervisor or SPM.
*/
diff --git a/include/runtime_services/realm_payload/realm_payload_test.h b/include/runtime_services/realm_payload/realm_payload_test.h
new file mode 100644
index 0000000..eccdbb3
--- /dev/null
+++ b/include/runtime_services/realm_payload/realm_payload_test.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <smccc.h>
+#include <tftf_lib.h>
+
+#define RMI_FNUM_MIN_VALUE U(0x00)
+#define RMI_FNUM_MAX_VALUE U(0x20)
+
+/* Get RMI fastcall std FID from function number */
+#define RMI_FID(smc_cc, func_num) \
+ ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) | \
+ ((smc_cc) << FUNCID_CC_SHIFT) | \
+ (OEN_ARM_START << FUNCID_OEN_SHIFT) | \
+ ((func_num) << FUNCID_NUM_SHIFT))
+
+/*
+ * SMC_RMM_INIT_COMPLETE is the only function in the RMI that originates from
+ * the Realm world and is handled by the RMMD. The remaining functions are
+ * always invoked by the Normal world, forwarded by RMMD and handled by the
+ * RMM
+ */
+#define RMI_FNUM_VERSION_REQ U(0)
+
+#define RMI_FNUM_GRAN_NS_REALM U(1)
+#define RMI_FNUM_GRAN_REALM_NS U(0x10)
+
+/********************************************************************************/
+
+
+/* RMI SMC64 FIDs handled by the RMMD */
+#define RMI_RMM_REQ_VERSION RMI_FID(SMC_64, RMI_FNUM_VERSION_REQ)
+
+#define SMC_RMM_GRANULE_DELEGATE RMI_FID(SMC_64, RMI_FNUM_GRAN_NS_REALM)
+#define SMC_RMM_GRANULE_UNDELEGATE RMI_FID(SMC_64, RMI_FNUM_GRAN_REALM_NS)
+
+#define RMI_ABI_VERSION_GET_MAJOR(_version) ((_version) >> 16)
+#define RMI_ABI_VERSION_GET_MINOR(_version) ((_version) & 0xFFFF)
+
+#define NUM_GRANULES 5
+#define NUM_RANDOM_ITERATIONS 7
+#define GRANULE_SIZE 4096
+
+#define B_DELEGATED 0
+#define B_UNDELEGATED 1
+
+#define NUM_CPU_DED_SPM PLATFORM_CORE_COUNT / 2
+
+u_register_t realm_version(void);
+u_register_t realm_granule_delegate(uintptr_t);
+u_register_t realm_granule_undelegate(uintptr_t);
diff --git a/tftf/tests/common/test_helpers.c b/tftf/tests/common/test_helpers.c
index fffad67..80497bd 100644
--- a/tftf/tests/common/test_helpers.c
+++ b/tftf/tests/common/test_helpers.c
@@ -176,3 +176,46 @@
return TEST_RESULT_SUCCESS;
}
+
+test_result_t spm_run_multi_core_test(uintptr_t cpu_on_handler,
+ event_t *cpu_done)
+{
+ unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int core_pos, cpu_node, mpidr;
+ int32_t ret;
+
+ VERBOSE("Powering on all cpus.\n");
+
+ for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+ tftf_init_event(&cpu_done[i]);
+ }
+
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (mpidr == lead_mpid) {
+ continue;
+ }
+
+ ret = tftf_cpu_on(mpidr, cpu_on_handler, 0U);
+ if (ret != 0) {
+ ERROR("tftf_cpu_on mpidr 0x%x returns %d\n",
+ mpidr, ret);
+ }
+ }
+
+ VERBOSE("Waiting secondary CPUs to turn off ...\n");
+
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (mpidr == lead_mpid) {
+ continue;
+ }
+
+ core_pos = platform_get_core_pos(mpidr);
+ tftf_wait_for_event(&cpu_done[core_pos]);
+ }
+
+ VERBOSE("Done exiting.\n");
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c b/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c
new file mode 100644
index 0000000..e552ecb
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c
@@ -0,0 +1,386 @@
+#include <stdlib.h>
+
+#include <debug.h>
+#include <smccc.h>
+
+#include <arch_helpers.h>
+#include <cactus_test_cmds.h>
+#include <ffa_endpoints.h>
+#include <ffa_svc.h>
+#include <lib/events.h>
+#include <lib/power_management.h>
+#include <platform.h>
+#include <test_helpers.h>
+
+#include <plat_topology.h>
+#include <runtime_services/realm_payload/realm_payload_test.h>
+
+#ifdef __aarch64__
+static test_result_t realm_multi_cpu_payload_del_undel(void);
+
+#define ECHO_VAL1 U(0xa0a0a0a0)
+#define ECHO_VAL2 U(0xb0b0b0b0)
+#define ECHO_VAL3 U(0xc0c0c0c0)
+
+/* Buffer to delegate and undelegate */
+static char bufferdelegate[NUM_GRANULES * GRANULE_SIZE * PLATFORM_CORE_COUNT] __aligned(GRANULE_SIZE);
+static char bufferstate[NUM_GRANULES * PLATFORM_CORE_COUNT];
+static int cpu_test_spm_rmi[PLATFORM_CORE_COUNT];
+
+/*
+ * The following test conducts SPM(direct messaging) tests on a subset of selected CPUs while
+ * simultaneously performing another set of tests of the RMI(delelgation)
+ * on the remaining CPU's to the full platform count. Once that test completes
+ * the same test is run again with a different assignment for what CPU does
+ * SPM versus RMI.
+ */
+
+/*
+ * Function that randomizes the CPU assignment of tests, SPM or RMI
+ */
+static void rand_cpu_spm_rmi(void)
+{
+ int fentry;
+ int seln;
+ for (int i = 0; i < PLATFORM_CORE_COUNT; i++) {
+ cpu_test_spm_rmi[i] = -1;
+ }
+ for (int i = 0; i < NUM_CPU_DED_SPM; i++) {
+ fentry = 0;
+ while (fentry == 0) {
+ seln = (rand() % (PLATFORM_CORE_COUNT - 1)) + 1;
+ if (cpu_test_spm_rmi[seln] == -1) {
+ cpu_test_spm_rmi[seln] = 1;
+ fentry = 1;
+ }
+ }
+ }
+ for (int i = 0; i < PLATFORM_CORE_COUNT; i++) {
+ if (cpu_test_spm_rmi[i] == -1) {
+ cpu_test_spm_rmi[i] = 0;
+ }
+ }
+}
+
+/*
+ * Get function to determine what has been assigned to a given CPU
+ */
+static int spm_rmi_test(unsigned int mpidr)
+{
+ return cpu_test_spm_rmi[platform_get_core_pos(mpidr)];
+}
+
+/*
+ * RMI function to randomize the initial state of granules allocated for the test.
+ * A certain subset will be delegated leaving the rest undelegated
+ */
+static test_result_t init_buffer_del_spm_rmi(void)
+{
+ u_register_t retrmm;
+
+ for (int i = 0; i < (NUM_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+ if ((rand() % 2) == 0) {
+ retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+ bufferstate[i] = B_DELEGATED;
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ } else {
+ bufferstate[i] = B_UNDELEGATED;
+ }
+ }
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * SPM functions for the direct messaging
+ */
+static const struct ffa_uuid expected_sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
+ };
+
+
+static event_t cpu_booted[PLATFORM_CORE_COUNT];
+
+static test_result_t send_cactus_echo_cmd(ffa_id_t sender,
+ ffa_id_t dest,
+ uint64_t value)
+{
+ smc_ret_values ret;
+ ret = cactus_echo_send_cmd(sender, dest, value);
+
+ /*
+ * Return responses may be FFA_MSG_SEND_DIRECT_RESP or FFA_INTERRUPT,
+ * but only expect the former. Expect SMC32 convention from SP.
+ */
+ if (!is_ffa_direct_response(ret)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (cactus_get_response(ret) != CACTUS_SUCCESS ||
+ cactus_echo_get_val(ret) != value) {
+ ERROR("Echo Failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Handler that is passed during tftf_cpu_on to individual CPU cores.
+ * Runs a specific core and send a direct message request.
+ * Expects core_pos | SP_ID as a response.
+ */
+static test_result_t run_spm_direct_message(void)
+{
+ unsigned int mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int core_pos = platform_get_core_pos(mpid);
+ test_result_t ret = TEST_RESULT_SUCCESS;
+ smc_ret_values ffa_ret;
+
+ /*
+ * Send a direct message request to SP1 (MP SP) from current physical
+ * CPU. Notice SP1 ECs are already woken as a result of the PSCI_CPU_ON
+ * invocation so they already reached the message loop.
+ * The SPMC uses the MP pinned context corresponding to the physical
+ * CPU emitting the request.
+ */
+ ret = send_cactus_echo_cmd(HYP_ID, SP_ID(1), ECHO_VAL1);
+ if (ret != TEST_RESULT_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Secure Partitions beyond the first SP only have their first
+ * EC (or vCPU0) woken up at boot time by the SPMC.
+ * Other ECs need one round of ffa_run to reach the message loop.
+ */
+ ffa_ret = ffa_run(SP_ID(2), core_pos);
+ if (ffa_func_id(ffa_ret) != FFA_MSG_WAIT) {
+ ERROR("Failed to run SP%x on core %u\n", SP_ID(2),
+ core_pos);
+ ret = TEST_RESULT_FAIL;
+ goto out;
+ }
+
+ /*
+ * Send a direct message request to SP2 (MP SP) from current physical
+ * CPU. The SPMC uses the MP pinned context corresponding to the
+ * physical CPU emitting the request.
+ */
+ ret = send_cactus_echo_cmd(HYP_ID, SP_ID(2), ECHO_VAL2);
+ if (ret != TEST_RESULT_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Send a direct message request to SP3 (UP SP) from current physical CPU.
+ * The SPMC uses the single vCPU migrated to the new physical core.
+ * The single SP vCPU may receive requests from multiple physical CPUs.
+ * Thus it is possible one message is being processed on one core while
+ * another (or multiple) cores attempt sending a new direct message
+ * request. In such case the cores attempting the new request receive
+ * a busy response from the SPMC. To handle this case a retry loop is
+ * implemented permitting some fairness.
+ */
+ uint32_t trial_loop = 5U;
+ while (trial_loop--) {
+ ffa_ret = cactus_echo_send_cmd(HYP_ID, SP_ID(3), ECHO_VAL3);
+ if ((ffa_func_id(ffa_ret) == FFA_ERROR) &&
+ (ffa_error_code(ffa_ret) == FFA_ERROR_BUSY)) {
+ VERBOSE("%s(%u) trial %u\n", __func__, core_pos, trial_loop);
+ waitms(1);
+ continue;
+ }
+
+ if (is_ffa_direct_response(ffa_ret) == true) {
+ if (cactus_get_response(ffa_ret) != CACTUS_SUCCESS ||
+ cactus_echo_get_val(ffa_ret) != ECHO_VAL3) {
+ ERROR("Echo Failed!\n");
+ ret = TEST_RESULT_FAIL;
+ }
+
+ goto out;
+ }
+ }
+
+ ret = TEST_RESULT_FAIL;
+
+out:
+ /* Tell the lead CPU that the calling CPU has completed the test */
+ tftf_send_event(&cpu_booted[core_pos]);
+
+ return ret;
+}
+#endif
+
+/*
+ * Test function to dispatch a number of SPM and RMI tests to the platform
+ * number of CPU's. The test is run twice on a another set of randomly determined
+ * CPU's.
+ */
+test_result_t test_ffa_secondary_core_direct_realm_msg(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int cpu_node, mpidr;
+ int32_t ret;
+
+ /**********************************************************************
+ * Check SPMC has ffa_version and expected FFA endpoints are deployed.
+ **********************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+ for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+ tftf_init_event(&cpu_booted[i]);
+ }
+
+ /*
+ * Randomize the assignment of the CPU's to either SPM or RMI
+ */
+ rand_cpu_spm_rmi();
+
+ /*
+ * Randomize the initial state of the RMI granules to realm or non-secure
+ */
+ if (init_buffer_del_spm_rmi() == TEST_RESULT_FAIL) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Main test to run both SPM and RMI together
+ */
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (mpidr == lead_mpid) {
+ continue;
+ }
+
+ if (spm_rmi_test(mpidr) == 1) {
+ ret = tftf_cpu_on(mpidr, (uintptr_t)run_spm_direct_message, 0U);
+ if (ret != 0) {
+ ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
+ return TEST_RESULT_FAIL;
+ }
+ } else {
+ ret = tftf_cpu_on(mpidr,
+ (uintptr_t)realm_multi_cpu_payload_del_undel, 0);
+
+ if (ret != PSCI_E_SUCCESS) {
+ ERROR("CPU ON failed for 0x%llx\n",
+ (unsigned long long)mpidr);
+ return TEST_RESULT_FAIL;
+ }
+ }
+ }
+
+ VERBOSE("Waiting for secondary CPUs to turn off ...\n");
+
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (mpidr == lead_mpid) {
+ continue;
+ }
+
+ while (tftf_psci_affinity_info(mpidr, MPIDR_AFFLVL0) !=
+ PSCI_STATE_OFF) {
+ continue;
+ }
+ }
+
+ /*
+ * Randomize the CPU's again
+ */
+ rand_cpu_spm_rmi();
+
+ /*
+ * Run test again
+ */
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (mpidr == lead_mpid) {
+ continue;
+ }
+
+ if (spm_rmi_test(mpidr) == 1) {
+ ret = tftf_cpu_on(mpidr, (uintptr_t)run_spm_direct_message, 0U);
+ if (ret != 0) {
+ ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
+ return TEST_RESULT_FAIL;
+ }
+ } else {
+ ret = tftf_cpu_on(mpidr,
+ (uintptr_t)realm_multi_cpu_payload_del_undel, 0);
+
+ if (ret != PSCI_E_SUCCESS) {
+ ERROR("CPU ON failed for 0x%llx\n",
+ (unsigned long long)mpidr);
+ return TEST_RESULT_FAIL;
+ }
+ }
+ }
+
+ VERBOSE("Waiting for secondary CPUs to turn off ...\n");
+
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (mpidr == lead_mpid) {
+ continue;
+ }
+
+ while (tftf_psci_affinity_info(mpidr, MPIDR_AFFLVL0) !=
+ PSCI_STATE_OFF) {
+ continue;
+ }
+
+ }
+
+ VERBOSE("Done exiting.\n");
+
+ /**********************************************************************
+ * All tests passed.
+ **********************************************************************/
+
+ return TEST_RESULT_SUCCESS;
+#endif
+}
+
+#ifdef __aarch64__
+/*
+ * Multi CPU testing of delegate and undelegate of granules
+ * The granules are first randomly initialized to either realm or non secure
+ * using the function init_buffer_del and then the function below
+ * assigns NUM_GRANULES to each CPU for delegation or undelgation
+ * depending upon the initial state
+ */
+static test_result_t realm_multi_cpu_payload_del_undel(void)
+{
+ u_register_t retrmm;
+ unsigned int cpu_node;
+
+ cpu_node = platform_get_core_pos(read_mpidr_el1() & MPID_MASK);
+
+ for (int i = 0; i < NUM_GRANULES; i++) {
+ if (bufferstate[((cpu_node * NUM_GRANULES) + i)] == B_UNDELEGATED) {
+ retrmm = realm_granule_delegate((u_register_t)
+ &bufferdelegate[((cpu_node * NUM_GRANULES) + i) * GRANULE_SIZE]);
+ bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_DELEGATED;
+ } else {
+ retrmm = realm_granule_undelegate((u_register_t)
+ &bufferdelegate[((cpu_node * NUM_GRANULES) + i) * GRANULE_SIZE]);
+ bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_UNDELEGATED;
+ }
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ }
+ return TEST_RESULT_SUCCESS;
+}
+#endif
diff --git a/tftf/tests/runtime_services/realm_payload/realm_payload_test.c b/tftf/tests/runtime_services/realm_payload/realm_payload_test.c
new file mode 100644
index 0000000..d1063f4
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_test.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <arch_features.h>
+#include <plat_topology.h>
+#include <power_management.h>
+#include <platform.h>
+#include <runtime_services/realm_payload/realm_payload_test.h>
+#include <test_helpers.h>
+
+#ifdef __aarch64__
+static test_result_t realm_multi_cpu_payload_test(void);
+static test_result_t realm_multi_cpu_payload_del_undel(void);
+
+/* Buffer to delegate and undelegate */
+static char bufferdelegate[NUM_GRANULES * GRANULE_SIZE * PLATFORM_CORE_COUNT] __aligned(GRANULE_SIZE);
+static char bufferstate[NUM_GRANULES * PLATFORM_CORE_COUNT];
+#endif
+
+/*
+ * Overall test for realm payload in three sections:
+ * 1. Single CPU version check: SMC call to realm payload to return
+ * version information
+ * 2. Multi CPU version check: SMC call to realm payload to return
+ * version information from all CPU's in system
+ * 3. Delegate and Undelegate Non-Secure granule via
+ * SMC call to realm payload
+ * 4. Multi CPU delegation where random assignment of states
+ * (realm, non-secure)is assigned to a set of granules.
+ * Each CPU is given a number of granules to delegate in
+ * parallel with the other CPU's
+ * 5. Fail testing of delegation parameters such as
+ * attempting to perform a delegation on the same granule
+ * twice and then testing a misaligned address
+ */
+
+#ifdef __aarch64__
+test_result_t init_buffer_del(void)
+{
+ u_register_t retrmm;
+
+ for (int i = 0; i < (NUM_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+ if ((rand() % 2) == 0) {
+ retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+ bufferstate[i] = B_DELEGATED;
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ } else {
+ bufferstate[i] = B_UNDELEGATED;
+ }
+ }
+ return TEST_RESULT_SUCCESS;
+}
+#endif
+
+/*
+ * Single CPU version check function
+ */
+test_result_t realm_version_single_cpu(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+ u_register_t retrmm;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ retrmm = realm_version();
+
+ tftf_testcase_printf("RMM version is: %lu.%lu\n",
+ RMI_ABI_VERSION_GET_MAJOR(retrmm),
+ RMI_ABI_VERSION_GET_MINOR(retrmm));
+
+ return TEST_RESULT_SUCCESS;
+#endif
+}
+
+/*
+ * Multi CPU version check function in parallel.
+ */
+test_result_t realm_version_multi_cpu(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+ u_register_t lead_mpid, target_mpid;
+ int cpu_node;
+ long long ret;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ lead_mpid = read_mpidr_el1() & MPID_MASK;
+
+ for_each_cpu(cpu_node) {
+ target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+ if (lead_mpid == target_mpid) {
+ continue;
+ }
+
+ ret = tftf_cpu_on(target_mpid,
+ (uintptr_t)realm_multi_cpu_payload_test, 0);
+
+ if (ret != PSCI_E_SUCCESS) {
+ ERROR("CPU ON failed for 0x%llx\n",
+ (unsigned long long)target_mpid);
+ return TEST_RESULT_FAIL;
+ }
+
+ }
+
+ ret = realm_multi_cpu_payload_test();
+
+ for_each_cpu(cpu_node) {
+ target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+ if (lead_mpid == target_mpid) {
+ continue;
+ }
+
+ while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) !=
+ PSCI_STATE_OFF) {
+ continue;
+ }
+ }
+
+ return ret;
+#endif
+}
+
+/*
+ * Delegate and Undelegate Non Secure Granule
+ */
+test_result_t realm_delegate_undelegate(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+ u_register_t retrmm;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ retrmm = realm_granule_delegate((u_register_t)bufferdelegate);
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ retrmm = realm_granule_undelegate((u_register_t)bufferdelegate);
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Undelegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ tftf_testcase_printf("Delegate and undelegate of buffer 0x%lx succeeded\n",
+ (uintptr_t)bufferdelegate);
+
+ return TEST_RESULT_SUCCESS;
+#endif
+}
+
+#ifdef __aarch64__
+static test_result_t realm_multi_cpu_payload_test(void)
+{
+ u_register_t retrmm = realm_version();
+
+ tftf_testcase_printf("Multi CPU RMM version on CPU %llx is: %lu.%lu\n",
+ read_mpidr_el1() & MPID_MASK, RMI_ABI_VERSION_GET_MAJOR(retrmm),
+ RMI_ABI_VERSION_GET_MINOR(retrmm));
+
+ return TEST_RESULT_SUCCESS;
+}
+#endif
+
+/*
+ * Select all CPU's to randomly delegate/undelegate
+ * granule pages to stress the delegate mechanism
+ */
+test_result_t realm_delundel_multi_cpu(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+ u_register_t lead_mpid, target_mpid;
+ int cpu_node;
+ long long ret;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ lead_mpid = read_mpidr_el1() & MPID_MASK;
+
+ if (init_buffer_del() == TEST_RESULT_FAIL) {
+ return TEST_RESULT_FAIL;
+ }
+
+ for_each_cpu(cpu_node) {
+ target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+ if (lead_mpid == target_mpid) {
+ continue;
+ }
+
+ ret = tftf_cpu_on(target_mpid,
+ (uintptr_t)realm_multi_cpu_payload_del_undel, 0);
+
+ if (ret != PSCI_E_SUCCESS) {
+ ERROR("CPU ON failed for 0x%llx\n",
+ (unsigned long long)target_mpid);
+ return TEST_RESULT_FAIL;
+ }
+
+ }
+
+ for_each_cpu(cpu_node) {
+ target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+ if (lead_mpid == target_mpid) {
+ continue;
+ }
+
+ while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) !=
+ PSCI_STATE_OFF) {
+ continue;
+ }
+ }
+
+ ret = TEST_RESULT_SUCCESS;
+ return ret;
+#endif
+}
+
+/*
+ * Multi CPU testing of delegate and undelegate of granules
+ * The granules are first randomly initialized to either realm or non secure
+ * using the function init_buffer_del and then the function below
+ * assigns NUM_GRANULES to each CPU for delegation or undelgation
+ * depending upon the initial state
+ */
+#ifdef __aarch64__
+static test_result_t realm_multi_cpu_payload_del_undel(void)
+{
+ u_register_t retrmm;
+ unsigned int cpu_node;
+
+ cpu_node = platform_get_core_pos(read_mpidr_el1() & MPID_MASK);
+
+ for (int i = 0; i < NUM_GRANULES; i++) {
+ if (bufferstate[((cpu_node * NUM_GRANULES) + i)] == B_UNDELEGATED) {
+ retrmm = realm_granule_delegate((u_register_t)
+ &bufferdelegate[((cpu_node * NUM_GRANULES) + i) * GRANULE_SIZE]);
+ bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_DELEGATED;
+ } else {
+ retrmm = realm_granule_undelegate((u_register_t)
+ &bufferdelegate[((cpu_node * NUM_GRANULES) + i) * GRANULE_SIZE]);
+ bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_UNDELEGATED;
+ }
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ }
+ return TEST_RESULT_SUCCESS;
+}
+#endif
+
+/*Fail testing of delegation process. The first is an error expected
+ * for processing the same granule twice and the second is submission of
+ * a misaligned address
+ */
+
+test_result_t realm_fail_del(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+ u_register_t retrmm;
+
+ retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[0]);
+ retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[0]);
+
+ if (retrmm == 0UL) {
+ tftf_testcase_printf
+ ("Delegate operation does not fail as expected for double delegation, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ retrmm = realm_granule_undelegate((u_register_t)&bufferdelegate[1]);
+
+ if (retrmm == 0UL) {
+ tftf_testcase_printf
+ ("Delegate operation does not return fail for misaligned address, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+#endif
+}
diff --git a/tftf/tests/runtime_services/realm_payload/realm_payload_test_helpers.c b/tftf/tests/runtime_services/realm_payload/realm_payload_test_helpers.c
new file mode 100644
index 0000000..e6aa10b
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_test_helpers.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <runtime_services/realm_payload/realm_payload_test.h>
+
+u_register_t realm_version(void)
+{
+ smc_args args = { RMI_RMM_REQ_VERSION };
+ smc_ret_values ret;
+
+ ret = tftf_smc(&args);
+ return ret.ret0;
+}
+
+u_register_t realm_granule_delegate(u_register_t add)
+{
+ smc_args args = { 0 };
+ smc_ret_values ret;
+
+ args.fid = SMC_RMM_GRANULE_DELEGATE;
+ args.arg1 = add;
+
+ ret = tftf_smc(&args);
+ return ret.ret0;
+}
+
+u_register_t realm_granule_undelegate(u_register_t add)
+{
+ smc_args args = { 0 };
+ smc_ret_values ret;
+
+ args.fid = SMC_RMM_GRANULE_UNDELEGATE;
+ args.arg1 = add;
+
+ ret = tftf_smc(&args);
+ return ret.ret0;
+}
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index 6011d8b..cbc028e 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -607,3 +607,19 @@
return tftf_smc(&args);
}
+
+smc_ret_values ffa_notification_info_get(void)
+{
+ smc_args args = {
+ .fid = FFA_NOTIFICATION_INFO_GET_SMC64,
+ .arg1 = FFA_PARAM_MBZ,
+ .arg2 = FFA_PARAM_MBZ,
+ .arg3 = FFA_PARAM_MBZ,
+ .arg4 = FFA_PARAM_MBZ,
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ
+ };
+
+ return tftf_smc(&args);
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c b/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c
index 1b9abe9..fb76362 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c
@@ -24,7 +24,6 @@
{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
};
-
static event_t cpu_booted[PLATFORM_CORE_COUNT];
static test_result_t send_cactus_echo_cmd(ffa_id_t sender,
@@ -165,7 +164,6 @@
/**
* Handler that is passed during tftf_cpu_on to individual CPU cores.
* Runs a specific core and send a direct message request.
- * Expects core_pos | SP_ID as a response.
*/
static test_result_t cpu_on_handler(void)
{
@@ -255,48 +253,9 @@
*/
test_result_t test_ffa_secondary_core_direct_msg(void)
{
- unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
- unsigned int core_pos, cpu_node, mpidr;
- int32_t ret;
-
/**********************************************************************
* Check SPMC has ffa_version and expected FFA endpoints are deployed.
**********************************************************************/
CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
-
- for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
- tftf_init_event(&cpu_booted[i]);
- }
-
- for_each_cpu(cpu_node) {
- mpidr = tftf_get_mpidr_from_node(cpu_node);
- if (mpidr == lead_mpid) {
- continue;
- }
-
- ret = tftf_cpu_on(mpidr, (uintptr_t)cpu_on_handler, 0U);
- if (ret != 0) {
- ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
- }
- }
-
- VERBOSE("Waiting secondary CPUs to turn off ...\n");
-
- for_each_cpu(cpu_node) {
- mpidr = tftf_get_mpidr_from_node(cpu_node);
- if (mpidr == lead_mpid) {
- continue;
- }
-
- core_pos = platform_get_core_pos(mpidr);
- tftf_wait_for_event(&cpu_booted[core_pos]);
- }
-
- VERBOSE("Done exiting.\n");
-
- /**********************************************************************
- * All tests passed.
- **********************************************************************/
-
- return TEST_RESULT_SUCCESS;
+ return spm_run_multi_core_test((uintptr_t)cpu_on_handler, cpu_booted);
}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
index 85a93a6..2245895 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
@@ -15,6 +15,23 @@
#include <spm_common.h>
#include <test_helpers.h>
+/**
+ * Defining variables to test the per-vCPU notifications.
+ * The conceived test follows the same logic, despite the sender receiver type
+ * of endpoint (VM or secure partition).
+ * Using global variables because these need to be accessed in the cpu on handler
+ * function 'request_notification_get_per_vcpu_on_handler'.
+ * In each specific test function, change 'per_vcpu_receiver' and
+ * 'per_vcpu_sender' have the logic work for:
+ * - NWd to SP;
+ * - SP to NWd;
+ * - SP to SP.
+ */
+static ffa_id_t per_vcpu_receiver;
+static ffa_id_t per_vcpu_sender;
+uint32_t per_vcpu_flags_get;
+static event_t per_vcpu_finished[PLATFORM_CORE_COUNT];
+
static const struct ffa_uuid expected_sp_uuids[] = {
{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
};
@@ -444,6 +461,41 @@
return true;
}
+static bool is_notifications_info_get_as_expected(
+ smc_ret_values *ret, uint16_t *ids, uint32_t *lists_sizes,
+ const uint32_t max_ids_count, uint32_t lists_count, bool more_pending)
+{
+ if (lists_count != ffa_notifications_info_get_lists_count(*ret) ||
+ more_pending != ffa_notifications_info_get_more_pending(*ret)) {
+ ERROR("Notification info get not as expected.\n"
+ " Lists counts: %u; more pending %u\n",
+ ffa_notifications_info_get_lists_count(*ret),
+ ffa_notifications_info_get_more_pending(*ret));
+ dump_smc_ret_values(*ret);
+ return false;
+ }
+
+ for (uint32_t i = 0; i < lists_count; i++) {
+ uint32_t cur_size =
+ ffa_notifications_info_get_list_size(*ret,
+ i + 1);
+
+ if (lists_sizes[i] != cur_size) {
+ ERROR("Expected list size[%u] %u != %u\n", i,
+ lists_sizes[i], cur_size);
+ return false;
+ }
+ }
+
+ /* Compare the IDs list */
+ if (memcmp(&ret->ret3, ids, sizeof(ids[0]) * max_ids_count) != 0) {
+ ERROR("List of IDs not as expected\n");
+ return false;
+ }
+
+ return true;
+}
+
/**
* Helper to bind notification and set it.
* If receiver is SP it will request SP to perform the bind, else invokes
@@ -509,21 +561,60 @@
receiver);
}
+static bool notifications_info_get(
+ uint16_t *expected_ids, uint32_t expected_lists_count,
+ uint32_t *expected_lists_sizes, const uint32_t max_ids_count,
+ bool expected_more_pending)
+{
+ smc_ret_values ret;
+
+ VERBOSE("Getting pending notification's info.\n");
+
+ ret = ffa_notification_info_get();
+
+ return !is_ffa_call_error(ret) &&
+ is_notifications_info_get_as_expected(&ret, expected_ids,
+ expected_lists_sizes,
+ max_ids_count,
+ expected_lists_count,
+ expected_more_pending);
+}
+
/**
* Test to validate a VM can signal an SP.
*/
test_result_t test_ffa_notifications_vm_signals_sp(void)
{
- CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
const ffa_id_t sender = 1;
const ffa_id_t receiver = SP_ID(1);
- ffa_notification_bitmap_t notifications = FFA_NOTIFICATION(1) | FFA_NOTIFICATION(60);
+ ffa_notification_bitmap_t notifications = FFA_NOTIFICATION(1) |
+ FFA_NOTIFICATION(60);
const uint32_t flags_get = FFA_NOTIFICATIONS_FLAG_BITMAP_VM;
+ /* Variables to validate calls to FFA_NOTIFICATION_INFO_GET. */
+ uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t lists_count;
+ uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ const bool more_notif_pending = false;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
if (!notification_bind_and_set(sender, receiver, notifications, 0)) {
return TEST_RESULT_FAIL;
}
+ /**
+ * Simple list of IDs expected on return from FFA_NOTIFICATION_INFO_GET.
+ */
+ ids[0] = receiver;
+ lists_count = 1;
+
+ if (!notifications_info_get(ids, lists_count, lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ more_notif_pending)) {
+ return TEST_RESULT_FAIL;
+ }
+
if (!notification_get_and_validate(receiver, 0, notifications, 0,
flags_get)) {
return TEST_RESULT_FAIL;
@@ -542,17 +633,36 @@
*/
test_result_t test_ffa_notifications_sp_signals_sp(void)
{
- CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
const ffa_id_t sender = SP_ID(1);
const ffa_id_t receiver = SP_ID(2);
uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_SP;
- /** Request receiver to bind a set of notifications to the sender */
+ /* Variables to validate calls to FFA_NOTIFICATION_INFO_GET. */
+ uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t lists_count;
+ uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Request receiver to bind a set of notifications to the sender. */
if (!notification_bind_and_set(sender, receiver,
g_notifications, 0)) {
return TEST_RESULT_FAIL;
}
+ /*
+ * FFA_NOTIFICATION_INFO_GET return list should be simple, containing
+ * only the receiver's ID.
+ */
+ ids[0] = receiver;
+ lists_count = 1;
+
+ if (!notifications_info_get(ids, lists_count, lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ false)) {
+ return TEST_RESULT_FAIL;
+ }
+
if (!notification_get_and_validate(receiver, g_notifications, 0, 0,
get_flags)) {
return TEST_RESULT_FAIL;
@@ -577,6 +687,11 @@
uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_SP;
smc_ret_values ret;
+ /* Variables to validate calls to FFA_NOTIFICATION_INFO_GET. */
+ uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ uint32_t lists_count;
+ uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+
/* Ask SPMC to allocate notifications bitmap. */
if (!notifications_bitmap_create(receiver, 1)) {
return TEST_RESULT_FAIL;
@@ -587,6 +702,19 @@
return TEST_RESULT_FAIL;
}
+ /*
+ * FFA_NOTIFICATION_INFO_GET return list should be simple, containing
+ * only the receiver's ID.
+ */
+ ids[0] = receiver;
+ lists_count = 1;
+
+ if (!notifications_info_get(ids, lists_count, lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ false)) {
+ return TEST_RESULT_FAIL;
+ }
+
/* Get pending notifications, and retrieve response. */
if (!notification_get_and_validate(receiver, g_notifications, 0, 0,
get_flags)) {
@@ -650,3 +778,329 @@
return TEST_RESULT_SUCCESS;
}
+
+/**
+ * Test the result of a call to FFA_NOTIFICATION_INFO_GET if no pending
+ * notifications.
+ */
+test_result_t test_ffa_notifications_info_get_none(void)
+{
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
+
+ if (check_spmc_execution_level()) {
+ VERBOSE("OPTEE as SPMC at S-EL1. Skipping test!\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ smc_ret_values ret;
+
+ ret = ffa_notification_info_get();
+
+ if (!is_expected_ffa_error(ret, FFA_ERROR_NO_DATA)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * CPU_ON handler for testing per-vCPU notifications to SPs (either from VMs
+ * or from SPs). It requests the SP to retrieve its pending notifications
+ * within its current Execution Context. The SP shall obtain all per-vCPU
+ * targeted to the running vCPU.
+ */
+static test_result_t request_notification_get_per_vcpu_on_handler(void)
+{
+ unsigned int mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int core_pos = platform_get_core_pos(mpid);
+ smc_ret_values ret;
+ test_result_t result = TEST_RESULT_FAIL;
+
+ uint64_t exp_from_vm = 0;
+ uint64_t exp_from_sp = 0;
+
+ if (IS_SP_ID(per_vcpu_sender)) {
+ exp_from_sp = FFA_NOTIFICATION(core_pos);
+ } else {
+ exp_from_vm = FFA_NOTIFICATION(core_pos);
+ }
+
+ VERBOSE("Request get per-vCPU notification to %x, core: %u.\n",
+ per_vcpu_receiver, core_pos);
+
+ /*
+ * Secure Partitions secondary ECs need one round of ffa_run to reach
+ * the message loop.
+ */
+ if (per_vcpu_receiver != SP_ID(1)) {
+ ret = ffa_run(per_vcpu_receiver, core_pos);
+
+ if (ffa_func_id(ret) != FFA_MSG_WAIT) {
+ ERROR("Failed to run SP%x on core %u\n",
+ per_vcpu_receiver, core_pos);
+ goto out;
+ }
+ }
+
+ /* Request to get notifications sent to the respective vCPU. */
+ if (!notification_get_and_validate(
+ per_vcpu_receiver, exp_from_sp, exp_from_vm, core_pos,
+ per_vcpu_flags_get)) {
+ goto out;
+ }
+
+ result = TEST_RESULT_SUCCESS;
+
+out:
+ /* Tell the lead CPU that the calling CPU has completed the test. */
+ tftf_send_event(&per_vcpu_finished[core_pos]);
+
+ return result;
+}
+
+/**
+ * Base function to test signaling of per-vCPU notifications.
+ * Test whole flow between two FF-A endpoints: binding, getting notification
+ * info, and getting pending notifications.
+ * Each vCPU will receive a notification whose ID is the same as the core
+ * position.
+ */
+static test_result_t base_test_per_vcpu_notifications(ffa_id_t sender,
+ ffa_id_t receiver)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /*
+ * Manually set variables to validate what should be the return of to
+ * FFA_NOTIFICATION_INFO_GET.
+ */
+ uint16_t exp_ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+ receiver, 0, 1, 2,
+ receiver, 3, 4, 5,
+ receiver, 6, 7, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ };
+ uint32_t exp_lists_count = 3;
+ uint32_t exp_lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+ 3, 3, 2, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ const bool exp_more_notif_pending = false;
+ test_result_t result = TEST_RESULT_SUCCESS;
+ uint64_t notifications_to_unbind = 0;
+
+ per_vcpu_flags_get = IS_SP_ID(sender)
+ ? FFA_NOTIFICATIONS_FLAG_BITMAP_SP
+ : FFA_NOTIFICATIONS_FLAG_BITMAP_VM;
+
+ /*
+ * Prepare notifications bitmap to request Cactus to bind them as
+ * per-vCPU.
+ */
+ for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++) {
+ notifications_to_unbind |= FFA_NOTIFICATION(i);
+
+ uint32_t flags = FFA_NOTIFICATIONS_FLAG_PER_VCPU |
+ FFA_NOTIFICATIONS_FLAGS_VCPU_ID((uint16_t)i);
+
+ if (!notification_bind_and_set(sender,
+ receiver,
+ FFA_NOTIFICATION(i),
+ flags)) {
+ return TEST_RESULT_FAIL;
+ }
+ }
+
+ /* Call FFA_NOTIFICATION_INFO_GET and validate return. */
+ if (!notifications_info_get(exp_ids, exp_lists_count, exp_lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ exp_more_notif_pending)) {
+ ERROR("Info Get Failed....\n");
+ result = TEST_RESULT_FAIL;
+ goto out;
+ }
+
+ /*
+ * Request SP to get notifications in core 0, as this is not iterated
+ * at the CPU ON handler.
+ */
+ if (!notification_get_and_validate(
+ receiver,
+ IS_SP_ID(sender) ? FFA_NOTIFICATION(0) : 0,
+ !IS_SP_ID(sender) ? FFA_NOTIFICATION(0) : 0,
+ 0,
+ per_vcpu_flags_get)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Setting global variables to be accessed by the cpu_on handler. */
+ per_vcpu_receiver = receiver;
+ per_vcpu_sender = sender;
+
+ /*
+ * Bring up all the cores, and request the receiver to get notifications
+ * in each one of them.
+ */
+ if (spm_run_multi_core_test(
+ (uintptr_t)request_notification_get_per_vcpu_on_handler,
+ per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+ result = TEST_RESULT_FAIL;
+ }
+
+out:
+ /* As a clean-up, unbind notifications. */
+ if (!request_notification_unbind(receiver, receiver,
+ sender,
+ notifications_to_unbind,
+ CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ return result;
+}
+
+/**
+ * Test to validate a VM can signal a per-vCPU notification to an SP.
+ */
+test_result_t test_ffa_notifications_vm_signals_sp_per_vcpu(void)
+{
+ return base_test_per_vcpu_notifications(0, SP_ID(1));
+}
+
+/**
+ * Test to validate an SP can signal a per-vCPU notification to an SP.
+ */
+test_result_t test_ffa_notifications_sp_signals_sp_per_vcpu(void)
+{
+ return base_test_per_vcpu_notifications(SP_ID(1), SP_ID(2));
+}
+
+static test_result_t notification_get_per_vcpu_on_handler(void)
+{
+ unsigned int mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int core_pos = platform_get_core_pos(mpid);
+ smc_ret_values ret;
+ test_result_t result = TEST_RESULT_SUCCESS;
+
+ VERBOSE("Getting per-vCPU notifications from %x, core: %u.\n",
+ per_vcpu_receiver, core_pos);
+
+ ret = ffa_run(per_vcpu_sender, core_pos);
+
+ if (ffa_func_id(ret) != FFA_MSG_WAIT) {
+ ERROR("Failed to run SP%x on core %u\n",
+ per_vcpu_sender, core_pos);
+ result = TEST_RESULT_FAIL;
+ goto out;
+ }
+
+ if (!notification_get_and_validate(per_vcpu_receiver,
+ FFA_NOTIFICATION(core_pos), 0,
+ core_pos,
+ FFA_NOTIFICATIONS_FLAG_BITMAP_SP)) {
+ result = TEST_RESULT_FAIL;
+ goto out;
+ }
+
+out:
+ /* Tell the lead CPU that the calling CPU has completed the test. */
+ tftf_send_event(&per_vcpu_finished[core_pos]);
+
+ return result;
+}
+
+/**
+ * Test whole flow from binding, to getting notifications' info, and getting
+ * pending notifications, namely signaling of notifications from SP to a VM.
+ * Each vCPU will receive a notification whose ID is the same as the core
+ * position.
+ */
+test_result_t test_ffa_notifications_sp_signals_vm_per_vcpu(void)
+{
+ /* Making a VM the receiver, and an SP the sender */
+ per_vcpu_receiver = 1;
+ per_vcpu_sender = SP_ID(2);
+
+ /**
+ * Manually set variables to validate what should be the return of to
+ * FFA_NOTIFICATION_INFO_GET.
+ */
+ uint16_t exp_ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+ per_vcpu_receiver, 0, 1, 2,
+ per_vcpu_receiver, 3, 4, 5,
+ per_vcpu_receiver, 6, 7, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ };
+ uint32_t exp_lists_count = 3;
+ uint32_t exp_lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+ 3, 3, 2, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ const bool exp_more_notif_pending = false;
+ test_result_t result = TEST_RESULT_SUCCESS;
+ uint64_t notifications_to_unbind = 0;
+ smc_ret_values ret;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Create bitmap for receiver. */
+ if (!notifications_bitmap_create(per_vcpu_receiver,
+ PLATFORM_CORE_COUNT)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Bind notifications, and request Cactus SP to set them. */
+ for (uint32_t i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+ notifications_to_unbind |= FFA_NOTIFICATION(i);
+
+ uint32_t flags = FFA_NOTIFICATIONS_FLAG_DELAY_SRI |
+ FFA_NOTIFICATIONS_FLAG_PER_VCPU |
+ FFA_NOTIFICATIONS_FLAGS_VCPU_ID((uint16_t)i);
+
+ if (!notification_bind_and_set(per_vcpu_sender,
+ per_vcpu_receiver,
+ FFA_NOTIFICATION(i),
+ flags)) {
+ return TEST_RESULT_FAIL;
+ };
+ }
+
+ /* Call FFA_NOTIFICATION_INFO_GET and validate return. */
+ if (!notifications_info_get(exp_ids, exp_lists_count, exp_lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ exp_more_notif_pending)) {
+ ERROR("Info Get Failed....\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Get notifications in core 0, as it is not iterated at the CPU ON
+ * handler.
+ */
+ if (!notification_get_and_validate(per_vcpu_receiver,
+ FFA_NOTIFICATION(0), 0, 0,
+ FFA_NOTIFICATIONS_FLAG_BITMAP_SP)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Bring up all the cores, and get notifications in each one of them. */
+ if (spm_run_multi_core_test(
+ (uintptr_t)notification_get_per_vcpu_on_handler,
+ per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+ ERROR("Failed to get per-vCPU notifications\n");
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* As a clean-up, unbind notifications. */
+ ret = ffa_notification_unbind(per_vcpu_sender, per_vcpu_receiver,
+ notifications_to_unbind);
+ if (is_ffa_call_error(ret)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ return result;
+}
diff --git a/tftf/tests/tests-realm-payload.mk b/tftf/tests/tests-realm-payload.mk
new file mode 100644
index 0000000..a8642fa
--- /dev/null
+++ b/tftf/tests/tests-realm-payload.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES += \
+ $(addprefix tftf/tests/runtime_services/realm_payload/, \
+ realm_payload_test_helpers.c \
+ realm_payload_test.c \
+ realm_payload_spm_test.c \
+ )
+
+TESTS_SOURCES += \
+ $(addprefix tftf/tests/runtime_services/secure_service/, \
+ ffa_helpers.c \
+ spm_common.c \
+ test_ffa_direct_messaging.c \
+ test_ffa_interrupts.c \
+ test_ffa_memory_sharing.c \
+ test_ffa_setup_and_discovery.c \
+ test_spm_cpu_features.c \
+ test_spm_smmu.c \
+ )
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
new file mode 100644
index 0000000..b401409
--- /dev/null
+++ b/tftf/tests/tests-realm-payload.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (c) 2021, Arm Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+
+ <testsuite name="Realm payload tests" description="Tests for Realm management interface">
+ <testcase name="Realm payload boot" function="realm_version_single_cpu" />
+ <testcase name="Realm payload multi CPU request" function="realm_version_multi_cpu" />
+ <testcase name="Realm payload Delegate and Undelegate" function="realm_delegate_undelegate" />
+ <testcase name="Multi CPU Realm payload Delegate and Undelegate" function="realm_delundel_multi_cpu" />
+ <testcase name="Testing delegation fails" function="realm_fail_del" />
+ <testcase name="Realm testing with SPM tests" function="test_ffa_secondary_core_direct_realm_msg" />
+ </testsuite>
+
+</testsuites>
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index b59ca0b..5752b8e 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -128,6 +128,14 @@
function="test_ffa_notifications_sp_signals_vm" />
<testcase name="Notifications unbind while pending"
function="test_ffa_notifications_unbind_pending" />
+ <testcase name="Notifications info get no data"
+ function="test_ffa_notifications_info_get_none" />
+ <testcase name="Notifications VM signals SP per-vCPU"
+ function="test_ffa_notifications_vm_signals_sp_per_vcpu" />
+ <testcase name="Notifications SP signals SP per-vCPU"
+ function="test_ffa_notifications_sp_signals_sp_per_vcpu" />
+ <testcase name="Notifications SP signals VM per-vCPU"
+ function="test_ffa_notifications_sp_signals_vm_per_vcpu" />
</testsuite>
</testsuites>
diff --git a/tftf/tests/tests-standard.mk b/tftf/tests/tests-standard.mk
index c6c9029..a722077 100644
--- a/tftf/tests/tests-standard.mk
+++ b/tftf/tests/tests-standard.mk
@@ -23,6 +23,7 @@
tests-tsp.mk \
tests-uncontainable.mk \
tests-debugfs.mk \
+ tests-realm-payload.mk \
)
include ${TESTS_MAKEFILE}
diff --git a/tftf/tests/tests-standard.xml b/tftf/tests/tests-standard.xml
index 8c66cda..384a5f4 100644
--- a/tftf/tests/tests-standard.xml
+++ b/tftf/tests/tests-standard.xml
@@ -24,6 +24,7 @@
<!ENTITY tests-spm SYSTEM "tests-spm.xml">
<!ENTITY tests-pmu-leakage SYSTEM "tests-pmu-leakage.xml">
<!ENTITY tests-debugfs SYSTEM "tests-debugfs.xml">
+ <!ENTITY tests-realm-payload SYSTEM "tests-realm-payload.xml">
]>
<testsuites>
@@ -43,5 +44,6 @@
&tests-spm;
&tests-pmu-leakage;
&tests-debugfs;
+ &tests-realm-payload;
</testsuites>