|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 26/30] x86emul: support APX+MOVDIR/ENQCMD insns
Besides adding table entries and case labels, generic map 4 handling
takes care of things here. The only special aspect is dealing with the
512-bit memory operands in EVEX Disp8 testing, including the need for a
->blk() hook and for MSR_PASID to be readable.
Treating MOVDIR64B and ENQCMD{,S} as WIG is speculative; the spec is
unclear in this regard, so GNU binutils are used as reference.
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,12 @@ static const struct test bmi2[] = {
INSN(shrx, f2, 0f38, f7, el, dq, no),
};
+static const struct test enqcmd[] = {
+ /* Element size is set arbitrarily here. See test_one(). */
+ INSN(enqcmd, f2, map4, f8, el, b, no),
+ INSN(enqcmds, f3, map4, f8, el, b, no),
+};
+
static const struct test lzcnt[] = {
INSN(lzcnt, , map4, f5, el, dq, no),
INSN(lzcntw, 66, map4, f5, el, w, no),
@@ -1166,6 +1172,15 @@ static const struct test movbe[] = {
INSN(movbew, 66, map4, 61, el, w, no),
};
+static const struct test movdir64b[] = {
+ /* Element size is set arbitrarily here. See test_one(). */
+ INSN(movdir64b, 66, map4, f8, el, b, no),
+};
+
+static const struct test movdiri[] = {
+ INSN(movdiri, , map4, f9, el, dq, no),
+};
+
static const struct test popcnt[] = {
INSN(popcnt, , map4, 88, el, dq, no),
INSN(popcntw, 66, map4, 88, el, w, no),
@@ -1270,6 +1285,18 @@ static int rmw(enum x86_segment seg, uns
return X86EMUL_OKAY;
}
+static int blk(enum x86_segment seg, unsigned long offset, void *p_data,
+ unsigned int bytes, uint32_t *eflags,
+ struct x86_emulate_state *state,
+ struct x86_emulate_ctxt *ctxt)
+{
+ /* For MOVDIRI ModR/M.rm specifies the sole memory operand. */
+ if ( ctxt->opcode == X86EMUL_OPC_EVEX(4, 0xf9) &&
+ !record_access(seg, offset, bytes) )
+ return X86EMUL_UNHANDLEABLE;
+ return X86EMUL_OKAY;
+}
+
static void test_one(const struct test *test, enum vl vl,
unsigned char *instr, struct x86_emulate_ctxt *ctxt)
{
@@ -1461,6 +1488,12 @@ static void test_one(const struct test *
imm = test->opc & 1 ? test->pfx != PFX_66 ? 4 : 2 : 1;
}
break;
+
+ case 0xf8:
+ /* (Fake) address for the special-type store. */
+ ctxt->regs->eax = 0;
+ vsz = 64;
+ break;
}
}
@@ -1726,6 +1759,7 @@ void evex_disp8_test(void *instr, struct
bool nci_ndd_nf = cpu_policy.apx.apx_nci_ndd_nf;
emulops.rmw = rmw;
+ emulops.blk = blk;
ctxt->force_writeback = true;
@@ -1762,8 +1796,11 @@ void evex_disp8_test(void *instr, struct
RUN(bmi1);
RUN(bmi2);
RUN(cmpccxadd);
+ RUN(enqcmd);
RUN(lzcnt);
RUN(movbe);
+ RUN(movdir64b);
+ RUN(movdiri);
RUN(popcnt);
#undef RUN
--- a/tools/tests/x86_emulator/predicates.c
+++ b/tools/tests/x86_emulator/predicates.c
@@ -2374,6 +2374,10 @@ static const struct evex {
{ { 0xf7, 0x30 }, 2, T, R, pfx_66, Wn, L0 }, /* div */
{ { 0xf7, 0x38 }, 2, T, R, pfx_no, Wn, L0 }, /* idiv */
{ { 0xf7, 0x38 }, 2, T, R, pfx_66, Wn, L0 }, /* idiv */
+ { { 0xf8 }, 2, F, W, pfx_66, WIG, L0 }, /* movdir64b */
+ { { 0xf8 }, 2, F, W, pfx_f3, WIG, L0 }, /* enqcmds */
+ { { 0xf8 }, 2, F, W, pfx_f2, WIG, L0 }, /* enqcmd */
+ { { 0xf9 }, 2, F, W, pfx_no, Wn, L0 }, /* movdiri */
{ { 0xfe, 0x00 }, 2, T, W, pfx_no, WIG, L0, ND }, /* inc */
{ { 0xfe, 0x08 }, 2, T, W, pfx_no, WIG, L0, ND }, /* dec */
{ { 0xff, 0x00 }, 2, T, W, pfx_no, Wn, L0, ND }, /* inc */
--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -872,6 +872,10 @@ static int read_msr(
*val = ((uint64_t)APERF_HI_VALUE << 32) | APERF_LO_VALUE;
return X86EMUL_OKAY;
+ case MSR_PASID:
+ *val = PASID_VALID;
+ return X86EMUL_OKAY;
+
case MSR_EFER:
*val = ctxt->addr_size > 32 ? EFER_LME | EFER_LMA : 0;
return X86EMUL_OKAY;
@@ -3773,6 +3777,27 @@ int main(int argc, char **argv)
res[0] != 0x44332211 || ~res[1] )
goto fail;
printf("okay\n");
+
+#ifdef __x86_64__
+ if ( cpu_has_apx_f )
+ {
+ printf("%-40s", "Testing movdiri %r16,4(%rcx)...");
+
+ instr[0] = 0x62; instr[1] = 0xe4; instr[2] = 0xfc; instr[3] = 0x08;
+ instr[4] = 0xf9; instr[5] = 0x41; instr[6] = 0x04;
+
+ regs.rip = (unsigned long)&instr[0];
+ load_egpr(16, 0x88776655U);
+ memset(res, -1, 16);
+
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) ||
+ (regs.rip != (unsigned long)&instr[7]) ||
+ ~res[0] || (res[1] != 0x88776655U) || res[2] || ~res[3] )
+ goto fail;
+ printf("okay\n");
+ }
+#endif
}
else
printf("skipped\n");
@@ -3798,6 +3823,32 @@ int main(int argc, char **argv)
if ( res[i] != i )
goto fail;
printf("okay\n");
+
+#ifdef __x86_64__
+ if ( cpu_has_apx_f )
+ {
+ printf("%-40s", "Testing movdir64b -128(%r20),%rdx...");
+
+ instr[0] = 0x62; instr[1] = 0xfc; instr[2] = 0x7d; instr[3] = 0x08;
+ instr[4] = 0xf8; instr[5] = 0x54; instr[6] = 0x24; instr[7] = 0x80;
+
+ regs.rip = (unsigned long)&instr[0];
+ for ( i = 0; i < 64; ++i )
+ res[i] = i + 32;
+ regs.rdx = (unsigned long)(res + 32);
+ load_egpr(20, regs.rdx);
+
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) ||
+ (regs.rip != (unsigned long)&instr[8]) ||
+ (res[31] != 63) )
+ goto fail;
+ for ( i = 32; i < 48; ++i )
+ if ( res[i] != i )
+ goto fail;
+ printf("okay\n");
+ }
+#endif
}
else
printf("skipped\n");
--- a/tools/tests/x86_emulator/x86-emulate.h
+++ b/tools/tests/x86_emulator/x86-emulate.h
@@ -204,6 +204,7 @@ void wrpkru(unsigned int val);
xcr0_mask(0xe6))
#define cpu_has_movdiri cpu_policy.feat.movdiri
#define cpu_has_movdir64b cpu_policy.feat.movdir64b
+#define cpu_has_enqcmd cpu_policy.feat.enqcmd
#define cpu_has_avx512_vp2intersect (cpu_policy.feat.avx512_vp2intersect && \
xcr0_mask(0xe6))
#define cpu_has_serialize cpu_policy.feat.serialize
--- a/xen/arch/x86/x86_emulate/decode.c
+++ b/xen/arch/x86/x86_emulate/decode.c
@@ -815,6 +815,14 @@ static const struct map4_table {
[vex_np] = { .nci_ndd_nf = true },
[vex_66] = { .nci_ndd_nf = true },
},
+ [0xf8] = {
+ [vex_66] = { .to_mem = true }, /* MOVDIR64B */
+ [vex_f3] = { .to_mem = true }, /* ENQCMDS */
+ [vex_f2] = { .to_mem = true }, /* ENQCMD */
+ },
+ [0xf9] = { /* MOVDIRI */
+ [vex_np] = { .to_mem = true },
+ },
[0xfe] = { /* Grp4 */
[vex_np] = { .to_mem = true, .byte = true, .nd = true, .nf = true,
.nci_ndd_nf = true },
@@ -1449,6 +1457,16 @@ decode_map4(struct x86_emulate_state *s,
}
break;
+ case 0xf8: /* movdir64b / enqcmd{,s} */
+ /* Make these match their legacy forms. */
+ s->desc = DstReg | Mov;
+ s->op_bytes = 0;
+ break;
+
+ case 0xf9: /* movdiri */
+ s->desc |= Mov;
+ break;
+
case 0xff: /* Grp5 */
switch ( s->modrm_reg & 7 )
{
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -7569,6 +7569,7 @@ x86_emulate(
break;
case X86EMUL_OPC_66(0x0f38, 0xf8): /* movdir64b r,m512 */
+ case X86EMUL_OPC_EVEX_66(4, 0xf8): /* movdir64b r,m512 */
vcpu_must_have(movdir64b);
generate_exception_if(ea.type != OP_MEM, X86_EXC_UD);
src.val = truncate_ea(*dst.reg);
@@ -7680,6 +7681,9 @@ x86_emulate(
}
break;
+ case X86EMUL_OPC_EVEX_F3(4, 0xf8): /* enqcmds r,m512 */
+ case X86EMUL_OPC_EVEX_F2(4, 0xf8): /* enqcmd r,m512 */
+ generate_exception_if(ea.type != OP_MEM, X86_EXC_UD);
enqcmd:
vcpu_must_have(enqcmd);
generate_exception_if(vex.pfx != vex_f2 && !mode_ring0(), X86_EXC_GP,
0);
@@ -7710,7 +7714,8 @@ x86_emulate(
state->simd_size = simd_none;
break;
- case X86EMUL_OPC(0x0f38, 0xf9): /* movdiri mem,r */
+ case X86EMUL_OPC(0x0f38, 0xf9): /* movdiri r,mem */
+ case X86EMUL_OPC_EVEX(4, 0xf9): /* movdiri r,mem */
vcpu_must_have(movdiri);
generate_exception_if(dst.type != OP_MEM, X86_EXC_UD);
fail_if(!ops->blk);
--- a/xen/arch/x86/x86_emulate/util.c
+++ b/xen/arch/x86/x86_emulate/util.c
@@ -215,8 +215,11 @@ bool cf_check x86_insn_is_mem_write(cons
return !mode_64bit();
case X86EMUL_OPC_66(0x0f38, 0xf8): /* MOVDIR64B */
- case X86EMUL_OPC_F2(0x0f38, 0xf8): /* ENQCMD */
case X86EMUL_OPC_F3(0x0f38, 0xf8): /* ENQCMDS */
+ case X86EMUL_OPC_F2(0x0f38, 0xf8): /* ENQCMD */
+ case X86EMUL_OPC_EVEX_66(4, 0xf8): /* MOVDIR64B */
+ case X86EMUL_OPC_EVEX_F3(4, 0xf8): /* ENQCMDS */
+ case X86EMUL_OPC_EVEX_F2(4, 0xf8): /* ENQCMD */
return true;
case X86EMUL_OPC_EVEX_F3(0x0f38, 0x10) ...
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |