fix(memory share): add precedence check for memory type

Since normal memory is more permissive than device, check in
memory sharing operations that device memory isn't being
shared as normal memory. If so return FFA_DENIED.

Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: I8eeb998ec161501835ce0fbea63b0db67b859f05
diff --git a/src/ffa_memory.c b/src/ffa_memory.c
index cda841a..ed36e73 100644
--- a/src/ffa_memory.c
+++ b/src/ffa_memory.c
@@ -361,7 +361,6 @@
 	sl_unlock(&share_states_lock_instance);
 }
 
-/* TODO: Add device attributes: GRE, cacheability, shareability. */
 static inline uint32_t ffa_memory_permissions_to_mode(
 	ffa_memory_access_permissions_t permissions, uint32_t default_mode)
 {
@@ -399,6 +398,8 @@
 		mode |= plat_ffa_other_world_mode();
 	}
 
+	mode |= default_mode & MM_MODE_D;
+
 	return mode;
 }
 
@@ -737,6 +738,19 @@
 		return ret;
 	}
 
+	/*
+	 * Check requested memory type is valid with the memory type of the
+	 * owner. E.g. they follow the memory type precedence where Normal
+	 * memory is more permissive than device and therefore device memory
+	 * can only be shared as device memory.
+	 */
+	if (memory_region->attributes.type == FFA_MEMORY_NORMAL_MEM &&
+	    (*orig_from_mode & MM_MODE_D) != 0U) {
+		dlog_verbose(
+			"Send device memory as Normal memory is not allowed\n");
+		return ffa_error(FFA_DENIED);
+	}
+
 	/* Device memory regions can only be lent a single borrower. */
 	if ((*orig_from_mode & MM_MODE_D) != 0U &&
 	    !(is_memory_lend && receivers_count == 1)) {
@@ -865,13 +879,6 @@
 		return ret;
 	}
 
-	/* Ensure the address range is normal memory and not a device. */
-	if (*orig_from_mode & MM_MODE_D) {
-		dlog_verbose("Can't relinquish device memory (mode is %#x).\n",
-			     *orig_from_mode);
-		return ffa_error(FFA_DENIED);
-	}
-
 	/*
 	 * Ensure the relinquishing VM is not the owner but has access to the
 	 * memory.
@@ -3319,6 +3326,21 @@
 	memory_to_mode = ffa_memory_permissions_to_mode(
 		permissions, share_state->sender_orig_mode);
 
+	/*
+	 * Check requested memory type is valid with the memory type of the
+	 * owner. E.g. they follow the memory type precedence where Normal
+	 * memory is more permissive than device and therefore device memory
+	 * can only be shared as device memory.
+	 */
+	if (retrieve_request->attributes.type == FFA_MEMORY_NORMAL_MEM &&
+	    ((share_state->sender_orig_mode & MM_MODE_D) != 0U ||
+	     memory_region->attributes.type == FFA_MEMORY_DEVICE_MEM)) {
+		dlog_verbose(
+			"Retrieving device memory as Normal memory is not "
+			"allowed\n");
+		return ffa_error(FFA_DENIED);
+	}
+
 	ret = ffa_retrieve_check_update(
 		to_locked, share_state->fragments,
 		share_state->fragment_constituent_counts,