|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 22/30] x86emul: support APX+BMI2 insns
These promoted-from-VEX insns are again handled by transforming them to
their VEX counterparts, re-using (where possible) logic already used for
BMI1. As before common EVEX.NF handling takes care of the EFLAGS aspect.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
--- a/tools/tests/x86_emulator/evex-disp8.c
+++ b/tools/tests/x86_emulator/evex-disp8.c
@@ -1136,6 +1136,17 @@ static const struct test bmi1[] = {
INSN(tzcntw, 66, map4, f4, el, w, no),
};
+static const struct test bmi2[] = {
+ INSN(bzhi, , 0f38, f5, el, dq, no),
+ INSN(mulx, f2, 0f38, f6, el, dq, no),
+ INSN(pdep, f2, 0f38, f5, el, dq, no),
+ INSN(pext, f3, 0f38, f5, el, dq, no),
+ INSN(rorx, f2, 0f3a, f0, el, dq, no),
+ INSN(sarx, f3, 0f38, f7, el, dq, no),
+ INSN(shlx, 66, 0f38, f7, el, dq, no),
+ INSN(shrx, f2, 0f38, f7, el, dq, 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 };
@@ -1725,6 +1736,7 @@ void evex_disp8_test(void *instr, struct
RUN(avx512dq);
RUN(avx512bw);
RUN(bmi1);
+ RUN(bmi2);
#undef RUN
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -2071,7 +2071,14 @@ static const struct evex {
{ { 0xf3, 0x08 }, 2, T, R, pfx_no, Wn, L0 }, /* blsr */
{ { 0xf3, 0x10 }, 2, T, R, pfx_no, Wn, L0 }, /* blsmsk */
{ { 0xf3, 0x18 }, 2, T, R, pfx_no, Wn, L0 }, /* blsi */
+ { { 0xf5 }, 2, T, R, pfx_no, Wn, L0 }, /* bzhi */
+ { { 0xf5 }, 2, T, R, pfx_f3, Wn, L0 }, /* pext */
+ { { 0xf5 }, 2, T, R, pfx_f2, Wn, L0 }, /* pdep */
+ { { 0xf6 }, 2, T, R, pfx_f2, Wn, L0 }, /* mulx */
{ { 0xf7 }, 2, T, R, pfx_no, Wn, L0 }, /* bextr */
+ { { 0xf7 }, 2, T, R, pfx_66, Wn, L0 }, /* shlx */
+ { { 0xf7 }, 2, T, R, pfx_f3, Wn, L0 }, /* sarx */
+ { { 0xf7 }, 2, T, R, pfx_f2, Wn, L0 }, /* shrx */
#endif
}, evex_0f3a[] = {
{ { 0x00 }, 3, T, R, pfx_66, W1, L1|L2 }, /* vpermq */
@@ -2147,6 +2154,9 @@ static const struct evex {
{ { 0xc2 }, 3, T, R, pfx_f2, W0, Ln }, /* vcmpbf16 */
{ { 0xce }, 3, T, R, pfx_66, W1, Ln }, /* vgf2p8affineqb */
{ { 0xcf }, 3, T, R, pfx_66, W1, Ln }, /* vgf2p8affineinvqb */
+#ifdef __x86_64__
+ { { 0xf0 }, 3, T, R, pfx_f2, Wn, L0 }, /* rorx */
+#endif
}, evex_map4[] = {
#ifdef __x86_64__
#define ND .nd = true
--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -2970,6 +2970,34 @@ int main(int argc, char **argv)
!check_eip(bzhi) )
goto fail;
printf("okay\n");
+
+#if defined(__x86_64__) && \
+ (defined(__clang__) ? __clang_major__ >= 18 : __GNUC__ >= 14)
+ if ( true /* cpu_has_apx_nci_ndd_nf */ )
+ {
+ decl_insn(bzhi_apx);
+
+ cpu_policy.apx.apx_nci_ndd_nf = true;
+
+ printf("%-40s", "Testing {nf}bzhi %edx,(%rcx),%ebx...");
+
+ asm volatile ( put_insn(bzhi_apx, "%{nf%} bzhi %%edx, (%0), %%ebx")
+ :: "c" (NULL) );
+ set_insn(bzhi_apx);
+
+ regs.rbx = 0;
+ regs.eflags = EFLAGS_ALWAYS_SET | X86_EFLAGS(OF, SF, ZF, CF);
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) || (regs.rbx != (*res & 0x7ffff)) ||
+ (regs.eflags !=
+ (EFLAGS_ALWAYS_SET | X86_EFLAGS(OF, SF, ZF, CF))) ||
+ !check_eip(bzhi_apx) )
+ goto fail;
+ printf("okay\n");
+
+ cpu_policy.apx.apx_nci_ndd_nf = nci_ndd_nf;
+ }
+#endif
}
else
printf("skipped\n");
@@ -2992,6 +3020,28 @@ int main(int argc, char **argv)
regs.eflags != 0xac3 || !check_eip(mulx) )
goto fail;
printf("okay\n");
+
+#if defined(__x86_64__) && \
+ (defined(__clang__) ? __clang_major__ >= 18 : __GNUC__ >= 14)
+ if ( cpu_has_apx_f )
+ {
+ decl_insn(mulx_apx);
+
+ printf("%-40s", "Testing mulx (%rax),%r25,%rbx...");
+
+ asm volatile ( put_insn(mulx_apx, "mulx (%0), %%r25, %%rbx")
+ :: "a" (NULL) );
+ set_insn(mulx_apx);
+
+ res[1] = 0;
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) || regs.rbx ||
+ !check_egpr(25, 0x121fa00a35068740UL) ||
+ !check_eip(mulx_apx) )
+ goto fail;
+ printf("okay\n");
+ }
+#endif
}
else
printf("skipped\n");
@@ -3014,6 +3064,28 @@ int main(int argc, char **argv)
regs.eflags != 0xa43 || !check_eip(pdep) )
goto fail;
printf("okay\n");
+
+#if defined(__x86_64__) && \
+ (defined(__clang__) ? __clang_major__ >= 18 : __GNUC__ >= 14)
+ if ( cpu_has_apx_f )
+ {
+ decl_insn(pdep_apx);
+
+ printf("%-40s", "Testing pdep (%rdx),%ecx,%r19d...");
+
+ asm volatile ( put_insn(pdep_apx, "pdep (%0), %%ecx, %%r19d")
+ :: "d" (NULL) );
+ set_insn(pdep_apx);
+
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) ||
+ !check_egpr(19, 0x850b298) ||
+ (regs.ecx != 0x8cef) ||
+ !check_eip(pdep_apx) )
+ goto fail;
+ printf("okay\n");
+ }
+#endif
}
else
printf("skipped\n");
@@ -3036,6 +3108,30 @@ int main(int argc, char **argv)
regs.eflags != 0xa43 || !check_eip(pext) )
goto fail;
printf("okay\n");
+
+#if defined(__x86_64__) && \
+ (defined(__clang__) ? __clang_major__ >= 18 : __GNUC__ >= 14)
+ if ( cpu_has_apx_f )
+ {
+ decl_insn(pext_apx);
+
+ printf("%-40s", "Testing pext (%edx),%r17d,%ebx...");
+
+ asm volatile ( put_insn(pext_apx, "pext (%0), %%r17d, %%ebx")
+ :: "d" (NULL) );
+ set_insn(pext_apx);
+
+ regs.rcx = 0;
+ regs.rbx = 0;
+ load_egpr(17, 0x137f8cef);
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) || (regs.ebx != 0x12f95) ||
+ !check_egpr(17, 0x137f8cef) ||
+ !check_eip(pext_apx) )
+ goto fail;
+ printf("okay\n");
+ }
+#endif
}
else
printf("skipped\n");
@@ -3057,6 +3153,27 @@ int main(int argc, char **argv)
regs.eflags != 0xa43 || !check_eip(rorx) )
goto fail;
printf("okay\n");
+
+#if defined(__x86_64__) && \
+ (defined(__clang__) ? __clang_major__ >= 18 : __GNUC__ >= 14)
+ if ( cpu_has_apx_f )
+ {
+ decl_insn(rorx_apx);
+
+ printf("%-40s", "Testing rorx $8,(%r17),%ebx...");
+
+ asm volatile ( put_insn(rorx_apx, "rorx $8, (%r17), %ebx") );
+ set_insn(rorx_apx);
+
+ regs.ecx = 0;
+ load_egpr(17, (unsigned long)res);
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) || (regs.rbx != 0x98fedcbaU) ||
+ !check_eip(rorx_apx) )
+ goto fail;
+ printf("okay\n");
+ }
+#endif
}
else
printf("skipped\n");
@@ -3080,6 +3197,29 @@ int main(int argc, char **argv)
regs.eflags != 0xa43 || !check_eip(sarx) )
goto fail;
printf("okay\n");
+
+#if defined(__x86_64__) && \
+ (defined(__clang__) ? __clang_major__ >= 18 : __GNUC__ >= 14)
+ if ( cpu_has_apx_f )
+ {
+ decl_insn(sarx_apx);
+
+ printf("%-40s", "Testing sarx %r26d,(%rcx),%ebx...");
+
+ asm volatile ( put_insn(sarx_apx, "sarx %%r26d, (%0), %%ebx")
+ :: "c" (NULL) );
+ set_insn(sarx_apx);
+
+ regs.ebx = 0;
+ load_egpr(26, 0xff11);
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) ||
+ (regs.rbx != (unsigned)(((signed)*res >> 0x11))) ||
+ !check_eip(sarx_apx) )
+ goto fail;
+ printf("okay\n");
+ }
+#endif
}
else
printf("skipped\n");
@@ -3100,6 +3240,27 @@ int main(int argc, char **argv)
regs.eflags != 0xa43 || !check_eip(shlx) )
goto fail;
printf("okay\n");
+
+#if defined(__x86_64__) && \
+ (defined(__clang__) ? __clang_major__ >= 18 : __GNUC__ >= 14)
+ if ( cpu_has_apx_f )
+ {
+ decl_insn(shlx_apx);
+
+ printf("%-40s", "Testing shlx %rdx,(%rcx),%r19...");
+
+ asm volatile ( put_insn(shlx_apx, "shlx %%rdx, (%0), %%r19")
+ :: "c" (NULL) );
+ set_insn(shlx_apx);
+
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) ||
+ !check_egpr(19, (unsigned long)*res << (regs.rdx & 0x1f)) ||
+ !check_eip(shlx_apx) )
+ goto fail;
+ printf("okay\n");
+ }
+#endif
}
else
printf("skipped\n");
@@ -3120,6 +3281,27 @@ int main(int argc, char **argv)
regs.eflags != 0xa43 || !check_eip(shrx) )
goto fail;
printf("okay\n");
+
+#if defined(__x86_64__) && \
+ (defined(__clang__) ? __clang_major__ >= 18 : __GNUC__ >= 14)
+ if ( cpu_has_apx_f )
+ {
+ decl_insn(shrx_apx);
+
+ printf("%-40s", "Testing shrx %edx,(%ecx),%r19d...");
+
+ asm volatile ( put_insn(shrx_apx, "shrx %%edx, (%0), %%r19d")
+ :: "c" (NULL) );
+ set_insn(shrx_apx);
+
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) ||
+ !check_egpr(19, (*res >> (regs.edx & 0x1f))) ||
+ !check_eip(shrx_apx) )
+ goto fail;
+ printf("okay\n");
+ }
+#endif
}
else
printf("skipped\n");
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -1269,7 +1269,14 @@ decode_0f38(struct x86_emulate_state *s,
case X86EMUL_OPC_EVEX(0, 0xf2): /* andn */
case X86EMUL_OPC_EVEX(0, 0xf3): /* Grp 17 */
+ case X86EMUL_OPC_EVEX(0, 0xf5): /* bzhi */
+ case X86EMUL_OPC_EVEX_F3(0, 0xf5): /* pext */
+ case X86EMUL_OPC_EVEX_F2(0, 0xf5): /* pdep */
+ case X86EMUL_OPC_EVEX_F2(0, 0xf6): /* mulx */
case X86EMUL_OPC_EVEX(0, 0xf7): /* bextr */
+ case X86EMUL_OPC_EVEX_66(0, 0xf7): /* shlx */
+ case X86EMUL_OPC_EVEX_F3(0, 0xf7): /* sarx */
+ case X86EMUL_OPC_EVEX_F2(0, 0xf7): /* shrx */
s->promoted_evex = true;
break;
@@ -1326,6 +1333,10 @@ decode_0f3a(struct x86_emulate_state *s,
s->desc = DstImplicit | SrcMem;
break;
+ case X86EMUL_OPC_EVEX_F2(0, 0xf0): /* rorx */
+ s->promoted_evex = true;
+ break;
+
default:
s->op_bytes = 0;
break;
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -7390,7 +7390,15 @@ x86_emulate(
}
break;
+ case X86EMUL_OPC_EVEX_F3(0x0f38, 0xf5): /* pext r/m,r,r */
+ case X86EMUL_OPC_EVEX_F2(0x0f38, 0xf5): /* pdep r/m,r,r */
+ case X86EMUL_OPC_EVEX_66(0x0f38, 0xf7): /* shlx r,r/m,r */
+ case X86EMUL_OPC_EVEX_F3(0x0f38, 0xf7): /* sarx r,r/m,r */
+ case X86EMUL_OPC_EVEX_F2(0x0f38, 0xf7): /* shrx r,r/m,r */
+ generate_exception_if(evex.opmsk, X86_EXC_UD);
+ fallthrough;
case X86EMUL_OPC_EVEX(0x0f38, 0xf2): /* andn r/m,r,r */
+ case X86EMUL_OPC_EVEX(0x0f38, 0xf5): /* bzhi r,r/m,r */
case X86EMUL_OPC_EVEX(0x0f38, 0xf7): /* bextr r,r/m,r */
generate_exception_if((evex.z || evex.lr || evex.brs ||
(evex.opmsk & 3)),
@@ -7524,10 +7532,19 @@ x86_emulate(
break;
}
+ case X86EMUL_OPC_EVEX_F2(0x0f38, 0xf6): /* mulx r/m,r,r */
+ generate_exception_if(evex.lr || evex.brs || evex.opmsk, X86_EXC_UD);
+ fallthrough;
case X86EMUL_OPC_VEX_F2(0x0f38, 0xf6): /* mulx r/m,r,r */
vcpu_must_have(bmi2);
- generate_exception_if(vex.l, X86_EXC_UD);
- ea.reg = decode_vex_gpr(vex.reg, &_regs, ctxt);
+ if ( state->promoted_evex )
+ ea.reg = decode_evex_gpr(evex.reg | (evex.RX << 4), &_regs,
+ &state->egpr, ctxt);
+ else
+ {
+ generate_exception_if(vex.l, X86_EXC_UD);
+ ea.reg = decode_vex_gpr(vex.reg, &_regs, ctxt);
+ }
if ( mode_64bit() && vex.w )
asm ( "mulq %3" : "=a" (*ea.reg), "=d" (dst.val)
: "0" (src.val), "rm" (_regs.r(dx)) );
@@ -8382,6 +8399,10 @@ x86_emulate(
#endif /* X86EMUL_NO_SIMD */
+ case X86EMUL_OPC_EVEX_F2(0x0f3a, 0xf0): /* rorx imm,r/m,r */
+ generate_exception_if((evex.lr || evex.brs || evex.opmsk || !evex.RX),
+ X86_EXC_UD);
+ fallthrough;
case X86EMUL_OPC_VEX_F2(0x0f3a, 0xf0): /* rorx imm,r/m,r */
vcpu_must_have(bmi2);
generate_exception_if(vex.l || vex.reg != 0xf, X86_EXC_UD);
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |