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-devel

[Xen-devel] [PATCH] x86-64: emulation support for cmpxchg16b

To: <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH] x86-64: emulation support for cmpxchg16b
From: "Jan Beulich" <jbeulich@xxxxxxxxxx>
Date: Mon, 21 Apr 2008 17:35:15 +0100
Delivery-date: Mon, 21 Apr 2008 09:35:33 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
With the x86 instruction emulator no pretty complete, I'd like to
re-submit this patch to support cmpxchg16b on x86-64 and at once rename
the underlying emulator callback function pointer (making clear that if
implemented, it is to operate on two longs rather than two 32-bit
values). At the same time it fixes an apparently wrong emulator context
initialization in the shadow code.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>

Index: 2008-04-15/tools/tests/test_x86_emulator.c
===================================================================
--- 2008-04-15.orig/tools/tests/test_x86_emulator.c     2008-04-01 
11:10:21.000000000 +0200
+++ 2008-04-15/tools/tests/test_x86_emulator.c  2008-04-15 08:48:15.000000000 
+0200
@@ -74,7 +74,7 @@ static int cmpxchg(
     return X86EMUL_OKAY;
 }
 
-static int cmpxchg8b(
+static int cmpxchg2(
     unsigned int seg,
     unsigned long offset,
     unsigned long old_lo,
@@ -94,7 +94,7 @@ static struct x86_emulate_ops emulops = 
     .insn_fetch = read,
     .write      = write,
     .cmpxchg    = cmpxchg,
-    .cmpxchg8b  = cmpxchg8b
+    .cmpxchg2   = cmpxchg2
 };
 
 int main(int argc, char **argv)
Index: 2008-04-15/tools/tests/x86_emulate.c
===================================================================
--- 2008-04-15.orig/tools/tests/x86_emulate.c   2008-04-01 11:10:21.000000000 
+0200
+++ 2008-04-15/tools/tests/x86_emulate.c        2008-04-15 08:48:15.000000000 
+0200
@@ -3,6 +3,8 @@
 #include <string.h>
 #include <public/xen.h>
 
+#define cpu_has_cmpxchg16b (sizeof(long) == 8)
+
 #include "x86_emulate/x86_emulate.h"
 
 #define __emulate_fpu_insn(_op)                 \
Index: 2008-04-15/xen/arch/x86/mm.c
===================================================================
--- 2008-04-15.orig/xen/arch/x86/mm.c   2008-04-11 14:48:16.000000000 +0200
+++ 2008-04-15/xen/arch/x86/mm.c        2008-04-15 08:48:15.000000000 +0200
@@ -3635,6 +3635,7 @@ static int ptwr_emulated_cmpxchg(
         container_of(ctxt, struct ptwr_emulate_ctxt, ctxt));
 }
 
+#ifdef __i386__
 static int ptwr_emulated_cmpxchg8b(
     enum x86_segment seg,
     unsigned long offset,
@@ -3650,13 +3651,16 @@ static int ptwr_emulated_cmpxchg8b(
         offset, ((u64)old_hi << 32) | old, ((u64)new_hi << 32) | new, 8, 1,
         container_of(ctxt, struct ptwr_emulate_ctxt, ctxt));
 }
+#else
+#define ptwr_emulated_cmpxchg8b NULL
+#endif
 
 static struct x86_emulate_ops ptwr_emulate_ops = {
     .read       = ptwr_emulated_read,
     .insn_fetch = ptwr_emulated_read,
     .write      = ptwr_emulated_write,
     .cmpxchg    = ptwr_emulated_cmpxchg,
-    .cmpxchg8b  = ptwr_emulated_cmpxchg8b
+    .cmpxchg2   = ptwr_emulated_cmpxchg8b
 };
 
 /* Write page fault handler: check if guest is trying to modify a PTE. */
Index: 2008-04-15/xen/arch/x86/mm/shadow/common.c
===================================================================
--- 2008-04-15.orig/xen/arch/x86/mm/shadow/common.c     2008-04-11 
14:48:16.000000000 +0200
+++ 2008-04-15/xen/arch/x86/mm/shadow/common.c  2008-04-15 08:48:15.000000000 
+0200
@@ -262,6 +262,7 @@ hvm_emulate_cmpxchg(enum x86_segment seg
         v, addr, old, new, bytes, sh_ctxt);
 }
 
