Merge "test(interrupts): add tests for interrupt routing"
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
 }