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