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