aboutsummaryrefslogtreecommitdiffstats
path: root/tools/tests
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2011-12-01 08:48:14 +0100
committerJan Beulich <jbeulich@suse.com>2011-12-01 08:48:14 +0100
commit11c35f84b53622c429071049b830bb9b7a880eff (patch)
tree63087f7a28dddc2acf531075ab36ca56dff4b50f /tools/tests
parentb6cf65cf7aeb21cea11075da268563fca22ede9c (diff)
downloadxen-11c35f84b53622c429071049b830bb9b7a880eff.tar.gz
xen-11c35f84b53622c429071049b830bb9b7a880eff.tar.bz2
xen-11c35f84b53622c429071049b830bb9b7a880eff.zip
x86/emulator: generalize movq emulation (SSE2 and AVX variants)
Extend the existing movq emulation to also support its SSE2 and AVX variants, the latter implying the addition of VEX decoding. Fold the read and write cases (as most of the logic is identical), and add movntq and variants (as they're very similar). Extend the testing code to also exercise these instructions. Signed-off-by: Jan Beulich <jbeulich@suse.com> Acked-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'tools/tests')
-rw-r--r--tools/tests/x86_emulator/test_x86_emulator.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/tools/tests/x86_emulator/test_x86_emulator.c b/tools/tests/x86_emulator/test_x86_emulator.c
index 1f5722baaa..bc66c97d2d 100644
--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -1,3 +1,5 @@
+#include <errno.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -53,11 +55,84 @@ static int cmpxchg(
return X86EMUL_OKAY;
}
+static int cpuid(
+ unsigned int *eax,
+ unsigned int *ebx,
+ unsigned int *ecx,
+ unsigned int *edx,
+ struct x86_emulate_ctxt *ctxt)
+{
+ asm ("cpuid" : "+a" (*eax), "+c" (*ecx), "=d" (*edx), "=b" (*ebx));
+ return X86EMUL_OKAY;
+}
+
+#define cpu_has_mmx ({ \
+ unsigned int eax = 1, ecx = 0, edx; \
+ cpuid(&eax, &ecx, &ecx, &edx, NULL); \
+ (edx & (1U << 23)) != 0; \
+})
+
+#define cpu_has_sse ({ \
+ unsigned int eax = 1, ecx = 0, edx; \
+ cpuid(&eax, &ecx, &ecx, &edx, NULL); \
+ (edx & (1U << 25)) != 0; \
+})
+
+#define cpu_has_sse2 ({ \
+ unsigned int eax = 1, ecx = 0, edx; \
+ cpuid(&eax, &ecx, &ecx, &edx, NULL); \
+ (edx & (1U << 26)) != 0; \
+})
+
+static inline uint64_t xgetbv(uint32_t xcr)
+{
+ uint64_t res;
+
+ asm ( ".byte 0x0f, 0x01, 0xd0" : "=A" (res) : "c" (xcr) );
+
+ return res;
+}
+
+#define cpu_has_avx ({ \
+ unsigned int eax = 1, ecx = 0, edx; \
+ cpuid(&eax, &edx, &ecx, &edx, NULL); \
+ if ( !(ecx & (1U << 27)) || ((xgetbv(0) & 6) != 6) ) \
+ ecx = 0; \
+ (ecx & (1U << 28)) != 0; \
+})
+
+int get_fpu(
+ void (*exception_callback)(void *, struct cpu_user_regs *),
+ void *exception_callback_arg,
+ enum x86_emulate_fpu_type type,
+ struct x86_emulate_ctxt *ctxt)
+{
+ switch ( type )
+ {
+ case X86EMUL_FPU_fpu:
+ break;
+ case X86EMUL_FPU_ymm:
+ if ( cpu_has_avx )
+ break;
+ case X86EMUL_FPU_xmm:
+ if ( cpu_has_sse )
+ break;
+ case X86EMUL_FPU_mmx:
+ if ( cpu_has_mmx )
+ break;
+ default:
+ return X86EMUL_UNHANDLEABLE;
+ }
+ return X86EMUL_OKAY;
+}
+
static struct x86_emulate_ops emulops = {
.read = read,
.insn_fetch = read,
.write = write,
.cmpxchg = cmpxchg,
+ .cpuid = cpuid,
+ .get_fpu = get_fpu,
};
int main(int argc, char **argv)
@@ -66,6 +141,8 @@ int main(int argc, char **argv)
struct cpu_user_regs regs;
char *instr;
unsigned int *res, i, j;
+ unsigned long sp;
+ bool stack_exec;
int rc;
#ifndef __x86_64__
unsigned int bcdres_native, bcdres_emul;
@@ -85,6 +162,16 @@ int main(int argc, char **argv)
}
instr = (char *)res + 0x100;
+#ifdef __x86_64__
+ asm ("movq %%rsp, %0" : "=g" (sp));
+#else
+ asm ("movl %%esp, %0" : "=g" (sp));
+#endif
+ stack_exec = mprotect((void *)(sp & -0x1000L) - (MMAP_SZ - 0x1000),
+ MMAP_SZ, PROT_READ|PROT_WRITE|PROT_EXEC) == 0;
+ if ( !stack_exec )
+ printf("Warning: Stack could not be made executable (%d).\n", errno);
+
printf("%-40s", "Testing addl %%ecx,(%%eax)...");
instr[0] = 0x01; instr[1] = 0x08;
regs.eflags = 0x200;
@@ -442,6 +529,106 @@ int main(int argc, char **argv)
printf("skipped\n");
#endif
+ printf("%-40s", "Testing movq %mm3,(%ecx)...");
+ if ( stack_exec && cpu_has_mmx )
+ {
+ extern const unsigned char movq_to_mem[];
+
+ asm volatile ( "pcmpeqb %%mm3, %%mm3\n"
+ ".pushsection .test, \"a\", @progbits\n"
+ "movq_to_mem: movq %%mm3, (%0)\n"
+ ".popsection" :: "c" (NULL) );
+
+ memcpy(instr, movq_to_mem, 15);
+ memset(res, 0x33, 64);
+ memset(res + 8, 0xff, 8);
+ regs.eip = (unsigned long)&instr[0];
+ regs.ecx = (unsigned long)res;
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) || memcmp(res, res + 8, 32) )
+ goto fail;
+ printf("okay\n");
+ }
+ else
+ printf("skipped\n");
+
+ printf("%-40s", "Testing movq (%edx),%mm5...");
+ if ( stack_exec && cpu_has_mmx )
+ {
+ extern const unsigned char movq_from_mem[];
+
+ asm volatile ( "pcmpgtb %%mm5, %%mm5\n"
+ ".pushsection .test, \"a\", @progbits\n"
+ "movq_from_mem: movq (%0), %%mm5\n"
+ ".popsection" :: "d" (NULL) );
+
+ memcpy(instr, movq_from_mem, 15);
+ regs.eip = (unsigned long)&instr[0];
+ regs.ecx = 0;
+ regs.edx = (unsigned long)res;
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( rc != X86EMUL_OKAY )
+ goto fail;
+ asm ( "pcmpeqb %%mm3, %%mm3\n\t"
+ "pcmpeqb %%mm5, %%mm3\n\t"
+ "pmovmskb %%mm3, %0" : "=r" (rc) );
+ if ( rc != 0xff )
+ goto fail;
+ printf("okay\n");
+ }
+ else
+ printf("skipped\n");
+
+ printf("%-40s", "Testing movdqu %xmm2,(%ecx)...");
+ if ( stack_exec && cpu_has_sse2 )
+ {
+ extern const unsigned char movdqu_to_mem[];
+
+ asm volatile ( "pcmpeqb %%xmm2, %%xmm2\n"
+ ".pushsection .test, \"a\", @progbits\n"
+ "movdqu_to_mem: movdqu %%xmm2, (%0)\n"
+ ".popsection" :: "c" (NULL) );
+
+ memcpy(instr, movdqu_to_mem, 15);
+ memset(res, 0x55, 64);
+ memset(res + 8, 0xff, 16);
+ regs.eip = (unsigned long)&instr[0];
+ regs.ecx = (unsigned long)res;
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( (rc != X86EMUL_OKAY) || memcmp(res, res + 8, 32) )
+ goto fail;
+ printf("okay\n");
+ }
+ else
+ printf("skipped\n");
+
+ printf("%-40s", "Testing movdqu (%edx),%xmm4...");
+ if ( stack_exec && cpu_has_sse2 )
+ {
+ extern const unsigned char movdqu_from_mem[];
+
+ asm volatile ( "pcmpgtb %%xmm4, %%xmm4\n"
+ ".pushsection .test, \"a\", @progbits\n"
+ "movdqu_from_mem: movdqu (%0), %%xmm4\n"
+ ".popsection" :: "d" (NULL) );
+
+ memcpy(instr, movdqu_from_mem, 15);
+ regs.eip = (unsigned long)&instr[0];
+ regs.ecx = 0;
+ regs.edx = (unsigned long)res;
+ rc = x86_emulate(&ctxt, &emulops);
+ if ( rc != X86EMUL_OKAY )
+ goto fail;
+ asm ( "pcmpeqb %%xmm2, %%xmm2\n\t"
+ "pcmpeqb %%xmm4, %%xmm2\n\t"
+ "pmovmskb %%xmm2, %0" : "=r" (rc) );
+ if ( rc != 0xffff )
+ goto fail;
+ printf("okay\n");
+ }
+ else
+ printf("skipped\n");
+
for ( j = 1; j <= 2; j++ )
{
#if defined(__i386__)