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