xref: /kvm-unit-tests/x86/emulator.c (revision 5647d55c903fca31e85d364ecd7ba279187a2e0e)
17d36db35SAvi Kivity #include "ioram.h"
27d36db35SAvi Kivity #include "vm.h"
37d36db35SAvi Kivity #include "libcflat.h"
47d36db35SAvi Kivity 
57d36db35SAvi Kivity #define memset __builtin_memset
67d36db35SAvi Kivity #define TESTDEV_IO_PORT 0xe0
77d36db35SAvi Kivity 
87d36db35SAvi Kivity int fails, tests;
97d36db35SAvi Kivity 
107d36db35SAvi Kivity void report(const char *name, int result)
117d36db35SAvi Kivity {
127d36db35SAvi Kivity 	++tests;
137d36db35SAvi Kivity 	if (result)
147d36db35SAvi Kivity 		printf("PASS: %s\n", name);
157d36db35SAvi Kivity 	else {
167d36db35SAvi Kivity 		printf("FAIL: %s\n", name);
177d36db35SAvi Kivity 		++fails;
187d36db35SAvi Kivity 	}
197d36db35SAvi Kivity }
207d36db35SAvi Kivity 
217d36db35SAvi Kivity static char st1[] = "abcdefghijklmnop";
227d36db35SAvi Kivity 
237d36db35SAvi Kivity void test_stringio()
247d36db35SAvi Kivity {
257d36db35SAvi Kivity 	unsigned char r = 0;
267d36db35SAvi Kivity 	asm volatile("cld \n\t"
277d36db35SAvi Kivity 		     "movw %0, %%dx \n\t"
287d36db35SAvi Kivity 		     "rep outsb \n\t"
297d36db35SAvi Kivity 		     : : "i"((short)TESTDEV_IO_PORT),
307d36db35SAvi Kivity 		       "S"(st1), "c"(sizeof(st1) - 1));
317d36db35SAvi Kivity 	asm volatile("inb %1, %0\n\t" : "=a"(r) : "i"((short)TESTDEV_IO_PORT));
327d36db35SAvi Kivity 	report("outsb up", r == st1[sizeof(st1) - 2]); /* last char */
337d36db35SAvi Kivity 
347d36db35SAvi Kivity 	asm volatile("std \n\t"
357d36db35SAvi Kivity 		     "movw %0, %%dx \n\t"
367d36db35SAvi Kivity 		     "rep outsb \n\t"
377d36db35SAvi Kivity 		     : : "i"((short)TESTDEV_IO_PORT),
387d36db35SAvi Kivity 		       "S"(st1 + sizeof(st1) - 2), "c"(sizeof(st1) - 1));
397d36db35SAvi Kivity 	asm volatile("cld \n\t" : : );
407d36db35SAvi Kivity 	asm volatile("in %1, %0\n\t" : "=a"(r) : "i"((short)TESTDEV_IO_PORT));
417d36db35SAvi Kivity 	report("outsb down", r == st1[0]);
427d36db35SAvi Kivity }
437d36db35SAvi Kivity 
447d36db35SAvi Kivity void test_cmps_one(unsigned char *m1, unsigned char *m3)
457d36db35SAvi Kivity {
467d36db35SAvi Kivity 	void *rsi, *rdi;
477d36db35SAvi Kivity 	long rcx, tmp;
487d36db35SAvi Kivity 
497d36db35SAvi Kivity 	rsi = m1; rdi = m3; rcx = 30;
507d36db35SAvi Kivity 	asm volatile("xor %[tmp], %[tmp] \n\t"
517d36db35SAvi Kivity 		     "repe/cmpsb"
527d36db35SAvi Kivity 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
537d36db35SAvi Kivity 		     : : "cc");
547d36db35SAvi Kivity 	report("repe/cmpsb (1)", rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30);
557d36db35SAvi Kivity 
567d36db35SAvi Kivity 	rsi = m1; rdi = m3; rcx = 15;
577d36db35SAvi Kivity 	asm volatile("xor %[tmp], %[tmp] \n\t"
587d36db35SAvi Kivity 		     "repe/cmpsw"
597d36db35SAvi Kivity 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
607d36db35SAvi Kivity 		     : : "cc");
617d36db35SAvi Kivity 	report("repe/cmpsw (1)", rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30);
627d36db35SAvi Kivity 
637d36db35SAvi Kivity 	rsi = m1; rdi = m3; rcx = 7;
647d36db35SAvi Kivity 	asm volatile("xor %[tmp], %[tmp] \n\t"
657d36db35SAvi Kivity 		     "repe/cmpsl"
667d36db35SAvi Kivity 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
677d36db35SAvi Kivity 		     : : "cc");
687d36db35SAvi Kivity 	report("repe/cmpll (1)", rcx == 0 && rsi == m1 + 28 && rdi == m3 + 28);
697d36db35SAvi Kivity 
707d36db35SAvi Kivity 	rsi = m1; rdi = m3; rcx = 4;
717d36db35SAvi Kivity 	asm volatile("xor %[tmp], %[tmp] \n\t"
727d36db35SAvi Kivity 		     "repe/cmpsq"
737d36db35SAvi Kivity 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
747d36db35SAvi Kivity 		     : : "cc");
757d36db35SAvi Kivity 	report("repe/cmpsq (1)", rcx == 0 && rsi == m1 + 32 && rdi == m3 + 32);
767d36db35SAvi Kivity 
777d36db35SAvi Kivity 	rsi = m1; rdi = m3; rcx = 130;
787d36db35SAvi Kivity 	asm volatile("xor %[tmp], %[tmp] \n\t"
797d36db35SAvi Kivity 		     "repe/cmpsb"
807d36db35SAvi Kivity 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
817d36db35SAvi Kivity 		     : : "cc");
827d36db35SAvi Kivity 	report("repe/cmpsb (2)",
837d36db35SAvi Kivity 	       rcx == 29 && rsi == m1 + 101 && rdi == m3 + 101);
847d36db35SAvi Kivity 
857d36db35SAvi Kivity 	rsi = m1; rdi = m3; rcx = 65;
867d36db35SAvi Kivity 	asm volatile("xor %[tmp], %[tmp] \n\t"
877d36db35SAvi Kivity 		     "repe/cmpsw"
887d36db35SAvi Kivity 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
897d36db35SAvi Kivity 		     : : "cc");
907d36db35SAvi Kivity 	report("repe/cmpsw (2)",
917d36db35SAvi Kivity 	       rcx == 14 && rsi == m1 + 102 && rdi == m3 + 102);
927d36db35SAvi Kivity 
937d36db35SAvi Kivity 	rsi = m1; rdi = m3; rcx = 32;
947d36db35SAvi Kivity 	asm volatile("xor %[tmp], %[tmp] \n\t"
957d36db35SAvi Kivity 		     "repe/cmpsl"
967d36db35SAvi Kivity 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
977d36db35SAvi Kivity 		     : : "cc");
987d36db35SAvi Kivity 	report("repe/cmpll (2)",
997d36db35SAvi Kivity 	       rcx == 6 && rsi == m1 + 104 && rdi == m3 + 104);
1007d36db35SAvi Kivity 
1017d36db35SAvi Kivity 	rsi = m1; rdi = m3; rcx = 16;
1027d36db35SAvi Kivity 	asm volatile("xor %[tmp], %[tmp] \n\t"
1037d36db35SAvi Kivity 		     "repe/cmpsq"
1047d36db35SAvi Kivity 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
1057d36db35SAvi Kivity 		     : : "cc");
1067d36db35SAvi Kivity 	report("repe/cmpsq (2)",
1077d36db35SAvi Kivity 	       rcx == 3 && rsi == m1 + 104 && rdi == m3 + 104);
1087d36db35SAvi Kivity 
1097d36db35SAvi Kivity }
1107d36db35SAvi Kivity 
1117d36db35SAvi Kivity void test_cmps(void *mem)
1127d36db35SAvi Kivity {
1137d36db35SAvi Kivity 	unsigned char *m1 = mem, *m2 = mem + 1024;
1147d36db35SAvi Kivity 	unsigned char m3[1024];
1157d36db35SAvi Kivity 
1167d36db35SAvi Kivity 	for (int i = 0; i < 100; ++i)
1177d36db35SAvi Kivity 		m1[i] = m2[i] = m3[i] = i;
1187d36db35SAvi Kivity 	for (int i = 100; i < 200; ++i)
1197d36db35SAvi Kivity 		m1[i] = (m3[i] = m2[i] = i) + 1;
1207d36db35SAvi Kivity 	test_cmps_one(m1, m3);
1217d36db35SAvi Kivity 	test_cmps_one(m1, m2);
1227d36db35SAvi Kivity }
1237d36db35SAvi Kivity 
1247d36db35SAvi Kivity void test_cr8(void)
1257d36db35SAvi Kivity {
1267d36db35SAvi Kivity 	unsigned long src, dst;
1277d36db35SAvi Kivity 
1287d36db35SAvi Kivity 	dst = 777;
1297d36db35SAvi Kivity 	src = 3;
1307d36db35SAvi Kivity 	asm volatile("mov %[src], %%cr8; mov %%cr8, %[dst]"
1317d36db35SAvi Kivity 		     : [dst]"+r"(dst), [src]"+r"(src));
1327d36db35SAvi Kivity 	report("mov %cr8", dst == 3 && src == 3);
1337d36db35SAvi Kivity }
1347d36db35SAvi Kivity 
1357d36db35SAvi Kivity void test_push(void *mem)
1367d36db35SAvi Kivity {
1377d36db35SAvi Kivity 	unsigned long tmp;
1387d36db35SAvi Kivity 	unsigned long *stack_top = mem + 4096;
1397d36db35SAvi Kivity 	unsigned long *new_stack_top;
1407d36db35SAvi Kivity 	unsigned long memw = 0x123456789abcdeful;
1417d36db35SAvi Kivity 
1427d36db35SAvi Kivity 	memset(mem, 0x55, (void *)stack_top - mem);
1437d36db35SAvi Kivity 
1447d36db35SAvi Kivity 	asm volatile("mov %%rsp, %[tmp] \n\t"
1457d36db35SAvi Kivity 		     "mov %[stack_top], %%rsp \n\t"
1467d36db35SAvi Kivity 		     "pushq $-7 \n\t"
1477d36db35SAvi Kivity 		     "pushq %[reg] \n\t"
1487d36db35SAvi Kivity 		     "pushq (%[mem]) \n\t"
1497d36db35SAvi Kivity 		     "pushq $-7070707 \n\t"
1507d36db35SAvi Kivity 		     "mov %%rsp, %[new_stack_top] \n\t"
1517d36db35SAvi Kivity 		     "mov %[tmp], %%rsp"
1527d36db35SAvi Kivity 		     : [tmp]"=&r"(tmp), [new_stack_top]"=r"(new_stack_top)
1537d36db35SAvi Kivity 		     : [stack_top]"r"(stack_top),
1547d36db35SAvi Kivity 		       [reg]"r"(-17l), [mem]"r"(&memw)
1557d36db35SAvi Kivity 		     : "memory");
1567d36db35SAvi Kivity 
1577d36db35SAvi Kivity 	report("push $imm8", stack_top[-1] == -7ul);
1587d36db35SAvi Kivity 	report("push %reg", stack_top[-2] == -17ul);
1597d36db35SAvi Kivity 	report("push mem", stack_top[-3] == 0x123456789abcdeful);
1607d36db35SAvi Kivity 	report("push $imm", stack_top[-4] == -7070707);
1617d36db35SAvi Kivity }
1627d36db35SAvi Kivity 
1637d36db35SAvi Kivity void test_pop(void *mem)
1647d36db35SAvi Kivity {
1657d36db35SAvi Kivity 	unsigned long tmp;
1667d36db35SAvi Kivity 	unsigned long *stack_top = mem + 4096;
1677d36db35SAvi Kivity 	unsigned long memw = 0x123456789abcdeful;
1687d36db35SAvi Kivity 	static unsigned long tmp2;
1697d36db35SAvi Kivity 
1707d36db35SAvi Kivity 	memset(mem, 0x55, (void *)stack_top - mem);
1717d36db35SAvi Kivity 
1727d36db35SAvi Kivity 	asm volatile("pushq %[val] \n\t"
1737d36db35SAvi Kivity 		     "popq (%[mem])"
1747d36db35SAvi Kivity 		     : : [val]"m"(memw), [mem]"r"(mem) : "memory");
1757d36db35SAvi Kivity 	report("pop mem", *(unsigned long *)mem == memw);
1767d36db35SAvi Kivity 
1777d36db35SAvi Kivity 	memw = 7 - memw;
1787d36db35SAvi Kivity 	asm volatile("mov %%rsp, %[tmp] \n\t"
1797d36db35SAvi Kivity 		     "mov %[stack_top], %%rsp \n\t"
1807d36db35SAvi Kivity 		     "pushq %[val] \n\t"
1817d36db35SAvi Kivity 		     "popq %[tmp2] \n\t"
1827d36db35SAvi Kivity 		     "mov %[tmp], %%rsp"
1837d36db35SAvi Kivity 		     : [tmp]"=&r"(tmp), [tmp2]"=m"(tmp2)
1847d36db35SAvi Kivity 		     : [val]"r"(memw), [stack_top]"r"(stack_top)
1857d36db35SAvi Kivity 		     : "memory");
1867d36db35SAvi Kivity 	report("pop mem (2)", tmp2 == memw);
1877d36db35SAvi Kivity 
1887d36db35SAvi Kivity 	memw = 129443 - memw;
1897d36db35SAvi Kivity 	asm volatile("mov %%rsp, %[tmp] \n\t"
1907d36db35SAvi Kivity 		     "mov %[stack_top], %%rsp \n\t"
1917d36db35SAvi Kivity 		     "pushq %[val] \n\t"
1927d36db35SAvi Kivity 		     "popq %[tmp2] \n\t"
1937d36db35SAvi Kivity 		     "mov %[tmp], %%rsp"
1947d36db35SAvi Kivity 		     : [tmp]"=&r"(tmp), [tmp2]"=r"(tmp2)
1957d36db35SAvi Kivity 		     : [val]"r"(memw), [stack_top]"r"(stack_top)
1967d36db35SAvi Kivity 		     : "memory");
1977d36db35SAvi Kivity 	report("pop reg", tmp2 == memw);
1987d36db35SAvi Kivity 
1997d36db35SAvi Kivity 	asm volatile("mov %%rsp, %[tmp] \n\t"
2007d36db35SAvi Kivity 		     "mov %[stack_top], %%rsp \n\t"
2017d36db35SAvi Kivity 		     "push $1f \n\t"
2027d36db35SAvi Kivity 		     "ret \n\t"
2037d36db35SAvi Kivity 		     "2: jmp 2b \n\t"
2047d36db35SAvi Kivity 		     "1: mov %[tmp], %%rsp"
2057d36db35SAvi Kivity 		     : [tmp]"=&r"(tmp) : [stack_top]"r"(stack_top)
2067d36db35SAvi Kivity 		     : "memory");
2077d36db35SAvi Kivity 	report("ret", 1);
2087d36db35SAvi Kivity }
2097d36db35SAvi Kivity 
2107d36db35SAvi Kivity void test_ljmp(void *mem)
2117d36db35SAvi Kivity {
2127d36db35SAvi Kivity     unsigned char *m = mem;
2137d36db35SAvi Kivity     volatile int res = 1;
2147d36db35SAvi Kivity 
2157d36db35SAvi Kivity     *(unsigned long**)m = &&jmpf;
2167d36db35SAvi Kivity     asm volatile ("data16/mov %%cs, %0":"=m"(*(m + sizeof(unsigned long))));
2177d36db35SAvi Kivity     asm volatile ("rex64/ljmp *%0"::"m"(*m));
2187d36db35SAvi Kivity     res = 0;
2197d36db35SAvi Kivity jmpf:
2207d36db35SAvi Kivity     report("ljmp", res);
2217d36db35SAvi Kivity }
2227d36db35SAvi Kivity 
2237d36db35SAvi Kivity void test_incdecnotneg(void *mem)
2247d36db35SAvi Kivity {
2257d36db35SAvi Kivity     unsigned long *m = mem, v = 1234;
2267d36db35SAvi Kivity     unsigned char *mb = mem, vb = 66;
2277d36db35SAvi Kivity 
2287d36db35SAvi Kivity     *m = 0;
2297d36db35SAvi Kivity 
2307d36db35SAvi Kivity     asm volatile ("incl %0":"+m"(*m));
2317d36db35SAvi Kivity     report("incl",  *m == 1);
2327d36db35SAvi Kivity     asm volatile ("decl %0":"+m"(*m));
2337d36db35SAvi Kivity     report("decl",  *m == 0);
2347d36db35SAvi Kivity     asm volatile ("incb %0":"+m"(*m));
2357d36db35SAvi Kivity     report("incb",  *m == 1);
2367d36db35SAvi Kivity     asm volatile ("decb %0":"+m"(*m));
2377d36db35SAvi Kivity     report("decb",  *m == 0);
2387d36db35SAvi Kivity 
2397d36db35SAvi Kivity     asm volatile ("lock incl %0":"+m"(*m));
2407d36db35SAvi Kivity     report("lock incl",  *m == 1);
2417d36db35SAvi Kivity     asm volatile ("lock decl %0":"+m"(*m));
2427d36db35SAvi Kivity     report("lock decl",  *m == 0);
2437d36db35SAvi Kivity     asm volatile ("lock incb %0":"+m"(*m));
2447d36db35SAvi Kivity     report("lock incb",  *m == 1);
2457d36db35SAvi Kivity     asm volatile ("lock decb %0":"+m"(*m));
2467d36db35SAvi Kivity     report("lock decb",  *m == 0);
2477d36db35SAvi Kivity 
2487d36db35SAvi Kivity     *m = v;
2497d36db35SAvi Kivity 
2507d36db35SAvi Kivity     asm ("lock negq %0" : "+m"(*m)); v = -v;
2517d36db35SAvi Kivity     report("lock negl", *m == v);
2527d36db35SAvi Kivity     asm ("lock notq %0" : "+m"(*m)); v = ~v;
2537d36db35SAvi Kivity     report("lock notl", *m == v);
2547d36db35SAvi Kivity 
2557d36db35SAvi Kivity     *mb = vb;
2567d36db35SAvi Kivity 
2577d36db35SAvi Kivity     asm ("lock negb %0" : "+m"(*mb)); vb = -vb;
2587d36db35SAvi Kivity     report("lock negb", *mb == vb);
2597d36db35SAvi Kivity     asm ("lock notb %0" : "+m"(*mb)); vb = ~vb;
2607d36db35SAvi Kivity     report("lock notb", *mb == vb);
2617d36db35SAvi Kivity }
2627d36db35SAvi Kivity 
2637d36db35SAvi Kivity void test_smsw(void)
2647d36db35SAvi Kivity {
2657d36db35SAvi Kivity 	char mem[16];
2667d36db35SAvi Kivity 	unsigned short msw, msw_orig, *pmsw;
2677d36db35SAvi Kivity 	int i, zero;
2687d36db35SAvi Kivity 
2697d36db35SAvi Kivity 	msw_orig = read_cr0();
2707d36db35SAvi Kivity 
2717d36db35SAvi Kivity 	asm("smsw %0" : "=r"(msw));
2727d36db35SAvi Kivity 	report("smsw (1)", msw == msw_orig);
2737d36db35SAvi Kivity 
2747d36db35SAvi Kivity 	memset(mem, 0, 16);
2757d36db35SAvi Kivity 	pmsw = (void *)mem;
2767d36db35SAvi Kivity 	asm("smsw %0" : "=m"(pmsw[4]));
2777d36db35SAvi Kivity 	zero = 1;
2787d36db35SAvi Kivity 	for (i = 0; i < 8; ++i)
2797d36db35SAvi Kivity 		if (i != 4 && pmsw[i])
2807d36db35SAvi Kivity 			zero = 0;
2817d36db35SAvi Kivity 	report("smsw (2)", msw == pmsw[4] && zero);
2827d36db35SAvi Kivity }
2837d36db35SAvi Kivity 
2847d36db35SAvi Kivity void test_lmsw(void)
2857d36db35SAvi Kivity {
2867d36db35SAvi Kivity 	char mem[16];
2877d36db35SAvi Kivity 	unsigned short msw, *pmsw;
2887d36db35SAvi Kivity 	unsigned long cr0;
2897d36db35SAvi Kivity 
2907d36db35SAvi Kivity 	cr0 = read_cr0();
2917d36db35SAvi Kivity 
2927d36db35SAvi Kivity 	msw = cr0 ^ 8;
2937d36db35SAvi Kivity 	asm("lmsw %0" : : "r"(msw));
2947d36db35SAvi Kivity 	printf("before %lx after %lx\n", cr0, read_cr0());
2957d36db35SAvi Kivity 	report("lmsw (1)", (cr0 ^ read_cr0()) == 8);
2967d36db35SAvi Kivity 
2977d36db35SAvi Kivity 	pmsw = (void *)mem;
2987d36db35SAvi Kivity 	*pmsw = cr0;
2997d36db35SAvi Kivity 	asm("lmsw %0" : : "m"(*pmsw));
3007d36db35SAvi Kivity 	printf("before %lx after %lx\n", cr0, read_cr0());
3017d36db35SAvi Kivity 	report("lmsw (2)", cr0 == read_cr0());
3027d36db35SAvi Kivity 
3037d36db35SAvi Kivity 	/* lmsw can't clear cr0.pe */
3047d36db35SAvi Kivity 	msw = (cr0 & ~1ul) ^ 4;  /* change EM to force trap */
3057d36db35SAvi Kivity 	asm("lmsw %0" : : "r"(msw));
3067d36db35SAvi Kivity 	report("lmsw (3)", (cr0 ^ read_cr0()) == 4 && (cr0 & 1));
3077d36db35SAvi Kivity 
3087d36db35SAvi Kivity 	/* back to normal */
3097d36db35SAvi Kivity 	msw = cr0;
3107d36db35SAvi Kivity 	asm("lmsw %0" : : "r"(msw));
3117d36db35SAvi Kivity }
3127d36db35SAvi Kivity 
3137d36db35SAvi Kivity void test_xchg(void *mem)
3147d36db35SAvi Kivity {
3157d36db35SAvi Kivity 	unsigned long *memq = mem;
3167d36db35SAvi Kivity 	unsigned long rax;
3177d36db35SAvi Kivity 
3187d36db35SAvi Kivity 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
3197d36db35SAvi Kivity 		     "mov %%rax, (%[memq])\n\t"
3207d36db35SAvi Kivity 		     "mov $0xfedcba9876543210, %%rax\n\t"
3217d36db35SAvi Kivity 		     "xchg %%al, (%[memq])\n\t"
3227d36db35SAvi Kivity 		     "mov %%rax, %[rax]\n\t"
3237d36db35SAvi Kivity 		     : [rax]"=r"(rax)
3247d36db35SAvi Kivity 		     : [memq]"r"(memq)
3257d36db35SAvi Kivity 		     : "memory");
3267d36db35SAvi Kivity 	report("xchg reg, r/m (1)",
3277d36db35SAvi Kivity 	       rax == 0xfedcba98765432ef && *memq == 0x123456789abcd10);
3287d36db35SAvi Kivity 
3297d36db35SAvi Kivity 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
3307d36db35SAvi Kivity 		     "mov %%rax, (%[memq])\n\t"
3317d36db35SAvi Kivity 		     "mov $0xfedcba9876543210, %%rax\n\t"
3327d36db35SAvi Kivity 		     "xchg %%ax, (%[memq])\n\t"
3337d36db35SAvi Kivity 		     "mov %%rax, %[rax]\n\t"
3347d36db35SAvi Kivity 		     : [rax]"=r"(rax)
3357d36db35SAvi Kivity 		     : [memq]"r"(memq)
3367d36db35SAvi Kivity 		     : "memory");
3377d36db35SAvi Kivity 	report("xchg reg, r/m (2)",
3387d36db35SAvi Kivity 	       rax == 0xfedcba987654cdef && *memq == 0x123456789ab3210);
3397d36db35SAvi Kivity 
3407d36db35SAvi Kivity 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
3417d36db35SAvi Kivity 		     "mov %%rax, (%[memq])\n\t"
3427d36db35SAvi Kivity 		     "mov $0xfedcba9876543210, %%rax\n\t"
3437d36db35SAvi Kivity 		     "xchg %%eax, (%[memq])\n\t"
3447d36db35SAvi Kivity 		     "mov %%rax, %[rax]\n\t"
3457d36db35SAvi Kivity 		     : [rax]"=r"(rax)
3467d36db35SAvi Kivity 		     : [memq]"r"(memq)
3477d36db35SAvi Kivity 		     : "memory");
3487d36db35SAvi Kivity 	report("xchg reg, r/m (3)",
3497d36db35SAvi Kivity 	       rax == 0x89abcdef && *memq == 0x123456776543210);
3507d36db35SAvi Kivity 
3517d36db35SAvi Kivity 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
3527d36db35SAvi Kivity 		     "mov %%rax, (%[memq])\n\t"
3537d36db35SAvi Kivity 		     "mov $0xfedcba9876543210, %%rax\n\t"
3547d36db35SAvi Kivity 		     "xchg %%rax, (%[memq])\n\t"
3557d36db35SAvi Kivity 		     "mov %%rax, %[rax]\n\t"
3567d36db35SAvi Kivity 		     : [rax]"=r"(rax)
3577d36db35SAvi Kivity 		     : [memq]"r"(memq)
3587d36db35SAvi Kivity 		     : "memory");
3597d36db35SAvi Kivity 	report("xchg reg, r/m (4)",
3607d36db35SAvi Kivity 	       rax == 0x123456789abcdef && *memq == 0xfedcba9876543210);
3617d36db35SAvi Kivity }
3627d36db35SAvi Kivity 
363*5647d55cSWei Yongjun void test_xadd(void *mem)
364*5647d55cSWei Yongjun {
365*5647d55cSWei Yongjun 	unsigned long *memq = mem;
366*5647d55cSWei Yongjun 	unsigned long rax;
367*5647d55cSWei Yongjun 
368*5647d55cSWei Yongjun 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
369*5647d55cSWei Yongjun 		     "mov %%rax, (%[memq])\n\t"
370*5647d55cSWei Yongjun 		     "mov $0xfedcba9876543210, %%rax\n\t"
371*5647d55cSWei Yongjun 		     "xadd %%al, (%[memq])\n\t"
372*5647d55cSWei Yongjun 		     "mov %%rax, %[rax]\n\t"
373*5647d55cSWei Yongjun 		     : [rax]"=r"(rax)
374*5647d55cSWei Yongjun 		     : [memq]"r"(memq)
375*5647d55cSWei Yongjun 		     : "memory");
376*5647d55cSWei Yongjun 	report("xadd reg, r/m (1)",
377*5647d55cSWei Yongjun 	       rax == 0xfedcba98765432ef && *memq == 0x123456789abcdff);
378*5647d55cSWei Yongjun 
379*5647d55cSWei Yongjun 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
380*5647d55cSWei Yongjun 		     "mov %%rax, (%[memq])\n\t"
381*5647d55cSWei Yongjun 		     "mov $0xfedcba9876543210, %%rax\n\t"
382*5647d55cSWei Yongjun 		     "xadd %%ax, (%[memq])\n\t"
383*5647d55cSWei Yongjun 		     "mov %%rax, %[rax]\n\t"
384*5647d55cSWei Yongjun 		     : [rax]"=r"(rax)
385*5647d55cSWei Yongjun 		     : [memq]"r"(memq)
386*5647d55cSWei Yongjun 		     : "memory");
387*5647d55cSWei Yongjun 	report("xadd reg, r/m (2)",
388*5647d55cSWei Yongjun 	       rax == 0xfedcba987654cdef && *memq == 0x123456789abffff);
389*5647d55cSWei Yongjun 
390*5647d55cSWei Yongjun 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
391*5647d55cSWei Yongjun 		     "mov %%rax, (%[memq])\n\t"
392*5647d55cSWei Yongjun 		     "mov $0xfedcba9876543210, %%rax\n\t"
393*5647d55cSWei Yongjun 		     "xadd %%eax, (%[memq])\n\t"
394*5647d55cSWei Yongjun 		     "mov %%rax, %[rax]\n\t"
395*5647d55cSWei Yongjun 		     : [rax]"=r"(rax)
396*5647d55cSWei Yongjun 		     : [memq]"r"(memq)
397*5647d55cSWei Yongjun 		     : "memory");
398*5647d55cSWei Yongjun 	report("xadd reg, r/m (3)",
399*5647d55cSWei Yongjun 	       rax == 0x89abcdef && *memq == 0x1234567ffffffff);
400*5647d55cSWei Yongjun 
401*5647d55cSWei Yongjun 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
402*5647d55cSWei Yongjun 		     "mov %%rax, (%[memq])\n\t"
403*5647d55cSWei Yongjun 		     "mov $0xfedcba9876543210, %%rax\n\t"
404*5647d55cSWei Yongjun 		     "xadd %%rax, (%[memq])\n\t"
405*5647d55cSWei Yongjun 		     "mov %%rax, %[rax]\n\t"
406*5647d55cSWei Yongjun 		     : [rax]"=r"(rax)
407*5647d55cSWei Yongjun 		     : [memq]"r"(memq)
408*5647d55cSWei Yongjun 		     : "memory");
409*5647d55cSWei Yongjun 	report("xadd reg, r/m (4)",
410*5647d55cSWei Yongjun 	       rax == 0x123456789abcdef && *memq == 0xffffffffffffffff);
411*5647d55cSWei Yongjun }
412*5647d55cSWei Yongjun 
413d4655eafSWei Yongjun void test_btc(void *mem)
414d4655eafSWei Yongjun {
415d4655eafSWei Yongjun 	unsigned int *a = mem;
416d4655eafSWei Yongjun 
417d4655eafSWei Yongjun 	memset(mem, 0, 3 * sizeof(unsigned int));
418d4655eafSWei Yongjun 
419d4655eafSWei Yongjun 	asm ("btcl $32, %0" :: "m"(a[0]) : "memory");
420d4655eafSWei Yongjun 	asm ("btcl $1, %0" :: "m"(a[1]) : "memory");
421d4655eafSWei Yongjun 	asm ("btcl %1, %0" :: "m"(a[0]), "r"(66) : "memory");
422d4655eafSWei Yongjun 	report("btcl imm8, r/m", a[0] == 1 && a[1] == 2 && a[2] == 4);
423d4655eafSWei Yongjun 
424d4655eafSWei Yongjun 	asm ("btcl %1, %0" :: "m"(a[3]), "r"(-1) : "memory");
425d4655eafSWei Yongjun 	report("btcl reg, r/m", a[0] == 1 && a[1] == 2 && a[2] == 0x80000004);
426d4655eafSWei Yongjun }
427d4655eafSWei Yongjun 
4282e16c7f6SWei Yongjun void test_bsfbsr(void *mem)
4292e16c7f6SWei Yongjun {
4302e16c7f6SWei Yongjun 	unsigned long *memq = mem, rax;
4312e16c7f6SWei Yongjun 
4322e16c7f6SWei Yongjun 	asm volatile("movw $0xC000, (%[memq])\n\t"
4332e16c7f6SWei Yongjun 		     "bsfw (%[memq]), %%ax\n\t"
4342e16c7f6SWei Yongjun 		     ::[memq]"r"(memq));
4352e16c7f6SWei Yongjun 	asm ("mov %%rax, %[rax]": [rax]"=m"(rax));
4362e16c7f6SWei Yongjun 	report("bsfw r/m, reg", rax == 14);
4372e16c7f6SWei Yongjun 
4382e16c7f6SWei Yongjun 	asm volatile("movl $0xC0000000, (%[memq])\n\t"
4392e16c7f6SWei Yongjun 		     "bsfl (%[memq]), %%eax\n\t"
4402e16c7f6SWei Yongjun 		     ::[memq]"r"(memq));
4412e16c7f6SWei Yongjun 	asm ("mov %%rax, %[rax]": [rax]"=m"(rax));
4422e16c7f6SWei Yongjun 	report("bsfl r/m, reg", rax == 30);
4432e16c7f6SWei Yongjun 
4442e16c7f6SWei Yongjun 	asm volatile("movq $0xC00000000000, %%rax\n\t"
4452e16c7f6SWei Yongjun 		     "movq %%rax, (%[memq])\n\t"
4462e16c7f6SWei Yongjun 		     "bsfq (%[memq]), %%rax\n\t"
4472e16c7f6SWei Yongjun 		     ::[memq]"r"(memq));
4482e16c7f6SWei Yongjun 	asm ("mov %%rax, %[rax]": [rax]"=m"(rax));
4492e16c7f6SWei Yongjun 	report("bsfq r/m, reg", rax == 46);
4502e16c7f6SWei Yongjun 
4512e16c7f6SWei Yongjun 	asm volatile("movq $0, %%rax\n\t"
4522e16c7f6SWei Yongjun 		     "movq %%rax, (%[memq])\n\t"
4532e16c7f6SWei Yongjun 		     "bsfq (%[memq]), %%rax\n\t"
4542e16c7f6SWei Yongjun 		     "jnz 1f\n\t"
4552e16c7f6SWei Yongjun 		     "movl $1, %[rax]\n\t"
4562e16c7f6SWei Yongjun 		     "1:\n\t"
4572e16c7f6SWei Yongjun 		     :[rax]"=m"(rax)
4582e16c7f6SWei Yongjun 		     :[memq]"r"(memq));
4592e16c7f6SWei Yongjun 	report("bsfq r/m, reg", rax == 1);
4602e16c7f6SWei Yongjun 
4612e16c7f6SWei Yongjun 	asm volatile("movw $0xC000, (%[memq])\n\t"
4622e16c7f6SWei Yongjun 		     "bsrw (%[memq]), %%ax\n\t"
4632e16c7f6SWei Yongjun 		     ::[memq]"r"(memq));
4642e16c7f6SWei Yongjun 	asm ("mov %%rax, %[rax]": [rax]"=m"(rax));
4652e16c7f6SWei Yongjun 	report("bsrw r/m, reg", rax == 15);
4662e16c7f6SWei Yongjun 
4672e16c7f6SWei Yongjun 	asm volatile("movl $0xC0000000, (%[memq])\n\t"
4682e16c7f6SWei Yongjun 		     "bsrl (%[memq]), %%eax\n\t"
4692e16c7f6SWei Yongjun 		     ::[memq]"r"(memq));
4702e16c7f6SWei Yongjun 	asm ("mov %%rax, %[rax]": [rax]"=m"(rax));
4712e16c7f6SWei Yongjun 	report("bsrl r/m, reg", rax == 31);
4722e16c7f6SWei Yongjun 
4732e16c7f6SWei Yongjun 	asm volatile("movq $0xC00000000000, %%rax\n\t"
4742e16c7f6SWei Yongjun 		     "movq %%rax, (%[memq])\n\t"
4752e16c7f6SWei Yongjun 		     "bsrq (%[memq]), %%rax\n\t"
4762e16c7f6SWei Yongjun 		     ::[memq]"r"(memq));
4772e16c7f6SWei Yongjun 	asm ("mov %%rax, %[rax]": [rax]"=m"(rax));
4782e16c7f6SWei Yongjun 	report("bsrq r/m, reg", rax == 47);
4792e16c7f6SWei Yongjun 
4802e16c7f6SWei Yongjun 	asm volatile("movq $0, %%rax\n\t"
4812e16c7f6SWei Yongjun 		     "movq %%rax, (%[memq])\n\t"
4822e16c7f6SWei Yongjun 		     "bsrq (%[memq]), %%rax\n\t"
4832e16c7f6SWei Yongjun 		     "jnz 1f\n\t"
4842e16c7f6SWei Yongjun 		     "movl $1, %[rax]\n\t"
4852e16c7f6SWei Yongjun 		     "1:\n\t"
4862e16c7f6SWei Yongjun 		     :[rax]"=m"(rax)
4872e16c7f6SWei Yongjun 		     :[memq]"r"(memq));
4882e16c7f6SWei Yongjun 	report("bsrq r/m, reg", rax == 1);
4892e16c7f6SWei Yongjun }
4902e16c7f6SWei Yongjun 
4917d36db35SAvi Kivity int main()
4927d36db35SAvi Kivity {
4937d36db35SAvi Kivity 	void *mem;
4947d36db35SAvi Kivity 	unsigned long t1, t2;
4957d36db35SAvi Kivity 
4967d36db35SAvi Kivity 	setup_vm();
4977d36db35SAvi Kivity 	mem = vmap(IORAM_BASE_PHYS, IORAM_LEN);
4987d36db35SAvi Kivity 
4997d36db35SAvi Kivity 	// test mov reg, r/m and mov r/m, reg
5007d36db35SAvi Kivity 	t1 = 0x123456789abcdef;
5017d36db35SAvi Kivity 	asm volatile("mov %[t1], (%[mem]) \n\t"
5027d36db35SAvi Kivity 		     "mov (%[mem]), %[t2]"
5037d36db35SAvi Kivity 		     : [t2]"=r"(t2)
5047d36db35SAvi Kivity 		     : [t1]"r"(t1), [mem]"r"(mem)
5057d36db35SAvi Kivity 		     : "memory");
5067d36db35SAvi Kivity 	report("mov reg, r/m (1)", t2 == 0x123456789abcdef);
5077d36db35SAvi Kivity 
5087d36db35SAvi Kivity 	test_cmps(mem);
5097d36db35SAvi Kivity 
5107d36db35SAvi Kivity 	test_push(mem);
5117d36db35SAvi Kivity 	test_pop(mem);
5127d36db35SAvi Kivity 
5137d36db35SAvi Kivity 	test_xchg(mem);
514*5647d55cSWei Yongjun 	test_xadd(mem);
5157d36db35SAvi Kivity 
5167d36db35SAvi Kivity 	test_cr8();
5177d36db35SAvi Kivity 
5187d36db35SAvi Kivity 	test_smsw();
5197d36db35SAvi Kivity 	test_lmsw();
5207d36db35SAvi Kivity 	test_ljmp(mem);
5217d36db35SAvi Kivity 	test_stringio();
5227d36db35SAvi Kivity 	test_incdecnotneg(mem);
523d4655eafSWei Yongjun 	test_btc(mem);
5242e16c7f6SWei Yongjun 	test_bsfbsr(mem);
5257d36db35SAvi Kivity 
5267d36db35SAvi Kivity 	printf("\nSUMMARY: %d tests, %d failures\n", tests, fails);
5277d36db35SAvi Kivity 	return fails ? 1 : 0;
5287d36db35SAvi Kivity }
529