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