# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1195940774 0
# Node ID 51082cf273d426b6443e729e8141be24f0bdc850
# Parent d5c3961288970acd963855b12c84ede7d8ebabfc
vmx: Initial framework for real-mode emulation (disabled by default).
Still plenty to do:
- i/o emulation
- more instructions
- interrupt/exception delivery
- vm86 fast path
At this stage we can get three instructions into the rombios.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
xen/arch/x86/hvm/vmx/Makefile | 3
xen/arch/x86/hvm/vmx/realmode.c | 274 ++++++++++++++++++++++++++++++++++++++
xen/arch/x86/hvm/vmx/vmx.c | 7
xen/include/asm-x86/hvm/vmx/vmx.h | 1
4 files changed, 278 insertions(+), 7 deletions(-)
diff -r d5c396128897 -r 51082cf273d4 xen/arch/x86/hvm/vmx/Makefile
--- a/xen/arch/x86/hvm/vmx/Makefile Sat Nov 24 21:40:19 2007 +0000
+++ b/xen/arch/x86/hvm/vmx/Makefile Sat Nov 24 21:46:14 2007 +0000
@@ -4,5 +4,8 @@ subdir-$(x86_64) += x86_64
subdir-$(x86_64) += x86_64
obj-y += intr.o
+ifneq ($(vmxassist),y)
+obj-y += realmode.o
+endif
obj-y += vmcs.o
obj-y += vmx.o
diff -r d5c396128897 -r 51082cf273d4 xen/arch/x86/hvm/vmx/realmode.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/vmx/realmode.c Sat Nov 24 21:46:14 2007 +0000
@@ -0,0 +1,274 @@
+/******************************************************************************
+ * arch/x86/hvm/vmx/realmode.c
+ *
+ * Real-mode emulation for VMX.
+ *
+ * Copyright (c) 2007 Citrix Systems, Inc.
+ *
+ * Authors:
+ * Keir Fraser <keir.fraser@xxxxxxxxxx>
+ */
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <asm/hvm/hvm.h>
+#include <asm/hvm/support.h>
+#include <asm/hvm/vmx/vmx.h>
+#include <asm/hvm/vmx/vmcs.h>
+#include <asm/hvm/vmx/cpu.h>
+#include <asm/x86_emulate.h>
+
+struct realmode_emulate_ctxt {
+ struct x86_emulate_ctxt ctxt;
+
+ /* Cache of up to 31 bytes of instruction. */
+ uint8_t insn_buf[31];
+ uint8_t insn_buf_bytes;
+ unsigned long insn_buf_eip;
+
+ struct segment_register seg_reg[10];
+};
+
+static int realmode_translate_linear_addr(
+ enum x86_segment seg,
+ unsigned long offset,
+ unsigned int bytes,
+ enum hvm_access_type access_type,
+ struct realmode_emulate_ctxt *rm_ctxt,
+ unsigned long *paddr)
+{
+ struct segment_register *reg = &rm_ctxt->seg_reg[seg];
+ int okay;
+
+ okay = hvm_virtual_to_linear_addr(
+ seg, reg, offset, bytes, access_type, rm_ctxt->ctxt.addr_size, paddr);
+
+ if ( !okay )
+ {
+ hvm_inject_exception(TRAP_gp_fault, 0, 0);
+ return X86EMUL_EXCEPTION;
+ }
+
+ return 0;
+}
+
+static int
+realmode_read(
+ enum x86_segment seg,
+ unsigned long offset,
+ unsigned long *val,
+ unsigned int bytes,
+ enum hvm_access_type access_type,
+ struct realmode_emulate_ctxt *rm_ctxt)
+{
+ unsigned long addr;
+ int rc;
+
+ rc = realmode_translate_linear_addr(
+ seg, offset, bytes, access_type, rm_ctxt, &addr);
+ if ( rc )
+ return rc;
+
+ *val = 0;
+ (void)hvm_copy_from_guest_phys(val, addr, bytes);
+ return X86EMUL_OKAY;
+}
+
+static int
+realmode_emulate_read(
+ enum x86_segment seg,
+ unsigned long offset,
+ unsigned long *val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ return realmode_read(
+ seg, offset, val, bytes, hvm_access_read,
+ container_of(ctxt, struct realmode_emulate_ctxt, ctxt));
+}
+
+static int
+realmode_emulate_insn_fetch(
+ enum x86_segment seg,
+ unsigned long offset,
+ unsigned long *val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct realmode_emulate_ctxt *rm_ctxt =
+ container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
+ unsigned int insn_off = offset - rm_ctxt->insn_buf_eip;
+
+ /* Fall back if requested bytes are not in the prefetch cache. */
+ if ( unlikely((insn_off + bytes) > rm_ctxt->insn_buf_bytes) )
+ return realmode_read(
+ seg, offset, val, bytes,
+ hvm_access_insn_fetch, rm_ctxt);
+
+ /* Hit the cache. Simple memcpy. */
+ *val = 0;
+ memcpy(val, &rm_ctxt->insn_buf[insn_off], bytes);
+ return X86EMUL_OKAY;
+}
+
+static int
+realmode_emulate_write(
+ enum x86_segment seg,
+ unsigned long offset,
+ unsigned long val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct realmode_emulate_ctxt *rm_ctxt =
+ container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
+ unsigned long addr;
+ int rc;
+
+ rc = realmode_translate_linear_addr(
+ seg, offset, bytes, hvm_access_write, rm_ctxt, &addr);
+ if ( rc )
+ return rc;
+
+ (void)hvm_copy_to_guest_phys(addr, &val, bytes);
+ return X86EMUL_OKAY;
+}
+
+static int
+realmode_emulate_cmpxchg(
+ enum x86_segment seg,
+ unsigned long offset,
+ unsigned long old,
+ unsigned long new,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ return X86EMUL_UNHANDLEABLE;
+}
+
+static int
+realmode_read_segment(
+ enum x86_segment seg,
+ struct segment_register *reg,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct realmode_emulate_ctxt *rm_ctxt =
+ container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
+ memcpy(reg, &rm_ctxt->seg_reg[seg], sizeof(struct segment_register));
+ return X86EMUL_OKAY;
+}
+
+static int
+realmode_write_segment(
+ enum x86_segment seg,
+ struct segment_register *reg,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct realmode_emulate_ctxt *rm_ctxt =
+ container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
+ memcpy(&rm_ctxt->seg_reg[seg], reg, sizeof(struct segment_register));
+ return X86EMUL_OKAY;
+}
+
+static int
+realmode_read_io(
+ unsigned int port,
+ unsigned int bytes,
+ unsigned long *val,
+ struct x86_emulate_ctxt *ctxt)
+{
+ return X86EMUL_UNHANDLEABLE;
+}
+
+static int realmode_write_io(
+ unsigned int port,
+ unsigned int bytes,
+ unsigned long val,
+ struct x86_emulate_ctxt *ctxt)
+{
+ return X86EMUL_UNHANDLEABLE;
+}
+
+static int
+realmode_read_cr(
+ unsigned int reg,
+ unsigned long *val,
+ struct x86_emulate_ctxt *ctxt)
+{
+ switch ( reg )
+ {
+ case 0:
+ case 2:
+ case 3:
+ case 4:
+ *val = current->arch.hvm_vcpu.guest_cr[reg];
+ break;
+ default:
+ return X86EMUL_UNHANDLEABLE;
+ }
+
+ return X86EMUL_OKAY;
+}
+
+static struct x86_emulate_ops realmode_emulator_ops = {
+ .read = realmode_emulate_read,
+ .insn_fetch = realmode_emulate_insn_fetch,
+ .write = realmode_emulate_write,
+ .cmpxchg = realmode_emulate_cmpxchg,
+ .read_segment = realmode_read_segment,
+ .write_segment = realmode_write_segment,
+ .read_io = realmode_read_io,
+ .write_io = realmode_write_io,
+ .read_cr = realmode_read_cr
+};
+
+int vmx_realmode(struct cpu_user_regs *regs)
+{
+ struct vcpu *curr = current;
+ struct realmode_emulate_ctxt rm_ctxt;
+ unsigned long addr;
+ int i, rc = 0;
+
+ for ( i = 0; i < 10; i++ )
+ hvm_get_segment_register(curr, i, &rm_ctxt.seg_reg[i]);
+
+ while ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) &&
+ !softirq_pending(smp_processor_id()) )
+ {
+ rm_ctxt.ctxt.regs = regs;
+ rm_ctxt.ctxt.addr_size =
+ rm_ctxt.seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16;
+ rm_ctxt.ctxt.sp_size =
+ rm_ctxt.seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16;
+
+ rm_ctxt.insn_buf_eip = regs->eip;
+ rm_ctxt.insn_buf_bytes =
+ (hvm_virtual_to_linear_addr(
+ x86_seg_cs, &rm_ctxt.seg_reg[x86_seg_cs],
+ regs->eip, sizeof(rm_ctxt.insn_buf),
+ hvm_access_insn_fetch, rm_ctxt.ctxt.addr_size, &addr) &&
+ !hvm_copy_from_guest_virt(
+ rm_ctxt.insn_buf, addr, sizeof(rm_ctxt.insn_buf)))
+ ? sizeof(rm_ctxt.insn_buf) : 0;
+
+ gdprintk(XENLOG_DEBUG,
+ "RM %04x:%08lx: %02x %02x %02x %02x %02x %02x\n",
+ rm_ctxt.seg_reg[x86_seg_cs].sel, regs->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]);
+
+ if ( x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops) )
+ {
+ gdprintk(XENLOG_ERR, "Emulation failed\n");
+ rc = -EINVAL;
+ break;
+ }
+ }
+
+ for ( i = 0; i < 10; i++ )
+ hvm_set_segment_register(curr, i, &rm_ctxt.seg_reg[i]);
+
+ return rc;
+}
diff -r d5c396128897 -r 51082cf273d4 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c Sat Nov 24 21:40:19 2007 +0000
+++ b/xen/arch/x86/hvm/vmx/vmx.c Sat Nov 24 21:46:14 2007 +0000
@@ -2078,13 +2078,6 @@ static int vmx_set_cr0(unsigned long val
#define vmx_set_cr0(v) hvm_set_cr0(v)
-static int vmx_realmode(struct cpu_user_regs *regs)
-{
- gdprintk(XENLOG_ERR, "Attempt to enter real mode on VCPU %d\n",
- current->vcpu_id);
- return -EINVAL;
-}
-
#endif
#define CASE_SET_REG(REG, reg) \
diff -r d5c396128897 -r 51082cf273d4 xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h Sat Nov 24 21:40:19 2007 +0000
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h Sat Nov 24 21:46:14 2007 +0000
@@ -33,6 +33,7 @@ void vmx_do_resume(struct vcpu *);
void vmx_do_resume(struct vcpu *);
void set_guest_time(struct vcpu *v, u64 gtime);
void vmx_vlapic_msr_changed(struct vcpu *v);
+int vmx_realmode(struct cpu_user_regs *regs);
/*
* Exit Reasons
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|