Merge "test: exercise secure espi interrupt handling"
diff --git a/include/runtime_services/cactus_test_cmds.h b/include/runtime_services/cactus_test_cmds.h
index a12a588..5f3d0d2 100644
--- a/include/runtime_services/cactus_test_cmds.h
+++ b/include/runtime_services/cactus_test_cmds.h
@@ -604,4 +604,23 @@
 	return cactus_send_cmd(source, dest, CACTUS_RESUME_AFTER_MANAGED_EXIT,
 				 0, 0, 0, 0);
 }
+
+/**
+ * Request SP to pend an interrupt in the extended SPI range.
+ *
+ * The command is the hex representation of the string "espi".
+ */
+#define CACTUS_TRIGGER_ESPI_CMD U(0x65737069)
+static inline struct ffa_value cactus_trigger_espi_cmd(
+	ffa_id_t source, ffa_id_t dest, uint32_t espi_id)
+{
+	return cactus_send_cmd(source, dest, CACTUS_TRIGGER_ESPI_CMD,
+				 espi_id, 0, 0, 0);
+}
+
+static inline uint32_t cactus_get_espi_id(struct ffa_value ret)
+{
+	return (uint32_t)ret.arg4;
+}
+
 #endif
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index 9e7f1e6..48471bc 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -30,6 +30,9 @@
 /* INTID for the notification pending interrupt. */
 #define NOTIFICATION_PENDING_INTERRUPT_INTID 5
 
+/* Interrupt used for testing extended SPI handling. */
+#define IRQ_ESPI_TEST_INTID			5000
+
 /** IRQ/FIQ pin used for signaling a virtual interrupt. */
 enum interrupt_pin {
 	INTERRUPT_TYPE_IRQ,
diff --git a/spm/cactus/cactus_tests/cactus_test_interrupts.c b/spm/cactus/cactus_tests/cactus_test_interrupts.c
index efe2260..6a1092b 100644
--- a/spm/cactus/cactus_tests/cactus_test_interrupts.c
+++ b/spm/cactus/cactus_tests/cactus_test_interrupts.c
@@ -12,11 +12,13 @@
 #include "cactus_message_loop.h"
 #include "cactus_test_cmds.h"
 
+#include <mmio.h>
 #include <platform.h>
 
 /* Secure virtual interrupt that was last handled by Cactus SP. */
 extern uint32_t last_serviced_interrupt[PLATFORM_CORE_COUNT];
 static int flag_set;
+static volatile bool test_espi_handled;
 
 static void handle_sec_wdog_interrupt(void)
 {
@@ -227,3 +229,43 @@
 			       ffa_dir_msg_source(*args),
 			       last_serviced_interrupt[core_pos]);
 }
+
+static void sec_interrupt_test_espi_handled(void)
+{
+	expect(test_espi_handled, false);
+	test_espi_handled = true;
+	NOTICE("Interrupt handler for test espi interrupt called\n");
+
+	/* Perform secure interrupt de-activation. */
+	spm_interrupt_deactivate(IRQ_ESPI_TEST_INTID);
+}
+
+CACTUS_CMD_HANDLER(trigger_espi_cmd, CACTUS_TRIGGER_ESPI_CMD)
+{
+	uint32_t espi_id = cactus_get_espi_id(*args);
+
+	/*
+	 * The SiP function ID 0x82000100 must have been added to the SMC
+	 * whitelist of the Cactus SP that invokes it.
+	 */
+	smc_args plat_sip_call = {
+			.fid = 0x82000100,
+			.arg1 = espi_id,
+	};
+	smc_ret_values ret;
+
+	sp_register_interrupt_handler(sec_interrupt_test_espi_handled,
+				      espi_id);
+	ret = tftf_smc(&plat_sip_call);
+
+	if (ret.ret0 == SMC_UNKNOWN) {
+		ERROR("SiP SMC call not supported\n");
+		return cactus_error_resp(ffa_dir_msg_dest(*args),
+				ffa_dir_msg_source(*args),
+				CACTUS_ERROR_TEST);
+	}
+
+	return cactus_response(ffa_dir_msg_dest(*args),
+			       ffa_dir_msg_source(*args),
+			       test_espi_handled ? 1 : 0);
+}
diff --git a/spm/cactus/plat/arm/fvp/fdts/cactus.dts b/spm/cactus/plat/arm/fvp/fdts/cactus.dts
index 4d27c9c..ed4eb6d 100644
--- a/spm/cactus/plat/arm/fvp/fdts/cactus.dts
+++ b/spm/cactus/plat/arm/fvp/fdts/cactus.dts
@@ -120,5 +120,19 @@
 			attributes = <0x3>; /* read-write */
 			interrupts = <56 0x900>;
 		};
+
+		espi_test_node {
+			/*
+			 * A dummy device region node representing a fake
+			 * peripheral. Explicitly used to specify properties of
+			 * interrupt 5000, in the extended SPI range, used for
+			 * testing purposes. All the properties below except
+			 * `interrupts` are irrelevant.
+			 */
+			base-address = <0x00000000 0x1c130000>;
+			pages-count = <1>; /* One 4KB page */
+			attributes = <0x1>; /* read-only */
+			interrupts = <5000 0x900>;
+		};
 	};
 };
