bitkeeper revision 1.1236.18.1 (422f27c9EveZXnXhkLBg8iYwaAffoQ)
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Wed, 9 Mar 2005 16:43:53 +0000 (16:43 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Wed, 9 Mar 2005 16:43:53 +0000 (16:43 +0000)
Begin integrating new instruction decoder and emulator.
Signed-off-by: Keir Fraser <keir@xensource.com>
.rootkeys
BitKeeper/etc/ignore
tools/tests/Makefile [new file with mode: 0644]
tools/tests/test_x86_emulator.c [new file with mode: 0644]
xen/arch/x86/traps.c
xen/arch/x86/x86_32/seg_fixup.c
xen/arch/x86/x86_64/traps.c
xen/arch/x86/x86_emulate.c [new file with mode: 0644]
xen/include/asm-x86/x86_emulate.h [new file with mode: 0644]

index f1e7482e2b4da873e45dcc3ff83357c309010f49..779e74a063c9f4655d116d82ff6afd5415e9c1ee 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 40fcefb3yMSrZvApO9ToIi-iQwnchA tools/sv/images/xen.png
 41013a83z27rKvWIxAfUBMVZ1eDCDg tools/sv/inc/script.js
 40fcefb3zGC9XNBkSwTEobCoq8YClA tools/sv/inc/style.css
+422f27c8MDeRoOWZNdcRC5VDTcj3TQ tools/tests/Makefile
+422f27c81CCtXt4Lthf7JF3Ajr0fUA tools/tests/test_x86_emulator.c
 420b963dK3yGNtqxRM8npGZtrCQd1g tools/vnet/00INSTALL
 41a21888_WlknVWjSxb32Fo13_ujsw tools/vnet/00README
 420a9b706I-bN_uPdiy0m3rmDifNNg tools/vnet/INSTALL
 42000d3cMb8o1WuFBXC07c8i3lPZBw xen/arch/x86/x86_64/traps.c
 40e96d3ahBTZqbTViInnq0lM03vs7A xen/arch/x86/x86_64/usercopy.c
 40e96d3akN3Hu_J5Bk-WXD8OGscrYQ xen/arch/x86/x86_64/xen.lds
+422f27c8J9DQfCpegccMid59XhSmGA xen/arch/x86/x86_emulate.c
 3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile
 3e397e66AyyD5fYraAySWuwi9uqSXg xen/common/ac_timer.c
 3ddb79bdLX_P6iB7ILiblRLWvebapg xen/common/dom0_ops.c
 404f1bb86rAXB3aLS1vYdcqpJiEcyg xen/include/asm-x86/x86_64/regs.h
 40e1966azOJZfNI6Ilthe6Q-T3Hewg xen/include/asm-x86/x86_64/string.h
 404f1bc4tWkB9Qr8RkKtZGW5eMQzhw xen/include/asm-x86/x86_64/uaccess.h
+422f27c8RHFkePhD34VIEpMMqofZcA xen/include/asm-x86/x86_emulate.h
 400304fcmRQmDdFYEzDh0wcBba9alg xen/include/public/COPYING
 421098b7OKb9YH_EUA_UpCxBjaqtgA xen/include/public/arch-ia64.h
 404f1bc68SXxmv0zQpXBWGrCzSyp8w xen/include/public/arch-x86_32.h
index 3c7420ae36be1cc4889e14601dbd6dec31d16c94..e7c52f6ba5668e7c4e7fb2aa3023e3b344d82ba7 100644 (file)
@@ -121,32 +121,6 @@ tools/blktap/vdi_snap
 tools/blktap/vdi_snap_list
 tools/blktap/vdi_tree
 tools/blktap/vdi_validate
-tools/blktap/xen/arch-ia64.h
-tools/blktap/xen/arch-x86_32.h
-tools/blktap/xen/arch-x86_64.h
-tools/blktap/xen/dom0_ops.h
-tools/blktap/xen/event_channel.h
-tools/blktap/xen/grant_table.h
-tools/blktap/xen/io/blkif.h
-tools/blktap/xen/io/domain_controller.h
-tools/blktap/xen/io/ioreq.h
-tools/blktap/xen/io/netif.h
-tools/blktap/xen/io/ring.h
-tools/blktap/xen/io/usbif.h
-tools/blktap/xen/linux/privcmd.h
-tools/blktap/xen/linux/suspend.h
-tools/blktap/xen/physdev.h
-tools/blktap/xen/sched_ctl.h
-tools/blktap/xen/trace.h
-tools/blktap/xen/xen.h
-tools/cmdline/Makefile
-tools/cmdline/ringbuster
-tools/cmdline/ringbuster.c
-tools/cmdline/xdestroy
-tools/cmdline/xdestroy.c
-tools/cmdline/xevtchn
-tools/cmdline/xevtchn.c
-tools/cmdline/xls
-tools/cmdline/xls.c
-tools/cmdline/xphysinfo
-tools/cmdline/xphysinfo.c
+tools/blktap/xen/*
+tools/cmdline/*
+tools/tests/test_x86_emulator
diff --git a/tools/tests/Makefile b/tools/tests/Makefile
new file mode 100644 (file)
index 0000000..3e8962a
--- /dev/null
@@ -0,0 +1,22 @@
+
+XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+TARGET := test_x86_emulator
+
+CC     := gcc
+CFLAGS := -O2 -Wall -Werror -D__TEST_HARNESS__
+
+$(TARGET): x86_emulate.o test_x86_emulator.o
+       $(CC) -o $@ $^
+
+clean:
+       rm -rf $(TARGET) *.o *~ core
+
+install:
+
+x86_emulate.o: $(XEN_ROOT)/xen/arch/x86/x86_emulate.c
+       $(CC) $(CFLAGS) -I$(XEN_ROOT)/xen/include -c -o $@ $<
+
+%.o: %.c
+       $(CC) $(CFLAGS) -I$(XEN_ROOT)/xen/include -c -o $@ $<
diff --git a/tools/tests/test_x86_emulator.c b/tools/tests/test_x86_emulator.c
new file mode 100644 (file)
index 0000000..2ccc20f
--- /dev/null
@@ -0,0 +1,168 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+typedef uint8_t            u8;
+typedef uint16_t           u16;
+typedef uint32_t           u32;
+typedef uint64_t           u64;
+typedef int8_t             s8;
+typedef int16_t            s16;
+typedef int32_t            s32;
+typedef int64_t            s64;
+#include <public/xen.h>
+#include <asm-x86/x86_emulate.h>
+
+static int read_any(
+    unsigned long addr,
+    unsigned long *val,
+    unsigned int bytes)
+{
+    switch ( bytes )
+    {
+    case 1: *val = *(u8 *)addr; break;
+    case 2: *val = *(u16 *)addr; break;
+    case 4: *val = *(u32 *)addr; break;
+    case 8: *val = *(unsigned long *)addr; break;
+    }
+    return 0;
+}
+
+static int write_any(
+    unsigned long addr,
+    unsigned long val,
+    unsigned int bytes)
+{
+    switch ( bytes )
+    {
+    case 1: *(u8 *)addr = (u8)val; break;
+    case 2: *(u16 *)addr = (u16)val; break;
+    case 4: *(u32 *)addr = (u32)val; break;
+    case 8: *(unsigned long *)addr = val; break;
+    }
+    return 0;
+}
+
+static int cmpxchg_any(
+    unsigned long addr,
+    unsigned long old,
+    unsigned long new,
+    unsigned long *seen,
+    unsigned int bytes)
+{
+    *seen = old;
+    switch ( bytes )
+    {
+    case 1: *(u8 *)addr = (u8)new; break;
+    case 2: *(u16 *)addr = (u16)new; break;
+    case 4: *(u32 *)addr = (u32)new; break;
+    case 8: *(unsigned long *)addr = new; break;
+    }
+    return 0;
+}
+
+static struct x86_mem_emulator emulops = {
+    read_any, write_any, read_any, write_any, cmpxchg_any
+};
+
+int main(int argc, char **argv)
+{
+    struct xen_regs regs;
+    char instr[] = { 0x01, 0x08 }; /* add %ecx,(%eax) */
+    unsigned int res = 0x7FFFFFFF;
+    unsigned long cr2;
+    int rc;
+
+    printf("%-40s", "Testing addl %%ecx,(%%eax)...");
+    instr[0] = 0x01; instr[1] = 0x08;
+    regs.eflags = 0x200;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.ecx    = 0x12345678;
+    cr2         = (unsigned long)&res;
+    res         = 0x7FFFFFFF;
+    rc = x86_emulate_memop(&regs, cr2, &emulops, 4);
+    if ( (rc != 0) || 
+         (res != 0x92345677) || 
+         (regs.eflags != 0xa94) ||
+         (regs.eip != (unsigned long)&instr[2]) )
+        goto fail;
+    printf("okay\n");
+
+    printf("%-40s", "Testing xorl (%%eax),%%ecx...");
+    instr[0] = 0x33; instr[1] = 0x08;
+    regs.eflags = 0x200;
+    regs.eip    = (unsigned long)&instr[0];
+#ifdef __x86_64__
+    regs.ecx    = 0xFFFFFFFF12345678UL;
+#else
+    regs.ecx    = 0x12345678UL;
+#endif
+    cr2         = (unsigned long)&res;
+    rc = x86_emulate_memop(&regs, cr2, &emulops, 4);
+    if ( (rc != 0) || 
+         (res != 0x92345677) || 
+         (regs.ecx != 0x8000000FUL) ||
+         (regs.eip != (unsigned long)&instr[2]) )
+        goto fail;
+    printf("okay\n");
+
+    printf("%-40s", "Testing lock cmpxchgb %%cl,(%%eax)...");
+    instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb0; instr[3] = 0x08;
+    regs.eflags = 0x200;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.eax    = 0x92345677UL;
+    regs.ecx    = 0xAA;
+    cr2         = (unsigned long)&res;
+    rc = x86_emulate_memop(&regs, cr2, &emulops, 4);    
+    if ( (rc != 0) || 
+         (res != 0x923456AA) || 
+         (regs.eflags != 0x244) ||
+         (regs.eax != 0x92345677UL) ||
+         (regs.eip != (unsigned long)&instr[4]) )
+        goto fail;
+    printf("okay\n");
+
+    printf("%-40s", "Testing lock cmpxchgl %%ecx,(%%eax)...");
+    instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb1; instr[3] = 0x08;
+    regs.eflags = 0x200;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.eax    = 0x923456AAUL;
+    regs.ecx    = 0xDDEEFF00L;
+    cr2         = (unsigned long)&res;
+    rc = x86_emulate_memop(&regs, cr2, &emulops, 4);    
+    if ( (rc != 0) || 
+         (res != 0xDDEEFF00) || 
+         (regs.eflags != 0x244) ||
+         (regs.eax != 0x923456AAUL) ||
+         (regs.eip != (unsigned long)&instr[4]) )
+        goto fail;
+    printf("okay\n");
+
+    printf("%-40s", "Testing rep movsw...");
+    instr[0] = 0xf3; instr[1] = 0x66; instr[2] = 0xa5;
+    res         = 0x22334455;
+    regs.eflags = 0x200;
+    regs.ecx    = 23;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.esi    = (unsigned long)&res + 0;
+    regs.edi    = (unsigned long)&res + 2;
+    regs.error_code = 0; /* read fault */
+    cr2         = regs.esi;
+    rc = x86_emulate_memop(&regs, cr2, &emulops, 4);    
+    if ( (rc != 0) || 
+         (res != 0x44554455) ||
+         (regs.eflags != 0x200) ||
+         (regs.ecx != 22) || 
+         (regs.esi != ((unsigned long)&res + 2)) ||
+         (regs.edi != ((unsigned long)&res + 4)) ||
+         (regs.eip != (unsigned long)&instr[0]) )
+        goto fail;
+    printf("okay\n");
+
+    return 0;
+
+ fail:
+    printf("failed!\n");
+    return 1;
+}
index eb44a63206aefc0ca3f8b36a2c80edcc4b8de147..9491787fcb97019a3b792697c3f2d885fda28088 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/i387.h>
 #include <asm/debugger.h>
 #include <asm/msr.h>
