target/arm: Add v8M stack checks on ADD/SUB/MOV of SP

Add code to insert calls to a helper function to do the stack
limit checking when we handle these forms of instruction
that write to SP:
* ADD (SP plus immediate)
* ADD (SP plus register)
* SUB (SP minus immediate)
* SUB (SP minus register)
* MOV (register)

Backports commit 5520318939fea5d659bf808157cd726cb967b761 from qemu
This commit is contained in:
Peter Maydell 2018-10-08 13:58:07 -04:00 committed by Lioncash
parent b2146058c3
commit ca5d7b8fd2
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
20 changed files with 124 additions and 9 deletions

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_aarch64
#define helper_v7m_msr helper_v7m_msr_aarch64
#define helper_v7m_tt helper_v7m_tt_aarch64
#define helper_v8m_stackcheck helper_v8m_stackcheck_aarch64
#define helper_vfp_absd helper_vfp_absd_aarch64
#define helper_vfp_abss helper_vfp_abss_aarch64
#define helper_vfp_addd helper_vfp_addd_aarch64

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_aarch64eb
#define helper_v7m_msr helper_v7m_msr_aarch64eb
#define helper_v7m_tt helper_v7m_tt_aarch64eb
#define helper_v8m_stackcheck helper_v8m_stackcheck_aarch64eb
#define helper_vfp_absd helper_vfp_absd_aarch64eb
#define helper_vfp_abss helper_vfp_abss_aarch64eb
#define helper_vfp_addd helper_vfp_addd_aarch64eb

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_arm
#define helper_v7m_msr helper_v7m_msr_arm
#define helper_v7m_tt helper_v7m_tt_arm
#define helper_v8m_stackcheck helper_v8m_stackcheck_arm
#define helper_vfp_absd helper_vfp_absd_arm
#define helper_vfp_abss helper_vfp_abss_arm
#define helper_vfp_addd helper_vfp_addd_arm

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_armeb
#define helper_v7m_msr helper_v7m_msr_armeb
#define helper_v7m_tt helper_v7m_tt_armeb
#define helper_v8m_stackcheck helper_v8m_stackcheck_armeb
#define helper_vfp_absd helper_vfp_absd_armeb
#define helper_vfp_abss helper_vfp_abss_armeb
#define helper_vfp_addd helper_vfp_addd_armeb

View file

@ -1713,6 +1713,7 @@ symbols = (
'helper_v7m_mrs',
'helper_v7m_msr',
'helper_v7m_tt',
'helper_v8m_stackcheck',
'helper_vfp_absd',
'helper_vfp_abss',
'helper_vfp_addd',

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_m68k
#define helper_v7m_msr helper_v7m_msr_m68k
#define helper_v7m_tt helper_v7m_tt_m68k
#define helper_v8m_stackcheck helper_v8m_stackcheck_m68k
#define helper_vfp_absd helper_vfp_absd_m68k
#define helper_vfp_abss helper_vfp_abss_m68k
#define helper_vfp_addd helper_vfp_addd_m68k

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_mips
#define helper_v7m_msr helper_v7m_msr_mips
#define helper_v7m_tt helper_v7m_tt_mips
#define helper_v8m_stackcheck helper_v8m_stackcheck_mips
#define helper_vfp_absd helper_vfp_absd_mips
#define helper_vfp_abss helper_vfp_abss_mips
#define helper_vfp_addd helper_vfp_addd_mips

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_mips64
#define helper_v7m_msr helper_v7m_msr_mips64
#define helper_v7m_tt helper_v7m_tt_mips64
#define helper_v8m_stackcheck helper_v8m_stackcheck_mips64
#define helper_vfp_absd helper_vfp_absd_mips64
#define helper_vfp_abss helper_vfp_abss_mips64
#define helper_vfp_addd helper_vfp_addd_mips64

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_mips64el
#define helper_v7m_msr helper_v7m_msr_mips64el
#define helper_v7m_tt helper_v7m_tt_mips64el
#define helper_v8m_stackcheck helper_v8m_stackcheck_mips64el
#define helper_vfp_absd helper_vfp_absd_mips64el
#define helper_vfp_abss helper_vfp_abss_mips64el
#define helper_vfp_addd helper_vfp_addd_mips64el

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_mipsel
#define helper_v7m_msr helper_v7m_msr_mipsel
#define helper_v7m_tt helper_v7m_tt_mipsel
#define helper_v8m_stackcheck helper_v8m_stackcheck_mipsel
#define helper_vfp_absd helper_vfp_absd_mipsel
#define helper_vfp_abss helper_vfp_abss_mipsel
#define helper_vfp_addd helper_vfp_addd_mipsel

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_powerpc
#define helper_v7m_msr helper_v7m_msr_powerpc
#define helper_v7m_tt helper_v7m_tt_powerpc
#define helper_v8m_stackcheck helper_v8m_stackcheck_powerpc
#define helper_vfp_absd helper_vfp_absd_powerpc
#define helper_vfp_abss helper_vfp_abss_powerpc
#define helper_vfp_addd helper_vfp_addd_powerpc

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_riscv32
#define helper_v7m_msr helper_v7m_msr_riscv32
#define helper_v7m_tt helper_v7m_tt_riscv32
#define helper_v8m_stackcheck helper_v8m_stackcheck_riscv32
#define helper_vfp_absd helper_vfp_absd_riscv32
#define helper_vfp_abss helper_vfp_abss_riscv32
#define helper_vfp_addd helper_vfp_addd_riscv32

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_riscv64
#define helper_v7m_msr helper_v7m_msr_riscv64
#define helper_v7m_tt helper_v7m_tt_riscv64
#define helper_v8m_stackcheck helper_v8m_stackcheck_riscv64
#define helper_vfp_absd helper_vfp_absd_riscv64
#define helper_vfp_abss helper_vfp_abss_riscv64
#define helper_vfp_addd helper_vfp_addd_riscv64

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_sparc
#define helper_v7m_msr helper_v7m_msr_sparc
#define helper_v7m_tt helper_v7m_tt_sparc
#define helper_v8m_stackcheck helper_v8m_stackcheck_sparc
#define helper_vfp_absd helper_vfp_absd_sparc
#define helper_vfp_abss helper_vfp_abss_sparc
#define helper_vfp_addd helper_vfp_addd_sparc

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_sparc64
#define helper_v7m_msr helper_v7m_msr_sparc64
#define helper_v7m_tt helper_v7m_tt_sparc64
#define helper_v8m_stackcheck helper_v8m_stackcheck_sparc64
#define helper_vfp_absd helper_vfp_absd_sparc64
#define helper_vfp_abss helper_vfp_abss_sparc64
#define helper_vfp_addd helper_vfp_addd_sparc64

View file

@ -71,6 +71,8 @@ DEF_HELPER_2(v7m_blxns, void, env, i32)
DEF_HELPER_3(v7m_tt, i32, env, i32, i32)
DEF_HELPER_2(v8m_stackcheck, void, env, i32)
DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32)
DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
DEF_HELPER_2(get_cp_reg, i32, env, ptr)

