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