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