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