xref: /kvm-unit-tests/x86/realmode.c (revision 99ee878c20ca1475ea1cf473dde29e7a9e115830)
1 #ifndef USE_SERIAL
2 #define USE_SERIAL
3 #endif
4 
5 asm(".code16gcc");
6 
7 typedef unsigned char u8;
8 typedef unsigned short u16;
9 typedef unsigned u32;
10 typedef unsigned long long u64;
11 
12 void test_function(void);
13 
14 asm(
15 	"test_function: \n\t"
16 	"mov $0x1234, %eax \n\t"
17 	"ret"
18    );
19 
20 static int strlen(const char *str)
21 {
22 	int n;
23 
24 	for (n = 0; *str; ++str)
25 		++n;
26 	return n;
27 }
28 
29 static void outb(u8 data, u16 port)
30 {
31 	asm volatile("out %0, %1" : : "a"(data), "d"(port));
32 }
33 
34 #ifdef USE_SERIAL
35 static int serial_iobase = 0x3f8;
36 static int serial_inited = 0;
37 
38 static u8 inb(u16 port)
39 {
40 	u8 data;
41 	asm volatile("in %1, %0" : "=a"(data) : "d"(port));
42 	return data;
43 }
44 
45 static void serial_outb(char ch)
46 {
47 	u8 lsr;
48 
49 	do {
50 		lsr = inb(serial_iobase + 0x05);
51 	} while (!(lsr & 0x20));
52 
53 	outb(ch, serial_iobase + 0x00);
54 }
55 
56 static void serial_init(void)
57 {
58 	u8 lcr;
59 
60 	/* set DLAB */
61 	lcr = inb(serial_iobase + 0x03);
62 	lcr |= 0x80;
63 	outb(lcr, serial_iobase + 0x03);
64 
65 	/* set baud rate to 115200 */
66 	outb(0x01, serial_iobase + 0x00);
67 	outb(0x00, serial_iobase + 0x01);
68 
69 	/* clear DLAB */
70 	lcr = inb(serial_iobase + 0x03);
71 	lcr &= ~0x80;
72 	outb(lcr, serial_iobase + 0x03);
73 }
74 #endif
75 
76 static void print_serial(const char *buf)
77 {
78 	unsigned long len = strlen(buf);
79 #ifdef USE_SERIAL
80 	unsigned long i;
81 	if (!serial_inited) {
82 	    serial_init();
83 	    serial_inited = 1;
84 	}
85 
86 	for (i = 0; i < len; i++) {
87 	    serial_outb(buf[i]);
88 	}
89 #else
90 	asm volatile ("addr32/rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1));
91 #endif
92 }
93 
94 static void print_serial_u32(u32 value)
95 {
96 	char n[12], *p;
97 	p = &n[11];
98 	*p = 0;
99 	do {
100 		*--p = '0' + (value % 10);
101 		value /= 10;
102 	} while (value > 0);
103 	print_serial(p);
104 }
105 
106 static int failed;
107 
108 static void exit(int code)
109 {
110 	outb(code, 0xf4);
111 }
112 
113 struct regs {
114 	u32 eax, ebx, ecx, edx;
115 	u32 esi, edi, esp, ebp;
116 	u32 eip, eflags;
117 };
118 
119 static u64 gdt[] = {
120 	0,
121 	0x00cf9b000000ffffull, // flat 32-bit code segment
122 	0x00cf93000000ffffull, // flat 32-bit data segment
123 };
124 
125 static struct {
126 	u16 limit;
127 	void *base;
128 } __attribute__((packed)) gdt_descr = {
129 	sizeof(gdt) - 1,
130 	gdt,
131 };
132 
133 struct insn_desc {
134     u16 ptr;
135     u16 len;
136 };
137 
138 static struct regs inregs, outregs;
139 
140 static void exec_in_big_real_mode(struct insn_desc *insn)
141 {
142 	unsigned long tmp;
143 	static struct regs save;
144 	int i;
145 	extern u8 test_insn[], test_insn_end[];
146 
147 	for (i = 0; i < insn->len; ++i)
148 	    test_insn[i] = ((u8 *)(unsigned long)insn->ptr)[i];
149 	for (; i < test_insn_end - test_insn; ++i)
150 		test_insn[i] = 0x90; // nop
151 
152 	save = inregs;
153 	asm volatile(
154 		"lgdtl %[gdt_descr] \n\t"
155 		"mov %%cr0, %[tmp] \n\t"
156 		"or $1, %[tmp] \n\t"
157 		"mov %[tmp], %%cr0 \n\t"
158 		"mov %[bigseg], %%gs \n\t"
159 		"and $-2, %[tmp] \n\t"
160 		"mov %[tmp], %%cr0 \n\t"
161 
162                 "pushw %[save]+36; popfw \n\t"
163 		"xchg %%eax, %[save]+0 \n\t"
164 		"xchg %%ebx, %[save]+4 \n\t"
165 		"xchg %%ecx, %[save]+8 \n\t"
166 		"xchg %%edx, %[save]+12 \n\t"
167 		"xchg %%esi, %[save]+16 \n\t"
168 		"xchg %%edi, %[save]+20 \n\t"
169 		"xchg %%esp, %[save]+24 \n\t"
170 		"xchg %%ebp, %[save]+28 \n\t"
171 
172 		"test_insn: . = . + 32\n\t"
173 		"test_insn_end: \n\t"
174 
175 		"xchg %%eax, %[save]+0 \n\t"
176 		"xchg %%ebx, %[save]+4 \n\t"
177 		"xchg %%ecx, %[save]+8 \n\t"
178 		"xchg %%edx, %[save]+12 \n\t"
179 		"xchg %%esi, %[save]+16 \n\t"
180 		"xchg %%edi, %[save]+20 \n\t"
181 		"xchg %%esp, %[save]+24 \n\t"
182 		"xchg %%ebp, %[save]+28 \n\t"
183 
184 		/* Save EFLAGS in outregs*/
185 		"pushfl \n\t"
186 		"popl %[save]+36 \n\t"
187 
188 		/* Restore DF for the harness code */
189 		"cld\n\t"
190 		"xor %[tmp], %[tmp] \n\t"
191 		"mov %[tmp], %%gs \n\t"
192 		: [tmp]"=&r"(tmp), [save]"+m"(save)
193 		: [gdt_descr]"m"(gdt_descr), [bigseg]"r"((short)16)
194 		: "cc", "memory"
195 		);
196 	outregs = save;
197 }
198 
199 #define R_AX 1
200 #define R_BX 2
201 #define R_CX 4
202 #define R_DX 8
203 #define R_SI 16
204 #define R_DI 32
205 #define R_SP 64
206 #define R_BP 128
207 
208 int regs_equal(int ignore)
209 {
210 	const u32 *p1 = &inregs.eax, *p2 = &outregs.eax;  // yuck
211 	int i;
212 
213 	for (i = 0; i < 8; ++i)
214 		if (!(ignore & (1 << i)) && p1[i] != p2[i])
215 			return 0;
216 	return 1;
217 }
218 
219 static void report(const char *name, u16 regs_ignore, _Bool ok)
220 {
221     if (!regs_equal(regs_ignore)) {
222 	ok = 0;
223     }
224     print_serial(ok ? "PASS: " : "FAIL: ");
225     print_serial(name);
226     print_serial("\n");
227     if (!ok)
228 	failed = 1;
229 }
230 
231 #define MK_INSN(name, str)				\
232     asm (						\
233 	 ".pushsection .data.insn  \n\t"		\
234 	 "insn_" #name ": \n\t"				\
235 	 ".word 1001f, 1002f - 1001f \n\t"		\
236 	 ".popsection \n\t"				\
237 	 ".pushsection .text.insn, \"ax\" \n\t"		\
238 	 "1001: \n\t"					\
239 	 "insn_code_" #name ": " str " \n\t"		\
240 	 "1002: \n\t"					\
241 	 ".popsection"					\
242     );							\
243     extern struct insn_desc insn_##name;
244 
245 void test_xchg(void)
246 {
247 	MK_INSN(xchg_test1, "xchg %eax,%eax\n\t");
248 	MK_INSN(xchg_test2, "xchg %eax,%ebx\n\t");
249 	MK_INSN(xchg_test3, "xchg %eax,%ecx\n\t");
250 	MK_INSN(xchg_test4, "xchg %eax,%edx\n\t");
251 	MK_INSN(xchg_test5, "xchg %eax,%esi\n\t");
252 	MK_INSN(xchg_test6, "xchg %eax,%edi\n\t");
253 	MK_INSN(xchg_test7, "xchg %eax,%ebp\n\t");
254 	MK_INSN(xchg_test8, "xchg %eax,%esp\n\t");
255 
256 	inregs = (struct regs){ .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = 7};
257 
258 	exec_in_big_real_mode(&insn_xchg_test1);
259 	report("xchg 1", 0, 1);
260 
261 	exec_in_big_real_mode(&insn_xchg_test2);
262 	report("xchg 2", R_AX | R_BX,
263 	       outregs.eax == inregs.ebx && outregs.ebx == inregs.eax);
264 
265 	exec_in_big_real_mode(&insn_xchg_test3);
266 	report("xchg 3", R_AX | R_CX,
267 	       outregs.eax == inregs.ecx && outregs.ecx == inregs.eax);
268 
269 	exec_in_big_real_mode(&insn_xchg_test4);
270 	report("xchg 4", R_AX | R_DX,
271 	       outregs.eax == inregs.edx && outregs.edx == inregs.eax);
272 
273 	exec_in_big_real_mode(&insn_xchg_test5);
274 	report("xchg 5", R_AX | R_SI,
275 	       outregs.eax == inregs.esi && outregs.esi == inregs.eax);
276 
277 	exec_in_big_real_mode(&insn_xchg_test6);
278 	report("xchg 6", R_AX | R_DI,
279 	       outregs.eax == inregs.edi && outregs.edi == inregs.eax);
280 
281 	exec_in_big_real_mode(&insn_xchg_test7);
282 	report("xchg 7", R_AX | R_BP,
283 	       outregs.eax == inregs.ebp && outregs.ebp == inregs.eax);
284 
285 	exec_in_big_real_mode(&insn_xchg_test8);
286 	report("xchg 8", R_AX | R_SP,
287 	       outregs.eax == inregs.esp && outregs.esp == inregs.eax);
288 }
289 
290 void test_shld(void)
291 {
292 	MK_INSN(shld_test, "shld $8,%edx,%eax\n\t");
293 
294 	inregs = (struct regs){ .eax = 0xbe, .edx = 0xef000000 };
295 	exec_in_big_real_mode(&insn_shld_test);
296 	report("shld", ~0, outregs.eax == 0xbeef);
297 }
298 
299 void test_mov_imm(void)
300 {
301 	MK_INSN(mov_r32_imm_1, "mov $1234567890, %eax");
302 	MK_INSN(mov_r16_imm_1, "mov $1234, %ax");
303 	MK_INSN(mov_r8_imm_1, "mov $0x12, %ah");
304 	MK_INSN(mov_r8_imm_2, "mov $0x34, %al");
305 	MK_INSN(mov_r8_imm_3, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t");
306 
307 	inregs = (struct regs){ 0 };
308 
309 	exec_in_big_real_mode(&insn_mov_r16_imm_1);
310 	report("mov 1", R_AX, outregs.eax == 1234);
311 
312 	/* test mov $imm, %eax */
313 	exec_in_big_real_mode(&insn_mov_r32_imm_1);
314 	report("mov 2", R_AX, outregs.eax == 1234567890);
315 
316 	/* test mov $imm, %al/%ah */
317 	exec_in_big_real_mode(&insn_mov_r8_imm_1);
318 	report("mov 3", R_AX, outregs.eax == 0x1200);
319 
320 	exec_in_big_real_mode(&insn_mov_r8_imm_2);
321 	report("mov 4", R_AX, outregs.eax == 0x34);
322 
323 	exec_in_big_real_mode(&insn_mov_r8_imm_3);
324 	report("mov 5", R_AX, outregs.eax == 0x1234);
325 }
326 
327 void test_sub_imm(void)
328 {
329 	MK_INSN(sub_r32_imm_1, "mov $1234567890, %eax\n\t" "sub $10, %eax\n\t");
330 	MK_INSN(sub_r16_imm_1, "mov $1234, %ax\n\t" "sub $10, %ax\n\t");
331 	MK_INSN(sub_r8_imm_1, "mov $0x12, %ah\n\t" "sub $0x10, %ah\n\t");
332 	MK_INSN(sub_r8_imm_2, "mov $0x34, %al\n\t" "sub $0x10, %al\n\t");
333 
334 	inregs = (struct regs){ 0 };
335 
336 	exec_in_big_real_mode(&insn_sub_r16_imm_1);
337 	report("sub 1", R_AX, outregs.eax == 1224);
338 
339 	/* test mov $imm, %eax */
340 	exec_in_big_real_mode(&insn_sub_r32_imm_1);
341 	report("sub 2", R_AX, outregs.eax == 1234567880);
342 
343 	/* test mov $imm, %al/%ah */
344 	exec_in_big_real_mode(&insn_sub_r8_imm_1);
345 	report("sub 3", R_AX, outregs.eax == 0x0200);
346 
347 	exec_in_big_real_mode(&insn_sub_r8_imm_2);
348 	report("sub 4", R_AX, outregs.eax == 0x24);
349 }
350 
351 void test_xor_imm(void)
352 {
353 	MK_INSN(xor_r32_imm_1, "mov $1234567890, %eax\n\t" "xor $1234567890, %eax\n\t");
354 	MK_INSN(xor_r16_imm_1, "mov $1234, %ax\n\t" "xor $1234, %ax\n\t");
355 	MK_INSN(xor_r8_imm_1, "mov $0x12, %ah\n\t" "xor $0x12, %ah\n\t");
356 	MK_INSN(xor_r8_imm_2, "mov $0x34, %al\n\t" "xor $0x34, %al\n\t");
357 
358 	inregs = (struct regs){ 0 };
359 
360 	exec_in_big_real_mode(&insn_xor_r16_imm_1);
361 	report("xor 1", R_AX, outregs.eax == 0);
362 
363 	/* test mov $imm, %eax */
364 	exec_in_big_real_mode(&insn_xor_r32_imm_1);
365 	report("xor 2", R_AX, outregs.eax == 0);
366 
367 	/* test mov $imm, %al/%ah */
368 	exec_in_big_real_mode(&insn_xor_r8_imm_1);
369 	report("xor 3", R_AX, outregs.eax == 0);
370 
371 	exec_in_big_real_mode(&insn_xor_r8_imm_2);
372 	report("xor 4", R_AX, outregs.eax == 0);
373 }
374 
375 void test_cmp_imm(void)
376 {
377 	MK_INSN(cmp_test1, "mov $0x34, %al\n\t"
378 			   "cmp $0x34, %al\n\t");
379 	MK_INSN(cmp_test2, "mov $0x34, %al\n\t"
380 			   "cmp $0x39, %al\n\t");
381 	MK_INSN(cmp_test3, "mov $0x34, %al\n\t"
382 			   "cmp $0x24, %al\n\t");
383 
384 	inregs = (struct regs){ 0 };
385 
386 	/* test cmp imm8 with AL */
387 	/* ZF: (bit 6) Zero Flag becomes 1 if an operation results
388 	 * in a 0 writeback, or 0 register
389 	 */
390 	exec_in_big_real_mode(&insn_cmp_test1);
391 	report("cmp 1", ~0, (outregs.eflags & (1<<6)) == (1<<6));
392 
393 	exec_in_big_real_mode(&insn_cmp_test2);
394 	report("cmp 2", ~0, (outregs.eflags & (1<<6)) == 0);
395 
396 	exec_in_big_real_mode(&insn_cmp_test3);
397 	report("cmp 3", ~0, (outregs.eflags & (1<<6)) == 0);
398 }
399 
400 void test_add_imm(void)
401 {
402 	MK_INSN(add_test1, "mov $0x43211234, %eax \n\t"
403 			   "add $0x12344321, %eax \n\t");
404 	MK_INSN(add_test2, "mov $0x12, %eax \n\t"
405 			   "add $0x21, %al\n\t");
406 
407 	inregs = (struct regs){ 0 };
408 
409 	exec_in_big_real_mode(&insn_add_test1);
410 	report("add 1", ~0, outregs.eax == 0x55555555);
411 
412 	exec_in_big_real_mode(&insn_add_test2);
413 	report("add 2", ~0, outregs.eax == 0x33);
414 }
415 
416 void test_eflags_insn(void)
417 {
418 	MK_INSN(clc, "clc");
419 	MK_INSN(stc, "stc");
420 	MK_INSN(cli, "cli");
421 	MK_INSN(sti, "sti");
422 	MK_INSN(cld, "cld");
423 	MK_INSN(std, "std");
424 
425 	inregs = (struct regs){ 0 };
426 
427 	exec_in_big_real_mode(&insn_clc);
428 	report("clc", ~0, (outregs.eflags & 1) == 0);
429 
430 	exec_in_big_real_mode(&insn_stc);
431 	report("stc", ~0, (outregs.eflags & 1) == 1);
432 
433 	exec_in_big_real_mode(&insn_cli);
434 	report("cli", ~0, !(outregs.eflags & (1 << 9)));
435 
436 	exec_in_big_real_mode(&insn_sti);
437 	report("sti", ~0, outregs.eflags & (1 << 9));
438 
439 	exec_in_big_real_mode(&insn_cld);
440 	report("cld", ~0, !(outregs.eflags & (1 << 10)));
441 
442 	exec_in_big_real_mode(&insn_std);
443 	report("std", ~0, (outregs.eflags & (1 << 10)));
444 }
445 
446 void test_io(void)
447 {
448 	MK_INSN(io_test1, "mov $0xff, %al \n\t"
449 		          "out %al, $0xe0 \n\t"
450 		          "mov $0x00, %al \n\t"
451 			  "in $0xe0, %al \n\t");
452 	MK_INSN(io_test2, "mov $0xffff, %ax \n\t"
453 			  "out %ax, $0xe0 \n\t"
454 			  "mov $0x0000, %ax \n\t"
455 			  "in $0xe0, %ax \n\t");
456 	MK_INSN(io_test3, "mov $0xffffffff, %eax \n\t"
457 			  "out %eax, $0xe0 \n\t"
458 			  "mov $0x000000, %eax \n\t"
459 			  "in $0xe0, %eax \n\t");
460 	MK_INSN(io_test4, "mov $0xe0, %dx \n\t"
461 			  "mov $0xff, %al \n\t"
462 			  "out %al, %dx \n\t"
463 			  "mov $0x00, %al \n\t"
464 			  "in %dx, %al \n\t");
465 	MK_INSN(io_test5, "mov $0xe0, %dx \n\t"
466 			  "mov $0xffff, %ax \n\t"
467 			  "out %ax, %dx \n\t"
468 			  "mov $0x0000, %ax \n\t"
469 			  "in %dx, %ax \n\t");
470 	MK_INSN(io_test6, "mov $0xe0, %dx \n\t"
471 			  "mov $0xffffffff, %eax \n\t"
472 			  "out %eax, %dx \n\t"
473 			  "mov $0x00000000, %eax \n\t"
474 			  "in %dx, %eax \n\t");
475 
476 	inregs = (struct regs){ 0 };
477 
478 	exec_in_big_real_mode(&insn_io_test1);
479 	report("pio 1", R_AX, outregs.eax == 0xff);
480 
481 	exec_in_big_real_mode(&insn_io_test2);
482 	report("pio 2", R_AX, outregs.eax == 0xffff);
483 
484 	exec_in_big_real_mode(&insn_io_test3);
485 	report("pio 3", R_AX, outregs.eax == 0xffffffff);
486 
487 	exec_in_big_real_mode(&insn_io_test4);
488 	report("pio 4", R_AX|R_DX, outregs.eax == 0xff);
489 
490 	exec_in_big_real_mode(&insn_io_test5);
491 	report("pio 5", R_AX|R_DX, outregs.eax == 0xffff);
492 
493 	exec_in_big_real_mode(&insn_io_test6);
494 	report("pio 6", R_AX|R_DX, outregs.eax == 0xffffffff);
495 }
496 
497 asm ("retf: lretw");
498 extern void retf();
499 
500 asm ("retf_imm: lretw $10");
501 extern void retf_imm();
502 
503 void test_call(void)
504 {
505 	u32 esp[16];
506 	u32 addr;
507 
508 	inregs = (struct regs){ 0 };
509 	inregs.esp = (u32)esp;
510 
511 	MK_INSN(call1, "mov $test_function, %eax \n\t"
512 		       "call *%eax\n\t");
513 	MK_INSN(call_near1, "jmp 2f\n\t"
514 			    "1: mov $0x1234, %eax\n\t"
515 			    "ret\n\t"
516 			    "2: call 1b\t");
517 	MK_INSN(call_near2, "call 1f\n\t"
518 			    "jmp 2f\n\t"
519 			    "1: mov $0x1234, %eax\n\t"
520 			    "ret\n\t"
521 			    "2:\t");
522 	MK_INSN(call_far1,  "lcallw *(%ebx)\n\t");
523 	MK_INSN(call_far2,  "lcallw $0, $retf\n\t");
524 	MK_INSN(ret_imm,    "sub $10, %sp; jmp 2f; 1: retw $10; 2: callw 1b");
525 	MK_INSN(retf_imm,   "sub $10, %sp; lcallw $0, $retf_imm");
526 
527 	exec_in_big_real_mode(&insn_call1);
528 	report("call 1", R_AX, outregs.eax == 0x1234);
529 
530 	exec_in_big_real_mode(&insn_call_near1);
531 	report("call near 1", R_AX, outregs.eax == 0x1234);
532 
533 	exec_in_big_real_mode(&insn_call_near2);
534 	report("call near 2", R_AX, outregs.eax == 0x1234);
535 
536 	addr = (((unsigned)retf >> 4) << 16) | ((unsigned)retf & 0x0f);
537 	inregs.ebx = (unsigned)&addr;
538 	exec_in_big_real_mode(&insn_call_far1);
539 	report("call far 1", 0, 1);
540 
541 	exec_in_big_real_mode(&insn_call_far2);
542 	report("call far 2", 0, 1);
543 
544 	exec_in_big_real_mode(&insn_ret_imm);
545 	report("ret imm 1", 0, 1);
546 
547 	exec_in_big_real_mode(&insn_retf_imm);
548 	report("retf imm 1", 0, 1);
549 }
550 
551 void test_jcc_short(void)
552 {
553 	MK_INSN(jnz_short1, "jnz 1f\n\t"
554 			    "mov $0x1234, %eax\n\t"
555 		            "1:\n\t");
556 	MK_INSN(jnz_short2, "1:\n\t"
557 			    "cmp $0x1234, %eax\n\t"
558 			    "mov $0x1234, %eax\n\t"
559 		            "jnz 1b\n\t");
560 	MK_INSN(jmp_short1, "jmp 1f\n\t"
561 		      "mov $0x1234, %eax\n\t"
562 		      "1:\n\t");
563 
564 	inregs = (struct regs){ 0 };
565 
566 	exec_in_big_real_mode(&insn_jnz_short1);
567 	report("jnz short 1", ~0, 1);
568 
569 	exec_in_big_real_mode(&insn_jnz_short2);
570 	report("jnz short 2", R_AX, (outregs.eflags & (1 << 6)));
571 
572 	exec_in_big_real_mode(&insn_jmp_short1);
573 	report("jmp short 1", ~0, 1);
574 }
575 
576 void test_jcc_near(void)
577 {
578 	/* encode near jmp manually. gas will not do it if offsets < 127 byte */
579 	MK_INSN(jnz_near1, ".byte 0x0f, 0x85, 0x06, 0x00\n\t"
580 		           "mov $0x1234, %eax\n\t");
581 	MK_INSN(jnz_near2, "cmp $0x1234, %eax\n\t"
582 			   "mov $0x1234, %eax\n\t"
583 		           ".byte 0x0f, 0x85, 0xf0, 0xff\n\t");
584 	MK_INSN(jmp_near1, ".byte 0xE9, 0x06, 0x00\n\t"
585 		           "mov $0x1234, %eax\n\t");
586 
587 	inregs = (struct regs){ 0 };
588 
589 	exec_in_big_real_mode(&insn_jnz_near1);
590 	report("jnz near 1", 0, 1);
591 
592 	exec_in_big_real_mode(&insn_jnz_near2);
593 	report("jnz near 2", R_AX, outregs.eflags & (1 << 6));
594 
595 	exec_in_big_real_mode(&insn_jmp_near1);
596 	report("jmp near 1", 0, 1);
597 }
598 
599 void test_long_jmp()
600 {
601 	u32 esp[16];
602 
603 	inregs = (struct regs){ 0 };
604 	inregs.esp = (u32)(esp+16);
605 	MK_INSN(long_jmp, "call 1f\n\t"
606 			  "jmp 2f\n\t"
607 			  "1: jmp $0, $test_function\n\t"
608 		          "2:\n\t");
609 	exec_in_big_real_mode(&insn_long_jmp);
610 	report("jmp far 1", R_AX, outregs.eax == 0x1234);
611 }
612 
613 void test_push_pop()
614 {
615 	MK_INSN(push32, "mov $0x12345678, %eax\n\t"
616 			"push %eax\n\t"
617 			"pop %ebx\n\t");
618 	MK_INSN(push16, "mov $0x1234, %ax\n\t"
619 			"push %ax\n\t"
620 			"pop %bx\n\t");
621 
622 	MK_INSN(push_es, "mov $0x231, %bx\n\t" //Just write a dummy value to see if it gets overwritten
623 			 "mov $0x123, %ax\n\t"
624 			 "mov %ax, %es\n\t"
625 			 "push %es\n\t"
626 			 "pop %bx \n\t"
627 			 );
628 	MK_INSN(pop_es, "push %ax\n\t"
629 			"pop %es\n\t"
630 			"mov %es, %bx\n\t"
631 			);
632 	MK_INSN(push_pop_ss, "push %ss\n\t"
633 			     "pushw %ax\n\t"
634 			     "popw %ss\n\t"
635 			     "mov %ss, %bx\n\t"
636 			     "pop %ss\n\t"
637 			);
638 	MK_INSN(push_pop_fs, "push %fs\n\t"
639 			     "pushl %eax\n\t"
640 			     "popl %fs\n\t"
641 			     "mov %fs, %ebx\n\t"
642 			     "pop %fs\n\t"
643 			);
644 	MK_INSN(push_pop_high_esp_bits,
645 		"xor $0x12340000, %esp \n\t"
646 		"push %ax; \n\t"
647 		"xor $0x12340000, %esp \n\t"
648 		"pop %bx");
649 
650 	inregs = (struct regs){ 0 };
651 
652 	exec_in_big_real_mode(&insn_push32);
653 	report("push/pop 1", R_AX|R_BX,
654 	       outregs.eax == outregs.ebx && outregs.eax == 0x12345678);
655 
656 	exec_in_big_real_mode(&insn_push16);
657 	report("push/pop 2", R_AX|R_BX,
658 	       outregs.eax == outregs.ebx && outregs.eax == 0x1234);
659 
660 	exec_in_big_real_mode(&insn_push_es);
661 	report("push/pop 3", R_AX|R_BX,
662 	       outregs.ebx == outregs.eax && outregs.eax == 0x123);
663 
664 	exec_in_big_real_mode(&insn_pop_es);
665 	report("push/pop 4", R_AX|R_BX, outregs.ebx == outregs.eax);
666 
667 	exec_in_big_real_mode(&insn_push_pop_ss);
668 	report("push/pop 5", R_AX|R_BX, outregs.ebx == outregs.eax);
669 
670 	exec_in_big_real_mode(&insn_push_pop_fs);
671 	report("push/pop 6", R_AX|R_BX, outregs.ebx == outregs.eax);
672 
673 	inregs.eax = 0x9977;
674 	inregs.ebx = 0x7799;
675 	exec_in_big_real_mode(&insn_push_pop_high_esp_bits);
676 	report("push/pop with high bits set in %esp", R_BX, outregs.ebx == 0x9977);
677 }
678 
679 void test_null(void)
680 {
681 	MK_INSN(null, "");
682 
683 	inregs = (struct regs){ 0 };
684 
685 	exec_in_big_real_mode(&insn_null);
686 	report("null", 0, 1);
687 }
688 
689 struct {
690     char stack[500];
691     char top[];
692 } tmp_stack;
693 
694 void test_pusha_popa()
695 {
696 	MK_INSN(pusha, "pusha\n\t"
697 		       "pop %edi\n\t"
698 		       "pop %esi\n\t"
699 		       "pop %ebp\n\t"
700 		       "add $4, %esp\n\t"
701 		       "pop %ebx\n\t"
702 		       "pop %edx\n\t"
703 		       "pop %ecx\n\t"
704 		       "pop %eax\n\t"
705 		       );
706 
707 	MK_INSN(popa, "push %eax\n\t"
708 		      "push %ecx\n\t"
709 		      "push %edx\n\t"
710 		      "push %ebx\n\t"
711 		      "push %esp\n\t"
712 		      "push %ebp\n\t"
713 		      "push %esi\n\t"
714 		      "push %edi\n\t"
715 		      "popa\n\t"
716 		      );
717 
718 	inregs = (struct regs){ .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = (unsigned long)&tmp_stack.top };
719 
720 	exec_in_big_real_mode(&insn_pusha);
721 	report("pusha/popa 1", 0, 1);
722 
723 	exec_in_big_real_mode(&insn_popa);
724 	report("pusha/popa 1", 0, 1);
725 }
726 
727 void test_iret()
728 {
729 	MK_INSN(iret32, "pushf\n\t"
730 			"pushl %cs\n\t"
731 			"call 1f\n\t" /* a near call will push eip onto the stack */
732 			"jmp 2f\n\t"
733 			"1: iret\n\t"
734 			"2:\n\t"
735 		     );
736 
737 	MK_INSN(iret16, "pushfw\n\t"
738 			"pushw %cs\n\t"
739 			"callw 1f\n\t"
740 			"jmp 2f\n\t"
741 			"1: iretw\n\t"
742 			"2:\n\t");
743 
744 	MK_INSN(iret_flags32, "pushfl\n\t"
745 			      "popl %eax\n\t"
746 			      "andl $~0x2, %eax\n\t"
747 			      "orl $0xffc08028, %eax\n\t"
748 			      "pushl %eax\n\t"
749 			      "pushl %cs\n\t"
750 			      "call 1f\n\t"
751 			      "jmp 2f\n\t"
752 			      "1: iret\n\t"
753 			      "2:\n\t");
754 
755 	MK_INSN(iret_flags16, "pushfw\n\t"
756 			      "popw %ax\n\t"
757 			      "and $~0x2, %ax\n\t"
758 			      "or $0x8028, %ax\n\t"
759 			      "pushw %ax\n\t"
760 			      "pushw %cs\n\t"
761 			      "callw 1f\n\t"
762 			      "jmp 2f\n\t"
763 			      "1: iretw\n\t"
764 			      "2:\n\t");
765 
766 	inregs = (struct regs){ 0 };
767 
768 	exec_in_big_real_mode(&insn_iret32);
769 	report("iret 1", 0, 1);
770 
771 	exec_in_big_real_mode(&insn_iret16);
772 	report("iret 2", 0, 1);
773 
774 	exec_in_big_real_mode(&insn_iret_flags32);
775 	report("iret 3", R_AX, 1);
776 
777 	exec_in_big_real_mode(&insn_iret_flags16);
778 	report("iret 4", R_AX, 1);
779 }
780 
781 void test_int()
782 {
783 	inregs = (struct regs){ 0 };
784 
785 	*(u32 *)(0x11 * 4) = 0x1000; /* Store a pointer to address 0x1000 in IDT entry 0x11 */
786 	*(u8 *)(0x1000) = 0xcf; /* 0x1000 contains an IRET instruction */
787 
788 	MK_INSN(int11, "int $0x11\n\t");
789 
790 	exec_in_big_real_mode(&insn_int11);
791 	report("int 1", 0, 1);
792 }
793 
794 void test_imul()
795 {
796 	MK_INSN(imul8_1, "mov $2, %al\n\t"
797 			"mov $-4, %cx\n\t"
798 			"imul %cl\n\t");
799 
800 	MK_INSN(imul16_1, "mov $2, %ax\n\t"
801 		      "mov $-4, %cx\n\t"
802 		      "imul %cx\n\t");
803 
804 	MK_INSN(imul32_1, "mov $2, %eax\n\t"
805 		       "mov $-4, %ecx\n\t"
806 		       "imul %ecx\n\t");
807 
808 	MK_INSN(imul8_2, "mov $0x12340002, %eax\n\t"
809 			"mov $4, %cx\n\t"
810 			"imul %cl\n\t");
811 
812 	MK_INSN(imul16_2, "mov $2, %ax\n\t"
813 			"mov $4, %cx\n\t"
814 			"imul %cx\n\t");
815 
816 	MK_INSN(imul32_2, "mov $2, %eax\n\t"
817 			"mov $4, %ecx\n\t"
818 			"imul %ecx\n\t");
819 
820 	inregs = (struct regs){ 0 };
821 
822 	exec_in_big_real_mode(&insn_imul8_1);
823 	report("imul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == (u8)-8);
824 
825 	exec_in_big_real_mode(&insn_imul16_1);
826 	report("imul 2", R_AX | R_CX | R_DX, outregs.eax == (u16)-8);
827 
828 	exec_in_big_real_mode(&insn_imul32_1);
829 	report("imul 3", R_AX | R_CX | R_DX, outregs.eax == (u32)-8);
830 
831 	exec_in_big_real_mode(&insn_imul8_2);
832 	report("imul 4", R_AX | R_CX | R_DX,
833 	       (outregs.eax & 0xffff) == 8
834 	       && (outregs.eax & 0xffff0000) == 0x12340000);
835 
836 	exec_in_big_real_mode(&insn_imul16_2);
837 	report("imul 5", R_AX | R_CX | R_DX, outregs.eax == 8);
838 
839 	exec_in_big_real_mode(&insn_imul32_2);
840 	report("imul 6", R_AX | R_CX | R_DX, outregs.eax == 8);
841 }
842 
843 void test_mul()
844 {
845 	MK_INSN(mul8, "mov $2, %al\n\t"
846 			"mov $4, %cx\n\t"
847 			"imul %cl\n\t");
848 
849 	MK_INSN(mul16, "mov $2, %ax\n\t"
850 			"mov $4, %cx\n\t"
851 			"imul %cx\n\t");
852 
853 	MK_INSN(mul32, "mov $2, %eax\n\t"
854 			"mov $4, %ecx\n\t"
855 			"imul %ecx\n\t");
856 
857 	inregs = (struct regs){ 0 };
858 
859 	exec_in_big_real_mode(&insn_mul8);
860 	report("mul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == 8);
861 
862 	exec_in_big_real_mode(&insn_mul16);
863 	report("mul 2", R_AX | R_CX | R_DX, outregs.eax == 8);
864 
865 	exec_in_big_real_mode(&insn_mul32);
866 	report("mul 3", R_AX | R_CX | R_DX, outregs.eax == 8);
867 }
868 
869 void test_div()
870 {
871 	MK_INSN(div8, "mov $257, %ax\n\t"
872 			"mov $2, %cl\n\t"
873 			"div %cl\n\t");
874 
875 	MK_INSN(div16, "mov $512, %ax\n\t"
876 			"mov $5, %cx\n\t"
877 			"div %cx\n\t");
878 
879 	MK_INSN(div32, "mov $512, %eax\n\t"
880 			"mov $5, %ecx\n\t"
881 			"div %ecx\n\t");
882 
883 	inregs = (struct regs){ 0 };
884 
885 	exec_in_big_real_mode(&insn_div8);
886 	report("div 1", R_AX | R_CX | R_DX, outregs.eax == 384);
887 
888 	exec_in_big_real_mode(&insn_div16);
889 	report("div 2", R_AX | R_CX | R_DX,
890 	       outregs.eax == 102 && outregs.edx == 2);
891 
892 	exec_in_big_real_mode(&insn_div32);
893 	report("div 3", R_AX | R_CX | R_DX,
894 	       outregs.eax == 102 && outregs.edx == 2);
895 }
896 
897 void test_idiv()
898 {
899 	MK_INSN(idiv8, "mov $256, %ax\n\t"
900 			"mov $-2, %cl\n\t"
901 			"idiv %cl\n\t");
902 
903 	MK_INSN(idiv16, "mov $512, %ax\n\t"
904 			"mov $-2, %cx\n\t"
905 			"idiv %cx\n\t");
906 
907 	MK_INSN(idiv32, "mov $512, %eax\n\t"
908 			"mov $-2, %ecx\n\t"
909 			"idiv %ecx\n\t");
910 
911 	inregs = (struct regs){ 0 };
912 
913 	exec_in_big_real_mode(&insn_idiv8);
914 	report("idiv 1", R_AX | R_CX | R_DX, outregs.eax == (u8)-128);
915 
916 	exec_in_big_real_mode(&insn_idiv16);
917 	report("idiv 2", R_AX | R_CX | R_DX, outregs.eax == (u16)-256);
918 
919 	exec_in_big_real_mode(&insn_idiv32);
920 	report("idiv 3", R_AX | R_CX | R_DX, outregs.eax == (u32)-256);
921 }
922 
923 void test_cbw(void)
924 {
925 	MK_INSN(cbw, "mov $0xFE, %eax \n\t"
926 		     "cbw\n\t");
927 	MK_INSN(cwde, "mov $0xFFFE, %eax \n\t"
928 		      "cwde\n\t");
929 
930 	inregs = (struct regs){ 0 };
931 
932 	exec_in_big_real_mode(&insn_cbw);
933 	report("cbq 1", ~0, outregs.eax == 0xFFFE);
934 
935 	exec_in_big_real_mode(&insn_cwde);
936 	report("cwde 1", ~0, outregs.eax == 0xFFFFFFFE);
937 }
938 
939 void test_loopcc(void)
940 {
941 	MK_INSN(loop, "mov $10, %ecx\n\t"
942 		      "1: inc %eax\n\t"
943 		      "loop 1b\n\t");
944 
945 	MK_INSN(loope, "mov $10, %ecx\n\t"
946 		       "mov $1, %eax\n\t"
947 		       "1: dec %eax\n\t"
948 		       "loope 1b\n\t");
949 
950 	MK_INSN(loopne, "mov $10, %ecx\n\t"
951 		        "mov $5, %eax\n\t"
952 		        "1: dec %eax\n\t"
953 			"loopne 1b\n\t");
954 
955 	inregs = (struct regs){ 0 };
956 
957 	exec_in_big_real_mode(&insn_loop);
958 	report("LOOPcc short 1", R_AX, outregs.eax == 10);
959 
960 	exec_in_big_real_mode(&insn_loope);
961 	report("LOOPcc short 2", R_AX | R_CX,
962 	       outregs.eax == -1 && outregs.ecx == 8);
963 
964 	exec_in_big_real_mode(&insn_loopne);
965 	report("LOOPcc short 3", R_AX | R_CX,
966 	       outregs.eax == 0 && outregs.ecx == 5);
967 }
968 
969 static void test_das(void)
970 {
971     short i;
972     u16 nr_fail = 0;
973     static unsigned test_cases[1024] = {
974         0x46000000, 0x8701a000, 0x9710fa00, 0x97119a00,
975         0x02000101, 0x8301a101, 0x9310fb01, 0x93119b01,
976         0x02000202, 0x8301a202, 0x9710fc02, 0x97119c02,
977         0x06000303, 0x8701a303, 0x9310fd03, 0x93119d03,
978         0x02000404, 0x8301a404, 0x9310fe04, 0x93119e04,
979         0x06000505, 0x8701a505, 0x9710ff05, 0x97119f05,
980         0x06000606, 0x8701a606, 0x56100006, 0x9711a006,
981         0x02000707, 0x8301a707, 0x12100107, 0x9311a107,
982         0x02000808, 0x8301a808, 0x12100208, 0x9311a208,
983         0x06000909, 0x8701a909, 0x16100309, 0x9711a309,
984         0x1200040a, 0x9301a40a, 0x1210040a, 0x9311a40a,
985         0x1600050b, 0x9701a50b, 0x1610050b, 0x9711a50b,
986         0x1600060c, 0x9701a60c, 0x1610060c, 0x9711a60c,
987         0x1200070d, 0x9301a70d, 0x1210070d, 0x9311a70d,
988         0x1200080e, 0x9301a80e, 0x1210080e, 0x9311a80e,
989         0x1600090f, 0x9701a90f, 0x1610090f, 0x9711a90f,
990         0x02001010, 0x8301b010, 0x16100a10, 0x9711aa10,
991         0x06001111, 0x8701b111, 0x12100b11, 0x9311ab11,
992         0x06001212, 0x8701b212, 0x16100c12, 0x9711ac12,
993         0x02001313, 0x8301b313, 0x12100d13, 0x9311ad13,
994         0x06001414, 0x8701b414, 0x12100e14, 0x9311ae14,
995         0x02001515, 0x8301b515, 0x16100f15, 0x9711af15,
996         0x02001616, 0x8301b616, 0x12101016, 0x9311b016,
997         0x06001717, 0x8701b717, 0x16101117, 0x9711b117,
998         0x06001818, 0x8701b818, 0x16101218, 0x9711b218,
999         0x02001919, 0x8301b919, 0x12101319, 0x9311b319,
1000         0x1600141a, 0x9701b41a, 0x1610141a, 0x9711b41a,
1001         0x1200151b, 0x9301b51b, 0x1210151b, 0x9311b51b,
1002         0x1200161c, 0x9301b61c, 0x1210161c, 0x9311b61c,
1003         0x1600171d, 0x9701b71d, 0x1610171d, 0x9711b71d,
1004         0x1600181e, 0x9701b81e, 0x1610181e, 0x9711b81e,
1005         0x1200191f, 0x9301b91f, 0x1210191f, 0x9311b91f,
1006         0x02002020, 0x8701c020, 0x12101a20, 0x9311ba20,
1007         0x06002121, 0x8301c121, 0x16101b21, 0x9711bb21,
1008         0x06002222, 0x8301c222, 0x12101c22, 0x9311bc22,
1009         0x02002323, 0x8701c323, 0x16101d23, 0x9711bd23,
1010         0x06002424, 0x8301c424, 0x16101e24, 0x9711be24,
1011         0x02002525, 0x8701c525, 0x12101f25, 0x9311bf25,
1012         0x02002626, 0x8701c626, 0x12102026, 0x9711c026,
1013         0x06002727, 0x8301c727, 0x16102127, 0x9311c127,
1014         0x06002828, 0x8301c828, 0x16102228, 0x9311c228,
1015         0x02002929, 0x8701c929, 0x12102329, 0x9711c329,
1016         0x1600242a, 0x9301c42a, 0x1610242a, 0x9311c42a,
1017         0x1200252b, 0x9701c52b, 0x1210252b, 0x9711c52b,
1018         0x1200262c, 0x9701c62c, 0x1210262c, 0x9711c62c,
1019         0x1600272d, 0x9301c72d, 0x1610272d, 0x9311c72d,
1020         0x1600282e, 0x9301c82e, 0x1610282e, 0x9311c82e,
1021         0x1200292f, 0x9701c92f, 0x1210292f, 0x9711c92f,
1022         0x06003030, 0x8301d030, 0x12102a30, 0x9711ca30,
1023         0x02003131, 0x8701d131, 0x16102b31, 0x9311cb31,
1024         0x02003232, 0x8701d232, 0x12102c32, 0x9711cc32,
1025         0x06003333, 0x8301d333, 0x16102d33, 0x9311cd33,
1026         0x02003434, 0x8701d434, 0x16102e34, 0x9311ce34,
1027         0x06003535, 0x8301d535, 0x12102f35, 0x9711cf35,
1028         0x06003636, 0x8301d636, 0x16103036, 0x9311d036,
1029         0x02003737, 0x8701d737, 0x12103137, 0x9711d137,
1030         0x02003838, 0x8701d838, 0x12103238, 0x9711d238,
1031         0x06003939, 0x8301d939, 0x16103339, 0x9311d339,
1032         0x1200343a, 0x9701d43a, 0x1210343a, 0x9711d43a,
1033         0x1600353b, 0x9301d53b, 0x1610353b, 0x9311d53b,
1034         0x1600363c, 0x9301d63c, 0x1610363c, 0x9311d63c,
1035         0x1200373d, 0x9701d73d, 0x1210373d, 0x9711d73d,
1036         0x1200383e, 0x9701d83e, 0x1210383e, 0x9711d83e,
1037         0x1600393f, 0x9301d93f, 0x1610393f, 0x9311d93f,
1038         0x02004040, 0x8301e040, 0x16103a40, 0x9311da40,
1039         0x06004141, 0x8701e141, 0x12103b41, 0x9711db41,
1040         0x06004242, 0x8701e242, 0x16103c42, 0x9311dc42,
1041         0x02004343, 0x8301e343, 0x12103d43, 0x9711dd43,
1042         0x06004444, 0x8701e444, 0x12103e44, 0x9711de44,
1043         0x02004545, 0x8301e545, 0x16103f45, 0x9311df45,
1044         0x02004646, 0x8301e646, 0x12104046, 0x9311e046,
1045         0x06004747, 0x8701e747, 0x16104147, 0x9711e147,
1046         0x06004848, 0x8701e848, 0x16104248, 0x9711e248,
1047         0x02004949, 0x8301e949, 0x12104349, 0x9311e349,
1048         0x1600444a, 0x9701e44a, 0x1610444a, 0x9711e44a,
1049         0x1200454b, 0x9301e54b, 0x1210454b, 0x9311e54b,
1050         0x1200464c, 0x9301e64c, 0x1210464c, 0x9311e64c,
1051         0x1600474d, 0x9701e74d, 0x1610474d, 0x9711e74d,
1052         0x1600484e, 0x9701e84e, 0x1610484e, 0x9711e84e,
1053         0x1200494f, 0x9301e94f, 0x1210494f, 0x9311e94f,
1054         0x06005050, 0x8701f050, 0x12104a50, 0x9311ea50,
1055         0x02005151, 0x8301f151, 0x16104b51, 0x9711eb51,
1056         0x02005252, 0x8301f252, 0x12104c52, 0x9311ec52,
1057         0x06005353, 0x8701f353, 0x16104d53, 0x9711ed53,
1058         0x02005454, 0x8301f454, 0x16104e54, 0x9711ee54,
1059         0x06005555, 0x8701f555, 0x12104f55, 0x9311ef55,
1060         0x06005656, 0x8701f656, 0x16105056, 0x9711f056,
1061         0x02005757, 0x8301f757, 0x12105157, 0x9311f157,
1062         0x02005858, 0x8301f858, 0x12105258, 0x9311f258,
1063         0x06005959, 0x8701f959, 0x16105359, 0x9711f359,
1064         0x1200545a, 0x9301f45a, 0x1210545a, 0x9311f45a,
1065         0x1600555b, 0x9701f55b, 0x1610555b, 0x9711f55b,
1066         0x1600565c, 0x9701f65c, 0x1610565c, 0x9711f65c,
1067         0x1200575d, 0x9301f75d, 0x1210575d, 0x9311f75d,
1068         0x1200585e, 0x9301f85e, 0x1210585e, 0x9311f85e,
1069         0x1600595f, 0x9701f95f, 0x1610595f, 0x9711f95f,
1070         0x06006060, 0x47010060, 0x16105a60, 0x9711fa60,
1071         0x02006161, 0x03010161, 0x12105b61, 0x9311fb61,
1072         0x02006262, 0x03010262, 0x16105c62, 0x9711fc62,
1073         0x06006363, 0x07010363, 0x12105d63, 0x9311fd63,
1074         0x02006464, 0x03010464, 0x12105e64, 0x9311fe64,
1075         0x06006565, 0x07010565, 0x16105f65, 0x9711ff65,
1076         0x06006666, 0x07010666, 0x16106066, 0x57110066,
1077         0x02006767, 0x03010767, 0x12106167, 0x13110167,
1078         0x02006868, 0x03010868, 0x12106268, 0x13110268,
1079         0x06006969, 0x07010969, 0x16106369, 0x17110369,
1080         0x1200646a, 0x1301046a, 0x1210646a, 0x1311046a,
1081         0x1600656b, 0x1701056b, 0x1610656b, 0x1711056b,
1082         0x1600666c, 0x1701066c, 0x1610666c, 0x1711066c,
1083         0x1200676d, 0x1301076d, 0x1210676d, 0x1311076d,
1084         0x1200686e, 0x1301086e, 0x1210686e, 0x1311086e,
1085         0x1600696f, 0x1701096f, 0x1610696f, 0x1711096f,
1086         0x02007070, 0x03011070, 0x16106a70, 0x17110a70,
1087         0x06007171, 0x07011171, 0x12106b71, 0x13110b71,
1088         0x06007272, 0x07011272, 0x16106c72, 0x17110c72,
1089         0x02007373, 0x03011373, 0x12106d73, 0x13110d73,
1090         0x06007474, 0x07011474, 0x12106e74, 0x13110e74,
1091         0x02007575, 0x03011575, 0x16106f75, 0x17110f75,
1092         0x02007676, 0x03011676, 0x12107076, 0x13111076,
1093         0x06007777, 0x07011777, 0x16107177, 0x17111177,
1094         0x06007878, 0x07011878, 0x16107278, 0x17111278,
1095         0x02007979, 0x03011979, 0x12107379, 0x13111379,
1096         0x1600747a, 0x1701147a, 0x1610747a, 0x1711147a,
1097         0x1200757b, 0x1301157b, 0x1210757b, 0x1311157b,
1098         0x1200767c, 0x1301167c, 0x1210767c, 0x1311167c,
1099         0x1600777d, 0x1701177d, 0x1610777d, 0x1711177d,
1100         0x1600787e, 0x1701187e, 0x1610787e, 0x1711187e,
1101         0x1200797f, 0x1301197f, 0x1210797f, 0x1311197f,
1102         0x82008080, 0x03012080, 0x12107a80, 0x13111a80,
1103         0x86008181, 0x07012181, 0x16107b81, 0x17111b81,
1104         0x86008282, 0x07012282, 0x12107c82, 0x13111c82,
1105         0x82008383, 0x03012383, 0x16107d83, 0x17111d83,
1106         0x86008484, 0x07012484, 0x16107e84, 0x17111e84,
1107         0x82008585, 0x03012585, 0x12107f85, 0x13111f85,
1108         0x82008686, 0x03012686, 0x92108086, 0x13112086,
1109         0x86008787, 0x07012787, 0x96108187, 0x17112187,
1110         0x86008888, 0x07012888, 0x96108288, 0x17112288,
1111         0x82008989, 0x03012989, 0x92108389, 0x13112389,
1112         0x9600848a, 0x1701248a, 0x9610848a, 0x1711248a,
1113         0x9200858b, 0x1301258b, 0x9210858b, 0x1311258b,
1114         0x9200868c, 0x1301268c, 0x9210868c, 0x1311268c,
1115         0x9600878d, 0x1701278d, 0x9610878d, 0x1711278d,
1116         0x9600888e, 0x1701288e, 0x9610888e, 0x1711288e,
1117         0x9200898f, 0x1301298f, 0x9210898f, 0x1311298f,
1118         0x86009090, 0x07013090, 0x92108a90, 0x13112a90,
1119         0x82009191, 0x03013191, 0x96108b91, 0x17112b91,
1120         0x82009292, 0x03013292, 0x92108c92, 0x13112c92,
1121         0x86009393, 0x07013393, 0x96108d93, 0x17112d93,
1122         0x82009494, 0x03013494, 0x96108e94, 0x17112e94,
1123         0x86009595, 0x07013595, 0x92108f95, 0x13112f95,
1124         0x86009696, 0x07013696, 0x96109096, 0x17113096,
1125         0x82009797, 0x03013797, 0x92109197, 0x13113197,
1126         0x82009898, 0x03013898, 0x92109298, 0x13113298,
1127         0x86009999, 0x07013999, 0x96109399, 0x17113399,
1128         0x1300349a, 0x1301349a, 0x1310349a, 0x1311349a,
1129         0x1700359b, 0x1701359b, 0x1710359b, 0x1711359b,
1130         0x1700369c, 0x1701369c, 0x1710369c, 0x1711369c,
1131         0x1300379d, 0x1301379d, 0x1310379d, 0x1311379d,
1132         0x1300389e, 0x1301389e, 0x1310389e, 0x1311389e,
1133         0x1700399f, 0x1701399f, 0x1710399f, 0x1711399f,
1134         0x030040a0, 0x030140a0, 0x17103aa0, 0x17113aa0,
1135         0x070041a1, 0x070141a1, 0x13103ba1, 0x13113ba1,
1136         0x070042a2, 0x070142a2, 0x17103ca2, 0x17113ca2,
1137         0x030043a3, 0x030143a3, 0x13103da3, 0x13113da3,
1138         0x070044a4, 0x070144a4, 0x13103ea4, 0x13113ea4,
1139         0x030045a5, 0x030145a5, 0x17103fa5, 0x17113fa5,
1140         0x030046a6, 0x030146a6, 0x131040a6, 0x131140a6,
1141         0x070047a7, 0x070147a7, 0x171041a7, 0x171141a7,
1142         0x070048a8, 0x070148a8, 0x171042a8, 0x171142a8,
1143         0x030049a9, 0x030149a9, 0x131043a9, 0x131143a9,
1144         0x170044aa, 0x170144aa, 0x171044aa, 0x171144aa,
1145         0x130045ab, 0x130145ab, 0x131045ab, 0x131145ab,
1146         0x130046ac, 0x130146ac, 0x131046ac, 0x131146ac,
1147         0x170047ad, 0x170147ad, 0x171047ad, 0x171147ad,
1148         0x170048ae, 0x170148ae, 0x171048ae, 0x171148ae,
1149         0x130049af, 0x130149af, 0x131049af, 0x131149af,
1150         0x070050b0, 0x070150b0, 0x13104ab0, 0x13114ab0,
1151         0x030051b1, 0x030151b1, 0x17104bb1, 0x17114bb1,
1152         0x030052b2, 0x030152b2, 0x13104cb2, 0x13114cb2,
1153         0x070053b3, 0x070153b3, 0x17104db3, 0x17114db3,
1154         0x030054b4, 0x030154b4, 0x17104eb4, 0x17114eb4,
1155         0x070055b5, 0x070155b5, 0x13104fb5, 0x13114fb5,
1156         0x070056b6, 0x070156b6, 0x171050b6, 0x171150b6,
1157         0x030057b7, 0x030157b7, 0x131051b7, 0x131151b7,
1158         0x030058b8, 0x030158b8, 0x131052b8, 0x131152b8,
1159         0x070059b9, 0x070159b9, 0x171053b9, 0x171153b9,
1160         0x130054ba, 0x130154ba, 0x131054ba, 0x131154ba,
1161         0x170055bb, 0x170155bb, 0x171055bb, 0x171155bb,
1162         0x170056bc, 0x170156bc, 0x171056bc, 0x171156bc,
1163         0x130057bd, 0x130157bd, 0x131057bd, 0x131157bd,
1164         0x130058be, 0x130158be, 0x131058be, 0x131158be,
1165         0x170059bf, 0x170159bf, 0x171059bf, 0x171159bf,
1166         0x070060c0, 0x070160c0, 0x17105ac0, 0x17115ac0,
1167         0x030061c1, 0x030161c1, 0x13105bc1, 0x13115bc1,
1168         0x030062c2, 0x030162c2, 0x17105cc2, 0x17115cc2,
1169         0x070063c3, 0x070163c3, 0x13105dc3, 0x13115dc3,
1170         0x030064c4, 0x030164c4, 0x13105ec4, 0x13115ec4,
1171         0x070065c5, 0x070165c5, 0x17105fc5, 0x17115fc5,
1172         0x070066c6, 0x070166c6, 0x171060c6, 0x171160c6,
1173         0x030067c7, 0x030167c7, 0x131061c7, 0x131161c7,
1174         0x030068c8, 0x030168c8, 0x131062c8, 0x131162c8,
1175         0x070069c9, 0x070169c9, 0x171063c9, 0x171163c9,
1176         0x130064ca, 0x130164ca, 0x131064ca, 0x131164ca,
1177         0x170065cb, 0x170165cb, 0x171065cb, 0x171165cb,
1178         0x170066cc, 0x170166cc, 0x171066cc, 0x171166cc,
1179         0x130067cd, 0x130167cd, 0x131067cd, 0x131167cd,
1180         0x130068ce, 0x130168ce, 0x131068ce, 0x131168ce,
1181         0x170069cf, 0x170169cf, 0x171069cf, 0x171169cf,
1182         0x030070d0, 0x030170d0, 0x17106ad0, 0x17116ad0,
1183         0x070071d1, 0x070171d1, 0x13106bd1, 0x13116bd1,
1184         0x070072d2, 0x070172d2, 0x17106cd2, 0x17116cd2,
1185         0x030073d3, 0x030173d3, 0x13106dd3, 0x13116dd3,
1186         0x070074d4, 0x070174d4, 0x13106ed4, 0x13116ed4,
1187         0x030075d5, 0x030175d5, 0x17106fd5, 0x17116fd5,
1188         0x030076d6, 0x030176d6, 0x131070d6, 0x131170d6,
1189         0x070077d7, 0x070177d7, 0x171071d7, 0x171171d7,
1190         0x070078d8, 0x070178d8, 0x171072d8, 0x171172d8,
1191         0x030079d9, 0x030179d9, 0x131073d9, 0x131173d9,
1192         0x170074da, 0x170174da, 0x171074da, 0x171174da,
1193         0x130075db, 0x130175db, 0x131075db, 0x131175db,
1194         0x130076dc, 0x130176dc, 0x131076dc, 0x131176dc,
1195         0x170077dd, 0x170177dd, 0x171077dd, 0x171177dd,
1196         0x170078de, 0x170178de, 0x171078de, 0x171178de,
1197         0x130079df, 0x130179df, 0x131079df, 0x131179df,
1198         0x830080e0, 0x830180e0, 0x13107ae0, 0x13117ae0,
1199         0x870081e1, 0x870181e1, 0x17107be1, 0x17117be1,
1200         0x870082e2, 0x870182e2, 0x13107ce2, 0x13117ce2,
1201         0x830083e3, 0x830183e3, 0x17107de3, 0x17117de3,
1202         0x870084e4, 0x870184e4, 0x17107ee4, 0x17117ee4,
1203         0x830085e5, 0x830185e5, 0x13107fe5, 0x13117fe5,
1204         0x830086e6, 0x830186e6, 0x931080e6, 0x931180e6,
1205         0x870087e7, 0x870187e7, 0x971081e7, 0x971181e7,
1206         0x870088e8, 0x870188e8, 0x971082e8, 0x971182e8,
1207         0x830089e9, 0x830189e9, 0x931083e9, 0x931183e9,
1208         0x970084ea, 0x970184ea, 0x971084ea, 0x971184ea,
1209         0x930085eb, 0x930185eb, 0x931085eb, 0x931185eb,
1210         0x930086ec, 0x930186ec, 0x931086ec, 0x931186ec,
1211         0x970087ed, 0x970187ed, 0x971087ed, 0x971187ed,
1212         0x970088ee, 0x970188ee, 0x971088ee, 0x971188ee,
1213         0x930089ef, 0x930189ef, 0x931089ef, 0x931189ef,
1214         0x870090f0, 0x870190f0, 0x93108af0, 0x93118af0,
1215         0x830091f1, 0x830191f1, 0x97108bf1, 0x97118bf1,
1216         0x830092f2, 0x830192f2, 0x93108cf2, 0x93118cf2,
1217         0x870093f3, 0x870193f3, 0x97108df3, 0x97118df3,
1218         0x830094f4, 0x830194f4, 0x97108ef4, 0x97118ef4,
1219         0x870095f5, 0x870195f5, 0x93108ff5, 0x93118ff5,
1220         0x870096f6, 0x870196f6, 0x971090f6, 0x971190f6,
1221         0x830097f7, 0x830197f7, 0x931091f7, 0x931191f7,
1222         0x830098f8, 0x830198f8, 0x931092f8, 0x931192f8,
1223         0x870099f9, 0x870199f9, 0x971093f9, 0x971193f9,
1224         0x930094fa, 0x930194fa, 0x931094fa, 0x931194fa,
1225         0x970095fb, 0x970195fb, 0x971095fb, 0x971195fb,
1226         0x970096fc, 0x970196fc, 0x971096fc, 0x971196fc,
1227         0x930097fd, 0x930197fd, 0x931097fd, 0x931197fd,
1228         0x930098fe, 0x930198fe, 0x931098fe, 0x931198fe,
1229         0x970099ff, 0x970199ff, 0x971099ff, 0x971199ff,
1230     };
1231 
1232     MK_INSN(das, "das");
1233 
1234     inregs = (struct regs){ 0 };
1235 
1236     for (i = 0; i < 1024; ++i) {
1237         unsigned tmp = test_cases[i];
1238         inregs.eax = tmp & 0xff;
1239         inregs.eflags = (tmp >> 16) & 0xff;
1240 	exec_in_big_real_mode(&insn_das);
1241 	if (!regs_equal(R_AX)
1242             || outregs.eax != ((tmp >> 8) & 0xff)
1243             || (outregs.eflags & 0xff) != (tmp >> 24)) {
1244 	    ++nr_fail;
1245 	    break;
1246         }
1247     }
1248     report("DAS", ~0, nr_fail == 0);
1249 }
1250 
1251 void test_cwd_cdq()
1252 {
1253 	/* Sign-bit set */
1254 	MK_INSN(cwd_1, "mov $0x8000, %ax\n\t"
1255 		       "cwd\n\t");
1256 
1257 	/* Sign-bit not set */
1258 	MK_INSN(cwd_2, "mov $0x1000, %ax\n\t"
1259 		       "cwd\n\t");
1260 
1261 	/* Sign-bit set */
1262 	MK_INSN(cdq_1, "mov $0x80000000, %eax\n\t"
1263 		       "cdq\n\t");
1264 
1265 	/* Sign-bit not set */
1266 	MK_INSN(cdq_2, "mov $0x10000000, %eax\n\t"
1267 		       "cdq\n\t");
1268 
1269 	inregs = (struct regs){ 0 };
1270 
1271 	exec_in_big_real_mode(&insn_cwd_1);
1272 	report("cwd 1", R_AX | R_DX,
1273 	       outregs.eax == 0x8000 && outregs.edx == 0xffff);
1274 
1275 	exec_in_big_real_mode(&insn_cwd_2);
1276 	report("cwd 2", R_AX | R_DX,
1277 	       outregs.eax == 0x1000 && outregs.edx == 0);
1278 
1279 	exec_in_big_real_mode(&insn_cdq_1);
1280 	report("cdq 1", R_AX | R_DX,
1281 	       outregs.eax == 0x80000000 && outregs.edx == 0xffffffff);
1282 
1283 	exec_in_big_real_mode(&insn_cdq_2);
1284 	report("cdq 2", R_AX | R_DX,
1285 	       outregs.eax == 0x10000000 && outregs.edx == 0);
1286 }
1287 
1288 static struct {
1289         void *address;
1290         unsigned short sel;
1291 } __attribute__((packed)) desc = {
1292 	(void *)0x1234,
1293 	0x10,
1294 };
1295 
1296 void test_lds_lss()
1297 {
1298 	inregs = (struct regs){ .ebx = (unsigned long)&desc };
1299 
1300 	MK_INSN(lds, "push %ds\n\t"
1301 		     "lds (%ebx), %eax\n\t"
1302 		     "mov %ds, %ebx\n\t"
1303 		     "pop %ds\n\t");
1304 	exec_in_big_real_mode(&insn_lds);
1305 	report("lds", R_AX | R_BX,
1306 		outregs.eax == (unsigned long)desc.address &&
1307 		outregs.ebx == desc.sel);
1308 
1309 	MK_INSN(les, "push %es\n\t"
1310 		     "les (%ebx), %eax\n\t"
1311 		     "mov %es, %ebx\n\t"
1312 		     "pop %es\n\t");
1313 	exec_in_big_real_mode(&insn_les);
1314 	report("les", R_AX | R_BX,
1315 		outregs.eax == (unsigned long)desc.address &&
1316 		outregs.ebx == desc.sel);
1317 
1318 	MK_INSN(lfs, "push %fs\n\t"
1319 		     "lfs (%ebx), %eax\n\t"
1320 		     "mov %fs, %ebx\n\t"
1321 		     "pop %fs\n\t");
1322 	exec_in_big_real_mode(&insn_lfs);
1323 	report("lfs", R_AX | R_BX,
1324 		outregs.eax == (unsigned long)desc.address &&
1325 		outregs.ebx == desc.sel);
1326 
1327 	MK_INSN(lgs, "push %gs\n\t"
1328 		     "lgs (%ebx), %eax\n\t"
1329 		     "mov %gs, %ebx\n\t"
1330 		     "pop %gs\n\t");
1331 	exec_in_big_real_mode(&insn_lgs);
1332 	report("lgs", R_AX | R_BX,
1333 		outregs.eax == (unsigned long)desc.address &&
1334 		outregs.ebx == desc.sel);
1335 
1336 	MK_INSN(lss, "push %ss\n\t"
1337 		     "lss (%ebx), %eax\n\t"
1338 		     "mov %ss, %ebx\n\t"
1339 		     "pop %ss\n\t");
1340 	exec_in_big_real_mode(&insn_lss);
1341 	report("lss", R_AX | R_BX,
1342 		outregs.eax == (unsigned long)desc.address &&
1343 		outregs.ebx == desc.sel);
1344 }
1345 
1346 void test_jcxz(void)
1347 {
1348 	MK_INSN(jcxz1, "jcxz 1f\n\t"
1349 		       "mov $0x1234, %eax\n\t"
1350 		       "1:\n\t");
1351 	MK_INSN(jcxz2, "mov $0x100, %ecx\n\t"
1352 		       "jcxz 1f\n\t"
1353 		       "mov $0x1234, %eax\n\t"
1354 		       "mov $0, %ecx\n\t"
1355 		       "1:\n\t");
1356 	MK_INSN(jcxz3, "mov $0x10000, %ecx\n\t"
1357 		       "jcxz 1f\n\t"
1358 		       "mov $0x1234, %eax\n\t"
1359 		       "1:\n\t");
1360 	MK_INSN(jecxz1, "jecxz 1f\n\t"
1361 			"mov $0x1234, %eax\n\t"
1362 			"1:\n\t");
1363 	MK_INSN(jecxz2, "mov $0x10000, %ecx\n\t"
1364 			"jecxz 1f\n\t"
1365 			"mov $0x1234, %eax\n\t"
1366 			"mov $0, %ecx\n\t"
1367 			"1:\n\t");
1368 
1369 	inregs = (struct regs){ 0 };
1370 
1371 	exec_in_big_real_mode(&insn_jcxz1);
1372 	report("jcxz short 1", 0, 1);
1373 
1374 	exec_in_big_real_mode(&insn_jcxz2);
1375 	report("jcxz short 2", R_AX, outregs.eax == 0x1234);
1376 
1377 	exec_in_big_real_mode(&insn_jcxz3);
1378 	report("jcxz short 3", R_CX, outregs.ecx == 0x10000);
1379 
1380 	exec_in_big_real_mode(&insn_jecxz1);
1381 	report("jecxz short 1", 0, 1);
1382 
1383 	exec_in_big_real_mode(&insn_jecxz2);
1384 	report("jecxz short 2", R_AX, outregs.eax == 0x1234);
1385 }
1386 
1387 static void test_cpuid(void)
1388 {
1389     MK_INSN(cpuid, "cpuid");
1390     unsigned function = 0x1234;
1391     unsigned eax, ebx, ecx, edx;
1392 
1393     inregs.eax = eax = function;
1394     inregs.ecx = ecx = 0;
1395     asm("cpuid" : "+a"(eax), "=b"(ebx), "+c"(ecx), "=d"(edx));
1396     exec_in_big_real_mode(&insn_cpuid);
1397     report("cpuid", R_AX|R_BX|R_CX|R_DX,
1398 	   outregs.eax == eax && outregs.ebx == ebx
1399 	   && outregs.ecx == ecx && outregs.edx == edx);
1400 }
1401 
1402 static void test_ss_base_for_esp_ebp(void)
1403 {
1404     MK_INSN(ssrel1, "mov %ss, %ax; mov %bx, %ss; movl (%ebp), %ebx; mov %ax, %ss");
1405     MK_INSN(ssrel2, "mov %ss, %ax; mov %bx, %ss; movl (%ebp,%edi,8), %ebx; mov %ax, %ss");
1406     static unsigned array[] = { 0x12345678, 0, 0, 0, 0x87654321 };
1407 
1408     inregs.ebx = 1;
1409     inregs.ebp = (unsigned)array;
1410     exec_in_big_real_mode(&insn_ssrel1);
1411     report("ss relative addressing (1)", R_AX | R_BX, outregs.ebx == 0x87654321);
1412     inregs.ebx = 1;
1413     inregs.ebp = (unsigned)array;
1414     inregs.edi = 0;
1415     exec_in_big_real_mode(&insn_ssrel2);
1416     report("ss relative addressing (2)", R_AX | R_BX, outregs.ebx == 0x87654321);
1417 }
1418 
1419 static void test_sgdt_sidt(void)
1420 {
1421     MK_INSN(sgdt, "sgdtw (%eax)");
1422     MK_INSN(sidt, "sidtw (%eax)");
1423     unsigned x, y;
1424 
1425     inregs.eax = (unsigned)&y;
1426     asm volatile("sgdtw %0" : "=m"(x));
1427     exec_in_big_real_mode(&insn_sgdt);
1428     report("sgdt", 0, x == y);
1429 
1430     inregs.eax = (unsigned)&y;
1431     asm volatile("sidtw %0" : "=m"(x));
1432     exec_in_big_real_mode(&insn_sidt);
1433     report("sidt", 0, x == y);
1434 }
1435 
1436 static void test_sahf(void)
1437 {
1438     MK_INSN(sahf, "sahf; pushfw; mov (%esp), %al; popfw");
1439 
1440     inregs.eax = 0xfd00;
1441     exec_in_big_real_mode(&insn_sahf);
1442     report("sahf", R_AX, outregs.eax == (inregs.eax | 0xd7));
1443 }
1444 
1445 static void test_lahf(void)
1446 {
1447     MK_INSN(lahf, "pushfw; mov %al, (%esp); popfw; lahf");
1448 
1449     inregs.eax = 0xc7;
1450     exec_in_big_real_mode(&insn_lahf);
1451     report("lahf", R_AX, (outregs.eax >> 8) == inregs.eax);
1452 }
1453 
1454 static void test_movzx_movsx(void)
1455 {
1456     MK_INSN(movsx, "movsx %al, %ebx");
1457     MK_INSN(movzx, "movzx %al, %ebx");
1458     MK_INSN(movzsah, "movsx %ah, %ebx");
1459     MK_INSN(movzxah, "movzx %ah, %ebx");
1460 
1461     inregs.eax = 0x1234569c;
1462     inregs.esp = 0xffff;
1463     exec_in_big_real_mode(&insn_movsx);
1464     report("movsx", R_BX, outregs.ebx == (signed char)inregs.eax);
1465     exec_in_big_real_mode(&insn_movzx);
1466     report("movzx", R_BX, outregs.ebx == (unsigned char)inregs.eax);
1467     exec_in_big_real_mode(&insn_movzsah);
1468     report("movsx ah", R_BX, outregs.ebx == (signed char)(inregs.eax>>8));
1469     exec_in_big_real_mode(&insn_movzxah);
1470     report("movzx ah", R_BX, outregs.ebx == (unsigned char)(inregs.eax >> 8));
1471 }
1472 
1473 static void test_bswap(void)
1474 {
1475     MK_INSN(bswap, "bswap %ecx");
1476 
1477     inregs.ecx = 0x12345678;
1478     exec_in_big_real_mode(&insn_bswap);
1479     report("bswap", R_CX, outregs.ecx == 0x78563412);
1480 }
1481 
1482 static void test_aad(void)
1483 {
1484     MK_INSN(aad, "aad");
1485 
1486     inregs.eax = 0x12345678;
1487     exec_in_big_real_mode(&insn_aad);
1488     report("aad", R_AX, outregs.eax == 0x123400d4);
1489 }
1490 
1491 static void test_aam(void)
1492 {
1493     MK_INSN(aam, "aam");
1494 
1495     inregs.eax = 0x76543210;
1496     exec_in_big_real_mode(&insn_aam);
1497     report("aam", R_AX, outregs.eax == 0x76540106);
1498 }
1499 
1500 static void test_xlat(void)
1501 {
1502     MK_INSN(xlat, "xlat");
1503     u8 table[256];
1504     int i;
1505 
1506     for (i = 0; i < 256; i++) {
1507         table[i] = i + 1;
1508     }
1509 
1510     inregs.eax = 0x89abcdef;
1511     inregs.ebx = (u32)table;
1512     exec_in_big_real_mode(&insn_xlat);
1513     report("xlat", R_AX, outregs.eax == 0x89abcdf0);
1514 }
1515 
1516 static void test_salc(void)
1517 {
1518     MK_INSN(clc_salc, "clc; .byte 0xd6");
1519     MK_INSN(stc_salc, "stc; .byte 0xd6");
1520 
1521     inregs.eax = 0x12345678;
1522     exec_in_big_real_mode(&insn_clc_salc);
1523     report("salc (1)", R_AX, outregs.eax == 0x12345600);
1524     exec_in_big_real_mode(&insn_stc_salc);
1525     report("salc (2)", R_AX, outregs.eax == 0x123456ff);
1526 }
1527 
1528 static void test_fninit(void)
1529 {
1530 	u16 fcw = -1, fsw = -1;
1531 	MK_INSN(fninit, "fninit ; fnstsw (%eax) ; fnstcw (%ebx)");
1532 
1533 	inregs.eax = (u32)&fsw;
1534 	inregs.ebx = (u32)&fcw;
1535 
1536 	exec_in_big_real_mode(&insn_fninit);
1537 	report("fninit", 0, fsw == 0 && (fcw & 0x103f) == 0x003f);
1538 }
1539 
1540 static void test_nopl(void)
1541 {
1542 	MK_INSN(nopl1, ".byte 0x90\n\r"); // 1 byte nop
1543 	MK_INSN(nopl2, ".byte 0x66, 0x90\n\r"); // 2 bytes nop
1544 	MK_INSN(nopl3, ".byte 0x0f, 0x1f, 0x00\n\r"); // 3 bytes nop
1545 	MK_INSN(nopl4, ".byte 0x0f, 0x1f, 0x40, 0x00\n\r"); // 4 bytes nop
1546 	exec_in_big_real_mode(&insn_nopl1);
1547 	exec_in_big_real_mode(&insn_nopl2);
1548 	exec_in_big_real_mode(&insn_nopl3);
1549 	exec_in_big_real_mode(&insn_nopl4);
1550 	report("nopl", 0, 1);
1551 }
1552 
1553 static u32 perf_baseline;
1554 
1555 #define PERF_COUNT 1000000
1556 
1557 #define MK_INSN_PERF(name, insn)                                \
1558 	MK_INSN(name, "rdtsc; mov %eax, %ebx; mov %edx, %esi\n" \
1559 		      "1:" insn "\n"                            \
1560 		      ".byte 0x67; loop 1b\n"                   \
1561 		      "rdtsc");
1562 
1563 static u32 cycles_in_big_real_mode(struct insn_desc *insn)
1564 {
1565 	u64 start, end;
1566 
1567 	inregs.ecx = PERF_COUNT;
1568 	exec_in_big_real_mode(insn);
1569 	start = ((u64)outregs.esi << 32) | outregs.ebx;
1570 	end = ((u64)outregs.edx << 32) | outregs.eax;
1571 
1572 	return end - start;
1573 }
1574 
1575 static void test_perf_loop(void)
1576 {
1577 	/*
1578 	 * This test runs simple instructions that should roughly take the
1579 	 * the same time to emulate: PERF_COUNT iterations of "loop" and 3
1580 	 * setup instructions.  Other performance tests can run PERF_COUNT
1581 	 * iterations of the same instruction and subtract the cycle count
1582 	 * of this test.
1583 	 */
1584 	MK_INSN_PERF(perf_loop, "");
1585 	perf_baseline = cycles_in_big_real_mode(&insn_perf_loop);
1586 	print_serial_u32(perf_baseline / (PERF_COUNT + 3));
1587 	print_serial(" cycles/emulated jump instruction\n");
1588 }
1589 
1590 static void test_perf_mov(void)
1591 {
1592 	u32 cyc;
1593 
1594 	MK_INSN_PERF(perf_move, "mov %esi, %edi");
1595 	cyc = cycles_in_big_real_mode(&insn_perf_move);
1596 	print_serial_u32((cyc - perf_baseline) / PERF_COUNT);
1597 	print_serial(" cycles/emulated move instruction\n");
1598 }
1599 
1600 static void test_perf_arith(void)
1601 {
1602 	u32 cyc;
1603 
1604 	MK_INSN_PERF(perf_arith, "add $4, %edi");
1605 	cyc = cycles_in_big_real_mode(&insn_perf_arith);
1606 	print_serial_u32((cyc - perf_baseline) / PERF_COUNT);
1607 	print_serial(" cycles/emulated arithmetic instruction\n");
1608 }
1609 
1610 static void test_perf_memory_load(void)
1611 {
1612 	u32 cyc, tmp;
1613 
1614 	MK_INSN_PERF(perf_memory_load, "cmp $0, (%edi)");
1615 	inregs.edi = (u32)&tmp;
1616 	cyc = cycles_in_big_real_mode(&insn_perf_memory_load);
1617 	print_serial_u32((cyc - perf_baseline) / PERF_COUNT);
1618 	print_serial(" cycles/emulated memory load instruction\n");
1619 }
1620 
1621 static void test_perf_memory_store(void)
1622 {
1623 	u32 cyc, tmp;
1624 
1625 	MK_INSN_PERF(perf_memory_store, "mov %ax, (%edi)");
1626 	inregs.edi = (u32)&tmp;
1627 	cyc = cycles_in_big_real_mode(&insn_perf_memory_store);
1628 	print_serial_u32((cyc - perf_baseline) / PERF_COUNT);
1629 	print_serial(" cycles/emulated memory store instruction\n");
1630 }
1631 
1632 static void test_perf_memory_rmw(void)
1633 {
1634 	u32 cyc, tmp;
1635 
1636 	MK_INSN_PERF(perf_memory_rmw, "add $1, (%edi)");
1637 	inregs.edi = (u32)&tmp;
1638 	cyc = cycles_in_big_real_mode(&insn_perf_memory_rmw);
1639 	print_serial_u32((cyc - perf_baseline) / PERF_COUNT);
1640 	print_serial(" cycles/emulated memory RMW instruction\n");
1641 }
1642 
1643 void test_dr_mod(void)
1644 {
1645 	MK_INSN(drmod, "movl %ebx, %dr0\n\t"
1646 		       ".byte 0x0f \n\t .byte 0x21 \n\t .byte 0x0\n\t");
1647 	inregs.eax = 0xdead;
1648 	inregs.ebx = 0xaced;
1649 	exec_in_big_real_mode(&insn_drmod);
1650 	report("mov dr with mod bits", R_AX | R_BX, outregs.eax == 0xaced);
1651 }
1652 
1653 void test_smsw(void)
1654 {
1655 	MK_INSN(smsw, "movl %cr0, %ebx\n\t"
1656 		      "movl %ebx, %ecx\n\t"
1657 		      "or $0x40000000, %ebx\n\t"
1658 		      "movl %ebx, %cr0\n\t"
1659 		      "smswl %eax\n\t"
1660 		      "movl %ecx, %cr0\n\t");
1661 	inregs.eax = 0x12345678;
1662 	exec_in_big_real_mode(&insn_smsw);
1663 	report("smsw", R_AX | R_BX | R_CX, outregs.eax == outregs.ebx);
1664 }
1665 
1666 
1667 void realmode_start(void)
1668 {
1669 	test_null();
1670 
1671 	test_shld();
1672 	test_push_pop();
1673 	test_pusha_popa();
1674 	test_mov_imm();
1675 	test_cmp_imm();
1676 	test_add_imm();
1677 	test_sub_imm();
1678 	test_xor_imm();
1679 	test_io();
1680 	test_eflags_insn();
1681 	test_jcc_short();
1682 	test_jcc_near();
1683 	/* test_call() uses short jump so call it after testing jcc */
1684 	test_call();
1685 	/* long jmp test uses call near so test it after testing call */
1686 	test_long_jmp();
1687 	test_xchg();
1688 	test_iret();
1689 	test_int();
1690 	test_imul();
1691 	test_mul();
1692 	test_div();
1693 	test_idiv();
1694 	test_loopcc();
1695 	test_cbw();
1696 	test_cwd_cdq();
1697 	test_das();
1698 	test_lds_lss();
1699 	test_jcxz();
1700 	test_cpuid();
1701 	test_ss_base_for_esp_ebp();
1702 	test_sgdt_sidt();
1703 	test_lahf();
1704 	test_sahf();
1705 	test_movzx_movsx();
1706 	test_bswap();
1707 	test_aad();
1708 	test_aam();
1709 	test_xlat();
1710 	test_salc();
1711 	test_fninit();
1712 	test_dr_mod();
1713 	test_smsw();
1714 	test_nopl();
1715 	test_perf_loop();
1716 	test_perf_mov();
1717 	test_perf_arith();
1718 	test_perf_memory_load();
1719 	test_perf_memory_store();
1720 	test_perf_memory_rmw();
1721 
1722 	exit(failed);
1723 }
1724 
1725 unsigned long long r_gdt[] = { 0, 0x9b000000ffff, 0x93000000ffff };
1726 
1727 struct __attribute__((packed)) {
1728 	unsigned short limit;
1729 	void *base;
1730 } r_gdt_descr = { sizeof(r_gdt) - 1, &r_gdt };
1731 
1732 asm(
1733 	".section .init \n\t"
1734 
1735 	".code32 \n\t"
1736 
1737 	"mb_magic = 0x1BADB002 \n\t"
1738 	"mb_flags = 0x0 \n\t"
1739 
1740 	"# multiboot header \n\t"
1741 	".long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) \n\t"
1742 
1743 	".globl start \n\t"
1744 	".data \n\t"
1745 	". = . + 4096 \n\t"
1746 	"stacktop: \n\t"
1747 
1748 	".text \n\t"
1749 	"start: \n\t"
1750 	"lgdt r_gdt_descr \n\t"
1751 	"ljmp $8, $1f; 1: \n\t"
1752 	".code16gcc \n\t"
1753 	"mov $16, %eax \n\t"
1754 	"mov %ax, %ds \n\t"
1755 	"mov %ax, %es \n\t"
1756 	"mov %ax, %fs \n\t"
1757 	"mov %ax, %gs \n\t"
1758 	"mov %ax, %ss \n\t"
1759 	"mov %cr0, %eax \n\t"
1760 	"btc $0, %eax \n\t"
1761 	"mov %eax, %cr0 \n\t"
1762 	"ljmp $0, $realmode_entry \n\t"
1763 
1764 	"realmode_entry: \n\t"
1765 
1766 	"xor %ax, %ax \n\t"
1767 	"mov %ax, %ds \n\t"
1768 	"mov %ax, %es \n\t"
1769 	"mov %ax, %ss \n\t"
1770 	"mov %ax, %fs \n\t"
1771 	"mov %ax, %gs \n\t"
1772 	"mov $stacktop, %esp\n\t"
1773 	"ljmp $0, $realmode_start \n\t"
1774 
1775 	".code16gcc \n\t"
1776 	);
1777