Merge changes from topic "rmm-eac5"

* changes:
  feat(rmm-eac5): update RSI_VERSION, RMI_VERSION
  feat(rmm) : add api for rec force exit
  test(rmm-eac4): add testcase for CPU_ON denied
diff --git a/Makefile b/Makefile
index e104814..58af796 100644
--- a/Makefile
+++ b/Makefile
@@ -169,6 +169,7 @@
 $(eval $(call assert_boolean,USE_NVM))
 $(eval $(call assert_numeric,BRANCH_PROTECTION))
 $(eval $(call assert_boolean,ENABLE_REALM_PAYLOAD_TESTS))
+$(eval $(call assert_boolean,TRANSFER_LIST))
 
 ################################################################################
 # Process build options
@@ -194,6 +195,7 @@
 $(eval $(call add_define,TFTF_DEFINES,PLAT_${PLAT}))
 $(eval $(call add_define,TFTF_DEFINES,USE_NVM))
 $(eval $(call add_define,TFTF_DEFINES,ENABLE_REALM_PAYLOAD_TESTS))
+$(eval $(call add_define,TFTF_DEFINES,TRANSFER_LIST))
 
 ################################################################################
 
diff --git a/include/lib/transfer_list.h b/include/lib/transfer_list.h
new file mode 100644
index 0000000..9ee1f55
--- /dev/null
+++ b/include/lib/transfer_list.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2023, Linaro Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __TRANSFER_LIST_H
+#define __TRANSFER_LIST_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define TRANSFER_LIST_SIGNATURE U(0x006ed0ff)
+#define TRANSFER_LIST_VERSION U(0x0001)
+
+// Init value of maximum alignment required by any TE data in the TL
+// specified as a power of two
+#define TRANSFER_LIST_INIT_MAX_ALIGN U(3)
+
+// alignment required by TE header start address, in bytes
+#define TRANSFER_LIST_GRANULE U(8)
+
+// version of the register convention used.
+// Set to 1 for both AArch64 and AArch32 according to fw handoff spec v0.9
+#define REGISTER_CONVENTION_VERSION_MASK (1 << 24)
+
+#ifndef __ASSEMBLER__
+
+enum transfer_list_tag_id {
+	TL_TAG_EMPTY = 0,
+	TL_TAG_FDT = 1,
+	TL_TAG_HOB_BLOCK = 2,
+	TL_TAG_HOB_LIST = 3,
+	TL_TAG_ACPI_TABLE_AGGREGATE = 4,
+};
+
+enum transfer_list_ops {
+	TL_OPS_NON, // invalid for any operation
+	TL_OPS_ALL, // valid for all operations
+};
+
+struct transfer_list_header {
+	uint32_t signature;
+	uint8_t checksum;
+	uint8_t version;
+	uint8_t hdr_size;
+	uint8_t alignment; // max alignment of TE data
+	uint32_t size; // TL header + all TEs
+	uint32_t max_size;
+	/*
+	 * Commented out element used to visualize dynamic part of the
+	 * data structure.
+	 *
+	 * Note that struct transfer_list_entry also is dynamic in size
+	 * so the elements can't be indexed directly but instead must be
+	 * traversed in order
+	 *
+	 * struct transfer_list_entry entries[];
+	 */
+};
+
+struct transfer_list_entry {
+	uint16_t tag_id;
+	uint8_t reserved0; // place holder
+	uint8_t hdr_size;
+	uint32_t data_size;
+	/*
+	 * Commented out element used to visualize dynamic part of the
+	 * data structure.
+	 *
+	 * Note that padding is added at the end of @data to make to reach
+	 * a 8-byte boundary.
+	 *
+	 * uint8_t	data[ROUNDUP(data_size, 8)];
+	 */
+};
+
+bool transfer_list_verify_checksum(const struct transfer_list_header *tl);
+
+void *transfer_list_entry_data(struct transfer_list_entry *entry);
+
+struct transfer_list_entry *transfer_list_find(struct transfer_list_header *tl,
+					       uint16_t tag_id);
+
+enum transfer_list_ops
+transfer_list_check_header(const struct transfer_list_header *tl);
+
+#endif /*__ASSEMBLER__*/
+#endif /*__TRANSFER_LIST_H*/
diff --git a/lib/transfer_list/transfer_list.c b/lib/transfer_list/transfer_list.c
new file mode 100644
index 0000000..c83b0b3
--- /dev/null
+++ b/lib/transfer_list/transfer_list.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <transfer_list.h>
+
+struct transfer_list_entry *transfer_list_find(struct transfer_list_header *tl,
+					       uint16_t tag_id)
+{
+	struct transfer_list_entry *te = (void *)tl + tl->hdr_size;
+
+	while (te->tag_id != tag_id) {
+		te += round_up(te->hdr_size + te->data_size, tl->alignment);
+	}
+
+	return te;
+}
+
+void *transfer_list_entry_data(struct transfer_list_entry *entry)
+{
+	return (uint8_t *)entry + entry->hdr_size;
+}
+
+/*******************************************************************************
+ * Verifying the header of a transfer list
+ * Compliant to 2.4.1 of Firmware handoff specification (v0.9)
+ * Return transfer list operation status code
+ ******************************************************************************/
+enum transfer_list_ops
+transfer_list_check_header(const struct transfer_list_header *tl)
+{
+	uint8_t byte_sum = 0U;
+	uint8_t *b = (uint8_t *)tl;
+
+	if (tl == NULL) {
+		return TL_OPS_NON;
+	}
+
+	if (tl->signature != TRANSFER_LIST_SIGNATURE ||
+	    tl->size > tl->max_size) {
+		return TL_OPS_NON;
+	}
+
+	for (size_t i = 0; i < tl->size; i++) {
+		byte_sum += b[i];
+	}
+
+	if (byte_sum - tl->checksum == tl->checksum) {
+		return TL_OPS_NON;
+	}
+
+	return TL_OPS_ALL;
+}
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 3605d01..d26ec06 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -51,3 +51,7 @@
 
 # Build RME stack
 ENABLE_REALM_PAYLOAD_TESTS	:= 0
+
+# Use the Firmware Handoff framework to receive configurations from preceding
+# bootloader.
+TRANSFER_LIST		:= 0
diff --git a/tftf/framework/aarch64/entrypoint.S b/tftf/framework/aarch64/entrypoint.S
index 6aa5645..7937b88 100644
--- a/tftf/framework/aarch64/entrypoint.S
+++ b/tftf/framework/aarch64/entrypoint.S
@@ -18,11 +18,13 @@
  */
 func tftf_entrypoint
 	/* --------------------------------------------------------------------
-	 * Save arguments x0, x1 from the previous Boot loader
+	 * Save arguments x0-x3 from the previous bootloader.
 	 * --------------------------------------------------------------------
 	 */
 	mov	x20, x0
 	mov	x21, x1
+	mov	x22, x2
+	mov	x23, x3
 
 	bl	arch_init
 
@@ -79,13 +81,15 @@
 	bl	platform_set_stack
 
 	/* --------------------------------------------------------------------
-	 * Save fw_config and hw_config addresses passed in x0, x1 from the
-	 * previous boot loader
+	 * Save the fw_config or transfer list and hw_config addresses passed
+	 * in registers x0 to x3 from the previous bootloader.
 	 * --------------------------------------------------------------------
 	 */
 	mov	x0, x20
 	mov	x1, x21
-	bl	save_fw_hw_configs
+	mov	x2, x22
+	mov	x3, x23
+	bl	save_handoff_params
 
 	/* --------------------------------------------------------------------
 	 * tftf_cold_boot_main() will perform the remaining architectural and
@@ -204,10 +208,22 @@
 	ret
 endfunc arch_init
 
-/* Set fw_config and hw_config addresses passed in x0, x1 */
-func save_fw_hw_configs
+
+/* ----------------------------------------------------------------------------
+ * Save fw_config or transfer list and hw_config addresses passed in registers
+ * x0 to x3 from the previous bootloader.
+ * ----------------------------------------------------------------------------
+ */
+func save_handoff_params
+#if TRANSFER_LIST
+	adrp	x4, ns_tl
+	str	x3, [x4, :lo12:ns_tl]
+	str	x1, [x4, :lo12:tl_signature]
+	str	x0, [x4, :lo12:hw_config_base]
+#else
 	adrp	x2, fw_config_base
 	str	x0, [x2, :lo12:fw_config_base]
 	str	x1, [x2, :lo12:hw_config_base]
+#endif
 	ret
