[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.