+#include <asm/x86_emulate.h>
 
 /*
  * opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
@@ -369,8 +370,6 @@ long do_fpu_taskswitch(int set)
 
 static int emulate_privileged_op(struct xen_regs *regs)
 {
-    extern void *decode_reg(struct xen_regs *regs, u8 b);
-
     struct exec_domain *ed = current;
     unsigned long *reg, eip = regs->eip;
     u8 opcode;
@@ -405,7 +404,7 @@ static int emulate_privileged_op(struct xen_regs *regs)
         eip += 1;
         if ( (opcode & 0xc0) != 0xc0 )
             goto fail;
-        reg = decode_reg(regs, opcode & 7);
+        reg = decode_register(opcode & 7, regs, 0);
         switch ( (opcode >> 3) & 7 )
         {
         case 0: /* Read CR0 */
@@ -433,7 +432,7 @@ static int emulate_privileged_op(struct xen_regs *regs)
         eip += 1;
         if ( (opcode & 0xc0) != 0xc0 )
             goto fail;
-        reg = decode_reg(regs, opcode & 7);
+        reg = decode_register(opcode & 7, regs, 0);
         switch ( (opcode >> 3) & 7 )
         {
         case 0: /* Write CR0 */
index 00c388dc92e88328cba2e4fc498fbbb1c7b54586..8c3d2a5d5205f806bfafb968b0e5ebb583cb05aa 100644 (file)
@@ -28,6 +28,7 @@
 #include <xen/mm.h>
 #include <xen/perfc.h>
 #include <asm/processor.h>
+#include <asm/x86_emulate.h>
 
 /* Make the scary benign errors go away. */
 #undef  DPRINTK
@@ -258,24 +259,6 @@ int fixup_seg(u16 seg, unsigned long offset)
     return 1;
 }
 
