refactor(smmu): secure side DMA rand and memcpy

Add operation, source and size parameters to the cactus command
initiating an operation to the DMA test engine through the SMMU.
Add RAND48 operation support to the DMA test engine.
Refactor to a common run_testengine helper exercised by MEMCPY
and RAND48 SMMU operations.
Cactus SP dispatches either one of the operation based on the
operation id passed from TFTF.

Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Change-Id: I2ca7c303e8fef6baf99fe4b64b33102546b9ff30
diff --git a/spm/cactus/cactus_tests/cactus_tests_smmuv3.c b/spm/cactus/cactus_tests/cactus_tests_smmuv3.c
index 3e6740b..5308d93 100644
--- a/spm/cactus/cactus_tests/cactus_tests_smmuv3.c
+++ b/spm/cactus/cactus_tests/cactus_tests_smmuv3.c
@@ -1,13 +1,14 @@
 /*
- * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <stdint.h>
 
-#include <arch_helpers.h>
+#include <assert.h>
 #include "cactus.h"
+#include <arch_helpers.h>
 #include "cactus_message_loop.h"
 #include <sp_platform_def.h>
 #include "cactus_test_cmds.h"
@@ -19,63 +20,33 @@
 #include "sp_tests.h"
 #include <spm_common.h>
 
-/* Source and target address for memcopy operation */
-#define MEMCPY_SOURCE_BASE	PLAT_CACTUS_MEMCPY_BASE
-#define MEMPCY_TOTAL_SIZE	(PLAT_CACTUS_MEMCPY_RANGE / 2)
-#define MEMCPY_TARGET_BASE	(MEMCPY_SOURCE_BASE + MEMPCY_TOTAL_SIZE)
-
 /* Miscellaneous */
 #define NO_SUBSTREAMID	(0xFFFFFFFFU)
-#define TRANSFER_SIZE	(MEMPCY_TOTAL_SIZE / FRAME_COUNT)
 #define LOOP_COUNT	(5000U)
 
-static bool run_smmuv3_test(void)
+static bool run_testengine(uint32_t operation, uintptr_t source_addr,
+			   uintptr_t target_addr, size_t transfer_size,
+			   uint32_t attributes)
 {
-	uint64_t source_addr, cpy_range, target_addr;
-	uint64_t begin_addr, end_addr, dest_addr;
+	const uint32_t streamID_list[] = { 0U, 1U };
+	uintptr_t begin_addr;
+	uintptr_t end_addr;
+	uintptr_t dest_addr;
 	uint32_t status;
-	unsigned int i, f, attempts;
+	uint32_t f;
+	uint32_t attempts;
 
-	/*
-	 * The test engine's MEMCPY command copies data from the region in
-	 * range [begin, end_incl] to the region with base address as udata.
-	 * In this test, we configure the test engine to initiate memcpy from
-	 * scratch page located at MEMCPY_SOURCE_BASE to the page located at
-	 * address MEMCPY_TARGET_BASE
-	 */
-
-	VERBOSE("CACTUS: Running SMMUv3 test\n");
-
-	source_addr = MEMCPY_SOURCE_BASE;
-	cpy_range = MEMPCY_TOTAL_SIZE;
-	target_addr = MEMCPY_TARGET_BASE;
-	uint32_t streamID_list[] = { 0U, 1U };
-
-	uint64_t data[] = {
-		ULL(0xBAADFEEDCEEBDAAF),
-		ULL(0x0123456776543210)
-	};
-
-	/* Write pre-determined content to source pages */
-	for (i = 0U; i < (cpy_range / 8U); i++) {
-		mmio_write64_offset(source_addr, i * 8, data[i%2]);
-	}
-
-	/* Clean the data caches */
-	clean_dcache_range(source_addr, cpy_range);
-
-	/*
-	 * Make sure above load, store and cache maintenance instructions
-	 * complete before we start writing to TestEngine frame configuration
-	 * fields
-	 */
-	dsbsy();
+	assert(operation == ENGINE_MEMCPY || operation == ENGINE_RAND48);
 
 	for (f = 0U; f < FRAME_COUNT; f++) {
-		attempts = 0U;
-		begin_addr = source_addr + (TRANSFER_SIZE * f);
-		end_addr = begin_addr + TRANSFER_SIZE - 1U;
-		dest_addr = target_addr + (TRANSFER_SIZE * f);
+		begin_addr = source_addr + (transfer_size * f);
+		end_addr = begin_addr + transfer_size - 1U;
+
+		if (operation == ENGINE_MEMCPY) {
+			dest_addr = target_addr + (transfer_size * f);
+		} else {
+			dest_addr = 0;
+		}
 
 		/* Initiate DMA sequence */
 		mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), PCTRL_OFF, 0);
