test(interrupts): add tests for interrupt routing

This patch modifies existing secure interrupt tests to test interrupt
routing to particular cores/mpidr. Hafnium added a new field
"interrupts-target" to enable targeting interrupts to cores that are NOT
the boot core. This change modifies the cactus manifest to target the
secure watchdog timer (existing secure interrupt on fvp) to a particular
mpidr. To test interrupt handling, it converts the existing tests that
use the secure watchdog timer to test interrupt handling, to multi
core tests, such that the same test runs on the appropriate mpidr as
opposed to the boot core. Since the interrupt may be targeted to a
secondary PE, the corresponding secondary vcpus of cactus need a round
of ffa_run to function, which has also been added.
The mpidr to target to is platform specific and is defined as a platform
specific macro.

Signed-off-by: Raghu Krishnamurthy <raghu.ncstate@gmail.com>
Change-Id: I27f48cde68945e59fb2ce84625ca145048eaffd1
diff --git a/plat/arm/fvp/include/platform_def.h b/plat/arm/fvp/include/platform_def.h
index b8871c4..ca391b3 100644
--- a/plat/arm/fvp/include/platform_def.h
+++ b/plat/arm/fvp/include/platform_def.h
@@ -308,4 +308,7 @@
 #define ARM_SECURE_SERVICE_BUFFER_BASE	0xff600000ull
 #define ARM_SECURE_SERVICE_BUFFER_SIZE	0x10000ull
 
+
+#define PLAT_INTERRUPT_MPIDR		0x81010300
+
 #endif /* __PLATFORM_DEF_H__ */
diff --git a/spm/cactus/plat/arm/fvp/fdts/cactus.dts b/spm/cactus/plat/arm/fvp/fdts/cactus.dts
index 4d27c9c..d3b933d 100644
--- a/spm/cactus/plat/arm/fvp/fdts/cactus.dts
+++ b/spm/cactus/plat/arm/fvp/fdts/cactus.dts
@@ -119,6 +119,7 @@
 			pages-count = <32>; /* Two 64KB pages */
 			attributes = <0x3>; /* read-write */
 			interrupts = <56 0x900>;
+			interrupts-target = <56 0x00 0x81010300>;
 		};
 	};
 };
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c b/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c
index 5977717..d672f08 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_secure_interrupts.c
@@ -21,9 +21,13 @@
 		{PRIMARY_UUID}, {SECONDARY_UUID}
 	};
 
+static event_t cpu_reached_end_of_test[PLATFORM_CORE_COUNT];
+
 /*
  * @Test_Aim@ Test secure interrupt handling while first Secure Partition is
- * in RUNNING state.
+ * in RUNNING state. The interrupt is routed to the core defined by
+ * PLAT_INTERRUPT_MPIDR and runs only on that core. If PLAT_INTERRUPT_MPIDR is
+ * not defined, it defaults to current core.
  *
  * 1. Send a direct message request command to first Cactus SP to start the
  *    trusted watchdog timer.
@@ -62,23 +66,28 @@
  *     interrupt through a direct message request command.
  *
  */
