[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] Add CMPXCHG8B support to the instruction emulator.



ChangeSet 1.1337, 2005/03/21 18:04:36+00:00, kaf24@xxxxxxxxxxxxxxxxxxxx

        Add CMPXCHG8B support to the instruction emulator.
        Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>



 tools/tests/test_x86_emulator.c   |   52 +++++++++++++++++++++++++++++++-
 xen/arch/x86/x86_emulate.c        |   61 ++++++++++++++++++++++++++++++++++++--
 xen/include/asm-x86/x86_emulate.h |   21 +++++++++++++
 3 files changed, 129 insertions(+), 5 deletions(-)


diff -Nru a/tools/tests/test_x86_emulator.c b/tools/tests/test_x86_emulator.c
--- a/tools/tests/test_x86_emulator.c   2005-03-21 14:03:00 -05:00
+++ b/tools/tests/test_x86_emulator.c   2005-03-21 14:03:00 -05:00
@@ -60,15 +60,28 @@
     return X86EMUL_CONTINUE;
 }
 
+static int cmpxchg8b_any(
+    unsigned long addr,
+    unsigned long old_lo,
+    unsigned long old_hi,
+    unsigned long new_lo,
+    unsigned long new_hi)
+{
+    ((unsigned long *)addr)[0] = new_lo;
+    ((unsigned long *)addr)[1] = new_hi;
+    return X86EMUL_CONTINUE;
+}
+
 static struct x86_mem_emulator emulops = {
-    read_any, write_any, read_any, write_any, cmpxchg_any
+    read_any, write_any, read_any, write_any, cmpxchg_any, cmpxchg8b_any
 };
 
 int main(int argc, char **argv)
 {
     struct xen_regs regs;
-    char instr[] = { 0x01, 0x08 }; /* add %ecx,(%eax) */
+    char instr[20] = { 0x01, 0x08 }; /* add %ecx,(%eax) */
     unsigned int res = 0x7FFFFFFF;
+    u32 cmpxchg8b_res[2] = { 0x12345678, 0x87654321 };
     unsigned long cr2;
     int rc;
 
@@ -170,6 +183,41 @@
          (res != 0x2233445D) ||
          ((regs.eflags&0x201) != 0x201) ||
          (regs.eip != (unsigned long)&instr[4]) )
+        goto fail;
+    printf("okay\n");
+
+    printf("%-40s", "Testing cmpxchg (%edi) [succeeding]...");
+    instr[0] = 0x0f; instr[1] = 0xc7; instr[2] = 0x0f;
+    regs.eflags = 0x200;
+    regs.eax    = cmpxchg8b_res[0];
+    regs.edx    = cmpxchg8b_res[1];
+    regs.ebx    = 0x9999AAAA;
+    regs.ecx    = 0xCCCCFFFF;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.edi    = (unsigned long)cmpxchg8b_res;
+    cr2         = regs.edi;
+    rc = x86_emulate_memop(&regs, cr2, &emulops, 4);
+    if ( (rc != 0) || 
+         (cmpxchg8b_res[0] != 0x9999AAAA) ||
+         (cmpxchg8b_res[1] != 0xCCCCFFFF) ||
+         ((regs.eflags&0x240) != 0x240) ||
+         (regs.eip != (unsigned long)&instr[3]) )
+        goto fail;
+    printf("okay\n");
+
+    printf("%-40s", "Testing cmpxchg (%edi) [failing]...");
+    instr[0] = 0x0f; instr[1] = 0xc7; instr[2] = 0x0f;
+    regs.eip    = (unsigned long)&instr[0];
+    regs.edi    = (unsigned long)cmpxchg8b_res;
+    cr2         = regs.edi;
+    rc = x86_emulate_memop(&regs, cr2, &emulops, 4);
+    if ( (rc != 0) || 
+         (cmpxchg8b_res[0] != 0x9999AAAA) ||
+         (cmpxchg8b_res[1] != 0xCCCCFFFF) ||
+         (regs.eax != 0x9999AAAA) ||
+         (regs.edx != 0xCCCCFFFF) ||
+         ((regs.eflags&0x240) != 0x200) ||
+         (regs.eip != (unsigned long)&instr[3]) )
         goto fail;
     printf("okay\n");
 
