test(cactus): add test for NS memory sharing between SPs

Define a new shared memory region in 48-bit address range
(configured as NS in the TZC) in cactus-tertiary's manifest.
Since SPs can share either secure or non-secure memory, propagate the
security information in the relevant cactus commands:
CACTUS_REQ_MEM_SEND_CMD and CACTUS_MEM_SEND_CMD.

Change-Id: I10af24c96ff8fc0d13c80a52b0264a1482a5cf56
Signed-off-by: Federico Recanati <federico.recanati@arm.com>
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index 78f1c58..a69eb72 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -290,6 +290,7 @@
 		}								\
 	} while (false)
 
+#ifdef __aarch64__
 #define SKIP_TEST_IF_PA_SIZE_LESS_THAN(n)					\
 	do {									\
 		static const unsigned int pa_range_bits_arr[] = {		\
@@ -301,6 +302,12 @@
 			return TEST_RESULT_SKIPPED;				\
 		}								\
 	} while (false)
+#else
+#define SKIP_TEST_IF_PA_SIZE_LESS_THAN(n)					\
+	do {									\
+		return TEST_RESULT_SKIPPED;					\
+	} while (false)
+#endif
 
 /* Helper macro to verify if system suspend API is supported */
 #define is_psci_sys_susp_supported()	\
diff --git a/include/runtime_services/cactus_test_cmds.h b/include/runtime_services/cactus_test_cmds.h
index 130cfa5..3bffb7b 100644
--- a/include/runtime_services/cactus_test_cmds.h
+++ b/include/runtime_services/cactus_test_cmds.h
@@ -197,10 +197,15 @@
 static inline smc_ret_values cactus_mem_send_cmd(
 	ffa_id_t source, ffa_id_t dest, uint32_t mem_func,
 	ffa_memory_handle_t handle, ffa_memory_region_flags_t retrieve_flags,
-	uint32_t word_to_write)
+	bool non_secure, uint16_t word_to_write)
 {
+	/*
+	 * `non_secure` and `word_to_write` are packed in the same register.
+	 * Packed in a 32-bit value to support AArch32 platforms (eg Juno).
+	 */
+	uint32_t val3 = ((uint32_t)non_secure << 16) | word_to_write;
 	return cactus_send_cmd(source, dest, CACTUS_MEM_SEND_CMD, mem_func,
-			       handle, retrieve_flags, word_to_write);
+			       handle, retrieve_flags, val3);
 }
 
 static inline ffa_memory_handle_t cactus_mem_send_get_handle(smc_ret_values ret)
@@ -214,9 +219,14 @@
 	return (ffa_memory_region_flags_t)ret.ret6;
 }
 
