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