diff -Nru a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c        2005-03-21 14:03:00 -05:00
+++ b/xen/arch/x86/x86_emulate.c        2005-03-21 14:03:00 -05:00
@@ -181,7 +181,7 @@
     /* 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,
+    0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, 0,
     /* 0xD0 - 0xDF */
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     /* 0xE0 - 0xEF */
@@ -963,8 +963,63 @@
     goto writeback;
 
  twobyte_special_insn:
-    /* Only prefetch instructions get here, so nothing to do. */
-    dst.orig_val = dst.val; /* disable writeback */
+    /* Disable writeback. */
+    dst.orig_val = dst.val;
+    switch ( b )
+    {
+    case 0x0d: /* GrpP (prefetch) */
+    case 0x18: /* Grp16 (prefetch/nop) */
+        break;
+    case 0xc7: /* Grp9 (cmpxchg8b) */
+#if defined(__i386__)
+    {
+        unsigned long old_lo, old_hi;
+        if ( ((rc = ops->read_emulated(cr2+0, &old_lo, 4)) != 0) ||
+             ((rc = ops->read_emulated(cr2+4, &old_hi, 4)) != 0) )
+            goto done;
+        if ( (old_lo != _regs.eax) || (old_hi != _regs.edx) )
+        {
+            _regs.eax = old_lo;
+            _regs.edx = old_hi;
+            _regs.eflags &= ~EFLG_ZF;
+        }
+        else if ( ops->cmpxchg8b_emulated == NULL )
+        {
+            rc = X86EMUL_UNHANDLEABLE;
+            goto done;
+        }
+        else
+        {
+            if ( (rc = ops->cmpxchg8b_emulated(cr2, old_lo, old_hi,
+                                               _regs.ebx, _regs.ecx)) != 0 )
+                goto done;
+            _regs.eflags |= EFLG_ZF;
+        }
+        break;
+    }
+#elif defined(__x86_64__)
+    {
+        unsigned long old, new;
+        if ( (rc = ops->read_emulated(cr2, &old, 8)) != 0 )
+            goto done;
+        if ( ((u32)(old>>0) != (u32)_regs.eax) ||
+             ((u32)(old>>32) != (u32)_regs.edx) )
+        {
+            _regs.eax = (u32)(old>>0);
+            _regs.edx = (u32)(old>>32);
+            _regs.eflags &= ~EFLG_ZF;
+        }
+        else
+        {
+            new = (_regs.ecx<<32)|(u32)_regs.ebx;
+            if ( (rc = ops->cmpxchg_emulated(cr2, old, new, 8)) != 0 )
+                goto done;
+            _regs.eflags |= EFLG_ZF;
+        }
+        break;
+    }
+#endif
+    }
     goto writeback;
 
  cannot_emulate:
diff -Nru a/xen/include/asm-x86/x86_emulate.h 
b/xen/include/asm-x86/x86_emulate.h
--- a/xen/include/asm-x86/x86_emulate.h 2005-03-21 14:03:00 -05:00
+++ b/xen/include/asm-x86/x86_emulate.h 2005-03-21 14:03:00 -05:00
@@ -34,6 +34,8 @@
  *     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
+ *     cmpxchg8b_emulated need support 8-byte accesses.
  */
 /* Access completed successfully: continue emulation as normal. */
 #define X86EMUL_CONTINUE        0
@@ -104,6 +106,25 @@
         unsigned long old,
         unsigned long new,
         unsigned int bytes);
+
+    /*
+     * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG8B 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.
+     * NOTES:
+     *  1. This function is only ever called when emulating a real CMPXCHG8B.
+     *  2. This function is *never* called on x86/64 systems.
+     *  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,
+        unsigned long old_lo,
+        unsigned long old_hi,
+        unsigned long new_lo,
+        unsigned long new_hi);
 };
 
 /* Standard reader/writer functions that callers may wish to use. */


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/xen-changelog


 


Rackspace

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