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