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