On 8/20/2026 12:02 PM, Brian Cain wrote:
>
> On 8/20/2026 1:40 PM, Pierrick Bouvier wrote:
>> 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?
>
> The cause_code is part of CPUState. This TCGv is a reference to that
> state member for use with translation. We take advantage of the single-
> threaded nature of translation with all of these file-global TCGv values.
>
>
>>
>>> 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
Reviewed-by: Pierrick Bouvier <[email protected]>