@samitouri / QOSamiQemu / commits / 54664e1362

target/hexagon: Implement stack overflow exception

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>

Brian Cain committed Jun 22, 2026 at 15:28 UTC 54664e1362fd30a8cd389905ebd6724e31bebf13
9 files changed +68 -10
target/hexagon/genptr.c
+11 -7
@@ -893,26 +893,30 @@ static void gen_load_frame(DisasContext *ctx, TCGv_i64 frame, TCGv EA)
893 tcg_gen_qemu_ld_i64(frame, EA, ctx->mem_idx, MO_LE | MO_UQ);
894 }
895
896 -#ifndef CONFIG_HEXAGON_IDEF_PARSER
896 /* Stack overflow check */
898 -static void gen_framecheck(TCGv EA, int framesize)
897 +void gen_framecheck(DisasContext *ctx, TCGv_i32 addr, TCGv_i32 ea)
898 {
900 - /* Not modelled in linux-user mode */
901 - /* Placeholder for system mode */
899 #ifndef CONFIG_USER_ONLY
903 - g_assert_not_reached();
900 + TCGLabel *ok = gen_new_label();
901 + tcg_gen_brcond_i32(TCG_COND_GEU, addr, hex_gpr[HEX_REG_FRAMELIMIT], ok);
902 + gen_helper_raise_stack_overflow(tcg_env,
903 + tcg_constant_i32(ctx->insn->slot), ea);
904 + gen_set_label(ok);
905 #endif
906 }
907
908 +#ifndef CONFIG_HEXAGON_IDEF_PARSER
909 static void gen_allocframe(DisasContext *ctx, TCGv r29, int framesize)
910 {
911 TCGv r30 = get_result_gpr(ctx, HEX_REG_FP);
912 + TCGv_i32 new_r29 = tcg_temp_new_i32();
913 TCGv_i64 frame;
914 tcg_gen_addi_tl(r30, r29, -8);
915 frame = gen_frame_scramble();
916 gen_store8(tcg_env, r30, frame, ctx->insn->slot);
914 - gen_framecheck(r30, framesize);
915 - tcg_gen_subi_tl(r29, r30, framesize);
917 + tcg_gen_subi_tl(new_r29, r30, framesize);
918 + gen_framecheck(ctx, new_r29, hex_gpr[HEX_REG_PC]);
919 + tcg_gen_mov_tl(r29, new_r29);
920 }
921
922 static void gen_deallocframe(DisasContext *ctx, TCGv_i64 r31_30, TCGv r30)
target/hexagon/helper.h
+1
@@ -109,6 +109,7 @@ DEF_HELPER_2(probe_hvx_stores, void, env, int)
109 DEF_HELPER_2(probe_pkt_scalar_hvx_stores, void, env, int)
110
111 #if !defined(CONFIG_USER_ONLY)
112 +DEF_HELPER_3(raise_stack_overflow, void, env, i32, i32)
113 DEF_HELPER_2(swi, void, env, i32)
114 DEF_HELPER_2(cswi, void, env, i32)
115 DEF_HELPER_2(ciad, void, env, i32)
target/hexagon/idef-parser/idef-parser.y
+3
@@ -404,6 +404,9 @@ control_statement : frame_check
404 ;
405
406 frame_check : FCHK '(' rvalue ',' rvalue ')' ';'
407 + {
408 + gen_framecheck(c, &@1, &$3, &$5);
409 + }
410 ;
411
412 cancel_statement : LOAD_CANCEL
target/hexagon/idef-parser/parser-helpers.c
+9
@@ -1731,6 +1731,15 @@ void gen_load_cancel(Context *c, YYLTYPE *locp)
1731 OUT(c, locp, "}\n");
1732 }
1733
1734 +void gen_framecheck(Context *c, YYLTYPE *locp, HexValue *addr, HexValue *ea)
1735 +{
1736 + HexValue addr_m = rvalue_materialize(c, locp, addr);
1737 + HexValue ea_m = rvalue_materialize(c, locp, ea);
1738 + addr_m = gen_rvalue_truncate(c, locp, &addr_m);
1739 + ea_m = gen_rvalue_truncate(c, locp, &ea_m);
1740 + OUT(c, locp, "gen_framecheck(ctx, ", &addr_m, ", ", &ea_m, ");\n");
1741 +}
1742 +
1743 void gen_load(Context *c, YYLTYPE *locp, HexValue *width,
1744 HexSignedness signedness, HexValue *ea, HexValue *dst)
1745 {
target/hexagon/idef-parser/parser-helpers.h
+2
@@ -295,6 +295,8 @@ void gen_cancel(Context *c, YYLTYPE *locp);
295
296 void gen_load_cancel(Context *c, YYLTYPE *locp);
297
298 +void gen_framecheck(Context *c, YYLTYPE *locp, HexValue *addr, HexValue *ea);
299 +
300 void gen_load(Context *c, YYLTYPE *locp, HexValue *size,
301 HexSignedness signedness, HexValue *ea, HexValue *dst);
302
target/hexagon/macros.h
-3
@@ -538,9 +538,6 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
538
539 #ifdef CONFIG_USER_ONLY
540 #define fFRAMECHECK(ADDR, EA) do { } while (0) /* Not modelled in linux-user */
541 -#else
542 -/* System mode not implemented yet */
543 -#define fFRAMECHECK(ADDR, EA) g_assert_not_reached();
541 #endif
542
543 #ifdef QEMU_GENERATE
target/hexagon/op_helper.c
+36
@@ -1393,6 +1393,42 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV)
1393 }
1394
1395 #ifndef CONFIG_USER_ONLY
1396 +void HELPER(raise_stack_overflow)(CPUHexagonState *env, uint32_t slot,
1397 + uint32_t badva)
1398 +{
1399 + /*
1400 + * Per section 7.3.1 of the V67 Programmer's Reference,
1401 + * stack limit exception isn't raised in monitor mode.
1402 + */
1403 + uint32_t ssr = env->t_sreg[HEX_SREG_SSR];
1404 + CPUState *cs;
1405 +
1406 + if (GET_SSR_FIELD(SSR_EX, ssr) ||
1407 + !GET_SSR_FIELD(SSR_UM, ssr)) {
1408 + return;
1409 + }
1410 +
1411 + cs = env_cpu(env);
1412 + cs->exception_index = HEX_EVENT_PRECISE;
1413 + env->cause_code = HEX_CAUSE_STACK_LIMIT;
1414 + ASSERT_DIRECT_TO_GUEST_UNSET(env, cs->exception_index);
1415 +
1416 + if (slot == 0) {
1417 + env->t_sreg[HEX_SREG_BADVA0] = badva;
1418 + SET_SSR_FIELD(env, SSR_V0, 1);
1419 + SET_SSR_FIELD(env, SSR_V1, 0);
1420 + SET_SSR_FIELD(env, SSR_BVS, 0);
1421 + } else if (slot == 1) {
1422 + env->t_sreg[HEX_SREG_BADVA1] = badva;
1423 + SET_SSR_FIELD(env, SSR_V0, 0);
1424 + SET_SSR_FIELD(env, SSR_V1, 1);
1425 + SET_SSR_FIELD(env, SSR_BVS, 1);
1426 + } else {
1427 + g_assert_not_reached();
1428 + }
1429 + cpu_loop_exit_restore(cs, 0);
1430 +}
1431 +
1432 void HELPER(ciad)(CPUHexagonState *env, uint32_t mask)
1433 {
1434 g_assert_not_reached();
target/hexagon/sys_macros.h
+4
@@ -97,6 +97,10 @@
97 #define fTRAP(TRAPTYPE, IMM) \
98 register_trap_exception(env, TRAPTYPE, IMM, PC)
99
100 +#ifdef QEMU_GENERATE
101 +#define fFRAMECHECK(ADDR, EA) gen_framecheck(ctx, ADDR, EA)
102 +#endif
103 +
104 #define fVIRTINSN_SPSWAP(IMM, REG)
105 #define fVIRTINSN_GETIE(IMM, REG) { REG = 0xdeafbeef; }
106 #define fVIRTINSN_SETIE(IMM, REG)
target/hexagon/translate.h
+2
@@ -341,4 +341,6 @@ FIELD(PROBE_PKT_SCALAR_HVX_STORES, S0_IS_PRED, 3, 1)
341 FIELD(PROBE_PKT_SCALAR_HVX_STORES, S1_IS_PRED, 4, 1)
342 FIELD(PROBE_PKT_SCALAR_HVX_STORES, MMU_IDX, 5, 2)
343
344 +void gen_framecheck(DisasContext *ctx, TCGv_i32 addr, TCGv_i32 ea);
345 +
346 #endif