# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1202291679 0
# Node ID 985bae80b6d7aa87e589e59b376f52a5000eaa64
# Parent 744ec35f1e3ab5aa6c5301c872c2f0685a46cd34
vmx realmode: Restructure code for clarity and better treatment of
VM_ENTRY_INTR_INFO. Also add more sanity checking.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
xen-unstable changeset: 16869:db620f1c9d3077e732440d1088e608b6d5530daa
xen-unstable date: Thu Jan 24 14:29:13 2008 +0000
vmx realmode: Multiple I/O reads to qemu in an instruction is not
allowed. But we do allow, for example, a read followed by a write
(e.g., MOVS within video RAM).
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
xen-unstable changeset: 16922:ed2ca78286a8c30ab68e37c7eccae6d1748f0d50
xen-unstable date: Mon Jan 28 11:28:55 2008 +0000
---
xen/arch/x86/hvm/vmx/realmode.c | 178 ++++++++++++++++++++++++----------------
1 files changed, 111 insertions(+), 67 deletions(-)
diff -r 744ec35f1e3a -r 985bae80b6d7 xen/arch/x86/hvm/vmx/realmode.c
--- a/xen/arch/x86/hvm/vmx/realmode.c Wed Feb 06 09:52:43 2008 +0000
+++ b/xen/arch/x86/hvm/vmx/realmode.c Wed Feb 06 09:54:39 2008 +0000
@@ -41,6 +41,8 @@ struct realmode_emulate_ctxt {
uint8_t exn_vector;
uint8_t exn_insn_len;
+
+ uint32_t intr_shadow;
};
static void realmode_deliver_exception(
@@ -502,13 +504,108 @@ static struct x86_emulate_ops realmode_e
.load_fpu_ctxt = realmode_load_fpu_ctxt
};
+static void realmode_emulate_one(struct realmode_emulate_ctxt *rm_ctxt)
+{
+ struct cpu_user_regs *regs = rm_ctxt->ctxt.regs;
+ struct vcpu *curr = current;
+ u32 new_intr_shadow;
+ int rc, io_completed;
+
+ rm_ctxt->insn_buf_eip = regs->eip;
+ (void)hvm_copy_from_guest_phys(
+ rm_ctxt->insn_buf,
+ (uint32_t)(rm_ctxt->seg_reg[x86_seg_cs].base + regs->eip),
+ sizeof(rm_ctxt->insn_buf));
+
+ rm_ctxt->flag_word = 0;
+
+ io_completed = curr->arch.hvm_vmx.real_mode_io_completed;
+ if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
+ {
+ gdprintk(XENLOG_ERR, "I/O in progress before insn is emulated.\n");
+ goto fail;
+ }
+
+ rc = x86_emulate(&rm_ctxt->ctxt, &realmode_emulator_ops);
+
+ if ( curr->arch.hvm_vmx.real_mode_io_completed )
+ {
+ gdprintk(XENLOG_ERR, "I/O completion after insn is emulated.\n");
+ goto fail;
+ }
+
+ if ( rc == X86EMUL_UNHANDLEABLE )
+ {
+ gdprintk(XENLOG_ERR, "Failed to emulate insn.\n");
+ goto fail;
+ }
+
+ if ( rc == X86EMUL_RETRY )
+ {
+ BUG_ON(!curr->arch.hvm_vmx.real_mode_io_in_progress);
+ if ( !io_completed )
+ return;
+ gdprintk(XENLOG_ERR, "Multiple I/O reads in a single insn.\n");
+ goto fail;
+ }
+
+ if ( curr->arch.hvm_vmx.real_mode_io_in_progress &&
+ (get_ioreq(curr)->vp_ioreq.dir == IOREQ_READ) )
+ {
+ gdprintk(XENLOG_ERR, "I/O read in progress but insn is retired.\n");
+ goto fail;
+ }
+
+ new_intr_shadow = rm_ctxt->intr_shadow;
+
+ /* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
+ if ( rm_ctxt->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->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 )
+ {
+ realmode_deliver_exception(
+ rm_ctxt->exn_vector, rm_ctxt->exn_insn_len, rm_ctxt);
+ }
+ else if ( rm_ctxt->flags.hlt && !hvm_local_events_need_delivery(curr) )
+ {
+ hvm_hlt(regs->eflags);
+ }
+
+ return;
+
+ fail:
+ gdprintk(XENLOG_ERR,
+ "Real-mode emulation failed @ %04x:%08lx: "
+ "%02x %02x %02x %02x %02x %02x\n",
+ rm_ctxt->seg_reg[x86_seg_cs].sel, rm_ctxt->insn_buf_eip,
+ rm_ctxt->insn_buf[0], rm_ctxt->insn_buf[1],
+ rm_ctxt->insn_buf[2], rm_ctxt->insn_buf[3],
+ rm_ctxt->insn_buf[4], rm_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;
unsigned long intr_info;
- int i, rc;
- u32 intr_shadow, new_intr_shadow;
+ int i;
rm_ctxt.ctxt.regs = regs;
@@ -520,77 +617,24 @@ void vmx_realmode(struct cpu_user_regs *
rm_ctxt.ctxt.sp_size =
rm_ctxt.seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16;
+ rm_ctxt.intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
+
+ if ( curr->arch.hvm_vmx.real_mode_io_in_progress ||
+ curr->arch.hvm_vmx.real_mode_io_completed )
+ realmode_emulate_one(&rm_ctxt);
+
intr_info = __vmread(VM_ENTRY_INTR_INFO);
- intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
- new_intr_shadow = intr_shadow;
+ if ( intr_info & INTR_INFO_VALID_MASK )
+ {
+ realmode_deliver_exception((uint8_t)intr_info, 0, &rm_ctxt);
+ __vmwrite(VM_ENTRY_INTR_INFO, 0);
+ }
while ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) &&
!softirq_pending(smp_processor_id()) &&
!hvm_local_events_need_delivery(curr) &&
!curr->arch.hvm_vmx.real_mode_io_in_progress )
- {
- if ( (intr_info & INTR_INFO_VALID_MASK) &&
- !curr->arch.hvm_vmx.real_mode_io_completed )
- {
- realmode_deliver_exception((uint8_t)intr_info, 0, &rm_ctxt);
- __vmwrite(VM_ENTRY_INTR_INFO, 0);
- intr_info = 0;
- }
-
- rm_ctxt.insn_buf_eip = regs->eip;
- (void)hvm_copy_from_guest_phys(
- rm_ctxt.insn_buf,
- (uint32_t)(rm_ctxt.seg_reg[x86_seg_cs].base + regs->eip),
- sizeof(rm_ctxt.insn_buf));
-
- rm_ctxt.flag_word = 0;
-
- rc = x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops);
-
- if ( rc == X86EMUL_RETRY )
- continue;
-
- if ( rc == X86EMUL_UNHANDLEABLE )
- {
- gdprintk(XENLOG_ERR,
- "Real-mode emulation failed @ %04x:%08lx: "
- "%02x %02x %02x %02x %02x %02x\n",
- rm_ctxt.seg_reg[x86_seg_cs].sel, rm_ctxt.insn_buf_eip,
- rm_ctxt.insn_buf[0], rm_ctxt.insn_buf[1],
- rm_ctxt.insn_buf[2], rm_ctxt.insn_buf[3],
- rm_ctxt.insn_buf[4], rm_ctxt.insn_buf[5]);
- domain_crash_synchronous();
- }
-
- /* MOV-SS instruction toggles MOV-SS shadow, else we just clear it. */
- if ( rm_ctxt.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.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 ( intr_shadow != new_intr_shadow )
- {
- intr_shadow = new_intr_shadow;
- __vmwrite(GUEST_INTERRUPTIBILITY_INFO, intr_shadow);
- }
-
- if ( rc == X86EMUL_EXCEPTION )
- {
- realmode_deliver_exception(
- rm_ctxt.exn_vector, rm_ctxt.exn_insn_len, &rm_ctxt);
- }
- else if ( rm_ctxt.flags.hlt && !hvm_local_events_need_delivery(curr) )
- {
- hvm_hlt(regs->eflags);
- }
- }
+ realmode_emulate_one(&rm_ctxt);
/*
* Cannot enter protected mode with bogus selector RPLs and DPLs. Hence we
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|