-endfunc save_fw_hw_configs
+endfunc save_handoff_params
diff --git a/tftf/framework/framework.mk b/tftf/framework/framework.mk
index ef59502..f57572c 100644
--- a/tftf/framework/framework.mk
+++ b/tftf/framework/framework.mk
@@ -65,6 +65,7 @@
 	lib/smc/${ARCH}/smc.c						\
 	lib/trng/trng.c							\
         lib/errata_abi/errata_abi.c                                     \
+	lib/transfer_list/transfer_list.c				\
 	lib/trusted_os/trusted_os.c					\
 	lib/utils/mp_printf.c						\
 	lib/utils/uuid.c						\
diff --git a/tftf/framework/main.c b/tftf/framework/main.c
index a203bd2..0701e28 100644
--- a/tftf/framework/main.c
+++ b/tftf/framework/main.c
@@ -24,6 +24,9 @@
 #include <tftf.h>
 #include <tftf_lib.h>
 #include <timer.h>
+#if TRANSFER_LIST
+#include <transfer_list.h>
+#endif
 
 #define MIN_RETRY_TO_POWER_ON_LEAD_CPU       10
 
@@ -44,7 +47,12 @@
 static unsigned int test_is_rebooting;
 
 /* Parameters arg0 and arg1 passed from BL31 */
+#if TRANSFER_LIST
+u_register_t ns_tl;
+u_register_t tl_signature;
+#else
 u_register_t fw_config_base;
+#endif
 u_register_t hw_config_base;
 
 static inline const test_suite_t *current_testsuite(void)
diff --git a/tftf/tests/aarch32_tests_to_skip.txt b/tftf/tests/aarch32_tests_to_skip.txt
index 83e4028..210d465 100644
--- a/tftf/tests/aarch32_tests_to_skip.txt
+++ b/tftf/tests/aarch32_tests_to_skip.txt
@@ -17,3 +17,4 @@
 SMMUv3 tests
 FF-A Notifications
 RMI and SPM tests
