Merge "fix: spurious error log message with mem share test"
diff --git a/include/runtime_services/cactus_test_cmds.h b/include/runtime_services/cactus_test_cmds.h
index 3bffb7b..435d270 100644
--- a/include/runtime_services/cactus_test_cmds.h
+++ b/include/runtime_services/cactus_test_cmds.h
@@ -318,6 +318,29 @@
 }
 
 /**
+ * Command to request cactus to sleep for half the given time in ms, trigger
+ * trusted watchdog timer and then sleep again for another half the given time.
+ *
+ * The sender of this command expects to receive CACTUS_SUCCESS if the requested
+ * echo interaction happened successfully, or CACTUS_ERROR otherwise.
+ */
+#define CACTUS_SLEEP_TRIGGER_TWDOG_CMD (CACTUS_SLEEP_CMD + 2)
+
+static inline smc_ret_values cactus_sleep_trigger_wdog_cmd(
+	ffa_id_t source, ffa_id_t dest, uint32_t sleep_time,
+	uint64_t wdog_time)
+{
+	return cactus_send_cmd(source, dest, CACTUS_SLEEP_TRIGGER_TWDOG_CMD, sleep_time,
+			       wdog_time, 0, 0);
+}
+
+
+static inline uint32_t cactus_get_wdog_trigger_duration(smc_ret_values ret)
+{
+	return (uint32_t)ret.ret5;
+}
+
+/**
  * Command to request cactus to enable/disable an interrupt
  *
  * The command id is the hex representation of string "intr"
@@ -537,4 +560,17 @@
 	return (uint32_t)ret.ret4;
 }
 
+/**
+ * Request SP to return the last serviced secure virtual interrupt.
+ *
+ * The command id is the hex representaton of the string "vINT"
+ */
+#define CACTUS_LAST_INTERRUPT_SERVICED_CMD U(0x76494e54)
+
+static inline smc_ret_values cactus_get_last_interrupt_cmd(
+	ffa_id_t source, ffa_id_t dest)
+{
+	return cactus_send_cmd(source, dest, CACTUS_LAST_INTERRUPT_SERVICED_CMD,
+				 0, 0, 0, 0);
+}
 #endif
diff --git a/spm/cactus/cactus_interrupt.c b/spm/cactus/cactus_interrupt.c
index ef3d5cc..2305b01 100644
--- a/spm/cactus/cactus_interrupt.c
+++ b/spm/cactus/cactus_interrupt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -22,9 +22,15 @@
 
 extern ffa_id_t g_ffa_id;
 
+/* Secure virtual interrupt that was last handled by Cactus SP. */
+uint32_t last_serviced_interrupt[PLATFORM_CORE_COUNT];
+
+extern spinlock_t sp_handler_lock[NUM_VINT_ID];
+
 void cactus_interrupt_handler(void)
 {
 	uint32_t intid = spm_interrupt_get();
+	unsigned int core_pos = get_current_core_id();
 
 	switch (intid) {
 	case MANAGED_EXIT_INTERRUPT_ID:
@@ -59,4 +65,13 @@
 			 intid);
 		panic();
 	}
+
+	last_serviced_interrupt[core_pos] = intid;
+
+	/* Invoke the tail end handler registered by the SP. */
+	spin_lock(&sp_handler_lock[intid]);
+	if (sp_interrupt_tail_end_handler[intid]) {
+		sp_interrupt_tail_end_handler[intid]();
+	}
+	spin_unlock(&sp_handler_lock[intid]);
 }
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index 58186d1..dd15d97 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -206,6 +206,9 @@
 
 		/* Configure and enable Stage-1 MMU, enable D-Cache */
 		cactus_plat_configure_mmu(ffa_id);
