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