@@ -1955,25 +1955,32 @@ static int _hvm_emulate_one(struct hvm_e
memcpy(vio->mmio_insn, hvmemul_ctxt->insn_buf, vio->mmio_insn_bytes);
}
- if ( rc != X86EMUL_OKAY )
- return rc;
+ new_intr_shadow = hvmemul_ctxt->intr_shadow;
- if ( hvmemul_ctxt->ctxt.retire.singlestep )
- hvm_inject_hw_exception(TRAP_debug, X86_EVENT_NO_EC);
+ /*
+ * IRET, if valid in the given context, clears NMI blocking
+ * (irrespective of rc).
+ */
+ if ( hvmemul_ctxt->ctxt.retire.unblock_nmi )
+ new_intr_shadow &= ~HVM_INTR_SHADOW_NMI;
- new_intr_shadow = hvmemul_ctxt->intr_shadow;
+ if ( rc == X86EMUL_OKAY )
+ {
+ if ( hvmemul_ctxt->ctxt.retire.singlestep )
+ hvm_inject_hw_exception(TRAP_debug, X86_EVENT_NO_EC);
- /* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
- if ( hvmemul_ctxt->ctxt.retire.mov_ss )
- new_intr_shadow ^= HVM_INTR_SHADOW_MOV_SS;
- else
- new_intr_shadow &= ~HVM_INTR_SHADOW_MOV_SS;
-
- /* STI instruction toggles STI shadow, else we just clear it. */
- if ( hvmemul_ctxt->ctxt.retire.sti )
- new_intr_shadow ^= HVM_INTR_SHADOW_STI;
- else
- new_intr_shadow &= ~HVM_INTR_SHADOW_STI;
+ /* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
+ if ( hvmemul_ctxt->ctxt.retire.mov_ss )
+ new_intr_shadow ^= HVM_INTR_SHADOW_MOV_SS;
+ else
+ new_intr_shadow &= ~HVM_INTR_SHADOW_MOV_SS;
+
+ /* STI instruction toggles STI shadow, else we just clear it. */
+ if ( hvmemul_ctxt->ctxt.retire.sti )
+ new_intr_shadow ^= HVM_INTR_SHADOW_STI;
+ else
+ new_intr_shadow &= ~HVM_INTR_SHADOW_STI;
+ }
if ( hvmemul_ctxt->intr_shadow != new_intr_shadow )
{
@@ -1981,13 +1988,11 @@ static int _hvm_emulate_one(struct hvm_e
hvm_funcs.set_interrupt_shadow(curr, new_intr_shadow);
}
- if ( hvmemul_ctxt->ctxt.retire.hlt &&
+ if ( rc == X86EMUL_OKAY && hvmemul_ctxt->ctxt.retire.hlt &&
!hvm_local_events_need_delivery(curr) )
- {
hvm_hlt(regs->eflags);
- }
- return X86EMUL_OKAY;
+ return rc;
}
int hvm_emulate_one(
@@ -4002,6 +4002,7 @@ x86_emulate(
uint32_t mask = X86_EFLAGS_VIP | X86_EFLAGS_VIF | X86_EFLAGS_VM;
fail_if(!in_realmode(ctxt, ops));
+ ctxt->retire.unblock_nmi = true;
if ( (rc = read_ulong(x86_seg_ss, sp_post_inc(op_bytes),
&eip, op_bytes, ctxt, ops)) ||
(rc = read_ulong(x86_seg_ss, sp_post_inc(op_bytes),
@@ -490,6 +490,7 @@ struct x86_emulate_ctxt
bool hlt:1; /* Instruction HLTed. */
bool mov_ss:1; /* Instruction sets MOV-SS irq shadow. */
bool sti:1; /* Instruction sets STI irq shadow. */
+ bool unblock_nmi:1; /* Instruction clears NMI blocking. */
bool singlestep:1; /* Singlestepping was active. */
};
} retire;