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