Commit 6ccd5ff3e8 for qemu.org

commit 6ccd5ff3e8328b393d0efc31ecb6ad82ddfb5585
Author: Brian Cain <brian.cain@oss.qualcomm.com>
Date:   Wed Sep 23 10:15:13 2026 -0700

    target/hexagon: raise an exception for HVX with SSR:XE clear

    SSR:XE gates access to the HVX coprocessor: executing an HVX instruction
    while it is clear must raise a precise exception with cause 0x16,
    NO_COPROC_ENABLE.

    Carry SSR:XE in a TB flag and emit the exception for the
    first HVX packet of a TB when the coprocessor is disabled.

    Reviewed-by: Marco Liebel <marco.liebel@oss.qualcomm.com>
    Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>

diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index fad526ccfb..19486e0f74 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -340,6 +340,8 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
     hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX,
                            cpu_mmu_index(env_cpu(env), false));
     hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, PCYCLE_ENABLED, 1);
+    hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, HVX_COPROC_ENABLED,
+                           GET_SSR_FIELD(SSR_XE, env->t_sreg[HEX_SREG_SSR]));
 #else
     hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, MMU_USER_IDX);
 #endif
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index b1533680bd..97f689fda2 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -207,6 +207,7 @@ struct ArchCPU {
 FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1)
 FIELD(TB_FLAGS, MMU_INDEX, 1, 3)
 FIELD(TB_FLAGS, PCYCLE_ENABLED, 4, 1)
+FIELD(TB_FLAGS, HVX_COPROC_ENABLED, 5, 1)

 G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env,
                                             uint32_t exception,
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 8561cec4e4..bf92166e0f 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -766,6 +766,14 @@ static void gen_start_packet(DisasContext *ctx)
             i = find_next_bit(ctx->predicated_tmp_vregs, NUM_VREGS, i + 1);
         }
     }
+
+#ifndef CONFIG_USER_ONLY
+    if (ctx->pkt.pkt_has_hvx && !ctx->hvx_coproc_enabled &&
+        !ctx->hvx_check_emitted) {
+        gen_precise_exception(HEX_CAUSE_NO_COPROC_ENABLE, ctx->pkt.pc);
+        ctx->hvx_check_emitted = true;
+    }
+#endif
 }

 bool is_gather_store_insn(DisasContext *ctx)
@@ -1289,6 +1297,9 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase,
 #ifndef CONFIG_USER_ONLY
     ctx->num_cycles = 0;
     ctx->pcycle_enabled = FIELD_EX32(hex_flags, TB_FLAGS, PCYCLE_ENABLED);
+    ctx->hvx_coproc_enabled =
+        FIELD_EX32(hex_flags, TB_FLAGS, HVX_COPROC_ENABLED);
+    ctx->hvx_check_emitted = false;
 #endif
 }

diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index b90f7fff1c..b33d5dbdbe 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -98,6 +98,8 @@ typedef struct DisasContext {
     TCGv branch_taken;
     TCGv dczero_addr;
     bool pcycle_enabled;
+    bool hvx_coproc_enabled;
+    bool hvx_check_emitted;
     uint32_t num_cycles;
 } DisasContext;