View file

@ -819,4 +819,18 @@ static inline bool v7m_using_psp(CPUARMState *env)
env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK;
}
/**
* v7m_sp_limit: Return SP limit for current CPU state
* Return the SP limit value for the current CPU security state
* and stack pointer.
*/
static inline uint32_t v7m_sp_limit(CPUARMState *env)
{
if (v7m_using_psp(env)) {
return env->v7m.psplim[env->v7m.secure];
} else {
return env->v7m.msplim[env->v7m.secure];
}
}
#endif

View file

@ -237,6 +237,25 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
#endif /* !defined(CONFIG_USER_ONLY) */
void HELPER(v8m_stackcheck)(CPUARMState *env, uint32_t newvalue)
{
/*
* Perform the v8M stack limit check for SP updates from translated code,
* raising an exception if the limit is breached.
*/
if (newvalue < v7m_sp_limit(env)) {
CPUState *cs = CPU(arm_env_get_cpu(env));
/*
* Stack limit exceptions are a rare case, so rather than syncing
* PC/condbits before the call, we use cpu_restore_state() to
* get them right before raising the exception.
*/
cpu_restore_state(cs, GETPC(), true);
raise_exception(env, EXCP_STKOF, 0, 1);
}
}
uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b)
{
uint32_t res = a + b;

View file

@ -235,6 +235,25 @@ static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
tcg_temp_free_i32(tcg_ctx, var);
}
/*
* Variant of store_reg which applies v8M stack-limit checks before updating
* SP. If the check fails this will result in an exception being taken.
* We disable the stack checks for CONFIG_USER_ONLY because we have
* no idea what the stack limits should be in that case.
* If stack checking is not being done this just acts like store_reg().
*/
static void store_sp_checked(DisasContext *s, TCGv_i32 var)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
#ifndef CONFIG_USER_ONLY
if (s->v8m_stackcheck) {
gen_helper_v8m_stackcheck(tcg_ctx, tcg_ctx->cpu_env, var);
}
#endif
store_reg(s, 13, var);
}
/* Value extensions. */
#define gen_uxtb(var) tcg_gen_ext8u_i32(tcg_ctx, var, var)
#define gen_uxth(var) tcg_gen_ext16u_i32(tcg_ctx, var, var)
@ -10769,7 +10788,13 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))
goto illegal_op;
tcg_temp_free_i32(tcg_ctx, tmp2);
if (rd != 15) {
if (rd == 13 &&
((op == 2 && rn == 15) ||
(op == 8 && rn == 13) ||
(op == 13 && rn == 13))) {
/* MOV SP, ... or ADD SP, SP, ... or SUB SP, SP, ... */
store_sp_checked(s, tmp);
} else if (rd != 15) {
store_reg(s, rd, tmp);
} else {
tcg_temp_free_i32(tcg_ctx, tmp);
@ -11453,8 +11478,15 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
gen_jmp(s, s->pc + offset);
}
} else {
/* Data processing immediate. */
/*
* 0b1111_0xxx_xxxx_0xxx_xxxx_xxxx
* - Data-processing (modified immediate, plain binary immediate)
*/
if (insn & (1 << 25)) {
/*
* 0b1111_0x1x_xxxx_0xxx_xxxx_xxxx
* - Data-processing (plain binary immediate)
*/
if (insn & (1 << 24)) {
if (insn & (1 << 20))
goto illegal_op;
@ -11550,6 +11582,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
tmp = tcg_temp_new_i32(tcg_ctx);
tcg_gen_movi_i32(tcg_ctx, tmp, imm);
}
store_reg(s, rd, tmp);
} else {
/* Add/sub 12-bit immediate. */
if (rn == 15) {
@ -11560,17 +11593,27 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
offset += imm;
tmp = tcg_temp_new_i32(tcg_ctx);
tcg_gen_movi_i32(tcg_ctx, tmp, offset);
store_reg(s, rd, tmp);
} else {
tmp = load_reg(s, rn);
if (insn & (1 << 23))
tcg_gen_subi_i32(tcg_ctx, tmp, tmp, imm);
else
tcg_gen_addi_i32(tcg_ctx, tmp, tmp, imm);
}
}
if (rn == 13 && rd == 13) {
/* ADD SP, SP, imm or SUB SP, SP, imm */
store_sp_checked(s, tmp);
} else {
store_reg(s, rd, tmp);
}
}
}
}
} else {
/*
* 0b1111_0x0x_xxxx_0xxx_xxxx_xxxx
* - Data-processing (modified immediate)
*/
int shifter_out = 0;
/* modified 12-bit immediate. */
shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12);
@ -11612,7 +11655,11 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
goto illegal_op;
tcg_temp_free_i32(tcg_ctx, tmp2);
rd = (insn >> 8) & 0xf;
if (rd != 15) {
if (rd == 13 && rn == 13
&& (op == 8 || op == 13)) {
/* ADD(S) SP, SP, imm or SUB(S) SP, SP, imm */
store_sp_checked(s, tmp);
} else if (rd != 15) {
store_reg(s, rd, tmp);
} else {
tcg_temp_free_i32(tcg_ctx, tmp);
@ -11945,7 +11992,12 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
tmp2 = load_reg(s, rm);
tcg_gen_add_i32(tcg_ctx, tmp, tmp, tmp2);
tcg_temp_free_i32(tcg_ctx, tmp2);
if (rd == 13) {
/* ADD SP, SP, reg */
store_sp_checked(s, tmp);
} else {
store_reg(s, rd, tmp);
}
break;
case 1: /* cmp */
tmp = load_reg(s, rd);
@ -11956,7 +12008,12 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
break;
case 2: /* mov/cpy */
tmp = load_reg(s, rm);
if (rd == 13) {
/* MOV SP, reg */
store_sp_checked(s, tmp);
} else {
store_reg(s, rd, tmp);
}
break;
case 3:
{
@ -12284,7 +12341,10 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
break;
case 10:
/* add to high reg */
/*
* 0b1010_xxxx_xxxx_xxxx
* - Add PC/SP (immediate)
*/
rd = (insn >> 8) & 7;
if (insn & (1 << 11)) {
/* SP */
@ -12304,13 +12364,17 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
op = (insn >> 8) & 0xf;
switch (op) {
case 0:
/* adjust stack pointer */
/*
* 0b1011_0000_xxxx_xxxx
* - ADD (SP plus immediate)
* - SUB (SP minus immediate)
*/
tmp = load_reg(s, 13);
val = (insn & 0x7f) * 4;
if (insn & (1 << 7))
val = -(int32_t)val;
tcg_gen_addi_i32(tcg_ctx, tmp, tmp, val);
store_reg(s, 13, tmp);
store_sp_checked(s, tmp);
break;
case 2: /* sign/zero extend. */

View file

@ -1707,6 +1707,7 @@
#define helper_v7m_mrs helper_v7m_mrs_x86_64
#define helper_v7m_msr helper_v7m_msr_x86_64
#define helper_v7m_tt helper_v7m_tt_x86_64
#define helper_v8m_stackcheck helper_v8m_stackcheck_x86_64
#define helper_vfp_absd helper_vfp_absd_x86_64
#define helper_vfp_abss helper_vfp_abss_x86_64
#define helper_vfp_addd helper_vfp_addd_x86_64