fix(memory share): Flags from mem region MBZ

According to the FF-A specification, the flags field from the memory
transaction descriptor is used to govern the behavior in a memory
management transaction, and in some cases some bits Must Be Zero (MBZ).
This patch adds proper checks to the 'ffa_memory_region' when handling
the memory sharing interfaces, so that error is returned when the bits
that MBZ aren't.

Change-Id: If5de9bb25d263b01a21e3c7d71bac707ab8652d5
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/api.c b/src/api.c
index 82619e0..d13e3ae 100644
--- a/src/api.c
+++ b/src/api.c
@@ -2052,6 +2052,36 @@
 	return (struct ffa_value){.func = FFA_INTERRUPT_32};
 }
 
+static bool api_memory_region_check_flags(
+	struct ffa_memory_region *memory_region, uint32_t share_func)
+{
+	switch (share_func) {
+	case FFA_MEM_SHARE_32:
+		if ((memory_region->flags & FFA_MEMORY_REGION_FLAG_CLEAR) !=
+		    0U) {
+			return false;
+		}
+		/* Intentional fall-through */
+	case FFA_MEM_LEND_32:
+	case FFA_MEM_DONATE_32: {
+		/* Bits 31:2 Must Be Zero. */
+		ffa_memory_receiver_flags_t to_mask =
+			~(FFA_MEMORY_REGION_FLAG_CLEAR |
+			  FFA_MEMORY_REGION_FLAG_TIME_SLICE);
+
+		if ((memory_region->flags & to_mask) != 0U) {
+			return false;
+		}
+		break;
+	}
+	default:
+		panic("Check for mem send calls only.\n");
+	}
+
+	/* Last check reserved values are 0 */
+	return true;
+}
+
 struct ffa_value api_ffa_mem_send(uint32_t share_func, uint32_t length,
 				  uint32_t fragment_length, ipaddr_t address,
 				  uint32_t page_count, struct vcpu *current)
@@ -2124,6 +2154,13 @@
 		goto out;
 	}
 
+	if (!api_memory_region_check_flags(memory_region, share_func)) {
+		dlog_verbose(
+			"Memory region reserved arguments must be zero.\n");
+		ret = ffa_error(FFA_INVALID_PARAMETERS);
+		goto out;
+	}
+
 	if (memory_region->receiver_count != 1) {
 		/* Hafnium doesn't support multi-way memory sharing for now. */
 		dlog_verbose(
diff --git a/src/ffa_memory.c b/src/ffa_memory.c
index f92957b..265f2f3 100644
--- a/src/ffa_memory.c
+++ b/src/ffa_memory.c
@@ -2246,6 +2246,24 @@
 		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;
+	}
+
 	/*
 	 * Check permissions from sender against permissions requested by
 	 * receiver.
@@ -2262,6 +2280,16 @@
 	requested_instruction_access =
 		ffa_get_instruction_access_attr(requested_permissions);
 	permissions = 0;
+
+	if ((sent_data_access == FFA_DATA_ACCESS_RO ||
+	     requested_permissions == FFA_DATA_ACCESS_RO) &&
+	    (retrieve_request->flags & FFA_MEMORY_REGION_FLAG_CLEAR) != 0U) {
+		dlog_verbose(
+			"Receiver has RO permissions can not request clear.\n");
+		ret = ffa_error(FFA_DENIED);
+		goto out;
+	}
+
 	switch (sent_data_access) {
 	case FFA_DATA_ACCESS_NOT_SPECIFIED:
 	case FFA_DATA_ACCESS_RW: