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