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