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