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