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

[Xen-devel] [PATCH 3/8] x86emul: support BMI1 insns



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

--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -892,6 +892,133 @@ int main(int argc, char **argv)
 #define check_eip(which) (regs.eip == (unsigned long)(which) + \
                                       (unsigned long)which##_len)
 
+    printf("%-40s", "Testing andn (%edx),%ecx,%ebx...");
+    if ( stack_exec && cpu_has_bmi1 )
+    {
+        decl_insn(andn);
+
+        asm volatile ( put_insn(andn, "andn (%0), %%ecx, %%ebx")
+                       :: "d" (NULL) );
+        set_insn(andn);
+
+        *res        = 0xfedcba98;
+        regs.ecx    = 0xcccc3333;
+        regs.edx    = (unsigned long)res;
+        regs.eflags = 0xac3;
+        rc = x86_emulate(&ctxt, &emulops);
+        if ( (rc != X86EMUL_OKAY) || regs.ebx != 0x32108888 ||
+             regs.ecx != 0xcccc3333 || *res != 0xfedcba98 ||
+             (regs.eflags & 0xfeb) != 0x202 || !check_eip(andn) )
+            goto fail;
+        printf("okay\n");
+    }
+    else
+        printf("skipped\n");
+
+    printf("%-40s", "Testing bextr %edx,(%ecx),%ebx...");
+    if ( stack_exec && cpu_has_bmi1 )
+    {
+        decl_insn(bextr);
+#ifdef __x86_64__
+        decl_insn(bextr64);
+#endif
+
+        asm volatile ( put_insn(bextr, "bextr %%edx, (%0), %%ebx")
+                       :: "c" (NULL) );
+        set_insn(bextr);
+
+        regs.ecx    = (unsigned long)res;
+        regs.edx    = 0x0a03;
+        regs.eflags = 0xa43;
+        rc = x86_emulate(&ctxt, &emulops);
+        if ( (rc != X86EMUL_OKAY) || regs.ebx != ((*res >> 3) & 0x3ff) ||
+             regs.edx != 0x0a03 || *res != 0xfedcba98 ||
+             (regs.eflags & 0xf6b) != 0x202 || !check_eip(bextr) )
+            goto fail;
+        printf("okay\n");
+#ifdef __x86_64__
+        printf("%-40s", "Testing bextr %r9,(%r10),%r11...");
+
+        asm volatile ( put_insn(bextr64, "bextr %r9, (%r10), %r11") );
+        set_insn(bextr64);
+
+        res[0]      = 0x76543210;
+        res[1]      = 0xfedcba98;
+        regs.r10    = (unsigned long)res;
+        regs.r9     = 0x211e;
+        regs.eflags = 0xa43;
+        rc = x86_emulate(&ctxt, &emulops);
+        if ( (rc != X86EMUL_OKAY) || regs.r9 != 0x211e ||
+             regs.r11 != (((unsigned long)(res[1] << 1) << 1) |
+                          (res[0] >> 30)) ||
+             res[0] != 0x76543210 || res[1] != 0xfedcba98 ||
+             (regs.eflags & 0xf6b) != 0x202 || !check_eip(bextr64) )
+            goto fail;
+        printf("okay\n");
+#endif
+    }
+    else
+        printf("skipped\n");
+
+    printf("%-40s", "Testing blsi (%edx),%ecx...");
+    if ( stack_exec && cpu_has_bmi1 )
+    {
+        decl_insn(blsi);
+
+        asm volatile ( put_insn(blsi, "blsi (%0), %%ecx")
+                       :: "d" (NULL) );
+        set_insn(blsi);
+
+        *res        = 0xfedcba98;
+        regs.edx    = (unsigned long)res;
+        regs.eflags = 0xac2;
+        rc = x86_emulate(&ctxt, &emulops);
+        if ( (rc != X86EMUL_OKAY) || regs.ecx != 8 || *res != 0xfedcba98 ||
+             (regs.eflags & 0xf6b) != 0x203 || !check_eip(blsi) )
+            goto fail;
+        printf("okay\n");
+    }
+    else
+        printf("skipped\n");
+
+    printf("%-40s", "Testing blsmsk (%edx),%ecx...");
+    if ( stack_exec && cpu_has_bmi1 )
+    {
+        decl_insn(blsmsk);
+
+        asm volatile ( put_insn(blsmsk, "blsmsk (%0), %%ecx")
+                       :: "d" (NULL) );
+        set_insn(blsmsk);
+
+        regs.eflags = 0xac3;
+        rc = x86_emulate(&ctxt, &emulops);
+        if ( (rc != X86EMUL_OKAY) || regs.ecx != 0xf || *res != 0xfedcba98 ||
+             (regs.eflags & 0xf6b) != 0x202 || !check_eip(blsmsk) )
+            goto fail;
+        printf("okay\n");
+    }
+    else
+        printf("skipped\n");
+
+    printf("%-40s", "Testing blsr (%edx),%ecx...");
+    if ( stack_exec && cpu_has_bmi1 )
+    {
+        decl_insn(blsr);
+
+        asm volatile ( put_insn(blsr, "blsr (%0), %%ecx")
+                       :: "d" (NULL) );
+        set_insn(blsr);
+
+        regs.eflags = 0xac3;
+        rc = x86_emulate(&ctxt, &emulops);
+        if ( (rc != X86EMUL_OKAY) || regs.ecx != 0xfedcba90 ||
+             (regs.eflags & 0xf6b) != 0x202 || !check_eip(blsr) )
+            goto fail;
+        printf("okay\n");
+    }
+    else
+        printf("skipped\n");
+
     printf("%-40s", "Testing adcx/adox ...");
     {
         static const unsigned int data[] = {
--- a/tools/tests/x86_emulator/x86_emulate.h
+++ b/tools/tests/x86_emulator/x86_emulate.h
@@ -113,6 +113,12 @@ static inline uint64_t xgetbv(uint32_t x
     (res.b & (1U << 5)) != 0; \
 })
 
+#define cpu_has_bmi1 ({ \
+    struct cpuid_leaf res; \
+    emul_test_cpuid(7, 0, &res, NULL); \
+    (res.b & (1U << 3)) != 0; \
+})
+
 int emul_test_cpuid(
     uint32_t leaf,
     uint32_t subleaf,
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -676,6 +676,16 @@ do{ asm volatile (
 #define __emulate_1op_8byte(_op, _dst, _eflags)
 #endif /* __i386__ */
 
+#define emulate_stub(dst, src...) do {                                  \
+    unsigned long tmp;                                                  \
+    asm volatile ( _PRE_EFLAGS("[efl]", "[msk]", "[tmp]")               \
+                   "call *%[stub];"                                     \
+                   _POST_EFLAGS("[efl]", "[msk]", "[tmp]")              \
+                   : dst, [tmp] "=&r" (tmp), [efl] "+g" (_regs._eflags) \
+                   : [stub] "r" (stub.func),                            \
+                     [msk] "i" (EFLAGS_MASK), ## src );                 \
+} while (0)
+
 /* Fetch next part of the instruction being emulated. */
 #define insn_fetch_bytes(_size)                                         \
 ({ unsigned long _x = 0, _ip = state->ip;                               \
@@ -2295,7 +2305,10 @@ x86_decode(
                         }
                     }
                     else
+                    {
+                        ASSERT(op_bytes == 4);
                         vex.b = 1;
+                    }
                     switch ( b )
                     {
                     case 0x62:
@@ -5866,6 +5879,67 @@ x86_emulate(
         break;
 #endif
 
+    case X86EMUL_OPC_VEX(0x0f38, 0xf2):    /* andn r/m,r,r */
+    case X86EMUL_OPC_VEX(0x0f38, 0xf7):    /* bextr r,r/m,r */
+    {
+        uint8_t *buf = get_stub(stub);
+        typeof(vex) *pvex = container_of(buf + 1, typeof(vex), raw[0]);
+
+        host_and_vcpu_must_have(bmi1);
+        generate_exception_if(vex.l, EXC_UD);
+
+        buf[0] = 0xc4;
+        *pvex = vex;
+        pvex->b = 1;
+        pvex->r = 1;
+        pvex->reg = ~0; /* rAX */
+        buf[3] = b;
+        buf[4] = 0x09; /* reg=rCX r/m=(%rCX) */
+        buf[5] = 0xc3;
+
+        src.reg = decode_register(~vex.reg & (mode_64bit() ? 0xf : 7),
+                                  &_regs, 0);
+        emulate_stub([dst] "=&c" (dst.val), "[dst]" (&src.val), "a" 
(*src.reg));
+
+        put_stub(stub);
+        break;
+    }
+
+    case X86EMUL_OPC_VEX(0x0f38, 0xf3): /* Grp 17 */
+    {
+        uint8_t *buf = get_stub(stub);
+        typeof(vex) *pvex = container_of(buf + 1, typeof(vex), raw[0]);
+
+        switch ( modrm_reg & 7 )
+        {
+        case 1: /* blsr r,r/m */
+        case 2: /* blsmsk r,r/m */
+        case 3: /* blsi r,r/m */
+            host_and_vcpu_must_have(bmi1);
+            break;
+        default:
+            goto cannot_emulate;
+        }
+
+        generate_exception_if(vex.l, EXC_UD);
+
+        buf[0] = 0xc4;
+        *pvex = vex;
+        pvex->b = 1;
+        pvex->r = 1;
+        pvex->reg = ~0; /* rAX */
+        buf[3] = b;
+        buf[4] = (modrm & 0x38) | 0x01; /* r/m=(%rCX) */
+        buf[5] = 0xc3;
+
+        dst.reg = decode_register(~vex.reg & (mode_64bit() ? 0xf : 7),
+                                  &_regs, 0);
+        emulate_stub("=&a" (dst.val), "c" (&src.val));
+
+        put_stub(stub);
+        break;
+    }
+
     case X86EMUL_OPC_66(0x0f38, 0xf6): /* adcx r/m,r */
     case X86EMUL_OPC_F3(0x0f38, 0xf6): /* adox r/m,r */
     {
--- a/xen/include/asm-x86/cpufeature.h
+++ b/xen/include/asm-x86/cpufeature.h
@@ -57,6 +57,7 @@
 #define cpu_has_xsave           boot_cpu_has(X86_FEATURE_XSAVE)
 #define cpu_has_avx             boot_cpu_has(X86_FEATURE_AVX)
 #define cpu_has_lwp             boot_cpu_has(X86_FEATURE_LWP)
+#define cpu_has_bmi1            boot_cpu_has(X86_FEATURE_BMI1)
 #define cpu_has_mpx             boot_cpu_has(X86_FEATURE_MPX)
 #define cpu_has_arch_perfmon    boot_cpu_has(X86_FEATURE_ARCH_PERFMON)
 #define cpu_has_rdtscp          boot_cpu_has(X86_FEATURE_RDTSCP)


Attachment: x86emul-BMI1.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®.