+#ifdef __i386__
 static int 
 hvm_emulate_cmpxchg8b(enum x86_segment seg,
                       unsigned long offset,
@@ -288,13 +289,16 @@ hvm_emulate_cmpxchg8b(enum x86_segment s
     return v->arch.paging.mode->shadow.x86_emulate_cmpxchg8b(
         v, addr, old_lo, old_hi, new_lo, new_hi, sh_ctxt);
 }
+#else
+#define hvm_emulate_cmpxchg8b NULL
+#endif
 
 static struct x86_emulate_ops hvm_shadow_emulator_ops = {
     .read       = hvm_emulate_read,
     .insn_fetch = hvm_emulate_insn_fetch,
     .write      = hvm_emulate_write,
     .cmpxchg    = hvm_emulate_cmpxchg,
-    .cmpxchg8b  = hvm_emulate_cmpxchg8b,
+    .cmpxchg2   = hvm_emulate_cmpxchg8b,
 };
 
 static int
@@ -352,6 +356,7 @@ pv_emulate_cmpxchg(enum x86_segment seg,
         v, offset, old, new, bytes, sh_ctxt);
 }
 
+#ifdef __i386__
 static int 
 pv_emulate_cmpxchg8b(enum x86_segment seg,
                      unsigned long offset,
@@ -369,13 +374,16 @@ pv_emulate_cmpxchg8b(enum x86_segment se
     return v->arch.paging.mode->shadow.x86_emulate_cmpxchg8b(
         v, offset, old_lo, old_hi, new_lo, new_hi, sh_ctxt);
 }
+#else
+#define pv_emulate_cmpxchg8b NULL
+#endif
 
 static struct x86_emulate_ops pv_shadow_emulator_ops = {
     .read       = pv_emulate_read,
     .insn_fetch = pv_emulate_read,
     .write      = pv_emulate_write,
     .cmpxchg    = pv_emulate_cmpxchg,
-    .cmpxchg8b  = pv_emulate_cmpxchg8b,
+    .cmpxchg2   = pv_emulate_cmpxchg8b,
 };
 
 struct x86_emulate_ops *shadow_init_emulation(
@@ -390,7 +398,12 @@ struct x86_emulate_ops *shadow_init_emul
 
     if ( !is_hvm_vcpu(v) )
     {
+#ifndef CONFIG_COMPAT
         sh_ctxt->ctxt.addr_size = sh_ctxt->ctxt.sp_size = BITS_PER_LONG;
+#else
+        sh_ctxt->ctxt.addr_size = sh_ctxt->ctxt.sp_size =
+            !is_pv_32on64_vcpu(v) ? BITS_PER_LONG : COMPAT_BITS_PER_LONG;
+#endif
         return &pv_shadow_emulator_ops;
     }
 
Index: 2008-04-15/xen/arch/x86/mm/shadow/multi.c
===================================================================
--- 2008-04-15.orig/xen/arch/x86/mm/shadow/multi.c      2008-04-01 
14:20:52.000000000 +0200
+++ 2008-04-15/xen/arch/x86/mm/shadow/multi.c   2008-04-15 08:48:15.000000000 
+0200
@@ -4432,7 +4432,8 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, u
     return rv;
 }
 
-int
+#ifdef __i386__
+static int
 sh_x86_emulate_cmpxchg8b(struct vcpu *v, unsigned long vaddr, 
                           unsigned long old_lo, unsigned long old_hi,
                           unsigned long new_lo, unsigned long new_hi,
@@ -4465,6 +4466,7 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v,
     shadow_unlock(v->domain);
     return rv;
 }
+#endif
 
 
 /**************************************************************************/
@@ -4738,7 +4740,9 @@ struct paging_mode sh_paging_mode = {
     .shadow.detach_old_tables      = sh_detach_old_tables,
     .shadow.x86_emulate_write      = sh_x86_emulate_write,
     .shadow.x86_emulate_cmpxchg    = sh_x86_emulate_cmpxchg,
+#ifdef __i386__
     .shadow.x86_emulate_cmpxchg8b  = sh_x86_emulate_cmpxchg8b,
+#endif
     .shadow.make_monitor_table     = sh_make_monitor_table,
     .shadow.destroy_monitor_table  = sh_destroy_monitor_table,
 #if SHADOW_OPTIMIZATIONS & SHOPT_WRITABLE_HEURISTIC
Index: 2008-04-15/xen/arch/x86/x86_emulate/x86_emulate.c
===================================================================
--- 2008-04-15.orig/xen/arch/x86/x86_emulate/x86_emulate.c      2008-04-01 
11:10:21.000000000 +0200
+++ 2008-04-15/xen/arch/x86/x86_emulate/x86_emulate.c   2008-04-15 
08:48:15.000000000 +0200
@@ -3346,60 +3346,64 @@ x86_emulate(
         src.val = x86_seg_gs;
         goto pop_seg;
 
-    case 0xc7: /* Grp9 (cmpxchg8b) */
-#if defined(__i386__)
-    {
-        unsigned long old_lo, old_hi;
+    case 0xc7: /* Grp9 (cmpxchg{8,16}b) */
         generate_exception_if((modrm_reg & 7) != 1, EXC_UD, -1);
         generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
-        if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0, &old_lo, 4, ctxt)) ||
-             (rc = ops->read(ea.mem.seg, ea.mem.off+4, &old_hi, 4, ctxt)) )
-            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 == NULL )
-        {
-            rc = X86EMUL_UNHANDLEABLE;
-            goto done;
-        }
-        else
+#ifdef __x86_64__
+        if ( op_bytes != 8 )
         {
-            if ( (rc = ops->cmpxchg8b(ea.mem.seg, ea.mem.off, old_lo, old_hi,
-                                      _regs.ebx, _regs.ecx, ctxt)) != 0 )
+            unsigned long old, new;
+
+            if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &old, 8, ctxt)) != 0 )
                 goto done;
