test: arch timer in nwd is honored across world switch

This patch introduces a test to ensure that the functionality of arch
(EL1 physical) timer configured by NWd endpoint, such as an hypervisor,
is not corrupted by SPMC when an SP also configures the arch timer for
its own use.

Also, necessary helpers and utilities to create the test scenario have
been added.

Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Change-Id: I1cfd1e1117412b2b23a57af30064c41dc2e66e0b
diff --git a/spm/cactus/cactus.mk b/spm/cactus/cactus.mk
index 0fa0ab5..b50975c 100644
--- a/spm/cactus/cactus.mk
+++ b/spm/cactus/cactus.mk
@@ -57,6 +57,7 @@
 		cactus_test_memory_sharing.c		\
 		cactus_tests_smmuv3.c			\
 		cactus_test_notifications.c		\
+		cactus_test_timer.c			\
 	)
 
 # TODO: Remove dependency on TFTF files.
@@ -66,7 +67,8 @@
 	tftf/tests/runtime_services/secure_service/${ARCH}/ffa_arch_helpers.S \
 	tftf/tests/runtime_services/secure_service/ffa_helpers.c 	\
 	tftf/tests/runtime_services/secure_service/spm_common.c		\
-	tftf/framework/${ARCH}/exception_report.c
+	tftf/framework/${ARCH}/exception_report.c			\
+	lib/delay/delay.c
 
 CACTUS_SOURCES	+= 	drivers/arm/pl011/${ARCH}/pl011_console.S	\
 			drivers/arm/sp805/sp805.c			\
diff --git a/spm/cactus/cactus_interrupt.c b/spm/cactus/cactus_interrupt.c
index 0a9035f..d0c15a5 100644
--- a/spm/cactus/cactus_interrupt.c
+++ b/spm/cactus/cactus_interrupt.c
@@ -89,18 +89,29 @@
 	VERBOSE("Resuming the suspended command\n");
 }
 
+static void timer_interrupt_handler(void)
+{
+	/* Disable the EL1 physical arch timer. */
+	write_cntp_ctl_el0(0);
+
+	spm_interrupt_deactivate(TIMER_VIRTUAL_INTID);
+	NOTICE("serviced el1 physical timer\n");
+}
+
 void register_maintenance_interrupt_handlers(void)
 {
 	sp_register_interrupt_handler(send_managed_exit_response,
 		managed_exit_interrupt_id);
 	sp_register_interrupt_handler(notification_pending_interrupt_handler,
 		NOTIFICATION_PENDING_INTERRUPT_INTID);
+	sp_register_interrupt_handler(timer_interrupt_handler,
+		TIMER_VIRTUAL_INTID);
 }
 
 void cactus_interrupt_handler_irq(void)
 {
 	uint32_t intid = spm_interrupt_get();
-	unsigned int core_pos = get_current_core_id();
+	unsigned int core_pos = spm_get_my_core_pos();
 
 	last_serviced_interrupt[core_pos] = intid;
 
@@ -118,7 +129,7 @@
 void cactus_interrupt_handler_fiq(void)
 {
 	uint32_t intid = spm_interrupt_get();
-	unsigned int core_pos = get_current_core_id();
+	unsigned int core_pos = spm_get_my_core_pos();
 
 	last_serviced_interrupt[core_pos] = intid;
 
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index b608d7b..40f7618 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -288,6 +288,12 @@
 	enable_irq();
 	enable_fiq();
 
+	/* Disable the arch timer at boot. */
+	write_cntp_ctl_el0(0);
+
+	/* Enable the arch timer virtual interrupt. */
+	spm_interrupt_enable(TIMER_VIRTUAL_INTID, true, 0);
+
 	if (primary_cold_boot == false) {
 		goto msg_loop;
 	}
diff --git a/spm/cactus/cactus_tests/cactus_test_interrupts.c b/spm/cactus/cactus_tests/cactus_test_interrupts.c
index c589119..0ae5011 100644
--- a/spm/cactus/cactus_tests/cactus_test_interrupts.c
+++ b/spm/cactus/cactus_tests/cactus_test_interrupts.c
@@ -224,7 +224,7 @@
 
 CACTUS_CMD_HANDLER(interrupt_serviced_cmd, CACTUS_LAST_INTERRUPT_SERVICED_CMD)
 {
-	unsigned int core_pos = get_current_core_id();
+	unsigned int core_pos = spm_get_my_core_pos();
 
 	return cactus_response(ffa_dir_msg_dest(*args),
 			       ffa_dir_msg_source(*args),
diff --git a/spm/cactus/cactus_tests/cactus_test_timer.c b/spm/cactus/cactus_tests/cactus_test_timer.c
new file mode 100644
index 0000000..6c8af0c
--- /dev/null
+++ b/spm/cactus/cactus_tests/cactus_test_timer.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "cactus_message_loop.h"
+#include "cactus_test_cmds.h"
+#include "debug.h"
+
+uint32_t ms_to_ticks(uint64_t ms)
+{
+	return ms * read_cntfrq_el0() / 1000;
+}
+
+CACTUS_CMD_HANDLER(set_virtual_timer, CACTUS_SET_ARCH_TIMER_CMD)
+{
+	uint64_t deadline_ms = cactus_get_timer_deadline(*args);
+	uint64_t wait_time = cactus_get_timer_wait_time(*args);
+	uint32_t ticks = ms_to_ticks(deadline_ms);
+
+	write_cntp_ctl_el0(0);
+	write_cntp_tval_el0(ticks);
+	write_cntp_ctl_el0(1);
+
+	if (wait_time != 0U) {
+		waitms(wait_time);
+	}
+
+	return cactus_response(ffa_dir_msg_dest(*args),
+			       ffa_dir_msg_source(*args),
+			       CACTUS_SUCCESS);
+}