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