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