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