+FF-A SMCCC compliance
diff --git a/tftf/tests/misc_tests/test_firmware_handoff.c b/tftf/tests/misc_tests/test_firmware_handoff.c
new file mode 100644
index 0000000..bd565ae
--- /dev/null
+++ b/tftf/tests/misc_tests/test_firmware_handoff.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <transfer_list.h>
+
+extern u_register_t hw_config_base;
+extern u_register_t ns_tl;
+extern u_register_t tl_signature;
+
+#define DTB_PREAMBLE U(0xedfe0dd0)
+
+test_result_t test_handoff_header(void)
+{
+	struct transfer_list_header *tl = (struct transfer_list_header *)ns_tl;
+
+	assert((uint32_t)tl_signature ==
+	       (REGISTER_CONVENTION_VERSION_MASK | TRANSFER_LIST_SIGNATURE));
+
+	if (transfer_list_check_header(tl) == TL_OPS_NON) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+test_result_t test_handoff_dtb_payload(void)
+{
+	tftf_testcase_printf("Validating HW_CONFIG from transfer list.\n");
+	struct transfer_list_header *tl = (struct transfer_list_header *)ns_tl;
+	struct transfer_list_entry *te = (void *)tl + tl->hdr_size;
+	uintptr_t dtb_ptr;
+
+	te = transfer_list_find(tl, TL_TAG_FDT);
+
+	if (te == NULL) {
+		tftf_testcase_printf(
+			"Failed to find HW CONFIG TE in transfer list!");
+		return TEST_RESULT_FAIL;
+	}
+
+	dtb_ptr = (unsigned long)transfer_list_entry_data(te);
+
+	if ((dtb_ptr != hw_config_base) &&
+	    (*(uint32_t *)dtb_ptr != DTB_PREAMBLE)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_smccc.c b/tftf/tests/runtime_services/secure_service/test_ffa_smccc.c
new file mode 100644
index 0000000..7a42633
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_smccc.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+
+#include <ffa_endpoints.h>
+#include <ffa_helpers.h>
+#include <ffa_svc.h>
+#include <runtime_services/spm_test_helpers.h>
+#include <spm_common.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <xlat_tables_defs.h>
+
+#define expect_eq(expr, value)							\
+	do {									\
+		if ((expr) != (value)) {					\
+			ERROR("expect failed %s:%u\n", __FILE__, __LINE__);	\
+			return TEST_RESULT_FAIL;				\
+		}								\
+	} while (0);
+
+static const struct ffa_uuid sp_uuids[] = {
+		{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}, {IVY_UUID}
+	};
+
+struct ffa_value8 {
+	u_register_t fid;
+	u_register_t arg1;
+	u_register_t arg2;
+	u_register_t arg3;
+	u_register_t arg4;
+	u_register_t arg5;
+	u_register_t arg6;
+	u_register_t arg7;
+};
+
+/* Declared in test_ffa_smccc_asm.S. */
+uint32_t test_ffa_smc(struct ffa_value8 *);
+uint32_t test_ffa_smc_ext(struct ffa_value *);
+
+/**
+ * FF-A service calls are emitted at the NS physical FF-A instance.
+ * Such services do not return results in registers beyond x7.
+ * Check callee(s) preserves GP registers beyond x7 per SMCCCv1.2.
+ */
+test_result_t test_smccc_callee_preserved(void)
+{
+	struct ffa_value8 args;
+	struct mailbox_buffers mb;
+
+	/*
+	 * Permit running the test on configurations running
+	 * the S-EL2 SPMC where 4 test partitions are deployed.
+	 */
+	CHECK_SPMC_TESTING_SETUP(1, 1, sp_uuids);
+	reset_tftf_mailbox();
+
+	/* Declare RX/TX buffers locally to the test. */
+	CONFIGURE_MAILBOX(mb, PAGE_SIZE);
+
+	memset(&args, 0, sizeof(struct ffa_value8));
+	args.fid  = FFA_VERSION;
+	args.arg1 = 0x10001;
+	expect_eq(test_ffa_smc(&args), 0);
+	expect_eq(args.fid, 0x10001);
+	expect_eq(args.arg1, 0);
+	expect_eq(args.arg2, 0);
+	expect_eq(args.arg3, 0);
+	expect_eq(args.arg4, 0);
+	expect_eq(args.arg5, 0);
+	expect_eq(args.arg6, 0);
+	expect_eq(args.arg7, 0);
+
+	memset(&args, 0, sizeof(struct ffa_value8));
+	args.fid  = FFA_ID_GET;
+	expect_eq(test_ffa_smc(&args), 0);
+	expect_eq(args.fid, FFA_SUCCESS_SMC32);
+	expect_eq(args.arg1, 0);
+	expect_eq(args.arg2, 0);
+	expect_eq(args.arg3, 0);
+	expect_eq(args.arg4, 0);
+	expect_eq(args.arg5, 0);
+	expect_eq(args.arg6, 0);
+	expect_eq(args.arg7, 0);
+
+	memset(&args, 0, sizeof(struct ffa_value8));
+	args.fid  = FFA_RXTX_MAP_SMC64;
+	args.arg1 = (uintptr_t)mb.send;
+	args.arg2 = (uintptr_t)mb.recv;
+	args.arg3 = 1;
+	expect_eq(test_ffa_smc(&args), 0);
+	expect_eq(args.fid, FFA_SUCCESS_SMC32);
+	expect_eq(args.arg1, 0);
+	expect_eq(args.arg2, 0);
+	expect_eq(args.arg3, 0);
+	expect_eq(args.arg4, 0);
+	expect_eq(args.arg5, 0);
+	expect_eq(args.arg6, 0);
+	expect_eq(args.arg7, 0);
+
+	memset(&args, 0, sizeof(struct ffa_value8));
+	args.fid = FFA_PARTITION_INFO_GET;
+	expect_eq(test_ffa_smc(&args), 0);
+	expect_eq(args.fid, FFA_SUCCESS_SMC32);
+	expect_eq(args.arg1, 0);
+	expect_eq(args.arg2, ARRAY_SIZE(sp_uuids));
+	expect_eq(args.arg3, sizeof(struct ffa_partition_info));
+	expect_eq(args.arg4, 0);
+	expect_eq(args.arg5, 0);
+	expect_eq(args.arg6, 0);
+	expect_eq(args.arg7, 0);
+
+	memset(&args, 0, sizeof(struct ffa_value8));
+	args.fid = FFA_RX_RELEASE;
+	expect_eq(test_ffa_smc(&args), 0);
+	expect_eq(args.fid, FFA_SUCCESS_SMC32);
+	expect_eq(args.arg1, 0);
+	expect_eq(args.arg2, 0);
+	expect_eq(args.arg3, 0);
+	expect_eq(args.arg4, 0);
+	expect_eq(args.arg5, 0);
+	expect_eq(args.arg6, 0);
+	expect_eq(args.arg7, 0);
+
+	memset(&args, 0, sizeof(struct ffa_value8));
+	args.fid = FFA_RXTX_UNMAP;
+	expect_eq(test_ffa_smc(&args), 0);
+	expect_eq(args.fid, FFA_SUCCESS_SMC32);
+	expect_eq(args.arg1, 0);
+	expect_eq(args.arg2, 0);
+	expect_eq(args.arg3, 0);
+	expect_eq(args.arg4, 0);
+	expect_eq(args.arg5, 0);
+	expect_eq(args.arg6, 0);
+	expect_eq(args.arg7, 0);
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * An FF-A service call is emitted at the NS physical FF-A instance.
+ * The service returns results in x0-x17 registers.
+ * Check callee(s) preserve GP registers beyond x17 per SMCCCv1.2.
+ */
+test_result_t test_smccc_ext_callee_preserved(void)
+{
+	struct ffa_value args_ext;
+
+	CHECK_SPMC_TESTING_SETUP(1, 1, sp_uuids);
+
+	/* Test the SMCCC extended registers range. */
+	memset(&args_ext, 0, sizeof(struct ffa_value));
+	args_ext.fid  = FFA_PARTITION_INFO_GET_REGS_SMC64;
+	expect_eq(test_ffa_smc_ext(&args_ext), 0);
+	expect_eq(args_ext.fid, FFA_SUCCESS_SMC64);
+	expect_eq(args_ext.arg1, 0);
+	expect_eq(args_ext.arg2 >> 48, sizeof(struct ffa_partition_info));
+	expect_eq(args_ext.arg2 & 0xffff, ARRAY_SIZE(sp_uuids) - 1);
+
+	return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_smccc_asm.S b/tftf/tests/runtime_services/secure_service/test_ffa_smccc_asm.S
new file mode 100644
index 0000000..00d82ee
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_smccc_asm.S
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+	.global test_ffa_smc
+	.global test_ffa_smc_ext
+
+	.section	.text, "ax"
+
+/**
+ * test_ffa_smc
+ *
+ * x0 - ptr to a struct ffa_value8
+ *
+ * This function is used to test FF-A ABIs on top of SMCCCv1.2 for interfaces
+ * requiring at most 8 input/output registers.
+ * Load 8 GP input registers, move a pattern into x8-x29 and emit an SMC.
+ * On return save 8 output registers to the structure and compare x8-x29
+ * to the known pattern. If a register was altered it indicates an SMCCC
+ * violation and the function returns with a value greater than 0.
+ * The function returns 0 on success.
+ */
+func test_ffa_smc
+	/* Save FP/LR. */
+	stp	x29, x30, [sp, #-16]!
+
+	/* Save x19-x28 per AAPCS64. */
+	stp	x27, x28, [sp, #-16]!
+	stp	x25, x26, [sp, #-16]!
+	stp	x23, x24, [sp, #-16]!
+	stp	x21, x22, [sp, #-16]!
+	stp	x19, x20, [sp, #-16]!
+
+	/*
+	 * Store the struct ffa_value pointer to x30.
+	 * x30 is preserved by the SMC callee.
+	 */
+	mov	x30, x0
+
+	/* Load the SMC service input values. */
+	ldp	x0, x1, [x30]
+	ldp	x2, x3, [x30, #16]
+	ldp	x4, x5, [x30, #32]
+	ldp	x6, x7, [x30, #48]
+	mov	x8, #0xa8
+	add	x9, x8, #1
+	add	x10, x8, #2
+	add	x11, x8, #3
+	add	x12, x8, #4
+	add	x13, x8, #5
+	add	x14, x8, #6
+	add	x15, x8, #7
+	add	x16, x8, #8
+	add	x17, x8, #9
+	add	x18, x8, #10
+	add	x19, x8, #11
+	add	x20, x8, #12
+	add	x21, x8, #13
+	add	x22, x8, #14
+	add	x23, x8, #15
+	add	x24, x8, #16
+	add	x25, x8, #17
+	add	x26, x8, #18
+	add	x27, x8, #19
+	add	x28, x8, #20
+	add	x29, x8, #21
+	smc     #0
+
+	/* Store the SMC service return values. */
+	stp	x0, x1, [x30]
+	stp	x2, x3, [x30, #16]
+	stp	x4, x5, [x30, #32]
+	stp	x6, x7, [x30, #48]
+
+	/* Check if SMC callee-preserved registers were altered. */
+	mov	w0, wzr
+	cmp	x8, #0xa8
+	cinc	x0, x0, ne
+	cmp	x9, #0xa9
+	cinc	x0, x0, ne
+	cmp	x10, #0xaa
+	cinc	x0, x0, ne
+	cmp	x11, #0xab
+	cinc	x0, x0, ne
+	cmp	x12, #0xac
+	cinc	x0, x0, ne
+	cmp	x13, #0xad
+	cinc	x0, x0, ne
+	cmp	x14, #0xae
+	cinc	x0, x0, ne
+	cmp	x15, #0xaf
+	cinc	x0, x0, ne
+	cmp	x16, #0xb0
+	cinc	x0, x0, ne
+	cmp	x17, #0xb1
+	cinc	x0, x0, ne
+	cmp	x18, #0xb2
+	cinc	x0, x0, ne
+	cmp	x19, #0xb3
+	cinc	x0, x0, ne
+	cmp	x20, #0xb4
+	cinc	x0, x0, ne
+	cmp	x21, #0xb5
+	cinc	x0, x0, ne
+	cmp	x22, #0xb6
+	cinc	x0, x0, ne
+	cmp	x23, #0xb7
+	cinc	x0, x0, ne
+	cmp	x24, #0xb8
+	cinc	x0, x0, ne
+	cmp	x25, #0xb9
+	cinc	x0, x0, ne
+	cmp	x26, #0xba
+	cinc	x0, x0, ne
+	cmp	x27, #0xbb
+	cinc	x0, x0, ne
+	cmp	x28, #0xbc
+	cinc	x0, x0, ne
+	cmp	x29, #0xbd
+	cinc	x0, x0, ne
+
+	/* Restore x19-x28 per AAPCS64. */
+	ldp	x19, x20, [sp], #16
+	ldp	x21, x22, [sp], #16
+	ldp	x23, x24, [sp], #16
+	ldp	x25, x26, [sp], #16
+	ldp	x27, x28, [sp], #16
+
+	/* Restore FP/LR. */
+	ldp	x29, x30, [sp], #16
+	ret
+endfunc test_ffa_smc
+
+/**
+ * test_ffa_smc_ext
+ *
+ * x0 - ptr to a struct ffa_value
+ *
+ * This function is used to test FF-A ABIs on top of SMCCCv1.2 for interfaces
+ * requiring at most 18 input/output registers.
+ * Load 18 GP input registers, move a pattern into x18-x29 and emit an SMC.
+ * On return save 18 output registers to the structure and compare x18-x29
+ * to the known pattern. If a register was altered it indicates an SMCCC
+ * violation and the function returns with a value greater than 0.
+ * The function returns 0 on success.
+ */
+func test_ffa_smc_ext
+	/* Save FP/LR. */
+	stp	x29, x30, [sp, #-16]!
+
+	/* Save x19-x28 per AAPCS64. */
+	stp	x27, x28, [sp, #-16]!
+	stp	x25, x26, [sp, #-16]!
+	stp	x23, x24, [sp, #-16]!
+	stp	x21, x22, [sp, #-16]!
+	stp	x19, x20, [sp, #-16]!
+
+	/*
+	 * Store the struct ffa_value_ext pointer to x30.
+	 * x30 is preserved by the SMC callee.
+	 */
+	mov	x30, x0
+
+	/* Load the SMC service input values. */
+	ldp	x0, x1, [x30]
+	ldp	x2, x3, [x30, #16]
+	ldp	x4, x5, [x30, #32]
+	ldp	x6, x7, [x30, #48]
+	ldp	x8, x9, [x30, #64]
+	ldp	x10, x11, [x30, #80]
+	ldp	x12, x13, [x30, #96]
+	ldp	x14, x15, [x30, #112]
+	ldp	x16, x17, [x30, #128]
+	mov	x18, #0xb2
+	add	x19, x18, #1
+	add	x20, x18, #2
+	add	x21, x18, #3
+	add	x22, x18, #4
+	add	x23, x18, #5
+	add	x24, x18, #6
+	add	x25, x18, #7
+	add	x26, x18, #8
+	add	x27, x18, #9
+	add	x28, x18, #10
+	add	x29, x18, #11
+	smc     #0
+
+	/* Store the SMC service return values. */
+	stp	x0, x1, [x30]
+	stp	x2, x3, [x30, #16]
+	stp	x4, x5, [x30, #32]
+	stp	x6, x7, [x30, #48]
+	stp	x8, x9, [x30, #64]
+	stp	x10, x11, [x30, #80]
+	stp	x12, x13, [x30, #96]
+	stp	x14, x15, [x30, #112]
+	stp	x16, x17, [x30, #128]
+
+	/* Check if SMC callee-preserved registers were altered. */
+	mov	w0, wzr
+	cmp	x18, #0xb2
+	cinc	x0, x0, ne
+	cmp	x19, #0xb3
+	cinc	x0, x0, ne
+	cmp	x20, #0xb4
+	cinc	x0, x0, ne
+	cmp	x21, #0xb5
+	cinc	x0, x0, ne
+	cmp	x22, #0xb6
+	cinc	x0, x0, ne
+	cmp	x23, #0xb7
+	cinc	x0, x0, ne
+	cmp	x24, #0xb8
+	cinc	x0, x0, ne
+	cmp	x25, #0xb9
+	cinc	x0, x0, ne
+	cmp	x26, #0xba
+	cinc	x0, x0, ne
+	cmp	x27, #0xbb
+	cinc	x0, x0, ne
+	cmp	x28, #0xbc
+	cinc	x0, x0, ne
+	cmp	x29, #0xbd
+	cinc	x0, x0, ne
+
+	/* Restore x19-x28 per AAPCS64. */
+	ldp	x19, x20, [sp], #16
+	ldp	x21, x22, [sp], #16
+	ldp	x23, x24, [sp], #16
+	ldp	x25, x26, [sp], #16
+	ldp	x27, x28, [sp], #16
+
+	/* Restore FP/LR. */
+	ldp	x29, x30, [sp], #16
+	ret
+endfunc test_ffa_smc_ext
diff --git a/tftf/tests/tests-firmware-handoff.mk b/tftf/tests/tests-firmware-handoff.mk
new file mode 100644
index 0000000..515188a
--- /dev/null
+++ b/tftf/tests/tests-firmware-handoff.mk
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${TRANSFER_LIST}, 1)
+
+TESTS_SOURCES	+=	$(addprefix tftf/tests/misc_tests/,		\
+	test_firmware_handoff.c						\
+)
+
+endif
diff --git a/tftf/tests/tests-firmware-handoff.xml b/tftf/tests/tests-firmware-handoff.xml
new file mode 100644
index 0000000..2761626
--- /dev/null
+++ b/tftf/tests/tests-firmware-handoff.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="Firmware Handoff" description="Validate transfer list managed by firmware hanoff framework">
+     <testcase name="Validate transfer list header" function="test_handoff_header" />
+     <testcase name="Validate HW_CONFIG in transfer list" function="test_handoff_dtb_payload" />
+  </testsuite>
+</testsuites>
diff --git a/tftf/tests/tests-spm.mk b/tftf/tests/tests-spm.mk
index 13f3f86..174e11d 100644
--- a/tftf/tests/tests-spm.mk
+++ b/tftf/tests/tests-spm.mk
@@ -36,5 +36,11 @@
 		host_realm_helper.c					\
 	)
 
+TESTS_SOURCES	+=							\
+	$(addprefix tftf/tests/runtime_services/secure_service/,	\
+		test_ffa_smccc.c					\
+		test_ffa_smccc_asm.S					\
+	)
+
 TESTS_SOURCES   += lib/extensions/fpu/fpu.c
 endif
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index 8ec2812..e47039f 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -42,6 +42,14 @@
 	       function="test_ffa_partition_info_v1_0" />
   </testsuite>
 
+  <testsuite name="FF-A SMCCC compliance"
+             description="SMCCC compliance" >
+     <testcase name="FF-A callee preserves GP register set per SMCCC"
+               function="test_smccc_callee_preserved" />
+     <testcase name="FF-A callee preserves extended GP register set per SMCCC"
+               function="test_smccc_ext_callee_preserved" />
+  </testsuite>
+
   <testsuite name="SP exceptions"
              description="SP exceptions" >