WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] [XEN] Simplify x86_emulate interface.

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [XEN] Simplify x86_emulate interface.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 30 Nov 2006 21:30:14 +0000
Delivery-date: Thu, 30 Nov 2006 13:29:45 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID 88935ae47fa92feeacaf25bf2c07770206ac14fa
# Parent  d1b0a5adaeabffa3a1a68ae08bc974f5fb28d2c7
[XEN] Simplify x86_emulate interface.

 - No distinction between 'special' and 'normal' memory accesses.
 - No reliance on caller-supplied %cr2 value
 - Memory operations include segment identifier to allow callers
   to support non-zero-based segments

TODO:
 1. HVM emulations should take into account segment base, limit, and
    attributes.
 2. We ought to obey stack-size attribute on PUSH/POP instructions.
    Could extend the mode input field, or could add an extra call-out
    hook, or perhaps we don't care at all...

Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 tools/tests/test_x86_emulator.c   |   76 +++---
 xen/arch/x86/mm.c                 |   97 ++++---
 xen/arch/x86/mm/shadow/common.c   |   92 +++----
 xen/arch/x86/mm/shadow/multi.c    |    1 
 xen/arch/x86/x86_emulate.c        |  465 ++++++++++++++++----------------------
 xen/include/asm-x86/x86_emulate.h |  113 ++-------
 6 files changed, 381 insertions(+), 463 deletions(-)

diff -r d1b0a5adaeab -r 88935ae47fa9 tools/tests/test_x86_emulator.c
--- a/tools/tests/test_x86_emulator.c   Wed Nov 29 23:40:40 2006 +0000
+++ b/tools/tests/test_x86_emulator.c   Thu Nov 30 10:57:28 2006 +0000
@@ -17,12 +17,14 @@ typedef int64_t            s64;
 
 #define PFEC_write_access (1U<<1)
 
