+ Alexander and qemu-arm (for HVF/arm),
On 5/29/26 7:47 PM, Peter Maydell wrote:
> From: Jason Wright <[email protected]>
>
> Add an .accessfn to the RNDR and RNDRRS system registers that traps
> reads to EL3 when SCR_EL3.TRNDR is set, as required by FEAT_RNG_TRAP.
> Mark SCR_EL3.TRNDR (bit 40) as a writable field in scr_write() when
> the CPU advertises the feature. The pseudocode in DDI0487 revision M.b
> shows the trap firing from EL0, EL1, EL2, and EL3, so there is no
> check of arm_current_el().
>
> When FEAT_RNG_TRAP is implemented without FEAT_RNG, an RNDR/RNDRRS read
> with SCR_EL3.TRNDR=0 should UNDEF rather than succeed; handle that case
> in access_rndr(). Register the rndr_reginfo CP reg entries whenever either
> FEAT_RNG or FEAT_RNG_TRAP is implemented, so the accessfn fires even on a
> FEAT_RNG_TRAP-only CPU.
>
> When SCR_EL3.TRNDR is set, ID_AA64ISAR0_EL1.RNDR reads as 1 regardless
> of whether FEAT_RNG is implemented; give ID_AA64ISAR0_EL1 a readfn so it
> reports this at runtime, as we already do for ID_AA64PFR0_EL1.
>
> Suggested-by: Richard Henderson <[email protected]>
> Suggested-by: Peter Maydell <[email protected]>
> Signed-off-by: Jason Wright <[email protected]>
> Reviewed-by: Richard Henderson <[email protected]>
> Signed-off-by: Peter Maydell <[email protected]>
> ---
> target/arm/cpu-features.h | 5 ++++
> target/arm/helper.c | 58 +++++++++++++++++++++++++++++++++++----
> 2 files changed, 58 insertions(+), 5 deletions(-)
>
> diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
> index 4e8d844fea..38a695ded7 100644
> --- a/target/arm/cpu-features.h
> +++ b/target/arm/cpu-features.h
> @@ -908,6 +908,11 @@ static inline bool isar_feature_aa64_rndr(const
> ARMISARegisters *id)
> return FIELD_EX64_IDREG(id, ID_AA64ISAR0, RNDR) != 0;
> }
>
> +static inline bool isar_feature_aa64_rng_trap(const ARMISARegisters *id)
> +{
> + return FIELD_EX64_IDREG(id, ID_AA64PFR1, RNDR_TRAP) != 0;
> +}
> +
> static inline bool isar_feature_aa64_tlbirange(const ARMISARegisters *id)
> {
> return FIELD_EX64_IDREG(id, ID_AA64ISAR0, TLB) == 2;
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index 34487eeaa3..9dd8fdfa41 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -790,6 +790,9 @@ static void scr_write(CPUARMState *env, const
> ARMCPRegInfo *ri, uint64_t value)
> if (cpu_isar_feature(aa64_fpmr, cpu)) {
> valid_mask |= SCR_ENFPM;
> }
> + if (cpu_isar_feature(aa64_rng_trap, cpu)) {
> + valid_mask |= SCR_TRNDR;
> + }
> } else {
> valid_mask &= ~(SCR_RW | SCR_ST);
> if (cpu_isar_feature(aa32_ras, cpu)) {
> @@ -5170,6 +5173,21 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env,
> const ARMCPRegInfo *ri)
> }
> return pfr0;
> }
> +
> +static uint64_t id_aa64isar0_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> + ARMCPU *cpu = env_archcpu(env);
> + uint64_t isar0 = GET_IDREG(&cpu->isar, ID_AA64ISAR0);
> +
> + /*
> + * When FEAT_RNG_TRAP is active (SCR_EL3.TRNDR set),
> ID_AA64ISAR0_EL1.RNDR
> + * reads as 1 regardless of whether FEAT_RNG is implemented.
> + */
> + if (env->cp15.scr_el3 & SCR_TRNDR) {
> + isar0 = FIELD_DP64(isar0, ID_AA64ISAR0, RNDR, 1);
> + }
> + return isar0;
> +}
> #endif
>
> /*
> @@ -5304,6 +5322,22 @@ static const ARMCPRegInfo pauth_reginfo[] = {
> .fieldoffset = offsetof(CPUARMState, keys.apib.hi) },
> };
>
> +static CPAccessResult access_rndr(CPUARMState *env, const ARMCPRegInfo *ri,
> + bool isread)
> +{
> + if (env->cp15.scr_el3 & SCR_TRNDR) {
> + return CP_ACCESS_TRAP_EL3;
> + }
> + /*
> + * Note that FEAT_RNG_TRAP may be implemented without FEAT_RNG.
> + * In that case, if the trap is not enabled, the read undefs.
> + */
> + if (!cpu_isar_feature(aa64_rndr, env_archcpu(env))) {
> + return CP_ACCESS_UNDEFINED;
> + }
> + return CP_ACCESS_OK;
> +}
> +
> static uint64_t rndr_readfn(CPUARMState *env, const ARMCPRegInfo *ri)
> {
> Error *err = NULL;
> @@ -5335,11 +5369,11 @@ static const ARMCPRegInfo rndr_reginfo[] = {
> { .name = "RNDR", .state = ARM_CP_STATE_AA64,
> .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
> .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 0,
> - .access = PL0_R, .readfn = rndr_readfn },
> + .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn },
> { .name = "RNDRRS", .state = ARM_CP_STATE_AA64,
> .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
> .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 1,
> - .access = PL0_R, .readfn = rndr_readfn },
> + .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn },
> };
>
> static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *ri,
> @@ -6522,11 +6556,24 @@ void register_cp_regs_for_features(ARMCPU *cpu)
> .access = PL1_R, .type = ARM_CP_CONST,
> .accessfn = access_tid3,
> .resetvalue = 0 },
> + /*
> + * ID_AA64ISAR0_EL1 is not a plain ARM_CP_CONST in system
> + * emulation because the RNDR field depends on SCR_EL3.TRNDR
> + * at read time when FEAT_RNG_TRAP is implemented.
> + */
> { .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64,
> .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0,
> - .access = PL1_R, .type = ARM_CP_CONST,
> + .access = PL1_R,
> +#ifdef CONFIG_USER_ONLY
> + .type = ARM_CP_CONST,
> + .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)
> +#else
> + .type = ARM_CP_NO_RAW,
> .accessfn = access_tid3,
> - .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)},
> + .readfn = id_aa64isar0_read,
> + .writefn = arm_cp_write_ignore
> +#endif
> + },
A new assert() was triggered when booting guest on M1 since this change:
Assertion failed: (!(ri->type & ARM_CP_NO_RAW)), function hvf_arch_init_vcpu,
file hvf.c, line 1442.
Thanks,
Zenghui
> { .name = "ID_AA64ISAR1_EL1", .state = ARM_CP_STATE_AA64,
> .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1,
> .access = PL1_R, .type = ARM_CP_CONST,
> @@ -7454,7 +7501,8 @@ void register_cp_regs_for_features(ARMCPU *cpu)
> if (cpu_isar_feature(aa64_pauth, cpu)) {
> define_arm_cp_regs(cpu, pauth_reginfo);
> }
> - if (cpu_isar_feature(aa64_rndr, cpu)) {
> + if (cpu_isar_feature(aa64_rndr, cpu) ||
> + cpu_isar_feature(aa64_rng_trap, cpu)) {
> define_arm_cp_regs(cpu, rndr_reginfo);
> }
> /* Data Cache clean instructions up to PoP */