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