Merge changes from topic "el3_direct_msg"

* changes:
  feat: use x0-x17 for ff-a calls
  test: add discovery of el3 spmd logical partitions
  feat(ff-a): partition information via registers
diff --git a/include/runtime_services/ffa_endpoints.h b/include/runtime_services/ffa_endpoints.h
index 88055c4..26297bc 100644
--- a/include/runtime_services/ffa_endpoints.h
+++ b/include/runtime_services/ffa_endpoints.h
@@ -14,12 +14,14 @@
 #define SECONDARY_UUID {0x092358d1, 0xb94723f0, 0x64447c82, 0xc88f57f5}
 #define TERTIARY_UUID {0x735cb579, 0xb9448c1d, 0xe1619385, 0xd2d80a77}
 #define IVY_UUID {0xd883baea, 0xaf4eafba, 0xfdf74481, 0xa744e5cb}
+#define EL3_SPMD_LP_UUID {0xe98e43ad, 0xb7db524f, 0x47a3bf57, 0x1588f4e3}
 
 /* vcpu_count of cactus SPs. */
 #define PRIMARY_EXEC_CTX_COUNT		PLATFORM_CORE_COUNT
 #define SECONDARY_EXEC_CTX_COUNT	PLATFORM_CORE_COUNT
 #define TERTIARY_EXEC_CTX_COUNT		(1)
 #define IVY_EXEC_CTX_COUNT		(1)
+#define EL3_SPMD_LP_EXEC_CTX_COUNT	(1)
 
 /* UUID of OPTEE SP as defined in the respective manifest. */
 #define OPTEE_UUID {0x486178e0, 0xe7f811e3, 0xbc5e0002, 0xa5d5c51b}
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index 8ce6ed3..a7cdcb5 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -22,7 +22,7 @@
 typedef uint8_t ffa_memory_receiver_flags_t;
 
 struct ffa_uuid {
-	const uint32_t uuid[4];
+	uint32_t uuid[4];
 };
 
 /** Length in bytes of the name in boot information descriptor. */
@@ -188,6 +188,16 @@
 	u_register_t arg5;
 	u_register_t arg6;
 	u_register_t arg7;
+	u_register_t arg8;
+	u_register_t arg9;
+	u_register_t arg10;
+	u_register_t arg11;
+	u_register_t arg12;
+	u_register_t arg13;
+	u_register_t arg14;
+	u_register_t arg15;
+	u_register_t arg16;
+	u_register_t arg17;
 };
 
 /* Function to make an SMC or SVC service call depending on the exception
@@ -237,6 +247,47 @@
 	return (uint32_t)val.arg2;
 }
 
+static inline uint16_t ffa_partition_info_regs_get_last_idx(
+	struct ffa_value args)
+{
+	return args.arg2 & 0xFFFF;
+}
+
+static inline uint16_t ffa_partition_info_regs_get_curr_idx(
+	struct ffa_value args)
+{
+	return (args.arg2 >> 16) & 0xFFFF;
+}
+
+static inline uint16_t ffa_partition_info_regs_get_tag(struct ffa_value args)
+{
+	return (args.arg2 >> 32) & 0xFFFF;
+}
+
+static inline uint16_t ffa_partition_info_regs_get_desc_size(
+	struct ffa_value args)
+{
+	return (args.arg2 >> 48);
+}
+
+static inline uint32_t ffa_partition_info_regs_partition_count(
+		struct ffa_value args)
+{
+	return ffa_partition_info_regs_get_last_idx(args) + 1;
+}
+
+static inline uint32_t ffa_partition_info_regs_entry_count(
+		struct ffa_value args, uint16_t start_idx)
+{
+	return (ffa_partition_info_regs_get_curr_idx(args) - start_idx + 1);
+}
+
+static inline uint16_t ffa_partition_info_regs_entry_size(
+		struct ffa_value args)
+{
+	return (args.arg2 >> 48) & 0xFFFFU;
+}
+
 typedef uint64_t ffa_notification_bitmap_t;
 
 #define FFA_NOTIFICATION(ID)		(UINT64_C(1) << ID)
@@ -703,7 +754,9 @@
 struct ffa_value ffa_notification_info_get(void);
 
 struct ffa_value ffa_console_log(const char* message, size_t char_count);
-
+struct ffa_value ffa_partition_info_get_regs(const struct ffa_uuid uuid,
+					     const uint16_t start_index,
+					     const uint16_t tag);
 #endif /* __ASSEMBLY__ */
 
 #endif /* FFA_HELPERS_H */
