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