@@ -2208,6 +2208,29 @@ int main(int argc, char **argv)
goto fail;
printf("okay\n");
+ printf("%-40s", "Testing movdir64b 144(%edx),%ecx...");
+ if ( stack_exec && cpu_has_movdir64b )
+ {
+ instr[0] = 0x66; instr[1] = 0x0f; instr[2] = 0x38; instr[3] = 0xf8;
+ instr[4] = 0x8a; instr[5] = 0x90; instr[8] = instr[7] = instr[6] = 0;
+ regs.eip = (unsigned long)&instr[0];
+ for ( i = 0; i < 64; ++i )
+ res[i] = i - 20;
+ regs.edx = (unsigned long)res;
+ regs.ecx = (unsigned long)(res + 16);
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) ||
+ (regs.eip != (unsigned long)&instr[9]) ||
+ res[15] != -5 || res[32] != 12 )
+ goto fail;
+ for ( i = 16; i < 32; ++i )
+ if ( res[i] != i )
+ goto fail;
+ printf("okay\n");
+ }
+ else
+ printf("skipped\n");
+
printf("%-40s", "Testing movq %mm3,(%ecx)...");
if ( stack_exec && cpu_has_mmx )
{
@@ -154,6 +154,7 @@ static inline bool xcr0_mask(uint64_t ma
#define cpu_has_avx512_vnni (cp.feat.avx512_vnni && xcr0_mask(0xe6))
#define cpu_has_avx512_bitalg (cp.feat.avx512_bitalg && xcr0_mask(0xe6))
#define cpu_has_avx512_vpopcntdq (cp.feat.avx512_vpopcntdq && xcr0_mask(0xe6))
+#define cpu_has_movdir64b cp.feat.movdir64b
#define cpu_has_avx512_4vnniw (cp.feat.avx512_4vnniw && xcr0_mask(0xe6))
#define cpu_has_avx512_4fmaps (cp.feat.avx512_4fmaps && xcr0_mask(0xe6))
@@ -249,12 +249,13 @@ $(BASEDIR)/include/asm-x86/asm-macros.h:
# sure we pick up changes when the compiler used has changed.)
ifeq ($(MAKECMDGOALS),asm-offsets.s)
-as-ISA-list := CLWB EPT FSGSBASE INVPCID RDRAND RDSEED SSE4_2 VMX XSAVEOPT
+as-ISA-list := CLWB EPT FSGSBASE INVPCID MOVDIR64B RDRAND RDSEED SSE4_2 VMX XSAVEOPT
CLWB-insn := clwb (%rax)
EPT-insn := invept (%rax),%rax
FSGSBASE-insn := rdfsbase %rax
INVPCID-insn := invpcid (%rax),%rax
+MOVDIR64B-insn := movdir64b (%rax),%rax
RDRAND-insn := rdrand %eax
RDSEED-insn := rdseed %eax
SSE4_2-insn := crc32 %eax,%eax
@@ -548,6 +548,7 @@ static const struct ext0f38_table {
[0xf1] = { .to_mem = 1, .two_op = 1 },
[0xf2 ... 0xf3] = {},
[0xf5 ... 0xf7] = {},
+ [0xf8] = { .simd_size = simd_other },
[0xf9] = { .to_mem = 1 },
};
@@ -834,6 +835,7 @@ struct x86_emulate_state {
rmw_bts,
rmw_dec,
rmw_inc,
+ rmw_movdir64b,
rmw_neg,
rmw_not,
rmw_or,
@@ -896,6 +898,7 @@ typedef union {
uint64_t __attribute__ ((aligned(16))) xmm[2];
uint64_t __attribute__ ((aligned(32))) ymm[4];
uint64_t __attribute__ ((aligned(64))) zmm[8];
+ uint32_t words[16];
} mmval_t;
/*
@@ -1904,6 +1907,7 @@ in_protmode(
#define vcpu_has_avx512_vpopcntdq() (ctxt->cpuid->feat.avx512_vpopcntdq)
#define vcpu_has_rdpid() (ctxt->cpuid->feat.rdpid)
#define vcpu_has_movdiri() (ctxt->cpuid->feat.movdiri)
+#define vcpu_has_movdir64b() (ctxt->cpuid->feat.movdir64b)
#define vcpu_has_avx512_4vnniw() (ctxt->cpuid->feat.avx512_4vnniw)
#define vcpu_has_avx512_4fmaps() (ctxt->cpuid->feat.avx512_4fmaps)
@@ -9919,6 +9923,23 @@ x86_emulate(
: "0" ((uint32_t)src.val), "rm" (_regs.edx) );
break;
+ case X86EMUL_OPC_66(0x0f38, 0xf8): /* movdir64b r,m512 */
+ host_and_vcpu_must_have(movdir64b);
+ generate_exception_if(ea.type != OP_MEM, EXC_UD);
+ src.val = truncate_ea(*dst.reg);
+ generate_exception_if(!is_aligned(x86_seg_es, src.val, 64, ctxt, ops),
+ EXC_GP, 0);
+ fail_if(!ops->rmw);
+ BUILD_BUG_ON(sizeof(*mmvalp) < 64);
+ state->rmw = rmw_movdir64b;
+ if ( (rc = ops->read(ea.mem.seg, ea.mem.off, mmvalp, 64,
+ ctxt)) != X86EMUL_OKAY ||
+ (rc = ops->rmw(x86_seg_es, src.val, 64, &mmvalp->words[0],
+ state, ctxt)) != X86EMUL_OKAY )
+ goto done;
+ state->simd_size = simd_none;
+ break;
+
case X86EMUL_OPC(0x0f38, 0xf9): /* movdiri mem,r */
vcpu_must_have(movdiri);
generate_exception_if(dst.type != OP_MEM, EXC_UD);
@@ -11074,6 +11095,26 @@ int x86_emul_rmw(
#undef BINOP
#undef SHIFT
+ case rmw_movdir64b:
+ if ( ((unsigned long)dst & 0x3f) )
+ {
+ ASSERT_UNREACHABLE();
+ return X86EMUL_UNHANDLEABLE;
+ }
+ /*
+ * eflags points to source data in this case. Use a memory clobber
+ * to compensate that the other operands don't properly express the
+ * (full) memory ranges covered.
+ */
+#ifdef HAVE_AS_MOVDIR64B
+ asm ( "movdir64b %0, %1" :: "m" (*dst), "r" (eflags) : "memory" );
+#else
+ /* movdir64b (%rdi), %rdx */
+ asm ( ".byte 0x66, 0x0f, 0x38, 0xf8, 0x17"
+ :: "D" (dst), "d" (eflags) : "memory" );
+#endif
+ break;
+
case rmw_not:
switch ( state->op_bytes )
{
@@ -120,6 +120,7 @@
#define cpu_has_avx512_bitalg boot_cpu_has(X86_FEATURE_AVX512_BITALG)
#define cpu_has_avx512_vpopcntdq boot_cpu_has(X86_FEATURE_AVX512_VPOPCNTDQ)
#define cpu_has_rdpid boot_cpu_has(X86_FEATURE_RDPID)
+#define cpu_has_movdir64b boot_cpu_has(X86_FEATURE_MOVDIR64B)
/* CPUID level 0x80000007.edx */
#define cpu_has_itsc boot_cpu_has(X86_FEATURE_ITSC)
@@ -238,6 +238,7 @@ XEN_CPUFEATURE(AVX512_VPOPCNTDQ, 6*32+14
XEN_CPUFEATURE(RDPID, 6*32+22) /*A RDPID instruction */
XEN_CPUFEATURE(CLDEMOTE, 6*32+25) /*A CLDEMOTE instruction */
XEN_CPUFEATURE(MOVDIRI, 6*32+27) /*A MOVDIRI instruction */
+XEN_CPUFEATURE(MOVDIR64B, 6*32+28) /*A MOVDIR64B instruction */
/* AMD-defined CPU features, CPUID level 0x80000007.edx, word 7 */
XEN_CPUFEATURE(ITSC, 7*32+ 8) /* Invariant TSC */
Note that SDM revision 070 doesn't specify exception behavior for ModRM.mod != 0b11; assuming #UD here. Signed-off-by: Jan Beulich <jbeulich@suse.com> --- RFC: Yet to be tested (once SDE supports it). --- v4: Split MOVDIRI and MOVDIR64B. Switch to using ->rmw(). Re-base. v3: Update description.