On 8/18/2026 6:31 PM, Brian Cain wrote:
> System mode reports an exception as cs->exception_index = HEX_EVENT_* plus
> env->cause_code = HEX_CAUSE_*, but translated code in user mode put the cause
> code straight into exception_index, so cpu_loop() was decoding both forms.
> gen_exception_decode_fail() and the misaligned-PC check used the raw form
> unconditionally, so in system mode the cause code was misread as an event
> number.
>
> Use the {event, cause} everywhere and drop the duplicated cases
> from cpu_loop(), which fixes HEX_CAUSE_PRIV_USER_NO_SINSN and
> HEX_CAUSE_PRIV_USER_NO_GINSN. The misaligned PC is no longer zeroed
> on its way out either, so it reaches the signal frame as si_addr instead
> of whatever r31 held.
>
> Signed-off-by: Brian Cain <[email protected]>
> ---
> target/hexagon/translate.h | 2 +-
> linux-user/hexagon/cpu_loop.c | 30 +++++++++++-------------------
> target/hexagon/cpu.c | 3 ++-
> target/hexagon/translate.c | 27 +++++++++------------------
> 4 files changed, 23 insertions(+), 39 deletions(-)
>
> diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
> index 3c5773e2c73..00de2b0d2ec 100644
> --- a/target/hexagon/translate.h
> +++ b/target/hexagon/translate.h
> @@ -330,7 +330,7 @@ extern TCGv_i32 hex_t_sreg[NUM_SREGS];
> #endif
>
>
> -void hex_gen_exception_end_tb(DisasContext *ctx, int excp);
> +void hex_gen_exception_end_tb(DisasContext *ctx, int cause);
>
> void process_store(DisasContext *ctx, int slot_num);
>
> diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c
> index d7f73439dbc..e4ef97a1184 100644
> --- a/linux-user/hexagon/cpu_loop.c
> +++ b/linux-user/hexagon/cpu_loop.c
> @@ -66,21 +66,22 @@ void cpu_loop(CPUHexagonState *env)
> case HEX_CAUSE_FETCH_NO_UPAGE:
> case HEX_CAUSE_PRIV_NO_UREAD:
> case HEX_CAUSE_PRIV_NO_UWRITE:
> - force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
> - env->gpr[HEX_REG_PC]);
> -
> - break;
> + force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
> + env->gpr[HEX_REG_PC]);
> + break;
> case HEX_CAUSE_PRIV_USER_NO_GINSN:
> case HEX_CAUSE_PRIV_USER_NO_SINSN:
> case HEX_CAUSE_INVALID_PACKET:
> - force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC,
> - env->gpr[HEX_REG_PC]);
> - break;
> + case HEX_CAUSE_REG_WRITE_CONFLICT:
> + force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC,
> + env->gpr[HEX_REG_PC]);
> + break;
> case HEX_CAUSE_MISALIGNED_LOAD:
> case HEX_CAUSE_MISALIGNED_STORE:
> - force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
> - env->gpr[HEX_REG_PC]);
> - break;
> + case HEX_CAUSE_PC_NOT_ALIGNED:
> + force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
> + env->gpr[HEX_REG_PC]);
> + break;
> default:
> EXCP_DUMP(env, "\nqemu: unhandled CPU precise exception "
> "cause code 0x%x - aborting\n",
> @@ -88,15 +89,6 @@ void cpu_loop(CPUHexagonState *env)
> exit(EXIT_FAILURE);
> }
> break;
> - case HEX_CAUSE_PC_NOT_ALIGNED:
> - force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
> - env->gpr[HEX_REG_R31]);
> - break;
> - case HEX_CAUSE_INVALID_PACKET:
> - case HEX_CAUSE_REG_WRITE_CONFLICT:
> - force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC,
> - env->gpr[HEX_REG_PC]);
> - break;
> case EXCP_ATOMIC:
> cpu_exec_step_atomic(cs);
> break;
> diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
> index 7067e5b70f7..0bbefc2fb87 100644
> --- a/target/hexagon/cpu.c
> +++ b/target/hexagon/cpu.c
> @@ -323,7 +323,8 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState
> *cs)
> hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP, 1);
> }
> if (pc & PCALIGN_MASK) {
> - hexagon_raise_exception_err(env, HEX_CAUSE_PC_NOT_ALIGNED, 0);
> + env->cause_code = HEX_CAUSE_PC_NOT_ALIGNED;
> + hexagon_raise_exception_err(env, HEX_EVENT_PRECISE, pc);
> }
>
> #ifndef CONFIG_USER_ONLY
> diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
> index 06a8159d283..5cfa60ca302 100644
> --- a/target/hexagon/translate.c
> +++ b/target/hexagon/translate.c
> @@ -73,8 +73,8 @@ TCGv hex_vstore_pending[VSTORES_MAX];
> #ifndef CONFIG_USER_ONLY
> TCGv_i32 hex_greg[NUM_GREGS];
> TCGv_i32 hex_t_sreg[NUM_SREGS];
> -TCGv_i32 hex_cause_code;
> #endif
> +static TCGv_i32 hex_cause_code;
>
Shouldn't this be part of CPUState?
What if multiple cpus trigger an exception at the same time?
> static const char * const hexagon_prednames[] = {
> "p0", "p1", "p2", "p3"
> @@ -128,19 +128,14 @@ intptr_t ctx_tmp_vreg_off(DisasContext *ctx, int regnum,
> return offset;
> }
>
> -static void gen_exception(int excp, uint32_t PC)
> +static void gen_precise_exception(int cause, uint32_t PC)
> {
> - gen_helper_raise_exception(tcg_env, tcg_constant_i32(excp),
> + tcg_gen_movi_i32(hex_cause_code, cause);
> + gen_helper_raise_exception(tcg_env, tcg_constant_i32(HEX_EVENT_PRECISE),
> tcg_constant_i32(PC));
> }
>
> #ifndef CONFIG_USER_ONLY
> -static inline void gen_precise_exception(int excp, uint32_t PC)
> -{
> - tcg_gen_movi_i32(hex_cause_code, excp);
> - gen_exception(HEX_EVENT_PRECISE, PC);
> -}
> -
> static void gen_pcycle_counters(DisasContext *ctx)
> {
> if (ctx->pcycle_enabled) {
> @@ -224,14 +219,10 @@ static void gen_end_tb(DisasContext *ctx)
> ctx->base.is_jmp = DISAS_NORETURN;
> }
>
> -void hex_gen_exception_end_tb(DisasContext *ctx, int excp)
> +void hex_gen_exception_end_tb(DisasContext *ctx, int cause)
> {
> gen_exec_counters(ctx);
> -#ifdef CONFIG_USER_ONLY
> - gen_exception(excp, ctx->pkt.pc);
> -#else
> - gen_precise_exception(excp, ctx->pkt.pc);
> -#endif
> + gen_precise_exception(cause, ctx->pkt.pc);
> ctx->base.is_jmp = DISAS_NORETURN;
> }
>
> @@ -239,13 +230,13 @@ void hex_gen_exception_end_tb(DisasContext *ctx, int
> excp)
> * Generate exception for decode failures. Unlike gen_exception_end_tb,
> * this is used when decode fails before ctx->next_PC is initialized.
> */
> -static void gen_exception_decode_fail(DisasContext *ctx, int nwords, int
> excp)
> +static void gen_exception_decode_fail(DisasContext *ctx, int nwords, int
> cause)
> {
> target_ulong fail_pc = ctx->base.pc_next + nwords * sizeof(uint32_t);
>
> gen_exec_counters(ctx);
> tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], fail_pc);
> - gen_exception(excp, fail_pc);
> + gen_precise_exception(cause, fail_pc);
> ctx->base.is_jmp = DISAS_NORETURN;
> ctx->base.pc_next = fail_pc;
> }
> @@ -1361,9 +1352,9 @@ void hexagon_translate_init(void)
> offsetof(CPUHexagonState, llsc_val), "llsc_val");
> hex_llsc_val_i64 = tcg_global_mem_new_i64(tcg_env,
> offsetof(CPUHexagonState, llsc_val_i64), "llsc_val_i64");
> -#ifndef CONFIG_USER_ONLY
> hex_cause_code = tcg_global_mem_new_i32(tcg_env,
> offsetof(CPUHexagonState, cause_code), "cause_code");
> +#ifndef CONFIG_USER_ONLY
> hex_cycle_count = tcg_global_mem_new_i64(tcg_env,
> offsetof(CPUHexagonState, t_cycle_count), "t_cycle_count");
> #endif