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 "pushw %es\n\t" 653 "pop %bx \n\t" 654 ); 655 MK_INSN(pop_es, "push %ax\n\t" 656 "popw %es\n\t" 657 "mov %es, %bx\n\t" 658 ); 659 MK_INSN(push_pop_ss, "pushw %ss\n\t" 660 "pushw %ax\n\t" 661 "popw %ss\n\t" 662 "mov %ss, %bx\n\t" 663 "popw %ss\n\t" 664 ); 665 MK_INSN(push_pop_fs, "pushl %fs\n\t" 666 "pushl %eax\n\t" 667 "popl %fs\n\t" 668 "mov %fs, %ebx\n\t" 669 "popl %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: iretl\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: iretl\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_sti_inhibit(void) 818 { 819 init_inregs(NULL); 820 821 *(u32 *)(0x73 * 4) = 0x1000; /* Store IRQ 11 handler in the IDT */ 822 *(u8 *)(0x1000) = 0xcf; /* 0x1000 contains an IRET instruction */ 823 824 MK_INSN(sti_inhibit, "cli\n\t" 825 "movw $0x200b, %dx\n\t" 826 "movl $1, %eax\n\t" 827 "outl %eax, %dx\n\t" /* Set IRQ11 */ 828 "movl $0, %eax\n\t" 829 "outl %eax, %dx\n\t" /* Clear IRQ11 */ 830 "sti\n\t" 831 "hlt\n\t"); 832 exec_in_big_real_mode(&insn_sti_inhibit); 833 834 report("sti inhibit", ~0, 1); 835 } 836 837 static void test_imul(void) 838 { 839 MK_INSN(imul8_1, "mov $2, %al\n\t" 840 "mov $-4, %cx\n\t" 841 "imul %cl\n\t"); 842 843 MK_INSN(imul16_1, "mov $2, %ax\n\t" 844 "mov $-4, %cx\n\t" 845 "imul %cx\n\t"); 846 847 MK_INSN(imul32_1, "mov $2, %eax\n\t" 848 "mov $-4, %ecx\n\t" 849 "imul %ecx\n\t"); 850 851 MK_INSN(imul8_2, "mov $0x12340002, %eax\n\t" 852 "mov $4, %cx\n\t" 853 "imul %cl\n\t"); 854 855 MK_INSN(imul16_2, "mov $2, %ax\n\t" 856 "mov $4, %cx\n\t" 857 "imul %cx\n\t"); 858 859 MK_INSN(imul32_2, "mov $2, %eax\n\t" 860 "mov $4, %ecx\n\t" 861 "imul %ecx\n\t"); 862 863 init_inregs(NULL); 864 865 exec_in_big_real_mode(&insn_imul8_1); 866 report("imul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == (u8)-8); 867 868 exec_in_big_real_mode(&insn_imul16_1); 869 report("imul 2", R_AX | R_CX | R_DX, outregs.eax == (u16)-8); 870 871 exec_in_big_real_mode(&insn_imul32_1); 872 report("imul 3", R_AX | R_CX | R_DX, outregs.eax == (u32)-8); 873 874 exec_in_big_real_mode(&insn_imul8_2); 875 report("imul 4", R_AX | R_CX | R_DX, 876 (outregs.eax & 0xffff) == 8 877 && (outregs.eax & 0xffff0000) == 0x12340000); 878 879 exec_in_big_real_mode(&insn_imul16_2); 880 report("imul 5", R_AX | R_CX | R_DX, outregs.eax == 8); 881 882 exec_in_big_real_mode(&insn_imul32_2); 883 report("imul 6", R_AX | R_CX | R_DX, outregs.eax == 8); 884 } 885 886 static void test_mul(void) 887 { 888 MK_INSN(mul8, "mov $2, %al\n\t" 889 "mov $4, %cx\n\t" 890 "imul %cl\n\t"); 891 892 MK_INSN(mul16, "mov $2, %ax\n\t" 893 "mov $4, %cx\n\t" 894 "imul %cx\n\t"); 895 896 MK_INSN(mul32, "mov $2, %eax\n\t" 897 "mov $4, %ecx\n\t" 898 "imul %ecx\n\t"); 899 900 init_inregs(NULL); 901 902 exec_in_big_real_mode(&insn_mul8); 903 report("mul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == 8); 904 905 exec_in_big_real_mode(&insn_mul16); 906 report("mul 2", R_AX | R_CX | R_DX, outregs.eax == 8); 907 908 exec_in_big_real_mode(&insn_mul32); 909 report("mul 3", R_AX | R_CX | R_DX, outregs.eax == 8); 910 } 911 912 static void test_div(void) 913 { 914 MK_INSN(div8, "mov $257, %ax\n\t" 915 "mov $2, %cl\n\t" 916 "div %cl\n\t"); 917 918 MK_INSN(div16, "mov $512, %ax\n\t" 919 "mov $5, %cx\n\t" 920 "div %cx\n\t"); 921 922 MK_INSN(div32, "mov $512, %eax\n\t" 923 "mov $5, %ecx\n\t" 924 "div %ecx\n\t"); 925 926 init_inregs(NULL); 927 928 exec_in_big_real_mode(&insn_div8); 929 report("div 1", R_AX | R_CX | R_DX, outregs.eax == 384); 930 931 exec_in_big_real_mode(&insn_div16); 932 report("div 2", R_AX | R_CX | R_DX, 933 outregs.eax == 102 && outregs.edx == 2); 934 935 exec_in_big_real_mode(&insn_div32); 936 report("div 3", R_AX | R_CX | R_DX, 937 outregs.eax == 102 && outregs.edx == 2); 938 } 939 940 static void test_idiv(void) 941 { 942 MK_INSN(idiv8, "mov $256, %ax\n\t" 943 "mov $-2, %cl\n\t" 944 "idiv %cl\n\t"); 945 946 MK_INSN(idiv16, "mov $512, %ax\n\t" 947 "mov $-2, %cx\n\t" 948 "idiv %cx\n\t"); 949 950 MK_INSN(idiv32, "mov $512, %eax\n\t" 951 "mov $-2, %ecx\n\t" 952 "idiv %ecx\n\t"); 953 954 init_inregs(NULL); 955 956 exec_in_big_real_mode(&insn_idiv8); 957 report("idiv 1", R_AX | R_CX | R_DX, outregs.eax == (u8)-128); 958 959 exec_in_big_real_mode(&insn_idiv16); 960 report("idiv 2", R_AX | R_CX | R_DX, outregs.eax == (u16)-256); 961 962 exec_in_big_real_mode(&insn_idiv32); 963 report("idiv 3", R_AX | R_CX | R_DX, outregs.eax == (u32)-256); 964 } 965 966 static void test_cbw(void) 967 { 968 MK_INSN(cbw, "mov $0xFE, %eax \n\t" 969 "cbw\n\t"); 970 MK_INSN(cwde, "mov $0xFFFE, %eax \n\t" 971 "cwde\n\t"); 972 973 init_inregs(NULL); 974 975 exec_in_big_real_mode(&insn_cbw); 976 report("cbq 1", ~0, outregs.eax == 0xFFFE); 977 978 exec_in_big_real_mode(&insn_cwde); 979 report("cwde 1", ~0, outregs.eax == 0xFFFFFFFE); 980 } 981 982 static void test_loopcc(void) 983 { 984 MK_INSN(loop, "mov $10, %ecx\n\t" 985 "1: inc %eax\n\t" 986 "loop 1b\n\t"); 987 988 MK_INSN(loope, "mov $10, %ecx\n\t" 989 "mov $1, %eax\n\t" 990 "1: dec %eax\n\t" 991 "loope 1b\n\t"); 992 993 MK_INSN(loopne, "mov $10, %ecx\n\t" 994 "mov $5, %eax\n\t" 995 "1: dec %eax\n\t" 996 "loopne 1b\n\t"); 997 998 init_inregs(NULL); 999 1000 exec_in_big_real_mode(&insn_loop); 1001 report("LOOPcc short 1", R_AX, outregs.eax == 10); 1002 1003 exec_in_big_real_mode(&insn_loope); 1004 report("LOOPcc short 2", R_AX | R_CX, 1005 outregs.eax == -1 && outregs.ecx == 8); 1006 1007 exec_in_big_real_mode(&insn_loopne); 1008 report("LOOPcc short 3", R_AX | R_CX, 1009 outregs.eax == 0 && outregs.ecx == 5); 1010 } 1011 1012 static void test_das(void) 1013 { 1014 short i; 1015 u16 nr_fail = 0; 1016 static unsigned test_cases[1024] = { 1017 0x46000000, 0x8701a000, 0x9710fa00, 0x97119a00, 1018 0x02000101, 0x8301a101, 0x9310fb01, 0x93119b01, 1019 0x02000202, 0x8301a202, 0x9710fc02, 0x97119c02, 1020 0x06000303, 0x8701a303, 0x9310fd03, 0x93119d03, 1021 0x02000404, 0x8301a404, 0x9310fe04, 0x93119e04, 1022 0x06000505, 0x8701a505, 0x9710ff05, 0x97119f05, 1023 0x06000606, 0x8701a606, 0x56100006, 0x9711a006, 1024 0x02000707, 0x8301a707, 0x12100107, 0x9311a107, 1025 0x02000808, 0x8301a808, 0x12100208, 0x9311a208, 1026 0x06000909, 0x8701a909, 0x16100309, 0x9711a309, 1027 0x1200040a, 0x9301a40a, 0x1210040a, 0x9311a40a, 1028 0x1600050b, 0x9701a50b, 0x1610050b, 0x9711a50b, 1029 0x1600060c, 0x9701a60c, 0x1610060c, 0x9711a60c, 1030 0x1200070d, 0x9301a70d, 0x1210070d, 0x9311a70d, 1031 0x1200080e, 0x9301a80e, 0x1210080e, 0x9311a80e, 1032 0x1600090f, 0x9701a90f, 0x1610090f, 0x9711a90f, 1033 0x02001010, 0x8301b010, 0x16100a10, 0x9711aa10, 1034 0x06001111, 0x8701b111, 0x12100b11, 0x9311ab11, 1035 0x06001212, 0x8701b212, 0x16100c12, 0x9711ac12, 1036 0x02001313, 0x8301b313, 0x12100d13, 0x9311ad13, 1037 0x06001414, 0x8701b414, 0x12100e14, 0x9311ae14, 1038 0x02001515, 0x8301b515, 0x16100f15, 0x9711af15, 1039 0x02001616, 0x8301b616, 0x12101016, 0x9311b016, 1040 0x06001717, 0x8701b717, 0x16101117, 0x9711b117, 1041 0x06001818, 0x8701b818, 0x16101218, 0x9711b218, 1042 0x02001919, 0x8301b919, 0x12101319, 0x9311b319, 1043 0x1600141a, 0x9701b41a, 0x1610141a, 0x9711b41a, 1044 0x1200151b, 0x9301b51b, 0x1210151b, 0x9311b51b, 1045 0x1200161c, 0x9301b61c, 0x1210161c, 0x9311b61c, 1046 0x1600171d, 0x9701b71d, 0x1610171d, 0x9711b71d, 1047 0x1600181e, 0x9701b81e, 0x1610181e, 0x9711b81e, 1048 0x1200191f, 0x9301b91f, 0x1210191f, 0x9311b91f, 1049 0x02002020, 0x8701c020, 0x12101a20, 0x9311ba20, 1050 0x06002121, 0x8301c121, 0x16101b21, 0x9711bb21, 1051 0x06002222, 0x8301c222, 0x12101c22, 0x9311bc22, 1052 0x02002323, 0x8701c323, 0x16101d23, 0x9711bd23, 1053 0x06002424, 0x8301c424, 0x16101e24, 0x9711be24, 1054 0x02002525, 0x8701c525, 0x12101f25, 0x9311bf25, 1055 0x02002626, 0x8701c626, 0x12102026, 0x9711c026, 1056 0x06002727, 0x8301c727, 0x16102127, 0x9311c127, 1057 0x06002828, 0x8301c828, 0x16102228, 0x9311c228, 1058 0x02002929, 0x8701c929, 0x12102329, 0x9711c329, 1059 0x1600242a, 0x9301c42a, 0x1610242a, 0x9311c42a, 1060 0x1200252b, 0x9701c52b, 0x1210252b, 0x9711c52b, 1061 0x1200262c, 0x9701c62c, 0x1210262c, 0x9711c62c, 1062 0x1600272d, 0x9301c72d, 0x1610272d, 0x9311c72d, 1063 0x1600282e, 0x9301c82e, 0x1610282e, 0x9311c82e, 1064 0x1200292f, 0x9701c92f, 0x1210292f, 0x9711c92f, 1065 0x06003030, 0x8301d030, 0x12102a30, 0x9711ca30, 1066 0x02003131, 0x8701d131, 0x16102b31, 0x9311cb31, 1067 0x02003232, 0x8701d232, 0x12102c32, 0x9711cc32, 1068 0x06003333, 0x8301d333, 0x16102d33, 0x9311cd33, 1069 0x02003434, 0x8701d434, 0x16102e34, 0x9311ce34, 1070 0x06003535, 0x8301d535, 0x12102f35, 0x9711cf35, 1071 0x06003636, 0x8301d636, 0x16103036, 0x9311d036, 1072 0x02003737, 0x8701d737, 0x12103137, 0x9711d137, 1073 0x02003838, 0x8701d838, 0x12103238, 0x9711d238, 1074 0x06003939, 0x8301d939, 0x16103339, 0x9311d339, 1075 0x1200343a, 0x9701d43a, 0x1210343a, 0x9711d43a, 1076 0x1600353b, 0x9301d53b, 0x1610353b, 0x9311d53b, 1077 0x1600363c, 0x9301d63c, 0x1610363c, 0x9311d63c, 1078 0x1200373d, 0x9701d73d, 0x1210373d, 0x9711d73d, 1079 0x1200383e, 0x9701d83e, 0x1210383e, 0x9711d83e, 1080 0x1600393f, 0x9301d93f, 0x1610393f, 0x9311d93f, 1081 0x02004040, 0x8301e040, 0x16103a40, 0x9311da40, 1082 0x06004141, 0x8701e141, 0x12103b41, 0x9711db41, 1083 0x06004242, 0x8701e242, 0x16103c42, 0x9311dc42, 1084 0x02004343, 0x8301e343, 0x12103d43, 0x9711dd43, 1085 0x06004444, 0x8701e444, 0x12103e44, 0x9711de44, 1086 0x02004545, 0x8301e545, 0x16103f45, 0x9311df45, 1087 0x02004646, 0x8301e646, 0x12104046, 0x9311e046, 1088 0x06004747, 0x8701e747, 0x16104147, 0x9711e147, 1089 0x06004848, 0x8701e848, 0x16104248, 0x9711e248, 1090 0x02004949, 0x8301e949, 0x12104349, 0x9311e349, 1091 0x1600444a, 0x9701e44a, 0x1610444a, 0x9711e44a, 1092 0x1200454b, 0x9301e54b, 0x1210454b, 0x9311e54b, 1093 0x1200464c, 0x9301e64c, 0x1210464c, 0x9311e64c, 1094 0x1600474d, 0x9701e74d, 0x1610474d, 0x9711e74d, 1095 0x1600484e, 0x9701e84e, 0x1610484e, 0x9711e84e, 1096 0x1200494f, 0x9301e94f, 0x1210494f, 0x9311e94f, 1097 0x06005050, 0x8701f050, 0x12104a50, 0x9311ea50, 1098 0x02005151, 0x8301f151, 0x16104b51, 0x9711eb51, 1099 0x02005252, 0x8301f252, 0x12104c52, 0x9311ec52, 1100 0x06005353, 0x8701f353, 0x16104d53, 0x9711ed53, 1101 0x02005454, 0x8301f454, 0x16104e54, 0x9711ee54, 1102 0x06005555, 0x8701f555, 0x12104f55, 0x9311ef55, 1103 0x06005656, 0x8701f656, 0x16105056, 0x9711f056, 1104 0x02005757, 0x8301f757, 0x12105157, 0x9311f157, 1105 0x02005858, 0x8301f858, 0x12105258, 0x9311f258, 1106 0x06005959, 0x8701f959, 0x16105359, 0x9711f359, 1107 0x1200545a, 0x9301f45a, 0x1210545a, 0x9311f45a, 1108 0x1600555b, 0x9701f55b, 0x1610555b, 0x9711f55b, 1109 0x1600565c, 0x9701f65c, 0x1610565c, 0x9711f65c, 1110 0x1200575d, 0x9301f75d, 0x1210575d, 0x9311f75d, 1111 0x1200585e, 0x9301f85e, 0x1210585e, 0x9311f85e, 1112 0x1600595f, 0x9701f95f, 0x1610595f, 0x9711f95f, 1113 0x06006060, 0x47010060, 0x16105a60, 0x9711fa60, 1114 0x02006161, 0x03010161, 0x12105b61, 0x9311fb61, 1115 0x02006262, 0x03010262, 0x16105c62, 0x9711fc62, 1116 0x06006363, 0x07010363, 0x12105d63, 0x9311fd63, 1117 0x02006464, 0x03010464, 0x12105e64, 0x9311fe64, 1118 0x06006565, 0x07010565, 0x16105f65, 0x9711ff65, 1119 0x06006666, 0x07010666, 0x16106066, 0x57110066, 1120 0x02006767, 0x03010767, 0x12106167, 0x13110167, 1121 0x02006868, 0x03010868, 0x12106268, 0x13110268, 1122 0x06006969, 0x07010969, 0x16106369, 0x17110369, 1123 0x1200646a, 0x1301046a, 0x1210646a, 0x1311046a, 1124 0x1600656b, 0x1701056b, 0x1610656b, 0x1711056b, 1125 0x1600666c, 0x1701066c, 0x1610666c, 0x1711066c, 1126 0x1200676d, 0x1301076d, 0x1210676d, 0x1311076d, 1127 0x1200686e, 0x1301086e, 0x1210686e, 0x1311086e, 1128 0x1600696f, 0x1701096f, 0x1610696f, 0x1711096f, 1129 0x02007070, 0x03011070, 0x16106a70, 0x17110a70, 1130 0x06007171, 0x07011171, 0x12106b71, 0x13110b71, 1131 0x06007272, 0x07011272, 0x16106c72, 0x17110c72, 1132 0x02007373, 0x03011373, 0x12106d73, 0x13110d73, 1133 0x06007474, 0x07011474, 0x12106e74, 0x13110e74, 1134 0x02007575, 0x03011575, 0x16106f75, 0x17110f75, 1135 0x02007676, 0x03011676, 0x12107076, 0x13111076, 1136 0x06007777, 0x07011777, 0x16107177, 0x17111177, 1137 0x06007878, 0x07011878, 0x16107278, 0x17111278, 1138 0x02007979, 0x03011979, 0x12107379, 0x13111379, 1139 0x1600747a, 0x1701147a, 0x1610747a, 0x1711147a, 1140 0x1200757b, 0x1301157b, 0x1210757b, 0x1311157b, 1141 0x1200767c, 0x1301167c, 0x1210767c, 0x1311167c, 1142 0x1600777d, 0x1701177d, 0x1610777d, 0x1711177d, 1143 0x1600787e, 0x1701187e, 0x1610787e, 0x1711187e, 1144 0x1200797f, 0x1301197f, 0x1210797f, 0x1311197f, 1145 0x82008080, 0x03012080, 0x12107a80, 0x13111a80, 1146 0x86008181, 0x07012181, 0x16107b81, 0x17111b81, 1147 0x86008282, 0x07012282, 0x12107c82, 0x13111c82, 1148 0x82008383, 0x03012383, 0x16107d83, 0x17111d83, 1149 0x86008484, 0x07012484, 0x16107e84, 0x17111e84, 1150 0x82008585, 0x03012585, 0x12107f85, 0x13111f85, 1151 0x82008686, 0x03012686, 0x92108086, 0x13112086, 1152 0x86008787, 0x07012787, 0x96108187, 0x17112187, 1153 0x86008888, 0x07012888, 0x96108288, 0x17112288, 1154 0x82008989, 0x03012989, 0x92108389, 0x13112389, 1155 0x9600848a, 0x1701248a, 0x9610848a, 0x1711248a, 1156 0x9200858b, 0x1301258b, 0x9210858b, 0x1311258b, 1157 0x9200868c, 0x1301268c, 0x9210868c, 0x1311268c, 1158 0x9600878d, 0x1701278d, 0x9610878d, 0x1711278d, 1159 0x9600888e, 0x1701288e, 0x9610888e, 0x1711288e, 1160 0x9200898f, 0x1301298f, 0x9210898f, 0x1311298f, 1161 0x86009090, 0x07013090, 0x92108a90, 0x13112a90, 1162 0x82009191, 0x03013191, 0x96108b91, 0x17112b91, 1163 0x82009292, 0x03013292, 0x92108c92, 0x13112c92, 1164 0x86009393, 0x07013393, 0x96108d93, 0x17112d93, 1165 0x82009494, 0x03013494, 0x96108e94, 0x17112e94, 1166 0x86009595, 0x07013595, 0x92108f95, 0x13112f95, 1167 0x86009696, 0x07013696, 0x96109096, 0x17113096, 1168 0x82009797, 0x03013797, 0x92109197, 0x13113197, 1169 0x82009898, 0x03013898, 0x92109298, 0x13113298, 1170 0x86009999, 0x07013999, 0x96109399, 0x17113399, 1171 0x1300349a, 0x1301349a, 0x1310349a, 0x1311349a, 1172 0x1700359b, 0x1701359b, 0x1710359b, 0x1711359b, 1173 0x1700369c, 0x1701369c, 0x1710369c, 0x1711369c, 1174 0x1300379d, 0x1301379d, 0x1310379d, 0x1311379d, 1175 0x1300389e, 0x1301389e, 0x1310389e, 0x1311389e, 1176 0x1700399f, 0x1701399f, 0x1710399f, 0x1711399f, 1177 0x030040a0, 0x030140a0, 0x17103aa0, 0x17113aa0, 1178 0x070041a1, 0x070141a1, 0x13103ba1, 0x13113ba1, 1179 0x070042a2, 0x070142a2, 0x17103ca2, 0x17113ca2, 1180 0x030043a3, 0x030143a3, 0x13103da3, 0x13113da3, 1181 0x070044a4, 0x070144a4, 0x13103ea4, 0x13113ea4, 1182 0x030045a5, 0x030145a5, 0x17103fa5, 0x17113fa5, 1183 0x030046a6, 0x030146a6, 0x131040a6, 0x131140a6, 1184 0x070047a7, 0x070147a7, 0x171041a7, 0x171141a7, 1185 0x070048a8, 0x070148a8, 0x171042a8, 0x171142a8, 1186 0x030049a9, 0x030149a9, 0x131043a9, 0x131143a9, 1187 0x170044aa, 0x170144aa, 0x171044aa, 0x171144aa, 1188 0x130045ab, 0x130145ab, 0x131045ab, 0x131145ab, 1189 0x130046ac, 0x130146ac, 0x131046ac, 0x131146ac, 1190 0x170047ad, 0x170147ad, 0x171047ad, 0x171147ad, 1191 0x170048ae, 0x170148ae, 0x171048ae, 0x171148ae, 1192 0x130049af, 0x130149af, 0x131049af, 0x131149af, 1193 0x070050b0, 0x070150b0, 0x13104ab0, 0x13114ab0, 1194 0x030051b1, 0x030151b1, 0x17104bb1, 0x17114bb1, 1195 0x030052b2, 0x030152b2, 0x13104cb2, 0x13114cb2, 1196 0x070053b3, 0x070153b3, 0x17104db3, 0x17114db3, 1197 0x030054b4, 0x030154b4, 0x17104eb4, 0x17114eb4, 1198 0x070055b5, 0x070155b5, 0x13104fb5, 0x13114fb5, 1199 0x070056b6, 0x070156b6, 0x171050b6, 0x171150b6, 1200 0x030057b7, 0x030157b7, 0x131051b7, 0x131151b7, 1201 0x030058b8, 0x030158b8, 0x131052b8, 0x131152b8, 1202 0x070059b9, 0x070159b9, 0x171053b9, 0x171153b9, 1203 0x130054ba, 0x130154ba, 0x131054ba, 0x131154ba, 1204 0x170055bb, 0x170155bb, 0x171055bb, 0x171155bb, 1205 0x170056bc, 0x170156bc, 0x171056bc, 0x171156bc, 1206 0x130057bd, 0x130157bd, 0x131057bd, 0x131157bd, 1207 0x130058be, 0x130158be, 0x131058be, 0x131158be, 1208 0x170059bf, 0x170159bf, 0x171059bf, 0x171159bf, 1209 0x070060c0, 0x070160c0, 0x17105ac0, 0x17115ac0, 1210 0x030061c1, 0x030161c1, 0x13105bc1, 0x13115bc1, 1211 0x030062c2, 0x030162c2, 0x17105cc2, 0x17115cc2, 1212 0x070063c3, 0x070163c3, 0x13105dc3, 0x13115dc3, 1213 0x030064c4, 0x030164c4, 0x13105ec4, 0x13115ec4, 1214 0x070065c5, 0x070165c5, 0x17105fc5, 0x17115fc5, 1215 0x070066c6, 0x070166c6, 0x171060c6, 0x171160c6, 1216 0x030067c7, 0x030167c7, 0x131061c7, 0x131161c7, 1217 0x030068c8, 0x030168c8, 0x131062c8, 0x131162c8, 1218 0x070069c9, 0x070169c9, 0x171063c9, 0x171163c9, 1219 0x130064ca, 0x130164ca, 0x131064ca, 0x131164ca, 1220 0x170065cb, 0x170165cb, 0x171065cb, 0x171165cb, 1221 0x170066cc, 0x170166cc, 0x171066cc, 0x171166cc, 1222 0x130067cd, 0x130167cd, 0x131067cd, 0x131167cd, 1223 0x130068ce, 0x130168ce, 0x131068ce, 0x131168ce, 1224 0x170069cf, 0x170169cf, 0x171069cf, 0x171169cf, 1225 0x030070d0, 0x030170d0, 0x17106ad0, 0x17116ad0, 1226 0x070071d1, 0x070171d1, 0x13106bd1, 0x13116bd1, 1227 0x070072d2, 0x070172d2, 0x17106cd2, 0x17116cd2, 1228 0x030073d3, 0x030173d3, 0x13106dd3, 0x13116dd3, 1229 0x070074d4, 0x070174d4, 0x13106ed4, 0x13116ed4, 1230 0x030075d5, 0x030175d5, 0x17106fd5, 0x17116fd5, 1231 0x030076d6, 0x030176d6, 0x131070d6, 0x131170d6, 1232 0x070077d7, 0x070177d7, 0x171071d7, 0x171171d7, 1233 0x070078d8, 0x070178d8, 0x171072d8, 0x171172d8, 1234 0x030079d9, 0x030179d9, 0x131073d9, 0x131173d9, 1235 0x170074da, 0x170174da, 0x171074da, 0x171174da, 1236 0x130075db, 0x130175db, 0x131075db, 0x131175db, 1237 0x130076dc, 0x130176dc, 0x131076dc, 0x131176dc, 1238 0x170077dd, 0x170177dd, 0x171077dd, 0x171177dd, 1239 0x170078de, 0x170178de, 0x171078de, 0x171178de, 1240 0x130079df, 0x130179df, 0x131079df, 0x131179df, 1241 0x830080e0, 0x830180e0, 0x13107ae0, 0x13117ae0, 1242 0x870081e1, 0x870181e1, 0x17107be1, 0x17117be1, 1243 0x870082e2, 0x870182e2, 0x13107ce2, 0x13117ce2, 1244 0x830083e3, 0x830183e3, 0x17107de3, 0x17117de3, 1245 0x870084e4, 0x870184e4, 0x17107ee4, 0x17117ee4, 1246 0x830085e5, 0x830185e5, 0x13107fe5, 0x13117fe5, 1247 0x830086e6, 0x830186e6, 0x931080e6, 0x931180e6, 1248 0x870087e7, 0x870187e7, 0x971081e7, 0x971181e7, 1249 0x870088e8, 0x870188e8, 0x971082e8, 0x971182e8, 1250 0x830089e9, 0x830189e9, 0x931083e9, 0x931183e9, 1251 0x970084ea, 0x970184ea, 0x971084ea, 0x971184ea, 1252 0x930085eb, 0x930185eb, 0x931085eb, 0x931185eb, 1253 0x930086ec, 0x930186ec, 0x931086ec, 0x931186ec, 1254 0x970087ed, 0x970187ed, 0x971087ed, 0x971187ed, 1255 0x970088ee, 0x970188ee, 0x971088ee, 0x971188ee, 1256 0x930089ef, 0x930189ef, 0x931089ef, 0x931189ef, 1257 0x870090f0, 0x870190f0, 0x93108af0, 0x93118af0, 1258 0x830091f1, 0x830191f1, 0x97108bf1, 0x97118bf1, 1259 0x830092f2, 0x830192f2, 0x93108cf2, 0x93118cf2, 1260 0x870093f3, 0x870193f3, 0x97108df3, 0x97118df3, 1261 0x830094f4, 0x830194f4, 0x97108ef4, 0x97118ef4, 1262 0x870095f5, 0x870195f5, 0x93108ff5, 0x93118ff5, 1263 0x870096f6, 0x870196f6, 0x971090f6, 0x971190f6, 1264 0x830097f7, 0x830197f7, 0x931091f7, 0x931191f7, 1265 0x830098f8, 0x830198f8, 0x931092f8, 0x931192f8, 1266 0x870099f9, 0x870199f9, 0x971093f9, 0x971193f9, 1267 0x930094fa, 0x930194fa, 0x931094fa, 0x931194fa, 1268 0x970095fb, 0x970195fb, 0x971095fb, 0x971195fb, 1269 0x970096fc, 0x970196fc, 0x971096fc, 0x971196fc, 1270 0x930097fd, 0x930197fd, 0x931097fd, 0x931197fd, 1271 0x930098fe, 0x930198fe, 0x931098fe, 0x931198fe, 1272 0x970099ff, 0x970199ff, 0x971099ff, 0x971199ff, 1273 }; 1274 1275 MK_INSN(das, "das"); 1276 1277 init_inregs(NULL); 1278 1279 for (i = 0; i < 1024; ++i) { 1280 unsigned tmp = test_cases[i]; 1281 inregs.eax = tmp & 0xff; 1282 inregs.eflags = (tmp >> 16) & 0xff; 1283 exec_in_big_real_mode(&insn_das); 1284 if (!regs_equal(R_AX) 1285 || outregs.eax != ((tmp >> 8) & 0xff) 1286 || (outregs.eflags & 0xff) != (tmp >> 24)) { 1287 ++nr_fail; 1288 break; 1289 } 1290 } 1291 report("DAS", ~0, nr_fail == 0); 1292 } 1293 1294 static void test_cwd_cdq(void) 1295 { 1296 /* Sign-bit set */ 1297 MK_INSN(cwd_1, "mov $0x8000, %ax\n\t" 1298 "cwd\n\t"); 1299 1300 /* Sign-bit not set */ 1301 MK_INSN(cwd_2, "mov $0x1000, %ax\n\t" 1302 "cwd\n\t"); 1303 1304 /* Sign-bit set */ 1305 MK_INSN(cdq_1, "mov $0x80000000, %eax\n\t" 1306 "cdq\n\t"); 1307 1308 /* Sign-bit not set */ 1309 MK_INSN(cdq_2, "mov $0x10000000, %eax\n\t" 1310 "cdq\n\t"); 1311 1312 init_inregs(NULL); 1313 1314 exec_in_big_real_mode(&insn_cwd_1); 1315 report("cwd 1", R_AX | R_DX, 1316 outregs.eax == 0x8000 && outregs.edx == 0xffff); 1317 1318 exec_in_big_real_mode(&insn_cwd_2); 1319 report("cwd 2", R_AX | R_DX, 1320 outregs.eax == 0x1000 && outregs.edx == 0); 1321 1322 exec_in_big_real_mode(&insn_cdq_1); 1323 report("cdq 1", R_AX | R_DX, 1324 outregs.eax == 0x80000000 && outregs.edx == 0xffffffff); 1325 1326 exec_in_big_real_mode(&insn_cdq_2); 1327 report("cdq 2", R_AX | R_DX, 1328 outregs.eax == 0x10000000 && outregs.edx == 0); 1329 } 1330 1331 static struct { 1332 void *address; 1333 unsigned short sel; 1334 } __attribute__((packed)) desc = { 1335 (void *)0x1234, 1336 0x10, 1337 }; 1338 1339 static void test_lds_lss(void) 1340 { 1341 init_inregs(&(struct regs){ .ebx = (unsigned long)&desc }); 1342 1343 MK_INSN(lds, "pushl %ds\n\t" 1344 "lds (%ebx), %eax\n\t" 1345 "mov %ds, %ebx\n\t" 1346 "popl %ds\n\t"); 1347 exec_in_big_real_mode(&insn_lds); 1348 report("lds", R_AX | R_BX, 1349 outregs.eax == (unsigned long)desc.address && 1350 outregs.ebx == desc.sel); 1351 1352 MK_INSN(les, "les (%ebx), %eax\n\t" 1353 "mov %es, %ebx\n\t"); 1354 exec_in_big_real_mode(&insn_les); 1355 report("les", R_AX | R_BX, 1356 outregs.eax == (unsigned long)desc.address && 1357 outregs.ebx == desc.sel); 1358 1359 MK_INSN(lfs, "pushl %fs\n\t" 1360 "lfs (%ebx), %eax\n\t" 1361 "mov %fs, %ebx\n\t" 1362 "popl %fs\n\t"); 1363 exec_in_big_real_mode(&insn_lfs); 1364 report("lfs", R_AX | R_BX, 1365 outregs.eax == (unsigned long)desc.address && 1366 outregs.ebx == desc.sel); 1367 1368 MK_INSN(lgs, "pushl %gs\n\t" 1369 "lgs (%ebx), %eax\n\t" 1370 "mov %gs, %ebx\n\t" 1371 "popl %gs\n\t"); 1372 exec_in_big_real_mode(&insn_lgs); 1373 report("lgs", R_AX | R_BX, 1374 outregs.eax == (unsigned long)desc.address && 1375 outregs.ebx == desc.sel); 1376 1377 MK_INSN(lss, "pushl %ss\n\t" 1378 "lss (%ebx), %eax\n\t" 1379 "mov %ss, %ebx\n\t" 1380 "popl %ss\n\t"); 1381 exec_in_big_real_mode(&insn_lss); 1382 report("lss", R_AX | R_BX, 1383 outregs.eax == (unsigned long)desc.address && 1384 outregs.ebx == desc.sel); 1385 } 1386 1387 static void test_jcxz(void) 1388 { 1389 MK_INSN(jcxz1, "jcxz 1f\n\t" 1390 "mov $0x1234, %eax\n\t" 1391 "1:\n\t"); 1392 MK_INSN(jcxz2, "mov $0x100, %ecx\n\t" 1393 "jcxz 1f\n\t" 1394 "mov $0x1234, %eax\n\t" 1395 "mov $0, %ecx\n\t" 1396 "1:\n\t"); 1397 MK_INSN(jcxz3, "mov $0x10000, %ecx\n\t" 1398 "jcxz 1f\n\t" 1399 "mov $0x1234, %eax\n\t" 1400 "1:\n\t"); 1401 MK_INSN(jecxz1, "jecxz 1f\n\t" 1402 "mov $0x1234, %eax\n\t" 1403 "1:\n\t"); 1404 MK_INSN(jecxz2, "mov $0x10000, %ecx\n\t" 1405 "jecxz 1f\n\t" 1406 "mov $0x1234, %eax\n\t" 1407 "mov $0, %ecx\n\t" 1408 "1:\n\t"); 1409 1410 init_inregs(NULL); 1411 1412 exec_in_big_real_mode(&insn_jcxz1); 1413 report("jcxz short 1", 0, 1); 1414 1415 exec_in_big_real_mode(&insn_jcxz2); 1416 report("jcxz short 2", R_AX, outregs.eax == 0x1234); 1417 1418 exec_in_big_real_mode(&insn_jcxz3); 1419 report("jcxz short 3", R_CX, outregs.ecx == 0x10000); 1420 1421 exec_in_big_real_mode(&insn_jecxz1); 1422 report("jecxz short 1", 0, 1); 1423 1424 exec_in_big_real_mode(&insn_jecxz2); 1425 report("jecxz short 2", R_AX, outregs.eax == 0x1234); 1426 } 1427 1428 static void test_cpuid(void) 1429 { 1430 MK_INSN(cpuid, "cpuid"); 1431 unsigned function = 0x1234; 1432 unsigned eax, ebx, ecx, edx; 1433 1434 init_inregs(&(struct regs){ .eax = function }); 1435 1436 eax = inregs.eax; 1437 ecx = inregs.ecx; 1438 asm("cpuid" : "+a"(eax), "=b"(ebx), "+c"(ecx), "=d"(edx)); 1439 exec_in_big_real_mode(&insn_cpuid); 1440 report("cpuid", R_AX|R_BX|R_CX|R_DX, 1441 outregs.eax == eax && outregs.ebx == ebx 1442 && outregs.ecx == ecx && outregs.edx == edx); 1443 } 1444 1445 static void test_ss_base_for_esp_ebp(void) 1446 { 1447 MK_INSN(ssrel1, "mov %ss, %ax; mov %bx, %ss; movl (%ebp), %ebx; mov %ax, %ss"); 1448 MK_INSN(ssrel2, "mov %ss, %ax; mov %bx, %ss; movl (%ebp,%edi,8), %ebx; mov %ax, %ss"); 1449 static unsigned array[] = { 0x12345678, 0, 0, 0, 0x87654321 }; 1450 1451 init_inregs(&(struct regs){ .ebx = 1, .ebp = (unsigned)array }); 1452 1453 exec_in_big_real_mode(&insn_ssrel1); 1454 report("ss relative addressing (1)", R_AX | R_BX, outregs.ebx == 0x87654321); 1455 1456 inregs.ebx = 1; 1457 inregs.ebp = (unsigned)array; 1458 inregs.edi = 0; 1459 exec_in_big_real_mode(&insn_ssrel2); 1460 report("ss relative addressing (2)", R_AX | R_BX, outregs.ebx == 0x87654321); 1461 } 1462 1463 extern unsigned long long r_gdt[]; 1464 1465 static void test_sgdt_sidt(void) 1466 { 1467 MK_INSN(sgdt, "sgdtw (%eax)"); 1468 MK_INSN(sidt, "sidtw (%eax)"); 1469 struct table_descr x, y; 1470 1471 init_inregs(&(struct regs){ .eax = (unsigned)&y }); 1472 1473 asm volatile("sgdtw %0" : "=m"(x)); 1474 exec_in_big_real_mode(&insn_sgdt); 1475 report("sgdt", 0, x.limit == y.limit && x.base == y.base); 1476 1477 inregs.eax = (unsigned)&y; 1478 asm volatile("sidtw %0" : "=m"(x)); 1479 exec_in_big_real_mode(&insn_sidt); 1480 report("sidt", 0, x.limit == y.limit && x.base == y.base); 1481 } 1482 1483 static void test_sahf(void) 1484 { 1485 MK_INSN(sahf, "sahf; pushfw; mov (%esp), %al; popfw"); 1486 1487 init_inregs(&(struct regs){ .eax = 0xfd00 }); 1488 1489 exec_in_big_real_mode(&insn_sahf); 1490 report("sahf", R_AX, outregs.eax == (inregs.eax | 0xd7)); 1491 } 1492 1493 static void test_lahf(void) 1494 { 1495 MK_INSN(lahf, "pushfw; mov %al, (%esp); popfw; lahf"); 1496 1497 init_inregs(&(struct regs){ .eax = 0xc7 }); 1498 1499 exec_in_big_real_mode(&insn_lahf); 1500 report("lahf", R_AX, (outregs.eax >> 8) == inregs.eax); 1501 } 1502 1503 static void test_movzx_movsx(void) 1504 { 1505 MK_INSN(movsx, "movsx %al, %ebx"); 1506 MK_INSN(movzx, "movzx %al, %ebx"); 1507 MK_INSN(movzsah, "movsx %ah, %ebx"); 1508 MK_INSN(movzxah, "movzx %ah, %ebx"); 1509 1510 init_inregs(&(struct regs){ .eax = 0x1234569c }); 1511 1512 exec_in_big_real_mode(&insn_movsx); 1513 report("movsx", R_BX, outregs.ebx == (signed char)inregs.eax); 1514 exec_in_big_real_mode(&insn_movzx); 1515 report("movzx", R_BX, outregs.ebx == (unsigned char)inregs.eax); 1516 exec_in_big_real_mode(&insn_movzsah); 1517 report("movsx ah", R_BX, outregs.ebx == (signed char)(inregs.eax>>8)); 1518 exec_in_big_real_mode(&insn_movzxah); 1519 report("movzx ah", R_BX, outregs.ebx == (unsigned char)(inregs.eax >> 8)); 1520 } 1521 1522 static void test_bswap(void) 1523 { 1524 MK_INSN(bswap, "bswap %ecx"); 1525 1526 init_inregs(&(struct regs){ .ecx = 0x12345678 }); 1527 1528 exec_in_big_real_mode(&insn_bswap); 1529 report("bswap", R_CX, outregs.ecx == 0x78563412); 1530 } 1531 1532 static void test_aad(void) 1533 { 1534 MK_INSN(aad, "aad"); 1535 1536 init_inregs(&(struct regs){ .eax = 0x12345678 }); 1537 1538 exec_in_big_real_mode(&insn_aad); 1539 report("aad", R_AX, outregs.eax == 0x123400d4); 1540 } 1541 1542 static void test_aam(void) 1543 { 1544 MK_INSN(aam, "aam"); 1545 1546 init_inregs(&(struct regs){ .eax = 0x76543210 }); 1547 1548 exec_in_big_real_mode(&insn_aam); 1549 report("aam", R_AX, outregs.eax == 0x76540106); 1550 } 1551 1552 static void test_xlat(void) 1553 { 1554 MK_INSN(xlat, "xlat"); 1555 u8 table[256]; 1556 int i; 1557 1558 for (i = 0; i < 256; i++) { 1559 table[i] = i + 1; 1560 } 1561 1562 init_inregs(&(struct regs){ .eax = 0x89abcdef, .ebx = (u32)table }); 1563 1564 exec_in_big_real_mode(&insn_xlat); 1565 report("xlat", R_AX, outregs.eax == 0x89abcdf0); 1566 } 1567 1568 static void test_salc(void) 1569 { 1570 MK_INSN(clc_salc, "clc; .byte 0xd6"); 1571 MK_INSN(stc_salc, "stc; .byte 0xd6"); 1572 1573 init_inregs(&(struct regs){ .eax = 0x12345678 }); 1574 1575 exec_in_big_real_mode(&insn_clc_salc); 1576 report("salc (1)", R_AX, outregs.eax == 0x12345600); 1577 exec_in_big_real_mode(&insn_stc_salc); 1578 report("salc (2)", R_AX, outregs.eax == 0x123456ff); 1579 } 1580 1581 static void test_fninit(void) 1582 { 1583 u16 fcw = -1, fsw = -1; 1584 MK_INSN(fninit, "fninit ; fnstsw (%eax) ; fnstcw (%ebx)"); 1585 1586 init_inregs(&(struct regs){ .eax = (u32)&fsw, .ebx = (u32)&fcw }); 1587 1588 exec_in_big_real_mode(&insn_fninit); 1589 report("fninit", 0, fsw == 0 && (fcw & 0x103f) == 0x003f); 1590 } 1591 1592 static void test_nopl(void) 1593 { 1594 MK_INSN(nopl1, ".byte 0x90\n\r"); // 1 byte nop 1595 MK_INSN(nopl2, ".byte 0x66, 0x90\n\r"); // 2 bytes nop 1596 MK_INSN(nopl3, ".byte 0x0f, 0x1f, 0x00\n\r"); // 3 bytes nop 1597 MK_INSN(nopl4, ".byte 0x0f, 0x1f, 0x40, 0x00\n\r"); // 4 bytes nop 1598 exec_in_big_real_mode(&insn_nopl1); 1599 exec_in_big_real_mode(&insn_nopl2); 1600 exec_in_big_real_mode(&insn_nopl3); 1601 exec_in_big_real_mode(&insn_nopl4); 1602 report("nopl", 0, 1); 1603 } 1604 1605 static u32 perf_baseline; 1606 1607 #define PERF_COUNT 1000000 1608 1609 #define MK_INSN_PERF(name, insn) \ 1610 MK_INSN(name, "rdtsc; mov %eax, %ebx; mov %edx, %esi\n" \ 1611 "1:" insn "\n" \ 1612 ".byte 0x67; loop 1b\n" \ 1613 "rdtsc"); 1614 1615 static u32 cycles_in_big_real_mode(struct insn_desc *insn) 1616 { 1617 u64 start, end; 1618 1619 init_inregs(&(struct regs){ .ecx = PERF_COUNT }); 1620 1621 exec_in_big_real_mode(insn); 1622 start = ((u64)outregs.esi << 32) | outregs.ebx; 1623 end = ((u64)outregs.edx << 32) | outregs.eax; 1624 1625 return end - start; 1626 } 1627 1628 static void test_perf_loop(void) 1629 { 1630 /* 1631 * This test runs simple instructions that should roughly take the 1632 * the same time to emulate: PERF_COUNT iterations of "loop" and 3 1633 * setup instructions. Other performance tests can run PERF_COUNT 1634 * iterations of the same instruction and subtract the cycle count 1635 * of this test. 1636 */ 1637 MK_INSN_PERF(perf_loop, ""); 1638 perf_baseline = cycles_in_big_real_mode(&insn_perf_loop); 1639 print_serial_u32(perf_baseline / (PERF_COUNT + 3)); 1640 print_serial(" cycles/emulated jump instruction\n"); 1641 } 1642 1643 static void test_perf_mov(void) 1644 { 1645 u32 cyc; 1646 1647 MK_INSN_PERF(perf_move, "mov %esi, %edi"); 1648 cyc = cycles_in_big_real_mode(&insn_perf_move); 1649 print_serial_u32((cyc - perf_baseline) / PERF_COUNT); 1650 print_serial(" cycles/emulated move instruction\n"); 1651 } 1652 1653 static void test_perf_arith(void) 1654 { 1655 u32 cyc; 1656 1657 MK_INSN_PERF(perf_arith, "add $4, %edi"); 1658 cyc = cycles_in_big_real_mode(&insn_perf_arith); 1659 print_serial_u32((cyc - perf_baseline) / PERF_COUNT); 1660 print_serial(" cycles/emulated arithmetic instruction\n"); 1661 } 1662 1663 static void test_perf_memory_load(void) 1664 { 1665 u32 cyc, tmp; 1666 1667 MK_INSN_PERF(perf_memory_load, "cmpw $0, (%edi)"); 1668 1669 init_inregs(&(struct regs){ .edi = (u32)&tmp }); 1670 1671 cyc = cycles_in_big_real_mode(&insn_perf_memory_load); 1672 print_serial_u32((cyc - perf_baseline) / PERF_COUNT); 1673 print_serial(" cycles/emulated memory load instruction\n"); 1674 } 1675 1676 static void test_perf_memory_store(void) 1677 { 1678 u32 cyc, tmp; 1679 1680 MK_INSN_PERF(perf_memory_store, "movw %ax, (%edi)"); 1681 1682 init_inregs(&(struct regs){ .edi = (u32)&tmp }); 1683 1684 cyc = cycles_in_big_real_mode(&insn_perf_memory_store); 1685 print_serial_u32((cyc - perf_baseline) / PERF_COUNT); 1686 print_serial(" cycles/emulated memory store instruction\n"); 1687 } 1688 1689 static void test_perf_memory_rmw(void) 1690 { 1691 u32 cyc, tmp; 1692 1693 MK_INSN_PERF(perf_memory_rmw, "addw $1, (%edi)"); 1694 1695 init_inregs(&(struct regs){ .edi = (u32)&tmp }); 1696 1697 cyc = cycles_in_big_real_mode(&insn_perf_memory_rmw); 1698 print_serial_u32((cyc - perf_baseline) / PERF_COUNT); 1699 print_serial(" cycles/emulated memory RMW instruction\n"); 1700 } 1701 1702 static void test_dr_mod(void) 1703 { 1704 MK_INSN(drmod, "movl %ebx, %dr0\n\t" 1705 ".byte 0x0f \n\t .byte 0x21 \n\t .byte 0x0\n\t"); 1706 1707 init_inregs(&(struct regs){ .eax = 0xdead, .ebx = 0xaced }); 1708 1709 exec_in_big_real_mode(&insn_drmod); 1710 report("mov dr with mod bits", R_AX | R_BX, outregs.eax == 0xaced); 1711 } 1712 1713 static void test_smsw(void) 1714 { 1715 MK_INSN(smsw, "movl %cr0, %ebx\n\t" 1716 "movl %ebx, %ecx\n\t" 1717 "or $0x40000000, %ebx\n\t" 1718 "movl %ebx, %cr0\n\t" 1719 "smswl %eax\n\t" 1720 "movl %ecx, %cr0\n\t"); 1721 1722 init_inregs(&(struct regs){ .eax = 0x12345678 }); 1723 1724 exec_in_big_real_mode(&insn_smsw); 1725 report("smsw", R_AX | R_BX | R_CX, outregs.eax == outregs.ebx); 1726 } 1727 1728 static void test_xadd(void) 1729 { 1730 MK_INSN(xadd, "xaddl %eax, %eax\n\t"); 1731 1732 init_inregs(&(struct regs){ .eax = 0x12345678 }); 1733 1734 exec_in_big_real_mode(&insn_xadd); 1735 report("xadd", R_AX, outregs.eax == inregs.eax * 2); 1736 } 1737 1738 1739 void realmode_start(void) 1740 { 1741 test_null(); 1742 1743 test_shld(); 1744 test_push_pop(); 1745 test_pusha_popa(); 1746 test_mov_imm(); 1747 test_cmp_imm(); 1748 test_add_imm(); 1749 test_sub_imm(); 1750 test_xor_imm(); 1751 test_io(); 1752 test_eflags_insn(); 1753 test_jcc_short(); 1754 test_jcc_near(); 1755 /* test_call() uses short jump so call it after testing jcc */ 1756 test_call(); 1757 /* long jmp test uses call near so test it after testing call */ 1758 test_long_jmp(); 1759 test_xchg(); 1760 test_iret(); 1761 test_int(); 1762 test_sti_inhibit(); 1763 test_imul(); 1764 test_mul(); 1765 test_div(); 1766 test_idiv(); 1767 test_loopcc(); 1768 test_cbw(); 1769 test_cwd_cdq(); 1770 test_das(); 1771 test_lds_lss(); 1772 test_jcxz(); 1773 test_cpuid(); 1774 test_ss_base_for_esp_ebp(); 1775 test_sgdt_sidt(); 1776 test_lahf(); 1777 test_sahf(); 1778 test_movzx_movsx(); 1779 test_bswap(); 1780 test_aad(); 1781 test_aam(); 1782 test_xlat(); 1783 test_salc(); 1784 test_fninit(); 1785 test_dr_mod(); 1786 test_smsw(); 1787 test_nopl(); 1788 test_xadd(); 1789 test_perf_loop(); 1790 test_perf_mov(); 1791 test_perf_arith(); 1792 test_perf_memory_load(); 1793 test_perf_memory_store(); 1794 test_perf_memory_rmw(); 1795 1796 exit(failed); 1797 } 1798 1799 unsigned long long r_gdt[] = { 0, 0x9b000000ffff, 0x93000000ffff }; 1800 1801 struct table_descr r_gdt_descr = { sizeof(r_gdt) - 1, &r_gdt }; 1802 1803 asm( 1804 ".section .init \n\t" 1805 1806 ".code32 \n\t" 1807 1808 "mb_magic = 0x1BADB002 \n\t" 1809 "mb_flags = 0x0 \n\t" 1810 1811 "# multiboot header \n\t" 1812 ".long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) \n\t" 1813 1814 ".globl start \n\t" 1815 ".data \n\t" 1816 ". = . + 4096 \n\t" 1817 "stacktop: \n\t" 1818 1819 ".text \n\t" 1820 "start: \n\t" 1821 "lgdt r_gdt_descr \n\t" 1822 "ljmp $8, $1f; 1: \n\t" 1823 ".code16gcc \n\t" 1824 "mov $16, %eax \n\t" 1825 "mov %ax, %ds \n\t" 1826 "mov %ax, %es \n\t" 1827 "mov %ax, %fs \n\t" 1828 "mov %ax, %gs \n\t" 1829 "mov %ax, %ss \n\t" 1830 "mov %cr0, %eax \n\t" 1831 "btc $0, %eax \n\t" 1832 "mov %eax, %cr0 \n\t" 1833 "ljmp $0, $realmode_entry \n\t" 1834 1835 "realmode_entry: \n\t" 1836 1837 "xor %ax, %ax \n\t" 1838 "mov %ax, %ds \n\t" 1839 "mov %ax, %es \n\t" 1840 "mov %ax, %ss \n\t" 1841 "mov %ax, %fs \n\t" 1842 "mov %ax, %gs \n\t" 1843 "mov $stacktop, %esp\n\t" 1844 "ljmp $0, $realmode_start \n\t" 1845 1846 ".code16gcc \n\t" 1847 ); 1848