feat(spmc): enable handling of the NS bit

In FF-A v1.1 the NS bit is used by the SPMC to specify the
security state of a memory region retrieved by a SP.

Enable the SPMC to set the bit for v1.1 callers or v1.0
callers that explicitly request the usage via FFA_FEATURES.

In this implementation the sender of the memory region must
reside in the normal world and the SPMC does not support
changing the security state of memory regions therefore
always set the NS bit if required by the caller.

Signed-off-by: Marc Bonnici <marc.bonnici@arm.com>
Change-Id: I215756b28e2382082933ba1dcc7584e7faf4b36b
diff --git a/services/std_svc/spm/el3_spmc/spmc_shared_mem.c b/services/std_svc/spm/el3_spmc/spmc_shared_mem.c
index 920dfca..7b9a526 100644
--- a/services/std_svc/spm/el3_spmc/spmc_shared_mem.c
+++ b/services/std_svc/spm/el3_spmc/spmc_shared_mem.c
@@ -876,6 +876,13 @@
 		goto err_arg;
 	}
 
+	/* Ensure the NS bit is set to 0. */
+	if ((obj->desc.memory_region_attributes & FFA_MEM_ATTR_NS_BIT) != 0U) {
+		WARN("%s: NS mem attributes flags MBZ.\n", __func__);
+		ret = FFA_ERROR_INVALID_PARAMETER;
+		goto err_arg;
+	}
+
 	/*
 	 * We don't currently support any optional flags so ensure none are
 	 * requested.
@@ -1190,6 +1197,33 @@
 }
 
 /**
+ * spmc_ffa_mem_retrieve_set_ns_bit - Set the NS bit in the response descriptor
+ *				      if the caller implements a version greater
+ *				      than FF-A 1.0 or if they have requested
+ *				      the functionality.
+ *				      TODO: We are assuming that the caller is
+ *				      an SP. To support retrieval from the
+ *				      normal world this function will need to be
+ *				      expanded accordingly.
+ * @resp:       Descriptor populated in callers RX buffer.
+ * @sp_ctx:     Context of the calling SP.
+ */
+void spmc_ffa_mem_retrieve_set_ns_bit(struct ffa_mtd *resp,
+			 struct secure_partition_desc *sp_ctx)
+{
+	if (sp_ctx->ffa_version > MAKE_FFA_VERSION(1, 0) ||
+	    sp_ctx->ns_bit_requested) {
+		/*
+		 * Currently memory senders must reside in the normal
+		 * world, and we do not have the functionlaity to change
+		 * the state of memory dynamically. Therefore we can always set
+		 * the NS bit to 1.
+		 */
+		resp->memory_region_attributes |= FFA_MEM_ATTR_NS_BIT;
+	}
+}
+
+/**
  * spmc_ffa_mem_retrieve_req - FFA_MEM_RETRIEVE_REQ implementation.
  * @smc_fid:            FID of SMC
  * @total_length:       Total length of retrieve request descriptor if this is
@@ -1237,6 +1271,7 @@
 	struct spmc_shmem_obj *obj = NULL;
 	struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
 	uint32_t ffa_version = get_partition_ffa_version(secure_origin);
+	struct secure_partition_desc *sp_ctx = spmc_get_current_sp_ctx();
 
 	if (!secure_origin) {
 		WARN("%s: unsupported retrieve req direction.\n", __func__);
@@ -1330,6 +1365,13 @@
 		goto err_unlock_all;
 	}
 
+	/* Ensure the NS bit is set to 0 in the request. */
+	if ((req->memory_region_attributes & FFA_MEM_ATTR_NS_BIT) != 0U) {
+		WARN("%s: NS mem attributes flags MBZ.\n", __func__);
+		ret = FFA_ERROR_INVALID_PARAMETER;
+		goto err_unlock_all;
+	}
+
 	if (req->flags != 0U) {
 		if ((req->flags & FFA_MTD_FLAG_TYPE_MASK) !=
 		    (obj->desc.flags & FFA_MTD_FLAG_TYPE_MASK)) {
@@ -1446,6 +1488,9 @@
 		memcpy(resp, &obj->desc, copy_size);
 	}
 
+	/* Set the NS bit in the response if applicable. */
+	spmc_ffa_mem_retrieve_set_ns_bit(resp, sp_ctx);
+
 	spin_unlock(&spmc_shmem_obj_state.lock);
 	spin_unlock(&mbox->lock);