feat(el3-runtime): introduce UNDEF injection to lower EL

For a feature to be used at lower ELs, EL3 generally needs to disable
the trap so that lower ELs can access the system registers associated
with the feature. Lower ELs generally check ID registers to dynamically
detect if a feature is present (in HW) or not while EL3 Firmware relies
statically on feature build macros to enable a feature.

If a lower EL accesses a system register for a feature that EL3 FW is
unaware of, EL3 traps the access and panics. This happens mostly with
EL2 but sometimes VMs can also cause EL3 panic.

To provide platforms with capability to mitigate this problem, UNDEF
injection support has been introduced which injects a synchronous
exception into the lower EL which is supposed to handle the
synchronous exception.

The current support is only provided for aarch64.

The implementation does the following on encountering sys reg trap

 - Get the target EL, which can be either EL2 or EL1
 - Update ELR_ELx with ELR_EL3, so that after UNDEF handling in lower EL
   control returns to original location.
 - ESR_ELx with EC_UNKNOWN
 - Update ELR_EL3 with vector address of sync exception handler with
   following possible causes
     - Current EL with SP0
     - Current EL with SPx
     - Lower EL using AArch64
 - Re-create SPSR_EL3 which will be used to generate PSTATE at ERET

Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
Change-Id: I1b7bf6c043ce7aec1ee4fc1121c389b490b7bfb7
diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S
index ed48311..962c362 100644
--- a/bl31/aarch64/runtime_exceptions.S
+++ b/bl31/aarch64/runtime_exceptions.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -476,21 +476,33 @@
 	bl	handle_sysreg_trap
 	/*
 	 * returns:
-	 *   -1: unhandled trap, panic
+	 *   -1: unhandled trap, UNDEF injection into lower EL
 	 *    0: handled trap, return to the trapping instruction (repeating it)
 	 *    1: handled trap, return to the next instruction
 	 */
 
 	tst	w0, w0
-	b.mi	elx_panic	/* negative return value: panic */
-	b.eq	1f		/* zero: do not change ELR_EL3 */
+	b.mi	2f	/* negative: undefined exception injection */
 
-	/* advance the PC to continue after the instruction */
+	b.eq	1f	/* zero: do not change ELR_EL3 */
+	/* positive: advance the PC to continue after the instruction */
 	ldr	x1, [x19, #CTX_EL3STATE_OFFSET + CTX_ELR_EL3]
 	add	x1, x1, #4
 	str	x1, [x19, #CTX_EL3STATE_OFFSET + CTX_ELR_EL3]
 1:
 	b	el3_exit
+2:
+	/*
+	 * UNDEF injection to lower EL, the support is only provided for lower
+	 * EL in AArch64 mode, for AArch32 mode it will do elx_panic as before.
+	 */
+	mrs	x0, spsr_el3
+	tst	x0, #(SPSR_M_MASK << SPSR_M_SHIFT)
+	b.ne	elx_panic
+	/* Pass context pointer as an argument to inject_undef64 */
+	mov	x0, x19
+	bl	inject_undef64
+	b	el3_exit
 
 smc_unknown:
 	/*