Implement the frame limit check for system emulation mode. When allocframe computes a new stack pointer below FRAMELIMIT, raise a precise exception (HEX_CAUSE_STACK_LIMIT). The check is skipped in monitor mode.
Signed-off-by: Brian Cain <[email protected]> --- target/hexagon/helper.h | 1 + target/hexagon/macros.h | 3 --- target/hexagon/sys_macros.h | 4 ++++ target/hexagon/translate.h | 2 ++ target/hexagon/genptr.c | 18 +++++++++++------- target/hexagon/op_helper.c | 34 ++++++++++++++++++++++++++++++++++ 6 files changed, 52 insertions(+), 10 deletions(-) diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index 9ca87acfe63..ebcd471ec0a 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -109,6 +109,7 @@ DEF_HELPER_2(probe_hvx_stores, void, env, int) DEF_HELPER_2(probe_pkt_scalar_hvx_stores, void, env, int) #if !defined(CONFIG_USER_ONLY) +DEF_HELPER_3(raise_stack_overflow, void, env, i32, i32) DEF_HELPER_2(swi, void, env, i32) DEF_HELPER_2(cswi, void, env, i32) DEF_HELPER_2(ciad, void, env, i32) diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index 26d3f7d8a4b..d3f2105c932 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -538,9 +538,6 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift) #ifdef CONFIG_USER_ONLY #define fFRAMECHECK(ADDR, EA) do { } while (0) /* Not modelled in linux-user */ -#else -/* System mode not implemented yet */ -#define fFRAMECHECK(ADDR, EA) g_assert_not_reached(); #endif #ifdef QEMU_GENERATE diff --git a/target/hexagon/sys_macros.h b/target/hexagon/sys_macros.h index 364fcde7383..cbc857fa2f5 100644 --- a/target/hexagon/sys_macros.h +++ b/target/hexagon/sys_macros.h @@ -95,6 +95,10 @@ #define fTRAP(TRAPTYPE, IMM) \ register_trap_exception(env, TRAPTYPE, IMM, PC) +#ifdef QEMU_GENERATE +#define fFRAMECHECK(ADDR, EA) gen_framecheck(ctx, ADDR, EA) +#endif + #define fVIRTINSN_SPSWAP(IMM, REG) #define fVIRTINSN_GETIE(IMM, REG) { REG = 0xdeafbeef; } #define fVIRTINSN_SETIE(IMM, REG) diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index e7acbae9ffa..82b327312ec 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -339,4 +339,6 @@ FIELD(PROBE_PKT_SCALAR_HVX_STORES, S0_IS_PRED, 3, 1) FIELD(PROBE_PKT_SCALAR_HVX_STORES, S1_IS_PRED, 4, 1) FIELD(PROBE_PKT_SCALAR_HVX_STORES, MMU_IDX, 5, 2) +void gen_framecheck(DisasContext *ctx, TCGv_i32 addr, TCGv_i32 ea); + #endif diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index bac63a42def..f32890f85c7 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -897,26 +897,30 @@ static void gen_load_frame(DisasContext *ctx, TCGv_i64 frame, TCGv EA) tcg_gen_qemu_ld_i64(frame, EA, ctx->mem_idx, MO_LE | MO_UQ); } -#ifndef CONFIG_HEXAGON_IDEF_PARSER /* Stack overflow check */ -static void gen_framecheck(TCGv EA, int framesize) +void gen_framecheck(DisasContext *ctx, TCGv_i32 addr, TCGv_i32 ea) { - /* Not modelled in linux-user mode */ - /* Placeholder for system mode */ #ifndef CONFIG_USER_ONLY - g_assert_not_reached(); + TCGLabel *ok = gen_new_label(); + tcg_gen_brcond_i32(TCG_COND_GEU, addr, hex_gpr[HEX_REG_FRAMELIMIT], ok); + gen_helper_raise_stack_overflow(tcg_env, + tcg_constant_i32(ctx->insn->slot), ea); + gen_set_label(ok); #endif } +#ifndef CONFIG_HEXAGON_IDEF_PARSER static void gen_allocframe(DisasContext *ctx, TCGv r29, int framesize) { TCGv r30 = get_result_gpr(ctx, HEX_REG_FP); + TCGv_i32 new_r29 = tcg_temp_new_i32(); TCGv_i64 frame; tcg_gen_addi_tl(r30, r29, -8); frame = gen_frame_scramble(); gen_store8(tcg_env, r30, frame, ctx->insn->slot); - gen_framecheck(r30, framesize); - tcg_gen_subi_tl(r29, r30, framesize); + tcg_gen_subi_tl(new_r29, r30, framesize); + gen_framecheck(ctx, new_r29, hex_gpr[HEX_REG_PC]); + tcg_gen_mov_tl(r29, new_r29); } static void gen_deallocframe(DisasContext *ctx, TCGv_i64 r31_30, TCGv r30) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 6dfc1269809..c5c638c132e 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1392,6 +1392,40 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV) } #ifndef CONFIG_USER_ONLY +void HELPER(raise_stack_overflow)(CPUHexagonState *env, uint32_t slot, + uint32_t badva) +{ + /* + * Per section 7.3.1 of the V67 Programmer's Reference, + * stack limit exception isn't raised in monitor mode. + */ + uint32_t ssr = env->t_sreg[HEX_SREG_SSR]; + if (GET_SSR_FIELD(SSR_EX, ssr) || + !GET_SSR_FIELD(SSR_UM, ssr)) { + return; + } + + CPUState *cs = env_cpu(env); + cs->exception_index = HEX_EVENT_PRECISE; + env->cause_code = HEX_CAUSE_STACK_LIMIT; + ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index); + + if (slot == 0) { + env->t_sreg[HEX_SREG_BADVA0] = badva; + SET_SSR_FIELD(env, SSR_V0, 1); + SET_SSR_FIELD(env, SSR_V1, 0); + SET_SSR_FIELD(env, SSR_BVS, 0); + } else if (slot == 1) { + env->t_sreg[HEX_SREG_BADVA1] = badva; + SET_SSR_FIELD(env, SSR_V0, 0); + SET_SSR_FIELD(env, SSR_V1, 1); + SET_SSR_FIELD(env, SSR_BVS, 1); + } else { + g_assert_not_reached(); + } + cpu_loop_exit_restore(cs, 0); +} + void HELPER(ciad)(CPUHexagonState *env, uint32_t mask) { g_assert_not_reached(); -- 2.34.1