diff --git a/spm/common/sp_helpers.h b/spm/common/sp_helpers.h
index 629801e..a82924b 100644
--- a/spm/common/sp_helpers.h
+++ b/spm/common/sp_helpers.h
@@ -12,8 +12,11 @@
 #include <spm_common.h>
 #include <spinlock.h>
 
-/* Currently, Hafnium/SPM supports 1024 virtual interrupt IDs. */
-#define NUM_VINT_ID	1024
+/*
+ * Use extended SPI interrupt ID range, hafnium/SPMC maps virtual interrupts
+ * to physical interrupts 1 to 1.
+ */
+#define NUM_VINT_ID	5120
 
 typedef struct {
 	u_register_t fid;
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 336faf9..3f746f4 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,6 +7,8 @@
 #include <cactus_test_cmds.h>
 #include <ffa_endpoints.h>
 #include <ffa_helpers.h>
+#include <mmio.h>
+#include <spm_common.h>
 #include <spm_test_helpers.h>
 #include <test_helpers.h>
 #include <timer.h>
@@ -424,3 +426,86 @@
 
 	return TEST_RESULT_SUCCESS;
 }
+
+/*
+ * @Test_Aim@ Test handling of interrupt belonging to the extended SPI range
+ * while first Secure Partition is in RUNNING state.
+ *
+ * 1. Send a direct message request command to first Cactus SP to trigger the
+ *    eSPI interrupt.
+ *
+ * 2. The Cactus SP either successfully handles the interrupt or fails to do
+ *    so. It sends a value through direct message response indicating if the
+ *    interrupt was handled.
+ *
+ * 3. TFTF sends a direct request message to SP to query the ID of last serviced
+ *    secure virtual interrupt.
+ *
+ * 4. Further, TFTF expects SP to return the appropriate interrupt id through a
+ *    direct response message.
+ */
+test_result_t test_ffa_espi_sec_interrupt(void)
+{
+	struct ffa_value ret_values;
+
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+	/* Enable ESPI. */
+	ret_values = cactus_interrupt_cmd(SENDER, RECEIVER, IRQ_ESPI_TEST_INTID,
+					  true, INTERRUPT_TYPE_IRQ);
+
+	if (!is_ffa_direct_response(ret_values)) {
+		ERROR("Expected a direct response message while configuring"
+			" interrupt ESPI %u\n", IRQ_ESPI_TEST_INTID);
+		return TEST_RESULT_FAIL;
+	}
+
+	if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
+		ERROR("Failed to configure ESPI interrupt\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Trigger ESPI while running. */
+	ret_values = cactus_trigger_espi_cmd(SENDER, RECEIVER, IRQ_ESPI_TEST_INTID);
+	if (!is_ffa_direct_response(ret_values)) {
+		ERROR("Expected a direct response message while triggering"
+			" interrupt ESPI %u\n", IRQ_ESPI_TEST_INTID);
+		return TEST_RESULT_FAIL;
+	}
+
+	if (cactus_get_response(ret_values) != 1) {
+		ERROR("Interrupt %u not serviced by SP\n", IRQ_ESPI_TEST_INTID);
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Disable ESPI. */
+	ret_values = cactus_interrupt_cmd(SENDER, RECEIVER, IRQ_ESPI_TEST_INTID,
+					  false, INTERRUPT_TYPE_IRQ);
+
+	if (!is_ffa_direct_response(ret_values)) {
+		ERROR("Expected a direct response message while configuring"
+			" interrupt ESPI %u\n", IRQ_ESPI_TEST_INTID);
+		return TEST_RESULT_FAIL;
+	}
+
+	if (cactus_get_response(ret_values) != CACTUS_SUCCESS) {
+		ERROR("Failed to configure ESPI interrupt %u\n", IRQ_ESPI_TEST_INTID);
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Check for the last serviced secure virtual interrupt. */
+	ret_values = cactus_get_last_interrupt_cmd(SENDER, RECEIVER);
+
+	if (!is_ffa_direct_response(ret_values)) {
+		ERROR("Expected a direct response for last serviced interrupt"
+			" command\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Make sure Trusted Watchdog timer interrupt was serviced*/
+	if (cactus_get_response(ret_values) != IRQ_ESPI_TEST_INTID) {
+		ERROR("ESPI interrupt %u not serviced by SP\n", IRQ_ESPI_TEST_INTID);
+		return TEST_RESULT_FAIL;
+	}
+	return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index 6285a97..8ec2812 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -140,6 +140,8 @@
                function="test_ffa_sec_interrupt_sp_blocked" />
      <testcase name="Test Secure interrupt handling while SP1 waiting SP2 running"
                function="test_ffa_sec_interrupt_sp1_waiting_sp2_running" />
+     <testcase name="Test ESPI Secure interrupt handling"
+               function="test_ffa_espi_sec_interrupt" />
   </testsuite>
 
   <testsuite name="SMMUv3 tests"