mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
hvm: More emulation changes: push some of the realmode or HVM-emulate
specific stuff into core x86_emulate(). Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
This commit is contained in:
1 parent
15adfd0426
commit
2ea2f369eb
13 files changed
+238
-281
No files matched your search
+42
-34
@@ -124,8 +124,9 @@ static int hvmemul_virtual_to_linear(
|
||||
|
||||
if ( !okay )
|
||||
{
|
||||
hvmemul_ctxt->flags.exn_pending = 1;
|
||||
hvmemul_ctxt->exn_pending = 1;
|
||||
hvmemul_ctxt->exn_vector = TRAP_gp_fault;
|
||||
hvmemul_ctxt->exn_error_code = 0;
|
||||
hvmemul_ctxt->exn_insn_len = 0;
|
||||
return X86EMUL_EXCEPTION;
|
||||
}
|
||||
@@ -439,9 +440,6 @@ static int hvmemul_write_segment(
|
||||
container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
|
||||
struct segment_register *sreg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
|
||||
|
||||
if ( seg == x86_seg_ss )
|
||||
hvmemul_ctxt->flags.mov_ss = 1;
|
||||
|
||||
memcpy(sreg, reg, sizeof(struct segment_register));
|
||||
__set_bit(seg, &hvmemul_ctxt->seg_reg_dirty);
|
||||
|
||||
@@ -571,17 +569,6 @@ static int hvmemul_write_msr(
|
||||
return hvm_funcs.msr_write_intercept(&_regs);
|
||||
}
|
||||
|
||||
static int hvmemul_write_rflags(
|
||||
unsigned long val,
|
||||
struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
struct hvm_emulate_ctxt *hvmemul_ctxt =
|
||||
container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
|
||||
if ( (val & X86_EFLAGS_IF) && !(ctxt->regs->eflags & X86_EFLAGS_IF) )
|
||||
hvmemul_ctxt->flags.sti = 1;
|
||||
return X86EMUL_OKAY;
|
||||
}
|
||||
|
||||
static int hvmemul_wbinvd(
|
||||
struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
@@ -600,28 +587,17 @@ static int hvmemul_cpuid(
|
||||
return X86EMUL_OKAY;
|
||||
}
|
||||
|
||||
static int hvmemul_hlt(
|
||||
struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
struct hvm_emulate_ctxt *hvmemul_ctxt =
|
||||
container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
|
||||
hvmemul_ctxt->flags.hlt = 1;
|
||||
return X86EMUL_OKAY;
|
||||
}
|
||||
|
||||
static int hvmemul_inject_hw_exception(
|
||||
uint8_t vector,
|
||||
uint16_t error_code,
|
||||
int32_t error_code,
|
||||
struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
struct hvm_emulate_ctxt *hvmemul_ctxt =
|
||||
container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
|
||||
|
||||
if ( error_code != 0 )
|
||||
return X86EMUL_UNHANDLEABLE;
|
||||
|
||||
hvmemul_ctxt->flags.exn_pending = 1;
|
||||
hvmemul_ctxt->exn_pending = 1;
|
||||
hvmemul_ctxt->exn_vector = vector;
|
||||
hvmemul_ctxt->exn_error_code = error_code;
|
||||
hvmemul_ctxt->exn_insn_len = 0;
|
||||
|
||||
return X86EMUL_OKAY;
|
||||
@@ -635,8 +611,9 @@ static int hvmemul_inject_sw_interrupt(
|
||||
struct hvm_emulate_ctxt *hvmemul_ctxt =
|
||||
container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
|
||||
|
||||
hvmemul_ctxt->flags.exn_pending = 1;
|
||||
hvmemul_ctxt->exn_pending = 1;
|
||||
hvmemul_ctxt->exn_vector = vector;
|
||||
hvmemul_ctxt->exn_error_code = -1;
|
||||
hvmemul_ctxt->exn_insn_len = insn_len;
|
||||
|
||||
return X86EMUL_OKAY;
|
||||
@@ -684,10 +661,8 @@ static struct x86_emulate_ops hvm_emulate_ops = {
|
||||
.write_cr = hvmemul_write_cr,
|
||||
.read_msr = hvmemul_read_msr,
|
||||
.write_msr = hvmemul_write_msr,
|
||||
.write_rflags = hvmemul_write_rflags,
|
||||
.wbinvd = hvmemul_wbinvd,
|
||||
.cpuid = hvmemul_cpuid,
|
||||
.hlt = hvmemul_hlt,
|
||||
.inject_hw_exception = hvmemul_inject_hw_exception,
|
||||
.inject_sw_interrupt = hvmemul_inject_sw_interrupt,
|
||||
.load_fpu_ctxt = hvmemul_load_fpu_ctxt,
|
||||
@@ -698,7 +673,9 @@ int hvm_emulate_one(
|
||||
struct hvm_emulate_ctxt *hvmemul_ctxt)
|
||||
{
|
||||
struct cpu_user_regs *regs = hvmemul_ctxt->ctxt.regs;
|
||||
uint32_t new_intr_shadow;
|
||||
unsigned long addr;
|
||||
int rc;
|
||||
|
||||
hvmemul_ctxt->ctxt.addr_size =
|
||||
hvmemul_ctxt->seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16;
|
||||
@@ -715,15 +692,46 @@ int hvm_emulate_one(
|
||||
hvmemul_ctxt->insn_buf, addr, sizeof(hvmemul_ctxt->insn_buf)))
|
||||
? sizeof(hvmemul_ctxt->insn_buf) : 0;
|
||||
|
||||
hvmemul_ctxt->flag_word = 0;
|
||||
hvmemul_ctxt->exn_pending = 0;
|
||||
|
||||
return x86_emulate(&hvmemul_ctxt->ctxt, &hvm_emulate_ops);
|
||||
rc = x86_emulate(&hvmemul_ctxt->ctxt, &hvm_emulate_ops);
|
||||
if ( rc != X86EMUL_OKAY )
|
||||
return rc;
|
||||
|
||||
new_intr_shadow = hvmemul_ctxt->intr_shadow;
|
||||
|
||||
/* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
|
||||
if ( hvmemul_ctxt->ctxt.retire.flags.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.flags.sti )
|
||||
new_intr_shadow ^= HVM_INTR_SHADOW_STI;
|
||||
else
|
||||
new_intr_shadow &= ~HVM_INTR_SHADOW_STI;
|
||||
|
||||
if ( hvmemul_ctxt->intr_shadow != new_intr_shadow )
|
||||
{
|
||||
hvmemul_ctxt->intr_shadow = new_intr_shadow;
|
||||
hvm_funcs.set_interrupt_shadow(current, new_intr_shadow);
|
||||
}
|
||||
|
||||
if ( hvmemul_ctxt->ctxt.retire.flags.hlt &&
|
||||
!hvm_local_events_need_delivery(current) )
|
||||
{
|
||||
hvm_hlt(regs->eflags);
|
||||
}
|
||||
|
||||
return X86EMUL_OKAY;
|
||||
}
|
||||
|
||||
void hvm_emulate_prepare(
|
||||
struct hvm_emulate_ctxt *hvmemul_ctxt,
|
||||
struct cpu_user_regs *regs)
|
||||
{
|
||||
hvmemul_ctxt->intr_shadow = hvm_funcs.get_interrupt_shadow(current);
|
||||
hvmemul_ctxt->ctxt.regs = regs;
|
||||
hvmemul_ctxt->ctxt.force_writeback = 1;
|
||||
hvmemul_ctxt->seg_reg_accessed = 0;
|
||||
|
||||
+15
-5
@@ -1640,12 +1640,22 @@ void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
|
||||
|
||||
enum hvm_intblk hvm_interrupt_blocked(struct vcpu *v, struct hvm_intack intack)
|
||||
{
|
||||
enum hvm_intblk r;
|
||||
unsigned long intr_shadow;
|
||||
|
||||
ASSERT(v == current);
|
||||
|
||||
r = hvm_funcs.interrupt_blocked(v, intack);
|
||||
if ( r != hvm_intblk_none )
|
||||
return r;
|
||||
if ( (intack.source != hvm_intsrc_nmi) &&
|
||||
!(guest_cpu_user_regs()->eflags & X86_EFLAGS_IF) )
|
||||
return hvm_intblk_rflags_ie;
|
||||
|
||||
intr_shadow = hvm_funcs.get_interrupt_shadow(v);
|
||||
|
||||
if ( intr_shadow & (HVM_INTR_SHADOW_STI|HVM_INTR_SHADOW_MOV_SS) )
|
||||
return hvm_intblk_shadow;
|
||||
|
||||
if ( intack.source == hvm_intsrc_nmi )
|
||||
return ((intr_shadow & HVM_INTR_SHADOW_NMI) ?
|
||||
hvm_intblk_nmi_iret : hvm_intblk_none);
|
||||
|
||||
if ( intack.source == hvm_intsrc_lapic )
|
||||
{
|
||||
@@ -1654,7 +1664,7 @@ enum hvm_intblk hvm_interrupt_blocked(struct vcpu *v, struct hvm_intack intack)
|
||||
return hvm_intblk_tpr;
|
||||
}
|
||||
|
||||
return r;
|
||||
return hvm_intblk_none;
|
||||
}
|
||||
|
||||
static long hvm_grant_table_op(
|
||||
|
||||
@@ -262,8 +262,8 @@ int handle_mmio(void)
|
||||
ctxt.insn_buf[4], ctxt.insn_buf[5]);
|
||||
return 0;
|
||||
case X86EMUL_EXCEPTION:
|
||||
if ( ctxt.flags.exn_pending )
|
||||
hvm_inject_exception(ctxt.exn_vector, 0, 0);
|
||||
if ( ctxt.exn_pending )
|
||||
hvm_inject_exception(ctxt.exn_vector, ctxt.exn_error_code, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
+11
-17
@@ -366,24 +366,17 @@ static void svm_fpu_leave(struct vcpu *v)
|
||||
}
|
||||
}
|
||||
|
||||
static enum hvm_intblk svm_interrupt_blocked(
|
||||
struct vcpu *v, struct hvm_intack intack)
|
||||
static unsigned int svm_get_interrupt_shadow(struct vcpu *v)
|
||||
{
|
||||
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
|
||||
return (vmcb->interrupt_shadow ? HVM_INTR_SHADOW_MOV_SS : 0);
|
||||
}
|
||||
|
||||
if ( vmcb->interrupt_shadow )
|
||||
return hvm_intblk_shadow;
|
||||
|
||||
if ( intack.source == hvm_intsrc_nmi )
|
||||
return hvm_intblk_none;
|
||||
|
||||
ASSERT((intack.source == hvm_intsrc_pic) ||
|
||||
(intack.source == hvm_intsrc_lapic));
|
||||
|
||||
if ( !(guest_cpu_user_regs()->eflags & X86_EFLAGS_IF) )
|
||||
return hvm_intblk_rflags_ie;
|
||||
|
||||
return hvm_intblk_none;
|
||||
static void svm_set_interrupt_shadow(struct vcpu *v, unsigned int intr_shadow)
|
||||
{
|
||||
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
|
||||
vmcb->interrupt_shadow = !!(vmcb->interrupt_shadow &
|
||||
(HVM_INTR_SHADOW_MOV_SS|HVM_INTR_SHADOW_STI));
|
||||
}
|
||||
|
||||
static int svm_guest_x86_mode(struct vcpu *v)
|
||||
@@ -779,7 +772,8 @@ static struct hvm_function_table svm_function_table = {
|
||||
.vcpu_destroy = svm_vcpu_destroy,
|
||||
.save_cpu_ctxt = svm_save_vmcb_ctxt,
|
||||
.load_cpu_ctxt = svm_load_vmcb_ctxt,
|
||||
.interrupt_blocked = svm_interrupt_blocked,
|
||||
.get_interrupt_shadow = svm_get_interrupt_shadow,
|
||||
.set_interrupt_shadow = svm_set_interrupt_shadow,
|
||||
.guest_x86_mode = svm_guest_x86_mode,
|
||||
.get_segment_register = svm_get_segment_register,
|
||||
.set_segment_register = svm_set_segment_register,
|
||||
@@ -1176,7 +1170,7 @@ static void svm_vmexit_do_hlt(struct vmcb_struct *vmcb,
|
||||
/* Check for pending exception or new interrupt. */
|
||||
if ( vmcb->eventinj.fields.v ||
|
||||
((intack.source != hvm_intsrc_none) &&
|
||||
!svm_interrupt_blocked(current, intack)) )
|
||||
!hvm_interrupt_blocked(current, intack)) )
|
||||
{
|
||||
HVMTRACE_1D(HLT, curr, /*int pending=*/ 1);
|
||||
return;
|
||||
|
||||
@@ -65,10 +65,6 @@
|
||||
* Injecting a virtual NMI sets the NMI-blocking interruptibility flag only
|
||||
* if the 'virtual NMIs' control is set. Injecting *any* kind of event clears
|
||||
* the STI- and MOV-SS-blocking interruptibility-state flags.
|
||||
*
|
||||
* If MOV/POP SS is executed while MOV-SS-blocking is in effect, the effect
|
||||
* is cleared. If STI is executed while MOV-SS- or STI-blocking is in effect,
|
||||
* the effect is cleared. (i.e., MOV-SS-blocking 'dominates' STI-blocking).
|
||||
*/
|
||||
|
||||
static void enable_intr_window(struct vcpu *v, struct hvm_intack intack)
|
||||
|
||||
@@ -21,25 +21,20 @@
|
||||
#include <asm/hvm/vmx/vmx.h>
|
||||
#include <asm/hvm/vmx/vmcs.h>
|
||||
|
||||
struct realmode_emulate_ctxt {
|
||||
struct hvm_emulate_ctxt hvm;
|
||||
uint32_t intr_shadow;
|
||||
};
|
||||
|
||||
static void realmode_deliver_exception(
|
||||
unsigned int vector,
|
||||
unsigned int insn_len,
|
||||
struct realmode_emulate_ctxt *rm_ctxt)
|
||||
struct hvm_emulate_ctxt *hvmemul_ctxt)
|
||||
{
|
||||
struct segment_register *idtr, *csr;
|
||||
struct cpu_user_regs *regs = rm_ctxt->hvm.ctxt.regs;
|
||||
struct cpu_user_regs *regs = hvmemul_ctxt->ctxt.regs;
|
||||
uint32_t cs_eip, pstk;
|
||||
uint16_t frame[3];
|
||||
unsigned int last_byte;
|
||||
|
||||
idtr = hvmemul_get_seg_reg(x86_seg_idtr, &rm_ctxt->hvm);
|
||||
csr = hvmemul_get_seg_reg(x86_seg_cs, &rm_ctxt->hvm);
|
||||
__set_bit(x86_seg_cs, &rm_ctxt->hvm.seg_reg_dirty);
|
||||
idtr = hvmemul_get_seg_reg(x86_seg_idtr, hvmemul_ctxt);
|
||||
csr = hvmemul_get_seg_reg(x86_seg_cs, hvmemul_ctxt);
|
||||
__set_bit(x86_seg_cs, &hvmemul_ctxt->seg_reg_dirty);
|
||||
|
||||
again:
|
||||
last_byte = (vector * 4) + 3;
|
||||
@@ -74,7 +69,7 @@ static void realmode_deliver_exception(
|
||||
frame[1] = csr->sel;
|
||||
frame[2] = regs->eflags & ~X86_EFLAGS_RF;
|
||||
|
||||
if ( rm_ctxt->hvm.ctxt.addr_size == 32 )
|
||||
if ( hvmemul_ctxt->ctxt.addr_size == 32 )
|
||||
{
|
||||
regs->esp -= 6;
|
||||
pstk = regs->esp;
|
||||
@@ -86,7 +81,7 @@ static void realmode_deliver_exception(
|
||||
regs->esp |= pstk;
|
||||
}
|
||||
|
||||
pstk += hvmemul_get_seg_reg(x86_seg_ss, &rm_ctxt->hvm)->base;
|
||||
pstk += hvmemul_get_seg_reg(x86_seg_ss, hvmemul_ctxt)->base;
|
||||
(void)hvm_copy_to_guest_phys(pstk, frame, sizeof(frame));
|
||||
|
||||
csr->sel = cs_eip >> 16;
|
||||
@@ -95,41 +90,42 @@ static void realmode_deliver_exception(
|
||||
regs->eflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_IF | X86_EFLAGS_RF);
|
||||
|
||||
/* Exception delivery clears STI and MOV-SS blocking. */
|
||||
if ( rm_ctxt->intr_shadow & (VMX_INTR_SHADOW_STI|VMX_INTR_SHADOW_MOV_SS) )
|
||||
if ( hvmemul_ctxt->intr_shadow &
|
||||
(VMX_INTR_SHADOW_STI|VMX_INTR_SHADOW_MOV_SS) )
|
||||
{
|
||||
rm_ctxt->intr_shadow &= ~(VMX_INTR_SHADOW_STI|VMX_INTR_SHADOW_MOV_SS);
|
||||
__vmwrite(GUEST_INTERRUPTIBILITY_INFO, rm_ctxt->intr_shadow);
|
||||
hvmemul_ctxt->intr_shadow &=
|
||||
~(VMX_INTR_SHADOW_STI|VMX_INTR_SHADOW_MOV_SS);
|
||||
__vmwrite(GUEST_INTERRUPTIBILITY_INFO, hvmemul_ctxt->intr_shadow);
|
||||
}
|
||||
}
|
||||
|
||||
static void realmode_emulate_one(struct realmode_emulate_ctxt *rm_ctxt)
|
||||
static void realmode_emulate_one(struct hvm_emulate_ctxt *hvmemul_ctxt)
|
||||
{
|
||||
struct cpu_user_regs *regs = rm_ctxt->hvm.ctxt.regs;
|
||||
struct vcpu *curr = current;
|
||||
unsigned long seg_reg_dirty;
|
||||
uint32_t new_intr_shadow, intr_info;
|
||||
uint32_t intr_info;
|
||||
int rc;
|
||||
|
||||
seg_reg_dirty = rm_ctxt->hvm.seg_reg_dirty;
|
||||
rm_ctxt->hvm.seg_reg_dirty = 0;
|
||||
seg_reg_dirty = hvmemul_ctxt->seg_reg_dirty;
|
||||
hvmemul_ctxt->seg_reg_dirty = 0;
|
||||
|
||||
rc = hvm_emulate_one(&rm_ctxt->hvm);
|
||||
rc = hvm_emulate_one(hvmemul_ctxt);
|
||||
|
||||
if ( test_bit(x86_seg_cs, &rm_ctxt->hvm.seg_reg_dirty) )
|
||||
if ( test_bit(x86_seg_cs, &hvmemul_ctxt->seg_reg_dirty) )
|
||||
{
|
||||
curr->arch.hvm_vmx.vmxemul &= ~VMXEMUL_BAD_CS;
|
||||
if ( hvmemul_get_seg_reg(x86_seg_cs, &rm_ctxt->hvm)->sel & 3 )
|
||||
if ( hvmemul_get_seg_reg(x86_seg_cs, hvmemul_ctxt)->sel & 3 )
|
||||
curr->arch.hvm_vmx.vmxemul |= VMXEMUL_BAD_CS;
|
||||
}
|
||||
|
||||
if ( test_bit(x86_seg_ss, &rm_ctxt->hvm.seg_reg_dirty) )
|
||||
if ( test_bit(x86_seg_ss, &hvmemul_ctxt->seg_reg_dirty) )
|
||||
{
|
||||
curr->arch.hvm_vmx.vmxemul &= ~VMXEMUL_BAD_SS;
|
||||
if ( hvmemul_get_seg_reg(x86_seg_ss, &rm_ctxt->hvm)->sel & 3 )
|
||||
if ( hvmemul_get_seg_reg(x86_seg_ss, hvmemul_ctxt)->sel & 3 )
|
||||
curr->arch.hvm_vmx.vmxemul |= VMXEMUL_BAD_SS;
|
||||
}
|
||||
|
||||
rm_ctxt->hvm.seg_reg_dirty |= seg_reg_dirty;
|
||||
hvmemul_ctxt->seg_reg_dirty |= seg_reg_dirty;
|
||||
|
||||
if ( rc == X86EMUL_UNHANDLEABLE )
|
||||
{
|
||||
@@ -137,33 +133,9 @@ static void realmode_emulate_one(struct realmode_emulate_ctxt *rm_ctxt)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( rc == X86EMUL_RETRY )
|
||||
return;
|
||||
|
||||
new_intr_shadow = rm_ctxt->intr_shadow;
|
||||
|
||||
/* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
|
||||
if ( rm_ctxt->hvm.flags.mov_ss )
|
||||
new_intr_shadow ^= VMX_INTR_SHADOW_MOV_SS;
|
||||
else
|
||||
new_intr_shadow &= ~VMX_INTR_SHADOW_MOV_SS;
|
||||
|
||||
/* STI instruction toggles STI shadow, else we just clear it. */
|
||||
if ( rm_ctxt->hvm.flags.sti )
|
||||
new_intr_shadow ^= VMX_INTR_SHADOW_STI;
|
||||
else
|
||||
new_intr_shadow &= ~VMX_INTR_SHADOW_STI;
|
||||
|
||||
/* Update interrupt shadow information in VMCS only if it changes. */
|
||||
if ( rm_ctxt->intr_shadow != new_intr_shadow )
|
||||
{
|
||||
rm_ctxt->intr_shadow = new_intr_shadow;
|
||||
__vmwrite(GUEST_INTERRUPTIBILITY_INFO, rm_ctxt->intr_shadow);
|
||||
}
|
||||
|
||||
if ( rc == X86EMUL_EXCEPTION )
|
||||
{
|
||||
if ( !rm_ctxt->hvm.flags.exn_pending )
|
||||
if ( !hvmemul_ctxt->exn_pending )
|
||||
{
|
||||
intr_info = __vmread(VM_ENTRY_INTR_INFO);
|
||||
__vmwrite(VM_ENTRY_INTR_INFO, 0);
|
||||
@@ -172,23 +144,21 @@ static void realmode_emulate_one(struct realmode_emulate_ctxt *rm_ctxt)
|
||||
gdprintk(XENLOG_ERR, "Exception pending but no info.\n");
|
||||
goto fail;
|
||||
}
|
||||
rm_ctxt->hvm.exn_vector = (uint8_t)intr_info;
|
||||
rm_ctxt->hvm.exn_insn_len = 0;
|
||||
hvmemul_ctxt->exn_vector = (uint8_t)intr_info;
|
||||
hvmemul_ctxt->exn_insn_len = 0;
|
||||
}
|
||||
|
||||
if ( curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE )
|
||||
{
|
||||
gdprintk(XENLOG_ERR, "Exception %02x in protected mode.\n",
|
||||
rm_ctxt->hvm.exn_vector);
|
||||
hvmemul_ctxt->exn_vector);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
realmode_deliver_exception(
|
||||
rm_ctxt->hvm.exn_vector, rm_ctxt->hvm.exn_insn_len, rm_ctxt);
|
||||
}
|
||||
else if ( rm_ctxt->hvm.flags.hlt && !hvm_local_events_need_delivery(curr) )
|
||||
{
|
||||
hvm_hlt(regs->eflags);
|
||||
hvmemul_ctxt->exn_vector,
|
||||
hvmemul_ctxt->exn_insn_len,
|
||||
hvmemul_ctxt);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -197,18 +167,18 @@ static void realmode_emulate_one(struct realmode_emulate_ctxt *rm_ctxt)
|
||||
gdprintk(XENLOG_ERR,
|
||||
"Real-mode emulation failed @ %04x:%08lx: "
|
||||
"%02x %02x %02x %02x %02x %02x\n",
|
||||
hvmemul_get_seg_reg(x86_seg_cs, &rm_ctxt->hvm)->sel,
|
||||
rm_ctxt->hvm.insn_buf_eip,
|
||||
rm_ctxt->hvm.insn_buf[0], rm_ctxt->hvm.insn_buf[1],
|
||||
rm_ctxt->hvm.insn_buf[2], rm_ctxt->hvm.insn_buf[3],
|
||||
rm_ctxt->hvm.insn_buf[4], rm_ctxt->hvm.insn_buf[5]);
|
||||
hvmemul_get_seg_reg(x86_seg_cs, hvmemul_ctxt)->sel,
|
||||
hvmemul_ctxt->insn_buf_eip,
|
||||
hvmemul_ctxt->insn_buf[0], hvmemul_ctxt->insn_buf[1],
|
||||
hvmemul_ctxt->insn_buf[2], hvmemul_ctxt->insn_buf[3],
|
||||
hvmemul_ctxt->insn_buf[4], hvmemul_ctxt->insn_buf[5]);
|
||||
domain_crash_synchronous();
|
||||
}
|
||||
|
||||
void vmx_realmode(struct cpu_user_regs *regs)
|
||||
{
|
||||
struct vcpu *curr = current;
|
||||
struct realmode_emulate_ctxt rm_ctxt;
|
||||
struct hvm_emulate_ctxt hvmemul_ctxt;
|
||||
struct segment_register *sreg;
|
||||
unsigned long intr_info;
|
||||
unsigned int emulations = 0;
|
||||
@@ -218,17 +188,16 @@ void vmx_realmode(struct cpu_user_regs *regs)
|
||||
if ( intr_info & INTR_INFO_VALID_MASK )
|
||||
__vmwrite(VM_ENTRY_INTR_INFO, 0);
|
||||
|
||||
hvm_emulate_prepare(&rm_ctxt.hvm, regs);
|
||||
rm_ctxt.intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
|
||||
hvm_emulate_prepare(&hvmemul_ctxt, regs);
|
||||
|
||||
if ( curr->arch.hvm_vcpu.io_completed )
|
||||
realmode_emulate_one(&rm_ctxt);
|
||||
realmode_emulate_one(&hvmemul_ctxt);
|
||||
|
||||
/* Only deliver interrupts into emulated real mode. */
|
||||
if ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) &&
|
||||
(intr_info & INTR_INFO_VALID_MASK) )
|
||||
{
|
||||
realmode_deliver_exception((uint8_t)intr_info, 0, &rm_ctxt);
|
||||
realmode_deliver_exception((uint8_t)intr_info, 0, &hvmemul_ctxt);
|
||||
intr_info = 0;
|
||||
}
|
||||
|
||||
@@ -245,7 +214,7 @@ void vmx_realmode(struct cpu_user_regs *regs)
|
||||
!(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) &&
|
||||
hvm_local_events_need_delivery(curr) )
|
||||
break;
|
||||
realmode_emulate_one(&rm_ctxt);
|
||||
realmode_emulate_one(&hvmemul_ctxt);
|
||||
}
|
||||
|
||||
if ( !curr->arch.hvm_vmx.vmxemul )
|
||||
@@ -255,20 +224,20 @@ void vmx_realmode(struct cpu_user_regs *regs)
|
||||
* At this point CS.RPL == SS.RPL == CS.DPL == SS.DPL == 0. For
|
||||
* DS, ES, FS and GS the most uninvasive trick is to set DPL == RPL.
|
||||
*/
|
||||
sreg = hvmemul_get_seg_reg(x86_seg_ds, &rm_ctxt.hvm);
|
||||
sreg = hvmemul_get_seg_reg(x86_seg_ds, &hvmemul_ctxt);
|
||||
sreg->attr.fields.dpl = sreg->sel & 3;
|
||||
sreg = hvmemul_get_seg_reg(x86_seg_es, &rm_ctxt.hvm);
|
||||
sreg = hvmemul_get_seg_reg(x86_seg_es, &hvmemul_ctxt);
|
||||
sreg->attr.fields.dpl = sreg->sel & 3;
|
||||
sreg = hvmemul_get_seg_reg(x86_seg_fs, &rm_ctxt.hvm);
|
||||
sreg = hvmemul_get_seg_reg(x86_seg_fs, &hvmemul_ctxt);
|
||||
sreg->attr.fields.dpl = sreg->sel & 3;
|
||||
sreg = hvmemul_get_seg_reg(x86_seg_gs, &rm_ctxt.hvm);
|
||||
sreg = hvmemul_get_seg_reg(x86_seg_gs, &hvmemul_ctxt);
|
||||
sreg->attr.fields.dpl = sreg->sel & 3;
|
||||
rm_ctxt.hvm.seg_reg_dirty |=
|
||||
hvmemul_ctxt.seg_reg_dirty |=
|
||||
(1ul << x86_seg_ds) | (1ul << x86_seg_es) |
|
||||
(1ul << x86_seg_fs) | (1ul << x86_seg_gs);
|
||||
}
|
||||
|
||||
hvm_emulate_writeback(&rm_ctxt.hvm);
|
||||
hvm_emulate_writeback(&hvmemul_ctxt);
|
||||
|
||||
/* Re-instate VM_ENTRY_INTR_INFO if we did not discharge it. */
|
||||
if ( intr_info & INTR_INFO_VALID_MASK )
|
||||
|
||||
@@ -890,32 +890,14 @@ static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page)
|
||||
*(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */
|
||||
}
|
||||
|
||||
static enum hvm_intblk vmx_interrupt_blocked(
|
||||
struct vcpu *v, struct hvm_intack intack)
|
||||
static unsigned int vmx_get_interrupt_shadow(struct vcpu *v)
|
||||
{
|
||||
unsigned long intr_shadow;
|
||||
return __vmread(GUEST_INTERRUPTIBILITY_INFO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test EFLAGS.IF first. It is often the most likely reason for interrupt
|
||||
* blockage, and is the cheapest to test (because no VMREAD is required).
|
||||
*/
|
||||
if ( (intack.source != hvm_intsrc_nmi) &&
|
||||
!(guest_cpu_user_regs()->eflags & X86_EFLAGS_IF) )
|
||||
return hvm_intblk_rflags_ie;
|
||||
|
||||
intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
|
||||
|
||||
if ( intr_shadow & (VMX_INTR_SHADOW_STI|VMX_INTR_SHADOW_MOV_SS) )
|
||||
return hvm_intblk_shadow;
|
||||
|
||||
if ( intack.source == hvm_intsrc_nmi )
|
||||
return ((intr_shadow & VMX_INTR_SHADOW_NMI) ?
|
||||
hvm_intblk_nmi_iret : hvm_intblk_none);
|
||||
|
||||
ASSERT((intack.source == hvm_intsrc_pic) ||
|
||||
(intack.source == hvm_intsrc_lapic));
|
||||
|
||||
return hvm_intblk_none;
|
||||
static void vmx_set_interrupt_shadow(struct vcpu *v, unsigned int intr_shadow)
|
||||
{
|
||||
__vmwrite(GUEST_INTERRUPTIBILITY_INFO, intr_shadow);
|
||||
}
|
||||
|
||||
static void vmx_update_host_cr3(struct vcpu *v)
|
||||
@@ -1038,7 +1020,8 @@ static struct hvm_function_table vmx_function_table = {
|
||||
.vcpu_destroy = vmx_vcpu_destroy,
|
||||
.save_cpu_ctxt = vmx_save_vmcs_ctxt,
|
||||
.load_cpu_ctxt = vmx_load_vmcs_ctxt,
|
||||
.interrupt_blocked = vmx_interrupt_blocked,
|
||||
.get_interrupt_shadow = vmx_get_interrupt_shadow,
|
||||
.set_interrupt_shadow = vmx_set_interrupt_shadow,
|
||||
.guest_x86_mode = vmx_guest_x86_mode,
|
||||
.get_segment_register = vmx_get_segment_register,
|
||||
.set_segment_register = vmx_set_segment_register,
|
||||
|
||||
@@ -89,7 +89,7 @@ ENTRY(vmx_asm_vmexit_handler)
|
||||
|
||||
ALIGN
|
||||
vmx_process_softirqs:
|
||||
sti
|
||||
sti
|
||||
call do_softirq
|
||||
jmp vmx_asm_do_vmentry
|
||||
|
||||
@@ -104,6 +104,10 @@ ENTRY(vmx_asm_do_vmentry)
|
||||
jnz vmx_process_softirqs
|
||||
|
||||
call vmx_intr_assist
|
||||
|
||||
testb $0xff,VCPU_vmx_emul(%ebx)
|
||||
jnz vmx_goto_realmode
|
||||
|
||||
movl VCPU_hvm_guest_cr2(%ebx),%eax
|
||||
movl %eax,%cr2
|
||||
call vmx_trace_vmentry
|
||||
@@ -115,9 +119,6 @@ ENTRY(vmx_asm_do_vmentry)
|
||||
movl $GUEST_RFLAGS,%eax
|
||||
VMWRITE(UREGS_eflags)
|
||||
|
||||
testb $0xff,VCPU_vmx_emul(%ebx)
|
||||
jnz vmx_goto_realmode
|
||||
|
||||
cmpb $0,VCPU_vmx_launched(%ebx)
|
||||
je vmx_launch
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ ENTRY(vmx_asm_vmexit_handler)
|
||||
|
||||
ALIGN
|
||||
vmx_process_softirqs:
|
||||
sti
|
||||
sti
|
||||
call do_softirq
|
||||
jmp vmx_asm_do_vmentry
|
||||
|
||||
@@ -121,6 +121,10 @@ ENTRY(vmx_asm_do_vmentry)
|
||||
jnz vmx_process_softirqs
|
||||
|
||||
call vmx_intr_assist
|
||||
|
||||
testb $0xff,VCPU_vmx_emul(%rbx)
|
||||
jnz vmx_goto_realmode
|
||||
|
||||
movq VCPU_hvm_guest_cr2(%rbx),%rax
|
||||
movq %rax,%cr2
|
||||
call vmx_trace_vmentry
|
||||
@@ -134,9 +138,6 @@ ENTRY(vmx_asm_do_vmentry)
|
||||
movl $GUEST_RFLAGS,%eax
|
||||
VMWRITE(UREGS_eflags)
|
||||
|
||||
testb $0xff,VCPU_vmx_emul(%rbx)
|
||||
jnz vmx_goto_realmode
|
||||
|
||||
cmpb $0,VCPU_vmx_launched(%rbx)
|
||||
je vmx_launch
|
||||
|
||||
|
||||
+80
-81
@@ -482,7 +482,7 @@ do{ asm volatile ( \
|
||||
if ( !mode_64bit() ) _eip = (uint32_t)_eip; /* ignore upper dword */ \
|
||||
_regs.eip += (_size); /* real hardware doesn't truncate */ \
|
||||
generate_exception_if((uint8_t)(_regs.eip - ctxt->regs->eip) > 15, \
|
||||
EXC_GP); \
|
||||
EXC_GP, 0); \
|
||||
rc = ops->insn_fetch(x86_seg_cs, _eip, &_x, (_size), ctxt); \
|
||||
if ( rc ) goto done; \
|
||||
_x; \
|
||||
@@ -505,12 +505,12 @@ do { \
|
||||
if ( rc ) goto done; \
|
||||
} while (0)
|
||||
|
||||
#define generate_exception_if(p, e) \
|
||||
({ if ( (p) ) { \
|
||||
fail_if(ops->inject_hw_exception == NULL); \
|
||||
rc = ops->inject_hw_exception(e, 0, ctxt) ? : X86EMUL_EXCEPTION; \
|
||||
goto done; \
|
||||
} \
|
||||
#define generate_exception_if(p, e, ec) \
|
||||
({ if ( (p) ) { \
|
||||
fail_if(ops->inject_hw_exception == NULL); \
|
||||
rc = ops->inject_hw_exception(e, ec, ctxt) ? : X86EMUL_EXCEPTION; \
|
||||
goto done; \
|
||||
} \
|
||||
})
|
||||
|
||||
/*
|
||||
@@ -1023,6 +1023,8 @@ x86_emulate(
|
||||
ea.mem.seg = x86_seg_ds;
|
||||
ea.mem.off = 0;
|
||||
|
||||
ctxt->retire.byte = 0;
|
||||
|
||||
op_bytes = def_op_bytes = ad_bytes = def_ad_bytes = ctxt->addr_size/8;
|
||||
if ( op_bytes == 8 )
|
||||
{
|
||||
@@ -1105,7 +1107,7 @@ x86_emulate(
|
||||
}
|
||||
|
||||
/* Lock prefix is allowed only on RMW instructions. */
|
||||
generate_exception_if((d & Mov) && lock_prefix, EXC_GP);
|
||||
generate_exception_if((d & Mov) && lock_prefix, EXC_GP, 0);
|
||||
|
||||
/* ModRM and SIB bytes. */
|
||||
if ( d & ModRM )
|
||||
@@ -1393,7 +1395,7 @@ x86_emulate(
|
||||
}
|
||||
|
||||
/* LOCK prefix allowed only on instructions with memory destination. */
|
||||
generate_exception_if(lock_prefix && (dst.type != OP_MEM), EXC_GP);
|
||||
generate_exception_if(lock_prefix && (dst.type != OP_MEM), EXC_GP, 0);
|
||||
|
||||
if ( twobyte )
|
||||
goto twobyte_insn;
|
||||
@@ -1459,14 +1461,15 @@ x86_emulate(
|
||||
case 0x62: /* bound */ {
|
||||
unsigned long src_val2;
|
||||
int lb, ub, idx;
|
||||
generate_exception_if(mode_64bit() || (src.type != OP_MEM), EXC_UD);
|
||||
generate_exception_if(mode_64bit() || (src.type != OP_MEM),
|
||||
EXC_UD, -1);
|
||||
if ( (rc = ops->read(src.mem.seg, src.mem.off + op_bytes,
|
||||
&src_val2, op_bytes, ctxt)) )
|
||||
goto done;
|
||||
ub = (op_bytes == 2) ? (int16_t)src_val2 : (int32_t)src_val2;
|
||||
lb = (op_bytes == 2) ? (int16_t)src.val : (int32_t)src.val;
|
||||
idx = (op_bytes == 2) ? (int16_t)dst.val : (int32_t)dst.val;
|
||||
generate_exception_if((idx < lb) || (idx > ub), EXC_BR);
|
||||
generate_exception_if((idx < lb) || (idx > ub), EXC_BR, -1);
|
||||
dst.type = OP_NONE;
|
||||
break;
|
||||
}
|
||||
@@ -1493,7 +1496,7 @@ x86_emulate(
|
||||
dst.val = (dst.val & ~3) | (src_val & 3);
|
||||
else
|
||||
dst.type = OP_NONE;
|
||||
generate_exception_if(in_realmode(ctxt, ops), EXC_UD);
|
||||
generate_exception_if(in_realmode(ctxt, ops), EXC_UD, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1534,7 +1537,7 @@ x86_emulate(
|
||||
}
|
||||
|
||||
case 0x82: /* Grp1 (x86/32 only) */
|
||||
generate_exception_if(mode_64bit(), EXC_UD);
|
||||
generate_exception_if(mode_64bit(), EXC_UD, -1);
|
||||
case 0x80: case 0x81: case 0x83: /* Grp1 */
|
||||
switch ( modrm_reg & 7 )
|
||||
{
|
||||
@@ -1571,7 +1574,7 @@ x86_emulate(
|
||||
break;
|
||||
|
||||
case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
|
||||
generate_exception_if((modrm_reg & 7) != 0, EXC_UD);
|
||||
generate_exception_if((modrm_reg & 7) != 0, EXC_UD, -1);
|
||||
case 0x88 ... 0x8b: /* mov */
|
||||
dst.val = src.val;
|
||||
break;
|
||||
@@ -1579,7 +1582,7 @@ x86_emulate(
|
||||
case 0x8c: /* mov Sreg,r/m */ {
|
||||
struct segment_register reg;
|
||||
enum x86_segment seg = decode_segment(modrm_reg);
|
||||
generate_exception_if(seg == decode_segment_failed, EXC_UD);
|
||||
generate_exception_if(seg == decode_segment_failed, EXC_UD, -1);
|
||||
fail_if(ops->read_segment == NULL);
|
||||
if ( (rc = ops->read_segment(seg, ®, ctxt)) != 0 )
|
||||
goto done;
|
||||
@@ -1591,9 +1594,11 @@ x86_emulate(
|
||||
|
||||
case 0x8e: /* mov r/m,Sreg */ {
|
||||
enum x86_segment seg = decode_segment(modrm_reg);
|
||||
generate_exception_if(seg == decode_segment_failed, EXC_UD);
|
||||
generate_exception_if(seg == decode_segment_failed, EXC_UD, -1);
|
||||
if ( (rc = load_seg(seg, (uint16_t)src.val, ctxt, ops)) != 0 )
|
||||
goto done;
|
||||
if ( seg == x86_seg_ss )
|
||||
ctxt->retire.flags.mov_ss = 1;
|
||||
dst.type = OP_NONE;
|
||||
break;
|
||||
}
|
||||
@@ -1603,7 +1608,7 @@ x86_emulate(
|
||||
break;
|
||||
|
||||
case 0x8f: /* pop (sole member of Grp1a) */
|
||||
generate_exception_if((modrm_reg & 7) != 0, EXC_UD);
|
||||
generate_exception_if((modrm_reg & 7) != 0, EXC_UD, -1);
|
||||
/* 64-bit mode: POP defaults to a 64-bit operand. */
|
||||
if ( mode_64bit() && (dst.bytes == 4) )
|
||||
dst.bytes = 8;
|
||||
@@ -1659,7 +1664,7 @@ x86_emulate(
|
||||
unsigned long sel;
|
||||
dst.val = x86_seg_es;
|
||||
les: /* dst.val identifies the segment */
|
||||
generate_exception_if(src.type != OP_MEM, EXC_UD);
|
||||
generate_exception_if(src.type != OP_MEM, EXC_UD, -1);
|
||||
if ( (rc = ops->read(src.mem.seg, src.mem.off + src.bytes,
|
||||
&sel, 2, ctxt)) != 0 )
|
||||
goto done;
|
||||
@@ -1797,7 +1802,7 @@ x86_emulate(
|
||||
v = (uint8_t)src.val;
|
||||
generate_exception_if(
|
||||
div_dbl(u, v) || ((uint8_t)u[0] != (uint16_t)u[0]),
|
||||
EXC_DE);
|
||||
EXC_DE, -1);
|
||||
dst.val = (uint8_t)u[0];
|
||||
((uint8_t *)&_regs.eax)[1] = u[1];
|
||||
break;
|
||||
@@ -1807,7 +1812,7 @@ x86_emulate(
|
||||
v = (uint16_t)src.val;
|
||||
generate_exception_if(
|
||||
div_dbl(u, v) || ((uint16_t)u[0] != (uint32_t)u[0]),
|
||||
EXC_DE);
|
||||
EXC_DE, -1);
|
||||
dst.val = (uint16_t)u[0];
|
||||
*(uint16_t *)&_regs.edx = u[1];
|
||||
break;
|
||||
@@ -1818,7 +1823,7 @@ x86_emulate(
|
||||
v = (uint32_t)src.val;
|
||||
generate_exception_if(
|
||||
div_dbl(u, v) || ((uint32_t)u[0] != u[0]),
|
||||
EXC_DE);
|
||||
EXC_DE, -1);
|
||||
dst.val = (uint32_t)u[0];
|
||||
_regs.edx = (uint32_t)u[1];
|
||||
break;
|
||||
@@ -1827,7 +1832,7 @@ x86_emulate(
|
||||
u[0] = _regs.eax;
|
||||
u[1] = _regs.edx;
|
||||
v = src.val;
|
||||
generate_exception_if(div_dbl(u, v), EXC_DE);
|
||||
generate_exception_if(div_dbl(u, v), EXC_DE, -1);
|
||||
dst.val = u[0];
|
||||
_regs.edx = u[1];
|
||||
break;
|
||||
@@ -1847,7 +1852,7 @@ x86_emulate(
|
||||
v = (int8_t)src.val;
|
||||
generate_exception_if(
|
||||
idiv_dbl(u, v) || ((int8_t)u[0] != (int16_t)u[0]),
|
||||
EXC_DE);
|
||||
EXC_DE, -1);
|
||||
dst.val = (int8_t)u[0];
|
||||
((int8_t *)&_regs.eax)[1] = u[1];
|
||||
break;
|
||||
@@ -1857,7 +1862,7 @@ x86_emulate(
|
||||
v = (int16_t)src.val;
|
||||
generate_exception_if(
|
||||
idiv_dbl(u, v) || ((int16_t)u[0] != (int32_t)u[0]),
|
||||
EXC_DE);
|
||||
EXC_DE, -1);
|
||||
dst.val = (int16_t)u[0];
|
||||
*(int16_t *)&_regs.edx = u[1];
|
||||
break;
|
||||
@@ -1868,7 +1873,7 @@ x86_emulate(
|
||||
v = (int32_t)src.val;
|
||||
generate_exception_if(
|
||||
idiv_dbl(u, v) || ((int32_t)u[0] != u[0]),
|
||||
EXC_DE);
|
||||
EXC_DE, -1);
|
||||
dst.val = (int32_t)u[0];
|
||||
_regs.edx = (uint32_t)u[1];
|
||||
break;
|
||||
@@ -1877,7 +1882,7 @@ x86_emulate(
|
||||
u[0] = _regs.eax;
|
||||
u[1] = _regs.edx;
|
||||
v = src.val;
|
||||
generate_exception_if(idiv_dbl(u, v), EXC_DE);
|
||||
generate_exception_if(idiv_dbl(u, v), EXC_DE, -1);
|
||||
dst.val = u[0];
|
||||
_regs.edx = u[1];
|
||||
break;
|
||||
@@ -1890,7 +1895,7 @@ x86_emulate(
|
||||
break;
|
||||
|
||||
case 0xfe: /* Grp4 */
|
||||
generate_exception_if((modrm_reg & 7) >= 2, EXC_UD);
|
||||
generate_exception_if((modrm_reg & 7) >= 2, EXC_UD, -1);
|
||||
case 0xff: /* Grp5 */
|
||||
switch ( modrm_reg & 7 )
|
||||
{
|
||||
@@ -1921,7 +1926,7 @@ x86_emulate(
|
||||
case 5: /* jmp (far, absolute indirect) */ {
|
||||
unsigned long sel;
|
||||
|
||||
generate_exception_if(dst.type != OP_MEM, EXC_UD);
|
||||
generate_exception_if(dst.type != OP_MEM, EXC_UD, -1);
|
||||
|
||||
if ( (rc = ops->read(dst.mem.seg, dst.mem.off+dst.bytes,
|
||||
&sel, 2, ctxt)) )
|
||||
@@ -1963,7 +1968,7 @@ x86_emulate(
|
||||
dst.type = OP_NONE;
|
||||
break;
|
||||
case 7:
|
||||
generate_exception_if(1, EXC_UD);
|
||||
generate_exception_if(1, EXC_UD, -1);
|
||||
default:
|
||||
goto cannot_emulate;
|
||||
}
|
||||
@@ -2003,11 +2008,9 @@ x86_emulate(
|
||||
/* Commit shadow register state. */
|
||||
_regs.eflags &= ~EFLG_RF;
|
||||
*ctxt->regs = _regs;
|
||||
|
||||
if ( (_regs.eflags & EFLG_TF) &&
|
||||
(rc == X86EMUL_OKAY) &&
|
||||
if ( (_regs.eflags & EFLG_TF) && (rc == X86EMUL_OKAY) &&
|
||||
(ops->inject_hw_exception != NULL) )
|
||||
rc = ops->inject_hw_exception(EXC_DB, 0, ctxt) ? : X86EMUL_EXCEPTION;
|
||||
rc = ops->inject_hw_exception(EXC_DB, -1, ctxt) ? : X86EMUL_EXCEPTION;
|
||||
|
||||
done:
|
||||
return rc;
|
||||
@@ -2022,7 +2025,7 @@ x86_emulate(
|
||||
generate_exception_if(lock_prefix &&
|
||||
((b < 0x20) || (b > 0x23)) && /* MOV CRn/DRn */
|
||||
(b != 0xc7), /* CMPXCHG{8,16}B */
|
||||
EXC_GP);
|
||||
EXC_GP, 0);
|
||||
|
||||
if ( twobyte )
|
||||
goto twobyte_special_insn;
|
||||
@@ -2069,6 +2072,7 @@ x86_emulate(
|
||||
|
||||
case 0x17: /* pop %%ss */
|
||||
src.val = x86_seg_ss;
|
||||
ctxt->retire.flags.mov_ss = 1;
|
||||
goto pop_seg;
|
||||
|
||||
case 0x1e: /* push %%ds */
|
||||
@@ -2082,7 +2086,7 @@ x86_emulate(
|
||||
case 0x27: /* daa */ {
|
||||
uint8_t al = _regs.eax;
|
||||
unsigned long eflags = _regs.eflags;
|
||||
generate_exception_if(mode_64bit(), EXC_UD);
|
||||
generate_exception_if(mode_64bit(), EXC_UD, -1);
|
||||
_regs.eflags &= ~(EFLG_CF|EFLG_AF);
|
||||
if ( ((al & 0x0f) > 9) || (eflags & EFLG_AF) )
|
||||
{
|
||||
@@ -2104,7 +2108,7 @@ x86_emulate(
|
||||
case 0x2f: /* das */ {
|
||||
uint8_t al = _regs.eax;
|
||||
unsigned long eflags = _regs.eflags;
|
||||
generate_exception_if(mode_64bit(), EXC_UD);
|
||||
generate_exception_if(mode_64bit(), EXC_UD, -1);
|
||||
_regs.eflags &= ~(EFLG_CF|EFLG_AF);
|
||||
if ( ((al & 0x0f) > 9) || (eflags & EFLG_AF) )
|
||||
{
|
||||
@@ -2127,7 +2131,7 @@ x86_emulate(
|
||||
|
||||
case 0x37: /* aaa */
|
||||
case 0x3f: /* aas */
|
||||
generate_exception_if(mode_64bit(), EXC_UD);
|
||||
generate_exception_if(mode_64bit(), EXC_UD, -1);
|
||||
_regs.eflags &= ~EFLG_CF;
|
||||
if ( ((uint8_t)_regs.eax > 9) || (_regs.eflags & EFLG_AF) )
|
||||
{
|
||||
@@ -2171,7 +2175,7 @@ x86_emulate(
|
||||
unsigned long regs[] = {
|
||||
_regs.eax, _regs.ecx, _regs.edx, _regs.ebx,
|
||||
_regs.esp, _regs.ebp, _regs.esi, _regs.edi };
|
||||
generate_exception_if(mode_64bit(), EXC_UD);
|
||||
generate_exception_if(mode_64bit(), EXC_UD, -1);
|
||||
for ( i = 0; i < 8; i++ )
|
||||
if ( (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes),
|
||||
regs[i], op_bytes, ctxt)) != 0 )
|
||||
@@ -2186,7 +2190,7 @@ x86_emulate(
|
||||
(unsigned long *)&_regs.ebp, (unsigned long *)&dummy_esp,
|
||||
(unsigned long *)&_regs.ebx, (unsigned long *)&_regs.edx,
|
||||
(unsigned long *)&_regs.ecx, (unsigned long *)&_regs.eax };
|
||||
generate_exception_if(mode_64bit(), EXC_UD);
|
||||
generate_exception_if(mode_64bit(), EXC_UD, -1);
|
||||
for ( i = 0; i < 8; i++ )
|
||||
{
|
||||
if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
|
||||
@@ -2224,7 +2228,7 @@ x86_emulate(
|
||||
|
||||
case 0x6c ... 0x6d: /* ins %dx,%es:%edi */ {
|
||||
unsigned long nr_reps = get_rep_prefix();
|
||||
generate_exception_if(!mode_iopl(), EXC_GP);
|
||||
generate_exception_if(!mode_iopl(), EXC_GP, 0);
|
||||
dst.bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes;
|
||||
dst.mem.seg = x86_seg_es;
|
||||
dst.mem.off = truncate_ea(_regs.edi);
|
||||
@@ -2254,7 +2258,7 @@ x86_emulate(
|
||||
|
||||
case 0x6e ... 0x6f: /* outs %esi,%dx */ {
|
||||
unsigned long nr_reps = get_rep_prefix();
|
||||
generate_exception_if(!mode_iopl(), EXC_GP);
|
||||
generate_exception_if(!mode_iopl(), EXC_GP, 0);
|
||||
dst.bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes;
|
||||
if ( (nr_reps > 1) && (ops->rep_outs != NULL) &&
|
||||
((rc = ops->rep_outs(ea.mem.seg, truncate_ea(_regs.esi),
|
||||
@@ -2333,7 +2337,7 @@ x86_emulate(
|
||||
uint32_t eip;
|
||||
|
||||
fail_if(ops->read_segment == NULL);
|
||||
generate_exception_if(mode_64bit(), EXC_UD);
|
||||
generate_exception_if(mode_64bit(), EXC_UD, -1);
|
||||
|
||||
eip = insn_fetch_bytes(op_bytes);
|
||||
sel = insn_fetch_type(uint16_t);
|
||||
@@ -2359,7 +2363,6 @@ x86_emulate(
|
||||
uint32_t mask = EFLG_VIP | EFLG_VIF | EFLG_VM;
|
||||
if ( !mode_iopl() )
|
||||
mask |= EFLG_IOPL;
|
||||
fail_if(ops->write_rflags == NULL);
|
||||
/* 64-bit mode: POP defaults to a 64-bit operand. */
|
||||
if ( mode_64bit() && (op_bytes == 4) )
|
||||
op_bytes = 8;
|
||||
@@ -2371,8 +2374,6 @@ x86_emulate(
|
||||
dst.val &= 0x257fd5;
|
||||
_regs.eflags &= mask;
|
||||
_regs.eflags |= (uint32_t)(dst.val & ~mask) | 0x02;
|
||||
if ( (rc = ops->write_rflags(_regs.eflags, ctxt)) != 0 )
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2597,7 +2598,7 @@ x86_emulate(
|
||||
goto done;
|
||||
|
||||
case 0xce: /* into */
|
||||
generate_exception_if(mode_64bit(), EXC_UD);
|
||||
generate_exception_if(mode_64bit(), EXC_UD, -1);
|
||||
if ( !(_regs.eflags & EFLG_OF) )
|
||||
break;
|
||||
src.val = EXC_OF;
|
||||
@@ -2609,7 +2610,6 @@ x86_emulate(
|
||||
if ( !mode_iopl() )
|
||||
mask |= EFLG_IOPL;
|
||||
fail_if(!in_realmode(ctxt, ops));
|
||||
fail_if(ops->write_rflags == NULL);
|
||||
if ( (rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
|
||||
&eip, op_bytes, ctxt)) ||
|
||||
(rc = ops->read(x86_seg_ss, sp_post_inc(op_bytes),
|
||||
@@ -2622,8 +2622,6 @@ x86_emulate(
|
||||
eflags &= 0x257fd5;
|
||||
_regs.eflags &= mask;
|
||||
_regs.eflags |= (uint32_t)(eflags & ~mask) | 0x02;
|
||||
if ( (rc = ops->write_rflags(_regs.eflags, ctxt)) != 0 )
|
||||
goto done;
|
||||
_regs.eip = eip;
|
||||
if ( (rc = load_seg(x86_seg_cs, (uint16_t)cs, ctxt, ops)) != 0 )
|
||||
goto done;
|
||||
@@ -2633,8 +2631,8 @@ x86_emulate(
|
||||
case 0xd4: /* aam */ {
|
||||
unsigned int base = insn_fetch_type(uint8_t);
|
||||
uint8_t al = _regs.eax;
|
||||
generate_exception_if(mode_64bit(), EXC_UD);
|
||||
generate_exception_if(base == 0, EXC_DE);
|
||||
generate_exception_if(mode_64bit(), EXC_UD, -1);
|
||||
generate_exception_if(base == 0, EXC_DE, -1);
|
||||
*(uint16_t *)&_regs.eax = ((al / base) << 8) | (al % base);
|
||||
_regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF);
|
||||
_regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0;
|
||||
@@ -2646,7 +2644,7 @@ x86_emulate(
|
||||
case 0xd5: /* aad */ {
|
||||
unsigned int base = insn_fetch_type(uint8_t);
|
||||
uint16_t ax = _regs.eax;
|
||||
generate_exception_if(mode_64bit(), EXC_UD);
|
||||
generate_exception_if(mode_64bit(), EXC_UD, -1);
|
||||
*(uint16_t *)&_regs.eax = (uint8_t)(ax + ((ax >> 8) * base));
|
||||
_regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF);
|
||||
_regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0;
|
||||
@@ -2656,7 +2654,7 @@ x86_emulate(
|
||||
}
|
||||
|
||||
case 0xd6: /* salc */
|
||||
generate_exception_if(mode_64bit(), EXC_UD);
|
||||
generate_exception_if(mode_64bit(), EXC_UD, -1);
|
||||
*(uint8_t *)&_regs.eax = (_regs.eflags & EFLG_CF) ? 0xff : 0x00;
|
||||
break;
|
||||
|
||||
@@ -2743,7 +2741,7 @@ x86_emulate(
|
||||
unsigned int port = ((b < 0xe8)
|
||||
? insn_fetch_type(uint8_t)
|
||||
: (uint16_t)_regs.edx);
|
||||
generate_exception_if(!mode_iopl(), EXC_GP);
|
||||
generate_exception_if(!mode_iopl(), EXC_GP, 0);
|
||||
op_bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes;
|
||||
if ( b & 2 )
|
||||
{
|
||||
@@ -2787,7 +2785,7 @@ x86_emulate(
|
||||
case 0xea: /* jmp (far, absolute) */ {
|
||||
uint16_t sel;
|
||||
uint32_t eip;
|
||||
generate_exception_if(mode_64bit(), EXC_UD);
|
||||
generate_exception_if(mode_64bit(), EXC_UD, -1);
|
||||
eip = insn_fetch_bytes(op_bytes);
|
||||
sel = insn_fetch_type(uint16_t);
|
||||
if ( (rc = load_seg(x86_seg_cs, sel, ctxt, ops)) != 0 )
|
||||
@@ -2807,9 +2805,7 @@ x86_emulate(
|
||||
goto swint;
|
||||
|
||||
case 0xf4: /* hlt */
|
||||
fail_if(ops->hlt == NULL);
|
||||
if ( (rc = ops->hlt(ctxt)) != 0 )
|
||||
goto done;
|
||||
ctxt->retire.flags.hlt = 1;
|
||||
break;
|
||||
|
||||
case 0xf5: /* cmc */
|
||||
@@ -2825,14 +2821,17 @@ x86_emulate(
|
||||
break;
|
||||
|
||||
case 0xfa: /* cli */
|
||||
case 0xfb: /* sti */
|
||||
generate_exception_if(!mode_iopl(), EXC_GP);
|
||||
fail_if(ops->write_rflags == NULL);
|
||||
generate_exception_if(!mode_iopl(), EXC_GP, 0);
|
||||
_regs.eflags &= ~EFLG_IF;
|
||||
if ( b == 0xfb ) /* sti */
|
||||
break;
|
||||
|
||||
case 0xfb: /* sti */
|
||||
generate_exception_if(!mode_iopl(), EXC_GP, 0);
|
||||
if ( !(_regs.eflags & EFLG_IF) )
|
||||
{
|
||||
_regs.eflags |= EFLG_IF;
|
||||
if ( (rc = ops->write_rflags(_regs.eflags, ctxt)) != 0 )
|
||||
goto done;
|
||||
ctxt->retire.flags.sti = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xfc: /* cld */
|
||||
@@ -3001,7 +3000,7 @@ x86_emulate(
|
||||
case 5: goto bts;
|
||||
case 6: goto btr;
|
||||
case 7: goto btc;
|
||||
default: generate_exception_if(1, EXC_UD);
|
||||
default: generate_exception_if(1, EXC_UD, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3038,8 +3037,8 @@ x86_emulate(
|
||||
|
||||
if ( modrm == 0xdf ) /* invlpga */
|
||||
{
|
||||
generate_exception_if(in_realmode(ctxt, ops), EXC_UD);
|
||||
generate_exception_if(!mode_ring0(), EXC_GP);
|
||||
generate_exception_if(in_realmode(ctxt, ops), EXC_UD, -1);
|
||||
generate_exception_if(!mode_ring0(), EXC_GP, 0);
|
||||
fail_if(ops->invlpg == NULL);
|
||||
if ( (rc = ops->invlpg(x86_seg_none, truncate_ea(_regs.eax),
|
||||
ctxt)) )
|
||||
@@ -3051,7 +3050,7 @@ x86_emulate(
|
||||
{
|
||||
case 0: /* sgdt */
|
||||
case 1: /* sidt */
|
||||
generate_exception_if(ea.type != OP_MEM, EXC_UD);
|
||||
generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
|
||||
fail_if(ops->read_segment == NULL);
|
||||
if ( (rc = ops->read_segment((modrm_reg & 1) ?
|
||||
x86_seg_idtr : x86_seg_gdtr,
|
||||
@@ -3067,7 +3066,7 @@ x86_emulate(
|
||||
break;
|
||||
case 2: /* lgdt */
|
||||
case 3: /* lidt */
|
||||
generate_exception_if(ea.type != OP_MEM, EXC_UD);
|
||||
generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
|
||||
fail_if(ops->write_segment == NULL);
|
||||
memset(®, 0, sizeof(reg));
|
||||
if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0,
|
||||
@@ -3108,8 +3107,8 @@ x86_emulate(
|
||||
goto done;
|
||||
break;
|
||||
case 7: /* invlpg */
|
||||
generate_exception_if(!mode_ring0(), EXC_GP);
|
||||
generate_exception_if(ea.type != OP_MEM, EXC_UD);
|
||||
generate_exception_if(!mode_ring0(), EXC_GP, 0);
|
||||
generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
|
||||
fail_if(ops->invlpg == NULL);
|
||||
if ( (rc = ops->invlpg(ea.mem.seg, ea.mem.off, ctxt)) )
|
||||
goto done;
|
||||
@@ -3121,7 +3120,7 @@ x86_emulate(
|
||||
}
|
||||
|
||||
case 0x06: /* clts */
|
||||
generate_exception_if(!mode_ring0(), EXC_GP);
|
||||
generate_exception_if(!mode_ring0(), EXC_GP, 0);
|
||||
fail_if((ops->read_cr == NULL) || (ops->write_cr == NULL));
|
||||
if ( (rc = ops->read_cr(0, &dst.val, ctxt)) ||
|
||||
(rc = ops->write_cr(0, dst.val&~8, ctxt)) )
|
||||
@@ -3130,7 +3129,7 @@ x86_emulate(
|
||||
|
||||
case 0x08: /* invd */
|
||||
case 0x09: /* wbinvd */
|
||||
generate_exception_if(!mode_ring0(), EXC_GP);
|
||||
generate_exception_if(!mode_ring0(), EXC_GP, 0);
|
||||
fail_if(ops->wbinvd == NULL);
|
||||
if ( (rc = ops->wbinvd(ctxt)) != 0 )
|
||||
goto done;
|
||||
@@ -3145,7 +3144,7 @@ x86_emulate(
|
||||
case 0x21: /* mov dr,reg */
|
||||
case 0x22: /* mov reg,cr */
|
||||
case 0x23: /* mov reg,dr */
|
||||
generate_exception_if(!mode_ring0(), EXC_GP);
|
||||
generate_exception_if(!mode_ring0(), EXC_GP, 0);
|
||||
modrm_rm |= (rex_prefix & 1) << 3;
|
||||
modrm_reg |= lock_prefix << 3;
|
||||
if ( b & 2 )
|
||||
@@ -3182,7 +3181,7 @@ x86_emulate(
|
||||
|
||||
case 0x30: /* wrmsr */ {
|
||||
uint64_t val = ((uint64_t)_regs.edx << 32) | (uint32_t)_regs.eax;
|
||||
generate_exception_if(!mode_ring0(), EXC_GP);
|
||||
generate_exception_if(!mode_ring0(), EXC_GP, 0);
|
||||
fail_if(ops->write_msr == NULL);
|
||||
if ( (rc = ops->write_msr((uint32_t)_regs.ecx, val, ctxt)) != 0 )
|
||||
goto done;
|
||||
@@ -3195,7 +3194,7 @@ x86_emulate(
|
||||
fail_if(ops->read_cr == NULL);
|
||||
if ( (rc = ops->read_cr(4, &cr4, ctxt)) )
|
||||
goto done;
|
||||
generate_exception_if((cr4 & CR4_TSD) && !mode_ring0(), EXC_GP);
|
||||
generate_exception_if((cr4 & CR4_TSD) && !mode_ring0(), EXC_GP, 0);
|
||||
fail_if(ops->read_msr == NULL);
|
||||
if ( (rc = ops->read_msr(MSR_TSC, &val, ctxt)) != 0 )
|
||||
goto done;
|
||||
@@ -3206,7 +3205,7 @@ x86_emulate(
|
||||
|
||||
case 0x32: /* rdmsr */ {
|
||||
uint64_t val;
|
||||
generate_exception_if(!mode_ring0(), EXC_GP);
|
||||
generate_exception_if(!mode_ring0(), EXC_GP, 0);
|
||||
fail_if(ops->read_msr == NULL);
|
||||
if ( (rc = ops->read_msr((uint32_t)_regs.ecx, &val, ctxt)) != 0 )
|
||||
goto done;
|
||||
@@ -3255,8 +3254,8 @@ x86_emulate(
|
||||
#if defined(__i386__)
|
||||
{
|
||||
unsigned long old_lo, old_hi;
|
||||
generate_exception_if((modrm_reg & 7) != 1, EXC_UD);
|
||||
generate_exception_if(ea.type != OP_MEM, EXC_UD);
|
||||
generate_exception_if((modrm_reg & 7) != 1, EXC_UD, -1);
|
||||
generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
|
||||
if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0, &old_lo, 4, ctxt)) ||
|
||||
(rc = ops->read(ea.mem.seg, ea.mem.off+4, &old_hi, 4, ctxt)) )
|
||||
goto done;
|
||||
@@ -3283,8 +3282,8 @@ x86_emulate(
|
||||
#elif defined(__x86_64__)
|
||||
{
|
||||
unsigned long old, new;
|
||||
generate_exception_if((modrm_reg & 7) != 1, EXC_UD);
|
||||
generate_exception_if(ea.type != OP_MEM, EXC_UD);
|
||||
generate_exception_if((modrm_reg & 7) != 1, EXC_UD, -1);
|
||||
generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
|
||||
if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &old, 8, ctxt)) != 0 )
|
||||
goto done;
|
||||
if ( ((uint32_t)(old>>0) != (uint32_t)_regs.eax) ||
|
||||
|
||||
@@ -27,18 +27,12 @@ struct hvm_emulate_ctxt {
|
||||
unsigned long seg_reg_accessed;
|
||||
unsigned long seg_reg_dirty;
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int hlt:1;
|
||||
unsigned int mov_ss:1;
|
||||
unsigned int sti:1;
|
||||
unsigned int exn_pending:1;
|
||||
} flags;
|
||||
unsigned int flag_word;
|
||||
};
|
||||
|
||||
bool_t exn_pending;
|
||||
uint8_t exn_vector;
|
||||
uint8_t exn_insn_len;
|
||||
int32_t exn_error_code;
|
||||
|
||||
uint32_t intr_shadow;
|
||||
};
|
||||
|
||||
int hvm_emulate_one(
|
||||
|
||||
@@ -49,6 +49,12 @@ enum hvm_intblk {
|
||||
hvm_intblk_nmi_iret /* NMI blocked until IRET */
|
||||
};
|
||||
|
||||
/* These happen to be the same as the VMX interrupt shadow definitions. */
|
||||
#define HVM_INTR_SHADOW_STI 0x00000001
|
||||
#define HVM_INTR_SHADOW_MOV_SS 0x00000002
|
||||
#define HVM_INTR_SHADOW_SMI 0x00000004
|
||||
#define HVM_INTR_SHADOW_NMI 0x00000008
|
||||
|
||||
/*
|
||||
* The hardware virtual machine (HVM) interface abstracts away from the
|
||||
* x86/x86_64 CPU virtualization assist specifics. Currently this interface
|
||||
@@ -72,14 +78,9 @@ struct hvm_function_table {
|
||||
void (*save_cpu_ctxt)(struct vcpu *v, struct hvm_hw_cpu *ctxt);
|
||||
int (*load_cpu_ctxt)(struct vcpu *v, struct hvm_hw_cpu *ctxt);
|
||||
|
||||
/*
|
||||
* Examine specifics of the guest state:
|
||||
* 1) determine whether interrupts are enabled or not
|
||||
* 2) determine the mode the guest is running in
|
||||
* 3) return the current guest segment descriptor base
|
||||
* 4) return the current guest segment descriptor
|
||||
*/
|
||||
enum hvm_intblk (*interrupt_blocked)(struct vcpu *v, struct hvm_intack);
|
||||
/* Examine specifics of the guest state. */
|
||||
unsigned int (*get_interrupt_shadow)(struct vcpu *v);
|
||||
void (*set_interrupt_shadow)(struct vcpu *v, unsigned int intr_shadow);
|
||||
int (*guest_x86_mode)(struct vcpu *v);
|
||||
void (*get_segment_register)(struct vcpu *v, enum x86_segment seg,
|
||||
struct segment_register *reg);
|
||||
|
||||
@@ -318,11 +318,6 @@ struct x86_emulate_ops
|
||||
uint64_t val,
|
||||
struct x86_emulate_ctxt *ctxt);
|
||||
|
||||
/* write_rflags: Modify privileged bits in RFLAGS. */
|
||||
int (*write_rflags)(
|
||||
unsigned long val,
|
||||
struct x86_emulate_ctxt *ctxt);
|
||||
|
||||
/* wbinvd: Write-back and invalidate cache contents. */
|
||||
int (*wbinvd)(
|
||||
struct x86_emulate_ctxt *ctxt);
|
||||
@@ -335,14 +330,10 @@ struct x86_emulate_ops
|
||||
unsigned int *edx,
|
||||
struct x86_emulate_ctxt *ctxt);
|
||||
|
||||
/* hlt: Emulate HLT. */
|
||||
int (*hlt)(
|
||||
struct x86_emulate_ctxt *ctxt);
|
||||
|
||||
/* inject_hw_exception */
|
||||
int (*inject_hw_exception)(
|
||||
uint8_t vector,
|
||||
uint16_t error_code,
|
||||
int32_t error_code,
|
||||
struct x86_emulate_ctxt *ctxt);
|
||||
|
||||
/* inject_sw_interrupt */
|
||||
@@ -376,7 +367,17 @@ struct x86_emulate_ctxt
|
||||
unsigned int sp_size;
|
||||
|
||||
/* Set this if writes may have side effects. */
|
||||
int force_writeback;
|
||||
uint8_t force_writeback;
|
||||
|
||||
/* Retirement state, set by the emulator (valid only on X86EMUL_OKAY). */
|
||||
union {
|
||||
struct {
|
||||
uint8_t hlt:1; /* Instruction HLTed. */
|
||||
uint8_t mov_ss:1; /* Instruction sets MOV-SS irq shadow. */
|
||||
uint8_t sti:1; /* Instruction sets STI irq shadow. */
|
||||
} flags;
|
||||
uint8_t byte;
|
||||
} retire;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||