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