@@ -84,7 +55,12 @@
 		mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), SUBSTREAM_ID_OFF, NO_SUBSTREAMID);
 
 		mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), UCTRL_OFF, 0);
-		mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), SEED_OFF, 0);
+		mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), ATTR_OFF, attributes);
+
+		if (operation == ENGINE_RAND48) {
+			mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), SEED_OFF, (f + 1) * 42);
+		}
+
 		mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), BEGIN_OFF, begin_addr);
 		mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), END_CTRL_OFF, end_addr);
 
@@ -92,8 +68,8 @@
 		mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), STRIDE_OFF, 1);
 		mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), UDATA_OFF, dest_addr);
 
-		mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF, ENGINE_MEMCPY);
-		VERBOSE("SMMUv3TestEngine: Waiting for MEMCPY completion for frame: %u\n", f);
+		mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF, operation);
+		VERBOSE("SMMUv3TestEngine: waiting completion for frame: %u\n", f);
 
 		/*
 		 * It is guaranteed that a read of "cmd" fields after writing to it will
@@ -101,17 +77,18 @@
 		 * invalid.
 		 */
 		if (mmio_read32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF) == ENGINE_MIS_CFG) {
-			ERROR("SMMUv3TestEngine: Misconfigured for frame: %u\n", f);
+			ERROR("SMMUv3TestEngine: misconfigured for frame: %u\n", f);
 			return false;
 		}
 
-		/* Wait for mem copy to be complete */
+		/* Wait for operation to be complete */
+		attempts = 0U;
 		while (attempts++ < LOOP_COUNT) {
 			status = mmio_read32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF);
 			if (status == ENGINE_HALTED) {
 				break;
 			} else if (status == ENGINE_ERROR) {
-				ERROR("SMMUv3: Test failed\n");
+				ERROR("SMMUv3: test failed, engine error.\n");
 				return false;
 			}
 
@@ -123,38 +100,70 @@
 		}
 
 		if (attempts == LOOP_COUNT) {
-			ERROR("SMMUv3: Test failed\n");
+			ERROR("SMMUv3: test failed, exceeded max. wait loop.\n");
 			return false;
 		}
 
 		dsbsy();
 	}
 
-	/*
-	 * Invalidate cached entries to force the CPU to fetch the data from
-	 * Main memory
-	 */
-	inv_dcache_range(source_addr, cpy_range);
-	inv_dcache_range(target_addr, cpy_range);
+	return true;
+}
 
