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