feat(spmd): add support for FFA_EL3_INTR_HANDLE_32 ABI

When Group0 Secure interrupts in secure world get trapped to S-EL2
SPMC, FFA_EL3_INTR_HANDLE ABI is invoked by SPMC to delegate
interrupt handling to EL3 firmware (i.e., SPMD).

SPMD further delegates to platform handler which successfully handles
the Group0 secure interrupt before returning control to SPMC.

Change-Id: I8cc0fec20803b96c81582910ad2668e38b167fb8
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c
index e34d394..80b506b 100644
--- a/services/std_svc/spmd/spmd_main.c
+++ b/services/std_svc/spmd/spmd_main.c
@@ -282,6 +282,41 @@
 	return 0U;
 }
 
+/*******************************************************************************
+ * spmd_handle_group0_intr_swd
+ * SPMC delegates handling of Group0 secure interrupt to EL3 firmware using
+ * FFA_EL3_INTR_HANDLE SMC call. Further, SPMD delegates the handling of the
+ * interrupt to the platform handler, and returns only upon successfully
+ * handling the Group0 interrupt.
+ ******************************************************************************/
+static uint64_t spmd_handle_group0_intr_swd(void *handle)
+{
+	uint32_t intid;
+
+	/* Sanity check the pointer to this cpu's context */
+	assert(handle == cm_get_context(SECURE));
+
+	assert(plat_ic_get_pending_interrupt_type() == INTR_TYPE_EL3);
+
+	intid = plat_ic_get_pending_interrupt_id();
+
+	/*
+	 * TODO: Currently due to a limitation in SPMD implementation, the
+	 * platform handler is expected to not delegate handling to NWd while
+	 * processing Group0 secure interrupt.
+	 */
+	if (plat_spmd_handle_group0_interrupt(intid) < 0) {
+		/* Group0 interrupt was not handled by the platform. */
+		ERROR("Group0 interrupt %u not handled\n", intid);
+		panic();
+	}
+
+	/* Return success. */
+	SMC_RET8(handle, FFA_SUCCESS_SMC32, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+		 FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
+		 FFA_PARAM_MBZ);
+}
+
 #if ENABLE_RME && SPMD_SPM_AT_SEL2 && !RESET_TO_BL31
 static int spmd_dynamic_map_mem(uintptr_t base_addr, size_t size,
 				 unsigned int attr, uintptr_t *align_addr,
@@ -1132,6 +1167,12 @@
 					handle, flags);
 		break; /* Not reached */
 #endif
+	case FFA_EL3_INTR_HANDLE:
+		if (secure_origin) {
+			return spmd_handle_group0_intr_swd(handle);
+		} else {
+			return spmd_ffa_error_return(handle, FFA_ERROR_DENIED);
+		}
 	default:
 		WARN("SPM: Unsupported call 0x%08x\n", smc_fid);
 		return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);