Commit 09c7cc31e1 for qemu.org

commit 09c7cc31e183f9c702e656f271a87240871c6bde
Author: Brian Cain <brian.cain@oss.qualcomm.com>
Date:   Tue Sep 1 10:33:43 2026 -0700

    target/hexagon: align exceptions for user/sysemu

    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.

    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
    Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>

diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c
index d7f73439db..e4ef97a118 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 47e3683d75..96d888149c 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 5463a07ec5..9d5402a982 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;

 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) {
@@ -230,14 +225,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;
 }

@@ -245,13 +236,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;
 }
@@ -1366,9 +1357,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
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index 3c5773e2c7..00de2b0d2e 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);