xref: /kvm-unit-tests/x86/realmode.c (revision 7d36db351752e29ad27eaafe3f102de7064e429b) !
1 asm(".code16gcc");
2 
3 typedef unsigned char u8;
4 typedef unsigned short u16;
5 typedef unsigned u32;
6 typedef unsigned long long u64;
7 
8 void test_function(void);
9 
10 asm(
11 	"test_function: \n\t"
12 	"mov $0x1234, %eax \n\t"
13 	"ret"
14    );
15 
16 static int strlen(const char *str)
17 {
18 	int n;
19 
20 	for (n = 0; *str; ++str)
21 		++n;
22 	return n;
23 }
24 
25 static void print_serial(const char *buf)
26 {
27 	unsigned long len = strlen(buf);
28 
29 	asm volatile ("cld; addr32/rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1));
30 }
31 
32 static void exit(int code)
33 {
34         asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4));
35 }
36 
37 struct regs {
38 	u32 eax, ebx, ecx, edx;
39 	u32 esi, edi, esp, ebp;
40 	u32 eip, eflags;
41 };
42 
43 static u64 gdt[] = {
44 	0,
45 	0x00cf9b000000ffffull, // flat 32-bit code segment
46 	0x00cf93000000ffffull, // flat 32-bit data segment
47 };
48 
49 static struct {
50 	u16 limit;
51 	void *base;
52 } __attribute__((packed)) gdt_descr = {
53 	sizeof(gdt) - 1,
54 	gdt,
55 };
56 
57 static void exec_in_big_real_mode(const struct regs *inregs,
58 				  struct regs *outregs,
59 				  const u8 *insn, int insn_len)
60 {
61 	unsigned long tmp;
62 	static struct regs save;
63 	int i;
64 	extern u8 test_insn[], test_insn_end[];
65 
66 	for (i = 0; i < insn_len; ++i)
67 		test_insn[i] = insn[i];
68 	for (; i < test_insn_end - test_insn; ++i)
69 		test_insn[i] = 0x90; // nop
70 
71 	save = *inregs;
72 	asm volatile(
73 		"lgdtl %[gdt_descr] \n\t"
74 		"mov %%cr0, %[tmp] \n\t"
75 		"or $1, %[tmp] \n\t"
76 		"mov %[tmp], %%cr0 \n\t"
77 		"mov %[bigseg], %%gs \n\t"
78 		"and $-2, %[tmp] \n\t"
79 		"mov %[tmp], %%cr0 \n\t"
80 
81 		"xchg %%eax, %[save]+0 \n\t"
82 		"xchg %%ebx, %[save]+4 \n\t"
83 		"xchg %%ecx, %[save]+8 \n\t"
84 		"xchg %%edx, %[save]+12 \n\t"
85 		"xchg %%esi, %[save]+16 \n\t"
86 		"xchg %%edi, %[save]+20 \n\t"
87 		"xchg %%esp, %[save]+24 \n\t"
88 		"xchg %%ebp, %[save]+28 \n\t"
89 
90 		"test_insn: . = . + 32\n\t"
91 		"test_insn_end: \n\t"
92 
93 		"xchg %%eax, %[save]+0 \n\t"
94 		"xchg %%ebx, %[save]+4 \n\t"
95 		"xchg %%ecx, %[save]+8 \n\t"
96 		"xchg %%edx, %[save]+12 \n\t"
97 		"xchg %%esi, %[save]+16 \n\t"
98 		"xchg %%edi, %[save]+20 \n\t"
99 		"xchg %%esp, %[save]+24 \n\t"
100 		"xchg %%ebp, %[save]+28 \n\t"
101 
102 		/* Save EFLAGS in outregs*/
103 		"pushfl \n\t"
104 		"popl %[save]+36 \n\t"
105 
106 		"xor %[tmp], %[tmp] \n\t"
107 		"mov %[tmp], %%gs \n\t"
108 		: [tmp]"=&r"(tmp), [save]"+m"(save)
109 		: [gdt_descr]"m"(gdt_descr), [bigseg]"r"((short)16)
110 		: "cc", "memory"
111 		);
112 	*outregs = save;
113 }
114 
115 #define R_AX 1
116 #define R_BX 2
117 #define R_CX 4
118 #define R_DX 8
119 #define R_SI 16
120 #define R_DI 32
121 #define R_SP 64
122 #define R_BP 128
123 
124 int regs_equal(const struct regs *r1, const struct regs *r2, int ignore)
125 {
126 	const u32 *p1 = &r1->eax, *p2 = &r2->eax;  // yuck
127 	int i;
128 
129 	for (i = 0; i < 8; ++i)
130 		if (!(ignore & (1 << i)) && p1[i] != p2[i])
131 			return 0;
132 	return 1;
133 }
134 
135 #define MK_INSN(name, str)                         \
136 	asm (				           \
137 		".text 1\n\t"                      \
138 		"insn_" #name ": " str " \n\t"	   \
139 		"insn_" #name "_end: \n\t"	   \
140 		".text\n\t"                        \
141 		);				   \
142 	extern u8 insn_##name[], insn_##name##_end[]
143 
144 void test_xchg(void)
145 {
146 	struct regs inregs = { .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = 7}, outregs;
147 
148 	MK_INSN(xchg_test1, "xchg %eax,%eax\n\t");
149 	MK_INSN(xchg_test2, "xchg %eax,%ebx\n\t");
150 	MK_INSN(xchg_test3, "xchg %eax,%ecx\n\t");
151 	MK_INSN(xchg_test4, "xchg %eax,%edx\n\t");
152 	MK_INSN(xchg_test5, "xchg %eax,%esi\n\t");
153 	MK_INSN(xchg_test6, "xchg %eax,%edi\n\t");
154 	MK_INSN(xchg_test7, "xchg %eax,%ebp\n\t");
155 	MK_INSN(xchg_test8, "xchg %eax,%esp\n\t");
156 
157 	exec_in_big_real_mode(&inregs, &outregs,
158 			      insn_xchg_test1,
159                               insn_xchg_test1_end - insn_xchg_test1);
160 
161 	if (!regs_equal(&inregs, &outregs, 0))
162 		print_serial("xchg test 1: FAIL\n");
163 	else
164 		print_serial("xchg test 1: PASS\n");
165 
166 	exec_in_big_real_mode(&inregs, &outregs,
167 			      insn_xchg_test2,
168                               insn_xchg_test2_end - insn_xchg_test2);
169 
170 	if (!regs_equal(&inregs, &outregs, R_AX | R_BX) ||
171             outregs.eax != inregs.ebx ||
172             outregs.ebx != inregs.eax)
173 		print_serial("xchg test 2: FAIL\n");
174 	else
175 		print_serial("xchg test 2: PASS\n");
176 
177 	exec_in_big_real_mode(&inregs, &outregs,
178 			      insn_xchg_test3,
179                               insn_xchg_test3_end - insn_xchg_test3);
180 
181 	if (!regs_equal(&inregs, &outregs, R_AX | R_CX) ||
182             outregs.eax != inregs.ecx ||
183             outregs.ecx != inregs.eax)
184 		print_serial("xchg test 3: FAIL\n");
185 	else
186 		print_serial("xchg test 3: PASS\n");
187 
188 	exec_in_big_real_mode(&inregs, &outregs,
189 			      insn_xchg_test4,
190                               insn_xchg_test4_end - insn_xchg_test4);
191 
192 	if (!regs_equal(&inregs, &outregs, R_AX | R_DX) ||
193             outregs.eax != inregs.edx ||
194             outregs.edx != inregs.eax)
195 		print_serial("xchg test 4: FAIL\n");
196 	else
197 		print_serial("xchg test 4: PASS\n");
198 
199 	exec_in_big_real_mode(&inregs, &outregs,
200 			      insn_xchg_test5,
201                               insn_xchg_test5_end - insn_xchg_test5);
202 
203 	if (!regs_equal(&inregs, &outregs, R_AX | R_SI) ||
204             outregs.eax != inregs.esi ||
205             outregs.esi != inregs.eax)
206 		print_serial("xchg test 5: FAIL\n");
207 	else
208 		print_serial("xchg test 5: PASS\n");
209 
210 	exec_in_big_real_mode(&inregs, &outregs,
211 			      insn_xchg_test6,
212                               insn_xchg_test6_end - insn_xchg_test6);
213 
214 	if (!regs_equal(&inregs, &outregs, R_AX | R_DI) ||
215             outregs.eax != inregs.edi ||
216             outregs.edi != inregs.eax)
217 		print_serial("xchg test 6: FAIL\n");
218 	else
219 		print_serial("xchg test 6: PASS\n");
220 
221 	exec_in_big_real_mode(&inregs, &outregs,
222 			      insn_xchg_test7,
223                               insn_xchg_test7_end - insn_xchg_test7);
224 
225 	if (!regs_equal(&inregs, &outregs, R_AX | R_BP) ||
226             outregs.eax != inregs.ebp ||
227             outregs.ebp != inregs.eax)
228 		print_serial("xchg test 7: FAIL\n");
229 	else
230 		print_serial("xchg test 7: PASS\n");
231 
232 	exec_in_big_real_mode(&inregs, &outregs,
233 			      insn_xchg_test8,
234                               insn_xchg_test8_end - insn_xchg_test8);
235 
236 	if (!regs_equal(&inregs, &outregs, R_AX | R_SP) ||
237             outregs.eax != inregs.esp ||
238             outregs.esp != inregs.eax)
239 		print_serial("xchg test 8: FAIL\n");
240 	else
241 		print_serial("xchg test 8: PASS\n");
242 }
243 
244 void test_shld(void)
245 {
246 	struct regs inregs = { .eax = 0xbe, .edx = 0xef000000 }, outregs;
247 	MK_INSN(shld_test, "shld $8,%edx,%eax\n\t");
248 
249 	exec_in_big_real_mode(&inregs, &outregs,
250 			      insn_shld_test,
251 			      insn_shld_test_end - insn_shld_test);
252 	if (outregs.eax != 0xbeef)
253 		print_serial("shld: FAIL\n");
254 	else
255 		print_serial("shld: PASS\n");
256 }
257 
258 void test_mov_imm(void)
259 {
260 	struct regs inregs = { 0 }, outregs;
261 	MK_INSN(mov_r32_imm_1, "mov $1234567890, %eax");
262 	MK_INSN(mov_r16_imm_1, "mov $1234, %ax");
263 	MK_INSN(mov_r8_imm_1, "mov $0x12, %ah");
264 	MK_INSN(mov_r8_imm_2, "mov $0x34, %al");
265 	MK_INSN(mov_r8_imm_3, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t");
266 
267 	exec_in_big_real_mode(&inregs, &outregs,
268 			      insn_mov_r16_imm_1,
269 			      insn_mov_r16_imm_1_end - insn_mov_r16_imm_1);
270 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234)
271 		print_serial("mov test 1: FAIL\n");
272 	else
273 		print_serial("mov test 1: PASS\n");
274 
275 	/* test mov $imm, %eax */
276 	exec_in_big_real_mode(&inregs, &outregs,
277 			      insn_mov_r32_imm_1,
278 			      insn_mov_r32_imm_1_end - insn_mov_r32_imm_1);
279 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234567890)
280 		print_serial("mov test 2: FAIL\n");
281 	else
282 		print_serial("mov test 2: PASS\n");
283 
284 	/* test mov $imm, %al/%ah */
285 	exec_in_big_real_mode(&inregs, &outregs,
286 			      insn_mov_r8_imm_1,
287 			      insn_mov_r8_imm_1_end - insn_mov_r8_imm_1);
288 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1200)
289 		print_serial("mov test 3: FAIL\n");
290 	else
291 		print_serial("mov test 3: PASS\n");
292 
293 	exec_in_big_real_mode(&inregs, &outregs,
294 			      insn_mov_r8_imm_2,
295 			      insn_mov_r8_imm_2_end - insn_mov_r8_imm_2);
296 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x34)
297 		print_serial("mov test 4: FAIL\n");
298 	else
299 		print_serial("mov test 4: PASS\n");
300 
301 	exec_in_big_real_mode(&inregs, &outregs,
302 			      insn_mov_r8_imm_3,
303 			      insn_mov_r8_imm_3_end - insn_mov_r8_imm_3);
304 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234)
305 		print_serial("mov test 5: FAIL\n");
306 	else
307 		print_serial("mov test 5: PASS\n");
308 }
309 
310 void test_sub_imm(void)
311 {
312 	struct regs inregs = { 0 }, outregs;
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 	exec_in_big_real_mode(&inregs, &outregs,
319 			      insn_sub_r16_imm_1,
320 			      insn_sub_r16_imm_1_end - insn_sub_r16_imm_1);
321 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1224)
322 		print_serial("sub test 1: FAIL\n");
323 	else
324 		print_serial("sub test 1: PASS\n");
325 
326 	/* test mov $imm, %eax */
327 	exec_in_big_real_mode(&inregs, &outregs,
328 			      insn_sub_r32_imm_1,
329 			      insn_sub_r32_imm_1_end - insn_sub_r32_imm_1);
330 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234567880)
331 		print_serial("sub test 2: FAIL\n");
332 	else
333 		print_serial("sub test 2: PASS\n");
334 
335 	/* test mov $imm, %al/%ah */
336 	exec_in_big_real_mode(&inregs, &outregs,
337 			      insn_sub_r8_imm_1,
338 			      insn_sub_r8_imm_1_end - insn_sub_r8_imm_1);
339 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x0200)
340 		print_serial("sub test 3: FAIL\n");
341 	else
342 		print_serial("sub test 3: PASS\n");
343 
344 	exec_in_big_real_mode(&inregs, &outregs,
345 			      insn_sub_r8_imm_2,
346 			      insn_sub_r8_imm_2_end - insn_sub_r8_imm_2);
347 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x24)
348 		print_serial("sub test 4: FAIL\n");
349 	else
350 		print_serial("sub test 4: PASS\n");
351 }
352 
353 
354 void test_xor_imm(void)
355 {
356 	struct regs inregs = { 0 }, outregs;
357 	MK_INSN(xor_r32_imm_1, "mov $1234567890, %eax\n\t" "xor $1234567890, %eax\n\t");
358 	MK_INSN(xor_r16_imm_1, "mov $1234, %ax\n\t" "xor $1234, %ax\n\t");
359 	MK_INSN(xor_r8_imm_1, "mov $0x12, %ah\n\t" "xor $0x12, %ah\n\t");
360 	MK_INSN(xor_r8_imm_2, "mov $0x34, %al\n\t" "xor $0x34, %al\n\t");
361 
362 	exec_in_big_real_mode(&inregs, &outregs,
363 			      insn_xor_r16_imm_1,
364 			      insn_xor_r16_imm_1_end - insn_xor_r16_imm_1);
365 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0)
366 		print_serial("xor test 1: FAIL\n");
367 	else
368 		print_serial("xor test 1: PASS\n");
369 
370 	/* test mov $imm, %eax */
371 	exec_in_big_real_mode(&inregs, &outregs,
372 			      insn_xor_r32_imm_1,
373 			      insn_xor_r32_imm_1_end - insn_xor_r32_imm_1);
374 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0)
375 		print_serial("xor test 2: FAIL\n");
376 	else
377 		print_serial("xor test 2: PASS\n");
378 
379 	/* test mov $imm, %al/%ah */
380 	exec_in_big_real_mode(&inregs, &outregs,
381 			      insn_xor_r8_imm_1,
382 			      insn_xor_r8_imm_1_end - insn_xor_r8_imm_1);
383 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0)
384 		print_serial("xor test 3: FAIL\n");
385 	else
386 		print_serial("xor test 3: PASS\n");
387 
388 	exec_in_big_real_mode(&inregs, &outregs,
389 			      insn_xor_r8_imm_2,
390 			      insn_xor_r8_imm_2_end - insn_xor_r8_imm_2);
391 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0)
392 		print_serial("xor test 4: FAIL\n");
393 	else
394 		print_serial("xor test 4: PASS\n");
395 }
396 
397 void test_cmp_imm(void)
398 {
399 	struct regs inregs = { 0 }, outregs;
400 	MK_INSN(cmp_test1, "mov $0x34, %al\n\t"
401 			   "cmp $0x34, %al\n\t");
402 	MK_INSN(cmp_test2, "mov $0x34, %al\n\t"
403 			   "cmp $0x39, %al\n\t");
404 	MK_INSN(cmp_test3, "mov $0x34, %al\n\t"
405 			   "cmp $0x24, %al\n\t");
406 
407 	/* test cmp imm8 with AL */
408 	/* ZF: (bit 6) Zero Flag becomes 1 if an operation results
409 	 * in a 0 writeback, or 0 register
410 	 */
411 	exec_in_big_real_mode(&inregs, &outregs,
412 			      insn_cmp_test1,
413 			      insn_cmp_test1_end - insn_cmp_test1);
414 	if ((outregs.eflags & (1<<6)) != (1<<6))
415 		print_serial("cmp test 1: FAIL\n");
416 	else
417 		print_serial("cmp test 1: PASS\n");
418 
419 	exec_in_big_real_mode(&inregs, &outregs,
420 			      insn_cmp_test2,
421 			      insn_cmp_test2_end - insn_cmp_test2);
422 	if ((outregs.eflags & (1<<6)) != 0)
423 		print_serial("cmp test 2: FAIL\n");
424 	else
425 		print_serial("cmp test 2: PASS\n");
426 
427 	exec_in_big_real_mode(&inregs, &outregs,
428 			      insn_cmp_test3,
429 			      insn_cmp_test3_end - insn_cmp_test3);
430 	if ((outregs.eflags & (1<<6)) != 0)
431 		print_serial("cmp test 3: FAIL\n");
432 	else
433 		print_serial("cmp test 3: PASS\n");
434 }
435 
436 void test_add_imm(void)
437 {
438 	struct regs inregs = { 0 }, outregs;
439 	MK_INSN(add_test1, "mov $0x43211234, %eax \n\t"
440 			   "add $0x12344321, %eax \n\t");
441 	MK_INSN(add_test2, "mov $0x12, %eax \n\t"
442 			   "add $0x21, %al\n\t");
443 
444 	exec_in_big_real_mode(&inregs, &outregs,
445 			      insn_add_test1,
446 			      insn_add_test1_end - insn_add_test1);
447 	if (outregs.eax != 0x55555555)
448 		print_serial("add test 1: FAIL\n");
449 	else
450 		print_serial("add test 1: PASS\n");
451 
452 	exec_in_big_real_mode(&inregs, &outregs,
453 			      insn_add_test2,
454 			      insn_add_test2_end - insn_add_test2);
455 	if (outregs.eax != 0x33)
456 		print_serial("add test 2: FAIL\n");
457 	else
458 		print_serial("add test 2: PASS\n");
459 }
460 
461 void test_eflags_insn(void)
462 {
463 	struct regs inregs = { 0 }, outregs;
464 	MK_INSN(clc, "clc");
465 	MK_INSN(cli, "cli");
466 	MK_INSN(sti, "sti");
467 	MK_INSN(cld, "cld");
468 	MK_INSN(std, "std");
469 
470 	exec_in_big_real_mode(&inregs, &outregs,
471 			      insn_clc,
472 			      insn_clc_end - insn_clc);
473 	if (outregs.eflags & 1)
474 		print_serial("clc test: FAIL\n");
475 	else
476 		print_serial("clc test: PASS\n");
477 
478 	exec_in_big_real_mode(&inregs, &outregs,
479 			      insn_cli,
480 			      insn_cli_end - insn_cli);
481 	if (outregs.eflags & (1 << 9))
482 		print_serial("cli test: FAIL\n");
483 	else
484 		print_serial("cli test: PASS\n");
485 
486 	exec_in_big_real_mode(&inregs, &outregs,
487 			      insn_sti,
488 			      insn_sti_end - insn_sti);
489 	if (!(outregs.eflags & (1 << 9)))
490 		print_serial("sti test: FAIL\n");
491 	else
492 		print_serial("sti test: PASS\n");
493 
494 	exec_in_big_real_mode(&inregs, &outregs,
495 			      insn_cld,
496 			      insn_cld_end - insn_cld);
497 	if (outregs.eflags & (1 << 10))
498 		print_serial("cld test: FAIL\n");
499 	else
500 		print_serial("cld test: PASS\n");
501 
502 	exec_in_big_real_mode(&inregs, &outregs,
503 			      insn_std,
504 			      insn_std_end - insn_std);
505 	if (!(outregs.eflags & (1 << 10)))
506 		print_serial("std test: FAIL\n");
507 	else
508 		print_serial("std test: PASS\n");
509 }
510 
511 void test_io(void)
512 {
513 	struct regs inregs = { 0 }, outregs;
514 	MK_INSN(io_test1, "mov $0xff, %al \n\t"
515 		          "out %al, $0xe0 \n\t"
516 		          "mov $0x00, %al \n\t"
517 			  "in $0xe0, %al \n\t");
518 	MK_INSN(io_test2, "mov $0xffff, %ax \n\t"
519 			  "out %ax, $0xe0 \n\t"
520 			  "mov $0x0000, %ax \n\t"
521 			  "in $0xe0, %ax \n\t");
522 	MK_INSN(io_test3, "mov $0xffffffff, %eax \n\t"
523 			  "out %eax, $0xe0 \n\t"
524 			  "mov $0x000000, %eax \n\t"
525 			  "in $0xe0, %eax \n\t");
526 	MK_INSN(io_test4, "mov $0xe0, %dx \n\t"
527 			  "mov $0xff, %al \n\t"
528 			  "out %al, %dx \n\t"
529 			  "mov $0x00, %al \n\t"
530 			  "in %dx, %al \n\t");
531 	MK_INSN(io_test5, "mov $0xe0, %dx \n\t"
532 			  "mov $0xffff, %ax \n\t"
533 			  "out %ax, %dx \n\t"
534 			  "mov $0x0000, %ax \n\t"
535 			  "in %dx, %ax \n\t");
536 	MK_INSN(io_test6, "mov $0xe0, %dx \n\t"
537 			  "mov $0xffffffff, %eax \n\t"
538 			  "out %eax, %dx \n\t"
539 			  "mov $0x00000000, %eax \n\t"
540 			  "in %dx, %eax \n\t");
541 
542 	exec_in_big_real_mode(&inregs, &outregs,
543 			      insn_io_test1,
544 			      insn_io_test1_end - insn_io_test1);
545 
546 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xff)
547 		print_serial("I/O test 1: FAIL\n");
548 	else
549 		print_serial("I/O test 1: PASS\n");
550 
551 	exec_in_big_real_mode(&inregs, &outregs,
552 			      insn_io_test2,
553 			      insn_io_test2_end - insn_io_test2);
554 
555 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffff)
556 		print_serial("I/O test 2: FAIL\n");
557 	else
558 		print_serial("I/O test 2: PASS\n");
559 
560 	exec_in_big_real_mode(&inregs, &outregs,
561 			      insn_io_test3,
562 			      insn_io_test3_end - insn_io_test3);
563 
564 	if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffffffff)
565 		print_serial("I/O test 3: FAIL\n");
566 	else
567 		print_serial("I/O test 3: PASS\n");
568 
569 	exec_in_big_real_mode(&inregs, &outregs,
570 			      insn_io_test4,
571 			      insn_io_test4_end - insn_io_test4);
572 
573 	if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xff)
574 		print_serial("I/O test 4: FAIL\n");
575 	else
576 		print_serial("I/O test 4: PASS\n");
577 
578 	exec_in_big_real_mode(&inregs, &outregs,
579 			      insn_io_test5,
580 			      insn_io_test5_end - insn_io_test5);
581 
582 	if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffff)
583 		print_serial("I/O test 5: FAIL\n");
584 	else
585 		print_serial("I/O test 5: PASS\n");
586 
587 	exec_in_big_real_mode(&inregs, &outregs,
588 			      insn_io_test6,
589 			      insn_io_test6_end - insn_io_test6);
590 
591 	if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffffffff)
592 		print_serial("I/O test 6: FAIL\n");
593 	else
594 		print_serial("I/O test 6: PASS\n");
595 }
596 
597 void test_call(void)
598 {
599 	struct regs inregs = { 0 }, outregs;
600 	u32 esp[16];
601 
602 	inregs.esp = (u32)esp;
603 
604 	MK_INSN(call1, "mov $test_function, %eax \n\t"
605 		       "call *%eax\n\t");
606 	MK_INSN(call_near1, "jmp 2f\n\t"
607 			    "1: mov $0x1234, %eax\n\t"
608 			    "ret\n\t"
609 			    "2: call 1b\t");
610 	MK_INSN(call_near2, "call 1f\n\t"
611 			    "jmp 2f\n\t"
612 			    "1: mov $0x1234, %eax\n\t"
613 			    "ret\n\t"
614 			    "2:\t");
615 
616 	exec_in_big_real_mode(&inregs, &outregs,
617 			      insn_call1,
618 			      insn_call1_end - insn_call1);
619 	if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234)
620 		print_serial("Call Test 1: FAIL\n");
621 	else
622 		print_serial("Call Test 1: PASS\n");
623 
624 	exec_in_big_real_mode(&inregs, &outregs,
625 			insn_call_near1, insn_call_near1_end - insn_call_near1);
626 	if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234)
627 		print_serial("Call near Test 1: FAIL\n");
628 	else
629 		print_serial("Call near Test 1: PASS\n");
630 
631 	exec_in_big_real_mode(&inregs, &outregs,
632 			insn_call_near2, insn_call_near2_end - insn_call_near2);
633 	if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234)
634 		print_serial("Call near Test 2: FAIL\n");
635 	else
636 		print_serial("Call near Test 2: PASS\n");
637 }
638 
639 void test_jcc_short(void)
640 {
641 	struct regs inregs = { 0 }, outregs;
642 	MK_INSN(jnz_short1, "jnz 1f\n\t"
643 			    "mov $0x1234, %eax\n\t"
644 		            "1:\n\t");
645 	MK_INSN(jnz_short2, "1:\n\t"
646 			    "cmp $0x1234, %eax\n\t"
647 			    "mov $0x1234, %eax\n\t"
648 		            "jnz 1b\n\t");
649 	MK_INSN(jmp_short1, "jmp 1f\n\t"
650 		      "mov $0x1234, %eax\n\t"
651 		      "1:\n\t");
652 
653 	exec_in_big_real_mode(&inregs, &outregs,
654 			insn_jnz_short1, insn_jnz_short1_end - insn_jnz_short1);
655 	if(!regs_equal(&inregs, &outregs, 0))
656 		print_serial("JNZ short Test 1: FAIL\n");
657 	else
658 		print_serial("JNZ short Test 1: PASS\n");
659 
660 	exec_in_big_real_mode(&inregs, &outregs,
661 			insn_jnz_short2, insn_jnz_short2_end - insn_jnz_short2);
662 	if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6)))
663 		print_serial("JNZ short Test 2: FAIL\n");
664 	else
665 		print_serial("JNZ short Test 2: PASS\n");
666 
667 	exec_in_big_real_mode(&inregs, &outregs,
668 			insn_jmp_short1, insn_jmp_short1_end - insn_jmp_short1);
669 	if(!regs_equal(&inregs, &outregs, 0))
670 		print_serial("JMP short Test 1: FAIL\n");
671 	else
672 		print_serial("JMP short Test 1: PASS\n");
673 }
674 
675 void test_jcc_near(void)
676 {
677 	struct regs inregs = { 0 }, outregs;
678 	/* encode near jmp manually. gas will not do it if offsets < 127 byte */
679 	MK_INSN(jnz_near1, ".byte 0x0f, 0x85, 0x06, 0x00\n\t"
680 		           "mov $0x1234, %eax\n\t");
681 	MK_INSN(jnz_near2, "cmp $0x1234, %eax\n\t"
682 			   "mov $0x1234, %eax\n\t"
683 		           ".byte 0x0f, 0x85, 0xf0, 0xff\n\t");
684 	MK_INSN(jmp_near1, ".byte 0xE9, 0x06, 0x00\n\t"
685 		           "mov $0x1234, %eax\n\t");
686 
687 	exec_in_big_real_mode(&inregs, &outregs,
688 			insn_jnz_near1, insn_jnz_near1_end - insn_jnz_near1);
689 	if(!regs_equal(&inregs, &outregs, 0))
690 		print_serial("JNZ near Test 1: FAIL\n");
691 	else
692 		print_serial("JNZ near Test 1: PASS\n");
693 
694 	exec_in_big_real_mode(&inregs, &outregs,
695 			insn_jnz_near2, insn_jnz_near2_end - insn_jnz_near2);
696 	if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6)))
697 		print_serial("JNZ near Test 2: FAIL\n");
698 	else
699 		print_serial("JNZ near Test 2: PASS\n");
700 
701 	exec_in_big_real_mode(&inregs, &outregs,
702 			insn_jmp_near1, insn_jmp_near1_end - insn_jmp_near1);
703 	if(!regs_equal(&inregs, &outregs, 0))
704 		print_serial("JMP near Test 1: FAIL\n");
705 	else
706 		print_serial("JMP near Test 1: PASS\n");
707 }
708 
709 void test_long_jmp()
710 {
711 	struct regs inregs = { 0 }, outregs;
712 	u32 esp[16];
713 
714 	inregs.esp = (u32)esp;
715 	MK_INSN(long_jmp, "call 1f\n\t"
716 			  "jmp 2f\n\t"
717 			  "1: jmp $0, $test_function\n\t"
718 		          "2:\n\t");
719 	exec_in_big_real_mode(&inregs, &outregs,
720 			      insn_long_jmp,
721 			      insn_long_jmp_end - insn_long_jmp);
722 	if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234)
723 		print_serial("Long JMP Test: FAIL\n");
724 	else
725 		print_serial("Long JMP Test: PASS\n");
726 }
727 void test_push_pop()
728 {
729 	struct regs inregs = { 0 }, outregs;
730 	MK_INSN(push32, "mov $0x12345678, %eax\n\t"
731 			"push %eax\n\t"
732 			"pop %ebx\n\t");
733 	MK_INSN(push16, "mov $0x1234, %ax\n\t"
734 			"push %ax\n\t"
735 			"pop %bx\n\t");
736 
737 	MK_INSN(push_es, "mov $0x231, %bx\n\t" //Just write a dummy value to see if it gets overwritten
738 			 "mov $0x123, %ax\n\t"
739 			 "mov %ax, %es\n\t"
740 			 "push %es\n\t"
741 			 "pop %bx \n\t"
742 			 );
743 	MK_INSN(pop_es, "push %ax\n\t"
744 			"pop %es\n\t"
745 			"mov %es, %bx\n\t"
746 			);
747 	MK_INSN(push_pop_ss, "push %ss\n\t"
748 			     "pushw %ax\n\t"
749 			     "popw %ss\n\t"
750 			     "mov %ss, %bx\n\t"
751 			     "pop %ss\n\t"
752 			);
753 	MK_INSN(push_pop_fs, "push %fs\n\t"
754 			     "pushl %eax\n\t"
755 			     "popl %fs\n\t"
756 			     "mov %fs, %ebx\n\t"
757 			     "pop %fs\n\t"
758 			);
759 
760 	exec_in_big_real_mode(&inregs, &outregs,
761 			      insn_push32,
762 			      insn_push32_end - insn_push32);
763 	if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x12345678)
764 		print_serial("Push/Pop Test 1: FAIL\n");
765 	else
766 		print_serial("Push/Pop Test 1: PASS\n");
767 
768 	exec_in_big_real_mode(&inregs, &outregs,
769 			      insn_push16,
770 			      insn_push16_end - insn_push16);
771 
772 	if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x1234)
773 		print_serial("Push/Pop Test 2: FAIL\n");
774 	else
775 		print_serial("Push/Pop Test 2: PASS\n");
776 
777 	exec_in_big_real_mode(&inregs, &outregs,
778 			      insn_push_es,
779 			      insn_push_es_end - insn_push_es);
780 	if (!regs_equal(&inregs, &outregs, R_AX|R_BX) ||  outregs.ebx != outregs.eax || outregs.eax != 0x123)
781 		print_serial("Push/Pop Test 3: FAIL\n");
782 	else
783 		print_serial("Push/Pop Test 3: PASS\n");
784 
785 	exec_in_big_real_mode(&inregs, &outregs,
786 			      insn_pop_es,
787 			      insn_pop_es_end - insn_pop_es);
788 
789 	if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax)
790 		print_serial("Push/Pop Test 4: FAIL\n");
791 	else
792 		print_serial("Push/Pop Test 4: PASS\n");
793 
794 	exec_in_big_real_mode(&inregs, &outregs,
795 			      insn_push_pop_ss,
796 			      insn_push_pop_ss_end - insn_push_pop_ss);
797 
798 	if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax)
799 		print_serial("Push/Pop Test 5: FAIL\n");
800 	else
801 		print_serial("Push/Pop Test 5: PASS\n");
802 
803 	exec_in_big_real_mode(&inregs, &outregs,
804 			      insn_push_pop_fs,
805 			      insn_push_pop_fs_end - insn_push_pop_fs);
806 
807 	if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax)
808 		print_serial("Push/Pop Test 6: FAIL\n");
809 	else
810 		print_serial("Push/Pop Test 6: PASS\n");
811 }
812 
813 void test_null(void)
814 {
815 	struct regs inregs = { 0 }, outregs;
816 	exec_in_big_real_mode(&inregs, &outregs, 0, 0);
817 	if (!regs_equal(&inregs, &outregs, 0))
818 		print_serial("null test: FAIL\n");
819 	else
820 		print_serial("null test: PASS\n");
821 }
822 
823 struct {
824     char stack[500];
825     char top[];
826 } tmp_stack;
827 
828 void test_pusha_popa()
829 {
830 	struct regs inregs = { .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = (unsigned long)&tmp_stack.top }, outregs;
831 
832 	MK_INSN(pusha, "pusha\n\t"
833 		       "pop %edi\n\t"
834 		       "pop %esi\n\t"
835 		       "pop %ebp\n\t"
836 		       "add $4, %esp\n\t"
837 		       "pop %ebx\n\t"
838 		       "pop %edx\n\t"
839 		       "pop %ecx\n\t"
840 		       "pop %eax\n\t"
841 		       );
842 
843 	MK_INSN(popa, "push %eax\n\t"
844 		      "push %ecx\n\t"
845 		      "push %edx\n\t"
846 		      "push %ebx\n\t"
847 		      "push %esp\n\t"
848 		      "push %ebp\n\t"
849 		      "push %esi\n\t"
850 		      "push %edi\n\t"
851 		      "popa\n\t"
852 		      );
853 
854 	exec_in_big_real_mode(&inregs, &outregs,
855 			      insn_pusha,
856 			      insn_pusha_end - insn_pusha);
857 
858 	if (!regs_equal(&inregs, &outregs, 0))
859 		print_serial("Pusha/Popa Test1: FAIL\n");
860 	else
861 		print_serial("Pusha/Popa Test1: PASS\n");
862 
863 	exec_in_big_real_mode(&inregs, &outregs,
864 			      insn_popa,
865 			      insn_popa_end - insn_popa);
866 	if (!regs_equal(&inregs, &outregs, 0))
867 		print_serial("Pusha/Popa Test2: FAIL\n");
868 	else
869 		print_serial("Pusha/Popa Test2: PASS\n");
870 }
871 
872 void test_iret()
873 {
874 	struct regs inregs = { 0 }, outregs;
875 
876 	MK_INSN(iret32, "pushf\n\t"
877 			"pushl %cs\n\t"
878 			"call 1f\n\t" /* a near call will push eip onto the stack */
879 			"jmp 2f\n\t"
880 			"1: iret\n\t"
881 			"2:\n\t"
882 		     );
883 
884 	MK_INSN(iret16, "pushfw\n\t"
885 			"pushw %cs\n\t"
886 			"callw 1f\n\t"
887 			"jmp 2f\n\t"
888 			"1: iretw\n\t"
889 			"2:\n\t");
890 
891 	MK_INSN(iret_flags32, "pushfl\n\t"
892 			      "popl %eax\n\t"
893 			      "andl $~0x2, %eax\n\t"
894 			      "orl $0xffc08028, %eax\n\t"
895 			      "pushl %eax\n\t"
896 			      "pushl %cs\n\t"
897 			      "call 1f\n\t"
898 			      "jmp 2f\n\t"
899 			      "1: iret\n\t"
900 			      "2:\n\t");
901 
902 	MK_INSN(iret_flags16, "pushfw\n\t"
903 			      "popw %ax\n\t"
904 			      "and $~0x2, %ax\n\t"
905 			      "or $0x8028, %ax\n\t"
906 			      "pushw %ax\n\t"
907 			      "pushw %cs\n\t"
908 			      "callw 1f\n\t"
909 			      "jmp 2f\n\t"
910 			      "1: iretw\n\t"
911 			      "2:\n\t");
912 
913 	exec_in_big_real_mode(&inregs, &outregs,
914 			      insn_iret32,
915 			      insn_iret32_end - insn_iret32);
916 
917 	if (!regs_equal(&inregs, &outregs, 0))
918 		print_serial("iret Test 1: FAIL\n");
919 	else
920 		print_serial("iret Test 1: PASS\n");
921 
922 	exec_in_big_real_mode(&inregs, &outregs,
923 			      insn_iret16,
924 			      insn_iret16_end - insn_iret16);
925 
926 	if (!regs_equal(&inregs, &outregs, 0))
927 		print_serial("iret Test 2: FAIL\n");
928 	else
929 		print_serial("iret Test 2: PASS\n");
930 
931 	exec_in_big_real_mode(&inregs, &outregs,
932 			      insn_iret_flags32,
933 			      insn_iret_flags32_end - insn_iret_flags32);
934 
935 	if (!regs_equal(&inregs, &outregs, R_AX))
936 		print_serial("iret Test 3: FAIL\n");
937 	else
938 		print_serial("iret Test 3: PASS\n");
939 
940 	exec_in_big_real_mode(&inregs, &outregs,
941 			      insn_iret_flags16,
942 			      insn_iret_flags16_end - insn_iret_flags16);
943 
944 	if (!regs_equal(&inregs, &outregs, R_AX))
945 		print_serial("iret Test 4: FAIL\n");
946 	else
947 		print_serial("iret Test 4: PASS\n");
948 }
949 
950 void realmode_start(void)
951 {
952 	test_null();
953 
954 	test_shld();
955 	test_push_pop();
956 	test_pusha_popa();
957 	test_mov_imm();
958 	test_cmp_imm();
959 	test_add_imm();
960 	test_sub_imm();
961 	test_xor_imm();
962 	test_io();
963 	test_eflags_insn();
964 	test_jcc_short();
965 	test_jcc_near();
966 	/* test_call() uses short jump so call it after testing jcc */
967 	test_call();
968 	/* long jmp test uses call near so test it after testing call */
969 	test_long_jmp();
970 	test_xchg();
971 	test_iret();
972 
973 	exit(0);
974 }
975 
976 unsigned long long r_gdt[] = { 0, 0x9b000000ffff, 0x93000000ffff };
977 
978 struct __attribute__((packed)) {
979 	unsigned short limit;
980 	void *base;
981 } r_gdt_descr = { sizeof(r_gdt) - 1, &r_gdt };
982 
983 asm(
984 	".section .init \n\t"
985 
986 	".code32 \n\t"
987 
988 	"mb_magic = 0x1BADB002 \n\t"
989 	"mb_flags = 0x0 \n\t"
990 
991 	"# multiboot header \n\t"
992 	".long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) \n\t"
993 
994 	".globl start \n\t"
995 	".data \n\t"
996 	". = . + 4096 \n\t"
997 	"stacktop: \n\t"
998 
999 	".text \n\t"
1000 	"start: \n\t"
1001 	"lgdt r_gdt_descr \n\t"
1002 	"ljmp $8, $1f; 1: \n\t"
1003 	".code16gcc \n\t"
1004 	"mov $16, %eax \n\t"
1005 	"mov %ax, %ds \n\t"
1006 	"mov %ax, %es \n\t"
1007 	"mov %ax, %fs \n\t"
1008 	"mov %ax, %gs \n\t"
1009 	"mov %ax, %ss \n\t"
1010 	"mov %cr0, %eax \n\t"
1011 	"btc $0, %eax \n\t"
1012 	"mov %eax, %cr0 \n\t"
1013 	"ljmp $0, $realmode_entry \n\t"
1014 
1015 	"realmode_entry: \n\t"
1016 
1017 	"xor %ax, %ax \n\t"
1018 	"mov %ax, %ds \n\t"
1019 	"mov %ax, %es \n\t"
1020 	"mov %ax, %ss \n\t"
1021 	"mov %ax, %fs \n\t"
1022 	"mov %ax, %gs \n\t"
1023 	"mov $stacktop, %esp\n\t"
1024 	"ljmp $0, $realmode_start \n\t"
1025 
1026 	".code16gcc \n\t"
1027 	);
1028