-static int read_any(
-    unsigned long addr,
+static int read(
+    unsigned int seg,
+    unsigned long offset,
     unsigned long *val,
     unsigned int bytes,
     struct x86_emulate_ctxt *ctxt)
 {
+    unsigned long addr = offset;
     switch ( bytes )
     {
     case 1: *val = *(u8 *)addr; break;
@@ -33,12 +35,14 @@ static int read_any(
     return X86EMUL_CONTINUE;
 }
 
-static int write_any(
-    unsigned long addr,
+static int write(
+    unsigned int seg,
+    unsigned long offset,
     unsigned long val,
     unsigned int bytes,
     struct x86_emulate_ctxt *ctxt)
 {
+    unsigned long addr = offset;
     switch ( bytes )
     {
     case 1: *(u8 *)addr = (u8)val; break;
@@ -49,13 +53,15 @@ static int write_any(
     return X86EMUL_CONTINUE;
 }
 
-static int cmpxchg_any(
-    unsigned long addr,
+static int cmpxchg(
+    unsigned int seg,
+    unsigned long offset,
     unsigned long old,
     unsigned long new,
     unsigned int bytes,
     struct x86_emulate_ctxt *ctxt)
 {
+    unsigned long addr = offset;
     switch ( bytes )
     {
     case 1: *(u8 *)addr = (u8)new; break;
@@ -66,21 +72,23 @@ static int cmpxchg_any(
     return X86EMUL_CONTINUE;
 }
 
-static int cmpxchg8b_any(
-    unsigned long addr,
+static int cmpxchg8b(
+    unsigned int seg,
+    unsigned long offset,
     unsigned long old_lo,
     unsigned long old_hi,
     unsigned long new_lo,
     unsigned long new_hi,
     struct x86_emulate_ctxt *ctxt)
 {
+    unsigned long addr = offset;
     ((unsigned long *)addr)[0] = new_lo;
     ((unsigned long *)addr)[1] = new_hi;
     return X86EMUL_CONTINUE;
 }
 
 static struct x86_emulate_ops emulops = {
-    read_any, write_any, read_any, write_any, cmpxchg_any, cmpxchg8b_any
+    read, write, cmpxchg, cmpxchg8b
 };
 
 int main(int argc, char **argv)
@@ -108,7 +116,7 @@ int main(int argc, char **argv)
     regs.eip    = (unsigned long)&instr[0];
     regs.ecx    = 0x12345678;
     regs.error_code = PFEC_write_access;
-    ctxt.cr2    = (unsigned long)res;
+    regs.eax    = (unsigned long)res;
     *res        = 0x7FFFFFFF;
     rc = x86_emulate_memop(&ctxt, &emulops);
     if ( (rc != 0) || 
@@ -127,7 +135,7 @@ int main(int argc, char **argv)
 #else
     regs.ecx    = 0x12345678UL;
 #endif
-    ctxt.cr2    = (unsigned long)res;
+    regs.eax    = (unsigned long)res;
     regs.error_code = 0;
     rc = x86_emulate_memop(&ctxt, &emulops);
     if ( (rc != 0) || 
@@ -142,7 +150,7 @@ int main(int argc, char **argv)
     regs.eflags = 0x200;
     regs.eip    = (unsigned long)&instr[0];
     regs.ecx    = ~0UL;
-    ctxt.cr2    = (unsigned long)res;
+    regs.eax    = (unsigned long)res;
     regs.error_code = 0;
     rc = x86_emulate_memop(&ctxt, &emulops);
     if ( (rc != 0) || 
@@ -152,13 +160,13 @@ int main(int argc, char **argv)
         goto fail;
     printf("okay\n");
 
-    printf("%-40s", "Testing lock cmpxchgb %%cl,(%%eax)...");
-    instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb0; instr[3] = 0x08;
+    printf("%-40s", "Testing lock cmpxchgb %%cl,(%%ebx)...");
+    instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb0; instr[3] = 0x0b;
     regs.eflags = 0x200;
     regs.eip    = (unsigned long)&instr[0];
     regs.eax    = 0x92345677UL;
     regs.ecx    = 0xAA;
-    ctxt.cr2    = (unsigned long)res;
+    regs.ebx    = (unsigned long)res;
     regs.error_code = PFEC_write_access;
     rc = x86_emulate_memop(&ctxt, &emulops);
     if ( (rc != 0) || 
@@ -169,13 +177,13 @@ int main(int argc, char **argv)
         goto fail;
     printf("okay\n");
 
-    printf("%-40s", "Testing lock cmpxchgb %%cl,(%%eax)...");
-    instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb0; instr[3] = 0x08;
+    printf("%-40s", "Testing lock cmpxchgb %%cl,(%%ebx)...");
+    instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb0; instr[3] = 0x0b;
     regs.eflags = 0x200;
     regs.eip    = (unsigned long)&instr[0];
     regs.eax    = 0xAABBCC77UL;
     regs.ecx    = 0xFF;
-    ctxt.cr2    = (unsigned long)res;
+    regs.ebx    = (unsigned long)res;
     regs.error_code = PFEC_write_access;
     rc = x86_emulate_memop(&ctxt, &emulops);
     if ( (rc != 0) || 
@@ -192,7 +200,7 @@ int main(int argc, char **argv)
     regs.eflags = 0x200;
     regs.eip    = (unsigned long)&instr[0];
     regs.ecx    = 0x12345678;
-    ctxt.cr2    = (unsigned long)res;
+    regs.eax    = (unsigned long)res;
     regs.error_code = PFEC_write_access;
     rc = x86_emulate_memop(&ctxt, &emulops);
     if ( (rc != 0) || 
@@ -203,14 +211,14 @@ int main(int argc, char **argv)
         goto fail;
     printf("okay\n");
 
-    printf("%-40s", "Testing lock cmpxchgl %%ecx,(%%eax)...");
-    instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb1; instr[3] = 0x08;
+    printf("%-40s", "Testing lock cmpxchgl %%ecx,(%%ebx)...");
+    instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb1; instr[3] = 0x0b;
     regs.eflags = 0x200;
     *res        = 0x923456AA;
     regs.eip    = (unsigned long)&instr[0];
     regs.eax    = 0x923456AAUL;
     regs.ecx    = 0xDDEEFF00L;
-    ctxt.cr2    = (unsigned long)res;
+    regs.ebx    = (unsigned long)res;
     regs.error_code = PFEC_write_access;
     rc = x86_emulate_memop(&ctxt, &emulops);
     if ( (rc != 0) || 
@@ -230,7 +238,6 @@ int main(int argc, char **argv)
     regs.esi    = (unsigned long)res + 0;
     regs.edi    = (unsigned long)res + 2;
     regs.error_code = 0; /* read fault */
-    ctxt.cr2    = regs.esi;
     rc = x86_emulate_memop(&ctxt, &emulops);
     if ( (rc != 0) || 
          (*res != 0x44554455) ||
@@ -248,13 +255,28 @@ int main(int argc, char **argv)
     regs.eflags = 0x200;
     regs.eip    = (unsigned long)&instr[0];
     regs.edi    = (unsigned long)res;
-    ctxt.cr2    = regs.edi;
     regs.error_code = PFEC_write_access;
     rc = x86_emulate_memop(&ctxt, &emulops);
     if ( (rc != 0) || 
          (*res != 0x2233445D) ||
          ((regs.eflags&0x201) != 0x201) ||
          (regs.eip != (unsigned long)&instr[4]) )
+        goto fail;
+    printf("okay\n");
+
+    printf("%-40s", "Testing btrl %eax,(%edi)...");
+    instr[0] = 0x0f; instr[1] = 0xb3; instr[2] = 0x07;
+    *res        = 0x2233445F;
+    regs.eflags = 0x200;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.eax    = -32;
+    regs.edi    = (unsigned long)(res+1);
+    regs.error_code = PFEC_write_access;
+    rc = x86_emulate_memop(&ctxt, &emulops);
+    if ( (rc != 0) || 
+         (*res != 0x2233445E) ||
+         ((regs.eflags&0x201) != 0x201) ||
+         (regs.eip != (unsigned long)&instr[3]) )
         goto fail;
     printf("okay\n");
 
@@ -270,7 +292,6 @@ int main(int argc, char **argv)
     regs.ecx    = 0xCCCCFFFF;
     regs.eip    = (unsigned long)&instr[0];
     regs.edi    = (unsigned long)res;
-    ctxt.cr2    = regs.edi;
     regs.error_code = PFEC_write_access;
     rc = x86_emulate_memop(&ctxt, &emulops);
     if ( (rc != 0) || 
@@ -285,7 +306,6 @@ int main(int argc, char **argv)
     instr[0] = 0x0f; instr[1] = 0xc7; instr[2] = 0x0f;
     regs.eip    = (unsigned long)&instr[0];
     regs.edi    = (unsigned long)res;
-    ctxt.cr2    = regs.edi;
     regs.error_code = PFEC_write_access;
     rc = x86_emulate_memop(&ctxt, &emulops);
     if ( (rc != 0) || 
@@ -302,7 +322,7 @@ int main(int argc, char **argv)
     instr[0] = 0x0f; instr[1] = 0xbe; instr[2] = 0x08;
     regs.eip    = (unsigned long)&instr[0];
     regs.ecx    = 0x12345678;
-    ctxt.cr2    = (unsigned long)res;
+    regs.eax    = (unsigned long)res;
     *res        = 0x82;
     regs.error_code = 0;
     rc = x86_emulate_memop(&ctxt, &emulops);
@@ -318,7 +338,7 @@ int main(int argc, char **argv)
     instr[0] = 0x0f; instr[1] = 0xb7; instr[2] = 0x08;
     regs.eip    = (unsigned long)&instr[0];
     regs.ecx    = 0x12345678;
-    ctxt.cr2    = (unsigned long)res;
+    regs.eax    = (unsigned long)res;
     *res        = 0x1234aa82;
     regs.error_code = 0;
     rc = x86_emulate_memop(&ctxt, &emulops);
diff -r d1b0a5adaeab -r 88935ae47fa9 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Wed Nov 29 23:40:40 2006 +0000
+++ b/xen/arch/x86/mm.c Thu Nov 30 10:57:28 2006 +0000
@@ -3033,12 +3033,39 @@ long arch_memory_op(int op, XEN_GUEST_HA
  * Writable Pagetables
  */
 
+struct ptwr_emulate_ctxt {
+    struct x86_emulate_ctxt ctxt;
+    unsigned long cr2;
+    l1_pgentry_t  pte;
+};
+
+static int ptwr_emulated_read(
+    unsigned int seg,
+    unsigned long offset,
+    unsigned long *val,
+    unsigned int bytes,
+    struct x86_emulate_ctxt *ctxt)
+{
+    unsigned int rc;
+    unsigned long addr = offset;
+
+    *val = 0;
+    if ( (rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0 )
+    {
+        propagate_page_fault(addr + bytes - rc, 0); /* read fault */
+        return X86EMUL_PROPAGATE_FAULT;
+    }
+
+    return X86EMUL_CONTINUE;
+}
+
 static int ptwr_emulated_update(
     unsigned long addr,
     paddr_t old,
     paddr_t val,
     unsigned int bytes,
-    unsigned int do_cmpxchg)
+    unsigned int do_cmpxchg,
+    struct ptwr_emulate_ctxt *ptwr_ctxt)
 {
     unsigned long gmfn, mfn;
     struct page_info *page;
@@ -3046,11 +3073,11 @@ static int ptwr_emulated_update(
     struct vcpu *v = current;
     struct domain *d = v->domain;
 
-    /* Aligned access only, thank you. */
-    if ( !access_ok(addr, bytes) || ((addr & (bytes-1)) != 0) )
-    {
-        MEM_LOG("ptwr_emulate: Unaligned or bad size ptwr access (%d, %lx)",
-                bytes, addr);
+    /* Only allow naturally-aligned stores within the original %cr2 page. */
+    if ( unlikely(((addr^ptwr_ctxt->cr2) & PAGE_MASK) || (addr & (bytes-1))) )
+    {
+        MEM_LOG("Bad ptwr access (cr2=%lx, addr=%lx, bytes=%u)",
+                ptwr_ctxt->cr2, addr, bytes);
         return X86EMUL_UNHANDLEABLE;
     }
 
@@ -3079,17 +3106,9 @@ static int ptwr_emulated_update(
         old  |= full;
     }
 
-    /* Read the PTE that maps the page being updated. */
-    guest_get_eff_l1e(v, addr, &pte);
-    if ( unlikely(!(l1e_get_flags(pte) & _PAGE_PRESENT)) )
-    {
-        MEM_LOG("%s: Cannot get L1 PTE for guest address %lx",
-                __func__, addr);
-        return X86EMUL_UNHANDLEABLE;
-    }
-
-    gmfn  = l1e_get_pfn(pte);
-    mfn = gmfn_to_mfn(d, gmfn);
+    pte  = ptwr_ctxt->pte;
+    gmfn = l1e_get_pfn(pte);
+    mfn  = gmfn_to_mfn(d, gmfn);
     page = mfn_to_page(mfn);
 
     /* We are looking only for read-only mappings of p.t. pages. */
@@ -3164,26 +3183,33 @@ static int ptwr_emulated_update(
 }
 
 static int ptwr_emulated_write(
-    unsigned long addr,
+    unsigned int seg,
+    unsigned long offset,
     unsigned long val,
     unsigned int bytes,
     struct x86_emulate_ctxt *ctxt)
 {
-    return ptwr_emulated_update(addr, 0, val, bytes, 0);
+    return ptwr_emulated_update(
+        offset, 0, val, bytes, 0,
+        container_of(ctxt, struct ptwr_emulate_ctxt, ctxt));
 }
 
 static int ptwr_emulated_cmpxchg(
-    unsigned long addr,
+    unsigned int seg,
+    unsigned long offset,
     unsigned long old,
     unsigned long new,
     unsigned int bytes,
     struct x86_emulate_ctxt *ctxt)
 {
-    return ptwr_emulated_update(addr, old, new, bytes, 1);
+    return ptwr_emulated_update(
+        offset, old, new, bytes, 1,
+        container_of(ctxt, struct ptwr_emulate_ctxt, ctxt));
 }
 
 static int ptwr_emulated_cmpxchg8b(
-    unsigned long addr,
+    unsigned int seg,
+    unsigned long offset,
     unsigned long old,
     unsigned long old_hi,
     unsigned long new,
@@ -3192,18 +3218,16 @@ static int ptwr_emulated_cmpxchg8b(
 {
     if ( CONFIG_PAGING_LEVELS == 2 )
         return X86EMUL_UNHANDLEABLE;
-    else
-        return ptwr_emulated_update(
-            addr, ((u64)old_hi << 32) | old, ((u64)new_hi << 32) | new, 8, 1);
+    return ptwr_emulated_update(
+        offset, ((u64)old_hi << 32) | old, ((u64)new_hi << 32) | new, 8, 1,
+        container_of(ctxt, struct ptwr_emulate_ctxt, ctxt));
 }
 
 static struct x86_emulate_ops ptwr_emulate_ops = {
-    .read_std           = x86_emulate_read_std,
-    .write_std          = x86_emulate_write_std,
-    .read_emulated      = x86_emulate_read_std,
-    .write_emulated     = ptwr_emulated_write,
-    .cmpxchg_emulated   = ptwr_emulated_cmpxchg,
-    .cmpxchg8b_emulated = ptwr_emulated_cmpxchg8b
+    .read      = ptwr_emulated_read,
+    .write     = ptwr_emulated_write,
+    .cmpxchg   = ptwr_emulated_cmpxchg,
+    .cmpxchg8b = ptwr_emulated_cmpxchg8b
 };
 
 /* Write page fault handler: check if guest is trying to modify a PTE. */
@@ -3214,7 +3238,7 @@ int ptwr_do_page_fault(struct vcpu *v, u
     unsigned long     pfn;
     struct page_info *page;
     l1_pgentry_t      pte;
-    struct x86_emulate_ctxt emul_ctxt;
+    struct ptwr_emulate_ctxt ptwr_ctxt;
 
     LOCK_BIGLOCK(d);
 
@@ -3235,10 +3259,11 @@ int ptwr_do_page_fault(struct vcpu *v, u
          (page_get_owner(page) != d) )
         goto bail;
 
-    emul_ctxt.regs = guest_cpu_user_regs();
-    emul_ctxt.cr2  = addr;
-    emul_ctxt.mode = X86EMUL_MODE_HOST;
-    if ( x86_emulate_memop(&emul_ctxt, &ptwr_emulate_ops) )
+    ptwr_ctxt.ctxt.regs = guest_cpu_user_regs();
+    ptwr_ctxt.ctxt.mode = X86EMUL_MODE_HOST;
+    ptwr_ctxt.cr2       = addr;
+    ptwr_ctxt.pte       = pte;
+    if ( x86_emulate_memop(&ptwr_ctxt.ctxt, &ptwr_emulate_ops) )
         goto bail;
 
     UNLOCK_BIGLOCK(d);
diff -r d1b0a5adaeab -r 88935ae47fa9 xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c   Wed Nov 29 23:40:40 2006 +0000
+++ b/xen/arch/x86/mm/shadow/common.c   Thu Nov 30 10:57:28 2006 +0000
@@ -70,11 +70,14 @@ int _shadow_mode_refcounts(struct domain
  */
 
 static int
-sh_x86_emulate_read_std(unsigned long addr,
-                         unsigned long *val,
-                         unsigned int bytes,
-                         struct x86_emulate_ctxt *ctxt)
-{
+sh_x86_emulate_read(unsigned int seg,
+                    unsigned long offset,
+                    unsigned long *val,
+                    unsigned int bytes,
+                    struct x86_emulate_ctxt *ctxt)
+{
+    unsigned long addr = offset;
+
     *val = 0;
     // XXX -- this is WRONG.
     //        It entirely ignores the permissions in the page tables.
@@ -99,40 +102,15 @@ sh_x86_emulate_read_std(unsigned long ad
 }
 
 static int
-sh_x86_emulate_write_std(unsigned long addr,
-                          unsigned long val,
-                          unsigned int bytes,
-                          struct x86_emulate_ctxt *ctxt)
-{
-#if 0
+sh_x86_emulate_write(unsigned int seg,
+                     unsigned long offset,
+                     unsigned long val,
+                     unsigned int bytes,
+                     struct x86_emulate_ctxt *ctxt)
+{
     struct vcpu *v = current;
-    SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n",
-                  v->domain->domain_id, v->vcpu_id, addr, val, bytes);
-#endif
-
-    // XXX -- this is WRONG.
-    //        It entirely ignores the permissions in the page tables.
-    //        In this case, that includes user vs supervisor, and
-    //        write access.
-    //
-    if ( hvm_copy_to_guest_virt(addr, &val, bytes) == 0 )
-        return X86EMUL_CONTINUE;
-
-    /* If we got here, there was nothing mapped here, or a bad GFN 
-     * was mapped here.  This should never happen: we're here because
-     * of a write fault at the end of the instruction we're emulating,
-     * which should be handled by sh_x86_emulate_write_emulated. */ 
-    SHADOW_PRINTK("write failed to va %#lx\n", addr);
-    return X86EMUL_PROPAGATE_FAULT;
-}
-
-static int
-sh_x86_emulate_write_emulated(unsigned long addr,
-                               unsigned long val,
-                               unsigned int bytes,
-                               struct x86_emulate_ctxt *ctxt)
-{
-    struct vcpu *v = current;
+    unsigned long addr = offset;
+
 #if 0
     SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n",
                   v->domain->domain_id, v->vcpu_id, addr, val, bytes);
@@ -141,13 +119,16 @@ sh_x86_emulate_write_emulated(unsigned l
 }
 
 static int 
-sh_x86_emulate_cmpxchg_emulated(unsigned long addr,
-                                 unsigned long old,
-                                 unsigned long new,
-                                 unsigned int bytes,
-                                 struct x86_emulate_ctxt *ctxt)
+sh_x86_emulate_cmpxchg(unsigned int seg,
+                       unsigned long offset,
+                       unsigned long old,
+                       unsigned long new,
+                       unsigned int bytes,
+                       struct x86_emulate_ctxt *ctxt)
 {
     struct vcpu *v = current;
+    unsigned long addr = offset;
+
 #if 0
     SHADOW_PRINTK("d=%u v=%u a=%#lx o?=%#lx n:=%#lx bytes=%u\n",
                    v->domain->domain_id, v->vcpu_id, addr, old, new, bytes);
@@ -157,14 +138,17 @@ sh_x86_emulate_cmpxchg_emulated(unsigned
 }
 
 static int 
-sh_x86_emulate_cmpxchg8b_emulated(unsigned long addr,
-                                   unsigned long old_lo,
-                                   unsigned long old_hi,
-                                   unsigned long new_lo,
-                                   unsigned long new_hi,
-                                   struct x86_emulate_ctxt *ctxt)
+sh_x86_emulate_cmpxchg8b(unsigned int seg,
+                         unsigned long offset,
+                         unsigned long old_lo,
+                         unsigned long old_hi,
+                         unsigned long new_lo,
+                         unsigned long new_hi,
+                         struct x86_emulate_ctxt *ctxt)
 {
     struct vcpu *v = current;
+    unsigned long addr = offset;
+
 #if 0
     SHADOW_PRINTK("d=%u v=%u a=%#lx o?=%#lx:%lx n:=%#lx:%lx\n",
                    v->domain->domain_id, v->vcpu_id, addr, old_hi, old_lo,
@@ -176,12 +160,10 @@ sh_x86_emulate_cmpxchg8b_emulated(unsign
 
 
 struct x86_emulate_ops shadow_emulator_ops = {
-    .read_std           = sh_x86_emulate_read_std,
-    .write_std          = sh_x86_emulate_write_std,
-    .read_emulated      = sh_x86_emulate_read_std,
-    .write_emulated     = sh_x86_emulate_write_emulated,
-    .cmpxchg_emulated   = sh_x86_emulate_cmpxchg_emulated,
-    .cmpxchg8b_emulated = sh_x86_emulate_cmpxchg8b_emulated,
+    .read      = sh_x86_emulate_read,
+    .write     = sh_x86_emulate_write,
+    .cmpxchg   = sh_x86_emulate_cmpxchg,
+    .cmpxchg8b = sh_x86_emulate_cmpxchg8b,
 };
 
 /**************************************************************************/
diff -r d1b0a5adaeab -r 88935ae47fa9 xen/arch/x86/mm/shadow/multi.c
--- a/xen/arch/x86/mm/shadow/multi.c    Wed Nov 29 23:40:40 2006 +0000
+++ b/xen/arch/x86/mm/shadow/multi.c    Thu Nov 30 10:57:28 2006 +0000
@@ -2812,7 +2812,6 @@ static int sh_page_fault(struct vcpu *v,
     if ( is_hvm_domain(d) )
         hvm_store_cpu_guest_regs(v, regs, NULL);
     emul_ctxt.regs = regs;
-    emul_ctxt.cr2  = va;
     emul_ctxt.mode = (is_hvm_domain(d) ?
                       hvm_guest_x86_mode(v) : X86EMUL_MODE_HOST);
 
diff -r d1b0a5adaeab -r 88935ae47fa9 xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c        Wed Nov 29 23:40:40 2006 +0000
+++ b/xen/arch/x86/x86_emulate.c        Thu Nov 30 10:57:28 2006 +0000
@@ -15,9 +15,9 @@
 #include <xen/config.h>
 #include <xen/types.h>
 #include <xen/lib.h>
-#include <xen/mm.h>
 #include <asm/regs.h>
 #define dprintf(_f, _a...) gdprintk(XENLOG_WARNING, _f , ## _a )
+#undef cmpxchg
 #endif
 #include <asm-x86/x86_emulate.h>
 
@@ -38,6 +38,7 @@
 /* Operand sizes: 8-bit operands or specified/overridden size. */
 #define ByteOp      (1<<0) /* 8-bit operands. */
 /* Destination operand type. */
+#define DstBitBase  (0<<1) /* Memory operand, bit string. */
 #define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */
 #define DstReg      (2<<1) /* Register operand. */
 #define DstMem      (3<<1) /* Memory operand. */
@@ -111,8 +112,8 @@ static uint8_t opcode_table[256] = {
     /* 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|Mov, ImplicitOps|Mov,
     ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, 0, 0,
     /* 0xA8 - 0xAF */
     0, 0, ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
@@ -170,14 +171,15 @@ static uint8_t twobyte_table[256] = {
     /* 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, 
+    0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, 
     /* 0xA8 - 0xAF */
-    0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0,
+    0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0,
     /* 0xB0 - 0xB7 */
-    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstMem|SrcReg|ModRM,
+    ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+    0, DstBitBase|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, DstBitBase|SrcImmByte|ModRM, DstBitBase|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,
@@ -193,7 +195,12 @@ struct operand {
 struct operand {
     enum { OP_REG, OP_MEM, OP_IMM } type;
     unsigned int  bytes;
-    unsigned long val, orig_val, *ptr;
+    unsigned long val, orig_val;
+    /* OP_REG: Pointer to register field. */
+    unsigned long *reg;
+    /* OP_MEM: Segment and offset. */
+    unsigned int  mem_seg;
+    unsigned long mem_off;
 };
 
 /* EFLAGS bit definitions. */
@@ -366,24 +373,23 @@ do{ __asm__ __volatile__ (              
 #endif /* __i386__ */
 
 /* Fetch next part of the instruction being emulated. */
-#define _insn_fetch(_size)                                              \
-({ unsigned long _x, _ptr = _regs.eip;                                  \
-   if ( mode == X86EMUL_MODE_REAL ) _ptr += _regs.cs << 4;              \
-   rc = ops->read_std(_ptr, &_x, (_size), ctxt);                        \
-   if ( rc != 0 )                                                       \
-       goto done;                                                       \
-   _regs.eip += (_size);                                                \
-   _x;                                                                  \
+#define _insn_fetch(_size)                                      \
+({ unsigned long _x;                                            \
+   rc = ops->read(_regs.cs, _regs.eip, &_x, (_size), ctxt);     \
+   if ( rc != 0 )                                               \
+       goto done;                                               \
+   _regs.eip += (_size);                                        \
+   _x;                                                          \
 })
 #define insn_fetch(_type) ((_type)_insn_fetch(sizeof(_type)))
 
-/* Access/update address held in a register, based on addressing mode. */
-#define register_address(sel, reg)                                      \
-({  unsigned long __reg = (reg);                                        \
-    (((mode == X86EMUL_MODE_REAL) ? ((unsigned long)(sel) << 4) : 0) +  \
-     ((ad_bytes == sizeof(unsigned long)) ? __reg :                     \
-      (__reg & ((1UL << (ad_bytes << 3)) - 1))));                       \
+#define truncate_ea(ea)                                 \
+({  unsigned long __ea = (ea);                          \
+    ((ad_bytes == sizeof(unsigned long)) ? __ea :       \
+     (__ea & ((1UL << (ad_bytes << 3)) - 1)));          \
 })
+
+/* Update address held in a register, based on addressing mode. */
 #define register_address_increment(reg, inc)                            \
 do {                                                                    \
     int _inc = (inc); /* signed type ensures sign extension to long */  \
@@ -393,17 +399,6 @@ do {                                    
         (reg) = ((reg) & ~((1UL << (ad_bytes << 3)) - 1)) |             \
                 (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1));      \
 } while (0)
-
-/*
- * We cannot handle a page fault on a data access that straddles two pages
- * and faults on the second page. This is because CR2 is not equal to the
- * memory operand's effective address in this case. Rather than fix up the
- * effective address it is okay for us to fail the emulation.
- */
-#define page_boundary_test() do {                               \
-    if ( ((cr2 & (PAGE_SIZE-1)) == 0) && ((ea & 7) != 0) )      \
-        goto bad_ea;                                            \
-} while ( 0 )
 
 void *
 decode_register(
@@ -452,16 +447,12 @@ dump_instr(
 {
 #ifdef __XEN__
     int i;
-    unsigned long x, pc;
-
-    pc = ctxt->regs->eip;
-    if ( ctxt->mode == X86EMUL_MODE_REAL )
-        pc += ctxt->regs->cs << 4;
+    unsigned long x, eip = ctxt->regs->eip;
 
     dprintf("Instr:");
-    for ( i = 0; i < 16; i++, pc++ )
-    {
-        if ( ops->read_std(pc, &x, 1, ctxt) != 0 )
+    for ( i = 0; i < 16; i++, eip++ )
+    {
+        if ( ops->read(ctxt->regs->cs, eip, &x, 1, ctxt) != 0 )
             printk(" ??");
         else
             printk(" %02x", (uint8_t)x);
@@ -480,19 +471,13 @@ x86_emulate_memop(
 
     uint8_t b, d, sib, sib_index, sib_base, twobyte = 0, rex_prefix = 0;
     uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
-    uint16_t *seg = &_regs.ds; /* override segment */
     unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
     int rc = 0;
     struct operand src, dst;
-    unsigned long ea = 0, cr2 = ctxt->cr2;
     int mode = ctxt->mode;
 
-    /*
-     * We do not emulate faults on instruction fetch. We assume that the
-     * guest never executes out of a special memory area.
-     */
-    if ( _regs.error_code & PFEC_insn_fetch )
-        return -1;
+    unsigned int  ea_seg = X86_SEG_DS;
+    unsigned long ea_off = 0;
 
     switch ( mode )
     {
@@ -528,22 +513,22 @@ x86_emulate_memop(
                 ad_bytes ^= 6;  /* switch between 2/4 bytes */
             break;
         case 0x2e: /* CS override */
-            seg = &_regs.cs;
+            ea_seg = X86_SEG_CS;
             break;
         case 0x3e: /* DS override */
-            seg = &_regs.ds;
+            ea_seg = X86_SEG_DS;
             break;
         case 0x26: /* ES override */
-            seg = &_regs.es;
+            ea_seg = X86_SEG_ES;
             break;
         case 0x64: /* FS override */
-            seg = &_regs.fs;
+            ea_seg = X86_SEG_FS;
             break;
         case 0x65: /* GS override */
-            seg = &_regs.gs;
+            ea_seg = X86_SEG_GS;
             break;
         case 0x36: /* SS override */
-            seg = &_regs.ss;
+            ea_seg = X86_SEG_SS;
             break;
         case 0xf0: /* LOCK */
             lock_prefix = 1;
@@ -604,20 +589,20 @@ x86_emulate_memop(
             /* 16-bit ModR/M decode. */
             switch ( modrm_rm )
             {
-            case 0: ea = _regs.ebx + _regs.esi; break;
-            case 1: ea = _regs.ebx + _regs.edi; break;
-            case 2: ea = _regs.ebp + _regs.esi; break;
-            case 3: ea = _regs.ebp + _regs.edi; break;
-            case 4: ea = _regs.esi; break;
-            case 5: ea = _regs.edi; break;
-            case 6: ea = _regs.ebp; break;
-            case 7: ea = _regs.ebx; break;
+            case 0: ea_off = _regs.ebx + _regs.esi; break;
+            case 1: ea_off = _regs.ebx + _regs.edi; break;
+            case 2: ea_off = _regs.ebp + _regs.esi; break;
+            case 3: ea_off = _regs.ebp + _regs.edi; break;
+            case 4: ea_off = _regs.esi; break;
+            case 5: ea_off = _regs.edi; break;
+            case 6: ea_off = _regs.ebp; break;
+            case 7: ea_off = _regs.ebx; break;
             }
             switch ( modrm_mod )
             {
-            case 0: if ( modrm_rm == 6 ) ea = insn_fetch(int16_t); break;
-            case 1: ea += insn_fetch(int8_t);  break;
-            case 2: ea += insn_fetch(int16_t); break;
+            case 0: if ( modrm_rm == 6 ) ea_off = insn_fetch(int16_t); break;
+            case 1: ea_off += insn_fetch(int8_t);  break;
+            case 2: ea_off += insn_fetch(int16_t); break;
             }
         }
         else
@@ -629,83 +614,50 @@ x86_emulate_memop(
                 sib_index = ((sib >> 3) & 7) | ((modrm << 2) & 8);
                 sib_base  = (sib & 7) | ((modrm << 3) & 8);
                 if ( sib_index != 4 )
-                    ea = *(long *)decode_register(sib_index, &_regs, 0);
-                ea <<= (sib >> 6) & 3;
+                    ea_off = *(long *)decode_register(sib_index, &_regs, 0);
+                ea_off <<= (sib >> 6) & 3;
                 if ( (modrm_mod == 0) && ((sib_base & 7) == 5) )
-                    ea += insn_fetch(int32_t);
+                    ea_off += insn_fetch(int32_t);
                 else
-                    ea += *(long *)decode_register(sib_base, &_regs, 0);
+                    ea_off += *(long *)decode_register(sib_base, &_regs, 0);
             }
             else
             {
                 modrm_rm |= (rex_prefix & 1) << 3;
-                ea = *(long *)decode_register(modrm_rm, &_regs, 0);
+                ea_off = *(long *)decode_register(modrm_rm, &_regs, 0);
             }
             switch ( modrm_mod )
             {
             case 0:
                 if ( (modrm_rm & 7) != 5 )
                     break;
-                ea = insn_fetch(int32_t);
+                ea_off = insn_fetch(int32_t);
                 if ( mode != X86EMUL_MODE_PROT64 )
                     break;
                 /* Relative to RIP of next instruction. Argh! */
-                ea += _regs.eip;
+                ea_off += _regs.eip;
                 if ( (d & SrcMask) == SrcImm )
-                    ea += (d & ByteOp) ? 1 : ((op_bytes == 8) ? 4 : op_bytes);
+                    ea_off += (d & ByteOp) ? 1 :
+                        ((op_bytes == 8) ? 4 : op_bytes);
                 else if ( (d & SrcMask) == SrcImmByte )
-                    ea += 1;
+                    ea_off += 1;
                 else if ( ((b == 0xf6) || (b == 0xf7)) &&
                           ((modrm_reg & 7) <= 1) )
                     /* Special case in Grp3: test has immediate operand. */
-                    ea += (d & ByteOp) ? 1
+                    ea_off += (d & ByteOp) ? 1
                         : ((op_bytes == 8) ? 4 : op_bytes);
                 break;
-            case 1: ea += insn_fetch(int8_t);  break;
-            case 2: ea += insn_fetch(int32_t); break;
+            case 1: ea_off += insn_fetch(int8_t);  break;
+            case 2: ea_off += insn_fetch(int32_t); break;
             }
         }
 
-        ea = register_address(*seg, ea);
-        page_boundary_test();
-    }
-
-    /* Decode and fetch the destination operand: register or memory. */
-    switch ( d & DstMask )
-    {
-    case ImplicitOps:
-        /* Special instructions do their own operand decoding. */
+        ea_off = truncate_ea(ea_off);
+    }
+
+    /* Special instructions do their own operand decoding. */
+    if ( (d & DstMask) == ImplicitOps )
         goto special_insn;
-    case DstReg:
-        dst.type = OP_REG;
-        if ( d & ByteOp )
-        {
-            dst.ptr = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
-            dst.val = *(uint8_t *)dst.ptr;
-            dst.bytes = 1;
-        }
-        else
-        {
-            dst.ptr = decode_register(modrm_reg, &_regs, 0);
-            switch ( (dst.bytes = op_bytes) )
-            {
-            case 2: dst.val = *(uint16_t *)dst.ptr; break;
-            case 4: dst.val = *(uint32_t *)dst.ptr; break;
-            case 8: dst.val = *(uint64_t *)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 */
-             ((rc = ops->read_emulated((unsigned long)dst.ptr,
-                                       &dst.val, dst.bytes, ctxt)) != 0) )
-             goto done;
-        break;
-    }
-    dst.orig_val = dst.val;
 
     /* Decode and fetch the source operand: register, memory or immediate. */
     switch ( d & SrcMask )
@@ -716,18 +668,18 @@ x86_emulate_memop(
         src.type = OP_REG;
         if ( d & ByteOp )
         {
-            src.ptr = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
-            src.val = src.orig_val = *(uint8_t *)src.ptr;
+            src.reg = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
+            src.val = src.orig_val = *(uint8_t *)src.reg;
             src.bytes = 1;
         }
         else
         {
-            src.ptr = decode_register(modrm_reg, &_regs, 0);
+            src.reg = decode_register(modrm_reg, &_regs, 0);
             switch ( (src.bytes = op_bytes) )
             {
-            case 2: src.val = src.orig_val = *(uint16_t *)src.ptr; break;
-            case 4: src.val = src.orig_val = *(uint32_t *)src.ptr; break;
-            case 8: src.val = src.orig_val = *(uint64_t *)src.ptr; break;
+            case 2: src.val = src.orig_val = *(uint16_t *)src.reg; break;
+            case 4: src.val = src.orig_val = *(uint32_t *)src.reg; break;
+            case 8: src.val = src.orig_val = *(uint64_t *)src.reg; break;
             }
         }
         break;
@@ -741,15 +693,15 @@ x86_emulate_memop(
         src.bytes = (d & ByteOp) ? 1 : op_bytes;
     srcmem_common:
         src.type  = OP_MEM;
-        src.ptr   = (unsigned long *)cr2;
-        if ( (rc = ops->read_emulated((unsigned long)src.ptr, 
-                                      &src.val, src.bytes, ctxt)) != 0 )
+        src.mem_seg = ea_seg;
+        src.mem_off = ea_off;
+        if ( (rc = ops->read(src.mem_seg, src.mem_off,
+                             &src.val, src.bytes, ctxt)) != 0 )
             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. */
@@ -762,11 +714,80 @@ x86_emulate_memop(
         break;
     case SrcImmByte:
         src.type  = OP_IMM;
-        src.ptr   = (unsigned long *)_regs.eip;
         src.bytes = 1;
         src.val   = insn_fetch(int8_t);
         break;
     }
+
+    /* Decode and fetch the destination operand: register or memory. */
+    switch ( d & DstMask )
+    {
+    case DstReg:
+        dst.type = OP_REG;
+        if ( d & ByteOp )
+        {
+            dst.reg = decode_register(modrm_reg, &_regs, (rex_prefix == 0));
+            dst.val = *(uint8_t *)dst.reg;
+            dst.bytes = 1;
+        }
+        else
+        {
+            dst.reg = decode_register(modrm_reg, &_regs, 0);
+            switch ( (dst.bytes = op_bytes) )
+            {
+            case 2: dst.val = *(uint16_t *)dst.reg; break;
+            case 4: dst.val = *(uint32_t *)dst.reg; break;
+            case 8: dst.val = *(uint64_t *)dst.reg; break;
+            }
+        }
+        break;
+    case DstBitBase:
+        dst.mem_off = ea_off;
+        if ( (d & SrcMask) == SrcImmByte )
+        {
+            src.val &= (op_bytes << 3) - 1;
+        }
+        else
+        {
+            /*
+             * EA       += BitOffset DIV op_bytes*8
+             * BitOffset = BitOffset MOD op_byte*8
+             * DIV truncates towards negative infinity.
+             * MOD always produces a positive result.
+             */
+            if ( op_bytes == 2 )
+                src.val = (int16_t)src.val;
+            else if ( op_bytes == 4 )
+                src.val = (int32_t)src.val;
+            if ( (long)src.val < 0 )
+            {
+                unsigned long byte_offset;
+                byte_offset = op_bytes + (((-src.val-1) >> 3) & ~(op_bytes-1));
+                dst.mem_off -= byte_offset;
+                src.val = (byte_offset << 3) + src.val;
+            }
+            else
+            {
+                dst.mem_off += (src.val >> 3) & ~(op_bytes - 1);
+                src.val &= (op_bytes << 3) - 1;
+            }
+        }
+        /* Becomes a normal DstMem operation from here on. */
+        d = (d & ~DstMask) | DstMem;
+        goto dstmem_common;
+    case DstMem:
+        dst.mem_off = ea_off;
+    dstmem_common:
+        dst.mem_seg = ea_seg;
+        dst.type  = OP_MEM;
+        dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+        if ( !(d & Mov) && /* optimisation - avoid slow emulated read */
+             ((rc = ops->read(dst.mem_seg, dst.mem_off,
+                              &dst.val, dst.bytes, ctxt)) != 0) )
+             goto done;
+        break;
+    }
+    dst.orig_val = dst.val;
 
     if ( twobyte )
         goto twobyte_insn;
@@ -822,45 +843,25 @@ x86_emulate_memop(
         /* Write back the register source. */
         switch ( dst.bytes )
         {
-        case 1: *(uint8_t  *)src.ptr = (uint8_t)dst.val; break;
-        case 2: *(uint16_t *)src.ptr = (uint16_t)dst.val; break;
-        case 4: *src.ptr = (uint32_t)dst.val; break; /* 64b reg: zero-extend */
-        case 8: *src.ptr = dst.val; break;
+        case 1: *(uint8_t  *)src.reg = (uint8_t)dst.val; break;
+        case 2: *(uint16_t *)src.reg = (uint16_t)dst.val; break;
+        case 4: *src.reg = (uint32_t)dst.val; break; /* 64b reg: zero-extend */
+        case 8: *src.reg = dst.val; break;
         }
         /* Write back the memory destination with implicit LOCK prefix. */
         dst.val = src.val;
         lock_prefix = 1;
         break;
-    case 0xa0 ... 0xa1: /* mov */
-        dst.ptr = (unsigned long *)&_regs.eax;
-        dst.val = src.val;
-        /* Source EA is not encoded via ModRM. */
-        ea = register_address(*seg, _insn_fetch(ad_bytes));
-        page_boundary_test();
-        break;
-    case 0xa2 ... 0xa3: /* mov */
-        dst.val = (unsigned long)_regs.eax;
-        /* Destination EA is not encoded via ModRM. */
-        ea = register_address(*seg, _insn_fetch(ad_bytes));
-        page_boundary_test();
-        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) */
-        /*
-         * If the faulting access was a read it means that the fault occurred
-         * when accessing the implicit stack operand. We assume the guest never
-         * uses special memory areas as stack space.
-         */
-        if ( !(_regs.error_code & PFEC_write_access) )
-            goto cannot_emulate; /* fault on stack access: bail */
         /* 64-bit mode: POP always pops a 64-bit operand. */
         if ( mode == X86EMUL_MODE_PROT64 )
             dst.bytes = 8;
-        if ( (rc = ops->read_std(register_address(_regs.ss, _regs.esp),
-                                 &dst.val, dst.bytes, ctxt)) != 0 )
+        if ( (rc = ops->read(X86_SEG_SS, truncate_ea(_regs.esp),
+                             &dst.val, dst.bytes, ctxt)) != 0 )
             goto done;
         register_address_increment(_regs.esp, dst.bytes);
         break;
@@ -903,7 +904,6 @@ x86_emulate_memop(
         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 )
@@ -933,24 +933,17 @@ x86_emulate_memop(
             emulate_1op("dec", dst, _regs.eflags);
             break;
         case 6: /* push */
-            /*
-             * If the faulting access was a write it means that the fault
-             * occurred when accessing the implicit stack operand. We assume
-             * the guest never uses special memory areas as stack space.
-             */
-            if ( _regs.error_code & PFEC_write_access )
-                goto cannot_emulate; /* fault on stack access: bail */
             /* 64-bit mode: PUSH always pushes a 64-bit operand. */
             if ( mode == X86EMUL_MODE_PROT64 )
             {
                 dst.bytes = 8;
-                if ( (rc = ops->read_std((unsigned long)dst.ptr,
-                                         &dst.val, 8, ctxt)) != 0 )
+                if ( (rc = ops->read(dst.mem_seg, dst.mem_off,
+                                     &dst.val, 8, ctxt)) != 0 )
                     goto done;
             }
             register_address_increment(_regs.esp, -dst.bytes);
-            if ( (rc = ops->write_std(register_address(_regs.ss, _regs.esp),
-                                      dst.val, dst.bytes, ctxt)) != 0 )
+            if ( (rc = ops->write(X86_SEG_SS, truncate_ea(_regs.esp),
+                                  dst.val, dst.bytes, ctxt)) != 0 )
                 goto done;
             dst.val = dst.orig_val; /* skanky: disable writeback */
             break;
@@ -969,20 +962,20 @@ x86_emulate_memop(
             /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
             switch ( dst.bytes )
             {
-            case 1: *(uint8_t  *)dst.ptr = (uint8_t)dst.val; break;
-            case 2: *(uint16_t *)dst.ptr = (uint16_t)dst.val; break;
-            case 4: *dst.ptr = (uint32_t)dst.val; break; /* 64b: zero-ext */
-            case 8: *dst.ptr = dst.val; break;
+            case 1: *(uint8_t  *)dst.reg = (uint8_t)dst.val; break;
+            case 2: *(uint16_t *)dst.reg = (uint16_t)dst.val; break;
+            case 4: *dst.reg = (uint32_t)dst.val; break; /* 64b: zero-ext */
+            case 8: *dst.reg = dst.val; break;
             }
             break;
         case OP_MEM:
             if ( lock_prefix )
-                rc = ops->cmpxchg_emulated(
-                    (unsigned long)dst.ptr, dst.orig_val,
+                rc = ops->cmpxchg(
+                    dst.mem_seg, dst.mem_off, dst.orig_val,
                     dst.val, dst.bytes, ctxt);
             else
-                rc = ops->write_emulated(
-                    (unsigned long)dst.ptr, dst.val, dst.bytes, ctxt);
+                rc = ops->write(
+                    dst.mem_seg, dst.mem_off, dst.val, dst.bytes, ctxt);
             if ( rc != 0 )
                 goto done;
         default:
@@ -1011,50 +1004,51 @@ x86_emulate_memop(
     }
     switch ( b )
     {
+    case 0xa0 ... 0xa1: /* mov moffs,{%al,%ax,%eax,%rax} */
+        /* Source EA is not encoded via ModRM. */
+        dst.type  = OP_REG;
+        dst.reg   = (unsigned long *)&_regs.eax;
+        dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+        if ( (rc = ops->read(ea_seg, _insn_fetch(ad_bytes),
+                             &dst.val, dst.bytes, ctxt)) != 0 )
+            goto done;
+        break;
+    case 0xa2 ... 0xa3: /* mov {%al,%ax,%eax,%rax},moffs */
+        /* Destination EA is not encoded via ModRM. */
+        dst.type    = OP_MEM;
+        dst.mem_seg = ea_seg;
+        dst.mem_off = _insn_fetch(ad_bytes);
+        dst.bytes   = (d & ByteOp) ? 1 : op_bytes;
+        dst.val     = (unsigned long)_regs.eax;
+        break;
     case 0xa4 ... 0xa5: /* movs */
         dst.type  = OP_MEM;
         dst.bytes = (d & ByteOp) ? 1 : op_bytes;
-        if ( _regs.error_code & PFEC_write_access )
-        {
-            /* Write fault: destination is special memory. */
-            dst.ptr = (unsigned long *)cr2;
-            if ( (rc = ops->read_std(register_address(*seg, _regs.esi),
-                                     &dst.val, dst.bytes, ctxt)) != 0 )
-                goto done;
-            ea = register_address(_regs.es, _regs.edi);
-        }
-        else
-        {
-            /* Read fault: source is special memory. */
-            dst.ptr = (unsigned long *)register_address(_regs.es, _regs.edi);
-            if ( (rc = ops->read_emulated(cr2, &dst.val,
-                                          dst.bytes, ctxt)) != 0 )
-                goto done;
-            ea = register_address(*seg, _regs.esi);
-        }
-        page_boundary_test();
+        dst.mem_seg = X86_SEG_ES;
+        dst.mem_off = truncate_ea(_regs.edi);
+        if ( (rc = ops->read(ea_seg, truncate_ea(_regs.esi),
+                             &dst.val, dst.bytes, ctxt)) != 0 )
+            goto done;
         register_address_increment(
             _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
         register_address_increment(
             _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
         break;
     case 0xaa ... 0xab: /* stos */
-        ea = register_address(_regs.es, _regs.edi);
-        page_boundary_test();
         dst.type  = OP_MEM;
         dst.bytes = (d & ByteOp) ? 1 : op_bytes;
-        dst.ptr   = (unsigned long *)cr2;
+        dst.mem_seg = X86_SEG_ES;
+        dst.mem_off = truncate_ea(_regs.edi);
         dst.val   = _regs.eax;
         register_address_increment(
             _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
         break;
     case 0xac ... 0xad: /* lods */
-        ea = register_address(*seg, _regs.esi);
-        page_boundary_test();
         dst.type  = OP_REG;
         dst.bytes = (d & ByteOp) ? 1 : op_bytes;
-        dst.ptr   = (unsigned long *)&_regs.eax;
-        if ( (rc = ops->read_emulated(cr2, &dst.val, dst.bytes, ctxt)) != 0 )
+        dst.reg   = (unsigned long *)&_regs.eax;
+        if ( (rc = ops->read(ea_seg, truncate_ea(_regs.esi),
+                             &dst.val, dst.bytes, ctxt)) != 0 )
             goto done;
         register_address_increment(
             _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
@@ -1116,19 +1110,16 @@ x86_emulate_memop(
         {
             /* Failure: write the value we saw to EAX. */
             dst.type = OP_REG;
-            dst.ptr  = (unsigned long *)&_regs.eax;
+            dst.reg  = (unsigned long *)&_regs.eax;
         }
         break;
     case 0xa3: bt: /* bt */
-        src.val &= (dst.bytes << 3) - 1; /* only subword offset */
         emulate_2op_SrcV_nobyte("bt", src, dst, _regs.eflags);
         break;
     case 0xb3: btr: /* btr */
-        src.val &= (dst.bytes << 3) - 1; /* only subword offset */
         emulate_2op_SrcV_nobyte("btr", src, dst, _regs.eflags);
         break;
     case 0xab: bts: /* bts */
-        src.val &= (dst.bytes << 3) - 1; /* only subword offset */
         emulate_2op_SrcV_nobyte("bts", src, dst, _regs.eflags);
         break;
     case 0xb6 ... 0xb7: /* movzx */
@@ -1136,7 +1127,6 @@ x86_emulate_memop(
         dst.val = (d & ByteOp) ? (uint8_t)src.val : (uint16_t)src.val;
         break;
     case 0xbb: btc: /* btc */
-        src.val &= (dst.bytes << 3) - 1; /* only subword offset */
         emulate_2op_SrcV_nobyte("btc", src, dst, _regs.eflags);
         break;
     case 0xba: /* Grp8 */
@@ -1167,8 +1157,8 @@ x86_emulate_memop(
 #if defined(__i386__)
     {
         unsigned long old_lo, old_hi;
-        if ( ((rc = ops->read_emulated(cr2+0, &old_lo, 4, ctxt)) != 0) ||
-             ((rc = ops->read_emulated(cr2+4, &old_hi, 4, ctxt)) != 0) )
+        if ( ((rc = ops->read(ea_seg, ea_off+0, &old_lo, 4, ctxt)) != 0) ||
+             ((rc = ops->read(ea_seg, ea_off+4, &old_hi, 4, ctxt)) != 0) )
             goto done;
         if ( (old_lo != _regs.eax) || (old_hi != _regs.edx) )
         {
@@ -1176,15 +1166,15 @@ x86_emulate_memop(
             _regs.edx = old_hi;
             _regs.eflags &= ~EFLG_ZF;
         }
-        else if ( ops->cmpxchg8b_emulated == NULL )
+        else if ( ops->cmpxchg8b == NULL )
         {
             rc = X86EMUL_UNHANDLEABLE;
             goto done;
         }
         else
         {
-            if ( (rc = ops->cmpxchg8b_emulated(cr2, old_lo, old_hi, _regs.ebx,
-                                               _regs.ecx, ctxt)) != 0 )
+            if ( (rc = ops->cmpxchg8b(ea_seg, ea_off, old_lo, old_hi,
+                                      _regs.ebx, _regs.ecx, ctxt)) != 0 )
                 goto done;
             _regs.eflags |= EFLG_ZF;
         }
@@ -1193,7 +1183,7 @@ x86_emulate_memop(
 #elif defined(__x86_64__)
     {
         unsigned long old, new;
-        if ( (rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0 )
+        if ( (rc = ops->read(ea_seg, ea_off, &old, 8, ctxt)) != 0 )
             goto done;
         if ( ((uint32_t)(old>>0) != (uint32_t)_regs.eax) ||
              ((uint32_t)(old>>32) != (uint32_t)_regs.edx) )
@@ -1205,7 +1195,7 @@ x86_emulate_memop(
         else
         {
             new = (_regs.ecx<<32)|(uint32_t)_regs.ebx;
-            if ( (rc = ops->cmpxchg_emulated(cr2, old, new, 8, ctxt)) != 0 )
+            if ( (rc = ops->cmpxchg(ea_seg, ea_off, old, new, 8, ctxt)) != 0 )
                 goto done;
             _regs.eflags |= EFLG_ZF;
         }
@@ -1219,55 +1209,4 @@ x86_emulate_memop(
     dprintf("Cannot emulate %02x\n", b);
     dump_instr(ctxt, ops);
     return -1;
-
- bad_ea:
-    dprintf("Access faulted on page boundary (cr2=%lx,ea=%lx).\n", cr2, ea);
-    dump_instr(ctxt, ops);
-    show_execution_state(ctxt->regs);
-    return -1;
 }
-
-#ifdef __XEN__
-
-#include <asm/mm.h>
-#include <asm/uaccess.h>
-
-int
-x86_emulate_read_std(
-    unsigned long addr,
-    unsigned long *val,
-    unsigned int bytes,
-    struct x86_emulate_ctxt *ctxt)
-{
-    unsigned int rc;
-
-    *val = 0;
-
-    if ( (rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0 )
-    {
-        propagate_page_fault(addr + bytes - rc, 0); /* read fault */
-        return X86EMUL_PROPAGATE_FAULT;
-    }
-
-    return X86EMUL_CONTINUE;
-}
-
-int
-x86_emulate_write_std(
-    unsigned long addr,
-    unsigned long val,
-    unsigned int bytes,
-    struct x86_emulate_ctxt *ctxt)
-{
-    unsigned int rc;
-
-    if ( (rc = copy_to_user((void *)addr, (void *)&val, bytes)) != 0 )
-    {
-        propagate_page_fault(addr + bytes - rc, PFEC_write_access);
-        return X86EMUL_PROPAGATE_FAULT;
-    }
-
-    return X86EMUL_CONTINUE;
-}
-
-#endif
diff -r d1b0a5adaeab -r 88935ae47fa9 xen/include/asm-x86/x86_emulate.h
--- a/xen/include/asm-x86/x86_emulate.h Wed Nov 29 23:40:40 2006 +0000
+++ b/xen/include/asm-x86/x86_emulate.h Thu Nov 30 10:57:28 2006 +0000
@@ -11,35 +11,27 @@
 
 struct x86_emulate_ctxt;
 
+#define X86_SEG_CS 0
+#define X86_SEG_SS 1
+#define X86_SEG_DS 2
+#define X86_SEG_ES 3
+#define X86_SEG_FS 4
+#define X86_SEG_GS 5
+
 /*
  * x86_emulate_ops:
  * 
  * 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, that this location is the given linear faulting address (cr2), and
- * that this is one of the instruction's 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 assumes 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
+ *  1. 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 X86EMUL_PROPAGATE_FAULT to the emulator, which will
  *     then immediately bail.
- *  3. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only
+ *  2. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only
  *     cmpxchg8b_emulated need support 8-byte accesses.
- *  4. The emulator cannot handle 64-bit mode emulation on an x86/32 system.
+ *  3. The emulator cannot handle 64-bit mode emulation on an x86/32 system.
  */
 /* Access completed successfully: continue emulation as normal. */
 #define X86EMUL_CONTINUE        0
@@ -52,74 +44,51 @@ struct x86_emulate_ops
 struct x86_emulate_ops
 {
     /*
-     * 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'.
+     * All functions:
+     *  @seg:   [IN ] Segment being dereferenced (specified as X86_SEG_??).
+     *  @offset [IN ] Offset within segment.
+     */
+
+    /*
+     * read: Emulate a memory read.
+     *  @val:   [OUT] Value read from memory, zero-extended to 'ulong'.
      *  @bytes: [IN ] Number of bytes to read from memory.
      */
-    int (*read_std)(
-        unsigned long addr,
+    int (*read)(
+        unsigned int seg,
+        unsigned long offset,
         unsigned long *val,
         unsigned int bytes,
         struct x86_emulate_ctxt *ctxt);
 
     /*
-     * write_std: Write bytes of standard (non-emulated/special) memory.
-     *            Used for stack operations, and others.
-     *  @addr:  [IN ] Linear address to which to write.
+     * write: Emulate a memory 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,
+    int (*write)(
+        unsigned int seg,
+        unsigned long offset,
         unsigned long val,
         unsigned int bytes,
         struct x86_emulate_ctxt *ctxt);
 
     /*
-     * 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,
-        struct x86_emulate_ctxt *ctxt);
-
-    /*
-     * 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,
-        struct x86_emulate_ctxt *ctxt);
-
-    /*
-     * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an
-     *                   emulated/special memory area.
-     *  @addr:  [IN ] Linear address to access.
+     * cmpxchg: Emulate an atomic (LOCKed) CMPXCHG operation.
      *  @old:   [IN ] Value expected to be current at @addr.
      *  @new:   [IN ] Value to write to @addr.
      *  @bytes: [IN ] Number of bytes to access using CMPXCHG.
      */
-    int (*cmpxchg_emulated)(
-        unsigned long addr,
+    int (*cmpxchg)(
+        unsigned int seg,
+        unsigned long offset,
         unsigned long old,
         unsigned long new,
         unsigned int bytes,
         struct x86_emulate_ctxt *ctxt);
 
     /*
-     * cmpxchg8b_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an
-     *                     emulated/special memory area.
-     *  @addr:  [IN ] Linear address to access.
+     * cmpxchg8b: Emulate an atomic (LOCKed) CMPXCHG8B operation.
      *  @old:   [IN ] Value expected to be current at @addr.
      *  @new:   [IN ] Value to write to @addr.
      * NOTES:
@@ -128,8 +97,9 @@ struct x86_emulate_ops
      *  2. Not defining this function (i.e., specifying NULL) is equivalent
      *     to defining a function that always returns X86EMUL_UNHANDLEABLE.
      */
-    int (*cmpxchg8b_emulated)(
-        unsigned long addr,
+    int (*cmpxchg8b)(
+        unsigned int seg,
+        unsigned long offset,
         unsigned long old_lo,
         unsigned long old_hi,
         unsigned long new_lo,
@@ -137,29 +107,12 @@ struct x86_emulate_ops
         struct x86_emulate_ctxt *ctxt);
 };
 
-/* Standard reader/writer functions that callers may wish to use. */
-extern int
-x86_emulate_read_std(
-    unsigned long addr,
-    unsigned long *val,
-    unsigned int bytes,
-    struct x86_emulate_ctxt *ctxt);
-extern int
-x86_emulate_write_std(
-    unsigned long addr,
-    unsigned long val,
-    unsigned int bytes,
-    struct x86_emulate_ctxt *ctxt);
-
 struct cpu_user_regs;
 
 struct x86_emulate_ctxt
 {
     /* Register state before/after emulation. */
     struct cpu_user_regs   *regs;
-
-    /* Linear faulting address (if emulating a page-faulting instruction). */
-    unsigned long           cr2;
 
     /* Emulated execution mode, represented by an X86EMUL_MODE value. */
     int                     mode;

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [XEN] Simplify x86_emulate interface., Xen patchbot-unstable <=