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 <brian.cain@oss.qualcomm.com>
---
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