-            _regs.eflags |= EFLG_ZF;
-        }
-        break;
-    }
-#elif defined(__x86_64__)
-    {
-        unsigned long old, new;
-        generate_exception_if((modrm_reg & 7) != 1, EXC_UD, -1);
-        generate_exception_if(ea.type != OP_MEM, EXC_UD, -1);
-        if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &old, 8, ctxt)) != 0 )
-            goto done;
-        if ( ((uint32_t)(old>>0) != (uint32_t)_regs.eax) ||
-             ((uint32_t)(old>>32) != (uint32_t)_regs.edx) )
-        {
-            _regs.eax = (uint32_t)(old>>0);
-            _regs.edx = (uint32_t)(old>>32);
-            _regs.eflags &= ~EFLG_ZF;
+            if ( ((uint32_t)(old>>0) != (uint32_t)_regs.eax) ||
+                 ((uint32_t)(old>>32) != (uint32_t)_regs.edx) )
+            {
+                _regs.eax = (uint32_t)(old>>0);
+                _regs.edx = (uint32_t)(old>>32);
+                _regs.eflags &= ~EFLG_ZF;
+            }
+            else
+            {
+                new = (_regs.ecx<<32)|(uint32_t)_regs.ebx;
+                if ( (rc = ops->cmpxchg(ea.mem.seg, ea.mem.off, old,
+                                        new, 8, ctxt)) != 0 )
+                    goto done;
+                _regs.eflags |= EFLG_ZF;
+            }
         }
+        else if ( !cpu_has_cmpxchg16b )
+            generate_exception_if(1, EXC_UD, -1);
         else
+#endif
         {
-            new = (_regs.ecx<<32)|(uint32_t)_regs.ebx;
-            if ( (rc = ops->cmpxchg(ea.mem.seg, ea.mem.off, old,
-                                    new, 8, ctxt)) != 0 )
+            unsigned long old_lo, old_hi;
+
+            if ( (rc = ops->read(ea.mem.seg, ea.mem.off,
+                                 &old_lo, sizeof(old_lo), ctxt)) ||
+                 (rc = ops->read(ea.mem.seg, ea.mem.off+sizeof(old_lo),
+                                 &old_hi, sizeof(old_lo), ctxt)) )
+                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->cmpxchg2 == NULL )
+            {
+                rc = X86EMUL_UNHANDLEABLE;
                 goto done;
-            _regs.eflags |= EFLG_ZF;
+            }
+            else
+            {
+                if ( (rc = ops->cmpxchg2(ea.mem.seg, ea.mem.off, old_lo, 
old_hi,
+                                         _regs.ebx, _regs.ecx, ctxt)) != 0 )
+                    goto done;
+                _regs.eflags |= EFLG_ZF;
+            }
         }
         break;
-    }
-#endif
 
     case 0xc8 ... 0xcf: /* bswap */
         dst.type = OP_REG;
