qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2] target-i386: fix iret emulation correctness


From: poletaev
Subject: Re: [Qemu-devel] [PATCH v2] target-i386: fix iret emulation correctness
Date: Wed, 22 Jun 2016 10:18:22 +0300

ping

 

Best regards, 

Dmitry Poletaev.

 

From: poletaev [mailto:address@hidden 
Sent: Tuesday, June 07, 2016 5:12 PM
To: 'address@hidden'
Cc: 'address@hidden'
Subject: [PATCH v2] target-i386: fix iret emulation correctness

 

From: Dmitry Poletaev <address@hidden>

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 <address@hidden>

---

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.

 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]