[PATCH v4 09/28] target/hexagon: Implement stack overflow exception

Brian Cain posted 28 patches 3 days, 14 hours ago
[PATCH v4 09/28] target/hexagon: Implement stack overflow exception
Posted by Brian Cain 3 days, 14 hours ago
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.

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
---
 target/hexagon/helper.h                     |  1 +
 target/hexagon/idef-parser/parser-helpers.h |  2 ++
 target/hexagon/macros.h                     |  3 --
 target/hexagon/sys_macros.h                 |  4 +++
 target/hexagon/translate.h                  |  2 ++
 target/hexagon/genptr.c                     | 18 +++++++----
 target/hexagon/idef-parser/parser-helpers.c |  9 ++++++
 target/hexagon/op_helper.c                  | 36 +++++++++++++++++++++
 target/hexagon/idef-parser/idef-parser.y    |  3 ++
 9 files changed, 68 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/idef-parser/parser-helpers.h b/target/hexagon/idef-parser/parser-helpers.h
index 2087d534a93..d3dfcec5690 100644
--- a/target/hexagon/idef-parser/parser-helpers.h
+++ b/target/hexagon/idef-parser/parser-helpers.h
@@ -295,6 +295,8 @@ void gen_cancel(Context *c, YYLTYPE *locp);
 
 void gen_load_cancel(Context *c, YYLTYPE *locp);
 
+void gen_framecheck(Context *c, YYLTYPE *locp, HexValue *addr, HexValue *ea);
+
 void gen_load(Context *c, YYLTYPE *locp, HexValue *size,
               HexSignedness signedness, HexValue *ea, HexValue *dst);
 
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 eaf48a865c2..4e090565aac 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -340,4 +340,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 63cbb7edbbc..129c13b637d 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -889,26 +889,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/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c
index 70bfa64432d..b942d9ea16b 100644
--- a/target/hexagon/idef-parser/parser-helpers.c
+++ b/target/hexagon/idef-parser/parser-helpers.c
@@ -1731,6 +1731,15 @@ void gen_load_cancel(Context *c, YYLTYPE *locp)
     OUT(c, locp, "}\n");
 }
 
+void gen_framecheck(Context *c, YYLTYPE *locp, HexValue *addr, HexValue *ea)
+{
+    HexValue addr_m = rvalue_materialize(c, locp, addr);
+    HexValue ea_m = rvalue_materialize(c, locp, ea);
+    addr_m = gen_rvalue_truncate(c, locp, &addr_m);
+    ea_m = gen_rvalue_truncate(c, locp, &ea_m);
+    OUT(c, locp, "gen_framecheck(ctx, ", &addr_m, ", ", &ea_m, ");\n");
+}
+
 void gen_load(Context *c, YYLTYPE *locp, HexValue *width,
               HexSignedness signedness, HexValue *ea, HexValue *dst)
 {
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index d40061de06e..6bc8287e8fe 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1392,6 +1392,42 @@ 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];
+    CPUState *cs;
+
+    if (GET_SSR_FIELD(SSR_EX, ssr) ||
+        !GET_SSR_FIELD(SSR_UM, ssr)) {
+        return;
+    }
+
+    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();
diff --git a/target/hexagon/idef-parser/idef-parser.y b/target/hexagon/idef-parser/idef-parser.y
index c6f17c6afa7..22070d8c3fe 100644
--- a/target/hexagon/idef-parser/idef-parser.y
+++ b/target/hexagon/idef-parser/idef-parser.y
@@ -404,6 +404,9 @@ control_statement : frame_check
                   ;
 
 frame_check : FCHK '(' rvalue ',' rvalue ')' ';'
+              {
+                  gen_framecheck(c, &@1, &$3, &$5);
+              }
             ;
 
 cancel_statement : LOAD_CANCEL
-- 
2.34.1