diff --git a/include/runtime_services/ffa_svc.h b/include/runtime_services/ffa_svc.h
index 6236ae3..bf535ea 100644
--- a/include/runtime_services/ffa_svc.h
+++ b/include/runtime_services/ffa_svc.h
@@ -100,6 +100,7 @@
 #define FFA_FNUM_SPM_ID_GET			U(0x85)
 #define FFA_FNUM_MSG_SEND2			U(0x86)
 #define FFA_FNUM_SECONDARY_EP_REGISTER		U(0x87)
+#define FFA_FNUM_PARTITION_INFO_GET_REGS	U(0x8B)
 
 /* Implementation defined function numbers */
 #define FFA_FNUM_CONSOLE_LOG			U(0x8A)
@@ -165,6 +166,8 @@
 	FFA_FID(SMC_64, FFA_FNUM_NOTIFICATION_INFO_GET)
 
 #define FFA_FEATURES_MEM_RETRIEVE_REQ_NS_SUPPORT (UINT32_C(1) << 1)
+#define FFA_PARTITION_INFO_GET_REGS_SMC64 \
+	FFA_FID(SMC_64, FFA_FNUM_PARTITION_INFO_GET_REGS)
 
 /* Implementation defined SMC64 FIDs */
 #define FFA_CONSOLE_LOG_SMC64	FFA_FID(SMC_64, FFA_FNUM_CONSOLE_LOG)
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index 7f47dc7..c1b3698 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -145,4 +145,7 @@
 bool enable_trusted_wdog_interrupt(ffa_id_t source, ffa_id_t dest);
 bool disable_trusted_wdog_interrupt(ffa_id_t source, ffa_id_t dest);
 
+bool ffa_partition_info_regs_helper(const struct ffa_uuid uuid,
+		       const struct ffa_partition_info *expected,
+		       const uint16_t expected_size);
 #endif /* SPM_COMMON_H */
diff --git a/spm/common/sp_tests/sp_test_ffa.c b/spm/common/sp_tests/sp_test_ffa.c
index f08f5f3..614770e 100644
--- a/spm/common/sp_tests/sp_test_ffa.c
+++ b/spm/common/sp_tests/sp_test_ffa.c
@@ -13,7 +13,6 @@
 #include <sp_helpers.h>
 #include <spm_helpers.h>
 #include <spm_common.h>
-
 #include <lib/libc/string.h>
 
 /* FFA version test helpers */
@@ -23,7 +22,7 @@
 static uint32_t spm_version;
 
 static const struct ffa_uuid sp_uuids[] = {
-		{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}, {IVY_UUID}
+		{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}, {IVY_UUID}, {EL3_SPMD_LP_UUID}
 	};
 
 static const struct ffa_partition_info ffa_expected_partition_info[] = {
@@ -65,7 +64,15 @@
 			       FFA_PARTITION_DIRECT_REQ_RECV |
 			       FFA_PARTITION_DIRECT_REQ_SEND),
 		.uuid = sp_uuids[3]