-	/* Compare source and destination memory locations for data */
-	for (i = 0U; i < (cpy_range / 8U); i++) {
-		if (mmio_read_64(source_addr + 8 * i) != mmio_read_64(target_addr + 8 * i)) {
-			ERROR("SMMUv3: Mem copy failed: %llx\n", target_addr + 8 * i);
-			return false;
+static bool run_smmuv3_memcpy(uintptr_t start_address, size_t size, uint32_t attributes)
+{
+	uintptr_t target_address;
+	size_t cpy_range = size >> 1;
+	bool ret;
+
+	/*
+	 * The test engine's MEMCPY command copies data from the region in
+	 * range [begin, end_incl] to the region with base address as udata.
+	 * In this test, we configure the test engine to initiate memcpy from
+	 * scratch page located at MEMCPY_SOURCE_BASE to the page located at
+	 * address MEMCPY_TARGET_BASE
+	 */
+
+	target_address = start_address + cpy_range;
+	ret = run_testengine(ENGINE_MEMCPY, start_address, target_address,
+			     cpy_range / FRAME_COUNT, attributes);
+
+	if (ret) {
+		/*
+		 * Invalidate cached entries to force the CPU to fetch the data from
+		 * Main memory
+		 */
+		inv_dcache_range(start_address, cpy_range);
+		inv_dcache_range(target_address, cpy_range);
+
+		/* Compare source and destination memory locations for data */
+		for (size_t i = 0U; i < (cpy_range / 8U); i++) {
+			if (mmio_read_64(start_address + 8 * i) !=
+			    mmio_read_64(target_address + 8 * i)) {
+				ERROR("SMMUv3: Mem copy failed: %lx\n", target_address + 8 * i);
+				return false;
+			}
 		}
 	}
 
-	return true;
+	return ret;
+}
+
+static bool run_smmuv3_rand48(uintptr_t start_address, size_t size, uint32_t attributes)
+{
+	return run_testengine(ENGINE_RAND48, start_address, 0, size / FRAME_COUNT, attributes);
 }
 
 CACTUS_CMD_HANDLER(smmuv3_cmd, CACTUS_DMA_SMMUv3_CMD)
 {
-	struct ffa_value ffa_ret;
 	ffa_id_t vm_id = ffa_dir_msg_dest(*args);
 	ffa_id_t source = ffa_dir_msg_source(*args);
+	uint32_t operation = args->arg4;
+	uintptr_t start_address = args->arg5;
+	size_t size = args->arg6;
+	uint32_t attributes = args->arg7;
 
-	VERBOSE("Received request through direct message for DMA service\n");
+	VERBOSE("Received request through direct message for DMA service.\n");
 
 	/*
 	 * At present, the test cannot be run concurrently on multiple SPs as
@@ -165,11 +174,21 @@
 		return cactus_error_resp(vm_id, source, 0);
 	}
 
-	if (run_smmuv3_test()) {
-		ffa_ret = cactus_success_resp(vm_id, source, 0);
-	} else {
-		ffa_ret = cactus_error_resp(vm_id, source, 0);
+	switch (operation) {
+	case ENGINE_MEMCPY:
+		if (run_smmuv3_memcpy(start_address, size, attributes)) {
+			return cactus_success_resp(vm_id, source, 0);
+		}
+		break;
+	case ENGINE_RAND48:
+		if (run_smmuv3_rand48(start_address, size, attributes)) {
+			return cactus_success_resp(vm_id, source, 0);
+		}
+		break;
+	default:
+		ERROR("SMMUv3TestEngine: unsupported operation (%u).\n", operation);
+		break;
 	}
 
-	return ffa_ret;
+	return cactus_error_resp(vm_id, source, 0);
 }
diff --git a/spm/cactus/cactus_tests/smmuv3_test_engine.h b/spm/cactus/cactus_tests/smmuv3_test_engine.h
index 32d86ac..d3a3dcf 100644
--- a/spm/cactus/cactus_tests/smmuv3_test_engine.h
+++ b/spm/cactus/cactus_tests/smmuv3_test_engine.h
@@ -32,6 +32,7 @@
 /* Offset of various control fields belonging to User Frame */
 #define CMD_OFF		(0x0U)
 #define UCTRL_OFF	(0x4U)
+#define ATTR_OFF	(0x20U)
 #define SEED_OFF	(0x24U)
 #define BEGIN_OFF	(0x28U)
 #define END_CTRL_OFF	(0x30U)
diff --git a/spm/cactus/plat/arm/fvp/include/sp_platform_def.h b/spm/cactus/plat/arm/fvp/include/sp_platform_def.h
index 0b23189..058209c 100644
--- a/spm/cactus/plat/arm/fvp/include/sp_platform_def.h
+++ b/spm/cactus/plat/arm/fvp/include/sp_platform_def.h
@@ -25,8 +25,9 @@
 #define CACTUS_PL011_UART_CLK_IN_HZ	PL011_UART2_CLK_IN_HZ
 
 /* Scratch memory used for SMMUv3 driver testing purposes in Cactus SP */
-#define PLAT_CACTUS_MEMCPY_BASE		ULL(0x7400000)
-#define PLAT_CACTUS_MEMCPY_RANGE	ULL(0x8000)
+#define PLAT_CACTUS_MEMCPY_BASE			ULL(0x7400000)
+#define PLAT_CACTUS_SMMU_NS_MEMCPY_BASE		ULL(0x90000000)
+#define PLAT_CACTUS_MEMCPY_RANGE		ULL(0x8000)
 
 /* Base address of user and PRIV frames in SMMUv3TestEngine */
 #define USR_BASE_FRAME			ULL(0x2BFE0000)