-static inline uint32_t cactus_mem_send_words_to_write(smc_ret_values ret)
+static inline uint16_t cactus_mem_send_words_to_write(smc_ret_values ret)
 {
-	return (uint32_t)ret.ret7;
+	return (uint16_t)ret.ret7;
+}
+
+static inline bool cactus_mem_send_get_non_secure(smc_ret_values ret)
+{
+	return (bool)(ret.ret7 >> 16);
 }
 
 /**
@@ -230,10 +240,10 @@
 
 static inline smc_ret_values cactus_req_mem_send_send_cmd(
 	ffa_id_t source, ffa_id_t dest, uint32_t mem_func,
-	ffa_id_t receiver)
+	ffa_id_t receiver, bool non_secure)
 {
 	return cactus_send_cmd(source, dest, CACTUS_REQ_MEM_SEND_CMD, mem_func,
-			       receiver, 0, 0);
+			       receiver, non_secure, 0);
 }
 
 static inline uint32_t cactus_req_mem_send_get_mem_func(smc_ret_values ret)
@@ -246,6 +256,11 @@
 	return (ffa_id_t)ret.ret5;
 }
 
+static inline bool cactus_req_mem_send_get_non_secure(smc_ret_values ret)
+{
+	return (bool)ret.ret6;
+}
+
 /**
  * Request to fill SIMD vectors with dummy values with purpose to check a
  * save/restore routine during the context switches between secure world and
diff --git a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
index 872cb41..884240b 100644
--- a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
+++ b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
@@ -57,6 +57,16 @@
 	}
 }
 
+static void *share_page_non_secure(ffa_id_t cactus_sp_id)
+{
+	if (cactus_sp_id != SP_ID(3)) {
+		ERROR("Helper function expecting a valid Cactus SP ID!\n");
+		panic();
+	}
+
+	return (void *)CACTUS_SP3_NS_MEM_SHARE_BASE;
+}
+
 CACTUS_CMD_HANDLER(mem_send_cmd, CACTUS_MEM_SEND_CMD)
 {
 	struct ffa_memory_region *m;
@@ -71,6 +81,7 @@
 	ffa_memory_region_flags_t retrv_flags =
 					 cactus_mem_send_get_retrv_flags(*args);
 	uint32_t words_to_write = cactus_mem_send_words_to_write(*args);
+	bool non_secure = cactus_mem_send_get_non_secure(*args);
 
 	expect(memory_retrieve(mb, &m, handle, source, vm_id,
 			       retrv_flags), true);
@@ -91,7 +102,7 @@
 
 	mem_attrs = MT_RW_DATA | MT_EXECUTE_NEVER;
 
-	if (!IS_SP_ID(source)) {
+	if (non_secure) {
 		mem_attrs |= MT_NS;
 	}
 
@@ -176,33 +187,37 @@
 	ffa_memory_handle_t handle;
 	ffa_id_t vm_id = ffa_dir_msg_dest(*args);
 	ffa_id_t source = ffa_dir_msg_source(*args);
+	bool non_secure = cactus_req_mem_send_get_non_secure(*args);
+	void *share_page_addr =
+		non_secure ? share_page_non_secure(vm_id) : share_page(vm_id);
+	unsigned int mem_attrs;
 	int ret;
-	static bool share_memory_mapped;
 
 	VERBOSE("%x requested to send memory to %x (func: %x), page: %llx\n",
-		source, receiver, mem_func, (uint64_t)share_page(vm_id));
+		source, receiver, mem_func, (uint64_t)share_page_addr);
 
 	const struct ffa_memory_region_constituent constituents[] = {
-		{share_page(vm_id), 1, 0}
+		{share_page_addr, 1, 0}
 	};
 
 	const uint32_t constituents_count = (sizeof(constituents) /
 					     sizeof(constituents[0]));
 
-	if (!share_memory_mapped) {
-		ret = mmap_add_dynamic_region(
-			(uint64_t)constituents[0].address,
-			(uint64_t)constituents[0].address,
-			constituents[0].page_count * PAGE_SIZE,
-			MT_RW_DATA);
+	VERBOSE("Sharing at 0x%llx\n", (uint64_t)constituents[0].address);
+	mem_attrs = MT_RW_DATA;
+	if (non_secure)
+		mem_attrs |= MT_NS;
+	ret = mmap_add_dynamic_region(
+		(uint64_t)constituents[0].address,
+		(uint64_t)constituents[0].address,
+		constituents[0].page_count * PAGE_SIZE,
+		mem_attrs);
 
-		if (ret != 0) {
-			ERROR("Failed map share memory before sending (%d)!\n",
-			      ret);
-			return cactus_error_resp(vm_id, source,
-						 CACTUS_ERROR_TEST);
-		}
-		share_memory_mapped = true;
+	if (ret != 0) {
+		ERROR("Failed map share memory before sending (%d)!\n",
+		      ret);
+		return cactus_error_resp(vm_id, source,
+					 CACTUS_ERROR_TEST);
 	}
 
 	handle = memory_init_and_send(
@@ -219,7 +234,8 @@
 					 ffa_error_code(ffa_ret));
 	}
 
-	ffa_ret = cactus_mem_send_cmd(vm_id, receiver, mem_func, handle, 0, 10);
+	ffa_ret = cactus_mem_send_cmd(vm_id, receiver, mem_func, handle,
+				      0, non_secure, 10);
 
 	if (!is_ffa_direct_response(ffa_ret)) {
 		return cactus_error_resp(vm_id, source, CACTUS_ERROR_FFA_CALL);
@@ -256,16 +272,18 @@
 				VERBOSE("      %u: %x\n", i, ptr[i]);
 			}
 		#endif
-	} else {
-		ret = mmap_remove_dynamic_region(
-			(uint64_t)constituents[0].address,
-			constituents[0].page_count * PAGE_SIZE);
+	}
 
-		if (ret != 0) {
-			ERROR("Failed to unmap donated region (%d)!\n", ret);
-			return cactus_error_resp(vm_id, source,
-						 CACTUS_ERROR_TEST);
-		}
+	/* Always unmap the sent memory region, will be remapped by another
+	 * test if needed. */
+	ret = mmap_remove_dynamic_region(
+		(uint64_t)constituents[0].address,
+		constituents[0].page_count * PAGE_SIZE);
+
+	if (ret != 0) {
+		ERROR("Failed to unmap share memory region (%d)!\n", ret);
+		return cactus_error_resp(vm_id, source,
+					 CACTUS_ERROR_TEST);
 	}
 
 	return cactus_success_resp(vm_id, source, 0);
diff --git a/spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts b/spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts
index 59408ea..772c3d4 100644
--- a/spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts
+++ b/spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts
@@ -51,5 +51,13 @@
 			base-address = <0x00000000 0x7502000>;
 			attributes = <0x3>; /* read-write */
 		};
+
+		/* Memory to be shared in memory sharing tests. */
+		share-memory-ns {
+			description = "NS share memory";
+			pages-count = <1>;
+			base-address = <0x00008800 0x80001000>;
+			attributes = <0x83>; /* NS / read-write */
+		};
 	};
 };
