feat(interrupts): add support for handling managed exit through vIRQ

An SP could specify, through its partition manifest, that the
preferred signaling mechanism for it to handle managed exit is
vIRQ instead of the default choice (vFIQ).

Hence, separate the vIRQ and vFIQ handlers and add support for
identifying the source of the direct message request for the current
endpoint to send the managed exit response.

Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Change-Id: I06d6d81232de58779f81f40d4c6d2a96df0da27a
diff --git a/spm/cactus/aarch64/cactus_exceptions.S b/spm/cactus/aarch64/cactus_exceptions.S
index 9b024f8..06df31c 100644
--- a/spm/cactus/aarch64/cactus_exceptions.S
+++ b/spm/cactus/aarch64/cactus_exceptions.S
@@ -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
  */
@@ -18,6 +18,15 @@
 	end_vector_entry \name
 .endm
 
+.macro interrupt_vector _type
+	sub	sp, sp, #0x100
+	save_gp_regs
+	bl	cactus_interrupt_handler_\_type
+	restore_gp_regs
+	add	sp, sp, #0x100
+	eret
+.endm
+
 vector_base cactus_vector
 
 	/*
@@ -36,11 +45,11 @@
 end_vector_entry sync_spx
 
 vector_entry irq_spx
-	b	interrupt_vector_entry
+	b	irq_vector_entry
 end_vector_entry irq_spx
 
 vector_entry fiq_spx
-	b	interrupt_vector_entry
+	b	fiq_vector_entry
 end_vector_entry fiq_spx
 
 unhandled_exception serr_spx
@@ -116,14 +125,13 @@
 	eret
 endfunc sync_exception_vector_entry
 
-func interrupt_vector_entry
-	sub	sp, sp, #0x100
-	save_gp_regs
-	bl	cactus_interrupt_handler
-	restore_gp_regs
-	add	sp, sp, #0x100
-	eret
-endfunc interrupt_vector_entry
+func irq_vector_entry
+	interrupt_vector irq
+endfunc irq_vector_entry
+
+func fiq_vector_entry
+	interrupt_vector fiq
+endfunc fiq_vector_entry
 
 func crash_dump
 	/* Save general-purpose registers on the stack. */
diff --git a/spm/cactus/cactus_interrupt.c b/spm/cactus/cactus_interrupt.c
index e08c4dd..35fdf30 100644
--- a/spm/cactus/cactus_interrupt.c
+++ b/spm/cactus/cactus_interrupt.c
@@ -21,6 +21,7 @@
 extern void notification_pending_interrupt_handler(void);
 
 extern ffa_id_t g_ffa_id;
+extern ffa_id_t g_dir_req_source_id;
 static uint32_t managed_exit_interrupt_id;
 
 /* Secure virtual interrupt that was last handled by Cactus SP. */
@@ -44,45 +45,10 @@
 	     managed_exit_interrupt_id);
 }
 
-void cactus_interrupt_handler(void)
+static void post_interrupt_handler(uint32_t intid)
 {
-	uint32_t intid = spm_interrupt_get();
 	unsigned int core_pos = get_current_core_id();
 
-	switch (intid) {
-	case MANAGED_EXIT_INTERRUPT_ID:
-		/*
-		 * A secure partition performs its housekeeping and sends a
-		 * direct response to signal interrupt completion.
-		 * This is a pure virtual interrupt, no need for deactivation.
-		 */
-		cactus_response(g_ffa_id, HYP_ID, MANAGED_EXIT_INTERRUPT_ID);
-		break;
-	case IRQ_TWDOG_INTID:
-		/*
-		 * Interrupt triggered due to Trusted watchdog timer expiry.
-		 * Clear the interrupt and stop the timer.
-		 */
-		VERBOSE("Trusted WatchDog timer stopped\n");
-		sp805_twdog_stop();
-
-		/* Perform secure interrupt de-activation. */
-		spm_interrupt_deactivate(intid);
-
-		break;
-	case NOTIFICATION_PENDING_INTERRUPT_INTID:
-		notification_pending_interrupt_handler();
-		break;
-	default:
-		/*
-		 * Currently the only source of secure interrupt is Trusted
-		 * Watchdog timer.
-		 */
-		ERROR("%s: Interrupt ID %x not handled!\n", __func__,
-			 intid);
-		panic();
-	}
-
 	last_serviced_interrupt[core_pos] = intid;
 
 	/* Invoke the tail end handler registered by the SP. */
@@ -92,3 +58,71 @@
 	}
 	spin_unlock(&sp_handler_lock[intid]);
 }
