17d36db35SAvi Kivity asm(".code16gcc"); 27d36db35SAvi Kivity 37d36db35SAvi Kivity typedef unsigned char u8; 47d36db35SAvi Kivity typedef unsigned short u16; 57d36db35SAvi Kivity typedef unsigned u32; 67d36db35SAvi Kivity typedef unsigned long long u64; 77d36db35SAvi Kivity 87d36db35SAvi Kivity void test_function(void); 97d36db35SAvi Kivity 107d36db35SAvi Kivity asm( 117d36db35SAvi Kivity "test_function: \n\t" 127d36db35SAvi Kivity "mov $0x1234, %eax \n\t" 137d36db35SAvi Kivity "ret" 147d36db35SAvi Kivity ); 157d36db35SAvi Kivity 167d36db35SAvi Kivity static int strlen(const char *str) 177d36db35SAvi Kivity { 187d36db35SAvi Kivity int n; 197d36db35SAvi Kivity 207d36db35SAvi Kivity for (n = 0; *str; ++str) 217d36db35SAvi Kivity ++n; 227d36db35SAvi Kivity return n; 237d36db35SAvi Kivity } 247d36db35SAvi Kivity 257d36db35SAvi Kivity static void print_serial(const char *buf) 267d36db35SAvi Kivity { 277d36db35SAvi Kivity unsigned long len = strlen(buf); 287d36db35SAvi Kivity 297d36db35SAvi Kivity asm volatile ("cld; addr32/rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1)); 307d36db35SAvi Kivity } 317d36db35SAvi Kivity 327d36db35SAvi Kivity static void exit(int code) 337d36db35SAvi Kivity { 347d36db35SAvi Kivity asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4)); 357d36db35SAvi Kivity } 367d36db35SAvi Kivity 377d36db35SAvi Kivity struct regs { 387d36db35SAvi Kivity u32 eax, ebx, ecx, edx; 397d36db35SAvi Kivity u32 esi, edi, esp, ebp; 407d36db35SAvi Kivity u32 eip, eflags; 417d36db35SAvi Kivity }; 427d36db35SAvi Kivity 437d36db35SAvi Kivity static u64 gdt[] = { 447d36db35SAvi Kivity 0, 457d36db35SAvi Kivity 0x00cf9b000000ffffull, // flat 32-bit code segment 467d36db35SAvi Kivity 0x00cf93000000ffffull, // flat 32-bit data segment 477d36db35SAvi Kivity }; 487d36db35SAvi Kivity 497d36db35SAvi Kivity static struct { 507d36db35SAvi Kivity u16 limit; 517d36db35SAvi Kivity void *base; 527d36db35SAvi Kivity } __attribute__((packed)) gdt_descr = { 537d36db35SAvi Kivity sizeof(gdt) - 1, 547d36db35SAvi Kivity gdt, 557d36db35SAvi Kivity }; 567d36db35SAvi Kivity 577d36db35SAvi Kivity static void exec_in_big_real_mode(const struct regs *inregs, 587d36db35SAvi Kivity struct regs *outregs, 597d36db35SAvi Kivity const u8 *insn, int insn_len) 607d36db35SAvi Kivity { 617d36db35SAvi Kivity unsigned long tmp; 627d36db35SAvi Kivity static struct regs save; 637d36db35SAvi Kivity int i; 647d36db35SAvi Kivity extern u8 test_insn[], test_insn_end[]; 657d36db35SAvi Kivity 667d36db35SAvi Kivity for (i = 0; i < insn_len; ++i) 677d36db35SAvi Kivity test_insn[i] = insn[i]; 687d36db35SAvi Kivity for (; i < test_insn_end - test_insn; ++i) 697d36db35SAvi Kivity test_insn[i] = 0x90; // nop 707d36db35SAvi Kivity 717d36db35SAvi Kivity save = *inregs; 727d36db35SAvi Kivity asm volatile( 737d36db35SAvi Kivity "lgdtl %[gdt_descr] \n\t" 747d36db35SAvi Kivity "mov %%cr0, %[tmp] \n\t" 757d36db35SAvi Kivity "or $1, %[tmp] \n\t" 767d36db35SAvi Kivity "mov %[tmp], %%cr0 \n\t" 777d36db35SAvi Kivity "mov %[bigseg], %%gs \n\t" 787d36db35SAvi Kivity "and $-2, %[tmp] \n\t" 797d36db35SAvi Kivity "mov %[tmp], %%cr0 \n\t" 807d36db35SAvi Kivity 817d36db35SAvi Kivity "xchg %%eax, %[save]+0 \n\t" 827d36db35SAvi Kivity "xchg %%ebx, %[save]+4 \n\t" 837d36db35SAvi Kivity "xchg %%ecx, %[save]+8 \n\t" 847d36db35SAvi Kivity "xchg %%edx, %[save]+12 \n\t" 857d36db35SAvi Kivity "xchg %%esi, %[save]+16 \n\t" 867d36db35SAvi Kivity "xchg %%edi, %[save]+20 \n\t" 877d36db35SAvi Kivity "xchg %%esp, %[save]+24 \n\t" 887d36db35SAvi Kivity "xchg %%ebp, %[save]+28 \n\t" 897d36db35SAvi Kivity 907d36db35SAvi Kivity "test_insn: . = . + 32\n\t" 917d36db35SAvi Kivity "test_insn_end: \n\t" 927d36db35SAvi Kivity 937d36db35SAvi Kivity "xchg %%eax, %[save]+0 \n\t" 947d36db35SAvi Kivity "xchg %%ebx, %[save]+4 \n\t" 957d36db35SAvi Kivity "xchg %%ecx, %[save]+8 \n\t" 967d36db35SAvi Kivity "xchg %%edx, %[save]+12 \n\t" 977d36db35SAvi Kivity "xchg %%esi, %[save]+16 \n\t" 987d36db35SAvi Kivity "xchg %%edi, %[save]+20 \n\t" 997d36db35SAvi Kivity "xchg %%esp, %[save]+24 \n\t" 1007d36db35SAvi Kivity "xchg %%ebp, %[save]+28 \n\t" 1017d36db35SAvi Kivity 1027d36db35SAvi Kivity /* Save EFLAGS in outregs*/ 1037d36db35SAvi Kivity "pushfl \n\t" 1047d36db35SAvi Kivity "popl %[save]+36 \n\t" 1057d36db35SAvi Kivity 1067d36db35SAvi Kivity "xor %[tmp], %[tmp] \n\t" 1077d36db35SAvi Kivity "mov %[tmp], %%gs \n\t" 1087d36db35SAvi Kivity : [tmp]"=&r"(tmp), [save]"+m"(save) 1097d36db35SAvi Kivity : [gdt_descr]"m"(gdt_descr), [bigseg]"r"((short)16) 1107d36db35SAvi Kivity : "cc", "memory" 1117d36db35SAvi Kivity ); 1127d36db35SAvi Kivity *outregs = save; 1137d36db35SAvi Kivity } 1147d36db35SAvi Kivity 1157d36db35SAvi Kivity #define R_AX 1 1167d36db35SAvi Kivity #define R_BX 2 1177d36db35SAvi Kivity #define R_CX 4 1187d36db35SAvi Kivity #define R_DX 8 1197d36db35SAvi Kivity #define R_SI 16 1207d36db35SAvi Kivity #define R_DI 32 1217d36db35SAvi Kivity #define R_SP 64 1227d36db35SAvi Kivity #define R_BP 128 1237d36db35SAvi Kivity 1247d36db35SAvi Kivity int regs_equal(const struct regs *r1, const struct regs *r2, int ignore) 1257d36db35SAvi Kivity { 1267d36db35SAvi Kivity const u32 *p1 = &r1->eax, *p2 = &r2->eax; // yuck 1277d36db35SAvi Kivity int i; 1287d36db35SAvi Kivity 1297d36db35SAvi Kivity for (i = 0; i < 8; ++i) 1307d36db35SAvi Kivity if (!(ignore & (1 << i)) && p1[i] != p2[i]) 1317d36db35SAvi Kivity return 0; 1327d36db35SAvi Kivity return 1; 1337d36db35SAvi Kivity } 1347d36db35SAvi Kivity 1357d36db35SAvi Kivity #define MK_INSN(name, str) \ 1367d36db35SAvi Kivity asm ( \ 1377d36db35SAvi Kivity ".text 1\n\t" \ 1387d36db35SAvi Kivity "insn_" #name ": " str " \n\t" \ 1397d36db35SAvi Kivity "insn_" #name "_end: \n\t" \ 1407d36db35SAvi Kivity ".text\n\t" \ 1417d36db35SAvi Kivity ); \ 1427d36db35SAvi Kivity extern u8 insn_##name[], insn_##name##_end[] 1437d36db35SAvi Kivity 1447d36db35SAvi Kivity void test_xchg(void) 1457d36db35SAvi Kivity { 1467d36db35SAvi Kivity struct regs inregs = { .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = 7}, outregs; 1477d36db35SAvi Kivity 1487d36db35SAvi Kivity MK_INSN(xchg_test1, "xchg %eax,%eax\n\t"); 1497d36db35SAvi Kivity MK_INSN(xchg_test2, "xchg %eax,%ebx\n\t"); 1507d36db35SAvi Kivity MK_INSN(xchg_test3, "xchg %eax,%ecx\n\t"); 1517d36db35SAvi Kivity MK_INSN(xchg_test4, "xchg %eax,%edx\n\t"); 1527d36db35SAvi Kivity MK_INSN(xchg_test5, "xchg %eax,%esi\n\t"); 1537d36db35SAvi Kivity MK_INSN(xchg_test6, "xchg %eax,%edi\n\t"); 1547d36db35SAvi Kivity MK_INSN(xchg_test7, "xchg %eax,%ebp\n\t"); 1557d36db35SAvi Kivity MK_INSN(xchg_test8, "xchg %eax,%esp\n\t"); 1567d36db35SAvi Kivity 1577d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 1587d36db35SAvi Kivity insn_xchg_test1, 1597d36db35SAvi Kivity insn_xchg_test1_end - insn_xchg_test1); 1607d36db35SAvi Kivity 1617d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 1627d36db35SAvi Kivity print_serial("xchg test 1: FAIL\n"); 1637d36db35SAvi Kivity else 1647d36db35SAvi Kivity print_serial("xchg test 1: PASS\n"); 1657d36db35SAvi Kivity 1667d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 1677d36db35SAvi Kivity insn_xchg_test2, 1687d36db35SAvi Kivity insn_xchg_test2_end - insn_xchg_test2); 1697d36db35SAvi Kivity 1707d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_BX) || 1717d36db35SAvi Kivity outregs.eax != inregs.ebx || 1727d36db35SAvi Kivity outregs.ebx != inregs.eax) 1737d36db35SAvi Kivity print_serial("xchg test 2: FAIL\n"); 1747d36db35SAvi Kivity else 1757d36db35SAvi Kivity print_serial("xchg test 2: PASS\n"); 1767d36db35SAvi Kivity 1777d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 1787d36db35SAvi Kivity insn_xchg_test3, 1797d36db35SAvi Kivity insn_xchg_test3_end - insn_xchg_test3); 1807d36db35SAvi Kivity 1817d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_CX) || 1827d36db35SAvi Kivity outregs.eax != inregs.ecx || 1837d36db35SAvi Kivity outregs.ecx != inregs.eax) 1847d36db35SAvi Kivity print_serial("xchg test 3: FAIL\n"); 1857d36db35SAvi Kivity else 1867d36db35SAvi Kivity print_serial("xchg test 3: PASS\n"); 1877d36db35SAvi Kivity 1887d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 1897d36db35SAvi Kivity insn_xchg_test4, 1907d36db35SAvi Kivity insn_xchg_test4_end - insn_xchg_test4); 1917d36db35SAvi Kivity 1927d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_DX) || 1937d36db35SAvi Kivity outregs.eax != inregs.edx || 1947d36db35SAvi Kivity outregs.edx != inregs.eax) 1957d36db35SAvi Kivity print_serial("xchg test 4: FAIL\n"); 1967d36db35SAvi Kivity else 1977d36db35SAvi Kivity print_serial("xchg test 4: PASS\n"); 1987d36db35SAvi Kivity 1997d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2007d36db35SAvi Kivity insn_xchg_test5, 2017d36db35SAvi Kivity insn_xchg_test5_end - insn_xchg_test5); 2027d36db35SAvi Kivity 2037d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_SI) || 2047d36db35SAvi Kivity outregs.eax != inregs.esi || 2057d36db35SAvi Kivity outregs.esi != inregs.eax) 2067d36db35SAvi Kivity print_serial("xchg test 5: FAIL\n"); 2077d36db35SAvi Kivity else 2087d36db35SAvi Kivity print_serial("xchg test 5: PASS\n"); 2097d36db35SAvi Kivity 2107d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2117d36db35SAvi Kivity insn_xchg_test6, 2127d36db35SAvi Kivity insn_xchg_test6_end - insn_xchg_test6); 2137d36db35SAvi Kivity 2147d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_DI) || 2157d36db35SAvi Kivity outregs.eax != inregs.edi || 2167d36db35SAvi Kivity outregs.edi != inregs.eax) 2177d36db35SAvi Kivity print_serial("xchg test 6: FAIL\n"); 2187d36db35SAvi Kivity else 2197d36db35SAvi Kivity print_serial("xchg test 6: PASS\n"); 2207d36db35SAvi Kivity 2217d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2227d36db35SAvi Kivity insn_xchg_test7, 2237d36db35SAvi Kivity insn_xchg_test7_end - insn_xchg_test7); 2247d36db35SAvi Kivity 2257d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_BP) || 2267d36db35SAvi Kivity outregs.eax != inregs.ebp || 2277d36db35SAvi Kivity outregs.ebp != inregs.eax) 2287d36db35SAvi Kivity print_serial("xchg test 7: FAIL\n"); 2297d36db35SAvi Kivity else 2307d36db35SAvi Kivity print_serial("xchg test 7: PASS\n"); 2317d36db35SAvi Kivity 2327d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2337d36db35SAvi Kivity insn_xchg_test8, 2347d36db35SAvi Kivity insn_xchg_test8_end - insn_xchg_test8); 2357d36db35SAvi Kivity 2367d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_SP) || 2377d36db35SAvi Kivity outregs.eax != inregs.esp || 2387d36db35SAvi Kivity outregs.esp != inregs.eax) 2397d36db35SAvi Kivity print_serial("xchg test 8: FAIL\n"); 2407d36db35SAvi Kivity else 2417d36db35SAvi Kivity print_serial("xchg test 8: PASS\n"); 2427d36db35SAvi Kivity } 2437d36db35SAvi Kivity 2447d36db35SAvi Kivity void test_shld(void) 2457d36db35SAvi Kivity { 2467d36db35SAvi Kivity struct regs inregs = { .eax = 0xbe, .edx = 0xef000000 }, outregs; 2477d36db35SAvi Kivity MK_INSN(shld_test, "shld $8,%edx,%eax\n\t"); 2487d36db35SAvi Kivity 2497d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2507d36db35SAvi Kivity insn_shld_test, 2517d36db35SAvi Kivity insn_shld_test_end - insn_shld_test); 2527d36db35SAvi Kivity if (outregs.eax != 0xbeef) 2537d36db35SAvi Kivity print_serial("shld: FAIL\n"); 2547d36db35SAvi Kivity else 2557d36db35SAvi Kivity print_serial("shld: PASS\n"); 2567d36db35SAvi Kivity } 2577d36db35SAvi Kivity 2587d36db35SAvi Kivity void test_mov_imm(void) 2597d36db35SAvi Kivity { 2607d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 2617d36db35SAvi Kivity MK_INSN(mov_r32_imm_1, "mov $1234567890, %eax"); 2627d36db35SAvi Kivity MK_INSN(mov_r16_imm_1, "mov $1234, %ax"); 2637d36db35SAvi Kivity MK_INSN(mov_r8_imm_1, "mov $0x12, %ah"); 2647d36db35SAvi Kivity MK_INSN(mov_r8_imm_2, "mov $0x34, %al"); 2657d36db35SAvi Kivity MK_INSN(mov_r8_imm_3, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t"); 2667d36db35SAvi Kivity 2677d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2687d36db35SAvi Kivity insn_mov_r16_imm_1, 2697d36db35SAvi Kivity insn_mov_r16_imm_1_end - insn_mov_r16_imm_1); 2707d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234) 2717d36db35SAvi Kivity print_serial("mov test 1: FAIL\n"); 2727d36db35SAvi Kivity else 2737d36db35SAvi Kivity print_serial("mov test 1: PASS\n"); 2747d36db35SAvi Kivity 2757d36db35SAvi Kivity /* test mov $imm, %eax */ 2767d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2777d36db35SAvi Kivity insn_mov_r32_imm_1, 2787d36db35SAvi Kivity insn_mov_r32_imm_1_end - insn_mov_r32_imm_1); 2797d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234567890) 2807d36db35SAvi Kivity print_serial("mov test 2: FAIL\n"); 2817d36db35SAvi Kivity else 2827d36db35SAvi Kivity print_serial("mov test 2: PASS\n"); 2837d36db35SAvi Kivity 2847d36db35SAvi Kivity /* test mov $imm, %al/%ah */ 2857d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2867d36db35SAvi Kivity insn_mov_r8_imm_1, 2877d36db35SAvi Kivity insn_mov_r8_imm_1_end - insn_mov_r8_imm_1); 2887d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1200) 2897d36db35SAvi Kivity print_serial("mov test 3: FAIL\n"); 2907d36db35SAvi Kivity else 2917d36db35SAvi Kivity print_serial("mov test 3: PASS\n"); 2927d36db35SAvi Kivity 2937d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2947d36db35SAvi Kivity insn_mov_r8_imm_2, 2957d36db35SAvi Kivity insn_mov_r8_imm_2_end - insn_mov_r8_imm_2); 2967d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x34) 2977d36db35SAvi Kivity print_serial("mov test 4: FAIL\n"); 2987d36db35SAvi Kivity else 2997d36db35SAvi Kivity print_serial("mov test 4: PASS\n"); 3007d36db35SAvi Kivity 3017d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3027d36db35SAvi Kivity insn_mov_r8_imm_3, 3037d36db35SAvi Kivity insn_mov_r8_imm_3_end - insn_mov_r8_imm_3); 3047d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 3057d36db35SAvi Kivity print_serial("mov test 5: FAIL\n"); 3067d36db35SAvi Kivity else 3077d36db35SAvi Kivity print_serial("mov test 5: PASS\n"); 3087d36db35SAvi Kivity } 3097d36db35SAvi Kivity 3107d36db35SAvi Kivity void test_sub_imm(void) 3117d36db35SAvi Kivity { 3127d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 3137d36db35SAvi Kivity MK_INSN(sub_r32_imm_1, "mov $1234567890, %eax\n\t" "sub $10, %eax\n\t"); 3147d36db35SAvi Kivity MK_INSN(sub_r16_imm_1, "mov $1234, %ax\n\t" "sub $10, %ax\n\t"); 3157d36db35SAvi Kivity MK_INSN(sub_r8_imm_1, "mov $0x12, %ah\n\t" "sub $0x10, %ah\n\t"); 3167d36db35SAvi Kivity MK_INSN(sub_r8_imm_2, "mov $0x34, %al\n\t" "sub $0x10, %al\n\t"); 3177d36db35SAvi Kivity 3187d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3197d36db35SAvi Kivity insn_sub_r16_imm_1, 3207d36db35SAvi Kivity insn_sub_r16_imm_1_end - insn_sub_r16_imm_1); 3217d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1224) 3227d36db35SAvi Kivity print_serial("sub test 1: FAIL\n"); 3237d36db35SAvi Kivity else 3247d36db35SAvi Kivity print_serial("sub test 1: PASS\n"); 3257d36db35SAvi Kivity 3267d36db35SAvi Kivity /* test mov $imm, %eax */ 3277d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3287d36db35SAvi Kivity insn_sub_r32_imm_1, 3297d36db35SAvi Kivity insn_sub_r32_imm_1_end - insn_sub_r32_imm_1); 3307d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234567880) 3317d36db35SAvi Kivity print_serial("sub test 2: FAIL\n"); 3327d36db35SAvi Kivity else 3337d36db35SAvi Kivity print_serial("sub test 2: PASS\n"); 3347d36db35SAvi Kivity 3357d36db35SAvi Kivity /* test mov $imm, %al/%ah */ 3367d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3377d36db35SAvi Kivity insn_sub_r8_imm_1, 3387d36db35SAvi Kivity insn_sub_r8_imm_1_end - insn_sub_r8_imm_1); 3397d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x0200) 3407d36db35SAvi Kivity print_serial("sub test 3: FAIL\n"); 3417d36db35SAvi Kivity else 3427d36db35SAvi Kivity print_serial("sub test 3: PASS\n"); 3437d36db35SAvi Kivity 3447d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3457d36db35SAvi Kivity insn_sub_r8_imm_2, 3467d36db35SAvi Kivity insn_sub_r8_imm_2_end - insn_sub_r8_imm_2); 3477d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x24) 3487d36db35SAvi Kivity print_serial("sub test 4: FAIL\n"); 3497d36db35SAvi Kivity else 3507d36db35SAvi Kivity print_serial("sub test 4: PASS\n"); 3517d36db35SAvi Kivity } 3527d36db35SAvi Kivity 3537d36db35SAvi Kivity 3547d36db35SAvi Kivity void test_xor_imm(void) 3557d36db35SAvi Kivity { 3567d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 3577d36db35SAvi Kivity MK_INSN(xor_r32_imm_1, "mov $1234567890, %eax\n\t" "xor $1234567890, %eax\n\t"); 3587d36db35SAvi Kivity MK_INSN(xor_r16_imm_1, "mov $1234, %ax\n\t" "xor $1234, %ax\n\t"); 3597d36db35SAvi Kivity MK_INSN(xor_r8_imm_1, "mov $0x12, %ah\n\t" "xor $0x12, %ah\n\t"); 3607d36db35SAvi Kivity MK_INSN(xor_r8_imm_2, "mov $0x34, %al\n\t" "xor $0x34, %al\n\t"); 3617d36db35SAvi Kivity 3627d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3637d36db35SAvi Kivity insn_xor_r16_imm_1, 3647d36db35SAvi Kivity insn_xor_r16_imm_1_end - insn_xor_r16_imm_1); 3657d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 3667d36db35SAvi Kivity print_serial("xor test 1: FAIL\n"); 3677d36db35SAvi Kivity else 3687d36db35SAvi Kivity print_serial("xor test 1: PASS\n"); 3697d36db35SAvi Kivity 3707d36db35SAvi Kivity /* test mov $imm, %eax */ 3717d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3727d36db35SAvi Kivity insn_xor_r32_imm_1, 3737d36db35SAvi Kivity insn_xor_r32_imm_1_end - insn_xor_r32_imm_1); 3747d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 3757d36db35SAvi Kivity print_serial("xor test 2: FAIL\n"); 3767d36db35SAvi Kivity else 3777d36db35SAvi Kivity print_serial("xor test 2: PASS\n"); 3787d36db35SAvi Kivity 3797d36db35SAvi Kivity /* test mov $imm, %al/%ah */ 3807d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3817d36db35SAvi Kivity insn_xor_r8_imm_1, 3827d36db35SAvi Kivity insn_xor_r8_imm_1_end - insn_xor_r8_imm_1); 3837d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 3847d36db35SAvi Kivity print_serial("xor test 3: FAIL\n"); 3857d36db35SAvi Kivity else 3867d36db35SAvi Kivity print_serial("xor test 3: PASS\n"); 3877d36db35SAvi Kivity 3887d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3897d36db35SAvi Kivity insn_xor_r8_imm_2, 3907d36db35SAvi Kivity insn_xor_r8_imm_2_end - insn_xor_r8_imm_2); 3917d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 3927d36db35SAvi Kivity print_serial("xor test 4: FAIL\n"); 3937d36db35SAvi Kivity else 3947d36db35SAvi Kivity print_serial("xor test 4: PASS\n"); 3957d36db35SAvi Kivity } 3967d36db35SAvi Kivity 3977d36db35SAvi Kivity void test_cmp_imm(void) 3987d36db35SAvi Kivity { 3997d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 4007d36db35SAvi Kivity MK_INSN(cmp_test1, "mov $0x34, %al\n\t" 4017d36db35SAvi Kivity "cmp $0x34, %al\n\t"); 4027d36db35SAvi Kivity MK_INSN(cmp_test2, "mov $0x34, %al\n\t" 4037d36db35SAvi Kivity "cmp $0x39, %al\n\t"); 4047d36db35SAvi Kivity MK_INSN(cmp_test3, "mov $0x34, %al\n\t" 4057d36db35SAvi Kivity "cmp $0x24, %al\n\t"); 4067d36db35SAvi Kivity 4077d36db35SAvi Kivity /* test cmp imm8 with AL */ 4087d36db35SAvi Kivity /* ZF: (bit 6) Zero Flag becomes 1 if an operation results 4097d36db35SAvi Kivity * in a 0 writeback, or 0 register 4107d36db35SAvi Kivity */ 4117d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4127d36db35SAvi Kivity insn_cmp_test1, 4137d36db35SAvi Kivity insn_cmp_test1_end - insn_cmp_test1); 4147d36db35SAvi Kivity if ((outregs.eflags & (1<<6)) != (1<<6)) 4157d36db35SAvi Kivity print_serial("cmp test 1: FAIL\n"); 4167d36db35SAvi Kivity else 4177d36db35SAvi Kivity print_serial("cmp test 1: PASS\n"); 4187d36db35SAvi Kivity 4197d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4207d36db35SAvi Kivity insn_cmp_test2, 4217d36db35SAvi Kivity insn_cmp_test2_end - insn_cmp_test2); 4227d36db35SAvi Kivity if ((outregs.eflags & (1<<6)) != 0) 4237d36db35SAvi Kivity print_serial("cmp test 2: FAIL\n"); 4247d36db35SAvi Kivity else 4257d36db35SAvi Kivity print_serial("cmp test 2: PASS\n"); 4267d36db35SAvi Kivity 4277d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4287d36db35SAvi Kivity insn_cmp_test3, 4297d36db35SAvi Kivity insn_cmp_test3_end - insn_cmp_test3); 4307d36db35SAvi Kivity if ((outregs.eflags & (1<<6)) != 0) 4317d36db35SAvi Kivity print_serial("cmp test 3: FAIL\n"); 4327d36db35SAvi Kivity else 4337d36db35SAvi Kivity print_serial("cmp test 3: PASS\n"); 4347d36db35SAvi Kivity } 4357d36db35SAvi Kivity 4367d36db35SAvi Kivity void test_add_imm(void) 4377d36db35SAvi Kivity { 4387d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 4397d36db35SAvi Kivity MK_INSN(add_test1, "mov $0x43211234, %eax \n\t" 4407d36db35SAvi Kivity "add $0x12344321, %eax \n\t"); 4417d36db35SAvi Kivity MK_INSN(add_test2, "mov $0x12, %eax \n\t" 4427d36db35SAvi Kivity "add $0x21, %al\n\t"); 4437d36db35SAvi Kivity 4447d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4457d36db35SAvi Kivity insn_add_test1, 4467d36db35SAvi Kivity insn_add_test1_end - insn_add_test1); 4477d36db35SAvi Kivity if (outregs.eax != 0x55555555) 4487d36db35SAvi Kivity print_serial("add test 1: FAIL\n"); 4497d36db35SAvi Kivity else 4507d36db35SAvi Kivity print_serial("add test 1: PASS\n"); 4517d36db35SAvi Kivity 4527d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4537d36db35SAvi Kivity insn_add_test2, 4547d36db35SAvi Kivity insn_add_test2_end - insn_add_test2); 4557d36db35SAvi Kivity if (outregs.eax != 0x33) 4567d36db35SAvi Kivity print_serial("add test 2: FAIL\n"); 4577d36db35SAvi Kivity else 4587d36db35SAvi Kivity print_serial("add test 2: PASS\n"); 4597d36db35SAvi Kivity } 4607d36db35SAvi Kivity 4617d36db35SAvi Kivity void test_eflags_insn(void) 4627d36db35SAvi Kivity { 4637d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 4647d36db35SAvi Kivity MK_INSN(clc, "clc"); 4657d36db35SAvi Kivity MK_INSN(cli, "cli"); 4667d36db35SAvi Kivity MK_INSN(sti, "sti"); 4677d36db35SAvi Kivity MK_INSN(cld, "cld"); 4687d36db35SAvi Kivity MK_INSN(std, "std"); 4697d36db35SAvi Kivity 4707d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4717d36db35SAvi Kivity insn_clc, 4727d36db35SAvi Kivity insn_clc_end - insn_clc); 4737d36db35SAvi Kivity if (outregs.eflags & 1) 4747d36db35SAvi Kivity print_serial("clc test: FAIL\n"); 4757d36db35SAvi Kivity else 4767d36db35SAvi Kivity print_serial("clc test: PASS\n"); 4777d36db35SAvi Kivity 4787d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4797d36db35SAvi Kivity insn_cli, 4807d36db35SAvi Kivity insn_cli_end - insn_cli); 4817d36db35SAvi Kivity if (outregs.eflags & (1 << 9)) 4827d36db35SAvi Kivity print_serial("cli test: FAIL\n"); 4837d36db35SAvi Kivity else 4847d36db35SAvi Kivity print_serial("cli test: PASS\n"); 4857d36db35SAvi Kivity 4867d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4877d36db35SAvi Kivity insn_sti, 4887d36db35SAvi Kivity insn_sti_end - insn_sti); 4897d36db35SAvi Kivity if (!(outregs.eflags & (1 << 9))) 4907d36db35SAvi Kivity print_serial("sti test: FAIL\n"); 4917d36db35SAvi Kivity else 4927d36db35SAvi Kivity print_serial("sti test: PASS\n"); 4937d36db35SAvi Kivity 4947d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4957d36db35SAvi Kivity insn_cld, 4967d36db35SAvi Kivity insn_cld_end - insn_cld); 4977d36db35SAvi Kivity if (outregs.eflags & (1 << 10)) 4987d36db35SAvi Kivity print_serial("cld test: FAIL\n"); 4997d36db35SAvi Kivity else 5007d36db35SAvi Kivity print_serial("cld test: PASS\n"); 5017d36db35SAvi Kivity 5027d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5037d36db35SAvi Kivity insn_std, 5047d36db35SAvi Kivity insn_std_end - insn_std); 5057d36db35SAvi Kivity if (!(outregs.eflags & (1 << 10))) 5067d36db35SAvi Kivity print_serial("std test: FAIL\n"); 5077d36db35SAvi Kivity else 5087d36db35SAvi Kivity print_serial("std test: PASS\n"); 5097d36db35SAvi Kivity } 5107d36db35SAvi Kivity 5117d36db35SAvi Kivity void test_io(void) 5127d36db35SAvi Kivity { 5137d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 5147d36db35SAvi Kivity MK_INSN(io_test1, "mov $0xff, %al \n\t" 5157d36db35SAvi Kivity "out %al, $0xe0 \n\t" 5167d36db35SAvi Kivity "mov $0x00, %al \n\t" 5177d36db35SAvi Kivity "in $0xe0, %al \n\t"); 5187d36db35SAvi Kivity MK_INSN(io_test2, "mov $0xffff, %ax \n\t" 5197d36db35SAvi Kivity "out %ax, $0xe0 \n\t" 5207d36db35SAvi Kivity "mov $0x0000, %ax \n\t" 5217d36db35SAvi Kivity "in $0xe0, %ax \n\t"); 5227d36db35SAvi Kivity MK_INSN(io_test3, "mov $0xffffffff, %eax \n\t" 5237d36db35SAvi Kivity "out %eax, $0xe0 \n\t" 5247d36db35SAvi Kivity "mov $0x000000, %eax \n\t" 5257d36db35SAvi Kivity "in $0xe0, %eax \n\t"); 5267d36db35SAvi Kivity MK_INSN(io_test4, "mov $0xe0, %dx \n\t" 5277d36db35SAvi Kivity "mov $0xff, %al \n\t" 5287d36db35SAvi Kivity "out %al, %dx \n\t" 5297d36db35SAvi Kivity "mov $0x00, %al \n\t" 5307d36db35SAvi Kivity "in %dx, %al \n\t"); 5317d36db35SAvi Kivity MK_INSN(io_test5, "mov $0xe0, %dx \n\t" 5327d36db35SAvi Kivity "mov $0xffff, %ax \n\t" 5337d36db35SAvi Kivity "out %ax, %dx \n\t" 5347d36db35SAvi Kivity "mov $0x0000, %ax \n\t" 5357d36db35SAvi Kivity "in %dx, %ax \n\t"); 5367d36db35SAvi Kivity MK_INSN(io_test6, "mov $0xe0, %dx \n\t" 5377d36db35SAvi Kivity "mov $0xffffffff, %eax \n\t" 5387d36db35SAvi Kivity "out %eax, %dx \n\t" 5397d36db35SAvi Kivity "mov $0x00000000, %eax \n\t" 5407d36db35SAvi Kivity "in %dx, %eax \n\t"); 5417d36db35SAvi Kivity 5427d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5437d36db35SAvi Kivity insn_io_test1, 5447d36db35SAvi Kivity insn_io_test1_end - insn_io_test1); 5457d36db35SAvi Kivity 5467d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xff) 5477d36db35SAvi Kivity print_serial("I/O test 1: FAIL\n"); 5487d36db35SAvi Kivity else 5497d36db35SAvi Kivity print_serial("I/O test 1: PASS\n"); 5507d36db35SAvi Kivity 5517d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5527d36db35SAvi Kivity insn_io_test2, 5537d36db35SAvi Kivity insn_io_test2_end - insn_io_test2); 5547d36db35SAvi Kivity 5557d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffff) 5567d36db35SAvi Kivity print_serial("I/O test 2: FAIL\n"); 5577d36db35SAvi Kivity else 5587d36db35SAvi Kivity print_serial("I/O test 2: PASS\n"); 5597d36db35SAvi Kivity 5607d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5617d36db35SAvi Kivity insn_io_test3, 5627d36db35SAvi Kivity insn_io_test3_end - insn_io_test3); 5637d36db35SAvi Kivity 5647d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffffffff) 5657d36db35SAvi Kivity print_serial("I/O test 3: FAIL\n"); 5667d36db35SAvi Kivity else 5677d36db35SAvi Kivity print_serial("I/O test 3: PASS\n"); 5687d36db35SAvi Kivity 5697d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5707d36db35SAvi Kivity insn_io_test4, 5717d36db35SAvi Kivity insn_io_test4_end - insn_io_test4); 5727d36db35SAvi Kivity 5737d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xff) 5747d36db35SAvi Kivity print_serial("I/O test 4: FAIL\n"); 5757d36db35SAvi Kivity else 5767d36db35SAvi Kivity print_serial("I/O test 4: PASS\n"); 5777d36db35SAvi Kivity 5787d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5797d36db35SAvi Kivity insn_io_test5, 5807d36db35SAvi Kivity insn_io_test5_end - insn_io_test5); 5817d36db35SAvi Kivity 5827d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffff) 5837d36db35SAvi Kivity print_serial("I/O test 5: FAIL\n"); 5847d36db35SAvi Kivity else 5857d36db35SAvi Kivity print_serial("I/O test 5: PASS\n"); 5867d36db35SAvi Kivity 5877d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5887d36db35SAvi Kivity insn_io_test6, 5897d36db35SAvi Kivity insn_io_test6_end - insn_io_test6); 5907d36db35SAvi Kivity 5917d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffffffff) 5927d36db35SAvi Kivity print_serial("I/O test 6: FAIL\n"); 5937d36db35SAvi Kivity else 5947d36db35SAvi Kivity print_serial("I/O test 6: PASS\n"); 5957d36db35SAvi Kivity } 5967d36db35SAvi Kivity 5977d36db35SAvi Kivity void test_call(void) 5987d36db35SAvi Kivity { 5997d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 6007d36db35SAvi Kivity u32 esp[16]; 6017d36db35SAvi Kivity 6027d36db35SAvi Kivity inregs.esp = (u32)esp; 6037d36db35SAvi Kivity 6047d36db35SAvi Kivity MK_INSN(call1, "mov $test_function, %eax \n\t" 6057d36db35SAvi Kivity "call *%eax\n\t"); 6067d36db35SAvi Kivity MK_INSN(call_near1, "jmp 2f\n\t" 6077d36db35SAvi Kivity "1: mov $0x1234, %eax\n\t" 6087d36db35SAvi Kivity "ret\n\t" 6097d36db35SAvi Kivity "2: call 1b\t"); 6107d36db35SAvi Kivity MK_INSN(call_near2, "call 1f\n\t" 6117d36db35SAvi Kivity "jmp 2f\n\t" 6127d36db35SAvi Kivity "1: mov $0x1234, %eax\n\t" 6137d36db35SAvi Kivity "ret\n\t" 6147d36db35SAvi Kivity "2:\t"); 6157d36db35SAvi Kivity 6167d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6177d36db35SAvi Kivity insn_call1, 6187d36db35SAvi Kivity insn_call1_end - insn_call1); 6197d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 6207d36db35SAvi Kivity print_serial("Call Test 1: FAIL\n"); 6217d36db35SAvi Kivity else 6227d36db35SAvi Kivity print_serial("Call Test 1: PASS\n"); 6237d36db35SAvi Kivity 6247d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6257d36db35SAvi Kivity insn_call_near1, insn_call_near1_end - insn_call_near1); 6267d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 6277d36db35SAvi Kivity print_serial("Call near Test 1: FAIL\n"); 6287d36db35SAvi Kivity else 6297d36db35SAvi Kivity print_serial("Call near Test 1: PASS\n"); 6307d36db35SAvi Kivity 6317d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6327d36db35SAvi Kivity insn_call_near2, insn_call_near2_end - insn_call_near2); 6337d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 6347d36db35SAvi Kivity print_serial("Call near Test 2: FAIL\n"); 6357d36db35SAvi Kivity else 6367d36db35SAvi Kivity print_serial("Call near Test 2: PASS\n"); 6377d36db35SAvi Kivity } 6387d36db35SAvi Kivity 6397d36db35SAvi Kivity void test_jcc_short(void) 6407d36db35SAvi Kivity { 6417d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 6427d36db35SAvi Kivity MK_INSN(jnz_short1, "jnz 1f\n\t" 6437d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 6447d36db35SAvi Kivity "1:\n\t"); 6457d36db35SAvi Kivity MK_INSN(jnz_short2, "1:\n\t" 6467d36db35SAvi Kivity "cmp $0x1234, %eax\n\t" 6477d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 6487d36db35SAvi Kivity "jnz 1b\n\t"); 6497d36db35SAvi Kivity MK_INSN(jmp_short1, "jmp 1f\n\t" 6507d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 6517d36db35SAvi Kivity "1:\n\t"); 6527d36db35SAvi Kivity 6537d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6547d36db35SAvi Kivity insn_jnz_short1, insn_jnz_short1_end - insn_jnz_short1); 6557d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, 0)) 6567d36db35SAvi Kivity print_serial("JNZ short Test 1: FAIL\n"); 6577d36db35SAvi Kivity else 6587d36db35SAvi Kivity print_serial("JNZ short Test 1: PASS\n"); 6597d36db35SAvi Kivity 6607d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6617d36db35SAvi Kivity insn_jnz_short2, insn_jnz_short2_end - insn_jnz_short2); 6627d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6))) 6637d36db35SAvi Kivity print_serial("JNZ short Test 2: FAIL\n"); 6647d36db35SAvi Kivity else 6657d36db35SAvi Kivity print_serial("JNZ short Test 2: PASS\n"); 6667d36db35SAvi Kivity 6677d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6687d36db35SAvi Kivity insn_jmp_short1, insn_jmp_short1_end - insn_jmp_short1); 6697d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, 0)) 6707d36db35SAvi Kivity print_serial("JMP short Test 1: FAIL\n"); 6717d36db35SAvi Kivity else 6727d36db35SAvi Kivity print_serial("JMP short Test 1: PASS\n"); 6737d36db35SAvi Kivity } 6747d36db35SAvi Kivity 6757d36db35SAvi Kivity void test_jcc_near(void) 6767d36db35SAvi Kivity { 6777d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 6787d36db35SAvi Kivity /* encode near jmp manually. gas will not do it if offsets < 127 byte */ 6797d36db35SAvi Kivity MK_INSN(jnz_near1, ".byte 0x0f, 0x85, 0x06, 0x00\n\t" 6807d36db35SAvi Kivity "mov $0x1234, %eax\n\t"); 6817d36db35SAvi Kivity MK_INSN(jnz_near2, "cmp $0x1234, %eax\n\t" 6827d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 6837d36db35SAvi Kivity ".byte 0x0f, 0x85, 0xf0, 0xff\n\t"); 6847d36db35SAvi Kivity MK_INSN(jmp_near1, ".byte 0xE9, 0x06, 0x00\n\t" 6857d36db35SAvi Kivity "mov $0x1234, %eax\n\t"); 6867d36db35SAvi Kivity 6877d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6887d36db35SAvi Kivity insn_jnz_near1, insn_jnz_near1_end - insn_jnz_near1); 6897d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, 0)) 6907d36db35SAvi Kivity print_serial("JNZ near Test 1: FAIL\n"); 6917d36db35SAvi Kivity else 6927d36db35SAvi Kivity print_serial("JNZ near Test 1: PASS\n"); 6937d36db35SAvi Kivity 6947d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6957d36db35SAvi Kivity insn_jnz_near2, insn_jnz_near2_end - insn_jnz_near2); 6967d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6))) 6977d36db35SAvi Kivity print_serial("JNZ near Test 2: FAIL\n"); 6987d36db35SAvi Kivity else 6997d36db35SAvi Kivity print_serial("JNZ near Test 2: PASS\n"); 7007d36db35SAvi Kivity 7017d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7027d36db35SAvi Kivity insn_jmp_near1, insn_jmp_near1_end - insn_jmp_near1); 7037d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, 0)) 7047d36db35SAvi Kivity print_serial("JMP near Test 1: FAIL\n"); 7057d36db35SAvi Kivity else 7067d36db35SAvi Kivity print_serial("JMP near Test 1: PASS\n"); 7077d36db35SAvi Kivity } 7087d36db35SAvi Kivity 7097d36db35SAvi Kivity void test_long_jmp() 7107d36db35SAvi Kivity { 7117d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 7127d36db35SAvi Kivity u32 esp[16]; 7137d36db35SAvi Kivity 7147d36db35SAvi Kivity inregs.esp = (u32)esp; 7157d36db35SAvi Kivity MK_INSN(long_jmp, "call 1f\n\t" 7167d36db35SAvi Kivity "jmp 2f\n\t" 7177d36db35SAvi Kivity "1: jmp $0, $test_function\n\t" 7187d36db35SAvi Kivity "2:\n\t"); 7197d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7207d36db35SAvi Kivity insn_long_jmp, 7217d36db35SAvi Kivity insn_long_jmp_end - insn_long_jmp); 7227d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 7237d36db35SAvi Kivity print_serial("Long JMP Test: FAIL\n"); 7247d36db35SAvi Kivity else 7257d36db35SAvi Kivity print_serial("Long JMP Test: PASS\n"); 7267d36db35SAvi Kivity } 7277d36db35SAvi Kivity void test_push_pop() 7287d36db35SAvi Kivity { 7297d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 7307d36db35SAvi Kivity MK_INSN(push32, "mov $0x12345678, %eax\n\t" 7317d36db35SAvi Kivity "push %eax\n\t" 7327d36db35SAvi Kivity "pop %ebx\n\t"); 7337d36db35SAvi Kivity MK_INSN(push16, "mov $0x1234, %ax\n\t" 7347d36db35SAvi Kivity "push %ax\n\t" 7357d36db35SAvi Kivity "pop %bx\n\t"); 7367d36db35SAvi Kivity 7377d36db35SAvi Kivity MK_INSN(push_es, "mov $0x231, %bx\n\t" //Just write a dummy value to see if it gets overwritten 7387d36db35SAvi Kivity "mov $0x123, %ax\n\t" 7397d36db35SAvi Kivity "mov %ax, %es\n\t" 7407d36db35SAvi Kivity "push %es\n\t" 7417d36db35SAvi Kivity "pop %bx \n\t" 7427d36db35SAvi Kivity ); 7437d36db35SAvi Kivity MK_INSN(pop_es, "push %ax\n\t" 7447d36db35SAvi Kivity "pop %es\n\t" 7457d36db35SAvi Kivity "mov %es, %bx\n\t" 7467d36db35SAvi Kivity ); 7477d36db35SAvi Kivity MK_INSN(push_pop_ss, "push %ss\n\t" 7487d36db35SAvi Kivity "pushw %ax\n\t" 7497d36db35SAvi Kivity "popw %ss\n\t" 7507d36db35SAvi Kivity "mov %ss, %bx\n\t" 7517d36db35SAvi Kivity "pop %ss\n\t" 7527d36db35SAvi Kivity ); 7537d36db35SAvi Kivity MK_INSN(push_pop_fs, "push %fs\n\t" 7547d36db35SAvi Kivity "pushl %eax\n\t" 7557d36db35SAvi Kivity "popl %fs\n\t" 7567d36db35SAvi Kivity "mov %fs, %ebx\n\t" 7577d36db35SAvi Kivity "pop %fs\n\t" 7587d36db35SAvi Kivity ); 7597d36db35SAvi Kivity 7607d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7617d36db35SAvi Kivity insn_push32, 7627d36db35SAvi Kivity insn_push32_end - insn_push32); 7637d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x12345678) 7647d36db35SAvi Kivity print_serial("Push/Pop Test 1: FAIL\n"); 7657d36db35SAvi Kivity else 7667d36db35SAvi Kivity print_serial("Push/Pop Test 1: PASS\n"); 7677d36db35SAvi Kivity 7687d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7697d36db35SAvi Kivity insn_push16, 7707d36db35SAvi Kivity insn_push16_end - insn_push16); 7717d36db35SAvi Kivity 7727d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x1234) 7737d36db35SAvi Kivity print_serial("Push/Pop Test 2: FAIL\n"); 7747d36db35SAvi Kivity else 7757d36db35SAvi Kivity print_serial("Push/Pop Test 2: PASS\n"); 7767d36db35SAvi Kivity 7777d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7787d36db35SAvi Kivity insn_push_es, 7797d36db35SAvi Kivity insn_push_es_end - insn_push_es); 7807d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax || outregs.eax != 0x123) 7817d36db35SAvi Kivity print_serial("Push/Pop Test 3: FAIL\n"); 7827d36db35SAvi Kivity else 7837d36db35SAvi Kivity print_serial("Push/Pop Test 3: PASS\n"); 7847d36db35SAvi Kivity 7857d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7867d36db35SAvi Kivity insn_pop_es, 7877d36db35SAvi Kivity insn_pop_es_end - insn_pop_es); 7887d36db35SAvi Kivity 7897d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 7907d36db35SAvi Kivity print_serial("Push/Pop Test 4: FAIL\n"); 7917d36db35SAvi Kivity else 7927d36db35SAvi Kivity print_serial("Push/Pop Test 4: PASS\n"); 7937d36db35SAvi Kivity 7947d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7957d36db35SAvi Kivity insn_push_pop_ss, 7967d36db35SAvi Kivity insn_push_pop_ss_end - insn_push_pop_ss); 7977d36db35SAvi Kivity 7987d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 7997d36db35SAvi Kivity print_serial("Push/Pop Test 5: FAIL\n"); 8007d36db35SAvi Kivity else 8017d36db35SAvi Kivity print_serial("Push/Pop Test 5: PASS\n"); 8027d36db35SAvi Kivity 8037d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 8047d36db35SAvi Kivity insn_push_pop_fs, 8057d36db35SAvi Kivity insn_push_pop_fs_end - insn_push_pop_fs); 8067d36db35SAvi Kivity 8077d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 8087d36db35SAvi Kivity print_serial("Push/Pop Test 6: FAIL\n"); 8097d36db35SAvi Kivity else 8107d36db35SAvi Kivity print_serial("Push/Pop Test 6: PASS\n"); 8117d36db35SAvi Kivity } 8127d36db35SAvi Kivity 8137d36db35SAvi Kivity void test_null(void) 8147d36db35SAvi Kivity { 8157d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 8167d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 0, 0); 8177d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 8187d36db35SAvi Kivity print_serial("null test: FAIL\n"); 8197d36db35SAvi Kivity else 8207d36db35SAvi Kivity print_serial("null test: PASS\n"); 8217d36db35SAvi Kivity } 8227d36db35SAvi Kivity 8237d36db35SAvi Kivity struct { 8247d36db35SAvi Kivity char stack[500]; 8257d36db35SAvi Kivity char top[]; 8267d36db35SAvi Kivity } tmp_stack; 8277d36db35SAvi Kivity 8287d36db35SAvi Kivity void test_pusha_popa() 8297d36db35SAvi Kivity { 8307d36db35SAvi Kivity struct regs inregs = { .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = (unsigned long)&tmp_stack.top }, outregs; 8317d36db35SAvi Kivity 8327d36db35SAvi Kivity MK_INSN(pusha, "pusha\n\t" 8337d36db35SAvi Kivity "pop %edi\n\t" 8347d36db35SAvi Kivity "pop %esi\n\t" 8357d36db35SAvi Kivity "pop %ebp\n\t" 8367d36db35SAvi Kivity "add $4, %esp\n\t" 8377d36db35SAvi Kivity "pop %ebx\n\t" 8387d36db35SAvi Kivity "pop %edx\n\t" 8397d36db35SAvi Kivity "pop %ecx\n\t" 8407d36db35SAvi Kivity "pop %eax\n\t" 8417d36db35SAvi Kivity ); 8427d36db35SAvi Kivity 8437d36db35SAvi Kivity MK_INSN(popa, "push %eax\n\t" 8447d36db35SAvi Kivity "push %ecx\n\t" 8457d36db35SAvi Kivity "push %edx\n\t" 8467d36db35SAvi Kivity "push %ebx\n\t" 8477d36db35SAvi Kivity "push %esp\n\t" 8487d36db35SAvi Kivity "push %ebp\n\t" 8497d36db35SAvi Kivity "push %esi\n\t" 8507d36db35SAvi Kivity "push %edi\n\t" 8517d36db35SAvi Kivity "popa\n\t" 8527d36db35SAvi Kivity ); 8537d36db35SAvi Kivity 8547d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 8557d36db35SAvi Kivity insn_pusha, 8567d36db35SAvi Kivity insn_pusha_end - insn_pusha); 8577d36db35SAvi Kivity 8587d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 8597d36db35SAvi Kivity print_serial("Pusha/Popa Test1: FAIL\n"); 8607d36db35SAvi Kivity else 8617d36db35SAvi Kivity print_serial("Pusha/Popa Test1: PASS\n"); 8627d36db35SAvi Kivity 8637d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 8647d36db35SAvi Kivity insn_popa, 8657d36db35SAvi Kivity insn_popa_end - insn_popa); 8667d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 8677d36db35SAvi Kivity print_serial("Pusha/Popa Test2: FAIL\n"); 8687d36db35SAvi Kivity else 8697d36db35SAvi Kivity print_serial("Pusha/Popa Test2: PASS\n"); 8707d36db35SAvi Kivity } 8717d36db35SAvi Kivity 8727d36db35SAvi Kivity void test_iret() 8737d36db35SAvi Kivity { 8747d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 8757d36db35SAvi Kivity 8767d36db35SAvi Kivity MK_INSN(iret32, "pushf\n\t" 8777d36db35SAvi Kivity "pushl %cs\n\t" 8787d36db35SAvi Kivity "call 1f\n\t" /* a near call will push eip onto the stack */ 8797d36db35SAvi Kivity "jmp 2f\n\t" 8807d36db35SAvi Kivity "1: iret\n\t" 8817d36db35SAvi Kivity "2:\n\t" 8827d36db35SAvi Kivity ); 8837d36db35SAvi Kivity 8847d36db35SAvi Kivity MK_INSN(iret16, "pushfw\n\t" 8857d36db35SAvi Kivity "pushw %cs\n\t" 8867d36db35SAvi Kivity "callw 1f\n\t" 8877d36db35SAvi Kivity "jmp 2f\n\t" 8887d36db35SAvi Kivity "1: iretw\n\t" 8897d36db35SAvi Kivity "2:\n\t"); 8907d36db35SAvi Kivity 8917d36db35SAvi Kivity MK_INSN(iret_flags32, "pushfl\n\t" 8927d36db35SAvi Kivity "popl %eax\n\t" 8937d36db35SAvi Kivity "andl $~0x2, %eax\n\t" 8947d36db35SAvi Kivity "orl $0xffc08028, %eax\n\t" 8957d36db35SAvi Kivity "pushl %eax\n\t" 8967d36db35SAvi Kivity "pushl %cs\n\t" 8977d36db35SAvi Kivity "call 1f\n\t" 8987d36db35SAvi Kivity "jmp 2f\n\t" 8997d36db35SAvi Kivity "1: iret\n\t" 9007d36db35SAvi Kivity "2:\n\t"); 9017d36db35SAvi Kivity 9027d36db35SAvi Kivity MK_INSN(iret_flags16, "pushfw\n\t" 9037d36db35SAvi Kivity "popw %ax\n\t" 9047d36db35SAvi Kivity "and $~0x2, %ax\n\t" 9057d36db35SAvi Kivity "or $0x8028, %ax\n\t" 9067d36db35SAvi Kivity "pushw %ax\n\t" 9077d36db35SAvi Kivity "pushw %cs\n\t" 9087d36db35SAvi Kivity "callw 1f\n\t" 9097d36db35SAvi Kivity "jmp 2f\n\t" 9107d36db35SAvi Kivity "1: iretw\n\t" 9117d36db35SAvi Kivity "2:\n\t"); 9127d36db35SAvi Kivity 9137d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 9147d36db35SAvi Kivity insn_iret32, 9157d36db35SAvi Kivity insn_iret32_end - insn_iret32); 9167d36db35SAvi Kivity 9177d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 9187d36db35SAvi Kivity print_serial("iret Test 1: FAIL\n"); 9197d36db35SAvi Kivity else 9207d36db35SAvi Kivity print_serial("iret Test 1: PASS\n"); 9217d36db35SAvi Kivity 9227d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 9237d36db35SAvi Kivity insn_iret16, 9247d36db35SAvi Kivity insn_iret16_end - insn_iret16); 9257d36db35SAvi Kivity 9267d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 9277d36db35SAvi Kivity print_serial("iret Test 2: FAIL\n"); 9287d36db35SAvi Kivity else 9297d36db35SAvi Kivity print_serial("iret Test 2: PASS\n"); 9307d36db35SAvi Kivity 9317d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 9327d36db35SAvi Kivity insn_iret_flags32, 9337d36db35SAvi Kivity insn_iret_flags32_end - insn_iret_flags32); 9347d36db35SAvi Kivity 9357d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX)) 9367d36db35SAvi Kivity print_serial("iret Test 3: FAIL\n"); 9377d36db35SAvi Kivity else 9387d36db35SAvi Kivity print_serial("iret Test 3: PASS\n"); 9397d36db35SAvi Kivity 9407d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 9417d36db35SAvi Kivity insn_iret_flags16, 9427d36db35SAvi Kivity insn_iret_flags16_end - insn_iret_flags16); 9437d36db35SAvi Kivity 9447d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX)) 9457d36db35SAvi Kivity print_serial("iret Test 4: FAIL\n"); 9467d36db35SAvi Kivity else 9477d36db35SAvi Kivity print_serial("iret Test 4: PASS\n"); 9487d36db35SAvi Kivity } 9497d36db35SAvi Kivity 950*96b9ca1eSMohammed Gamal void test_int() 951*96b9ca1eSMohammed Gamal { 952*96b9ca1eSMohammed Gamal struct regs inregs = { 0 }, outregs; 953*96b9ca1eSMohammed Gamal 954*96b9ca1eSMohammed Gamal *(u32 *)(0x11 * 4) = 0x1000; /* Store a pointer to address 0x1000 in IDT entry 0x11 */ 955*96b9ca1eSMohammed Gamal *(u8 *)(0x1000) = 0xcf; /* 0x1000 contains an IRET instruction */ 956*96b9ca1eSMohammed Gamal 957*96b9ca1eSMohammed Gamal MK_INSN(int11, "int $0x11\n\t"); 958*96b9ca1eSMohammed Gamal 959*96b9ca1eSMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 960*96b9ca1eSMohammed Gamal insn_int11, 961*96b9ca1eSMohammed Gamal insn_int11_end - insn_int11); 962*96b9ca1eSMohammed Gamal 963*96b9ca1eSMohammed Gamal if (!regs_equal(&inregs, &outregs, 0)) 964*96b9ca1eSMohammed Gamal print_serial("int Test 1: FAIL\n"); 965*96b9ca1eSMohammed Gamal else 966*96b9ca1eSMohammed Gamal print_serial("int Test 1: PASS\n"); 967*96b9ca1eSMohammed Gamal } 968*96b9ca1eSMohammed Gamal 9697d36db35SAvi Kivity void realmode_start(void) 9707d36db35SAvi Kivity { 9717d36db35SAvi Kivity test_null(); 9727d36db35SAvi Kivity 9737d36db35SAvi Kivity test_shld(); 9747d36db35SAvi Kivity test_push_pop(); 9757d36db35SAvi Kivity test_pusha_popa(); 9767d36db35SAvi Kivity test_mov_imm(); 9777d36db35SAvi Kivity test_cmp_imm(); 9787d36db35SAvi Kivity test_add_imm(); 9797d36db35SAvi Kivity test_sub_imm(); 9807d36db35SAvi Kivity test_xor_imm(); 9817d36db35SAvi Kivity test_io(); 9827d36db35SAvi Kivity test_eflags_insn(); 9837d36db35SAvi Kivity test_jcc_short(); 9847d36db35SAvi Kivity test_jcc_near(); 9857d36db35SAvi Kivity /* test_call() uses short jump so call it after testing jcc */ 9867d36db35SAvi Kivity test_call(); 9877d36db35SAvi Kivity /* long jmp test uses call near so test it after testing call */ 9887d36db35SAvi Kivity test_long_jmp(); 9897d36db35SAvi Kivity test_xchg(); 9907d36db35SAvi Kivity test_iret(); 991*96b9ca1eSMohammed Gamal test_int(); 9927d36db35SAvi Kivity 9937d36db35SAvi Kivity exit(0); 9947d36db35SAvi Kivity } 9957d36db35SAvi Kivity 9967d36db35SAvi Kivity unsigned long long r_gdt[] = { 0, 0x9b000000ffff, 0x93000000ffff }; 9977d36db35SAvi Kivity 9987d36db35SAvi Kivity struct __attribute__((packed)) { 9997d36db35SAvi Kivity unsigned short limit; 10007d36db35SAvi Kivity void *base; 10017d36db35SAvi Kivity } r_gdt_descr = { sizeof(r_gdt) - 1, &r_gdt }; 10027d36db35SAvi Kivity 10037d36db35SAvi Kivity asm( 10047d36db35SAvi Kivity ".section .init \n\t" 10057d36db35SAvi Kivity 10067d36db35SAvi Kivity ".code32 \n\t" 10077d36db35SAvi Kivity 10087d36db35SAvi Kivity "mb_magic = 0x1BADB002 \n\t" 10097d36db35SAvi Kivity "mb_flags = 0x0 \n\t" 10107d36db35SAvi Kivity 10117d36db35SAvi Kivity "# multiboot header \n\t" 10127d36db35SAvi Kivity ".long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) \n\t" 10137d36db35SAvi Kivity 10147d36db35SAvi Kivity ".globl start \n\t" 10157d36db35SAvi Kivity ".data \n\t" 10167d36db35SAvi Kivity ". = . + 4096 \n\t" 10177d36db35SAvi Kivity "stacktop: \n\t" 10187d36db35SAvi Kivity 10197d36db35SAvi Kivity ".text \n\t" 10207d36db35SAvi Kivity "start: \n\t" 10217d36db35SAvi Kivity "lgdt r_gdt_descr \n\t" 10227d36db35SAvi Kivity "ljmp $8, $1f; 1: \n\t" 10237d36db35SAvi Kivity ".code16gcc \n\t" 10247d36db35SAvi Kivity "mov $16, %eax \n\t" 10257d36db35SAvi Kivity "mov %ax, %ds \n\t" 10267d36db35SAvi Kivity "mov %ax, %es \n\t" 10277d36db35SAvi Kivity "mov %ax, %fs \n\t" 10287d36db35SAvi Kivity "mov %ax, %gs \n\t" 10297d36db35SAvi Kivity "mov %ax, %ss \n\t" 10307d36db35SAvi Kivity "mov %cr0, %eax \n\t" 10317d36db35SAvi Kivity "btc $0, %eax \n\t" 10327d36db35SAvi Kivity "mov %eax, %cr0 \n\t" 10337d36db35SAvi Kivity "ljmp $0, $realmode_entry \n\t" 10347d36db35SAvi Kivity 10357d36db35SAvi Kivity "realmode_entry: \n\t" 10367d36db35SAvi Kivity 10377d36db35SAvi Kivity "xor %ax, %ax \n\t" 10387d36db35SAvi Kivity "mov %ax, %ds \n\t" 10397d36db35SAvi Kivity "mov %ax, %es \n\t" 10407d36db35SAvi Kivity "mov %ax, %ss \n\t" 10417d36db35SAvi Kivity "mov %ax, %fs \n\t" 10427d36db35SAvi Kivity "mov %ax, %gs \n\t" 10437d36db35SAvi Kivity "mov $stacktop, %esp\n\t" 10447d36db35SAvi Kivity "ljmp $0, $realmode_start \n\t" 10457d36db35SAvi Kivity 10467d36db35SAvi Kivity ".code16gcc \n\t" 10477d36db35SAvi Kivity ); 1048