diff --git a/spm/cactus/plat/arm/fvp/include/cactus_platform_def.h b/spm/cactus/plat/arm/fvp/include/cactus_platform_def.h
index c48ce96..a356577 100644
--- a/spm/cactus/plat/arm/fvp/include/cactus_platform_def.h
+++ b/spm/cactus/plat/arm/fvp/include/cactus_platform_def.h
@@ -30,5 +30,6 @@
 #define CACTUS_SP1_MEM_SHARE_BASE 0x7500000
 #define CACTUS_SP2_MEM_SHARE_BASE 0x7501000
 #define CACTUS_SP3_MEM_SHARE_BASE 0x7502000
+#define CACTUS_SP3_NS_MEM_SHARE_BASE 0x880080001000ULL
 
 #endif /* CACTUS_PLATFORM_DEF_H */
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c b/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
index f68a527..ffa2a6f 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
@@ -79,7 +79,7 @@
 
 	/* Retrieve the shared page and attempt accessing it. */
 	ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_SHARE_SMC32,
-				  handle, 0, 1);
+				  handle, 0, true, 1);
 
 	/* Undelegate the shared page. */
 	retmm = realm_granule_undelegate((u_register_t)&share_page);
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
index d47cf39..7f62ea5 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
@@ -96,7 +96,7 @@
 	ptr = (uint32_t *)constituents[0].address;
 
 	ret = cactus_mem_send_cmd(SENDER, RECEIVER, mem_func, handle, 0,
-				  nr_words_to_write);
+				  true, nr_words_to_write);
 
 	if (!is_ffa_direct_response(ret)) {
 		return TEST_RESULT_FAIL;
@@ -143,7 +143,8 @@
  */
 static test_result_t test_req_mem_send_sp_to_sp(uint32_t mem_func,
 						ffa_id_t sender_sp,
-						ffa_id_t receiver_sp)
+						ffa_id_t receiver_sp,
+						bool non_secure)
 {
 	smc_ret_values ret;
 
@@ -153,7 +154,7 @@
 	CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
 
 	ret = cactus_req_mem_send_send_cmd(HYP_ID, sender_sp, mem_func,
-					   receiver_sp);
+					   receiver_sp, non_secure);
 
 	if (!is_ffa_direct_response(ret)) {
 		return TEST_RESULT_FAIL;
@@ -185,7 +186,7 @@
 	CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
 
 	ret = cactus_req_mem_send_send_cmd(HYP_ID, sender_sp, mem_func,
-					   receiver_vm);
+					   receiver_vm, false);
 
 	if (!is_ffa_direct_response(ret)) {
 		return TEST_RESULT_FAIL;
@@ -205,19 +206,34 @@
 test_result_t test_req_mem_share_sp_to_sp(void)
 {
 	return test_req_mem_send_sp_to_sp(FFA_MEM_SHARE_SMC32, SP_ID(3),
-					  SP_ID(2));
+					  SP_ID(2), false);
+}
+
+test_result_t test_req_ns_mem_share_sp_to_sp(void)
+{
+	/* Added this peprocessor condition because the test fails when RME is
+	 * enabled, because the model has PA_SIZE=48, but still doesn't have
+	 * allocated RAM allocatable there nor the itnerconnect support 48bit
+	 * addresses. */
+#if PA_SIZE == 48
+	SKIP_TEST_IF_PA_SIZE_LESS_THAN(48);
+	return test_req_mem_send_sp_to_sp(FFA_MEM_SHARE_SMC32, SP_ID(3),
+					  SP_ID(2), true);
+#else
+	return TEST_RESULT_SKIPPED;
+#endif
 }
 
 test_result_t test_req_mem_lend_sp_to_sp(void)
 {
 	return test_req_mem_send_sp_to_sp(FFA_MEM_LEND_SMC32, SP_ID(3),
-					  SP_ID(2));
+					  SP_ID(2), false);
 }
 
 test_result_t test_req_mem_donate_sp_to_sp(void)
 {
 	return test_req_mem_send_sp_to_sp(FFA_MEM_DONATE_SMC32, SP_ID(1),
-					  SP_ID(3));
+					  SP_ID(3), false);
 }
 
 test_result_t test_req_mem_share_sp_to_vm(void)
@@ -276,7 +292,7 @@
 	VERBOSE("Memory has been shared!\n");
 
 	ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_LEND_SMC32, handle,
-				  FFA_MEMORY_REGION_FLAG_CLEAR,
+				  FFA_MEMORY_REGION_FLAG_CLEAR, true,
 				  nr_words_to_write);
 
 	if (!is_ffa_direct_response(ret)) {
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index 04cb55d..878bec6 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -90,6 +90,8 @@
                function="test_req_mem_lend_sp_to_sp" />
      <testcase name="Request Donate Memory SP-to-SP"
                function="test_req_mem_donate_sp_to_sp" />
+     <testcase name="Request Share NS Memory SP-to-SP"
+               function="test_req_ns_mem_share_sp_to_sp" />
      <testcase name="Request Share Memory SP-to-VM"
                function="test_req_mem_share_sp_to_vm" />
      <testcase name="Request Lend Memory SP-to-VM"