+
+void cactus_interrupt_handler_irq(void)
+{
+	uint32_t intid = spm_interrupt_get();
+
+	if (intid == managed_exit_interrupt_id) {
+		/*
+		 * A secure partition performs its housekeeping and
+		 * sends a direct response to signal interrupt
+		 * completion. This is a pure virtual interrupt, no
+		 * need for deactivation.
+		 */
+		VERBOSE("vIRQ: Sending ME response to %x\n",
+			g_dir_req_source_id);
+		cactus_response(g_ffa_id, g_dir_req_source_id,
+				managed_exit_interrupt_id);
+	} else {
+		switch (intid) {
+		case IRQ_TWDOG_INTID:
+			/*
+			 * Interrupt triggered due to Trusted watchdog timer expiry.
+			 * Clear the interrupt and stop the timer.
+			 */
+			VERBOSE("Trusted WatchDog timer stopped\n");
+			sp805_twdog_stop();
+
+			/* Perform secure interrupt de-activation. */
+			spm_interrupt_deactivate(intid);
+
+			break;
+		case NOTIFICATION_PENDING_INTERRUPT_INTID:
+			notification_pending_interrupt_handler();
+			break;
+		default:
+			ERROR("%s: Interrupt ID %x not handled!\n", __func__,
+				 intid);
+			panic();
+			break;
+		}
+	}
+	post_interrupt_handler(intid);
+}
+
+void cactus_interrupt_handler_fiq(void)
+{
+	uint32_t intid = spm_interrupt_get();
+
+	switch (intid) {
+	case MANAGED_EXIT_INTERRUPT_ID:
+		/*
+		 * A secure partition performs its housekeeping and sends a
+		 * direct response to signal interrupt completion.
+		 * This is a pure virtual interrupt, no need for deactivation.
+		 */
+		VERBOSE("vFIQ: Sending ME response to %x\n",
+			g_dir_req_source_id);
+		cactus_response(g_ffa_id, g_dir_req_source_id,
+				MANAGED_EXIT_INTERRUPT_ID);
+		break;
+	default:
+		/*
+		 * Currently only managed exit interrupt is supported by vFIQ.
+		 */
+		panic();
+		break;
+	}
+	post_interrupt_handler(intid);
+}
diff --git a/spm/cactus/cactus_tests/cactus_message_loop.c b/spm/cactus/cactus_tests/cactus_message_loop.c
index 01ea32f..e56e51e 100644
--- a/spm/cactus/cactus_tests/cactus_message_loop.c
+++ b/spm/cactus/cactus_tests/cactus_message_loop.c
@@ -31,6 +31,9 @@
 		smc_ret.arg3, smc_ret.arg4, smc_ret.arg5, 		\
 		smc_ret.arg6, smc_ret.arg7)
 
+/* Global FFA_MSG_DIRECT_REQ source ID */
+ffa_id_t g_dir_req_source_id;
+
 /**
  * Traverses command table from section ".cactus_handler", searches for a
  * registered command and invokes the respective handler.
@@ -49,6 +52,12 @@
 		return false;
 	}
 
+	/* Get the source of the Direct Request message. */
+	if (ffa_func_id(*cmd_args) == FFA_MSG_SEND_DIRECT_REQ_SMC32 ||
+	    ffa_func_id(*cmd_args) == FFA_MSG_SEND_DIRECT_REQ_SMC64) {
+		g_dir_req_source_id = ffa_dir_msg_source(*cmd_args);
+	}
+
 	PRINT_CMD((*cmd_args));
 
 	in_cmd = cactus_get_cmd(*cmd_args);
diff --git a/spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts b/spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts
index 856be85..b7632da 100644
--- a/spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts
+++ b/spm/cactus/plat/arm/fvp/fdts/cactus-tertiary.dts
@@ -30,6 +30,7 @@
 	notification-support;
 	messaging-method = <3>; /* Direct messaging only */
 	managed-exit; /* Managed exit is supported */
+	managed-exit-virq;
 
 	memory-regions {
 		compatible = "arm,ffa-manifest-memory-regions";