@@ -3409,7 +3413,7 @@ x86_emulate(
         {
         default: /* case 2: */
             /* Undefined behaviour. Writes zero on all tested CPUs. */
-            dst.val = 0;
+            __asm__("data16 bswap %k0" : "+r" (dst.val));
             break;
         case 4:
 #ifdef __x86_64__
Index: 2008-04-15/xen/arch/x86/x86_emulate/x86_emulate.h
===================================================================
--- 2008-04-15.orig/xen/arch/x86/x86_emulate/x86_emulate.h      2008-04-01 
11:10:21.000000000 +0200
+++ 2008-04-15/xen/arch/x86/x86_emulate/x86_emulate.h   2008-04-15 
08:48:15.000000000 +0200
@@ -104,8 +104,9 @@ struct segment_register {
  *     some out-of-band mechanism, unknown to the emulator. The memop signals
  *     failure by returning X86EMUL_EXCEPTION to the emulator, which will
  *     then immediately bail.
- *  2. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only
- *     cmpxchg8b_emulated need support 8-byte accesses.
+ *  2. Valid access sizes are 1, 2, 4, 8, and 16 bytes. On x86/32 systems only
+ *     cmpxchg2_emulated need support 8-byte accesses. On x86/64 systems only
+ *     cmpxchg2_emulated need support 16-byte accesses.
  *  3. The emulator cannot handle 64-bit mode emulation on an x86/32 system.
  */
 struct x86_emulate_ops
@@ -165,16 +166,17 @@ struct x86_emulate_ops
         struct x86_emulate_ctxt *ctxt);
 
     /*
-     * cmpxchg8b: Emulate an atomic (LOCKed) CMPXCHG8B operation.
+     * cmpxchg2: Emulate an atomic (LOCKed) CMPXCHG{8,16}B operation.
      *  @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
+     *  1. This function is only ever called when emulating a real 
CMPXCHG{8,16}B.
+     *  2. This function is *never* called on x86/64 systems for emulating
+     *     CMPXCHG8B.
+     *  3. Not defining this function (i.e., specifying NULL) is equivalent
      *     to defining a function that always returns X86EMUL_UNHANDLEABLE.
      */
-    int (*cmpxchg8b)(
+    int (*cmpxchg2)(
         enum x86_segment seg,
         unsigned long offset,
         unsigned long old_lo,
Index: 2008-04-15/xen/arch/x86/x86_emulate.c
===================================================================
--- 2008-04-15.orig/xen/arch/x86/x86_emulate.c  2008-04-01 14:20:52.000000000 
+0200
+++ 2008-04-15/xen/arch/x86/x86_emulate.c       2008-04-15 08:48:15.000000000 
+0200
@@ -12,6 +12,8 @@
 #include <asm/x86_emulate.h>
 
 #undef cmpxchg
+#undef cpuid
+#undef wbinvd
 
 #define __emulate_fpu_insn(_op)                 \
 do{ int _exn;                                   \
Index: 2008-04-15/xen/include/asm-x86/cpufeature.h
===================================================================
--- 2008-04-15.orig/xen/include/asm-x86/cpufeature.h    2008-04-01 
14:20:52.000000000 +0200
+++ 2008-04-15/xen/include/asm-x86/cpufeature.h 2008-04-15 08:48:15.000000000 
+0200
@@ -149,6 +149,7 @@
 #define cpu_has_cyrix_arr      boot_cpu_has(X86_FEATURE_CYRIX_ARR)
 #define cpu_has_centaur_mcr    boot_cpu_has(X86_FEATURE_CENTAUR_MCR)
 #define cpu_has_clflush                boot_cpu_has(X86_FEATURE_CLFLSH)
+#define cpu_has_cmpxchg16b     0
 #define cpu_has_page1gb                0
 #define cpu_has_efer           (boot_cpu_data.x86_capability[1] & 0x20100800)
 #else /* __x86_64__ */
@@ -175,6 +176,7 @@
 #define cpu_has_cyrix_arr      0
 #define cpu_has_centaur_mcr    0
 #define cpu_has_clflush                boot_cpu_has(X86_FEATURE_CLFLSH)
+#define cpu_has_cmpxchg16b     boot_cpu_has(X86_FEATURE_CX16)
 #define cpu_has_page1gb                boot_cpu_has(X86_FEATURE_PAGE1GB)
 #define cpu_has_efer           1
 #endif
Index: 2008-04-15/xen/include/asm-x86/paging.h
===================================================================
--- 2008-04-15.orig/xen/include/asm-x86/paging.h        2008-04-11 
14:48:16.000000000 +0200
+++ 2008-04-15/xen/include/asm-x86/paging.h     2008-04-15 08:48:15.000000000 
+0200
@@ -83,12 +83,14 @@ struct shadow_paging_mode {
                                             unsigned long new,
                                             unsigned int bytes,
                                             struct sh_emulate_ctxt *sh_ctxt);
+#ifdef __i386__
     int           (*x86_emulate_cmpxchg8b )(struct vcpu *v, unsigned long va,
                                             unsigned long old_lo, 
                                             unsigned long old_hi, 
                                             unsigned long new_lo,
                                             unsigned long new_hi,
                                             struct sh_emulate_ctxt *sh_ctxt);
+#endif
     mfn_t         (*make_monitor_table    )(struct vcpu *v);
     void          (*destroy_monitor_table )(struct vcpu *v, mfn_t mmfn);
     int           (*guess_wrmap           )(struct vcpu *v, 
Index: 2008-04-15/xen/include/asm-x86/x86_emulate.h
===================================================================
--- 2008-04-15.orig/xen/include/asm-x86/x86_emulate.h   2008-04-01 
14:20:52.000000000 +0200
+++ 2008-04-15/xen/include/asm-x86/x86_emulate.h        2008-04-15 
08:48:15.000000000 +0200
@@ -16,6 +16,7 @@
 #include <xen/types.h>
 #include <xen/lib.h>
 #include <asm/regs.h>
+#include <asm/processor.h>
 
 #include "../../arch/x86/x86_emulate/x86_emulate.h"
 



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

<Prev in Thread] Current Thread [Next in Thread>