Merge "feat(mt8188): update INFRA IOMMU enable flow" into integration
diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S
index 614ea71..c9c3da9 100644
--- a/bl31/aarch64/runtime_exceptions.S
+++ b/bl31/aarch64/runtime_exceptions.S
@@ -10,6 +10,7 @@
 #include <asm_macros.S>
 #include <bl31/ea_handle.h>
 #include <bl31/interrupt_mgmt.h>
+#include <bl31/sync_handle.h>
 #include <common/runtime_svc.h>
 #include <context.h>
 #include <el3_common_macros.S>
@@ -191,7 +192,10 @@
 	b.eq	smc_handler32
 
 	cmp	x30, #EC_AARCH64_SMC
-	b.eq	smc_handler64
+	b.eq	sync_handler64
+
+	cmp	x30, #EC_AARCH64_SYS
+	b.eq	sync_handler64
 
 	/* Synchronous exceptions other than the above are assumed to be EA */
 	ldr	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
@@ -452,12 +456,12 @@
 	 * Note that x30 has been explicitly saved and can be used here
 	 * ---------------------------------------------------------------------
 	 */
-func smc_handler
+func sync_exception_handler
 smc_handler32:
 	/* Check whether aarch32 issued an SMC64 */
 	tbnz	x0, #FUNCID_CC_SHIFT, smc_prohibited
 
-smc_handler64:
+sync_handler64:
 	/* NOTE: The code below must preserve x0-x4 */
 
 	/*
@@ -504,6 +508,12 @@
 	/* Load SCR_EL3 */
 	mrs	x18, scr_el3
 
+	/* check for system register traps */
+	mrs	x16, esr_el3
+	ubfx	x17, x16, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+	cmp	x17, #EC_AARCH64_SYS
+	b.eq	sysreg_handler64
+
 	/* Clear flag register */
 	mov	x7, xzr
 
@@ -567,6 +577,32 @@
 #endif
 	blr	x15
 
+	b	el3_exit
+
+sysreg_handler64:
+	mov	x0, x16		/* ESR_EL3, containing syndrome information */
+	mov	x1, x6		/* lower EL's context */
+	mov	x19, x6		/* save context pointer for after the call */
+	mov	sp, x12		/* EL3 runtime stack, as loaded above */
+
+	/* int handle_sysreg_trap(uint64_t esr_el3, cpu_context_t *ctx); */
+	bl	handle_sysreg_trap
+	/*
+	 * returns:
+	 *   -1: unhandled trap, panic
+	 *    0: handled trap, return to the trapping instruction (repeating it)
+	 *    1: handled trap, return to the next instruction
+	 */
+
+	tst	w0, w0
+	b.mi	do_panic	/* negative return value: panic */
+	b.eq	1f		/* zero: do not change ELR_EL3 */
+
+	/* 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
 
 smc_unknown:
@@ -593,7 +629,7 @@
 	msr	spsel, #MODE_SP_ELX
 	no_ret	report_unhandled_exception
 #endif
-endfunc smc_handler
+endfunc sync_exception_handler
 
 	/* ---------------------------------------------------------------------
 	 * The following code handles exceptions caused by BRK instructions.
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index 4c93a55..ac15f9f 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -42,6 +42,7 @@
 				bl31/aarch64/ea_delegate.S			\
 				bl31/aarch64/runtime_exceptions.S		\
 				bl31/bl31_context_mgmt.c			\
+				bl31/bl31_traps.c				\
 				common/runtime_svc.c				\
 				lib/cpus/aarch64/dsu_helpers.S			\
 				plat/common/aarch64/platform_mp_stack.S		\
diff --git a/bl31/bl31_traps.c b/bl31/bl31_traps.c
new file mode 100644
index 0000000..b12185d
--- /dev/null
+++ b/bl31/bl31_traps.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Dispatch synchronous system register traps from lower ELs.
+ */
+
+#include <bl31/sync_handle.h>
+#include <context.h>
+
+int handle_sysreg_trap(uint64_t esr_el3, cpu_context_t *ctx)
+{
+	switch (esr_el3 & ISS_SYSREG_OPCODE_MASK) {
+#if ENABLE_FEAT_RNG_TRAP
+	case ISS_SYSREG_OPCODE_RNDR:
+	case ISS_SYSREG_OPCODE_RNDRRS:
+		return plat_handle_rng_trap(esr_el3, ctx);
+#endif
+	default:
+		return TRAP_RET_UNHANDLED;
+	}
+}
diff --git a/docs/getting_started/porting-guide.rst b/docs/getting_started/porting-guide.rst
index aa57e1d..d57345d 100644
--- a/docs/getting_started/porting-guide.rst
+++ b/docs/getting_started/porting-guide.rst
@@ -3396,6 +3396,39 @@
 The default implementation of this function calls
 ``report_unhandled_exception``.
 
