diff --git a/cpu-all.h b/cpu-all.h index 21ed731a59..a4dee2196d 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -753,6 +753,7 @@ extern int code_copy_enabled; #define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt pending */ #define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */ #define CPU_INTERRUPT_VIRQ 0x100 /* virtual interrupt pending. */ +#define CPU_INTERRUPT_NMI 0x200 /* NMI pending. */ void cpu_interrupt(CPUState *s, int mask); void cpu_reset_interrupt(CPUState *env, int mask); diff --git a/cpu-exec.c b/cpu-exec.c index a17ea2f739..25dcf2b125 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -444,6 +444,12 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_SMI; do_smm_enter(); BREAK_CHAIN; + } else if ((interrupt_request & CPU_INTERRUPT_NMI) && + !(env->hflags & HF_NMI_MASK)) { + env->interrupt_request &= ~CPU_INTERRUPT_NMI; + env->hflags |= HF_NMI_MASK; + do_interrupt(EXCP02_NMI, 0, 0, 0, 1); + BREAK_CHAIN; } else if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 1c49b3691b..152b673ee9 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -148,6 +148,7 @@ #define HF_SMM_SHIFT 19 /* CPU in SMM mode */ #define HF_GIF_SHIFT 20 /* if set CPU takes interrupts */ #define HF_HIF_SHIFT 21 /* shadow copy of IF_MASK when in SVM */ +#define HF_NMI_SHIFT 22 /* CPU serving NMI */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT) #define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) @@ -167,6 +168,7 @@ #define HF_SMM_MASK (1 << HF_SMM_SHIFT) #define HF_GIF_MASK (1 << HF_GIF_SHIFT) #define HF_HIF_MASK (1 << HF_HIF_SHIFT) +#define HF_NMI_MASK (1 << HF_NMI_SHIFT) #define CR0_PE_MASK (1 << 0) #define CR0_MP_MASK (1 << 1) diff --git a/target-i386/exec.h b/target-i386/exec.h index 37fcdc01b7..11d12c9b00 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -593,8 +593,9 @@ static inline int cpu_halted(CPUState *env) { if (!(env->hflags & HF_HALTED_MASK)) return 0; /* disable halt condition */ - if ((env->interrupt_request & CPU_INTERRUPT_HARD) && - (env->eflags & IF_MASK)) { + if (((env->interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK)) || + (env->interrupt_request & CPU_INTERRUPT_NMI)) { env->hflags &= ~HF_HALTED_MASK; return 0; } diff --git a/target-i386/helper.c b/target-i386/helper.c index 69c2051f7c..b2c829926c 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -2383,6 +2383,7 @@ void helper_iret_real(int shift) if (shift == 0) eflags_mask &= 0xffff; load_eflags(new_eflags, eflags_mask); + env->hflags &= ~HF_NMI_MASK; } static inline void validate_seg(int seg_reg, int cpl) @@ -2634,6 +2635,7 @@ void helper_iret_protected(int shift, int next_eip) } else { helper_ret_protected(shift, 1, 0); } + env->hflags &= ~HF_NMI_MASK; #ifdef USE_KQEMU if (kqemu_is_ok(env)) { CC_OP = CC_OP_EFLAGS;