[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] vmx: Initial framework for real-mode emulation (disabled by default).
# 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |