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