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