Merge "TRNG: clean up TRNG test"
diff --git a/include/runtime_services/cactus_message_loop.h b/include/runtime_services/cactus_message_loop.h
new file mode 100644
index 0000000..d69e77c
--- /dev/null
+++ b/include/runtime_services/cactus_message_loop.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <ffa_helpers.h>
+#include <spm_common.h>
+
+/**
+ * Pairs a command id with a function call, to handle the command ID.
+ */
+struct cactus_cmd_handler {
+ const uint64_t id;
+ smc_ret_values (*fn)(const smc_ret_values *args,
+ struct mailbox_buffers *mb);
+};
+
+/**
+ * Helper to create the name of a handler function.
+ */
+#define CACTUS_HANDLER_FN_NAME(name) cactus_##name##_handler
+
+/**
+ * Define handler's function signature.
+ */
+#define CACTUS_HANDLER_FN(name) \
+ static smc_ret_values CACTUS_HANDLER_FN_NAME(name)( \
+ const smc_ret_values *args, struct mailbox_buffers *mb)
+
+/**
+ * Helper to define Cactus command handler, and pair it with a command ID.
+ * It also creates a table with this information, to be traversed by
+ * 'cactus_handle_cmd' function.
+ */
+#define CACTUS_CMD_HANDLER(name, ID) \
+ CACTUS_HANDLER_FN(name); \
+ struct cactus_cmd_handler name __section(".cactus_handler") = { \
+ .id = ID, .fn = CACTUS_HANDLER_FN_NAME(name), \
+ }; \
+ CACTUS_HANDLER_FN(name)
+
+bool cactus_handle_cmd(smc_ret_values *cmd_args, smc_ret_values *ret,
+ struct mailbox_buffers *mb);
diff --git a/spm/cactus/cactus_test_cmds.h b/include/runtime_services/cactus_test_cmds.h
similarity index 75%
rename from spm/cactus/cactus_test_cmds.h
rename to include/runtime_services/cactus_test_cmds.h
index c662d27..246f4f9 100644
--- a/spm/cactus/cactus_test_cmds.h
+++ b/include/runtime_services/cactus_test_cmds.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,14 +7,21 @@
#ifndef CACTUS_TEST_CMDS
#define CACTUS_TEST_CMDS
-#include <debug.h>
#include <ffa_helpers.h>
/**
* Success and error return to be sent over a msg response.
*/
-#define CACTUS_SUCCESS U(0)
-#define CACTUS_ERROR U(-1)
+#define CACTUS_SUCCESS U(0)
+#define CACTUS_ERROR U(-1)
+
+/**
+ * Error codes.
+ */
+#define CACTUS_ERROR_INVALID U(1)
+#define CACTUS_ERROR_TEST U(2)
+#define CACTUS_ERROR_FFA_CALL U(3)
+#define CACTUS_ERROR_UNHANDLED U(4)
/**
* Get command from struct smc_ret_values.
@@ -32,14 +39,66 @@
ffa_vm_id_t source, ffa_vm_id_t dest, uint64_t cmd, uint64_t val0,
uint64_t val1, uint64_t val2, uint64_t val3)
{
- return ffa_msg_send_direct_req64_5args(source, dest, cmd, val0, val1,
- val2, val3);
+ return ffa_msg_send_direct_req64(source, dest, cmd, val0, val1, val2,
+ val3);
}
-#define PRINT_CMD(smc_ret) \
- VERBOSE("cmd %lx; args: %lx, %lx, %lx, %lx\n", \
- smc_ret.ret3, smc_ret.ret4, smc_ret.ret5, \
- smc_ret.ret6, smc_ret.ret7)
+/**
+ * Template for responses to Cactus commands.
+ * 'cactus_send_response' is the template for custom responses, in case there is
+ * a need to propagate more than one value in the response of a command.
+ */
+static inline smc_ret_values cactus_send_response(
+ ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t resp, uint32_t val0,
+ uint64_t val1, uint64_t val2, uint64_t val3)
+{
+ return ffa_msg_send_direct_resp64(source, dest, resp, val0, val1,
+ val2, val3);
+}
+
+/**
+ * For responses of one value only.
+ */
+static inline smc_ret_values cactus_response(
+ ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t response)
+{
+ return ffa_msg_send_direct_resp64(source, dest, response, 0, 0, 0, 0);
+}
+
+static inline uint32_t cactus_get_response(smc_ret_values ret)
+{
+ return (uint32_t)ret.ret3;
+}
+
+/**
+ * In a successful test, in case the SP needs to propagate an extra value
+ * to conclude the test.
+ * If more arguments are needed, a custom response should be defined for the
+ * specific test.
+ */
+static inline smc_ret_values cactus_success_resp(
+ ffa_vm_id_t source, ffa_vm_id_t dest, uint64_t value)
+{
+ return cactus_send_response(source, dest, CACTUS_SUCCESS, value,
+ 0, 0, 0);
+}
+
+/**
+ * In case the test fails on the SP side, the 'error_code' should help specify
+ * the reason, which can be specific to the test, or general ones as defined
+ * in the error code list.
+ */
+static inline smc_ret_values cactus_error_resp(
+ ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t error_code)
+{
+ return cactus_send_response(source, dest, CACTUS_ERROR, error_code,
+ 0, 0, 0);
+}
+
+static inline uint32_t cactus_error_code(smc_ret_values ret)
+{
+ return (uint32_t) ret.ret4;
+}
/**
* With this test command the sender transmits a 64-bit value that it then
@@ -186,33 +245,8 @@
static inline smc_ret_values cactus_req_simd_fill_send_cmd(
ffa_vm_id_t source, ffa_vm_id_t dest)
{
- return cactus_send_cmd(source, dest, CACTUS_REQ_SIMD_FILL_CMD, 0, 0, 0, 0);
-}
-
-/**
- * Template for responses to CACTUS commands.
- */
-static inline smc_ret_values cactus_response(
- ffa_vm_id_t source, ffa_vm_id_t dest, uint32_t response)
-{
- return ffa_msg_send_direct_resp(source, dest, response);
-}
-
-static inline smc_ret_values cactus_success_resp(
- ffa_vm_id_t source, ffa_vm_id_t dest)
-{
- return cactus_response(source, dest, CACTUS_SUCCESS);
-}
-
-static inline smc_ret_values cactus_error_resp(
- ffa_vm_id_t source, ffa_vm_id_t dest)
-{
- return cactus_response(source, dest, CACTUS_ERROR);
-}
-
-static inline uint32_t cactus_get_response(smc_ret_values ret)
-{
- return (uint32_t)ret.ret3;
+ return cactus_send_cmd(source, dest, CACTUS_REQ_SIMD_FILL_CMD, 0, 0, 0,
+ 0);
}
#endif
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index 02a956e..4af051b 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -364,16 +364,6 @@
enum ffa_memory_shareability shareability, uint32_t *total_length,
uint32_t *fragment_length);
-ffa_memory_handle_t ffa_memory_send(
- struct ffa_memory_region *memory_region, uint32_t mem_func,
- uint32_t fragment_length, uint32_t total_length);
-
-ffa_memory_handle_t ffa_memory_init_and_send(
- struct ffa_memory_region *memory_region, size_t memory_region_max_size,
- ffa_vm_id_t sender, ffa_vm_id_t receiver,
- const struct ffa_memory_region_constituent* constituents,
- uint32_t constituents_count, uint32_t mem_func);
-
static inline ffa_vm_id_t ffa_dir_msg_dest(smc_ret_values val) {
return (ffa_vm_id_t)val.ret1 & U(0xFFFF);
}
@@ -382,24 +372,35 @@
return (ffa_vm_id_t)(val.ret1 >> 16U);
}
-smc_ret_values ffa_msg_send_direct_req(uint32_t source_id, uint32_t dest_id, uint32_t message);
-smc_ret_values ffa_msg_send_direct_req64_5args(uint32_t source_id, uint32_t dest_id,
- uint64_t arg0, uint64_t arg1,
- uint64_t arg2, uint64_t arg3,
- uint64_t arg4);
+smc_ret_values ffa_msg_send_direct_req64(ffa_vm_id_t source_id,
+ ffa_vm_id_t dest_id, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2,
+ uint64_t arg3, uint64_t arg4);
+
+smc_ret_values ffa_msg_send_direct_req32(ffa_vm_id_t source_id,
+ ffa_vm_id_t dest_id, uint32_t arg0,
+ uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t arg4);
+
+smc_ret_values ffa_msg_send_direct_resp64(ffa_vm_id_t source_id,
+ ffa_vm_id_t dest_id, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2,
+ uint64_t arg3, uint64_t arg4);
+
+smc_ret_values ffa_msg_send_direct_resp32(ffa_vm_id_t source_id,
+ ffa_vm_id_t dest_id, uint32_t arg0,
+ uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t arg4);
smc_ret_values ffa_run(uint32_t dest_id, uint32_t vcpu_id);
smc_ret_values ffa_version(uint32_t input_version);
smc_ret_values ffa_id_get(void);
smc_ret_values ffa_msg_wait(void);
-smc_ret_values ffa_msg_send_direct_resp(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id, uint32_t message);
smc_ret_values ffa_error(int32_t error_code);
smc_ret_values ffa_features(uint32_t feature);
smc_ret_values ffa_partition_info_get(const uint32_t uuid[4]);
smc_ret_values ffa_rx_release(void);
smc_ret_values ffa_rxtx_map(uintptr_t send, uintptr_t recv, uint32_t pages);
-
smc_ret_values ffa_mem_donate(uint32_t descriptor_length,
uint32_t fragment_length);
smc_ret_values ffa_mem_lend(uint32_t descriptor_length,
diff --git a/include/runtime_services/ffa_svc.h b/include/runtime_services/ffa_svc.h
index f08e803..c970265 100644
--- a/include/runtime_services/ffa_svc.h
+++ b/include/runtime_services/ffa_svc.h
@@ -22,7 +22,7 @@
/* The macros below are used to identify FFA calls from the SMC function ID */
#define FFA_FNUM_MIN_VALUE U(0x60)
-#define FFA_FNUM_MAX_VALUE U(0x7f)
+#define FFA_FNUM_MAX_VALUE U(0x84)
#define is_ffa_fid(fid) __extension__ ({ \
__typeof__(fid) _fid = (fid); \
((GET_SMC_NUM(_fid) >= FFA_FNUM_MIN_VALUE) && \
@@ -84,6 +84,7 @@
#define FFA_FNUM_MEM_RETRIEVE_RESP U(0x75)
#define FFA_FNUM_MEM_RELINQUISH U(0x76)
#define FFA_FNUM_MEM_RECLAIM U(0x77)
+#define FFA_FNUM_SECONDARY_EP_REGISTER U(0x84)
/* FFA SMC32 FIDs */
#define FFA_ERROR FFA_FID(SMC_32, FFA_FNUM_ERROR)
@@ -126,6 +127,8 @@
#define FFA_MEM_SHARE_SMC64 FFA_FID(SMC_64, FFA_FNUM_MEM_SHARE)
#define FFA_MEM_RETRIEVE_REQ_SMC64 \
FFA_FID(SMC_64, FFA_FNUM_MEM_RETRIEVE_REQ)
+#define FFA_SECONDARY_EP_REGISTER_SMC64 \
+ FFA_FID(SMC_64, FFA_FNUM_SECONDARY_EP_REGISTER)
/*
* Reserve a special value for traffic targeted to the Hypervisor or SPM.
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index b090002..dbb113b 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -53,11 +53,18 @@
CONFIGURE_MAILBOX(mb_name, buffers_size); \
smc_ret = ffa_rxtx_map( \
(uintptr_t)mb_name.send, \
- (uintptr_t)mb_name.recv, \
+ (uintptr_t)mb_name.recv, \
buffers_size / PAGE_SIZE \
); \
} while (false)
+/**
+ * Helpers to evaluate returns of FF-A calls.
+ */
+bool is_ffa_call_error(smc_ret_values val);
+bool is_ffa_direct_response(smc_ret_values ret);
+bool is_expected_ffa_return(smc_ret_values ret, uint32_t func_id);
+
/*
* Vector length:
* SIMD: 128 bits = 16 bytes
@@ -82,4 +89,30 @@
unsigned int get_ffa_feature_test_target(const struct ffa_features_test **test_target);
+/**
+ * Helper to conduct a memory retrieve. This is to be called by the receiver
+ * of a memory share operation.
+ */
+bool memory_retrieve(struct mailbox_buffers *mb,
+ struct ffa_memory_region **retrieved, uint64_t handle,
+ ffa_vm_id_t sender, ffa_vm_id_t receiver,
+ uint32_t mem_func);
+
+/**
+ * Helper to conduct a memory relinquish. The caller is usually the receiver,
+ * after it being done with the memory shared, identified by the 'handle'.
+ */
+bool memory_relinquish(struct ffa_mem_relinquish *m, uint64_t handle,
+ ffa_vm_id_t id);
+
+ffa_memory_handle_t memory_send(
+ struct ffa_memory_region *memory_region, uint32_t mem_func,
+ uint32_t fragment_length, uint32_t total_length);
+
+ffa_memory_handle_t memory_init_and_send(
+ struct ffa_memory_region *memory_region, size_t memory_region_max_size,
+ ffa_vm_id_t sender, ffa_vm_id_t receiver,
+ const struct ffa_memory_region_constituent* constituents,
+ uint32_t constituents_count, uint32_t mem_func);
+
#endif /* SPM_COMMON_H */
diff --git a/spm/cactus/aarch64/cactus_entrypoint.S b/spm/cactus/aarch64/cactus_entrypoint.S
index b0f89d4..7e63856 100644
--- a/spm/cactus/aarch64/cactus_entrypoint.S
+++ b/spm/cactus/aarch64/cactus_entrypoint.S
@@ -7,25 +7,35 @@
#include <arch.h>
#include <asm_macros.S>
#include <cactus_def.h>
-#include <platform_def.h>
+#include <cactus_platform_def.h>
.globl cactus_entrypoint
+ .globl secondary_cold_entry
+/* Provision one stack per Execution Context (or vCPU) */
.section .bss.stacks
.balign CACHE_WRITEBACK_GRANULE
- .fill CACTUS_STACKS_SIZE
+ .fill CACTUS_STACKS_SIZE * PLAT_CACTUS_CORE_COUNT
stacks_end:
func cactus_entrypoint
+ /* Entry reason is primary EC cold boot */
+ mov x19, #1
+secondary_cold_entry:
+ /* Entry reason is secondary EC cold boot */
+ mrs x0, mpidr_el1
+ bl platform_get_core_pos
/* Setup the stack pointer. */
- adr x0, stacks_end
- mov sp, x0
+ adr x1, stacks_end
+ mov x2, #CACTUS_STACKS_SIZE
+ mul x2, x0, x2
+ sub sp, x1, x2
/* Enable I-Cache */
- mrs x0, sctlr_el1
- orr x0, x0, #SCTLR_I_BIT
- msr sctlr_el1, x0
+ mrs x1, sctlr_el1
+ orr x1, x1, #SCTLR_I_BIT
+ msr sctlr_el1, x1
isb
/*
@@ -38,6 +48,15 @@
msr cpacr_el1, x0
isb
+ /* Set up exceptions vector table */
+ adrp x1, tftf_vector
+ add x1, x1, :lo12:tftf_vector
+ msr vbar_el1, x1
+ isb
+
+ /* Skip to main if warm boot */
+ cbz x19, 0f
+
/* Relocate symbols */
pie_fixup:
ldr x0, =pie_fixup
@@ -46,13 +65,7 @@
add x1, x1, x0
bl fixup_gdt_reloc
- /* Set up exceptions vector table */
- adrp x0, tftf_vector
- add x0, x0, :lo12:tftf_vector
- msr vbar_el1, x0
- isb
-
- /* And jump to the C entrypoint. */
+ /* Jump to the C entrypoint (it does not return) */
+0: mov x0, x19
b cactus_main
-
endfunc cactus_entrypoint
diff --git a/spm/cactus/cactus.ld.S b/spm/cactus/cactus.ld.S
index 11b28ba..50fc576 100644
--- a/spm/cactus/cactus.ld.S
+++ b/spm/cactus/cactus.ld.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -52,6 +52,10 @@
. = ALIGN(PAGE_SIZE);
__DATA_START__ = .;
*(.data*)
+ . = ALIGN(PAGE_SIZE);
+ cactus_cmd_handler_begin = .;
+ KEEP(*(.cactus_handler))
+ cactus_cmd_handler_end = .;
. = NEXT(PAGE_SIZE);
__DATA_END__ = .;
}
diff --git a/spm/cactus/cactus.mk b/spm/cactus/cactus.mk
index 4a9cfcc..08b824c 100644
--- a/spm/cactus/cactus.mk
+++ b/spm/cactus/cactus.mk
@@ -33,13 +33,19 @@
$(addprefix spm/cactus/, \
aarch64/cactus_entrypoint.S \
cactus_debug.c \
- cactus_ffa_tests.c \
cactus_main.c \
) \
$(addprefix spm/common/, \
aarch64/sp_arch_helpers.S \
sp_helpers.c \
) \
+ $(addprefix spm/cactus/cactus_tests/, \
+ cactus_message_loop.c \
+ cactus_test_cpu_features.c \
+ cactus_test_direct_messaging.c \
+ cactus_test_ffa.c \
+ cactus_test_memory_sharing.c \
+ )
# TODO: Remove dependency on TFTF files.
CACTUS_SOURCES += \
diff --git a/spm/cactus/cactus_ffa_tests.c b/spm/cactus/cactus_ffa_tests.c
deleted file mode 100644
index 032d2e2..0000000
--- a/spm/cactus/cactus_ffa_tests.c
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-#include <assert.h>
-#include <debug.h>
-#include <errno.h>
-
-#include <cactus_def.h>
-#include <cactus_platform_def.h>
-#include <ffa_endpoints.h>
-#include <sp_helpers.h>
-#include <spm_common.h>
-
-#include <lib/libc/string.h>
-#include <lib/xlat_tables/xlat_tables_v2.h>
-
-/* FFA version test helpers */
-#define FFA_MAJOR 1U
-#define FFA_MINOR 0U
-
-static const uint32_t primary_uuid[4] = PRIMARY_UUID;
-static const uint32_t secondary_uuid[4] = SECONDARY_UUID;
-static const uint32_t tertiary_uuid[4] = TERTIARY_UUID;
-static const uint32_t null_uuid[4] = {0};
-
-/*
- * Fill SIMD vectors from secure world side with a unique value.
- * 0x22 is just a dummy value to be distinguished from the value
- * in the normal world.
- */
-void fill_simd_vectors(void)
-{
- simd_vector_t simd_vectors[SIMD_NUM_VECTORS];
-
- for (unsigned int num = 0U; num < SIMD_NUM_VECTORS; num++) {
- memset(simd_vectors[num], 0x22 * num, sizeof(simd_vector_t));
- }
-
- fill_simd_vector_regs(simd_vectors);
-}
-
-/*
- * Test FFA_FEATURES interface.
- */
-static void ffa_features_test(void)
-{
- const char *test_features = "FFA Features interface";
- smc_ret_values ffa_ret;
- const struct ffa_features_test *ffa_feature_test_target;
- unsigned int i, test_target_size =
- get_ffa_feature_test_target(&ffa_feature_test_target);
-
-
- announce_test_section_start(test_features);
-
- for (i = 0U; i < test_target_size; i++) {
- announce_test_start(ffa_feature_test_target[i].test_name);
-
- ffa_ret = ffa_features(ffa_feature_test_target[i].feature);
- expect(ffa_func_id(ffa_ret), ffa_feature_test_target[i].expected_ret);
- if (ffa_feature_test_target[i].expected_ret == FFA_ERROR) {
- expect(ffa_error_code(ffa_ret), FFA_ERROR_NOT_SUPPORTED);
- }
-
- announce_test_end(ffa_feature_test_target[i].test_name);
- }
-
- announce_test_section_end(test_features);
-}
-
-static void ffa_partition_info_helper(struct mailbox_buffers *mb, const uint32_t uuid[4],
- const struct ffa_partition_info *expected,
- const uint16_t expected_size)
-{
- smc_ret_values ret = ffa_partition_info_get(uuid);
- unsigned int i;
- expect(ffa_func_id(ret), FFA_SUCCESS_SMC32);
-
- struct ffa_partition_info *info = (struct ffa_partition_info *)(mb->recv);
- for (i = 0U; i < expected_size; i++) {
- expect(info[i].id, expected[i].id);
- expect(info[i].exec_context, expected[i].exec_context);
- expect(info[i].properties, expected[i].properties);
- }
-
- ret = ffa_rx_release();
- expect(ffa_func_id(ret), FFA_SUCCESS_SMC32);
-}
-
-static void ffa_partition_info_wrong_test(void)
-{
- const char *test_wrong_uuid = "Request wrong UUID";
- uint32_t uuid[4] = {1};
-
- announce_test_start(test_wrong_uuid);
-
- smc_ret_values ret = ffa_partition_info_get(uuid);
- expect(ffa_func_id(ret), FFA_ERROR);
- expect(ffa_error_code(ret), FFA_ERROR_INVALID_PARAMETER);
-
- announce_test_end(test_wrong_uuid);
-}
-
-static void ffa_partition_info_get_test(struct mailbox_buffers *mb)
-{
- const char *test_partition_info = "FFA Partition info interface";
- const char *test_primary = "Get primary partition info";
- const char *test_secondary = "Get secondary partition info";
- const char *test_tertiary = "Get tertiary partition info";
- const char *test_all = "Get all partitions info";
-
- const struct ffa_partition_info expected_info[] = {
- /* Primary partition info */
- {
- .id = SPM_VM_ID_FIRST,
- .exec_context = CACTUS_PRIMARY_EC_COUNT,
- /* Supports receipt of direct message requests. */
- .properties = 1U
- },
- /* Secondary partition info */
- {
- .id = SPM_VM_ID_FIRST + 1U,
- .exec_context = CACTUS_SECONDARY_EC_COUNT,
- .properties = 1U
- },
- /* Tertiary partition info */
- {
- .id = SPM_VM_ID_FIRST + 2U,
- .exec_context = CACTUS_TERTIARY_EC_COUNT,
- .properties = 1U
- }
- };
-
- announce_test_section_start(test_partition_info);
-
- announce_test_start(test_tertiary);
- ffa_partition_info_helper(mb, tertiary_uuid, &expected_info[2], 1);
- announce_test_end(test_tertiary);
-
- announce_test_start(test_secondary);
- ffa_partition_info_helper(mb, secondary_uuid, &expected_info[1], 1);
- announce_test_end(test_secondary);
-
- announce_test_start(test_primary);
- ffa_partition_info_helper(mb, primary_uuid, &expected_info[0], 1);
- announce_test_end(test_primary);
-
- announce_test_start(test_all);
- ffa_partition_info_helper(mb, null_uuid, expected_info, 3);
- announce_test_end(test_all);
-
- ffa_partition_info_wrong_test();
-
- announce_test_section_end(test_partition_info);
-}
-
-void ffa_version_test(void)
-{
- const char *test_ffa_version = "FFA Version interface";
-
- announce_test_start(test_ffa_version);
-
- smc_ret_values ret = ffa_version(MAKE_FFA_VERSION(FFA_MAJOR, FFA_MINOR));
- uint32_t spm_version = (uint32_t)ret.ret0;
-
- bool ffa_version_compatible =
- ((spm_version >> FFA_VERSION_MAJOR_SHIFT) == FFA_MAJOR &&
- (spm_version & FFA_VERSION_MINOR_MASK) >= FFA_MINOR);
-
- NOTICE("FFA_VERSION returned %u.%u; Compatible: %i\n",
- spm_version >> FFA_VERSION_MAJOR_SHIFT,
- spm_version & FFA_VERSION_MINOR_MASK,
- (int)ffa_version_compatible);
-
- expect((int)ffa_version_compatible, (int)true);
-
- announce_test_end(test_ffa_version);
-}
-
-bool ffa_memory_retrieve_test(struct mailbox_buffers *mb,
- struct ffa_memory_region **retrieved,
- uint64_t handle, ffa_vm_id_t sender,
- ffa_vm_id_t receiver, uint32_t mem_func)
-{
- smc_ret_values ret;
- uint32_t fragment_size;
- uint32_t total_size;
- uint32_t descriptor_size;
-
- if (retrieved == NULL || mb == NULL) {
- ERROR("Invalid parameters!\n");
- return false;
- }
-
- /*
- * TODO: Revise shareability attribute in function call
- * below.
- * https://lists.trustedfirmware.org/pipermail/hafnium/2020-June/000023.html
- */
- descriptor_size = ffa_memory_retrieve_request_init(
- mb->send, handle, sender, receiver, 0, 0,
- FFA_DATA_ACCESS_RW,
- FFA_INSTRUCTION_ACCESS_NX,
- FFA_MEMORY_NORMAL_MEM,
- FFA_MEMORY_CACHE_WRITE_BACK,
- FFA_MEMORY_OUTER_SHAREABLE);
-
- ret = ffa_mem_retrieve_req(descriptor_size, descriptor_size);
-
- if (ffa_func_id(ret) != FFA_MEM_RETRIEVE_RESP) {
- ERROR("Couldn't retrieve the memory page. Error: %lx\n",
- ret.ret2);
- return false;
- }
-
- /*
- * Following total_size and fragment_size are useful to keep track
- * of the state of transaction. When the sum of all fragment_size of all
- * fragments is equal to total_size, the memory transaction has been
- * completed.
- * This is a simple test with only one segment. As such, upon
- * successful ffa_mem_retrieve_req, total_size must be equal to
- * fragment_size.
- */
- total_size = ret.ret1;
- fragment_size = ret.ret2;
-
- if (total_size != fragment_size) {
- ERROR("Only expect one memory segment to be sent!\n");
- return false;
- }
-
- if (fragment_size > PAGE_SIZE) {
- ERROR("Fragment should be smaller than RX buffer!\n");
- return false;
- }
-
- *retrieved = (struct ffa_memory_region *)mb->recv;
-
- if ((*retrieved)->receiver_count > MAX_MEM_SHARE_RECIPIENTS) {
- VERBOSE("SPMC memory sharing operations support max of %u "
- "receivers!\n", MAX_MEM_SHARE_RECIPIENTS);
- return false;
- }
-
- VERBOSE("Memory Retrieved!\n");
-
- return true;
-}
-
-bool ffa_memory_relinquish_test(struct ffa_mem_relinquish *m,
- uint64_t handle,
- ffa_vm_id_t id)
-{
- smc_ret_values ret;
-
- ffa_mem_relinquish_init(m, handle, 0, id);
- ret = ffa_mem_relinquish();
- if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
- ERROR("%s failed to relinquish memory! error: %x\n",
- __func__, ffa_error_code(ret));
- return false;
- }
-
- VERBOSE("Memory Relinquished!\n");
- return true;
-}
-
-void ffa_memory_management_test(struct mailbox_buffers *mb, ffa_vm_id_t vm_id,
- ffa_vm_id_t sender, uint32_t mem_func,
- uint64_t handle)
-{
- const char *test_ffa = "Memory Management";
- struct ffa_memory_region *m;
- struct ffa_composite_memory_region *composite;
- int ret;
- unsigned int mem_attrs;
- uint32_t *ptr;
-
- announce_test_section_start(test_ffa);
-
- expect(ffa_memory_retrieve_test(
- mb, &m, handle, sender, vm_id, mem_func),
- true);
-
- 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. */
- expect(ffa_get_data_access_attr(
- m->receivers[0].receiver_permissions.permissions),
- FFA_DATA_ACCESS_RW);
-
- mem_attrs = MT_RW_DATA | MT_EXECUTE_NEVER;
-
- if (!IS_SP_ID(sender)) {
- 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);
- expect(ret, 0);
-
- VERBOSE("Memory has been mapped\n");
-
- ptr = (uint32_t *) composite->constituents[0].address;
-
- /* Write mem_func to retrieved memory region for validation purposes. */
- VERBOSE("Writing: %x\n", mem_func);
- for (unsigned int i = 0U; i < 5U; i++)
- ptr[i] = mem_func;
-
- /*
- * 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);
- expect(ret, 0);
-
- expect(ffa_memory_relinquish_test(
- (struct ffa_mem_relinquish *)mb->send,
- m->handle, vm_id),
- true);
- }
-
- expect(ffa_func_id(ffa_rx_release()), FFA_SUCCESS_SMC32);
-
- announce_test_section_end(test_ffa);
-}
-
-void ffa_tests(struct mailbox_buffers *mb)
-{
- const char *test_ffa = "FFA Interfaces";
-
- announce_test_section_start(test_ffa);
-
- ffa_features_test();
- ffa_version_test();
- ffa_partition_info_get_test(mb);
-
- announce_test_section_end(test_ffa);
-}
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index 11d7b99..e54f3b0 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -8,11 +8,12 @@
#include <errno.h>
#include <debug.h>
+#include <cactus_message_loop.h>
#include <cactus_platform_def.h>
-#include <cactus_test_cmds.h>
#include <drivers/arm/pl011.h>
#include <drivers/console.h>
#include <lib/aarch64/arch_helpers.h>
+#include <lib/tftf_lib.h>
#include <lib/xlat_tables/xlat_mmu_helpers.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <plat_arm.h>
@@ -29,8 +30,7 @@
extern const char build_message[];
extern const char version_string[];
-/* Memory section to be used for memory share operations */
-static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE];
+extern void secondary_cold_entry(void);
/*
*
@@ -40,13 +40,11 @@
* but rather through Hafnium print hypercall.
*
*/
+
static void __dead2 message_loop(ffa_vm_id_t vm_id, struct mailbox_buffers *mb)
{
smc_ret_values ffa_ret;
- uint32_t sp_response;
- ffa_vm_id_t source;
ffa_vm_id_t destination;
- uint64_t cactus_cmd;
/*
* This initial wait call is necessary to inform SPMD that
@@ -73,235 +71,13 @@
destination = ffa_dir_msg_dest(ffa_ret);
- source = ffa_dir_msg_source(ffa_ret);
-
if (destination != vm_id) {
ERROR("%s(%u) invalid vm id 0x%x\n",
__func__, vm_id, destination);
break;
}
- PRINT_CMD(ffa_ret);
-
- cactus_cmd = cactus_get_cmd(ffa_ret);
-
- switch (cactus_cmd) {
- case CACTUS_MEM_SEND_CMD:
- ffa_memory_management_test(
- mb, vm_id, source,
- cactus_req_mem_send_get_mem_func(
- ffa_ret),
- cactus_mem_send_get_handle(ffa_ret));
-
- /*
- * If execution gets to this point means all operations
- * with memory retrieval went well, as such replying
- */
- ffa_ret = cactus_success_resp(vm_id, source);
- break;
- case CACTUS_REQ_MEM_SEND_CMD:
- {
- uint32_t mem_func =
- cactus_req_mem_send_get_mem_func(ffa_ret);
- ffa_vm_id_t receiver =
- cactus_req_mem_send_get_receiver(ffa_ret);
- ffa_memory_handle_t handle;
-
- VERBOSE("%x requested to send memory to %x (func: %x)\n",
- source, receiver, mem_func);
-
- const struct ffa_memory_region_constituent
- constituents[] = {
- {(void *)share_page, 1, 0}
- };
-
- const uint32_t constituents_count = (
- sizeof(constituents) /
- sizeof(constituents[0])
- );
-
- handle = ffa_memory_init_and_send(
- (struct ffa_memory_region *)mb->send, PAGE_SIZE,
- vm_id, receiver, constituents,
- constituents_count, mem_func);
-
- /*
- * If returned an invalid handle, we should break the
- * test.
- */
- expect(handle != FFA_MEMORY_HANDLE_INVALID, true);
-
- ffa_ret = cactus_mem_send_cmd(vm_id, receiver, mem_func,
- handle);
-
- if (ffa_func_id(ffa_ret) !=
- FFA_MSG_SEND_DIRECT_RESP_SMC32) {
- ERROR("Failed to send message. error: %x\n",
- ffa_error_code(ffa_ret));
- ffa_ret = cactus_error_resp(vm_id, source);
- break;
- }
-
- /* If anything went bad on the receiver's end. */
- if (cactus_get_response(ffa_ret) == CACTUS_ERROR) {
- ERROR("Received error from receiver!\n");
- ffa_ret = cactus_error_resp(vm_id, source);
- break;
- }
-
- if (mem_func != FFA_MEM_DONATE_SMC32) {
- /*
- * Do a memory reclaim only if the mem_func
- * regards to memory share or lend operations,
- * as with a donate the owner is permanently
- * given up access to the memory region.
- */
- if (ffa_mem_reclaim(handle, 0)
- .ret0 == FFA_ERROR) {
- ERROR("Failed to reclaim memory!\n");
- ffa_ret = cactus_error_resp(vm_id,
- source);
- break;
- }
-
- /**
- * Read Content that has been written to memory
- * to validate access to memory segment has been
- * reestablished, and receiver made use of
- * memory region.
- */
- #if (LOG_LEVEL >= LOG_LEVEL_VERBOSE)
- uint32_t *ptr =
- (uint32_t *)constituents
- ->address;
- VERBOSE("Memory contents after receiver"
- " SP's use:\n");
- for (unsigned int i = 0U; i < 5U; i++)
- VERBOSE(" %u: %x\n", i,
- ptr[i]);
- #endif
- }
-
- ffa_ret = cactus_success_resp(vm_id, source);
- break;
- }
- case CACTUS_ECHO_CMD:
- {
- uint64_t echo_val = cactus_echo_get_val(ffa_ret);
-
- VERBOSE("Received echo at %x, value %llx from %x.\n",
- destination, echo_val, source);
- ffa_ret = cactus_response(destination, source, echo_val);
- break;
- }
- case CACTUS_REQ_ECHO_CMD:
- {
- ffa_vm_id_t echo_dest =
- cactus_req_echo_get_echo_dest(ffa_ret);
- uint64_t echo_val = cactus_echo_get_val(ffa_ret);
- bool success = true;
-
- VERBOSE("%x requested to send echo to %x, value %llx\n",
- source, echo_dest, echo_val);
-
- ffa_ret = cactus_echo_send_cmd(vm_id, echo_dest,
- echo_val);
-
- if (ffa_func_id(ffa_ret) !=
- FFA_MSG_SEND_DIRECT_RESP_SMC32) {
- ERROR("Failed to send message. error: %x\n",
- ffa_error_code(ffa_ret));
- success = false;
- }
-
- if (cactus_get_response(ffa_ret) != echo_val) {
- ERROR("Echo Failed!\n");
- success = false;
- }
-
- ffa_ret = success ? cactus_success_resp(vm_id, source) :
- cactus_error_resp(vm_id, source);
- break;
- }
- case CACTUS_DEADLOCK_CMD:
- case CACTUS_REQ_DEADLOCK_CMD:
- {
- ffa_vm_id_t deadlock_dest =
- cactus_deadlock_get_next_dest(ffa_ret);
- ffa_vm_id_t deadlock_next_dest = source;
-
- if (cactus_cmd == CACTUS_DEADLOCK_CMD) {
- VERBOSE("%x is creating deadlock. next: %x\n",
- source, deadlock_dest);
- } else if (cactus_cmd == CACTUS_REQ_DEADLOCK_CMD) {
- VERBOSE(
- "%x requested deadlock with %x and %x\n",
- source, deadlock_dest, deadlock_next_dest);
-
- deadlock_next_dest =
- cactus_deadlock_get_next_dest2(ffa_ret);
- }
-
- ffa_ret = cactus_deadlock_send_cmd(vm_id, deadlock_dest,
- deadlock_next_dest);
-
- /*
- * Should be true for the last partition to attempt
- * an FF-A direct message, to the first partition.
- */
- bool is_deadlock_detected =
- (ffa_func_id(ffa_ret) == FFA_ERROR) &&
- (ffa_error_code(ffa_ret) == FFA_ERROR_BUSY);
-
- /*
- * Should be true after the deadlock has been detected
- * and after the first response has been sent down the
- * request chain.
- */
- bool is_returning_from_deadlock =
- (ffa_func_id(ffa_ret) ==
- FFA_MSG_SEND_DIRECT_RESP_SMC32)
- &&
- (cactus_get_response(ffa_ret) == CACTUS_SUCCESS);
-
- if (is_deadlock_detected) {
- NOTICE("Attempting dealock but got error %x\n",
- ffa_error_code(ffa_ret));
- }
-
- if (is_deadlock_detected ||
- is_returning_from_deadlock) {
- /*
- * This is not the partition, that would have
- * created the deadlock. As such, reply back
- * to the partitions.
- */
- ffa_ret = cactus_success_resp(vm_id, source);
- break;
- }
-
- /* Shouldn't get to this point */
- ERROR("Deadlock test went wrong!\n");
- ffa_ret = cactus_error_resp(vm_id, source);
- break;
- }
- case CACTUS_REQ_SIMD_FILL_CMD:
- fill_simd_vectors();
- ffa_ret = cactus_success_resp(vm_id, source);
- break;
- default:
- /*
- * Currently direct message test is handled here.
- * TODO: create a case within the switch case
- * For the sake of testing, add the vm id to the
- * received message.
- */
- sp_response = ffa_ret.ret3 | vm_id;
- VERBOSE("Replying with direct message response: %x\n", sp_response);
- ffa_ret = ffa_msg_send_direct_resp(vm_id,
- HYP_ID,
- sp_response);
-
+ if (!cactus_handle_cmd(&ffa_ret, &ffa_ret, mb)) {
break;
}
}
@@ -374,6 +150,16 @@
init_xlat_tables();
}
+static void register_secondary_entrypoint(void)
+{
+ smc_args args;
+
+ args.fid = FFA_SECONDARY_EP_REGISTER_SMC64;
+ args.arg1 = (u_register_t)&secondary_cold_entry;
+
+ tftf_smc(&args);
+}
+
int tftf_irq_handler_dispatcher(void)
{
ERROR("%s\n", __func__);
@@ -381,31 +167,39 @@
return 0;
}
-void __dead2 cactus_main(void)
+void __dead2 cactus_main(bool primary_cold_boot)
{
assert(IS_IN_EL1() != 0);
struct mailbox_buffers mb;
- /* Clear BSS */
- memset((void *)CACTUS_BSS_START,
- 0, CACTUS_BSS_END - CACTUS_BSS_START);
-
/* Get current FFA id */
smc_ret_values ffa_id_ret = ffa_id_get();
if (ffa_func_id(ffa_id_ret) != FFA_SUCCESS_SMC32) {
ERROR("FFA_ID_GET failed.\n");
panic();
}
-
ffa_vm_id_t ffa_id = ffa_id_ret.ret2 & 0xffff;
- mb.send = (void *) get_sp_tx_start(ffa_id);
- mb.recv = (void *) get_sp_rx_start(ffa_id);
- /* Configure and enable Stage-1 MMU, enable D-Cache */
- cactus_plat_configure_mmu(ffa_id);
+ if (primary_cold_boot == true) {
+ /* Clear BSS */
+ memset((void *)CACTUS_BSS_START,
+ 0, CACTUS_BSS_END - CACTUS_BSS_START);
+
+
+ mb.send = (void *) get_sp_tx_start(ffa_id);
+ mb.recv = (void *) get_sp_rx_start(ffa_id);
+
+ /* Configure and enable Stage-1 MMU, enable D-Cache */
+ cactus_plat_configure_mmu(ffa_id);
+ }
+
enable_mmu_el1(0);
+ if (primary_cold_boot == false) {
+ goto msg_loop;
+ }
+
if (ffa_id == SPM_VM_ID_FIRST) {
console_init(CACTUS_PL011_UART_BASE,
CACTUS_PL011_UART_CLK_IN_HZ,
@@ -437,9 +231,12 @@
INFO("FF-A id: %x\n", ffa_id);
cactus_print_memory_layout(ffa_id);
+ register_secondary_entrypoint();
+
/* Invoking Tests */
ffa_tests(&mb);
+msg_loop:
/* End up to message loop */
message_loop(ffa_id, &mb);
diff --git a/spm/cactus/cactus_tests.h b/spm/cactus/cactus_tests.h
index c0c235e..1039ba5 100644
--- a/spm/cactus/cactus_tests.h
+++ b/spm/cactus/cactus_tests.h
@@ -13,19 +13,6 @@
* Test functions
*/
-/*
- * Alter SIMD vectors to check saving of the context while switching between
- * the normal world and the secure world.
- */
-void fill_simd_vectors(void);
-
-/*
- * Test to FFA interfaces.
- */
-void ffa_memory_management_test(struct mailbox_buffers *mb, ffa_vm_id_t vm_id,
- ffa_vm_id_t sender, uint32_t mem_func,
- uint64_t handle);
-
void ffa_tests(struct mailbox_buffers *mb);
/*
diff --git a/spm/cactus/cactus_tests/cactus_message_loop.c b/spm/cactus/cactus_tests/cactus_message_loop.c
new file mode 100644
index 0000000..11207dc
--- /dev/null
+++ b/spm/cactus/cactus_tests/cactus_message_loop.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "cactus_message_loop.h"
+#include "cactus_test_cmds.h"
+#include <ffa_helpers.h>
+#include <debug.h>
+
+
+/**
+ * Begin and end of command handler table, respectively. Both symbols defined by
+ * the linker.
+ */
+extern struct cactus_cmd_handler cactus_cmd_handler_begin[];
+extern struct cactus_cmd_handler cactus_cmd_handler_end[];
+
+#define PRINT_CMD(smc_ret) \
+ VERBOSE("cmd %lx; args: %lx, %lx, %lx, %lx\n", \
+ smc_ret.ret3, smc_ret.ret4, smc_ret.ret5, \
+ smc_ret.ret6, smc_ret.ret7)
+
+/**
+ * Traverses command table from section ".cactus_handler", searches for a
+ * registered command and invokes the respective handler.
+ */
+bool cactus_handle_cmd(smc_ret_values *cmd_args, smc_ret_values *ret,
+ struct mailbox_buffers *mb)
+{
+ uint64_t in_cmd;
+
+ if (cmd_args == NULL || ret == NULL) {
+ ERROR("Invalid argumentos passed to %s!\n", __func__);
+ return false;
+ }
+
+ PRINT_CMD((*cmd_args));
+
+ in_cmd = cactus_get_cmd(*cmd_args);
+
+ for (struct cactus_cmd_handler *it_cmd = cactus_cmd_handler_begin;
+ it_cmd < cactus_cmd_handler_end;
+ it_cmd++) {
+ if (it_cmd->id == in_cmd) {
+ *ret = it_cmd->fn(cmd_args, mb);
+ return true;
+ }
+ }
+
+ ERROR("Unhandled test command!\n");
+ *ret = cactus_error_resp(ffa_dir_msg_dest(*cmd_args),
+ ffa_dir_msg_source(*cmd_args),
+ CACTUS_ERROR_UNHANDLED);
+ return true;
+}
diff --git a/spm/cactus/cactus_tests/cactus_test_cpu_features.c b/spm/cactus/cactus_tests/cactus_test_cpu_features.c
new file mode 100644
index 0000000..7bf6e83
--- /dev/null
+++ b/spm/cactus/cactus_tests/cactus_test_cpu_features.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "cactus_message_loop.h"
+#include "cactus_test_cmds.h"
+#include "spm_common.h"
+
+/*
+ * Fill SIMD vectors from secure world side with a unique value.
+ * 0x22 is just a dummy value to be distinguished from the value
+ * in the normal world.
+ */
+CACTUS_CMD_HANDLER(req_simd_fill, CACTUS_REQ_SIMD_FILL_CMD)
+{
+ simd_vector_t simd_vectors[SIMD_NUM_VECTORS];
+
+ for (unsigned int num = 0U; num < SIMD_NUM_VECTORS; num++) {
+ memset(simd_vectors[num], 0x22 * num, sizeof(simd_vector_t));
+ }
+
+ fill_simd_vector_regs(simd_vectors);
+
+ return cactus_response(ffa_dir_msg_dest(*args),
+ ffa_dir_msg_source(*args),
+ CACTUS_SUCCESS);
+}
diff --git a/spm/cactus/cactus_tests/cactus_test_direct_messaging.c b/spm/cactus/cactus_tests/cactus_test_direct_messaging.c
new file mode 100644
index 0000000..a59cfa2
--- /dev/null
+++ b/spm/cactus/cactus_tests/cactus_test_direct_messaging.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "cactus_message_loop.h"
+#include "cactus_test_cmds.h"
+#include <debug.h>
+#include <ffa_helpers.h>
+
+CACTUS_CMD_HANDLER(echo_cmd, CACTUS_ECHO_CMD)
+{
+ uint64_t echo_val = cactus_echo_get_val(*args);
+
+ VERBOSE("Received echo at %x, value %llx.\n", ffa_dir_msg_dest(*args),
+ echo_val);
+
+ return cactus_success_resp(ffa_dir_msg_dest(*args),
+ ffa_dir_msg_source(*args),
+ echo_val);
+}
+
+CACTUS_CMD_HANDLER(req_echo_cmd, CACTUS_REQ_ECHO_CMD)
+{
+ smc_ret_values ffa_ret;
+ ffa_vm_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_vm_id_t echo_dest = cactus_req_echo_get_echo_dest(*args);
+ uint64_t echo_val = cactus_echo_get_val(*args);
+
+ VERBOSE("%x requested to send echo to %x, value %llx\n",
+ ffa_dir_msg_source(*args), echo_dest, echo_val);
+
+ ffa_ret = cactus_echo_send_cmd(vm_id, echo_dest, echo_val);
+
+ if (!is_ffa_direct_response(ffa_ret)) {
+ return cactus_error_resp(vm_id, ffa_dir_msg_source(*args),
+ CACTUS_ERROR_FFA_CALL);
+ }
+
+ if (cactus_get_response(ffa_ret) != CACTUS_SUCCESS ||
+ cactus_echo_get_val(ffa_ret) != echo_val) {
+ ERROR("Echo Failed!\n");
+ return cactus_error_resp(vm_id, ffa_dir_msg_source(*args),
+ CACTUS_ERROR_TEST);
+ }
+
+ return cactus_success_resp(vm_id, ffa_dir_msg_source(*args), 0);
+}
+
+static smc_ret_values base_deadlock_handler(ffa_vm_id_t vm_id,
+ ffa_vm_id_t source,
+ ffa_vm_id_t deadlock_dest,
+ ffa_vm_id_t deadlock_next_dest)
+{
+ smc_ret_values ffa_ret;
+
+ ffa_ret = cactus_deadlock_send_cmd(vm_id, deadlock_dest,
+ deadlock_next_dest);
+
+ /*
+ * Should be true for the last partition to attempt
+ * an FF-A direct message, to the first partition.
+ */
+ bool is_deadlock_detected = (ffa_func_id(ffa_ret) == FFA_ERROR) &&
+ (ffa_error_code(ffa_ret) == FFA_ERROR_BUSY);
+
+ /*
+ * Should be true after the deadlock has been detected and after the
+ * first response has been sent down the request chain.
+ */
+ bool is_returning_from_deadlock =
+ (is_ffa_direct_response(ffa_ret)) &&
+ (cactus_get_response(ffa_ret) == CACTUS_SUCCESS);
+
+ if (is_deadlock_detected) {
+ VERBOSE("Attempt to create deadlock failed\n");
+ }
+
+ if (is_deadlock_detected || is_returning_from_deadlock) {
+ /*
+ * This is not the partition, that would have created the
+ * deadlock. As such, reply back to the partitions.
+ */
+ return cactus_success_resp(vm_id, source, 0);
+ }
+
+ /* Shouldn't get to this point */
+ ERROR("Deadlock test went wrong!\n");
+ return cactus_error_resp(vm_id, source, CACTUS_ERROR_TEST);
+}
+
+CACTUS_CMD_HANDLER(deadlock_cmd, CACTUS_DEADLOCK_CMD)
+{
+ ffa_vm_id_t source = ffa_dir_msg_source(*args);
+ ffa_vm_id_t deadlock_dest = cactus_deadlock_get_next_dest(*args);
+ ffa_vm_id_t deadlock_next_dest = source;
+
+ VERBOSE("%x is creating deadlock. next: %x\n", source, deadlock_dest);
+
+ return base_deadlock_handler(ffa_dir_msg_dest(*args), source,
+ deadlock_dest, deadlock_next_dest);
+}
+
+CACTUS_CMD_HANDLER(req_deadlock_cmd, CACTUS_REQ_DEADLOCK_CMD)
+{
+ ffa_vm_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_vm_id_t source = ffa_dir_msg_source(*args);
+ ffa_vm_id_t deadlock_dest = cactus_deadlock_get_next_dest(*args);
+ ffa_vm_id_t deadlock_next_dest = cactus_deadlock_get_next_dest2(*args);
+
+ VERBOSE("%x requested deadlock with %x and %x\n",
+ ffa_dir_msg_source(*args), deadlock_dest, deadlock_next_dest);
+
+ return base_deadlock_handler(vm_id, source, deadlock_dest, deadlock_next_dest);
+}
diff --git a/spm/cactus/cactus_tests/cactus_test_ffa.c b/spm/cactus/cactus_tests/cactus_test_ffa.c
new file mode 100644
index 0000000..c1ba783
--- /dev/null
+++ b/spm/cactus/cactus_tests/cactus_test_ffa.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <cactus_def.h>
+#include <cactus_platform_def.h>
+#include <ffa_endpoints.h>
+#include <sp_helpers.h>
+#include <spm_common.h>
+
+#include <lib/libc/string.h>
+
+/* FFA version test helpers */
+#define FFA_MAJOR 1U
+#define FFA_MINOR 0U
+
+static const uint32_t primary_uuid[4] = PRIMARY_UUID;
+static const uint32_t secondary_uuid[4] = SECONDARY_UUID;
+static const uint32_t tertiary_uuid[4] = TERTIARY_UUID;
+static const uint32_t null_uuid[4] = {0};
+
+/*
+ * Test FFA_FEATURES interface.
+ */
+static void ffa_features_test(void)
+{
+ const char *test_features = "FFA Features interface";
+ smc_ret_values ffa_ret;
+ const struct ffa_features_test *ffa_feature_test_target;
+ unsigned int i, test_target_size =
+ get_ffa_feature_test_target(&ffa_feature_test_target);
+
+
+ announce_test_section_start(test_features);
+
+ for (i = 0U; i < test_target_size; i++) {
+ announce_test_start(ffa_feature_test_target[i].test_name);
+
+ ffa_ret = ffa_features(ffa_feature_test_target[i].feature);
+ expect(ffa_func_id(ffa_ret), ffa_feature_test_target[i].expected_ret);
+ if (ffa_feature_test_target[i].expected_ret == FFA_ERROR) {
+ expect(ffa_error_code(ffa_ret), FFA_ERROR_NOT_SUPPORTED);
+ }
+
+ announce_test_end(ffa_feature_test_target[i].test_name);
+ }
+
+ announce_test_section_end(test_features);
+}
+
+static void ffa_partition_info_helper(struct mailbox_buffers *mb, const uint32_t uuid[4],
+ const struct ffa_partition_info *expected,
+ const uint16_t expected_size)
+{
+ smc_ret_values ret = ffa_partition_info_get(uuid);
+ unsigned int i;
+ expect(ffa_func_id(ret), FFA_SUCCESS_SMC32);
+
+ struct ffa_partition_info *info = (struct ffa_partition_info *)(mb->recv);
+ for (i = 0U; i < expected_size; i++) {
+ expect(info[i].id, expected[i].id);
+ expect(info[i].exec_context, expected[i].exec_context);
+ expect(info[i].properties, expected[i].properties);
+ }
+
+ ret = ffa_rx_release();
+ expect(ffa_func_id(ret), FFA_SUCCESS_SMC32);
+}
+
+static void ffa_partition_info_wrong_test(void)
+{
+ const char *test_wrong_uuid = "Request wrong UUID";
+ uint32_t uuid[4] = {1};
+
+ announce_test_start(test_wrong_uuid);
+
+ smc_ret_values ret = ffa_partition_info_get(uuid);
+ expect(ffa_func_id(ret), FFA_ERROR);
+ expect(ffa_error_code(ret), FFA_ERROR_INVALID_PARAMETER);
+
+ announce_test_end(test_wrong_uuid);
+}
+
+static void ffa_partition_info_get_test(struct mailbox_buffers *mb)
+{
+ const char *test_partition_info = "FFA Partition info interface";
+ const char *test_primary = "Get primary partition info";
+ const char *test_secondary = "Get secondary partition info";
+ const char *test_tertiary = "Get tertiary partition info";
+ const char *test_all = "Get all partitions info";
+
+ const struct ffa_partition_info expected_info[] = {
+ /* Primary partition info */
+ {
+ .id = SPM_VM_ID_FIRST,
+ .exec_context = CACTUS_PRIMARY_EC_COUNT,
+ /* Supports receipt of direct message requests. */
+ .properties = 1U
+ },
+ /* Secondary partition info */
+ {
+ .id = SPM_VM_ID_FIRST + 1U,
+ .exec_context = CACTUS_SECONDARY_EC_COUNT,
+ .properties = 1U
+ },
+ /* Tertiary partition info */
+ {
+ .id = SPM_VM_ID_FIRST + 2U,
+ .exec_context = CACTUS_TERTIARY_EC_COUNT,
+ .properties = 1U
+ }
+ };
+
+ announce_test_section_start(test_partition_info);
+
+ announce_test_start(test_tertiary);
+ ffa_partition_info_helper(mb, tertiary_uuid, &expected_info[2], 1);
+ announce_test_end(test_tertiary);
+
+ announce_test_start(test_secondary);
+ ffa_partition_info_helper(mb, secondary_uuid, &expected_info[1], 1);
+ announce_test_end(test_secondary);
+
+ announce_test_start(test_primary);
+ ffa_partition_info_helper(mb, primary_uuid, &expected_info[0], 1);
+ announce_test_end(test_primary);
+
+ announce_test_start(test_all);
+ ffa_partition_info_helper(mb, null_uuid, expected_info, 3);
+ announce_test_end(test_all);
+
+ ffa_partition_info_wrong_test();
+
+ announce_test_section_end(test_partition_info);
+}
+
+void ffa_version_test(void)
+{
+ const char *test_ffa_version = "FFA Version interface";
+
+ announce_test_start(test_ffa_version);
+
+ smc_ret_values ret = ffa_version(MAKE_FFA_VERSION(FFA_MAJOR, FFA_MINOR));
+ uint32_t spm_version = (uint32_t)ret.ret0;
+
+ bool ffa_version_compatible =
+ ((spm_version >> FFA_VERSION_MAJOR_SHIFT) == FFA_MAJOR &&
+ (spm_version & FFA_VERSION_MINOR_MASK) >= FFA_MINOR);
+
+ NOTICE("FFA_VERSION returned %u.%u; Compatible: %i\n",
+ spm_version >> FFA_VERSION_MAJOR_SHIFT,
+ spm_version & FFA_VERSION_MINOR_MASK,
+ (int)ffa_version_compatible);
+
+ expect((int)ffa_version_compatible, (int)true);
+
+ announce_test_end(test_ffa_version);
+}
+
+void ffa_tests(struct mailbox_buffers *mb)
+{
+ const char *test_ffa = "FFA Interfaces";
+
+ announce_test_section_start(test_ffa);
+
+ ffa_features_test();
+ ffa_version_test();
+ ffa_partition_info_get_test(mb);
+
+ announce_test_section_end(test_ffa);
+}
diff --git a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
new file mode 100644
index 0000000..e7bce50
--- /dev/null
+++ b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cactus_def.h>
+#include "cactus_message_loop.h"
+#include "cactus_test_cmds.h"
+#include "cactus_tests.h"
+#include <debug.h>
+#include <ffa_helpers.h>
+#include <sp_helpers.h>
+#include <xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/* Memory section to be used for memory share operations */
+static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE];
+
+CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
+{
+ struct ffa_memory_region *m;
+ struct ffa_composite_memory_region *composite;
+ int ret;
+ unsigned int mem_attrs;
+ uint32_t *ptr;
+ ffa_vm_id_t source = ffa_dir_msg_source(*args);
+ ffa_vm_id_t vm_id = ffa_dir_msg_dest(*args);
+ uint32_t mem_func = cactus_req_mem_send_get_mem_func(*args);
+ uint64_t handle = cactus_mem_send_get_handle(*args);
+
+ expect(memory_retrieve(mb, &m, handle, source, vm_id, mem_func), true);
+
+ 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 (ffa_get_data_access_attr(
+ m->receivers[0].receiver_permissions.permissions) !=
+ FFA_DATA_ACCESS_RW) {
+ ERROR("Permissions not expected!\n");
+ return cactus_error_resp(vm_id, source, CACTUS_ERROR_TEST);
+ }
+
+ mem_attrs = MT_RW_DATA | MT_EXECUTE_NEVER;
+
+ if (!IS_SP_ID(source)) {
+ 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);
+
+ if (ret != 0) {
+ ERROR("Failed first mmap_add_dynamic_region!\n");
+ return cactus_error_resp(vm_id, source, CACTUS_ERROR_TEST);
+ }
+
+ VERBOSE("Memory has been mapped\n");
+
+ ptr = (uint32_t *) composite->constituents[0].address;
+
+ /* Write mem_func to retrieved memory region for validation purposes. */
+ VERBOSE("Writing: %x\n", mem_func);
+ for (unsigned int i = 0U; i < 5U; i++)
+ ptr[i] = mem_func;
+
+ /*
+ * 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 first mmap_add_dynamic_region!\n");
+ 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 (ffa_func_id(ffa_rx_release()) != FFA_SUCCESS_SMC32) {
+ ERROR("Failed to release buffer!\n");
+ return cactus_error_resp(vm_id, source,
+ CACTUS_ERROR_FFA_CALL);
+ }
+
+ return cactus_success_resp(vm_id,
+ source, 0);
+}
+
+CACTUS_CMD_HANDLER(req_mem_send_cmd, CACTUS_REQ_MEM_SEND_CMD)
+{
+ smc_ret_values ffa_ret;
+ uint32_t mem_func = cactus_req_mem_send_get_mem_func(*args);
+ ffa_vm_id_t receiver = cactus_req_mem_send_get_receiver(*args);
+ ffa_memory_handle_t handle;
+ ffa_vm_id_t vm_id = ffa_dir_msg_dest(*args);
+ ffa_vm_id_t source = ffa_dir_msg_source(*args);
+
+ VERBOSE("%x requested to send memory to %x (func: %x)\n",
+ source, receiver, mem_func);
+
+ const struct ffa_memory_region_constituent constituents[] = {
+ {(void *)share_page, 1, 0}
+ };
+
+ const uint32_t constituents_count = (sizeof(constituents) /
+ sizeof(constituents[0]));
+
+ handle = memory_init_and_send(
+ (struct ffa_memory_region *)mb->send, PAGE_SIZE,
+ vm_id, receiver, constituents,
+ constituents_count, mem_func);
+
+ /*
+ * If returned an invalid handle, we should break the test.
+ */
+ if (handle == FFA_MEMORY_HANDLE_INVALID) {
+ ERROR("Received an invalid FF-A memory Handle!\n");
+ return cactus_error_resp(vm_id, source,
+ CACTUS_ERROR_TEST);
+ }
+
+ ffa_ret = cactus_mem_send_cmd(vm_id, receiver, mem_func, handle);
+
+ if (!is_ffa_direct_response(ffa_ret)) {
+ return cactus_error_resp(vm_id, source, CACTUS_ERROR_FFA_CALL);
+ }
+
+ /* If anything went bad on the receiver's end. */
+ if (cactus_get_response(ffa_ret) == CACTUS_ERROR) {
+ ERROR("Received error from receiver!\n");
+ return cactus_error_resp(vm_id, source, CACTUS_ERROR_TEST);
+ }
+
+ if (mem_func != FFA_MEM_DONATE_SMC32) {
+ /*
+ * Do a memory reclaim only if the mem_func regards to memory
+ * share or lend operations, as with a donate the owner is
+ * permanently given up access to the memory region.
+ */
+ ffa_ret = ffa_mem_reclaim(handle, 0);
+ if (is_ffa_call_error(ffa_ret)) {
+ return cactus_error_resp(vm_id, source,
+ CACTUS_ERROR_TEST);
+ }
+
+ /**
+ * Read Content that has been written to memory to validate
+ * access to memory segment has been reestablished, and receiver
+ * made use of memory region.
+ */
+ #if (LOG_LEVEL >= LOG_LEVEL_VERBOSE)
+ uint32_t *ptr = (uint32_t *)constituents->address;
+
+ VERBOSE("Memory contents after receiver SP's use:\n");
+ for (unsigned int i = 0U; i < 5U; i++) {
+ VERBOSE(" %u: %x\n", i, ptr[i]);
+ }
+ #endif
+ }
+
+ return cactus_success_resp(vm_id, source, 0);
+}
diff --git a/spm/cactus/plat/arm/fvp/include/cactus_platform_def.h b/spm/cactus/plat/arm/fvp/include/cactus_platform_def.h
index e879002..b4c57ef 100644
--- a/spm/cactus/plat/arm/fvp/include/cactus_platform_def.h
+++ b/spm/cactus/plat/arm/fvp/include/cactus_platform_def.h
@@ -16,9 +16,10 @@
#define CACTUS_PL011_UART_CLK_IN_HZ PL011_UART2_CLK_IN_HZ
#define PLAT_CACTUS_RX_BASE ULL(0x7300000)
+#define PLAT_CACTUS_CORE_COUNT (8U)
#define CACTUS_PRIMARY_EC_COUNT (8U)
#define CACTUS_SECONDARY_EC_COUNT (8U)
-#define CACTUS_TERTIARY_EC_COUNT (8U)
+#define CACTUS_TERTIARY_EC_COUNT (1U)
#endif /* CACTUS_PLATFORM_DEF_H */
diff --git a/spm/cactus/plat/arm/tc0/fdts/cactus-tertiary.dts b/spm/cactus/plat/arm/tc0/fdts/cactus-tertiary.dts
index 724d595..3b50530 100644
--- a/spm/cactus/plat/arm/tc0/fdts/cactus-tertiary.dts
+++ b/spm/cactus/plat/arm/tc0/fdts/cactus-tertiary.dts
@@ -18,7 +18,7 @@
ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
uuid = <0x79b55c73 0x1d8c44b9 0x859361e1 0x770ad8d2>;
id = <3>;
- execution-ctx-count = <8>;
+ execution-ctx-count = <1>;
exception-level = <2>; /* S-EL1 */
execution-state = <0>; /* AARCH64 */
load-address = <0xfe200000>;
diff --git a/spm/cactus/plat/arm/tc0/include/cactus_platform_def.h b/spm/cactus/plat/arm/tc0/include/cactus_platform_def.h
index d551314..42dd291 100644
--- a/spm/cactus/plat/arm/tc0/include/cactus_platform_def.h
+++ b/spm/cactus/plat/arm/tc0/include/cactus_platform_def.h
@@ -19,6 +19,6 @@
#define CACTUS_PRIMARY_EC_COUNT (8U)
#define CACTUS_SECONDARY_EC_COUNT (8U)
-#define CACTUS_TERTIARY_EC_COUNT (8U)
+#define CACTUS_TERTIARY_EC_COUNT (1U)
#endif /* CACTUS_PLATFORM_DEF_H */
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index 923ee2c..8e7b58c 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -3,8 +3,6 @@
*
* SPDX-License-Identifier: BSD-3-Clause
*/
-
-#include <debug.h>
#include <smccc.h>
#include <ffa_endpoints.h>
@@ -57,58 +55,83 @@
* -BUSY: Message target is busy
* -ABORTED: Message target ran into an unexpected error and has aborted
*/
-static smc_ret_values __ffa_msg_send_direct_req32_5(uint32_t source_id,
- uint32_t dest_id,
- uint32_t arg0,
- uint32_t arg1,
- uint32_t arg2,
- uint32_t arg3,
- uint32_t arg4)
+smc_ret_values ffa_msg_send_direct_req64(ffa_vm_id_t source_id,
+ ffa_vm_id_t dest_id, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2,
+ uint64_t arg3, uint64_t arg4)
{
smc_args args = {
- FFA_MSG_SEND_DIRECT_REQ_SMC32,
- (source_id << 16) | dest_id,
- 0,
- arg0, arg1, arg2, arg3, arg4
+ .fid = FFA_MSG_SEND_DIRECT_REQ_SMC64,
+ .arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
+ .arg2 = 0,
+ .arg3 = arg0,
+ .arg4 = arg1,
+ .arg5 = arg2,
+ .arg6 = arg3,
+ .arg7 = arg4,
};
return tftf_smc(&args);
}
-/* Direct message send helper accepting a single 32b message argument */
-smc_ret_values ffa_msg_send_direct_req(uint32_t source_id, uint32_t dest_id,
- uint32_t message)
-{
- return __ffa_msg_send_direct_req32_5(source_id, dest_id,
- message, 0, 0, 0, 0);
-}
-
-smc_ret_values ffa_msg_send_direct_req64_5args(uint32_t source_id,
- uint32_t dest_id,
- uint64_t arg0,
- uint64_t arg1,
- uint64_t arg2,
- uint64_t arg3,
- uint64_t arg4)
+smc_ret_values ffa_msg_send_direct_req32(ffa_vm_id_t source_id,
+ ffa_vm_id_t dest_id, uint32_t arg0,
+ uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t arg4)
{
smc_args args = {
- FFA_MSG_SEND_DIRECT_REQ_SMC64,
- (source_id << 16) | dest_id,
- 0,
- arg0, arg1, arg2, arg3, arg4
+ .fid = FFA_MSG_SEND_DIRECT_REQ_SMC32,
+ .arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
+ .arg2 = 0,
+ .arg3 = arg0,
+ .arg4 = arg1,
+ .arg5 = arg2,
+ .arg6 = arg3,
+ .arg7 = arg4,
};
return tftf_smc(&args);
}
-/* Direct message send helper accepting a single 64b message argument */
-smc_ret_values ffa_msg_send_direct_req64(uint32_t source_id, uint32_t dest_id,
- uint64_t message)
+smc_ret_values ffa_msg_send_direct_resp64(ffa_vm_id_t source_id,
+ ffa_vm_id_t dest_id, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2,
+ uint64_t arg3, uint64_t arg4)
{
- return ffa_msg_send_direct_req64_5args(source_id, dest_id,
- message, 0, 0, 0, 0);
+ smc_args args = {
+ .fid = FFA_MSG_SEND_DIRECT_RESP_SMC64,
+ .arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
+ .arg2 = 0,
+ .arg3 = arg0,
+ .arg4 = arg1,
+ .arg5 = arg2,
+ .arg6 = arg3,
+ .arg7 = arg4,
+ };
+
+ return tftf_smc(&args);
}
+smc_ret_values ffa_msg_send_direct_resp32(ffa_vm_id_t source_id,
+ ffa_vm_id_t dest_id, uint32_t arg0,
+ uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t arg4)
+{
+ smc_args args = {
+ .fid = FFA_MSG_SEND_DIRECT_RESP_SMC32,
+ .arg1 = ((uint32_t)(source_id << 16)) | (dest_id),
+ .arg2 = 0,
+ .arg3 = arg0,
+ .arg4 = arg1,
+ .arg5 = arg2,
+ .arg6 = arg3,
+ .arg7 = arg4,
+ };
+
+ return tftf_smc(&args);
+}
+
+
/**
* Initialises the header of the given `ffa_memory_region`, not including the
* composite memory region offset.
@@ -268,91 +291,6 @@
memory_region->receiver_count * sizeof(struct ffa_memory_access);
}
-/**
- * Helper to call memory send function whose func id is passed as a parameter.
- * Returns a valid handle in case of successful operation or
- * FFA_MEMORY_HANDLE_INVALID if something goes wrong.
- *
- * TODO: Do memory send with 'ffa_memory_region' taking multiple segments
- */
-ffa_memory_handle_t ffa_memory_send(
- struct ffa_memory_region *memory_region, uint32_t mem_func,
- uint32_t fragment_length, uint32_t total_length)
-{
- smc_ret_values ret;
- ffa_vm_id_t receiver =
- memory_region->receivers[0].receiver_permissions.receiver;
-
- if (fragment_length != total_length) {
- ERROR("For now, fragment_length and total_length need to be"
- " equal");
- return FFA_MEMORY_HANDLE_INVALID;
- }
-
- switch (mem_func) {
- case FFA_MEM_SHARE_SMC32:
- ret = ffa_mem_share(total_length, fragment_length);
- break;
- 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("TFTF - Invalid func id %x!\n", mem_func);
- return FFA_MEMORY_HANDLE_INVALID;
- }
-
- if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
- ERROR("Failed to send memory to %x, error: %x.\n",
- receiver, ffa_error_code(ret));
- return FFA_MEMORY_HANDLE_INVALID;
- }
-
- return ffa_mem_success_handle(ret);
-;
-}
-
-/**
- * Helper that initializes and sends a memory region. The memory region's
- * configuration is statically defined and is implementation specific. However,
- * doing it in this file for simplicity and for testing purposes.
- */
-ffa_memory_handle_t ffa_memory_init_and_send(
- struct ffa_memory_region *memory_region, size_t memory_region_max_size,
- ffa_vm_id_t sender, ffa_vm_id_t receiver,
- const struct ffa_memory_region_constituent *constituents,
- uint32_t constituents_count, uint32_t mem_func)
-{
- uint32_t remaining_constituent_count;
- uint32_t total_length;
- uint32_t fragment_length;
-
- enum ffa_data_access data_access = (mem_func == FFA_MEM_DONATE_SMC32) ?
- FFA_DATA_ACCESS_NOT_SPECIFIED :
- FFA_DATA_ACCESS_RW;
-
- remaining_constituent_count = ffa_memory_region_init(
- memory_region, memory_region_max_size, sender, receiver, constituents,
- constituents_count, 0, 0, data_access,
- FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
- FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
- FFA_MEMORY_INNER_SHAREABLE, &total_length, &fragment_length
- );
-
- /*
- * For simplicity of the test, and at least for the time being,
- * the following condition needs to be true.
- */
- if (remaining_constituent_count != 0U) {
- ERROR("Remaining constituent should be 0\n");
- return FFA_MEMORY_HANDLE_INVALID;
- }
-
- return ffa_memory_send(memory_region, mem_func, fragment_length,
- total_length);
-}
/*
* FFA Version ABI helper.
@@ -388,19 +326,6 @@
return tftf_smc(&args);
}
-smc_ret_values ffa_msg_send_direct_resp(ffa_vm_id_t source_id,
- ffa_vm_id_t dest_id,
- uint32_t message)
-{
- smc_args args = {
- .fid = FFA_MSG_SEND_DIRECT_RESP_SMC32,
- .arg1 = ((uint32_t)source_id << 16) | dest_id,
- .arg3 = message
- };
-
- return tftf_smc(&args);
-}
-
smc_ret_values ffa_error(int32_t error_code)
{
smc_args args = {
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index cc3ed5d..12b70a9 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -4,13 +4,61 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <debug.h>
#include <ffa_endpoints.h>
#include <spm_common.h>
+#include <xlat_tables_v2.h>
#define __STR(x) #x
#define STR(x) __STR(x)
#define SIMD_TWO_VECTORS_BYTES_STR (2 * SIMD_VECTOR_LEN_BYTES)
+/**
+ * Helper to log errors after FF-A calls.
+ */
+bool is_ffa_call_error(smc_ret_values ret)
+{
+ if (ffa_func_id(ret) == FFA_ERROR) {
+ ERROR("FF-A call returned error (%x): %d\n",
+ ffa_func_id(ret), ffa_error_code(ret));
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Helper to verify return of FF-A call is an FFA_MSG_SEND_DIRECT_RESP.
+ * Should be used after FFA_MSG_SEND_DIRECT_REQ, or after sending a test command
+ * to an SP.
+ */
+bool is_ffa_direct_response(smc_ret_values ret)
+{
+ if ((ffa_func_id(ret) == FFA_MSG_SEND_DIRECT_RESP_SMC32) ||
+ (ffa_func_id(ret) == FFA_MSG_SEND_DIRECT_RESP_SMC64)) {
+ return true;
+ }
+
+ ERROR("%x is not FF-A response.\n", ffa_func_id(ret));
+ /* To log error in case it is FFA_ERROR*/
+ is_ffa_call_error(ret);
+
+ return false;
+}
+
+/**
+ * Helper to check the return value of FF-A call is as expected.
+ */
+bool is_expected_ffa_return(smc_ret_values ret, uint32_t func_id)
+{
+ if (ffa_func_id(ret) == func_id) {
+ return true;
+ }
+
+ ERROR("Expecting %x, FF-A return was %x\n", func_id, ffa_func_id(ret));
+
+ return false;
+}
+
void fill_simd_vector_regs(const simd_vector_t v[SIMD_NUM_VECTORS])
{
#ifdef __aarch64__
@@ -83,8 +131,9 @@
* Send a first OP-TEE-defined protocol message through
* FFA direct message.
*/
- ret_values = ffa_msg_send_direct_req(HYP_ID, SP_ID(1),
- OPTEE_FFA_GET_API_VERSION);
+ ret_values = ffa_msg_send_direct_req32(HYP_ID, SP_ID(1),
+ OPTEE_FFA_GET_API_VERSION, 0,
+ 0, 0, 0);
if ((ret_values.ret3 == FFA_VERSION_MAJOR) &&
(ret_values.ret4 == FFA_VERSION_MINOR)) {
is_optee_spmc_criteria++;
@@ -94,8 +143,9 @@
* Send a second OP-TEE-defined protocol message through
* FFA direct message.
*/
- ret_values = ffa_msg_send_direct_req(HYP_ID, SP_ID(1),
- OPTEE_FFA_GET_OS_VERSION);
+ ret_values = ffa_msg_send_direct_req32(HYP_ID, SP_ID(1),
+ OPTEE_FFA_GET_OS_VERSION,
+ 0, 0, 0, 0);
if ((ret_values.ret3 == OPTEE_FFA_GET_OS_VERSION_MAJOR) &&
(ret_values.ret4 == OPTEE_FFA_GET_OS_VERSION_MINOR)) {
is_optee_spmc_criteria++;
@@ -146,3 +196,175 @@
return sizeof(ffa_feature_test_target) /
sizeof(struct ffa_features_test);
}
+
+bool memory_retrieve(struct mailbox_buffers *mb,
+ struct ffa_memory_region **retrieved, uint64_t handle,
+ ffa_vm_id_t sender, ffa_vm_id_t receiver,
+ uint32_t mem_func)
+{
+ smc_ret_values ret;
+ uint32_t fragment_size;
+ uint32_t total_size;
+ uint32_t descriptor_size;
+
+ if (retrieved == NULL || mb == NULL) {
+ ERROR("Invalid parameters!\n");
+ return false;
+ }
+
+ /*
+ * TODO: Revise shareability attribute in function call
+ * below.
+ * https://lists.trustedfirmware.org/pipermail/hafnium/2020-June/000023.html
+ */
+ descriptor_size = ffa_memory_retrieve_request_init(
+ mb->send, handle, sender, receiver, 0, 0,
+ FFA_DATA_ACCESS_RW,
+ FFA_INSTRUCTION_ACCESS_NX,
+ FFA_MEMORY_NORMAL_MEM,
+ FFA_MEMORY_CACHE_WRITE_BACK,
+ FFA_MEMORY_OUTER_SHAREABLE);
+
+ ret = ffa_mem_retrieve_req(descriptor_size, descriptor_size);
+
+ if (ffa_func_id(ret) != FFA_MEM_RETRIEVE_RESP) {
+ ERROR("Couldn't retrieve the memory page. Error: %x\n",
+ ffa_error_code(ret));
+ return false;
+ }
+
+ /*
+ * Following total_size and fragment_size are useful to keep track
+ * of the state of transaction. When the sum of all fragment_size of all
+ * fragments is equal to total_size, the memory transaction has been
+ * completed.
+ * This is a simple test with only one segment. As such, upon
+ * successful ffa_mem_retrieve_req, total_size must be equal to
+ * fragment_size.
+ */
+ total_size = ret.ret1;
+ fragment_size = ret.ret2;
+
+ if (total_size != fragment_size) {
+ ERROR("Only expect one memory segment to be sent!\n");
+ return false;
+ }
+
+ if (fragment_size > PAGE_SIZE) {
+ ERROR("Fragment should be smaller than RX buffer!\n");
+ return false;
+ }
+
+ *retrieved = (struct ffa_memory_region *)mb->recv;
+
+ if ((*retrieved)->receiver_count > MAX_MEM_SHARE_RECIPIENTS) {
+ VERBOSE("SPMC memory sharing operations support max of %u "
+ "receivers!\n", MAX_MEM_SHARE_RECIPIENTS);
+ return false;
+ }
+
+ VERBOSE("Memory Retrieved!\n");
+
+ return true;
+}
+
+bool memory_relinquish(struct ffa_mem_relinquish *m, uint64_t handle,
+ ffa_vm_id_t id)
+{
+ smc_ret_values ret;
+
+ ffa_mem_relinquish_init(m, handle, 0, id);
+ ret = ffa_mem_relinquish();
+ if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
+ ERROR("%s failed to relinquish memory! error: %x\n",
+ __func__, ffa_error_code(ret));
+ return false;
+ }
+
+ VERBOSE("Memory Relinquished!\n");
+ return true;
+}
+
+/**
+ * Helper to call memory send function whose func id is passed as a parameter.
+ * Returns a valid handle in case of successful operation or
+ * FFA_MEMORY_HANDLE_INVALID if something goes wrong.
+ *
+ * TODO: Do memory send with 'ffa_memory_region' taking multiple segments
+ */
+ffa_memory_handle_t memory_send(
+ struct ffa_memory_region *memory_region, uint32_t mem_func,
+ uint32_t fragment_length, uint32_t total_length)
+{
+ smc_ret_values ret;
+ ffa_vm_id_t receiver =
+ memory_region->receivers[0].receiver_permissions.receiver;
+
+ if (fragment_length != total_length) {
+ ERROR("For now, fragment_length and total_length need to be"
+ " equal");
+ return FFA_MEMORY_HANDLE_INVALID;
+ }
+
+ switch (mem_func) {
+ case FFA_MEM_SHARE_SMC32:
+ ret = ffa_mem_share(total_length, fragment_length);
+ break;
+ 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("TFTF - Invalid func id %x!\n", mem_func);
+ return FFA_MEMORY_HANDLE_INVALID;
+ }
+
+ if (is_ffa_call_error(ret)) {
+ ERROR("Failed to send message to: %x\n", receiver);
+ return FFA_MEMORY_HANDLE_INVALID;
+ }
+
+ return ffa_mem_success_handle(ret);
+}
+
+/**
+ * Helper that initializes and sends a memory region. The memory region's
+ * configuration is statically defined and is implementation specific. However,
+ * doing it in this file for simplicity and for testing purposes.
+ */
+ffa_memory_handle_t memory_init_and_send(
+ struct ffa_memory_region *memory_region, size_t memory_region_max_size,
+ ffa_vm_id_t sender, ffa_vm_id_t receiver,
+ const struct ffa_memory_region_constituent *constituents,
+ uint32_t constituents_count, uint32_t mem_func)
+{
+ uint32_t remaining_constituent_count;
+ uint32_t total_length;
+ uint32_t fragment_length;
+
+ enum ffa_data_access data_access = (mem_func == FFA_MEM_DONATE_SMC32) ?
+ FFA_DATA_ACCESS_NOT_SPECIFIED :
+ FFA_DATA_ACCESS_RW;
+
+ remaining_constituent_count = ffa_memory_region_init(
+ memory_region, memory_region_max_size, sender, receiver, constituents,
+ constituents_count, 0, 0, data_access,
+ FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
+ FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
+ FFA_MEMORY_INNER_SHAREABLE, &total_length, &fragment_length
+ );
+
+ /*
+ * For simplicity of the test, and at least for the time being,
+ * the following condition needs to be true.
+ */
+ if (remaining_constituent_count != 0U) {
+ ERROR("Remaining constituent should be 0\n");
+ return FFA_MEMORY_HANDLE_INVALID;
+ }
+
+ return memory_send(memory_region, mem_func, fragment_length,
+ total_length);
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c b/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c
index 1295442..0a722e4 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c
@@ -11,6 +11,8 @@
#include <cactus_test_cmds.h>
#include <ffa_endpoints.h>
#include <ffa_svc.h>
+#include <lib/events.h>
+#include <lib/power_management.h>
#include <platform.h>
#include <test_helpers.h>
@@ -18,37 +20,31 @@
#define ECHO_VAL2 U(0xb0b0b0b0)
#define ECHO_VAL3 U(0xc0c0c0c0)
-#define DIRECT_MSG_TEST_PATTERN1 (0xaaaa0000)
-#define DIRECT_MSG_TEST_PATTERN2 (0xbbbb0000)
-#define DIRECT_MSG_TEST_PATTERN3 (0xcccc0000)
-
static const struct ffa_uuid expected_sp_uuids[] = {
{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
};
-static test_result_t send_receive_direct_msg(unsigned int sp_id,
- unsigned int test_pattern)
-{
- smc_ret_values ret_values;
- /* Send a message to SP through direct messaging */
- ret_values = ffa_msg_send_direct_req(HYP_ID, sp_id, test_pattern);
+static event_t cpu_booted[PLATFORM_CORE_COUNT];
+
+static test_result_t send_cactus_echo_cmd(ffa_vm_id_t sender,
+ ffa_vm_id_t dest,
+ uint64_t value)
+{
+ smc_ret_values ret;
+ ret = cactus_echo_send_cmd(sender, dest, value);
/*
* Return responses may be FFA_MSG_SEND_DIRECT_RESP or FFA_INTERRUPT,
* but only expect the former. Expect SMC32 convention from SP.
*/
- if (ffa_func_id(ret_values) != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
- tftf_testcase_printf("ffa_msg_send_direct_req returned %x\n",
- ffa_func_id(ret_values));
+ if (!is_ffa_direct_response(ret)) {
return TEST_RESULT_FAIL;
}
- /*
- * Message loop in SP returns initial message with the running VM id
- * into the lower 16 bits of initial message.
- */
- if (ret_values.ret3 != (test_pattern | sp_id)) {
+ if (cactus_get_response(ret) != CACTUS_SUCCESS ||
+ cactus_echo_get_val(ret) != value) {
+ ERROR("Echo Failed!\n");
return TEST_RESULT_FAIL;
}
@@ -67,7 +63,7 @@
/**********************************************************************
* Send a message to SP1 through direct messaging
**********************************************************************/
- result = send_receive_direct_msg(SP_ID(1), DIRECT_MSG_TEST_PATTERN1);
+ result = send_cactus_echo_cmd(HYP_ID, SP_ID(1), ECHO_VAL1);
if (result != TEST_RESULT_SUCCESS) {
return result;
}
@@ -75,7 +71,7 @@
/**********************************************************************
* Send a message to SP2 through direct messaging
**********************************************************************/
- result = send_receive_direct_msg(SP_ID(2), DIRECT_MSG_TEST_PATTERN2);
+ result = send_cactus_echo_cmd(HYP_ID, SP_ID(2), ECHO_VAL2);
if (result != TEST_RESULT_SUCCESS) {
return result;
}
@@ -83,7 +79,7 @@
/**********************************************************************
* Send a message to SP1 through direct messaging
**********************************************************************/
- result = send_receive_direct_msg(SP_ID(1), DIRECT_MSG_TEST_PATTERN3);
+ result = send_cactus_echo_cmd(HYP_ID, SP_ID(1), ECHO_VAL3);
return result;
}
@@ -105,9 +101,7 @@
ret = cactus_req_echo_send_cmd(sender, dest, echo_dest, value);
- if (ffa_func_id(ret) != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
- ERROR("Failed to send message. error: %x\n",
- ffa_error_code(ret));
+ if (!is_ffa_direct_response(ret)) {
return TEST_RESULT_FAIL;
}
@@ -157,9 +151,7 @@
ret = cactus_req_deadlock_send_cmd(HYP_ID, SP_ID(1), SP_ID(2), SP_ID(3));
- if (ffa_func_id(ret) != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
- ERROR("Failed to send message. error: %x\n",
- ffa_error_code(ret));
+ if (is_ffa_direct_response(ret) == false) {
return TEST_RESULT_FAIL;
}
@@ -169,3 +161,142 @@
return TEST_RESULT_SUCCESS;
}
+
+/**
+ * Handler that is passed during tftf_cpu_on to individual CPU cores.
+ * Runs a specific core and send a direct message request.
+ * Expects core_pos | SP_ID as a response.
+ */
+static test_result_t cpu_on_handler(void)
+{
+ unsigned int mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int core_pos = platform_get_core_pos(mpid);
+ test_result_t ret = TEST_RESULT_SUCCESS;
+ smc_ret_values ffa_ret;
+
+ /*
+ * Send a direct message request to SP1 (MP SP) from current physical
+ * CPU. Notice SP1 ECs are already woken as a result of the PSCI_CPU_ON
+ * invocation so they already reached the message loop.
+ * The SPMC uses the MP pinned context corresponding to the physical
+ * CPU emitting the request.
+ */
+ ret = send_cactus_echo_cmd(HYP_ID, SP_ID(1), ECHO_VAL1);
+ if (ret != TEST_RESULT_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Secure Partitions beyond the first SP only have their first
+ * EC (or vCPU0) woken up at boot time by the SPMC.
+ * Other ECs need one round of ffa_run to reach the message loop.
+ */
+ ffa_ret = ffa_run(SP_ID(2), core_pos);
+ if (ffa_func_id(ffa_ret) != FFA_MSG_WAIT) {
+ ERROR("Failed to run SP%x on core %u\n", SP_ID(2),
+ core_pos);
+ ret = TEST_RESULT_FAIL;
+ goto out;
+ }
+
+ /*
+ * Send a direct message request to SP2 (MP SP) from current physical
+ * CPU. The SPMC uses the MP pinned context corresponding to the
+ * physical CPU emitting the request.
+ */
+ ret = send_cactus_echo_cmd(HYP_ID, SP_ID(2), ECHO_VAL2);
+ if (ret != TEST_RESULT_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Send a direct message request to SP3 (UP SP) from current physical CPU.
+ * The SPMC uses the single vCPU migrated to the new physical core.
+ * The single SP vCPU may receive requests from multiple physical CPUs.
+ * Thus it is possible one message is being processed on one core while
+ * another (or multiple) cores attempt sending a new direct message
+ * request. In such case the cores attempting the new request receive
+ * a busy response from the SPMC. To handle this case a retry loop is
+ * implemented permitting some fairness.
+ */
+ uint32_t trial_loop = 5U;
+ while (trial_loop--) {
+ ffa_ret = cactus_echo_send_cmd(HYP_ID, SP_ID(3), ECHO_VAL3);
+ if ((ffa_func_id(ffa_ret) == FFA_ERROR) &&
+ (ffa_error_code(ffa_ret) == FFA_ERROR_BUSY)) {
+ VERBOSE("%s(%u) trial %u\n", __func__, core_pos, trial_loop);
+ waitms(1);
+ continue;
+ }
+
+ if (is_ffa_direct_response(ffa_ret) == true) {
+ if (cactus_get_response(ffa_ret) != CACTUS_SUCCESS ||
+ cactus_echo_get_val(ffa_ret) != ECHO_VAL3) {
+ ERROR("Echo Failed!\n");
+ ret = TEST_RESULT_FAIL;
+ }
+
+ goto out;
+ }
+ }
+
+ ret = TEST_RESULT_FAIL;
+
+out:
+ /* Tell the lead CPU that the calling CPU has completed the test */
+ tftf_send_event(&cpu_booted[core_pos]);
+
+ return ret;
+}
+
+/**
+ * Test direct messaging in multicore setup. Runs SPs on all the cores and sends
+ * direct messages to SPs.
+ */
+test_result_t test_ffa_secondary_core_direct_msg(void)
+{
+ unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int core_pos, cpu_node, mpidr;
+ int32_t ret;
+
+ /**********************************************************************
+ * Check SPMC has ffa_version and expected FFA endpoints are deployed.
+ **********************************************************************/
+ CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+ for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+ tftf_init_event(&cpu_booted[i]);
+ }
+
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (mpidr == lead_mpid) {
+ continue;
+ }
+
+ ret = tftf_cpu_on(mpidr, (uintptr_t)cpu_on_handler, 0U);
+ if (ret != 0) {
+ ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
+ }
+ }
+
+ VERBOSE("Waiting secondary CPUs to turn off ...\n");
+
+ for_each_cpu(cpu_node) {
+ mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (mpidr == lead_mpid) {
+ continue;
+ }
+
+ core_pos = platform_get_core_pos(mpidr);
+ tftf_wait_for_event(&cpu_booted[core_pos]);
+ }
+
+ VERBOSE("Done exiting.\n");
+
+ /**********************************************************************
+ * All tests passed.
+ **********************************************************************/
+
+ return TEST_RESULT_SUCCESS;
+}
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 05a8b59..f126c57 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
@@ -10,6 +10,7 @@
#include <ffa_endpoints.h>
#include <test_helpers.h>
#include <tftf_lib.h>
+#include <spm_common.h>
#include <xlat_tables_defs.h>
#define MAILBOX_SIZE PAGE_SIZE
@@ -63,7 +64,7 @@
const uint32_t constituents_count = sizeof(constituents) /
sizeof(struct ffa_memory_region_constituent);
- handle = ffa_memory_init_and_send((struct ffa_memory_region *)mb.send,
+ handle = memory_init_and_send((struct ffa_memory_region *)mb.send,
MAILBOX_SIZE, SENDER, RECEIVER,
constituents, constituents_count,
mem_func);
@@ -79,9 +80,7 @@
ret = cactus_mem_send_cmd(SENDER, RECEIVER, mem_func, handle);
- if (ffa_func_id(ret) != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
- ERROR("Failed to send message. error: %x\n",
- ffa_error_code(ret));
+ if (!is_ffa_direct_response(ret)) {
return TEST_RESULT_FAIL;
}
@@ -103,7 +102,7 @@
(void)ptr;
if (mem_func != FFA_MEM_DONATE_SMC32 &&
- ffa_mem_reclaim(handle, 0).ret0 == FFA_ERROR) {
+ is_ffa_call_error(ffa_mem_reclaim(handle, 0))) {
tftf_testcase_printf("Couldn't reclaim memory\n");
return TEST_RESULT_FAIL;
}
@@ -144,9 +143,7 @@
ret = cactus_req_mem_send_send_cmd(HYP_ID, sender_sp, mem_func,
receiver_sp);
- if (ffa_func_id(ret) != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
- ERROR("Failed to send message. error: %x\n",
- ffa_error_code(ret));
+ if (!is_ffa_direct_response(ret)) {
return TEST_RESULT_FAIL;
}
diff --git a/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c b/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
index c6470c1..f57fa24 100644
--- a/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
+++ b/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
@@ -55,9 +55,7 @@
smc_ret_values ret = cactus_req_simd_fill_send_cmd(SENDER, RECEIVER);
- if (ffa_func_id(ret) != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
- ERROR("Failed to send message. error: %x\n",
- ffa_error_code(ret));
+ if (!is_ffa_direct_response(ret)) {
return TEST_RESULT_FAIL;
}
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index 5e80988..ee34292 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -44,6 +44,12 @@
</testsuite>
+ <testsuite name="FF-A Power management"
+ description="Test FF-A power management" >
+ <testcase name="FF-A SP hotplug"
+ function="test_ffa_secondary_core_direct_msg" />
+ </testsuite>
+
<testsuite name="FF-A Memory Sharing"
description="Test FF-A Memory Sharing ABIs" >
<testcase name="Lend Memory to Secure World"