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