+Function : plat_handle_rng_trap
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : uint64_t
+    Argument : cpu_context_t *
+    Return   : int
+
+This function is invoked by BL31's exception handler when there is a synchronous
+system register trap caused by access to the RNDR or RNDRRS registers. It allows
+platforms implementing ``FEAT_RNG_TRAP`` and enabling ``ENABLE_FEAT_RNG_TRAP`` to
+emulate those system registers by returing back some entropy to the lower EL.
+
+The first parameter (``uint64_t esr_el3``) contains the content of the ESR_EL3
+syndrome register, which encodes the instruction that was trapped. The interesting
+information in there is the target register (``get_sysreg_iss_rt()``).
+
+The second parameter (``cpu_context_t *ctx``) represents the CPU state in the
+lower exception level, at the time when the execution of the ``mrs`` instruction
+was trapped. Its content can be changed, to put the entropy into the target
+register.
+
+The return value indicates how to proceed:
+
+-  When returning ``TRAP_RET_UNHANDLED`` (-1), the machine will panic.
+-  When returning ``TRAP_RET_REPEAT`` (0), the exception handler will return
+   to the same instruction, so its execution will be repeated.
+-  When returning ``TRAP_RET_CONTINUE`` (1), the exception handler will return
+   to the next instruction.
+
+This function needs to be implemented by a platform if it enables FEAT_RNG_TRAP.
+
 Build flags
 -----------
 
diff --git a/drivers/auth/mbedtls/mbedtls_x509_parser.c b/drivers/auth/mbedtls/mbedtls_x509_parser.c
index 4b880d9..44b25ba 100644
--- a/drivers/auth/mbedtls/mbedtls_x509_parser.c
+++ b/drivers/auth/mbedtls/mbedtls_x509_parser.c
@@ -142,7 +142,7 @@
 	int ret, is_critical;
 	size_t len;
 	unsigned char *p, *end, *crt_end, *pk_end;
-	mbedtls_asn1_buf sig_alg1, sig_alg2;
+	mbedtls_asn1_buf sig_alg1;
 	/*
 	 * The unique ASN.1 DER encoding of [0] EXPLICIT INTEGER { v3(2} }.
 	 */
@@ -395,26 +395,15 @@
 	 *  -- end of TBSCertificate
 	 *
 	 *  signatureAlgorithm   AlgorithmIdentifier
+	 *  -- Does not need to be parsed.  Ensuring it is bitwise
+	 *  -- identical (including the tag!) with the first signature
+	 *  -- algorithm is sufficient.
 	 */
