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 MK_INSN(push_pop_high_esp_bits, 558 "xor $0x12340000, %esp \n\t" 559 "push %ax; \n\t" 560 "xor $0x12340000, %esp \n\t" 561 "pop %bx"); 562 563 inregs = (struct regs){ 0 }; 564 565 exec_in_big_real_mode(&insn_push32); 566 report("push/pop 1", R_AX|R_BX, 567 outregs.eax == outregs.ebx && outregs.eax == 0x12345678); 568 569 exec_in_big_real_mode(&insn_push16); 570 report("push/pop 2", R_AX|R_BX, 571 outregs.eax == outregs.ebx && outregs.eax == 0x1234); 572 573 exec_in_big_real_mode(&insn_push_es); 574 report("push/pop 3", R_AX|R_BX, 575 outregs.ebx == outregs.eax && outregs.eax == 0x123); 576 577 exec_in_big_real_mode(&insn_pop_es); 578 report("push/pop 4", R_AX|R_BX, outregs.ebx == outregs.eax); 579 580 exec_in_big_real_mode(&insn_push_pop_ss); 581 report("push/pop 5", R_AX|R_BX, outregs.ebx == outregs.eax); 582 583 exec_in_big_real_mode(&insn_push_pop_fs); 584 report("push/pop 6", R_AX|R_BX, outregs.ebx == outregs.eax); 585 586 inregs.eax = 0x9977; 587 inregs.ebx = 0x7799; 588 exec_in_big_real_mode(&insn_push_pop_high_esp_bits); 589 report("push/pop with high bits set in %esp", R_BX, outregs.ebx == 0x9977); 590 } 591 592 void test_null(void) 593 { 594 MK_INSN(null, ""); 595 596 inregs = (struct regs){ 0 }; 597 598 exec_in_big_real_mode(&insn_null); 599 report("null", 0, 1); 600 } 601 602 struct { 603 char stack[500]; 604 char top[]; 605 } tmp_stack; 606 607 void test_pusha_popa() 608 { 609 MK_INSN(pusha, "pusha\n\t" 610 "pop %edi\n\t" 611 "pop %esi\n\t" 612 "pop %ebp\n\t" 613 "add $4, %esp\n\t" 614 "pop %ebx\n\t" 615 "pop %edx\n\t" 616 "pop %ecx\n\t" 617 "pop %eax\n\t" 618 ); 619 620 MK_INSN(popa, "push %eax\n\t" 621 "push %ecx\n\t" 622 "push %edx\n\t" 623 "push %ebx\n\t" 624 "push %esp\n\t" 625 "push %ebp\n\t" 626 "push %esi\n\t" 627 "push %edi\n\t" 628 "popa\n\t" 629 ); 630 631 inregs = (struct regs){ .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = (unsigned long)&tmp_stack.top }; 632 633 exec_in_big_real_mode(&insn_pusha); 634 report("pusha/popa 1", 0, 1); 635 636 exec_in_big_real_mode(&insn_popa); 637 report("pusha/popa 1", 0, 1); 638 } 639 640 void test_iret() 641 { 642 MK_INSN(iret32, "pushf\n\t" 643 "pushl %cs\n\t" 644 "call 1f\n\t" /* a near call will push eip onto the stack */ 645 "jmp 2f\n\t" 646 "1: iret\n\t" 647 "2:\n\t" 648 ); 649 650 MK_INSN(iret16, "pushfw\n\t" 651 "pushw %cs\n\t" 652 "callw 1f\n\t" 653 "jmp 2f\n\t" 654 "1: iretw\n\t" 655 "2:\n\t"); 656 657 MK_INSN(iret_flags32, "pushfl\n\t" 658 "popl %eax\n\t" 659 "andl $~0x2, %eax\n\t" 660 "orl $0xffc08028, %eax\n\t" 661 "pushl %eax\n\t" 662 "pushl %cs\n\t" 663 "call 1f\n\t" 664 "jmp 2f\n\t" 665 "1: iret\n\t" 666 "2:\n\t"); 667 668 MK_INSN(iret_flags16, "pushfw\n\t" 669 "popw %ax\n\t" 670 "and $~0x2, %ax\n\t" 671 "or $0x8028, %ax\n\t" 672 "pushw %ax\n\t" 673 "pushw %cs\n\t" 674 "callw 1f\n\t" 675 "jmp 2f\n\t" 676 "1: iretw\n\t" 677 "2:\n\t"); 678 679 inregs = (struct regs){ 0 }; 680 681 exec_in_big_real_mode(&insn_iret32); 682 report("iret 1", 0, 1); 683 684 exec_in_big_real_mode(&insn_iret16); 685 report("iret 2", 0, 1); 686 687 exec_in_big_real_mode(&insn_iret_flags32); 688 report("iret 3", R_AX, 1); 689 690 exec_in_big_real_mode(&insn_iret_flags16); 691 report("iret 4", R_AX, 1); 692 } 693 694 void test_int() 695 { 696 inregs = (struct regs){ 0 }; 697 698 *(u32 *)(0x11 * 4) = 0x1000; /* Store a pointer to address 0x1000 in IDT entry 0x11 */ 699 *(u8 *)(0x1000) = 0xcf; /* 0x1000 contains an IRET instruction */ 700 701 MK_INSN(int11, "int $0x11\n\t"); 702 703 exec_in_big_real_mode(&insn_int11); 704 report("int 1", 0, 1); 705 } 706 707 void test_imul() 708 { 709 MK_INSN(imul8_1, "mov $2, %al\n\t" 710 "mov $-4, %cx\n\t" 711 "imul %cl\n\t"); 712 713 MK_INSN(imul16_1, "mov $2, %ax\n\t" 714 "mov $-4, %cx\n\t" 715 "imul %cx\n\t"); 716 717 MK_INSN(imul32_1, "mov $2, %eax\n\t" 718 "mov $-4, %ecx\n\t" 719 "imul %ecx\n\t"); 720 721 MK_INSN(imul8_2, "mov $0x12340002, %eax\n\t" 722 "mov $4, %cx\n\t" 723 "imul %cl\n\t"); 724 725 MK_INSN(imul16_2, "mov $2, %ax\n\t" 726 "mov $4, %cx\n\t" 727 "imul %cx\n\t"); 728 729 MK_INSN(imul32_2, "mov $2, %eax\n\t" 730 "mov $4, %ecx\n\t" 731 "imul %ecx\n\t"); 732 733 inregs = (struct regs){ 0 }; 734 735 exec_in_big_real_mode(&insn_imul8_1); 736 report("imul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == (u8)-8); 737 738 exec_in_big_real_mode(&insn_imul16_1); 739 report("imul 2", R_AX | R_CX | R_DX, outregs.eax == (u16)-8); 740 741 exec_in_big_real_mode(&insn_imul32_1); 742 report("imul 3", R_AX | R_CX | R_DX, outregs.eax == (u32)-8); 743 744 exec_in_big_real_mode(&insn_imul8_2); 745 report("imul 4", R_AX | R_CX | R_DX, 746 (outregs.eax & 0xffff) == 8 747 && (outregs.eax & 0xffff0000) == 0x12340000); 748 749 exec_in_big_real_mode(&insn_imul16_2); 750 report("imul 5", R_AX | R_CX | R_DX, outregs.eax == 8); 751 752 exec_in_big_real_mode(&insn_imul32_2); 753 report("imul 6", R_AX | R_CX | R_DX, outregs.eax == 8); 754 } 755 756 void test_mul() 757 { 758 MK_INSN(mul8, "mov $2, %al\n\t" 759 "mov $4, %cx\n\t" 760 "imul %cl\n\t"); 761 762 MK_INSN(mul16, "mov $2, %ax\n\t" 763 "mov $4, %cx\n\t" 764 "imul %cx\n\t"); 765 766 MK_INSN(mul32, "mov $2, %eax\n\t" 767 "mov $4, %ecx\n\t" 768 "imul %ecx\n\t"); 769 770 inregs = (struct regs){ 0 }; 771 772 exec_in_big_real_mode(&insn_mul8); 773 report("mul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == 8); 774 775 exec_in_big_real_mode(&insn_mul16); 776 report("mul 2", R_AX | R_CX | R_DX, outregs.eax == 8); 777 778 exec_in_big_real_mode(&insn_mul32); 779 report("mul 3", R_AX | R_CX | R_DX, outregs.eax == 8); 780 } 781 782 void test_div() 783 { 784 MK_INSN(div8, "mov $257, %ax\n\t" 785 "mov $2, %cl\n\t" 786 "div %cl\n\t"); 787 788 MK_INSN(div16, "mov $512, %ax\n\t" 789 "mov $5, %cx\n\t" 790 "div %cx\n\t"); 791 792 MK_INSN(div32, "mov $512, %eax\n\t" 793 "mov $5, %ecx\n\t" 794 "div %ecx\n\t"); 795 796 inregs = (struct regs){ 0 }; 797 798 exec_in_big_real_mode(&insn_div8); 799 report("div 1", R_AX | R_CX | R_DX, outregs.eax == 384); 800 801 exec_in_big_real_mode(&insn_div16); 802 report("div 2", R_AX | R_CX | R_DX, 803 outregs.eax == 102 && outregs.edx == 2); 804 805 exec_in_big_real_mode(&insn_div32); 806 report("div 3", R_AX | R_CX | R_DX, 807 outregs.eax == 102 && outregs.edx == 2); 808 } 809 810 void test_idiv() 811 { 812 MK_INSN(idiv8, "mov $256, %ax\n\t" 813 "mov $-2, %cl\n\t" 814 "idiv %cl\n\t"); 815 816 MK_INSN(idiv16, "mov $512, %ax\n\t" 817 "mov $-2, %cx\n\t" 818 "idiv %cx\n\t"); 819 820 MK_INSN(idiv32, "mov $512, %eax\n\t" 821 "mov $-2, %ecx\n\t" 822 "idiv %ecx\n\t"); 823 824 inregs = (struct regs){ 0 }; 825 826 exec_in_big_real_mode(&insn_idiv8); 827 report("idiv 1", R_AX | R_CX | R_DX, outregs.eax == (u8)-128); 828 829 exec_in_big_real_mode(&insn_idiv16); 830 report("idiv 2", R_AX | R_CX | R_DX, outregs.eax == (u16)-256); 831 832 exec_in_big_real_mode(&insn_idiv32); 833 report("idiv 3", R_AX | R_CX | R_DX, outregs.eax == (u32)-256); 834 } 835 836 void test_cbw(void) 837 { 838 MK_INSN(cbw, "mov $0xFE, %eax \n\t" 839 "cbw\n\t"); 840 MK_INSN(cwde, "mov $0xFFFE, %eax \n\t" 841 "cwde\n\t"); 842 843 inregs = (struct regs){ 0 }; 844 845 exec_in_big_real_mode(&insn_cbw); 846 report("cbq 1", ~0, outregs.eax == 0xFFFE); 847 848 exec_in_big_real_mode(&insn_cwde); 849 report("cwde 1", ~0, outregs.eax == 0xFFFFFFFE); 850 } 851 852 void test_loopcc(void) 853 { 854 MK_INSN(loop, "mov $10, %ecx\n\t" 855 "1: inc %eax\n\t" 856 "loop 1b\n\t"); 857 858 MK_INSN(loope, "mov $10, %ecx\n\t" 859 "mov $1, %eax\n\t" 860 "1: dec %eax\n\t" 861 "loope 1b\n\t"); 862 863 MK_INSN(loopne, "mov $10, %ecx\n\t" 864 "mov $5, %eax\n\t" 865 "1: dec %eax\n\t" 866 "loopne 1b\n\t"); 867 868 inregs = (struct regs){ 0 }; 869 870 exec_in_big_real_mode(&insn_loop); 871 report("LOOPcc short 1", R_AX, outregs.eax == 10); 872 873 exec_in_big_real_mode(&insn_loope); 874 report("LOOPcc short 2", R_AX | R_CX, 875 outregs.eax == -1 && outregs.ecx == 8); 876 877 exec_in_big_real_mode(&insn_loopne); 878 report("LOOPcc short 3", R_AX | R_CX, 879 outregs.eax == 0 && outregs.ecx == 5); 880 } 881 882 static void test_das(void) 883 { 884 short i; 885 u16 nr_fail = 0; 886 static unsigned test_cases[1024] = { 887 0x46000000, 0x8701a000, 0x9710fa00, 0x97119a00, 888 0x02000101, 0x8301a101, 0x9310fb01, 0x93119b01, 889 0x02000202, 0x8301a202, 0x9710fc02, 0x97119c02, 890 0x06000303, 0x8701a303, 0x9310fd03, 0x93119d03, 891 0x02000404, 0x8301a404, 0x9310fe04, 0x93119e04, 892 0x06000505, 0x8701a505, 0x9710ff05, 0x97119f05, 893 0x06000606, 0x8701a606, 0x56100006, 0x9711a006, 894 0x02000707, 0x8301a707, 0x12100107, 0x9311a107, 895 0x02000808, 0x8301a808, 0x12100208, 0x9311a208, 896 0x06000909, 0x8701a909, 0x16100309, 0x9711a309, 897 0x1200040a, 0x9301a40a, 0x1210040a, 0x9311a40a, 898 0x1600050b, 0x9701a50b, 0x1610050b, 0x9711a50b, 899 0x1600060c, 0x9701a60c, 0x1610060c, 0x9711a60c, 900 0x1200070d, 0x9301a70d, 0x1210070d, 0x9311a70d, 901 0x1200080e, 0x9301a80e, 0x1210080e, 0x9311a80e, 902 0x1600090f, 0x9701a90f, 0x1610090f, 0x9711a90f, 903 0x02001010, 0x8301b010, 0x16100a10, 0x9711aa10, 904 0x06001111, 0x8701b111, 0x12100b11, 0x9311ab11, 905 0x06001212, 0x8701b212, 0x16100c12, 0x9711ac12, 906 0x02001313, 0x8301b313, 0x12100d13, 0x9311ad13, 907 0x06001414, 0x8701b414, 0x12100e14, 0x9311ae14, 908 0x02001515, 0x8301b515, 0x16100f15, 0x9711af15, 909 0x02001616, 0x8301b616, 0x12101016, 0x9311b016, 910 0x06001717, 0x8701b717, 0x16101117, 0x9711b117, 911 0x06001818, 0x8701b818, 0x16101218, 0x9711b218, 912 0x02001919, 0x8301b919, 0x12101319, 0x9311b319, 913 0x1600141a, 0x9701b41a, 0x1610141a, 0x9711b41a, 914 0x1200151b, 0x9301b51b, 0x1210151b, 0x9311b51b, 915 0x1200161c, 0x9301b61c, 0x1210161c, 0x9311b61c, 916 0x1600171d, 0x9701b71d, 0x1610171d, 0x9711b71d, 917 0x1600181e, 0x9701b81e, 0x1610181e, 0x9711b81e, 918 0x1200191f, 0x9301b91f, 0x1210191f, 0x9311b91f, 919 0x02002020, 0x8701c020, 0x12101a20, 0x9311ba20, 920 0x06002121, 0x8301c121, 0x16101b21, 0x9711bb21, 921 0x06002222, 0x8301c222, 0x12101c22, 0x9311bc22, 922 0x02002323, 0x8701c323, 0x16101d23, 0x9711bd23, 923 0x06002424, 0x8301c424, 0x16101e24, 0x9711be24, 924 0x02002525, 0x8701c525, 0x12101f25, 0x9311bf25, 925 0x02002626, 0x8701c626, 0x12102026, 0x9711c026, 926 0x06002727, 0x8301c727, 0x16102127, 0x9311c127, 927 0x06002828, 0x8301c828, 0x16102228, 0x9311c228, 928 0x02002929, 0x8701c929, 0x12102329, 0x9711c329, 929 0x1600242a, 0x9301c42a, 0x1610242a, 0x9311c42a, 930 0x1200252b, 0x9701c52b, 0x1210252b, 0x9711c52b, 931 0x1200262c, 0x9701c62c, 0x1210262c, 0x9711c62c, 932 0x1600272d, 0x9301c72d, 0x1610272d, 0x9311c72d, 933 0x1600282e, 0x9301c82e, 0x1610282e, 0x9311c82e, 934 0x1200292f, 0x9701c92f, 0x1210292f, 0x9711c92f, 935 0x06003030, 0x8301d030, 0x12102a30, 0x9711ca30, 936 0x02003131, 0x8701d131, 0x16102b31, 0x9311cb31, 937 0x02003232, 0x8701d232, 0x12102c32, 0x9711cc32, 938 0x06003333, 0x8301d333, 0x16102d33, 0x9311cd33, 939 0x02003434, 0x8701d434, 0x16102e34, 0x9311ce34, 940 0x06003535, 0x8301d535, 0x12102f35, 0x9711cf35, 941 0x06003636, 0x8301d636, 0x16103036, 0x9311d036, 942 0x02003737, 0x8701d737, 0x12103137, 0x9711d137, 943 0x02003838, 0x8701d838, 0x12103238, 0x9711d238, 944 0x06003939, 0x8301d939, 0x16103339, 0x9311d339, 945 0x1200343a, 0x9701d43a, 0x1210343a, 0x9711d43a, 946 0x1600353b, 0x9301d53b, 0x1610353b, 0x9311d53b, 947 0x1600363c, 0x9301d63c, 0x1610363c, 0x9311d63c, 948 0x1200373d, 0x9701d73d, 0x1210373d, 0x9711d73d, 949 0x1200383e, 0x9701d83e, 0x1210383e, 0x9711d83e, 950 0x1600393f, 0x9301d93f, 0x1610393f, 0x9311d93f, 951 0x02004040, 0x8301e040, 0x16103a40, 0x9311da40, 952 0x06004141, 0x8701e141, 0x12103b41, 0x9711db41, 953 0x06004242, 0x8701e242, 0x16103c42, 0x9311dc42, 954 0x02004343, 0x8301e343, 0x12103d43, 0x9711dd43, 955 0x06004444, 0x8701e444, 0x12103e44, 0x9711de44, 956 0x02004545, 0x8301e545, 0x16103f45, 0x9311df45, 957 0x02004646, 0x8301e646, 0x12104046, 0x9311e046, 958 0x06004747, 0x8701e747, 0x16104147, 0x9711e147, 959 0x06004848, 0x8701e848, 0x16104248, 0x9711e248, 960 0x02004949, 0x8301e949, 0x12104349, 0x9311e349, 961 0x1600444a, 0x9701e44a, 0x1610444a, 0x9711e44a, 962 0x1200454b, 0x9301e54b, 0x1210454b, 0x9311e54b, 963 0x1200464c, 0x9301e64c, 0x1210464c, 0x9311e64c, 964 0x1600474d, 0x9701e74d, 0x1610474d, 0x9711e74d, 965 0x1600484e, 0x9701e84e, 0x1610484e, 0x9711e84e, 966 0x1200494f, 0x9301e94f, 0x1210494f, 0x9311e94f, 967 0x06005050, 0x8701f050, 0x12104a50, 0x9311ea50, 968 0x02005151, 0x8301f151, 0x16104b51, 0x9711eb51, 969 0x02005252, 0x8301f252, 0x12104c52, 0x9311ec52, 970 0x06005353, 0x8701f353, 0x16104d53, 0x9711ed53, 971 0x02005454, 0x8301f454, 0x16104e54, 0x9711ee54, 972 0x06005555, 0x8701f555, 0x12104f55, 0x9311ef55, 973 0x06005656, 0x8701f656, 0x16105056, 0x9711f056, 974 0x02005757, 0x8301f757, 0x12105157, 0x9311f157, 975 0x02005858, 0x8301f858, 0x12105258, 0x9311f258, 976 0x06005959, 0x8701f959, 0x16105359, 0x9711f359, 977 0x1200545a, 0x9301f45a, 0x1210545a, 0x9311f45a, 978 0x1600555b, 0x9701f55b, 0x1610555b, 0x9711f55b, 979 0x1600565c, 0x9701f65c, 0x1610565c, 0x9711f65c, 980 0x1200575d, 0x9301f75d, 0x1210575d, 0x9311f75d, 981 0x1200585e, 0x9301f85e, 0x1210585e, 0x9311f85e, 982 0x1600595f, 0x9701f95f, 0x1610595f, 0x9711f95f, 983 0x06006060, 0x47010060, 0x16105a60, 0x9711fa60, 984 0x02006161, 0x03010161, 0x12105b61, 0x9311fb61, 985 0x02006262, 0x03010262, 0x16105c62, 0x9711fc62, 986 0x06006363, 0x07010363, 0x12105d63, 0x9311fd63, 987 0x02006464, 0x03010464, 0x12105e64, 0x9311fe64, 988 0x06006565, 0x07010565, 0x16105f65, 0x9711ff65, 989 0x06006666, 0x07010666, 0x16106066, 0x57110066, 990 0x02006767, 0x03010767, 0x12106167, 0x13110167, 991 0x02006868, 0x03010868, 0x12106268, 0x13110268, 992 0x06006969, 0x07010969, 0x16106369, 0x17110369, 993 0x1200646a, 0x1301046a, 0x1210646a, 0x1311046a, 994 0x1600656b, 0x1701056b, 0x1610656b, 0x1711056b, 995 0x1600666c, 0x1701066c, 0x1610666c, 0x1711066c, 996 0x1200676d, 0x1301076d, 0x1210676d, 0x1311076d, 997 0x1200686e, 0x1301086e, 0x1210686e, 0x1311086e, 998 0x1600696f, 0x1701096f, 0x1610696f, 0x1711096f, 999 0x02007070, 0x03011070, 0x16106a70, 0x17110a70, 1000 0x06007171, 0x07011171, 0x12106b71, 0x13110b71, 1001 0x06007272, 0x07011272, 0x16106c72, 0x17110c72, 1002 0x02007373, 0x03011373, 0x12106d73, 0x13110d73, 1003 0x06007474, 0x07011474, 0x12106e74, 0x13110e74, 1004 0x02007575, 0x03011575, 0x16106f75, 0x17110f75, 1005 0x02007676, 0x03011676, 0x12107076, 0x13111076, 1006 0x06007777, 0x07011777, 0x16107177, 0x17111177, 1007 0x06007878, 0x07011878, 0x16107278, 0x17111278, 1008 0x02007979, 0x03011979, 0x12107379, 0x13111379, 1009 0x1600747a, 0x1701147a, 0x1610747a, 0x1711147a, 1010 0x1200757b, 0x1301157b, 0x1210757b, 0x1311157b, 1011 0x1200767c, 0x1301167c, 0x1210767c, 0x1311167c, 1012 0x1600777d, 0x1701177d, 0x1610777d, 0x1711177d, 1013 0x1600787e, 0x1701187e, 0x1610787e, 0x1711187e, 1014 0x1200797f, 0x1301197f, 0x1210797f, 0x1311197f, 1015 0x82008080, 0x03012080, 0x12107a80, 0x13111a80, 1016 0x86008181, 0x07012181, 0x16107b81, 0x17111b81, 1017 0x86008282, 0x07012282, 0x12107c82, 0x13111c82, 1018 0x82008383, 0x03012383, 0x16107d83, 0x17111d83, 1019 0x86008484, 0x07012484, 0x16107e84, 0x17111e84, 1020 0x82008585, 0x03012585, 0x12107f85, 0x13111f85, 1021 0x82008686, 0x03012686, 0x92108086, 0x13112086, 1022 0x86008787, 0x07012787, 0x96108187, 0x17112187, 1023 0x86008888, 0x07012888, 0x96108288, 0x17112288, 1024 0x82008989, 0x03012989, 0x92108389, 0x13112389, 1025 0x9600848a, 0x1701248a, 0x9610848a, 0x1711248a, 1026 0x9200858b, 0x1301258b, 0x9210858b, 0x1311258b, 1027 0x9200868c, 0x1301268c, 0x9210868c, 0x1311268c, 1028 0x9600878d, 0x1701278d, 0x9610878d, 0x1711278d, 1029 0x9600888e, 0x1701288e, 0x9610888e, 0x1711288e, 1030 0x9200898f, 0x1301298f, 0x9210898f, 0x1311298f, 1031 0x86009090, 0x07013090, 0x92108a90, 0x13112a90, 1032 0x82009191, 0x03013191, 0x96108b91, 0x17112b91, 1033 0x82009292, 0x03013292, 0x92108c92, 0x13112c92, 1034 0x86009393, 0x07013393, 0x96108d93, 0x17112d93, 1035 0x82009494, 0x03013494, 0x96108e94, 0x17112e94, 1036 0x86009595, 0x07013595, 0x92108f95, 0x13112f95, 1037 0x86009696, 0x07013696, 0x96109096, 0x17113096, 1038 0x82009797, 0x03013797, 0x92109197, 0x13113197, 1039 0x82009898, 0x03013898, 0x92109298, 0x13113298, 1040 0x86009999, 0x07013999, 0x96109399, 0x17113399, 1041 0x1300349a, 0x1301349a, 0x1310349a, 0x1311349a, 1042 0x1700359b, 0x1701359b, 0x1710359b, 0x1711359b, 1043 0x1700369c, 0x1701369c, 0x1710369c, 0x1711369c, 1044 0x1300379d, 0x1301379d, 0x1310379d, 0x1311379d, 1045 0x1300389e, 0x1301389e, 0x1310389e, 0x1311389e, 1046 0x1700399f, 0x1701399f, 0x1710399f, 0x1711399f, 1047 0x030040a0, 0x030140a0, 0x17103aa0, 0x17113aa0, 1048 0x070041a1, 0x070141a1, 0x13103ba1, 0x13113ba1, 1049 0x070042a2, 0x070142a2, 0x17103ca2, 0x17113ca2, 1050 0x030043a3, 0x030143a3, 0x13103da3, 0x13113da3, 1051 0x070044a4, 0x070144a4, 0x13103ea4, 0x13113ea4, 1052 0x030045a5, 0x030145a5, 0x17103fa5, 0x17113fa5, 1053 0x030046a6, 0x030146a6, 0x131040a6, 0x131140a6, 1054 0x070047a7, 0x070147a7, 0x171041a7, 0x171141a7, 1055 0x070048a8, 0x070148a8, 0x171042a8, 0x171142a8, 1056 0x030049a9, 0x030149a9, 0x131043a9, 0x131143a9, 1057 0x170044aa, 0x170144aa, 0x171044aa, 0x171144aa, 1058 0x130045ab, 0x130145ab, 0x131045ab, 0x131145ab, 1059 0x130046ac, 0x130146ac, 0x131046ac, 0x131146ac, 1060 0x170047ad, 0x170147ad, 0x171047ad, 0x171147ad, 1061 0x170048ae, 0x170148ae, 0x171048ae, 0x171148ae, 1062 0x130049af, 0x130149af, 0x131049af, 0x131149af, 1063 0x070050b0, 0x070150b0, 0x13104ab0, 0x13114ab0, 1064 0x030051b1, 0x030151b1, 0x17104bb1, 0x17114bb1, 1065 0x030052b2, 0x030152b2, 0x13104cb2, 0x13114cb2, 1066 0x070053b3, 0x070153b3, 0x17104db3, 0x17114db3, 1067 0x030054b4, 0x030154b4, 0x17104eb4, 0x17114eb4, 1068 0x070055b5, 0x070155b5, 0x13104fb5, 0x13114fb5, 1069 0x070056b6, 0x070156b6, 0x171050b6, 0x171150b6, 1070 0x030057b7, 0x030157b7, 0x131051b7, 0x131151b7, 1071 0x030058b8, 0x030158b8, 0x131052b8, 0x131152b8, 1072 0x070059b9, 0x070159b9, 0x171053b9, 0x171153b9, 1073 0x130054ba, 0x130154ba, 0x131054ba, 0x131154ba, 1074 0x170055bb, 0x170155bb, 0x171055bb, 0x171155bb, 1075 0x170056bc, 0x170156bc, 0x171056bc, 0x171156bc, 1076 0x130057bd, 0x130157bd, 0x131057bd, 0x131157bd, 1077 0x130058be, 0x130158be, 0x131058be, 0x131158be, 1078 0x170059bf, 0x170159bf, 0x171059bf, 0x171159bf, 1079 0x070060c0, 0x070160c0, 0x17105ac0, 0x17115ac0, 1080 0x030061c1, 0x030161c1, 0x13105bc1, 0x13115bc1, 1081 0x030062c2, 0x030162c2, 0x17105cc2, 0x17115cc2, 1082 0x070063c3, 0x070163c3, 0x13105dc3, 0x13115dc3, 1083 0x030064c4, 0x030164c4, 0x13105ec4, 0x13115ec4, 1084 0x070065c5, 0x070165c5, 0x17105fc5, 0x17115fc5, 1085 0x070066c6, 0x070166c6, 0x171060c6, 0x171160c6, 1086 0x030067c7, 0x030167c7, 0x131061c7, 0x131161c7, 1087 0x030068c8, 0x030168c8, 0x131062c8, 0x131162c8, 1088 0x070069c9, 0x070169c9, 0x171063c9, 0x171163c9, 1089 0x130064ca, 0x130164ca, 0x131064ca, 0x131164ca, 1090 0x170065cb, 0x170165cb, 0x171065cb, 0x171165cb, 1091 0x170066cc, 0x170166cc, 0x171066cc, 0x171166cc, 1092 0x130067cd, 0x130167cd, 0x131067cd, 0x131167cd, 1093 0x130068ce, 0x130168ce, 0x131068ce, 0x131168ce, 1094 0x170069cf, 0x170169cf, 0x171069cf, 0x171169cf, 1095 0x030070d0, 0x030170d0, 0x17106ad0, 0x17116ad0, 1096 0x070071d1, 0x070171d1, 0x13106bd1, 0x13116bd1, 1097 0x070072d2, 0x070172d2, 0x17106cd2, 0x17116cd2, 1098 0x030073d3, 0x030173d3, 0x13106dd3, 0x13116dd3, 1099 0x070074d4, 0x070174d4, 0x13106ed4, 0x13116ed4, 1100 0x030075d5, 0x030175d5, 0x17106fd5, 0x17116fd5, 1101 0x030076d6, 0x030176d6, 0x131070d6, 0x131170d6, 1102 0x070077d7, 0x070177d7, 0x171071d7, 0x171171d7, 1103 0x070078d8, 0x070178d8, 0x171072d8, 0x171172d8, 1104 0x030079d9, 0x030179d9, 0x131073d9, 0x131173d9, 1105 0x170074da, 0x170174da, 0x171074da, 0x171174da, 1106 0x130075db, 0x130175db, 0x131075db, 0x131175db, 1107 0x130076dc, 0x130176dc, 0x131076dc, 0x131176dc, 1108 0x170077dd, 0x170177dd, 0x171077dd, 0x171177dd, 1109 0x170078de, 0x170178de, 0x171078de, 0x171178de, 1110 0x130079df, 0x130179df, 0x131079df, 0x131179df, 1111 0x830080e0, 0x830180e0, 0x13107ae0, 0x13117ae0, 1112 0x870081e1, 0x870181e1, 0x17107be1, 0x17117be1, 1113 0x870082e2, 0x870182e2, 0x13107ce2, 0x13117ce2, 1114 0x830083e3, 0x830183e3, 0x17107de3, 0x17117de3, 1115 0x870084e4, 0x870184e4, 0x17107ee4, 0x17117ee4, 1116 0x830085e5, 0x830185e5, 0x13107fe5, 0x13117fe5, 1117 0x830086e6, 0x830186e6, 0x931080e6, 0x931180e6, 1118 0x870087e7, 0x870187e7, 0x971081e7, 0x971181e7, 1119 0x870088e8, 0x870188e8, 0x971082e8, 0x971182e8, 1120 0x830089e9, 0x830189e9, 0x931083e9, 0x931183e9, 1121 0x970084ea, 0x970184ea, 0x971084ea, 0x971184ea, 1122 0x930085eb, 0x930185eb, 0x931085eb, 0x931185eb, 1123 0x930086ec, 0x930186ec, 0x931086ec, 0x931186ec, 1124 0x970087ed, 0x970187ed, 0x971087ed, 0x971187ed, 1125 0x970088ee, 0x970188ee, 0x971088ee, 0x971188ee, 1126 0x930089ef, 0x930189ef, 0x931089ef, 0x931189ef, 1127 0x870090f0, 0x870190f0, 0x93108af0, 0x93118af0, 1128 0x830091f1, 0x830191f1, 0x97108bf1, 0x97118bf1, 1129 0x830092f2, 0x830192f2, 0x93108cf2, 0x93118cf2, 1130 0x870093f3, 0x870193f3, 0x97108df3, 0x97118df3, 1131 0x830094f4, 0x830194f4, 0x97108ef4, 0x97118ef4, 1132 0x870095f5, 0x870195f5, 0x93108ff5, 0x93118ff5, 1133 0x870096f6, 0x870196f6, 0x971090f6, 0x971190f6, 1134 0x830097f7, 0x830197f7, 0x931091f7, 0x931191f7, 1135 0x830098f8, 0x830198f8, 0x931092f8, 0x931192f8, 1136 0x870099f9, 0x870199f9, 0x971093f9, 0x971193f9, 1137 0x930094fa, 0x930194fa, 0x931094fa, 0x931194fa, 1138 0x970095fb, 0x970195fb, 0x971095fb, 0x971195fb, 1139 0x970096fc, 0x970196fc, 0x971096fc, 0x971196fc, 1140 0x930097fd, 0x930197fd, 0x931097fd, 0x931197fd, 1141 0x930098fe, 0x930198fe, 0x931098fe, 0x931198fe, 1142 0x970099ff, 0x970199ff, 0x971099ff, 0x971199ff, 1143 }; 1144 1145 MK_INSN(das, "das"); 1146 1147 inregs = (struct regs){ 0 }; 1148 1149 for (i = 0; i < 1024; ++i) { 1150 unsigned tmp = test_cases[i]; 1151 inregs.eax = tmp & 0xff; 1152 inregs.eflags = (tmp >> 16) & 0xff; 1153 exec_in_big_real_mode(&insn_das); 1154 if (!regs_equal(R_AX) 1155 || outregs.eax != ((tmp >> 8) & 0xff) 1156 || (outregs.eflags & 0xff) != (tmp >> 24)) { 1157 ++nr_fail; 1158 break; 1159 } 1160 } 1161 report("DAS", ~0, nr_fail == 0); 1162 } 1163 1164 void test_cwd_cdq() 1165 { 1166 /* Sign-bit set */ 1167 MK_INSN(cwd_1, "mov $0x8000, %ax\n\t" 1168 "cwd\n\t"); 1169 1170 /* Sign-bit not set */ 1171 MK_INSN(cwd_2, "mov $0x1000, %ax\n\t" 1172 "cwd\n\t"); 1173 1174 /* Sign-bit set */ 1175 MK_INSN(cdq_1, "mov $0x80000000, %eax\n\t" 1176 "cdq\n\t"); 1177 1178 /* Sign-bit not set */ 1179 MK_INSN(cdq_2, "mov $0x10000000, %eax\n\t" 1180 "cdq\n\t"); 1181 1182 inregs = (struct regs){ 0 }; 1183 1184 exec_in_big_real_mode(&insn_cwd_1); 1185 report("cwd 1", R_AX | R_DX, 1186 outregs.eax == 0x8000 && outregs.edx == 0xffff); 1187 1188 exec_in_big_real_mode(&insn_cwd_2); 1189 report("cwd 2", R_AX | R_DX, 1190 outregs.eax == 0x1000 && outregs.edx == 0); 1191 1192 exec_in_big_real_mode(&insn_cdq_1); 1193 report("cdq 1", R_AX | R_DX, 1194 outregs.eax == 0x80000000 && outregs.edx == 0xffffffff); 1195 1196 exec_in_big_real_mode(&insn_cdq_2); 1197 report("cdq 2", R_AX | R_DX, 1198 outregs.eax == 0x10000000 && outregs.edx == 0); 1199 } 1200 1201 static struct { 1202 void *address; 1203 unsigned short sel; 1204 } __attribute__((packed)) desc = { 1205 (void *)0x1234, 1206 0x10, 1207 }; 1208 1209 void test_lds_lss() 1210 { 1211 inregs = (struct regs){ .ebx = (unsigned long)&desc }; 1212 1213 MK_INSN(lds, "push %ds\n\t" 1214 "lds (%ebx), %eax\n\t" 1215 "mov %ds, %ebx\n\t" 1216 "pop %ds\n\t"); 1217 exec_in_big_real_mode(&insn_lds); 1218 report("lds", R_AX | R_BX, 1219 outregs.eax == (unsigned long)desc.address && 1220 outregs.ebx == desc.sel); 1221 1222 MK_INSN(les, "push %es\n\t" 1223 "les (%ebx), %eax\n\t" 1224 "mov %es, %ebx\n\t" 1225 "pop %es\n\t"); 1226 exec_in_big_real_mode(&insn_les); 1227 report("les", R_AX | R_BX, 1228 outregs.eax == (unsigned long)desc.address && 1229 outregs.ebx == desc.sel); 1230 1231 MK_INSN(lfs, "push %fs\n\t" 1232 "lfs (%ebx), %eax\n\t" 1233 "mov %fs, %ebx\n\t" 1234 "pop %fs\n\t"); 1235 exec_in_big_real_mode(&insn_lfs); 1236 report("lfs", R_AX | R_BX, 1237 outregs.eax == (unsigned long)desc.address && 1238 outregs.ebx == desc.sel); 1239 1240 MK_INSN(lgs, "push %gs\n\t" 1241 "lgs (%ebx), %eax\n\t" 1242 "mov %gs, %ebx\n\t" 1243 "pop %gs\n\t"); 1244 exec_in_big_real_mode(&insn_lgs); 1245 report("lgs", R_AX | R_BX, 1246 outregs.eax == (unsigned long)desc.address && 1247 outregs.ebx == desc.sel); 1248 1249 MK_INSN(lss, "push %ss\n\t" 1250 "lss (%ebx), %eax\n\t" 1251 "mov %ss, %ebx\n\t" 1252 "pop %ss\n\t"); 1253 exec_in_big_real_mode(&insn_lss); 1254 report("lss", R_AX | R_BX, 1255 outregs.eax == (unsigned long)desc.address && 1256 outregs.ebx == desc.sel); 1257 } 1258 1259 void test_jcxz(void) 1260 { 1261 MK_INSN(jcxz1, "jcxz 1f\n\t" 1262 "mov $0x1234, %eax\n\t" 1263 "1:\n\t"); 1264 MK_INSN(jcxz2, "mov $0x100, %ecx\n\t" 1265 "jcxz 1f\n\t" 1266 "mov $0x1234, %eax\n\t" 1267 "mov $0, %ecx\n\t" 1268 "1:\n\t"); 1269 MK_INSN(jcxz3, "mov $0x10000, %ecx\n\t" 1270 "jcxz 1f\n\t" 1271 "mov $0x1234, %eax\n\t" 1272 "1:\n\t"); 1273 MK_INSN(jecxz1, "jecxz 1f\n\t" 1274 "mov $0x1234, %eax\n\t" 1275 "1:\n\t"); 1276 MK_INSN(jecxz2, "mov $0x10000, %ecx\n\t" 1277 "jecxz 1f\n\t" 1278 "mov $0x1234, %eax\n\t" 1279 "mov $0, %ecx\n\t" 1280 "1:\n\t"); 1281 1282 inregs = (struct regs){ 0 }; 1283 1284 exec_in_big_real_mode(&insn_jcxz1); 1285 report("jcxz short 1", 0, 1); 1286 1287 exec_in_big_real_mode(&insn_jcxz2); 1288 report("jcxz short 2", R_AX, outregs.eax == 0x1234); 1289 1290 exec_in_big_real_mode(&insn_jcxz3); 1291 report("jcxz short 3", R_CX, outregs.ecx == 0x10000); 1292 1293 exec_in_big_real_mode(&insn_jecxz1); 1294 report("jecxz short 1", 0, 1); 1295 1296 exec_in_big_real_mode(&insn_jecxz2); 1297 report("jecxz short 2", R_AX, outregs.eax == 0x1234); 1298 } 1299 1300 static void test_cpuid(void) 1301 { 1302 MK_INSN(cpuid, "cpuid"); 1303 unsigned function = 0x1234; 1304 unsigned eax, ebx, ecx, edx; 1305 1306 inregs.eax = eax = function; 1307 asm("cpuid" : "+a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)); 1308 exec_in_big_real_mode(&insn_cpuid); 1309 report("cpuid", R_AX|R_BX|R_CX|R_DX, 1310 outregs.eax == eax && outregs.ebx == ebx 1311 && outregs.ecx == ecx && outregs.edx == edx); 1312 } 1313 1314 static void test_ss_base_for_esp_ebp(void) 1315 { 1316 MK_INSN(ssrel1, "mov %ss, %ax; mov %bx, %ss; movl (%ebp), %ebx; mov %ax, %ss"); 1317 MK_INSN(ssrel2, "mov %ss, %ax; mov %bx, %ss; movl (%ebp,%edi,8), %ebx; mov %ax, %ss"); 1318 static unsigned array[] = { 0x12345678, 0, 0, 0, 0x87654321 }; 1319 1320 inregs.ebx = 1; 1321 inregs.ebp = (unsigned)array; 1322 exec_in_big_real_mode(&insn_ssrel1); 1323 report("ss relative addressing (1)", R_AX | R_BX, outregs.ebx == 0x87654321); 1324 inregs.ebx = 1; 1325 inregs.ebp = (unsigned)array; 1326 inregs.edi = 0; 1327 exec_in_big_real_mode(&insn_ssrel2); 1328 report("ss relative addressing (2)", R_AX | R_BX, outregs.ebx == 0x87654321); 1329 } 1330 1331 static void test_sgdt_sidt(void) 1332 { 1333 MK_INSN(sgdt, "sgdtw (%eax)"); 1334 MK_INSN(sidt, "sidtw (%eax)"); 1335 unsigned x, y; 1336 1337 inregs.eax = (unsigned)&y; 1338 asm volatile("sgdtw %0" : "=m"(x)); 1339 exec_in_big_real_mode(&insn_sgdt); 1340 report("sgdt", 0, x == y); 1341 1342 inregs.eax = (unsigned)&y; 1343 asm volatile("sidtw %0" : "=m"(x)); 1344 exec_in_big_real_mode(&insn_sidt); 1345 report("sidt", 0, x == y); 1346 } 1347 1348 static void test_lahf(void) 1349 { 1350 MK_INSN(lahf, "pushfw; mov %al, (%esp); popfw; lahf"); 1351 1352 inregs.eax = 0xc7; 1353 exec_in_big_real_mode(&insn_lahf); 1354 report("lahf", R_AX, (outregs.eax >> 8) == inregs.eax); 1355 } 1356 1357 static void test_movzx_movsx(void) 1358 { 1359 MK_INSN(movsx, "movsx %al, %ebx"); 1360 MK_INSN(movzx, "movzx %al, %ebx"); 1361 1362 inregs.eax = 0x1234569c; 1363 exec_in_big_real_mode(&insn_movsx); 1364 report("movsx", R_BX, outregs.ebx == (signed char)inregs.eax); 1365 exec_in_big_real_mode(&insn_movzx); 1366 report("movzx", R_BX, outregs.ebx == (unsigned char)inregs.eax); 1367 } 1368 1369 static void test_bswap(void) 1370 { 1371 MK_INSN(bswap, "bswap %ecx"); 1372 1373 inregs.ecx = 0x12345678; 1374 exec_in_big_real_mode(&insn_bswap); 1375 report("bswap", R_CX, outregs.ecx == 0x78563412); 1376 } 1377 1378 static void test_aad(void) 1379 { 1380 MK_INSN(aad, "aad"); 1381 1382 inregs.eax = 0x12345678; 1383 exec_in_big_real_mode(&insn_aad); 1384 report("aad", R_AX, outregs.eax == 0x123400d4); 1385 } 1386 1387 static void test_fninit(void) 1388 { 1389 u16 fcw = -1, fsw = -1; 1390 MK_INSN(fninit, "fninit ; fnstsw (%eax) ; fnstcw (%ebx)"); 1391 1392 inregs.eax = (u32)&fsw; 1393 inregs.ebx = (u32)&fcw; 1394 1395 exec_in_big_real_mode(&insn_fninit); 1396 report("fninit", 0, fsw == 0 && (fcw & 0x103f) == 0x003f); 1397 } 1398 1399 void realmode_start(void) 1400 { 1401 test_null(); 1402 1403 test_shld(); 1404 test_push_pop(); 1405 test_pusha_popa(); 1406 test_mov_imm(); 1407 test_cmp_imm(); 1408 test_add_imm(); 1409 test_sub_imm(); 1410 test_xor_imm(); 1411 test_io(); 1412 test_eflags_insn(); 1413 test_jcc_short(); 1414 test_jcc_near(); 1415 /* test_call() uses short jump so call it after testing jcc */ 1416 test_call(); 1417 /* long jmp test uses call near so test it after testing call */ 1418 test_long_jmp(); 1419 test_xchg(); 1420 test_iret(); 1421 test_int(); 1422 test_imul(); 1423 test_mul(); 1424 test_div(); 1425 test_idiv(); 1426 test_loopcc(); 1427 test_cbw(); 1428 test_cwd_cdq(); 1429 test_das(); 1430 test_lds_lss(); 1431 test_jcxz(); 1432 test_cpuid(); 1433 test_ss_base_for_esp_ebp(); 1434 test_sgdt_sidt(); 1435 test_lahf(); 1436 test_movzx_movsx(); 1437 test_bswap(); 1438 test_aad(); 1439 test_fninit(); 1440 1441 exit(0); 1442 } 1443 1444 unsigned long long r_gdt[] = { 0, 0x9b000000ffff, 0x93000000ffff }; 1445 1446 struct __attribute__((packed)) { 1447 unsigned short limit; 1448 void *base; 1449 } r_gdt_descr = { sizeof(r_gdt) - 1, &r_gdt }; 1450 1451 asm( 1452 ".section .init \n\t" 1453 1454 ".code32 \n\t" 1455 1456 "mb_magic = 0x1BADB002 \n\t" 1457 "mb_flags = 0x0 \n\t" 1458 1459 "# multiboot header \n\t" 1460 ".long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) \n\t" 1461 1462 ".globl start \n\t" 1463 ".data \n\t" 1464 ". = . + 4096 \n\t" 1465 "stacktop: \n\t" 1466 1467 ".text \n\t" 1468 "start: \n\t" 1469 "lgdt r_gdt_descr \n\t" 1470 "ljmp $8, $1f; 1: \n\t" 1471 ".code16gcc \n\t" 1472 "mov $16, %eax \n\t" 1473 "mov %ax, %ds \n\t" 1474 "mov %ax, %es \n\t" 1475 "mov %ax, %fs \n\t" 1476 "mov %ax, %gs \n\t" 1477 "mov %ax, %ss \n\t" 1478 "mov %cr0, %eax \n\t" 1479 "btc $0, %eax \n\t" 1480 "mov %eax, %cr0 \n\t" 1481 "ljmp $0, $realmode_entry \n\t" 1482 1483 "realmode_entry: \n\t" 1484 1485 "xor %ax, %ax \n\t" 1486 "mov %ax, %ds \n\t" 1487 "mov %ax, %es \n\t" 1488 "mov %ax, %ss \n\t" 1489 "mov %ax, %fs \n\t" 1490 "mov %ax, %gs \n\t" 1491 "mov $stacktop, %esp\n\t" 1492 "ljmp $0, $realmode_start \n\t" 1493 1494 ".code16gcc \n\t" 1495 ); 1496