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