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