xref: /kvm-unit-tests/x86/emulator.c (revision 762b94763db4d8093e53e19c697bf061f93b1f97)
1 #include "ioram.h"
2 #include "vm.h"
3 #include "libcflat.h"
4 #include "idt.h"
5 
6 #define memset __builtin_memset
7 #define TESTDEV_IO_PORT 0xe0
8 
9 int fails, tests;
10 
11 void report(const char *name, int result)
12 {
13 	++tests;
14 	if (result)
15 		printf("PASS: %s\n", name);
16 	else {
17 		printf("FAIL: %s\n", name);
18 		++fails;
19 	}
20 }
21 
22 static char st1[] = "abcdefghijklmnop";
23 
24 void test_stringio()
25 {
26 	unsigned char r = 0;
27 	asm volatile("cld \n\t"
28 		     "movw %0, %%dx \n\t"
29 		     "rep outsb \n\t"
30 		     : : "i"((short)TESTDEV_IO_PORT),
31 		       "S"(st1), "c"(sizeof(st1) - 1));
32 	asm volatile("inb %1, %0\n\t" : "=a"(r) : "i"((short)TESTDEV_IO_PORT));
33 	report("outsb up", r == st1[sizeof(st1) - 2]); /* last char */
34 
35 	asm volatile("std \n\t"
36 		     "movw %0, %%dx \n\t"
37 		     "rep outsb \n\t"
38 		     : : "i"((short)TESTDEV_IO_PORT),
39 		       "S"(st1 + sizeof(st1) - 2), "c"(sizeof(st1) - 1));
40 	asm volatile("cld \n\t" : : );
41 	asm volatile("in %1, %0\n\t" : "=a"(r) : "i"((short)TESTDEV_IO_PORT));
42 	report("outsb down", r == st1[0]);
43 }
44 
45 void test_cmps_one(unsigned char *m1, unsigned char *m3)
46 {
47 	void *rsi, *rdi;
48 	long rcx, tmp;
49 
50 	rsi = m1; rdi = m3; rcx = 30;
51 	asm volatile("xor %[tmp], %[tmp] \n\t"
52 		     "repe/cmpsb"
53 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
54 		     : : "cc");
55 	report("repe/cmpsb (1)", rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30);
56 
57 	rsi = m1; rdi = m3; rcx = 30;
58 	asm volatile("or $1, %[tmp]\n\t" // clear ZF
59 		     "repe/cmpsb"
60 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
61 		     : : "cc");
62 	report("repe/cmpsb (1.zf)", rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30);
63 
64 	rsi = m1; rdi = m3; rcx = 15;
65 	asm volatile("xor %[tmp], %[tmp] \n\t"
66 		     "repe/cmpsw"
67 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
68 		     : : "cc");
69 	report("repe/cmpsw (1)", rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30);
70 
71 	rsi = m1; rdi = m3; rcx = 7;
72 	asm volatile("xor %[tmp], %[tmp] \n\t"
73 		     "repe/cmpsl"
74 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
75 		     : : "cc");
76 	report("repe/cmpll (1)", rcx == 0 && rsi == m1 + 28 && rdi == m3 + 28);
77 
78 	rsi = m1; rdi = m3; rcx = 4;
79 	asm volatile("xor %[tmp], %[tmp] \n\t"
80 		     "repe/cmpsq"
81 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
82 		     : : "cc");
83 	report("repe/cmpsq (1)", rcx == 0 && rsi == m1 + 32 && rdi == m3 + 32);
84 
85 	rsi = m1; rdi = m3; rcx = 130;
86 	asm volatile("xor %[tmp], %[tmp] \n\t"
87 		     "repe/cmpsb"
88 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
89 		     : : "cc");
90 	report("repe/cmpsb (2)",
91 	       rcx == 29 && rsi == m1 + 101 && rdi == m3 + 101);
92 
93 	rsi = m1; rdi = m3; rcx = 65;
94 	asm volatile("xor %[tmp], %[tmp] \n\t"
95 		     "repe/cmpsw"
96 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
97 		     : : "cc");
98 	report("repe/cmpsw (2)",
99 	       rcx == 14 && rsi == m1 + 102 && rdi == m3 + 102);
100 
101 	rsi = m1; rdi = m3; rcx = 32;
102 	asm volatile("xor %[tmp], %[tmp] \n\t"
103 		     "repe/cmpsl"
104 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
105 		     : : "cc");
106 	report("repe/cmpll (2)",
107 	       rcx == 6 && rsi == m1 + 104 && rdi == m3 + 104);
108 
109 	rsi = m1; rdi = m3; rcx = 16;
110 	asm volatile("xor %[tmp], %[tmp] \n\t"
111 		     "repe/cmpsq"
112 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
113 		     : : "cc");
114 	report("repe/cmpsq (2)",
115 	       rcx == 3 && rsi == m1 + 104 && rdi == m3 + 104);
116 
117 }
118 
119 void test_cmps(void *mem)
120 {
121 	unsigned char *m1 = mem, *m2 = mem + 1024;
122 	unsigned char m3[1024];
123 
124 	for (int i = 0; i < 100; ++i)
125 		m1[i] = m2[i] = m3[i] = i;
126 	for (int i = 100; i < 200; ++i)
127 		m1[i] = (m3[i] = m2[i] = i) + 1;
128 	test_cmps_one(m1, m3);
129 	test_cmps_one(m1, m2);
130 }
131 
132 void test_scas(void *mem)
133 {
134     bool z;
135     void *di;
136 
137     *(ulong *)mem = 0x77665544332211;
138 
139     di = mem;
140     asm ("scasb; setz %0" : "=rm"(z), "+D"(di) : "a"(0xff11));
141     report("scasb match", di == mem + 1 && z);
142 
143     di = mem;
144     asm ("scasb; setz %0" : "=rm"(z), "+D"(di) : "a"(0xff54));
145     report("scasb mismatch", di == mem + 1 && !z);
146 
147     di = mem;
148     asm ("scasw; setz %0" : "=rm"(z), "+D"(di) : "a"(0xff2211));
149     report("scasw match", di == mem + 2 && z);
150 
151     di = mem;
152     asm ("scasw; setz %0" : "=rm"(z), "+D"(di) : "a"(0xffdd11));
153     report("scasw mismatch", di == mem + 2 && !z);
154 
155     di = mem;
156     asm ("scasl; setz %0" : "=rm"(z), "+D"(di) : "a"(0xff44332211ul));
157     report("scasd match", di == mem + 4 && z);
158 
159     di = mem;
160     asm ("scasl; setz %0" : "=rm"(z), "+D"(di) : "a"(0x45332211));
161     report("scasd mismatch", di == mem + 4 && !z);
162 
163     di = mem;
164     asm ("scasq; setz %0" : "=rm"(z), "+D"(di) : "a"(0x77665544332211ul));
165     report("scasq match", di == mem + 8 && z);
166 
167     di = mem;
168     asm ("scasq; setz %0" : "=rm"(z), "+D"(di) : "a"(3));
169     report("scasq mismatch", di == mem + 8 && !z);
170 }
171 
172 void test_cr8(void)
173 {
174 	unsigned long src, dst;
175 
176 	dst = 777;
177 	src = 3;
178 	asm volatile("mov %[src], %%cr8; mov %%cr8, %[dst]"
179 		     : [dst]"+r"(dst), [src]"+r"(src));
180 	report("mov %cr8", dst == 3 && src == 3);
181 }
182 
183 void test_push(void *mem)
184 {
185 	unsigned long tmp;
186 	unsigned long *stack_top = mem + 4096;
187 	unsigned long *new_stack_top;
188 	unsigned long memw = 0x123456789abcdeful;
189 
190 	memset(mem, 0x55, (void *)stack_top - mem);
191 
192 	asm volatile("mov %%rsp, %[tmp] \n\t"
193 		     "mov %[stack_top], %%rsp \n\t"
194 		     "pushq $-7 \n\t"
195 		     "pushq %[reg] \n\t"
196 		     "pushq (%[mem]) \n\t"
197 		     "pushq $-7070707 \n\t"
198 		     "mov %%rsp, %[new_stack_top] \n\t"
199 		     "mov %[tmp], %%rsp"
200 		     : [tmp]"=&r"(tmp), [new_stack_top]"=r"(new_stack_top)
201 		     : [stack_top]"r"(stack_top),
202 		       [reg]"r"(-17l), [mem]"r"(&memw)
203 		     : "memory");
204 
205 	report("push $imm8", stack_top[-1] == -7ul);
206 	report("push %reg", stack_top[-2] == -17ul);
207 	report("push mem", stack_top[-3] == 0x123456789abcdeful);
208 	report("push $imm", stack_top[-4] == -7070707);
209 }
210 
211 void test_pop(void *mem)
212 {
213 	unsigned long tmp;
214 	unsigned long *stack_top = mem + 4096;
215 	unsigned long memw = 0x123456789abcdeful;
216 	static unsigned long tmp2;
217 
218 	memset(mem, 0x55, (void *)stack_top - mem);
219 
220 	asm volatile("pushq %[val] \n\t"
221 		     "popq (%[mem])"
222 		     : : [val]"m"(memw), [mem]"r"(mem) : "memory");
223 	report("pop mem", *(unsigned long *)mem == memw);
224 
225 	memw = 7 - memw;
226 	asm volatile("mov %%rsp, %[tmp] \n\t"
227 		     "mov %[stack_top], %%rsp \n\t"
228 		     "pushq %[val] \n\t"
229 		     "popq %[tmp2] \n\t"
230 		     "mov %[tmp], %%rsp"
231 		     : [tmp]"=&r"(tmp), [tmp2]"=m"(tmp2)
232 		     : [val]"r"(memw), [stack_top]"r"(stack_top)
233 		     : "memory");
234 	report("pop mem (2)", tmp2 == memw);
235 
236 	memw = 129443 - memw;
237 	asm volatile("mov %%rsp, %[tmp] \n\t"
238 		     "mov %[stack_top], %%rsp \n\t"
239 		     "pushq %[val] \n\t"
240 		     "popq %[tmp2] \n\t"
241 		     "mov %[tmp], %%rsp"
242 		     : [tmp]"=&r"(tmp), [tmp2]"=r"(tmp2)
243 		     : [val]"r"(memw), [stack_top]"r"(stack_top)
244 		     : "memory");
245 	report("pop reg", tmp2 == memw);
246 
247 	asm volatile("mov %%rsp, %[tmp] \n\t"
248 		     "mov %[stack_top], %%rsp \n\t"
249 		     "push $1f \n\t"
250 		     "ret \n\t"
251 		     "2: jmp 2b \n\t"
252 		     "1: mov %[tmp], %%rsp"
253 		     : [tmp]"=&r"(tmp) : [stack_top]"r"(stack_top)
254 		     : "memory");
255 	report("ret", 1);
256 }
257 
258 void test_ljmp(void *mem)
259 {
260     unsigned char *m = mem;
261     volatile int res = 1;
262 
263     *(unsigned long**)m = &&jmpf;
264     asm volatile ("data16/mov %%cs, %0":"=m"(*(m + sizeof(unsigned long))));
265     asm volatile ("rex64/ljmp *%0"::"m"(*m));
266     res = 0;
267 jmpf:
268     report("ljmp", res);
269 }
270 
271 void test_incdecnotneg(void *mem)
272 {
273     unsigned long *m = mem, v = 1234;
274     unsigned char *mb = mem, vb = 66;
275 
276     *m = 0;
277 
278     asm volatile ("incl %0":"+m"(*m));
279     report("incl",  *m == 1);
280     asm volatile ("decl %0":"+m"(*m));
281     report("decl",  *m == 0);
282     asm volatile ("incb %0":"+m"(*m));
283     report("incb",  *m == 1);
284     asm volatile ("decb %0":"+m"(*m));
285     report("decb",  *m == 0);
286 
287     asm volatile ("lock incl %0":"+m"(*m));
288     report("lock incl",  *m == 1);
289     asm volatile ("lock decl %0":"+m"(*m));
290     report("lock decl",  *m == 0);
291     asm volatile ("lock incb %0":"+m"(*m));
292     report("lock incb",  *m == 1);
293     asm volatile ("lock decb %0":"+m"(*m));
294     report("lock decb",  *m == 0);
295 
296     *m = v;
297 
298     asm ("lock negq %0" : "+m"(*m)); v = -v;
299     report("lock negl", *m == v);
300     asm ("lock notq %0" : "+m"(*m)); v = ~v;
301     report("lock notl", *m == v);
302 
303     *mb = vb;
304 
305     asm ("lock negb %0" : "+m"(*mb)); vb = -vb;
306     report("lock negb", *mb == vb);
307     asm ("lock notb %0" : "+m"(*mb)); vb = ~vb;
308     report("lock notb", *mb == vb);
309 }
310 
311 void test_smsw(void)
312 {
313 	char mem[16];
314 	unsigned short msw, msw_orig, *pmsw;
315 	int i, zero;
316 
317 	msw_orig = read_cr0();
318 
319 	asm("smsw %0" : "=r"(msw));
320 	report("smsw (1)", msw == msw_orig);
321 
322 	memset(mem, 0, 16);
323 	pmsw = (void *)mem;
324 	asm("smsw %0" : "=m"(pmsw[4]));
325 	zero = 1;
326 	for (i = 0; i < 8; ++i)
327 		if (i != 4 && pmsw[i])
328 			zero = 0;
329 	report("smsw (2)", msw == pmsw[4] && zero);
330 }
331 
332 void test_lmsw(void)
333 {
334 	char mem[16];
335 	unsigned short msw, *pmsw;
336 	unsigned long cr0;
337 
338 	cr0 = read_cr0();
339 
340 	msw = cr0 ^ 8;
341 	asm("lmsw %0" : : "r"(msw));
342 	printf("before %lx after %lx\n", cr0, read_cr0());
343 	report("lmsw (1)", (cr0 ^ read_cr0()) == 8);
344 
345 	pmsw = (void *)mem;
346 	*pmsw = cr0;
347 	asm("lmsw %0" : : "m"(*pmsw));
348 	printf("before %lx after %lx\n", cr0, read_cr0());
349 	report("lmsw (2)", cr0 == read_cr0());
350 
351 	/* lmsw can't clear cr0.pe */
352 	msw = (cr0 & ~1ul) ^ 4;  /* change EM to force trap */
353 	asm("lmsw %0" : : "r"(msw));
354 	report("lmsw (3)", (cr0 ^ read_cr0()) == 4 && (cr0 & 1));
355 
356 	/* back to normal */
357 	msw = cr0;
358 	asm("lmsw %0" : : "r"(msw));
359 }
360 
361 void test_xchg(void *mem)
362 {
363 	unsigned long *memq = mem;
364 	unsigned long rax;
365 
366 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
367 		     "mov %%rax, (%[memq])\n\t"
368 		     "mov $0xfedcba9876543210, %%rax\n\t"
369 		     "xchg %%al, (%[memq])\n\t"
370 		     "mov %%rax, %[rax]\n\t"
371 		     : [rax]"=r"(rax)
372 		     : [memq]"r"(memq)
373 		     : "memory");
374 	report("xchg reg, r/m (1)",
375 	       rax == 0xfedcba98765432ef && *memq == 0x123456789abcd10);
376 
377 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
378 		     "mov %%rax, (%[memq])\n\t"
379 		     "mov $0xfedcba9876543210, %%rax\n\t"
380 		     "xchg %%ax, (%[memq])\n\t"
381 		     "mov %%rax, %[rax]\n\t"
382 		     : [rax]"=r"(rax)
383 		     : [memq]"r"(memq)
384 		     : "memory");
385 	report("xchg reg, r/m (2)",
386 	       rax == 0xfedcba987654cdef && *memq == 0x123456789ab3210);
387 
388 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
389 		     "mov %%rax, (%[memq])\n\t"
390 		     "mov $0xfedcba9876543210, %%rax\n\t"
391 		     "xchg %%eax, (%[memq])\n\t"
392 		     "mov %%rax, %[rax]\n\t"
393 		     : [rax]"=r"(rax)
394 		     : [memq]"r"(memq)
395 		     : "memory");
396 	report("xchg reg, r/m (3)",
397 	       rax == 0x89abcdef && *memq == 0x123456776543210);
398 
399 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
400 		     "mov %%rax, (%[memq])\n\t"
401 		     "mov $0xfedcba9876543210, %%rax\n\t"
402 		     "xchg %%rax, (%[memq])\n\t"
403 		     "mov %%rax, %[rax]\n\t"
404 		     : [rax]"=r"(rax)
405 		     : [memq]"r"(memq)
406 		     : "memory");
407 	report("xchg reg, r/m (4)",
408 	       rax == 0x123456789abcdef && *memq == 0xfedcba9876543210);
409 }
410 
411 void test_xadd(void *mem)
412 {
413 	unsigned long *memq = mem;
414 	unsigned long rax;
415 
416 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
417 		     "mov %%rax, (%[memq])\n\t"
418 		     "mov $0xfedcba9876543210, %%rax\n\t"
419 		     "xadd %%al, (%[memq])\n\t"
420 		     "mov %%rax, %[rax]\n\t"
421 		     : [rax]"=r"(rax)
422 		     : [memq]"r"(memq)
423 		     : "memory");
424 	report("xadd reg, r/m (1)",
425 	       rax == 0xfedcba98765432ef && *memq == 0x123456789abcdff);
426 
427 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
428 		     "mov %%rax, (%[memq])\n\t"
429 		     "mov $0xfedcba9876543210, %%rax\n\t"
430 		     "xadd %%ax, (%[memq])\n\t"
431 		     "mov %%rax, %[rax]\n\t"
432 		     : [rax]"=r"(rax)
433 		     : [memq]"r"(memq)
434 		     : "memory");
435 	report("xadd reg, r/m (2)",
436 	       rax == 0xfedcba987654cdef && *memq == 0x123456789abffff);
437 
438 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
439 		     "mov %%rax, (%[memq])\n\t"
440 		     "mov $0xfedcba9876543210, %%rax\n\t"
441 		     "xadd %%eax, (%[memq])\n\t"
442 		     "mov %%rax, %[rax]\n\t"
443 		     : [rax]"=r"(rax)
444 		     : [memq]"r"(memq)
445 		     : "memory");
446 	report("xadd reg, r/m (3)",
447 	       rax == 0x89abcdef && *memq == 0x1234567ffffffff);
448 
449 	asm volatile("mov $0x123456789abcdef, %%rax\n\t"
450 		     "mov %%rax, (%[memq])\n\t"
451 		     "mov $0xfedcba9876543210, %%rax\n\t"
452 		     "xadd %%rax, (%[memq])\n\t"
453 		     "mov %%rax, %[rax]\n\t"
454 		     : [rax]"=r"(rax)
455 		     : [memq]"r"(memq)
456 		     : "memory");
457 	report("xadd reg, r/m (4)",
458 	       rax == 0x123456789abcdef && *memq == 0xffffffffffffffff);
459 }
460 
461 void test_btc(void *mem)
462 {
463 	unsigned int *a = mem;
464 
465 	memset(mem, 0, 3 * sizeof(unsigned int));
466 
467 	asm ("btcl $32, %0" :: "m"(a[0]) : "memory");
468 	asm ("btcl $1, %0" :: "m"(a[1]) : "memory");
469 	asm ("btcl %1, %0" :: "m"(a[0]), "r"(66) : "memory");
470 	report("btcl imm8, r/m", a[0] == 1 && a[1] == 2 && a[2] == 4);
471 
472 	asm ("btcl %1, %0" :: "m"(a[3]), "r"(-1) : "memory");
473 	report("btcl reg, r/m", a[0] == 1 && a[1] == 2 && a[2] == 0x80000004);
474 }
475 
476 void test_bsfbsr(void *mem)
477 {
478 	unsigned long *memq = mem, rax;
479 
480 	asm volatile("movw $0xC000, (%[memq])\n\t"
481 		     "bsfw (%[memq]), %%ax\n\t"
482 		     ::[memq]"r"(memq));
483 	asm ("mov %%rax, %[rax]": [rax]"=m"(rax));
484 	report("bsfw r/m, reg", rax == 14);
485 
486 	asm volatile("movl $0xC0000000, (%[memq])\n\t"
487 		     "bsfl (%[memq]), %%eax\n\t"
488 		     ::[memq]"r"(memq));
489 	asm ("mov %%rax, %[rax]": [rax]"=m"(rax));
490 	report("bsfl r/m, reg", rax == 30);
491 
492 	asm volatile("movq $0xC00000000000, %%rax\n\t"
493 		     "movq %%rax, (%[memq])\n\t"
494 		     "bsfq (%[memq]), %%rax\n\t"
495 		     ::[memq]"r"(memq));
496 	asm ("mov %%rax, %[rax]": [rax]"=m"(rax));
497 	report("bsfq r/m, reg", rax == 46);
498 
499 	asm volatile("movq $0, %%rax\n\t"
500 		     "movq %%rax, (%[memq])\n\t"
501 		     "bsfq (%[memq]), %%rax\n\t"
502 		     "jnz 1f\n\t"
503 		     "movl $1, %[rax]\n\t"
504 		     "1:\n\t"
505 		     :[rax]"=m"(rax)
506 		     :[memq]"r"(memq));
507 	report("bsfq r/m, reg", rax == 1);
508 
509 	asm volatile("movw $0xC000, (%[memq])\n\t"
510 		     "bsrw (%[memq]), %%ax\n\t"
511 		     ::[memq]"r"(memq));
512 	asm ("mov %%rax, %[rax]": [rax]"=m"(rax));
513 	report("bsrw r/m, reg", rax == 15);
514 
515 	asm volatile("movl $0xC0000000, (%[memq])\n\t"
516 		     "bsrl (%[memq]), %%eax\n\t"
517 		     ::[memq]"r"(memq));
518 	asm ("mov %%rax, %[rax]": [rax]"=m"(rax));
519 	report("bsrl r/m, reg", rax == 31);
520 
521 	asm volatile("movq $0xC00000000000, %%rax\n\t"
522 		     "movq %%rax, (%[memq])\n\t"
523 		     "bsrq (%[memq]), %%rax\n\t"
524 		     ::[memq]"r"(memq));
525 	asm ("mov %%rax, %[rax]": [rax]"=m"(rax));
526 	report("bsrq r/m, reg", rax == 47);
527 
528 	asm volatile("movq $0, %%rax\n\t"
529 		     "movq %%rax, (%[memq])\n\t"
530 		     "bsrq (%[memq]), %%rax\n\t"
531 		     "jnz 1f\n\t"
532 		     "movl $1, %[rax]\n\t"
533 		     "1:\n\t"
534 		     :[rax]"=m"(rax)
535 		     :[memq]"r"(memq));
536 	report("bsrq r/m, reg", rax == 1);
537 }
538 
539 static void test_imul(ulong *mem)
540 {
541     ulong a;
542 
543     *mem = 51; a = 0x1234567812345678UL;
544     asm ("imulw %1, %%ax" : "+a"(a) : "m"(*mem));
545     report("imul ax, mem", a == 0x12345678123439e8);
546 
547     *mem = 51; a = 0x1234567812345678UL;
548     asm ("imull %1, %%eax" : "+a"(a) : "m"(*mem));
549     report("imul eax, mem", a == 0xa06d39e8);
550 
551     *mem = 51; a = 0x1234567812345678UL;
552     asm ("imulq %1, %%rax" : "+a"(a) : "m"(*mem));
553     report("imul rax, mem", a == 0xA06D39EBA06D39E8UL);
554 
555     *mem  = 0x1234567812345678UL; a = 0x8765432187654321L;
556     asm ("imulw $51, %1, %%ax" : "+a"(a) : "m"(*mem));
557     report("imul ax, mem, imm8", a == 0x87654321876539e8);
558 
559     *mem = 0x1234567812345678UL;
560     asm ("imull $51, %1, %%eax" : "+a"(a) : "m"(*mem));
561     report("imul eax, mem, imm8", a == 0xa06d39e8);
562 
563     *mem = 0x1234567812345678UL;
564     asm ("imulq $51, %1, %%rax" : "+a"(a) : "m"(*mem));
565     report("imul rax, mem, imm8", a == 0xA06D39EBA06D39E8UL);
566 
567     *mem  = 0x1234567812345678UL; a = 0x8765432187654321L;
568     asm ("imulw $311, %1, %%ax" : "+a"(a) : "m"(*mem));
569     report("imul ax, mem, imm", a == 0x8765432187650bc8);
570 
571     *mem = 0x1234567812345678UL;
572     asm ("imull $311, %1, %%eax" : "+a"(a) : "m"(*mem));
573     report("imul eax, mem, imm", a == 0x1d950bc8);
574 
575     *mem = 0x1234567812345678UL;
576     asm ("imulq $311, %1, %%rax" : "+a"(a) : "m"(*mem));
577     report("imul rax, mem, imm", a == 0x1D950BDE1D950BC8L);
578 }
579 
580 static void test_div(long *mem)
581 {
582     long a, d;
583     u8 ex = 1;
584 
585     *mem = 0; a = 1; d = 2;
586     asm (ASM_TRY("1f") "divq %3; movb $0, %2; 1:"
587 	 : "+a"(a), "+d"(d), "+q"(ex) : "m"(*mem));
588     report("divq (fault)", a == 1 && d == 2 && ex);
589 
590     *mem = 987654321098765UL; a = 123456789012345UL; d = 123456789012345UL;
591     asm (ASM_TRY("1f") "divq %3; movb $0, %2; 1:"
592 	 : "+a"(a), "+d"(d), "+q"(ex) : "m"(*mem));
593     report("divq (1)",
594 	   a == 0x1ffffffb1b963b33ul && d == 0x273ba4384ede2ul && !ex);
595 }
596 
597 int main()
598 {
599 	void *mem;
600 	unsigned long t1, t2;
601 
602 	setup_vm();
603 	setup_idt();
604 	mem = vmap(IORAM_BASE_PHYS, IORAM_LEN);
605 
606 	// test mov reg, r/m and mov r/m, reg
607 	t1 = 0x123456789abcdef;
608 	asm volatile("mov %[t1], (%[mem]) \n\t"
609 		     "mov (%[mem]), %[t2]"
610 		     : [t2]"=r"(t2)
611 		     : [t1]"r"(t1), [mem]"r"(mem)
612 		     : "memory");
613 	report("mov reg, r/m (1)", t2 == 0x123456789abcdef);
614 
615 	test_cmps(mem);
616 	test_scas(mem);
617 
618 	test_push(mem);
619 	test_pop(mem);
620 
621 	test_xchg(mem);
622 	test_xadd(mem);
623 
624 	test_cr8();
625 
626 	test_smsw();
627 	test_lmsw();
628 	test_ljmp(mem);
629 	test_stringio();
630 	test_incdecnotneg(mem);
631 	test_btc(mem);
632 	test_bsfbsr(mem);
633 	test_imul(mem);
634 	test_div(mem);
635 
636 	printf("\nSUMMARY: %d tests, %d failures\n", tests, fails);
637 	return fails ? 1 : 0;
638 }
639