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