-	sig_alg2.p = p;
-	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
-				   MBEDTLS_ASN1_SEQUENCE);
-	if (ret != 0) {
-		return IMG_PARSER_ERR_FORMAT;
-	}
-	if ((end - p) < 1) {
-		return IMG_PARSER_ERR_FORMAT;
-	}
-	sig_alg2.len = (p + len) - sig_alg2.p;
-	p += len;
-
-	/* Compare both signature algorithms */
-	if (sig_alg1.len != sig_alg2.len) {
-		return IMG_PARSER_ERR_FORMAT;
-	}
-	if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) {
+	if ((sig_alg1.len >= (size_t)(end - p)) ||
+	    (0 != memcmp(sig_alg1.p, p, sig_alg1.len))) {
 		return IMG_PARSER_ERR_FORMAT;
 	}
+	p += sig_alg1.len;
 	memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg));
 
 	/*
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index f63e923..9e13c3d 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -1282,6 +1282,12 @@
 #define GCR_EL1			S3_0_C1_C0_6
 
 /*******************************************************************************
+ * Armv8.5 - Random Number Generator Registers
+ ******************************************************************************/
+#define RNDR			S3_3_C2_C4_0
+#define RNDRRS			S3_3_C2_C4_1
+
+/*******************************************************************************
  * FEAT_HCX - Extended Hypervisor Configuration Register
  ******************************************************************************/
 #define HCRX_EL2		S3_4_C1_C2_2
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 50a5ad4..fe9b5a5 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -546,8 +546,8 @@
 DEFINE_RENAME_SYSREG_RW_FUNCS(gcr_el1, GCR_EL1)
 
 /* Armv8.5 FEAT_RNG Registers */
-DEFINE_SYSREG_READ_FUNC(rndr)
-DEFINE_SYSREG_READ_FUNC(rndrrs)
+DEFINE_RENAME_SYSREG_READ_FUNC(rndr, RNDR)
+DEFINE_RENAME_SYSREG_READ_FUNC(rndrrs, RNDRRS)
 
 /* FEAT_HCX Register */
 DEFINE_RENAME_SYSREG_RW_FUNCS(hcrx_el2, HCRX_EL2)
diff --git a/include/bl31/sync_handle.h b/include/bl31/sync_handle.h
new file mode 100644
index 0000000..e211575
--- /dev/null
+++ b/include/bl31/sync_handle.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TRAP_HANDLE_H
+#define TRAP_HANDLE_H
+
+#include <stdbool.h>
+#include <context.h>
+
+#define ISS_SYSREG_OPCODE_MASK		0x3ffc1eUL
+#define ISS_SYSREG_REG_MASK		0x0003e0UL
+#define ISS_SYSREG_REG_SHIFT		5U
+#define ISS_SYSREG_DIRECTION_MASK	0x000001UL
+
+#define ISS_SYSREG_OPCODE_RNDR		0x30c808U
+#define ISS_SYSREG_OPCODE_RNDRRS	0x32c808U
+
+#define TRAP_RET_UNHANDLED		-1
+#define TRAP_RET_REPEAT			0
+#define TRAP_RET_CONTINUE		1
+
+#ifndef __ASSEMBLER__
+static inline unsigned int get_sysreg_iss_rt(uint64_t esr)
+{
+	return (esr & ISS_SYSREG_REG_MASK) >> ISS_SYSREG_REG_SHIFT;
+}
+
+static inline bool is_sysreg_iss_write(uint64_t esr)
+{
+	return !(esr & ISS_SYSREG_DIRECTION_MASK);
+}
+
+/**
+ * handle_sysreg_trap() - Handle AArch64 system register traps from lower ELs
+ * @esr_el3: The content of ESR_EL3, containing the trap syndrome information
+ * @ctx: Pointer to the lower EL context, containing saved registers
+ *
+ * Called by the exception handler when a synchronous trap identifies as a
+ * system register trap (EC=0x18). ESR contains the encoding of the op[x] and
+ * CRm/CRn fields, to identify the system register, and the target/source
+ * GPR plus the direction (MRS/MSR). The lower EL's context can be altered
+ * by the function, to inject back the result of the emulation.
+ *
+ * Return: indication how to proceed with the trap:
+ *   TRAP_RET_UNHANDLED(-1): trap is unhandled, trigger panic
+ *   TRAP_RET_REPEAT(0): trap was handled, return to the trapping instruction
+ *			 (repeating it)
+ *   TRAP_RET_CONTINUE(1): trap was handled, return to the next instruction
+ *		           (continuing after it)
+ */
+int handle_sysreg_trap(uint64_t esr_el3, cpu_context_t *ctx);
+
+/* Prototypes for system register emulation handlers provided by platforms. */
+int plat_handle_rng_trap(uint64_t esr_el3, cpu_context_t *ctx);
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/plat/arm/board/fvp/fvp_sync_traps.c b/plat/arm/board/fvp/fvp_sync_traps.c
new file mode 100644
index 0000000..91240f7
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_sync_traps.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2022, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file just contains demonstration code, to "handle" RNG traps.
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl31/sync_handle.h>
+#include <context.h>
+
+/*
+ * SCR_EL3.SCR_TRNDR_BIT also affects execution in EL3, so allow to disable
+ * the trap temporarily.
+ */
+static void enable_rng_trap(bool enable)
+{
+	uint64_t scr_el3 = read_scr_el3();
+
+	if (enable) {
+		scr_el3 |= SCR_TRNDR_BIT;
+	} else {
+		scr_el3 &= ~SCR_TRNDR_BIT;
+	}
+
+	write_scr_el3(scr_el3);
+	isb();
+}
+
+/*
+ * This emulation code here is not very meaningful: enabling the RNG
+ * trap typically happens for a reason, so just calling the actual
+ * hardware instructions might not be useful or even possible.
+ */
+int plat_handle_rng_trap(uint64_t esr_el3, cpu_context_t *ctx)
+{
+	/* extract the target register number from the exception syndrome */
+	unsigned int rt = get_sysreg_iss_rt(esr_el3);
+
+	/* ignore XZR accesses and writes to the register */
+	if (rt == 31 || is_sysreg_iss_write(esr_el3)) {
+		return TRAP_RET_CONTINUE;
+	}
+
+	enable_rng_trap(false);
+	if ((esr_el3 & ISS_SYSREG_OPCODE_MASK) == ISS_SYSREG_OPCODE_RNDR) {
+		ctx->gpregs_ctx.ctx_regs[rt] = read_rndr();
+	} else {
+		ctx->gpregs_ctx.ctx_regs[rt] = read_rndrrs();
+	}
+	enable_rng_trap(true);
+
+	/*
+	 * We successfully handled the trap, continue with the next
+	 * instruction.
+	 */
+	return TRAP_RET_CONTINUE;
+}
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 51ba035..f28a6ff 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -198,6 +198,10 @@
 				plat/arm/board/fvp/fvp_realm_attest_key.c
 endif
 
