Skip to content

Commit 5d71c68

Browse files
committed
target/arm: SCR_EL3.RW should be treated as 1 if EL2 doesn't support AArch32
The definition of SCR_EL3.RW says that its effective value is 1 if: - EL2 is implemented and does not support AArch32, and SCR_EL3.NS is 1 - the effective value of SCR_EL3.{EEL2,NS} is {1,0} (i.e. we are Secure and Secure EL2 is disabled) We implement the second of these in arm_el_is_aa64(), but forgot the first. Provide a new function arm_scr_rw_eff() to return the effective value of SCR_EL3.RW, and use it in arm_el_is_aa64() and the other places that currently look directly at the bit value. (scr_write() enforces that the RW bit is RAO/WI if neither EL1 nor EL2 have AArch32 support, but if EL1 does but EL2 does not then the bit must still be writeable.) This will mean that if code at EL3 attempts to perform an exception return to AArch32 EL2 when EL2 is AArch64-only we will correctly handle this as an illegal exception return: it will be caught by the "return to an EL which is configured for a different register width" check in HELPER(exception_return). We do already have some CPU types which don't implement AArch32 above EL0, so this is technically a bug; it doesn't seem worth backporting to stable because no sensible guest code will be deliberately attempting to set the RW bit to a value corresponding to an unimplemented execution state and then checking that we did the right thing. Signed-off-by: Peter Maydell <[email protected]> Reviewed-by: Richard Henderson <[email protected]>
1 parent 2beb051 commit 5d71c68

File tree

2 files changed

+25
-5
lines changed

2 files changed

+25
-5
lines changed

target/arm/helper.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9818,7 +9818,7 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
98189818
uint64_t hcr_el2;
98199819

98209820
if (arm_feature(env, ARM_FEATURE_EL3)) {
9821-
rw = ((env->cp15.scr_el3 & SCR_RW) == SCR_RW);
9821+
rw = arm_scr_rw_eff(env);
98229822
} else {
98239823
/*
98249824
* Either EL2 is the highest EL (and so the EL2 register width
@@ -10627,7 +10627,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
1062710627

1062810628
switch (new_el) {
1062910629
case 3:
10630-
is_aa64 = (env->cp15.scr_el3 & SCR_RW) != 0;
10630+
is_aa64 = arm_scr_rw_eff(env);
1063110631
break;
1063210632
case 2:
1063310633
hcr = arm_hcr_el2_eff(env);

target/arm/internals.h

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,27 @@ static inline FloatRoundMode arm_rmode_to_sf(ARMFPRounding rmode)
392392
return arm_rmode_to_sf_map[rmode];
393393
}
394394

395+
/* Return the effective value of SCR_EL3.RW */
396+
static inline bool arm_scr_rw_eff(CPUARMState *env)
397+
{
398+
/*
399+
* SCR_EL3.RW has an effective value of 1 if:
400+
* - we are NS and EL2 is implemented but doesn't support AArch32
401+
* - we are S and EL2 is enabled (in which case it must be AArch64)
402+
*/
403+
ARMCPU *cpu = env_archcpu(env);
404+
405+
if (env->cp15.scr_el3 & SCR_RW) {
406+
return true;
407+
}
408+
if (env->cp15.scr_el3 & SCR_NS) {
409+
return arm_feature(env, ARM_FEATURE_EL2) &&
410+
!cpu_isar_feature(aa64_aa32_el2, cpu);
411+
} else {
412+
return env->cp15.scr_el3 & SCR_EEL2;
413+
}
414+
}
415+
395416
/* Return true if the specified exception level is running in AArch64 state. */
396417
static inline bool arm_el_is_aa64(CPUARMState *env, int el)
397418
{
@@ -411,9 +432,8 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el)
411432
return aa64;
412433
}
413434

414-
if (arm_feature(env, ARM_FEATURE_EL3) &&
415-
((env->cp15.scr_el3 & SCR_NS) || !(env->cp15.scr_el3 & SCR_EEL2))) {
416-
aa64 = aa64 && (env->cp15.scr_el3 & SCR_RW);
435+
if (arm_feature(env, ARM_FEATURE_EL3)) {
436+
aa64 = aa64 && arm_scr_rw_eff(env);
417437
}
418438

419439
if (el == 2) {

0 commit comments

Comments
 (0)