feat(memory share): add impdef field to ffa_memory_access

FF-A v1.2 introduces an impdef field to the endpoint memory
access descriptor and ensures an impdef value set for a receiver
in a memory send operation matches the value sent in the
retrieve request.

Also add new fields to the dump_memory_region logs.

Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: I4e424fba54e1435a898d6fa3e7837bad87a55802
diff --git a/src/ffa_memory.c b/src/ffa_memory.c
index 546d188..eb06b25 100644
--- a/src/ffa_memory.c
+++ b/src/ffa_memory.c
@@ -272,11 +272,12 @@
 		return;
 	}
 
-	dlog("from VM %#x, attributes %#x, flags %#x, tag %u, to "
-	     "%u "
+	dlog("from VM %#x, attributes %#x, flags %#x, handle %#x "
+	     "tag %u, memory access descriptor size %u, to %u "
 	     "recipients [",
 	     memory_region->sender, memory_region->attributes,
-	     memory_region->flags, memory_region->tag,
+	     memory_region->flags, memory_region->handle, memory_region->tag,
+	     memory_region->memory_access_desc_size,
 	     memory_region->receiver_count);
 	for (i = 0; i < memory_region->receiver_count; ++i) {
 		struct ffa_memory_access *receiver =
@@ -288,7 +289,15 @@
 		     receiver->receiver_permissions.receiver,
 		     receiver->receiver_permissions.permissions,
 		     receiver->composite_memory_region_offset);
+		/* The impdef field is only present from v1.2 and later */
+		if (ffa_version_from_memory_access_desc_size(
+			    memory_region->memory_access_desc_size) >=
+		    MAKE_FFA_VERSION(1, 2)) {
+			dlog(", impdef: %#x %#x", receiver->impdef.val[0],
+			     receiver->impdef.val[1]);
+		}
 	}
+	dlog("] at offset %u", memory_region->receivers_offset);
 }
 
 void dump_share_states(void)
@@ -454,8 +463,10 @@
 	 * v1.1 is the first version to include the memory access descriptor
 	 * size field so return v1.1.
 	 */
-	case sizeof(struct ffa_memory_access):
+	case sizeof(struct ffa_memory_access_v1_0):
 		return MAKE_FFA_VERSION(1, 1);
+	case sizeof(struct ffa_memory_access):
+		return MAKE_FFA_VERSION(1, 2);
 	}
 	return 0;
 }
@@ -484,6 +495,7 @@
 	 */
 	switch (expected_ffa_version) {
 	case MAKE_FFA_VERSION(1, 1):
+	case MAKE_FFA_VERSION(1, 2):
 		return receivers_offset == sizeof(struct ffa_memory_region);
 	default:
 		return false;
@@ -2122,8 +2134,9 @@
 	ffa_id_t sender, ffa_memory_attributes_t attributes,
 	ffa_memory_region_flags_t flags, ffa_memory_handle_t handle,
 	ffa_id_t receiver_id, uint32_t memory_access_desc_size,
-	ffa_memory_access_permissions_t permissions, uint32_t page_count,
-	uint32_t total_constituent_count,
+	ffa_memory_access_permissions_t permissions,
+	struct ffa_memory_access_impdef receiver_impdef_val,
+	uint32_t page_count, uint32_t total_constituent_count,
 	const struct ffa_memory_region_constituent constituents[],
 	uint32_t fragment_constituent_count, uint32_t *total_length,
 	uint32_t *fragment_length)
@@ -2203,6 +2216,11 @@
 		receiver->composite_memory_region_offset = composite_offset;
 		composite_memory_region =
 			ffa_memory_region_get_composite(retrieve_response, 0);
+		if (ffa_version_from_memory_access_desc_size(
+			    memory_access_desc_size) >=
+		    MAKE_FFA_VERSION(1, 2)) {
+			receiver->impdef = receiver_impdef_val;
+		}
 	}
 
 	assert(composite_memory_region != NULL);
@@ -2416,7 +2434,8 @@
 static struct ffa_value ffa_memory_retrieve_validate_memory_access_list(
 	struct ffa_memory_region *memory_region,
 	struct ffa_memory_region *retrieve_request, ffa_id_t to_vm_id,
-	ffa_memory_access_permissions_t *permissions, uint32_t func_id)
+	ffa_memory_access_permissions_t *permissions, uint32_t func_id,
+	struct ffa_memory_access_impdef *to_impdef_val)
 {
 	uint32_t retrieve_receiver_index;
 	bool bypass_multi_receiver_check =
@@ -2535,6 +2554,39 @@
 				"clear.\n");
 			return ffa_error(FFA_DENIED);
 		}
+
+		/*
+		 * Check the impdef in the retrieve_request matches the value in
+		 * the original memory send.
+		 */
+		if (ffa_version_from_memory_access_desc_size(
+			    memory_region->memory_access_desc_size) >=
+			    MAKE_FFA_VERSION(1, 2) &&
+		    ffa_version_from_memory_access_desc_size(
+			    retrieve_request->memory_access_desc_size) >=
+			    MAKE_FFA_VERSION(1, 2)) {
+			if (found_to_id) {
+				*to_impdef_val =
+					retrieve_request_receiver->impdef;
+			}
+			if (receiver->impdef.val[0] !=
+				    retrieve_request_receiver->impdef.val[0] ||
+			    receiver->impdef.val[1] !=
+				    retrieve_request_receiver->impdef.val[1]) {
+				dlog_verbose(
+					"Impdef value in memory send does not "
+					"match retrieve request value "
+					"send value %#x %#x retrieve request "
+					"value %#x %#x\n",
+					receiver->impdef.val[0],
+					receiver->impdef.val[1],
+					retrieve_request_receiver->impdef
+						.val[0],
+					retrieve_request_receiver->impdef
+						.val[1]);
+				return ffa_error(FFA_INVALID_PARAMETERS);
+			}
+		}
 	}
 
 	if (retrieve_receiver_index == retrieve_request->receiver_count) {
@@ -2731,6 +2783,9 @@
 	ffa_id_t receiver_id = to_locked.vm->id;
 	bool is_send_complete = false;
 	ffa_memory_attributes_t attributes;
+	struct ffa_memory_access_impdef receiver_impdef_val;
+	uint64_t retrieve_memory_access_desc_size =
+		retrieve_request->memory_access_desc_size;
 
 	dump_share_states();
 
@@ -2844,7 +2899,8 @@
 		 */
 		ret = ffa_memory_retrieve_validate_memory_access_list(
 			memory_region, retrieve_request, receiver_id,
-			&permissions, share_state->share_func);
+			&permissions, share_state->share_func,
+			&receiver_impdef_val);
 		if (ret.func != FFA_SUCCESS_32) {
 			goto out;
 		}
@@ -2914,9 +2970,9 @@
 		to_locked.vm->mailbox.recv, to_locked.vm->ffa_version,
 		HF_MAILBOX_SIZE, memory_region->sender, attributes,
 		memory_region->flags, handle, receiver_id,
-		memory_region->memory_access_desc_size, permissions,
-		composite->page_count, composite->constituent_count,
-		share_state->fragments[0],
+		retrieve_memory_access_desc_size, permissions,
+		receiver_impdef_val, composite->page_count,
+		composite->constituent_count, share_state->fragments[0],
 		share_state->fragment_constituent_counts[0], &total_length,
 		&fragment_length));