+ifeq (${ENABLE_FEAT_RNG_TRAP},1)
+BL31_SOURCES		+=	plat/arm/board/fvp/fvp_sync_traps.c
+endif
+
 ifeq (${BL2_AT_EL3},1)
 BL2_SOURCES		+=	plat/arm/board/fvp/${ARCH}/fvp_helpers.S	\
 				plat/arm/board/fvp/fvp_bl2_el3_setup.c		\
diff --git a/services/std_svc/trng/trng_entropy_pool.c b/services/std_svc/trng/trng_entropy_pool.c
index 30105b3..dd08c5e 100644
--- a/services/std_svc/trng/trng_entropy_pool.c
+++ b/services/std_svc/trng/trng_entropy_pool.c
@@ -66,7 +66,7 @@
 bool trng_pack_entropy(uint32_t nbits, uint64_t *out)
 {
 	bool ret = true;
-
+	uint32_t bits_to_discard = nbits;
 	spin_lock(&trng_pool_lock);
 
 	if (!trng_fill_entropy(nbits)) {
@@ -111,9 +111,66 @@
 		 *                   5 4 3 2 1 0 7 6
 		 *                  [e,e,e,e,e,e,e,e]
 		 */
-		out[word_i] = 0;
 		out[word_i] |= entropy[ENTROPY_WORD_INDEX(word_i)] >> rshift;
 
+		/**
+		 * Discarding the used/packed entropy bits from the respective
+		 * words, (word_i) and (word_i+1) as applicable.
+		 * In each iteration of the loop, we pack 64bits of entropy to
+		 * the output buffer. The bits are picked linearly starting from
+		 * 1st word (entropy[0]) till 4th word (entropy[3]) and then
+		 * rolls back (entropy[0]). Discarding of bits is managed
+		 * similarly.
+		 *
+		 * The following diagram illustrates the logic:
+		 *
+		 *          |---------entropy pool----------|
+		 * C var    |--(word_i + 1)-|----word_i-----|
+		 * bit idx  |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
+		 *          [e,e,e,e,e,e,e,e|e,e,0,0,0,0,0,0]
+		 *          |   [e,e,e,e,e,e,e,e]           |
+		 *          |   |--out[word_i]--|           |
+		 *    lshift|---|               |--rshift---|
+		 *          |e,e|0,0,0,0,0,0,0,0|0,0,0,0,0,0|
+		 *              |<==   ||    ==>|
+		 *               bits_to_discard (from these bytes)
+		 *
+		 * variable(bits_to_discard): Tracks the amount of bits to be
+		 * discarded and is updated accordingly in each iteration.
+		 *
+		 * It monitors these packed bits from respective word_i and
+		 * word_i+1 and overwrites them with zeros accordingly.
+		 * It discards linearly from the lowest index and moves upwards
+		 * until bits_to_discard variable becomes zero.
+		 *
+		 * In the above diagram,for example, we pack 2bytes(7th and 6th
+		 * from word_i) and 6bytes(0th till 5th from word_i+1), combine
+		 * and pack them as 64bit to output buffer out[i].
+		 * Depending on the number of bits requested, we discard the
+		 * bits from these packed bytes by overwriting them with zeros.
+		 */
+
+		/*
+		 * If the bits to be discarded is lesser than the amount of bits
+		 * copied to the output buffer from word_i, we discard that much
+		 * amount of bits only.
+		 */
+		if (bits_to_discard < (BITS_PER_WORD - rshift)) {
+			entropy[ENTROPY_WORD_INDEX(word_i)] &=
+			(~0ULL << ((bits_to_discard+rshift) % BITS_PER_WORD));
+			bits_to_discard = 0;
+		} else {
+		/*
+		 * If the bits to be discarded is more than the amount of valid
+		 * upper bits from word_i, which has been copied to the output
+		 * buffer, we just set the entire word_i to 0, as the lower bits
+		 * will be already zeros from previous operations, and the
+		 * bits_to_discard is updated precisely.
+		 */
+			entropy[ENTROPY_WORD_INDEX(word_i)] = 0;
+			bits_to_discard -= (BITS_PER_WORD - rshift);
+		}
+
 		/*
 		 * Note that a shift of 64 bits is treated as a shift of 0 bits.
 		 * When the shift amount is the same as the BITS_PER_WORD, we
@@ -123,6 +180,35 @@
 		if (lshift != BITS_PER_WORD) {
 			out[word_i] |= entropy[ENTROPY_WORD_INDEX(word_i + 1)]
 				<< lshift;
+			/**
+			 * Discarding the remaining packed bits from upperword
+			 * (word[i+1]) which was copied to output buffer by
+			 * overwriting with zeros.
+			 *
+			 * If the remaining bits to be discarded is lesser than
+			 * the amount of bits from [word_i+1], which has been
+			 * copied to the output buffer, we overwrite that much
+			 * amount of bits only.
+			 */
+			if (bits_to_discard < (BITS_PER_WORD - lshift)) {
+				entropy[ENTROPY_WORD_INDEX(word_i+1)]  &=
+				(~0ULL << ((bits_to_discard) % BITS_PER_WORD));
+				bits_to_discard = 0;
+			} else {
+			/*
+			 * If bits to discard is more than the bits from word_i+1
+			 * which got packed into the output, then we discard all
+			 * those copied bits.
+			 *
+			 * Note: we cannot set the entire word_i+1 to 0, as
+			 * there are still some unused valid entropy bits at the
+			 * upper end for future use.
+			 */
+				entropy[ENTROPY_WORD_INDEX(word_i+1)]  &=
+				(~0ULL << ((BITS_PER_WORD - lshift) % BITS_PER_WORD));
+				bits_to_discard -= (BITS_PER_WORD - lshift);
+		}
+
 		}
 	}
 	const uint64_t mask = ~0ULL >> (BITS_PER_WORD - (nbits % BITS_PER_WORD));