test: add discovery of el3 spmd logical partitions
This patch adds a test to query the presence of an SPMD logical
partition and also tests basic functionality using the
ffa_partition_info_get_regs abi. Note that the register based discovery
reports the presence of el3 spmd logical partitions whereas the memory
based discovery interface does not report the el3 spmd logical
partitions. To that end, the patch adds helper functions to use the
register based discovery, and also refactors code that can be shared
between the register and memory based interfaces.
Signed-off-by: Raghu Krishnamurthy <raghu.ncstate@gmail.com>
Change-Id: I755ffe4098c635de2c6aeb0ebe73eb16c3acd206
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/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/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;
- }
}
}