target/arm: Enforce that M-profile SP low 2 bits are always zero
For M-profile, unlike A-profile, the low 2 bits of SP are defined to be RES0H, which is to say that they must be hardwired to zero so that guest attempts to write non-zero values to them are ignored. Implement this behaviour by masking out the low bits: * for writes to r13 by the gdbstub * for writes to any of the various flavours of SP via MSR * for writes to r13 via store_reg() in generated code Note that all the direct uses of cpu_R[] in translate.c are in places where the register is definitely not r13 (usually because that has been checked for as an UNDEFINED or UNPREDICTABLE case and handled as UNDEF). All the other writes to regs[13] in C code are either: * A-profile only code * writes of values we can guarantee to be aligned, such as - writes of previous-SP-value plus or minus a 4-aligned constant - writes of the value in an SP limit register (which we already enforce to be aligned) Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20210723162146.5167-2-peter.maydell@linaro.org
This commit is contained in:
parent
953558291e
commit
888f470f12
@ -84,6 +84,10 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
|||||||
|
|
||||||
if (n < 16) {
|
if (n < 16) {
|
||||||
/* Core integer register. */
|
/* Core integer register. */
|
||||||
|
if (n == 13 && arm_feature(env, ARM_FEATURE_M)) {
|
||||||
|
/* M profile SP low bits are always 0 */
|
||||||
|
tmp &= ~3;
|
||||||
|
}
|
||||||
env->regs[n] = tmp;
|
env->regs[n] = tmp;
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
@ -2563,13 +2563,13 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
|
|||||||
if (!env->v7m.secure) {
|
if (!env->v7m.secure) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
env->v7m.other_ss_msp = val;
|
env->v7m.other_ss_msp = val & ~3;
|
||||||
return;
|
return;
|
||||||
case 0x89: /* PSP_NS */
|
case 0x89: /* PSP_NS */
|
||||||
if (!env->v7m.secure) {
|
if (!env->v7m.secure) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
env->v7m.other_ss_psp = val;
|
env->v7m.other_ss_psp = val & ~3;
|
||||||
return;
|
return;
|
||||||
case 0x8a: /* MSPLIM_NS */
|
case 0x8a: /* MSPLIM_NS */
|
||||||
if (!env->v7m.secure) {
|
if (!env->v7m.secure) {
|
||||||
@ -2638,6 +2638,8 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
|
|||||||
|
|
||||||
limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false];
|
limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false];
|
||||||
|
|
||||||
|
val &= ~0x3;
|
||||||
|
|
||||||
if (val < limit) {
|
if (val < limit) {
|
||||||
raise_exception_ra(env, EXCP_STKOF, 0, 1, GETPC());
|
raise_exception_ra(env, EXCP_STKOF, 0, 1, GETPC());
|
||||||
}
|
}
|
||||||
@ -2660,16 +2662,16 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
|
|||||||
break;
|
break;
|
||||||
case 8: /* MSP */
|
case 8: /* MSP */
|
||||||
if (v7m_using_psp(env)) {
|
if (v7m_using_psp(env)) {
|
||||||
env->v7m.other_sp = val;
|
env->v7m.other_sp = val & ~3;
|
||||||
} else {
|
} else {
|
||||||
env->regs[13] = val;
|
env->regs[13] = val & ~3;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 9: /* PSP */
|
case 9: /* PSP */
|
||||||
if (v7m_using_psp(env)) {
|
if (v7m_using_psp(env)) {
|
||||||
env->regs[13] = val;
|
env->regs[13] = val & ~3;
|
||||||
} else {
|
} else {
|
||||||
env->v7m.other_sp = val;
|
env->v7m.other_sp = val & ~3;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 10: /* MSPLIM */
|
case 10: /* MSPLIM */
|
||||||
|
@ -291,6 +291,9 @@ void store_reg(DisasContext *s, int reg, TCGv_i32 var)
|
|||||||
*/
|
*/
|
||||||
tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
|
tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
|
||||||
s->base.is_jmp = DISAS_JUMP;
|
s->base.is_jmp = DISAS_JUMP;
|
||||||
|
} else if (reg == 13 && arm_dc_feature(s, ARM_FEATURE_M)) {
|
||||||
|
/* For M-profile SP bits [1:0] are always zero */
|
||||||
|
tcg_gen_andi_i32(var, var, ~3);
|
||||||
}
|
}
|
||||||
tcg_gen_mov_i32(cpu_R[reg], var);
|
tcg_gen_mov_i32(cpu_R[reg], var);
|
||||||
tcg_temp_free_i32(var);
|
tcg_temp_free_i32(var);
|
||||||
|
Loading…
Reference in New Issue
Block a user