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