test: exercise secure espi interrupt handling
Hafnium/SPMC added support for enabling interrupts in the extended SPI
range. With the help of an SiP SMC call that can pend an interrupt,
this patch adds a test to trigger an espi interrupt when cactus is
running and ensure it is handled.
Additionally, a dummy device region node representing a fake
peripheral has been added to the Cactus SP manifest. It is used to
specify properties of the interrupt in the extended SPI range used
for the above test scenario.
Signed-off-by: Raghu Krishnamurthy <raghu.ncstate@gmail.com>
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Change-Id: Ief932c40e3abd33d619f2b144e61cae449147b27
diff --git a/include/runtime_services/cactus_test_cmds.h b/include/runtime_services/cactus_test_cmds.h
index 9dc0d90..6398138 100644
--- a/include/runtime_services/cactus_test_cmds.h
+++ b/include/runtime_services/cactus_test_cmds.h
@@ -614,4 +614,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"