xref: /kvm-unit-tests/x86/emulator.c (revision b36f35a82ff4cec5f71a68aa782332e2bc3488f7)
1 #include <asm/debugreg.h>
2 
3 #include "ioram.h"
4 #include "vm.h"
5 #include "libcflat.h"
6 #include "desc.h"
7 #include "types.h"
8 #include "processor.h"
9 #include "vmalloc.h"
10 #include "alloc_page.h"
11 #include "usermode.h"
12 
13 #define TESTDEV_IO_PORT 0xe0
14 
15 static int exceptions;
16 
17 #ifdef __x86_64__
18 #include "emulator64.c"
19 #endif
20 
21 static char st1[] = "abcdefghijklmnop";
22 
23 static void test_stringio(void)
24 {
25 	unsigned char r = 0;
26 	asm volatile("cld \n\t"
27 		     "movw %0, %%dx \n\t"
28 		     "rep outsb \n\t"
29 		     : : "i"((short)TESTDEV_IO_PORT),
30 		       "S"(st1), "c"(sizeof(st1) - 1));
31 	asm volatile("inb %1, %0\n\t" : "=a"(r) : "i"((short)TESTDEV_IO_PORT));
32 	report(r == st1[sizeof(st1) - 2], "outsb up"); /* last char */
33 
34 	asm volatile("std \n\t"
35 		     "movw %0, %%dx \n\t"
36 		     "rep outsb \n\t"
37 		     : : "i"((short)TESTDEV_IO_PORT),
38 		       "S"(st1 + sizeof(st1) - 2), "c"(sizeof(st1) - 1));
39 	asm volatile("cld \n\t" : : );
40 	asm volatile("in %1, %0\n\t" : "=a"(r) : "i"((short)TESTDEV_IO_PORT));
41 	report(r == st1[0], "outsb down");
42 }
43 
44 static void test_cmps_one(unsigned char *m1, unsigned char *m3)
45 {
46 	void *rsi, *rdi;
47 	long rcx, tmp;
48 
49 	rsi = m1; rdi = m3; rcx = 30;
50 	asm volatile("xor %[tmp], %[tmp] \n\t"
51 		     "repe cmpsb"
52 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
53 		     : : "cc");
54 	report(rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30, "repe/cmpsb (1)");
55 
56 	rsi = m1; rdi = m3; rcx = 30;
57 	asm volatile("or $1, %[tmp]\n\t" // clear ZF
58 		     "repe cmpsb"
59 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
60 		     : : "cc");
61 	report(rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30,
62 	       "repe cmpsb (1.zf)");
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(rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30, "repe cmpsw (1)");
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(rcx == 0 && rsi == m1 + 28 && rdi == m3 + 28, "repe cmpll (1)");
77 
78 #ifdef __x86_64__
79 	rsi = m1; rdi = m3; rcx = 4;
80 	asm volatile("xor %[tmp], %[tmp] \n\t"
81 		     "repe cmpsq"
82 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
83 		     : : "cc");
84 	report(rcx == 0 && rsi == m1 + 32 && rdi == m3 + 32, "repe cmpsq (1)");
85 #endif
86 
87 	rsi = m1; rdi = m3; rcx = 130;
88 	asm volatile("xor %[tmp], %[tmp] \n\t"
89 		     "repe cmpsb"
90 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
91 		     : : "cc");
92 	report(rcx == 29 && rsi == m1 + 101 && rdi == m3 + 101,
93 	       "repe cmpsb (2)");
94 
95 	rsi = m1; rdi = m3; rcx = 65;
96 	asm volatile("xor %[tmp], %[tmp] \n\t"
97 		     "repe cmpsw"
98 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
99 		     : : "cc");
100 	report(rcx == 14 && rsi == m1 + 102 && rdi == m3 + 102,
101 	       "repe cmpsw (2)");
102 
103 	rsi = m1; rdi = m3; rcx = 32;
104 	asm volatile("xor %[tmp], %[tmp] \n\t"
105 		     "repe cmpsl"
106 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
107 		     : : "cc");
108 	report(rcx == 6 && rsi == m1 + 104 && rdi == m3 + 104,
109 	       "repe cmpll (2)");
110 
111 #ifdef __x86_64__
112 	rsi = m1; rdi = m3; rcx = 16;
113 	asm volatile("xor %[tmp], %[tmp] \n\t"
114 		     "repe cmpsq"
115 		     : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp)
116 		     : : "cc");
117 	report(rcx == 3 && rsi == m1 + 104 && rdi == m3 + 104,
118 	       "repe cmpsq (2)");
119 #endif
120 }
121 
122 static void test_cmps(void *mem)
123 {
124 	unsigned char *m1 = mem, *m2 = mem + 1024;
125 	unsigned char m3[1024];
126 
127 	for (int i = 0; i < 100; ++i)
128 		m1[i] = m2[i] = m3[i] = i;
129 	for (int i = 100; i < 200; ++i)
130 		m1[i] = (m3[i] = m2[i] = i) + 1;
131 	test_cmps_one(m1, m3);
132 	test_cmps_one(m1, m2);
133 }
134 
135 static void test_scas(void *mem)
136 {
137     bool z;
138     void *di;
139 
140     *(uint64_t *)mem = 0x77665544332211;
141 
142     di = mem;
143     asm ("scasb; setz %0" : "=rm"(z), "+D"(di) : "a"(0xff11));
144     report(di == mem + 1 && z, "scasb match");
145 
146     di = mem;
147     asm ("scasb; setz %0" : "=rm"(z), "+D"(di) : "a"(0xff54));
148     report(di == mem + 1 && !z, "scasb mismatch");
149 
150     di = mem;
151     asm ("scasw; setz %0" : "=rm"(z), "+D"(di) : "a"(0xff2211));
152     report(di == mem + 2 && z, "scasw match");
153 
154     di = mem;
155     asm ("scasw; setz %0" : "=rm"(z), "+D"(di) : "a"(0xffdd11));
156     report(di == mem + 2 && !z, "scasw mismatch");
157 
158     di = mem;
159     asm ("scasl; setz %0" : "=rm"(z), "+D"(di) : "a"((ulong)0xff44332211ul));
160     report(di == mem + 4 && z, "scasd match");
161 
162     di = mem;
163     asm ("scasl; setz %0" : "=rm"(z), "+D"(di) : "a"(0x45332211));
164     report(di == mem + 4 && !z, "scasd mismatch");
165 
166 #ifdef __x86_64__
167     di = mem;
168     asm ("scasq; setz %0" : "=rm"(z), "+D"(di) : "a"(0x77665544332211ul));
169     report(di == mem + 8 && z, "scasq match");
170 
171     di = mem;
172     asm ("scasq; setz %0" : "=rm"(z), "+D"(di) : "a"(3));
173     report(di == mem + 8 && !z, "scasq mismatch");
174 #endif
175 }
176 
177 static void test_incdecnotneg(void *mem)
178 {
179 	unsigned long *m = mem, v = 1234;
180 	unsigned char *mb = mem, vb = 66;
181 
182 	*m = 0;
183 
184 	asm volatile ("incl %0":"+m"(*m));
185 	report(*m == 1, "incl");
186 	asm volatile ("decl %0":"+m"(*m));
187 	report(*m == 0, "decl");
188 	asm volatile ("incb %0":"+m"(*m));
189 	report(*m == 1, "incb");
190 	asm volatile ("decb %0":"+m"(*m));
191 	report(*m == 0, "decb");
192 
193 	asm volatile ("lock incl %0":"+m"(*m));
194 	report(*m == 1, "lock incl");
195 	asm volatile ("lock decl %0":"+m"(*m));
196 	report(*m == 0, "lock decl");
197 	asm volatile ("lock incb %0":"+m"(*m));
198 	report(*m == 1, "lock incb");
199 	asm volatile ("lock decb %0":"+m"(*m));
200 	report(*m == 0, "lock decb");
201 
202 	*m = v;
203 
204 #ifdef __x86_64__
205 	asm ("lock negq %0" : "+m"(*m)); v = -v;
206 	report(*m == v, "lock negl");
207 	asm ("lock notq %0" : "+m"(*m)); v = ~v;
208 	report(*m == v, "lock notl");
209 #endif
210 
211 	*mb = vb;
212 
213 	asm ("lock negb %0" : "+m"(*mb)); vb = -vb;
214 	report(*mb == vb, "lock negb");
215 	asm ("lock notb %0" : "+m"(*mb)); vb = ~vb;
216 	report(*mb == vb, "lock notb");
217 }
218 
219 static void test_smsw(unsigned long *h_mem)
220 {
221 	char mem[16];
222 	unsigned short msw, msw_orig, *pmsw;
223 	int i, zero;
224 
225 	msw_orig = read_cr0();
226 
227 	asm("smsw %0" : "=r"(msw));
228 	report(msw == msw_orig, "smsw (1)");
229 
230 	memset(mem, 0, 16);
231 	pmsw = (void *)mem;
232 	asm("smsw %0" : "=m"(pmsw[4]));
233 	zero = 1;
234 	for (i = 0; i < 8; ++i)
235 		if (i != 4 && pmsw[i])
236 			zero = 0;
237 	report(msw == pmsw[4] && zero, "smsw (2)");
238 
239 	/* Trigger exit on smsw */
240 	*h_mem = -1ul;
241 	asm volatile("smsw %0" : "+m"(*h_mem));
242 	report(msw == (unsigned short)*h_mem &&
243 	       (*h_mem & ~0xfffful) == (-1ul & ~0xfffful), "smsw (3)");
244 }
245 
246 static void test_lmsw(void)
247 {
248 	char mem[16];
249 	unsigned short msw, *pmsw;
250 	unsigned long cr0;
251 
252 	cr0 = read_cr0();
253 
254 	msw = cr0 ^ 8;
255 	asm("lmsw %0" : : "r"(msw));
256 	printf("before %lx after %lx\n", cr0, read_cr0());
257 	report((cr0 ^ read_cr0()) == 8, "lmsw (1)");
258 
259 	pmsw = (void *)mem;
260 	*pmsw = cr0;
261 	asm("lmsw %0" : : "m"(*pmsw));
262 	printf("before %lx after %lx\n", cr0, read_cr0());
263 	report(cr0 == read_cr0(), "lmsw (2)");
264 
265 	/* lmsw can't clear cr0.pe */
266 	msw = (cr0 & ~1ul) ^ 4;  /* change EM to force trap */
267 	asm("lmsw %0" : : "r"(msw));
268 	report((cr0 ^ read_cr0()) == 4 && (cr0 & 1), "lmsw (3)");
269 
270 	/* back to normal */
271 	msw = cr0;
272 	asm("lmsw %0" : : "r"(msw));
273 }
274 
275 static void test_btc(void *mem)
276 {
277 	unsigned int *a = mem;
278 
279 	memset(mem, 0, 4 * sizeof(unsigned int));
280 
281 	asm ("btcl $32, %0" :: "m"(a[0]) : "memory");
282 	asm ("btcl $1, %0" :: "m"(a[1]) : "memory");
283 	asm ("btcl %1, %0" :: "m"(a[0]), "r"(66) : "memory");
284 	report(a[0] == 1 && a[1] == 2 && a[2] == 4, "btcl imm8, r/m");
285 
286 	asm ("btcl %1, %0" :: "m"(a[3]), "r"(-1) : "memory");
287 	report(a[0] == 1 && a[1] == 2 && a[2] == 0x80000004, "btcl reg, r/m");
288 
289 #ifdef __x86_64__
290 	asm ("btcq %1, %0" : : "m"(a[2]), "r"(-1l) : "memory");
291 	report(a[0] == 1 && a[1] == 0x80000002 && a[2] == 0x80000004 && a[3] == 0,
292 	       "btcq reg, r/m");
293 #endif
294 }
295 
296 static void test_bsfbsr(void *mem)
297 {
298 	unsigned eax, *meml = mem;
299 	unsigned short ax, *memw = mem;
300 #ifdef __x86_64__
301 	unsigned long rax, *memq = mem;
302 	unsigned char z;
303 #endif
304 
305 	*memw = 0xc000;
306 	asm("bsfw %[mem], %[a]" : [a]"=a"(ax) : [mem]"m"(*memw));
307 	report(ax == 14, "bsfw r/m, reg");
308 
309 	*meml = 0xc0000000;
310 	asm("bsfl %[mem], %[a]" : [a]"=a"(eax) : [mem]"m"(*meml));
311 	report(eax == 30, "bsfl r/m, reg");
312 
313 #ifdef __x86_64__
314 	*memq = 0xc00000000000;
315 	asm("bsfq %[mem], %[a]" : [a]"=a"(rax) : [mem]"m"(*memq));
316 	report(rax == 46, "bsfq r/m, reg");
317 
318 	*memq = 0;
319 	asm("bsfq %[mem], %[a]; setz %[z]"
320 	    : [a]"=a"(rax), [z]"=rm"(z) : [mem]"m"(*memq));
321 	report(z == 1, "bsfq r/m, reg");
322 #endif
323 
324 	*memw = 0xc000;
325 	asm("bsrw %[mem], %[a]" : [a]"=a"(ax) : [mem]"m"(*memw));
326 	report(ax == 15, "bsrw r/m, reg");
327 
328 	*meml = 0xc0000000;
329 	asm("bsrl %[mem], %[a]" : [a]"=a"(eax) : [mem]"m"(*meml));
330 	report(eax == 31, "bsrl r/m, reg");
331 
332 #ifdef __x86_64__
333 	*memq = 0xc00000000000;
334 	asm("bsrq %[mem], %[a]" : [a]"=a"(rax) : [mem]"m"(*memq));
335 	report(rax == 47, "bsrq r/m, reg");
336 
337 	*memq = 0;
338 	asm("bsrq %[mem], %[a]; setz %[z]"
339 	    : [a]"=a"(rax), [z]"=rm"(z) : [mem]"m"(*memq));
340 	report(z == 1, "bsrq r/m, reg");
341 #endif
342 }
343 
344 static void test_imul(uint64_t *mem)
345 {
346 	ulong a;
347 
348 	*mem = 51; a = 0x1234567812345678ULL & -1ul;;
349 	asm ("imulw %1, %%ax" : "+a"(a) : "m"(*mem));
350 	report(a == (0x12345678123439e8ULL & -1ul), "imul ax, mem");
351 
352 	*mem = 51; a = 0x1234567812345678ULL & -1ul;;
353 	asm ("imull %1, %%eax" : "+a"(a) : "m"(*mem));
354 	report(a == 0xa06d39e8, "imul eax, mem");
355 
356 	*mem  = 0x1234567812345678ULL; a = 0x8765432187654321ULL & -1ul;
357 	asm ("imulw $51, %1, %%ax" : "+a"(a) : "m"(*mem));
358 	report(a == (0x87654321876539e8ULL & -1ul), "imul ax, mem, imm8");
359 
360 	*mem = 0x1234567812345678ULL;
361 	asm ("imull $51, %1, %%eax" : "+a"(a) : "m"(*mem));
362 	report(a == 0xa06d39e8, "imul eax, mem, imm8");
363 
364 	*mem  = 0x1234567812345678ULL; a = 0x8765432187654321ULL & -1ul;
365 	asm ("imulw $311, %1, %%ax" : "+a"(a) : "m"(*mem));
366 	report(a == (0x8765432187650bc8ULL & -1ul), "imul ax, mem, imm");
367 
368 	*mem = 0x1234567812345678ULL;
369 	asm ("imull $311, %1, %%eax" : "+a"(a) : "m"(*mem));
370 	report(a == 0x1d950bc8, "imul eax, mem, imm");
371 
372 #ifdef __x86_64__
373 	*mem = 51; a = 0x1234567812345678UL;
374 	asm ("imulq %1, %%rax" : "+a"(a) : "m"(*mem));
375 	report(a == 0xA06D39EBA06D39E8UL, "imul rax, mem");
376 
377 	*mem = 0x1234567812345678UL;
378 	asm ("imulq $51, %1, %%rax" : "+a"(a) : "m"(*mem));
379 	report(a == 0xA06D39EBA06D39E8UL, "imul rax, mem, imm8");
380 
381 	*mem = 0x1234567812345678UL;
382 	asm ("imulq $311, %1, %%rax" : "+a"(a) : "m"(*mem));
383 	report(a == 0x1D950BDE1D950BC8L, "imul rax, mem, imm");
384 #endif
385 }
386 typedef unsigned __attribute__((vector_size(16))) sse128;
387 
388 static bool sseeq(uint32_t *v1, uint32_t *v2)
389 {
390 	bool ok = true;
391 	int i;
392 
393 	for (i = 0; i < 4; ++i)
394 		ok &= v1[i] == v2[i];
395 
396 	return ok;
397 }
398 
399 static __attribute__((target("sse2"))) void test_sse(uint32_t *mem)
400 {
401 	sse128 vv;
402 	uint32_t *v = (uint32_t *)&vv;
403 
404 	write_cr0(read_cr0() & ~6); /* EM, TS */
405 	write_cr4(read_cr4() | 0x200); /* OSFXSR */
406 	memset(&vv, 0, sizeof(vv));
407 
408 #define TEST_RW_SSE(insn) do { \
409 		v[0] = 1; v[1] = 2; v[2] = 3; v[3] = 4; \
410 		asm(insn " %1, %0" : "=m"(*mem) : "x"(vv) : "memory"); \
411 		report(sseeq(v, mem), insn " (read)"); \
412 		mem[0] = 5; mem[1] = 6; mem[2] = 7; mem[3] = 8; \
413 		asm(insn " %1, %0" : "=x"(vv) : "m"(*mem) : "memory"); \
414 		report(sseeq(v, mem), insn " (write)"); \
415 } while (0)
416 
417 	TEST_RW_SSE("movdqu");
418 	TEST_RW_SSE("movaps");
419 	TEST_RW_SSE("movapd");
420 	TEST_RW_SSE("movups");
421 	TEST_RW_SSE("movupd");
422 #undef TEST_RW_SSE
423 }
424 
425 static void unaligned_movaps_handler(struct ex_regs *regs)
426 {
427 	extern char unaligned_movaps_cont;
428 
429 	++exceptions;
430 	regs->rip = (ulong)&unaligned_movaps_cont;
431 }
432 
433 static void cross_movups_handler(struct ex_regs *regs)
434 {
435 	extern char cross_movups_cont;
436 
437 	++exceptions;
438 	regs->rip = (ulong)&cross_movups_cont;
439 }
440 
441 static __attribute__((target("sse2"))) void test_sse_exceptions(void *cross_mem)
442 {
443 	sse128 vv;
444 	uint32_t *v = (uint32_t *)&vv;
445 	uint32_t *mem;
446 	uint8_t *bytes = cross_mem; // aligned on PAGE_SIZE*2
447 	void *page2 = (void *)(&bytes[4096]);
448 	struct pte_search search;
449 	pteval_t orig_pte;
450 	handler old;
451 
452 	// setup memory for unaligned access
453 	mem = (uint32_t *)(&bytes[8]);
454 
455 	// test unaligned access for movups, movupd and movaps
456 	v[0] = 1; v[1] = 2; v[2] = 3; v[3] = 4;
457 	mem[0] = 5; mem[1] = 6; mem[2] = 8; mem[3] = 9;
458 	asm("movups %1, %0" : "=m"(*mem) : "x"(vv) : "memory");
459 	report(sseeq(v, mem), "movups unaligned");
460 
461 	v[0] = 1; v[1] = 2; v[2] = 3; v[3] = 4;
462 	mem[0] = 5; mem[1] = 6; mem[2] = 7; mem[3] = 8;
463 	asm("movupd %1, %0" : "=m"(*mem) : "x"(vv) : "memory");
464 	report(sseeq(v, mem), "movupd unaligned");
465 	exceptions = 0;
466 	old = handle_exception(GP_VECTOR, unaligned_movaps_handler);
467 	asm("movaps %1, %0\n\t unaligned_movaps_cont:"
468 			: "=m"(*mem) : "x"(vv));
469 	handle_exception(GP_VECTOR, old);
470 	report(exceptions == 1, "unaligned movaps exception");
471 
472 	// setup memory for cross page access
473 	mem = (uint32_t *)(&bytes[4096-8]);
474 	v[0] = 1; v[1] = 2; v[2] = 3; v[3] = 4;
475 	mem[0] = 5; mem[1] = 6; mem[2] = 7; mem[3] = 8;
476 
477 	asm("movups %1, %0" : "=m"(*mem) : "x"(vv) : "memory");
478 	report(sseeq(v, mem), "movups unaligned crosspage");
479 
480 	// invalidate second page
481 	search = find_pte_level(current_page_table(), page2, 1);
482 	orig_pte = *search.pte;
483 	install_pte(current_page_table(), 1, page2, 0, NULL);
484 	invlpg(page2);
485 
486 	exceptions = 0;
487 	old = handle_exception(PF_VECTOR, cross_movups_handler);
488 	asm("movups %1, %0\n\t cross_movups_cont:" : "=m"(*mem) : "x"(vv) :
489 			"memory");
490 	handle_exception(PF_VECTOR, old);
491 	report(exceptions == 1, "movups crosspage exception");
492 
493 	// restore invalidated page
494 	install_pte(current_page_table(), 1, page2, orig_pte, NULL);
495 }
496 
497 static void test_shld_shrd(u32 *mem)
498 {
499 	*mem = 0x12345678;
500 	asm("shld %2, %1, %0" : "+m"(*mem) : "r"(0xaaaaaaaaU), "c"((u8)3));
501 	report(*mem == ((0x12345678 << 3) | 5), "shld (cl)");
502 	*mem = 0x12345678;
503 	asm("shrd %2, %1, %0" : "+m"(*mem) : "r"(0x55555555U), "c"((u8)3));
504 	report(*mem == ((0x12345678 >> 3) | (5u << 29)), "shrd (cl)");
505 }
506 
507 static void test_smsw_reg(uint64_t *mem)
508 {
509 	unsigned long cr0 = read_cr0();
510 	unsigned long rax;
511 	const unsigned long in_rax = 0x1234567890abcdefull & -1ul;
512 
513 	asm(KVM_FEP "smsww %w0\n\t" : "=a" (rax) : "0" (in_rax));
514 	report((u16)rax == (u16)cr0 && rax >> 16 == in_rax >> 16,
515 	       "16-bit smsw reg");
516 
517 	asm(KVM_FEP "smswl %k0\n\t" : "=a" (rax) : "0" (in_rax));
518 	report(rax == (u32)cr0, "32-bit smsw reg");
519 
520 #ifdef __x86_64__
521 	asm(KVM_FEP "smswq %q0\n\t" : "=a" (rax) : "0" (in_rax));
522 	report(rax == cr0, "64-bit smsw reg");
523 #endif
524 }
525 
526 static void test_nop(uint64_t *mem)
527 {
528 	unsigned long rax;
529 	const unsigned long in_rax = 0x12345678ul;
530 	asm(KVM_FEP "nop\n\t" : "=a" (rax) : "0" (in_rax));
531 	report(rax == in_rax, "nop");
532 }
533 
534 static void test_mov_dr(uint64_t *mem)
535 {
536 	unsigned long rax;
537 
538 	asm(KVM_FEP "mov %0, %%dr6\n\t"
539 	    KVM_FEP "mov %%dr6, %0\n\t" : "=a" (rax) : "a" (0));
540 
541 	if (this_cpu_has(X86_FEATURE_RTM))
542 		report(rax == (DR6_ACTIVE_LOW & ~DR6_RTM), "mov_dr6");
543 	else
544 		report(rax == DR6_ACTIVE_LOW, "mov_dr6");
545 }
546 
547 static void test_illegal_lea(void)
548 {
549 	unsigned int vector;
550 
551 	asm volatile (ASM_TRY_FEP("1f")
552 		      ".byte 0x8d; .byte 0xc0\n\t"
553 		      "1:"
554 		      : : : "memory", "eax");
555 
556 	vector = exception_vector();
557 	report(vector == UD_VECTOR,
558 	       "Wanted #UD on LEA with /reg, got vector = %u", vector);
559 }
560 
561 static void test_crosspage_mmio(volatile uint8_t *mem)
562 {
563 	volatile uint16_t w, *pw;
564 
565 	pw = (volatile uint16_t *)&mem[4095];
566 	mem[4095] = 0x99;
567 	mem[4096] = 0x77;
568 	asm volatile("mov %1, %0" : "=r"(w) : "m"(*pw) : "memory");
569 	report(w == 0x7799, "cross-page mmio read");
570 	asm volatile("mov %1, %0" : "=m"(*pw) : "r"((uint16_t)0x88aa));
571 	report(mem[4095] == 0xaa && mem[4096] == 0x88, "cross-page mmio write");
572 }
573 
574 static void test_string_io_mmio(volatile uint8_t *mem)
575 {
576 	/* Cross MMIO pages.*/
577 	volatile uint8_t *mmio = mem + 4032;
578 
579 	asm volatile("outw %%ax, %%dx  \n\t" : : "a"(0x9999), "d"(TESTDEV_IO_PORT));
580 
581 	asm volatile ("cld; rep insb" : : "d" (TESTDEV_IO_PORT), "D" (mmio), "c" (1024));
582 
583 	report(mmio[1023] == 0x99, "string_io_mmio");
584 }
585 
586 /* kvm doesn't allow lidt/lgdt from mmio, so the test is disabled */
587 #if 0
588 static void test_lgdt_lidt(volatile uint8_t *mem)
589 {
590 	struct descriptor_table_ptr orig, fresh = {};
591 
592 	sgdt(&orig);
593 	*(struct descriptor_table_ptr *)mem = (struct descriptor_table_ptr) {
594 		.limit = 0xf234,
595 		.base = 0x12345678abcd,
596 	};
597 	cli();
598 	asm volatile("lgdt %0" : : "m"(*(struct descriptor_table_ptr *)mem));
599 	sgdt(&fresh);
600 	lgdt(&orig);
601 	sti();
602 	report(orig.limit == fresh.limit && orig.base == fresh.base, "lgdt (long address)");
603 
604 	sidt(&orig);
605 	*(struct descriptor_table_ptr *)mem = (struct descriptor_table_ptr) {
606 		.limit = 0x432f,
607 		.base = 0xdbca87654321,
608 	};
609 	cli();
610 	asm volatile("lidt %0" : : "m"(*(struct descriptor_table_ptr *)mem));
611 	sidt(&fresh);
612 	lidt(&orig);
613 	sti();
614 	report(orig.limit == fresh.limit && orig.base == fresh.base, "lidt (long address)");
615 }
616 #endif
617 
618 /* Broken emulation causes triple fault, which skips the other tests. */
619 #if 0
620 static void test_lldt(volatile uint16_t *mem)
621 {
622 	u64 gdt[] = { 0, /* null descriptor */
623 #ifdef __X86_64__
624 		0, /* ldt descriptor is 16 bytes in long mode */
625 #endif
626 		0x0000f82000000ffffull /* ldt descriptor */
627 	};
628 	struct descriptor_table_ptr gdt_ptr = { .limit = sizeof(gdt) - 1,
629 						.base = (ulong)&gdt };
630 	struct descriptor_table_ptr orig_gdt;
631 
632 	cli();
633 	sgdt(&orig_gdt);
634 	lgdt(&gdt_ptr);
635 	*mem = 0x8;
636 	asm volatile("lldt %0" : : "m"(*mem));
637 	lgdt(&orig_gdt);
638 	sti();
639 	report(sldt() == *mem, "lldt");
640 }
641 #endif
642 
643 static void test_ltr(volatile uint16_t *mem)
644 {
645 	struct descriptor_table_ptr gdt_ptr;
646 	uint64_t *gdt, *trp;
647 	uint16_t tr = str();
648 	uint64_t busy_mask = (uint64_t)1 << 41;
649 
650 	sgdt(&gdt_ptr);
651 	gdt = (uint64_t *)gdt_ptr.base;
652 	trp = &gdt[tr >> 3];
653 	*trp &= ~busy_mask;
654 	*mem = tr;
655 	asm volatile("ltr %0" : : "m"(*mem) : "memory");
656 	report(str() == tr && (*trp & busy_mask), "ltr");
657 }
658 
659 static void test_mov(void *mem)
660 {
661 	unsigned long t1, t2;
662 
663 	// test mov reg, r/m and mov r/m, reg
664 	t1 = 0x123456789abcdefull & -1ul;
665 	asm volatile("mov %[t1], (%[mem]) \n\t"
666 		     "mov (%[mem]), %[t2]"
667 		     : [t2]"=r"(t2)
668 		     : [t1]"r"(t1), [mem]"r"(mem)
669 		     : "memory");
670 	report(t2 == (0x123456789abcdefull & -1ul), "mov reg, r/m (1)");
671 }
672 
673 static void test_simplealu(u32 *mem)
674 {
675 	*mem = 0x1234;
676 	asm("or %1, %0" : "+m"(*mem) : "r"(0x8001));
677 	report(*mem == 0x9235, "or");
678 	asm("add %1, %0" : "+m"(*mem) : "r"(2));
679 	report(*mem == 0x9237, "add");
680 	asm("xor %1, %0" : "+m"(*mem) : "r"(0x1111));
681 	report(*mem == 0x8326, "xor");
682 	asm("sub %1, %0" : "+m"(*mem) : "r"(0x26));
683 	report(*mem == 0x8300, "sub");
684 	asm("clc; adc %1, %0" : "+m"(*mem) : "r"(0x100));
685 	report(*mem == 0x8400, "adc(0)");
686 	asm("stc; adc %1, %0" : "+m"(*mem) : "r"(0x100));
687 	report(*mem == 0x8501, "adc(0)");
688 	asm("clc; sbb %1, %0" : "+m"(*mem) : "r"(0));
689 	report(*mem == 0x8501, "sbb(0)");
690 	asm("stc; sbb %1, %0" : "+m"(*mem) : "r"(0));
691 	report(*mem == 0x8500, "sbb(1)");
692 	asm("and %1, %0" : "+m"(*mem) : "r"(0xfe77));
693 	report(*mem == 0x8400, "and");
694 	asm("test %1, %0" : "+m"(*mem) : "r"(0xf000));
695 	report(*mem == 0x8400, "test");
696 }
697 
698 static void test_illegal_movbe(void)
699 {
700 	unsigned int vector;
701 
702 	if (!this_cpu_has(X86_FEATURE_MOVBE)) {
703 		report_skip("MOVBE unsupported by CPU");
704 		return;
705 	}
706 
707 	asm volatile(ASM_TRY("1f")
708 		     ".byte 0x0f; .byte 0x38; .byte 0xf0; .byte 0xc0;\n\t"
709 		     "1:"
710 		     : : : "memory", "rax");
711 
712 	vector = exception_vector();
713 	report(vector == UD_VECTOR,
714 	       "Wanted #UD on MOVBE with /reg, got vector = %u", vector);
715 }
716 
717 #ifdef __x86_64__
718 #define RIP_RELATIVE "(%%rip)"
719 #else
720 #define RIP_RELATIVE ""
721 #endif
722 
723 static void handle_db(struct ex_regs *regs)
724 {
725 	++exceptions;
726 	regs->rflags |= X86_EFLAGS_RF;
727 }
728 
729 static void test_mov_pop_ss_code_db(void)
730 {
731 	handler old_db_handler = handle_exception(DB_VECTOR, handle_db);
732 	bool fep_available = is_fep_available();
733 	/* On Intel, code #DBs are inhibited when MOV/POP SS blocking is active. */
734 	int nr_expected = is_intel() ? 0 : 1;
735 
736 	write_dr7(DR7_FIXED_1 |
737 		  DR7_GLOBAL_ENABLE_DRx(0) |
738 		  DR7_EXECUTE_DRx(0) |
739 		  DR7_LEN_1_DRx(0));
740 
741 #define MOV_POP_SS_DB(desc, fep1, fep2, insn, store_ss, load_ss)	\
742 ({									\
743 	unsigned long r;						\
744 									\
745 	exceptions = 0;							\
746 	asm volatile("lea 1f " RIP_RELATIVE ", %0\n\t"			\
747 		     "mov %0, %%dr0\n\t"				\
748 		     store_ss						\
749 		     fep1 load_ss	   				\
750 		     fep2 "1: xor %0, %0\n\t"				\
751 		     "2:"						\
752 		     : "=r" (r)						\
753 		     :							\
754 		     : "memory");					\
755 	report(exceptions == nr_expected && !r,				\
756 	       desc ": #DB %s after " insn " SS",			\
757 	       nr_expected ? "occurred" : "suppressed");		\
758 })
759 
760 #define MOV_SS_DB(desc, fep1, fep2)					\
761 	MOV_POP_SS_DB(desc, fep1, fep2, "MOV",				\
762 		      "mov %%ss, %0\n\t", "mov %0, %%ss\n\t")
763 
764 	MOV_SS_DB("no fep", "", "");
765 	if (fep_available) {
766 		MOV_SS_DB("fep MOV-SS", KVM_FEP, "");
767 		MOV_SS_DB("fep XOR", "", KVM_FEP);
768 		MOV_SS_DB("fep MOV-SS/fep XOR", KVM_FEP, KVM_FEP);
769 	}
770 
771 /* PUSH/POP SS are invalid in 64-bit mode. */
772 #ifndef __x86_64__
773 #define POP_SS_DB(desc, fep1, fep2)					\
774 	MOV_POP_SS_DB(desc, fep1, fep2,	"POP",				\
775 		      "push %%ss\n\t", "pop %%ss\n\t")
776 
777 	POP_SS_DB("no fep", "", "");
778 	if (fep_available) {
779 		POP_SS_DB("fep POP-SS", KVM_FEP, "");
780 		POP_SS_DB("fep XOR", "", KVM_FEP);
781 		POP_SS_DB("fep POP-SS/fep XOR", KVM_FEP, KVM_FEP);
782 	}
783 #endif
784 
785 	write_dr7(DR7_FIXED_1);
786 
787 	handle_exception(DB_VECTOR, old_db_handler);
788 }
789 
790 int main(void)
791 {
792 	void *mem;
793 	void *cross_mem;
794 
795 	if (!is_fep_available())
796 		report_skip("Skipping tests the require forced emulation, "
797 			    "use kvm.force_emulation_prefix=1 to enable");
798 
799 	setup_vm();
800 
801 	mem = alloc_vpages(2);
802 	install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem);
803 	// install the page twice to test cross-page mmio
804 	install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem + 4096);
805 	cross_mem = vmap(virt_to_phys(alloc_pages(2)), 2 * PAGE_SIZE);
806 
807 	test_mov(mem);
808 	test_simplealu(mem);
809 	test_cmps(mem);
810 	test_scas(mem);
811 	test_smsw(mem);
812 	test_lmsw();
813 	test_stringio();
814 	test_incdecnotneg(mem);
815 	test_btc(mem);
816 	test_bsfbsr(mem);
817 	test_imul(mem);
818 	test_sse(mem);
819 	test_sse_exceptions(cross_mem);
820 	test_shld_shrd(mem);
821 	//test_lgdt_lidt(mem);
822 	//test_lldt(mem);
823 	test_ltr(mem);
824 
825 	if (is_fep_available()) {
826 		test_smsw_reg(mem);
827 		test_nop(mem);
828 		test_mov_dr(mem);
829 		test_illegal_lea();
830 	}
831 
832 	test_crosspage_mmio(mem);
833 
834 	test_string_io_mmio(mem);
835 	test_illegal_movbe();
836 	test_mov_pop_ss_code_db();
837 
838 #ifdef __x86_64__
839 	test_emulator_64(mem);
840 #endif
841 	return report_summary();
842 }
843