-
-test_result_t test_ffa_sec_interrupt_sp_running(void)
+static test_result_t test_ffa_sec_interrupt_sp_running_handler(void)
 {
 	struct ffa_value ret_values;
+	test_result_t test_ret = TEST_RESULT_FAIL;
 
-	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+#ifdef PLAT_INTERRUPT_MPIDR
+	if (read_mpidr_el1() != PLAT_INTERRUPT_MPIDR) {
+		test_ret = TEST_RESULT_SUCCESS;
+		goto exit;
+	}
+#endif
 
 	/* Enable trusted watchdog interrupt as IRQ in the secure side. */
 	if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER, 50);
 
 	if (!is_ffa_direct_response(ret_values)) {
 		ERROR("Expected a direct response for starting TWDOG timer\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/* Send request to first Cactus SP to sleep */
@@ -90,7 +99,7 @@
 	 */
 	if (!is_ffa_direct_response(ret_values)) {
 		ERROR("Expected a direct response for sleep command\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	VERBOSE("Secure interrupt has preempted execution: %u\n",
@@ -99,7 +108,7 @@
 	/* Make sure elapsed time not less than sleep time */
 	if (cactus_get_response(ret_values) < SP_SLEEP_TIME) {
 		ERROR("Lapsed time less than requested sleep time\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/* Check for the last serviced secure virtual interrupt. */
@@ -108,26 +117,49 @@
 	if (!is_ffa_direct_response(ret_values)) {
 		ERROR("Expected a direct response for last serviced interrupt"
 			" command\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/* Make sure Trusted Watchdog timer interrupt was serviced*/
 	if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
 		ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/* Disable Trusted Watchdog interrupt. */
 	if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
-	return TEST_RESULT_SUCCESS;
+	test_ret = TEST_RESULT_SUCCESS;
+exit:
+	if (test_ret != TEST_RESULT_SUCCESS) {
+		ERROR("%s - Test Failed - core - %d\n", __func__,
+			get_current_core_id());
+	}
+	tftf_send_event(&cpu_reached_end_of_test[get_current_core_id()]);
+	return test_ret;
+}
+
+test_result_t test_ffa_sec_interrupt_sp_running(void)
+{
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+	memset(cpu_reached_end_of_test, 0, sizeof(cpu_reached_end_of_test));
+
+#ifdef PLAT_INTERRUPT_MPIDR
+	return spm_run_multi_core_test(
+			(uintptr_t)test_ffa_sec_interrupt_sp_running_handler,
+			cpu_reached_end_of_test);
+#else
+	return test_ffa_sec_interrupt_sp_running_handler();
+#endif
 }
 
 /*
  * @Test_Aim@ Test secure interrupt handling while Secure Partition is waiting
- * for a message.
+ * for a message. The interrupt is routed to the core defined by
+ * PLAT_INTERRUPT_MPIDR and runs only on that core. If PLAT_INTERRUPT_MPIDR is
+ * not defined, it defaults to current core.
  *
  * 1. Send a direct message request command to first Cactus SP to start the
  *    trusted watchdog timer.
@@ -164,18 +196,24 @@
  *     interrupt through a direct message request command.
  *
  */
-test_result_t test_ffa_sec_interrupt_sp_waiting(void)
+static test_result_t test_ffa_sec_interrupt_sp_waiting_handler(void)
 {
 	uint64_t time1;
 	volatile uint64_t time2, time_lapsed;
 	uint64_t timer_freq = read_cntfrq_el0();
 	struct ffa_value ret_values;
+	test_result_t test_ret = TEST_RESULT_FAIL;
 
-	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+#ifdef PLAT_INTERRUPT_MPIDR
+	if (read_mpidr_el1() != PLAT_INTERRUPT_MPIDR) {
+		test_ret = TEST_RESULT_SUCCESS;
+		goto exit;
+	}
+#endif
 
 	/* Enable trusted watchdog interrupt as IRQ in the secure side. */
 	if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/*
@@ -185,7 +223,7 @@
 
 	if (!is_ffa_direct_response(ret_values)) {
 		ERROR("Expected a direct response for starting TWDOG timer\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	time1 = syscounter_read();
@@ -203,7 +241,7 @@
 	if (time_lapsed < NS_TIME_SLEEP) {
 		ERROR("Time elapsed less than expected value: %llu vs %u\n",
 				time_lapsed, NS_TIME_SLEEP);
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/* Check for the last serviced secure virtual interrupt. */
@@ -212,26 +250,49 @@
 	if (!is_ffa_direct_response(ret_values)) {
 		ERROR("Expected a direct response for last serviced interrupt"
 			" command\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/* Make sure Trusted Watchdog timer interrupt was serviced*/
 	if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
 		ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/* Disable Trusted Watchdog interrupt. */
 	if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
-	return TEST_RESULT_SUCCESS;
+	test_ret = TEST_RESULT_SUCCESS;
+exit:
+	if (test_ret != TEST_RESULT_SUCCESS) {
+		ERROR("%s - Test Failed - core - %d\n", __func__,
+			get_current_core_id());
+	}
+	tftf_send_event(&cpu_reached_end_of_test[get_current_core_id()]);
+	return test_ret;
+}
+
+test_result_t test_ffa_sec_interrupt_sp_waiting(void)
+{
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+	memset(cpu_reached_end_of_test, 0, sizeof(cpu_reached_end_of_test));
+
+#ifdef PLAT_INTERRUPT_MPIDR
+	return spm_run_multi_core_test(
+			(uintptr_t)test_ffa_sec_interrupt_sp_waiting_handler,
+			cpu_reached_end_of_test);
+#else
+	return test_ffa_sec_interrupt_sp_waiting_handler();
+#endif
 }
 
 /*
  * @Test_Aim@ Test secure interrupt handling while first Secure Partition is
- * in BLOCKED state.
+ * in BLOCKED state. The interrupt is routed to the core defined by
+ * PLAT_INTERRUPT_MPIDR and runs only on that core. If PLAT_INTERRUPT_MPIDR is
+ * not defined, it defaults to current core.
  *
  * 1. Send a direct message request command to first Cactus SP to start the
  *    trusted watchdog timer.
@@ -266,22 +327,41 @@
  * 11. Test finishes successfully once the TFTF disables the trusted watchdog
  *     interrupt through a direct message request command.
  */
-test_result_t test_ffa_sec_interrupt_sp_blocked(void)
+static test_result_t test_ffa_sec_interrupt_sp_blocked_handler(void)
 {
 	struct ffa_value ret_values;
+	test_result_t test_ret = TEST_RESULT_FAIL;
 
-	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+#ifdef PLAT_INTERRUPT_MPIDR
+	if (read_mpidr_el1() != PLAT_INTERRUPT_MPIDR) {
+		test_ret = TEST_RESULT_SUCCESS;
+		goto exit;
+	}
+#endif
 
 	/* Enable trusted watchdog interrupt as IRQ in the secure side. */
 	if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER, 100);
 
 	if (!is_ffa_direct_response(ret_values)) {
 		ERROR("Expected a direct response for starting TWDOG timer\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
+	}
+
+	/*
+	 * Call FFA_RUN on the secondary vcpus to start it up. it is possible
+	 * that another test has already started in, in which case we may get
+	 * an error. We ignore the error and proceed, if the vcpu is not started
+	 * the following direct requests would fail.
+	 */
+	ret_values = ffa_run(RECEIVER_2, get_current_core_id());
+	if (ffa_func_id(ret_values) == FFA_ERROR) {
+		WARN("Failed to start secondary vcpu of RECEIVER_2, "
+			"may already be started by other tests. Ignoring"
+			" error\n");
 	}
 
 	/*
@@ -297,11 +377,12 @@
 	 */
 	if (!is_ffa_direct_response(ret_values)) {
 		ERROR("Expected a direct response\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
-		return TEST_RESULT_FAIL;
+		ERROR("Expected CACTUS_SUCCESS %x\n", cactus_get_response(ret_values));
+		goto exit;
 	}
 
 	/* Check for the last serviced secure virtual interrupt. */
@@ -310,26 +391,50 @@
 	if (!is_ffa_direct_response(ret_values)) {
 		ERROR("Expected a direct response for last serviced interrupt"
 			" command\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/* Make sure Trusted Watchdog timer interrupt was serviced*/
 	if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
 		ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/* Disable Trusted Watchdog interrupt. */
 	if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
-	return TEST_RESULT_SUCCESS;
+	test_ret = TEST_RESULT_SUCCESS;
+exit:
+	if (test_ret != TEST_RESULT_SUCCESS) {
+		ERROR("%s - Test Failed - core - %d\n", __func__,
+			get_current_core_id());
+	}
+	tftf_send_event(&cpu_reached_end_of_test[get_current_core_id()]);
+	return test_ret;
+}
+
+test_result_t test_ffa_sec_interrupt_sp_blocked(void)
+{
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+	memset(cpu_reached_end_of_test, 0, sizeof(cpu_reached_end_of_test));
+
+#ifdef PLAT_INTERRUPT_MPIDR
+	return spm_run_multi_core_test(
+			(uintptr_t)test_ffa_sec_interrupt_sp_blocked_handler,
+			cpu_reached_end_of_test);
+#else
+	return test_ffa_sec_interrupt_sp_blocked_handler();
+#endif
 }
 
 /*
  * @Test_Aim@ Test secure interrupt handling while first Secure Partition is
  * in WAITING state while the second Secure Partition is running.
+ * The interrupt is routed to the core defined by PLAT_INTERRUPT_MPIDR and
+ * runs only on that core. If PLAT_INTERRUPT_MPIDR is not defined, it defaults
+ * to current core.
  *
  * 1. Send a direct message request command to first Cactus SP to start the
  *    trusted watchdog timer.
@@ -366,22 +471,41 @@
  * 12. Test finishes successfully once the TFTF disables the trusted watchdog
  *     interrupt through a direct message request command.
  */
-test_result_t test_ffa_sec_interrupt_sp1_waiting_sp2_running(void)
+static test_result_t test_ffa_sec_interrupt_sp1_waiting_sp2_running_handler(void)
 {
 	struct ffa_value ret_values;
+	test_result_t test_ret = TEST_RESULT_FAIL;
 
-	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+#ifdef PLAT_INTERRUPT_MPIDR
+	if (read_mpidr_el1() != PLAT_INTERRUPT_MPIDR) {
+		test_ret = TEST_RESULT_SUCCESS;
+		goto exit;
+	}
+#endif
 
 	/* Enable trusted watchdog interrupt as IRQ in the secure side. */
 	if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER, 100);
 
 	if (!is_ffa_direct_response(ret_values)) {
 		ERROR("Expected a direct response for starting TWDOG timer\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
+	}
+
+	/*
+	 * Call FFA_RUN on the secondary vcpus to start it up. It is possible
+	 * that another test has already started in, in which case we may get
+	 * an error. We ignore the error and proceed, if the vcpu is not started
+	 * the following direct requests would fail.
+	 */
+	ret_values = ffa_run(RECEIVER_2, get_current_core_id());
+	if (ffa_func_id(ret_values) == FFA_ERROR) {
+		WARN("Failed to start secondary vcpu of RECEIVER_2, "
+			"may already be started by other tests. Ignoring"
+			" error\n");
 	}
 
 	/* Send request to Second Cactus SP to sleep. */
@@ -393,7 +517,7 @@
 	 */
 	if (!is_ffa_direct_response(ret_values)) {
 		ERROR("Expected a direct response for sleep command\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/* Make sure elapsed time not less than sleep time. */
@@ -407,19 +531,40 @@
 	if (!is_ffa_direct_response(ret_values)) {
 		ERROR("Expected a direct response for last serviced interrupt"
 			" command\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/* Make sure Trusted Watchdog timer interrupt was serviced*/
 	if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
 		ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
 	/* Disable Trusted Watchdog interrupt. */
 	if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
-		return TEST_RESULT_FAIL;
+		goto exit;
 	}
 
-	return TEST_RESULT_SUCCESS;
+	test_ret = TEST_RESULT_SUCCESS;
+exit:
+	if (test_ret != TEST_RESULT_SUCCESS) {
+		ERROR("%s - Test Failed - core - %d\n", __func__,
+			get_current_core_id());
+	}
+	tftf_send_event(&cpu_reached_end_of_test[get_current_core_id()]);
+	return test_ret;
+}
+
+test_result_t test_ffa_sec_interrupt_sp1_waiting_sp2_running(void)
+{
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+	memset(cpu_reached_end_of_test, 0, sizeof(cpu_reached_end_of_test));
+
+#ifdef PLAT_INTERRUPT_MPIDR
+	return spm_run_multi_core_test(
+			(uintptr_t)test_ffa_sec_interrupt_sp1_waiting_sp2_running_handler,
+			cpu_reached_end_of_test);
+#else
+	return test_ffa_sec_interrupt_sp1_waiting_sp2_running_handler();
+#endif
 }