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