aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Bonnici <marc.bonnici@arm.com>2022-01-13 11:39:10 +0000
committerMarc Bonnici <marc.bonnici@arm.com>2022-05-19 15:02:26 +0100
commitf0244e5dd1b8cbab75ef00c1b9b56eed5b3cad4b (patch)
treef28a5b3192a2b7ae4910e85553b795824bcacc48
parent2e21921502b1317031cf2a2f69c5d47ac88a505d (diff)
downloadtrusted-firmware-a-f0244e5dd1b8cbab75ef00c1b9b56eed5b3cad4b.tar.gz
feat(spmc/mem): support multiple endpoints in memory transactions
Enable FFA_MEM_LEND and FFA_MEM_SHARE transactions to support multiple borrowers and add the appropriate validation. Since we currently only support a single S-EL1 partition, this functionality is to support the use case where a VM shares or lends memory to one or more VMs in the normal world as part of the same transaction to the SP. Signed-off-by: Marc Bonnici <marc.bonnici@arm.com> Change-Id: Ia12c4357e9d015cb5f9b38e518b7a25b1ea2e30e
-rw-r--r--include/services/el3_spmc_ffa_memory.h3
-rw-r--r--services/std_svc/spm/el3_spmc/spmc.h6
-rw-r--r--services/std_svc/spm/el3_spmc/spmc_shared_mem.c139
3 files changed, 121 insertions, 27 deletions
diff --git a/include/services/el3_spmc_ffa_memory.h b/include/services/el3_spmc_ffa_memory.h
index d4738a1bd8..6c867329b7 100644
--- a/include/services/el3_spmc_ffa_memory.h
+++ b/include/services/el3_spmc_ffa_memory.h
@@ -196,8 +196,7 @@ CASSERT(sizeof(struct ffa_emad_v1_0) == 16, assert_ffa_emad_v1_0_size_mismatch);
* @reserved_24_27:
* Reserved bytes 24-27. Must be 0.
* @emad_count:
- * Number of entries in @emad. Must be 1 in current implementation.
- * FFA spec allows more entries.
+ * Number of entries in @emad.
* @emad:
* Endpoint memory access descriptor array (see @struct ffa_emad_v1_0).
*/
diff --git a/services/std_svc/spm/el3_spmc/spmc.h b/services/std_svc/spm/el3_spmc/spmc.h
index 22a745e963..18b71bba04 100644
--- a/services/std_svc/spm/el3_spmc/spmc.h
+++ b/services/std_svc/spm/el3_spmc/spmc.h
@@ -273,4 +273,10 @@ struct el3_lp_desc *get_el3_lp_array(void);
*/
struct mailbox *spmc_get_mbox_desc(bool secure_origin);
+/*
+ * Helper function to obtain the context of an SP with a given partition ID.
+ */
+struct secure_partition_desc *spmc_get_sp_ctx(uint16_t id);
+
+
#endif /* SPMC_H */
diff --git a/services/std_svc/spm/el3_spmc/spmc_shared_mem.c b/services/std_svc/spm/el3_spmc/spmc_shared_mem.c
index b9ca2fe552..227d7cf52e 100644
--- a/services/std_svc/spm/el3_spmc/spmc_shared_mem.c
+++ b/services/std_svc/spm/el3_spmc/spmc_shared_mem.c
@@ -166,18 +166,27 @@ spmc_shmem_obj_ffa_constituent_size(struct spmc_shmem_obj *obj)
* spmc_shmem_check_obj - Check that counts in descriptor match overall size.
* @obj: Object containing ffa_memory_region_descriptor.
*
- * Return: 0 if object is valid, -EINVAL if memory region attributes count is
- * not 1, -EINVAL if constituent_memory_region_descriptor offset or count is
- * invalid.
+ * Return: 0 if object is valid, -EINVAL if constituent_memory_region_descriptor
+ * offset or count is invalid.
*/
static int spmc_shmem_check_obj(struct spmc_shmem_obj *obj)
{
- if (obj->desc.emad_count != 1) {
- WARN("%s: unsupported attribute desc count %u != 1\n",
+ if (obj->desc.emad_count == 0U) {
+ WARN("%s: unsupported attribute desc count %u.\n",
__func__, obj->desc.emad_count);
return -EINVAL;
}
+ /*
+ * Ensure the emad array lies within the bounds of the descriptor by
+ * checking the address of the element past the end of the array.
+ */
+ if ((uintptr_t) &obj->desc.emad[obj->desc.emad_count] >
+ (uintptr_t)((uint8_t *) &obj->desc + obj->desc_size)) {
+ WARN("Invalid emad access.\n");
+ return -EINVAL;
+ }
+
for (size_t emad_num = 0; emad_num < obj->desc.emad_count; emad_num++) {
size_t size;
size_t count;
@@ -330,6 +339,38 @@ static long spmc_ffa_fill_desc(struct mailbox *mbox,
(uint32_t)obj->desc.sender_id << 16, 0, 0, 0);
}
+ /* The full descriptor has been received, perform any final checks. */
+
+ /*
+ * If a partition ID resides in the secure world validate that the
+ * partition ID is for a known partition. Ignore any partition ID
+ * belonging to the normal world as it is assumed the Hypervisor will
+ * have validated these.
+ */
+ for (size_t i = 0; i < obj->desc.emad_count; i++) {
+ ffa_endpoint_id16_t ep_id = obj->desc.emad[i].mapd.endpoint_id;
+
+ if (ffa_is_secure_world_id(ep_id)) {
+ if (spmc_get_sp_ctx(ep_id) == NULL) {
+ WARN("%s: Invalid receiver id 0x%x\n",
+ __func__, ep_id);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_bad_desc;
+ }
+ }
+ }
+
+ /* Ensure partition IDs are not duplicated. */
+ for (size_t i = 0; i < obj->desc.emad_count; i++) {
+ for (size_t j = i + 1; j < obj->desc.emad_count; j++) {
+ if (obj->desc.emad[i].mapd.endpoint_id ==
+ obj->desc.emad[j].mapd.endpoint_id) {
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_bad_desc;
+ }
+ }
+ }
+
SMC_RET8(smc_handle, FFA_SUCCESS_SMC32, 0, handle_low, handle_high, 0,
0, 0, 0);
@@ -565,15 +606,10 @@ spmc_ffa_mem_retrieve_req(uint32_t smc_fid,
goto err_unlock_mailbox;
}
- /*
- * Ensure endpoint count is 1, additional receivers not currently
- * supported.
- */
- if (req->emad_count != 1U) {
- WARN("%s: unsupported retrieve descriptor count: %u\n",
- __func__, req->emad_count);
- ret = FFA_ERROR_INVALID_PARAMETER;
- goto err_unlock_mailbox;
+ if (req->emad_count == 0U) {
+ WARN("%s: unsupported attribute desc count %u.\n",
+ __func__, obj->desc.emad_count);
+ return -EINVAL;
}
if (total_length < sizeof(*req)) {
@@ -612,6 +648,13 @@ spmc_ffa_mem_retrieve_req(uint32_t smc_fid,
goto err_unlock_all;
}
+ if (req->emad_count != 0U && req->emad_count != obj->desc.emad_count) {
+ WARN("%s: mistmatch of endpoint counts %u != %u\n",
+ __func__, req->emad_count, obj->desc.emad_count);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
+
if (req->flags != 0U) {
if ((req->flags & FFA_MTD_FLAG_TYPE_MASK) !=
(obj->desc.flags & FFA_MTD_FLAG_TYPE_MASK)) {
@@ -637,15 +680,39 @@ spmc_ffa_mem_retrieve_req(uint32_t smc_fid,
}
}
- /* TODO: support more than one endpoint ids. */
- if (req->emad_count != 0U &&
- req->emad[0].mapd.endpoint_id !=
- obj->desc.emad[0].mapd.endpoint_id) {
- WARN("%s: wrong receiver id 0x%x != 0x%x\n",
- __func__, req->emad[0].mapd.endpoint_id,
- obj->desc.emad[0].mapd.endpoint_id);
- ret = FFA_ERROR_INVALID_PARAMETER;
- goto err_unlock_all;
+ /*
+ * Ensure the emad array lies within the bounds of the descriptor by
+ * checking the address of the element past the end of the array.
+ */
+ if ((uintptr_t) &req->emad[req->emad_count] >
+ (uintptr_t)((uint8_t *) &req + total_length)) {
+ WARN("Invalid emad access.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Validate all the endpoints match in the case of multiple
+ * borrowers. We don't mandate that the order of the borrowers
+ * must match in the descriptors therefore check to see if the
+ * endpoints match in any order.
+ */
+ for (size_t i = 0; i < req->emad_count; i++) {
+ bool found = false;
+
+ for (size_t j = 0; j < obj->desc.emad_count; j++) {
+ if (req->emad[i].mapd.endpoint_id ==
+ obj->desc.emad[j].mapd.endpoint_id) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ WARN("%s: invalid receiver id (0x%x).\n",
+ __func__, req->emad[i].mapd.endpoint_id);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_all;
+ }
}
mbox->state = MAILBOX_STATE_FULL;
@@ -822,6 +889,12 @@ int spmc_ffa_mem_relinquish(uint32_t smc_fid,
goto err_unlock_mailbox;
}
+ if (req->endpoint_count == 0) {
+ WARN("%s: endpoint count cannot be 0.\n", __func__);
+ ret = FFA_ERROR_INVALID_PARAMETER;
+ goto err_unlock_mailbox;
+ }
+
spin_lock(&spmc_shmem_obj_state.lock);
obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, req->handle);
@@ -831,16 +904,32 @@ int spmc_ffa_mem_relinquish(uint32_t smc_fid,
}
if (obj->desc.emad_count != req->endpoint_count) {
+ WARN("%s: mismatch of endpoint count %u != %u\n", __func__,
+ obj->desc.emad_count, req->endpoint_count);
ret = FFA_ERROR_INVALID_PARAMETER;
goto err_unlock_all;
}
+
+ /* Validate requested endpoint IDs match descriptor. */
for (size_t i = 0; i < req->endpoint_count; i++) {
- if (req->endpoint_array[i] !=
- obj->desc.emad[i].mapd.endpoint_id) {
+ bool found = false;
+
+ for (unsigned int j = 0; j < obj->desc.emad_count; j++) {
+ if (req->endpoint_array[i] ==
+ obj->desc.emad[j].mapd.endpoint_id) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ WARN("%s: Invalid endpoint ID (0x%x).\n",
+ __func__, req->endpoint_array[i]);
ret = FFA_ERROR_INVALID_PARAMETER;
goto err_unlock_all;
}
}
+
if (obj->in_use == 0U) {
ret = FFA_ERROR_INVALID_PARAMETER;
goto err_unlock_all;