Merge "fix(xilinx): wire Xilinx platforms in docs"
diff --git a/docs/about/contact.rst b/docs/about/contact.rst
index 2b1778c..bb1e2a4 100644
--- a/docs/about/contact.rst
+++ b/docs/about/contact.rst
@@ -20,14 +20,14 @@
Issue Tracker
^^^^^^^^^^^^^
-Specific issues may be raised using the `issue tracker`_ on the
-TrustedFirmware.org website. Using this tracker makes it easy for the
-maintainers to prioritise and respond to your ticket.
+Specific issues may be raised using the `issue tracker`_ on Github. Using this
+tracker makes it easy for the maintainers to prioritise and respond to your
+ticket.
--------------
-*Copyright (c) 2019-2022, Arm Limited. All rights reserved.*
+*Copyright (c) 2019-2024, Arm Limited. All rights reserved.*
-.. _`issue tracker`: https://developer.trustedfirmware.org
+.. _`issue tracker`: https://github.com/TrustedFirmware-A/tf-a-tests/issues
.. _`TF-A-Tests development`: https://lists.trustedfirmware.org/mailman3/lists/tf-a-tests.lists.trustedfirmware.org/
.. _`summary of all the lists`: https://lists.trustedfirmware.org/mailman3/lists/
diff --git a/include/common/firmware_image_package.h b/include/common/firmware_image_package.h
index aba5b57..2a144ba 100644
--- a/include/common/firmware_image_package.h
+++ b/include/common/firmware_image_package.h
@@ -22,6 +22,8 @@
{{0x4f, 0x51, 0x1d, 0x11}, {0x2b, 0xe5}, {0x4e, 0x49}, 0xb4, 0xc5, {0x83, 0xc2, 0xf7, 0x15, 0x84, 0x0a} }
#define UUID_FIRMWARE_UPDATE_FWU_CERT \
{{0x71, 0x40, 0x8a, 0xb2}, {0x18, 0xd6}, {0x87, 0x4c}, 0x8b, 0x2e, {0xc6, 0xdc, 0xcd, 0x50, 0xf0, 0x96} }
+#define UUID_TRUSTED_KEY_CERT \
+ {{0x82, 0x7e, 0xe8, 0x90}, {0xf8, 0x60}, {0xe4, 0x11}, 0xa1, 0xb4, {0x77, 0x7a, 0x21, 0xb4, 0xf9, 0x4c} }
typedef struct fip_toc_header {
uint32_t name;
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 88c873c..6a0d286 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -828,8 +828,32 @@
#define EC_SERROR U(0x2f)
/* Data Fault Status code, not all error codes listed */
#define ISS_DFSC_MASK U(0x3f)
+#define DFSC_L0_ADR_SIZE_FAULT U(0)
+#define DFSC_L0_TRANS_FAULT U(4)
+#define DFSC_L1_TRANS_FAULT U(5)
+#define DFSC_L2_TRANS_FAULT U(6)
+#define DFSC_L3_TRANS_FAULT U(7)
+#define DFSC_NO_WALK_SEA U(0x10)
+#define DFSC_L0_SEA U(0x14)
+#define DFSC_L1_SEA U(0x15)
+#define DFSC_L2_SEA U(0x16)
+#define DFSC_L3_SEA U(0x17)
#define DFSC_EXT_DABORT U(0x10)
#define DFSC_GPF_DABORT U(0x28)
+
+/* Instr Fault Status code, not all error codes listed */
+#define ISS_IFSC_MASK U(0x3f)
+#define IFSC_L0_ADR_SIZE_FAULT U(0)
+#define IFSC_L0_TRANS_FAULT U(4)
+#define IFSC_L1_TRANS_FAULT U(5)
+#define IFSC_L2_TRANS_FAULT U(6)
+#define IFSC_L3_TRANS_FAULT U(7)
+#define IFSC_NO_WALK_SEA U(0x10)
+#define IFSC_L0_SEA U(0x24)
+#define IFSC_L1_SEA U(0x25)
+#define IFSC_L2_SEA U(0x26)
+#define IFSC_L3_SEA U(0x27)
+
/* ISS encoding an exception from HVC or SVC instruction execution */
#define ISS_HVC_SMC_IMM16_MASK U(0xffff)
diff --git a/include/lib/extensions/pauth.h b/include/lib/extensions/pauth.h
index c8d577f..8816e18 100644
--- a/include/lib/extensions/pauth.h
+++ b/include/lib/extensions/pauth.h
@@ -11,6 +11,11 @@
#include <stdint.h>
#ifdef __aarch64__
+/* Number of ARMv8.3-PAuth keys */
+#define NUM_KEYS 5U
+
+static const char * const key_name[] = {"IA", "IB", "DA", "DB", "GA"};
+
/* Initialize 128-bit ARMv8.3-PAuth key */
uint128_t init_apkey(void);
@@ -24,13 +29,13 @@
* Fill Pauth Keys and template with random values if keys werenot initialized earlier,
* Else Copy PAuth key registers to template.
*/
-void pauth_test_lib_fill_regs_and_template(void);
+void pauth_test_lib_fill_regs_and_template(uint128_t *pauth_keys_arr);
/* Read and Compare PAuth registers with provided template values. */
-bool pauth_test_lib_compare_template(void);
+bool pauth_test_lib_compare_template(uint128_t *pauth_keys_before, uint128_t *pauth_keys_after);
/* Read and Store PAuth registers in template. */
-void pauth_test_lib_read_keys(void);
+void pauth_test_lib_read_keys(uint128_t *pauth_keys_arr);
/* Test PAuth instructions. */
void pauth_test_lib_test_intrs(void);
diff --git a/include/lib/tftf_lib.h b/include/lib/tftf_lib.h
index 8eff7fc..36e2e0f 100644
--- a/include/lib/tftf_lib.h
+++ b/include/lib/tftf_lib.h
@@ -38,6 +38,23 @@
#define TEST_RESULT_IS_VALID(result) \
((result >= TEST_RESULT_MIN) && (result < TEST_RESULT_MAX))
+#define TEST_ASSERT(must_be_true) \
+ do { \
+ if (!(must_be_true)) { \
+ tftf_testcase_printf("Failed at %s:%d\n", __FILE__, __LINE__); \
+ return TEST_RESULT_FAIL;\
+ } \
+ } while (0)
+
+#define TEST_ASSERT_SKIP(must_be_true) \
+ do { \
+ if (!(must_be_true)) { \
+ tftf_testcase_printf("Failed at %s:%d\n", __FILE__, __LINE__); \
+ return TEST_RESULT_SKIPPED;\
+ } \
+ } while (0)
+
+
/*
* PSCI Function Wrappers
*
diff --git a/include/runtime_services/cactus_test_cmds.h b/include/runtime_services/cactus_test_cmds.h
index af5d066..3938c2f 100644
--- a/include/runtime_services/cactus_test_cmds.h
+++ b/include/runtime_services/cactus_test_cmds.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -201,10 +201,13 @@
static inline struct ffa_value cactus_mem_send_cmd(
ffa_id_t source, ffa_id_t dest, uint32_t mem_func,
ffa_memory_handle_t handle, ffa_memory_region_flags_t retrieve_flags,
- uint16_t word_to_write)
+ uint16_t word_to_write, bool expect_exception)
{
+ uint64_t _expect_exception = expect_exception ? (1ULL << 32) : 0;
+ uint64_t packed = (uint64_t)word_to_write | _expect_exception;
+
return cactus_send_cmd(source, dest, CACTUS_MEM_SEND_CMD, mem_func,
- handle, retrieve_flags, word_to_write);
+ handle, retrieve_flags, packed);
}
static inline ffa_memory_handle_t cactus_mem_send_get_handle(
@@ -221,7 +224,12 @@
static inline uint16_t cactus_mem_send_words_to_write(struct ffa_value ret)
{
- return (uint16_t)ret.arg7;
+ return (uint16_t)ret.arg7 & 0xFFFFU;
+}
+
+static inline bool cactus_mem_send_expect_exception(struct ffa_value ret)
+{
+ return (bool)(ret.arg7 >> 32);
}
/**
@@ -625,4 +633,25 @@
return (uint32_t)ret.arg4;
}
+/*
+ * Request SP to mimic handling a RAS error delegated by an EL3 logical secure
+ * partition.
+ *
+ * The command ID is the hex representation of the string 'rase' which
+ * denotes RAS Error.
+ */
+#define CACTUS_RAS_DELEGATE_CMD U(0x72617365)
+
+static inline struct ffa_value cactus_ras_delegate_send_cmd(
+ ffa_id_t source, ffa_id_t dest, uint64_t event_id)
+{
+ return cactus_send_cmd(source, dest, CACTUS_RAS_DELEGATE_CMD, event_id, 0, 0,
+ 0);
+}
+
+static inline uint64_t cactus_ras_get_event_id(struct ffa_value ret)
+{
+ return (uint64_t)ret.arg4;
+}
+
#endif
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index 3f760fa..0f19827 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -525,7 +525,11 @@
#define FFA_MEMORY_REGION_TRANSACTION_TYPE_DONATE ((0x3U) << 3)
/** The maximum number of recipients a memory region may be sent to. */
-#define MAX_MEM_SHARE_RECIPIENTS 1U
+#define MAX_MEM_SHARE_RECIPIENTS 2U
+
+struct ffa_memory_access_impdef {
+ uint64_t val[2];
+};
/**
* This corresponds to table "Endpoint memory access descriptor" of the FFA 1.0
@@ -538,6 +542,8 @@
* an `ffa_composite_memory_region` struct.
*/
uint32_t composite_memory_region_offset;
+ /* Space for implementation defined information */
+ struct ffa_memory_access_impdef impdef;
uint64_t reserved_0;
};
@@ -619,6 +625,43 @@
}
/**
+ * To maintain forwards compatability we can't make assumptions about the size
+ * of the endpoint memory access descriptor so provide a helper function
+ * to get a receiver from the receiver array using the memory access descriptor
+ * size field from the memory region descriptor struct.
+ * Returns NULL if we cannot return the receiver.
+ */
+static inline struct ffa_memory_access *ffa_memory_region_get_receiver(
+ struct ffa_memory_region *memory_region, uint32_t receiver_index)
+{
+ uint32_t memory_access_desc_size =
+ memory_region->memory_access_desc_size;
+
+ if (receiver_index >= memory_region->receiver_count) {
+ return NULL;
+ }
+
+ /*
+ * Memory access descriptor size cannot be greater than the size of
+ * the memory access descriptor defined by the current FF-A version.
+ */
+ if (memory_access_desc_size > sizeof(struct ffa_memory_access)) {
+ return NULL;
+ }
+
+ /* Check we cannot use receivers offset to cause overflow. */
+ if (memory_region->receivers_offset !=
+ sizeof(struct ffa_memory_region)) {
+ return NULL;
+ }
+
+ return (struct ffa_memory_access *)((uint8_t *)memory_region +
+ memory_region->receivers_offset +
+ (receiver_index *
+ memory_access_desc_size));
+}
+
+/**
* Gets the `ffa_composite_memory_region` for the given receiver from an
* `ffa_memory_region`, or NULL if it is not valid.
*/
@@ -751,10 +794,11 @@
const uint16_t start_index,
const uint16_t tag);
-struct ffa_memory_access ffa_memory_access_init_permissions(
+struct ffa_memory_access ffa_memory_access_init(
ffa_id_t receiver_id, enum ffa_data_access data_access,
enum ffa_instruction_access instruction_access,
- ffa_memory_receiver_flags_t flags);
+ ffa_memory_receiver_flags_t flags,
+ struct ffa_memory_access_impdef *impdef);
#endif /* __ASSEMBLY__ */
diff --git a/include/runtime_services/host_realm_managment/host_realm_rmi.h b/include/runtime_services/host_realm_managment/host_realm_rmi.h
index 4f81042..3159ad4 100644
--- a/include/runtime_services/host_realm_managment/host_realm_rmi.h
+++ b/include/runtime_services/host_realm_managment/host_realm_rmi.h
@@ -549,37 +549,64 @@
u_register_t host_rmi_realm_create(u_register_t rd, u_register_t params_ptr);
u_register_t host_rmi_realm_destroy(u_register_t rd);
u_register_t host_rmi_features(u_register_t index, u_register_t *features);
+u_register_t host_rmi_data_destroy(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t *data,
+ u_register_t *top);
+u_register_t host_rmi_rtt_readentry(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t level,
+ struct rtt_entry *rtt);
+u_register_t host_rmi_rtt_destroy(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t level,
+ u_register_t *rtt,
+ u_register_t *top);
+u_register_t host_rmi_rtt_init_ripas(u_register_t rd,
+ u_register_t start,
+ u_register_t end,
+ u_register_t *top);
+u_register_t host_rmi_create_rtt_levels(struct realm *realm,
+ u_register_t map_addr,
+ u_register_t level,
+ u_register_t max_level);
+u_register_t host_rmi_rtt_unmap_unprotected(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t level,
+ u_register_t *top);
+u_register_t host_rmi_rtt_set_ripas(u_register_t rd,
+ u_register_t rec,
+ u_register_t start,
+ u_register_t end,
+ u_register_t *top);
+u_register_t host_rmi_psci_complete(u_register_t calling_rec, u_register_t target_rec,
+ unsigned long status);
+void host_rmi_init_cmp_result(void);
+bool host_rmi_get_cmp_result(void);
/* Realm management */
u_register_t host_realm_create(struct realm *realm);
u_register_t host_realm_map_payload_image(struct realm *realm,
u_register_t realm_payload_adr);
u_register_t host_realm_map_ns_shared(struct realm *realm,
- u_register_t ns_shared_mem_adr,
- u_register_t ns_shared_mem_size);
+ u_register_t ns_shared_mem_adr,
+ u_register_t ns_shared_mem_size);
u_register_t host_realm_rec_create(struct realm *realm);
unsigned int host_realm_find_rec_by_mpidr(unsigned int mpidr, struct realm *realm);
u_register_t host_realm_activate(struct realm *realm);
u_register_t host_realm_destroy(struct realm *realm);
u_register_t host_realm_rec_enter(struct realm *realm,
- u_register_t *exit_reason,
- unsigned int *host_call_result,
- unsigned int rec_num);
+ u_register_t *exit_reason,
+ unsigned int *host_call_result,
+ unsigned int rec_num);
u_register_t host_realm_init_ipa_state(struct realm *realm, u_register_t level,
- u_register_t start, uint64_t end);
-u_register_t host_rmi_psci_complete(u_register_t calling_rec, u_register_t target_rec,
- unsigned long status);
-void host_rmi_init_cmp_result(void);
-bool host_rmi_get_cmp_result(void);
-u_register_t host_realm_map_protected_data(bool unknown,
- struct realm *realm,
- u_register_t target_pa,
- u_register_t map_size,
- u_register_t src_pa);
-u_register_t host_rmi_rtt_set_ripas(u_register_t rd,
- u_register_t rec,
- u_register_t start,
- u_register_t end,
- u_register_t *top);
+ u_register_t start, uint64_t end);
+u_register_t host_realm_delegate_map_protected_data(bool unknown,
+ struct realm *realm,
+ u_register_t target_pa,
+ u_register_t map_size,
+ u_register_t src_pa);
+u_register_t host_realm_map_unprotected(struct realm *realm, u_register_t ns_pa,
+ u_register_t map_size);
#endif /* HOST_REALM_RMI_H */
diff --git a/include/runtime_services/host_realm_managment/host_shared_data.h b/include/runtime_services/host_realm_managment/host_shared_data.h
index 8549512..632fdaa 100644
--- a/include/runtime_services/host_realm_managment/host_shared_data.h
+++ b/include/runtime_services/host_realm_managment/host_shared_data.h
@@ -47,6 +47,8 @@
REALM_MULTIPLE_REC_PSCI_DENIED_CMD,
REALM_MULTIPLE_REC_MULTIPLE_CPU_CMD,
REALM_GET_RSI_VERSION,
+ REALM_INSTR_FETCH_CMD,
+ REALM_DATA_ACCESS_CMD,
REALM_PMU_CYCLE,
REALM_PMU_EVENT,
REALM_PMU_PRESERVE,
@@ -65,6 +67,7 @@
REALM_PAUTH_SET_CMD,
REALM_PAUTH_CHECK_CMD,
REALM_PAUTH_FAULT,
+ REALM_DIT_CHECK_CMD,
REALM_SME_ID_REGISTERS,
REALM_SME_UNDEF_ABORT
};
@@ -101,6 +104,12 @@
unsigned int rec_num, uint8_t index, u_register_t val);
/*
+ * Get data shared from realm to Host
+ */
+u_register_t host_shared_data_get_realm_val(struct realm *realm_ptr,
+ unsigned int rec_num, uint8_t index);
+
+/*
* Set command to be send from Host to realm
*/
void host_shared_data_set_realm_cmd(struct realm *realm_ptr, uint8_t cmd,
diff --git a/lib/extensions/pauth/aarch64/pauth.c b/lib/extensions/pauth/aarch64/pauth.c
index 90e16d5..9608b97 100644
--- a/lib/extensions/pauth/aarch64/pauth.c
+++ b/lib/extensions/pauth/aarch64/pauth.c
@@ -11,14 +11,6 @@
#include <debug.h>
#include <pauth.h>
-/* Number of ARMv8.3-PAuth keys */
-#define NUM_KEYS 5U
-
-static const char * const key_name[] = {"IA", "IB", "DA", "DB", "GA"};
-
-static uint128_t pauth_keys_before[NUM_KEYS];
-static uint128_t pauth_keys_after[NUM_KEYS];
-
/*
* This is only a toy implementation to generate a seemingly random
* 128-bit key from sp, x30 and cntpct_el0 values.
@@ -49,11 +41,11 @@
return false;
}
-bool pauth_test_lib_compare_template(void)
+bool pauth_test_lib_compare_template(uint128_t *pauth_keys_before, uint128_t *pauth_keys_after)
{
bool result = true;
- pauth_test_lib_read_keys();
+ pauth_test_lib_read_keys(pauth_keys_after);
for (unsigned int i = 0U; i < NUM_KEYS; ++i) {
if (pauth_keys_before[i] != pauth_keys_after[i]) {
ERROR("AP%sKey_EL1 read 0x%llx:%llx "
@@ -73,7 +65,7 @@
* Program or read ARMv8.3-PAuth keys (if already enabled)
* and store them in <pauth_keys_before> buffer
*/
-void pauth_test_lib_fill_regs_and_template(void)
+void pauth_test_lib_fill_regs_and_template(uint128_t *pauth_keys_before)
{
uint128_t plat_key;
@@ -146,30 +138,30 @@
/*
* Read ARMv8.3-PAuth keys and store them in
- * <pauth_keys_after> buffer
+ * <pauth_keys_arr> buffer
*/
-void pauth_test_lib_read_keys(void)
+void pauth_test_lib_read_keys(uint128_t *pauth_keys_arr)
{
- (void)memset(pauth_keys_after, 0, NUM_KEYS * sizeof(uint128_t));
+ (void)memset(pauth_keys_arr, 0, NUM_KEYS * sizeof(uint128_t));
/* Read APIAKey_EL1 */
- pauth_keys_after[0] = read_apiakeylo_el1() |
+ pauth_keys_arr[0] = read_apiakeylo_el1() |
((uint128_t)(read_apiakeyhi_el1()) << 64U);
/* Read APIBKey_EL1 */
- pauth_keys_after[1] = read_apibkeylo_el1() |
+ pauth_keys_arr[1] = read_apibkeylo_el1() |
((uint128_t)(read_apibkeyhi_el1()) << 64U);
/* Read APDAKey_EL1 */
- pauth_keys_after[2] = read_apdakeylo_el1() |
+ pauth_keys_arr[2] = read_apdakeylo_el1() |
((uint128_t)(read_apdakeyhi_el1()) << 64U);
/* Read APDBKey_EL1 */
- pauth_keys_after[3] = read_apdbkeylo_el1() |
+ pauth_keys_arr[3] = read_apdbkeylo_el1() |
((uint128_t)(read_apdbkeyhi_el1()) << 64U);
/* Read APGAKey_EL1 */
- pauth_keys_after[4] = read_apgakeylo_el1() |
+ pauth_keys_arr[4] = read_apgakeylo_el1() |
((uint128_t)(read_apgakeyhi_el1()) << 64U);
}
diff --git a/plat/arm/fvp/include/platform_def.h b/plat/arm/fvp/include/platform_def.h
index b8871c4..60c33e9 100644
--- a/plat/arm/fvp/include/platform_def.h
+++ b/plat/arm/fvp/include/platform_def.h
@@ -89,6 +89,12 @@
#define SECURE_MEMORY_ACCESS_ADDR U(0xFD000000)
/*******************************************************************************
+ * Base address and size for the FIP.
+ ******************************************************************************/
+#define PLAT_ARM_FIP_BASE (FLASH_BASE)
+#define PLAT_ARM_FIP_SIZE (0x100000)
+
+/*******************************************************************************
* Base address and size for the FIP that contains FWU images.
******************************************************************************/
#define PLAT_ARM_FWU_FIP_BASE (FLASH_BASE + 0x400000)
@@ -253,11 +259,11 @@
#define MAX_MMAP_REGIONS 50
#else
#if IMAGE_CACTUS
-#define MAX_XLAT_TABLES 9
+#define MAX_XLAT_TABLES 12
#else
#define MAX_XLAT_TABLES 5
#endif
-#define MAX_MMAP_REGIONS 16
+#define MAX_MMAP_REGIONS 20
#endif
/*******************************************************************************
diff --git a/plat/arm/tc/include/platform_def.h b/plat/arm/tc/include/platform_def.h
index 1f0c28d..82fa6c2 100644
--- a/plat/arm/tc/include/platform_def.h
+++ b/plat/arm/tc/include/platform_def.h
@@ -80,7 +80,7 @@
#define TC_GICC_BASE 0x2C000000
/* SoC's PL011 UART0 related constants */
-#define PL011_UART0_BASE 0x7FF70000
+#define PL011_UART0_BASE 0x2A400000
#define PL011_UART0_CLK_IN_HZ 7372800
/* SoC's PL011 UART1 related constants */
diff --git a/plat/xilinx/versal/tests_to_skip.txt b/plat/xilinx/versal/tests_to_skip.txt
index fddf331..b430058 100644
--- a/plat/xilinx/versal/tests_to_skip.txt
+++ b/plat/xilinx/versal/tests_to_skip.txt
@@ -39,8 +39,14 @@
PSCI CPU ON OFF Stress Tests/Repeated hotplug of all cores to stress test CPU_ON and CPU_OFF
PSCI CPU ON OFF Stress Tests/Random hotplug cores in a large iteration to stress boot path code
- #TESTS: TSP
- IRQ support in TSP/Resume preempted STD SMC after PSCI CPU OFF/ON cycle
- IRQ support in TSP/Resume preempted STD SMC after PSCI SYSTEM SUSPEND
- IRQ support in TSP/Resume preempted STD SMC
- TSP PSTATE test
+#TESTS: TSP
+IRQ support in TSP/Resume preempted STD SMC after PSCI CPU OFF/ON cycle
+IRQ support in TSP/Resume preempted STD SMC after PSCI SYSTEM SUSPEND
+IRQ support in TSP/Resume preempted STD SMC
+TSP PSTATE test
+
+#TESTS: runtime-instrumentation
+Runtime Instrumentation Validation
+
+#TESTS: debugfs
+DebugFS
diff --git a/plat/xilinx/versal_net/aarch64/plat_helpers.S b/plat/xilinx/versal_net/aarch64/plat_helpers.S
index 77012ef..698a8bc 100644
--- a/plat/xilinx/versal_net/aarch64/plat_helpers.S
+++ b/plat/xilinx/versal_net/aarch64/plat_helpers.S
@@ -22,14 +22,36 @@
* ---------------------------------------------------------------------
*/
func platform_get_core_pos
+ /*
+ * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it
+ * look as if in a multi-threaded implementation.
+ */
+ tst x0, #MPIDR_MT_MASK
+ lsl x3, x0, #MPIDR_AFFINITY_BITS
+ csel x3, x3, x0, eq
+
/* x1 = core-id inside cluster */
- ubfx x1, x0, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
/* x2 = cluster-id */
- ubfx x2, x0, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+ ubfx x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+
+ /* check if cpu_id valid */
+ cmp x1, #PLATFORM_CORE_COUNT_PER_CLUSTER
+ b.hi error
+
+ /* check if cluster valid */
+ cmp x2, #PLATFORM_CLUSTER_COUNT
+ b.hi error
/* core-position = cluster-id * cores per cluster + core-id */
- mov x3, #PLATFORM_CORE_COUNT_PER_CLUSTER
- madd x0, x2, x3, x1
+ mov x3, #PLATFORM_CORE_COUNT_PER_CLUSTER
+ madd x1, x2, x3, x1
+ mov x3, #PLATFORM_MAX_PE_PER_CPU
+ madd x0, x1, x3, x0
+ ret
+error:
+ mov x0, #-1
ret
endfunc platform_get_core_pos
diff --git a/plat/xilinx/versal_net/include/platform_def.h b/plat/xilinx/versal_net/include/platform_def.h
index c357c96..8431ca6 100644
--- a/plat/xilinx/versal_net/include/platform_def.h
+++ b/plat/xilinx/versal_net/include/platform_def.h
@@ -18,6 +18,10 @@
#define PLATFORM_CLUSTER_COUNT U(4)
#define PLATFORM_CORE_COUNT_PER_CLUSTER U(4)
+#define PLATFORM_MAX_PE_PER_CPU U(1)
+/* Because of make_mpid from include/lib/tftf_lib.h */
+#define PLAT_MAX_PE_PER_CPU PLATFORM_MAX_PE_PER_CPU
+
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
PLATFORM_CORE_COUNT_PER_CLUSTER)
#define PLATFORM_NUM_AFFS (PLATFORM_CORE_COUNT + \
diff --git a/plat/xilinx/versal_net/tests_to_skip.txt b/plat/xilinx/versal_net/tests_to_skip.txt
index a45426f..46bc1a3 100644
--- a/plat/xilinx/versal_net/tests_to_skip.txt
+++ b/plat/xilinx/versal_net/tests_to_skip.txt
@@ -62,8 +62,8 @@
#TESTS: el3-power-state
EL3 power state parser validation
-#TESTS: TSP
-IRQ support in TSP/Resume preempted STD SMC
-IRQ support in TSP/Resume preempted STD SMC from other CPUs
-IRQ support in TSP/Resume preempted STD SMC after PSCI CPU OFF/ON cycle
-IRQ support in TSP/Resume preempted STD SMC after PSCI SYSTEM SUSPEND
+#TESTS: runtime-instrumentation
+Runtime Instrumentation Validation
+
+#TESTS: debugfs
+DebugFS
diff --git a/realm/realm_pauth.c b/realm/realm_pauth.c
index cf3bec3..31b26e7 100644
--- a/realm/realm_pauth.c
+++ b/realm/realm_pauth.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -7,12 +7,15 @@
#include <stdio.h>
#include <arch_features.h>
+#include <assert.h>
#include <debug.h>
#include <pauth.h>
#include <realm_rsi.h>
#include <sync.h>
-static volatile bool set_cmd_done;
+static volatile bool set_cmd_done[MAX_REC_COUNT];
+static uint128_t pauth_keys_before[MAX_REC_COUNT][NUM_KEYS];
+static uint128_t pauth_keys_after[MAX_REC_COUNT][NUM_KEYS];
static bool exception_handler(void)
{
@@ -68,19 +71,28 @@
*/
bool test_realm_pauth_set_cmd(void)
{
+ unsigned int rec = read_mpidr_el1() & MPID_MASK;
+
if (!is_armv8_3_pauth_present()) {
return false;
}
+ assert(rec < MAX_REC_COUNT);
pauth_test_lib_test_intrs();
- pauth_test_lib_fill_regs_and_template();
- set_cmd_done = true;
+ pauth_test_lib_fill_regs_and_template(pauth_keys_before[rec]);
+ set_cmd_done[rec] = true;
return true;
}
bool test_realm_pauth_check_cmd(void)
{
- if (!is_armv8_3_pauth_present() || !set_cmd_done) {
+ unsigned int rec = read_mpidr_el1() & MPID_MASK;
+ bool ret;
+
+ assert(rec < MAX_REC_COUNT);
+ if (!is_armv8_3_pauth_present() || !set_cmd_done[rec]) {
return false;
}
- return pauth_test_lib_compare_template();
+ ret = pauth_test_lib_compare_template(pauth_keys_before[rec], pauth_keys_after[rec]);
+ realm_printf("Pauth key comparison ret=%d\n", ret);
+ return ret;
}
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index ddaa3cb..ce25f43 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -16,6 +16,7 @@
#include "realm_def.h"
#include <realm_rsi.h>
#include <realm_tests.h>
+#include <sync.h>
#include <tftf_lib.h>
static fpu_state_t rl_fpu_state_write;
@@ -129,6 +130,72 @@
return false;
}
+bool test_realm_dit_check_cmd(void)
+{
+ if (is_armv8_4_dit_present()) {
+ write_dit(DIT_BIT);
+ realm_printf("Testing DIT=0x%lx\n", read_dit());
+ /* Test if DIT is preserved after HOST_CALL */
+ if (read_dit() == DIT_BIT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+static bool test_realm_instr_fetch_cmd(void)
+{
+ u_register_t base;
+ void (*func_ptr)(void);
+ rsi_ripas_type ripas;
+
+ base = realm_shared_data_get_my_host_val(HOST_ARG1_INDEX);
+ rsi_ipa_state_get(base, &ripas);
+ realm_printf("Initial ripas=0x%lx\n", ripas);
+ /* causes instruction abort */
+ realm_printf("Generate Instruction Abort\n");
+ func_ptr = (void (*)(void))base;
+ func_ptr();
+ /* should not return */
+ return false;
+}
+
+static bool test_realm_data_access_cmd(void)
+{
+ u_register_t base;
+ rsi_ripas_type ripas;
+
+ base = realm_shared_data_get_my_host_val(HOST_ARG1_INDEX);
+ rsi_ipa_state_get(base, &ripas);
+ realm_printf("Initial ripas=0x%lx\n", ripas);
+ /* causes data abort */
+ realm_printf("Generate Data Abort\n");
+ *((volatile uint64_t *)base);
+ /* should not return */
+ return false;
+}
+
+static bool realm_exception_handler(void)
+{
+ u_register_t base, far, esr;
+
+ base = realm_shared_data_get_my_host_val(HOST_ARG1_INDEX);
+ far = read_far_el1();
+ esr = read_esr_el1();
+
+ if (far == base) {
+ /* return ESR to Host */
+ realm_shared_data_set_my_realm_val(HOST_ARG2_INDEX, esr);
+ rsi_exit_to_host(HOST_CALL_EXIT_SUCCESS_CMD);
+ }
+ realm_printf("Realm Abort fail incorrect FAR=0x%lx ESR+0x%lx\n", far, esr);
+ rsi_exit_to_host(HOST_CALL_EXIT_FAILED_CMD);
+
+ /* Should not return. */
+ return false;
+}
+
/*
* This is the entry function for Realm payload, it first requests the shared buffer
* IPA address from Host using HOST_CALL/RSI, it reads the command to be executed,
@@ -141,6 +208,7 @@
{
bool test_succeed = false;
+ register_custom_sync_exception_handler(realm_exception_handler);
realm_set_shared_structure((host_shared_data_t *)rsi_get_ns_buffer());
if (realm_get_my_shared_structure() != NULL) {
uint8_t cmd = realm_shared_data_get_my_realm_cmd();
@@ -156,9 +224,16 @@
break;
case REALM_MULTIPLE_REC_PSCI_DENIED_CMD:
test_succeed = test_realm_multiple_rec_psci_denied_cmd();
+ break;
case REALM_MULTIPLE_REC_MULTIPLE_CPU_CMD:
test_succeed = test_realm_multiple_rec_multiple_cpu_cmd();
break;
+ case REALM_INSTR_FETCH_CMD:
+ test_succeed = test_realm_instr_fetch_cmd();
+ break;
+ case REALM_DATA_ACCESS_CMD:
+ test_succeed = test_realm_data_access_cmd();
+ break;
case REALM_PAUTH_SET_CMD:
test_succeed = test_realm_pauth_set_cmd();
break;
@@ -168,6 +243,9 @@
case REALM_PAUTH_FAULT:
test_succeed = test_realm_pauth_fault();
break;
+ case REALM_DIT_CHECK_CMD:
+ test_succeed = test_realm_dit_check_cmd();
+ break;
case REALM_GET_RSI_VERSION:
test_succeed = realm_get_rsi_version();
break;
diff --git a/smc_fuzz/dts/sdei.dts b/smc_fuzz/dts/sdei.dts
index 2418916..a8199e1 100644
--- a/smc_fuzz/dts/sdei.dts
+++ b/smc_fuzz/dts/sdei.dts
@@ -15,31 +15,31 @@
bias = <30>;
sdei_version {
bias = <30>;
- functionname = "sdei_version";
+ functionname = "sdei_version_funcid";
};
sdei_pe_unmask {
bias = <30>;
- functionname = "sdei_pe_unmask";
+ functionname = "sdei_pe_unmask_funcid";
};
sdei_pe_mask {
bias = <30>;
- functionname = "sdei_pe_mask";
+ functionname = "sdei_pe_mask_funcid";
};
sdei_event_status {
bias = <30>;
- functionname = "sdei_event_status";
+ functionname = "sdei_event_status_funcid";
};
sdei_event_signal {
bias = <30>;
- functionname = "sdei_event_signal";
+ functionname = "sdei_event_signal_funcid";
};
sdei_private_reset {
bias = <30>;
- functionname = "sdei_private_reset";
+ functionname = "sdei_private_reset_funcid";
};
sdei_shared_reset {
bias = <30>;
- functionname = "sdei_shared_reset";
+ functionname = "sdei_shared_reset_funcid";
};
};
diff --git a/smc_fuzz/dts/top.dts b/smc_fuzz/dts/top.dts
index bda77d6..4d37c7e 100644
--- a/smc_fuzz/dts/top.dts
+++ b/smc_fuzz/dts/top.dts
@@ -20,50 +20,50 @@
bias = <30>;
sdei_version {
bias = <30>;
- functionname = "sdei_version";
+ functionname = "sdei_version_funcid";
};
sdei_pe_unmask {
bias = <30>;
- functionname = "sdei_pe_unmask";
+ functionname = "sdei_pe_unmask_funcid";
};
sdei_pe_mask {
bias = <30>;
- functionname = "sdei_pe_mask";
+ functionname = "sdei_pe_mask_funcid";
};
sdei_event_status {
bias = <30>;
- functionname = "sdei_event_status";
+ functionname = "sdei_event_status_funcid";
};
sdei_event_signal {
bias = <30>;
- functionname = "sdei_event_signal";
+ functionname = "sdei_event_signal_funcid";
};
sdei_private_reset {
bias = <30>;
- functionname = "sdei_private_reset";
+ functionname = "sdei_private_reset_funcid";
};
sdei_shared_reset {
bias = <30>;
- functionname = "sdei_shared_reset";
+ functionname = "sdei_shared_reset_funcid";
};
};
tsp {
bias = <30>;
tsp_add_op {
bias = <30>;
- functionname = "tsp_add_op";
+ functionname = "tsp_add_op_funcid";
};
tsp_sub_op {
bias = <30>;
- functionname = "tsp_sub_op";
+ functionname = "tsp_sub_op_funcid";
};
tsp_mul_op {
bias = <30>;
- functionname = "tsp_mul_op";
+ functionname = "tsp_mul_op_funcid";
};
tsp_div_op {
bias = <30>;
- functionname = "tsp_div_op";
+ functionname = "tsp_div_op_funcid";
};
};
};
diff --git a/smc_fuzz/include/fifo3d.h b/smc_fuzz/include/fifo3d.h
index c04567c..95ebb4a 100644
--- a/smc_fuzz/include/fifo3d.h
+++ b/smc_fuzz/include/fifo3d.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -18,22 +18,28 @@
char ***nnfifo;
char ***fnamefifo;
int **biasfifo;
+ int **fidfifo;
int col;
int curr_col;
int *row;
};
/*
- * Push function name string into raw data structure
+ * Push function name string into the raw data structure
*/
void push_3dfifo_fname(struct fifo3d *f3d, char *fname);
/*
- * Push bias value into raw data structure
+ * Push bias value into the raw data structure
*/
void push_3dfifo_bias(struct fifo3d *f3d, int bias);
/*
+ * Push id for function value into the raw data structure
+ */
+void push_3dfifo_fid(struct fifo3d *f3d, int id);
+
+/*
* Create new column and/or row for raw data structure for newly
* found node from device tree
*/
diff --git a/smc_fuzz/include/nfifo.h b/smc_fuzz/include/nfifo.h
new file mode 100644
index 0000000..cef07da
--- /dev/null
+++ b/smc_fuzz/include/nfifo.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#ifndef NFIFO_H
+#define NFIFO_H
+
+#define CMP_SUCCESS 0
+#define NFIFO_Q_THRESHOLD 10
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "smcmalloc.h"
+
+struct nfifo {
+ char **lnme;
+ int nent;
+ int thent;
+};
+
+void nfifoinit(struct nfifo *nf, struct memmod *mmod);
+void pushnme(char *nme, struct nfifo *nf, struct memmod *mmod);
+char *readnme(int ent, struct nfifo *nf, struct memmod *mmod);
+int searchnme(char *nme, struct nfifo *nf, struct memmod *mmod);
+void printent(struct nfifo *nf);
+
+#endif /* NFIFO_H */
diff --git a/smc_fuzz/include/sdei_fuzz_helper.h b/smc_fuzz/include/sdei_fuzz_helper.h
index 71d462d..cf4ddd1 100644
--- a/smc_fuzz/include/sdei_fuzz_helper.h
+++ b/smc_fuzz/include/sdei_fuzz_helper.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,6 +11,29 @@
#include <tftf_lib.h>
#include <timer.h>
-void tftf_test_sdei_noarg(int64_t (*sdei_func)(void), char *);
+#ifndef sdei_version_funcid
+#define sdei_version_funcid 0
+#endif
+#ifndef sdei_pe_unmask_funcid
+#define sdei_pe_unmask_funcid 0
+#endif
+#ifndef sdei_pe_mask_funcid
+#define sdei_pe_mask_funcid 0
+#endif
+#ifndef sdei_event_status_funcid
+#define sdei_event_status_funcid 0
+#endif
+#ifndef sdei_event_signal_funcid
+#define sdei_event_signal_funcid 0
+#endif
+#ifndef sdei_private_reset_funcid
+#define sdei_private_reset_funcid 0
+#endif
+#ifndef sdei_shared_reset_funcid
+#define sdei_shared_reset_funcid 0
+#endif
+
+
+void tftf_test_sdei_noarg(int64_t (*sdei_func)(void), char *funcstr);
void tftf_test_sdei_singlearg(int64_t (*sdei_func)(uint64_t), char *funcstr);
-void run_sdei_fuzz(char *);
+void run_sdei_fuzz(int funcid);
diff --git a/smc_fuzz/include/smcmalloc.h b/smc_fuzz/include/smcmalloc.h
index 129e07c..fe134bf 100644
--- a/smc_fuzz/include/smcmalloc.h
+++ b/smc_fuzz/include/smcmalloc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,7 +11,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "fifo3d.h"
#define TOTALMEMORYSIZE (0x10000)
#define BLKSPACEDIV (4)
diff --git a/smc_fuzz/include/tsp_fuzz_helper.h b/smc_fuzz/include/tsp_fuzz_helper.h
index 444d54b..019ee68 100644
--- a/smc_fuzz/include/tsp_fuzz_helper.h
+++ b/smc_fuzz/include/tsp_fuzz_helper.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,5 +11,18 @@
#include <tftf_lib.h>
#include <timer.h>
-void tftf_test_tsp_smc(uint64_t tsp_id, char *);
-void run_tsp_fuzz(char *);
+#ifndef tsp_add_op_funcid
+#define tsp_add_op_funcid 0
+#endif
+#ifndef tsp_sub_op_funcid
+#define tsp_sub_op_funcid 0
+#endif
+#ifndef tsp_mul_op_funcid
+#define tsp_mul_op_funcid 0
+#endif
+#ifndef tsp_div_op_funcid
+#define tsp_div_op_funcid 0
+#endif
+
+void tftf_test_tsp_smc(uint64_t tsp_id, char *funcstr);
+void run_tsp_fuzz(int funcid);
diff --git a/smc_fuzz/src/fifo3d.c b/smc_fuzz/src/fifo3d.c
index 119b26c..0b99907 100644
--- a/smc_fuzz/src/fifo3d.c
+++ b/smc_fuzz/src/fifo3d.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -27,7 +27,7 @@
#endif
/*
- * Push function name string into raw data structure
+ * Push function name string into the data structure from device tree file
*/
void push_3dfifo_fname(struct fifo3d *f3d, char *fname)
{
@@ -36,7 +36,7 @@
}
/*
- * Push bias value into raw data structure
+ * Push bias value into data structure from device tree file
*/
void push_3dfifo_bias(struct fifo3d *f3d, int bias)
{
@@ -44,14 +44,36 @@
}
/*
+ * Push function id value into data structure from device tree file
+ */
+void push_3dfifo_fid(struct fifo3d *f3d, int id)
+{
+ f3d->fidfifo[f3d->col - 1][f3d->row[f3d->col - 1] - 1] = id;
+}
+
+
+/*
* Create new column and/or row for raw data structure for newly
- * found node from device tree
+ * found node from device tree. The fifo has four elements that reflect
+ * values obtained from the device tree for each node read. This preserves
+ * the hierarchy found in that file so it can be utilized in construction of
+ * the smc nodes structure for final use in randomly calling the SMC functions.
+ * This is essentially a bias tree in final form.
*/
void push_3dfifo_col(struct fifo3d *f3d, char *entry, struct memmod *mmod)
{
+
+/*
+ * four elements required:
+ * 1. node name as a string
+ * 2. function name as a string
+ * 3. bias value as an integer
+ * 4. id value as an integer
+ */
char ***tnnfifo;
char ***tfnamefifo;
int **tbiasfifo;
+ int **tfidfifo;
if (f3d->col == f3d->curr_col) {
f3d->col++;
@@ -76,15 +98,17 @@
f3d->row[f3d->col - 1] = 1;
/*
- * Create new raw data memory
+ * Start node creation for reading of device tree file
*/
tnnfifo = GENMALLOC(f3d->col * sizeof(char **));
tfnamefifo = GENMALLOC(f3d->col * sizeof(char **));
tbiasfifo = GENMALLOC((f3d->col) * sizeof(int *));
+ tfidfifo = GENMALLOC((f3d->col) * sizeof(int *));
for (unsigned int i = 0U; (int)i < f3d->col; i++) {
tnnfifo[i] = GENMALLOC(f3d->row[i] * sizeof(char *));
tfnamefifo[i] = GENMALLOC(f3d->row[i] * sizeof(char *));
tbiasfifo[i] = GENMALLOC((f3d->row[i]) * sizeof(int));
+ tfidfifo[i] = GENMALLOC((f3d->row[i]) * sizeof(int));
for (unsigned int j = 0U; (int)j < f3d->row[i]; j++) {
tnnfifo[i][j] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
tfnamefifo[i][j] =
@@ -95,6 +119,7 @@
strlcpy(tfnamefifo[i][j],
f3d->fnamefifo[i][j], MAX_NAME_CHARS);
tbiasfifo[i][j] = f3d->biasfifo[i][j];
+ tfidfifo[i][j] = f3d->fidfifo[i][j];
}
}
}
@@ -107,6 +132,7 @@
strlcpy(tfnamefifo[f3d->col - 1][f3d->row[f3d->col - 1] - 1],
"none", MAX_NAME_CHARS);
tbiasfifo[f3d->col - 1][f3d->row[f3d->col - 1] - 1] = 0;
+ tfidfifo[f3d->col - 1][f3d->row[f3d->col - 1] - 1] = 0;
/*
* Free the old raw data structres
@@ -119,11 +145,13 @@
GENFREE(f3d->nnfifo[i]);
GENFREE(f3d->fnamefifo[i]);
GENFREE(f3d->biasfifo[i]);
+ GENFREE(f3d->fidfifo[i]);
}
if (f3d->col > 1) {
GENFREE(f3d->nnfifo);
GENFREE(f3d->fnamefifo);
GENFREE(f3d->biasfifo);
+ GENFREE(f3d->fidfifo);
}
/*
@@ -132,6 +160,7 @@
f3d->nnfifo = tnnfifo;
f3d->fnamefifo = tfnamefifo;
f3d->biasfifo = tbiasfifo;
+ f3d->fidfifo = tfidfifo;
}
if (f3d->col != f3d->curr_col) {
/*
@@ -141,15 +170,17 @@
f3d->row[f3d->col - 1]++;
/*
- * Create new raw data memory
+ * Create new node form device tree file
*/
tnnfifo = GENMALLOC(f3d->col * sizeof(char **));
tfnamefifo = GENMALLOC(f3d->col * sizeof(char **));
tbiasfifo = GENMALLOC((f3d->col) * sizeof(int *));
+ tfidfifo = GENMALLOC((f3d->col) * sizeof(int *));
for (unsigned int i = 0U; (int)i < f3d->col; i++) {
tnnfifo[i] = GENMALLOC(f3d->row[i] * sizeof(char *));
tfnamefifo[i] = GENMALLOC(f3d->row[i] * sizeof(char *));
tbiasfifo[i] = GENMALLOC((f3d->row[i]) * sizeof(int));
+ tfidfifo[i] = GENMALLOC((f3d->row[i]) * sizeof(int));
for (unsigned int j = 0U; (int)j < f3d->row[i]; j++) {
tnnfifo[i][j] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
tfnamefifo[i][j] =
@@ -160,6 +191,7 @@
strlcpy(tfnamefifo[i][j],
f3d->fnamefifo[i][j], MAX_NAME_CHARS);
tbiasfifo[i][j] = f3d->biasfifo[i][j];
+ tfidfifo[i][j] = f3d->fidfifo[i][j];
}
}
}
@@ -172,6 +204,7 @@
strlcpy(tfnamefifo[f3d->col - 1][f3d->row[f3d->col - 1] - 1],
"none", MAX_NAME_CHARS);
tbiasfifo[f3d->col - 1][f3d->row[f3d->col - 1] - 1] = 0;
+ tfidfifo[f3d->col - 1][f3d->row[f3d->col - 1] - 1] = 0;
/*
* Free the old raw data structres
@@ -187,10 +220,12 @@
GENFREE(f3d->nnfifo[i]);
GENFREE(f3d->fnamefifo[i]);
GENFREE(f3d->biasfifo[i]);
+ GENFREE(f3d->fidfifo[i]);
}
GENFREE(f3d->nnfifo);
GENFREE(f3d->fnamefifo);
GENFREE(f3d->biasfifo);
+ GENFREE(f3d->fidfifo);
/*
* Point to new data
@@ -198,5 +233,6 @@
f3d->nnfifo = tnnfifo;
f3d->fnamefifo = tfnamefifo;
f3d->biasfifo = tbiasfifo;
+ f3d->fidfifo = tfidfifo;
}
}
diff --git a/smc_fuzz/src/nfifo.c b/smc_fuzz/src/nfifo.c
new file mode 100644
index 0000000..b4a021c
--- /dev/null
+++ b/smc_fuzz/src/nfifo.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * FIFO for matching strings to integers
+ */
+
+#include "nfifo.h"
+
+#ifdef SMC_FUZZ_TMALLOC
+#define GENMALLOC(x) malloc((x))
+#define GENFREE(x) free((x))
+#else
+#define GENMALLOC(x) smcmalloc((x), mmod)
+#define GENFREE(x) smcfree((x), mmod)
+#endif
+
+/*
+ * Initialization of FIFO
+ */
+void nfifoinit(struct nfifo *nf, struct memmod *mmod)
+{
+ nf->nent = 0;
+ nf->thent = NFIFO_Q_THRESHOLD;
+ nf->lnme = GENMALLOC(nf->thent * sizeof(char *));
+}
+
+/*
+ * push string to FIFO for automatic numerical assignment
+ */
+void pushnme(char *nme, struct nfifo *nf, struct memmod *mmod)
+{
+ char **tnme;
+
+ if (searchnme(nme, nf, mmod) == -1) {
+ if (nf->nent >= nf->thent) {
+ nf->thent += NFIFO_Q_THRESHOLD;
+ tnme = GENMALLOC(nf->thent * sizeof(char *));
+ for (unsigned int x = 0; x < nf->nent; x++) {
+ tnme[x] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
+ strlcpy(tnme[x], nf->lnme[x], MAX_NAME_CHARS);
+ }
+ tnme[nf->nent] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
+ strlcpy(tnme[nf->nent], nme, MAX_NAME_CHARS);
+ for (unsigned int x = 0; x < nf->nent; x++) {
+ GENFREE(nf->lnme[x]);
+ }
+ GENFREE(nf->lnme);
+ nf->lnme = tnme;
+ } else {
+ nf->lnme[nf->nent] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
+ strlcpy(nf->lnme[nf->nent], nme, MAX_NAME_CHARS);
+ }
+ nf->nent++;
+ }
+}
+
+/*
+ * Find name associated with numercal designation
+ */
+char *readnme(int ent, struct nfifo *nf, struct memmod *mmod)
+{
+ return nf->lnme[ent];
+}
+
+/*
+ * Search FIFO for integer given an input string returns -1
+ * if not found
+ */
+int searchnme(char *nme, struct nfifo *nf, struct memmod *mmod)
+{
+ for (unsigned int x = 0; x < nf->nent; x++) {
+ if (strcmp(nf->lnme[x], nme) == CMP_SUCCESS) {
+ return (x + 1);
+ }
+ }
+ return -1;
+}
+
+/*
+ * Print of all elements of FIFO string and associated integer
+ */
+void printent(struct nfifo *nf)
+{
+ for (unsigned int x = 0; x < nf->nent; x++) {
+ printf("nfifo entry %s has value %d\n", nf->lnme[x], x);
+ }
+}
diff --git a/smc_fuzz/src/randsmcmod.c b/smc_fuzz/src/randsmcmod.c
index 7bedf81..a86feb6 100644
--- a/smc_fuzz/src/randsmcmod.c
+++ b/smc_fuzz/src/randsmcmod.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,6 +9,7 @@
#include <drivers/arm/private_timer.h>
#include <events.h>
#include "fifo3d.h"
+#include "nfifo.h"
#include <libfdt.h>
#include <plat_topology.h>
@@ -16,7 +17,7 @@
#include <tftf_lib.h>
extern char _binary___dtb_start[];
-extern void runtestfunction(char *funcstr);
+extern void runtestfunction(int funcid);
struct memmod tmod __aligned(65536) __section("smcfuzz");
static int cntndarray;
@@ -119,13 +120,14 @@
int *biases; // Biases of the individual nodes
int *biasarray; // Array of biases across all nodes
char **snames; // String that is unique to the SMC call called in test
+ int *snameid; // ID that is unique to the SMC call called in test
struct rand_smc_node *treenodes; // Selection of nodes that are farther down in the tree
- // that reference further rand_smc_node objects
+ // that reference further rand_smc_node objects
int *norcall; // Specifies whether a particular node is a leaf node or tree node
- int entries; // Number of nodes in object
- int biasent; // Number that gives the total number of entries in biasarray
- // based on all biases of the nodes
- char **nname; // Array of node names
+ int entries; // Number of nodes in object
+ int biasent; // Number that gives the total number of entries in biasarray
+ // based on all biases of the nodes
+ char **nname; // Array of node names
};
@@ -156,6 +158,9 @@
int cntndarray;
struct rand_smc_node nrnode;
struct rand_smc_node *tndarray;
+ struct nfifo nf;
+
+ nfifoinit(&nf, mmod);
f3d.col = 0;
f3d.curr_col = 0;
@@ -166,9 +171,6 @@
fhdptr = (struct fdt_header *)_binary___dtb_start;
- if (fdt_check_header((void *)fhdptr) != 0) {
- printf("ERROR, not device tree compliant\n");
- }
fhd = *fhdptr;
cntndarray = 0;
nrnode.entries = 0;
@@ -244,6 +246,8 @@
if (strcmp(cset, "functionname") == 0) {
pullstringdt(&dtb, dtb_beg, 0, cset);
push_3dfifo_fname(&f3d, cset);
+ pushnme(cset, &nf, mmod);
+ push_3dfifo_fid(&f3d, searchnme(cset, &nf, mmod));
leafnode = 1;
if (bias_count == 0U) {
bintnode = 1U;
@@ -279,6 +283,7 @@
for (unsigned int j = 0U; (int)j < cntndarray; j++) {
tndarray[j].biases = GENMALLOC(ndarray[j].entries * sizeof(int));
tndarray[j].snames = GENMALLOC(ndarray[j].entries * sizeof(char *));
+ tndarray[j].snameid = GENMALLOC(ndarray[j].entries * sizeof(int));
tndarray[j].norcall = GENMALLOC(ndarray[j].entries * sizeof(int));
tndarray[j].nname = GENMALLOC(ndarray[j].entries * sizeof(char *));
tndarray[j].treenodes = GENMALLOC(ndarray[j].entries * sizeof(struct rand_smc_node));
@@ -286,6 +291,7 @@
for (unsigned int i = 0U; (int)i < ndarray[j].entries; i++) {
tndarray[j].snames[i] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
strlcpy(tndarray[j].snames[i], ndarray[j].snames[i], MAX_NAME_CHARS);
+ tndarray[j].snameid[i] = ndarray[j].snameid[i];
tndarray[j].nname[i] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
strlcpy(tndarray[j].nname[i], ndarray[j].nname[i], MAX_NAME_CHARS);
tndarray[j].biases[i] = ndarray[j].biases[i];
@@ -303,6 +309,7 @@
}
tndarray[cntndarray].biases = GENMALLOC(f3d.row[f3d.col + 1] * sizeof(int));
tndarray[cntndarray].snames = GENMALLOC(f3d.row[f3d.col + 1] * sizeof(char *));
+ tndarray[cntndarray].snameid = GENMALLOC(f3d.row[f3d.col + 1] * sizeof(int));
tndarray[cntndarray].norcall = GENMALLOC(f3d.row[f3d.col + 1] * sizeof(int));
tndarray[cntndarray].nname = GENMALLOC(f3d.row[f3d.col + 1] * sizeof(char *));
tndarray[cntndarray].treenodes = GENMALLOC(f3d.row[f3d.col + 1] * sizeof(struct rand_smc_node));
@@ -313,9 +320,11 @@
*/
int cntbias = 0;
int bias_count = 0;
+
for (unsigned int j = 0U; (int)j < f3d.row[f3d.col + 1]; j++) {
tndarray[cntndarray].snames[j] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
strlcpy(tndarray[cntndarray].snames[j], f3d.fnamefifo[f3d.col + 1][j], MAX_NAME_CHARS);
+ tndarray[cntndarray].snameid[j] = f3d.fidfifo[f3d.col + 1][j];
tndarray[cntndarray].nname[j] = GENMALLOC(1 * sizeof(char[MAX_NAME_CHARS]));
strlcpy(tndarray[cntndarray].nname[j], f3d.nnfifo[f3d.col + 1][j], MAX_NAME_CHARS);
tndarray[cntndarray].biases[j] = f3d.biasfifo[f3d.col + 1][j];
@@ -355,6 +364,7 @@
GENFREE(ndarray[j].norcall);
GENFREE(ndarray[j].biasarray);
GENFREE(ndarray[j].snames);
+ GENFREE(ndarray[j].snameid);
GENFREE(ndarray[j].nname);
GENFREE(ndarray[j].treenodes);
}
@@ -377,6 +387,7 @@
GENFREE(f3d.nnfifo[f3d.col + 1]);
GENFREE(f3d.fnamefifo[f3d.col + 1]);
GENFREE(f3d.biasfifo[f3d.col + 1]);
+ GENFREE(f3d.fidfifo[f3d.col + 1]);
f3d.curr_col -= 1;
}
}
@@ -393,16 +404,17 @@
GENFREE(f3d.nnfifo[i]);
GENFREE(f3d.fnamefifo[i]);
GENFREE(f3d.biasfifo[i]);
+ GENFREE(f3d.fidfifo[i]);
}
GENFREE(f3d.nnfifo);
GENFREE(f3d.fnamefifo);
GENFREE(f3d.biasfifo);
+ GENFREE(f3d.fidfifo);
GENFREE(f3d.row);
dtdone = 1;
}
}
-
*casz = cntndarray;
return ndarray;
}
@@ -445,9 +457,6 @@
return TEST_RESULT_SUCCESS;
}
-/*
- * Declaration of single fuzzing instance(seed based)
- */
test_result_t smc_fuzzing_instance(uint32_t seed)
{
struct rand_smc_node *tlnode;
@@ -479,11 +488,13 @@
for (unsigned int i = 0U; i < SMC_FUZZ_CALLS_PER_INSTANCE; i++) {
tlnode = &ndarray[cntndarray - 1];
int nd = 0;
+
while (nd == 0) {
int nch = rand()%tlnode->biasent;
int selent = tlnode->biasarray[nch];
+
if (tlnode->norcall[selent] == 0) {
- runtestfunction(tlnode->snames[selent]);
+ runtestfunction(tlnode->snameid[selent]);
nd = 1;
} else {
tlnode = &tlnode->treenodes[selent];
@@ -493,9 +504,6 @@
return TEST_RESULT_SUCCESS;
}
-/*
- * free memory after fuzzing is complete
- */
test_result_t smc_fuzzing_deinit(void)
{
/*
@@ -511,6 +519,7 @@
GENFREE(ndarray[j].norcall);
GENFREE(ndarray[j].biasarray);
GENFREE(ndarray[j].snames);
+ GENFREE(ndarray[j].snameid);
GENFREE(ndarray[j].nname);
GENFREE(ndarray[j].treenodes);
}
@@ -521,7 +530,7 @@
}
/*
- * Execute fuzzing module
+ * Top of SMC fuzzing module
*/
test_result_t smc_fuzzer_execute(void)
{
@@ -576,14 +585,11 @@
return result;
}
-/*
- * Top level of fuzzing module
- */
test_result_t smc_fuzzing_top(void)
{
test_result_t result = TEST_RESULT_SUCCESS;
-
init_smc_fuzzing();
+
#ifdef MULTI_CPU_SMC_FUZZER
u_register_t lead_mpid, target_mpid;
int cpu_node;
diff --git a/smc_fuzz/src/runtestfunction_helpers.c b/smc_fuzz/src/runtestfunction_helpers.c
index b9fa794..c3b2cca 100644
--- a/smc_fuzz/src/runtestfunction_helpers.c
+++ b/smc_fuzz/src/runtestfunction_helpers.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,8 +11,8 @@
/*
* Invoke the SMC call based on the function name specified.
*/
-void runtestfunction(char *funcstr)
+void runtestfunction(int funcid)
{
- run_sdei_fuzz(funcstr);
- run_tsp_fuzz(funcstr);
+ run_sdei_fuzz(funcid);
+ run_tsp_fuzz(funcid);
}
diff --git a/smc_fuzz/src/sdei_fuzz_helper.c b/smc_fuzz/src/sdei_fuzz_helper.c
index cb634dc..1d22335 100644
--- a/smc_fuzz/src/sdei_fuzz_helper.c
+++ b/smc_fuzz/src/sdei_fuzz_helper.c
@@ -1,11 +1,15 @@
/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <fuzz_names.h>
#include <sdei_fuzz_helper.h>
+/*
+ * SDEI function that has no arguments
+ */
void tftf_test_sdei_noarg(int64_t (*sdei_func)(void), char *funcstr)
{
int64_t ret = (*sdei_func)();
@@ -15,6 +19,9 @@
}
}
+/*
+ * SDEI function that has single argument
+ */
void tftf_test_sdei_singlearg(int64_t (*sdei_func)(uint64_t), char *funcstr)
{
int64_t ret = (*sdei_func)(0);
@@ -24,28 +31,30 @@
}
}
-
-void run_sdei_fuzz(char *funcstr)
+/*
+ * SDEI function called from fuzzer
+ */
+void run_sdei_fuzz(int funcid)
{
- if (strcmp(funcstr, "sdei_version") == CMP_SUCCESS) {
+ if (funcid == sdei_version_funcid) {
long long ret = sdei_version();
if (ret != MAKE_SDEI_VERSION(1, 0, 0)) {
tftf_testcase_printf("Unexpected SDEI version: 0x%llx\n",
ret);
}
- } else if (strcmp(funcstr, "sdei_pe_unmask") == CMP_SUCCESS) {
- tftf_test_sdei_noarg(sdei_pe_unmask, "sdei_pe_unmask");
- } else if (strcmp(funcstr, "sdei_pe_mask") == CMP_SUCCESS) {
+ } else if (funcid == sdei_pe_unmask_funcid) {
+ tftf_test_sdei_noarg(sdei_pe_unmask, "sdei_pe_unmuask");
+ } else if (funcid == sdei_pe_mask_funcid) {
tftf_test_sdei_noarg(sdei_pe_mask, "sdei_pe_mask");
- } else if (strcmp(funcstr, "sdei_event_status") == CMP_SUCCESS) {
+ } else if (funcid == sdei_event_status_funcid) {
tftf_test_sdei_singlearg((int64_t (*)(uint64_t))sdei_event_status,
"sdei_event_status");
- } else if (strcmp(funcstr, "sdei_event_signal") == CMP_SUCCESS) {
+ } else if (funcid == sdei_event_signal_funcid) {
tftf_test_sdei_singlearg(sdei_event_signal, "sdei_event_signal");
- } else if (strcmp(funcstr, "sdei_private_reset") == CMP_SUCCESS) {
+ } else if (funcid == sdei_private_reset_funcid) {
tftf_test_sdei_noarg(sdei_private_reset, "sdei_private_reset");
- } else if (strcmp(funcstr, "sdei_shared_reset") == CMP_SUCCESS) {
+ } else if (funcid == sdei_shared_reset_funcid) {
tftf_test_sdei_noarg(sdei_shared_reset, "sdei_shared_reset");
}
}
diff --git a/smc_fuzz/src/tsp_fuzz_helper.c b/smc_fuzz/src/tsp_fuzz_helper.c
index c6ed219..610fae0 100644
--- a/smc_fuzz/src/tsp_fuzz_helper.c
+++ b/smc_fuzz/src/tsp_fuzz_helper.c
@@ -1,10 +1,14 @@
/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <fuzz_names.h>
#include <tsp_fuzz_helper.h>
+/*
+ * Generic TSP based function call for math operations
+ */
void tftf_test_tsp_smc(uint64_t tsp_id, char *funcstr)
{
uint64_t fn_identifier = TSP_FAST_FID(tsp_id);
@@ -22,15 +26,18 @@
}
}
-void run_tsp_fuzz(char *funcstr)
+/*
+ * TSP function called from fuzzer
+ */
+void run_tsp_fuzz(int funcid)
{
- if (strcmp(funcstr, "tsp_add_op") == CMP_SUCCESS) {
+ if (funcid == tsp_add_op_funcid) {
tftf_test_tsp_smc(TSP_ADD, "tsp_add_op");
- } else if (strcmp(funcstr, "tsp_sub_op") == CMP_SUCCESS) {
+ } else if (funcid == tsp_sub_op_funcid) {
tftf_test_tsp_smc(TSP_SUB, "tsp_sub_op");
- } else if (strcmp(funcstr, "tsp_mul_op") == CMP_SUCCESS) {
+ } else if (funcid == tsp_mul_op_funcid) {
tftf_test_tsp_smc(TSP_MUL, "tsp_mul_op");
- } else if (strcmp(funcstr, "tsp_div_op") == CMP_SUCCESS) {
+ } else if (funcid == tsp_div_op_funcid) {
tftf_test_tsp_smc(TSP_DIV, "tsp_div_op");
}
}
diff --git a/spm/cactus/cactus.mk b/spm/cactus/cactus.mk
index be8997e..4e86e3d 100644
--- a/spm/cactus/cactus.mk
+++ b/spm/cactus/cactus.mk
@@ -49,7 +49,7 @@
) \
$(addprefix spm/cactus/cactus_tests/, \
cactus_message_loop.c \
- cactus_test_cpu_features.c \
+ cactus_test_simd.c \
cactus_test_direct_messaging.c \
cactus_test_interrupts.c \
cactus_test_memory_sharing.c \
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index 19a89f5..b3f7451 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -115,6 +115,10 @@
/* scratch memory allocated to be used for running SMMU tests */
MAP_REGION_FLAT(PLAT_CACTUS_MEMCPY_BASE, PLAT_CACTUS_MEMCPY_RANGE,
MT_MEMORY | MT_RW),
+#if PLAT_fvp
+ MAP_REGION_FLAT(PLAT_CACTUS_NS_MEMCPY_BASE, PLAT_CACTUS_MEMCPY_RANGE,
+ MT_MEMORY | MT_RW | MT_NS),
+#endif
{0}
};
@@ -286,22 +290,16 @@
goto msg_loop;
}
- if (ffa_id == SPM_VM_ID_FIRST) {
- console_init(CACTUS_PL011_UART_BASE,
- CACTUS_PL011_UART_CLK_IN_HZ,
- PL011_BAUDRATE);
-
- set_putc_impl(PL011_AS_STDOUT);
-
- cactus_print_boot_info(boot_info_header);
- } else {
- set_putc_impl(FFA_SVC_SMC_CALL_AS_STDOUT);
- }
+ set_putc_impl(FFA_SVC_SMC_CALL_AS_STDOUT);
/* Below string is monitored by CI expect script. */
NOTICE("Booting Secure Partition (ID: %x)\n%s\n%s\n",
ffa_id, build_message, version_string);
+ if (ffa_id == SP_ID(1)) {
+ cactus_print_boot_info(boot_info_header);
+ }
+
if (ffa_id == (SPM_VM_ID_FIRST + 2)) {
VERBOSE("Mapping RXTX Region\n");
CONFIGURE_AND_MAP_MAILBOX(mb, PAGE_SIZE, ret);
diff --git a/spm/cactus/cactus_tests/cactus_message_loop.c b/spm/cactus/cactus_tests/cactus_message_loop.c
index e56e51e..c0abf2b 100644
--- a/spm/cactus/cactus_tests/cactus_message_loop.c
+++ b/spm/cactus/cactus_tests/cactus_message_loop.c
@@ -11,6 +11,7 @@
#include <ffa_helpers.h>
#include <events.h>
#include <platform.h>
+#include <spm_helpers.h>
/**
* Counter of the number of handled requests, for each CPU. The number of
@@ -43,9 +44,8 @@
{
uint64_t in_cmd;
- /* Get which core it is running from. */
- unsigned int core_pos = platform_get_core_pos(
- read_mpidr_el1() & MPID_MASK);
+ /* Get vCPU index for currently running vCPU. */
+ unsigned int core_pos = spm_get_my_core_pos();
if (cmd_args == NULL || ret == NULL) {
ERROR("Invalid arguments passed to %s!\n", __func__);
diff --git a/spm/cactus/cactus_tests/cactus_test_direct_messaging.c b/spm/cactus/cactus_tests/cactus_test_direct_messaging.c
index 540ef01..fd82f82 100644
--- a/spm/cactus/cactus_tests/cactus_test_direct_messaging.c
+++ b/spm/cactus/cactus_tests/cactus_test_direct_messaging.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -114,3 +114,15 @@
return base_deadlock_handler(vm_id, source, deadlock_dest, deadlock_next_dest);
}
+
+CACTUS_CMD_HANDLER(ras_delegate_cmd, CACTUS_RAS_DELEGATE_CMD)
+{
+ uint64_t event_id = cactus_ras_get_event_id(*args);
+
+ INFO("Received RAS cmd at %x, value %llu.\n", ffa_dir_msg_dest(*args),
+ event_id);
+
+ return cactus_success_resp(ffa_dir_msg_dest(*args),
+ ffa_dir_msg_source(*args),
+ event_id);
+}
diff --git a/spm/cactus/cactus_tests/cactus_test_interrupts.c b/spm/cactus/cactus_tests/cactus_test_interrupts.c
index 4250445..2e0249c 100644
--- a/spm/cactus/cactus_tests/cactus_test_interrupts.c
+++ b/spm/cactus/cactus_tests/cactus_test_interrupts.c
@@ -86,8 +86,9 @@
/* Received FFA_INTERRUPT in blocked state. */
VERBOSE("Processing FFA_INTERRUPT while"
" blocked on direct response\n");
- unsigned int my_core_pos =
- platform_get_core_pos(read_mpidr_el1());
+
+ /* Get vCPU index for currently running vCPU. */
+ unsigned int my_core_pos = spm_get_my_core_pos();
ffa_ret = ffa_run(fwd_dest, my_core_pos);
} else {
diff --git a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
index 2fbc63b..4d738b1 100644
--- a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
+++ b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
@@ -11,6 +11,8 @@
#include <ffa_helpers.h>
#include <sp_helpers.h>
#include "sp_tests.h"
+#include "spm_common.h"
+#include "stdint.h"
#include <xlat_tables_defs.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <sync.h>
@@ -66,11 +68,42 @@
return (void *)CACTUS_SP3_NS_MEM_SHARE_BASE;
}
+static bool cactus_mem_unmap_and_relinquish(
+ struct ffa_composite_memory_region *composite,
+ void *send, ffa_memory_handle_t handle, ffa_id_t vm_id)
+{
+ int ret;
+
+ for (uint32_t i = 0; i < composite->constituent_count; i++) {
+ uint64_t base_address = (uint64_t)composite->constituents[i]
+ .address;
+ size_t size = composite->constituents[i].page_count * PAGE_SIZE;
+
+ ret = mmap_remove_dynamic_region(
+ (uint64_t)composite->constituents[i].address,
+ composite->constituents[i].page_count * PAGE_SIZE);
+
+ if (ret != 0) {
+ ERROR("Failed to unmap received memory region %llx "
+ "size: %lu (error:%d)\n",
+ base_address, size, ret);
+ return false;
+ }
+ }
+
+ if (!memory_relinquish((struct ffa_mem_relinquish *)send,
+ handle, vm_id)) {
+ return false;
+ }
+
+ return true;
+}
+
CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
{
struct ffa_memory_region *m;
struct ffa_composite_memory_region *composite;
- int ret;
+ int ret = -1;
unsigned int mem_attrs;
uint32_t *ptr;
ffa_id_t source = ffa_dir_msg_source(*args);
@@ -80,13 +113,14 @@
ffa_memory_region_flags_t retrv_flags =
cactus_mem_send_get_retrv_flags(*args);
uint32_t words_to_write = cactus_mem_send_words_to_write(*args);
+ bool expect_exception = cactus_mem_send_expect_exception(*args);
- struct ffa_memory_access receiver = ffa_memory_access_init_permissions(
+ struct ffa_memory_access receiver = ffa_memory_access_init(
vm_id, FFA_DATA_ACCESS_RW,
(mem_func == FFA_MEM_SHARE_SMC32)
? FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED
: FFA_INSTRUCTION_ACCESS_NX,
- 0);
+ 0, NULL);
expect(memory_retrieve(mb, &m, handle, source, &receiver, 1,
retrv_flags),
@@ -94,10 +128,6 @@
composite = ffa_memory_region_get_composite(m, 0);
- VERBOSE("Address: %p; page_count: %x %x\n",
- composite->constituents[0].address,
- composite->constituents[0].page_count, PAGE_SIZE);
-
/* This test is only concerned with RW permissions. */
if (m->receivers[0].receiver_permissions.permissions.data_access !=
FFA_DATA_ACCESS_RW) {
@@ -111,32 +141,89 @@
mem_attrs |= MT_NS;
}
- ret = mmap_add_dynamic_region(
- (uint64_t)composite->constituents[0].address,
- (uint64_t)composite->constituents[0].address,
- composite->constituents[0].page_count * PAGE_SIZE,
- mem_attrs);
+ for (uint32_t i = 0; i < composite->constituent_count; i++) {
+ uint64_t base_address = (uint64_t)composite->constituents[i]
+ .address;
+ size_t size = composite->constituents[i].page_count * PAGE_SIZE;
- if (ret != 0) {
- ERROR("Failed to map received memory region(%d)!\n", ret);
- return cactus_error_resp(vm_id, source, CACTUS_ERROR_TEST);
+ ret = mmap_add_dynamic_region(
+ base_address, base_address, size, mem_attrs);
+
+ if (ret != 0) {
+ ERROR("Failed to map received memory region %llx "
+ "size: %lu (error:%d)\n",
+ base_address, size, ret);
+ return cactus_error_resp(vm_id,
+ source,
+ CACTUS_ERROR_TEST);
+ }
}
VERBOSE("Memory has been mapped\n");
- ptr = (uint32_t *) composite->constituents[0].address;
+ for (uint32_t i = 0; i < composite->constituent_count; i++) {
+ ptr = (uint32_t *) composite->constituents[i].address;
- /* Check that memory has been cleared by the SPMC before using it. */
- if ((retrv_flags & FFA_MEMORY_REGION_FLAG_CLEAR) != 0U) {
- VERBOSE("Check if memory has been cleared!\n");
- for (uint32_t i = 0; i < words_to_write; i++) {
- if (ptr[i] != 0) {
+ for (uint32_t j = 0; j < words_to_write; j++) {
+
+ /**
+ * Check that memory has been cleared by the SPMC
+ * before using it.
+ */
+ if ((retrv_flags & FFA_MEMORY_REGION_FLAG_CLEAR) != 0U) {
+ VERBOSE("Check if memory has been cleared.\n");
+ if (ptr[j] != 0) {
+ /*
+ * If it hasn't been cleared, shouldn't
+ * be used.
+ */
+ ERROR("Memory NOT cleared!\n");
+ cactus_mem_unmap_and_relinquish(composite,
+ mb->send,
+ handle, vm_id);
+ ffa_rx_release();
+ return cactus_error_resp(
+ vm_id, source,
+ CACTUS_ERROR_TEST);
+ }
+ } else {
/*
- * If it hasn't been cleared, shouldn't be used.
+ * In RME enabled systems, the memory is expected
+ * to be scrubbed on PAS updates from S to NS.
+ * As well, it is likely that the memory
+ * addresses are shadowed, and the contents are
+ * not visible accross updates from the
+ * different address spaces. As such, the SP
+ * shall not rely on memory content to be
+ * in any form. FFA_MEM_LEND/FFA_MEM_DONATE are
+ * thus considered for memory allocation
+ * purposes.
+ *
+ * Expect valid data if:
+ * - Operation between SPs.
+ * - Memory sharing from NWd to SP.
*/
- ERROR("Memory should have been cleared!\n");
- return cactus_error_resp(
- vm_id, source, CACTUS_ERROR_TEST);
+ if ((mem_func != FFA_MEM_SHARE_SMC32 &&
+ !IS_SP_ID(m->sender)) ||
+ expect_exception) {
+ continue;
+ }
+
+ VERBOSE("Check memory contents. Expect %u "
+ "words of %x\n", words_to_write,
+ mem_func + 0xFFA);
+
+ /* SPs writing `mem_func` + 0xFFA. */
+ if (ptr[i] != mem_func + 0xFFA) {
+ ERROR("Memory content NOT as expected!\n");
+ cactus_mem_unmap_and_relinquish(
+ composite, mb->send, handle,
+ vm_id);
+ ffa_rx_release();
+ return cactus_error_resp(
+ vm_id, source,
+ CACTUS_ERROR_TEST);
+ }
}
}
}
@@ -145,9 +232,11 @@
register_custom_sync_exception_handler(data_abort_gpf_handler);
/* Write mem_func to retrieved memory region for validation purposes. */
- VERBOSE("Writing: %x\n", mem_func);
- for (unsigned int i = 0U; i < words_to_write; i++) {
- ptr[i] = mem_func;
+ for (uint32_t i = 0; i < composite->constituent_count; i++) {
+ ptr = (uint32_t *) composite->constituents[i].address;
+ for (uint32_t j = 0; j < words_to_write; j++) {
+ ptr[j] = mem_func + 0xFFA;
+ }
}
unregister_custom_sync_exception_handler();
@@ -156,22 +245,11 @@
* A FFA_MEM_DONATE changes the ownership of the page, as such no
* relinquish is needed.
*/
- if (mem_func != FFA_MEM_DONATE_SMC32) {
- ret = mmap_remove_dynamic_region(
- (uint64_t)composite->constituents[0].address,
- composite->constituents[0].page_count * PAGE_SIZE);
-
- if (ret != 0) {
- ERROR("Failed to unmap received memory region(%d)!\n", ret);
- return cactus_error_resp(vm_id, source,
- CACTUS_ERROR_TEST);
- }
-
- if (!memory_relinquish((struct ffa_mem_relinquish *)mb->send,
- m->handle, vm_id)) {
- return cactus_error_resp(vm_id, source,
- CACTUS_ERROR_TEST);
- }
+ if (mem_func != FFA_MEM_DONATE_SMC32 &&
+ !cactus_mem_unmap_and_relinquish(composite, mb->send, handle,
+ vm_id)) {
+ return cactus_error_resp(vm_id, source,
+ CACTUS_ERROR_TEST);
}
if (ffa_func_id(ffa_rx_release()) != FFA_SUCCESS_SMC32) {
@@ -192,18 +270,19 @@
ffa_memory_handle_t handle;
ffa_id_t vm_id = ffa_dir_msg_dest(*args);
ffa_id_t source = ffa_dir_msg_source(*args);
+ uint32_t *ptr;
bool non_secure = cactus_req_mem_send_get_non_secure(*args);
void *share_page_addr =
non_secure ? share_page_non_secure(vm_id) : share_page(vm_id);
unsigned int mem_attrs;
int ret;
-
+ const uint32_t words_to_write = 10;
struct ffa_memory_access receiver =
ffa_memory_access_init_permissions_from_mem_func(receiver_id,
mem_func);
VERBOSE("%x requested to send memory to %x (func: %x), page: %llx\n",
- source, receiver, mem_func, (uint64_t)share_page_addr);
+ source, receiver_id, mem_func, (uint64_t)share_page_addr);
const struct ffa_memory_region_constituent constituents[] = {
{share_page_addr, 1, 0}
@@ -232,6 +311,18 @@
CACTUS_ERROR_TEST);
}
+ /* Write to memory before sharing to SP. */
+ if (IS_SP_ID(receiver_id)) {
+ for (size_t i = 0; i < constituents_count; i++) {
+ VERBOSE("Sharing Address: %p\n",
+ constituents[i].address);
+ ptr = (uint32_t *)constituents[i].address;
+ for (size_t j = 0; j < words_to_write; j++) {
+ ptr[j] = mem_func + 0xFFA;
+ }
+ }
+ }
+
handle = memory_init_and_send(mb->send, PAGE_SIZE, vm_id, &receiver, 1,
constituents, constituents_count,
mem_func, &ffa_ret);
@@ -245,8 +336,8 @@
ffa_error_code(ffa_ret));
}
- ffa_ret = cactus_mem_send_cmd(vm_id, receiver_id, mem_func, handle, 0,
- 10);
+ ffa_ret = cactus_mem_send_cmd(vm_id, receiver_id, mem_func, handle,
+ 0, 10, false);
if (!is_ffa_direct_response(ffa_ret)) {
return cactus_error_resp(vm_id, source, CACTUS_ERROR_FFA_CALL);
diff --git a/spm/cactus/cactus_tests/cactus_test_notifications.c b/spm/cactus/cactus_tests/cactus_test_notifications.c
index d8b88ed..6d7b41b 100644
--- a/spm/cactus/cactus_tests/cactus_test_notifications.c
+++ b/spm/cactus/cactus_tests/cactus_test_notifications.c
@@ -9,6 +9,7 @@
#include "sp_tests.h"
#include <ffa_helpers.h>
+#include <spm_helpers.h>
#include <debug.h>
/* Booleans to keep track of which CPUs handled NPI. */
@@ -33,9 +34,8 @@
void notification_pending_interrupt_handler(void)
{
- /* Get which core it is running from. */
- unsigned int core_pos = platform_get_core_pos(
- read_mpidr_el1() & MPID_MASK);
+ /* Get vCPU index for currently running vCPU. */
+ unsigned int core_pos = spm_get_my_core_pos();
VERBOSE("NPI handled in core %u\n", core_pos);
diff --git a/spm/cactus/cactus_tests/cactus_test_cpu_features.c b/spm/cactus/cactus_tests/cactus_test_simd.c
similarity index 85%
rename from spm/cactus/cactus_tests/cactus_test_cpu_features.c
rename to spm/cactus/cactus_tests/cactus_test_simd.c
index a1366d3..bcf1c38 100644
--- a/spm/cactus/cactus_tests/cactus_test_cpu_features.c
+++ b/spm/cactus/cactus_tests/cactus_test_simd.c
@@ -7,6 +7,7 @@
#include "cactus_message_loop.h"
#include "cactus_test_cmds.h"
#include <fpu.h>
+#include <spm_helpers.h>
#include "spm_common.h"
/*
@@ -21,7 +22,8 @@
*/
CACTUS_CMD_HANDLER(req_simd_fill, CACTUS_REQ_SIMD_FILL_CMD)
{
- core_pos = platform_get_core_pos(read_mpidr_el1());
+ /* Get vCPU index for currently running vCPU. */
+ core_pos = spm_get_my_core_pos();
fpu_state_write_rand(&sp_fpu_state_write);
return cactus_response(ffa_dir_msg_dest(*args),
ffa_dir_msg_source(*args),
@@ -36,7 +38,8 @@
{
bool test_succeed = false;
- unsigned int core_pos1 = platform_get_core_pos(read_mpidr_el1());
+ /* Get vCPU index for currently running vCPU. */
+ unsigned int core_pos1 = spm_get_my_core_pos();
if (core_pos1 == core_pos) {
fpu_state_read(&sp_fpu_state_read);
if (fpu_state_compare(&sp_fpu_state_write,
diff --git a/spm/cactus/plat/arm/fvp/fdts/cactus.dts b/spm/cactus/plat/arm/fvp/fdts/cactus.dts
index 12d7b84..3effb39 100644
--- a/spm/cactus/plat/arm/fvp/fdts/cactus.dts
+++ b/spm/cactus/plat/arm/fvp/fdts/cactus.dts
@@ -80,6 +80,9 @@
pages-count = <4>;
base-address = <0x00000000 0x7400000>;
attributes = <0x3>; /* read-write */
+ smmu-id = <0>;
+ stream-ids = <0x0 0x1>;
+ stream-ids-access-permissions = <0x3 0x3>;
};
smmuv3-memcpy-dst {
@@ -87,25 +90,25 @@
pages-count = <4>;
base-address = <0x00000000 0x7404000>;
attributes = <0x3>; /* read-write */
+ smmu-id = <0>;
+ stream-ids = <0x0 0x1>;
+ stream-ids-access-permissions = <0x3 0x3>;
};
smmuv3-ns-region {
- description = "smmuv3-ns-region";
+ description = "smmuv3-memcpy-ns-region";
pages-count = <8>;
base-address = <0x0 0x90000000>;
attributes = <0xb>; /* ns-read-write */
+ smmu-id = <0>;
+ stream-ids = <0x0 0x1>;
+ stream-ids-access-permissions = <0xb 0xb>;
};
};
device-regions {
compatible = "arm,ffa-manifest-device-regions";
- uart2 {
- base-address = <0x00000000 0x1c0b0000>;
- pages-count = <1>;
- attributes = <0x3>; /* read-write */
- };
-
smmuv3-testengine {
/*
* SMMUv3TestEngine is a DMA IP modeled in the
diff --git a/spm/cactus/plat/arm/fvp/include/sp_platform_def.h b/spm/cactus/plat/arm/fvp/include/sp_platform_def.h
index 0025dce..bb57ce8 100644
--- a/spm/cactus/plat/arm/fvp/include/sp_platform_def.h
+++ b/spm/cactus/plat/arm/fvp/include/sp_platform_def.h
@@ -21,9 +21,6 @@
#define PLAT_ARM_DEVICE0_BASE DEVICE0_BASE
#define PLAT_ARM_DEVICE0_SIZE DEVICE0_SIZE
-#define CACTUS_PL011_UART_BASE PL011_UART2_BASE
-#define CACTUS_PL011_UART_CLK_IN_HZ PL011_UART2_CLK_IN_HZ
-
/* Scratch memory used for SMMUv3 driver testing purposes in Cactus SP */
#define PLAT_CACTUS_MEMCPY_BASE ULL(0x7400000)
#define PLAT_CACTUS_NS_MEMCPY_BASE ULL(0x90000000)
diff --git a/spm/cactus/plat/arm/tc/fdts/cactus.dts b/spm/cactus/plat/arm/tc/fdts/cactus.dts
index fe450e8..31b9e8e 100644
--- a/spm/cactus/plat/arm/tc/fdts/cactus.dts
+++ b/spm/cactus/plat/arm/tc/fdts/cactus.dts
@@ -70,13 +70,4 @@
attributes = <0x3>; /* read-write */
};
};
-
- device-regions {
- compatible = "arm,ffa-manifest-device-regions";
- uart2 {
- base-address = <0x00000000 0x7FF80000>;
- pages-count = <1>;
- attributes = <0x3>; /* read-write */
- };
- };
};
diff --git a/spm/cactus/plat/arm/tc/include/sp_platform_def.h b/spm/cactus/plat/arm/tc/include/sp_platform_def.h
index c5b548d..b3a3514 100644
--- a/spm/cactus/plat/arm/tc/include/sp_platform_def.h
+++ b/spm/cactus/plat/arm/tc/include/sp_platform_def.h
@@ -21,9 +21,6 @@
#define PLAT_ARM_DEVICE0_BASE TC_DEVICE0_BASE
#define PLAT_ARM_DEVICE0_SIZE TC_DEVICE0_SIZE
-#define CACTUS_PL011_UART_BASE PL011_UART1_BASE
-#define CACTUS_PL011_UART_CLK_IN_HZ PL011_UART1_CLK_IN_HZ
-
/* Scratch memory used for SMMUv3 driver testing purposes in Cactus SP */
/* SMMUv3 tests are disabled for TC platform */
#define PLAT_CACTUS_MEMCPY_BASE ULL(0xfe400000)
diff --git a/spm/common/sp_tests/sp_test_ffa.c b/spm/common/sp_tests/sp_test_ffa.c
index 73db187..219b149 100644
--- a/spm/common/sp_tests/sp_test_ffa.c
+++ b/spm/common/sp_tests/sp_test_ffa.c
@@ -17,7 +17,7 @@
/* FFA version test helpers */
#define FFA_MAJOR 1U
-#define FFA_MINOR 1U
+#define FFA_MINOR 2U
static uint32_t spm_version;
@@ -133,11 +133,11 @@
struct ffa_value ret = { 0 };
VERBOSE("FF-A Partition Info regs interface tests\n");
- ret = ffa_version(MAKE_FFA_VERSION(1, 1));
+ ret = ffa_version(MAKE_FFA_VERSION(1, 2));
uint32_t version = ret.fid;
if (version == FFA_ERROR_NOT_SUPPORTED) {
- ERROR("FFA_VERSION 1.1 not supported, skipping"
+ ERROR("FFA_VERSION 1.2 not supported, skipping"
" FFA_PARTITION_INFO_GET_REGS test.\n");
return;
}
diff --git a/spm/common/spm_helpers.c b/spm/common/spm_helpers.c
index 1cb5f4d..b2a4709 100644
--- a/spm/common/spm_helpers.c
+++ b/spm/common/spm_helpers.c
@@ -56,3 +56,16 @@
return (int64_t)ret.ret0;
}
+
+/**
+ * Return vCPU index for the currently running vCPU.
+ * Virtual MPIDR holds the linear vCPU index information in lower bits.
+ * Keep only first 24 bits (mapping to Aff0/Aff1/Aff2).
+ * Omit Aff3, bit [31], U[30], MT[24].
+ */
+unsigned int spm_get_my_core_pos(void)
+{
+ uint64_t mpidr = read_mpidr_el1();
+
+ return (unsigned int)(mpidr & 0xffffff);
+}
diff --git a/spm/common/spm_helpers.h b/spm/common/spm_helpers.h
index 1d3ddc2..59cdaf1 100644
--- a/spm/common/spm_helpers.h
+++ b/spm/common/spm_helpers.h
@@ -23,4 +23,6 @@
int64_t spm_interrupt_enable(uint32_t int_id, bool enable, enum interrupt_pin pin);
int64_t spm_interrupt_deactivate(uint32_t vint_id);
+unsigned int spm_get_my_core_pos(void);
+
#endif /* SPMC_H */
diff --git a/tftf/tests/extensions/pauth/test_pauth.c b/tftf/tests/extensions/pauth/test_pauth.c
index b29e5d0..ada2f1d 100644
--- a/tftf/tests/extensions/pauth/test_pauth.c
+++ b/tftf/tests/extensions/pauth/test_pauth.c
@@ -13,6 +13,11 @@
#include <tsp.h>
#include <string.h>
+#ifdef __aarch64__
+static uint128_t pauth_keys_before[NUM_KEYS];
+static uint128_t pauth_keys_after[NUM_KEYS];
+#endif
+
/*
* TF-A is expected to allow access to key registers from lower EL's,
* reading the keys excercises this, on failure this will trap to
@@ -23,7 +28,7 @@
SKIP_TEST_IF_AARCH32();
#ifdef __aarch64__
SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
- pauth_test_lib_read_keys();
+ pauth_test_lib_read_keys(pauth_keys_before);
return TEST_RESULT_SUCCESS;
#endif /* __aarch64__ */
}
@@ -37,11 +42,11 @@
SKIP_TEST_IF_AARCH32();
#ifdef __aarch64__
SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
- pauth_test_lib_read_keys();
+ pauth_test_lib_read_keys(pauth_keys_before);
tftf_get_psci_version();
- return pauth_test_lib_compare_template();
+ return pauth_test_lib_compare_template(pauth_keys_before, pauth_keys_after);
#endif /* __aarch64__ */
}
@@ -84,7 +89,7 @@
SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
SKIP_TEST_IF_TSP_NOT_PRESENT();
- pauth_test_lib_fill_regs_and_template();
+ pauth_test_lib_fill_regs_and_template(pauth_keys_before);
/* Standard SMC to ADD two numbers */
tsp_svc_params.fid = TSP_STD_FID(TSP_ADD);
@@ -106,6 +111,6 @@
return TEST_RESULT_FAIL;
}
- return pauth_test_lib_compare_template();
+ return pauth_test_lib_compare_template(pauth_keys_before, pauth_keys_after);
#endif /* __aarch64__ */
}
diff --git a/tftf/tests/misc_tests/test_invalid_access.c b/tftf/tests/misc_tests/test_invalid_access.c
index b05d694..3baeed5 100644
--- a/tftf/tests/misc_tests/test_invalid_access.c
+++ b/tftf/tests/misc_tests/test_invalid_access.c
@@ -302,7 +302,7 @@
return TEST_RESULT_SKIPPED;
}
- CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ CHECK_SPMC_TESTING_SETUP(1, 2, expected_sp_uuids);
GET_TFTF_MAILBOX(mb);
diff --git a/tftf/tests/misc_tests/test_undef_injection.c b/tftf/tests/misc_tests/test_undef_injection.c
new file mode 100644
index 0000000..2d925a2
--- /dev/null
+++ b/tftf/tests/misc_tests/test_undef_injection.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <arm_arch_svc.h>
+#include <assert.h>
+#include <debug.h>
+#include <smccc.h>
+#include <sync.h>
+#include <tftf_lib.h>
+#include <platform_def.h>
+
+static volatile bool undef_injection_triggered;
+
+static bool undef_injection_handler(void)
+{
+ uint64_t esr_el2 = read_esr_el2();
+ if (EC_BITS(esr_el2) == EC_UNKNOWN) {
+ VERBOSE("UNDEF injection from EL3\n");
+ undef_injection_triggered = true;
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Test to verify UNDEF injection support in TF-A
+ *
+ * This test tries to access FGT EL2 registers which traps to EL3 and then
+ * the error is injected back from EL3 to TFTF to ensure that injection
+ * logic in TF-A is working, it also ensures that EL3 is still functional
+ * after UNDEF injection.
+ *
+ * To trap FGT register access to EL3, we run this test on a model with
+ * FEAT_FGT present but the traps from EL3 are not disabled by setting
+ * ENABLE_FEAT_FGT = 0
+ */
+test_result_t test_undef_injection(void)
+{
+ undef_injection_triggered = false;
+
+ register_custom_sync_exception_handler(undef_injection_handler);
+
+ /* Try to access a register which traps to EL3 */
+ read_hfgitr_el2();
+
+ unregister_custom_sync_exception_handler();
+
+ /* Ensure that EL3 still functional */
+ smc_args args;
+ smc_ret_values smc_ret;
+ memset(&args, 0, sizeof(args));
+ args.fid = SMCCC_VERSION;
+ smc_ret = tftf_smc(&args);
+
+ tftf_testcase_printf("SMCCC Version = %d.%d\n",
+ (int)((smc_ret.ret0 >> SMCCC_VERSION_MAJOR_SHIFT) & SMCCC_VERSION_MAJOR_MASK),
+ (int)((smc_ret.ret0 >> SMCCC_VERSION_MINOR_SHIFT) & SMCCC_VERSION_MINOR_MASK));
+
+ if (undef_injection_triggered == false) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c b/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c
index a424b09..682a699 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c
@@ -215,6 +215,18 @@
}
}
+ /*
+ * At the moment, TFTF does not have support for FEAT_LPA2, so if
+ * S2SZ is larger than 48 bits, truncate it to ensure we don't surpass
+ * the maximum IPA size for a realm with no LPA2 support.
+ */
+ if (EXTRACT(RMI_FEATURE_REGISTER_0_S2SZ, realm_ptr->rmm_feat_reg0) > 48U) {
+ realm_ptr->rmm_feat_reg0 &=
+ ~MASK(RMI_FEATURE_REGISTER_0_S2SZ);
+ realm_ptr->rmm_feat_reg0 |=
+ INPLACE(RMI_FEATURE_REGISTER_0_S2SZ, 48U);
+ }
+
/* Create Realm */
if (host_realm_create(realm_ptr) != REALM_SUCCESS) {
ERROR("%s() failed\n", "host_realm_create");
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c b/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
index c678217..057dd00 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
@@ -142,10 +142,10 @@
return host_rmi_handler(&(smc_args) {RMI_REALM_DESTROY, rd}, 2U).ret0;
}
-static inline u_register_t host_rmi_data_destroy(u_register_t rd,
- u_register_t map_addr,
- u_register_t *data,
- u_register_t *top)
+u_register_t host_rmi_data_destroy(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t *data,
+ u_register_t *top)
{
smc_ret_values rets;
@@ -179,11 +179,11 @@
rd, rtt, map_addr, level}, 5U).ret0;
}
-static inline u_register_t host_rmi_rtt_destroy(u_register_t rd,
- u_register_t map_addr,
- u_register_t level,
- u_register_t *rtt,
- u_register_t *top)
+u_register_t host_rmi_rtt_destroy(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t level,
+ u_register_t *rtt,
+ u_register_t *top)
{
smc_ret_values rets;
@@ -203,10 +203,10 @@
return rets.ret0;
}
-static inline u_register_t host_rmi_rtt_init_ripas(u_register_t rd,
- u_register_t start,
- u_register_t end,
- u_register_t *top)
+u_register_t host_rmi_rtt_init_ripas(u_register_t rd,
+ u_register_t start,
+ u_register_t end,
+ u_register_t *top)
{
smc_ret_values rets;
@@ -263,10 +263,10 @@
rd, map_addr, level, ns_pa}, 5U).ret0;
}
-static u_register_t host_rmi_rtt_readentry(u_register_t rd,
- u_register_t map_addr,
- u_register_t level,
- struct rtt_entry *rtt)
+u_register_t host_rmi_rtt_readentry(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t level,
+ struct rtt_entry *rtt)
{
smc_ret_values rets;
@@ -279,10 +279,10 @@
return rets.ret0;
}
-static inline u_register_t host_rmi_rtt_unmap_unprotected(u_register_t rd,
- u_register_t map_addr,
- u_register_t level,
- u_register_t *top)
+u_register_t host_rmi_rtt_unmap_unprotected(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t level,
+ u_register_t *top)
{
smc_ret_values rets;
@@ -292,7 +292,7 @@
return rets.ret0;
}
-static inline u_register_t host_rtt_level_mapsize(u_register_t level)
+u_register_t host_rtt_level_mapsize(u_register_t level)
{
if (level > RTT_MAX_LEVEL) {
return PAGE_SIZE;
@@ -315,10 +315,10 @@
return host_rmi_rtt_create(realm->rd, phys, addr, level);
}
-static u_register_t host_rmi_create_rtt_levels(struct realm *realm,
- u_register_t map_addr,
- u_register_t level,
- u_register_t max_level)
+u_register_t host_rmi_create_rtt_levels(struct realm *realm,
+ u_register_t map_addr,
+ u_register_t level,
+ u_register_t max_level)
{
u_register_t rtt, ret;
@@ -381,11 +381,11 @@
}
-u_register_t host_realm_map_protected_data(bool unknown,
- struct realm *realm,
- u_register_t target_pa,
- u_register_t map_size,
- u_register_t src_pa)
+u_register_t host_realm_delegate_map_protected_data(bool unknown,
+ struct realm *realm,
+ u_register_t target_pa,
+ u_register_t map_size,
+ u_register_t src_pa)
{
u_register_t rd = realm->rd;
u_register_t map_level, level;
@@ -393,8 +393,6 @@
u_register_t size = 0UL;
u_register_t phys = target_pa;
u_register_t map_addr = target_pa;
- u_register_t end_addr = map_addr + map_size;
- u_register_t top;
if (!IS_ALIGNED(map_addr, map_size)) {
return REALM_ERROR;
@@ -412,23 +410,6 @@
return REALM_ERROR;
}
- ret = host_rmi_rtt_init_ripas(rd, map_addr, end_addr, &top);
- if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
- ret = host_rmi_create_rtt_levels(realm, map_addr,
- RMI_RETURN_INDEX(ret),
- map_level);
- if (ret != RMI_SUCCESS) {
- ERROR("%s() failed, ret=0x%lx line=%u\n",
- "host_rmi_create_rtt_levels", ret, __LINE__);
- goto err;
- }
- ret = host_rmi_rtt_init_ripas(rd, map_addr, end_addr, &top);
- if (ret != RMI_SUCCESS) {
- ERROR("%s() failed, ret=0x%lx line=%u\n",
- "host_rmi_rtt_init_ripas", ret, __LINE__);
- goto err;
- }
- }
for (size = 0UL; size < map_size; size += PAGE_SIZE) {
ret = host_rmi_granule_delegate(phys);
if (ret != RMI_SUCCESS) {
@@ -533,7 +514,6 @@
ERROR("Unknown map_size=0x%lx\n", map_size);
return REALM_ERROR;
}
-
u_register_t desc = phys | S2TTE_ATTR_FWB_WB_RW;
ret = host_rmi_rtt_mapunprotected(rd, map_addr, map_level, desc);
@@ -877,7 +857,7 @@
/* MAP image regions */
while (i < (realm->par_size / PAGE_SIZE)) {
- ret = host_realm_map_protected_data(false, realm,
+ ret = host_realm_delegate_map_protected_data(false, realm,
realm->par_base + i * PAGE_SIZE,
PAGE_SIZE,
src_pa + i * PAGE_SIZE);
@@ -1130,17 +1110,12 @@
return REALM_SUCCESS;
}
- if (realm->state == REALM_STATE_NEW) {
- goto undo_from_new_state;
- }
-
- if (realm->state != REALM_STATE_ACTIVE) {
- ERROR("Invalid realm state found 0x%x\n", realm->state);
- return REALM_ERROR;
- }
-
+ /* For each REC - Destroy, undelegate and free */
for (unsigned int i = 0U; i < realm->rec_count; i++) {
- /* For each REC - Destroy, undelegate and free */
+ if (realm->rec[i] == 0U) {
+ break;
+ }
+
ret = host_rmi_rec_destroy(realm->rec[i]);
if (ret != RMI_SUCCESS) {
ERROR("%s() failed, rec=0x%lx ret=0x%lx\n",
@@ -1176,13 +1151,14 @@
ERROR("host_realm_tear_down_rtt_range() line=%u\n", __LINE__);
return REALM_ERROR;
}
- if (host_realm_tear_down_rtt_range(realm, 0UL, realm->ipa_ns_buffer,
- (realm->ipa_ns_buffer + realm->ns_buffer_size)) !=
- RMI_SUCCESS) {
- ERROR("host_realm_tear_down_rtt_range() line=%u\n", __LINE__);
- return REALM_ERROR;
+ if (realm->shared_mem_created == true) {
+ if (host_realm_tear_down_rtt_range(realm, 0UL, realm->ipa_ns_buffer,
+ (realm->ipa_ns_buffer + realm->ns_buffer_size)) !=
+ RMI_SUCCESS) {
+ ERROR("host_realm_tear_down_rtt_range() line=%u\n", __LINE__);
+ return REALM_ERROR;
+ }
}
-undo_from_new_state:
/*
* RD Destroy, undelegate and free
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c b/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
index 1948c1f..ff69869 100644
--- a/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,6 +25,11 @@
extern const char *rmi_exit[];
+#if ENABLE_PAUTH
+static uint128_t pauth_keys_before[NUM_KEYS];
+static uint128_t pauth_keys_after[NUM_KEYS];
+#endif
+
/*
* @Test_Aim@ Test realm payload creation, execution and destruction iteratively
*/
@@ -97,7 +102,8 @@
}
/*
- * @Test_Aim@ Test PAuth in realm
+ * @Test_Aim@ Create realm with multiple rec
+ * Test PAuth registers are preserved for each rec
*/
test_result_t host_realm_enable_pauth(void)
{
@@ -105,16 +111,17 @@
return TEST_RESULT_SKIPPED;
#else
bool ret1, ret2;
- u_register_t rec_flag[1] = {RMI_RUNNABLE};
+ u_register_t rec_flag[MAX_REC_COUNT] = {RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE,
+ RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE,};
struct realm realm;
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
- pauth_test_lib_fill_regs_and_template();
+ pauth_test_lib_fill_regs_and_template(pauth_keys_before);
if (!host_create_activate_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
(u_register_t)PAGE_POOL_BASE,
(u_register_t)PAGE_POOL_MAX_SIZE,
- 0UL, rec_flag, 1U)) {
+ 0UL, rec_flag, MAX_REC_COUNT)) {
return TEST_RESULT_FAIL;
}
@@ -123,24 +130,33 @@
return TEST_RESULT_FAIL;
}
- ret1 = host_enter_realm_execute(&realm, REALM_PAUTH_SET_CMD, RMI_EXIT_HOST_CALL, 0U);
+ for (unsigned int i = 0U; i < MAX_REC_COUNT; i++) {
+ ret1 = host_enter_realm_execute(&realm, REALM_PAUTH_SET_CMD,
+ RMI_EXIT_HOST_CALL, i);
- if (ret1) {
+ if (!ret1) {
+ ERROR("Pauth set cmd failed\n");
+ break;
+ }
/* Re-enter Realm to compare PAuth registers. */
ret1 = host_enter_realm_execute(&realm, REALM_PAUTH_CHECK_CMD,
- RMI_EXIT_HOST_CALL, 0U);
+ RMI_EXIT_HOST_CALL, i);
+ if (!ret1) {
+ ERROR("Pauth check cmd failed\n");
+ break;
+ }
}
ret2 = host_destroy_realm(&realm);
- if (!ret1) {
+ if (!ret1 || !ret2) {
ERROR("%s(): enter=%d destroy=%d\n",
__func__, ret1, ret2);
return TEST_RESULT_FAIL;
}
/* Check if PAuth keys are preserved. */
- if (!pauth_test_lib_compare_template()) {
+ if (!pauth_test_lib_compare_template(pauth_keys_before, pauth_keys_after)) {
ERROR("%s(): NS PAuth keys not preserved\n",
__func__);
return TEST_RESULT_FAIL;
@@ -456,11 +472,11 @@
base + (PAGE_SIZE * test_page_num));
for (unsigned int i = 0U; i < test_page_num; i++) {
- ret = host_realm_map_protected_data(true, &realm,
+ ret = host_realm_delegate_map_protected_data(true, &realm,
base + (PAGE_SIZE * i), PAGE_SIZE,
base + (PAGE_SIZE * i));
if (ret != REALM_SUCCESS) {
- ERROR("host_realm_map_protected_data failed\n");
+ ERROR("host_realm_delegate_map_protected_data failed\n");
goto destroy_realm;
}
}
@@ -548,9 +564,9 @@
base = (u_register_t)page_alloc(PAGE_SIZE);
- ret = host_realm_map_protected_data(true, &realm, base, PAGE_SIZE, base);
+ ret = host_realm_delegate_map_protected_data(true, &realm, base, PAGE_SIZE, base);
if (ret != RMI_SUCCESS) {
- ERROR("host_realm_map_protected_data failede\n");
+ ERROR("host_realm_delegate_map_protected_data failede\n");
goto destroy_realm;
}
host_shared_data_set_host_val(&realm, 0U, HOST_ARG1_INDEX, base);
@@ -584,3 +600,676 @@
return host_call_result;
}
+/*
+ * Test aims to generate REALM Exit due to abort
+ * when access page with RIPAS=DESTOYED HIPAS=ASSIGNED
+ * Host maps a protected page (calls data_create) when realm is in new state
+ * Initial state of PAGE is RIPAS=RAM HIPAS=ASSIGNED
+ * Host calls data_destroy, new state HIPAS=UNASSIGNED RIPAS=DESTROYED
+ * Enter Realm, Rec0 executes from page, and Rec1 reads the page
+ * Realm should trigger an Instr/Data abort, and will exit to Host.
+ * The Host verifies exit reason is Instr/Data abort
+ */
+test_result_t host_realm_abort_unassigned_destroyed(void)
+{
+ bool ret1, ret2;
+ test_result_t res = TEST_RESULT_FAIL;
+ u_register_t ret, data, top;
+ struct realm realm;
+ struct rmi_rec_run *run;
+ struct rtt_entry rtt;
+ u_register_t rec_flag[2U] = {RMI_RUNNABLE, RMI_RUNNABLE}, base;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (!host_create_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE,
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ 0UL, rec_flag, 2U)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ goto destroy_realm;
+ }
+
+ base = (u_register_t)page_alloc(PAGE_SIZE);
+
+ run = (struct rmi_rec_run *)realm.run[0];
+
+ /* DATA_CREATE
+ * Copies content of TFTF_BASE in newly created page, any PA can be used for dummy copy
+ * maps 1:1 IPA:PA
+ */
+ ret = host_realm_delegate_map_protected_data(false, &realm, base, PAGE_SIZE, TFTF_BASE);
+ if (ret != RMI_SUCCESS) {
+ ERROR("host_realm_delegate_map_protected_data failed\n");
+ goto destroy_realm;
+ }
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (ret != RMI_SUCCESS || rtt.state != RMI_ASSIGNED ||
+ (rtt.ripas != RMI_RAM)) {
+ ERROR("wrong state after DATA_CRATE_UNKNOWN\n");
+ goto undelegate_destroy;
+ }
+ INFO("Initial state base = 0x%lx rtt.state=0x%lx rtt.ripas=0x%lx\n",
+ base, rtt.state, rtt.ripas);
+ host_shared_data_set_host_val(&realm, 0U, HOST_ARG1_INDEX, base);
+ host_shared_data_set_host_val(&realm, 1U, HOST_ARG1_INDEX, base);
+
+ ret = host_rmi_data_destroy(realm.rd, base, &data, &top);
+ if (ret != RMI_SUCCESS || data != base) {
+ ERROR("host_rmi_data_destroy failed\n");
+ goto undelegate_destroy;
+ }
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+ rtt.ripas != RMI_DESTROYED) {
+ ERROR("Wrong state after host_rmi_data_destroy\n");
+ goto undelegate_destroy;
+ }
+
+ INFO("New state4 base = 0x%lx rtt.state=0x%lx rtt.ripas=0x%lx\n",
+ base, rtt.state, rtt.ripas);
+
+ if (host_realm_activate(&realm) != REALM_SUCCESS) {
+ ERROR("%s() failed\n", "host_realm_activate");
+ goto undelegate_destroy;
+ }
+
+ /* Realm0 expect rec exit due to Instr Abort unassigned destroyed page */
+ ret1 = host_enter_realm_execute(&realm, REALM_INSTR_FETCH_CMD,
+ RMI_EXIT_SYNC, 0U);
+
+ /* ESR.EC == 0b100000 Instruction Abort from a lower Exception level */
+ if (!ret1 || ((run->exit.hpfar >> 4U) != (base >> PAGE_SIZE_SHIFT)
+ || (EC_BITS(run->exit.esr) != EC_IABORT_LOWER_EL)
+ || ((run->exit.esr & ISS_IFSC_MASK) < IFSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_IFSC_MASK) > IFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
+ ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
+ goto undelegate_destroy;
+ }
+ INFO("IA FAR=0x%lx, HPFAR=0x%lx ESR=0x%lx\n", run->exit.far, run->exit.hpfar,
+ run->exit.esr);
+
+ run = (struct rmi_rec_run *)realm.run[1];
+
+ /* Realm1 expect rec exit due to Data Abort unassigned destroyed page */
+ ret1 = host_enter_realm_execute(&realm, REALM_DATA_ACCESS_CMD,
+ RMI_EXIT_SYNC, 1U);
+
+ /* ESR.EC == 0b100100 Data Abort exception from a lower Exception level */
+ if (!ret1 || ((run->exit.hpfar >> 4U) != (base >> PAGE_SIZE_SHIFT)
+ || (EC_BITS(run->exit.esr) != EC_DABORT_LOWER_EL)
+ || ((run->exit.esr & ISS_DFSC_MASK) < DFSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_DFSC_MASK) > DFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
+ ERROR("Rec did not fault\n");
+ goto undelegate_destroy;
+ }
+ INFO("DA FAR=0x%lx, HPFAR=0x%lx ESR= 0x%lx\n", run->exit.far, run->exit.hpfar,
+ run->exit.esr);
+ res = TEST_RESULT_SUCCESS;
+
+undelegate_destroy:
+ ret = host_rmi_granule_undelegate(base);
+destroy_realm:
+ ret2 = host_destroy_realm(&realm);
+
+ if (!ret2) {
+ ERROR("%s(): destroy=%d\n",
+ __func__, ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ return res;
+}
+
+/*
+ * Test aims to generate REALM Exit due to Abort
+ * when access page with RIPAS=RAM HIPAS=UNASSIGNED
+ * Host allocates a PAGE, calls init_ripas when realm is in new state
+ * Initial state of PAGE is RIPAS=RAM HIPAS=UNASSIGNED
+ * Enter Realm, REC0 executes from page, and REC1 reads the page
+ * Realm should trigger an Instr/Data abort, and will exit to Host.
+ * Host verifies exit reason is Instr/Data abort.
+ */
+test_result_t host_realm_abort_unassigned_ram(void)
+{
+ bool ret1, ret2;
+ u_register_t ret, top;
+ struct realm realm;
+ struct rmi_rec_run *run;
+ struct rtt_entry rtt;
+ test_result_t res = TEST_RESULT_FAIL;
+ u_register_t rec_flag[2U] = {RMI_RUNNABLE, RMI_RUNNABLE}, base;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (!host_create_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE,
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ 0UL, rec_flag, 2U)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ goto destroy_realm;
+ }
+
+ /* This is dummy allocation to get a base address */
+ base = (u_register_t)page_alloc(PAGE_SIZE);
+
+ run = (struct rmi_rec_run *)realm.run[0];
+
+ /* Set RIPAS of PAGE to RAM */
+ ret = host_rmi_rtt_init_ripas(realm.rd, base, base + PAGE_SIZE, &top);
+ if (ret != RMI_SUCCESS) {
+ ERROR("%s() failed, ret=0x%lx line=%u\n",
+ "host_rmi_rtt_init_ripas", ret, __LINE__);
+ goto destroy_realm;
+ }
+ if (host_realm_activate(&realm) != REALM_SUCCESS) {
+ ERROR("%s() failed\n", "host_realm_activate");
+ goto destroy_realm;
+ }
+
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+ (rtt.ripas != RMI_RAM)) {
+ ERROR("wrong initial state\n");
+ goto destroy_realm;
+ }
+ INFO("Initial state base = 0x%lx rtt.state=0x%lx rtt.ripas=0x%lx\n",
+ base, rtt.state, rtt.ripas);
+ host_shared_data_set_host_val(&realm, 0U, HOST_ARG1_INDEX, base);
+ host_shared_data_set_host_val(&realm, 1U, HOST_ARG1_INDEX, base);
+
+ /* Rec0 expect rec exit due to Instr Abort unassigned ram page */
+ ret1 = host_enter_realm_execute(&realm, REALM_INSTR_FETCH_CMD,
+ RMI_EXIT_SYNC, 0U);
+
+ /* ESR.EC == 0b100000 Instruction Abort from a lower Exception level */
+ if (!ret1 || ((run->exit.hpfar >> 4U) != (base >> PAGE_SIZE_SHIFT)
+ || (EC_BITS(run->exit.esr) != EC_IABORT_LOWER_EL)
+ || ((run->exit.esr & ISS_IFSC_MASK) < IFSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_IFSC_MASK) > IFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
+ ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
+ goto destroy_realm;
+ }
+ INFO("IA FAR=0x%lx, HPFAR=0x%lx ESR=0x%lx\n", run->exit.far, run->exit.hpfar,
+ run->exit.esr);
+ run = (struct rmi_rec_run *)realm.run[1];
+
+ /* Rec1 expect rec exit due to Data Abort unassigned ram page */
+ ret1 = host_enter_realm_execute(&realm, REALM_DATA_ACCESS_CMD,
+ RMI_EXIT_SYNC, 1U);
+
+ /* ESR.EC == 0b100100 Data Abort exception from a lower Exception level */
+ if (!ret1 || ((run->exit.hpfar >> 4U) != (base >> PAGE_SIZE_SHIFT)
+ || (EC_BITS(run->exit.esr) != EC_DABORT_LOWER_EL)
+ || ((run->exit.esr & ISS_DFSC_MASK) < DFSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_DFSC_MASK) > DFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
+ ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
+ goto destroy_realm;
+ }
+ INFO("DA FAR=0x%lx, HPFAR=0x%lx ESR=0x%lx\n", run->exit.far, run->exit.hpfar,
+ run->exit.esr);
+ res = TEST_RESULT_SUCCESS;
+
+destroy_realm:
+ ret2 = host_destroy_realm(&realm);
+
+ if (!ret2) {
+ ERROR("%s(): destroy=%d\n",
+ __func__, ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ return res;
+}
+
+/*
+ * Test aims to generate REALM Exit due to Abort
+ * when access page with RIPAS=DESTOYED HIPAS=Assigned
+ * Host maps a protected page (calls data_create) when realm is in new state
+ * initial state of PAGE is RIPAS=RAM HIPAS=ASSIGNED
+ * Host calls data_destroy, new state HIPAS=UNASSIGNED RIPAS=DESTROYED
+ * Host calls data_create_unknown, new state HIPAS=ASSIGNED RIPAS=DESTROYED
+ * Enter Realm, REC0 executes from page, and REC1 reads the page
+ * Realm should trigger an Instr/Data abort, and will exit to Host.
+ * The Host verifies exit reason is Instr/Data abort
+ */
+test_result_t host_realm_abort_assigned_destroyed(void)
+{
+ bool ret1, ret2;
+ test_result_t res = TEST_RESULT_FAIL;
+ u_register_t ret, top, data;
+ struct realm realm;
+ struct rmi_rec_run *run;
+ struct rtt_entry rtt;
+ u_register_t rec_flag[2U] = {RMI_RUNNABLE, RMI_RUNNABLE}, base;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (!host_create_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE,
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ 0UL, rec_flag, 2U)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ goto destroy_realm;
+ }
+
+ base = (u_register_t)page_alloc(PAGE_SIZE);
+ run = (struct rmi_rec_run *)realm.run[0];
+
+ /* DATA_CREATE */
+ /* Copied content of TFTF_BASE to new page, can use any adr, maps 1:1 IPA:PA */
+ ret = host_realm_delegate_map_protected_data(false, &realm, base, PAGE_SIZE, TFTF_BASE);
+ if (ret != RMI_SUCCESS) {
+ ERROR("host_realm_delegate_map_protected_data failed\n");
+ goto destroy_realm;
+ }
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (ret != RMI_SUCCESS || rtt.state != RMI_ASSIGNED ||
+ (rtt.ripas != RMI_RAM)) {
+ ERROR("wrong state after data create\n");
+ goto destroy_realm;
+ }
+ INFO("Initial state base = 0x%lx rtt.state=0x%lx rtt.ripas=0x%lx\n",
+ base, rtt.state, rtt.ripas);
+ host_shared_data_set_host_val(&realm, 0U, HOST_ARG1_INDEX, base);
+ host_shared_data_set_host_val(&realm, 1U, HOST_ARG1_INDEX, base);
+
+ if (host_realm_activate(&realm) != REALM_SUCCESS) {
+ ERROR("%s() failed\n", "host_realm_activate");
+ goto destroy_realm;
+ }
+
+ ret = host_rmi_data_destroy(realm.rd, base, &data, &top);
+ if (ret != RMI_SUCCESS || data != base) {
+ ERROR("host_rmi_data_destroy failed\n");
+ goto destroy_realm;
+ }
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+ rtt.ripas != RMI_DESTROYED) {
+ ERROR("Wrong state after host_rmi_data_destroy\n");
+ goto destroy_realm;
+ }
+ ret = host_rmi_granule_undelegate(base);
+
+ /* DATA_CREATE_UNKNOWN */
+ ret = host_realm_delegate_map_protected_data(true, &realm, base, PAGE_SIZE, 0U);
+ if (ret != RMI_SUCCESS) {
+ ERROR("host_realm_delegate_map_protected_data failede\n");
+ goto destroy_realm;
+ }
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (ret != RMI_SUCCESS || rtt.state != RMI_ASSIGNED ||
+ (rtt.ripas != RMI_DESTROYED)) {
+ ERROR("wrong state after data create unknown\n");
+ goto destroy_data;
+ }
+
+ /* Rec0, expect rec exit due to Instr Abort assigned destroyed page */
+ ret1 = host_enter_realm_execute(&realm, REALM_INSTR_FETCH_CMD,
+ RMI_EXIT_SYNC, 0U);
+
+ /* ESR.EC == 0b100000 Instruction Abort from a lower Exception level */
+ if (!ret1 || ((run->exit.hpfar >> 4U) != (base >> PAGE_SIZE_SHIFT)
+ || (EC_BITS(run->exit.esr) != EC_IABORT_LOWER_EL)
+ || ((run->exit.esr & ISS_IFSC_MASK) < IFSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_IFSC_MASK) > IFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
+ ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
+ goto destroy_data;
+ }
+ INFO("IA FAR=0x%lx, HPFAR=0x%lx ESR=0x%lx\n", run->exit.far, run->exit.hpfar,
+ run->exit.esr);
+ run = (struct rmi_rec_run *)realm.run[1];
+
+ /* Rec1 expect rec exit due to Data Abort assigned destroyed page */
+ ret1 = host_enter_realm_execute(&realm, REALM_DATA_ACCESS_CMD,
+ RMI_EXIT_SYNC, 1U);
+
+ /* ESR.EC == 0b100100 Data Abort exception from a lower Exception level */
+ if (!ret1 || ((run->exit.hpfar >> 4U) != (base >> PAGE_SIZE_SHIFT)
+ || (EC_BITS(run->exit.esr) != EC_DABORT_LOWER_EL)
+ || ((run->exit.esr & ISS_DFSC_MASK) < DFSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_DFSC_MASK) > DFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U))) {
+ ERROR("Rec did not fault ESR=0x%lx\n", run->exit.esr);
+ goto destroy_data;
+ }
+ INFO("DA FAR=0x%lx, HPFAR=0x%lx ESR=0x%lx\n", run->exit.far, run->exit.hpfar,
+ run->exit.esr);
+ res = TEST_RESULT_SUCCESS;
+
+destroy_data:
+ ret = host_rmi_data_destroy(realm.rd, base, &data, &top);
+ ret = host_rmi_granule_undelegate(base);
+destroy_realm:
+ ret2 = host_destroy_realm(&realm);
+
+ if (!ret2) {
+ ERROR("%s(): destroy=%d\n",
+ __func__, ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ return res;
+}
+
+/*
+ * Test aims to generate SEA in Realm by accessing
+ * PAGE with HIPAS=assigned/unassigned and RIPAS=EMPTY
+ * Host creates and executes 4 recs to generate SEA
+ * Rec exception handler runs and returns back ESR to Host
+ * Host validates ESR
+ * Rec0 generated IA unassigned empty
+ * Rec1 generated DA unassigned empty
+ * Rec2 generated IA for assigned empty
+ * Rec3 generated DA for assigned empty
+ */
+test_result_t host_realm_sea_empty(void)
+{
+ bool ret1, ret2;
+ test_result_t res = TEST_RESULT_FAIL;
+ u_register_t ret, base, esr;
+ struct realm realm;
+ struct rtt_entry rtt;
+ u_register_t rec_flag[] = {RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE};
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (!host_create_activate_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE,
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ 0UL, rec_flag, 4U)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ goto destroy_realm;
+ }
+
+ base = (u_register_t)page_alloc(PAGE_SIZE);
+
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (rtt.state != RMI_UNASSIGNED ||
+ (rtt.ripas != RMI_EMPTY)) {
+ ERROR("wrong initial state\n");
+ goto destroy_realm;
+ }
+ host_shared_data_set_host_val(&realm, 0U, HOST_ARG1_INDEX, base);
+ host_shared_data_set_host_val(&realm, 1U, HOST_ARG1_INDEX, base);
+ host_shared_data_set_host_val(&realm, 2U, HOST_ARG1_INDEX, base);
+ host_shared_data_set_host_val(&realm, 3U, HOST_ARG1_INDEX, base);
+
+ /* Rec0 expect IA due to SEA unassigned empty page */
+ ret1 = host_enter_realm_execute(&realm, REALM_INSTR_FETCH_CMD,
+ RMI_EXIT_HOST_CALL, 0U);
+ if (!ret1) {
+ ERROR("Rec0 did not fault\n");
+ goto destroy_realm;
+ }
+
+ /* get ESR set by Realm exception handler */
+ esr = host_shared_data_get_realm_val(&realm, 0U, HOST_ARG2_INDEX);
+ if (((esr & ISS_IFSC_MASK) != IFSC_NO_WALK_SEA) || (EC_BITS(esr) != EC_IABORT_CUR_EL)) {
+ ERROR("Rec0 incorrect ESR=0x%lx\n", esr);
+ goto destroy_realm;
+ }
+ INFO("Rec0 ESR=0x%lx\n", esr);
+
+ /* Rec1 expect DA due to SEA unassigned empty page */
+ ret1 = host_enter_realm_execute(&realm, REALM_DATA_ACCESS_CMD,
+ RMI_EXIT_HOST_CALL, 1U);
+ if (!ret1) {
+ ERROR("Rec1 did not fault\n");
+ goto destroy_realm;
+ }
+
+ /* get ESR set by Realm exception handler */
+ esr = host_shared_data_get_realm_val(&realm, 1U, HOST_ARG2_INDEX);
+ if (((esr & ISS_DFSC_MASK) != DFSC_NO_WALK_SEA) || (EC_BITS(esr) != EC_DABORT_CUR_EL)) {
+ ERROR("Rec1 incorrect ESR=0x%lx\n", esr);
+ goto destroy_realm;
+ }
+ INFO("Rec1 ESR=0x%lx\n", esr);
+
+ /* DATA_CREATE_UNKNOWN */
+ ret = host_realm_delegate_map_protected_data(true, &realm, base, PAGE_SIZE, 0U);
+ if (ret != RMI_SUCCESS) {
+ ERROR("host_realm_map_protected_data failed\n");
+ goto destroy_realm;
+ }
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (rtt.state != RMI_ASSIGNED ||
+ (rtt.ripas != RMI_EMPTY)) {
+ ERROR("wrong state after DATA_CRATE_UNKNOWN\n");
+ goto undelegate_destroy;
+ }
+ INFO("state base = 0x%lx rtt.state=0x%lx rtt.ripas=0x%lx\n",
+ base, rtt.state, rtt.ripas);
+
+ /* Rec2 expect IA due to SEA assigned empty page */
+ ret1 = host_enter_realm_execute(&realm, REALM_INSTR_FETCH_CMD,
+ RMI_EXIT_HOST_CALL, 2U);
+
+ if (!ret1) {
+ ERROR("Rec2 did not fault\n");
+ goto undelegate_destroy;
+ }
+
+ /* get ESR set by Realm exception handler */
+ esr = host_shared_data_get_realm_val(&realm, 2U, HOST_ARG2_INDEX);
+ if (((esr & ISS_IFSC_MASK) != IFSC_NO_WALK_SEA) || (EC_BITS(esr) != EC_IABORT_CUR_EL)) {
+ ERROR("Rec2 incorrect ESR=0x%lx\n", esr);
+ goto destroy_realm;
+ }
+ INFO("Rec2 ESR=0x%lx\n", esr);
+
+ /* Rec3 expect DA due to SEA unassigned empty page */
+ ret1 = host_enter_realm_execute(&realm, REALM_DATA_ACCESS_CMD,
+ RMI_EXIT_HOST_CALL, 3U);
+ if (!ret1) {
+ ERROR("Rec3 did not fault\n");
+ goto undelegate_destroy;
+ }
+
+ /* get ESR set by Realm exception handler */
+ esr = host_shared_data_get_realm_val(&realm, 3U, HOST_ARG2_INDEX);
+ if (((esr & ISS_DFSC_MASK) != DFSC_NO_WALK_SEA) || (EC_BITS(esr) != EC_DABORT_CUR_EL)) {
+ ERROR("Rec3 incorrect ESR=0x%lx\n", esr);
+ }
+ INFO("Rec3 ESR=0x%lx\n", esr);
+ res = TEST_RESULT_SUCCESS;
+
+undelegate_destroy:
+ ret = host_rmi_granule_undelegate(base);
+destroy_realm:
+ ret2 = host_destroy_realm(&realm);
+
+ if (!ret2) {
+ ERROR("%s(): destroy=%d\n",
+ __func__, ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ return res;
+}
+
+/*
+ * Test aims to generate SEA in Realm by
+ * executing instructions in unprotected IPA - Rec0
+ * In Rec 1 , when HIPAS=UNASSIGNED_NS, we expect to get a Data abort.
+ * Then Host will inject SEA to realm.
+ * Realm exception handler runs and returns ESR back to Host
+ * Host validates ESR
+ */
+test_result_t host_realm_sea_unprotected(void)
+{
+
+ bool ret1, ret2;
+ test_result_t res = TEST_RESULT_FAIL;
+ u_register_t ret, base, base_ipa, esr;
+ unsigned int host_call_result;
+ u_register_t exit_reason;
+ struct realm realm;
+ struct rtt_entry rtt;
+ struct rmi_rec_run *run;
+ u_register_t rec_flag[2U] = {RMI_RUNNABLE, RMI_RUNNABLE};
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (!host_create_activate_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE,
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ 0UL, rec_flag, 2U)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ goto destroy_realm;
+ }
+
+ /* Can choose any unprotected IPA adr, TFTF_BASE chosen for convenience */
+ base = TFTF_BASE;
+ base_ipa = base | (1UL << (EXTRACT(RMI_FEATURE_REGISTER_0_S2SZ,
+ realm.rmm_feat_reg0) - 1U));
+
+
+ ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+ if (rtt.state != RMI_UNASSIGNED) {
+ ERROR("wrong state\n");
+ goto destroy_realm;
+ }
+
+ run = (struct rmi_rec_run *)realm.run[0];
+ host_shared_data_set_host_val(&realm, 0U, HOST_ARG1_INDEX, base_ipa);
+ host_shared_data_set_host_val(&realm, 1U, HOST_ARG1_INDEX, base_ipa);
+
+ /* Rec0 expect SEA in realm due to IA unprotected IPA page */
+ ret1 = host_enter_realm_execute(&realm, REALM_INSTR_FETCH_CMD,
+ RMI_EXIT_HOST_CALL, 0U);
+ if (!ret1) {
+ ERROR("Rec0 did not fault\n");
+ goto destroy_realm;
+ }
+
+ /* get ESR set by Realm exception handler */
+ esr = host_shared_data_get_realm_val(&realm, 0U, HOST_ARG2_INDEX);
+ if (((esr & ISS_IFSC_MASK) != IFSC_NO_WALK_SEA) || (EC_BITS(esr) != EC_IABORT_CUR_EL)) {
+ ERROR("Rec0 incorrect ESR=0x%lx\n", esr);
+ goto destroy_realm;
+ }
+ INFO("Rec0 ESR=0x%lx\n", esr);
+
+ run = (struct rmi_rec_run *)realm.run[1U];
+
+ /* Rec1 expect rec exit due to DA unprotected IPA page when HIPAS is UNASSIGNED_NS */
+ ret1 = host_enter_realm_execute(&realm, REALM_DATA_ACCESS_CMD,
+ RMI_EXIT_SYNC, 1U);
+
+ if (!ret1 || (run->exit.hpfar >> 4U) != (base_ipa >> PAGE_SIZE_SHIFT)
+ || (EC_BITS(run->exit.esr) != EC_DABORT_LOWER_EL)
+ || ((run->exit.esr & ISS_DFSC_MASK) < DFSC_L0_TRANS_FAULT)
+ || ((run->exit.esr & ISS_DFSC_MASK) > DFSC_L3_TRANS_FAULT)
+ || ((run->exit.esr & (1UL << ESR_ISS_EABORT_EA_BIT)) != 0U)) {
+ ERROR("Rec1 did not fault exit=0x%lx ret1=%d HPFAR=0x%lx esr=0x%lx\n",
+ run->exit.exit_reason, ret1, run->exit.hpfar, run->exit.esr);
+ goto destroy_realm;
+ }
+ INFO("Host DA FAR=0x%lx, HPFAR=0x%lx\n", run->exit.far, run->exit.hpfar);
+ INFO("Injecting SEA to Realm\n");
+
+ /* Inject SEA back to Realm */
+ run->entry.flags = REC_ENTRY_FLAG_INJECT_SEA;
+
+ /* Rec1 re-entry expect exception handler to run, return ESR */
+ ret = host_realm_rec_enter(&realm, &exit_reason, &host_call_result, 1U);
+ if (ret != RMI_SUCCESS || exit_reason != RMI_EXIT_HOST_CALL) {
+ ERROR("rec1 failed ret=0x%lx exit_reason=0x%lx", ret, run->exit.exit_reason);
+ goto destroy_realm;
+ }
+
+ /* get ESR set by Realm exception handler */
+ esr = host_shared_data_get_realm_val(&realm, 1U, HOST_ARG2_INDEX);
+ if (((esr & ISS_DFSC_MASK) != DFSC_NO_WALK_SEA) || (EC_BITS(esr) != EC_DABORT_CUR_EL)) {
+ ERROR("Rec1 incorrect ESR=0x%lx\n", esr);
+ goto destroy_realm;
+ }
+ INFO("Rec1 ESR=0x%lx\n", esr);
+ res = host_call_result;
+
+destroy_realm:
+ ret2 = host_destroy_realm(&realm);
+
+ if (!ret2) {
+ ERROR("%s(): destroy=%d\n",
+ __func__, ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ return res;
+}
+
+/*
+ * @Test_Aim@ Test to check if DIT bit is preserved across NS/RL switch
+ */
+test_result_t host_realm_enable_dit(void)
+{
+ bool ret1, ret2;
+ struct realm realm;
+ u_register_t rec_flag[] = {RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE,
+ RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE}, dit;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (!host_create_activate_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE,
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ 0UL, rec_flag, MAX_REC_COUNT)) {
+ return TEST_RESULT_FAIL;
+ }
+ if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Enable FEAT_DIT on Host */
+ write_dit(DIT_BIT);
+ for (unsigned int i = 0; i < MAX_REC_COUNT; i++) {
+ host_shared_data_set_host_val(&realm, i, HOST_ARG1_INDEX, 10U);
+ ret1 = host_enter_realm_execute(&realm, REALM_DIT_CHECK_CMD,
+ RMI_EXIT_HOST_CALL, i);
+ if (!ret1) {
+ break;
+ }
+ }
+
+ ret2 = host_destroy_realm(&realm);
+
+ dit = read_dit();
+ if (dit != DIT_BIT) {
+ ERROR("Host DIT bit not preserved\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ write_dit(0U);
+ if (!ret1 || !ret2) {
+ ERROR("%s(): enter=%d destroy=%d\n",
+ __func__, ret1, ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index ad63e68..8b53bb0 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -787,10 +787,11 @@
/**
* Initializes receiver permissions in a memory transaction descriptor.
*/
-struct ffa_memory_access ffa_memory_access_init_permissions(
+struct ffa_memory_access ffa_memory_access_init(
ffa_id_t receiver_id, enum ffa_data_access data_access,
enum ffa_instruction_access instruction_access,
- ffa_memory_receiver_flags_t flags)
+ ffa_memory_receiver_flags_t flags,
+ struct ffa_memory_access_impdef *impdef)
{
struct ffa_memory_access access;
access.reserved_0 = 0;
@@ -800,6 +801,8 @@
access.receiver_permissions.permissions.data_access = data_access;
access.receiver_permissions.permissions.instruction_access =
instruction_access;
+ access.impdef = impdef != NULL ? *impdef :
+ (struct ffa_memory_access_impdef){{0, 0}};
return access;
}
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index dce4b7f..ee25c82 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -323,7 +323,7 @@
* because `mb->recv` will be overwritten if sending a fragmented
* message.
*/
- memcpy(out, mb->recv, total_size);
+ memcpy(out, mb->recv, fragment_size);
if (region_out->receiver_count == 0) {
VERBOSE("copied region has no recivers\n");
@@ -370,7 +370,7 @@
return false;
}
- fragment_size = ret.arg3;
+ fragment_size = ret.arg2;
if (fragment_size == 0) {
ERROR("%s: fragment size must not be 0\n", __func__);
return false;
@@ -537,13 +537,13 @@
*ret = ffa_mem_donate(total_length, fragment_length);
break;
default:
- ERROR("%s: Invalid func id %d!\n", __func__, mem_func);
+ ERROR("%s: Invalid func id %x!\n", __func__, mem_func);
return FFA_MEMORY_HANDLE_INVALID;
}
if (is_ffa_call_error(*ret)) {
VERBOSE("%s: Failed to send memory: %d\n", __func__,
- ffa_error_code(ret));
+ ffa_error_code(*ret));
return FFA_MEMORY_HANDLE_INVALID;
}
@@ -827,6 +827,6 @@
? FFA_DATA_ACCESS_NOT_SPECIFIED
: FFA_DATA_ACCESS_RW;
- return ffa_memory_access_init_permissions(receiver_id, data_access,
- instruction_access, 0);
+ return ffa_memory_access_init(receiver_id, data_access,
+ instruction_access, 0, NULL);
}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c b/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
index 19f33a2..0a345d4 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
@@ -60,7 +60,7 @@
return TEST_RESULT_SKIPPED;
}
- CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ CHECK_SPMC_TESTING_SETUP(1, 2, expected_sp_uuids);
GET_TFTF_MAILBOX(mb);
@@ -84,9 +84,12 @@
return TEST_RESULT_FAIL;
}
- /* Retrieve the shared page and attempt accessing it. */
+ /*
+ * Retrieve the shared page and attempt accessing it.
+ * Tell SP to expect an exception.
+ */
ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_SHARE_SMC32,
- handle, 0, 1);
+ handle, 0, 1, true);
/* Undelegate the shared page. */
retmm = host_rmi_granule_undelegate((u_register_t)&share_page);
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 f678a6a..af5a077 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,14 +1,22 @@
/*
- * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include "arch_features.h"
+#include "arch_helpers.h"
+#include "ffa_helpers.h"
+#include "ffa_svc.h"
+#include "stdint.h"
+#include "utils_def.h"
#include <debug.h>
#include "ffa_helpers.h"
+#include <sync.h>
#include <cactus_test_cmds.h>
#include <ffa_endpoints.h>
+#include <host_realm_rmi.h>
#include <spm_common.h>
#include <spm_test_helpers.h>
#include <test_helpers.h>
@@ -35,9 +43,12 @@
/* Memory section to be used for memory share operations */
static __aligned(PAGE_SIZE) uint8_t
share_page[PAGE_SIZE * FRAGMENTED_SHARE_PAGE_COUNT];
+static __aligned(PAGE_SIZE) uint8_t donate_page[PAGE_SIZE];
static __aligned(PAGE_SIZE) uint8_t consecutive_donate_page[PAGE_SIZE];
static __aligned(PAGE_SIZE) uint8_t four_share_pages[PAGE_SIZE * 4];
+static bool gpc_abort_triggered;
+
static bool check_written_words(uint32_t *ptr, uint32_t word, uint32_t wcount)
{
VERBOSE("TFTF - Memory contents after SP use:\n");
@@ -90,6 +101,34 @@
return true;
}
+static bool data_abort_handler(void)
+{
+ uint64_t esr_elx = IS_IN_EL2() ? read_esr_el2() : read_esr_el1();
+
+ VERBOSE("%s esr_elx %llx\n", __func__, esr_elx);
+
+ if (EC_BITS(esr_elx) == EC_DABORT_CUR_EL) {
+ /* Synchronous data abort triggered by Granule protection */
+ if ((ISS_BITS(esr_elx) & ISS_DFSC_MASK) == DFSC_GPF_DABORT) {
+ VERBOSE("%s GPF Data Abort caught to address: %llx\n",
+ __func__, (uint64_t)read_far_el2());
+ gpc_abort_triggered = true;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool get_gpc_abort_triggered(void)
+{
+ bool ret = gpc_abort_triggered;
+
+ gpc_abort_triggered = false;
+
+ return ret;
+}
+
/**
* Test invocation to FF-A memory sharing interfaces that should return in an
* error.
@@ -105,7 +144,7 @@
(uintptr_t)0x0000880080001000,
};
- CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ CHECK_SPMC_TESTING_SETUP(1, 2, expected_sp_uuids);
for (unsigned i = 0; i < 3; i++) {
if (!test_memory_send_expect_denied(
@@ -144,6 +183,10 @@
ffa_memory_handle_t handle;
uint32_t *ptr;
struct mailbox_buffers mb;
+ unsigned int rme_supported = get_armv9_2_feat_rme_support();
+ const bool check_gpc_fault =
+ mem_func != FFA_MEM_SHARE_SMC32 &&
+ rme_supported != 0U;
/* Arbitrarily write 5 words after using memory. */
const uint32_t nr_words_to_write = 5;
@@ -155,16 +198,24 @@
/***********************************************************************
* Check if SPMC has ffa_version and expected FFA endpoints are deployed.
**********************************************************************/
- CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ CHECK_SPMC_TESTING_SETUP(1, 2, expected_sp_uuids);
GET_TFTF_MAILBOX(mb);
- if (constituents_count != 1) {
- WARN("Test expects constituents_count to be 1\n");
+ /*
+ * If the RME is enabled for the platform under test, check that the
+ * GPCs are working as expected, as such setup the exception handler.
+ */
+ if (check_gpc_fault) {
+ register_custom_sync_exception_handler(data_abort_handler);
}
for (size_t i = 0; i < constituents_count; i++) {
- VERBOSE("TFTF - Address: %p\n", constituents[0].address);
+ VERBOSE("Sharing Address: %p\n", constituents[i].address);
+ ptr = (uint32_t *)constituents[i].address;
+ for (size_t j = 0; j < nr_words_to_write; j++) {
+ ptr[j] = mem_func + 0xFFA;
+ }
}
handle = memory_init_and_send((struct ffa_memory_region *)mb.send,
@@ -181,15 +232,21 @@
ptr = (uint32_t *)constituents[0].address;
ret = cactus_mem_send_cmd(SENDER, borrower, mem_func, handle, 0,
- nr_words_to_write);
+ nr_words_to_write, false);
- if (!is_ffa_direct_response(ret)) {
+ if (!is_ffa_direct_response(ret) ||
+ cactus_get_response(ret) != CACTUS_SUCCESS) {
+ ffa_mem_reclaim(handle, 0);
+ ERROR("Failed memory send operation!\n");
return TEST_RESULT_FAIL;
}
- if (cactus_get_response(ret) != CACTUS_SUCCESS) {
- ERROR("Failed memory send operation!\n");
- return TEST_RESULT_FAIL;
+ /*
+ * If there is RME support, look to trigger an exception as soon as the
+ * security state is update, due to GPC fault.
+ */
+ if (check_gpc_fault) {
+ *ptr = 0xBEEF;
}
if (mem_func != FFA_MEM_DONATE_SMC32) {
@@ -200,12 +257,27 @@
return TEST_RESULT_FAIL;
}
- /*
- * Check that borrower used the memory as expected for this
- * test.
- */
- if (!check_written_words(ptr, mem_func, nr_words_to_write)) {
- ERROR("Fail because of state of memory.\n");
+ for (uint32_t i = 0; i < constituents_count; i++) {
+ ptr = constituents[i].address;
+
+ /*
+ * Check that borrower used the memory as expected
+ * for FFA_MEM_SHARE test.
+ */
+ if (mem_func == FFA_MEM_SHARE_SMC32 &&
+ !check_written_words(ptr,
+ mem_func + 0xFFAU,
+ nr_words_to_write)) {
+ ERROR("Fail because of state of memory.\n");
+ return TEST_RESULT_FAIL;
+ }
+ }
+ }
+
+ if (check_gpc_fault) {
+ unregister_custom_sync_exception_handler();
+ if (!get_gpc_abort_triggered()) {
+ ERROR("No exception due to GPC for lend/donate with RME.\n");
return TEST_RESULT_FAIL;
}
}
@@ -229,6 +301,7 @@
test_result_t test_mem_lend_sp(void)
{
struct ffa_memory_region_constituent constituents[] = {
+ {(void *)four_share_pages, 4, 0},
{(void *)share_page, 1, 0}
};
@@ -242,7 +315,7 @@
test_result_t test_mem_donate_sp(void)
{
struct ffa_memory_region_constituent constituents[] = {
- {(void *)share_page, 1, 0}
+ {(void *)donate_page, 1, 0}
};
const uint32_t constituents_count = sizeof(constituents) /
sizeof(struct ffa_memory_region_constituent);
@@ -258,7 +331,7 @@
const uint32_t constituents_count = sizeof(constituents) /
sizeof(struct ffa_memory_region_constituent);
- CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ CHECK_SPMC_TESTING_SETUP(1, 2, expected_sp_uuids);
test_result_t ret = test_memory_send_sp(FFA_MEM_DONATE_SMC32, SP_ID(1),
constituents,
@@ -302,7 +375,7 @@
/***********************************************************************
* Check if SPMC's ffa_version and presence of expected FF-A endpoints.
**********************************************************************/
- CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ CHECK_SPMC_TESTING_SETUP(1, 2, expected_sp_uuids);
ret = cactus_req_mem_send_send_cmd(HYP_ID, sender_sp, mem_func,
receiver_sp, non_secure);
@@ -334,7 +407,7 @@
/**********************************************************************
* Check if SPMC's ffa_version and presence of expected FF-A endpoints.
*********************************************************************/
- CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ CHECK_SPMC_TESTING_SETUP(1, 2, expected_sp_uuids);
ret = cactus_req_mem_send_send_cmd(HYP_ID, sender_sp, mem_func,
receiver_vm, false);
@@ -418,7 +491,6 @@
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;
@@ -426,7 +498,7 @@
ffa_memory_access_init_permissions_from_mem_func(
RECEIVER, FFA_MEM_LEND_SMC32);
- CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+ CHECK_SPMC_TESTING_SETUP(1, 2, expected_sp_uuids);
GET_TFTF_MAILBOX(mb);
@@ -454,7 +526,8 @@
VERBOSE("Memory has been shared!\n");
ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_LEND_SMC32, handle,
- FFA_MEMORY_REGION_FLAG_CLEAR, nr_words_to_write);
+ FFA_MEMORY_REGION_FLAG_CLEAR,
+ nr_words_to_write, false);
if (!is_ffa_direct_response(ret)) {
return TEST_RESULT_FAIL;
@@ -472,14 +545,6 @@
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;
}
@@ -636,6 +701,100 @@
return true;
}
+static bool verify_receivers_impdef(struct ffa_memory_access_impdef impdef1,
+ struct ffa_memory_access_impdef impdef2)
+{
+ if (impdef1.val[0] != impdef2.val[0] ||
+ impdef1.val[1] != impdef2.val[1]) {
+ ERROR("ipmdef1.val[0]=%llu expected=%llu"
+ " ipmdef1.val[1]=%llu expected=%llu\n",
+ impdef1.val[0], impdef2.val[0],
+ impdef1.val[1], impdef2.val[1]);
+ return false;
+ }
+
+ return true;
+}
+
+static bool verify_permissions(
+ ffa_memory_access_permissions_t permissions1,
+ ffa_memory_access_permissions_t permissions2)
+{
+ uint8_t access1;
+ uint8_t access2;
+
+ access1 = permissions1.data_access;
+ access2 = permissions2.data_access;
+
+ if (access1 != access2) {
+ ERROR("permissions1.data_access=%u expected=%u\n",
+ access1, access2);
+ return false;
+ }
+
+ access1 = permissions1.instruction_access;
+ access2 = permissions2.instruction_access;
+
+ if (access1 != access2) {
+ ERROR("permissions1.instruction_access=%u expected=%u\n",
+ access1, access2);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Used by hypervisor retrieve request test: validate descriptors provided by
+ * SPMC.
+ */
+static bool verify_receivers(struct ffa_memory_access *receivers1,
+ struct ffa_memory_access *receivers2,
+ uint32_t receivers_count)
+{
+ for (uint32_t i = 0; i < receivers_count; i++) {
+ if (receivers1[i].receiver_permissions.receiver !=
+ receivers2[i].receiver_permissions.receiver) {
+ ERROR("receivers1[%u].receiver_permissions.receiver=%x"
+ " expected=%x\n", i,
+ receivers1[i].receiver_permissions.receiver,
+ receivers2[i].receiver_permissions.receiver);
+ return false;
+ }
+
+ if (receivers1[i].receiver_permissions.flags !=
+ receivers2[i].receiver_permissions.flags) {
+ ERROR("receivers1[%u].receiver_permissions.flags=%u"
+ " expected=%u\n", i,
+ receivers1[i].receiver_permissions.flags,
+ receivers2[i].receiver_permissions.flags);
+ return false;
+ }
+
+ if (!verify_permissions(
+ receivers1[i].receiver_permissions.permissions,
+ receivers2[i].receiver_permissions.permissions)) {
+ return false;
+ }
+
+ if (receivers1[i].composite_memory_region_offset !=
+ receivers2[i].composite_memory_region_offset) {
+ ERROR("receivers1[%u].composite_memory_region_offset=%u"
+ " expected %u\n",
+ i, receivers1[i].composite_memory_region_offset,
+ receivers2[i].composite_memory_region_offset);
+ return false;
+ }
+
+ if (!verify_receivers_impdef(receivers1[i].impdef,
+ receivers1[i].impdef)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
/**
* Helper for performing a hypervisor retrieve request test.
*/
@@ -644,7 +803,6 @@
{
static struct ffa_memory_region_constituent
sent_constituents[FRAGMENTED_SHARE_PAGE_COUNT];
-
__aligned(PAGE_SIZE) static uint8_t page[PAGE_SIZE * 2] = {0};
struct ffa_memory_region *hypervisor_retrieve_response =
(struct ffa_memory_region *)page;
@@ -652,7 +810,8 @@
struct mailbox_buffers mb;
ffa_memory_handle_t handle;
struct ffa_value ret;
-
+ struct ffa_composite_memory_region *composite;
+ struct ffa_memory_access *retrvd_receivers;
uint32_t expected_flags = 0;
ffa_memory_attributes_t expected_attrs = {
@@ -679,10 +838,17 @@
uint32_t receiver_count =
multiple_receivers ? ARRAY_SIZE(receivers) : 1;
-
uint32_t sent_constituents_count =
fragmented ? ARRAY_SIZE(sent_constituents) : 1;
+ /* Prepare the composite offset for the comparison. */
+ for (uint32_t i = 0; i < receiver_count; i++) {
+ receivers[i].composite_memory_region_offset =
+ sizeof(struct ffa_memory_region) +
+ receiver_count *
+ sizeof(struct ffa_memory_access);
+ }
+
/* Add a page per constituent, so that we exhaust the size of a single
* fragment (for testing). In a real world scenario, the whole region
* could be described in a single constituent.
@@ -711,8 +877,8 @@
panic();
}
- handle = memory_init_and_send(mb.send, MAILBOX_SIZE, SENDER, receivers, receiver_count,
- sent_constituents,
+ handle = memory_init_and_send(mb.send, MAILBOX_SIZE, SENDER, receivers,
+ receiver_count, sent_constituents,
sent_constituents_count, mem_func, &ret);
if (handle == FFA_MEMORY_HANDLE_INVALID) {
ERROR("Memory share failed: %d\n", ffa_error_code(ret));
@@ -733,34 +899,37 @@
* Verify the received `FFA_MEM_RETRIEVE_RESP` aligns with
* transaction description sent above.
*/
- expected_response = (struct ffa_memory_region){
+ expected_response = (struct ffa_memory_region) {
.sender = SENDER,
.attributes = expected_attrs,
.flags = expected_flags,
.handle = handle,
.tag = 0,
.memory_access_desc_size = sizeof(struct ffa_memory_access),
- .receiver_count = 1,
+ .receiver_count = receiver_count,
.receivers_offset =
offsetof(struct ffa_memory_region, receivers),
};
- if (!verify_retrieve_response(hypervisor_retrieve_response, &expected_response)) {
+
+ if (!verify_retrieve_response(hypervisor_retrieve_response,
+ &expected_response)) {
return TEST_RESULT_FAIL;
}
- for (uint32_t i = 0; i < hypervisor_retrieve_response->receiver_count; i++) {
- struct ffa_composite_memory_region *composite =
- ffa_memory_region_get_composite(
- hypervisor_retrieve_response, i);
- if (composite == NULL) {
- ERROR("composite %d is null\n", i);
- return TEST_RESULT_FAIL;
- }
+ retrvd_receivers =
+ ffa_memory_region_get_receiver(hypervisor_retrieve_response, 0);
- if (!verify_composite(composite, &composite->constituents[i],
- sent_constituents_count, sent_constituents_count)) {
- return TEST_RESULT_FAIL;
- }
+ if (!verify_receivers(retrvd_receivers,
+ receivers, receiver_count)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ composite = ffa_memory_region_get_composite(
+ hypervisor_retrieve_response, 0);
+
+ if (!verify_composite(composite, composite->constituents,
+ sent_constituents_count, sent_constituents_count)) {
+ return TEST_RESULT_FAIL;
}
/*
@@ -809,3 +978,186 @@
{
return hypervisor_retrieve_request_test_helper(FFA_MEM_LEND_SMC32, false, true);
}
+
+/**
+ * Test helper that performs memory sharing operation, and alters the PAS
+ * of the memory, to validate that SPM intersects the operation in case the PAS
+ * is not coherent with its use. Relevant for the functioning of FFA_MEM_LEND
+ * and FFA_MEM_DONATE from NWd to an SP.
+ *
+ * In cases the memory is not in NS state, the SPMC should intersect memory
+ * management call with an appropriate FFA_ERROR.
+ */
+static test_result_t test_ffa_mem_send_realm_expect_fail(
+ uint32_t mem_func, ffa_id_t borrower,
+ struct ffa_memory_region_constituent *constituents,
+ size_t constituents_count, uint64_t delegate_addr)
+{
+ struct ffa_value ret;
+ uint32_t remaining_constituent_count;
+ uint32_t total_length;
+ uint32_t fragment_length;
+ struct mailbox_buffers mb;
+ u_register_t ret_rmm;
+ test_result_t result = TEST_RESULT_FAIL;
+ struct ffa_memory_access receiver =
+ ffa_memory_access_init_permissions_from_mem_func(borrower,
+ mem_func);
+
+ if (get_armv9_2_feat_rme_support() == 0U) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /***********************************************************************
+ * Check if SPMC has ffa_version and expected FFA endpoints are deployed.
+ **********************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 2, expected_sp_uuids);
+
+ GET_TFTF_MAILBOX(mb);
+
+ register_custom_sync_exception_handler(data_abort_handler);
+
+ /*
+ * Delegate page to a realm. This should make memory sharing operation
+ * fail.
+ */
+ ret_rmm = host_rmi_granule_delegate((u_register_t)delegate_addr);
+
+ if (ret_rmm != 0UL) {
+ INFO("Delegate operation returns 0x%lx for address %llx\n",
+ ret_rmm, delegate_addr);
+ return TEST_RESULT_FAIL;
+ }
+
+ remaining_constituent_count = ffa_memory_region_init(
+ (struct ffa_memory_region *)mb.send, MAILBOX_SIZE, SENDER,
+ &receiver, 1, constituents, constituents_count, 0,
+ FFA_MEMORY_REGION_FLAG_CLEAR,
+ FFA_MEMORY_NOT_SPECIFIED_MEM, 0, 0,
+ &total_length, &fragment_length);
+
+ if (remaining_constituent_count != 0) {
+ goto out;
+ }
+
+ switch (mem_func) {
+ case FFA_MEM_LEND_SMC32:
+ ret = ffa_mem_lend(total_length, fragment_length);
+ break;
+ case FFA_MEM_DONATE_SMC32:
+ ret = ffa_mem_donate(total_length, fragment_length);
+ break;
+ default:
+ ERROR("Not expected for func name: %x\n", mem_func);
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!is_expected_ffa_error(ret, FFA_ERROR_DENIED)) {
+ goto out;
+ }
+
+ /* Undelegate to reestablish the same security state for PAS. */
+ ret_rmm = host_rmi_granule_undelegate((u_register_t)delegate_addr);
+
+ for (uint32_t i = 0; i < constituents_count; i++) {
+ uint32_t *ptr = (uint32_t *)constituents[i].address;
+
+ *ptr = 0xFFA;
+ }
+
+ if (get_gpc_abort_triggered()) {
+ ERROR("Exception due to GPC for lend/donate with RME. Not"
+ " expected for this case.\n");
+ result = TEST_RESULT_FAIL;
+ } else {
+ result = TEST_RESULT_SUCCESS;
+ }
+out:
+ unregister_custom_sync_exception_handler();
+
+ if (ret_rmm != 0UL) {
+ INFO("Undelegate operation returns 0x%lx for address %llx\n",
+ ret_rmm, (uint64_t)delegate_addr);
+ return TEST_RESULT_FAIL;
+ }
+
+ return result;
+}
+
+/**
+ * Memory to be shared between partitions is described in a composite, with
+ * various constituents. In an RME system, the memory must be in NS PAS in
+ * operations from NWd to an SP. In case the PAS is not following this
+ * expectation memory lend/donate should fail, and all constituents must
+ * remain in the NS PAS.
+ *
+ * This test validates that if one page in the middle of one of the constituents
+ * is not in the NS PAS the operation fails.
+ */
+test_result_t test_ffa_mem_send_sp_realm_memory(void)
+{
+ test_result_t ret;
+ uint32_t mem_func[] = {FFA_MEM_LEND_SMC32, FFA_MEM_DONATE_SMC32};
+ struct ffa_memory_region_constituent constituents[] = {
+ {(void *)four_share_pages, 4, 0},
+ {(void *)share_page, 1, 0}
+ };
+
+ const uint32_t constituents_count = sizeof(constituents) /
+ sizeof(struct ffa_memory_region_constituent);
+
+ for (unsigned j = 0; j < ARRAY_SIZE(mem_func); j++) {
+ for (unsigned int i = 0; i < 4; i++) {
+ /* Address to be delegated to Realm PAS. */
+ uint64_t realm_addr =
+ (uint64_t)&four_share_pages[i * PAGE_SIZE];
+
+ INFO("%s memory with realm addr: %llx\n",
+ mem_func[j] == FFA_MEM_LEND_SMC32
+ ? "Lend"
+ : "Donate",
+ realm_addr);
+
+ ret = test_ffa_mem_send_realm_expect_fail(
+ mem_func[j], SP_ID(1), constituents,
+ constituents_count, realm_addr);
+
+ if (ret != TEST_RESULT_SUCCESS) {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Memory to be shared between partitions is described in a composite, with
+ * various constituents. In an RME system, the memory must be in NS PAS in
+ * operations from NWd to an SP. In case the PAS is not following this
+ * expectation memory lend/donate should fail, and all constituents must
+ * remain in the NS PAS.
+ *
+ * This test validates the case in which the memory lend/donate fail in
+ * case one of the constituents in the composite is not in the NS PAS.
+ */
+test_result_t test_ffa_mem_lend_sp_realm_memory_separate_constituent(void)
+{
+ test_result_t ret;
+ struct ffa_memory_region_constituent constituents[] = {
+ {(void *)four_share_pages, 4, 0},
+ {(void *)share_page, 1, 0}
+ };
+ const uint32_t constituents_count = sizeof(constituents) /
+ sizeof(struct ffa_memory_region_constituent);
+ /* Address to be delegated to Realm PAS. */
+ uint64_t realm_addr = (uint64_t)&share_page[0];
+
+ INFO("Sharing memory with realm addr: %llx\n", realm_addr);
+
+ ret = test_ffa_mem_send_realm_expect_fail(
+ FFA_MEM_LEND_SMC32, SP_ID(1), constituents,
+ constituents_count, realm_addr);
+
+ return ret;
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c b/tftf/tests/runtime_services/secure_service/test_spm_simd.c
similarity index 100%
rename from tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
rename to tftf/tests/runtime_services/secure_service/test_spm_simd.c
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 ae2068a..6237eb8 100644
--- a/tftf/tests/runtime_services/secure_service/test_spm_smmu.c
+++ b/tftf/tests/runtime_services/secure_service/test_spm_smmu.c
@@ -20,8 +20,20 @@
#define TEST_DMA_ENGINE_MEMCPY (2U)
#define TEST_DMA_ENGINE_RAND48 (3U)
-#define TEST_DMA_ENGINE_ATTR_DEST_ACACHE_RAWAWB_S (0xffU)
-#define TEST_DMA_ENGINE_ATTR_DEST_ACACHE_RAWAWB_NS (0x2ffU)
+/*
+ * Attribute encoding for Inner and Outer:
+ * Read-Allocate Write-Allocate Write-Back Normal Memory
+ */
+#define ATTR_ACACHE_RAWAWB_S (0xffU)
+#define ATTR_ACACHE_RAWAWB_NS (0x2ffU)
+
+/* Source attributes occupy the bottom halfword */
+#define DMA_ENGINE_ATTR_SRC_ACACHE_RAWAWB_S ATTR_ACACHE_RAWAWB_S
+#define DMA_ENGINE_ATTR_SRC_ACACHE_RAWAWB_NS ATTR_ACACHE_RAWAWB_NS
+
+/* Destination attributes occupy the top halfword */
+#define DMA_ENGINE_ATTR_DEST_ACACHE_RAWAWB_S (ATTR_ACACHE_RAWAWB_S << 16)
+#define DMA_ENGINE_ATTR_DEST_ACACHE_RAWAWB_NS (ATTR_ACACHE_RAWAWB_NS << 16)
/**************************************************************************
* test_smmu_spm
@@ -54,7 +66,7 @@
TEST_DMA_ENGINE_RAND48,
PLAT_CACTUS_MEMCPY_BASE,
PLAT_CACTUS_MEMCPY_RANGE / 2,
- TEST_DMA_ENGINE_ATTR_DEST_ACACHE_RAWAWB_S << 16);
+ DMA_ENGINE_ATTR_DEST_ACACHE_RAWAWB_S);
/* Expect the SMMU DMA operation to pass. */
if (cactus_get_response(ret) != CACTUS_SUCCESS) {
@@ -70,8 +82,27 @@
TEST_DMA_ENGINE_MEMCPY,
PLAT_CACTUS_MEMCPY_BASE,
PLAT_CACTUS_MEMCPY_RANGE,
- (TEST_DMA_ENGINE_ATTR_DEST_ACACHE_RAWAWB_S << 16) |
- TEST_DMA_ENGINE_ATTR_DEST_ACACHE_RAWAWB_S);
+ DMA_ENGINE_ATTR_DEST_ACACHE_RAWAWB_S |
+ DMA_ENGINE_ATTR_SRC_ACACHE_RAWAWB_S);
+
+ /* Expect the SMMU DMA operation to pass. */
+ if (cactus_get_response(ret) != CACTUS_SUCCESS) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Copy first half to second half of the non-secure buffer and
+ * check both match.
+ * Source and destination memory attributes are non-secure rawaWB.
+ * This test helps to validate a scenario where a secure stream
+ * belonging to Cactus SP accesses non-secure IPA space.
+ */
+ ret = cactus_send_dma_cmd(HYP_ID, SP_ID(1),
+ TEST_DMA_ENGINE_MEMCPY,
+ PLAT_CACTUS_NS_MEMCPY_BASE,
+ PLAT_CACTUS_MEMCPY_RANGE,
+ DMA_ENGINE_ATTR_DEST_ACACHE_RAWAWB_NS |
+ DMA_ENGINE_ATTR_SRC_ACACHE_RAWAWB_NS);
/* Expect the SMMU DMA operation to pass. */
if (cactus_get_response(ret) != CACTUS_SUCCESS) {
@@ -127,7 +158,7 @@
TEST_DMA_ENGINE_RAND48,
PLAT_CACTUS_NS_MEMCPY_BASE,
PLAT_CACTUS_MEMCPY_RANGE,
- TEST_DMA_ENGINE_ATTR_DEST_ACACHE_RAWAWB_NS << 16);
+ DMA_ENGINE_ATTR_DEST_ACACHE_RAWAWB_NS);
/* Update the buffer back to NS PAS. */
retmm = host_rmi_granule_undelegate((u_register_t)PLAT_CACTUS_NS_MEMCPY_BASE);
diff --git a/tftf/tests/tbb-tests/tbb_test_infra.c b/tftf/tests/tbb-tests/tbb_test_infra.c
new file mode 100644
index 0000000..dc8ae38
--- /dev/null
+++ b/tftf/tests/tbb-tests/tbb_test_infra.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "tbb_test_infra.h"
+
+#include <fwu_nvm.h>
+#include <io_storage.h>
+#include <platform.h>
+#include <status.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+test_result_t test_corrupt_boot_fip(unsigned int offset)
+{
+ unsigned int flag = 0xDEADBEEF;
+ size_t written = 0;
+ uintptr_t dev_handle;
+ int result;
+
+ if (tftf_is_rebooted()) {
+ /* FIP successfully repaired */
+ return TEST_RESULT_SUCCESS;
+ }
+
+ /* Corrupt the FIP at the provided offset */
+ plat_get_nvm_handle(&dev_handle);
+ result = io_seek(dev_handle, IO_SEEK_SET, offset);
+ TEST_ASSERT(result == IO_SUCCESS);
+ result = io_write(dev_handle, (uintptr_t) &flag, sizeof(flag), &written);
+ TEST_ASSERT(result == IO_SUCCESS);
+ TEST_ASSERT(written == sizeof(flag));
+
+ /*
+ * Now reboot the system.
+ * On the next boot, EL3 firmware should notice and repair the corruption
+ * before re-entering TFTF
+ */
+
+ tftf_notify_reboot();
+ psci_system_reset();
+ return TEST_RESULT_FAIL;
+}
diff --git a/tftf/tests/tbb-tests/tbb_test_infra.h b/tftf/tests/tbb-tests/tbb_test_infra.h
new file mode 100644
index 0000000..e6bf0e5
--- /dev/null
+++ b/tftf/tests/tbb-tests/tbb_test_infra.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TBB_TEST_INFRA_H_INCLUDED
+#define TBB_TEST_INFRA_H_INCLUDED
+
+#include <tftf_lib.h>
+
+test_result_t test_corrupt_boot_fip(unsigned int offset);
+
+#endif /* TBB_TEST_INFRA_H_INCLUDED */
+
diff --git a/tftf/tests/tbb-tests/test_tbb_corrupt_fip.c b/tftf/tests/tbb-tests/test_tbb_corrupt_fip.c
new file mode 100644
index 0000000..135efee
--- /dev/null
+++ b/tftf/tests/tbb-tests/test_tbb_corrupt_fip.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <uuid.h>
+
+#include "tbb_test_infra.h"
+
+#include <firmware_image_package.h>
+#include <platform.h>
+#include <tftf_lib.h>
+#include <uuid_utils.h>
+
+/*
+ * Return the offset relative to the base of the FIP of
+ * the image described by the uuid. 0 is returned on failure.
+ * The first image will not have an offset of 0, as the header
+ * exists at offset 0.
+ */
+static unsigned int
+find_offset_in_fip(const uuid_t *uuid)
+{
+ fip_toc_entry_t *current_file =
+ (fip_toc_entry_t *) (PLAT_ARM_FIP_BASE + sizeof(fip_toc_header_t));
+
+ while (!is_uuid_null(&(current_file->uuid))) {
+ if (uuid_equal(&(current_file->uuid), uuid)) {
+ return current_file->offset_address;
+ }
+ current_file += 1;
+ };
+ return 0;
+}
+
+test_result_t test_tbb_tkey_cert_header(void)
+{
+ static const uuid_t tkey_cert_uuid = UUID_TRUSTED_KEY_CERT;
+ unsigned int image_offset = find_offset_in_fip(&tkey_cert_uuid);
+
+ TEST_ASSERT_SKIP(image_offset != 0);
+ return test_corrupt_boot_fip(image_offset);
+}
+
diff --git a/tftf/tests/tests-corrupt-fip.mk b/tftf/tests/tests-corrupt-fip.mk
new file mode 100644
index 0000000..22fa686
--- /dev/null
+++ b/tftf/tests/tests-corrupt-fip.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES += $(addprefix tftf/tests/tbb-tests/, \
+ test_tbb_corrupt_fip.c \
+ tbb_test_infra.c \
+)
+
+TESTS_SOURCES += plat/common/fwu_nvm_accessors.c \
+ plat/arm/common/arm_fwu_io_storage.c \
+ drivers/io/io_fip.c \
+ drivers/io/io_memmap.c
diff --git a/tftf/tests/tests-corrupt-fip.xml b/tftf/tests/tests-corrupt-fip.xml
new file mode 100644
index 0000000..6bfa4a4
--- /dev/null
+++ b/tftf/tests/tests-corrupt-fip.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (c) 2023, Arm Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+
+ <testsuite name="tbb corrupt trusted key header" description="The FIP is corrupted before update">
+ <testcase name="tbb bad tkey cert header" function="test_tbb_tkey_cert_header" />
+ </testsuite>
+
+</testsuites>
diff --git a/tftf/tests/tests-invalid-access.xml b/tftf/tests/tests-invalid-access.xml
deleted file mode 100644
index 33b85c5..0000000
--- a/tftf/tests/tests-invalid-access.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright (c) 2023, 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 Secure memory from NS world"
- function="s_memory_cannot_be_accessed_in_ns" />
- </testsuite>
-
- <testsuite name="Invalid memory access with RME extension"
- description="Invalid memory access with RME extension">
- <testcase name="Access Realm memory from NS world"
- function="rl_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 Root memory from Realm world"
- function="rt_memory_cannot_be_accessed_in_rl" />
- <testcase name="Share memory to an SP from a Root region"
- function="rt_memory_cannot_be_accessed_in_s" />
- </testsuite>
-</testsuites>
diff --git a/tftf/tests/tests-invalid-access.mk b/tftf/tests/tests-memory-access.mk
similarity index 94%
rename from tftf/tests/tests-invalid-access.mk
rename to tftf/tests/tests-memory-access.mk
index 346ba9d..13b2241 100644
--- a/tftf/tests/tests-invalid-access.mk
+++ b/tftf/tests/tests-memory-access.mk
@@ -24,6 +24,7 @@
${ARCH}/ffa_arch_helpers.S \
ffa_helpers.c \
spm_common.c \
+ test_ffa_memory_sharing.c \
test_ffa_setup_and_discovery.c \
spm_test_helpers.c \
)
diff --git a/tftf/tests/tests-memory-access.xml b/tftf/tests/tests-memory-access.xml
new file mode 100644
index 0000000..4318cc9
--- /dev/null
+++ b/tftf/tests/tests-memory-access.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (c) 2024, Arm Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+
+ <testsuite name="FF-A Memory Sharing (RME)"
+ 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"
+ function="test_mem_donate_sp"/>
+ <testcase name="Request Share Memory SP-to-SP"
+ function="test_req_mem_share_sp_to_sp" />
+ <testcase name="Request Lend Memory SP-to-SP"
+ function="test_req_mem_lend_sp_to_sp" />
+ <testcase name="Request Donate Memory SP-to-SP"
+ function="test_req_mem_donate_sp_to_sp" />
+ <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" />
+ <testcase name="Share forbidden memory with SP"
+ function="test_share_forbidden_ranges" />
+ <testcase name="Donate consecutively"
+ function="test_consecutive_donate" />
+ </testsuite>
+
+ <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 Secure memory from NS world"
+ function="s_memory_cannot_be_accessed_in_ns" />
+ </testsuite>
+
+ <testsuite name="Invalid memory access with RME extension"
+ description="Invalid memory access with RME extension">
+ <testcase name="Access Realm memory from NS world"
+ function="rl_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 Root memory from Realm world"
+ function="rt_memory_cannot_be_accessed_in_rl" />
+ <testcase name="Share memory to an SP from a Root region"
+ function="rt_memory_cannot_be_accessed_in_s" />
+ <testcase name="FF-A memory share fails if using realm memory"
+ function="test_ffa_mem_send_sp_realm_memory" />
+ <testcase name="FF-A memory share fail realm memory other constituent"
+ function="test_ffa_mem_lend_sp_realm_memory_separate_constituent" />
+ </testsuite>
+
+</testsuites>
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 68d68dd..0ecefee 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -16,6 +16,16 @@
function="host_realm_multi_rec_multiple_cpu" />
<testcase name="Realm payload multi rec validations"
function="host_realm_multi_rec_multiple_cpu2" />
+ <testcase name="Realm SEA Empty"
+ function="host_realm_sea_empty" />
+ <testcase name="Realm SEA Unprotected"
+ function="host_realm_sea_unprotected" />
+ <testcase name="Realm Abort Unassigned RAM"
+ function="host_realm_abort_unassigned_ram" />
+ <testcase name="Realm Abort Unassigned Destroyed"
+ function="host_realm_abort_unassigned_destroyed" />
+ <testcase name="Realm Abort Assigned destroyed"
+ function="host_realm_abort_assigned_destroyed" />
<testcase name="Realm payload multi rec single cpu"
function="host_realm_multi_rec_single_cpu" />
<testcase name="Realm payload multi rec psci denied"
@@ -87,5 +97,7 @@
function="host_realm_enable_pauth" />
<testcase name="Generate PAuth Fault by overwriting LR"
function="host_realm_pauth_fault" />
+ <testcase name="Check if DIT Bit is preserved in RL/NS"
+ function="host_realm_enable_dit" />
</testsuite>
</testsuites>
diff --git a/tftf/tests/tests-rmi-spm.mk b/tftf/tests/tests-rmi-spm.mk
index 12ebb5a..735e191 100644
--- a/tftf/tests/tests-rmi-spm.mk
+++ b/tftf/tests/tests-rmi-spm.mk
@@ -21,6 +21,7 @@
${ARCH}/ffa_arch_helpers.S \
ffa_helpers.c \
spm_common.c \
+ spm_test_helpers.c \
)
TESTS_SOURCES += \
diff --git a/tftf/tests/tests-smcfuzzing.mk b/tftf/tests/tests-smcfuzzing.mk
index 738e1d6..2834e4e 100644
--- a/tftf/tests/tests-smcfuzzing.mk
+++ b/tftf/tests/tests-smcfuzzing.mk
@@ -46,4 +46,5 @@
runtestfunction_helpers.c \
sdei_fuzz_helper.c \
tsp_fuzz_helper.c \
+ nfifo.c \
)
diff --git a/tftf/tests/tests-spm.mk b/tftf/tests/tests-spm.mk
index 174e11d..97b3a49 100644
--- a/tftf/tests/tests-spm.mk
+++ b/tftf/tests/tests-spm.mk
@@ -27,7 +27,7 @@
ifeq (${ARCH},aarch64)
TESTS_SOURCES += \
$(addprefix tftf/tests/runtime_services/secure_service/, \
- test_spm_cpu_features.c \
+ test_spm_simd.c \
)
TESTS_SOURCES += \
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index b682837..09e0fd7 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -88,6 +88,20 @@
<testsuite name="FF-A Memory Sharing"
description="Test FF-A Memory Sharing ABIs" >
+ <testcase name="Hypervisor share + memory retrieve request"
+ function="test_hypervisor_share_retrieve" />
+ <testcase name="Hypervisor lend + memory retrieve request"
+ function="test_hypervisor_lend_retrieve" />
+ <testcase name="Hypervisor donate + memory retrieve request"
+ function="test_hypervisor_donate_retrieve" />
+ <testcase name="Hypervisor share + memory retrieve request (multiple receivers)"
+ function="test_hypervisor_share_retrieve_multiple_receivers" />
+ <testcase name="Hypervisor lend + memory retrieve request (multiple receivers)"
+ function="test_hypervisor_lend_retrieve_multiple_receivers" />
+ <testcase name="Hypervisor share + memory retrieve request (fragmented)"
+ function="test_hypervisor_share_retrieve_fragmented" />
+ <testcase name="Hypervisor lend + memory retrieve request (fragmented)"
+ function="test_hypervisor_lend_retrieve_fragmented" />
<testcase name="Lend Memory to Secure World"
function="test_mem_lend_sp" />
<testcase name="Lend memory, clear flag set"
diff --git a/tftf/tests/tests-undef-injection.mk b/tftf/tests/tests-undef-injection.mk
new file mode 100644
index 0000000..e13df17
--- /dev/null
+++ b/tftf/tests/tests-undef-injection.mk
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES += tftf/tests/misc_tests/test_undef_injection.c
diff --git a/tftf/tests/tests-undef-injection.xml b/tftf/tests/tests-undef-injection.xml
new file mode 100644
index 0000000..0d43cdf
--- /dev/null
+++ b/tftf/tests/tests-undef-injection.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (c) 2023, Arm Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+ <testsuite name="UNDEF Injection" description="UNDEF injection from EL3 to lower EL">
+ <testcase name="UNDEF Injection to lower EL"
+ function="test_undef_injection" />
+ </testsuite>
+</testsuites>