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