Merge changes from topic "fvp_trap_rng" into integration
* changes:
feat(fvp): emulate trapped RNDR
feat(el3-runtime): introduce system register trap handler
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/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 \