aboutsummaryrefslogtreecommitdiff
path: root/tftf
diff options
context:
space:
mode:
Diffstat (limited to 'tftf')
-rw-r--r--tftf/framework/aarch64/exceptions.S54
-rw-r--r--tftf/framework/framework.mk7
-rw-r--r--tftf/framework/main.c25
-rw-r--r--tftf/tests/common/test_helpers.c127
-rw-r--r--tftf/tests/extensions/afp/test_afp.c35
-rw-r--r--tftf/tests/extensions/brbe/test_brbe.c36
-rw-r--r--tftf/tests/extensions/hcx/test_hcx.c30
-rw-r--r--tftf/tests/extensions/pauth/test_pauth.c10
-rw-r--r--tftf/tests/extensions/rng_trap/test_rndr_trap.c35
-rw-r--r--tftf/tests/extensions/rng_trap/test_rndrrs_trap.c35
-rw-r--r--tftf/tests/extensions/sme/test_sme.c104
-rw-r--r--tftf/tests/extensions/spe/test_spe.c71
-rw-r--r--tftf/tests/extensions/sve/test_sve.c7
-rw-r--r--tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.c59
-rw-r--r--tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.h15
-rw-r--r--tftf/tests/extensions/trbe/test_trbe.c33
-rw-r--r--tftf/tests/extensions/trf/test_trf.c31
-rw-r--r--tftf/tests/extensions/wfxt/test_wfxt.c89
-rw-r--r--tftf/tests/misc_tests/inject_serror.S2
-rw-r--r--tftf/tests/misc_tests/test_invalid_access.c394
-rw-r--r--tftf/tests/performance_tests/test_psci_latencies.c21
-rw-r--r--tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c466
-rw-r--r--tftf/tests/runtime_services/realm_payload/realm_payload_test.c317
-rw-r--r--tftf/tests/runtime_services/realm_payload/realm_payload_test_helpers.c65
-rw-r--r--tftf/tests/runtime_services/secure_service/aarch32/ffa_arch_helpers.S42
-rw-r--r--tftf/tests/runtime_services/secure_service/aarch64/ffa_arch_helpers.S53
-rw-r--r--tftf/tests/runtime_services/secure_service/ffa_helpers.c371
-rw-r--r--tftf/tests/runtime_services/secure_service/spm_common.c407
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c70
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c107
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_features.c47
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c24
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c198
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_notifications.c1634
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_rxtx_map.c67
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c456
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_setup_and_discovery.c431
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_version.c88
-rw-r--r--tftf/tests/runtime_services/secure_service/test_spci_blocking_request.c3
-rw-r--r--tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c100
-rw-r--r--tftf/tests/runtime_services/secure_service/test_spm_smmu.c4
-rw-r--r--tftf/tests/runtime_services/standard_service/psci/system_tests/test_psci_on_off_suspend_stress.c21
-rw-r--r--tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S30
-rw-r--r--tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_pstate.c318
-rw-r--r--tftf/tests/runtime_services/trusted_os/tsp/test_pstate_after_exception.c75
-rw-r--r--tftf/tests/tests-cpu-extensions.mk18
-rw-r--r--tftf/tests/tests-cpu-extensions.xml11
-rw-r--r--tftf/tests/tests-hcx.mk9
-rw-r--r--tftf/tests/tests-hcx.xml15
-rw-r--r--tftf/tests/tests-invalid-access.mk20
-rw-r--r--tftf/tests/tests-invalid-access.xml24
-rw-r--r--tftf/tests/tests-realm-payload.mk24
-rw-r--r--tftf/tests/tests-realm-payload.xml21
-rw-r--r--tftf/tests/tests-rndr_trap.mk9
-rw-r--r--tftf/tests/tests-rndr_trap.xml15
-rw-r--r--tftf/tests/tests-rndrrs_trap.mk9
-rw-r--r--tftf/tests/tests-rndrrs_trap.xml15
-rw-r--r--tftf/tests/tests-sdei.mk3
-rw-r--r--tftf/tests/tests-sdei.xml3
-rw-r--r--tftf/tests/tests-smcfuzzing.mk31
-rw-r--r--tftf/tests/tests-spm.mk15
-rw-r--r--tftf/tests/tests-spm.xml129
-rw-r--r--tftf/tests/tests-standard.mk1
-rw-r--r--tftf/tests/tests-standard.xml2
-rw-r--r--tftf/tests/tests-tsp.mk3
-rw-r--r--tftf/tests/tests-tsp.xml7
66 files changed, 6396 insertions, 602 deletions
diff --git a/tftf/framework/aarch64/exceptions.S b/tftf/framework/aarch64/exceptions.S
index 677b30fe..3dedb923 100644
--- a/tftf/framework/aarch64/exceptions.S
+++ b/tftf/framework/aarch64/exceptions.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -23,38 +23,40 @@ vector_base tftf_vector
/*
* Current EL with SP0 : 0x0 - 0x200.
*/
-unhandled_exception SynchronousExceptionSP0
-unhandled_exception IrqSP0
-unhandled_exception FiqSP0
-unhandled_exception SErrorSP0
+unhandled_exception sync_exception_sp_el0
+unhandled_exception irq_sp_el0
+unhandled_exception fiq_sp_el0
+unhandled_exception serror_sp_el0
/*
* Current EL with SPx : 0x200 - 0x400.
*/
-unhandled_exception SynchronousExceptionSPx
+vector_entry sync_spx
+ b sync_exception_vector_entry
+end_vector_entry sync_spx
-vector_entry IrqSPx
+vector_entry irq_sp_elx
b irq_vector_entry
-end_vector_entry IrqSPx
+end_vector_entry irq_sp_elx
-unhandled_exception FiqSPx
-unhandled_exception SErrorSPx
+unhandled_exception fiq_sp_elx
+unhandled_exception serror_sp_elx
/*
* Lower EL using AArch64 : 0x400 - 0x600.
*/
-unhandled_exception SynchronousExceptionA64
-unhandled_exception IrqA64
-unhandled_exception FiqA64
-unhandled_exception SErrorA64
+unhandled_exception sync_exception_aarch64
+unhandled_exception irq_aarch64
+unhandled_exception fiq_aarch64
+unhandled_exception serror_aarch64
/*
* Lower EL using AArch32 : 0x600 - 0x800.
*/
-unhandled_exception SynchronousExceptionA32
-unhandled_exception IrqA32
-unhandled_exception FiqA32
-unhandled_exception SErrorA32
+unhandled_exception sync_exception_aarch32
+unhandled_exception irq_aarch32
+unhandled_exception fiq_aarch32
+unhandled_exception serror_aarch32
.macro save_gp_regs
stp x0, x1, [sp, #0x0]
@@ -95,6 +97,22 @@ unhandled_exception SErrorA32
ldp x0, x1, [sp, #0x0]
.endm
+func sync_exception_vector_entry
+ sub sp, sp, #0x100
+ save_gp_regs
+ mov x19, sp
+ bl tftf_sync_exception_handler
+ cbnz x0, 0f
+ mov x0, x19
+ /* Save original stack pointer value on the stack */
+ add x1, x0, #0x100
+ str x1, [x0, #0xf8]
+ b print_exception
+0: restore_gp_regs
+ add sp, sp, #0x100
+ eret
+endfunc sync_exception_vector_entry
+
func irq_vector_entry
sub sp, sp, #0x100
save_gp_regs
diff --git a/tftf/framework/framework.mk b/tftf/framework/framework.mk
index 8ec18ea9..11026f2d 100644
--- a/tftf/framework/framework.mk
+++ b/tftf/framework/framework.mk
@@ -53,7 +53,7 @@ FRAMEWORK_SOURCES += \
lib/events/events.c \
lib/extensions/amu/${ARCH}/amu.c \
lib/extensions/amu/${ARCH}/amu_helpers.S \
- lib/irq/irq.c \
+ lib/exceptions/irq.c \
lib/locks/${ARCH}/spinlock.S \
lib/power_management/hotplug/hotplug.c \
lib/power_management/suspend/${ARCH}/asm_tftf_suspend.S \
@@ -79,8 +79,11 @@ FRAMEWORK_SOURCES += ${COMPILER_RT_SRCS}
ifeq (${ARCH},aarch64)
# ARMv8.3 Pointer Authentication support files
FRAMEWORK_SOURCES += \
+ lib/exceptions/aarch64/sync.c \
lib/extensions/pauth/aarch64/pauth.c \
- lib/extensions/pauth/aarch64/pauth_helpers.S
+ lib/extensions/pauth/aarch64/pauth_helpers.S \
+ lib/extensions/sme/aarch64/sme.c \
+ lib/extensions/sme/aarch64/sme_helpers.S
endif
TFTF_LINKERFILE := tftf/framework/tftf.ld.S
diff --git a/tftf/framework/main.c b/tftf/framework/main.c
index 2350b962..a203bd2f 100644
--- a/tftf/framework/main.c
+++ b/tftf/framework/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,6 +25,8 @@
#include <tftf_lib.h>
#include <timer.h>
+#define MIN_RETRY_TO_POWER_ON_LEAD_CPU 10
+
/* version information for TFTF */
extern const char version_string[];
@@ -309,6 +311,7 @@ static unsigned int close_test(void)
static void __dead2 hand_over_to_lead_cpu(void)
{
int ret;
+ unsigned int tftf_cpu_pwr_on_ctr = 0U;
unsigned int mpid = read_mpidr_el1() & MPID_MASK;
unsigned int core_pos = platform_get_core_pos(mpid);
@@ -321,8 +324,24 @@ static void __dead2 hand_over_to_lead_cpu(void)
* doesn't matter because it will be overwritten by prepare_next_test().
* Pass a NULL pointer to easily catch the problem in case something
* goes wrong.
+ *
+ * In CI with four world system (Normal, Secure, Root and Realm), on few
+ * instances, while the framework tries to turn on the CPU for next-test
+ * it fails to do so and receives error code (-4 : ALREADY_ON).
+ * This is due to the fact that the lead-cpu is still powering down as
+ * per EL-3 but invisible to EL-2. Hence retrying it in a loop with a
+ * small delay in bewteen for certain iterations will resolve it.
*/
- ret = tftf_cpu_on(lead_cpu_mpid, 0, 0);
+ while (tftf_cpu_pwr_on_ctr < MIN_RETRY_TO_POWER_ON_LEAD_CPU) {
+ ret = tftf_cpu_on(lead_cpu_mpid, 0, 0);
+ if (ret == PSCI_E_SUCCESS) {
+ break;
+ } else {
+ tftf_cpu_pwr_on_ctr += 1;
+ waitms(1);
+ }
+ }
+
if (ret != PSCI_E_SUCCESS) {
ERROR("CPU%u: Failed to power on lead CPU%u (%d)\n",
core_pos, platform_get_core_pos(lead_cpu_mpid), ret);
@@ -531,7 +550,7 @@ void __dead2 tftf_cold_boot_main(void)
* authentication would fail then.
*/
#if ENABLE_PAUTH
- assert(is_armv8_3_pauth_apa_api_present());
+ assert(is_armv8_3_pauth_apa_api_apa3_present());
/*
* Program APIAKey_EL1 key and enable ARMv8.3-PAuth here as this
diff --git a/tftf/tests/common/test_helpers.c b/tftf/tests/common/test_helpers.c
index d794bebc..f4995796 100644
--- a/tftf/tests/common/test_helpers.c
+++ b/tftf/tests/common/test_helpers.c
@@ -1,10 +1,11 @@
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
+#include <cactus_test_cmds.h>
#include <plat_topology.h>
#include <platform.h>
#include <power_management.h>
@@ -172,7 +173,129 @@ test_result_t check_spmc_testing_set_up(
GET_TFTF_MAILBOX(mb);
for (unsigned int i = 0U; i < ffa_uuids_size; i++)
- SKIP_TEST_IF_FFA_ENDPOINT_NOT_DEPLOYED(*mb, ffa_uuids[i].uuid);
+ SKIP_TEST_IF_FFA_ENDPOINT_NOT_DEPLOYED(*mb, ffa_uuids[i]);
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;
+}
+
+bool spm_core_sp_init(ffa_id_t sp_id)
+{
+ /*
+ * Secure Partitions secondary ECs need one round of ffa_run to reach
+ * the message loop.
+ */
+ if (sp_id != SP_ID(1)) {
+ uint32_t core_pos = get_current_core_id();
+ struct ffa_value ret = ffa_run(sp_id, core_pos);
+
+ if (ffa_func_id(ret) != FFA_MSG_WAIT) {
+ ERROR("Failed to run SP%x on core %u\n",
+ sp_id, core_pos);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool spm_set_managed_exit_int(ffa_id_t sp_id, bool enable)
+{
+ struct ffa_value ret;
+
+ ret = cactus_interrupt_cmd(HYP_ID, sp_id, MANAGED_EXIT_INTERRUPT_ID,
+ enable, INTERRUPT_TYPE_FIQ);
+
+ if (!is_ffa_direct_response(ret) ||
+ cactus_get_response(ret) != CACTUS_SUCCESS) {
+ ERROR("Failed to enable Managed exit interrupt\n");
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Initializes the Mailbox for other SPM related tests that need to use
+ * RXTX buffers.
+ */
+bool mailbox_init(struct mailbox_buffers mb)
+{
+ struct ffa_value ret;
+
+ ffa_rxtx_unmap();
+ CONFIGURE_AND_MAP_MAILBOX(mb, PAGE_SIZE, ret);
+ if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
+ ERROR("Failed to map RXTX buffers %x!\n", ffa_error_code(ret));
+ return false;
+ }
+ set_tftf_mailbox(&mb);
+ return true;
+}
+
+/*
+ * Utility function to wait for all CPUs other than the caller to be
+ * OFF.
+ */
+void wait_for_non_lead_cpus(void)
+{
+ unsigned int target_mpid, target_node;
+
+ for_each_cpu(target_node) {
+ target_mpid = tftf_get_mpidr_from_node(target_node);
+ wait_for_core_to_turn_off(target_mpid);
+ }
+}
+
+void wait_for_core_to_turn_off(unsigned int mpidr)
+{
+ /* Skip lead CPU, as it is powered on */
+ if (mpidr == (read_mpidr_el1() & MPID_MASK))
+ return;
+
+ while (tftf_psci_affinity_info(mpidr, MPIDR_AFFLVL0) != PSCI_STATE_OFF) {
+ continue;
+ }
+}
diff --git a/tftf/tests/extensions/afp/test_afp.c b/tftf/tests/extensions/afp/test_afp.c
new file mode 100644
index 00000000..625d9cf4
--- /dev/null
+++ b/tftf/tests/extensions/afp/test_afp.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <test_helpers.h>
+
+test_result_t test_afp_support(void)
+{
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ test_result_t ret;
+ uint64_t saved_fpcr, fpcr;
+
+ SKIP_TEST_IF_AFP_NOT_SUPPORTED();
+
+ saved_fpcr = read_fpcr();
+ /* Write advanced floating point controlling bits */
+ write_fpcr(saved_fpcr | FPCR_FIZ_BIT | FPCR_AH_BIT | FPCR_NEP_BIT);
+
+ fpcr = read_fpcr();
+ /* Check if all bits got written successfully */
+ if ((fpcr | ~(FPCR_FIZ_BIT | FPCR_AH_BIT | FPCR_NEP_BIT)) == ~0ULL) {
+ ret = TEST_RESULT_SUCCESS;
+ } else {
+ ret = TEST_RESULT_FAIL;
+ }
+
+ write_fpcr(saved_fpcr);
+
+ return ret;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/extensions/brbe/test_brbe.c b/tftf/tests/extensions/brbe/test_brbe.c
new file mode 100644
index 00000000..f2c244a3
--- /dev/null
+++ b/tftf/tests/extensions/brbe/test_brbe.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <tftf.h>
+
+/*
+ * EL3 is expected to allow access to branch record buffer control registers
+ * from NS world. Accessing these registers will trap to EL3 and crash when EL3
+ * has not properly enabled it.
+ */
+test_result_t test_brbe_enabled(void)
+{
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ SKIP_TEST_IF_BRBE_NOT_SUPPORTED();
+
+ read_brbcr_el1();
+ read_brbcr_el2();
+ read_brbfcr_el1();
+ read_brbts_el1();
+ read_brbinfinj_el1();
+ read_brbsrcinj_el1();
+ read_brbtgtinj_el1();
+ read_brbidr0_el1();
+
+ return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/extensions/hcx/test_hcx.c b/tftf/tests/extensions/hcx/test_hcx.c
new file mode 100644
index 00000000..ebc6e818
--- /dev/null
+++ b/tftf/tests/extensions/hcx/test_hcx.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <tftf_lib.h>
+#include <tftf.h>
+#include <arch_helpers.h>
+#include <arch_features.h>
+
+/* This very simple test just ensures that HCRX_EL2 access does not trap. */
+test_result_t test_feat_hcx_enabled(void)
+{
+#ifdef __aarch64__
+ /* Make sure FEAT_HCX is supported. */
+ if (!get_feat_hcx_support()) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /* Attempt to read HCRX_EL2, if not enabled this should trap to EL3. */
+ read_hcrx_el2();
+
+ /* If we make it this far, the test was successful. */
+ return TEST_RESULT_SUCCESS;
+#else
+ /* Skip test if AArch32 */
+ return TEST_RESULT_SKIPPED;
+#endif
+}
diff --git a/tftf/tests/extensions/pauth/test_pauth.c b/tftf/tests/extensions/pauth/test_pauth.c
index 30b78ef1..b7434a81 100644
--- a/tftf/tests/extensions/pauth/test_pauth.c
+++ b/tftf/tests/extensions/pauth/test_pauth.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -60,7 +60,7 @@ static void set_store_pauth_keys(void)
memset(pauth_keys_before, 0, NUM_KEYS * sizeof(uint128_t));
- if (is_armv8_3_pauth_apa_api_present()) {
+ if (is_armv8_3_pauth_apa_api_apa3_present()) {
if (is_pauth_key_enabled(SCTLR_EnIA_BIT)) {
/* Read APIAKey_EL1 */
plat_key = read_apiakeylo_el1() |
@@ -119,7 +119,7 @@ static void set_store_pauth_keys(void)
* APGAKey_EL1 can be re-programmed, as this key is not set in
* TF-A Test suite and PACGA instruction is not used.
*/
- if (is_armv8_3_pauth_gpa_gpi_present()) {
+ if (is_armv8_3_pauth_gpa_gpi_gpa3_present()) {
/* Program APGAKey_EL1 */
plat_key = init_apkey();
write_apgakeylo_el1((uint64_t)plat_key);
@@ -138,7 +138,7 @@ static void read_pauth_keys(void)
{
memset(pauth_keys_after, 0, NUM_KEYS * sizeof(uint128_t));
- if (is_armv8_3_pauth_apa_api_present()) {
+ if (is_armv8_3_pauth_apa_api_apa3_present()) {
/* Read APIAKey_EL1 */
pauth_keys_after[0] = read_apiakeylo_el1() |
((uint128_t)(read_apiakeyhi_el1()) << 64);
@@ -156,7 +156,7 @@ static void read_pauth_keys(void)
((uint128_t)(read_apdbkeyhi_el1()) << 64);
}
- if (is_armv8_3_pauth_gpa_gpi_present()) {
+ if (is_armv8_3_pauth_gpa_gpi_gpa3_present()) {
/* Read APGAKey_EL1 */
pauth_keys_after[4] = read_apgakeylo_el1() |
((uint128_t)(read_apgakeyhi_el1()) << 64);
diff --git a/tftf/tests/extensions/rng_trap/test_rndr_trap.c b/tftf/tests/extensions/rng_trap/test_rndr_trap.c
new file mode 100644
index 00000000..423c78f5
--- /dev/null
+++ b/tftf/tests/extensions/rng_trap/test_rndr_trap.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <test_helpers.h>
+#include <tftf.h>
+#include <tftf_lib.h>
+
+/*
+ * This very simple test just ensures that a RNDR read access causes a trap
+ * to EL3.
+ */
+test_result_t test_rndr_trap_enabled(void)
+{
+#if defined __aarch64__
+ /* Make sure FEAT_RNG_TRAP is supported. */
+ SKIP_TEST_IF_RNG_TRAP_NOT_SUPPORTED();
+
+ /* Attempt to read RNDR. */
+ read_rndr();
+
+ /*
+ * If we make it this far, the test fails, as there was no trap
+ * to EL3 triggered.
+ */
+ return TEST_RESULT_FAIL;
+#else
+ /* Skip test if AArch32 */
+ SKIP_TEST_IF_AARCH32();
+#endif
+}
diff --git a/tftf/tests/extensions/rng_trap/test_rndrrs_trap.c b/tftf/tests/extensions/rng_trap/test_rndrrs_trap.c
new file mode 100644
index 00000000..e9beb537
--- /dev/null
+++ b/tftf/tests/extensions/rng_trap/test_rndrrs_trap.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <test_helpers.h>
+#include <tftf.h>
+#include <tftf_lib.h>
+
+/*
+ * This very simple test just ensures that a RNDRRS read access causes a trap
+ * to EL3.
+ */
+test_result_t test_rndrrs_trap_enabled(void)
+{
+#if defined __aarch64__
+ /* Make sure FEAT_RNG_TRAP is supported. */
+ SKIP_TEST_IF_RNG_TRAP_NOT_SUPPORTED();
+
+ /* Attempt to read RNDR. */
+ read_rndrrs();
+
+ /*
+ * If we make it this far, the test fails, as there was no trap
+ * to EL3 triggered.
+ */
+ return TEST_RESULT_FAIL;
+#else
+ /* Skip test if AArch32 */
+ SKIP_TEST_IF_AARCH32();
+#endif
+}
diff --git a/tftf/tests/extensions/sme/test_sme.c b/tftf/tests/extensions/sme/test_sme.c
new file mode 100644
index 00000000..4bf6e59e
--- /dev/null
+++ b/tftf/tests/extensions/sme/test_sme.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <lib/extensions/sme.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+test_result_t test_sme_support(void)
+{
+ /* SME is an AArch64-only feature.*/
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ u_register_t reg;
+ unsigned int current_vector_len;
+ unsigned int requested_vector_len;
+ unsigned int len_max;
+
+ /* Skip the test if SME is not supported. */
+ if (!feat_sme_supported()) {
+ INFO("SME not supported, skipping.\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /* Enable SME for use at NS EL2. */
+ if (sme_enable() != 0) {
+ ERROR("Could not enable SME.\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure TPIDR2_EL0 is accessible. */
+ write_tpidr2_el0(0);
+ if (read_tpidr2_el0() != 0) {
+ ERROR("Could not read TPIDR2_EL0.\n");
+ return TEST_RESULT_FAIL;
+ }
+ write_tpidr2_el0(0xb0bafe77);
+ if (read_tpidr2_el0() != 0xb0bafe77) {
+ ERROR("Could not write TPIDR2_EL0.\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure we can start and stop streaming mode. */
+ VERBOSE("Entering Streaming SVE mode.\n");
+ sme_smstart(false);
+ read_smcr_el2();
+ sme_smstop(false);
+ sme_smstart(true);
+ read_smcr_el2();
+ sme_smstop(true);
+
+ /*
+ * Iterate through values for LEN to detect supported vector lengths.
+ * SME instructions aren't supported by GCC yet so for now this is all
+ * we'll do.
+ */
+ sme_smstart(false);
+
+ /* Write SMCR_EL2 with the LEN max to find implemented width. */
+ write_smcr_el2(SME_SMCR_LEN_MAX);
+ len_max = (unsigned int)read_smcr_el2();
+ VERBOSE("Maximum SMCR_EL2.LEN value: 0x%x\n", len_max);
+ VERBOSE("Enumerating supported vector lengths...\n");
+ for (unsigned int i = 0; i <= len_max; i++) {
+ /* Load new value into SMCR_EL2.LEN */
+ reg = read_smcr_el2();
+ reg &= ~(SMCR_ELX_LEN_MASK << SMCR_ELX_LEN_SHIFT);
+ reg |= (i << SMCR_ELX_LEN_SHIFT);
+ write_smcr_el2(reg);
+
+ /* Compute current and requested vector lengths in bits. */
+ current_vector_len = ((unsigned int)sme_rdvl_1() * 8U);
+ requested_vector_len = (i+1U)*128U;
+
+ /*
+ * We count down from the maximum SMLEN value, so if the values
+ * match, we've found the largest supported value for SMLEN.
+ */
+ if (current_vector_len == requested_vector_len) {
+ VERBOSE("SUPPORTED: %u bits (LEN=%u)\n", requested_vector_len, i);
+ } else {
+ VERBOSE("NOT SUPPORTED: %u bits (LEN=%u)\n", requested_vector_len, i);
+ }
+ }
+ sme_smstop(false);
+
+ /* If FEAT_SME_FA64 then attempt to execute an illegal instruction. */
+ if (feat_sme_fa64_supported()) {
+ VERBOSE("FA64 supported, trying illegal instruction.\n");
+ sme_try_illegal_instruction();
+ }
+
+ return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/extensions/spe/test_spe.c b/tftf/tests/extensions/spe/test_spe.c
new file mode 100644
index 00000000..8b18654f
--- /dev/null
+++ b/tftf/tests/extensions/spe/test_spe.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <test_helpers.h>
+
+#ifdef __aarch64__
+/*
+ * Get SPE version value from id_aa64dfr0_el1.
+ * Return values
+ * ID_AA64DFR0_SPE_NOT_SUPPORTED: not supported
+ * ID_AA64DFR0_SPE: FEAT_SPE supported (introduced in ARM v8.2)
+ * ID_AA64DFR0_SPE_V1P1: FEAT_SPEv1p1 supported (introduced in ARM v8.5)
+ * ID_AA64DFR0_SPE_V1P2: FEAT_SPEv1p2 supported (introduced in ARM v8.7)
+ */
+
+typedef enum {
+ ID_AA64DFR0_SPE_NOT_SUPPORTED = 0,
+ ID_AA64DFR0_SPE,
+ ID_AA64DFR0_SPE_V1P1,
+ ID_AA64DFR0_SPE_V1P2
+} spe_ver_t;
+
+static spe_ver_t spe_get_version(void)
+{
+ return (spe_ver_t)((read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT) &
+ ID_AA64DFR0_PMS_MASK);
+}
+#endif /* __aarch64__ */
+
+test_result_t test_spe_support(void)
+{
+ /* SPE is an AArch64-only feature.*/
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ spe_ver_t spe_ver = spe_get_version();
+
+ assert(spe_ver <= ID_AA64DFR0_SPE_V1P2);
+
+ if (spe_ver == ID_AA64DFR0_SPE_NOT_SUPPORTED) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /*
+ * If runtime-EL3 does not enable access to SPE system
+ * registers from NS-EL2/NS-EL1 then read of these
+ * registers traps in EL3
+ */
+ read_pmscr_el1();
+ read_pmsfcr_el1();
+ read_pmsicr_el1();
+ read_pmsidr_el1();
+ read_pmsirr_el1();
+ read_pmslatfr_el1();
+ read_pmblimitr_el1();
+ read_pmbptr_el1();
+ read_pmbsr_el1();
+ read_pmsevfr_el1();
+ if (IS_IN_EL2()) {
+ read_pmscr_el2();
+ }
+ if (spe_ver == ID_AA64DFR0_SPE_V1P2) {
+ read_pmsnevfr_el1();
+ }
+
+ return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/extensions/sve/test_sve.c b/tftf/tests/extensions/sve/test_sve.c
index 235e2b8e..eabc0de4 100644
--- a/tftf/tests/extensions/sve/test_sve.c
+++ b/tftf/tests/extensions/sve/test_sve.c
@@ -8,6 +8,7 @@
#include <arch_helpers.h>
#include <debug.h>
#include <stdlib.h>
+#include <test_helpers.h>
#include <tftf_lib.h>
#include "./test_sve.h"
@@ -32,11 +33,7 @@ static int sve_op_2[SVE_ARRAYSIZE];
*/
test_result_t test_sve_support(void)
{
- /* Check if SVE is implemented and usable */
- if (is_armv8_2_sve_present() == false) {
- tftf_testcase_printf("SVE support absent\n");
- return TEST_RESULT_SKIPPED;
- }
+ SKIP_TEST_IF_SVE_NOT_SUPPORTED();
for (int i = 0; i < SVE_ARRAYSIZE; i++) {
/* Generate a random number between 200 and 299 */
diff --git a/tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.c b/tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.c
new file mode 100644
index 00000000..6c28c871
--- /dev/null
+++ b/tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <tftf.h>
+
+#include "./test_sys_reg_trace.h"
+
+static uint32_t get_trace_arch_ver(void)
+{
+ uint32_t val = read_trcdevarch();
+ val = (val >> TRCDEVARCH_ARCHVER_SHIFT) & TRCDEVARCH_ARCHVER_MASK;
+
+ return val;
+}
+
+/*
+ * EL3 is expected to allow access to trace system registers from EL2.
+ * Reading these register will trap to EL3 and crash when EL3 has not
+ * allowed access.
+ */
+test_result_t test_sys_reg_trace_enabled(void)
+{
+ SKIP_TEST_IF_SYS_REG_TRACE_NOT_SUPPORTED();
+
+ /*
+ * Read few ETMv4 system trace registers to verify correct access
+ * been provided from EL3.
+ */
+ uint32_t trace_arch_ver __unused = get_trace_arch_ver();
+ read_trcauxctlr();
+ read_trcccctlr();
+ read_trcbbctlr();
+ read_trcclaimset();
+ read_trcclaimclr();
+
+ /*
+ * Read few ETE system trace registers to verify correct access
+ * been provided from EL3. ETE system trace register access are
+ * not possible from NS-EL2 in aarch32 state.
+ */
+#if __aarch64__
+ if (trace_arch_ver == TRCDEVARCH_ARCHVER_ETE) {
+ read_trcrsr();
+ read_trcextinselr0();
+ read_trcextinselr1();
+ read_trcextinselr2();
+ read_trcextinselr3();
+ }
+#endif /* __aarch64__ */
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.h b/tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.h
new file mode 100644
index 00000000..640b82c2
--- /dev/null
+++ b/tftf/tests/extensions/sys_reg_trace/test_sys_reg_trace.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEST_SYS_REG_TRACE_H
+#define TEST_SYS_REG_TRACE_H
+
+/* TRCEDEVARCH definitions */
+#define TRCDEVARCH_ARCHVER_SHIFT U(12)
+#define TRCDEVARCH_ARCHVER_MASK U(0xf)
+#define TRCDEVARCH_ARCHVER_ETE U(0x5)
+
+#endif /* TEST_SYS_REG_TRACE_H */
diff --git a/tftf/tests/extensions/trbe/test_trbe.c b/tftf/tests/extensions/trbe/test_trbe.c
new file mode 100644
index 00000000..8ef9576e
--- /dev/null
+++ b/tftf/tests/extensions/trbe/test_trbe.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <tftf.h>
+
+/*
+ * EL3 is expected to allow access to trace control registers from EL2.
+ * Reading these register will trap to EL3 and crash when EL3 has not
+ * allowed access.
+ */
+test_result_t test_trbe_enabled(void)
+{
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ SKIP_TEST_IF_TRBE_NOT_SUPPORTED();
+ read_trblimitr_el1();
+ read_trbptr_el1();
+ read_trbbaser_el1();
+ read_trbsr_el1();
+ read_trbmar_el1();
+ read_trbtrg_el1();
+ read_trbidr_el1();
+ return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/extensions/trf/test_trf.c b/tftf/tests/extensions/trf/test_trf.c
new file mode 100644
index 00000000..eeb967db
--- /dev/null
+++ b/tftf/tests/extensions/trf/test_trf.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <tftf.h>
+
+/*
+ * EL3 is expected to allow access to trace filter control registers from EL2.
+ * Reading these register will trap to EL3 and crash when EL3 has not
+ * allowed access.
+ */
+test_result_t test_trf_enabled(void)
+{
+ SKIP_TEST_IF_TRF_NOT_SUPPORTED();
+
+#ifdef __aarch64__
+ read_trfcr_el1();
+ read_trfcr_el2();
+#else
+ read_htrfcr();
+ read_trfcr();
+#endif /* __aarch64__ */
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/extensions/wfxt/test_wfxt.c b/tftf/tests/extensions/wfxt/test_wfxt.c
new file mode 100644
index 00000000..bb3e4866
--- /dev/null
+++ b/tftf/tests/extensions/wfxt/test_wfxt.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <arch.h>
+#include <arch_helpers.h>
+#include <debug.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+typedef enum {
+ EXEC_WFIT = 0,
+ EXEC_WFET
+} exec_wfxt;
+
+#ifdef __aarch64__
+static test_result_t test_wfxt_inst(exec_wfxt val, uint64_t ms)
+{
+ __asm__ volatile(".arch armv8.7-a");
+ uint64_t timer_cnt1, timer_cnt2, feed_cnt;
+ uint64_t timer_freq = read_cntfrq_el0();
+ uint64_t ms_to_counts = ((ms * timer_freq) / 1000U);
+
+ timer_cnt1 = virtualcounter_read();
+ feed_cnt = timer_cnt1 + ms_to_counts;
+
+ if (val == EXEC_WFIT) {
+ wfit(feed_cnt);
+ } else {
+ wfet(feed_cnt);
+ }
+
+ timer_cnt2 = virtualcounter_read();
+
+ /* Lapsed time should be at least equal to sleep time */
+ if ((timer_cnt2 - timer_cnt1) >= ms_to_counts) {
+ return TEST_RESULT_SUCCESS;
+ } else {
+ /* unlikely ends up here */
+ uint64_t lapsed_ms = ((timer_cnt2 - timer_cnt1) * 1000) / timer_freq;
+
+ ERROR("Time elapsed: actual(%llu)ms vs requested(%llu)ms \n",
+ lapsed_ms, ms);
+ return TEST_RESULT_FAIL;
+ }
+}
+#endif /* __aarch64__ */
+
+test_result_t test_wfet_instruction(void)
+{
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ SKIP_TEST_IF_WFXT_NOT_SUPPORTED();
+
+ /*
+ * first invocation of wfe returns immediately clearing the event
+ * register
+ */
+ sevl();
+ wfe();
+
+ return test_wfxt_inst(EXEC_WFET, 10);
+#endif /* __aarch64__ */
+}
+
+test_result_t test_wfit_instruction(void)
+{
+ test_result_t ret;
+
+ SKIP_TEST_IF_AARCH32();
+
+#ifdef __aarch64__
+ SKIP_TEST_IF_WFXT_NOT_SUPPORTED();
+
+ /* disable irqs to run wfi till timeout */
+ disable_irq();
+
+ ret = test_wfxt_inst(EXEC_WFIT, 10);
+
+ /* enable irq back */
+ enable_irq();
+#endif /* __aarch64__ */
+
+ return ret;
+}
diff --git a/tftf/tests/misc_tests/inject_serror.S b/tftf/tests/misc_tests/inject_serror.S
index d42441dd..fd51f855 100644
--- a/tftf/tests/misc_tests/inject_serror.S
+++ b/tftf/tests/misc_tests/inject_serror.S
@@ -27,6 +27,7 @@ func inject_serror_record
/* Clear SError received flag if necessary */
cbz x3, 1f
str xzr, [x3, #0]
+ dsb st
1:
/* Choose Error record 0 on the PE */
msr ERRSELR_EL1, x0
@@ -52,6 +53,7 @@ func inject_serror_record
2:
wfe
+ dsb st
ldr x0, [x3, #0]
cbz x0, 2b
diff --git a/tftf/tests/misc_tests/test_invalid_access.c b/tftf/tests/misc_tests/test_invalid_access.c
new file mode 100644
index 00000000..14be340d
--- /dev/null
+++ b/tftf/tests/misc_tests/test_invalid_access.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <debug.h>
+#ifdef __aarch64__
+#include <sync.h>
+#endif
+#include <test_helpers.h>
+#include <lib/aarch64/arch_features.h>
+#include <runtime_services/realm_payload/realm_payload_test.h>
+#include <tftf_lib.h>
+#include <xlat_tables_v2.h>
+
+#include <platform_def.h>
+#include <cactus_test_cmds.h>
+#include <ffa_endpoints.h>
+
+
+/*
+ * Using "__aarch64__" here looks weird but its unavoidable because of following reason
+ * This test is part of standard test which runs on all platforms but pre-requisite
+ * to run this test (custom sync exception handler) is only implemented for aarch64.
+ * TODO: Write a framework so that tests kept in standard list can be selectively
+ * run on a given architecture
+ */
+#ifdef __aarch64__
+
+#define SENDER HYP_ID
+#define RECEIVER SP_ID(1)
+
+static volatile bool sync_exception_triggered;
+static volatile bool data_abort_triggered;
+static const struct ffa_uuid expected_sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
+};
+
+static __aligned(PAGE_SIZE) uint64_t share_page[PAGE_SIZE / sizeof(uint64_t)];
+
+static bool data_abort_handler(void)
+{
+ uint64_t esr_elx = IS_IN_EL2() ? read_esr_el2() : read_esr_el1();
+ unsigned int rme_supported = get_armv9_2_feat_rme_support();
+
+ sync_exception_triggered = true;
+
+ VERBOSE("%s esr_elx %llx\n", __func__, esr_elx);
+
+ if (EC_BITS(esr_elx) == EC_DABORT_CUR_EL) {
+ if (rme_supported == 0) {
+ /* Synchronous external data abort triggered by trustzone controller */
+ if ((ISS_BITS(esr_elx) & ISS_DFSC_MASK) == DFSC_EXT_DABORT) {
+ VERBOSE("%s TZC Data Abort caught\n", __func__);
+ data_abort_triggered = true;
+ return true;
+ }
+ } else {
+ /* Synchronous data abort triggered by Granule protection */
+ if ((ISS_BITS(esr_elx) & ISS_DFSC_MASK) == DFSC_GPF_DABORT) {
+ VERBOSE("%s GPF Data Abort caught\n", __func__);
+ data_abort_triggered = true;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+test_result_t el3_memory_cannot_be_accessed_in_ns(void)
+{
+ const uintptr_t test_address = EL3_MEMORY_ACCESS_ADDR;
+
+ VERBOSE("Attempt to access el3 memory (0x%lx)\n", test_address);
+
+ sync_exception_triggered = false;
+ data_abort_triggered = false;
+
+ int rc = mmap_add_dynamic_region(test_address, test_address, PAGE_SIZE,
+ MT_MEMORY | MT_RW | MT_NS);
+ if (rc != 0) {
+ tftf_testcase_printf("%d: mmap_add_dynamic_region() = %d\n", __LINE__, rc);
+ return TEST_RESULT_FAIL;
+ }
+
+ register_custom_sync_exception_handler(data_abort_handler);
+ *((volatile uint64_t *)test_address);
+ unregister_custom_sync_exception_handler();
+
+ rc = mmap_remove_dynamic_region(test_address, PAGE_SIZE);
+ if (rc != 0) {
+ tftf_testcase_printf("%d: mmap_remove_dynamic_region() = %d\n", __LINE__, rc);
+ return TEST_RESULT_FAIL;
+ }
+
+ if (sync_exception_triggered == false) {
+ tftf_testcase_printf("No sync exception while accessing (0x%lx)\n", test_address);
+ return TEST_RESULT_SKIPPED;
+ }
+
+ if (data_abort_triggered == false) {
+ tftf_testcase_printf("Sync exception is not data abort\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * @Test_Aim@ Check a realm region cannot be accessed from normal world.
+ *
+ * This test delegates a TFTF allocated buffer to Realm. It then attempts
+ * a read access to the region from normal world. This results in the PE
+ * triggering a GPF caught by a custom synchronous abort handler.
+ *
+ */
+test_result_t rl_memory_cannot_be_accessed_in_ns(void)
+{
+ test_result_t result = TEST_RESULT_FAIL;
+ u_register_t retmm;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ sync_exception_triggered = false;
+ data_abort_triggered = false;
+ register_custom_sync_exception_handler(data_abort_handler);
+
+ /* First read access to the test region must not fail. */
+ *((volatile uint64_t *)share_page);
+
+ if ((sync_exception_triggered != false) ||
+ (data_abort_triggered != false)) {
+ goto out_unregister;
+ }
+
+ /* Delegate the shared page to Realm. */
+ retmm = realm_granule_delegate((u_register_t)&share_page);
+ if (retmm != 0UL) {
+ ERROR("Granule delegate failed!\n");
+ goto out_unregister;
+ }
+
+ /* This access shall trigger a GPF. */
+ *((volatile uint64_t *)share_page);
+
+ if ((sync_exception_triggered != true) ||
+ (data_abort_triggered != true)) {
+ goto out_undelegate;
+ }
+
+ result = TEST_RESULT_SUCCESS;
+
+out_undelegate:
+ /* Undelegate the shared page. */
+ retmm = realm_granule_undelegate((u_register_t)&share_page);
+ if (retmm != 0UL) {
+ ERROR("Granule undelegate failed!\n");
+ }
+
+out_unregister:
+ unregister_custom_sync_exception_handler();
+
+ return result;
+}
+
+/**
+ * @Test_Aim@ Check a secure region cannot be accessed from normal world.
+ *
+ * Following test intends to run on RME enabled platforms when EL3
+ * is Root world. In a non RME platform, EL3 is secure.
+ * Access to secure memory from NS world is already covered
+ * by el3_memory_cannot_be_accessed_in_ns.
+ */
+test_result_t s_memory_cannot_be_accessed_in_ns(void)
+{
+ const uintptr_t test_address = SECURE_MEMORY_ACCESS_ADDR;
+
+ /* skipp non RME platforms */
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ VERBOSE("Attempt to access secure memory (0x%lx)\n", test_address);
+
+ data_abort_triggered = false;
+ sync_exception_triggered = false;
+ register_custom_sync_exception_handler(data_abort_handler);
+ dsbsy();
+
+ int rc = mmap_add_dynamic_region(test_address, test_address, PAGE_SIZE,
+ MT_MEMORY | MT_RW | MT_NS);
+
+ if (rc != 0) {
+ tftf_testcase_printf("%d: mmap_add_dynamic_region() = %d\n", __LINE__, rc);
+ return TEST_RESULT_FAIL;
+ }
+
+ *((volatile uint64_t *)test_address);
+
+ mmap_remove_dynamic_region(test_address, PAGE_SIZE);
+
+ dsbsy();
+ unregister_custom_sync_exception_handler();
+
+ if (sync_exception_triggered == false) {
+ tftf_testcase_printf("No sync exception while accessing (0x%lx)\n", test_address);
+ return TEST_RESULT_SKIPPED;
+ }
+
+ if (data_abort_triggered == false) {
+ tftf_testcase_printf("Sync exception is not data abort\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+static test_result_t memory_cannot_be_accessed_in_rl(u_register_t params)
+{
+ u_register_t retrmm;
+ static char rd[GRANULE_SIZE] __aligned(GRANULE_SIZE);
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ retrmm = realm_version();
+
+ VERBOSE("RMM version is: %lu.%lu\n",
+ RMI_ABI_VERSION_GET_MAJOR(retrmm),
+ RMI_ABI_VERSION_GET_MINOR(retrmm));
+
+ /*
+ * TODO: Remove this once SMC_RMM_REALM_CREATE is implemented in TRP
+ * For the moment skip the test if RMM is TRP, TRP version is always null.
+ */
+ if (retrmm == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ retrmm = realm_granule_delegate((u_register_t)&rd[0]);
+ if (retrmm != 0UL) {
+ ERROR("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Create a realm using a parameter in a secure physical address space should fail. */
+ retrmm = realm_create((u_register_t)&rd[0], params);
+ if (retrmm == 0UL) {
+ ERROR("Realm create operation should fail, %lx\n", retrmm);
+ retrmm = realm_destroy((u_register_t)&rd[0]);
+ if (retrmm != 0UL) {
+ ERROR("Realm destroy operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ return TEST_RESULT_FAIL;
+ } else if (retrmm != RMM_STATUS_ERROR_INPUT) {
+ ERROR("Realm create operation should fail with code:%ld retrmm:%ld\n",
+ RMM_STATUS_ERROR_INPUT, retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ retrmm = realm_granule_undelegate((u_register_t)&rd[0]);
+ if (retrmm != 0UL) {
+ INFO("Undelegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * @Test_Aim@ Check a root region cannot be accessed from a secure partition.
+ *
+ * This change adds TFTF and cactus test to permit checking a root region
+ * cannot be accessed from secure world.
+ * A hardcoded address marked Root in the GPT is shared to a secure
+ * partition. The SP retrieves the region from the SPM, maps it and
+ * attempts a read access to the region. It is expected to trigger a GPF
+ * data abort on the PE caught by a custom exception handler.
+ *
+ */
+test_result_t rt_memory_cannot_be_accessed_in_s(void)
+{
+ const uintptr_t test_address = EL3_MEMORY_ACCESS_ADDR;
+ struct ffa_memory_region_constituent constituents[] = {
+ {
+ (void *)test_address, 1, 0
+ }
+ };
+ const uint32_t constituents_count = sizeof(constituents) /
+ sizeof(struct ffa_memory_region_constituent);
+ ffa_memory_handle_t handle;
+ struct mailbox_buffers mb;
+ struct ffa_value ret;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ INIT_TFTF_MAILBOX(mb);
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ GET_TFTF_MAILBOX(mb);
+
+ handle = memory_init_and_send((struct ffa_memory_region *)mb.send,
+ PAGE_SIZE, SENDER, RECEIVER,
+ constituents, constituents_count,
+ FFA_MEM_SHARE_SMC32, &ret);
+
+ if (handle == FFA_MEMORY_HANDLE_INVALID) {
+ return TEST_RESULT_FAIL;
+ }
+
+ VERBOSE("TFTF - Handle: %llx Address: %p\n",
+ handle, constituents[0].address);
+
+ /* Retrieve the shared page and attempt accessing it. */
+ ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_SHARE_SMC32,
+ handle, 0, true, 1);
+
+ if (is_ffa_call_error(ffa_mem_reclaim(handle, 0))) {
+ ERROR("Memory reclaim failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Expect success response with value 1 hinting an exception
+ * triggered while the SP accessed the region.
+ */
+ if (!(cactus_get_response(ret) == CACTUS_SUCCESS &&
+ cactus_error_code(ret) == 1)) {
+ ERROR("Exceptions test failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+test_result_t s_memory_cannot_be_accessed_in_rl(void)
+{
+ u_register_t params = (u_register_t)SECURE_MEMORY_ACCESS_ADDR;
+ return memory_cannot_be_accessed_in_rl(params);
+}
+
+test_result_t rt_memory_cannot_be_accessed_in_rl(void)
+{
+ u_register_t params = (u_register_t)EL3_MEMORY_ACCESS_ADDR;
+ return memory_cannot_be_accessed_in_rl(params);
+}
+
+#else
+
+test_result_t el3_memory_cannot_be_accessed_in_ns(void)
+{
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+}
+
+test_result_t rl_memory_cannot_be_accessed_in_ns(void)
+{
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+}
+
+test_result_t s_memory_cannot_be_accessed_in_ns(void)
+{
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+}
+
+test_result_t s_memory_cannot_be_accessed_in_rl(void)
+{
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+}
+
+test_result_t rt_memory_cannot_be_accessed_in_rl(void)
+{
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+}
+
+#endif /* __aarch64__ */
diff --git a/tftf/tests/performance_tests/test_psci_latencies.c b/tftf/tests/performance_tests/test_psci_latencies.c
index 8a7a1d03..b20fe887 100644
--- a/tftf/tests/performance_tests/test_psci_latencies.c
+++ b/tftf/tests/performance_tests/test_psci_latencies.c
@@ -34,27 +34,6 @@ static event_t target_booted, target_keep_on_booted, target_keep_on;
*/
#define BASELINE_VARIANCE 10
-/*
- * Utility function to wait for all CPUs other than the caller to be
- * OFF.
- */
-static void wait_for_non_lead_cpus(void)
-{
- unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
- unsigned int target_mpid, target_node;
-
- for_each_cpu(target_node) {
- target_mpid = tftf_get_mpidr_from_node(target_node);
- /* Skip lead CPU, as it is powered on */
- if (target_mpid == lead_mpid)
- continue;
-
- while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0)
- != PSCI_STATE_OFF)
- ;
- }
-}
-
static test_result_t test_target_function(void)
{
tftf_send_event(&target_booted);
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 00000000..1aaa12c0
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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>
+
+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)
+#define MAX_REPEATED_TEST 3
+
+/* 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];
+static event_t cpu_booted[PLATFORM_CORE_COUNT];
+static unsigned int lead_mpid;
+/*
+ * The following test conducts SPM(direct messaging) tests on a subset of selected CPUs while
+ * simultaneously performing another set of tests of the RMI(delegation)
+ * 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 = 0;
+ 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) {
+#if (PLATFORM_CORE_COUNT > 1)
+ seln = (rand() % (PLATFORM_CORE_COUNT - 1)) + 1;
+#endif
+ 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;
+}
+
+static test_result_t reset_buffer_del_spm_rmi(void)
+{
+ u_register_t retrmm;
+
+ for (uint32_t i = 0; i < (NUM_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+ if (bufferstate[i] == B_DELEGATED) {
+ retrmm = realm_granule_undelegate(
+ (u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+ if (retrmm != 0UL) {
+ ERROR("Undelegate operation returns fail, %lx\n",
+ retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ bufferstate[i] = B_UNDELEGATED;
+ }
+ }
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Each CPU reaching this function will send a ready event to all other CPUs
+ * and wait for others CPUs before start executing its callback in parallel
+ * with all others CPUs
+ */
+static test_result_t wait_then_call(test_result_t (*callback)(void))
+{
+ unsigned int mpidr, this_mpidr = read_mpidr_el1() & MPID_MASK;
+ unsigned int cpu_node, core_pos, this_core_pos = platform_get_core_pos(this_mpidr);
+ tftf_send_event_to_all(&cpu_booted[this_core_pos]);
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ /* Ignore myself and the lead core */
+ if (mpidr == this_mpidr || mpidr == lead_mpid) {
+ continue;
+ }
+ core_pos = platform_get_core_pos(mpidr);
+ tftf_wait_for_event(&cpu_booted[core_pos]);
+ }
+ /* All cores reach this call in approximately "same" time */
+ return (*callback)();
+}
+
+/*
+ * Power on the given cpu and provide it with entrypoint to run and return result
+ */
+static test_result_t run_on_cpu(unsigned int mpidr, uintptr_t cpu_on_handler)
+{
+ int32_t ret;
+
+ ret = tftf_cpu_on(mpidr, cpu_on_handler, 0U);
+ if (ret != PSCI_E_SUCCESS) {
+ ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
+ return TEST_RESULT_FAIL;
+ }
+ 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 test_result_t send_cactus_echo_cmd(ffa_id_t sender,
+ ffa_id_t dest,
+ uint64_t value)
+{
+ struct ffa_value 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;
+ struct ffa_value 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:
+ return ret;
+}
+
+/*
+ * Secondary core will perform sequentially a call to secure and realm worlds.
+ */
+test_result_t non_secure_call_secure_and_realm(void)
+{
+ test_result_t result = run_spm_direct_message();
+ if (result != TEST_RESULT_SUCCESS)
+ return result;
+ return realm_multi_cpu_payload_del_undel();
+}
+
+/*
+ * Non secure call secure synchronously in parallel
+ * with all other cores in this test
+ */
+static test_result_t non_secure_call_secure_multi_cpu_sync(void)
+{
+ return wait_then_call(run_spm_direct_message);
+}
+
+/*
+ * 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;
+}
+
+/*
+ * Non secure call realm synchronously in parallel
+ * with all other cores in this test
+ */
+static test_result_t non_secure_call_realm_multi_cpu_sync(void)
+{
+ return wait_then_call(realm_multi_cpu_payload_del_undel);
+}
+
+/*
+ * NS world communicate with S and RL worlds in series via SMC from a single core.
+ */
+test_result_t test_spm_rmm_serial_smc(void)
+{
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ lead_mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int mpidr;
+
+ /**********************************************************************
+ * Check SPMC has ffa_version and expected FFA endpoints are deployed.
+ **********************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+ /*
+ * 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;
+ }
+
+ /*
+ * Preparation step:
+ * Find another CPU than the lead CPU and power it on.
+ */
+ mpidr = tftf_find_any_cpu_other_than(lead_mpid);
+ assert(mpidr != INVALID_MPID);
+
+ /*
+ * Run SPM direct message call and RMI call in serial on a second core.
+ * wait for core power cycle between each call.
+ */
+ for (size_t i = 0; i < MAX_REPEATED_TEST; i++) {
+ /* SPM FF-A direct message call */
+ if (TEST_RESULT_SUCCESS != run_on_cpu(mpidr,
+ (uintptr_t)non_secure_call_secure_and_realm)) {
+ return TEST_RESULT_FAIL;
+ }
+ /* Wait for the target CPU to finish the test execution */
+ wait_for_core_to_turn_off(mpidr);
+ }
+
+ if (TEST_RESULT_SUCCESS != reset_buffer_del_spm_rmi()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ VERBOSE("Done exiting.\n");
+
+ /**********************************************************************
+ * All tests passed.
+ **********************************************************************/
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Test function to let NS world communicate with S and RL worlds in parallel
+ * via SMC using multiple cores
+ */
+test_result_t test_spm_rmm_parallel_smc(void)
+{
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ lead_mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int cpu_node, mpidr;
+
+ /**********************************************************************
+ * Check SPMC has ffa_version and expected FFA endpoints are deployed.
+ **********************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+ /*
+ * 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 RMM or TRP together in parallel
+ */
+ for (int i = 0; i < MAX_REPEATED_TEST; i++) {
+ VERBOSE("Main test(%d) to run both SPM and RMM or TRP together in parallel...\n", i);
+
+ /* Reinitialize all CPUs event */
+ for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+ tftf_init_event(&cpu_booted[i]);
+ }
+
+ /*
+ * Randomise the assignment of the CPU's to either SPM or RMI
+ */
+ rand_cpu_spm_rmi();
+
+ /*
+ * for each CPU we assign it randomly either spm or rmi test function
+ */
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (mpidr == lead_mpid) {
+ continue;
+ }
+ if (spm_rmi_test(mpidr) == 1) {
+ if (TEST_RESULT_SUCCESS != run_on_cpu(mpidr,
+ (uintptr_t)non_secure_call_secure_multi_cpu_sync)) {
+ return TEST_RESULT_FAIL;
+ }
+ } else {
+ if (TEST_RESULT_SUCCESS != run_on_cpu(mpidr,
+ (uintptr_t)non_secure_call_realm_multi_cpu_sync)) {
+ return TEST_RESULT_FAIL;
+ }
+ }
+ }
+
+ VERBOSE("Waiting for secondary CPUs to turn off ...\n");
+ wait_for_non_lead_cpus();
+ }
+
+ VERBOSE("Done exiting.\n");
+
+ return reset_buffer_del_spm_rmi();
+}
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 00000000..8bdc60a2
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_test.c
@@ -0,0 +1,317 @@
+/*
+ * 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>
+
+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];
+
+/*
+ * 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
+ */
+
+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;
+}
+
+/*
+ * Single CPU version check function
+ */
+test_result_t realm_version_single_cpu(void)
+{
+ 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;
+}
+
+/*
+ * Multi CPU version check function in parallel.
+ */
+test_result_t realm_version_multi_cpu(void)
+{
+ 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;
+}
+
+/*
+ * Delegate and Undelegate Non Secure Granule
+ */
+test_result_t realm_delegate_undelegate(void)
+{
+ 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;
+}
+
+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",
+ (long long)read_mpidr_el1() & MPID_MASK, RMI_ABI_VERSION_GET_MAJOR(retrmm),
+ RMI_ABI_VERSION_GET_MINOR(retrmm));
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Select all CPU's to randomly delegate/undelegate
+ * granule pages to stress the delegate mechanism
+ */
+test_result_t realm_delundel_multi_cpu(void)
+{
+ u_register_t lead_mpid, target_mpid;
+ int cpu_node;
+ long long ret;
+ u_register_t retrmm;
+
+ 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;
+ }
+ }
+
+ /*
+ * Cleanup to set all granules back to undelegated
+ */
+
+ for (int i = 0; i < (NUM_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+ if (bufferstate[i] == B_DELEGATED) {
+ retrmm = realm_granule_undelegate((u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+ bufferstate[i] = B_UNDELEGATED;
+ if (retrmm != 0UL) {
+ tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+ }
+ }
+
+ ret = TEST_RESULT_SUCCESS;
+ return ret;
+}
+
+/*
+ * 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;
+}
+
+/*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)
+{
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ u_register_t retrmm;
+
+ retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[0]);
+
+ if (retrmm != 0UL) {
+ tftf_testcase_printf
+ ("Delegate operation does not pass as expected for double delegation, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ 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;
+ }
+
+ retrmm = realm_granule_undelegate((u_register_t)&bufferdelegate[0]);
+
+ if (retrmm != 0UL) {
+ tftf_testcase_printf
+ ("Delegate operation returns fail for cleanup, %lx\n", retrmm);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
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 00000000..49bf674a
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_test_helpers.c
@@ -0,0 +1,65 @@
+/*
+ * 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;
+}
+
+u_register_t realm_create(u_register_t rd_addr, u_register_t realm_params_addr)
+{
+ smc_args args = { 0 };
+ smc_ret_values ret;
+
+ args.fid = SMC_RMM_REALM_CREATE;
+ args.arg1 = rd_addr;
+ args.arg2 = realm_params_addr;
+
+ ret = tftf_smc(&args);
+ return ret.ret0;
+}
+
+u_register_t realm_destroy(u_register_t rd_addr)
+{
+ smc_args args = { 0 };
+ smc_ret_values ret;
+
+ args.fid = SMC_RMM_REALM_DESTROY;
+ args.arg1 = rd_addr;
+
+ ret = tftf_smc(&args);
+ return ret.ret0;
+} \ No newline at end of file
diff --git a/tftf/tests/runtime_services/secure_service/aarch32/ffa_arch_helpers.S b/tftf/tests/runtime_services/secure_service/aarch32/ffa_arch_helpers.S
new file mode 100644
index 00000000..0d5395fa
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/aarch32/ffa_arch_helpers.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .macro service_call _conduit
+ /* Push r9 to keep the stack pointer aligned to 64 bit. */
+ push {r4 - r9}
+
+ /*
+ * Save the ffa_value pointer in a callee saved register.
+ */
+ mov r8, r0
+
+ /* Load the argument values into the appropriate registers. */
+ ldm r0, {r0 - r7}
+
+ \_conduit #0
+
+ /*
+ * The return values are stored in x0-x7, put them in the ffa_value
+ * return structure.
+ */
+ stm r8, {r0 - r7}
+
+ pop {r4 - r9}
+ .endm
+
+.globl ffa_svc
+func ffa_svc
+ service_call svc
+ bx lr
+endfunc ffa_svc
+
+.globl ffa_smc
+func ffa_smc
+ service_call smc
+ bx lr
+endfunc ffa_smc
diff --git a/tftf/tests/runtime_services/secure_service/aarch64/ffa_arch_helpers.S b/tftf/tests/runtime_services/secure_service/aarch64/ffa_arch_helpers.S
new file mode 100644
index 00000000..0e35a382
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/aarch64/ffa_arch_helpers.S
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+ .macro service_call _conduit
+ /*
+ * Save the address of the ffa_value structure on the stack.
+ *
+ * Although x0 contains an 8-byte value, we are allocating 16 bytes
+ * on the stack to respect the 16-byte stack-alignment.
+ */
+ str x0, [sp, #-16]!
+
+ /* Load the argument values into the appropriate registers. */
+ ldp x6, x7, [x0, #48]
+ ldp x4, x5, [x0, #32]
+ ldp x2, x3, [x0, #16]
+ ldp x0, x1, [x0, #0]
+
+ \_conduit #0
+
+ /*
+ * Pop the ffa_value structure address from the stack into a
+ * caller-saved register.
+ */
+ ldr x9, [sp], #16
+
+ /*
+ * The return values are stored in x0-x7, put them in the ffa_value
+ * return structure.
+ */
+ stp x0, x1, [x9, #0]
+ stp x2, x3, [x9, #16]
+ stp x4, x5, [x9, #32]
+ stp x6, x7, [x9, #48]
+
+ .endm
+
+.globl ffa_svc
+func ffa_svc
+ service_call svc
+ ret
+endfunc ffa_svc
+
+.globl ffa_smc
+func ffa_smc
+ service_call smc
+ ret
+endfunc ffa_smc
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index 8e7b58c6..f7370566 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -1,13 +1,24 @@
/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-#include <smccc.h>
+#include <assert.h>
#include <ffa_endpoints.h>
#include <ffa_helpers.h>
#include <ffa_svc.h>
+#include <smccc.h>
+
+struct ffa_value ffa_service_call(struct ffa_value *args)
+{
+#if IMAGE_IVY
+ ffa_svc(args);
+#else
+ ffa_smc(args);
+#endif
+ return *args;
+}
/*-----------------------------------------------------------------------------
* FFA_RUN
@@ -26,15 +37,15 @@
* -BUSY: vCPU is busy and caller must retry later
* -ABORTED: vCPU or VM ran into an unexpected error and has aborted
*/
-smc_ret_values ffa_run(uint32_t dest_id, uint32_t vcpu_id)
+struct ffa_value ffa_run(uint32_t dest_id, uint32_t vcpu_id)
{
- smc_args args = {
- FFA_MSG_RUN,
+ struct ffa_value args = {
+ FFA_RUN,
(dest_id << 16) | vcpu_id,
0, 0, 0, 0, 0, 0
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/*-----------------------------------------------------------------------------
@@ -55,12 +66,12 @@ smc_ret_values ffa_run(uint32_t dest_id, uint32_t vcpu_id)
* -BUSY: Message target is busy
* -ABORTED: Message target ran into an unexpected error and has aborted
*/
-smc_ret_values ffa_msg_send_direct_req64(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint64_t arg0,
- uint64_t arg1, uint64_t arg2,
- uint64_t arg3, uint64_t arg4)
+struct ffa_value ffa_msg_send_direct_req64(ffa_id_t source_id,
+ ffa_id_t dest_id, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2,
+ uint64_t arg3, uint64_t arg4)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MSG_SEND_DIRECT_REQ_SMC64,
.arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
.arg2 = 0,
@@ -71,15 +82,15 @@ smc_ret_values ffa_msg_send_direct_req64(ffa_vm_id_t source_id,
.arg7 = arg4,
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
-smc_ret_values ffa_msg_send_direct_req32(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint32_t arg0,
- uint32_t arg1, uint32_t arg2,
- uint32_t arg3, uint32_t arg4)
+struct ffa_value ffa_msg_send_direct_req32(ffa_id_t source_id,
+ ffa_id_t dest_id, uint32_t arg0,
+ uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t arg4)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MSG_SEND_DIRECT_REQ_SMC32,
.arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
.arg2 = 0,
@@ -90,15 +101,15 @@ smc_ret_values ffa_msg_send_direct_req32(ffa_vm_id_t source_id,
.arg7 = arg4,
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
-smc_ret_values ffa_msg_send_direct_resp64(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint64_t arg0,
- uint64_t arg1, uint64_t arg2,
- uint64_t arg3, uint64_t arg4)
+struct ffa_value ffa_msg_send_direct_resp64(ffa_id_t source_id,
+ ffa_id_t dest_id, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2,
+ uint64_t arg3, uint64_t arg4)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MSG_SEND_DIRECT_RESP_SMC64,
.arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
.arg2 = 0,
@@ -109,15 +120,15 @@ smc_ret_values ffa_msg_send_direct_resp64(ffa_vm_id_t source_id,
.arg7 = arg4,
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
-smc_ret_values ffa_msg_send_direct_resp32(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint32_t arg0,
- uint32_t arg1, uint32_t arg2,
- uint32_t arg3, uint32_t arg4)
+struct ffa_value ffa_msg_send_direct_resp32(ffa_id_t source_id,
+ ffa_id_t dest_id, uint32_t arg0,
+ uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t arg4)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MSG_SEND_DIRECT_RESP_SMC32,
.arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
.arg2 = 0,
@@ -128,7 +139,7 @@ smc_ret_values ffa_msg_send_direct_resp32(ffa_vm_id_t source_id,
.arg7 = arg4,
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
@@ -137,9 +148,9 @@ smc_ret_values ffa_msg_send_direct_resp32(ffa_vm_id_t source_id,
* composite memory region offset.
*/
static void ffa_memory_region_init_header(
- struct ffa_memory_region *memory_region, ffa_vm_id_t sender,
+ struct ffa_memory_region *memory_region, ffa_id_t sender,
ffa_memory_attributes_t attributes, ffa_memory_region_flags_t flags,
- ffa_memory_handle_t handle, uint32_t tag, ffa_vm_id_t receiver,
+ ffa_memory_handle_t handle, uint32_t tag, ffa_id_t receiver,
ffa_memory_access_permissions_t permissions)
{
memory_region->sender = sender;
@@ -168,7 +179,7 @@ static void ffa_memory_region_init_header(
*/
uint32_t ffa_memory_region_init(
struct ffa_memory_region *memory_region, size_t memory_region_max_size,
- ffa_vm_id_t sender, ffa_vm_id_t receiver,
+ ffa_id_t sender, ffa_id_t receiver,
const struct ffa_memory_region_constituent constituents[],
uint32_t constituent_count, uint32_t tag,
ffa_memory_region_flags_t flags, enum ffa_data_access data_access,
@@ -259,7 +270,7 @@ uint32_t ffa_memory_region_init(
*/
uint32_t ffa_memory_retrieve_request_init(
struct ffa_memory_region *memory_region, ffa_memory_handle_t handle,
- ffa_vm_id_t sender, ffa_vm_id_t receiver, uint32_t tag,
+ ffa_id_t sender, ffa_id_t receiver, uint32_t tag,
ffa_memory_region_flags_t flags, enum ffa_data_access data_access,
enum ffa_instruction_access instruction_access,
enum ffa_memory_type type, enum ffa_memory_cacheability cacheability,
@@ -291,105 +302,134 @@ uint32_t ffa_memory_retrieve_request_init(
memory_region->receiver_count * sizeof(struct ffa_memory_access);
}
-
/*
* FFA Version ABI helper.
* Version fields:
* -Bits[30:16]: Major version.
* -Bits[15:0]: Minor version.
*/
-smc_ret_values ffa_version(uint32_t input_version)
+struct ffa_value ffa_version(uint32_t input_version)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_VERSION,
.arg1 = input_version
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
-smc_ret_values ffa_id_get(void)
+struct ffa_value ffa_id_get(void)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_ID_GET
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
-smc_ret_values ffa_msg_wait(void)
+struct ffa_value ffa_spm_id_get(void)
{
- smc_args args = {
+ struct ffa_value args = {
+ .fid = FFA_SPM_ID_GET
+ };
+
+ return ffa_service_call(&args);
+}
+
+struct ffa_value ffa_msg_wait(void)
+{
+ struct ffa_value args = {
.fid = FFA_MSG_WAIT
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
-smc_ret_values ffa_error(int32_t error_code)
+struct ffa_value ffa_error(int32_t error_code)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_ERROR,
.arg1 = 0,
.arg2 = error_code
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Query the higher EL if the requested FF-A feature is implemented. */
-smc_ret_values ffa_features(uint32_t feature)
+struct ffa_value ffa_features(uint32_t feature)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_FEATURES,
.arg1 = feature
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Get information about VMs or SPs based on UUID */
-smc_ret_values ffa_partition_info_get(const uint32_t uuid[4])
+struct ffa_value ffa_partition_info_get(const struct ffa_uuid uuid)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_PARTITION_INFO_GET,
- .arg1 = uuid[0],
- .arg2 = uuid[1],
- .arg3 = uuid[2],
- .arg4 = uuid[3]
+ .arg1 = uuid.uuid[0],
+ .arg2 = uuid.uuid[1],
+ .arg3 = uuid.uuid[2],
+ .arg4 = uuid.uuid[3]
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Query SPMD that the rx buffer of the partition can be released */
-smc_ret_values ffa_rx_release(void)
+struct ffa_value ffa_rx_release(void)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_RX_RELEASE
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Map the RXTX buffer */
-smc_ret_values ffa_rxtx_map(uintptr_t send, uintptr_t recv, uint32_t pages)
+struct ffa_value ffa_rxtx_map(uintptr_t send, uintptr_t recv, uint32_t pages)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_RXTX_MAP_SMC64,
.arg1 = send,
.arg2 = recv,
- .arg3 = pages
+ .arg3 = pages,
+ .arg4 = FFA_PARAM_MBZ,
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ
+ };
+
+ return ffa_service_call(&args);
+}
+
+/* Unmap the RXTX buffer allocated by the given FF-A component */
+struct ffa_value ffa_rxtx_unmap(void)
+{
+ struct ffa_value args = {
+ .fid = FFA_RXTX_UNMAP,
+ .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);
+ return ffa_service_call(&args);
}
/* Donate memory to another partition */
-smc_ret_values ffa_mem_donate(uint32_t descriptor_length,
+struct ffa_value ffa_mem_donate(uint32_t descriptor_length,
uint32_t fragment_length)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MEM_DONATE_SMC32,
.arg1 = descriptor_length,
.arg2 = fragment_length,
@@ -397,14 +437,14 @@ smc_ret_values ffa_mem_donate(uint32_t descriptor_length,
.arg4 = FFA_PARAM_MBZ
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Lend memory to another partition */
-smc_ret_values ffa_mem_lend(uint32_t descriptor_length,
- uint32_t fragment_length)
+struct ffa_value ffa_mem_lend(uint32_t descriptor_length,
+ uint32_t fragment_length)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MEM_LEND_SMC32,
.arg1 = descriptor_length,
.arg2 = fragment_length,
@@ -412,14 +452,14 @@ smc_ret_values ffa_mem_lend(uint32_t descriptor_length,
.arg4 = FFA_PARAM_MBZ
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Share memory with another partition */
-smc_ret_values ffa_mem_share(uint32_t descriptor_length,
- uint32_t fragment_length)
+struct ffa_value ffa_mem_share(uint32_t descriptor_length,
+ uint32_t fragment_length)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MEM_SHARE_SMC32,
.arg1 = descriptor_length,
.arg2 = fragment_length,
@@ -427,14 +467,14 @@ smc_ret_values ffa_mem_share(uint32_t descriptor_length,
.arg4 = FFA_PARAM_MBZ
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Retrieve memory shared by another partition */
-smc_ret_values ffa_mem_retrieve_req(uint32_t descriptor_length,
- uint32_t fragment_length)
+struct ffa_value ffa_mem_retrieve_req(uint32_t descriptor_length,
+ uint32_t fragment_length)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MEM_RETRIEVE_REQ_SMC32,
.arg1 = descriptor_length,
.arg2 = fragment_length,
@@ -445,28 +485,189 @@ smc_ret_values ffa_mem_retrieve_req(uint32_t descriptor_length,
.arg7 = FFA_PARAM_MBZ
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Relinquish access to memory region */
-smc_ret_values ffa_mem_relinquish(void)
+struct ffa_value ffa_mem_relinquish(void)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MEM_RELINQUISH,
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
}
/* Reclaim exclusive access to owned memory region */
-smc_ret_values ffa_mem_reclaim(uint64_t handle, uint32_t flags)
+struct ffa_value ffa_mem_reclaim(uint64_t handle, uint32_t flags)
{
- smc_args args = {
+ struct ffa_value args = {
.fid = FFA_MEM_RECLAIM,
.arg1 = (uint32_t) handle,
.arg2 = (uint32_t) (handle >> 32),
.arg3 = flags
};
- return tftf_smc(&args);
+ return ffa_service_call(&args);
+}
+
+/** Create Notifications Bitmap for the given VM */
+struct ffa_value ffa_notification_bitmap_create(ffa_id_t vm_id,
+ ffa_vcpu_count_t vcpu_count)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_BITMAP_CREATE,
+ .arg1 = vm_id,
+ .arg2 = vcpu_count,
+ .arg3 = FFA_PARAM_MBZ,
+ .arg4 = FFA_PARAM_MBZ,
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ,
+ };
+
+ return ffa_service_call(&args);
+}
+
+/** Destroy Notifications Bitmap for the given VM */
+struct ffa_value ffa_notification_bitmap_destroy(ffa_id_t vm_id)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_BITMAP_DESTROY,
+ .arg1 = vm_id,
+ .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 ffa_service_call(&args);
+}
+
+/** Bind VM to all the notifications in the bitmap */
+struct ffa_value ffa_notification_bind(ffa_id_t sender, ffa_id_t receiver,
+ uint32_t flags,
+ ffa_notification_bitmap_t bitmap)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_BIND,
+ .arg1 = (sender << 16) | (receiver),
+ .arg2 = flags,
+ .arg3 = (uint32_t)(bitmap & 0xFFFFFFFFU),
+ .arg4 = (uint32_t)(bitmap >> 32),
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ,
+ };
+
+ return ffa_service_call(&args);
+}
+
+/** Unbind previously bound VM from notifications in bitmap */
+struct ffa_value ffa_notification_unbind(ffa_id_t sender,
+ ffa_id_t receiver,
+ ffa_notification_bitmap_t bitmap)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_UNBIND,
+ .arg1 = (sender << 16) | (receiver),
+ .arg2 = FFA_PARAM_MBZ,
+ .arg3 = (uint32_t)(bitmap),
+ .arg4 = (uint32_t)(bitmap >> 32),
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ,
+ };
+
+ return ffa_service_call(&args);
+}
+
+struct ffa_value ffa_notification_set(ffa_id_t sender, ffa_id_t receiver,
+ uint32_t flags,
+ ffa_notification_bitmap_t bitmap)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_SET,
+ .arg1 = (sender << 16) | (receiver),
+ .arg2 = flags,
+ .arg3 = (uint32_t)(bitmap & 0xFFFFFFFFU),
+ .arg4 = (uint32_t)(bitmap >> 32),
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ
+ };
+
+ return ffa_service_call(&args);
+}
+
+struct ffa_value ffa_notification_get(ffa_id_t receiver, uint32_t vcpu_id,
+ uint32_t flags)
+{
+ struct ffa_value args = {
+ .fid = FFA_NOTIFICATION_GET,
+ .arg1 = (vcpu_id << 16) | (receiver),
+ .arg2 = flags,
+ .arg3 = FFA_PARAM_MBZ,
+ .arg4 = FFA_PARAM_MBZ,
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ
+ };
+
+ return ffa_service_call(&args);
+}
+
+struct ffa_value ffa_notification_info_get(void)
+{
+ struct ffa_value 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 ffa_service_call(&args);
+}
+
+static size_t char_to_arg_helper(const char *message, size_t size,
+ u_register_t *arg)
+{
+ size_t to_write = size > sizeof(uint64_t) ? sizeof(uint64_t) : size;
+
+ for (int i = 0; i < to_write; i++) {
+ ((char *)arg)[i] = message[i];
+ }
+ return to_write;
+}
+
+struct ffa_value ffa_console_log(const char *message, size_t char_count)
+{
+ struct ffa_value args = {
+ .fid = FFA_CONSOLE_LOG_SMC64,
+ .arg1 = char_count,
+ };
+ size_t written = 0;
+
+ assert(char_count <= sizeof(uint64_t) * 6);
+
+ written += char_to_arg_helper(&message[written], char_count - written,
+ &args.arg2);
+ written += char_to_arg_helper(&message[written], char_count - written,
+ &args.arg3);
+ written += char_to_arg_helper(&message[written], char_count - written,
+ &args.arg4);
+ written += char_to_arg_helper(&message[written], char_count - written,
+ &args.arg5);
+ written += char_to_arg_helper(&message[written], char_count - written,
+ &args.arg6);
+ char_to_arg_helper(&message[written], char_count - written,
+ &args.arg7);
+
+ return ffa_service_call(&args);
}
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index 179ef1cb..ae00ff59 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -1,22 +1,29 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <cactus_test_cmds.h>
#include <debug.h>
#include <ffa_endpoints.h>
+#include <ffa_svc.h>
+#include <lib/extensions/sve.h>
#include <spm_common.h>
#include <xlat_tables_v2.h>
#define __STR(x) #x
#define STR(x) __STR(x)
-#define SIMD_TWO_VECTORS_BYTES_STR (2 * SIMD_VECTOR_LEN_BYTES)
+
+#define fill_simd_helper(num1, num2) "ldp q"#num1", q"#num2",\
+ [%0], #"STR(2 * SIMD_VECTOR_LEN_BYTES)";"
+#define read_simd_helper(num1, num2) "stp q"#num1", q"#num2",\
+ [%0], #"STR(2 * SIMD_VECTOR_LEN_BYTES)";"
/**
* Helper to log errors after FF-A calls.
*/
-bool is_ffa_call_error(smc_ret_values ret)
+bool is_ffa_call_error(struct ffa_value ret)
{
if (ffa_func_id(ret) == FFA_ERROR) {
VERBOSE("FF-A call returned error (%x): %d\n",
@@ -26,12 +33,25 @@ bool is_ffa_call_error(smc_ret_values ret)
return false;
}
+bool is_expected_ffa_error(struct ffa_value ret, int32_t error_code)
+{
+ if (ffa_func_id(ret) == FFA_ERROR &&
+ ffa_error_code(ret) == error_code) {
+ return true;
+ }
+
+ ERROR("Expected FFA_ERROR(%x), code: %d, got %x %d\n",
+ FFA_ERROR, error_code, ffa_func_id(ret), ffa_error_code(ret));
+
+ return false;
+}
+
/**
* Helper to verify return of FF-A call is an FFA_MSG_SEND_DIRECT_RESP.
* Should be used after FFA_MSG_SEND_DIRECT_REQ, or after sending a test command
* to an SP.
*/
-bool is_ffa_direct_response(smc_ret_values ret)
+bool is_ffa_direct_response(struct ffa_value ret)
{
if ((ffa_func_id(ret) == FFA_MSG_SEND_DIRECT_RESP_SMC32) ||
(ffa_func_id(ret) == FFA_MSG_SEND_DIRECT_RESP_SMC64)) {
@@ -48,7 +68,7 @@ bool is_ffa_direct_response(smc_ret_values ret)
/**
* Helper to check the return value of FF-A call is as expected.
*/
-bool is_expected_ffa_return(smc_ret_values ret, uint32_t func_id)
+bool is_expected_ffa_return(struct ffa_value ret, uint32_t func_id)
{
if (ffa_func_id(ret) == func_id) {
return true;
@@ -59,26 +79,58 @@ bool is_expected_ffa_return(smc_ret_values ret, uint32_t func_id)
return false;
}
+bool is_expected_cactus_response(struct ffa_value ret, uint32_t expected_resp,
+ uint32_t arg)
+{
+ if (!is_ffa_direct_response(ret)) {
+ return false;
+ }
+
+ if (cactus_get_response(ret) != expected_resp ||
+ (uint32_t)ret.arg4 != arg) {
+ ERROR("Expected response %x and %x; "
+ "Obtained %x and %x\n",
+ expected_resp, arg, cactus_get_response(ret),
+ (int32_t)ret.arg4);
+ return false;
+ }
+
+ return true;
+}
+
+void dump_ffa_value(struct ffa_value ret)
+{
+ NOTICE("FF-A value: %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx\n",
+ ret.fid,
+ ret.arg1,
+ ret.arg2,
+ ret.arg3,
+ ret.arg4,
+ ret.arg5,
+ ret.arg6,
+ ret.arg7);
+}
+
void fill_simd_vector_regs(const simd_vector_t v[SIMD_NUM_VECTORS])
{
#ifdef __aarch64__
__asm__ volatile(
- "ldp q0, q1, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q2, q3, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q4, q5, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q6, q7, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q8, q9, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q10, q11, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q12, q13, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q14, q15, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q16, q17, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q18, q19, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q20, q21, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q22, q23, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q24, q25, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q26, q27, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q28, q29, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "ldp q30, q31, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
+ fill_simd_helper(0, 1)
+ fill_simd_helper(2, 3)
+ fill_simd_helper(4, 5)
+ fill_simd_helper(6, 7)
+ fill_simd_helper(8, 9)
+ fill_simd_helper(10, 11)
+ fill_simd_helper(12, 13)
+ fill_simd_helper(14, 15)
+ fill_simd_helper(16, 17)
+ fill_simd_helper(18, 19)
+ fill_simd_helper(20, 21)
+ fill_simd_helper(22, 23)
+ fill_simd_helper(24, 25)
+ fill_simd_helper(26, 27)
+ fill_simd_helper(28, 29)
+ fill_simd_helper(30, 31)
"sub %0, %0, #" STR(SIMD_NUM_VECTORS * SIMD_VECTOR_LEN_BYTES) ";"
: : "r" (v));
#endif
@@ -88,29 +140,112 @@ void read_simd_vector_regs(simd_vector_t v[SIMD_NUM_VECTORS])
{
#ifdef __aarch64__
memset(v, 0, sizeof(simd_vector_t) * SIMD_NUM_VECTORS);
-
__asm__ volatile(
- "stp q0, q1, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q2, q3, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q4, q5, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q6, q7, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q8, q9, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q10, q11, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q12, q13, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q14, q15, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q16, q17, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q18, q19, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q20, q21, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q22, q23, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q24, q25, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q26, q27, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q28, q29, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
- "stp q30, q31, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
+ read_simd_helper(0, 1)
+ read_simd_helper(2, 3)
+ read_simd_helper(4, 5)
+ read_simd_helper(6, 7)
+ read_simd_helper(8, 9)
+ read_simd_helper(10, 11)
+ read_simd_helper(12, 13)
+ read_simd_helper(14, 15)
+ read_simd_helper(16, 17)
+ read_simd_helper(18, 19)
+ read_simd_helper(20, 21)
+ read_simd_helper(22, 23)
+ read_simd_helper(24, 25)
+ read_simd_helper(26, 27)
+ read_simd_helper(28, 29)
+ read_simd_helper(30, 31)
"sub %0, %0, #" STR(SIMD_NUM_VECTORS * SIMD_VECTOR_LEN_BYTES) ";"
: : "r" (v));
#endif
}
+void fill_sve_vector_regs(const sve_vector_t v[SVE_NUM_VECTORS])
+{
+#ifdef __aarch64__
+ __asm__ volatile(
+ ".arch_extension sve\n"
+ fill_sve_helper(0)
+ fill_sve_helper(1)
+ fill_sve_helper(2)
+ fill_sve_helper(3)
+ fill_sve_helper(4)
+ fill_sve_helper(5)
+ fill_sve_helper(6)
+ fill_sve_helper(7)
+ fill_sve_helper(8)
+ fill_sve_helper(9)
+ fill_sve_helper(10)
+ fill_sve_helper(11)
+ fill_sve_helper(12)
+ fill_sve_helper(13)
+ fill_sve_helper(14)
+ fill_sve_helper(15)
+ fill_sve_helper(16)
+ fill_sve_helper(17)
+ fill_sve_helper(18)
+ fill_sve_helper(19)
+ fill_sve_helper(20)
+ fill_sve_helper(21)
+ fill_sve_helper(22)
+ fill_sve_helper(23)
+ fill_sve_helper(24)
+ fill_sve_helper(25)
+ fill_sve_helper(26)
+ fill_sve_helper(27)
+ fill_sve_helper(28)
+ fill_sve_helper(29)
+ fill_sve_helper(30)
+ fill_sve_helper(31)
+ ".arch_extension nosve\n"
+ : : "r" (v));
+#endif
+}
+
+void read_sve_vector_regs(sve_vector_t v[SVE_NUM_VECTORS])
+{
+#ifdef __aarch64__
+ __asm__ volatile(
+ ".arch_extension sve\n"
+ read_sve_helper(0)
+ read_sve_helper(1)
+ read_sve_helper(2)
+ read_sve_helper(3)
+ read_sve_helper(4)
+ read_sve_helper(5)
+ read_sve_helper(6)
+ read_sve_helper(7)
+ read_sve_helper(8)
+ read_sve_helper(9)
+ read_sve_helper(10)
+ read_sve_helper(11)
+ read_sve_helper(12)
+ read_sve_helper(13)
+ read_sve_helper(14)
+ read_sve_helper(15)
+ read_sve_helper(16)
+ read_sve_helper(17)
+ read_sve_helper(18)
+ read_sve_helper(19)
+ read_sve_helper(20)
+ read_sve_helper(21)
+ read_sve_helper(22)
+ read_sve_helper(23)
+ read_sve_helper(24)
+ read_sve_helper(25)
+ read_sve_helper(26)
+ read_sve_helper(27)
+ read_sve_helper(28)
+ read_sve_helper(29)
+ read_sve_helper(30)
+ read_sve_helper(31)
+ ".arch_extension nosve\n"
+ : : "r" (v));
+#endif
+}
+
/*
* check_spmc_execution_level
*
@@ -125,17 +260,17 @@ void read_simd_vector_regs(simd_vector_t v[SIMD_NUM_VECTORS])
bool check_spmc_execution_level(void)
{
unsigned int is_optee_spmc_criteria = 0U;
- smc_ret_values ret_values;
+ struct ffa_value ret_values;
/*
* Send a first OP-TEE-defined protocol message through
- * FFA direct message.
+ * FFA direct message. Expect it to implement either v1.0 or v1.1.
*/
ret_values = ffa_msg_send_direct_req32(HYP_ID, SP_ID(1),
OPTEE_FFA_GET_API_VERSION, 0,
0, 0, 0);
- if ((ret_values.ret3 == FFA_VERSION_MAJOR) &&
- (ret_values.ret4 == FFA_VERSION_MINOR)) {
+ if (ret_values.arg3 == 1 &&
+ (ret_values.arg4 == 0 || ret_values.arg4 == 1)) {
is_optee_spmc_criteria++;
}
@@ -146,8 +281,8 @@ bool check_spmc_execution_level(void)
ret_values = ffa_msg_send_direct_req32(HYP_ID, SP_ID(1),
OPTEE_FFA_GET_OS_VERSION,
0, 0, 0, 0);
- if ((ret_values.ret3 == OPTEE_FFA_GET_OS_VERSION_MAJOR) &&
- (ret_values.ret4 == OPTEE_FFA_GET_OS_VERSION_MINOR)) {
+ if ((ret_values.arg3 == OPTEE_FFA_GET_OS_VERSION_MAJOR) &&
+ (ret_values.arg4 == OPTEE_FFA_GET_OS_VERSION_MINOR)) {
is_optee_spmc_criteria++;
}
@@ -163,14 +298,13 @@ static const struct ffa_features_test ffa_feature_test_target[] = {
{"FFA_RX_RELEASE_32 check", FFA_RX_RELEASE, FFA_SUCCESS_SMC32},
{"FFA_RXTX_MAP_32 check", FFA_RXTX_MAP_SMC32, FFA_ERROR},
{"FFA_RXTX_MAP_64 check", FFA_RXTX_MAP_SMC64, FFA_SUCCESS_SMC32},
- {"FFA_RXTX_UNMAP_32 check", FFA_RXTX_UNMAP, FFA_ERROR},
+ {"FFA_RXTX_UNMAP_32 check", FFA_RXTX_UNMAP, FFA_SUCCESS_SMC32},
{"FFA_PARTITION_INFO_GET_32 check", FFA_PARTITION_INFO_GET, FFA_SUCCESS_SMC32},
{"FFA_ID_GET_32 check", FFA_ID_GET, FFA_SUCCESS_SMC32},
- {"FFA_MSG_POLL_32 check", FFA_MSG_POLL, FFA_SUCCESS_SMC32},
+ {"FFA_SPM_ID_GET_32 check", FFA_SPM_ID_GET, FFA_SUCCESS_SMC32,
+ MAKE_FFA_VERSION(1, 1)},
{"FFA_MSG_WAIT_32 check", FFA_MSG_WAIT, FFA_SUCCESS_SMC32},
- {"FFA_YIELD_32 check", FFA_MSG_YIELD, FFA_SUCCESS_SMC32},
- {"FFA_RUN_32 check", FFA_MSG_RUN, FFA_SUCCESS_SMC32},
- {"FFA_MSG_SEND_32 check", FFA_MSG_SEND, FFA_SUCCESS_SMC32},
+ {"FFA_RUN_32 check", FFA_RUN, FFA_SUCCESS_SMC32},
{"FFA_MEM_DONATE_32 check", FFA_MEM_DONATE_SMC32, FFA_SUCCESS_SMC32},
{"FFA_MEM_LEND_32 check", FFA_MEM_LEND_SMC32, FFA_SUCCESS_SMC32},
{"FFA_MEM_SHARE_32 check", FFA_MEM_SHARE_SMC32, FFA_SUCCESS_SMC32},
@@ -178,7 +312,23 @@ static const struct ffa_features_test ffa_feature_test_target[] = {
{"FFA_MEM_RETRIEVE_RESP_32 check", FFA_MEM_RETRIEVE_RESP, FFA_SUCCESS_SMC32},
{"FFA_MEM_RELINQUISH_32 check", FFA_MEM_RELINQUISH, FFA_SUCCESS_SMC32},
{"FFA_MEM_RECLAIM_32 check", FFA_MEM_RECLAIM, FFA_SUCCESS_SMC32},
- {"Check non-existent command", 0xFFFF, FFA_ERROR}
+ {"FFA_NOTIFICATION_BITMAP_CREATE_32 check",
+ FFA_NOTIFICATION_BITMAP_CREATE, FFA_SUCCESS_SMC32},
+ {"FFA_NOTIFICATION_BITMAP_DESTROY_32 check",
+ FFA_NOTIFICATION_BITMAP_DESTROY, FFA_SUCCESS_SMC32},
+ {"FFA_NOTIFICATION_BIND_32 check", FFA_NOTIFICATION_BIND,
+ FFA_SUCCESS_SMC32},
+ {"FFA_NOTIFICATION_UNBIND_32 check", FFA_NOTIFICATION_UNBIND,
+ FFA_SUCCESS_SMC32},
+ {"FFA_NOTIFICATION_SET_32 check", FFA_NOTIFICATION_SET,
+ FFA_SUCCESS_SMC32},
+ {"FFA_NOTIFICATION_INFO_GET_64 check", FFA_NOTIFICATION_INFO_GET_SMC64,
+ FFA_SUCCESS_SMC32},
+ /* Indirect messaging is only supported in Nwd */
+ {"FFA_YIELD_32 check", FFA_MSG_YIELD, FFA_ERROR},
+ {"FFA_MSG_SEND_32 check", FFA_MSG_SEND, FFA_ERROR},
+ {"FFA_MSG_POLL_32 check", FFA_MSG_POLL, FFA_ERROR},
+ {"Check non-existent command", 0xFFFF, FFA_ERROR},
};
/*
@@ -199,10 +349,10 @@ unsigned int get_ffa_feature_test_target(
bool memory_retrieve(struct mailbox_buffers *mb,
struct ffa_memory_region **retrieved, uint64_t handle,
- ffa_vm_id_t sender, ffa_vm_id_t receiver,
- uint32_t mem_func)
+ ffa_id_t sender, ffa_id_t receiver,
+ ffa_memory_region_flags_t flags)
{
- smc_ret_values ret;
+ struct ffa_value ret;
uint32_t fragment_size;
uint32_t total_size;
uint32_t descriptor_size;
@@ -212,18 +362,13 @@ bool memory_retrieve(struct mailbox_buffers *mb,
return false;
}
- /*
- * TODO: Revise shareability attribute in function call
- * below.
- * https://lists.trustedfirmware.org/pipermail/hafnium/2020-June/000023.html
- */
descriptor_size = ffa_memory_retrieve_request_init(
- mb->send, handle, sender, receiver, 0, 0,
+ mb->send, handle, sender, receiver, 0, flags,
FFA_DATA_ACCESS_RW,
FFA_INSTRUCTION_ACCESS_NX,
FFA_MEMORY_NORMAL_MEM,
FFA_MEMORY_CACHE_WRITE_BACK,
- FFA_MEMORY_OUTER_SHAREABLE);
+ FFA_MEMORY_INNER_SHAREABLE);
ret = ffa_mem_retrieve_req(descriptor_size, descriptor_size);
@@ -242,8 +387,8 @@ bool memory_retrieve(struct mailbox_buffers *mb,
* successful ffa_mem_retrieve_req, total_size must be equal to
* fragment_size.
*/
- total_size = ret.ret1;
- fragment_size = ret.ret2;
+ total_size = ret.arg1;
+ fragment_size = ret.arg2;
if (total_size != fragment_size) {
ERROR("Only expect one memory segment to be sent!\n");
@@ -269,9 +414,9 @@ bool memory_retrieve(struct mailbox_buffers *mb,
}
bool memory_relinquish(struct ffa_mem_relinquish *m, uint64_t handle,
- ffa_vm_id_t id)
+ ffa_id_t id)
{
- smc_ret_values ret;
+ struct ffa_value ret;
ffa_mem_relinquish_init(m, handle, 0, id);
ret = ffa_mem_relinquish();
@@ -288,18 +433,15 @@ bool memory_relinquish(struct ffa_mem_relinquish *m, uint64_t handle,
/**
* Helper to call memory send function whose func id is passed as a parameter.
* Returns a valid handle in case of successful operation or
- * FFA_MEMORY_HANDLE_INVALID if something goes wrong.
+ * FFA_MEMORY_HANDLE_INVALID if something goes wrong. Populates *ret with a
+ * resulting smc value to handle the error higher in the test chain.
*
* TODO: Do memory send with 'ffa_memory_region' taking multiple segments
*/
ffa_memory_handle_t memory_send(
struct ffa_memory_region *memory_region, uint32_t mem_func,
- uint32_t fragment_length, uint32_t total_length)
+ uint32_t fragment_length, uint32_t total_length, struct ffa_value *ret)
{
- smc_ret_values ret;
- ffa_vm_id_t receiver =
- memory_region->receivers[0].receiver_permissions.receiver;
-
if (fragment_length != total_length) {
ERROR("For now, fragment_length and total_length need to be"
" equal");
@@ -308,25 +450,29 @@ ffa_memory_handle_t memory_send(
switch (mem_func) {
case FFA_MEM_SHARE_SMC32:
- ret = ffa_mem_share(total_length, fragment_length);
+ *ret = ffa_mem_share(total_length, fragment_length);
break;
case FFA_MEM_LEND_SMC32:
- ret = ffa_mem_lend(total_length, fragment_length);
+ *ret = ffa_mem_lend(total_length, fragment_length);
break;
case FFA_MEM_DONATE_SMC32:
- ret = ffa_mem_donate(total_length, fragment_length);
+ *ret = ffa_mem_donate(total_length, fragment_length);
break;
default:
+ *ret = (struct ffa_value){0};
ERROR("TFTF - Invalid func id %x!\n", mem_func);
return FFA_MEMORY_HANDLE_INVALID;
}
- if (is_ffa_call_error(ret)) {
- ERROR("Failed to send message to: %x\n", receiver);
+ if (is_ffa_call_error(*ret)) {
+ VERBOSE("Failed to send memory to: %x\n",
+ memory_region->receivers[0]
+ .receiver_permissions
+ .receiver);
return FFA_MEMORY_HANDLE_INVALID;
}
- return ffa_mem_success_handle(ret);
+ return ffa_mem_success_handle(*ret);
}
/**
@@ -336,9 +482,9 @@ ffa_memory_handle_t memory_send(
*/
ffa_memory_handle_t memory_init_and_send(
struct ffa_memory_region *memory_region, size_t memory_region_max_size,
- ffa_vm_id_t sender, ffa_vm_id_t receiver,
+ ffa_id_t sender, ffa_id_t receiver,
const struct ffa_memory_region_constituent *constituents,
- uint32_t constituents_count, uint32_t mem_func)
+ uint32_t constituents_count, uint32_t mem_func, struct ffa_value *ret)
{
uint32_t remaining_constituent_count;
uint32_t total_length;
@@ -348,13 +494,21 @@ ffa_memory_handle_t memory_init_and_send(
FFA_DATA_ACCESS_NOT_SPECIFIED :
FFA_DATA_ACCESS_RW;
+ /*
+ * Initialize memory region structure for the respective memory send
+ * operation. Note that memory type shall only be specified for memory
+ * share, for memory lend and memory donate these shall remain
+ * unspecified.
+ */
remaining_constituent_count = ffa_memory_region_init(
memory_region, memory_region_max_size, sender, receiver, constituents,
constituents_count, 0, 0, data_access,
FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
- FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
- FFA_MEMORY_INNER_SHAREABLE, &total_length, &fragment_length
- );
+ mem_func == FFA_MEM_SHARE_SMC32
+ ? FFA_MEMORY_NORMAL_MEM
+ : FFA_MEMORY_NOT_SPECIFIED_MEM,
+ FFA_MEMORY_CACHE_WRITE_BACK, FFA_MEMORY_INNER_SHAREABLE,
+ &total_length, &fragment_length);
/*
* For simplicity of the test, and at least for the time being,
@@ -366,5 +520,94 @@ ffa_memory_handle_t memory_init_and_send(
}
return memory_send(memory_region, mem_func, fragment_length,
- total_length);
+ total_length, ret);
+}
+
+static bool ffa_uuid_equal(const struct ffa_uuid uuid1,
+ const struct ffa_uuid uuid2)
+{
+ return (uuid1.uuid[0] == uuid2.uuid[0]) &&
+ (uuid1.uuid[1] == uuid2.uuid[1]) &&
+ (uuid1.uuid[2] == uuid2.uuid[2]) &&
+ (uuid2.uuid[3] == uuid2.uuid[3]);
+}
+
+/**
+ * Sends a ffa_partition_info request and checks the response against the
+ * target.
+ */
+bool ffa_partition_info_helper(struct mailbox_buffers *mb,
+ const struct ffa_uuid uuid,
+ const struct ffa_partition_info *expected,
+ const uint16_t expected_size)
+{
+ bool result = true;
+ struct ffa_value ret = ffa_partition_info_get(uuid);
+
+ if (ffa_func_id(ret) == FFA_SUCCESS_SMC32) {
+ if (ffa_partition_info_count(ret) != expected_size) {
+ ERROR("Unexpected number of partitions %d\n",
+ ffa_partition_info_count(ret));
+ return false;
+ }
+ if (ffa_partition_info_desc_size(ret) !=
+ sizeof(struct ffa_partition_info)) {
+ ERROR("Unexpected partition info descriptor size %d\n",
+ ffa_partition_info_desc_size(ret));
+ return false;
+ }
+ const struct ffa_partition_info *info =
+ (const struct ffa_partition_info *)(mb->recv);
+
+ for (unsigned int i = 0U; i < expected_size; i++) {
+ /*
+ * If a UUID is specified then the UUID returned in the
+ * partition info descriptor MBZ.
+ */
+ struct ffa_uuid expected_uuid =
+ ffa_uuid_equal(uuid, NULL_UUID) ?
+ expected[i].uuid :
+ NULL_UUID;
+
+ if (info[i].id != expected[i].id) {
+ ERROR("Wrong ID. Expected %x, got %x\n",
+ expected[i].id,
+ info[i].id);
+ result = false;
+ }
+ if (info[i].exec_context != expected[i].exec_context) {
+ ERROR("Wrong context. Expected %d, got %d\n",
+ expected[i].exec_context,
+ info[i].exec_context);
+ result = false;
+ }
+ if (info[i].properties != expected[i].properties) {
+ ERROR("Wrong properties. Expected %d, got %d\n",
+ expected[i].properties,
+ info[i].properties);
+ result = false;
+ }
+
+ if (!ffa_uuid_equal(info[i].uuid, expected_uuid)) {
+ ERROR("Wrong UUID. Expected %x %x %x %x, "
+ "got %x %x %x %x\n",
+ expected_uuid.uuid[0],
+ expected_uuid.uuid[1],
+ expected_uuid.uuid[2],
+ expected_uuid.uuid[3],
+ info[i].uuid.uuid[0],
+ info[i].uuid.uuid[1],
+ info[i].uuid.uuid[2],
+ info[i].uuid.uuid[3]);
+ result = false;
+ }
+ }
+ }
+
+ ret = ffa_rx_release();
+ if (is_ffa_call_error(ret)) {
+ ERROR("Failed to release RX buffer\n");
+ result = false;
+ }
+ return result;
}
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 0a722e49..5e52f125 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
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -24,14 +24,13 @@ 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_vm_id_t sender,
- ffa_vm_id_t dest,
+static test_result_t send_cactus_echo_cmd(ffa_id_t sender,
+ ffa_id_t dest,
uint64_t value)
{
- smc_ret_values ret;
+ struct ffa_value ret;
ret = cactus_echo_send_cmd(sender, dest, value);
/*
@@ -92,12 +91,12 @@ test_result_t test_ffa_direct_messaging(void)
* otherwise.
* For the CACTUS_SUCCESS response, the test returns TEST_RESULT_SUCCESS.
*/
-static test_result_t send_cactus_req_echo_cmd(ffa_vm_id_t sender,
- ffa_vm_id_t dest,
- ffa_vm_id_t echo_dest,
+static test_result_t send_cactus_req_echo_cmd(ffa_id_t sender,
+ ffa_id_t dest,
+ ffa_id_t echo_dest,
uint64_t value)
{
- smc_ret_values ret;
+ struct ffa_value ret;
ret = cactus_req_echo_send_cmd(sender, dest, echo_dest, value);
@@ -128,13 +127,13 @@ test_result_t test_ffa_sp_to_sp_direct_messaging(void)
* The following the tests are intended to test the handling of a
* direct message request with a VM's ID as a the sender.
*/
- result = send_cactus_req_echo_cmd(HYP_ID + 1, SP_ID(2), SP_ID(3),
+ result = send_cactus_req_echo_cmd(VM_ID(1), SP_ID(2), SP_ID(3),
ECHO_VAL2);
if (result != TEST_RESULT_SUCCESS) {
return result;
}
- result = send_cactus_req_echo_cmd(HYP_ID + 2, SP_ID(3), SP_ID(1),
+ result = send_cactus_req_echo_cmd(VM_ID(2), SP_ID(3), SP_ID(1),
ECHO_VAL3);
return result;
@@ -142,7 +141,7 @@ test_result_t test_ffa_sp_to_sp_direct_messaging(void)
test_result_t test_ffa_sp_to_sp_deadlock(void)
{
- smc_ret_values ret;
+ struct ffa_value ret;
/**********************************************************************
* Check SPMC has ffa_version and expected FFA endpoints are deployed.
@@ -165,14 +164,12 @@ test_result_t test_ffa_sp_to_sp_deadlock(void)
/**
* 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)
{
- unsigned int mpid = read_mpidr_el1() & MPID_MASK;
- unsigned int core_pos = platform_get_core_pos(mpid);
+ unsigned int core_pos = get_current_core_id();
test_result_t ret = TEST_RESULT_SUCCESS;
- smc_ret_values ffa_ret;
+ struct ffa_value ffa_ret;
/*
* Send a direct message request to SP1 (MP SP) from current physical
@@ -255,48 +252,9 @@ out:
*/
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_exceptions.c b/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
new file mode 100644
index 00000000..61cf2ada
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <cactus_test_cmds.h>
+#include <debug.h>
+#include <ffa_endpoints.h>
+#include <ffa_svc.h>
+#include <irq.h>
+#include <platform.h>
+#include <runtime_services/realm_payload/realm_payload_test.h>
+#include <smccc.h>
+#include <spm_common.h>
+#include <test_helpers.h>
+
+#define SENDER HYP_ID
+#define RECEIVER SP_ID(1)
+
+static __aligned(PAGE_SIZE) uint64_t share_page[PAGE_SIZE / sizeof(uint64_t)];
+
+static const struct ffa_uuid expected_sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
+};
+
+/**
+ * @Test_Aim@ Check a realm region cannot be accessed from a secure partition.
+ *
+ * This test shares a TFTF allocated buffer with a secure partition through
+ * FF-A memory sharing operation. The buffer is initially marked NS in the GPT
+ * and transitioned to realm after sharing. Then, the SP is invoked to retrieve
+ * the region (map it to its S2 translation regime), and maps it to its secure
+ * S1 translation regime. It then attempts a read access which results in the
+ * PE triggering a GPF caught by a custom synchronous abort handler.
+ *
+ */
+test_result_t rl_memory_cannot_be_accessed_in_s(void)
+{
+ struct ffa_memory_region_constituent constituents[] = {
+ {
+ (void *)share_page, 1, 0
+ }
+ };
+ const uint32_t constituents_count = sizeof(constituents) /
+ sizeof(struct ffa_memory_region_constituent);
+ ffa_memory_handle_t handle;
+ struct mailbox_buffers mb;
+ struct ffa_value ret;
+ u_register_t retmm;
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ GET_TFTF_MAILBOX(mb);
+
+ handle = memory_init_and_send((struct ffa_memory_region *)mb.send,
+ PAGE_SIZE, SENDER, RECEIVER,
+ constituents, constituents_count,
+ FFA_MEM_SHARE_SMC32, &ret);
+
+ if (handle == FFA_MEMORY_HANDLE_INVALID) {
+ return TEST_RESULT_FAIL;
+ }
+
+ VERBOSE("TFTF - Handle: %llx Address: %p\n",
+ handle, constituents[0].address);
+
+ /* Delegate the shared page to Realm. */
+ retmm = realm_granule_delegate((u_register_t)&share_page);
+ if (retmm != 0UL) {
+ ERROR("Granule delegate failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Retrieve the shared page and attempt accessing it. */
+ ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_SHARE_SMC32,
+ handle, 0, true, 1);
+
+ /* Undelegate the shared page. */
+ retmm = realm_granule_undelegate((u_register_t)&share_page);
+ if (retmm != 0UL) {
+ ERROR("Granule undelegate failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ if (is_ffa_call_error(ffa_mem_reclaim(handle, 0))) {
+ ERROR("Memory reclaim failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Expect success response with value 1 hinting an exception
+ * triggered while the SP accessed the region.
+ */
+ if (!(cactus_get_response(ret) == CACTUS_SUCCESS &&
+ cactus_error_code(ret) == 1)) {
+ ERROR("Exceptions test failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_features.c b/tftf/tests/runtime_services/secure_service/test_ffa_features.c
deleted file mode 100644
index e4cd845f..00000000
--- a/tftf/tests/runtime_services/secure_service/test_ffa_features.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <spm_common.h>
-#include <test_helpers.h>
-#include <tftf_lib.h>
-
-test_result_t test_ffa_features(void)
-{
- SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
-
- /* Check if SPMC is OP-TEE at S-EL1 */
- if (check_spmc_execution_level()) {
- /* FFA_FEATURES is not yet supported in OP-TEE */
- return TEST_RESULT_SUCCESS;
- }
-
- smc_ret_values ffa_ret;
- const struct ffa_features_test *ffa_feature_test_target;
- unsigned int i, test_target_size =
- get_ffa_feature_test_target(&ffa_feature_test_target);
-
- for (i = 0U; i < test_target_size; i++) {
- ffa_ret = ffa_features(ffa_feature_test_target[i].feature);
- if (ffa_func_id(ffa_ret) != ffa_feature_test_target[i].expected_ret) {
- tftf_testcase_printf("%s returned %x, expected %x\n",
- ffa_feature_test_target[i].test_name,
- ffa_func_id(ffa_ret),
- ffa_feature_test_target[i].expected_ret);
- return TEST_RESULT_FAIL;
- }
- if ((ffa_feature_test_target[i].expected_ret == FFA_ERROR) &&
- (ffa_error_code(ffa_ret) != FFA_ERROR_NOT_SUPPORTED)) {
- tftf_testcase_printf("%s failed for the wrong reason: "
- "returned %x, expected %x\n",
- ffa_feature_test_target[i].test_name,
- ffa_error_code(ffa_ret),
- FFA_ERROR_NOT_SUPPORTED);
- return TEST_RESULT_FAIL;
- }
- }
-
- return TEST_RESULT_SUCCESS;
-}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c b/tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c
index 7c70de2c..1c175137 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_interrupts.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -64,20 +64,12 @@ static int timer_handler(void *data)
test_result_t test_ffa_ns_interrupt(void)
{
int ret;
- smc_ret_values ret_values;
+ struct ffa_value ret_values;
CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
/* Enable managed exit interrupt as FIQ in the secure side. */
- ret_values = cactus_interrupt_cmd(SENDER, RECEIVER, MANAGED_EXIT_INTERRUPT_ID,
- true, INTERRUPT_TYPE_FIQ);
-
- if (!is_ffa_direct_response(ret_values)) {
- return TEST_RESULT_FAIL;
- }
-
- if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
- ERROR("Failed to enable Managed exit interrupt\n");
+ if (!spm_set_managed_exit_int(RECEIVER, true)) {
return TEST_RESULT_FAIL;
}
@@ -134,15 +126,7 @@ test_result_t test_ffa_ns_interrupt(void)
}
/* Disable Managed exit interrupt */
- ret_values = cactus_interrupt_cmd(SENDER, RECEIVER, MANAGED_EXIT_INTERRUPT_ID,
- false, 0);
-
- if (!is_ffa_direct_response(ret_values)) {
- return TEST_RESULT_FAIL;
- }
-
- if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
- ERROR("Failed to disable Managed exit interrupt\n");
+ if (!spm_set_managed_exit_int(RECEIVER, false)) {
return TEST_RESULT_FAIL;
}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
index f126c57d..f382ff39 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,6 +25,20 @@ static const struct ffa_uuid expected_sp_uuids[] = {
/* Memory section to be used for memory share operations */
static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE];
+static bool check_written_words(uint32_t *ptr, uint32_t word, uint32_t wcount)
+{
+ VERBOSE("TFTF - Memory contents after SP use:\n");
+ for (unsigned int i = 0U; i < wcount; i++) {
+ VERBOSE(" %u: %x\n", i, ptr[i]);
+
+ /* Verify content of memory is as expected. */
+ if (ptr[i] != word) {
+ return false;
+ }
+ }
+ return true;
+}
+
/**
* Tests that it is possible to share memory with SWd from NWd.
* After calling the respective memory send API, it will expect a reply from
@@ -45,11 +59,14 @@ static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE];
*/
static test_result_t test_memory_send_sp(uint32_t mem_func)
{
- smc_ret_values ret;
+ struct ffa_value ret;
ffa_memory_handle_t handle;
uint32_t *ptr;
struct mailbox_buffers mb;
+ /* Arbitrarily write 5 words after using memory. */
+ const uint32_t nr_words_to_write = 5;
+
/***********************************************************************
* Check if SPMC has ffa_version and expected FFA endpoints are deployed.
**********************************************************************/
@@ -67,7 +84,7 @@ static test_result_t test_memory_send_sp(uint32_t mem_func)
handle = memory_init_and_send((struct ffa_memory_region *)mb.send,
MAILBOX_SIZE, SENDER, RECEIVER,
constituents, constituents_count,
- mem_func);
+ mem_func, &ret);
if (handle == FFA_MEMORY_HANDLE_INVALID) {
return TEST_RESULT_FAIL;
@@ -78,7 +95,8 @@ static test_result_t test_memory_send_sp(uint32_t mem_func)
ptr = (uint32_t *)constituents[0].address;
- ret = cactus_mem_send_cmd(SENDER, RECEIVER, mem_func, handle);
+ ret = cactus_mem_send_cmd(SENDER, RECEIVER, mem_func, handle, 0,
+ true, nr_words_to_write);
if (!is_ffa_direct_response(ret)) {
return TEST_RESULT_FAIL;
@@ -89,17 +107,11 @@ static test_result_t test_memory_send_sp(uint32_t mem_func)
return TEST_RESULT_FAIL;
}
- /*
- * Print 5 words from the memory region to validate SP wrote to the
- * memory region.
- */
- VERBOSE("TFTF - Memory contents after SP use:\n");
- for (unsigned int i = 0U; i < 5U; i++)
- VERBOSE(" %u: %x\n", i, ptr[i]);
-
- /* To make the compiler happy in case it is not a verbose build */
- if (LOG_LEVEL < LOG_LEVEL_VERBOSE)
- (void)ptr;
+ /* Check that borrower used the memory as expected for this test. */
+ if (!check_written_words(ptr, mem_func, nr_words_to_write)) {
+ ERROR("Words written to shared memory, not as expected.\n");
+ return TEST_RESULT_FAIL;
+ }
if (mem_func != FFA_MEM_DONATE_SMC32 &&
is_ffa_call_error(ffa_mem_reclaim(handle, 0))) {
@@ -130,10 +142,11 @@ test_result_t test_mem_donate_sp(void)
* Cactus SP should reply to TFTF on whether the test succeeded or not.
*/
static test_result_t test_req_mem_send_sp_to_sp(uint32_t mem_func,
- ffa_vm_id_t sender_sp,
- ffa_vm_id_t receiver_sp)
+ ffa_id_t sender_sp,
+ ffa_id_t receiver_sp,
+ bool non_secure)
{
- smc_ret_values ret;
+ struct ffa_value ret;
/***********************************************************************
* Check if SPMC's ffa_version and presence of expected FF-A endpoints.
@@ -141,33 +154,174 @@ static test_result_t test_req_mem_send_sp_to_sp(uint32_t mem_func,
CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
ret = cactus_req_mem_send_send_cmd(HYP_ID, sender_sp, mem_func,
- receiver_sp);
+ receiver_sp, non_secure);
if (!is_ffa_direct_response(ret)) {
return TEST_RESULT_FAIL;
}
if (cactus_get_response(ret) == CACTUS_ERROR) {
+ ERROR("Failed sharing memory between SPs. Error code: %d\n",
+ cactus_error_code(ret));
return TEST_RESULT_FAIL;
}
return TEST_RESULT_SUCCESS;
}
+/*
+ * Test requests a memory send operation from SP to VM.
+ * The tests expects cactus to reply CACTUS_ERROR, providing FF-A error code of
+ * the last memory send FF-A call that cactus performed.
+ */
+static test_result_t test_req_mem_send_sp_to_vm(uint32_t mem_func,
+ ffa_id_t sender_sp,
+ ffa_id_t receiver_vm)
+{
+ struct ffa_value ret;
+
+ /**********************************************************************
+ * Check if SPMC's ffa_version and presence of expected FF-A endpoints.
+ *********************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+ ret = cactus_req_mem_send_send_cmd(HYP_ID, sender_sp, mem_func,
+ receiver_vm, false);
+
+ if (!is_ffa_direct_response(ret)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (cactus_get_response(ret) == CACTUS_ERROR &&
+ cactus_error_code(ret) == FFA_ERROR_DENIED) {
+ return TEST_RESULT_SUCCESS;
+ }
+
+ tftf_testcase_printf("Did not get the expected error, "
+ "mem send returned with %d\n",
+ cactus_get_response(ret));
+ return TEST_RESULT_FAIL;
+}
+
test_result_t test_req_mem_share_sp_to_sp(void)
{
return test_req_mem_send_sp_to_sp(FFA_MEM_SHARE_SMC32, SP_ID(3),
- SP_ID(2));
+ SP_ID(2), false);
+}
+
+test_result_t test_req_ns_mem_share_sp_to_sp(void)
+{
+ /*
+ * Skip the test when RME is enabled (for test setup reasons).
+ * For RME tests, the model specifies 48b physical address size
+ * at the PE, but misses allocating RAM and increasing the PA at
+ * the interconnect level.
+ */
+ if (get_armv9_2_feat_rme_support() != 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /* This test requires 48b physical address size capability. */
+ SKIP_TEST_IF_PA_SIZE_LESS_THAN(48);
+
+ return test_req_mem_send_sp_to_sp(FFA_MEM_SHARE_SMC32, SP_ID(3),
+ SP_ID(2), true);
}
test_result_t test_req_mem_lend_sp_to_sp(void)
{
return test_req_mem_send_sp_to_sp(FFA_MEM_LEND_SMC32, SP_ID(3),
- SP_ID(2));
+ SP_ID(2), false);
}
test_result_t test_req_mem_donate_sp_to_sp(void)
{
return test_req_mem_send_sp_to_sp(FFA_MEM_DONATE_SMC32, SP_ID(1),
- SP_ID(3));
+ SP_ID(3), false);
+}
+
+test_result_t test_req_mem_share_sp_to_vm(void)
+{
+ return test_req_mem_send_sp_to_vm(FFA_MEM_SHARE_SMC32, SP_ID(1),
+ HYP_ID);
+}
+
+test_result_t test_req_mem_lend_sp_to_vm(void)
+{
+ return test_req_mem_send_sp_to_vm(FFA_MEM_LEND_SMC32, SP_ID(2),
+ HYP_ID);
+}
+
+test_result_t test_mem_share_to_sp_clear_memory(void)
+{
+ struct ffa_memory_region_constituent constituents[] = {
+ {(void *)share_page, 1, 0}};
+ const uint32_t constituents_count = sizeof(constituents) /
+ sizeof(struct ffa_memory_region_constituent);
+ struct mailbox_buffers mb;
+ uint32_t remaining_constituent_count;
+ uint32_t total_length;
+ uint32_t fragment_length;
+ ffa_memory_handle_t handle;
+ struct ffa_value ret;
+ uint32_t *ptr;
+ /* Arbitrarily write 10 words after using shared memory. */
+ const uint32_t nr_words_to_write = 10U;
+
+ CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+ GET_TFTF_MAILBOX(mb);
+
+ remaining_constituent_count = ffa_memory_region_init(
+ (struct ffa_memory_region *)mb.send, MAILBOX_SIZE, SENDER,
+ RECEIVER, constituents, constituents_count, 0,
+ FFA_MEMORY_REGION_FLAG_CLEAR, FFA_DATA_ACCESS_RW,
+ FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
+ FFA_MEMORY_NOT_SPECIFIED_MEM, 0, 0,
+ &total_length, &fragment_length);
+
+ if (remaining_constituent_count != 0) {
+ ERROR("Transaction descriptor initialization failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ handle = memory_send(mb.send, FFA_MEM_LEND_SMC32, fragment_length,
+ total_length, &ret);
+
+ if (handle == FFA_MEMORY_HANDLE_INVALID) {
+ ERROR("Memory Share failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ VERBOSE("Memory has been shared!\n");
+
+ ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_LEND_SMC32, handle,
+ FFA_MEMORY_REGION_FLAG_CLEAR, true,
+ nr_words_to_write);
+
+ if (!is_ffa_direct_response(ret)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (cactus_get_response(ret) != CACTUS_SUCCESS) {
+ ERROR("Failed memory send operation!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_mem_reclaim(handle, 0);
+
+ if (is_ffa_call_error(ret)) {
+ ERROR("Memory reclaim failed!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ ptr = (uint32_t *)constituents[0].address;
+
+ /* Check that borrower used the memory as expected for this test. */
+ if (!check_written_words(ptr, FFA_MEM_LEND_SMC32, nr_words_to_write)) {
+ ERROR("Words written to shared memory, not as expected.\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
new file mode 100644
index 00000000..e900ae35
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
@@ -0,0 +1,1634 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <irq.h>
+#include <smccc.h>
+
+#include <arch_helpers.h>
+#include <cactus_test_cmds.h>
+#include <ffa_endpoints.h>
+#include <ffa_svc.h>
+#include <platform.h>
+#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}
+};
+
+static ffa_notification_bitmap_t g_notifications = FFA_NOTIFICATION(0) |
+ FFA_NOTIFICATION(1) |
+ FFA_NOTIFICATION(30) |
+ FFA_NOTIFICATION(50) |
+ FFA_NOTIFICATION(63);
+
+/**
+ * Use FFA_FEATURES to retrieve the ID of:
+ * - Schedule Receiver Interrupt
+ * - Notification Pending Interrupt
+ * - Managed Exit Interrupt
+ * Validate the call works as expected, and they match the used int ID in the
+ * remainder of the tests.
+ */
+test_result_t test_notifications_retrieve_int_ids(void)
+{
+ struct ffa_value ret;
+
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
+
+ /* Check if SPMC is OP-TEE at S-EL1 */
+ if (check_spmc_execution_level()) {
+ /* FFA_FEATURES is not yet supported in OP-TEE */
+ return TEST_RESULT_SUCCESS;
+ }
+
+ ret = ffa_features(FFA_FEATURE_NPI);
+ if (is_ffa_call_error(ret) ||
+ ffa_feature_intid(ret) != NOTIFICATION_PENDING_INTERRUPT_INTID) {
+ ERROR("Failed to retrieved NPI (exp: %u, got: %u)\n",
+ NOTIFICATION_PENDING_INTERRUPT_INTID,
+ ffa_feature_intid(ret));
+
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_features(FFA_FEATURE_SRI);
+ if (is_ffa_call_error(ret) ||
+ ffa_feature_intid(ret) != FFA_SCHEDULE_RECEIVER_INTERRUPT_ID) {
+ ERROR("Failed to retrieved SRI (exp: %u, got: %u)\n",
+ FFA_SCHEDULE_RECEIVER_INTERRUPT_ID,
+ ffa_feature_intid(ret));
+
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_features(FFA_FEATURE_MEI);
+ if (is_ffa_call_error(ret) ||
+ ffa_feature_intid(ret) != MANAGED_EXIT_INTERRUPT_ID) {
+ ERROR("Failed to retrieved MEI (exp: %u, got: %u)\n",
+ MANAGED_EXIT_INTERRUPT_ID,
+ ffa_feature_intid(ret));
+
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Helper to create bitmap for NWd VMs.
+ */
+static bool notifications_bitmap_create(ffa_id_t vm_id,
+ ffa_vcpu_count_t vcpu_count)
+{
+ VERBOSE("Creating bitmap for VM %x; cpu count: %u.\n",
+ vm_id, vcpu_count);
+ struct ffa_value ret = ffa_notification_bitmap_create(vm_id,
+ vcpu_count);
+
+ return !is_ffa_call_error(ret);
+}
+
+/**
+ * Helper to destroy bitmap for NWd VMs.
+ */
+static bool notifications_bitmap_destroy(ffa_id_t vm_id)
+{
+ VERBOSE("Destroying bitmap of VM %x.\n", vm_id);
+ struct ffa_value ret = ffa_notification_bitmap_destroy(vm_id);
+
+ return !is_ffa_call_error(ret);
+}
+
+/**
+ * Test notifications bitmap create and destroy interfaces.
+ */
+test_result_t test_ffa_notifications_bitmap_create_destroy(void)
+{
+ const ffa_id_t vm_id = VM_ID(1);
+
+ 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;
+ }
+
+ if (!notifications_bitmap_create(vm_id, PLATFORM_CORE_COUNT)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!notifications_bitmap_destroy(vm_id)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test notifications bitmap destroy in a case the bitmap hasn't been created.
+ */
+test_result_t test_ffa_notifications_destroy_not_created(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;
+ }
+
+ struct ffa_value ret = ffa_notification_bitmap_destroy(VM_ID(1));
+
+ if (!is_expected_ffa_error(ret, FFA_ERROR_DENIED)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test attempt to create notifications bitmap for NWd VM if it had been
+ * already created.
+ */
+test_result_t test_ffa_notifications_create_after_create(void)
+{
+ struct ffa_value ret;
+ const ffa_id_t vm_id = VM_ID(2);
+
+ 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;
+ }
+
+ /* First successfully create a notifications bitmap */
+ if (!notifications_bitmap_create(vm_id, 1)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Attempt to do the same to the same VM. */
+ ret = ffa_notification_bitmap_create(vm_id, 1);
+
+ if (!is_expected_ffa_error(ret, FFA_ERROR_DENIED)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Destroy to not affect other tests */
+ if (!notifications_bitmap_destroy(vm_id)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Helper function to test FFA_NOTIFICATION_BIND interface.
+ * Receives all arguments to use 'cactus_notification_bind_send_cmd', and
+ * expected response for the test command.
+ *
+ * Returns:
+ * - 'true' if response was obtained and it was as expected;
+ * - 'false' if there was an error with use of FFA_MSG_SEND_DIRECT_REQ, or
+ * the obtained response was not as expected.
+ */
+static bool request_notification_bind(
+ ffa_id_t cmd_dest, ffa_id_t receiver, ffa_id_t sender,
+ ffa_notification_bitmap_t notifications, uint32_t flags,
+ uint32_t expected_resp, uint32_t error_code)
+{
+ struct ffa_value ret;
+
+ VERBOSE("TFTF requesting SP to bind notifications!\n");
+
+ ret = cactus_notification_bind_send_cmd(HYP_ID, cmd_dest, receiver,
+ sender, notifications, flags);
+
+ if (!is_expected_cactus_response(ret, expected_resp, error_code)) {
+ ERROR("Failed notifications bind. receiver: %x; sender: %x\n",
+ receiver, sender);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Helper function to test FFA_NOTIFICATION_UNBIND interface.
+ * Receives all arguments to use 'cactus_notification_unbind_send_cmd', and
+ * expected response for the test command.
+ *
+ * Returns:
+ * - 'true' if response was obtained and it was as expected;
+ * - 'false' if there was an error with use of FFA_MSG_SEND_DIRECT_REQ, or
+ * the obtained response was not as expected.
+ */
+static bool request_notification_unbind(
+ ffa_id_t cmd_dest, ffa_id_t receiver, ffa_id_t sender,
+ ffa_notification_bitmap_t notifications, uint32_t expected_resp,
+ uint32_t error_code)
+{
+ struct ffa_value ret;
+
+ VERBOSE("TFTF requesting SP to unbind notifications!\n");
+
+ ret = cactus_notification_unbind_send_cmd(HYP_ID, cmd_dest, receiver,
+ sender, notifications);
+
+ if (!is_expected_cactus_response(ret, expected_resp, error_code)) {
+ ERROR("Failed notifications unbind. receiver: %x; sender: %x\n",
+ receiver, sender);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Test calls from SPs to the bind and unbind interfaces, expecting success
+ * returns.
+ * This test issues a request via direct messaging to the SP, which executes
+ * the test and responds with the result of the call.
+ */
+test_result_t test_ffa_notifications_sp_bind_unbind(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /** First bind... */
+ if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(2),
+ g_notifications, 0, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!request_notification_bind(SP_ID(1), SP_ID(1), 1,
+ g_notifications, 0, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /** ... then unbind using the same arguments. */
+ if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(2),
+ g_notifications, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!request_notification_unbind(SP_ID(1), SP_ID(1), 1,
+ g_notifications, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test successful attempt of doing bind and unbind of the same set of
+ * notifications.
+ */
+test_result_t test_ffa_notifications_vm_bind_unbind(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ const ffa_id_t vm_id = VM_ID(1);
+ struct ffa_value ret;
+
+ if (!notifications_bitmap_create(vm_id, 1)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_notification_bind(SP_ID(2), vm_id, 0, g_notifications);
+
+ if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_notification_unbind(SP_ID(2), vm_id, g_notifications);
+
+ if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!notifications_bitmap_destroy(vm_id)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test expected failure of using a NS FF-A ID for the sender.
+ */
+test_result_t test_ffa_notifications_vm_bind_vm(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ const ffa_id_t vm_id = VM_ID(1);
+ const ffa_id_t sender_id = VM_ID(2);
+ struct ffa_value ret;
+
+ if (!notifications_bitmap_create(vm_id, 1)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_notification_bind(sender_id, vm_id, 0, g_notifications);
+
+ if (!is_expected_ffa_error(ret, FFA_ERROR_INVALID_PARAMETER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!notifications_bitmap_destroy(vm_id)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test failure of both bind and unbind in case at least one notification is
+ * already bound to another FF-A endpoint.
+ * Expect error code FFA_ERROR_DENIED.
+ */
+test_result_t test_ffa_notifications_already_bound(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /** Bind first to test */
+ if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(2),
+ g_notifications, 0, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /** Attempt to bind notifications bound in above request. */
+ if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(3),
+ g_notifications, 0, CACTUS_ERROR,
+ FFA_ERROR_DENIED)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /** Attempt to unbind notifications bound in initial request. */
+ if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(3),
+ g_notifications, CACTUS_ERROR,
+ FFA_ERROR_DENIED)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /** Reset the state the SP's notifications state. */
+ if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(2),
+ g_notifications, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Try to bind/unbind notifications spoofing the identity of the receiver.
+ * Commands will be sent to SP_ID(1), which will use SP_ID(3) as the receiver.
+ * Expect error code FFA_ERROR_INVALID_PARAMETER.
+ */
+test_result_t test_ffa_notifications_bind_unbind_spoofing(void)
+{
+ ffa_notification_bitmap_t notifications = FFA_NOTIFICATION(8);
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ if (!request_notification_bind(SP_ID(1), SP_ID(3), SP_ID(2),
+ notifications, 0, CACTUS_ERROR,
+ FFA_ERROR_INVALID_PARAMETER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!request_notification_unbind(SP_ID(1), SP_ID(3), SP_ID(2),
+ notifications, CACTUS_ERROR,
+ FFA_ERROR_INVALID_PARAMETER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Call FFA_NOTIFICATION_BIND with notifications bitmap zeroed.
+ * Expecting error code FFA_ERROR_INVALID_PARAMETER.
+ */
+test_result_t test_ffa_notifications_bind_unbind_zeroed(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(2),
+ 0, 0, CACTUS_ERROR,
+ FFA_ERROR_INVALID_PARAMETER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(2),
+ 0, CACTUS_ERROR,
+ FFA_ERROR_INVALID_PARAMETER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Helper function to test FFA_NOTIFICATION_GET interface.
+ * Receives all arguments to use 'cactus_notification_get_send_cmd', and returns
+ * the received response. Depending on the testing scenario, this will allow
+ * to validate if the returned bitmaps are as expected.
+ *
+ * Returns:
+ * - 'true' if response was obtained.
+ * - 'false' if there was an error sending the request.
+ */
+static bool request_notification_get(
+ ffa_id_t cmd_dest, ffa_id_t receiver, uint32_t vcpu_id, uint32_t flags,
+ bool check_npi_handled, struct ffa_value *response)
+{
+ VERBOSE("TFTF requesting SP to get notifications!\n");
+
+ *response = cactus_notification_get_send_cmd(HYP_ID, cmd_dest,
+ receiver, vcpu_id,
+ flags, check_npi_handled);
+
+ return is_ffa_direct_response(*response);
+}
+
+static bool request_notification_set(
+ ffa_id_t cmd_dest, ffa_id_t receiver, ffa_id_t sender, uint32_t flags,
+ ffa_notification_bitmap_t notifications, ffa_id_t echo_dest,
+ uint32_t exp_resp, int32_t exp_error)
+{
+ struct ffa_value ret;
+
+ VERBOSE("TFTF requesting SP %x (as %x) to set notifications to %x\n",
+ cmd_dest, sender, receiver);
+
+ ret = cactus_notifications_set_send_cmd(HYP_ID, cmd_dest, receiver,
+ sender, flags, notifications,
+ echo_dest);
+
+ if (!is_expected_cactus_response(ret, exp_resp, exp_error)) {
+ ERROR("Failed notifications set. receiver: %x; sender: %x\n",
+ receiver, sender);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Helper to set notification. If sender is VM, the function will call directly
+ * FFA_NOTIFICATION_SET, if it is an SP it will request the SP to set
+ * notifications. In both cases it is expected a successful outcome.
+ */
+static bool notification_set(ffa_id_t receiver, ffa_id_t sender,
+ uint32_t flags,
+ ffa_notification_bitmap_t notifications)
+{
+ struct ffa_value ret;
+
+ /* Sender sets notifications to receiver. */
+ if (!IS_SP_ID(sender)) {
+ VERBOSE("VM %x Setting notifications %llx to receiver %x\n",
+ sender, notifications, receiver);
+ ret = ffa_notification_set(sender, receiver, flags, notifications);
+
+ if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) {
+ ERROR("Failed notifications set. receiver: %x; sender: %x\n",
+ receiver, sender);
+ return false;
+ }
+ return true;
+ }
+
+ return request_notification_set(sender, receiver, sender, flags,
+ notifications, 0, CACTUS_SUCCESS, 0);
+}
+
+/**
+ * Check that SP's response to CACTUS_NOTIFICATION_GET_CMD is as expected.
+ */
+static bool is_notifications_get_as_expected(
+ struct ffa_value *ret, uint64_t exp_from_sp, uint64_t exp_from_vm,
+ ffa_id_t receiver)
+{
+ uint64_t from_sp;
+ uint64_t from_vm;
+ bool success_ret;
+
+ /**
+ * If receiver ID is SP, this is to evaluate the response to test
+ * command 'CACTUS_NOTIFICATION_GET_CMD'.
+ */
+ if (IS_SP_ID(receiver)) {
+ success_ret = (cactus_get_response(*ret) == CACTUS_SUCCESS);
+ from_sp = cactus_notifications_get_from_sp(*ret);
+ from_vm = cactus_notifications_get_from_vm(*ret);
+ } else {
+ /**
+ * Else, this is to evaluate the return of FF-A call:
+ * ffa_notification_get.
+ */
+ success_ret = (ffa_func_id(*ret) == FFA_SUCCESS_SMC32);
+ from_sp = ffa_notifications_get_from_sp(*ret);
+ from_vm = ffa_notifications_get_from_vm(*ret);
+ }
+
+ if (success_ret != true ||
+ exp_from_sp != from_sp ||
+ exp_from_vm != from_vm) {
+ VERBOSE("Notifications not as expected:\n"
+ " from sp: %llx exp: %llx\n"
+ " from vm: %llx exp: %llx\n",
+ from_sp, exp_from_sp, from_vm, exp_from_vm);
+ return false;
+ }
+
+ return true;
+}
+
+static bool is_notifications_info_get_as_expected(
+ struct ffa_value *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_ffa_value(*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->arg3, 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
+ * FFA_NOTIFICATION_BIND.
+ * If Sender is SP it will request it to perform the set, else invokes
+ * FFA_NOTIFICATION_SET.
+ */
+static bool notification_bind_and_set(ffa_id_t sender,
+ ffa_id_t receiver, ffa_notification_bitmap_t notifications, uint32_t flags)
+{
+ struct ffa_value ret;
+ uint32_t flags_bind = flags & FFA_NOTIFICATIONS_FLAG_PER_VCPU;
+
+ /* Receiver binds notifications to sender. */
+ if (!IS_SP_ID(receiver)) {
+ ret = ffa_notification_bind(sender, receiver,
+ flags_bind, notifications);
+
+ if (is_ffa_call_error(ret)) {
+ return false;
+ }
+ } else {
+ if (!request_notification_bind(receiver, receiver, sender,
+ notifications, flags_bind,
+ CACTUS_SUCCESS,
+ 0)) {
+ return false;
+ }
+ }
+
+ return notification_set(receiver, sender, flags, notifications);
+}
+
+/**
+ * Helper to request SP to get the notifications and validate the return.
+ */
+static bool notification_get_and_validate(
+ ffa_id_t receiver, ffa_notification_bitmap_t exp_from_sp,
+ ffa_notification_bitmap_t exp_from_vm, uint32_t vcpu_id,
+ uint32_t flags, bool check_npi_handled)
+{
+ struct ffa_value ret;
+
+ /* Receiver gets pending notifications. */
+ if (IS_SP_ID(receiver)) {
+ request_notification_get(receiver, receiver, vcpu_id, flags,
+ check_npi_handled, &ret);
+ } else {
+ ret = ffa_notification_get(receiver, vcpu_id, flags);
+ }
+
+ return is_notifications_get_as_expected(&ret, exp_from_sp, exp_from_vm,
+ 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)
+{
+ struct ffa_value 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);
+}
+
+static volatile int schedule_receiver_interrupt_received;
+
+static int schedule_receiver_interrupt_handler(void *data)
+{
+ assert(schedule_receiver_interrupt_received == 0);
+ schedule_receiver_interrupt_received = 1;
+ return 0;
+}
+
+/**
+ * Enable the Schedule Receiver Interrupt and register the respective
+ * handler.
+ */
+static void schedule_receiver_interrupt_init(void)
+{
+ tftf_irq_register_handler(FFA_SCHEDULE_RECEIVER_INTERRUPT_ID,
+ schedule_receiver_interrupt_handler);
+
+ tftf_irq_enable(FFA_SCHEDULE_RECEIVER_INTERRUPT_ID, 0xA);
+}
+
+/**
+ * Enable the Notification Pending Interrupt for the target SP.
+ */
+static bool notification_pending_interrupt_sp_enable(ffa_id_t receiver,
+ bool enable)
+{
+ VERBOSE("Configuring NPI to receiver: %x\n", receiver);
+ struct ffa_value ret = cactus_interrupt_cmd(
+ HYP_ID, receiver, NOTIFICATION_PENDING_INTERRUPT_INTID,
+ enable, INTERRUPT_TYPE_IRQ);
+
+
+ if (!is_ffa_direct_response(ret) ||
+ cactus_get_response(ret) != CACTUS_SUCCESS) {
+ ERROR("Failed to configure NPI in SP %x core: %x\n",
+ receiver, get_current_core_id());
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Disable the Schedule Receiver Interrupt and unregister the respective
+ * handler.
+ */
+static void schedule_receiver_interrupt_deinit(void)
+{
+ tftf_irq_disable(FFA_SCHEDULE_RECEIVER_INTERRUPT_ID);
+ tftf_irq_unregister_handler(FFA_SCHEDULE_RECEIVER_INTERRUPT_ID);
+ schedule_receiver_interrupt_received = 0;
+}
+
+bool check_schedule_receiver_interrupt_handled(void)
+{
+ if (schedule_receiver_interrupt_received == 1) {
+ VERBOSE("Schedule Receiver Interrupt handled!\n");
+ schedule_receiver_interrupt_received = 0;
+ return true;
+ }
+ VERBOSE("Schedule Receiver Interrupt NOT handled!\n");
+ return false;
+}
+
+/**
+ * Base function to test notifications signaling with an SP as a receiver.
+ */
+static test_result_t base_test_global_notifications_signal_sp(
+ const ffa_id_t sender, const ffa_id_t receiver,
+ const ffa_notification_bitmap_t notifications, const uint32_t flags_get)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ if (!IS_SP_ID(receiver)) {
+ ERROR("Receiver is expected to be an SP ID!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* 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);
+
+ schedule_receiver_interrupt_init();
+
+ /* Enable NPI. */
+ if (!notification_pending_interrupt_sp_enable(receiver, true)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!notification_bind_and_set(sender, receiver, notifications,
+ FFA_NOTIFICATIONS_FLAG_DELAY_SRI)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!check_schedule_receiver_interrupt_handled()) {
+ 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,
+ false)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!notification_get_and_validate(
+ receiver, IS_SP_ID(sender) ? notifications : 0,
+ !IS_SP_ID(sender) ? notifications : 0, 0, flags_get, true)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!request_notification_unbind(receiver, receiver, sender,
+ notifications, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Disable NPI. */
+ if (!notification_pending_interrupt_sp_enable(receiver, false)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_deinit();
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test to validate a VM can signal an SP.
+ */
+test_result_t test_ffa_notifications_vm_signals_sp(void)
+{
+ return base_test_global_notifications_signal_sp(
+ 1, SP_ID(1), FFA_NOTIFICATION(1) | FFA_NOTIFICATION(60),
+ FFA_NOTIFICATIONS_FLAG_BITMAP_VM);
+}
+
+/**
+ * Test to validate an SP can signal an SP.
+ */
+test_result_t test_ffa_notifications_sp_signals_sp(void)
+{
+ return base_test_global_notifications_signal_sp(
+ SP_ID(1), SP_ID(2), g_notifications,
+ FFA_NOTIFICATIONS_FLAG_BITMAP_SP);
+}
+
+/**
+ * Test to validate an SP can signal a VM.
+ */
+test_result_t test_ffa_notifications_sp_signals_vm(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ const ffa_id_t sender = SP_ID(1);
+ const ffa_id_t receiver = VM_ID(1);
+ uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_SP;
+ struct ffa_value ret;
+ test_result_t result = TEST_RESULT_SUCCESS;
+
+ /* 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)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_init();
+
+ /* Request receiver to bind a set of notifications to the sender. */
+ if (!notification_bind_and_set(sender, receiver, g_notifications,
+ FFA_NOTIFICATIONS_FLAG_DELAY_SRI)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ if (!check_schedule_receiver_interrupt_handled()) {
+ result = 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)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Get pending notifications, and retrieve response. */
+ if (!notification_get_and_validate(receiver, g_notifications, 0, 0,
+ get_flags, false)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ ret = ffa_notification_unbind(sender, receiver, g_notifications);
+
+ if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ if (!notifications_bitmap_destroy(receiver)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_deinit();
+
+ return result;
+}
+
+/**
+ * Test to validate it is not possible to unbind a pending notification.
+ */
+test_result_t test_ffa_notifications_unbind_pending(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ const ffa_id_t receiver = SP_ID(1);
+ const ffa_id_t sender = VM_ID(1);
+ const ffa_notification_bitmap_t notifications = FFA_NOTIFICATION(30) |
+ FFA_NOTIFICATION(35);
+ uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_VM;
+
+ schedule_receiver_interrupt_init();
+
+ /* Request receiver to bind a set of notifications to the sender. */
+ if (!notification_bind_and_set(sender, receiver, notifications, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Attempt to unbind the pending notification, but expect error return
+ * given the notification is pending.
+ */
+ if (!request_notification_unbind(receiver, receiver, sender,
+ FFA_NOTIFICATION(30),
+ CACTUS_ERROR, FFA_ERROR_DENIED)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!check_schedule_receiver_interrupt_handled()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Request receiver partition to get pending notifications from VMs.
+ * Only notification 30 is expected.
+ */
+ if (!notification_get_and_validate(receiver, 0, notifications, 0,
+ get_flags, false)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Unbind all notifications, to not interfere with other tests. */
+ if (!request_notification_unbind(receiver, receiver, sender,
+ notifications, CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_deinit();
+
+ 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;
+ }
+
+ struct ffa_value 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 core_pos = get_current_core_id();
+ 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 (!spm_core_sp_init(per_vcpu_receiver)) {
+ goto out;
+ }
+
+ /*
+ * Request to get notifications sent to the respective vCPU.
+ * Check also if NPI was handled by the receiver. It should have been
+ * pended at notifications set, in the respective vCPU.
+ */
+ if (!notification_get_and_validate(
+ per_vcpu_receiver, exp_from_sp, exp_from_vm, core_pos,
+ per_vcpu_flags_get, true)) {
+ 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;
+}
+
+static test_result_t base_npi_enable_per_cpu(bool enable)
+{
+ test_result_t result = TEST_RESULT_FAIL;
+ uint32_t core_pos = get_current_core_id();
+
+ VERBOSE("Request SP %x to enable NPI in core %u\n",
+ per_vcpu_receiver, core_pos);
+
+ /*
+ * Secure Partitions secondary ECs need one round of ffa_run to reach
+ * the message loop.
+ */
+ if (!spm_core_sp_init(per_vcpu_receiver)) {
+ goto out;
+ }
+
+ if (!notification_pending_interrupt_sp_enable(per_vcpu_receiver,
+ enable)) {
+ 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;
+}
+
+static test_result_t npi_enable_per_vcpu_on_handler(void)
+{
+ return base_npi_enable_per_cpu(true);
+}
+
+static test_result_t npi_disable_per_vcpu_on_handler(void)
+{
+ return base_npi_enable_per_cpu(false);
+}
+/**
+ * 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)
+{
+ /*
+ * 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;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ per_vcpu_flags_get = IS_SP_ID(sender)
+ ? FFA_NOTIFICATIONS_FLAG_BITMAP_SP
+ : FFA_NOTIFICATIONS_FLAG_BITMAP_VM;
+
+ /* Setting global variables to be accessed by the cpu_on handler. */
+ per_vcpu_receiver = receiver;
+ per_vcpu_sender = sender;
+
+ /* Boot all cores and enable the NPI in all of them. */
+ if (spm_run_multi_core_test(
+ (uintptr_t)npi_enable_per_vcpu_on_handler,
+ per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Enable NPI in lead core. */
+ if (!notification_pending_interrupt_sp_enable(receiver, true)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * 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_DELAY_SRI |
+ 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.
+ * Set `check_npi_handled` to true, as the receiver is supposed to be
+ * preempted by the NPI.
+ */
+ 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, true)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /*
+ * 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;
+ }
+
+ /* Boot all cores and DISABLE the NPI in all of them. */
+ if (spm_run_multi_core_test(
+ (uintptr_t)npi_disable_per_vcpu_on_handler,
+ per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Disable the NPI in the receiver. */
+ if (!notification_pending_interrupt_sp_enable(receiver, false)) {
+ return 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 core_pos = get_current_core_id();
+ test_result_t result = TEST_RESULT_SUCCESS;
+
+ VERBOSE("Getting per-vCPU notifications from %x, core: %u.\n",
+ per_vcpu_receiver, core_pos);
+
+ if (!spm_core_sp_init(per_vcpu_sender)) {
+ goto out;
+ }
+
+ if (!notification_get_and_validate(per_vcpu_receiver,
+ FFA_NOTIFICATION(core_pos), 0,
+ core_pos,
+ FFA_NOTIFICATIONS_FLAG_BITMAP_SP,
+ false)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+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 = VM_ID(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;
+ struct ffa_value 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,
+ false)) {
+ 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;
+}
+
+/**
+ * Test to validate behavior in SWd if the SRI is not delayed. If the
+ * notification setter handled a managed exit it is indicative the SRI was
+ * sent immediately.
+ */
+test_result_t test_ffa_notifications_sp_signals_sp_immediate_sri(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;
+ struct ffa_value ret;
+ test_result_t result = TEST_RESULT_SUCCESS;
+
+ /** 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};
+
+ ids[0] = receiver;
+ lists_count = 1;
+
+ /* Enable managed exit interrupt as FIQ in the secure side. */
+ if (!spm_set_managed_exit_int(sender, true)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_init();
+
+ /* Request receiver to bind a set of notifications to the sender. */
+ if (!request_notification_bind(receiver, receiver, sender,
+ g_notifications, 0, CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Request sender to set notification, and expect the response is
+ * MANAGED_EXIT_INTERRUPT_ID.
+ */
+ if (!request_notification_set(sender, receiver, sender, 0,
+ g_notifications, 0,
+ MANAGED_EXIT_INTERRUPT_ID, 0)) {
+ ERROR("SRI not handled immediately!\n");
+ result = TEST_RESULT_FAIL;
+ } else {
+ VERBOSE("SP %x did a managed exit.\n", sender);
+ }
+
+ if (!check_schedule_receiver_interrupt_handled()) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Call FFA_NOTIFICATION_INFO_GET and validate return. */
+ if (!notifications_info_get(ids, lists_count, lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ false)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Validate notification get. */
+ if (!request_notification_get(receiver, receiver, 0, get_flags, false, &ret) ||
+ !is_notifications_get_as_expected(&ret, g_notifications, 0,
+ receiver)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Resume setter Cactus in the handling of CACTUS_NOTIFICATIONS_SET_CMD.
+ */
+ ret = ffa_msg_send_direct_req64(HYP_ID, sender, 0, 0, 0, 0, 0);
+
+ /* Expected result to CACTUS_NOTIFICATIONS_SET_CMD. */
+ if (!is_expected_cactus_response(ret, CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Unbind for clean-up. */
+ if (!request_notification_unbind(receiver, receiver, sender,
+ g_notifications, CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_deinit();
+
+ /* Disable managed exit interrupt as FIQ in the secure side. */
+ if (!spm_set_managed_exit_int(sender, false)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return result;
+}
+
+/**
+ * Test to validate behavior in SWd if the SRI is delayed.
+ */
+test_result_t test_ffa_notifications_sp_signals_sp_delayed_sri(void)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ const ffa_id_t sender = SP_ID(3);
+ const ffa_id_t receiver = SP_ID(2);
+ const ffa_id_t echo_dest = SP_ID(1);
+ uint32_t echo_dest_cmd_count = 0;
+ uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_SP;
+ struct ffa_value ret;
+ test_result_t result = TEST_RESULT_SUCCESS;
+
+ /** 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};
+
+ ids[0] = receiver;
+ lists_count = 1;
+
+ /* Enable managed exit interrupt as FIQ in the secure side. */
+ if (!spm_set_managed_exit_int(sender, true)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_init();
+
+ /* Request receiver to bind a set of notifications to the sender. */
+ if (!request_notification_bind(receiver, receiver, sender,
+ g_notifications, 0, CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ ret = cactus_get_req_count_send_cmd(HYP_ID, echo_dest);
+
+ if (cactus_get_response(ret) == CACTUS_SUCCESS) {
+ /*
+ * Save the command count from the echo_dest, to validate it
+ * has been incremented after the request to set notifications.
+ */
+ echo_dest_cmd_count = cactus_get_req_count(ret);
+ VERBOSE("Partition %x command count %u.\n", echo_dest,
+ echo_dest_cmd_count);
+ } else {
+ VERBOSE("Failed to get cmds count from %u\n", echo_dest);
+ result = TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Request sender to set notification with Delay SRI flag, and specify
+ * echo destination.
+ */
+ if (!request_notification_set(sender, receiver, sender,
+ FFA_NOTIFICATIONS_FLAG_DELAY_SRI,
+ g_notifications, echo_dest,
+ CACTUS_SUCCESS, 0)) {
+ VERBOSE("Failed to set notifications!\n");
+ result = TEST_RESULT_FAIL;
+ }
+
+ if (!check_schedule_receiver_interrupt_handled()) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Get command count again from echo_dest, to validate that it has been
+ * incremented by one. This should indicate the notification setter has
+ * issued a request to echo_dest right after the notification set, thus
+ * proving the SRI hasn't been sent right after FFA_NOTIFICATION_SET.
+ */
+ ret = cactus_get_req_count_send_cmd(HYP_ID, echo_dest);
+ if (cactus_get_response(ret) == CACTUS_SUCCESS) {
+ if (cactus_get_req_count(ret) == echo_dest_cmd_count + 1) {
+ VERBOSE("SRI successfully delayed.\n");
+ } else {
+ VERBOSE("Failed to get cmds count from %u.\n",
+ echo_dest);
+ result = TEST_RESULT_FAIL;
+ }
+ } else {
+ VERBOSE("Failed to get cmds count from %x\n", echo_dest);
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Call FFA_NOTIFICATION_INFO_GET and validate return. */
+ if (!notifications_info_get(ids, lists_count, lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ false)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Validate notification get. */
+ if (!request_notification_get(receiver, receiver, 0, get_flags, false, &ret) ||
+ !is_notifications_get_as_expected(&ret, g_notifications, 0,
+ receiver)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Unbind for clean-up. */
+ if (!request_notification_unbind(receiver, receiver, sender,
+ g_notifications, CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_deinit();
+
+ /* Disable managed exit interrupt as FIQ in the secure side. */
+ if (!spm_set_managed_exit_int(sender, false)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return result;
+}
+
+test_result_t notifications_set_per_vcpu_on_handler(void)
+{
+ unsigned int core_pos = get_current_core_id();
+ test_result_t result = TEST_RESULT_FAIL;
+
+ if (!spm_core_sp_init(per_vcpu_sender)) {
+ goto out;
+ }
+
+ if (!notification_set(per_vcpu_receiver, per_vcpu_sender,
+ FFA_NOTIFICATIONS_FLAG_DELAY_SRI |
+ FFA_NOTIFICATIONS_FLAG_PER_VCPU |
+ FFA_NOTIFICATIONS_FLAGS_VCPU_ID(0),
+ FFA_NOTIFICATION(core_pos))) {
+ 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;
+}
+
+test_result_t test_ffa_notifications_mp_sp_signals_up_sp(void)
+{
+ ffa_notification_bitmap_t to_bind = 0;
+
+ /* prepare info get variables. */
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Setting per-vCPU sender and receiver IDs. */
+ per_vcpu_sender = SP_ID(2); /* MP SP */
+ per_vcpu_receiver = SP_ID(3); /* UP SP */
+
+ schedule_receiver_interrupt_init();
+
+ notification_pending_interrupt_sp_enable(per_vcpu_receiver, true);
+
+ /* Prepare notifications bitmap to have one bit platform core. */
+ for (uint32_t i = 0; i < PLATFORM_CORE_COUNT; i++) {
+ to_bind |= FFA_NOTIFICATION(i);
+ }
+
+ /* Request receiver to bind a set of notifications to the sender. */
+ if (!request_notification_bind(per_vcpu_receiver, per_vcpu_receiver,
+ per_vcpu_sender, to_bind,
+ FFA_NOTIFICATIONS_FLAG_PER_VCPU,
+ CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Boot up system, and then request sender to signal notification from
+ * every core into into receiver's only vCPU. Delayed SRI.
+ */
+ if (!notification_set(per_vcpu_receiver, per_vcpu_sender,
+ FFA_NOTIFICATIONS_FLAG_DELAY_SRI |
+ FFA_NOTIFICATIONS_FLAG_PER_VCPU |
+ FFA_NOTIFICATIONS_FLAGS_VCPU_ID(0),
+ FFA_NOTIFICATION(0))) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (spm_run_multi_core_test(
+ (uintptr_t)notifications_set_per_vcpu_on_handler,
+ per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!check_schedule_receiver_interrupt_handled()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!notification_get_and_validate(per_vcpu_receiver, to_bind, 0, 0,
+ FFA_NOTIFICATIONS_FLAG_BITMAP_SP, true)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Request unbind. */
+ if (!request_notification_unbind(per_vcpu_receiver, per_vcpu_receiver,
+ per_vcpu_sender, to_bind,
+ CACTUS_SUCCESS, 0)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ schedule_receiver_interrupt_deinit();
+
+ notification_pending_interrupt_sp_enable(per_vcpu_receiver, false);
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_rxtx_map.c b/tftf/tests/runtime_services/secure_service/test_ffa_rxtx_map.c
deleted file mode 100644
index 1b47c5f9..00000000
--- a/tftf/tests/runtime_services/secure_service/test_ffa_rxtx_map.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <debug.h>
-
-#include <test_helpers.h>
-#include <xlat_tables_defs.h>
-
-static struct mailbox_buffers mb;
-
-static test_result_t test_ffa_rxtx_map(uint32_t expected_return)
-{
- smc_ret_values ret;
-
- /**********************************************************************
- * Verify that FFA is there and that it has the correct version.
- **********************************************************************/
- SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
-
- /**********************************************************************
- * If OP-TEE is SPMC skip this test.
- **********************************************************************/
- if (check_spmc_execution_level()) {
- VERBOSE("OP-TEE as SPMC at S-EL1. Skipping test!\n");
- return TEST_RESULT_SKIPPED;
- }
-
- /*
- * Declare RXTX buffers, assign them to the mailbox and call
- * FFA_RXTX_MAP.
- */
- CONFIGURE_AND_MAP_MAILBOX(mb, PAGE_SIZE, ret);
- if (ffa_func_id(ret) != expected_return) {
- ERROR("Failed to map RXTX buffers %x!\n", ffa_error_code(ret));
- return TEST_RESULT_FAIL;
- }
-
- return TEST_RESULT_SUCCESS;
-}
-
-/**
- * Test mapping RXTX buffers from NWd.
- * This test also sets the Mailbox for other SPM related tests that need to use
- * RXTX buffers.
- */
-test_result_t test_ffa_rxtx_map_success(void)
-{
- test_result_t ret = test_ffa_rxtx_map(FFA_SUCCESS_SMC32);
-
- if (ret == TEST_RESULT_SUCCESS) {
- INFO("Set RXTX Mailbox for remaining spm tests!\n");
- set_tftf_mailbox(&mb);
- }
- return ret;
-}
-
-/**
- * Test to verify that 2nd call to FFA_RXTX_MAP should fail.
- */
-test_result_t test_ffa_rxtx_map_fail(void)
-{
- INFO("This test expects error log.\n");
- return test_ffa_rxtx_map(FFA_ERROR);
-}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c b/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c
new file mode 100644
index 00000000..ac19c06f
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cactus_test_cmds.h>
+#include <ffa_endpoints.h>
+#include <ffa_helpers.h>
+#include <test_helpers.h>
+#include <timer.h>
+
+#define SENDER HYP_ID
+#define RECEIVER SP_ID(1)
+#define RECEIVER_2 SP_ID(2)
+#define SP_SLEEP_TIME 1000U
+#define NS_TIME_SLEEP 1500U
+#define ECHO_VAL1 U(0xa0a0a0a0)
+
+static const struct ffa_uuid expected_sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}
+ };
+
+static bool configure_trusted_wdog_interrupt(ffa_id_t source, ffa_id_t dest,
+ bool enable)
+{
+ struct ffa_value ret_values;
+
+ ret_values = cactus_interrupt_cmd(source, dest, IRQ_TWDOG_INTID,
+ enable, INTERRUPT_TYPE_IRQ);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response message while configuring"
+ " TWDOG interrupt\n");
+ return false;
+ }
+
+ if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
+ ERROR("Failed to configure Trusted Watchdog interrupt\n");
+ return false;
+ }
+ return true;
+}
+
+static bool enable_trusted_wdog_interrupt(ffa_id_t source, ffa_id_t dest)
+{
+ return configure_trusted_wdog_interrupt(source, dest, true);
+}
+
+static bool disable_trusted_wdog_interrupt(ffa_id_t source, ffa_id_t dest)
+{
+ return configure_trusted_wdog_interrupt(source, dest, false);
+}
+
+/*
+ * @Test_Aim@ Test secure interrupt handling while first Secure Partition is
+ * in RUNNING state.
+ *
+ * 1. Send a direct message request command to first Cactus SP to start the
+ * trusted watchdog timer.
+ *
+ * 2. Send a command to SP to first sleep( by executing a busy loop), then
+ * restart trusted watchdog timer and then sleep again.
+ *
+ * 3. While SP is running the first busy loop, Secure interrupt should trigger
+ * during this time.
+ *
+ * 4. The interrupt will be trapped to SPM as IRQ. SPM will inject the virtual
+ * IRQ to the first SP through vIRQ conduit and perform eret to resume
+ * execution in SP.
+ *
+ * 5. Execution traps to irq handler of Cactus SP. It will handle the secure
+ * interrupt triggered by the trusted watchdog timer.
+ *
+ * 6. Cactus SP will perform End-Of-Interrupt and resume execution in the busy
+ * loop.
+ *
+ * 7. Trusted watchdog timer will trigger once again followed by steps 4 to 6.
+ *
+ * 8. Cactus SP will send a direct response message with the elapsed time back
+ * to the normal world.
+ *
+ * 9. We make sure the time elapsed in the sleep routine by SP is not less than
+ * the requested value.
+ *
+ * 10. TFTF sends a direct request message to SP to query the ID of last serviced
+ * secure virtual interrupt.
+ *
+ * 11. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ * interrupt through a direct response message.
+ *
+ * 12. Test finishes successfully once the TFTF disables the trusted watchdog
+ * interrupt through a direct message request command.
+ *
+ */
+
+test_result_t test_ffa_sec_interrupt_sp_running(void)
+{
+ struct ffa_value ret_values;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Enable trusted watchdog interrupt as IRQ in the secure side. */
+ if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER, 50);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for starting TWDOG timer\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Send request to first Cactus SP to sleep */
+ ret_values = cactus_sleep_trigger_wdog_cmd(SENDER, RECEIVER, SP_SLEEP_TIME, 50);
+
+ /*
+ * Secure interrupt should trigger during this time, Cactus
+ * will handle the trusted watchdog timer.
+ */
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for sleep command\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ VERBOSE("Secure interrupt has preempted execution: %u\n",
+ cactus_get_response(ret_values));
+
+ /* Make sure elapsed time not less than sleep time */
+ if (cactus_get_response(ret_values) < SP_SLEEP_TIME) {
+ ERROR("Lapsed time less than requested sleep time\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Check for the last serviced secure virtual interrupt. */
+ ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for last serviced interrupt"
+ " command\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure Trusted Watchdog timer interrupt was serviced*/
+ if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
+ ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Disable Trusted Watchdog interrupt. */
+ if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test secure interrupt handling while Secure Partition is waiting
+ * for a message.
+ *
+ * 1. Send a direct message request command to first Cactus SP to start the
+ * trusted watchdog timer.
+ *
+ * 2. Once the SP returns with a direct response message, it moves to WAITING
+ state.
+ *
+ * 3. Execute a busy loop to sleep for NS_TIME_SLEEP ms.
+ *
+ * 4. Trusted watchdog timer expires during this time which leads to secure
+ * interrupt being triggered while cpu is executing in normal world.
+ *
+ * 5. The interrupt is trapped to BL31/SPMD as FIQ and later synchronously
+ * delivered to SPM.
+ *
+ * 6. SPM injects a virtual IRQ to first Cactus Secure Partition.
+ *
+ * 7. Once the SP handles the interrupt, it returns execution back to normal
+ * world using FFA_MSG_WAIT call.
+ *
+ * 8. SPM, through the help of SPMD, resumes execution in normal world to
+ * continue the busy loop.
+ *
+ * 9. We make sure the time elapsed in the sleep routine is not less than
+ * the requested value.
+ *
+ * 10. TFTF sends a direct request message to SP to query the ID of last serviced
+ * secure virtual interrupt.
+ *
+ * 11. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ * interrupt through a direct response message.
+ *
+ * 12. Test finishes successfully once the TFTF disables the trusted watchdog
+ * interrupt through a direct message request command.
+ *
+ */
+test_result_t test_ffa_sec_interrupt_sp_waiting(void)
+{
+ uint64_t time1;
+ volatile uint64_t time2, time_lapsed;
+ uint64_t timer_freq = read_cntfrq_el0();
+ struct ffa_value ret_values;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Enable trusted watchdog interrupt as IRQ in the secure side. */
+ if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Send a message to SP1 through direct messaging.
+ */
+ ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER, 100);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for starting TWDOG timer\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ time1 = syscounter_read();
+
+ /*
+ * Sleep for NS_TIME_SLEEP ms. This ensures secure wdog timer triggers during this
+ * time. We explicitly do not use tftf_timer_sleep();
+ */
+ waitms(NS_TIME_SLEEP);
+ time2 = syscounter_read();
+
+ /* Lapsed time should be at least equal to sleep time */
+ time_lapsed = ((time2 - time1) * 1000) / timer_freq;
+
+ if (time_lapsed < NS_TIME_SLEEP) {
+ ERROR("Time elapsed less than expected value: %llu vs %u\n",
+ time_lapsed, NS_TIME_SLEEP);
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Check for the last serviced secure virtual interrupt. */
+ ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for last serviced interrupt"
+ " command\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure Trusted Watchdog timer interrupt was serviced*/
+ if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
+ ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Disable Trusted Watchdog interrupt. */
+ if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test secure interrupt handling while first Secure Partition is
+ * in BLOCKED state.
+ *
+ * 1. Send a direct message request command to first Cactus SP to start the
+ * trusted watchdog timer.
+ *
+ * 2. Send a direct request to first SP to forward sleep command to second SP.
+ *
+ * 3. While second SP is running the busy loop, Secure interrupt should trigger
+ * during this time.
+ *
+ * 4. The interrupt will be trapped to SPM as IRQ. SPM will inject the virtual
+ * IRQ to the first SP through vIRQ conduit and perform eret to resume
+ * execution in first SP.
+ *
+ * 5. Execution traps to irq handler of Cactus SP. It will handle the secure
+ * interrupt triggered by the trusted watchdog timer.
+ *
+ * 6. First SP performs EOI by calling interrupt deactivate ABI and invokes
+ * FFA_RUN to resume second SP in the busy loop.
+ *
+ * 7. Second SP will complete the busy sleep loop and send a direct response
+ * message with the elapsed time back to the first SP.
+ *
+ * 8. First SP checks for the elapsed time and sends a direct response with
+ * a SUCCESS value back to tftf.
+ *
+ * 9. TFTF sends a direct request message to SP to query the ID of last serviced
+ * secure virtual interrupt.
+ *
+ * 10. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ * interrupt through a direct response message.
+ *
+ * 11. Test finishes successfully once the TFTF disables the trusted watchdog
+ * interrupt through a direct message request command.
+ */
+test_result_t test_ffa_sec_interrupt_sp_blocked(void)
+{
+ struct ffa_value ret_values;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Enable trusted watchdog interrupt as IRQ in the secure side. */
+ if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER, 100);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for starting TWDOG timer\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Send request to first Cactus SP to send request to Second Cactus
+ * SP to sleep
+ */
+ ret_values = cactus_fwd_sleep_cmd(SENDER, RECEIVER, RECEIVER_2,
+ SP_SLEEP_TIME);
+
+ /*
+ * Secure interrupt should trigger during this time, Cactus
+ * will handle the trusted watchdog timer.
+ */
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Check for the last serviced secure virtual interrupt. */
+ ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for last serviced interrupt"
+ " command\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure Trusted Watchdog timer interrupt was serviced*/
+ if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
+ ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Disable Trusted Watchdog interrupt. */
+ if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test secure interrupt handling while first Secure Partition is
+ * in WAITING state while the second Secure Partition is running.
+ *
+ * 1. Send a direct message request command to first Cactus SP to start the
+ * trusted watchdog timer.
+ *
+ * 2. Send a direct request to second SP to sleep by executing a busy loop.
+ *
+ * 3. While second SP is running the busy loop, Secure interrupt should trigger
+ * during this time.
+ *
+ * 4. The interrupt is trapped to the SPM as a physical IRQ. The SPM injects a
+ * virtual IRQ to the first SP and resumes it while it is in waiting state.
+ *
+ * 5. Execution traps to irq handler of the first Cactus SP. It will handle the
+ * secure interrupt triggered by the trusted watchdog timer.
+ *
+ * 6. Cactus SP will perform End-Of-Interrupt by calling the interrupt
+ * deactivate HVC and invoke FFA_MSG_WAIT ABI to perform interrupt signal
+ * completion.
+ *
+ * 7. SPM then resumes the second SP which was pre-empted by secure interrupt.
+ *
+ * 8. Second SP will complete the busy sleep loop and send a direct response
+ * message with the elapsed time back to the first SP.
+ *
+ * 9. We make sure the time elapsed in the sleep routine by SP is not less than
+ * the requested value.
+ *
+ * 10. TFTF sends a direct request message to SP to query the ID of last serviced
+ * secure virtual interrupt.
+ *
+ * 11. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ * interrupt through a direct response message.
+ *
+ * 12. Test finishes successfully once the TFTF disables the trusted watchdog
+ * interrupt through a direct message request command.
+ */
+test_result_t test_ffa_sec_interrupt_sp1_waiting_sp2_running(void)
+{
+ struct ffa_value ret_values;
+
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /* Enable trusted watchdog interrupt as IRQ in the secure side. */
+ if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER, 100);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for starting TWDOG timer\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Send request to Second Cactus SP to sleep. */
+ ret_values = cactus_sleep_cmd(SENDER, RECEIVER_2, SP_SLEEP_TIME);
+
+ /*
+ * Secure interrupt should trigger during this time, Cactus
+ * will handle the trusted watchdog timer.
+ */
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for sleep command\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure elapsed time not less than sleep time. */
+ if (cactus_get_response(ret_values) < SP_SLEEP_TIME) {
+ ERROR("Lapsed time less than requested sleep time\n");
+ }
+
+ /* Check for the last serviced secure virtual interrupt. */
+ ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
+
+ if (!is_ffa_direct_response(ret_values)) {
+ ERROR("Expected a direct response for last serviced interrupt"
+ " command\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Make sure Trusted Watchdog timer interrupt was serviced*/
+ if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
+ ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Disable Trusted Watchdog interrupt. */
+ if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_setup_and_discovery.c b/tftf/tests/runtime_services/secure_service/test_ffa_setup_and_discovery.c
new file mode 100644
index 00000000..b80f9c4f
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_setup_and_discovery.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+
+#include <ffa_endpoints.h>
+#include <ffa_helpers.h>
+#include <ffa_svc.h>
+#include <spm_common.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <xlat_tables_defs.h>
+
+static bool should_skip_version_test;
+
+static struct mailbox_buffers mb;
+
+static const struct ffa_uuid sp_uuids[] = {
+ {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}, {IVY_UUID}
+ };
+
+static const struct ffa_partition_info ffa_expected_partition_info[] = {
+ /* Primary partition info */
+ {
+ .id = SP_ID(1),
+ .exec_context = PRIMARY_EXEC_CTX_COUNT,
+ .properties = FFA_PARTITION_DIRECT_REQ_RECV |
+ FFA_PARTITION_NOTIFICATION,
+ .uuid = sp_uuids[0]
+ },
+ /* Secondary partition info */
+ {
+ .id = SP_ID(2),
+ .exec_context = SECONDARY_EXEC_CTX_COUNT,
+ .properties = FFA_PARTITION_DIRECT_REQ_RECV |
+ FFA_PARTITION_NOTIFICATION,
+ .uuid = sp_uuids[1]
+ },
+ /* Tertiary partition info */
+ {
+ .id = SP_ID(3),
+ .exec_context = TERTIARY_EXEC_CTX_COUNT,
+ .properties = FFA_PARTITION_DIRECT_REQ_RECV |
+ FFA_PARTITION_NOTIFICATION,
+ .uuid = sp_uuids[2]
+ },
+ /* Ivy partition info */
+ {
+ .id = SP_ID(4),
+ .exec_context = IVY_EXEC_CTX_COUNT,
+ .properties = FFA_PARTITION_DIRECT_REQ_RECV,
+ .uuid = sp_uuids[3]
+ }
+};
+
+/*
+ * Using FFA version expected for SPM.
+ */
+#define SPM_VERSION MAKE_FFA_VERSION(FFA_VERSION_MAJOR, FFA_VERSION_MINOR)
+
+/******************************************************************************
+ * FF-A Features ABI Tests
+ ******************************************************************************/
+
+test_result_t test_ffa_features(void)
+{
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
+
+ /* Check if SPMC is OP-TEE at S-EL1 */
+ if (check_spmc_execution_level()) {
+ /* FFA_FEATURES is not yet supported in OP-TEE */
+ return TEST_RESULT_SUCCESS;
+ }
+
+ struct ffa_value ffa_ret;
+ unsigned int expected_ret;
+ const struct ffa_features_test *ffa_feature_test_target;
+ unsigned int i, test_target_size =
+ get_ffa_feature_test_target(&ffa_feature_test_target);
+ struct ffa_features_test test_target;
+
+ for (i = 0U; i < test_target_size; i++) {
+ test_target = ffa_feature_test_target[i];
+ ffa_ret = ffa_features(test_target.feature);
+ expected_ret = FFA_VERSION_COMPILED
+ >= test_target.version_added ?
+ test_target.expected_ret : FFA_ERROR;
+ if (ffa_func_id(ffa_ret) != expected_ret) {
+ tftf_testcase_printf("%s returned %x, expected %x\n",
+ test_target.test_name,
+ ffa_func_id(ffa_ret),
+ expected_ret);
+ return TEST_RESULT_FAIL;
+ }
+ if ((expected_ret == FFA_ERROR) &&
+ (ffa_error_code(ffa_ret) != FFA_ERROR_NOT_SUPPORTED)) {
+ tftf_testcase_printf("%s failed for the wrong reason: "
+ "returned %x, expected %x\n",
+ test_target.test_name,
+ ffa_error_code(ffa_ret),
+ FFA_ERROR_NOT_SUPPORTED);
+ return TEST_RESULT_FAIL;
+ }
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/******************************************************************************
+ * FF-A Version ABI Tests
+ ******************************************************************************/
+
+/*
+ * Calls FFA Version ABI, and checks if the result as expected.
+ */
+static test_result_t test_ffa_version(uint32_t input_version,
+ uint32_t expected_return)
+{
+ if (should_skip_version_test) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ struct ffa_value ret_values = ffa_version(input_version);
+
+ uint32_t spm_version = (uint32_t)(0xFFFFFFFF & ret_values.fid);
+
+ if (spm_version == expected_return) {
+ return TEST_RESULT_SUCCESS;
+ }
+
+ tftf_testcase_printf("Input Version: 0x%x\n"
+ "Return: 0x%x\nExpected: 0x%x\n",
+ input_version, spm_version, expected_return);
+
+ return TEST_RESULT_FAIL;
+}
+
+/*
+ * @Test_Aim@ Validate what happens when using same version as SPM.
+ */
+test_result_t test_ffa_version_equal(void)
+{
+ /*
+ * FFA_VERSION interface is used to check that SPM functionality is
+ * supported. On FFA_VERSION invocation from TFTF, the SPMD returns
+ * either NOT_SUPPORTED or the SPMC version value provided in the SPMC
+ * manifest. The variable "should_skip_test" is set to true when the
+ * SPMD returns NOT_SUPPORTED or a mismatched version, which means that
+ * a TFTF physical FF-A endpoint version (SPM_VERSION) does not match
+ * the SPMC's physical FF-A endpoint version. This prevents running the
+ * subsequent FF-A version tests (and break the test flow), as they're
+ * not relevant when the SPMD is not present within BL31
+ * (FFA_VERSION returns NOT_SUPPORTED).
+ */
+ test_result_t ret = test_ffa_version(SPM_VERSION, SPM_VERSION);
+
+ if (ret != TEST_RESULT_SUCCESS) {
+ should_skip_version_test = true;
+ ret = TEST_RESULT_SKIPPED;
+ }
+ return ret;
+}
+
+/*
+ * @Test_Aim@ Validate what happens when setting bit 31 in
+ * 'input_version'. As per spec, FFA version is 31 bits long.
+ * Bit 31 set is an invalid input.
+ */
+test_result_t test_ffa_version_bit31(void)
+{
+ return test_ffa_version(FFA_VERSION_BIT31_MASK | SPM_VERSION,
+ FFA_ERROR_NOT_SUPPORTED);
+}
+
+/*
+ * @Test_Aim@ Validate what happens for bigger version than SPM's.
+ */
+test_result_t test_ffa_version_bigger(void)
+{
+ return test_ffa_version(MAKE_FFA_VERSION(FFA_VERSION_MAJOR + 1, 0),
+ SPM_VERSION);
+}
+
+/*
+ * @Test_Aim@ Validate what happens for smaller version than SPM's.
+ */
+test_result_t test_ffa_version_smaller(void)
+{
+ return test_ffa_version(MAKE_FFA_VERSION(0, 9), SPM_VERSION);
+}
+
+/******************************************************************************
+ * FF-A RXTX ABI Tests
+ ******************************************************************************/
+
+static test_result_t test_ffa_rxtx_map(uint32_t expected_return)
+{
+ struct ffa_value ret;
+
+ /**********************************************************************
+ * Verify that FFA is there and that it has the correct version.
+ **********************************************************************/
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
+
+ /**********************************************************************
+ * If OP-TEE is SPMC skip this test.
+ **********************************************************************/
+ if (check_spmc_execution_level()) {
+ VERBOSE("OP-TEE as SPMC at S-EL1. Skipping test!\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /*
+ * Declare RXTX buffers, assign them to the mailbox and call
+ * FFA_RXTX_MAP.
+ */
+ CONFIGURE_AND_MAP_MAILBOX(mb, PAGE_SIZE, ret);
+ if (ffa_func_id(ret) != expected_return) {
+ ERROR("Failed to map RXTX buffers %x!\n", ffa_error_code(ret));
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test mapping RXTX buffers from NWd.
+ */
+test_result_t test_ffa_rxtx_map_success(void)
+{
+ return test_ffa_rxtx_map(FFA_SUCCESS_SMC32);
+}
+
+/**
+ * Test to verify that 2nd call to FFA_RXTX_MAP should fail.
+ */
+test_result_t test_ffa_rxtx_map_fail(void)
+{
+ VERBOSE("This test expects error log.\n");
+ return test_ffa_rxtx_map(FFA_ERROR);
+}
+
+static test_result_t test_ffa_rxtx_unmap(uint32_t expected_return)
+{
+ struct ffa_value ret;
+
+ /**********************************************************************
+ * Verify that FFA is there and that it has the correct version.
+ **********************************************************************/
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
+
+ /**********************************************************************
+ * If OP-TEE is SPMC skip this test.
+ **********************************************************************/
+ if (check_spmc_execution_level()) {
+ VERBOSE("OP-TEE as SPMC at S-EL1. Skipping test!\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ ret = ffa_rxtx_unmap();
+ if (!is_expected_ffa_return(ret, expected_return)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Test unmapping RXTX buffers from NWd.
+ */
+test_result_t test_ffa_rxtx_unmap_success(void)
+{
+ return test_ffa_rxtx_unmap(FFA_SUCCESS_SMC32);
+}
+
+/**
+ * Test to verify that 2nd call to FFA_RXTX_UNMAP should fail.
+ */
+test_result_t test_ffa_rxtx_unmap_fail(void)
+{
+ VERBOSE("This test expects error log.\n");
+ return test_ffa_rxtx_unmap(FFA_ERROR);
+}
+
+/**
+ * Test mapping RXTX buffers that have been previously unmapped from NWd.
+ * This test also sets the Mailbox for other SPM related tests that need to use
+ * RXTX buffers.
+ */
+test_result_t test_ffa_rxtx_map_unmapped_success(void)
+{
+ test_result_t ret = test_ffa_rxtx_map(FFA_SUCCESS_SMC32);
+
+ if (ret == TEST_RESULT_SUCCESS) {
+ VERBOSE("Set RXTX Mailbox for remaining spm tests.\n");
+ set_tftf_mailbox(&mb);
+ }
+ return ret;
+}
+/******************************************************************************
+ * FF-A SPM_ID_GET ABI Tests
+ ******************************************************************************/
+
+test_result_t test_ffa_spm_id_get(void)
+{
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
+
+ struct ffa_value ffa_ret = ffa_spm_id_get();
+
+ if (is_ffa_call_error(ffa_ret)) {
+ ERROR("FFA_SPM_ID_GET call failed! Error code: 0x%x\n",
+ ffa_error_code(ffa_ret));
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Check the SPMC value given in the fvp_spmc_manifest is returned */
+ ffa_id_t spm_id = ffa_endpoint_id(ffa_ret);
+
+ if (spm_id != SPMC_ID) {
+ ERROR("Expected SPMC_ID of 0x%x\n received: 0x%x\n",
+ SPMC_ID, spm_id);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/******************************************************************************
+ * FF-A PARTITION_INFO_GET ABI Tests
+ ******************************************************************************/
+
+/**
+ * Attempt to get the SP partition information for individual partitions as well
+ * as all secure partitions.
+ */
+test_result_t test_ffa_partition_info(void)
+{
+ /***********************************************************************
+ * Check if SPMC has ffa_version and expected FFA endpoints are deployed.
+ **********************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 1, sp_uuids);
+
+ GET_TFTF_MAILBOX(mb);
+
+ if (!ffa_partition_info_helper(&mb, sp_uuids[0],
+ &ffa_expected_partition_info[0], 1)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!ffa_partition_info_helper(&mb, sp_uuids[1],
+ &ffa_expected_partition_info[1], 1)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!ffa_partition_info_helper(&mb, sp_uuids[2],
+ &ffa_expected_partition_info[2], 1)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!ffa_partition_info_helper(&mb, NULL_UUID,
+ ffa_expected_partition_info,
+ ARRAY_SIZE(ffa_expected_partition_info))) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Attempt to get v1.0 partition info descriptors.
+ */
+test_result_t test_ffa_partition_info_v1_0(void)
+{
+ /**************************************************************
+ * Check if SPMC has ffa_version and expected FFA endpoints
+ * are deployed.
+ *************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 0, sp_uuids);
+
+ GET_TFTF_MAILBOX(mb);
+
+ test_result_t result = TEST_RESULT_SUCCESS;
+ struct ffa_value ret = ffa_partition_info_get(NULL_UUID);
+ uint64_t expected_size = ARRAY_SIZE(ffa_expected_partition_info);
+
+ if (ffa_func_id(ret) == FFA_SUCCESS_SMC32) {
+ if (ffa_partition_info_count(ret) != expected_size) {
+ ERROR("Unexpected number of partitions %d\n",
+ ffa_partition_info_count(ret));
+ return TEST_RESULT_FAIL;
+ }
+ if (ffa_partition_info_desc_size(ret) !=
+ sizeof(struct ffa_partition_info_v1_0)) {
+ ERROR("Unexepcted partition info descriptor size %d\n",
+ ffa_partition_info_desc_size(ret));
+ return TEST_RESULT_FAIL;
+ }
+ const struct ffa_partition_info_v1_0 *info =
+ (const struct ffa_partition_info_v1_0 *)(mb.recv);
+
+ for (unsigned int i = 0U; i < expected_size; i++) {
+ if (info[i].id != ffa_expected_partition_info[i].id) {
+ ERROR("Wrong ID. Expected %x, got %x\n",
+ ffa_expected_partition_info[i].id,
+ info[i].id);
+ result = TEST_RESULT_FAIL;
+ }
+ if (info[i].exec_context !=
+ ffa_expected_partition_info[i].exec_context) {
+ ERROR("Wrong context. Expected %d, got %d\n",
+ ffa_expected_partition_info[i].exec_context,
+ info[i].exec_context);
+ result = TEST_RESULT_FAIL;
+ }
+ if (info[i].properties !=
+ ffa_expected_partition_info[i].properties) {
+ ERROR("Wrong properties. Expected %d, got %d\n",
+ ffa_expected_partition_info[i].properties,
+ info[i].properties);
+ result = TEST_RESULT_FAIL;
+ }
+ }
+ }
+
+ ret = ffa_rx_release();
+ if (is_ffa_call_error(ret)) {
+ ERROR("Failed to release RX buffer\n");
+ result = TEST_RESULT_FAIL;
+ }
+ return result;
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_version.c b/tftf/tests/runtime_services/secure_service/test_ffa_version.c
deleted file mode 100644
index 41eca5ad..00000000
--- a/tftf/tests/runtime_services/secure_service/test_ffa_version.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <ffa_svc.h>
-#include <test_helpers.h>
-#include <tftf_lib.h>
-
-/*
- * Using FFA version expected for SPM.
- */
-#define SPM_VERSION MAKE_FFA_VERSION(FFA_VERSION_MAJOR, FFA_VERSION_MINOR)
-
-static bool should_skip_test;
-
-/*
- * Calls FFA Version ABI, and checks if the result as expected.
- */
-static test_result_t test_ffa_version(uint32_t input_version, uint32_t expected_return)
-{
- if (should_skip_test) {
- return TEST_RESULT_SKIPPED;
- }
-
- smc_ret_values ret_values = ffa_version(input_version);
-
- uint32_t spm_version = (uint32_t)(0xFFFFFFFF & ret_values.ret0);
-
- if (spm_version == expected_return) {
- return TEST_RESULT_SUCCESS;
- }
-
- tftf_testcase_printf("Input Version: 0x%x\nReturn: 0x%x\nExpected: 0x%x\n",
- input_version, spm_version, expected_return);
-
- return TEST_RESULT_FAIL;
-}
-
-/*
- * @Test_Aim@ Validate what happens when using same version as SPM.
- */
-test_result_t test_ffa_version_equal(void)
-{
- /*
- * FFA_VERSION interface is used to check that SPM functionality is supported.
- * On FFA_VERSION invocation from TFTF, the SPMD returns either NOT_SUPPORTED or
- * the SPMC version value provided in the SPMC manifest. The variable "should_skip_test"
- * is set to true when the SPMD returns NOT_SUPPORTED or a mismatched version, which
- * means that a TFTF physical FF-A endpoint version (SPM_VERSION) does not match the
- * SPMC's physical FF-A endpoint version. This prevents running the subsequent FF-A
- * version tests (and break the test flow), as they're not relevant when the SPMD is
- * not present within BL31 (FFA_VERSION returns NOT_SUPPORTED).
- */
- test_result_t ret = test_ffa_version(SPM_VERSION, SPM_VERSION);
- if (ret != TEST_RESULT_SUCCESS) {
- should_skip_test = true;
- ret = TEST_RESULT_SKIPPED;
- }
- return ret;
-}
-
-/*
- * @Test_Aim@ Validate what happens when setting bit 31 in
- * 'input_version'. As per spec, FFA version is 31 bits long.
- * Bit 31 set is an invalid input.
- */
-test_result_t test_ffa_version_bit31(void)
-{
- return test_ffa_version(FFA_VERSION_BIT31_MASK | SPM_VERSION, FFA_ERROR_NOT_SUPPORTED);
-}
-
-/*
- * @Test_Aim@ Validate what happens for bigger version than SPM's.
- */
-test_result_t test_ffa_version_bigger(void)
-{
- return test_ffa_version(MAKE_FFA_VERSION(FFA_VERSION_MAJOR + 1, 0), SPM_VERSION);
-}
-
-/*
- * @Test_Aim@ Validate what happens for smaller version than SPM's.
- */
-test_result_t test_ffa_version_smaller(void)
-{
- return test_ffa_version(MAKE_FFA_VERSION(0, 9), SPM_VERSION);
-}
diff --git a/tftf/tests/runtime_services/secure_service/test_spci_blocking_request.c b/tftf/tests/runtime_services/secure_service/test_spci_blocking_request.c
index 6d248428..d2aa20b8 100644
--- a/tftf/tests/runtime_services/secure_service/test_spci_blocking_request.c
+++ b/tftf/tests/runtime_services/secure_service/test_spci_blocking_request.c
@@ -29,8 +29,7 @@ static test_result_t test_spci_blocking_multicore_fn(void)
u_register_t rx1, rx2, rx3;
test_result_t result = TEST_RESULT_SUCCESS;
- u_register_t cpu_mpid = read_mpidr_el1() & MPID_MASK;
- unsigned int core_pos = platform_get_core_pos(cpu_mpid);
+ unsigned int core_pos = get_current_core_id();
tftf_send_event(&cpu_has_entered_test[core_pos]);
diff --git a/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c b/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
index f57fa243..2927fc2d 100644
--- a/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
+++ b/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,7 @@
#include <cactus_test_cmds.h>
#include <ffa_endpoints.h>
#include <ffa_helpers.h>
+#include <lib/extensions/sve.h>
#include <test_helpers.h>
#define SENDER HYP_ID
@@ -14,19 +15,20 @@
static const struct ffa_uuid expected_sp_uuids[] = { {PRIMARY_UUID} };
-static test_result_t simd_vector_compare(simd_vector_t a[SIMD_NUM_VECTORS],
- simd_vector_t b[SIMD_NUM_VECTORS])
+static test_result_t fp_vector_compare(uint8_t *a, uint8_t *b,
+ size_t vector_size, uint8_t vectors_num)
{
- for (unsigned int num = 0U; num < SIMD_NUM_VECTORS; num++) {
- if (memcmp(a[num], b[num], sizeof(simd_vector_t)) != 0) {
- ERROR("Vectors not equal: a:0x%llx b:0x%llx\n",
- (uint64_t)a[num][0], (uint64_t)b[num][0]);
- return TEST_RESULT_FAIL;
- }
+ if (memcmp(a, b, vector_size * vectors_num) != 0) {
+ return TEST_RESULT_FAIL;
}
return TEST_RESULT_SUCCESS;
}
+#ifdef __aarch64__
+static sve_vector_t sve_vectors_input[SVE_NUM_VECTORS] __aligned(16);
+static sve_vector_t sve_vectors_output[SVE_NUM_VECTORS] __aligned(16);
+#endif
+
/*
* Tests that SIMD vectors are preserved during the context switches between
* normal world and the secure world.
@@ -35,8 +37,6 @@ static test_result_t simd_vector_compare(simd_vector_t a[SIMD_NUM_VECTORS],
*/
test_result_t test_simd_vectors_preserved(void)
{
- SKIP_TEST_IF_AARCH32();
-
/**********************************************************************
* Verify that FFA is there and that it has the correct version.
**********************************************************************/
@@ -48,12 +48,11 @@ test_result_t test_simd_vectors_preserved(void)
/* 0x11 is just a dummy value to be distinguished from the value in the
* secure world. */
for (unsigned int num = 0U; num < SIMD_NUM_VECTORS; num++) {
- memset(simd_vectors_send[num], 0x11 * num, sizeof(simd_vector_t));
+ memset(simd_vectors_send[num], 0x11 * (num+1), sizeof(simd_vector_t));
}
-
fill_simd_vector_regs(simd_vectors_send);
- smc_ret_values ret = cactus_req_simd_fill_send_cmd(SENDER, RECEIVER);
+ struct ffa_value ret = cactus_req_simd_fill_send_cmd(SENDER, RECEIVER);
if (!is_ffa_direct_response(ret)) {
return TEST_RESULT_FAIL;
@@ -65,5 +64,76 @@ test_result_t test_simd_vectors_preserved(void)
read_simd_vector_regs(simd_vectors_receive);
- return simd_vector_compare(simd_vectors_send, simd_vectors_receive);
+ return fp_vector_compare((uint8_t *)simd_vectors_send,
+ (uint8_t *)simd_vectors_receive,
+ sizeof(simd_vector_t), SIMD_NUM_VECTORS);
+}
+
+/*
+ * Tests that SVE vectors are preserved during the context switches between
+ * normal world and the secure world.
+ * Fills the SVE vectors with known values, requests SP to fill the vectors
+ * with a different values, checks that the context is restored on return.
+ */
+test_result_t test_sve_vectors_preserved(void)
+{
+#ifdef __aarch64__
+ uint64_t vl;
+ uint8_t *sve_vector;
+
+ SKIP_TEST_IF_SVE_NOT_SUPPORTED();
+
+ /**********************************************************************
+ * Verify that FFA is there and that it has the correct version.
+ **********************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+ /*
+ * Clear SVE vectors buffers used to compare the SVE state before calling
+ * into the Swd compared to SVE state restored after returning to NWd.
+ */
+ memset(sve_vectors_input, sizeof(sve_vector_t) * SVE_NUM_VECTORS, 0);
+ memset(sve_vectors_output, sizeof(sve_vector_t) * SVE_NUM_VECTORS, 0);
+
+ /* Set ZCR_EL2.LEN to implemented VL (constrained by EL3). */
+ write_zcr_el2(0xf);
+ isb();
+
+ /* Get the implemented VL. */
+ vl = sve_vector_length_get();
+
+ /* Fill each vector for the VL size with a fixed pattern. */
+ sve_vector = (uint8_t *) sve_vectors_input;
+ for (uint32_t vector_num = 0U; vector_num < SVE_NUM_VECTORS; vector_num++) {
+ memset(sve_vector, 0x11 * (vector_num + 1), vl);
+ sve_vector += vl;
+ }
+
+ /* Fill SVE vector registers with the buffer contents prepared above. */
+ fill_sve_vector_regs(sve_vectors_input);
+
+ /*
+ * Call cactus secure partition which uses SIMD (and expect it doesn't
+ * affect the normal world state on return).
+ */
+ struct ffa_value ret = cactus_req_simd_fill_send_cmd(SENDER, RECEIVER);
+
+ if (!is_ffa_direct_response(ret)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ if (cactus_get_response(ret) == CACTUS_ERROR) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Get the SVE vectors state after returning to normal world. */
+ read_sve_vector_regs(sve_vectors_output);
+
+ /* Compare to state before calling into secure world. */
+ return fp_vector_compare((uint8_t *)sve_vectors_input,
+ (uint8_t *)sve_vectors_output,
+ vl, SVE_NUM_VECTORS);
+#else
+ return TEST_RESULT_SKIPPED;
+#endif /* __aarch64__ */
}
diff --git a/tftf/tests/runtime_services/secure_service/test_spm_smmu.c b/tftf/tests/runtime_services/secure_service/test_spm_smmu.c
index b041a976..0f0a5d9f 100644
--- a/tftf/tests/runtime_services/secure_service/test_spm_smmu.c
+++ b/tftf/tests/runtime_services/secure_service/test_spm_smmu.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -18,7 +18,7 @@ static const struct ffa_uuid expected_sp_uuids[] = { {PRIMARY_UUID} };
**************************************************************************/
test_result_t test_smmu_spm(void)
{
- smc_ret_values ret;
+ struct ffa_value ret;
/**********************************************************************
* Check SPMC has ffa_version and expected FFA endpoints are deployed.
diff --git a/tftf/tests/runtime_services/standard_service/psci/system_tests/test_psci_on_off_suspend_stress.c b/tftf/tests/runtime_services/standard_service/psci/system_tests/test_psci_on_off_suspend_stress.c
index 99f68540..58ece719 100644
--- a/tftf/tests/runtime_services/standard_service/psci/system_tests/test_psci_on_off_suspend_stress.c
+++ b/tftf/tests/runtime_services/standard_service/psci/system_tests/test_psci_on_off_suspend_stress.c
@@ -47,27 +47,6 @@ static unsigned int include_cpu_suspend;
static test_result_t secondary_cpu_on_race_test(void);
/*
- * Utility function to wait for all CPUs other than the caller to be
- * OFF.
- */
-static void wait_for_non_lead_cpus(void)
-{
- unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
- unsigned int target_mpid, target_node;
-
- for_each_cpu(target_node) {
- target_mpid = tftf_get_mpidr_from_node(target_node);
- /* Skip lead CPU, as it is powered on */
- if (target_mpid == lead_mpid)
- continue;
-
- while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0)
- != PSCI_STATE_OFF)
- ;
- }
-}
-
-/*
* Update per-cpu counter corresponding to the current CPU.
* This function updates 2 counters, one in normal memory and the other
* in coherent device memory. The counts are then compared to check if they
diff --git a/tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S b/tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S
index 74fe4a60..a8872346 100644
--- a/tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S
+++ b/tftf/tests/runtime_services/standard_service/sdei/system_tests/sdei_entrypoint.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,6 +13,7 @@
.globl sdei_entrypoint_resume
.globl sdei_handler_done
.globl sdei_rm_any_entrypoint
+ .globl sdei_check_pstate_entrypoint
.local event_handled
.comm event_handled, PLATFORM_CORE_COUNT * 4, 8
@@ -126,6 +127,33 @@ func sdei_rm_any_entrypoint
b .
endfunc sdei_rm_any_entrypoint
+func sdei_check_pstate_entrypoint
+ stp x2, x30, [sp, #-16]!
+
+ /* Dispatch to C handler */
+ bl sdei_check_pstate_handler
+
+ /* Calculate address of event completion variable */
+ mrs x0, mpidr_el1
+ mov_imm x1, MPID_MASK
+ and x0, x0, x1
+ bl platform_get_core_pos
+ lsl x0, x0, #2
+ adrp x1, event_handled
+ add x1, x1, :lo12:event_handled
+ add x1, x0, x1
+
+ /* Mark event handling as complete so `sdei_handler_done` can return */
+ mov w2, #1
+ str w2, [x1]
+ sev
+
+ /* Populate `x0` and `x1` to prepare for SMC call */
+ ldp x1, x30, [sp], #16
+ mov_imm x0, SDEI_EVENT_COMPLETE_AND_RESUME
+ smc #0
+endfunc sdei_check_pstate_entrypoint
+
#else /* AARCH32 */
func sdei_entrypoint
/* SDEI is not supported on AArch32. */
diff --git a/tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_pstate.c b/tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_pstate.c
new file mode 100644
index 00000000..024352e9
--- /dev/null
+++ b/tftf/tests/runtime_services/standard_service/sdei/system_tests/test_sdei_pstate.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <debug.h>
+#include <events.h>
+#include <plat_topology.h>
+#include <platform.h>
+#include <power_management.h>
+#include <sdei.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <timer.h>
+
+#ifdef __aarch64__
+
+#define EV_COOKIE 0xDEADBEEF
+
+extern sdei_handler_t sdei_check_pstate_entrypoint;
+
+u_register_t daif;
+u_register_t sp;
+u_register_t pan;
+u_register_t dit;
+
+int sdei_check_pstate_handler(int ev, unsigned long long arg)
+{
+ printf("%s: handler fired\n", __func__);
+ daif = read_daif();
+ sp = read_spsel();
+ if (is_armv8_1_pan_present())
+ pan = read_pan();
+
+ if (is_armv8_4_dit_present())
+ dit = read_dit();
+
+ assert(arg == EV_COOKIE);
+ return 0;
+}
+
+static test_result_t sdei_event_check_pstate(void)
+{
+ long long ret;
+
+ ret = sdei_event_register(0, sdei_check_pstate_entrypoint, EV_COOKIE,
+ SDEI_REGF_RM_PE, read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event register failed: 0x%llx\n",
+ ret);
+ return TEST_RESULT_FAIL;
+ }
+
+ ret = sdei_event_enable(0);
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event enable failed: 0x%llx\n", ret);
+ goto err0;
+ }
+
+ ret = sdei_pe_unmask();
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI pe unmask failed: 0x%llx\n", ret);
+ goto err1;
+ }
+
+ /* Check the common bits are set correctly */
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: 0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+
+ u_register_t all_interrupts_masked = 0x3c0;
+
+ if (daif != all_interrupts_masked) {
+ tftf_testcase_printf("Interrupts were not correctly masked " \
+ "during SDEI event signal\n" \
+ "Expected DAIF: 0x%lx, " \
+ "Actual DAIF: 0x%lx\n",
+ all_interrupts_masked, daif);
+ ret = -1;
+ goto err1;
+ }
+
+ u_register_t use_sp_elx = 0x1;
+
+ if (sp != use_sp_elx) {
+ tftf_testcase_printf("The SPSel PSTATE Bit was not set " \
+ "correctly during SDEI event signal\n" \
+ "Expected SPSel: 0x%lx, " \
+ "Actual SPSel: 0x%lx\n",
+ use_sp_elx, sp);
+ ret = -1;
+ goto err1;
+ }
+
+ if (is_armv8_1_pan_present()) {
+ printf("PAN Enabled so testing PAN PSTATE bit\n");
+ /*
+ * Check that when the SPAN bit is 0
+ * the PAN PSTATE bit is maintained
+ */
+
+ /* When PAN bit is 0 */
+ u_register_t expected_pan = 0;
+
+ write_pan(expected_pan);
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (pan != expected_pan) {
+ tftf_testcase_printf("PAN PSTATE bit not maintained " \
+ "during SDEI event signal\n" \
+ "Expected PAN: 0x%lx, " \
+ "Actual PAN: 0x%lx\n",
+ expected_pan, pan);
+ ret = -1;
+ goto err1;
+ }
+
+ /* When PAN bit is 1 */
+ expected_pan = PAN_BIT;
+ write_pan(expected_pan);
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (pan != expected_pan) {
+ tftf_testcase_printf("PAN PSTATE bit not maintained " \
+ "during SDEI event signal\n" \
+ "Expected PAN: 0x%lx, " \
+ "Actual PAN: 0x%lx\n",
+ expected_pan, pan);
+ ret = -1;
+ goto err1;
+ }
+
+ /* Test that the SPAN condition is met */
+ /* Set the SPAN bit */
+ u_register_t old_sctlr = read_sctlr_el2();
+
+ write_sctlr_el2(old_sctlr & ~SCTLR_SPAN_BIT);
+
+ expected_pan = 0;
+ /*
+ * Check that when the HCR_EL2.{E2H, TGE} != {1, 1}
+ * the PAN bit is maintained
+ */
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (pan != expected_pan) {
+ tftf_testcase_printf("PAN PSTATE bit not maintained " \
+ "during SDEI event signal " \
+ "when the SPAN bit is set and " \
+ "HCR_EL2.{E2H, TGE} != {1, 1}\n" \
+ "Expected PAN: 0x%lx, " \
+ "Actual PAN: 0x%lx\n",
+ expected_pan, pan);
+ ret = -1;
+ goto err1;
+ }
+
+ expected_pan = PAN_BIT;
+ write_pan(expected_pan);
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (pan != expected_pan) {
+ tftf_testcase_printf("PAN PSTATE bit not maintained " \
+ "during SDEI event signal " \
+ "when the SPAN bit is set and " \
+ "HCR_EL2.{E2H, TGE} != {1, 1}\n" \
+ "Expected PAN: 0x%lx, " \
+ "Actual PAN: 0x%lx\n",
+ expected_pan, pan);
+ ret = -1;
+ goto err1;
+ }
+
+ /*
+ * Check that when the HCR_EL2.{E2H, TGE} = {1, 1}
+ * PAN bit is forced to 1
+ */
+ /* Set E2H Bit */
+ u_register_t old_hcr_el2 = read_hcr_el2();
+
+ write_hcr_el2(old_hcr_el2 | HCR_E2H_BIT);
+
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (pan != PAN_BIT) {
+ tftf_testcase_printf("PAN PSTATE bit was not forced " \
+ "to 1 during SDEI event signal " \
+ "when the SPAN bit is set and " \
+ "HCR_EL2.{E2H, TGE} = {1, 1}\n");
+ ret = -1;
+ goto err1;
+ }
+
+ /*
+ * Set the SCTLR and HCR_EL2 registers back to their old values
+ */
+ write_sctlr_el2(old_sctlr);
+ write_hcr_el2(old_hcr_el2);
+ }
+
+ /* Check that the DIT PSTATE bit is maintained during event signal */
+ if (is_armv8_4_dit_present()) {
+ printf("DIT Enabled so testing DIT PSTATE bit\n");
+ /* When DIT bit is 0 */
+ u_register_t expected_dit = 0;
+
+ write_dit(expected_dit);
+ ret = sdei_event_signal(read_mpidr_el1());
+
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (dit != expected_dit) {
+ tftf_testcase_printf("DIT PSTATE bit not maintained " \
+ "during SDEI event signal\n" \
+ "Expected DIT: 0x%lx, " \
+ "Actual DIT: 0x%lx\n",
+ expected_dit, dit);
+ ret = -1;
+ goto err1;
+ }
+
+ /* When dit bit is 1 */
+ expected_dit = DIT_BIT;
+ write_dit(expected_dit);
+ ret = sdei_event_signal(read_mpidr_el1());
+ if (ret < 0) {
+ tftf_testcase_printf("SDEI event signal failed: " \
+ "0x%llx\n", ret);
+ goto err2;
+ }
+ sdei_handler_done();
+ if (dit != expected_dit) {
+ tftf_testcase_printf("DIT PSTATE bit not maintained " \
+ "during SDEI event signal\n" \
+ "Expected DIT: 0x%lx, " \
+ "Actual DIT: 0x%lx\n",
+ expected_dit, dit);
+ ret = -1;
+ goto err1;
+ }
+ }
+
+err2:
+ sdei_pe_mask();
+err1:
+ sdei_event_disable(0);
+err0:
+ sdei_event_unregister(0);
+
+ if (ret < 0)
+ return TEST_RESULT_FAIL;
+
+ return TEST_RESULT_SUCCESS;
+}
+#endif /* __aarch64__ */
+
+/* Each core signals itself using SDEI event signalling. */
+test_result_t test_sdei_event_check_pstate(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+ long long ret;
+
+ ret = sdei_version();
+ if (ret != MAKE_SDEI_VERSION(1, 0, 0)) {
+ tftf_testcase_printf("Unexpected SDEI version: 0x%llx\n", ret);
+ return TEST_RESULT_SKIPPED;
+ }
+
+ disable_irq();
+ /* We only need to run these tests on the main CPU */
+ if (sdei_event_check_pstate() != TEST_RESULT_SUCCESS) {
+ ret = -1;
+ goto err0;
+ }
+
+err0:
+ enable_irq();
+ if (ret < 0)
+ return TEST_RESULT_FAIL;
+ return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/runtime_services/trusted_os/tsp/test_pstate_after_exception.c b/tftf/tests/runtime_services/trusted_os/tsp/test_pstate_after_exception.c
new file mode 100644
index 00000000..a17a54e1
--- /dev/null
+++ b/tftf/tests/runtime_services/trusted_os/tsp/test_pstate_after_exception.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <test_helpers.h>
+
+/*
+ * Test that the PSTATE bits not set in Aarch64.TakeException but
+ * set to a default when taking an exception to EL3 are maintained
+ * after an exception and that changes in TSP do not effect the PSTATE
+ * in TFTF and vice versa.
+ */
+test_result_t tsp_check_pstate_maintained_on_exception(void)
+{
+ smc_args tsp_svc_params;
+ smc_ret_values ret;
+ u_register_t dit;
+ u_register_t dit_bit;
+
+ SKIP_TEST_IF_TSP_NOT_PRESENT();
+ SKIP_TEST_IF_DIT_NOT_SUPPORTED();
+
+#ifdef __aarch64__
+ dit_bit = DIT_BIT;
+#else
+ dit_bit = CPSR_DIT_BIT;
+#endif
+
+ write_dit(dit_bit);
+
+ /* Standard SMC */
+ tsp_svc_params.fid = TSP_STD_FID(TSP_CHECK_DIT);
+ tsp_svc_params.arg1 = 0;
+ tsp_svc_params.arg2 = 0;
+ ret = tftf_smc(&tsp_svc_params);
+ if (ret.ret1 == 0) {
+ if (ret.ret2 == 0xffff) {
+ tftf_testcase_printf("DIT bit not supported by TSP");
+ return TEST_RESULT_SKIPPED;
+ }
+ tftf_testcase_printf("DIT bit in the TSP is not 0.\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ dit = read_dit();
+ if (dit != dit_bit) {
+ tftf_testcase_printf("DIT bit in TFTF was not maintained.\n"
+ "Expected: 0x%x, Actual: 0x%x",
+ (uint32_t) dit_bit, (uint32_t) dit);
+ return TEST_RESULT_FAIL;
+ }
+
+ tsp_svc_params.fid = TSP_STD_FID(TSP_CHECK_DIT);
+ tsp_svc_params.arg1 = dit_bit;
+ tsp_svc_params.arg2 = 0;
+ ret = tftf_smc(&tsp_svc_params);
+ if (ret.ret1 == 0) {
+ tftf_testcase_printf("DIT bit in the TSP was not maintained\n"
+ "Expected: 0x%x, Actual: 0x%x",
+ (uint32_t) dit_bit, (uint32_t) ret.ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ dit = read_dit();
+ if (dit != dit_bit) {
+ tftf_testcase_printf("DIT bit in TFTF was not maintained.\n"
+ "Expected: 0x%x, Actual: 0x%x",
+ (uint32_t) dit_bit, (uint32_t) dit);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/tests-cpu-extensions.mk b/tftf/tests/tests-cpu-extensions.mk
index fedf7837..061ab7e8 100644
--- a/tftf/tests/tests-cpu-extensions.mk
+++ b/tftf/tests/tests-cpu-extensions.mk
@@ -1,18 +1,26 @@
#
-# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
TESTS_SOURCES += $(addprefix tftf/tests/, \
+ extensions/afp/test_afp.c \
extensions/amu/test_amu.c \
+ extensions/brbe/test_brbe.c \
+ extensions/ecv/test_ecv.c \
+ extensions/fgt/test_fgt.c \
extensions/mte/test_mte.c \
+ extensions/pauth/test_pauth.c \
extensions/sve/sve_operations.S \
+ extensions/sme/test_sme.c \
+ extensions/spe/test_spe.c \
extensions/sve/test_sve.c \
- extensions/fgt/test_fgt.c \
- extensions/ecv/test_ecv.c \
+ extensions/sys_reg_trace/test_sys_reg_trace.c \
+ extensions/trbe/test_trbe.c \
+ extensions/trf/test_trf.c \
+ extensions/wfxt/test_wfxt.c \
+ runtime_services/arm_arch_svc/smccc_arch_soc_id.c \
runtime_services/arm_arch_svc/smccc_arch_workaround_1.c \
runtime_services/arm_arch_svc/smccc_arch_workaround_2.c \
- runtime_services/arm_arch_svc/smccc_arch_soc_id.c \
- extensions/pauth/test_pauth.c \
)
diff --git a/tftf/tests/tests-cpu-extensions.xml b/tftf/tests/tests-cpu-extensions.xml
index 08a65c7f..bc84659a 100644
--- a/tftf/tests/tests-cpu-extensions.xml
+++ b/tftf/tests/tests-cpu-extensions.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ Copyright (c) 2018-2022, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
-->
@@ -20,6 +20,15 @@
<testcase name="Check for MTE register leakage" function="test_mte_leakage" />
<testcase name="Use FGT Registers" function="test_fgt_enabled" />
<testcase name="Use ECV Registers" function="test_ecv_enabled" />
+ <testcase name="Use trace buffer control Registers" function="test_trbe_enabled" />
+ <testcase name="Use branch record buffer control registers" function="test_brbe_enabled" />
+ <testcase name="Use trace filter control Registers" function="test_trf_enabled" />
+ <testcase name="Use trace system Registers" function="test_sys_reg_trace_enabled" />
+ <testcase name="SME support" function="test_sme_support" />
+ <testcase name="SPE support" function="test_spe_support" />
+ <testcase name="AFP support" function="test_afp_support" />
+ <testcase name="Test wfit instruction" function="test_wfit_instruction" />
+ <testcase name="Test wfet instruction" function="test_wfet_instruction" />
</testsuite>
<testsuite name="ARM_ARCH_SVC" description="Arm Architecture Service tests">
diff --git a/tftf/tests/tests-hcx.mk b/tftf/tests/tests-hcx.mk
new file mode 100644
index 00000000..ba7cd78f
--- /dev/null
+++ b/tftf/tests/tests-hcx.mk
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES += $(addprefix tftf/tests/, \
+ extensions/hcx/test_hcx.c \
+)
diff --git a/tftf/tests/tests-hcx.xml b/tftf/tests/tests-hcx.xml
new file mode 100644
index 00000000..5b7f947f
--- /dev/null
+++ b/tftf/tests/tests-hcx.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (c) 2021, Arm Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+
+ <testsuite name="FEAT_HCX" description="Tests that HCRX_EL2 access has been granted by EL3.">
+ <testcase name="Test access to HCRX_EL2" function="test_feat_hcx_enabled" />
+ </testsuite>
+
+</testsuites>
diff --git a/tftf/tests/tests-invalid-access.mk b/tftf/tests/tests-invalid-access.mk
new file mode 100644
index 00000000..ffca79e4
--- /dev/null
+++ b/tftf/tests/tests-invalid-access.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES += tftf/tests/misc_tests/test_invalid_access.c
+
+TESTS_SOURCES += \
+ $(addprefix tftf/tests/runtime_services/realm_payload/, \
+ realm_payload_test_helpers.c \
+ )
+
+TESTS_SOURCES += \
+ $(addprefix tftf/tests/runtime_services/secure_service/, \
+ ${ARCH}/ffa_arch_helpers.S \
+ ffa_helpers.c \
+ spm_common.c \
+ test_ffa_setup_and_discovery.c \
+)
diff --git a/tftf/tests/tests-invalid-access.xml b/tftf/tests/tests-invalid-access.xml
new file mode 100644
index 00000000..60d9a2b0
--- /dev/null
+++ b/tftf/tests/tests-invalid-access.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (c) 2022, Arm Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+ <testsuite name="Invalid memory access" description="Invalid memory access">
+ <testcase name="Access EL3 memory from NS world"
+ function="el3_memory_cannot_be_accessed_in_ns" />
+ <testcase name="Access Realm memory from NS world"
+ function="rl_memory_cannot_be_accessed_in_ns" />
+ <testcase name="Access Secure memory from NS world"
+ function="s_memory_cannot_be_accessed_in_ns" />
+ <testcase name="Access Secure memory from Realm world"
+ function="s_memory_cannot_be_accessed_in_rl" />
+ <testcase name="Access from a SP to a Root region"
+ function="rt_memory_cannot_be_accessed_in_s" />
+ <testcase name="Access Root memory from Realm world"
+ function="rt_memory_cannot_be_accessed_in_rl" />
+ </testsuite>
+</testsuites>
diff --git a/tftf/tests/tests-realm-payload.mk b/tftf/tests/tests-realm-payload.mk
new file mode 100644
index 00000000..a8642faf
--- /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 00000000..f80ead63
--- /dev/null
+++ b/tftf/tests/tests-realm-payload.xml
@@ -0,0 +1,21 @@
+<?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="Test TFTF can call RMM/TRP and SPM serially on a single core" function="test_spm_rmm_serial_smc" />
+ <testcase name="Test TFTF can call RMM/TRP and SPM parallelly on a multi core" function="test_spm_rmm_parallel_smc" />
+ </testsuite>
+
+</testsuites>
diff --git a/tftf/tests/tests-rndr_trap.mk b/tftf/tests/tests-rndr_trap.mk
new file mode 100644
index 00000000..147b704b
--- /dev/null
+++ b/tftf/tests/tests-rndr_trap.mk
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES += $(addprefix tftf/tests/, \
+ extensions/rng_trap/test_rndr_trap.c \
+)
diff --git a/tftf/tests/tests-rndr_trap.xml b/tftf/tests/tests-rndr_trap.xml
new file mode 100644
index 00000000..fa32cbf4
--- /dev/null
+++ b/tftf/tests/tests-rndr_trap.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (c) 2022, Arm Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+
+ <testsuite name="RNDR_TRAP" description="Tests that a read access to RNDR generates a trap to EL3.">
+ <testcase name="Test EL3 trap upon a RNDR read access" function="test_rndr_trap_enabled" />
+ </testsuite>
+
+</testsuites>
diff --git a/tftf/tests/tests-rndrrs_trap.mk b/tftf/tests/tests-rndrrs_trap.mk
new file mode 100644
index 00000000..2b2bd088
--- /dev/null
+++ b/tftf/tests/tests-rndrrs_trap.mk
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES += $(addprefix tftf/tests/, \
+ extensions/rng_trap/test_rndrrs_trap.c \
+)
diff --git a/tftf/tests/tests-rndrrs_trap.xml b/tftf/tests/tests-rndrrs_trap.xml
new file mode 100644
index 00000000..bf33e318
--- /dev/null
+++ b/tftf/tests/tests-rndrrs_trap.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (c) 2022, Arm Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+
+ <testsuite name="RNDRRS_TRAP" description="Tests that a read access to RNDRRS generates a trap to EL3.">
+ <testcase name="Test EL3 trap upon a RNDRRS read access" function="test_rndrrs_trap_enabled" />
+ </testsuite>
+
+</testsuites>
diff --git a/tftf/tests/tests-sdei.mk b/tftf/tests/tests-sdei.mk
index 0c495d99..e73bfb72 100644
--- a/tftf/tests/tests-sdei.mk
+++ b/tftf/tests/tests-sdei.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2020, Arm Limited. All rights reserved.
+# Copyright (c) 2020-2021, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -10,4 +10,5 @@ TESTS_SOURCES += \
test_sdei.c \
test_sdei_state.c \
test_sdei_rm_any.c \
+ test_sdei_pstate.c \
)
diff --git a/tftf/tests/tests-sdei.xml b/tftf/tests/tests-sdei.xml
index 147835bc..38c7c0d0 100644
--- a/tftf/tests/tests-sdei.xml
+++ b/tftf/tests/tests-sdei.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (c) 2020, Arm Limited. All rights reserved.
+ Copyright (c) 2020-2021, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
-->
@@ -15,6 +15,7 @@
<testcase name="SDEI event signaling: each core signals itself" function="test_sdei_event_signal_serial" />
<testcase name="SDEI event signaling: one core signals all others" function="test_sdei_event_signal_all" />
<testcase name="SDEI event routing all: SPI events routed to all CPUs" function="test_sdei_routing_any" />
+ <testcase name="SDEI event handler pstate testing" function="test_sdei_event_check_pstate" />
</testsuite>
</testsuites>
diff --git a/tftf/tests/tests-smcfuzzing.mk b/tftf/tests/tests-smcfuzzing.mk
index 82b6a7c8..1837ee93 100644
--- a/tftf/tests/tests-smcfuzzing.mk
+++ b/tftf/tests/tests-smcfuzzing.mk
@@ -4,6 +4,37 @@
# SPDX-License-Identifier: BSD-3-Clause
#
+# Generate random fuzzing seeds
+# If no instance count is provided, default to 1 instance
+# If no seeds are provided, generate them randomly
+# The number of seeds provided must match the instance count
+SMC_FUZZ_INSTANCE_COUNT ?= 1
+SMC_FUZZ_SEEDS ?= $(shell python -c "from random import randint; seeds = [randint(0, 4294967295) for i in range($(SMC_FUZZ_INSTANCE_COUNT))];print(\",\".join(str(x) for x in seeds));")
+SMC_FUZZ_CALLS_PER_INSTANCE ?= 100
+
+# Validate SMC fuzzer parameters
+
+# Instance count must not be zero
+ifeq ($(SMC_FUZZ_INSTANCE_COUNT),0)
+$(error SMC_FUZZ_INSTANCE_COUNT must not be zero!)
+endif
+
+# Calls per instance must not be zero
+ifeq ($(SMC_FUZZ_CALLS_PER_INSTANCE),0)
+$(error SMC_FUZZ_CALLS_PER_INSTANCE must not be zero!)
+endif
+
+# Make sure seed count and instance count match
+TEST_SEED_COUNT = $(shell python -c "print(len(\"$(SMC_FUZZ_SEEDS)\".split(\",\")))")
+ifneq ($(TEST_SEED_COUNT), $(SMC_FUZZ_INSTANCE_COUNT))
+$(error Number of seeds does not match SMC_FUZZ_INSTANCE_COUNT!)
+endif
+
+# Add definitions to TFTF_DEFINES so they can be used in the code
+$(eval $(call add_define,TFTF_DEFINES,SMC_FUZZ_SEEDS))
+$(eval $(call add_define,TFTF_DEFINES,SMC_FUZZ_INSTANCE_COUNT))
+$(eval $(call add_define,TFTF_DEFINES,SMC_FUZZ_CALLS_PER_INSTANCE))
+
TESTS_SOURCES += \
$(addprefix smc_fuzz/src/, \
randsmcmod.c \
diff --git a/tftf/tests/tests-spm.mk b/tftf/tests/tests-spm.mk
index e62e03d9..702c10c3 100644
--- a/tftf/tests/tests-spm.mk
+++ b/tftf/tests/tests-spm.mk
@@ -1,19 +1,26 @@
#
-# Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
TESTS_SOURCES += \
$(addprefix tftf/tests/runtime_services/secure_service/, \
+ ${ARCH}/ffa_arch_helpers.S \
ffa_helpers.c \
spm_common.c \
test_ffa_direct_messaging.c \
- test_ffa_features.c \
test_ffa_interrupts.c \
+ test_ffa_secure_interrupts.c \
test_ffa_memory_sharing.c \
- test_ffa_rxtx_map.c \
- test_ffa_version.c \
+ test_ffa_setup_and_discovery.c \
+ test_ffa_notifications.c \
test_spm_cpu_features.c \
test_spm_smmu.c \
+ test_ffa_exceptions.c \
+ )
+
+TESTS_SOURCES += \
+ $(addprefix tftf/tests/runtime_services/realm_payload/, \
+ realm_payload_test_helpers.c \
)
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index 32efc161..19033b7b 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -1,33 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ Copyright (c) 2018-2022, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
-->
<testsuites>
+ <testsuite name="FF-A Setup and Discovery"
+ description="Test FF-A Setup and Discovery interfaces" >
+ <testcase name="Test FFA_FEATURES"
+ function="test_ffa_features" />
- <testsuite name="FF-A Version"
- description="Test FF-A Version ABI" >
-
- <testcase name="Same FFA version as SPM"
- function="test_ffa_version_equal" />
- <testcase name="Setting bit 31 in input version"
- function="test_ffa_version_bit31"/>
- <testcase name="Bigger FFA version than SPM"
- function="test_ffa_version_bigger" />
- <testcase name="Smaller FFA version than SPM"
- function="test_ffa_version_smaller" />
-
- </testsuite>
-
- <testsuite name="FF-A RXTX Mapping"
- description="Test to FF-A RXTX mapping ABI" >
+ <testcase name="Same FFA version as SPM"
+ function="test_ffa_version_equal" />
+ <testcase name="Setting bit 31 in input version"
+ function="test_ffa_version_bit31"/>
+ <testcase name="Bigger FFA version than SPM"
+ function="test_ffa_version_bigger" />
+ <testcase name="Smaller FFA version than SPM"
+ function="test_ffa_version_smaller" />
+
+ <!--
+ The ordering of the RXTX Buffer tests must be maintained.
+ With test_ffa_rxtx_map_unmapped_success coming last as the
+ mailbox for the remaining tftf tests is set here.
+ -->
<testcase name="FF-A RXTX Map API success"
function="test_ffa_rxtx_map_success" />
<testcase name="FF-A RXTX Map API consecutive"
function="test_ffa_rxtx_map_fail" />
+ <testcase name="FF-A RXTX Unmap API success"
+ function="test_ffa_rxtx_unmap_success" />
+ <testcase name="FF-A RXTX Unmap API consecutive"
+ function="test_ffa_rxtx_unmap_fail" />
+ <testcase name="FF-A RXTX remap unmapped region success"
+ function="test_ffa_rxtx_map_unmapped_success" />
+
+ <testcase name="Test FFA_SPM_ID_GET"
+ function="test_ffa_spm_id_get" />
+
+ <testcase name="Test FFA_PARTITION_INFO_GET"
+ function="test_ffa_partition_info" />
+ <testcase name="Test FFA_PARTITION_INFO_GET v1.0"
+ function="test_ffa_partition_info_v1_0" />
+ </testsuite>
+
+ <testsuite name="SP exceptions"
+ description="SP exceptions" >
+
+ <testcase name="Access from a SP to a Realm region"
+ function="rl_memory_cannot_be_accessed_in_s" />
+
</testsuite>
<testsuite name="FF-A Direct messaging"
@@ -54,6 +78,8 @@
description="Test FF-A Memory Sharing ABIs" >
<testcase name="Lend Memory to Secure World"
function="test_mem_lend_sp" />
+ <testcase name="Lend memory, clear flag set"
+ function="test_mem_share_to_sp_clear_memory"/>
<testcase name="Share Memory with Secure World"
function="test_mem_share_sp" />
<testcase name="Donate Memory to Secure World"
@@ -64,24 +90,34 @@
function="test_req_mem_lend_sp_to_sp" />
<testcase name="Request Donate Memory SP-to-SP"
function="test_req_mem_donate_sp_to_sp" />
- </testsuite>
-
- <testsuite name="FF-A features"
- description="Test FFA_FEATURES ABI" >
- <testcase name="Test FFA_FEATURES"
- function="test_ffa_features" />
+ <testcase name="Request Share NS Memory (large PA) SP-to-SP"
+ function="test_req_ns_mem_share_sp_to_sp" />
+ <testcase name="Request Share Memory SP-to-VM"
+ function="test_req_mem_share_sp_to_vm" />
+ <testcase name="Request Lend Memory SP-to-VM"
+ function="test_req_mem_lend_sp_to_vm" />
</testsuite>
<testsuite name="SIMD,SVE Registers context"
description="Validate context switch between NWd and SWd" >
<testcase name="Check that SIMD registers context is preserved"
function="test_simd_vectors_preserved" />
+ <testcase name="Check that SVE registers context is preserved"
+ function="test_sve_vectors_preserved" />
</testsuite>
<testsuite name="FF-A Interrupt"
description="Test non-secure Interrupts" >
<testcase name="Test NS interrupts"
function="test_ffa_ns_interrupt" />
+ <testcase name="Test Secure interrupt handling while SP running"
+ function="test_ffa_sec_interrupt_sp_running" />
+ <testcase name="Test Secure interrupt handling while SP waiting"
+ function="test_ffa_sec_interrupt_sp_waiting" />
+ <testcase name="Test Secure interrupt handling while SP blocked"
+ function="test_ffa_sec_interrupt_sp_blocked" />
+ <testcase name="Test Secure interrupt handling while SP1 waiting SP2 running"
+ function="test_ffa_sec_interrupt_sp1_waiting_sp2_running" />
</testsuite>
<testsuite name="SMMUv3 tests"
@@ -89,4 +125,51 @@
<testcase name="Check DMA command by SMMUv3TestEngine completes"
function="test_smmu_spm" />
</testsuite>
+
+ <testsuite name="FF-A Notifications"
+ description="Test Notifications functionality" >
+ <testcase name="Notifications interrupts ID retrieval with FFA_FEATURES"
+ function= "test_notifications_retrieve_int_ids" />
+ <testcase name="Notifications bitmap create and destroy"
+ function="test_ffa_notifications_bitmap_create_destroy" />
+ <testcase name="Notifications bitmap destroy not created"
+ function="test_ffa_notifications_destroy_not_created" />
+ <testcase name="Notifications bitmap create after create"
+ function="test_ffa_notifications_create_after_create" />
+ <testcase name="SP Notifications bind and unbind"
+ function="test_ffa_notifications_sp_bind_unbind" />
+ <testcase name="VM Notifications bind and unbind"
+ function="test_ffa_notifications_vm_bind_unbind" />
+ <testcase name="VM Notifications bind NS Sender"
+ function="test_ffa_notifications_vm_bind_vm" />
+ <testcase name="Notifications bind/unbind of bound Notifications"
+ function="test_ffa_notifications_already_bound" />
+ <testcase name="Notifications bind/unbind SPs spoofing receiver"
+ function="test_ffa_notifications_bind_unbind_spoofing" />
+ <testcase name="Notifications zeroed in bind and unbind"
+ function="test_ffa_notifications_bind_unbind_zeroed" />
+ <testcase name="Notifications VM signals SP"
+ function="test_ffa_notifications_vm_signals_sp" />
+ <testcase name="Notifications SP signals SP"
+ function="test_ffa_notifications_sp_signals_sp" />
+ <testcase name="Notifications SP signals VM"
+ function="test_ffa_notifications_sp_signals_vm" />
+ <testcase name="Notifications SP signals SP with immediate SRI"
+ function="test_ffa_notifications_sp_signals_sp_immediate_sri" />
+ <testcase name="Notifications SP signals SP with delayed SRI"
+ function="test_ffa_notifications_sp_signals_sp_delayed_sri" />
+ <testcase name="Notifications unbind while pending"
+ function="test_ffa_notifications_unbind_pending" />
+ <testcase name="Notifications MP SP signals UP SP per-vCPU"
+ function="test_ffa_notifications_mp_sp_signals_up_sp" />
+ <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 c6c9029f..a7220772 100644
--- a/tftf/tests/tests-standard.mk
+++ b/tftf/tests/tests-standard.mk
@@ -23,6 +23,7 @@ TESTS_MAKEFILE := $(addprefix tftf/tests/, \
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 8c66cdaf..384a5f4e 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>
diff --git a/tftf/tests/tests-tsp.mk b/tftf/tests/tests-tsp.mk
index b1d8b15c..35ef02af 100644
--- a/tftf/tests/tests-tsp.mk
+++ b/tftf/tests/tests-tsp.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2018, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -11,4 +11,5 @@ TESTS_SOURCES += \
test_smc_tsp_std_fn_call.c \
test_tsp_fast_smc.c \
test_normal_int_switch.c \
+ test_pstate_after_exception.c \
)
diff --git a/tftf/tests/tests-tsp.xml b/tftf/tests/tests-tsp.xml
index 7e1018ec..55dfbea8 100644
--- a/tftf/tests/tests-tsp.xml
+++ b/tftf/tests/tests-tsp.xml
@@ -1,13 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (c) 2018, Arm Limited. All rights reserved.
+ Copyright (c) 2018-2022, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
-->
<testsuites>
-
<testsuite name="IRQ support in TSP" description="Test the normal IRQ preemption support in TSP.">
<testcase name="TSP preempt by IRQ and resume" function="tsp_int_and_resume" />
<testcase name="Fast SMC while TSP preempted" function="test_fast_smc_when_tsp_preempted" />
@@ -32,4 +31,8 @@
<testcase name="Stress test TSP functionality" function="test_tsp_fast_smc_operations" />
</testsuite>
+ <testsuite name="TSP PSTATE test" description="Test PSTATE bits are maintained during exception">
+ <testcase name="Test PSTATE bits maintained on exception" function="tsp_check_pstate_maintained_on_exception" />
+ </testsuite>
+
</testsuites>