mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
x86emul: support BMI1 insns
Signed-off-by: Jan Beulich <jbeulich@suse.com> Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
1 parent
12ec20c732
commit
771daacd19
4 files changed
+212
No files matched your search
@@ -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[] = {
|
||||
|
||||
@@ -113,6 +113,12 @@ static inline uint64_t xgetbv(uint32_t xcr)
|
||||
(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,
|
||||
|
||||
@@ -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; \
|
||||
@@ -1687,6 +1697,12 @@ decode_register(
|
||||
return p;
|
||||
}
|
||||
|
||||
static void *decode_vex_gpr(unsigned int vex_reg, struct cpu_user_regs *regs,
|
||||
const struct x86_emulate_ctxt *ctxt)
|
||||
{
|
||||
return decode_register(~vex_reg & (mode_64bit() ? 0xf : 7), regs, 0);
|
||||
}
|
||||
|
||||
static bool is_aligned(enum x86_segment seg, unsigned long offs,
|
||||
unsigned int size, struct x86_emulate_ctxt *ctxt,
|
||||
const struct x86_emulate_ops *ops)
|
||||
@@ -2320,7 +2336,10 @@ x86_decode(
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(op_bytes == 4);
|
||||
vex.b = 1;
|
||||
}
|
||||
switch ( b )
|
||||
{
|
||||
case 0x62:
|
||||
@@ -5877,6 +5896,65 @@ 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_vex_gpr(vex.reg, &_regs, ctxt);
|
||||
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_vex_gpr(vex.reg, &_regs, ctxt);
|
||||
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 */
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||