-	}
+	},
+	/* EL3 SPMD logical partition */
+	{
+		.id = SP_ID(0x7FC0),
+		.exec_context = EL3_SPMD_LP_EXEC_CTX_COUNT,
+		.properties = (FFA_PARTITION_AARCH64_EXEC |
+			       FFA_PARTITION_DIRECT_REQ_SEND),
+		.uuid = sp_uuids[4]
+	},
 };
 
 /*
@@ -121,6 +128,62 @@
 	expect(ffa_error_code(ret), FFA_ERROR_INVALID_PARAMETER);
 }
 
+static void ffa_partition_info_get_regs_test(void)
+{
+	struct ffa_value ret = { 0 };
+
+	VERBOSE("FF-A Partition Info regs interface tests\n");
+	ret = ffa_version(MAKE_FFA_VERSION(1, 1));
+	uint32_t version = ret.fid;
+
+	if (version == FFA_ERROR_NOT_SUPPORTED) {
+		ERROR("FFA_VERSION 1.1 not supported, skipping"
+			" FFA_PARTITION_INFO_GET_REGS test.\n");
+		return;
+	}
+
+	ret = ffa_features(FFA_PARTITION_INFO_GET_REGS_SMC64);
+	if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
+		ERROR("FFA_PARTITION_INFO_GET_REGS not supported skipping tests.\n");
+		return;
+	}
+
+	expect(ffa_partition_info_regs_helper(sp_uuids[3],
+		&ffa_expected_partition_info[3], 1), true);
+	expect(ffa_partition_info_regs_helper(sp_uuids[2],
+		&ffa_expected_partition_info[2], 1), true);
+	expect(ffa_partition_info_regs_helper(sp_uuids[1],
+		&ffa_expected_partition_info[1], 1), true);
+	expect(ffa_partition_info_regs_helper(sp_uuids[0],
+		&ffa_expected_partition_info[0], 1), true);
+
+	/*
+	 * Check partition information if there is support for SPMD EL3
+	 * partitions. calling partition_info_get_regs with the SPMD EL3
+	 * UUID successfully, indicates the presence of it (there is no
+	 * spec defined way to discover presence of el3 spmd logical
+	 * partitions). If the call fails with a not supported error,
+	 * we assume they dont exist and skip further tests to avoid
+	 * failures on platforms without el3 spmd logical partitions.
+	 */
+	ret = ffa_partition_info_get_regs(sp_uuids[4], 0, 0);
+	if ((ffa_func_id(ret) == FFA_ERROR) &&
+	    ((ffa_error_code(ret) == FFA_ERROR_NOT_SUPPORTED) ||
+	    (ffa_error_code(ret) == FFA_ERROR_INVALID_PARAMETER))) {
+		INFO("Skipping register based EL3 SPMD Logical partition"
+				" discovery\n");
+		expect(ffa_partition_info_regs_helper(NULL_UUID,
+			ffa_expected_partition_info,
+			(ARRAY_SIZE(ffa_expected_partition_info) - 1)), true);
+	} else {
+		expect(ffa_partition_info_regs_helper(sp_uuids[4],
+			&ffa_expected_partition_info[4], 1), true);
+		expect(ffa_partition_info_regs_helper(NULL_UUID,
+			ffa_expected_partition_info,
+			ARRAY_SIZE(ffa_expected_partition_info)), true);
+	}
+}
+
 static void ffa_partition_info_get_test(struct mailbox_buffers *mb)
 {
 	INFO("Test FFA_PARTITION_INFO_GET.\n");
@@ -134,9 +197,16 @@
 	expect(ffa_partition_info_helper(mb, sp_uuids[0],
 		&ffa_expected_partition_info[0], 1), true);
 
+	/*
+	 * TODO: ffa_partition_info_get_regs returns EL3 SPMD LP information
+	 * but partition_info_get does not. Ignore the last entry, that is
+	 * assumed to be the EL3 SPMD LP information. ffa_partition_info_get
+	 * uses the rx/tx buffer and the SPMD does not support the use of
+	 * rx/tx buffer to return SPMD logical partition information.
+	 */
 	expect(ffa_partition_info_helper(mb, NULL_UUID,
 		ffa_expected_partition_info,
-		ARRAY_SIZE(ffa_expected_partition_info)), true);
+		(ARRAY_SIZE(ffa_expected_partition_info) - 1)), true);
 
 	ffa_partition_info_wrong_test();
 }
