Commit 48166a6c9e for qemu.org

commit 48166a6c9ed117fe35a5202acf8e49a9bc36f220
Author: Brian Cain <brian.cain@oss.qualcomm.com>
Date:   Mon Oct 5 12:45:19 2026 -0700

    target/hexagon: implement nmi

    Y4_nmi was a no-op, let's fill in the missing implementation.

    We'll raise CPU_INTERRUPT_NMI on each running thread in the mask.

    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@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 5ae2026eb2..6550e7fa80 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -393,7 +393,8 @@ static bool hexagon_cpu_has_work(CPUState *cs)

     return hexagon_thread_is_enabled(env) &&
         (cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_SWI
-            | CPU_INTERRUPT_K0_UNLOCK | CPU_INTERRUPT_TLB_UNLOCK));
+            | CPU_INTERRUPT_K0_UNLOCK | CPU_INTERRUPT_TLB_UNLOCK
+            | CPU_INTERRUPT_NMI));
 }
 #endif

@@ -759,6 +760,14 @@ static const struct SysemuCPUOps hexagon_sysemu_ops = {
 static bool hexagon_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 {
     CPUHexagonState *env = cpu_env(cs);
+    if (interrupt_request & CPU_INTERRUPT_NMI) {
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_NMI);
+        cs->halted = false;
+        cs->exception_index = HEX_EVENT_IMPRECISE;
+        env->cause_code = HEX_CAUSE_IMPRECISE_NMI;
+        hexagon_cpu_do_interrupt(cs);
+        return true;
+    }
     if (interrupt_request & CPU_INTERRUPT_TLB_UNLOCK) {
         cs->halted = false;
         cpu_reset_interrupt(cs, CPU_INTERRUPT_TLB_UNLOCK);
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 188a91e882..65fd2b2983 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -59,6 +59,7 @@ typedef struct HexagonHVXContextState HexagonHVXContextState;
 #define CPU_INTERRUPT_SWI      CPU_INTERRUPT_TGT_INT_0
 #define CPU_INTERRUPT_K0_UNLOCK CPU_INTERRUPT_TGT_INT_1
 #define CPU_INTERRUPT_TLB_UNLOCK CPU_INTERRUPT_TGT_INT_2
+#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_0

 #define HEX_CPU_MODE_USER    1
 #define HEX_CPU_MODE_GUEST   2
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index 0f999a48ac..c2fc27f1c0 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -539,6 +539,23 @@ void hexagon_stop_thread(CPUHexagonState *env)
     }
 }

+void hexagon_nmi(CPUHexagonState *env, uint32_t thread_mask)
+{
+    CPUState *cs;
+
+    BQL_LOCK_GUARD();
+
+    CPU_FOREACH(cs) {
+        CPUHexagonState *thread = cpu_env(cs);
+
+        if (!(thread_mask & (1u << thread->threadId)) ||
+            get_exe_mode(thread) == HEX_EXE_MODE_OFF) {
+            continue;
+        }
+        cpu_interrupt(cs, CPU_INTERRUPT_NMI);
+    }
+}
+
 static int sys_in_monitor_mode_ssr(uint32_t ssr)
 {
     if ((GET_SSR_FIELD(SSR_EX, ssr) != 0) ||
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index afb4df59f8..95a8f6587b 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -22,6 +22,7 @@ void clear_wait_mode(CPUHexagonState *env);
 void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause);
 void hexagon_start_threads(CPUHexagonState *env, uint32_t mask);
 void hexagon_stop_thread(CPUHexagonState *env);
+void hexagon_nmi(CPUHexagonState *env, uint32_t thread_mask);
 void hexagon_resume_threads(CPUHexagonState *env, uint32_t mask);
 uint64_t hexagon_get_sys_pcycle_count(CPUHexagonState *env);
 uint32_t hexagon_get_sys_pcycle_count_high(CPUHexagonState *env);
diff --git a/target/hexagon/sys_macros.h b/target/hexagon/sys_macros.h
index 72179d49ab..2e4cda29e6 100644
--- a/target/hexagon/sys_macros.h
+++ b/target/hexagon/sys_macros.h
@@ -253,7 +253,6 @@

 #define NUM_TLB_REGS(x) (hexagon_tlb_get_num_entries(env_archcpu(env)->tlb))

-/* NMI routing not yet implemented; Y4_nmi is a no-op for now */
-#define fDO_NMI(THREAD_MASK) do { } while (0)
+#define fDO_NMI(THREAD_MASK) hexagon_nmi(env, THREAD_MASK)

 #endif