[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.