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