test(nop): add "nop" test case

This is intended for use in conjunction with Trusted Firmware eXplorer
(TFX). The dummy test case exists only to provide a symbol with a
well-known name ("debug_hook"), at which TFX can set a breakpoint and
therefore marshall all PEs on entry to Non-secure state.

The "nop" test case is not built by default, and therefore must be
explicitly included, e.g.

    make TESTS=nop

Signed-off-by: Gareth Stockwell <gareth.stockwell@arm.com>
Change-Id: I1d0f95714e5f662ca0f2d90db32020be15b43aed
diff --git a/tftf/tests/misc_tests/test_nop.c b/tftf/tests/misc_tests/test_nop.c
new file mode 100644
index 0000000..d3c4386
--- /dev/null
+++ b/tftf/tests/misc_tests/test_nop.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <power_management.h>
+#include <test_helpers.h>
+
+__attribute__((noinline))
+static void debug_hook_func(void)
+{
+	__asm__ volatile(
+		"nop\n"
+		"nop\n"
+		"nop\n"
+		"nop\n"
+		"debug_hook:\n"
+		".global debug_hook\n"
+		"nop\n"
+		"nop\n"
+		"nop\n"
+		"nop\n"
+	);
+
+	return;
+}
+
+static test_result_t secondary_cpu(void)
+{
+	debug_hook_func();
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * This is intended for use in conjunction with Trusted Firmware eXplorer
+ * (TFX).
+ *
+ * 1. Power up all secondary CPUs and execute test_nop.
+ * 2. TFX is expected to set a breakpoint on debug_hook.  When this is hit,
+ *    TFX takes over control and starts injecting test code.
+ * 3. Once the test is complete, TFX powers down all CPUs.
+ */
+test_result_t test_nop(void)
+{
+	u_register_t lead_mpid, target_mpid;
+	int cpu_node;
+	long long ret;
+
+	lead_mpid = read_mpidr_el1() & MPID_MASK;
+
+	/* Start all other CPUs */
+	for_each_cpu(cpu_node) {
+		target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+		if (lead_mpid == target_mpid) {
+			continue;
+		}
+
+		ret = tftf_cpu_on(target_mpid, (uintptr_t)secondary_cpu, 0);
+		if (ret != PSCI_E_SUCCESS) {
+			ERROR("CPU ON failed for 0x0x%llx\n", (unsigned long long)target_mpid);
+			return TEST_RESULT_FAIL;
+		}
+	}
+
+	/* Do the actual work */
+	debug_hook_func();
+
+	/* Wait for other CPUs to complete */
+	for_each_cpu(cpu_node) {
+		target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+		if (lead_mpid == target_mpid) {
+			continue;
+		}
+
+		while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) != PSCI_STATE_OFF) {
+			continue;
+		}
+	}
+
+	return TEST_RESULT_SUCCESS;
+}