@samitouri / QOSamiQemu / commits / 887eaa8a29

target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS

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 <richard.henderson@linaro.org> Suggested-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Jason Wright <wrigjl@proton.me> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Jason Wright committed May 28, 2026 at 18:19 UTC 887eaa8a29019082a68a0389abbfddd21a6d5bb7
2 files changed +58 -5
target/arm/cpu-features.h
+5
@@ -908,6 +908,11 @@ static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id)
908 return FIELD_EX64_IDREG(id, ID_AA64ISAR0, RNDR) != 0;
909 }
910
911 +static inline bool isar_feature_aa64_rng_trap(const ARMISARegisters *id)
912 +{
913 + return FIELD_EX64_IDREG(id, ID_AA64PFR1, RNDR_TRAP) != 0;
914 +}
915 +
916 static inline bool isar_feature_aa64_tlbirange(const ARMISARegisters *id)
917 {
918 return FIELD_EX64_IDREG(id, ID_AA64ISAR0, TLB) == 2;
target/arm/helper.c
+53 -5
@@ -790,6 +790,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
790 if (cpu_isar_feature(aa64_fpmr, cpu)) {
791 valid_mask |= SCR_ENFPM;
792 }
793 + if (cpu_isar_feature(aa64_rng_trap, cpu)) {
794 + valid_mask |= SCR_TRNDR;
795 + }
796 } else {
797 valid_mask &= ~(SCR_RW | SCR_ST);
798 if (cpu_isar_feature(aa32_ras, cpu)) {
@@ -5170,6 +5173,21 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
5173 }
5174 return pfr0;
5175 }
5176 +
5177 +static uint64_t id_aa64isar0_read(CPUARMState *env, const ARMCPRegInfo *ri)
5178 +{
5179 + ARMCPU *cpu = env_archcpu(env);
5180 + uint64_t isar0 = GET_IDREG(&cpu->isar, ID_AA64ISAR0);
5181 +
5182 + /*
5183 + * When FEAT_RNG_TRAP is active (SCR_EL3.TRNDR set), ID_AA64ISAR0_EL1.RNDR
5184 + * reads as 1 regardless of whether FEAT_RNG is implemented.
5185 + */
5186 + if (env->cp15.scr_el3 & SCR_TRNDR) {
5187 + isar0 = FIELD_DP64(isar0, ID_AA64ISAR0, RNDR, 1);
5188 + }
5189 + return isar0;
5190 +}
5191 #endif
5192
5193 /*
@@ -5304,6 +5322,22 @@ static const ARMCPRegInfo pauth_reginfo[] = {
5322 .fieldoffset = offsetof(CPUARMState, keys.apib.hi) },
5323 };
5324
5325 +static CPAccessResult access_rndr(CPUARMState *env, const ARMCPRegInfo *ri,
5326 + bool isread)
5327 +{
5328 + if (env->cp15.scr_el3 & SCR_TRNDR) {
5329 + return CP_ACCESS_TRAP_EL3;
5330 + }
5331 + /*
5332 + * Note that FEAT_RNG_TRAP may be implemented without FEAT_RNG.
5333 + * In that case, if the trap is not enabled, the read undefs.
5334 + */
5335 + if (!cpu_isar_feature(aa64_rndr, env_archcpu(env))) {
5336 + return CP_ACCESS_UNDEFINED;
5337 + }
5338 + return CP_ACCESS_OK;
5339 +}
5340 +
5341 static uint64_t rndr_readfn(CPUARMState *env, const ARMCPRegInfo *ri)
5342 {
5343 Error *err = NULL;
@@ -5335,11 +5369,11 @@ static const ARMCPRegInfo rndr_reginfo[] = {
5369 { .name = "RNDR", .state = ARM_CP_STATE_AA64,
5370 .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
5371 .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 0,
5338 - .access = PL0_R, .readfn = rndr_readfn },
5372 + .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn },
5373 { .name = "RNDRRS", .state = ARM_CP_STATE_AA64,
5374 .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
5375 .opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 1,
5342 - .access = PL0_R, .readfn = rndr_readfn },
5376 + .access = PL0_R, .accessfn = access_rndr, .readfn = rndr_readfn },
5377 };
5378
5379 static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -6522,11 +6556,24 @@ void register_cp_regs_for_features(ARMCPU *cpu)
6556 .access = PL1_R, .type = ARM_CP_CONST,
6557 .accessfn = access_tid3,
6558 .resetvalue = 0 },
6559 + /*
6560 + * ID_AA64ISAR0_EL1 is not a plain ARM_CP_CONST in system
6561 + * emulation because the RNDR field depends on SCR_EL3.TRNDR
6562 + * at read time when FEAT_RNG_TRAP is implemented.
6563 + */
6564 { .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64,
6565 .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0,
6527 - .access = PL1_R, .type = ARM_CP_CONST,
6566 + .access = PL1_R,
6567 +#ifdef CONFIG_USER_ONLY
6568 + .type = ARM_CP_CONST,
6569 + .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)
6570 +#else
6571 + .type = ARM_CP_NO_RAW,
6572 .accessfn = access_tid3,
6529 - .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)},
6573 + .readfn = id_aa64isar0_read,
6574 + .writefn = arm_cp_write_ignore
6575 +#endif
6576 + },
6577 { .name = "ID_AA64ISAR1_EL1", .state = ARM_CP_STATE_AA64,
6578 .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1,
6579 .access = PL1_R, .type = ARM_CP_CONST,
@@ -7454,7 +7501,8 @@ void register_cp_regs_for_features(ARMCPU *cpu)
7501 if (cpu_isar_feature(aa64_pauth, cpu)) {
7502 define_arm_cp_regs(cpu, pauth_reginfo);
7503 }
7457 - if (cpu_isar_feature(aa64_rndr, cpu)) {
7504 + if (cpu_isar_feature(aa64_rndr, cpu) ||
7505 + cpu_isar_feature(aa64_rng_trap, cpu)) {
7506 define_arm_cp_regs(cpu, rndr_reginfo);
7507 }
7508 /* Data Cache clean instructions up to PoP */