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

[Xen-devel] [PATCH 1/8] x86emul: support POPCNT



Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
TBD: Alternative code needed for binutils < 2.18?

--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -684,6 +684,52 @@ int main(int argc, char **argv)
         goto fail;
     printf("okay\n");
 
+    printf("%-40s", "Testing popcnt (%edx),%cx...");
+    if ( cpu_has_popcnt )
+    {
+        instr[0] = 0x66; instr[1] = 0xf3;
+        instr[2] = 0x0f; instr[3] = 0xb8; instr[4] = 0x0a;
+
+        *res        = 0xfedcba98;
+        regs.edx    = (unsigned long)res;
+        regs.eflags = 0xac3;
+        regs.eip    = (unsigned long)&instr[0];
+        rc = x86_emulate(&ctxt, &emulops);
+        if ( (rc != X86EMUL_OKAY) || (uint16_t)regs.ecx != 8 || *res != 
0xfedcba98 ||
+             (regs.eflags & 0xfeb) != 0x202 ||
+             (regs.eip != (unsigned long)&instr[5]) )
+            goto fail;
+        printf("okay\n");
+
+        printf("%-40s", "Testing popcnt (%edx),%ecx...");
+        regs.eflags = 0xac3;
+        regs.eip    = (unsigned long)&instr[1];
+        rc = x86_emulate(&ctxt, &emulops);
+        if ( (rc != X86EMUL_OKAY) || regs.ecx != 20 || *res != 0xfedcba98 ||
+             (regs.eflags & 0xfeb) != 0x202 ||
+             (regs.eip != (unsigned long)&instr[5]) )
+            goto fail;
+        printf("okay\n");
+
+#ifdef __x86_64__
+        printf("%-40s", "Testing popcnt (%rdx),%rcx...");
+        instr[0]    = 0xf3;
+        instr[1]    = 0x48;
+        res[1]      = 0x12345678;
+        regs.eflags = 0xac3;
+        regs.eip    = (unsigned long)&instr[0];
+        rc = x86_emulate(&ctxt, &emulops);
+        if ( (rc != X86EMUL_OKAY) || regs.ecx != 33 ||
+             res[0] != 0xfedcba98 || res[1] != 0x12345678 ||
+             (regs.eflags & 0xfeb) != 0x202 ||
+             (regs.eip != (unsigned long)&instr[5]) )
+            goto fail;
+        printf("okay\n");
+#endif
+    }
+    else
+        printf("skipped\n");
+
     printf("%-40s", "Testing lar (null selector)...");
     instr[0] = 0x0f; instr[1] = 0x02; instr[2] = 0xc1;
     regs.eflags = 0x240;
--- a/tools/tests/x86_emulator/x86_emulate.h
+++ b/tools/tests/x86_emulator/x86_emulate.h
@@ -81,6 +81,12 @@ static inline uint64_t xgetbv(uint32_t x
     (res.d & (1U << 26)) != 0; \
 })
 
+#define cpu_has_popcnt ({ \
+    struct cpuid_leaf res; \
+    emul_test_cpuid(1, 0, &res, NULL); \
+    (res.c & (1U << 23)) != 0; \
+})
+
 #define cpu_has_xsave ({ \
     struct cpuid_leaf res; \
     emul_test_cpuid(1, 0, &res, NULL); \
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -1335,6 +1335,7 @@ static bool vcpu_has(
 #define vcpu_has_cx16()        vcpu_has(         1, ECX, 13, ctxt, ops)
 #define vcpu_has_sse4_2()      vcpu_has(         1, ECX, 20, ctxt, ops)
 #define vcpu_has_movbe()       vcpu_has(         1, ECX, 22, ctxt, ops)
+#define vcpu_has_popcnt()      vcpu_has(         1, ECX, 23, ctxt, ops)
 #define vcpu_has_avx()         vcpu_has(         1, ECX, 28, ctxt, ops)
 #define vcpu_has_lahf_lm()     vcpu_has(0x80000001, ECX,  0, ctxt, ops)
 #define vcpu_has_cr8_legacy()  vcpu_has(0x80000001, ECX,  4, ctxt, ops)
@@ -2078,8 +2079,12 @@ x86_decode_twobyte(
         op_bytes = mode_64bit() ? 8 : 4;
         break;
 
+    case 0xb8: /* jmpe / popcnt */
+        if ( rep_prefix() )
+            ctxt->opcode |= MASK_INSR(vex.pfx, X86EMUL_OPC_PFX_MASK);
+        break;
+
         /* Intentionally not handling here despite being modified by F3:
-    case 0xb8: jmpe / popcnt
     case 0xbc: bsf / tzcnt
     case 0xbd: bsr / lzcnt
          * They're being dealt with in the execution phase (if at all).
@@ -5603,6 +5608,14 @@ x86_emulate(
         dst.val = (uint16_t)src.val;
         break;
 
+    case X86EMUL_OPC_F3(0x0f, 0xb8): /* popcnt r/m,r */
+        host_and_vcpu_must_have(popcnt);
+        asm ( "popcnt %1,%0" : "=r" (dst.val) : "rm" (src.val) );
+        _regs._eflags &= ~EFLAGS_MASK;
+        if ( !dst.val )
+            _regs._eflags |= EFLG_ZF;
+        break;
+
     case X86EMUL_OPC(0x0f, 0xba): /* Grp8 */
         switch ( modrm_reg & 7 )
         {
--- a/xen/include/asm-x86/cpufeature.h
+++ b/xen/include/asm-x86/cpufeature.h
@@ -40,6 +40,7 @@
 #define cpu_has_mmx            1
 #define cpu_has_sse3           boot_cpu_has(X86_FEATURE_SSE3)
 #define cpu_has_sse4_2         boot_cpu_has(X86_FEATURE_SSE4_2)
+#define cpu_has_popcnt         boot_cpu_has(X86_FEATURE_POPCNT)
 #define cpu_has_htt            boot_cpu_has(X86_FEATURE_HTT)
 #define cpu_has_nx             boot_cpu_has(X86_FEATURE_NX)
 #define cpu_has_clflush                boot_cpu_has(X86_FEATURE_CLFLUSH)


Attachment: x86emul-POPCNT.patch
Description: Text document

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

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