feat(memory share): allow device memory lend SP to SP

This patch allows the simple case of lending device memory
between two SPs.

Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: I904fb81745f786a50b37ebff1a65266ebc76ccd4
diff --git a/src/ffa_memory.c b/src/ffa_memory.c
index c3d3884..5169c57 100644
--- a/src/ffa_memory.c
+++ b/src/ffa_memory.c
@@ -719,10 +719,17 @@
 		return ret;
 	}
 
-	/* Ensure the address range is normal memory and not a device. */
-	if ((*orig_from_mode & MM_MODE_D) != 0U) {
-		dlog_verbose("Can't share device memory (mode is %#x).\n",
-			     *orig_from_mode);
+	/*
+	 * Device memory regions can only be lent from SP to SP and to a single
+	 * borrower.
+	 */
+	if ((*orig_from_mode & MM_MODE_D) != 0U &&
+	    !(share_func == FFA_MEM_LEND_32 && !ffa_is_vm_id(from.vm->id) &&
+	      receivers_count == 1)) {
+		dlog_verbose(
+			"Device memory can only be lent, from the secure world "
+			"and to a single borrower (mode is %#x).\n",
+			*orig_from_mode);
 		return ffa_error(FFA_DENIED);
 	}
 
@@ -1768,9 +1775,13 @@
 }
 
 /**
- * Check that the memory attributes match Hafnium expectations:
- * Normal Memory, Inner shareable, Write-Back Read-Allocate
- * Write-Allocate Cacheable.
+ * Check that the memory attributes match Hafnium expectations.
+ * Cacheability:
+ * - Normal Memory as `FFA_MEMORY_CACHE_WRITE_BACK`.
+ * - Device memory as `FFA_MEMORY_DEV_NGNRNE`.
+ *
+ * Shareability:
+ * - Inner Shareable.
  */
 static struct ffa_value ffa_memory_attributes_validate(
 	ffa_memory_attributes_t attributes)
@@ -1780,19 +1791,25 @@
 	enum ffa_memory_shareability shareability;
 
 	memory_type = attributes.type;
-	if (memory_type != FFA_MEMORY_NORMAL_MEM) {
-		dlog_verbose("Invalid memory type %s, expected %s\n",
-			     ffa_memory_type_name(memory_type),
-			     ffa_memory_type_name(FFA_MEMORY_NORMAL_MEM));
+	cacheability = attributes.cacheability;
+	if (memory_type == FFA_MEMORY_NORMAL_MEM &&
+	    cacheability != FFA_MEMORY_CACHE_WRITE_BACK) {
+		dlog_verbose(
+			"Normal Memory: Invalid cacheability %s, "
+			"expected %s.\n",
+			ffa_memory_cacheability_name(cacheability),
+			ffa_memory_cacheability_name(
+				FFA_MEMORY_CACHE_WRITE_BACK));
 		return ffa_error(FFA_DENIED);
 	}
-
-	cacheability = attributes.cacheability;
-	if (cacheability != FFA_MEMORY_CACHE_WRITE_BACK) {
-		dlog_verbose("Invalid cacheability %s, expected %s.\n",
-			     ffa_memory_cacheability_name(cacheability),
-			     ffa_memory_cacheability_name(
-				     FFA_MEMORY_CACHE_WRITE_BACK));
+	if (memory_type == FFA_MEMORY_DEVICE_MEM &&
+	    cacheability != FFA_MEMORY_DEV_NGNRNE) {
+		dlog_verbose(
+			"Device Memory: Invalid cacheability %s, "
+			"expected %s.\n",
+			ffa_device_memory_cacheability_name(cacheability),
+			ffa_device_memory_cacheability_name(
+				FFA_MEMORY_DEV_NGNRNE));
 		return ffa_error(FFA_DENIED);
 	}