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
This commit is contained in:
parent
2e21921502
commit
f0244e5dd1
|
@ -196,8 +196,7 @@ CASSERT(sizeof(struct ffa_emad_v1_0) == 16, assert_ffa_emad_v1_0_size_mismatch);
|
||||||
* @reserved_24_27:
|
* @reserved_24_27:
|
||||||
* Reserved bytes 24-27. Must be 0.
|
* Reserved bytes 24-27. Must be 0.
|
||||||
* @emad_count:
|
* @emad_count:
|
||||||
* Number of entries in @emad. Must be 1 in current implementation.
|
* Number of entries in @emad.
|
||||||
* FFA spec allows more entries.
|
|
||||||
* @emad:
|
* @emad:
|
||||||
* Endpoint memory access descriptor array (see @struct ffa_emad_v1_0).
|
* Endpoint memory access descriptor array (see @struct ffa_emad_v1_0).
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -273,4 +273,10 @@ struct el3_lp_desc *get_el3_lp_array(void);
|
||||||
*/
|
*/
|
||||||
struct mailbox *spmc_get_mbox_desc(bool secure_origin);
|
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 */
|
#endif /* SPMC_H */
|
||||||
|
|
|
@ -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.
|
* spmc_shmem_check_obj - Check that counts in descriptor match overall size.
|
||||||
* @obj: Object containing ffa_memory_region_descriptor.
|
* @obj: Object containing ffa_memory_region_descriptor.
|
||||||
*
|
*
|
||||||
* Return: 0 if object is valid, -EINVAL if memory region attributes count is
|
* Return: 0 if object is valid, -EINVAL if constituent_memory_region_descriptor
|
||||||
* not 1, -EINVAL if constituent_memory_region_descriptor offset or count is
|
* offset or count is invalid.
|
||||||
* invalid.
|
|
||||||
*/
|
*/
|
||||||
static int spmc_shmem_check_obj(struct spmc_shmem_obj *obj)
|
static int spmc_shmem_check_obj(struct spmc_shmem_obj *obj)
|
||||||
{
|
{
|
||||||
if (obj->desc.emad_count != 1) {
|
if (obj->desc.emad_count == 0U) {
|
||||||
WARN("%s: unsupported attribute desc count %u != 1\n",
|
WARN("%s: unsupported attribute desc count %u.\n",
|
||||||
__func__, obj->desc.emad_count);
|
__func__, obj->desc.emad_count);
|
||||||
return -EINVAL;
|
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++) {
|
for (size_t emad_num = 0; emad_num < obj->desc.emad_count; emad_num++) {
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t count;
|
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);
|
(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,
|
SMC_RET8(smc_handle, FFA_SUCCESS_SMC32, 0, handle_low, handle_high, 0,
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
|
|
||||||
|
@ -565,15 +606,10 @@ spmc_ffa_mem_retrieve_req(uint32_t smc_fid,
|
||||||
goto err_unlock_mailbox;
|
goto err_unlock_mailbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (req->emad_count == 0U) {
|
||||||
* Ensure endpoint count is 1, additional receivers not currently
|
WARN("%s: unsupported attribute desc count %u.\n",
|
||||||
* supported.
|
__func__, obj->desc.emad_count);
|
||||||
*/
|
return -EINVAL;
|
||||||
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 (total_length < sizeof(*req)) {
|
if (total_length < sizeof(*req)) {
|
||||||
|
@ -612,6 +648,13 @@ spmc_ffa_mem_retrieve_req(uint32_t smc_fid,
|
||||||
goto err_unlock_all;
|
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 != 0U) {
|
||||||
if ((req->flags & FFA_MTD_FLAG_TYPE_MASK) !=
|
if ((req->flags & FFA_MTD_FLAG_TYPE_MASK) !=
|
||||||
(obj->desc.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 &&
|
* Ensure the emad array lies within the bounds of the descriptor by
|
||||||
req->emad[0].mapd.endpoint_id !=
|
* checking the address of the element past the end of the array.
|
||||||
obj->desc.emad[0].mapd.endpoint_id) {
|
*/
|
||||||
WARN("%s: wrong receiver id 0x%x != 0x%x\n",
|
if ((uintptr_t) &req->emad[req->emad_count] >
|
||||||
__func__, req->emad[0].mapd.endpoint_id,
|
(uintptr_t)((uint8_t *) &req + total_length)) {
|
||||||
obj->desc.emad[0].mapd.endpoint_id);
|
WARN("Invalid emad access.\n");
|
||||||
ret = FFA_ERROR_INVALID_PARAMETER;
|
return -EINVAL;
|
||||||
goto err_unlock_all;
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
mbox->state = MAILBOX_STATE_FULL;
|
||||||
|
@ -822,6 +889,12 @@ int spmc_ffa_mem_relinquish(uint32_t smc_fid,
|
||||||
goto err_unlock_mailbox;
|
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);
|
spin_lock(&spmc_shmem_obj_state.lock);
|
||||||
|
|
||||||
obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, req->handle);
|
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) {
|
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;
|
ret = FFA_ERROR_INVALID_PARAMETER;
|
||||||
goto err_unlock_all;
|
goto err_unlock_all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Validate requested endpoint IDs match descriptor. */
|
||||||
for (size_t i = 0; i < req->endpoint_count; i++) {
|
for (size_t i = 0; i < req->endpoint_count; i++) {
|
||||||
if (req->endpoint_array[i] !=
|
bool found = false;
|
||||||
obj->desc.emad[i].mapd.endpoint_id) {
|
|
||||||
|
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;
|
ret = FFA_ERROR_INVALID_PARAMETER;
|
||||||
goto err_unlock_all;
|
goto err_unlock_all;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->in_use == 0U) {
|
if (obj->in_use == 0U) {
|
||||||
ret = FFA_ERROR_INVALID_PARAMETER;
|
ret = FFA_ERROR_INVALID_PARAMETER;
|
||||||
goto err_unlock_all;
|
goto err_unlock_all;
|
||||||
|
|
Loading…
Reference in New Issue