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