-/* Decode Reg field of a ModRM byte: return a pointer into a register block. */
-void *decode_reg(struct xen_regs *regs, u8 b)
-{
-    switch ( b & 7 )
-    {
-    case 0: return &regs->eax;
-    case 1: return &regs->ecx;
-    case 2: return &regs->edx;
-    case 3: return &regs->ebx;
-    case 4: return &regs->esp;
-    case 5: return &regs->ebp;
-    case 6: return &regs->esi;
-    case 7: return &regs->edi;
-    }
-
-    return NULL;
-}
-
 /*
  * Called from the general-protection fault handler to attempt to decode
  * and emulate an instruction that depends on 4GB segments.
@@ -402,8 +385,8 @@ int gpf_emulate_4gb(struct xen_regs *regs)
     }
 
     /* Decode Reg and R/M fields. */
-    regreg = decode_reg(regs, reg);
-    memreg = decode_reg(regs, rm);
+    regreg = decode_register(reg, regs, 0);
+    memreg = decode_register(rm,  regs, 0);
 
     /* Decode Mod field. */
     switch ( modrm >> 6 )
index 8cc16a1279d0c9ca674b5f33d4fef1794721da02..2c74f27d0ce8f06a06ffbe348f095ecc95fd793e 100644 (file)
@@ -248,31 +248,6 @@ void __init percpu_traps_init(void)
     wrmsr(MSR_SYSCALL_MASK, EF_VM|EF_RF|EF_NT|EF_DF|EF_IE|EF_TF, 0U);
 }
 
-void *decode_reg(struct xen_regs *regs, u8 b)
-{
-    switch ( b )
-    {
-    case  0: return &regs->rax;
-    case  1: return &regs->rcx;
-    case  2: return &regs->rdx;
-    case  3: return &regs->rbx;
-    case  4: return &regs->rsp;
-    case  5: return &regs->rbp;
-    case  6: return &regs->rsi;
-    case  7: return &regs->rdi;
-    case  8: return &regs->r8;
-    case  9: return &regs->r9;
-    case 10: return &regs->r10;
-    case 11: return &regs->r11;
-    case 12: return &regs->r12;
-    case 13: return &regs->r13;
-    case 14: return &regs->r14;
-    case 15: return &regs->r15;
-    }
-
-    return NULL;
-}
-
 long do_set_callbacks(unsigned long event_address,
                       unsigned long failsafe_address,
                       unsigned long syscall_address)
diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c
new file mode 100644 (file)
index 0000000..a36c31f
--- /dev/null
@@ -0,0 +1,968 @@
+/******************************************************************************
+ * x86_emulate.c
+ * 
+ * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
+ * 
+ * Copyright (c) 2005 Keir Fraser
+ */
+
+#ifdef __TEST_HARNESS__
+#include <stdio.h>
+#include <stdint.h>
+typedef uint8_t            u8;
+typedef uint16_t           u16;
+typedef uint32_t           u32;
+typedef uint64_t           u64;
+typedef int8_t             s8;
+typedef int16_t            s16;
+typedef int32_t            s32;
+typedef int64_t            s64;
+#include <public/xen.h>
+#else
+#include <xen/config.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <asm/regs.h>
+#endif
+#include <asm-x86/x86_emulate.h>
+
+/*
+ * 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 SrcImm      (3<<3) /* Immediate operand. */
+#define SrcImmByte  (4<<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 u8 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, 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 - 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 */
+    0, 0, 0, 0, 0, 0, 0, 0, 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 u8 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, 0, 0,
+    /* 0xB8 - 0xBF */
+    0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM, 0, 0, 0, 0,
+    /* 0xC0 - 0xCF */
+    0, 0, 0, 0, 0, 0, 0, 0, 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
+};
+
+/* Type, address-of, and value of an instruction's operand. */
+struct operand {
+    enum { OP_REG, OP_MEM, OP_IMM } type;
+    unsigned int  bytes;
+    unsigned long val, orig_val, *ptr;
+};
+
+/* EFLAGS bit definitions. */
+#define EFLG_OF (1<<11)
+#define EFLG_DF (1<<10)
+#define EFLG_SF (1<<7)
+#define EFLG_ZF (1<<6)
+#define EFLG_AF (1<<4)
+#define EFLG_PF (1<<2)
+#define EFLG_CF (1<<0)
+
+/*
+ * Instruction emulation:
+ * Most instructions are emulated directly via a fragment of inline assembly
+ * code. This allows us to save/restore EFLAGS and thus very easily pick up
+ * any modified flags.
+ */
+
+#if defined(__x86_64__)
+#define _LO32 "k"          /* force 32-bit operand */
+#define _STK  "%%rsp"      /* stack pointer */
+#elif defined(__i386__)
+#define _LO32 ""           /* force 32-bit operand */
+#define _STK  "%%esp"      /* stack pointer */
+#endif
+
+/*
+ * These EFLAGS bits are restored from saved value during emulation, and
+ * any changes are written back to the saved value after emulation.
+ */
+#define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF)
+
+/* Before executing instruction: restore necessary bits in EFLAGS. */
+/* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); _sav &= ~msk; */
+#define _PRE_EFLAGS(_sav, _msk, _tmp)           \
+"push %"_sav"; "                                \
+"movl %"_msk",%"_LO32 _tmp"; "                  \
+"andl %"_LO32 _tmp",("_STK"); "                 \
+"notl %"_LO32 _tmp"; "                          \
+"andl %"_LO32 _tmp",%"_sav"; "                  \
+"pushf; "                                       \
+"andl %"_LO32 _tmp",("_STK"); "                 \
+"pop  %"_tmp"; "                                \
+"orl  %"_LO32 _tmp",("_STK"); "                 \
+"popf; "
+
+/* After executing instruction: write-back necessary bits in EFLAGS. */
+/* _sav |= EFLAGS & _msk; */
+#define _POST_EFLAGS(_sav, _msk, _tmp)          \
+"pushf; "                                       \
+"pop  %"_tmp"; "                                \
+"andl %"_msk",%"_LO32 _tmp"; "                  \
+"orl  %"_LO32 _tmp",%"_sav"; "
+
+/* Raw emulation: instruction has two explicit operands. */
+#define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy)\
+do{ unsigned long _tmp;                                                    \
+    switch ( (_dst).bytes )                                                \
+    {                                                                      \
+    case 2:                                                                \
+        __asm__ __volatile__ (                                             \
+            _PRE_EFLAGS("0","4","2")                                       \
+            _op"w %"_wx"3,%1; "                                            \
+            _POST_EFLAGS("0","4","2")                                      \
+            : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)              \
+            : _wy ((_src).val), "i" (EFLAGS_MASK) );                       \
+        break;                                                             \
+    case 4:                                                                \
+        __asm__ __volatile__ (                                             \
+            _PRE_EFLAGS("0","4","2")                                       \
+            _op"l %"_lx"3,%1; "                                            \
+            _POST_EFLAGS("0","4","2")                                      \
+            : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)              \
+            : _ly ((_src).val), "i" (EFLAGS_MASK) );                       \
+        break;                                                             \
+    case 8:                                                                \
+        __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy);           \
+        break;                                                             \
+    }                                                                      \
+} while (0)
+#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy)\
+do{ unsigned long _tmp;                                                    \
+    switch ( (_dst).bytes )                                                \
+    {                                                                      \
+    case 1:                                                                \
+        __asm__ __volatile__ (                                             \
+            _PRE_EFLAGS("0","4","2")                                       \
+            _op"b %"_bx"3,%1; "                                            \
+            _POST_EFLAGS("0","4","2")                                      \
+            : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)              \
+            : _by ((_src).val), "i" (EFLAGS_MASK) );                       \
+        break;                                                             \
+    default:                                                               \
+        __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy);\
+        break;                                                             \
+    }                                                                      \
+} while (0)
+/* Source operand is byte-sized and may be restricted to just %cl. */
+#define emulate_2op_SrcB(_op, _src, _dst, _eflags)                         \
+    __emulate_2op(_op, _src, _dst, _eflags,                                \
+                  "b", "c", "b", "c", "b", "c", "b", "c")
+/* Source operand is byte, word, long or quad sized. */
+#define emulate_2op_SrcV(_op, _src, _dst, _eflags)                         \
+    __emulate_2op(_op, _src, _dst, _eflags,                                \
+                  "b", "q", "w", "r", _LO32, "r", "", "r")
+/* Source operand is word, long or quad sized. */
+#define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags)                  \
+    __emulate_2op_nobyte(_op, _src, _dst, _eflags,                         \
+                  "w", "r", _LO32, "r", "", "r")
+
+/* Instruction has only one explicit operand (no source operand). */
+#define emulate_1op(_op,_dst,_eflags)                                      \
+do{ unsigned long _tmp;                                                    \
+    switch ( (_dst).bytes )                                                \
+    {                                                                      \
+    case 1:                                                                \
+        __asm__ __volatile__ (                                             \
+            _PRE_EFLAGS("0","3","2")                                       \
+            _op"b %1; "                                                    \
+            _POST_EFLAGS("0","3","2")                                      \
+            : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)              \
+            : "i" (EFLAGS_MASK) );                                         \
+        break;                                                             \
+    case 2:                                                                \
+        __asm__ __volatile__ (                                             \
+            _PRE_EFLAGS("0","3","2")                                       \
+            _op"w %1; "                                                    \
+            _POST_EFLAGS("0","3","2")                                      \
+            : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)              \
+            : "i" (EFLAGS_MASK) );                                         \
+        break;                                                             \
+    case 4:                                                                \
+        __asm__ __volatile__ (                                             \
+            _PRE_EFLAGS("0","3","2")                                       \
+            _op"l %1; "                                                    \
+            _POST_EFLAGS("0","3","2")                                      \
+            : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)              \
+            : "i" (EFLAGS_MASK) );                                         \
+        break;                                                             \
+    case 8:                                                                \
+        __emulate_1op_8byte(_op, _dst, _eflags);                           \
+        break;                                                             \
+    }                                                                      \
+} while (0)
+
+/* Emulate an instruction with quadword operands (x86/64 only). */
+#if defined(__x86_64__)
+#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy)         \
+do{ __asm__ __volatile__ (                                              \
+        _PRE_EFLAGS("0","4","2")                                        \
+        _op"q %"_qx"3,%1; "                                             \
+        _POST_EFLAGS("0","4","2")                                       \
+        : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)               \
+        : _qy ((_src).val), "i" (EFLAGS_MASK) );                        \
+} while (0)
+#define __emulate_1op_8byte(_op, _dst, _eflags)                         \
+do{ __asm__ __volatile__ (                                              \
+        _PRE_EFLAGS("0","3","2")                                        \
+        _op"q %1; "                                                     \
+        _POST_EFLAGS("0","3","2")                                       \
+        : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp)               \
+        : "i" (EFLAGS_MASK) );                                          \
+} while (0)
+#elif defined(__i386__)
+#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy)
+#define __emulate_1op_8byte(_op, _dst, _eflags)
+#endif /* __i386__ */
+
+/* Fetch next part of the instruction being emulated. */
+#define insn_fetch(_type, _size, _eip) \
+({ unsigned long _x; \
+   if ( ops->read_std((unsigned long)(_eip), &_x, (_size)) ) \
+       goto done; \
+   (_eip) += (_size); \
+   (_type)_x; \
+})
+
+#define DPRINTF(_f, _a...) printf( _f , ## _a )
+
+void *
+decode_register(
+    u8 modrm_reg, struct xen_regs *regs, int highbyte_regs)
+{
+    void *p;
+
+    switch ( modrm_reg )
+    {
+    case  0: p = &regs->eax; break;
+    case  1: p = &regs->ecx; break;
+    case  2: p = &regs->edx; break;
+    case  3: p = &regs->ebx; break;
+    case  4: p = (highbyte_regs ?
+                  ((unsigned char *)&regs->eax + 1) : 
+                  (unsigned char *)&regs->esp); break;
+    case  5: p = (highbyte_regs ?
+                  ((unsigned char *)&regs->ecx + 1) : 
+                  (unsigned char *)&regs->ebp); break;
+    case  6: p = (highbyte_regs ?
+                  ((unsigned char *)&regs->edx + 1) : 
+                  (unsigned char *)&regs->esi); break;
+    case  7: p = (highbyte_regs ?
+                  ((unsigned char *)&regs->ebx + 1) : 
+                  (unsigned char *)&regs->edi); break;
+#if defined(__x86_64__)
+    case  8: p = &regs->r8;  break;
+    case  9: p = &regs->r9;  break;
+    case 10: p = &regs->r10; break;
+    case 11: p = &regs->r11; break;
+    case 12: p = &regs->r12; break;
+    case 13: p = &regs->r13; break;
+    case 14: p = &regs->r14; break;
+    case 15: p = &regs->r15; break;
+#endif
+    default: p = NULL; break;
+    }
+
+    return p;
+}
+
+int 
+x86_emulate_memop(
+    struct xen_regs *regs,
+    unsigned long cr2,
+    struct x86_mem_emulator *ops,
+    int mode)
+{
+    u8 b, d, sib, twobyte = 0, rex_prefix = 0;
+    u8 modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
+    unsigned int op_bytes = (mode == 8) ? 4 : mode, ad_bytes = mode;
+    unsigned int lock_prefix = 0, rep_prefix = 0;
+    struct operand src, dst;
+
+    /* Shadow copy of register state. Committed on successful emulation. */
+    struct xen_regs _regs = *regs;
+
+    /* Legacy prefixes. */
+ next_prefix:
+    switch ( b = insn_fetch(u8, 1, _regs.eip) )
+    {
+    case 0x66: /* operand-size override */
+        op_bytes ^= 6;                    /* switch between 2/4 bytes */
+        goto next_prefix;
+    case 0x67: /* address-size override */
+        ad_bytes ^= (mode == 8) ? 12 : 6; /* switch between 2/4 or 4/8 bytes */
+        goto next_prefix;
+    case 0x2e: /* CS override */
+    case 0x3e: /* DS override */
+    case 0x26: /* ES override */
+    case 0x64: /* FS override */
+    case 0x65: /* GS override */
+    case 0x36: /* SS override */
+        DPRINTF("Warning: ignoring a segment override. Probably okay. :-)\n");
+        goto next_prefix;
+    case 0xf0: /* LOCK */
+        lock_prefix = 1;
+        goto next_prefix;
+    case 0xf3: /* REP/REPE/REPZ */
+        rep_prefix = 1;
+        goto next_prefix;
+    case 0xf2: /* REPNE/REPNZ */
+        goto next_prefix;
+    }
+
+    if ( ad_bytes == 2 )
+    {
+        DPRINTF("Cannot parse 16-bit effective addresses.\n");
+        goto cannot_emulate;
+    }
+
+    /* REX prefix. */
+    if ( (mode == 8) && ((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(u8, 1, _regs.eip);
+    }
+
+    /* Opcode byte(s). */
+    d = opcode_table[b];
+    if ( d == 0 )
+    {
+        /* Two-byte opcode? */
+        if ( b == 0x0f )
+        {
+            twobyte = 1;
+            b = insn_fetch(u8, 1, _regs.eip);
+            d = twobyte_table[b];
+        }
+
+        /* Unrecognised? */
+        if ( d == 0 )
+            goto cannot_emulate;
+    }
+
+    /* ModRM and SIB bytes. */
+    if ( d & ModRM )
+    {
+        modrm = insn_fetch(u8, 1, _regs.eip);
+        modrm_mod |= (modrm & 0xc0) >> 6;
+        modrm_reg |= (modrm & 0x38) >> 3;
+        modrm_rm  |= (modrm & 0x07);
+        switch ( modrm_mod )
+        {
+        case 0:
+            if ( (modrm_rm == 4) && 
+                 (((sib = insn_fetch(u8, 1, _regs.eip)) & 7) == 5) )
+                _regs.eip += 4; /* skip disp32 specified by SIB.base */
+            else if ( modrm_rm == 5 )
+                _regs.eip += 4; /* skip disp32 */
+            break;
+        case 1:
+            if ( modrm_rm == 4 )
+                sib = insn_fetch(u8, 1, _regs.eip);
+            _regs.eip += 1; /* skip disp8 */
+            break;
+        case 2:
+            if ( modrm_rm == 4 )
+                sib = insn_fetch(u8, 1, _regs.eip);
+            _regs.eip += 4; /* skip disp32 */
+            break;
+        case 3:
+            DPRINTF("Cannot parse ModRM.mod == 3.\n");
+            goto cannot_emulate;
+        }
+    }
+
+    /* Decode and fetch the destination operand: register or memory. */
+    switch ( d & DstMask )
+    {
+    case ImplicitOps:
+        /* Special instructions do their own operand decoding. */
+        goto special_insn;
+    case DstReg:
+        dst.type = OP_REG;
+        if ( d & ByteOp )
+        {
+            dst.ptr = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
+            dst.val = *(u8 *)dst.ptr;
+            dst.bytes = 1;
+        }
+        else
+        {
+            dst.ptr = decode_register(modrm_reg, &_regs, 0);
+            switch ( (dst.bytes = op_bytes) )
+            {
+            case 2: dst.val = *(u16 *)dst.ptr; break;
+            case 4: dst.val = *(u32 *)dst.ptr; break;
+            case 8: dst.val = *(u64 *)dst.ptr; break;
+            }
+        }
+        break;
+    case DstMem:
+        dst.type  = OP_MEM;
+        dst.ptr   = (unsigned long *)cr2;
+        dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+        if ( !(d & Mov) && /* optimisation - avoid slow emulated read */
+             ops->read_emulated((unsigned long)dst.ptr, &dst.val, dst.bytes) )
+             goto done;
+        break;
+    }
+    dst.orig_val = dst.val;
+
+    /* Decode and fetch the source operand: register, memory or immediate. */
+    switch ( d & SrcMask )
+    {
+    case SrcNone:
+        break;
+    case SrcReg:
+        src.type = OP_REG;
+        if ( d & ByteOp )
+        {
+            src.ptr = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
+            src.val = src.orig_val = *(u8 *)src.ptr;
+            src.bytes = 1;
+        }
+        else
+        {
+            src.ptr = decode_register(modrm_reg, &_regs, 0);
+            switch ( (src.bytes = op_bytes) )
+            {
+            case 2: src.val = src.orig_val = *(u16 *)src.ptr; break;
+            case 4: src.val = src.orig_val = *(u32 *)src.ptr; break;
+            case 8: src.val = src.orig_val = *(u64 *)src.ptr; break;
+            }
+        }
+        break;
+    case SrcMem:
+        src.type  = OP_MEM;
+        src.ptr   = (unsigned long *)cr2;
+        src.bytes = (d & ByteOp) ? 1 : op_bytes;
+        if ( ops->read_emulated((unsigned long)src.ptr, &src.val, src.bytes) )
+            goto done;
+        src.orig_val = src.val;
+        break;
+    case SrcImm:
+        src.type  = OP_IMM;
+        src.ptr   = (unsigned long *)_regs.eip;
+        src.bytes = (d & ByteOp) ? 1 : op_bytes;
+        if ( src.bytes == 8 ) src.bytes = 4;
+        /* NB. Immediates are sign-extended as necessary. */
+        switch ( src.bytes )
+        {
+        case 1: src.val = insn_fetch(s8,  1, _regs.eip); break;
+        case 2: src.val = insn_fetch(s16, 2, _regs.eip); break;
+        case 4: src.val = insn_fetch(s32, 4, _regs.eip); break;
+        }
+        break;
+    case SrcImmByte:
+        src.type  = OP_IMM;
+        src.ptr   = (unsigned long *)_regs.eip;
+        src.bytes = 1;
+        src.val   = insn_fetch(s8,  1, _regs.eip);
+        break;
+    }
+
+    if ( twobyte )
+        goto twobyte_insn;
+
+    switch ( b )
+    {
+    case 0x00 ... 0x05: add: /* add */
+        emulate_2op_SrcV("add", src, dst, _regs.eflags);
+        break;
+    case 0x08 ... 0x0d: or:  /* or */
+        emulate_2op_SrcV("or", src, dst, _regs.eflags);
+        break;
+    case 0x10 ... 0x15: adc: /* adc */
+        emulate_2op_SrcV("adc", src, dst, _regs.eflags);
+        break;
+    case 0x18 ... 0x1d: sbb: /* sbb */
+        emulate_2op_SrcV("sbb", src, dst, _regs.eflags);
+        break;
+    case 0x20 ... 0x25: and: /* and */
+        emulate_2op_SrcV("and", src, dst, _regs.eflags);
+        break;
+    case 0x28 ... 0x2d: sub: /* sub */
+        emulate_2op_SrcV("sub", src, dst, _regs.eflags);
+        break;
+    case 0x30 ... 0x35: xor: /* xor */
+        emulate_2op_SrcV("xor", src, dst, _regs.eflags);
+        break;
+    case 0x38 ... 0x3d: cmp: /* cmp */
+        emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
+        break;
+    case 0x80 ... 0x83: /* Grp1 */
+        switch ( modrm_reg )
+        {
+        case 0: goto add;
+        case 1: goto or;
+        case 2: goto adc;
+        case 3: goto sbb;
+        case 4: goto and;
+        case 5: goto sub;
+        case 6: goto xor;
+        case 7: goto cmp;
+        }
+        break;
+    case 0x84 ... 0x85: test: /* test */
+        emulate_2op_SrcV("test", src, dst, _regs.eflags);
+        break;
+    case 0x86 ... 0x87: /* xchg */
+        src.val ^= dst.val;
+        dst.val ^= src.val;
+        src.val ^= dst.val;
+        break;
+    case 0xa0 ... 0xa1: /* mov */
+        dst.ptr = (unsigned long *)&_regs.eax;
+        dst.val = src.val;
+        _regs.eip += ad_bytes; /* skip src displacement */
+        break;
+    case 0xa2 ... 0xa3: /* mov */
+        dst.val = (unsigned long)_regs.eax;
+        _regs.eip += ad_bytes; /* skip dst displacement */
+        break;
+    case 0x88 ... 0x8b: /* mov */
+    case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
+        dst.val = src.val;
+        break;
+    case 0x8f: /* pop (sole member of Grp1a) */
+        /* 64-bit mode: POP defaults to 64-bit operands. */
+        if ( (mode == 8) && (dst.bytes == 4) )
+            dst.bytes = 8;
+        if ( ops->read_std(_regs.esp, &dst.val, dst.bytes) )
+            goto done;
+        _regs.esp += dst.bytes;
+        break;
+    case 0xc0 ... 0xc1: grp2: /* Grp2 */
+        switch ( modrm_reg )
+        {
+        case 0: /* rol */
+            emulate_2op_SrcB("rol", src, dst, _regs.eflags);
+            break;
+        case 1: /* ror */
+            emulate_2op_SrcB("ror", src, dst, _regs.eflags);
+            break;
+        case 2: /* rcl */
+            emulate_2op_SrcB("rcl", src, dst, _regs.eflags);
+            break;
+        case 3: /* rcr */
+            emulate_2op_SrcB("rcr", src, dst, _regs.eflags);
+            break;
+        case 4: /* sal/shl */
+        case 6: /* sal/shl */
+            emulate_2op_SrcB("sal", src, dst, _regs.eflags);
+            break;
+        case 5: /* shr */
+            emulate_2op_SrcB("shr", src, dst, _regs.eflags);
+            break;
+        case 7: /* sar */
+            emulate_2op_SrcB("sar", src, dst, _regs.eflags);
+            break;
+        }
+        break;
+    case 0xd0 ... 0xd1: /* Grp2 */
+        src.val = 1;
+        goto grp2;
+    case 0xd2 ... 0xd3: /* Grp2 */
+        src.val = _regs.ecx;
+        goto grp2;
+    case 0xf6 ... 0xf7: /* Grp3 */
+        switch ( modrm_reg )
+        {
+        case 0 ... 1: /* test */
+            /* Special case in Grp3: test has an immediate source operand. */
+            src.type = OP_IMM;
+            src.ptr  = (unsigned long *)_regs.eip;
+            src.bytes = (d & ByteOp) ? 1 : op_bytes;
+            if ( src.bytes == 8 ) src.bytes = 4;
+            switch ( src.bytes )
+            {
+            case 1: src.val = insn_fetch(s8,  1, _regs.eip); break;
+            case 2: src.val = insn_fetch(s16, 2, _regs.eip); break;
+            case 4: src.val = insn_fetch(s32, 4, _regs.eip); break;
+            }
+            goto test;
+        case 2: /* not */
+            dst.val = ~dst.val;
+            break;
+        case 3: /* neg */
+            emulate_1op("neg", dst, _regs.eflags);
+            break;
+        default:
+            goto cannot_emulate;
+        }
+        break;
+    case 0xfe ... 0xff: /* Grp4/Grp5 */
+        switch ( modrm_reg )
+        {
+        case 0: /* inc */
+            emulate_1op("inc", dst, _regs.eflags);
+            break;
+        case 1: /* dec */
+            emulate_1op("dec", dst, _regs.eflags);
+            break;
+        case 6: /* push */
+            /* 64-bit mode: PUSH defaults to 64-bit operands. */
+            if ( (mode == 8) && (dst.bytes == 4) )
+            {
+                dst.bytes = 8;
+                if ( ops->read_std((unsigned long)dst.ptr, &dst.val, 8) )
+                    goto done;
+            }
+            _regs.esp -= dst.bytes;
+            if ( ops->write_std(_regs.esp, dst.val, dst.bytes) )
+                goto done;
+            dst.val = dst.orig_val; /* skanky: disable writeback */
+            break;
+        default:
+            goto cannot_emulate;
+        }
+        break;
+    }
+
+ writeback:
+    if ( (d & Mov) || (dst.orig_val != dst.val) )
+    {
+        switch ( dst.type )
+        {
+        case OP_REG:
+            /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
+            switch ( dst.bytes )
+            {
+            case 1: *(u8  *)dst.ptr = (u8)dst.val; break;
+            case 2: *(u16 *)dst.ptr = (u16)dst.val; break;
+            case 4: *dst.ptr = (u32)dst.val; break; /* 64b mode: zero-extend */
+            case 8: *dst.ptr = dst.val; break;
+            }
+            break;
+        case OP_MEM:
+            if ( lock_prefix )
+            {
+                unsigned long seen;
+                if ( ops->cmpxchg_emulated((unsigned long)dst.ptr,
+                                           dst.orig_val, dst.val,
+                                           &seen, dst.bytes) )
+                    goto done;
+                if ( seen != dst.orig_val )
+                    goto done; /* Try again... */
+            }
+            else
+            {
+                if ( ops->write_emulated((unsigned long)dst.ptr,
+                                         dst.val, dst.bytes) )
+                    goto done;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
+    /* Commit shadow register state. */
+    *regs = _regs;
+
+ done:
+    return 0;
+
+ special_insn:
+    if ( twobyte )
+        goto twobyte_special_insn;
+    if ( rep_prefix )
+    {
+        if ( _regs.ecx == 0 )
+        {
+            regs->eip = _regs.eip;
+            goto done;
+        }
+        _regs.ecx--;
+        _regs.eip = regs->eip;
+    }
+    switch ( b )
+    {
+    case 0xa4 ... 0xa5: /* movs */
+        dst.type  = OP_MEM;
+        dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+        if ( _regs.error_code & 2 )
+        {
+            /* Write fault: destination is special memory. */
+            dst.ptr = (unsigned long *)cr2;
+            if ( ops->read_std(_regs.esi - _regs.edi + cr2, 
+                               &dst.val, dst.bytes) )
+                goto done;
+        }
+        else
+        {
+            /* Read fault: source is special memory. */
+            dst.ptr = (unsigned long *)(_regs.edi - _regs.esi + cr2);
+            if ( ops->read_emulated(cr2, &dst.val, dst.bytes) )
+                goto done;
+        }
+        _regs.esi += (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes;
+        _regs.edi += (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes;
+        break;
+    case 0xa6 ... 0xa7: /* cmps */
+        DPRINTF("Urk! I don't handle CMPS.\n");
+        goto cannot_emulate;
+    case 0xaa ... 0xab: /* stos */
+        dst.type  = OP_MEM;
+        dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+        dst.ptr   = (unsigned long *)cr2;
+        dst.val   = _regs.eax;
+        _regs.edi += (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes;
+        break;
+    case 0xac ... 0xad: /* lods */
+        dst.type  = OP_REG;
+        dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+        dst.ptr   = (unsigned long *)&_regs.eax;
+        if ( ops->read_emulated(cr2, &dst.val, dst.bytes) )
+            goto done;
+        _regs.esi += (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes;
+        break;
+    case 0xae ... 0xaf: /* scas */
+        DPRINTF("Urk! I don't handle SCAS.\n");
+        goto cannot_emulate;
+    }
+    goto writeback;
+
+ twobyte_insn:
+    switch ( b )
+    {
+    case 0x40 ... 0x4f: /* cmov */
+        dst.val = dst.orig_val = src.val;
+        d &= ~Mov; /* default to no move */
+        /* First, assume we're decoding an even cmov opcode (lsb == 0). */
+        switch ( (b & 15) >> 1 )
+        {
+        case 0: /* cmovo */
+            d |= (_regs.eflags & EFLG_OF) ? Mov : 0;
+            break;
+        case 1: /* cmovb/cmovc/cmovnae */
+            d |= (_regs.eflags & EFLG_CF) ? Mov : 0;
+            break;
+        case 2: /* cmovz/cmove */
+            d |= (_regs.eflags & EFLG_ZF) ? Mov : 0;
+            break;
+        case 3: /* cmovbe/cmovna */
+            d |= (_regs.eflags & (EFLG_CF|EFLG_ZF)) ? Mov : 0;
+            break;
+        case 4: /* cmovs */
+            d |= (_regs.eflags & EFLG_SF) ? Mov : 0;
+            break;
+        case 5: /* cmovp/cmovpe */
+            d |= (_regs.eflags & EFLG_PF) ? Mov : 0;
+            break;
+        case 7: /* cmovle/cmovng */
+            d |= (_regs.eflags & EFLG_ZF) ? Mov : 0;
+            /* fall through */
+        case 6: /* cmovl/cmovnge */
+            d |= (!(_regs.eflags & EFLG_SF) != !(_regs.eflags & EFLG_OF)) ?
+                Mov : 0;
+            break;
+        }
+        /* Odd cmov opcodes (lsb == 1) have inverted sense. */
+        d ^= (b & 1) ? Mov : 0;
+        break;
+    case 0xb0 ... 0xb1: /* cmpxchg */
+        /* Save real source value, then compare EAX against destination. */
+        src.orig_val = src.val;
+        src.val = _regs.eax;
+        emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
+        /* Always write back. The question is: where to? */
+        d |= Mov;
+        if ( _regs.eflags & EFLG_ZF )
+        {
+            /* Success: write back to memory. */
+            dst.val = src.orig_val;
+        }
+        else
+        {
+            /* Failure: write the value we saw to EAX. */
+            dst.type = OP_REG;
+            dst.ptr  = (unsigned long *)&_regs.eax;
+        }
+        break;
+    case 0xa3: bt: /* bt */
+        src.val &= (1UL << (1 << dst.bytes)) - 1; /* only subword offset */
+        emulate_2op_SrcV_nobyte("bt", src, dst, _regs.eflags);
+        break;
+    case 0xb3: btr: /* btr */
+        src.val &= (1UL << (1 << dst.bytes)) - 1; /* only subword offset */
+        emulate_2op_SrcV_nobyte("btr", src, dst, _regs.eflags);
+        break;
+    case 0xab: bts: /* bts */
+        src.val &= (1UL << (1 << dst.bytes)) - 1; /* only subword offset */
+        emulate_2op_SrcV_nobyte("bts", src, dst, _regs.eflags);
+        break;
+    case 0xbb: btc: /* btc */
+        src.val &= (1UL << (1 << dst.bytes)) - 1; /* only subword offset */
+        emulate_2op_SrcV_nobyte("btc", src, dst, _regs.eflags);
+        break;
+    case 0xba: /* Grp8 */
+        switch ( modrm_reg >> 1 )
+        {
+        case 0: goto bt;
+        case 1: goto bts;
+        case 2: goto btr;
+        case 3: goto btc;
+        }
+        break;
+    }
+    goto writeback;
+
+ twobyte_special_insn:
+    /* Only prefetch instructions get here, so nothing to do. */
+    dst.orig_val = dst.val; /* disable writeback */
+    goto writeback;
+
+ cannot_emulate:
+    DPRINTF("Cannot emulate %02x\n", b);
+    return -1;
+}
diff --git a/xen/include/asm-x86/x86_emulate.h b/xen/include/asm-x86/x86_emulate.h
new file mode 100644 (file)
index 0000000..fc2301d
--- /dev/null
@@ -0,0 +1,131 @@
+/******************************************************************************
+ * x86_emulate.h
+ * 
+ * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
+ * 
+ * Copyright (c) 2005 Keir Fraser
+ */
+
+#ifndef __X86_EMULATE_H__
+#define __X86_EMULATE_H__
+
+/*
+ * x86_mem_emulator:
+ * 
+ * These operations represent the instruction emulator's interface to memory.
+ * There are two categories of operation: those that act on ordinary memory
+ * regions (*_std), and those that act on memory regions known to require
+ * special treatment or emulation (*_emulated).
+ * 
+ * The emulator assumes that an instruction accesses only one 'emulated memory'
+ * location, and that this is one of its data operands. Instruction fetches and
+ * stack operations are assumed never to access emulated memory. The emulator
+ * automatically deduces which operand of a string-move operation is accessing
+ * emulated memory, and requires that the other operand accesses normal memory.
+ * 
+ * NOTES:
+ *  1. The emulator isn't very smart about emulated vs. standard memory.
+ *     'Emulated memory' access addresses should be checked for sanity.
+ *     'Normal memory' accesses may fault, and the caller must arrange to
+ *     detect and handle reentrancy into the emulator via recursive faults.
+ *     Accesses may be unaligned and may cross page boundaries.
+ *  2. If the access fails (cannot emulate, or a standard access faults) then
+ *     it is up to the memop to propagate the fault to the guest VM via
+ *     some out-of-band mechanism, unknown to the emulator. The memop signals
+ *     failure by returning a non-zero value to the emulator, which will then
+ *     immediately bail.
+ */
+struct x86_mem_emulator
+{
+    /*
+     * read_std: Read bytes of standard (non-emulated/special) memory.
+     *           Used for instruction fetch, stack operations, and others.
+     *  @addr:  [IN ] Linear address from which to read.
+     *  @val:   [OUT] Value read from memory, zero-extended to 'u_long'.
+     *  @bytes: [IN ] Number of bytes to read from memory.
+     */
+    int (*read_std)(
+        unsigned long addr,
+        unsigned long *val,
+        unsigned int bytes);
+
+    /*
+     * write_std: Write bytes of standard (non-emulated/special) memory.
+     *            Used for stack operations, and others.
+     *  @addr:  [IN ] Linear address to which to write.
+     *  @val:   [IN ] Value to write to memory (low-order bytes used as req'd).
+     *  @bytes: [IN ] Number of bytes to write to memory.
+     */
+    int (*write_std)(
+        unsigned long addr,
+        unsigned long val,
+        unsigned int bytes);
+
+    /*
+     * read_emulated: Read bytes from emulated/special memory area.
+     *  @addr:  [IN ] Linear address from which to read.
+     *  @val:   [OUT] Value read from memory, zero-extended to 'u_long'.
+     *  @bytes: [IN ] Number of bytes to read from memory.
+     */
+    int (*read_emulated)(
+        unsigned long addr,
+        unsigned long *val,
+        unsigned int bytes);
+
+    /*
+     * write_emulated: Read bytes from emulated/special memory area.
+     *  @addr:  [IN ] Linear address to which to write.
+     *  @val:   [IN ] Value to write to memory (low-order bytes used as req'd).
+     *  @bytes: [IN ] Number of bytes to write to memory.
+     */
+    int (*write_emulated)(
+        unsigned long addr,
+        unsigned long val,
+        unsigned int bytes);
+
+    /*
+     * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an
+     *                   emulated/special memory area.
+     *  @addr:  [IN ] Linear address to access.
+     *  @old:   [IN ] Value expected to be current at @addr.
+     *  @new:   [IN ] Value to write to @addr.
+     *  @seen:  [OUT] Value actually seen at @addr, zero-extended to 'u_long'.
+     *  @bytes: [IN ] Number of bytes to access using CMPXCHG.
+     */
+    int (*cmpxchg_emulated)(
+        unsigned long addr,
+        unsigned long old, 
+        unsigned long new,
+        unsigned long *seen,
+        unsigned int bytes);
+};
+
+
+struct xen_regs;
+
+/*
+ * x86_emulate_memop: Emulate an instruction that faulted attempting to
+ *                    read/write a 'special' memory area.
+ *  @regs: Register state at time of fault.
+ *  @cr2:  Linear faulting address.
+ *  @ops:  Interface to access special memory.
+ *  @mode: Current execution mode, represented by the default size of memory
+ *         addresses, in bytes. Valid values are 2, 4 and 8 (x86/64 only).
+ */
+extern int
+x86_emulate_memop(
+    struct xen_regs *regs,
+    unsigned long cr2,
+    struct x86_mem_emulator *ops,
+    int mode);
+
+/*
+ * Given the 'reg' portion of a ModRM byte, and a register block, return a
+ * pointer into the block that addresses the relevant register.
+ * @highbyte_regs specifies whether to decode AH,CH,DH,BH.
+ */
+extern void *
+decode_register(
+    u8 modrm_reg, struct xen_regs *regs, int highbyte_regs);
+
+#endif /* __X86_EMULATE_H__ */