+
+		/* Initialize locks for tail end interrupt handler */
+		sp_handler_spin_lock_init();
 	}
 
 	/*
diff --git a/spm/cactus/cactus_tests/cactus_test_interrupts.c b/spm/cactus/cactus_tests/cactus_test_interrupts.c
index ced5dca..dc64512 100644
--- a/spm/cactus/cactus_tests/cactus_test_interrupts.c
+++ b/spm/cactus/cactus_tests/cactus_test_interrupts.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,6 +14,16 @@
 
 #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 void sec_wdog_interrupt_handled(void)
+{
+	expect(flag_set, 0);
+	flag_set = 1;
+}
+
 CACTUS_CMD_HANDLER(sleep_cmd, CACTUS_SLEEP_CMD)
 {
 	uint64_t time_lapsed;
@@ -101,3 +111,70 @@
 
 	return cactus_success_resp(vm_id, source, time_ms);
 }
+
+bool handle_twdog_interrupt_sp_sleep(uint32_t sleep_time, uint64_t *time_lapsed)
+{
+	sp_register_interrupt_tail_end_handler(sec_wdog_interrupt_handled,
+						IRQ_TWDOG_INTID);
+	*time_lapsed += sp_sleep_elapsed_time(sleep_time);
+
+	if (flag_set == 0) {
+		return false;
+	}
+
+	/* Reset the flag and unregister the handler. */
+	flag_set = 0;
+	sp_unregister_interrupt_tail_end_handler(IRQ_TWDOG_INTID);
+
+	return true;
+}
+
+CACTUS_CMD_HANDLER(sleep_twdog_cmd, CACTUS_SLEEP_TRIGGER_TWDOG_CMD)
+{
+	uint64_t time_lapsed = 0;
+	uint32_t sleep_time = cactus_get_sleep_time(*args) / 2;
+	uint64_t time_ms = cactus_get_wdog_trigger_duration(*args);
+
+	VERBOSE("Request to sleep %x for %ums.\n", ffa_dir_msg_dest(*args),
+		sleep_time);
+
+	if (!handle_twdog_interrupt_sp_sleep(sleep_time, &time_lapsed)) {
+		goto fail;
+	}
+
+	/* Lapsed time should be at least equal to sleep time. */
+	VERBOSE("Sleep complete: %llu\n", time_lapsed);
+
+	VERBOSE("Starting TWDOG: %llums\n", time_ms);
+	sp805_twdog_refresh();
+	sp805_twdog_start((time_ms * ARM_SP805_TWDG_CLK_HZ) / 1000);
+
+	VERBOSE("2nd Request to sleep %x for %ums.\n", ffa_dir_msg_dest(*args),
+		sleep_time);
+
+	if (!handle_twdog_interrupt_sp_sleep(sleep_time, &time_lapsed)) {
+		goto fail;
+	}
+
+	/* Lapsed time should be at least equal to sleep time. */
+	VERBOSE("2nd Sleep complete: %llu\n", time_lapsed);
+
+	return cactus_response(ffa_dir_msg_dest(*args),
+			       ffa_dir_msg_source(*args),
+			       time_lapsed);
+fail:
+	/* Test failed. */
+	ERROR("Watchdog interrupt not handled\n");
+	return cactus_error_resp(ffa_dir_msg_dest(*args),
+				 ffa_dir_msg_source(*args),
+				 CACTUS_ERROR_TEST);
+}
+
+CACTUS_CMD_HANDLER(interrupt_serviced_cmd, CACTUS_LAST_INTERRUPT_SERVICED_CMD)
+{
+	unsigned int core_pos = get_current_core_id();
+
+	return cactus_response(ffa_dir_msg_dest(*args),
+			       ffa_dir_msg_source(*args),
+			       last_serviced_interrupt[core_pos]);
+}
diff --git a/spm/common/sp_helpers.c b/spm/common/sp_helpers.c
index 77031f8..448084f 100644
--- a/spm/common/sp_helpers.c
+++ b/spm/common/sp_helpers.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -13,6 +13,10 @@
 
 #include "sp_helpers.h"
 
