ping
Best regards, Dmitry Poletaev. From: poletaev [mailto:dmitry.polet...@ispras.ru] Sent: Tuesday, June 07, 2016 5:12 PM To: 'qemu-devel@nongnu.org' Cc: 'pavel.dovga...@ispras.ru' Subject: [PATCH v2] target-i386: fix iret emulation correctness From: Dmitry Poletaev <dmitry.polet...@ispras.ru> Subject: [PATCH v2] target-i386: fix iret emulation correctness According to Intel manual: "If the NMI handler is a virtual-8086 task with an IOPL of less than 3, an IRET instruction issued from the handler generates a general-protection exception, the NMI is unmasked before the general-protection exception handler is invoked." QEMU does not reset NMI-blocking in such situation. This patch fixes it. Signed-off-by: Dmitry Poletaev <dmitry.polet...@ispras.ru> --- v2: HF2_NMI_MASK was moved to hflags, situation from discussion leads to NMI-blocking reset and eob generation target-i386/cpu.h | 5 +++-- target-i386/kvm.c | 6 +++--- target-i386/seg_helper.c | 8 ++++---- target-i386/smm_helper.c | 6 +++--- target-i386/translate.c | 7 ++++++- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 0426459..8857034 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -158,6 +158,7 @@ #define HF_IOBPT_SHIFT 24 /* an io breakpoint enabled */ #define HF_MPX_EN_SHIFT 25 /* MPX Enabled (CR4+XCR0+BNDCFGx) */ #define HF_MPX_IU_SHIFT 26 /* BND registers in-use */ +#define HF_NMI_SHIFT 27 /* CPU serving NMI */ #define HF_CPL_MASK (3 << HF_CPL_SHIFT) #define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) @@ -184,19 +185,19 @@ #define HF_IOBPT_MASK (1 << HF_IOBPT_SHIFT) #define HF_MPX_EN_MASK (1 << HF_MPX_EN_SHIFT) #define HF_MPX_IU_MASK (1 << HF_MPX_IU_SHIFT) +#define HF_NMI_MASK (1 << HF_NMI_SHIFT) /* hflags2 */ #define HF2_GIF_SHIFT 0 /* if set CPU takes interrupts */ #define HF2_HIF_SHIFT 1 /* value of IF_MASK when entering SVM */ -#define HF2_NMI_SHIFT 2 /* CPU serving NMI */ +/* 2 is vacant */ #define HF2_VINTR_SHIFT 3 /* value of V_INTR_MASKING bit */ #define HF2_SMM_INSIDE_NMI_SHIFT 4 /* CPU serving SMI nested inside NMI */ #define HF2_MPX_PR_SHIFT 5 /* BNDCFGx.BNDPRESERVE */ #define HF2_GIF_MASK (1 << HF2_GIF_SHIFT) #define HF2_HIF_MASK (1 << HF2_HIF_SHIFT) -#define HF2_NMI_MASK (1 << HF2_NMI_SHIFT) #define HF2_VINTR_MASK (1 << HF2_VINTR_SHIFT) #define HF2_SMM_INSIDE_NMI_MASK (1 << HF2_SMM_INSIDE_NMI_SHIFT) #define HF2_MPX_PR_MASK (1 << HF2_MPX_PR_SHIFT) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index abf50e6..3fc204a 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -2357,7 +2357,7 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level) events.nmi.injected = env->nmi_injected; events.nmi.pending = env->nmi_pending; - events.nmi.masked = !!(env->hflags2 & HF2_NMI_MASK); + events.nmi.masked = !!(env->hflags & HF_NMI_MASK); events.nmi.pad = 0; events.sipi_vector = env->sipi_vector; @@ -2416,9 +2416,9 @@ static int kvm_get_vcpu_events(X86CPU *cpu) env->nmi_injected = events.nmi.injected; env->nmi_pending = events.nmi.pending; if (events.nmi.masked) { - env->hflags2 |= HF2_NMI_MASK; + env->hflags |= HF_NMI_MASK; } else { - env->hflags2 &= ~HF2_NMI_MASK; + env->hflags &= ~HF_NMI_MASK; } if (events.flags & KVM_VCPUEVENT_VALID_SMM) { diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index 97aee09..acda3e9 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -1333,9 +1333,9 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) do_smm_enter(cpu); ret = true; } else if ((interrupt_request & CPU_INTERRUPT_NMI) && - !(env->hflags2 & HF2_NMI_MASK)) { + !(env->hflags & HF_NMI_MASK)) { cs->interrupt_request &= ~CPU_INTERRUPT_NMI; - env->hflags2 |= HF2_NMI_MASK; + env->hflags |= HF_NMI_MASK; do_interrupt_x86_hardirq(env, EXCP02_NMI, 1); ret = true; } else if (interrupt_request & CPU_INTERRUPT_MCE) { @@ -1978,7 +1978,7 @@ void helper_iret_real(CPUX86State *env, int shift) eflags_mask &= 0xffff; } cpu_load_eflags(env, new_eflags, eflags_mask); - env->hflags2 &= ~HF2_NMI_MASK; + env->hflags &= ~HF_NMI_MASK; } static inline void validate_seg(CPUX86State *env, int seg_reg, int cpl) @@ -2253,7 +2253,7 @@ void helper_iret_protected(CPUX86State *env, int shift, int next_eip) } else { helper_ret_protected(env, shift, 1, 0, GETPC()); } - env->hflags2 &= ~HF2_NMI_MASK; + env->hflags &= ~HF_NMI_MASK; } void helper_lret_protected(CPUX86State *env, int shift, int addend) diff --git a/target-i386/smm_helper.c b/target-i386/smm_helper.c index 4dd6a2c..f5bec7b 100644 --- a/target-i386/smm_helper.c +++ b/target-i386/smm_helper.c @@ -64,10 +64,10 @@ void do_smm_enter(X86CPU *cpu) log_cpu_state_mask(CPU_LOG_INT, CPU(cpu), CPU_DUMP_CCOP); env->hflags |= HF_SMM_MASK; - if (env->hflags2 & HF2_NMI_MASK) { + if (env->hflags & HF_NMI_MASK) { env->hflags2 |= HF2_SMM_INSIDE_NMI_MASK; } else { - env->hflags2 |= HF2_NMI_MASK; + env->hflags |= HF_NMI_MASK; } cpu_smm_update(cpu); @@ -329,7 +329,7 @@ void helper_rsm(CPUX86State *env) } #endif if ((env->hflags2 & HF2_SMM_INSIDE_NMI_MASK) == 0) { - env->hflags2 &= ~HF2_NMI_MASK; + env->hflags &= ~HF_NMI_MASK; } env->hflags2 &= ~HF2_SMM_INSIDE_NMI_MASK; env->hflags &= ~HF_SMM_MASK; diff --git a/target-i386/translate.c b/target-i386/translate.c index f010022..fae87a2 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -6319,7 +6319,12 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, set_cc_op(s, CC_OP_EFLAGS); } else if (s->vm86) { if (s->iopl != 3) { - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + if (s->flags & HF_NMI_MASK) { + gen_reset_hflag(s, HF_NMI_MASK); + gen_jmp_im(pc_start - s->cs_base); + } else { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } } else { gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1)); set_cc_op(s, CC_OP_EFLAGS); -- 1.8.4.msysgit.0 Best regards, Dmitry Poletaev.