test(interrupts): secure interrupt target in RUNNING state

This patch adds a new test to exercise secure interrupt targeted
for an SP in RUNNING state. The test is made part of a new test suite
named secure_interrupts.

All the tests in this test suite are run as part of two different
configurations: one where the target SP is a S-EL1 partition and
another where the target SP is a S-EL0 partition.

Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Change-Id: Ibdea25bffa3c8285509e1c21a2ff93f2cc0acdda
diff --git a/test/vmapi/ffa_secure_partitions/BUILD.gn b/test/vmapi/ffa_secure_partitions/BUILD.gn
index 02394d7..c397ce2 100644
--- a/test/vmapi/ffa_secure_partitions/BUILD.gn
+++ b/test/vmapi/ffa_secure_partitions/BUILD.gn
@@ -43,6 +43,7 @@
     "interrupts.c",
     "notifications.c",
     "power_mgt.c",
+    "secure_interrupts.c",
     "setup_and_discovery.c",
   ]
 
diff --git a/test/vmapi/ffa_secure_partitions/secure_interrupts.c b/test/vmapi/ffa_secure_partitions/secure_interrupts.c
new file mode 100644
index 0000000..92776d3
--- /dev/null
+++ b/test/vmapi/ffa_secure_partitions/secure_interrupts.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2023 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+#include "ffa_secure_partitions.h"
+#include "partition_services.h"
+#include "sp_helpers.h"
+
+#define SP_SLEEP_TIME 400U
+
+static void configure_trusted_wdog_interrupt(ffa_vm_id_t source,
+					     ffa_vm_id_t dest, bool enable)
+{
+	struct ffa_value res;
+
+	res = sp_virtual_interrupt_cmd_send(source, dest, IRQ_TWDOG_INTID,
+					    enable, 0);
+
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+}
+
+static void enable_trusted_wdog_interrupt(ffa_vm_id_t source, ffa_vm_id_t dest)
+{
+	configure_trusted_wdog_interrupt(source, dest, true);
+}
+
+static void disable_trusted_wdog_interrupt(ffa_vm_id_t source, ffa_vm_id_t dest)
+{
+	configure_trusted_wdog_interrupt(source, dest, false);
+}
+
+static void enable_trigger_trusted_wdog_timer(ffa_vm_id_t own_id,
+					      ffa_vm_id_t receiver_id,
+					      uint32_t timer_ms)
+{
+	struct ffa_value res;
+
+	/* Enable trusted watchdog interrupt as vIRQ in the secure side. */
+	enable_trusted_wdog_interrupt(own_id, receiver_id);
+
+	res = sp_twdog_map_cmd_send(own_id, receiver_id);
+
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+
+	/*
+	 * Send a message to the SP through direct messaging requesting it to
+	 * start the trusted watchdog timer.
+	 */
+	res = sp_twdog_cmd_send(own_id, receiver_id, timer_ms);
+
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+}
+
+static void check_and_disable_trusted_wdog_timer(ffa_vm_id_t own_id,
+						 ffa_vm_id_t receiver_id)
+{
+	struct ffa_value res;
+
+	/* Check for the last serviced secure virtual interrupt. */
+	res = sp_get_last_interrupt_cmd_send(own_id, receiver_id);
+
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+
+	/* Make sure Trusted Watchdog timer interrupt was serviced. */
+	EXPECT_EQ(sp_resp_value(res), IRQ_TWDOG_INTID);
+
+	/* Disable Trusted Watchdog interrupt. */
+	disable_trusted_wdog_interrupt(own_id, receiver_id);
+}
+
+/*
+ * Test secure interrupt handling while the Secure Partition is in RUNNING
+ * state.
+ */
+TEST(secure_interrupts, sp_running)
+{
+	struct ffa_value res;
+	ffa_vm_id_t own_id = hf_vm_get_id();
+	struct ffa_partition_info *service2_info = service2();
+	const ffa_vm_id_t receiver_id = service2_info->vm_id;
+
+	enable_trigger_trusted_wdog_timer(own_id, receiver_id, 400);
+
+	/* Send request to the SP to sleep. */
+	res = sp_sleep_cmd_send(own_id, receiver_id, SP_SLEEP_TIME);
+
+	/*
+	 * Secure interrupt should trigger during this time, SP will handle the
+	 * trusted watchdog timer interrupt.
+	 */
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+
+	/* Make sure elapsed time not less than sleep time. */
+	EXPECT_GE(sp_resp_value(res), SP_SLEEP_TIME);
+
+	check_and_disable_trusted_wdog_timer(own_id, receiver_id);
+}