+spinlock_t sp_handler_lock[NUM_VINT_ID];
+
+void (*sp_interrupt_tail_end_handler[NUM_VINT_ID])(void);
+
 uintptr_t bound_rand(uintptr_t min, uintptr_t max)
 {
 	/*
@@ -80,3 +84,35 @@
 {
 	(void)sp_sleep_elapsed_time(ms);
 }
+
+void sp_handler_spin_lock_init(void)
+{
+	for (uint32_t i = 0; i < NUM_VINT_ID; i++) {
+		init_spinlock(&sp_handler_lock[i]);
+	}
+}
+
+void sp_register_interrupt_tail_end_handler(void (*handler)(void),
+			uint32_t interrupt_id)
+{
+	if (interrupt_id >= NUM_VINT_ID) {
+		ERROR("Cannot register handler for interrupt %u\n", interrupt_id);
+		panic();
+	}
+
+	spin_lock(&sp_handler_lock[interrupt_id]);
+	sp_interrupt_tail_end_handler[interrupt_id] = handler;
+	spin_unlock(&sp_handler_lock[interrupt_id]);
+}
+
+void sp_unregister_interrupt_tail_end_handler(uint32_t interrupt_id)
+{
+	if (interrupt_id >= NUM_VINT_ID) {
+		ERROR("Cannot unregister handler for interrupt %u\n", interrupt_id);
+		panic();
+	}
+
+	spin_lock(&sp_handler_lock[interrupt_id]);
+	sp_interrupt_tail_end_handler[interrupt_id] = NULL;
+	spin_unlock(&sp_handler_lock[interrupt_id]);
+}
diff --git a/spm/common/sp_helpers.h b/spm/common/sp_helpers.h
index 6fe8ec0..ef60221 100644
--- a/spm/common/sp_helpers.h
+++ b/spm/common/sp_helpers.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,6 +10,10 @@
 #include <stdint.h>
 #include <tftf_lib.h>
 #include <spm_common.h>
+#include <spinlock.h>
+
+/* Currently, Hafnium/SPM supports only 64 virtual interrupt IDs. */
+#define NUM_VINT_ID	64
 
 typedef struct {
 	u_register_t fid;
@@ -62,4 +66,16 @@
 /* Sleep for at least 'ms' milliseconds. */
 void sp_sleep(uint32_t ms);
 
+void sp_handler_spin_lock_init(void);
+
+/* Handler invoked at the tail end of interrupt processing by SP. */
+extern void (*sp_interrupt_tail_end_handler[NUM_VINT_ID])(void);
+
+/* Register the handler. */
+void sp_register_interrupt_tail_end_handler(void (*handler)(void),
+						uint32_t interrupt_id);
+
+/* Un-register the handler. */
+void sp_unregister_interrupt_tail_end_handler(uint32_t interrupt_id);
+
 #endif /* SP_HELPERS_H */
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 6ff30f6..8ed590a 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, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -59,10 +59,11 @@
  * 1. Send a direct message request command to first Cactus SP to start the
  *    trusted watchdog timer.
  *
- * 2. Send a command to SP to sleep by executing a busy loop.
+ * 2. Send a command to SP to first sleep( by executing a busy loop), then
+ *    restart trusted watchdog timer and then sleep again.
  *
- * 3. While SP is running the busy loop, Secure interrupt should trigger during
- *    this time.
+ * 3. While SP is running the first busy loop, Secure interrupt should trigger
+ *    during this time.
  *
  * 4. The interrupt will be trapped to SPM as IRQ. SPM will inject the virtual
  *    IRQ to the first SP through vIRQ conduit and perform eret to resume
@@ -74,22 +75,25 @@
  * 6. Cactus SP will perform End-Of-Interrupt and resume execution in the busy
  *    loop.
  *
- * 7. Cactus SP will send a direct response message with the elapsed time back
+ * 7. Trusted watchdog timer will trigger once again followed by steps 4 to 6.
+ *
+ * 8. Cactus SP will send a direct response message with the elapsed time back
  *    to the normal world.
  *
- * 8. We make sure the time elapsed in the sleep routine by SP is not less than
+ * 9. We make sure the time elapsed in the sleep routine by SP is not less than
  *    the requested value.
  *
- * 9. For robustness of state transition checks, TFTF sends echo command using
- *    a direct request message.
+ * 10. TFTF sends a direct request message to SP to query the ID of last serviced
+ *     secure virtual interrupt.
  *
- * 10. Further, TFTF expects SP to return with a success value through a direct
- *    response message.
+ * 11. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ *     interrupt through a direct response message.
  *
- * 11. Test finishes successfully once the TFTF disables the trusted watchdog
+ * 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_sp_running(void)
 {
 	smc_ret_values ret_values;
@@ -109,7 +113,7 @@
 	}
 
 	/* Send request to first Cactus SP to sleep */
-	ret_values = cactus_sleep_cmd(SENDER, RECEIVER, SP_SLEEP_TIME);
+	ret_values = cactus_sleep_trigger_wdog_cmd(SENDER, RECEIVER, SP_SLEEP_TIME, 50);
 
 	/*
 	 * Secure interrupt should trigger during this time, Cactus
@@ -129,16 +133,18 @@
 		return TEST_RESULT_FAIL;
 	}
 
-	ret_values = cactus_echo_send_cmd(SENDER, RECEIVER, ECHO_VAL1);
+	/* 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 direct response for echo command\n");
+		ERROR("Expected a direct response for last serviced interrupt"
+			" command\n");
 		return TEST_RESULT_FAIL;
 	}
 
-	if (cactus_get_response(ret_values) != CACTUS_SUCCESS ||
-	    cactus_echo_get_val(ret_values) != ECHO_VAL1) {
-		ERROR("Echo Failed!\n");
+	/* 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;
 	}
 
@@ -179,11 +185,11 @@
  * 9. We make sure the time elapsed in the sleep routine is not less than
  *    the requested value.
  *
- * 10. For robustness of state transition checks, TFTF sends echo command using
- *    a direct request message.
+ * 10. TFTF sends a direct request message to SP to query the ID of last serviced
+ *     secure virtual interrupt.
  *
- * 11. Further, TFTF expects SP to return with a success value through a direct
- *    response message.
+ * 11. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ *     interrupt through a direct response message.
  *
  * 12. Test finishes successfully once the TFTF disables the trusted watchdog
  *     interrupt through a direct message request command.
@@ -231,16 +237,18 @@
 		return TEST_RESULT_FAIL;
 	}
 
-	ret_values = cactus_echo_send_cmd(SENDER, RECEIVER, ECHO_VAL1);
+	/* 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 direct response for echo command\n");
+		ERROR("Expected a direct response for last serviced interrupt"
+			" command\n");
 		return TEST_RESULT_FAIL;
 	}
 
-	if (cactus_get_response(ret_values) != CACTUS_SUCCESS ||
-	    cactus_echo_get_val(ret_values) != ECHO_VAL1) {
-		ERROR("Echo Failed!\n");
+	/* 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;
 	}
 
@@ -280,11 +288,11 @@
  * 8. First SP checks for the elapsed time and sends a direct response with
  *    a SUCCESS value back to tftf.
  *
- * 9. For robustness of state transition checks, TFTF sends echo command using
- *    a direct request message to first SP.
+ * 9. TFTF sends a direct request message to SP to query the ID of last serviced
+ *    secure virtual interrupt.
  *
- * 10. Further, TFTF expects SP to return with a success value through a direct
- *    response message.
+ * 10. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ *     interrupt through a direct response message.
  *
  * 11. Test finishes successfully once the TFTF disables the trusted watchdog
  *     interrupt through a direct message request command.
@@ -327,16 +335,18 @@
 		return TEST_RESULT_FAIL;
 	}
 
-	ret_values = cactus_echo_send_cmd(SENDER, RECEIVER, ECHO_VAL1);
+	/* 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 direct response for echo command\n");
+		ERROR("Expected a direct response for last serviced interrupt"
+			" command\n");
 		return TEST_RESULT_FAIL;
 	}
 
-	if (cactus_get_response(ret_values) != CACTUS_SUCCESS ||
-	    cactus_echo_get_val(ret_values) != ECHO_VAL1) {
-		ERROR("Echo Failed!\n");
+	/* 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;
 	}
 
@@ -378,11 +388,11 @@
  * 9. We make sure the time elapsed in the sleep routine by SP is not less than
  *    the requested value.
  *
- * 10. For robustness of state transition checks, TFTF sends echo command using
- *    a direct request message to both SPs.
+ * 10. TFTF sends a direct request message to SP to query the ID of last serviced
+ *     secure virtual interrupt.
  *
- * 11. Further, TFTF expects SP to return with a success value through a direct
- *    response message.
+ * 11. Further, TFTF expects SP to return the ID of Trusted Watchdog timer
+ *     interrupt through a direct response message.
  *
  * 12. Test finishes successfully once the TFTF disables the trusted watchdog
  *     interrupt through a direct message request command.
@@ -422,29 +432,18 @@
 		ERROR("Lapsed time less than requested sleep time\n");
 	}
 
-	ret_values = cactus_echo_send_cmd(SENDER, RECEIVER, ECHO_VAL1);
+	/* 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("Echo to SP1 Failed no response!\n");
+		ERROR("Expected a direct response for last serviced interrupt"
+			" command\n");
 		return TEST_RESULT_FAIL;
 	}
 
-	if (cactus_get_response(ret_values) != CACTUS_SUCCESS ||
-	    cactus_echo_get_val(ret_values) != ECHO_VAL1) {
-		ERROR("Echo to SP1 Failed!\n");
-		return TEST_RESULT_FAIL;
-	}
-
-	ret_values = cactus_echo_send_cmd(SENDER, RECEIVER_2, ECHO_VAL1);
-
-	if (!is_ffa_direct_response(ret_values)) {
-		ERROR("Echo to SP2 Failed no response!\n");
-		return TEST_RESULT_FAIL;
-	}
-
-	if (cactus_get_response(ret_values) != CACTUS_SUCCESS ||
-	    cactus_echo_get_val(ret_values) != ECHO_VAL1) {
-		ERROR("Echo to SP2 Failed!\n");
+	/* 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;
 	}