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