[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [XEN] Tweak x86 emulator interface.
# HG changeset patch # User kfraser@xxxxxxxxxxxxxxxxxxxxx # Date 1168281569 0 # Node ID 8a99ebc5f5a42543d41f97329087d04d4ff301b5 # Parent 1e7bbecdc0a2f286efba0e817415908b2c5744da [XEN] Tweak x86 emulator interface. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> --- tools/tests/test_x86_emulator.c | 2 - xen/arch/x86/hvm/instrlen.c | 32 ++++++------------- xen/arch/x86/hvm/platform.c | 22 ++++++------- xen/arch/x86/hvm/svm/svm.c | 10 ++---- xen/arch/x86/hvm/vmx/vmx.c | 10 ++---- xen/arch/x86/mm.c | 6 +-- xen/arch/x86/mm/shadow/common.c | 12 +++---- xen/arch/x86/x86_emulate.c | 62 ++++++++++++++------------------------ xen/include/asm-x86/hvm/hvm.h | 2 - xen/include/asm-x86/x86_emulate.h | 19 +---------- 10 files changed, 67 insertions(+), 110 deletions(-) diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 tools/tests/test_x86_emulator.c --- a/tools/tests/test_x86_emulator.c Mon Jan 08 17:38:47 2007 +0000 +++ b/tools/tests/test_x86_emulator.c Mon Jan 08 18:39:29 2007 +0000 @@ -102,7 +102,7 @@ int main(int argc, char **argv) int rc; ctxt.regs = ®s; - ctxt.mode = X86EMUL_MODE_PROT32; + ctxt.address_bytes = 4; res = mmap((void *)0x100000, 0x1000, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/hvm/instrlen.c --- a/xen/arch/x86/hvm/instrlen.c Mon Jan 08 17:38:47 2007 +0000 +++ b/xen/arch/x86/hvm/instrlen.c Mon Jan 08 18:39:29 2007 +0000 @@ -201,7 +201,7 @@ static uint8_t twobyte_table[256] = { if ( inst_copy_from_guest(&_x, pc, 1) != 1 ) { \ gdprintk(XENLOG_WARNING, \ "Cannot read from address %lx (eip %lx, mode %d)\n", \ - pc, org_pc, mode); \ + pc, org_pc, address_bytes); \ return -1; \ } \ pc += 1; \ @@ -218,30 +218,20 @@ static uint8_t twobyte_table[256] = { * EXTERNAL this routine calculates the length of the current instruction * pointed to by org_pc. The guest state is _not_ changed by this routine. */ -int hvm_instruction_length(unsigned long org_pc, int mode) +int hvm_instruction_length(unsigned long org_pc, int address_bytes) { uint8_t b, d, twobyte = 0, rex_prefix = 0, modrm_reg = 0; unsigned int op_default, op_bytes, ad_default, ad_bytes, tmp; int length = 0; unsigned long pc = org_pc; - switch ( mode ) - { - case X86EMUL_MODE_REAL: - case X86EMUL_MODE_PROT16: - op_bytes = op_default = ad_bytes = ad_default = 2; - break; - case X86EMUL_MODE_PROT32: - op_bytes = op_default = ad_bytes = ad_default = 4; - break; -#ifdef __x86_64__ - case X86EMUL_MODE_PROT64: + op_bytes = op_default = ad_bytes = ad_default = address_bytes; + if ( op_bytes == 8 ) + { op_bytes = op_default = 4; - ad_bytes = ad_default = 8; - break; +#ifndef __x86_64__ + return -1; #endif - default: - return -1; } /* Legacy prefixes. */ @@ -253,7 +243,7 @@ int hvm_instruction_length(unsigned long op_bytes = op_default ^ 6; /* switch between 2/4 bytes */ break; case 0x67: /* address-size override */ - if ( mode == X86EMUL_MODE_PROT64 ) + if ( ad_default == 8 ) ad_bytes = ad_default ^ 12; /* switch between 4/8 bytes */ else ad_bytes = ad_default ^ 6; /* switch between 2/4 bytes */ @@ -270,7 +260,7 @@ int hvm_instruction_length(unsigned long break; #ifdef __x86_64__ case 0x40 ... 0x4f: - if ( mode == X86EMUL_MODE_PROT64 ) + if ( ad_default == 8 ) { rex_prefix = b; continue; @@ -434,7 +424,7 @@ done: cannot_emulate: gdprintk(XENLOG_WARNING, - "Cannot emulate %02x at address %lx (%lx, mode %d)\n", - b, pc - 1, org_pc, mode); + "Cannot emulate %02x at address %lx (%lx, addr_bytes %d)\n", + b, pc - 1, org_pc, address_bytes); return -1; } diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/hvm/platform.c --- a/xen/arch/x86/hvm/platform.c Mon Jan 08 17:38:47 2007 +0000 +++ b/xen/arch/x86/hvm/platform.c Mon Jan 08 18:39:29 2007 +0000 @@ -352,7 +352,7 @@ static int reg_mem(unsigned char size, u return DECODE_success; } -static int mmio_decode(int mode, unsigned char *opcode, +static int mmio_decode(int address_bytes, unsigned char *opcode, struct hvm_io_op *mmio_op, unsigned char *ad_size, unsigned char *op_size, unsigned char *seg_sel) @@ -368,9 +368,9 @@ static int mmio_decode(int mode, unsigne opcode = check_prefix(opcode, mmio_op, ad_size, op_size, seg_sel, &rex); - switch ( mode ) { - case X86EMUL_MODE_REAL: /* meaning is reversed */ - case X86EMUL_MODE_PROT16: + switch ( address_bytes ) + { + case 2: if ( *op_size == WORD ) *op_size = LONG; else if ( *op_size == LONG ) @@ -384,14 +384,14 @@ static int mmio_decode(int mode, unsigne else if ( *ad_size == 0 ) *ad_size = WORD; break; - case X86EMUL_MODE_PROT32: + case 4: if ( *op_size == 0 ) *op_size = LONG; if ( *ad_size == 0 ) *ad_size = LONG; break; #ifdef __x86_64__ - case X86EMUL_MODE_PROT64: + case 8: if ( *op_size == 0 ) *op_size = rex & 0x8 ? QUAD : LONG; if ( *ad_size == 0 ) @@ -907,7 +907,7 @@ void handle_mmio(unsigned long gpa) struct hvm_io_op *mmio_op; struct cpu_user_regs *regs; unsigned char inst[MAX_INST_LEN], ad_size, op_size, seg_sel; - int i, mode, df, inst_len; + int i, address_bytes, df, inst_len; struct vcpu *v = current; mmio_op = &v->arch.hvm_vcpu.io_op; @@ -919,9 +919,9 @@ void handle_mmio(unsigned long gpa) df = regs->eflags & X86_EFLAGS_DF ? 1 : 0; - mode = hvm_guest_x86_mode(v); + address_bytes = hvm_guest_x86_mode(v); inst_addr = hvm_get_segment_base(v, x86_seg_cs) + regs->eip; - inst_len = hvm_instruction_length(inst_addr, mode); + inst_len = hvm_instruction_length(inst_addr, address_bytes); if ( inst_len <= 0 ) { printk("handle_mmio: failed to get instruction length\n"); @@ -934,8 +934,8 @@ void handle_mmio(unsigned long gpa) domain_crash_synchronous(); } - if ( mmio_decode(mode, inst, mmio_op, &ad_size, &op_size, &seg_sel) - == DECODE_failure ) { + if ( mmio_decode(address_bytes, inst, mmio_op, &ad_size, + &op_size, &seg_sel) == DECODE_failure ) { printk("handle_mmio: failed to decode instruction\n"); printk("mmio opcode: gpa 0x%lx, len %d:", gpa, inst_len); for ( i = 0; i < inst_len; i++ ) diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Mon Jan 08 17:38:47 2007 +0000 +++ b/xen/arch/x86/hvm/svm/svm.c Mon Jan 08 18:39:29 2007 +0000 @@ -483,14 +483,12 @@ static int svm_guest_x86_mode(struct vcp struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; if ( vmcb->efer & EFER_LMA ) - return (vmcb->cs.attr.fields.l ? - X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32); + return (vmcb->cs.attr.fields.l ? 8 : 4); if ( svm_realmode(v) ) - return X86EMUL_MODE_REAL; - - return (vmcb->cs.attr.fields.db ? - X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16); + return 2; + + return (vmcb->cs.attr.fields.db ? 4 : 2); } void svm_update_host_cr3(struct vcpu *v) diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Mon Jan 08 17:38:47 2007 +0000 +++ b/xen/arch/x86/hvm/vmx/vmx.c Mon Jan 08 18:39:29 2007 +0000 @@ -695,14 +695,12 @@ static int vmx_guest_x86_mode(struct vcp cs_ar_bytes = __vmread(GUEST_CS_AR_BYTES); if ( vmx_long_mode_enabled(v) ) - return ((cs_ar_bytes & (1u<<13)) ? - X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32); + return ((cs_ar_bytes & (1u<<13)) ? 8 : 4); if ( vmx_realmode(v) ) - return X86EMUL_MODE_REAL; - - return ((cs_ar_bytes & (1u<<14)) ? - X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16); + return 2; + + return ((cs_ar_bytes & (1u<<14)) ? 4 : 2); } static int vmx_pae_enabled(struct vcpu *v) diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/mm.c --- a/xen/arch/x86/mm.c Mon Jan 08 17:38:47 2007 +0000 +++ b/xen/arch/x86/mm.c Mon Jan 08 18:39:29 2007 +0000 @@ -3379,9 +3379,9 @@ int ptwr_do_page_fault(struct vcpu *v, u goto bail; ptwr_ctxt.ctxt.regs = guest_cpu_user_regs(); - ptwr_ctxt.ctxt.mode = !IS_COMPAT(d) ? X86EMUL_MODE_HOST : X86EMUL_MODE_PROT32; - ptwr_ctxt.cr2 = addr; - ptwr_ctxt.pte = pte; + ptwr_ctxt.ctxt.address_bytes = IS_COMPAT(d) ? 4 : sizeof(long); + ptwr_ctxt.cr2 = addr; + ptwr_ctxt.pte = pte; if ( x86_emulate(&ptwr_ctxt.ctxt, &ptwr_emulate_ops) ) goto bail; diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/mm/shadow/common.c --- a/xen/arch/x86/mm/shadow/common.c Mon Jan 08 17:38:47 2007 +0000 +++ b/xen/arch/x86/mm/shadow/common.c Mon Jan 08 18:39:29 2007 +0000 @@ -110,7 +110,7 @@ static int hvm_translate_linear_addr( unsigned long limit, addr = offset; uint32_t last_byte; - if ( sh_ctxt->ctxt.mode != X86EMUL_MODE_PROT64 ) + if ( sh_ctxt->ctxt.address_bytes != 8 ) { /* * COMPATIBILITY MODE: Apply segment checks and add base. @@ -407,7 +407,7 @@ struct x86_emulate_ops *shadow_init_emul if ( !is_hvm_vcpu(v) ) { - sh_ctxt->ctxt.mode = X86EMUL_MODE_HOST; + sh_ctxt->ctxt.address_bytes = sizeof(long); return &pv_shadow_emulator_ops; } @@ -417,13 +417,11 @@ struct x86_emulate_ops *shadow_init_emul /* Work out the emulation mode. */ if ( hvm_long_mode_enabled(v) ) - sh_ctxt->ctxt.mode = creg->attr.fields.l ? - X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32; + sh_ctxt->ctxt.address_bytes = creg->attr.fields.l ? 8 : 4; else if ( regs->eflags & X86_EFLAGS_VM ) - sh_ctxt->ctxt.mode = X86EMUL_MODE_REAL; + sh_ctxt->ctxt.address_bytes = 2; else - sh_ctxt->ctxt.mode = creg->attr.fields.db ? - X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; + sh_ctxt->ctxt.address_bytes = creg->attr.fields.db ? 4 : 2; /* Attempt to prefetch whole instruction. */ sh_ctxt->insn_buf_bytes = diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/arch/x86/x86_emulate.c --- a/xen/arch/x86/x86_emulate.c Mon Jan 08 17:38:47 2007 +0000 +++ b/xen/arch/x86/x86_emulate.c Mon Jan 08 18:39:29 2007 +0000 @@ -391,10 +391,10 @@ do{ __asm__ __volatile__ ( /* Fetch next part of the instruction being emulated. */ #define insn_fetch_bytes(_size) \ ({ unsigned long _x, _eip = _truncate_ea(_regs.eip, def_ad_bytes); \ + if ( !mode_64bit() ) _eip = (uint32_t)_eip; /* ignore upper dword */ \ rc = ops->insn_fetch(x86_seg_cs, _eip, &_x, (_size), ctxt); \ - if ( rc != 0 ) \ - goto done; \ - _register_address_increment(_regs.eip, (_size), def_ad_bytes); \ + if ( rc ) goto done; \ + _regs.eip += (_size); /* real hardware doesn't truncate */ \ _x; \ }) #define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type))) @@ -406,13 +406,15 @@ do{ __asm__ __volatile__ ( }) #define truncate_ea(ea) _truncate_ea((ea), ad_bytes) +#define mode_64bit() (def_ad_bytes == 8) + /* Update address held in a register, based on addressing mode. */ #define _register_address_increment(reg, inc, byte_width) \ do { \ int _inc = (inc); /* signed type ensures sign extension to long */ \ if ( (byte_width) == sizeof(unsigned long) ) \ (reg) += _inc; \ - else if ( mode == X86EMUL_MODE_PROT64 ) \ + else if ( mode_64bit() ) \ (reg) = ((reg) + _inc) & ((1UL << ((byte_width) << 3)) - 1); \ else \ (reg) = ((reg) & ~((1UL << ((byte_width) << 3)) - 1)) | \ @@ -424,7 +426,7 @@ do { #define jmp_rel(rel) \ do { \ _regs.eip += (int)(rel); \ - if ( mode != X86EMUL_MODE_PROT64 ) \ + if ( !mode_64bit() ) \ _regs.eip = ((op_bytes == 2) \ ? (uint16_t)_regs.eip : (uint32_t)_regs.eip); \ } while (0) @@ -521,7 +523,6 @@ x86_emulate( unsigned int lock_prefix = 0, rep_prefix = 0, i; int rc = 0; struct operand src, dst; - int mode = ctxt->mode; /* Data operand effective address (usually computed from ModRM). */ struct operand ea; @@ -531,26 +532,14 @@ x86_emulate( ea.mem.seg = x86_seg_ds; ea.mem.off = 0; - switch ( mode ) - { - case X86EMUL_MODE_REAL: - case X86EMUL_MODE_PROT16: - op_bytes = def_ad_bytes = 2; - break; - case X86EMUL_MODE_PROT32: - op_bytes = def_ad_bytes = 4; - break; -#ifdef __x86_64__ - case X86EMUL_MODE_PROT64: + op_bytes = ad_bytes = def_ad_bytes = ctxt->address_bytes; + if ( op_bytes == 8 ) + { op_bytes = 4; - def_ad_bytes = 8; - break; +#ifndef __x86_64__ + return -1; #endif - default: - return -1; - } - - ad_bytes = def_ad_bytes; + } /* Prefix bytes. */ for ( i = 0; i < 8; i++ ) @@ -561,7 +550,7 @@ x86_emulate( op_bytes ^= 6; /* switch between 2/4 bytes */ break; case 0x67: /* address-size override */ - if ( mode == X86EMUL_MODE_PROT64 ) + if ( mode_64bit() ) ad_bytes ^= 12; /* switch between 4/8 bytes */ else ad_bytes ^= 6; /* switch between 2/4 bytes */ @@ -592,7 +581,7 @@ x86_emulate( rep_prefix = 1; break; case 0x40 ... 0x4f: /* REX */ - if ( mode != X86EMUL_MODE_PROT64 ) + if ( !mode_64bit() ) goto done_prefixes; rex_prefix = b; continue; @@ -685,8 +674,7 @@ x86_emulate( else if ( (sib_base == 4) && !twobyte && (b == 0x8f) ) /* POP <rm> must have its EA calculated post increment. */ ea.mem.off += _regs.esp + - (((mode == X86EMUL_MODE_PROT64) && (op_bytes == 4)) - ? 8 : op_bytes); + ((mode_64bit() && (op_bytes == 4)) ? 8 : op_bytes); else ea.mem.off += *(long*)decode_register(sib_base, &_regs, 0); } @@ -701,7 +689,7 @@ x86_emulate( if ( (modrm_rm & 7) != 5 ) break; ea.mem.off = insn_fetch_type(int32_t); - if ( mode != X86EMUL_MODE_PROT64 ) + if ( !mode_64bit() ) break; /* Relative to RIP of next instruction. Argh! */ ea.mem.off += _regs.eip; @@ -935,7 +923,7 @@ x86_emulate( break; case 0x63: /* movsxd */ - if ( mode != X86EMUL_MODE_PROT64 ) + if ( !mode_64bit() ) goto cannot_emulate; dst.val = (int32_t)src.val; break; @@ -983,7 +971,7 @@ x86_emulate( case 0x8f: /* pop (sole member of Grp1a) */ /* 64-bit mode: POP defaults to a 64-bit operand. */ - if ( (mode == X86EMUL_MODE_PROT64) && (dst.bytes == 4) ) + if ( mode_64bit() && (dst.bytes == 4) ) dst.bytes = 8; if ( (rc = ops->read(x86_seg_ss, truncate_ea(_regs.esp), &dst.val, dst.bytes, ctxt)) != 0 ) @@ -1079,7 +1067,7 @@ x86_emulate( break; case 6: /* push */ /* 64-bit mode: PUSH defaults to a 64-bit operand. */ - if ( (mode == X86EMUL_MODE_PROT64) && (dst.bytes == 4) ) + if ( mode_64bit() && (dst.bytes == 4) ) { dst.bytes = 8; if ( (rc = ops->read(dst.mem.seg, dst.mem.off, @@ -1168,7 +1156,7 @@ x86_emulate( case 0x50 ... 0x57: /* push reg */ dst.type = OP_MEM; dst.bytes = op_bytes; - if ( (mode == X86EMUL_MODE_PROT64) && (dst.bytes == 4) ) + if ( mode_64bit() && (dst.bytes == 4) ) dst.bytes = 8; dst.val = *(unsigned long *)decode_register( (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0); @@ -1182,7 +1170,7 @@ x86_emulate( dst.reg = decode_register( (b & 7) | ((rex_prefix & 1) << 3), &_regs, 0); dst.bytes = op_bytes; - if ( (mode == X86EMUL_MODE_PROT64) && (dst.bytes == 4) ) + if ( mode_64bit() && (dst.bytes == 4) ) dst.bytes = 8; if ( (rc = ops->read(x86_seg_ss, truncate_ea(_regs.esp), &dst.val, dst.bytes, ctxt)) != 0 ) @@ -1278,8 +1266,7 @@ x86_emulate( break; case 0xeb: /* jmp (near) */ - jmp_rel(insn_fetch_bytes( - (mode == X86EMUL_MODE_PROT64) ? 4 : op_bytes)); + jmp_rel(insn_fetch_bytes(mode_64bit() ? 4 : op_bytes)); break; case 0xf5: /* cmc */ @@ -1401,8 +1388,7 @@ x86_emulate( break; case 0x80 ... 0x8f: /* jcc (near) */ { - int rel = insn_fetch_bytes( - (mode == X86EMUL_MODE_PROT64) ? 4 : op_bytes); + int rel = insn_fetch_bytes(mode_64bit() ? 4 : op_bytes); if ( test_cc(b, _regs.eflags) ) jmp_rel(rel); break; diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/include/asm-x86/hvm/hvm.h --- a/xen/include/asm-x86/hvm/hvm.h Mon Jan 08 17:38:47 2007 +0000 +++ b/xen/include/asm-x86/hvm/hvm.h Mon Jan 08 18:39:29 2007 +0000 @@ -185,7 +185,7 @@ hvm_guest_x86_mode(struct vcpu *v) return hvm_funcs.guest_x86_mode(v); } -int hvm_instruction_length(unsigned long pc, int mode); +int hvm_instruction_length(unsigned long pc, int address_bytes); static inline void hvm_update_host_cr3(struct vcpu *v) diff -r 1e7bbecdc0a2 -r 8a99ebc5f5a4 xen/include/asm-x86/x86_emulate.h --- a/xen/include/asm-x86/x86_emulate.h Mon Jan 08 17:38:47 2007 +0000 +++ b/xen/include/asm-x86/x86_emulate.h Mon Jan 08 18:39:29 2007 +0000 @@ -134,24 +134,11 @@ struct x86_emulate_ctxt struct x86_emulate_ctxt { /* Register state before/after emulation. */ - struct cpu_user_regs *regs; + struct cpu_user_regs *regs; - /* Emulated execution mode, represented by an X86EMUL_MODE value. */ - int mode; + /* Default address size in current execution mode (2, 4, or 8). */ + int address_bytes; }; - -/* Execution mode, passed to the emulator. */ -#define X86EMUL_MODE_REAL 0 /* Real mode. */ -#define X86EMUL_MODE_PROT16 2 /* 16-bit protected mode. */ -#define X86EMUL_MODE_PROT32 4 /* 32-bit protected mode. */ -#define X86EMUL_MODE_PROT64 8 /* 64-bit (long) mode. */ - -/* Host execution mode. */ -#if defined(__i386__) -#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32 -#elif defined(__x86_64__) -#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64 -#endif /* * x86_emulate: Emulate an instruction. _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |