|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 24/30] x86emul: support APX+{LZ,POP}CNT insns
Besides adding table entries and case labels there's very little to do
here; generic map 4 handling takes care of things.
To aid making the connection between ABM and LZCNT (the sole insn the
feature bit covers), amend the comment in cpufeatures.h at the same
time.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -1154,6 +1154,16 @@ static const struct test bmi2[] = {
INSN(shrx, f2, 0f38, f7, el, dq, no),
};
+static const struct test lzcnt[] = {
+ INSN(lzcnt, , map4, f5, el, dq, no),
+ INSN(lzcntw, 66, map4, f5, el, w, no),
+};
+
+static const struct test popcnt[] = {
+ INSN(popcnt, , map4, 88, el, dq, no),
+ INSN(popcntw, 66, map4, 88, el, w, no),
+};
+
static const unsigned char vl_all[] = { VL_512, VL_128, VL_256 };
static const unsigned char vl_128[] = { VL_128 };
static const unsigned char vl_no128[] = { VL_512, VL_256 };
@@ -1745,6 +1755,8 @@ void evex_disp8_test(void *instr, struct
RUN(bmi1);
RUN(bmi2);
RUN(cmpccxadd);
+ RUN(lzcnt);
+ RUN(popcnt);
#undef RUN
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -2260,6 +2260,8 @@ static const struct evex {
{ { 0x84 }, 2, T, R, pfx_no, WIG, L0, SCC }, /* ctest<scc> */
{ { 0x85 }, 2, T, R, pfx_no, Wn, L0, SCC }, /* ctest<scc> */
{ { 0x85 }, 2, T, R, pfx_66, Wn, L0, SCC }, /* ctest<scc> */
+ { { 0x88 }, 2, T, R, pfx_no, Wn, L0 }, /* popcnt */
+ { { 0x88 }, 2, T, R, pfx_66, Wn, L0 }, /* popcnt */
{ { 0x8f, 0xc0 }, 2, F, R, pfx_no, Wn, L0, ND }, /* pop2 */
{ { 0xa5 }, 2, T, W, pfx_no, Wn, L0, ND }, /* shld */
{ { 0xa5 }, 2, T, W, pfx_66, Wn, L0, ND }, /* shld */
@@ -2344,6 +2346,8 @@ static const struct evex {
{ { 0xf1 }, 2, T, R, pfx_66, Wn, L0 }, /* crc32 */
{ { 0xf4 }, 2, T, R, pfx_no, Wn, L0 }, /* tzcnt */
{ { 0xf4 }, 2, T, R, pfx_66, Wn, L0 }, /* tzcnt */
+ { { 0xf5 }, 2, T, R, pfx_no, Wn, L0 }, /* lzcnt */
+ { { 0xf5 }, 2, T, R, pfx_66, Wn, L0 }, /* lzcnt */
{ { 0xf6, 0x00 }, 3, T, R, pfx_no, WIG, L0, SCC }, /* ctest<scc> */
{ { 0xf6, 0x10 }, 2, T, W, pfx_no, WIG, L0, ND }, /* not */
{ { 0xf6, 0x18 }, 2, T, W, pfx_no, WIG, L0, ND }, /* neg */
--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -2516,6 +2516,26 @@ int main(int argc, char **argv)
(regs.eip != (unsigned long)&instr[5]) )
goto fail;
printf("okay\n");
+
+ if ( true /* cpu_has_apx_nci_ndd_nf */ )
+ {
+ cpu_policy.apx.apx_nci_ndd_nf = true;
+
+ printf("%-40s", "Testing {nf}popcnt (%rdx),%rcx...");
+ instr[0] = 0x62; instr[1] = 0xf4; instr[2] = 0xfc; instr[3] = 0x0c;
+ instr[4] = 0x88; instr[5] = 0x0a;
+ res[1] = 0x23456789;
+ regs.eflags = EFLAGS_MASK;
+ regs.rip = (unsigned long)&instr[0];
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) || regs.rcx != 34 ||
+ (regs.eflags != EFLAGS_MASK) ||
+ (regs.rip != (unsigned long)&instr[6]) )
+ goto fail;
+ printf("okay\n");
+
+ cpu_policy.apx.apx_nci_ndd_nf = nci_ndd_nf;
+ }
#endif
}
else
--- a/tools/tests/x86_emulator/x86-emulate.h
+++ b/tools/tests/x86_emulator/x86-emulate.h
@@ -234,6 +234,7 @@ void wrpkru(unsigned int val);
#define cpu_has_xgetbv1 (cpu_has_xsave &&
cpu_policy.xstate.xgetbv1)
#define cpu_has_3dnow_ext cpu_policy.extd._3dnowext
+#define cpu_has_lzcnt cpu_policy.extd.abm
#define cpu_has_sse4a cpu_policy.extd.sse4a
#define cpu_has_xop (cpu_policy.extd.xop && xcr0_mask(6))
#define cpu_has_fma4 (cpu_policy.extd.fma4 && xcr0_mask(6))
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -730,6 +730,10 @@ static const struct map4_table {
[vex_np] = { },
[vex_66] = { },
},
+ [0x88] = { /* POPCNT ({,d,q}word) */
+ [vex_np] = { .nf = true, .nci_ndd_nf = true },
+ [vex_66] = { .nf = true, .nci_ndd_nf = true },
+ },
[0x8f] = { /* Grp1a */
[vex_np] = { .nd = true },
},
@@ -792,6 +796,10 @@ static const struct map4_table {
[vex_np] = { .nf = true, .nci_ndd_nf = true },
[vex_66] = { .nf = true, .nci_ndd_nf = true },
},
+ [0xf5] = { /* LZCNT ({,d,q}word) */
+ [vex_np] = { .nf = true, .nci_ndd_nf = true },
+ [vex_66] = { .nf = true, .nci_ndd_nf = true },
+ },
[0xf6] = { /* Grp3 (byte); most attributes depend on modrm_reg */
[vex_np] = { .byte = true, .nci_ndd_nf = true },
},
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -5668,7 +5668,9 @@ x86_emulate(
dst.val = (uint16_t)src.val;
break;
- case X86EMUL_OPC_F3(0x0f, 0xb8): /* popcnt r/m,r */
+ case X86EMUL_OPC_F3 (0x0f, 0xb8): /* popcnt r/m,r */
+ case X86EMUL_OPC_EVEX (4, 0x88): /* popcnt r/m,reg */
+ case X86EMUL_OPC_EVEX_66(4, 0x88): /* popcnt r/m,r16 */
vcpu_must_have(popcnt);
asm ( "popcnt %1,%0" : "=r" (dst.val) : "rm" (src.val) );
_regs.eflags &= ~EFLAGS_MASK;
@@ -5709,8 +5711,12 @@ x86_emulate(
}
break;
+ case X86EMUL_OPC_EVEX (4, 0xf5): /* lzcnt r/m,reg */
+ case X86EMUL_OPC_EVEX_66(4, 0xf5): /* lzcnt r/m,r16 */
+ vcpu_must_have(lzcnt);
+ fallthrough;
case X86EMUL_OPC(0x0f, 0xbd): /* bsr or lzcnt */
- if ( vex.pfx == vex_f3 )
+ if ( vex.pfx == vex_f3 || state->promoted_evex )
emulate_2op_SrcV_srcmem("lzcnt", src, dst, _regs.eflags);
else
{
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -159,7 +159,7 @@ XEN_CPUFEATURE(CMP_LEGACY, 3*32+ 1) /
XEN_CPUFEATURE(SVM, 3*32+ 2) /*h Secure virtual machine */
XEN_CPUFEATURE(EXTAPIC, 3*32+ 3) /* Extended APIC space */
XEN_CPUFEATURE(CR8_LEGACY, 3*32+ 4) /*S CR8 in 32-bit mode */
-XEN_CPUFEATURE(ABM, 3*32+ 5) /*A Advanced bit manipulation */
+XEN_CPUFEATURE(ABM, 3*32+ 5) /*A LZCNT insn (Advanced Bit
Manipulation) */
XEN_CPUFEATURE(SSE4A, 3*32+ 6) /*A SSE-4A */
XEN_CPUFEATURE(MISALIGNSSE, 3*32+ 7) /*A Misaligned SSE mode */
XEN_CPUFEATURE(3DNOWPREFETCH, 3*32+ 8) /*A 3DNow prefetch instructions */
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |