[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [HVM] Use AMD's isntruction-length decoder for VMX as well as SVM
# HG changeset patch # User kfraser@xxxxxxxxxxxxxxxxxxxxx # Node ID e0db5a3a2ef613f61e1d873cd2749c75c1d0caa7 # Parent 807fbfb0a0dcf7c1e2c4c46f10f093d0905e49f3 [HVM] Use AMD's isntruction-length decoder for VMX as well as SVM MMIO decode. The VMX-defined instruction-length info field is not valid for use during most page faults. Hence we have to obtain the instruction length the slow-and-stupid way. This *will* go away when we throw away the wretched MMIO emulator. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> --- xen/arch/x86/hvm/svm/instrlen.c | 479 -------------------------------------- xen/arch/x86/hvm/Makefile | 1 xen/arch/x86/hvm/instrlen.c | 474 +++++++++++++++++++++++++++++++++++++ xen/arch/x86/hvm/platform.c | 48 +-- xen/arch/x86/hvm/svm/Makefile | 1 xen/arch/x86/hvm/svm/svm.c | 27 -- xen/arch/x86/hvm/vmx/vmx.c | 40 ++- xen/include/asm-x86/hvm/hvm.h | 18 - xen/include/asm-x86/hvm/vmx/vmx.h | 26 -- 9 files changed, 548 insertions(+), 566 deletions(-) diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/Makefile --- a/xen/arch/x86/hvm/Makefile Mon Sep 25 09:36:11 2006 +0100 +++ b/xen/arch/x86/hvm/Makefile Mon Sep 25 10:22:17 2006 +0100 @@ -4,6 +4,7 @@ obj-y += hvm.o obj-y += hvm.o obj-y += i8254.o obj-y += i8259.o +obj-y += instrlen.o obj-y += intercept.o obj-y += io.o obj-y += platform.o diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/platform.c --- a/xen/arch/x86/hvm/platform.c Mon Sep 25 09:36:11 2006 +0100 +++ b/xen/arch/x86/hvm/platform.c Mon Sep 25 10:22:17 2006 +0100 @@ -52,7 +52,7 @@ static inline long __get_reg_value(unsig case QUAD: return (long)(reg); default: - printf("Error: (__get_reg_value) Invalid reg size\n"); + printk("Error: (__get_reg_value) Invalid reg size\n"); domain_crash_synchronous(); } } @@ -78,7 +78,7 @@ long get_reg_value(int size, int index, case 7: /* %bh */ return (char)((regs->rbx & 0xFF00) >> 8); default: - printf("Error: (get_reg_value) Invalid index value\n"); + printk("Error: (get_reg_value) Invalid index value\n"); domain_crash_synchronous(); } /* NOTREACHED */ @@ -102,7 +102,7 @@ long get_reg_value(int size, int index, case 14: return __get_reg_value(regs->r14, size); case 15: return __get_reg_value(regs->r15, size); default: - printf("Error: (get_reg_value) Invalid index value\n"); + printk("Error: (get_reg_value) Invalid index value\n"); domain_crash_synchronous(); } } @@ -115,7 +115,7 @@ static inline long __get_reg_value(unsig case LONG: return (int)(reg & 0xFFFFFFFF); default: - printf("Error: (__get_reg_value) Invalid reg size\n"); + printk("Error: (__get_reg_value) Invalid reg size\n"); domain_crash_synchronous(); } } @@ -141,7 +141,7 @@ long get_reg_value(int size, int index, case 7: /* %bh */ return (char)((regs->ebx & 0xFF00) >> 8); default: - printf("Error: (get_reg_value) Invalid index value\n"); + printk("Error: (get_reg_value) Invalid index value\n"); domain_crash_synchronous(); } } @@ -156,7 +156,7 @@ long get_reg_value(int size, int index, case 6: return __get_reg_value(regs->esi, size); case 7: return __get_reg_value(regs->edi, size); default: - printf("Error: (get_reg_value) Invalid index value\n"); + printk("Error: (get_reg_value) Invalid index value\n"); domain_crash_synchronous(); } } @@ -464,7 +464,7 @@ static int hvm_decode(int realmode, unsi return DECODE_success; default: - printf("%x/%x, This opcode isn't handled yet!\n", + printk("%x/%x, This opcode isn't handled yet!\n", *opcode, ins_subtype); return DECODE_failure; } @@ -614,7 +614,7 @@ static int hvm_decode(int realmode, unsi break; default: - printf("%x, This opcode isn't handled yet!\n", *opcode); + printk("%x, This opcode isn't handled yet!\n", *opcode); return DECODE_failure; } @@ -675,12 +675,12 @@ static int hvm_decode(int realmode, unsi } else { - printf("0f %x, This opcode subtype isn't handled yet\n", *opcode); + printk("0f %x, This opcode subtype isn't handled yet\n", *opcode); return DECODE_failure; } default: - printf("0f %x, This opcode isn't handled yet\n", *opcode); + printk("0f %x, This opcode isn't handled yet\n", *opcode); return DECODE_failure; } } @@ -702,7 +702,7 @@ static void hvm_send_assist_req(struct v if ( unlikely(p->state != STATE_INVALID) ) { /* This indicates a bug in the device model. Crash the domain. */ - printf("Device model set bad IO state %d.\n", p->state); + printk("Device model set bad IO state %d.\n", p->state); domain_crash(v->domain); return; } @@ -733,7 +733,7 @@ void send_pio_req(struct cpu_user_regs * p = &vio->vp_ioreq; if ( p->state != STATE_INVALID ) - printf("WARNING: send pio with something already pending (%d)?\n", + printk("WARNING: send pio with something already pending (%d)?\n", p->state); p->dir = dir; p->pdata_valid = pvalid; @@ -776,14 +776,14 @@ void send_mmio_req( vio = get_vio(v->domain, v->vcpu_id); if (vio == NULL) { - printf("bad shared page\n"); + printk("bad shared page\n"); domain_crash_synchronous(); } p = &vio->vp_ioreq; if ( p->state != STATE_INVALID ) - printf("WARNING: send mmio with something already pending (%d)?\n", + printk("WARNING: send mmio with something already pending (%d)?\n", p->state); p->dir = dir; p->pdata_valid = pvalid; @@ -841,7 +841,7 @@ static void mmio_operands(int type, unsi else send_mmio_req(type, gpa, 1, inst->op_size, 0, IOREQ_READ, 0); } else { - printf("mmio_operands: invalid operand\n"); + printk("mmio_operands: invalid operand\n"); domain_crash_synchronous(); } } @@ -866,8 +866,10 @@ void handle_mmio(unsigned long va, unsig memcpy(regs, guest_cpu_user_regs(), HVM_CONTEXT_STACK_BYTES); hvm_store_cpu_guest_regs(v, regs, NULL); - if ((inst_len = hvm_instruction_length(v)) <= 0) { - printf("handle_mmio: failed to get instruction length\n"); + inst_len = hvm_instruction_length(regs, hvm_guest_x86_mode(v)); + if ( inst_len <= 0 ) + { + printk("handle_mmio: failed to get instruction length\n"); domain_crash_synchronous(); } @@ -880,19 +882,19 @@ void handle_mmio(unsigned long va, unsig memset(inst, 0, MAX_INST_LEN); ret = inst_copy_from_guest(inst, inst_addr, inst_len); if (ret != inst_len) { - printf("handle_mmio: failed to copy instruction\n"); + printk("handle_mmio: failed to copy instruction\n"); domain_crash_synchronous(); } init_instruction(&mmio_inst); if (hvm_decode(realmode, inst, &mmio_inst) == DECODE_failure) { - printf("handle_mmio: failed to decode instruction\n"); - printf("mmio opcode: va 0x%lx, gpa 0x%lx, len %d:", + printk("handle_mmio: failed to decode instruction\n"); + printk("mmio opcode: va 0x%lx, gpa 0x%lx, len %d:", va, gpa, inst_len); for (i = 0; i < inst_len; i++) - printf(" %02x", inst[i] & 0xFF); - printf("\n"); + printk(" %02x", inst[i] & 0xFF); + printk("\n"); domain_crash_synchronous(); } @@ -1073,7 +1075,7 @@ void handle_mmio(unsigned long va, unsig break; default: - printf("Unhandled MMIO instruction\n"); + printk("Unhandled MMIO instruction\n"); domain_crash_synchronous(); } } diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/svm/Makefile --- a/xen/arch/x86/hvm/svm/Makefile Mon Sep 25 09:36:11 2006 +0100 +++ b/xen/arch/x86/hvm/svm/Makefile Mon Sep 25 10:22:17 2006 +0100 @@ -2,7 +2,6 @@ subdir-$(x86_64) += x86_64 subdir-$(x86_64) += x86_64 obj-y += emulate.o -obj-y += instrlen.o obj-y += intr.o obj-y += svm.o obj-y += vmcb.o diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Mon Sep 25 09:36:11 2006 +0100 +++ b/xen/arch/x86/hvm/svm/svm.c Mon Sep 25 10:22:17 2006 +0100 @@ -44,6 +44,7 @@ #include <asm/hvm/svm/emulate.h> #include <asm/hvm/svm/vmmcall.h> #include <asm/hvm/svm/intr.h> +#include <asm/x86_emulate.h> #include <public/sched.h> #define SVM_EXTRA_DEBUG @@ -60,7 +61,6 @@ extern asmlinkage void do_IRQ(struct cpu extern asmlinkage void do_IRQ(struct cpu_user_regs *); extern void send_pio_req(struct cpu_user_regs *regs, unsigned long port, unsigned long count, int size, long value, int dir, int pvalid); -extern int svm_instrlen(struct cpu_user_regs *regs, int mode); extern void svm_dump_inst(unsigned long eip); extern int svm_dbg_on; void svm_dump_regs(const char *from, struct cpu_user_regs *regs); @@ -468,21 +468,19 @@ static int svm_realmode(struct vcpu *v) return (eflags & X86_EFLAGS_VM) || !(cr0 & X86_CR0_PE); } -int svm_guest_x86_mode(struct vcpu *v) +static int svm_guest_x86_mode(struct vcpu *v) { struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; - unsigned long cr0 = vmcb->cr0, eflags = vmcb->rflags, mode; - /* check which operating mode the guest is running */ - if( vmcb->efer & EFER_LMA ) - mode = vmcb->cs.attributes.fields.l ? 8 : 4; - else - mode = (eflags & X86_EFLAGS_VM) || !(cr0 & X86_CR0_PE) ? 2 : 4; - return mode; -} - -int svm_instruction_length(struct vcpu *v) -{ - return svm_instrlen(guest_cpu_user_regs(), svm_guest_x86_mode(v)); + + if ( vmcb->efer & EFER_LMA ) + return (vmcb->cs.attributes.fields.l ? + X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32); + + if ( svm_realmode(v) ) + return X86EMUL_MODE_REAL; + + return (vmcb->cs.attributes.fields.db ? + X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16); } void svm_update_host_cr3(struct vcpu *v) @@ -878,7 +876,6 @@ int start_svm(void) hvm_funcs.long_mode_enabled = svm_long_mode_enabled; hvm_funcs.pae_enabled = svm_pae_enabled; hvm_funcs.guest_x86_mode = svm_guest_x86_mode; - hvm_funcs.instruction_length = svm_instruction_length; hvm_funcs.get_guest_ctrl_reg = svm_get_ctrl_reg; hvm_funcs.update_host_cr3 = svm_update_host_cr3; diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Mon Sep 25 09:36:11 2006 +0100 +++ b/xen/arch/x86/hvm/vmx/vmx.c Mon Sep 25 10:22:17 2006 +0100 @@ -45,6 +45,7 @@ #include <public/hvm/ioreq.h> #include <asm/hvm/vpic.h> #include <asm/hvm/vlapic.h> +#include <asm/x86_emulate.h> extern uint32_t vlapic_update_ppr(struct vlapic *vlapic); @@ -593,15 +594,6 @@ static void vmx_load_cpu_guest_regs(stru vmx_vmcs_exit(v); } -static int vmx_instruction_length(struct vcpu *v) -{ - unsigned long inst_len; - - if ( __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len) ) /* XXX Unsafe XXX */ - return 0; - return inst_len; -} - static unsigned long vmx_get_ctrl_reg(struct vcpu *v, unsigned int num) { switch ( num ) @@ -729,6 +721,35 @@ static void vmx_init_hypercall_page(stru *(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */ } +static int vmx_realmode(struct vcpu *v) +{ + unsigned long rflags; + + ASSERT(v == current); + + __vmread(GUEST_RFLAGS, &rflags); + return rflags & X86_EFLAGS_VM; +} + +static int vmx_guest_x86_mode(struct vcpu *v) +{ + unsigned long cs_ar_bytes; + + ASSERT(v == current); + + __vmread(GUEST_CS_AR_BYTES, &cs_ar_bytes); + + if ( vmx_long_mode_enabled(v) ) + return ((cs_ar_bytes & (1u<<13)) ? + X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32); + + if ( vmx_realmode(v) ) + return X86EMUL_MODE_REAL; + + return ((cs_ar_bytes & (1u<<14)) ? + X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16); +} + /* Setup HVM interfaces */ static void vmx_setup_hvm_funcs(void) { @@ -748,7 +769,6 @@ static void vmx_setup_hvm_funcs(void) hvm_funcs.long_mode_enabled = vmx_long_mode_enabled; hvm_funcs.pae_enabled = vmx_pae_enabled; hvm_funcs.guest_x86_mode = vmx_guest_x86_mode; - hvm_funcs.instruction_length = vmx_instruction_length; hvm_funcs.get_guest_ctrl_reg = vmx_get_ctrl_reg; hvm_funcs.update_host_cr3 = vmx_update_host_cr3; diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/include/asm-x86/hvm/hvm.h --- a/xen/include/asm-x86/hvm/hvm.h Mon Sep 25 09:36:11 2006 +0100 +++ b/xen/include/asm-x86/hvm/hvm.h Mon Sep 25 10:22:17 2006 +0100 @@ -51,15 +51,13 @@ struct hvm_function_table { * Examine specifics of the guest state: * 1) determine whether the guest is in real or vm8086 mode, * 2) determine whether paging is enabled, - * 3) return the length of the instruction that caused an exit. - * 4) return the current guest control-register value + * 3) return the current guest control-register value */ int (*realmode)(struct vcpu *v); int (*paging_enabled)(struct vcpu *v); int (*long_mode_enabled)(struct vcpu *v); int (*pae_enabled)(struct vcpu *v); int (*guest_x86_mode)(struct vcpu *v); - int (*instruction_length)(struct vcpu *v); unsigned long (*get_guest_ctrl_reg)(struct vcpu *v, unsigned int num); /* @@ -159,11 +157,7 @@ hvm_guest_x86_mode(struct vcpu *v) return hvm_funcs.guest_x86_mode(v); } -static inline int -hvm_instruction_length(struct vcpu *v) -{ - return hvm_funcs.instruction_length(v); -} +int hvm_instruction_length(struct cpu_user_regs *regs, int mode); static inline void hvm_update_host_cr3(struct vcpu *v) @@ -182,9 +176,9 @@ hvm_get_guest_ctrl_reg(struct vcpu *v, u return 0; /* force to fail */ } -extern void hvm_stts(struct vcpu *v); -extern void hvm_set_guest_time(struct vcpu *v, u64 gtime); -extern void hvm_do_resume(struct vcpu *v); +void hvm_stts(struct vcpu *v); +void hvm_set_guest_time(struct vcpu *v, u64 gtime); +void hvm_do_resume(struct vcpu *v); static inline void hvm_init_ap_context(struct vcpu_guest_context *ctxt, @@ -193,6 +187,6 @@ hvm_init_ap_context(struct vcpu_guest_co return hvm_funcs.init_ap_context(ctxt, vcpuid, trampoline_vector); } -extern int hvm_bringup_ap(int vcpuid, int trampoline_vector); +int hvm_bringup_ap(int vcpuid, int trampoline_vector); #endif /* __ASM_X86_HVM_HVM_H__ */ diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/include/asm-x86/hvm/vmx/vmx.h --- a/xen/include/asm-x86/hvm/vmx/vmx.h Mon Sep 25 09:36:11 2006 +0100 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h Mon Sep 25 10:22:17 2006 +0100 @@ -425,36 +425,10 @@ static inline int vmx_pae_enabled(struct } /* Works only for vcpu == current */ -static inline int vmx_realmode(struct vcpu *v) -{ - unsigned long rflags; - ASSERT(v == current); - - __vmread(GUEST_RFLAGS, &rflags); - return rflags & X86_EFLAGS_VM; -} - -/* Works only for vcpu == current */ static inline void vmx_update_host_cr3(struct vcpu *v) { ASSERT(v == current); __vmwrite(HOST_CR3, v->arch.cr3); -} - -static inline int vmx_guest_x86_mode(struct vcpu *v) -{ - unsigned long cs_ar_bytes; - ASSERT(v == current); - - if ( vmx_long_mode_enabled(v) ) - { - __vmread(GUEST_CS_AR_BYTES, &cs_ar_bytes); - return (cs_ar_bytes & (1u<<13)) ? 8 : 4; - } - if ( vmx_realmode(v) ) - return 2; - __vmread(GUEST_CS_AR_BYTES, &cs_ar_bytes); - return (cs_ar_bytes & (1u<<14)) ? 4 : 2; } static inline int vmx_pgbit_test(struct vcpu *v) diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/instrlen.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/hvm/instrlen.c Mon Sep 25 10:22:17 2006 +0100 @@ -0,0 +1,474 @@ +/* + * instrlen.c - calculates the instruction length for all operating modes + * + * Travis Betak, travis.betak@xxxxxxx + * Copyright (c) 2005,2006 AMD + * Copyright (c) 2005 Keir Fraser + * + * Essentially a very, very stripped version of Keir Fraser's work in + * x86_emulate.c. Used for MMIO. + */ + +/* + * TODO: The way in which we use hvm_instruction_length is very inefficient as + * it now stands. It will be worthwhile to return the actual instruction buffer + * along with the instruction length since one of the reasons we are getting + * the instruction length is to know how many instruction bytes we need to + * fetch. + */ + +#include <xen/config.h> +#include <xen/sched.h> +#include <xen/mm.h> +#include <asm/regs.h> +#include <asm-x86/x86_emulate.h> + +/* read from guest memory */ +extern int inst_copy_from_guest(unsigned char *buf, unsigned long eip, + int length); + +/* + * Opcode effective-address decode tables. + * Note that we only emulate instructions that have at least one memory + * operand (excluding implicit stack references). We assume that stack + * references and instruction fetches will never occur in special memory + * areas that require emulation. So, for example, 'mov <imm>,<reg>' need + * not be handled. + */ + +/* Operand sizes: 8-bit operands or specified/overridden size. */ +#define ByteOp (1<<0) /* 8-bit operands. */ +/* Destination operand type. */ +#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */ +#define DstReg (2<<1) /* Register operand. */ +#define DstMem (3<<1) /* Memory operand. */ +#define DstMask (3<<1) +/* Source operand type. */ +#define SrcNone (0<<3) /* No source operand. */ +#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */ +#define SrcReg (1<<3) /* Register operand. */ +#define SrcMem (2<<3) /* Memory operand. */ +#define SrcMem16 (3<<3) /* Memory operand (16-bit). */ +#define SrcMem32 (4<<3) /* Memory operand (32-bit). */ +#define SrcImm (5<<3) /* Immediate operand. */ +#define SrcImmByte (6<<3) /* 8-bit sign-extended immediate operand. */ +#define SrcMask (7<<3) +/* Generic ModRM decode. */ +#define ModRM (1<<6) +/* Destination is only written; never read. */ +#define Mov (1<<7) + +static uint8_t opcode_table[256] = { + /* 0x00 - 0x07 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x08 - 0x0F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x10 - 0x17 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x18 - 0x1F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x20 - 0x27 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x28 - 0x2F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x30 - 0x37 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x38 - 0x3F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, 0, + /* 0x40 - 0x4F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x50 - 0x5F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x60 - 0x6F */ + 0, 0, 0, DstReg|SrcMem32|ModRM|Mov /* movsxd (x86/64) */, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x70 - 0x7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x80 - 0x87 */ + ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM, + ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + /* 0x88 - 0x8F */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, + 0, 0, 0, DstMem|SrcNone|ModRM|Mov, + /* 0x90 - 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xA0 - 0xA7 */ + ByteOp|DstReg|SrcMem|Mov, DstReg|SrcMem|Mov, + ByteOp|DstMem|SrcReg|Mov, DstMem|SrcReg|Mov, + ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, + ByteOp|ImplicitOps, ImplicitOps, + /* 0xA8 - 0xAF */ + 0, 0, ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, + ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, + ByteOp|ImplicitOps, ImplicitOps, + /* 0xB0 - 0xBF */ + SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, + SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xC0 - 0xC7 */ + ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, 0, 0, + 0, 0, ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM, + /* 0xC8 - 0xCF */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xD0 - 0xD7 */ + ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, + ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, + 0, 0, 0, 0, + /* 0xD8 - 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE0 - 0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xF0 - 0xF7 */ + 0, 0, 0, 0, + 0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM, + /* 0xF8 - 0xFF */ + 0, 0, 0, 0, + 0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM +}; + +static uint8_t twobyte_table[256] = { + /* 0x00 - 0x0F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, + /* 0x10 - 0x1F */ + 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, + /* 0x20 - 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x30 - 0x3F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x40 - 0x47 */ + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + /* 0x48 - 0x4F */ + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, + /* 0x50 - 0x5F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x60 - 0x6F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x70 - 0x7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x80 - 0x8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x90 - 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xA0 - 0xA7 */ + 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0, + /* 0xA8 - 0xAF */ + 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0, + /* 0xB0 - 0xB7 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstMem|SrcReg|ModRM, + 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov, + /* 0xB8 - 0xBF */ + 0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM, + 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov, + /* 0xC0 - 0xCF */ + 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xD0 - 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xE0 - 0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xF0 - 0xFF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * insn_fetch - fetch the next 1 to 4 bytes from instruction stream + * + * @_type: u8, u16, u32, s8, s16, or s32 + * @_size: 1, 2, or 4 bytes + * @_eip: address to fetch from guest memory + * @_length: increments the current instruction length counter by _size + * + * This is used internally by hvm_instruction_length to fetch the next byte, + * word, or dword from guest memory at location _eip. we currently use a local + * unsigned long as the storage buffer since the most bytes we're gonna get + * is limited to 4. + */ +#define insn_fetch(_type, _size, _eip, _length) \ +({ unsigned long _x; \ + if ((rc = inst_copy_from_guest((unsigned char *)(&(_x)), \ + (unsigned long)(_eip), _size)) \ + != _size) \ + goto done; \ + (_eip) += (_size); \ + (_length) += (_size); \ + (_type)_x; \ +}) + +/** + * hvm_instruction_length - returns the current instructions length + * + * @regs: guest register state + * @mode: guest operating mode + * + * EXTERNAL this routine calculates the length of the current instruction + * pointed to by eip. The guest state is _not_ changed by this routine. + */ +int hvm_instruction_length(struct cpu_user_regs *regs, int mode) +{ + uint8_t b, d, twobyte = 0, rex_prefix = 0; + uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0; + unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i; + int rc = 0; + int length = 0; + unsigned int tmp; + + /* Shadow copy of register state. Committed on successful emulation. */ + struct cpu_user_regs _regs = *regs; + + /* include CS for 16-bit modes */ + if (mode == X86EMUL_MODE_REAL || mode == X86EMUL_MODE_PROT16) + _regs.eip += (_regs.cs << 4); + + switch ( mode ) + { + case X86EMUL_MODE_REAL: + case X86EMUL_MODE_PROT16: + op_bytes = ad_bytes = 2; + break; + case X86EMUL_MODE_PROT32: + op_bytes = ad_bytes = 4; + break; +#ifdef __x86_64__ + case X86EMUL_MODE_PROT64: + op_bytes = 4; + ad_bytes = 8; + break; +#endif + default: + return -1; + } + + /* Legacy prefixes. */ + for ( i = 0; i < 8; i++ ) + { + switch ( b = insn_fetch(uint8_t, 1, _regs.eip, length) ) + { + case 0x66: /* operand-size override */ + op_bytes ^= 6; /* switch between 2/4 bytes */ + break; + case 0x67: /* address-size override */ + if ( mode == X86EMUL_MODE_PROT64 ) + ad_bytes ^= 12; /* switch between 4/8 bytes */ + else + ad_bytes ^= 6; /* switch between 2/4 bytes */ + break; + case 0x2e: /* CS override */ + case 0x3e: /* DS override */ + case 0x26: /* ES override */ + case 0x64: /* FS override */ + case 0x65: /* GS override */ + case 0x36: /* SS override */ + break; + case 0xf0: /* LOCK */ + lock_prefix = 1; + break; + case 0xf3: /* REP/REPE/REPZ */ + rep_prefix = 1; + break; + case 0xf2: /* REPNE/REPNZ */ + break; + default: + goto done_prefixes; + } + } +done_prefixes: + + /* Note quite the same as 80386 real mode, but hopefully good enough. */ + if ( (mode == X86EMUL_MODE_REAL) && (ad_bytes != 2) ) { + printf("sonofabitch!! we don't support 32-bit addresses in realmode\n"); + goto cannot_emulate; + } + + /* REX prefix. */ + if ( (mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40) ) + { + rex_prefix = b; + if ( b & 8 ) + op_bytes = 8; /* REX.W */ + modrm_reg = (b & 4) << 1; /* REX.R */ + /* REX.B and REX.X do not need to be decoded. */ + b = insn_fetch(uint8_t, 1, _regs.eip, length); + } + + /* Opcode byte(s). */ + d = opcode_table[b]; + if ( d == 0 ) + { + /* Two-byte opcode? */ + if ( b == 0x0f ) + { + twobyte = 1; + b = insn_fetch(uint8_t, 1, _regs.eip, length); + d = twobyte_table[b]; + } + + /* Unrecognised? */ + if ( d == 0 ) + goto cannot_emulate; + } + + /* ModRM and SIB bytes. */ + if ( d & ModRM ) + { + modrm = insn_fetch(uint8_t, 1, _regs.eip, length); + modrm_mod |= (modrm & 0xc0) >> 6; + modrm_reg |= (modrm & 0x38) >> 3; + modrm_rm |= (modrm & 0x07); + + if ( modrm_mod == 3 ) + { + DPRINTK("Cannot parse ModRM.mod == 3.\n"); + goto cannot_emulate; + } + + if ( ad_bytes == 2 ) + { + /* 16-bit ModR/M decode. */ + switch ( modrm_mod ) + { + case 0: + if ( modrm_rm == 6 ) + { + length += 2; + _regs.eip += 2; /* skip disp16 */ + } + break; + case 1: + length += 1; + _regs.eip += 1; /* skip disp8 */ + break; + case 2: + length += 2; + _regs.eip += 2; /* skip disp16 */ + break; + } + } + else + { + /* 32/64-bit ModR/M decode. */ + switch ( modrm_mod ) + { + case 0: + if ( (modrm_rm == 4) && + (((insn_fetch(uint8_t, 1, _regs.eip, length)) & 7) + == 5) ) + { + length += 4; + _regs.eip += 4; /* skip disp32 specified by SIB.base */ + } + else if ( modrm_rm == 5 ) + { + length += 4; + _regs.eip += 4; /* skip disp32 */ + } + break; + case 1: + if ( modrm_rm == 4 ) + { + insn_fetch(uint8_t, 1, _regs.eip, length); + } + length += 1; + _regs.eip += 1; /* skip disp8 */ + break; + case 2: + if ( modrm_rm == 4 ) + { + insn_fetch(uint8_t, 1, _regs.eip, length); + } + length += 4; + _regs.eip += 4; /* skip disp32 */ + break; + } + } + } + + /* Decode and fetch the destination operand: register or memory. */ + switch ( d & DstMask ) + { + case ImplicitOps: + /* Special instructions do their own operand decoding. */ + goto done; + } + + /* Decode and fetch the source operand: register, memory or immediate. */ + switch ( d & SrcMask ) + { + case SrcImm: + tmp = (d & ByteOp) ? 1 : op_bytes; + if ( tmp == 8 ) tmp = 4; + /* NB. Immediates are sign-extended as necessary. */ + switch ( tmp ) + { + case 1: insn_fetch(int8_t, 1, _regs.eip, length); break; + case 2: insn_fetch(int16_t, 2, _regs.eip, length); break; + case 4: insn_fetch(int32_t, 4, _regs.eip, length); break; + } + break; + case SrcImmByte: + insn_fetch(int8_t, 1, _regs.eip, length); + break; + } + + if ( twobyte ) + goto done; + + switch ( b ) + { + case 0xa0 ... 0xa1: /* mov */ + length += ad_bytes; + _regs.eip += ad_bytes; /* skip src displacement */ + break; + case 0xa2 ... 0xa3: /* mov */ + length += ad_bytes; + _regs.eip += ad_bytes; /* skip dst displacement */ + break; + case 0xf6 ... 0xf7: /* Grp3 */ + switch ( modrm_reg ) + { + case 0 ... 1: /* test */ + /* Special case in Grp3: test has an immediate source operand. */ + tmp = (d & ByteOp) ? 1 : op_bytes; + if ( tmp == 8 ) tmp = 4; + switch ( tmp ) + { + case 1: insn_fetch(int8_t, 1, _regs.eip, length); break; + case 2: insn_fetch(int16_t, 2, _regs.eip, length); break; + case 4: insn_fetch(int32_t, 4, _regs.eip, length); break; + } + goto done; + } + break; + } + +done: + return length; + +cannot_emulate: + DPRINTK("Cannot emulate %02x at address %lx (eip %lx, mode %d)\n", + b, (unsigned long)_regs.eip, (unsigned long)regs->eip, mode); + return -1; +} diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/svm/instrlen.c --- a/xen/arch/x86/hvm/svm/instrlen.c Mon Sep 25 09:36:11 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,479 +0,0 @@ -/* - * instrlen.c - calculates the instruction length for all operating modes - * - * Travis Betak, travis.betak@xxxxxxx - * Copyright (c) 2005,2006 AMD - * Copyright (c) 2005 Keir Fraser - * - * Essentially a very, very stripped version of Keir Fraser's work in - * x86_emulate.c. Used for MMIO. - */ - -/* - * TODO: the way in which we use svm_instrlen is very inefficient as is now - * stands. It will be worth while to return the actual instruction buffer - * along with the instruction length since one of the reasons we are getting - * the instruction length is to know how many instruction bytes we need to - * fetch. - */ - -#include <xen/config.h> -#include <xen/types.h> -#include <xen/lib.h> -#include <xen/mm.h> -#include <asm/regs.h> -#define DPRINTF DPRINTK -#include <asm-x86/x86_emulate.h> - -/* read from guest memory */ -extern int inst_copy_from_guest(unsigned char *buf, unsigned long eip, - int length); -extern void svm_dump_inst(unsigned long eip); - -/* - * Opcode effective-address decode tables. - * Note that we only emulate instructions that have at least one memory - * operand (excluding implicit stack references). We assume that stack - * references and instruction fetches will never occur in special memory - * areas that require emulation. So, for example, 'mov <imm>,<reg>' need - * not be handled. - */ - -/* Operand sizes: 8-bit operands or specified/overridden size. */ -#define ByteOp (1<<0) /* 8-bit operands. */ -/* Destination operand type. */ -#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */ -#define DstReg (2<<1) /* Register operand. */ -#define DstMem (3<<1) /* Memory operand. */ -#define DstMask (3<<1) -/* Source operand type. */ -#define SrcNone (0<<3) /* No source operand. */ -#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */ -#define SrcReg (1<<3) /* Register operand. */ -#define SrcMem (2<<3) /* Memory operand. */ -#define SrcMem16 (3<<3) /* Memory operand (16-bit). */ -#define SrcMem32 (4<<3) /* Memory operand (32-bit). */ -#define SrcImm (5<<3) /* Immediate operand. */ -#define SrcImmByte (6<<3) /* 8-bit sign-extended immediate operand. */ -#define SrcMask (7<<3) -/* Generic ModRM decode. */ -#define ModRM (1<<6) -/* Destination is only written; never read. */ -#define Mov (1<<7) - -static uint8_t opcode_table[256] = { - /* 0x00 - 0x07 */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - 0, 0, 0, 0, - /* 0x08 - 0x0F */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - 0, 0, 0, 0, - /* 0x10 - 0x17 */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - 0, 0, 0, 0, - /* 0x18 - 0x1F */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - 0, 0, 0, 0, - /* 0x20 - 0x27 */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - 0, 0, 0, 0, - /* 0x28 - 0x2F */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - 0, 0, 0, 0, - /* 0x30 - 0x37 */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - 0, 0, 0, 0, - /* 0x38 - 0x3F */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - 0, 0, 0, 0, - /* 0x40 - 0x4F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x50 - 0x5F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x60 - 0x6F */ - 0, 0, 0, DstReg|SrcMem32|ModRM|Mov /* movsxd (x86/64) */, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x70 - 0x7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x80 - 0x87 */ - ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM, - ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - /* 0x88 - 0x8F */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, - ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM, - 0, 0, 0, DstMem|SrcNone|ModRM|Mov, - /* 0x90 - 0x9F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xA0 - 0xA7 */ - ByteOp|DstReg|SrcMem|Mov, DstReg|SrcMem|Mov, - ByteOp|DstMem|SrcReg|Mov, DstMem|SrcReg|Mov, - ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, - ByteOp|ImplicitOps, ImplicitOps, - /* 0xA8 - 0xAF */ - 0, 0, ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, - ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, - ByteOp|ImplicitOps, ImplicitOps, - /* 0xB0 - 0xBF */ - SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, - SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte, - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xC0 - 0xC7 */ - ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, 0, 0, - 0, 0, ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM, - /* 0xC8 - 0xCF */ - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xD0 - 0xD7 */ - ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, - ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM, - 0, 0, 0, 0, - /* 0xD8 - 0xDF */ - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xE0 - 0xEF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xF0 - 0xF7 */ - 0, 0, 0, 0, - 0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM, - /* 0xF8 - 0xFF */ - 0, 0, 0, 0, - 0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM -}; - -static uint8_t twobyte_table[256] = { - /* 0x00 - 0x0F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, - /* 0x10 - 0x1F */ - 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, - /* 0x20 - 0x2F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x30 - 0x3F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x40 - 0x47 */ - DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, - DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, - DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, - DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, - /* 0x48 - 0x4F */ - DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, - DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, - DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, - DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov, - /* 0x50 - 0x5F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x60 - 0x6F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x70 - 0x7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x80 - 0x8F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x90 - 0x9F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xA0 - 0xA7 */ - 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0, - /* 0xA8 - 0xAF */ - 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0, - /* 0xB0 - 0xB7 */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstMem|SrcReg|ModRM, - 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov, - /* 0xB8 - 0xBF */ - 0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM, - 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov, - /* 0xC0 - 0xCF */ - 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xD0 - 0xDF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xE0 - 0xEF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xF0 - 0xFF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* - * insn_fetch - fetch the next 1 to 4 bytes from instruction stream - * - * @_type: u8, u16, u32, s8, s16, or s32 - * @_size: 1, 2, or 4 bytes - * @_eip: address to fetch from guest memory - * @_length: updated! increments the current instruction length counter by _size - * - * INTERNAL this is used internally by svm_instrlen to fetch the next byte, - * word, or dword from guest memory at location _eip. we currently use a local - * unsigned long as the storage buffer since the most bytes we're gonna get - * is limited to 4. - */ -#define insn_fetch(_type, _size, _eip, _length) \ -({ unsigned long _x; \ - if ((rc = inst_copy_from_guest((unsigned char *)(&(_x)), \ - (unsigned long)(_eip), _size)) \ - != _size) \ - goto done; \ - (_eip) += (_size); \ - (_length) += (_size); \ - (_type)_x; \ -}) - - -/** - * svn_instrlen - returns the current instructions length - * - * @regs: guest register state - * @mode: guest operating mode - * - * EXTERNAL this routine calculates the length of the current instruction - * pointed to by eip. The guest state is _not_ changed by this routine. - */ -int svm_instrlen(struct cpu_user_regs *regs, int mode) -{ - uint8_t b, d, twobyte = 0, rex_prefix = 0; - uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0; - unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i; - int rc = 0; - int length = 0; - unsigned int tmp; - - /* Shadow copy of register state. Committed on successful emulation. */ - struct cpu_user_regs _regs = *regs; - - /* include CS for 16-bit modes */ - if (mode == X86EMUL_MODE_REAL || mode == X86EMUL_MODE_PROT16) - _regs.eip += (_regs.cs << 4); - - switch ( mode ) - { - case X86EMUL_MODE_REAL: - case X86EMUL_MODE_PROT16: - op_bytes = ad_bytes = 2; - break; - case X86EMUL_MODE_PROT32: - op_bytes = ad_bytes = 4; - break; -#ifdef __x86_64__ - case X86EMUL_MODE_PROT64: - op_bytes = 4; - ad_bytes = 8; - break; -#endif - default: - return -1; - } - - /* Legacy prefixes. */ - for ( i = 0; i < 8; i++ ) - { - switch ( b = insn_fetch(uint8_t, 1, _regs.eip, length) ) - { - case 0x66: /* operand-size override */ - op_bytes ^= 6; /* switch between 2/4 bytes */ - break; - case 0x67: /* address-size override */ - if ( mode == X86EMUL_MODE_PROT64 ) - ad_bytes ^= 12; /* switch between 4/8 bytes */ - else - ad_bytes ^= 6; /* switch between 2/4 bytes */ - break; - case 0x2e: /* CS override */ - case 0x3e: /* DS override */ - case 0x26: /* ES override */ - case 0x64: /* FS override */ - case 0x65: /* GS override */ - case 0x36: /* SS override */ - break; - case 0xf0: /* LOCK */ - lock_prefix = 1; - break; - case 0xf3: /* REP/REPE/REPZ */ - rep_prefix = 1; - break; - case 0xf2: /* REPNE/REPNZ */ - break; - default: - goto done_prefixes; - } - } -done_prefixes: - - /* Note quite the same as 80386 real mode, but hopefully good enough. */ - if ( (mode == X86EMUL_MODE_REAL) && (ad_bytes != 2) ) { - printf("sonofabitch!! we don't support 32-bit addresses in realmode\n"); - goto cannot_emulate; - } - - /* REX prefix. */ - if ( (mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40) ) - { - rex_prefix = b; - if ( b & 8 ) - op_bytes = 8; /* REX.W */ - modrm_reg = (b & 4) << 1; /* REX.R */ - /* REX.B and REX.X do not need to be decoded. */ - b = insn_fetch(uint8_t, 1, _regs.eip, length); - } - - /* Opcode byte(s). */ - d = opcode_table[b]; - if ( d == 0 ) - { - /* Two-byte opcode? */ - if ( b == 0x0f ) - { - twobyte = 1; - b = insn_fetch(uint8_t, 1, _regs.eip, length); - d = twobyte_table[b]; - } - - /* Unrecognised? */ - if ( d == 0 ) - goto cannot_emulate; - } - - /* ModRM and SIB bytes. */ - if ( d & ModRM ) - { - modrm = insn_fetch(uint8_t, 1, _regs.eip, length); - modrm_mod |= (modrm & 0xc0) >> 6; - modrm_reg |= (modrm & 0x38) >> 3; - modrm_rm |= (modrm & 0x07); - - if ( modrm_mod == 3 ) - { - DPRINTF("Cannot parse ModRM.mod == 3.\n"); - goto cannot_emulate; - } - - if ( ad_bytes == 2 ) - { - /* 16-bit ModR/M decode. */ - switch ( modrm_mod ) - { - case 0: - if ( modrm_rm == 6 ) - { - length += 2; - _regs.eip += 2; /* skip disp16 */ - } - break; - case 1: - length += 1; - _regs.eip += 1; /* skip disp8 */ - break; - case 2: - length += 2; - _regs.eip += 2; /* skip disp16 */ - break; - } - } - else - { - /* 32/64-bit ModR/M decode. */ - switch ( modrm_mod ) - { - case 0: - if ( (modrm_rm == 4) && - (((insn_fetch(uint8_t, 1, _regs.eip, length)) & 7) - == 5) ) - { - length += 4; - _regs.eip += 4; /* skip disp32 specified by SIB.base */ - } - else if ( modrm_rm == 5 ) - { - length += 4; - _regs.eip += 4; /* skip disp32 */ - } - break; - case 1: - if ( modrm_rm == 4 ) - { - insn_fetch(uint8_t, 1, _regs.eip, length); - } - length += 1; - _regs.eip += 1; /* skip disp8 */ - break; - case 2: - if ( modrm_rm == 4 ) - { - insn_fetch(uint8_t, 1, _regs.eip, length); - } - length += 4; - _regs.eip += 4; /* skip disp32 */ - break; - } - } - } - - /* Decode and fetch the destination operand: register or memory. */ - switch ( d & DstMask ) - { - case ImplicitOps: - /* Special instructions do their own operand decoding. */ - goto done; - } - - /* Decode and fetch the source operand: register, memory or immediate. */ - switch ( d & SrcMask ) - { - case SrcImm: - tmp = (d & ByteOp) ? 1 : op_bytes; - if ( tmp == 8 ) tmp = 4; - /* NB. Immediates are sign-extended as necessary. */ - switch ( tmp ) - { - case 1: insn_fetch(int8_t, 1, _regs.eip, length); break; - case 2: insn_fetch(int16_t, 2, _regs.eip, length); break; - case 4: insn_fetch(int32_t, 4, _regs.eip, length); break; - } - break; - case SrcImmByte: - insn_fetch(int8_t, 1, _regs.eip, length); - break; - } - - if ( twobyte ) - goto done; - - switch ( b ) - { - case 0xa0 ... 0xa1: /* mov */ - length += ad_bytes; - _regs.eip += ad_bytes; /* skip src displacement */ - break; - case 0xa2 ... 0xa3: /* mov */ - length += ad_bytes; - _regs.eip += ad_bytes; /* skip dst displacement */ - break; - case 0xf6 ... 0xf7: /* Grp3 */ - switch ( modrm_reg ) - { - case 0 ... 1: /* test */ - /* Special case in Grp3: test has an immediate source operand. */ - tmp = (d & ByteOp) ? 1 : op_bytes; - if ( tmp == 8 ) tmp = 4; - switch ( tmp ) - { - case 1: insn_fetch(int8_t, 1, _regs.eip, length); break; - case 2: insn_fetch(int16_t, 2, _regs.eip, length); break; - case 4: insn_fetch(int32_t, 4, _regs.eip, length); break; - } - goto done; - } - break; - } - -done: - return length; - -cannot_emulate: - DPRINTF("Cannot emulate %02x at address %lx (eip %lx, mode %d)\n", - b, (unsigned long)_regs.eip, (unsigned long)regs->eip, mode); - svm_dump_inst(_regs.eip); - return -1; -} _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |