test: SP can yield cycles while handling secure interrupt

This patch adds a new command to program SP to yield cycles
while handling secure interrupt.

A detailed description of the test is provided in the comments
within the test files.

Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Change-Id: I284aec6eff79332a8fd8090116f3d4c091144854
diff --git a/test/vmapi/ffa_secure_partitions/secure_interrupts.c b/test/vmapi/ffa_secure_partitions/secure_interrupts.c
index 319a9c5..fb48bbc 100644
--- a/test/vmapi/ffa_secure_partitions/secure_interrupts.c
+++ b/test/vmapi/ffa_secure_partitions/secure_interrupts.c
@@ -291,3 +291,52 @@
 	 */
 	check_and_disable_trusted_wdog_timer(own_id, target_id);
 }
+
+/*
+ * Test that an SP can attempt to yield CPU cycles while handling secure
+ * interrupt by invoking FFA_YIELD.
+ */
+TEST(secure_interrupts, sp_yield_sec_interrupt_handling)
+{
+	struct ffa_value res;
+	ffa_vm_id_t own_id = hf_vm_get_id();
+	struct mailbox_buffers mb = set_up_mailbox();
+	struct ffa_partition_info *service2_info = service2(mb.recv);
+	const ffa_vm_id_t receiver_id = service2_info->vm_id;
+	uint64_t time1;
+	volatile uint64_t time_lapsed;
+	uint64_t timer_freq = read_msr(cntfrq_el0);
+
+	/*
+	 * Send command to SP asking it attempt to yield cycles while handling
+	 * secure interrupt.
+	 */
+	res = sp_yield_secure_interrupt_handling_cmd_send(own_id, receiver_id,
+							  true);
+
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+
+	enable_trigger_trusted_wdog_timer(own_id, receiver_id, 75);
+	time1 = syscounter_read();
+
+	/*
+	 * Sleep for 100ms. This ensures secure wdog timer triggers
+	 * during this time. SP starts handling secure interrupt but attempts
+	 * to yields cycles. However, SPMC just resumes the SP to complete
+	 * interrupt handling.
+	 */
+	waitms(100);
+
+	/* Lapsed time should be at least equal to sleep time. */
+	time_lapsed = ((syscounter_read() - time1) * 1000) / timer_freq;
+
+	EXPECT_GE(time_lapsed, 100);
+
+	res = sp_yield_secure_interrupt_handling_cmd_send(own_id, receiver_id,
+							  false);
+
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+	check_and_disable_trusted_wdog_timer(own_id, receiver_id);
+}
diff --git a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/el0/sp_helpers.c b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/el0/sp_helpers.c
index d5a1e65..c610d97 100644
--- a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/el0/sp_helpers.c
+++ b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/el0/sp_helpers.c
@@ -16,6 +16,8 @@
 
 #define ITERATIONS_PER_MS 15000
 
+extern bool yield_while_handling_sec_interrupt;
+
 uint64_t sp_sleep_active_wait(uint32_t ms)
 {
 	sp_wait_loop(ms * ITERATIONS_PER_MS);
@@ -49,6 +51,15 @@
 
 	/* Perform secure interrupt de-activation. */
 	ASSERT_EQ(hf_interrupt_deactivate(intid), 0);
+
+	if (yield_while_handling_sec_interrupt) {
+		struct ffa_value ret;
+		HFTEST_LOG("Yield cycles while handling secure interrupt");
+		ret = ffa_yield();
+
+		ASSERT_EQ(ret.func, FFA_SUCCESS_32);
+		HFTEST_LOG("Resuming secure interrupt handling");
+	}
 	exception_handler_set_last_interrupt(intid);
 	return ffa_msg_wait();
 }
diff --git a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/inc/partition_services.h b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/inc/partition_services.h
index 18dd985..e94b98c 100644
--- a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/inc/partition_services.h
+++ b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/inc/partition_services.h
@@ -449,3 +449,20 @@
 }
 
 struct ffa_value sp_check_partition_info_get_regs_cmd(ffa_vm_id_t test_source);
+
+/**
+ * Command to request an SP to yield while handling a secure interrupt.
+ * The command id is the hex representaton of the string "YSIH".
+ */
+#define SP_YIELD_SEC_INTERRUPT_HANDLING_CMD 0x59534948U
+
+static inline struct ffa_value sp_yield_secure_interrupt_handling_cmd_send(
+	ffa_vm_id_t source, ffa_vm_id_t dest, bool yield)
+{
+	return ffa_msg_send_direct_req(source, dest,
+				       SP_YIELD_SEC_INTERRUPT_HANDLING_CMD,
+				       yield, 0, 0, 0);
+}
+
+struct ffa_value sp_yield_secure_interrupt_handling_cmd(ffa_vm_id_t source,
+							bool yield);
diff --git a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/message_loop.c b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/message_loop.c
index 4c62889..1b090bf 100644
--- a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/message_loop.c
+++ b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/message_loop.c
@@ -86,6 +86,10 @@
 	case SP_CHECK_PARTITION_INFO_GET_REGS_CMD:
 		res = sp_check_partition_info_get_regs_cmd(ffa_sender(res));
 		break;
+	case SP_YIELD_SEC_INTERRUPT_HANDLING_CMD:
+		res = sp_yield_secure_interrupt_handling_cmd(ffa_sender(res),
+							     res.arg4);
+		break;
 	default:
 		HFTEST_LOG_FAILURE();
 		HFTEST_LOG(HFTEST_LOG_INDENT
diff --git a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/secure_interrupts.c b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/secure_interrupts.c
index 9e181b3..2cd05d3 100644
--- a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/secure_interrupts.c
+++ b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/secure_interrupts.c
@@ -23,6 +23,8 @@
 #define PLAT_ARM_TWDOG_BASE 0x2a490000
 #define PLAT_ARM_TWDOG_SIZE 0x20000
 
+bool yield_while_handling_sec_interrupt = false;
+
 static void send_managed_exit_response(ffa_vm_id_t dir_req_source_id)
 {
 	struct ffa_value ffa_ret;
@@ -75,6 +77,17 @@
 
 		/* Perform secure interrupt de-activation. */
 		ASSERT_EQ(hf_interrupt_deactivate(intid), 0);
+
+		if (yield_while_handling_sec_interrupt) {
+			struct ffa_value ret;
+			HFTEST_LOG(
+				"Yield cycles while handling secure interrupt");
+			ret = ffa_yield();
+
+			ASSERT_EQ(ret.func, FFA_SUCCESS_32);
+			HFTEST_LOG("Resuming secure interrupt handling");
+		}
+
 		exception_handler_set_last_interrupt(intid);
 	}
 }
@@ -227,3 +240,12 @@
 
 	return sp_success(own_id, source, 0);
 }
+
+struct ffa_value sp_yield_secure_interrupt_handling_cmd(ffa_vm_id_t source,
+							bool yield)
+{
+	ffa_vm_id_t own_id = hf_vm_get_id();
+
+	yield_while_handling_sec_interrupt = yield;
+	return sp_success(own_id, source, 0);
+}