refactor(memory share): validate memory retrieve request
Refactored function that validates a memory retrieve request,
factoring out the code validating the memory region provided
with retrieve request call.
This is to make the function 'ffa_memory_retrieve' easier
to read.
Change-Id: Ifa139cdd846aa0f982b242aea9c75badad1a836b
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/ffa_memory.c b/src/ffa_memory.c
index fd3030b..93dcce6 100644
--- a/src/ffa_memory.c
+++ b/src/ffa_memory.c
@@ -2105,6 +2105,126 @@
}
}
+/**
+ * Validate that the memory region descriptor provided by the borrower on
+ * FFA_MEM_RETRIEVE_REQ, against saved memory region provided by lender at the
+ * memory sharing call.
+ */
+static struct ffa_value ffa_memory_retrieve_validate(
+ ffa_vm_id_t receiver_id, struct ffa_memory_region *retrieve_request,
+ struct ffa_memory_region *memory_region, uint32_t *receiver_index,
+ uint32_t share_func)
+{
+ ffa_memory_region_flags_t transaction_type =
+ retrieve_request->flags &
+ FFA_MEMORY_REGION_TRANSACTION_TYPE_MASK;
+
+ assert(retrieve_request != NULL);
+ assert(memory_region != NULL);
+ assert(receiver_index != NULL);
+ assert(retrieve_request->sender == memory_region->sender);
+
+ /*
+ * Check that the transaction type expected by the receiver is
+ * correct, if it has been specified.
+ */
+ if (transaction_type !=
+ FFA_MEMORY_REGION_TRANSACTION_TYPE_UNSPECIFIED &&
+ transaction_type != (memory_region->flags &
+ FFA_MEMORY_REGION_TRANSACTION_TYPE_MASK)) {
+ dlog_verbose(
+ "Incorrect transaction type %#x for "
+ "FFA_MEM_RETRIEVE_REQ, expected %#x for handle %#x.\n",
+ transaction_type,
+ memory_region->flags &
+ FFA_MEMORY_REGION_TRANSACTION_TYPE_MASK,
+ retrieve_request->handle);
+ return ffa_error(FFA_INVALID_PARAMETERS);
+ }
+
+ if (retrieve_request->tag != memory_region->tag) {
+ dlog_verbose(
+ "Incorrect tag %d for FFA_MEM_RETRIEVE_REQ, expected "
+ "%d for handle %#x.\n",
+ retrieve_request->tag, memory_region->tag,
+ retrieve_request->handle);
+ return ffa_error(FFA_INVALID_PARAMETERS);
+ }
+
+ *receiver_index =
+ ffa_memory_region_get_receiver(memory_region, receiver_id);
+
+ if (*receiver_index == memory_region->receiver_count) {
+ dlog_verbose(
+ "Incorrect receiver VM ID %d for "
+ "FFA_MEM_RETRIEVE_REQ, for handle %#x.\n",
+ receiver_id, handle);
+ return ffa_error(FFA_INVALID_PARAMETERS);
+ }
+
+ if ((retrieve_request->flags &
+ FFA_MEMORY_REGION_ADDRESS_RANGE_HINT_VALID) != 0U) {
+ dlog_verbose(
+ "Retriever specified 'address range alignment 'hint' "
+ "not supported.\n");
+ return ffa_error(FFA_INVALID_PARAMETERS);
+ }
+ if ((retrieve_request->flags &
+ FFA_MEMORY_REGION_ADDRESS_RANGE_HINT_MASK) != 0) {
+ dlog_verbose(
+ "Bits 8-5 must be zero in memory region's flags "
+ "(address range alignment hint not supported).\n");
+ return ffa_error(FFA_INVALID_PARAMETERS);
+ }
+
+ if ((retrieve_request->flags & ~0x7FF) != 0U) {
+ dlog_verbose(
+ "Bits 31-10 must be zero in memory region's flags.\n");
+ return ffa_error(FFA_INVALID_PARAMETERS);
+ }
+
+ if (share_func == FFA_MEM_SHARE_32 &&
+ (retrieve_request->flags &
+ (FFA_MEMORY_REGION_FLAG_CLEAR |
+ FFA_MEMORY_REGION_FLAG_CLEAR_RELINQUISH)) != 0U) {
+ dlog_verbose(
+ "Memory Share operation can't clean after relinquish "
+ "memory region.\n");
+ return ffa_error(FFA_INVALID_PARAMETERS);
+ }
+
+ /*
+ * If the borrower needs the memory to be cleared before mapping
+ * to its address space, the sender should have set the flag
+ * when calling FFA_MEM_LEND/FFA_MEM_DONATE, else return
+ * FFA_DENIED.
+ */
+ if ((retrieve_request->flags & FFA_MEMORY_REGION_FLAG_CLEAR) != 0U &&
+ (memory_region->flags & FFA_MEMORY_REGION_FLAG_CLEAR) == 0U) {
+ dlog_verbose(
+ "Borrower needs memory cleared. Sender needs to set "
+ "flag for clearing memory.\n");
+ return ffa_error(FFA_DENIED);
+ }
+
+ /*
+ * If memory type is not specified, bypass validation of memory
+ * attributes in the retrieve request. The retriever is expecting to
+ * obtain this information from the SPMC.
+ */
+ if (ffa_get_memory_type_attr(retrieve_request->attributes) ==
+ FFA_MEMORY_NOT_SPECIFIED_MEM) {
+ return (struct ffa_value){.func = FFA_SUCCESS_32};
+ }
+
+ /*
+ * Ensure receiver's attributes are compatible with how
+ * Hafnium maps memory: Normal Memory, Inner shareable,
+ * Write-Back Read-Allocate Write-Allocate Cacheable.
+ */
+ return ffa_memory_attributes_validate(retrieve_request->attributes);
+}
+
struct ffa_value ffa_memory_retrieve(struct vm_locked to_locked,
struct ffa_memory_region *retrieve_request,
uint32_t retrieve_request_length,
@@ -2115,9 +2235,6 @@
retrieve_request->receiver_count *
sizeof(struct ffa_memory_access);
ffa_memory_handle_t handle = retrieve_request->handle;
- ffa_memory_region_flags_t transaction_type =
- retrieve_request->flags &
- FFA_MEMORY_REGION_TRANSACTION_TYPE_MASK;
struct ffa_memory_region *memory_region;
ffa_memory_access_permissions_t permissions = 0;
uint32_t memory_to_attributes;
@@ -2127,7 +2244,7 @@
struct ffa_composite_memory_region *composite;
uint32_t total_length;
uint32_t fragment_length;
- ffa_vm_id_t receiver_id;
+ ffa_vm_id_t receiver_id = to_locked.vm->id;
bool is_send_complete = false;
dump_share_states();
@@ -2159,27 +2276,26 @@
}
memory_region = share_state->memory_region;
+
CHECK(memory_region != NULL);
- receiver_id = to_locked.vm->id;
+ if (retrieve_request->sender != memory_region->sender) {
+ dlog_verbose(
+ "Memory with handle %#x not fully sent, can't "
+ "retrieve.\n",
+ handle);
+ ret = ffa_error(FFA_INVALID_PARAMETERS);
+ goto out;
+ }
if (!is_ffa_memory_retrieve_borrower_request(retrieve_request,
to_locked)) {
uint32_t receiver_index;
- /*
- * Find receiver index in the receivers list specified by the
- * sender.
- */
- receiver_index = ffa_memory_region_get_receiver(
- memory_region, to_locked.vm->id);
- if (receiver_index == memory_region->receiver_count) {
- dlog_verbose(
- "Incorrect receiver VM ID %x for "
- "FFA_MEM_RETRIEVE_REQ, "
- "for handle %#x.\n",
- to_locked.vm->id, handle);
- ret = ffa_error(FFA_INVALID_PARAMETERS);
+ ret = ffa_memory_retrieve_validate(
+ receiver_id, retrieve_request, memory_region,
+ &receiver_index, share_state->share_func);
+ if (ret.func != FFA_SUCCESS_32) {
goto out;
}
@@ -2192,106 +2308,6 @@
goto out;
}
- /*
- * Check that the transaction type expected by the receiver is
- * correct, if it has been specified.
- */
- if (transaction_type !=
- FFA_MEMORY_REGION_TRANSACTION_TYPE_UNSPECIFIED &&
- transaction_type !=
- (memory_region->flags &
- FFA_MEMORY_REGION_TRANSACTION_TYPE_MASK)) {
- dlog_verbose(
- "Incorrect transaction type %#x for "
- "FFA_MEM_RETRIEVE_REQ, expected %#x for handle "
- "%#x.\n",
- transaction_type,
- memory_region->flags &
- FFA_MEMORY_REGION_TRANSACTION_TYPE_MASK,
- handle);
- ret = ffa_error(FFA_INVALID_PARAMETERS);
- goto out;
- }
-
- if (retrieve_request->sender != memory_region->sender) {
- dlog_verbose(
- "Incorrect sender ID %d for "
- "FFA_MEM_RETRIEVE_REQ, "
- "expected %d for handle %#x.\n",
- retrieve_request->sender, memory_region->sender,
- handle);
- ret = ffa_error(FFA_DENIED);
- goto out;
- }
-
- if (retrieve_request->tag != memory_region->tag) {
- dlog_verbose(
- "Incorrect tag %d for FFA_MEM_RETRIEVE_REQ, "
- "expected "
- "%d for handle %#x.\n",
- retrieve_request->tag, memory_region->tag,
- handle);
- ret = ffa_error(FFA_INVALID_PARAMETERS);
- goto out;
- }
-
- if ((retrieve_request->flags &
- FFA_MEMORY_REGION_ADDRESS_RANGE_HINT_VALID) != 0U) {
- dlog_verbose(
- "Retriever specified 'address range alignment "
- "hint' not supported.\n");
- ret = ffa_error(FFA_INVALID_PARAMETERS);
- goto out;
- }
-
- if ((retrieve_request->flags &
- FFA_MEMORY_REGION_ADDRESS_RANGE_HINT_MASK) != 0) {
- dlog_verbose(
- "Bits 8-5 must be zero in memory region's "
- "flags (address range alignment hint not "
- "supported).\n");
- ret = ffa_error(FFA_INVALID_PARAMETERS);
- goto out;
- }
-
- if ((retrieve_request->flags & ~0x7FF) != 0U) {
- dlog_verbose(
- "Bits 31-10 must be zero in memory region's "
- "flags.\n");
- ret = ffa_error(FFA_INVALID_PARAMETERS);
- goto out;
- }
-
- if (share_state->share_func == FFA_MEM_SHARE_32 &&
- (retrieve_request->flags &
- (FFA_MEMORY_REGION_FLAG_CLEAR |
- FFA_MEMORY_REGION_FLAG_CLEAR_RELINQUISH)) != 0U) {
- dlog_verbose(
- "Memory Share operation can't clean after "
- "relinquish "
- "memory region.\n");
- ret = ffa_error(FFA_INVALID_PARAMETERS);
- goto out;
- }
-
- /*
- * If the borrower needs the memory to be cleared before mapping
- * to its address space, the sender should have set the flag
- * when calling FFA_MEM_LEND/FFA_MEM_DONATE, else return
- * FFA_DENIED.
- */
- if ((retrieve_request->flags & FFA_MEMORY_REGION_FLAG_CLEAR) !=
- 0U &&
- (memory_region->flags & FFA_MEMORY_REGION_FLAG_CLEAR) ==
- 0U) {
- dlog_verbose(
- "Borrower needs memory cleared. Sender needs "
- "to set "
- "flag for clearing memory.\n");
- ret = ffa_error(FFA_DENIED);
- goto out;
- }
-
ret = ffa_memory_retrieve_validate_memory_access_list(
memory_region, retrieve_request, receiver_id,
&permissions);
@@ -2299,20 +2315,6 @@
goto out;
}
- if (ffa_get_memory_type_attr(retrieve_request->attributes) !=
- FFA_MEMORY_NOT_SPECIFIED_MEM) {
- /*
- * Ensure receiver's attributes are compatible with how
- * Hafnium maps memory: Normal Memory, Inner shareable,
- * Write-Back Read-Allocate Write-Allocate Cacheable.
- */
- ret = ffa_memory_attributes_validate(
- retrieve_request->attributes);
- if (ret.func != FFA_SUCCESS_32) {
- goto out;
- }
- }
-
memory_to_attributes = ffa_memory_permissions_to_mode(
permissions, share_state->sender_orig_mode);
ret = ffa_retrieve_check_update(