@@ -192,6 +262,7 @@
 	ffa_version_test();
 	ffa_spm_id_get_test();
 	ffa_partition_info_get_test(mb);
+	ffa_partition_info_get_regs_test();
 
 	announce_test_section_end(test_ffa);
 }
diff --git a/tftf/tests/runtime_services/secure_service/aarch64/ffa_arch_helpers.S b/tftf/tests/runtime_services/secure_service/aarch64/ffa_arch_helpers.S
index 0e35a38..b9c9cd9 100644
--- a/tftf/tests/runtime_services/secure_service/aarch64/ffa_arch_helpers.S
+++ b/tftf/tests/runtime_services/secure_service/aarch64/ffa_arch_helpers.S
@@ -8,14 +8,24 @@
 
 	.macro service_call _conduit
 	/*
-	 * Save the address of the ffa_value structure on the stack.
-	 *
-	 * Although x0 contains an 8-byte value, we are allocating 16 bytes
+	 * Use a callee saved register to point to ffa_value structure after
+	 * returning from the conduit.
+	 * Although x19 contains an 8-byte value, we are allocating 16 bytes
 	 * on the stack to respect the 16-byte stack-alignment.
 	 */
-	str	x0, [sp, #-16]!
+	str	x19, [sp, #-16]!
 
+	/*
+	 * Save pointed to ffa_value structure into x19, which is a callee saved
+	 * register.
+	 */
+	mov	x19, x0
 	/* Load the argument values into the appropriate registers. */
+	ldp	x16, x17, [x0, #128]
+	ldp	x14, x15, [x0, #112]
+	ldp	x12, x13, [x0, #96]
+	ldp	x10, x11, [x0, #80]
+	ldp	x8, x9, [x0, #64]
 	ldp	x6, x7, [x0, #48]
 	ldp	x4, x5, [x0, #32]
 	ldp	x2, x3, [x0, #16]
@@ -24,20 +34,19 @@
 	\_conduit	#0
 
 	/*
-	 * Pop the ffa_value structure address from the stack into a
-	 * caller-saved register.
+	 * The return values are stored in x0-x17, put them in the ffa_value
+	 * return structure. x19 points to the ffa_value structure.
 	 */
-	ldr	x9, [sp], #16
-
-	/*
-	 * The return values are stored in x0-x7, put them in the ffa_value
-	 * return structure.
-	 */
-	stp	x0, x1, [x9, #0]
-	stp	x2, x3, [x9, #16]
-	stp	x4, x5, [x9, #32]
-	stp	x6, x7, [x9, #48]
-
+	stp	x0, x1, [x19, #0]
+	stp	x2, x3, [x19, #16]
+	stp	x4, x5, [x19, #32]
+	stp	x6, x7, [x19, #48]
+	stp	x8, x9, [x19, #64]
+	stp	x10, x11, [x19, #80]
+	stp	x12, x13, [x19, #96]
+	stp	x14, x15, [x19, #112]
+	stp	x16, x17, [x19, #128]
+	ldr	x19, [sp], #16
 	.endm
 
 .globl ffa_svc
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index 55221da..9547c07 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -382,6 +382,25 @@
 	return ffa_service_call(&args);
 }
 
+/* Get information about VMs or SPs based on UUID, using registers. */
+struct ffa_value ffa_partition_info_get_regs(const struct ffa_uuid uuid,
+					     const uint16_t start_index,
+					     const uint16_t tag)
+{
+	uint64_t arg1 = (uint64_t)uuid.uuid[1] << 32 | uuid.uuid[0];
+	uint64_t arg2 = (uint64_t)uuid.uuid[3] << 32 | uuid.uuid[2];
+	uint64_t arg3 = start_index | (uint64_t)tag << 16;
+
+	struct ffa_value args = {
+		.fid = FFA_PARTITION_INFO_GET_REGS_SMC64,
+		.arg1 = arg1,
+		.arg2 = arg2,
+		.arg3 = arg3,
+	};
+
+	return ffa_service_call(&args);
+}
+
 /* Get information about VMs or SPs based on UUID */
 struct ffa_value ffa_partition_info_get(const struct ffa_uuid uuid)
 {
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index 4d08bd0..43357a2 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -390,6 +390,149 @@
 	       (uuid2.uuid[3] == uuid2.uuid[3]);
 }
 
+static bool ffa_partition_info_regs_get_part_info(
+	struct ffa_value *args, uint8_t idx,
+	struct ffa_partition_info *partition_info)
+{
+	/*
+	 * The list of pointers to args in return value: arg0/func encodes ff-a
+	 * function, arg1 is reserved, arg2 encodes indices. arg3 and greater
+	 * values reflect partition properties.
+	 */
+	uint64_t *arg_ptrs = (uint64_t *)args + ((idx * 3) + 3);
+	uint64_t info, uuid_lo, uuid_high;
+
+	/*
+	 * Each partition information is encoded in 3 registers, so there can be
+	 * a maximum of 5 entries.
+	 */
+	if (idx >= 5 || !partition_info) {
+		return false;
+	}
+
+	info = *arg_ptrs;
+
+	arg_ptrs++;
+	uuid_lo = *arg_ptrs;
+
+	arg_ptrs++;
+	uuid_high = *arg_ptrs;
+
+	/*
+	 * As defined in FF-A 1.2 ALP0, 14.9 FFA_PARTITION_INFO_GET_REGS.
+	 */
+	partition_info->id = info & 0xFFFFU;
+	partition_info->exec_context = (info >> 16) & 0xFFFFU;
+	partition_info->properties = (info >> 32);
+	partition_info->uuid.uuid[0] = uuid_lo & 0xFFFFFFFFU;
+	partition_info->uuid.uuid[1] = (uuid_lo >> 32) & 0xFFFFFFFFU;
+	partition_info->uuid.uuid[2] = uuid_high & 0xFFFFFFFFU;
+	partition_info->uuid.uuid[3] = (uuid_high >> 32) & 0xFFFFFFFFU;
+
+	return true;
+}
+
+static bool ffa_compare_partition_info(
+		const struct ffa_uuid uuid,
+		const struct ffa_partition_info *info,
+		const struct ffa_partition_info *expected)
+{
+	bool result = true;
+	/*
+	 * If a UUID is specified then the UUID returned in the
+	 * partition info descriptor MBZ.
+	 */
+	struct ffa_uuid expected_uuid =
+		ffa_uuid_equal(uuid, NULL_UUID) ? expected->uuid : NULL_UUID;
+
+	if (info->id != expected->id) {
+		ERROR("Wrong ID. Expected %x, got %x\n", expected->id, info->id);
+		result = false;
+	}
+
+	if (info->exec_context != expected->exec_context) {
+		ERROR("Wrong context. Expected %d, got %d\n",
+		      expected->exec_context,
+		      info->exec_context);
+		result = false;
+	}
+	if (info->properties != expected->properties) {
+		ERROR("Wrong properties. Expected %d, got %d\n",
+		      expected->properties,
+		      info->properties);
+		result = false;
+	}
+
+	if (!ffa_uuid_equal(info->uuid, expected_uuid)) {
+		ERROR("Wrong UUID. Expected %x %x %x %x, "
+		      "got %x %x %x %x\n",
+		      expected_uuid.uuid[0],
+		      expected_uuid.uuid[1],
+		      expected_uuid.uuid[2],
+		      expected_uuid.uuid[3],
+		      info->uuid.uuid[0],
+		      info->uuid.uuid[1],
+		      info->uuid.uuid[2],
+		      info->uuid.uuid[3]);
+		result = false;
+	}
+
+	return result;
+}
+
+/**
+ * Sends a ffa_partition_info_get_regs request and returns the information
+ * returned in registers in the output parameters. Validation against
+ * expected results shall be done by the caller outside the function.
+ */
+bool ffa_partition_info_regs_helper(const struct ffa_uuid uuid,
+		       const struct ffa_partition_info *expected,
+		       const uint16_t expected_size)
+{
+	/*
+	 * TODO: For now, support only one invocation. Can be enhanced easily
+	 * to extend to arbitrary number of partitions.
+	 */
+	if (expected_size > 5) {
+		ERROR("%s only supports information received in"
+			" one invocation of the ABI (5 partitions)\n",
+			__func__);
+		return false;
+	}
+
+	struct ffa_value ret = ffa_partition_info_get_regs(uuid, 0, 0);
+
+	if (ffa_func_id(ret) != FFA_SUCCESS_SMC64) {
+		return false;
+	}
+
+	if (ffa_partition_info_regs_partition_count(ret) !=
+	    expected_size) {
+		ERROR("Unexpected number of partitions %d (expected %d)\n",
+		      ffa_partition_info_regs_partition_count(ret),
+		      expected_size);
+		return false;
+	}
+
+	if (ffa_partition_info_regs_entry_size(ret) !=
+	    sizeof(struct ffa_partition_info)) {
+		ERROR("Unexpected partition info descriptor size %d\n",
+		      ffa_partition_info_regs_entry_size(ret));
+		return false;
+	}
+
+	for (unsigned int i = 0U; i < expected_size; i++) {
+		struct ffa_partition_info info = { 0 };
+
+		ffa_partition_info_regs_get_part_info(&ret, i, &info);
+		if (!ffa_compare_partition_info(uuid, &info, &expected[i])) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
 /**
  * Sends a ffa_partition_info request and checks the response against the
  * target.
@@ -418,47 +561,8 @@
 			(const struct ffa_partition_info *)(mb->recv);
 
 		for (unsigned int i = 0U; i < expected_size; i++) {
-			/*
-			 * If a UUID is specified then the UUID returned in the
-			 * partition info descriptor MBZ.
-			 */
-			struct ffa_uuid expected_uuid =
-				ffa_uuid_equal(uuid, NULL_UUID) ?
-				expected[i].uuid :
-				NULL_UUID;
-
-			if (info[i].id != expected[i].id) {
-				ERROR("Wrong ID. Expected %x, got %x\n",
-				      expected[i].id,
-				      info[i].id);
+			if (!ffa_compare_partition_info(uuid, &info[i], &expected[i]))
 				result = false;
-			}
-			if (info[i].exec_context != expected[i].exec_context) {
-				ERROR("Wrong context. Expected %d, got %d\n",
-				      expected[i].exec_context,
-				      info[i].exec_context);
-				result = false;
-			}
-			if (info[i].properties != expected[i].properties) {
-				ERROR("Wrong properties. Expected %d, got %d\n",
-				      expected[i].properties,
-				      info[i].properties);
-				result = false;
-			}
-
-			if (!ffa_uuid_equal(info[i].uuid, expected_uuid)) {
-				ERROR("Wrong UUID. Expected %x %x %x %x, "
-				      "got %x %x %x %x\n",
-				      expected_uuid.uuid[0],
-				      expected_uuid.uuid[1],
-				      expected_uuid.uuid[2],
-				      expected_uuid.uuid[3],
-				      info[i].uuid.uuid[0],
-				      info[i].uuid.uuid[1],
-				      info[i].uuid.uuid[2],
-				      info[i].uuid.uuid[3]);
-				result = false;
-			}
 		}
 	}