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