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 81*32001692SAvi Kivity "pushw %[save]+36; popfw \n\t" 827d36db35SAvi Kivity "xchg %%eax, %[save]+0 \n\t" 837d36db35SAvi Kivity "xchg %%ebx, %[save]+4 \n\t" 847d36db35SAvi Kivity "xchg %%ecx, %[save]+8 \n\t" 857d36db35SAvi Kivity "xchg %%edx, %[save]+12 \n\t" 867d36db35SAvi Kivity "xchg %%esi, %[save]+16 \n\t" 877d36db35SAvi Kivity "xchg %%edi, %[save]+20 \n\t" 887d36db35SAvi Kivity "xchg %%esp, %[save]+24 \n\t" 897d36db35SAvi Kivity "xchg %%ebp, %[save]+28 \n\t" 907d36db35SAvi Kivity 917d36db35SAvi Kivity "test_insn: . = . + 32\n\t" 927d36db35SAvi Kivity "test_insn_end: \n\t" 937d36db35SAvi Kivity 947d36db35SAvi Kivity "xchg %%eax, %[save]+0 \n\t" 957d36db35SAvi Kivity "xchg %%ebx, %[save]+4 \n\t" 967d36db35SAvi Kivity "xchg %%ecx, %[save]+8 \n\t" 977d36db35SAvi Kivity "xchg %%edx, %[save]+12 \n\t" 987d36db35SAvi Kivity "xchg %%esi, %[save]+16 \n\t" 997d36db35SAvi Kivity "xchg %%edi, %[save]+20 \n\t" 1007d36db35SAvi Kivity "xchg %%esp, %[save]+24 \n\t" 1017d36db35SAvi Kivity "xchg %%ebp, %[save]+28 \n\t" 1027d36db35SAvi Kivity 1037d36db35SAvi Kivity /* Save EFLAGS in outregs*/ 1047d36db35SAvi Kivity "pushfl \n\t" 1057d36db35SAvi Kivity "popl %[save]+36 \n\t" 1067d36db35SAvi Kivity 1077d36db35SAvi Kivity "xor %[tmp], %[tmp] \n\t" 1087d36db35SAvi Kivity "mov %[tmp], %%gs \n\t" 1097d36db35SAvi Kivity : [tmp]"=&r"(tmp), [save]"+m"(save) 1107d36db35SAvi Kivity : [gdt_descr]"m"(gdt_descr), [bigseg]"r"((short)16) 1117d36db35SAvi Kivity : "cc", "memory" 1127d36db35SAvi Kivity ); 1137d36db35SAvi Kivity *outregs = save; 1147d36db35SAvi Kivity } 1157d36db35SAvi Kivity 1167d36db35SAvi Kivity #define R_AX 1 1177d36db35SAvi Kivity #define R_BX 2 1187d36db35SAvi Kivity #define R_CX 4 1197d36db35SAvi Kivity #define R_DX 8 1207d36db35SAvi Kivity #define R_SI 16 1217d36db35SAvi Kivity #define R_DI 32 1227d36db35SAvi Kivity #define R_SP 64 1237d36db35SAvi Kivity #define R_BP 128 1247d36db35SAvi Kivity 1257d36db35SAvi Kivity int regs_equal(const struct regs *r1, const struct regs *r2, int ignore) 1267d36db35SAvi Kivity { 1277d36db35SAvi Kivity const u32 *p1 = &r1->eax, *p2 = &r2->eax; // yuck 1287d36db35SAvi Kivity int i; 1297d36db35SAvi Kivity 1307d36db35SAvi Kivity for (i = 0; i < 8; ++i) 1317d36db35SAvi Kivity if (!(ignore & (1 << i)) && p1[i] != p2[i]) 1327d36db35SAvi Kivity return 0; 1337d36db35SAvi Kivity return 1; 1347d36db35SAvi Kivity } 1357d36db35SAvi Kivity 1367d36db35SAvi Kivity #define MK_INSN(name, str) \ 1377d36db35SAvi Kivity asm ( \ 1387d36db35SAvi Kivity ".text 1\n\t" \ 1397d36db35SAvi Kivity "insn_" #name ": " str " \n\t" \ 1407d36db35SAvi Kivity "insn_" #name "_end: \n\t" \ 1417d36db35SAvi Kivity ".text\n\t" \ 1427d36db35SAvi Kivity ); \ 1437d36db35SAvi Kivity extern u8 insn_##name[], insn_##name##_end[] 1447d36db35SAvi Kivity 1457d36db35SAvi Kivity void test_xchg(void) 1467d36db35SAvi Kivity { 1477d36db35SAvi Kivity struct regs inregs = { .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = 7}, outregs; 1487d36db35SAvi Kivity 1497d36db35SAvi Kivity MK_INSN(xchg_test1, "xchg %eax,%eax\n\t"); 1507d36db35SAvi Kivity MK_INSN(xchg_test2, "xchg %eax,%ebx\n\t"); 1517d36db35SAvi Kivity MK_INSN(xchg_test3, "xchg %eax,%ecx\n\t"); 1527d36db35SAvi Kivity MK_INSN(xchg_test4, "xchg %eax,%edx\n\t"); 1537d36db35SAvi Kivity MK_INSN(xchg_test5, "xchg %eax,%esi\n\t"); 1547d36db35SAvi Kivity MK_INSN(xchg_test6, "xchg %eax,%edi\n\t"); 1557d36db35SAvi Kivity MK_INSN(xchg_test7, "xchg %eax,%ebp\n\t"); 1567d36db35SAvi Kivity MK_INSN(xchg_test8, "xchg %eax,%esp\n\t"); 1577d36db35SAvi Kivity 1587d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 1597d36db35SAvi Kivity insn_xchg_test1, 1607d36db35SAvi Kivity insn_xchg_test1_end - insn_xchg_test1); 1617d36db35SAvi Kivity 1627d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 1637d36db35SAvi Kivity print_serial("xchg test 1: FAIL\n"); 1647d36db35SAvi Kivity else 1657d36db35SAvi Kivity print_serial("xchg test 1: PASS\n"); 1667d36db35SAvi Kivity 1677d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 1687d36db35SAvi Kivity insn_xchg_test2, 1697d36db35SAvi Kivity insn_xchg_test2_end - insn_xchg_test2); 1707d36db35SAvi Kivity 1717d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_BX) || 1727d36db35SAvi Kivity outregs.eax != inregs.ebx || 1737d36db35SAvi Kivity outregs.ebx != inregs.eax) 1747d36db35SAvi Kivity print_serial("xchg test 2: FAIL\n"); 1757d36db35SAvi Kivity else 1767d36db35SAvi Kivity print_serial("xchg test 2: PASS\n"); 1777d36db35SAvi Kivity 1787d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 1797d36db35SAvi Kivity insn_xchg_test3, 1807d36db35SAvi Kivity insn_xchg_test3_end - insn_xchg_test3); 1817d36db35SAvi Kivity 1827d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_CX) || 1837d36db35SAvi Kivity outregs.eax != inregs.ecx || 1847d36db35SAvi Kivity outregs.ecx != inregs.eax) 1857d36db35SAvi Kivity print_serial("xchg test 3: FAIL\n"); 1867d36db35SAvi Kivity else 1877d36db35SAvi Kivity print_serial("xchg test 3: PASS\n"); 1887d36db35SAvi Kivity 1897d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 1907d36db35SAvi Kivity insn_xchg_test4, 1917d36db35SAvi Kivity insn_xchg_test4_end - insn_xchg_test4); 1927d36db35SAvi Kivity 1937d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_DX) || 1947d36db35SAvi Kivity outregs.eax != inregs.edx || 1957d36db35SAvi Kivity outregs.edx != inregs.eax) 1967d36db35SAvi Kivity print_serial("xchg test 4: FAIL\n"); 1977d36db35SAvi Kivity else 1987d36db35SAvi Kivity print_serial("xchg test 4: PASS\n"); 1997d36db35SAvi Kivity 2007d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2017d36db35SAvi Kivity insn_xchg_test5, 2027d36db35SAvi Kivity insn_xchg_test5_end - insn_xchg_test5); 2037d36db35SAvi Kivity 2047d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_SI) || 2057d36db35SAvi Kivity outregs.eax != inregs.esi || 2067d36db35SAvi Kivity outregs.esi != inregs.eax) 2077d36db35SAvi Kivity print_serial("xchg test 5: FAIL\n"); 2087d36db35SAvi Kivity else 2097d36db35SAvi Kivity print_serial("xchg test 5: PASS\n"); 2107d36db35SAvi Kivity 2117d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2127d36db35SAvi Kivity insn_xchg_test6, 2137d36db35SAvi Kivity insn_xchg_test6_end - insn_xchg_test6); 2147d36db35SAvi Kivity 2157d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_DI) || 2167d36db35SAvi Kivity outregs.eax != inregs.edi || 2177d36db35SAvi Kivity outregs.edi != inregs.eax) 2187d36db35SAvi Kivity print_serial("xchg test 6: FAIL\n"); 2197d36db35SAvi Kivity else 2207d36db35SAvi Kivity print_serial("xchg test 6: PASS\n"); 2217d36db35SAvi Kivity 2227d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2237d36db35SAvi Kivity insn_xchg_test7, 2247d36db35SAvi Kivity insn_xchg_test7_end - insn_xchg_test7); 2257d36db35SAvi Kivity 2267d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_BP) || 2277d36db35SAvi Kivity outregs.eax != inregs.ebp || 2287d36db35SAvi Kivity outregs.ebp != inregs.eax) 2297d36db35SAvi Kivity print_serial("xchg test 7: FAIL\n"); 2307d36db35SAvi Kivity else 2317d36db35SAvi Kivity print_serial("xchg test 7: PASS\n"); 2327d36db35SAvi Kivity 2337d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2347d36db35SAvi Kivity insn_xchg_test8, 2357d36db35SAvi Kivity insn_xchg_test8_end - insn_xchg_test8); 2367d36db35SAvi Kivity 2377d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX | R_SP) || 2387d36db35SAvi Kivity outregs.eax != inregs.esp || 2397d36db35SAvi Kivity outregs.esp != inregs.eax) 2407d36db35SAvi Kivity print_serial("xchg test 8: FAIL\n"); 2417d36db35SAvi Kivity else 2427d36db35SAvi Kivity print_serial("xchg test 8: PASS\n"); 2437d36db35SAvi Kivity } 2447d36db35SAvi Kivity 2457d36db35SAvi Kivity void test_shld(void) 2467d36db35SAvi Kivity { 2477d36db35SAvi Kivity struct regs inregs = { .eax = 0xbe, .edx = 0xef000000 }, outregs; 2487d36db35SAvi Kivity MK_INSN(shld_test, "shld $8,%edx,%eax\n\t"); 2497d36db35SAvi Kivity 2507d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2517d36db35SAvi Kivity insn_shld_test, 2527d36db35SAvi Kivity insn_shld_test_end - insn_shld_test); 2537d36db35SAvi Kivity if (outregs.eax != 0xbeef) 2547d36db35SAvi Kivity print_serial("shld: FAIL\n"); 2557d36db35SAvi Kivity else 2567d36db35SAvi Kivity print_serial("shld: PASS\n"); 2577d36db35SAvi Kivity } 2587d36db35SAvi Kivity 2597d36db35SAvi Kivity void test_mov_imm(void) 2607d36db35SAvi Kivity { 2617d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 2627d36db35SAvi Kivity MK_INSN(mov_r32_imm_1, "mov $1234567890, %eax"); 2637d36db35SAvi Kivity MK_INSN(mov_r16_imm_1, "mov $1234, %ax"); 2647d36db35SAvi Kivity MK_INSN(mov_r8_imm_1, "mov $0x12, %ah"); 2657d36db35SAvi Kivity MK_INSN(mov_r8_imm_2, "mov $0x34, %al"); 2667d36db35SAvi Kivity MK_INSN(mov_r8_imm_3, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t"); 2677d36db35SAvi Kivity 2687d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2697d36db35SAvi Kivity insn_mov_r16_imm_1, 2707d36db35SAvi Kivity insn_mov_r16_imm_1_end - insn_mov_r16_imm_1); 2717d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234) 2727d36db35SAvi Kivity print_serial("mov test 1: FAIL\n"); 2737d36db35SAvi Kivity else 2747d36db35SAvi Kivity print_serial("mov test 1: PASS\n"); 2757d36db35SAvi Kivity 2767d36db35SAvi Kivity /* test mov $imm, %eax */ 2777d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2787d36db35SAvi Kivity insn_mov_r32_imm_1, 2797d36db35SAvi Kivity insn_mov_r32_imm_1_end - insn_mov_r32_imm_1); 2807d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234567890) 2817d36db35SAvi Kivity print_serial("mov test 2: FAIL\n"); 2827d36db35SAvi Kivity else 2837d36db35SAvi Kivity print_serial("mov test 2: PASS\n"); 2847d36db35SAvi Kivity 2857d36db35SAvi Kivity /* test mov $imm, %al/%ah */ 2867d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2877d36db35SAvi Kivity insn_mov_r8_imm_1, 2887d36db35SAvi Kivity insn_mov_r8_imm_1_end - insn_mov_r8_imm_1); 2897d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1200) 2907d36db35SAvi Kivity print_serial("mov test 3: FAIL\n"); 2917d36db35SAvi Kivity else 2927d36db35SAvi Kivity print_serial("mov test 3: PASS\n"); 2937d36db35SAvi Kivity 2947d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 2957d36db35SAvi Kivity insn_mov_r8_imm_2, 2967d36db35SAvi Kivity insn_mov_r8_imm_2_end - insn_mov_r8_imm_2); 2977d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x34) 2987d36db35SAvi Kivity print_serial("mov test 4: FAIL\n"); 2997d36db35SAvi Kivity else 3007d36db35SAvi Kivity print_serial("mov test 4: PASS\n"); 3017d36db35SAvi Kivity 3027d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3037d36db35SAvi Kivity insn_mov_r8_imm_3, 3047d36db35SAvi Kivity insn_mov_r8_imm_3_end - insn_mov_r8_imm_3); 3057d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 3067d36db35SAvi Kivity print_serial("mov test 5: FAIL\n"); 3077d36db35SAvi Kivity else 3087d36db35SAvi Kivity print_serial("mov test 5: PASS\n"); 3097d36db35SAvi Kivity } 3107d36db35SAvi Kivity 3117d36db35SAvi Kivity void test_sub_imm(void) 3127d36db35SAvi Kivity { 3137d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 3147d36db35SAvi Kivity MK_INSN(sub_r32_imm_1, "mov $1234567890, %eax\n\t" "sub $10, %eax\n\t"); 3157d36db35SAvi Kivity MK_INSN(sub_r16_imm_1, "mov $1234, %ax\n\t" "sub $10, %ax\n\t"); 3167d36db35SAvi Kivity MK_INSN(sub_r8_imm_1, "mov $0x12, %ah\n\t" "sub $0x10, %ah\n\t"); 3177d36db35SAvi Kivity MK_INSN(sub_r8_imm_2, "mov $0x34, %al\n\t" "sub $0x10, %al\n\t"); 3187d36db35SAvi Kivity 3197d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3207d36db35SAvi Kivity insn_sub_r16_imm_1, 3217d36db35SAvi Kivity insn_sub_r16_imm_1_end - insn_sub_r16_imm_1); 3227d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1224) 3237d36db35SAvi Kivity print_serial("sub test 1: FAIL\n"); 3247d36db35SAvi Kivity else 3257d36db35SAvi Kivity print_serial("sub test 1: PASS\n"); 3267d36db35SAvi Kivity 3277d36db35SAvi Kivity /* test mov $imm, %eax */ 3287d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3297d36db35SAvi Kivity insn_sub_r32_imm_1, 3307d36db35SAvi Kivity insn_sub_r32_imm_1_end - insn_sub_r32_imm_1); 3317d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234567880) 3327d36db35SAvi Kivity print_serial("sub test 2: FAIL\n"); 3337d36db35SAvi Kivity else 3347d36db35SAvi Kivity print_serial("sub test 2: PASS\n"); 3357d36db35SAvi Kivity 3367d36db35SAvi Kivity /* test mov $imm, %al/%ah */ 3377d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3387d36db35SAvi Kivity insn_sub_r8_imm_1, 3397d36db35SAvi Kivity insn_sub_r8_imm_1_end - insn_sub_r8_imm_1); 3407d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x0200) 3417d36db35SAvi Kivity print_serial("sub test 3: FAIL\n"); 3427d36db35SAvi Kivity else 3437d36db35SAvi Kivity print_serial("sub test 3: PASS\n"); 3447d36db35SAvi Kivity 3457d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3467d36db35SAvi Kivity insn_sub_r8_imm_2, 3477d36db35SAvi Kivity insn_sub_r8_imm_2_end - insn_sub_r8_imm_2); 3487d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x24) 3497d36db35SAvi Kivity print_serial("sub test 4: FAIL\n"); 3507d36db35SAvi Kivity else 3517d36db35SAvi Kivity print_serial("sub test 4: PASS\n"); 3527d36db35SAvi Kivity } 3537d36db35SAvi Kivity 3547d36db35SAvi Kivity 3557d36db35SAvi Kivity void test_xor_imm(void) 3567d36db35SAvi Kivity { 3577d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 3587d36db35SAvi Kivity MK_INSN(xor_r32_imm_1, "mov $1234567890, %eax\n\t" "xor $1234567890, %eax\n\t"); 3597d36db35SAvi Kivity MK_INSN(xor_r16_imm_1, "mov $1234, %ax\n\t" "xor $1234, %ax\n\t"); 3607d36db35SAvi Kivity MK_INSN(xor_r8_imm_1, "mov $0x12, %ah\n\t" "xor $0x12, %ah\n\t"); 3617d36db35SAvi Kivity MK_INSN(xor_r8_imm_2, "mov $0x34, %al\n\t" "xor $0x34, %al\n\t"); 3627d36db35SAvi Kivity 3637d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3647d36db35SAvi Kivity insn_xor_r16_imm_1, 3657d36db35SAvi Kivity insn_xor_r16_imm_1_end - insn_xor_r16_imm_1); 3667d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 3677d36db35SAvi Kivity print_serial("xor test 1: FAIL\n"); 3687d36db35SAvi Kivity else 3697d36db35SAvi Kivity print_serial("xor test 1: PASS\n"); 3707d36db35SAvi Kivity 3717d36db35SAvi Kivity /* test mov $imm, %eax */ 3727d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3737d36db35SAvi Kivity insn_xor_r32_imm_1, 3747d36db35SAvi Kivity insn_xor_r32_imm_1_end - insn_xor_r32_imm_1); 3757d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 3767d36db35SAvi Kivity print_serial("xor test 2: FAIL\n"); 3777d36db35SAvi Kivity else 3787d36db35SAvi Kivity print_serial("xor test 2: PASS\n"); 3797d36db35SAvi Kivity 3807d36db35SAvi Kivity /* test mov $imm, %al/%ah */ 3817d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3827d36db35SAvi Kivity insn_xor_r8_imm_1, 3837d36db35SAvi Kivity insn_xor_r8_imm_1_end - insn_xor_r8_imm_1); 3847d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 3857d36db35SAvi Kivity print_serial("xor test 3: FAIL\n"); 3867d36db35SAvi Kivity else 3877d36db35SAvi Kivity print_serial("xor test 3: PASS\n"); 3887d36db35SAvi Kivity 3897d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 3907d36db35SAvi Kivity insn_xor_r8_imm_2, 3917d36db35SAvi Kivity insn_xor_r8_imm_2_end - insn_xor_r8_imm_2); 3927d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 3937d36db35SAvi Kivity print_serial("xor test 4: FAIL\n"); 3947d36db35SAvi Kivity else 3957d36db35SAvi Kivity print_serial("xor test 4: PASS\n"); 3967d36db35SAvi Kivity } 3977d36db35SAvi Kivity 3987d36db35SAvi Kivity void test_cmp_imm(void) 3997d36db35SAvi Kivity { 4007d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 4017d36db35SAvi Kivity MK_INSN(cmp_test1, "mov $0x34, %al\n\t" 4027d36db35SAvi Kivity "cmp $0x34, %al\n\t"); 4037d36db35SAvi Kivity MK_INSN(cmp_test2, "mov $0x34, %al\n\t" 4047d36db35SAvi Kivity "cmp $0x39, %al\n\t"); 4057d36db35SAvi Kivity MK_INSN(cmp_test3, "mov $0x34, %al\n\t" 4067d36db35SAvi Kivity "cmp $0x24, %al\n\t"); 4077d36db35SAvi Kivity 4087d36db35SAvi Kivity /* test cmp imm8 with AL */ 4097d36db35SAvi Kivity /* ZF: (bit 6) Zero Flag becomes 1 if an operation results 4107d36db35SAvi Kivity * in a 0 writeback, or 0 register 4117d36db35SAvi Kivity */ 4127d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4137d36db35SAvi Kivity insn_cmp_test1, 4147d36db35SAvi Kivity insn_cmp_test1_end - insn_cmp_test1); 4157d36db35SAvi Kivity if ((outregs.eflags & (1<<6)) != (1<<6)) 4167d36db35SAvi Kivity print_serial("cmp test 1: FAIL\n"); 4177d36db35SAvi Kivity else 4187d36db35SAvi Kivity print_serial("cmp test 1: PASS\n"); 4197d36db35SAvi Kivity 4207d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4217d36db35SAvi Kivity insn_cmp_test2, 4227d36db35SAvi Kivity insn_cmp_test2_end - insn_cmp_test2); 4237d36db35SAvi Kivity if ((outregs.eflags & (1<<6)) != 0) 4247d36db35SAvi Kivity print_serial("cmp test 2: FAIL\n"); 4257d36db35SAvi Kivity else 4267d36db35SAvi Kivity print_serial("cmp test 2: PASS\n"); 4277d36db35SAvi Kivity 4287d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4297d36db35SAvi Kivity insn_cmp_test3, 4307d36db35SAvi Kivity insn_cmp_test3_end - insn_cmp_test3); 4317d36db35SAvi Kivity if ((outregs.eflags & (1<<6)) != 0) 4327d36db35SAvi Kivity print_serial("cmp test 3: FAIL\n"); 4337d36db35SAvi Kivity else 4347d36db35SAvi Kivity print_serial("cmp test 3: PASS\n"); 4357d36db35SAvi Kivity } 4367d36db35SAvi Kivity 4377d36db35SAvi Kivity void test_add_imm(void) 4387d36db35SAvi Kivity { 4397d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 4407d36db35SAvi Kivity MK_INSN(add_test1, "mov $0x43211234, %eax \n\t" 4417d36db35SAvi Kivity "add $0x12344321, %eax \n\t"); 4427d36db35SAvi Kivity MK_INSN(add_test2, "mov $0x12, %eax \n\t" 4437d36db35SAvi Kivity "add $0x21, %al\n\t"); 4447d36db35SAvi Kivity 4457d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4467d36db35SAvi Kivity insn_add_test1, 4477d36db35SAvi Kivity insn_add_test1_end - insn_add_test1); 4487d36db35SAvi Kivity if (outregs.eax != 0x55555555) 4497d36db35SAvi Kivity print_serial("add test 1: FAIL\n"); 4507d36db35SAvi Kivity else 4517d36db35SAvi Kivity print_serial("add test 1: PASS\n"); 4527d36db35SAvi Kivity 4537d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4547d36db35SAvi Kivity insn_add_test2, 4557d36db35SAvi Kivity insn_add_test2_end - insn_add_test2); 4567d36db35SAvi Kivity if (outregs.eax != 0x33) 4577d36db35SAvi Kivity print_serial("add test 2: FAIL\n"); 4587d36db35SAvi Kivity else 4597d36db35SAvi Kivity print_serial("add test 2: PASS\n"); 4607d36db35SAvi Kivity } 4617d36db35SAvi Kivity 4627d36db35SAvi Kivity void test_eflags_insn(void) 4637d36db35SAvi Kivity { 4647d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 4657d36db35SAvi Kivity MK_INSN(clc, "clc"); 466b3261e48SMohammed Gamal MK_INSN(stc, "stc"); 4677d36db35SAvi Kivity MK_INSN(cli, "cli"); 4687d36db35SAvi Kivity MK_INSN(sti, "sti"); 4697d36db35SAvi Kivity MK_INSN(cld, "cld"); 4707d36db35SAvi Kivity MK_INSN(std, "std"); 4717d36db35SAvi Kivity 4727d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4737d36db35SAvi Kivity insn_clc, 4747d36db35SAvi Kivity insn_clc_end - insn_clc); 4757d36db35SAvi Kivity if (outregs.eflags & 1) 4767d36db35SAvi Kivity print_serial("clc test: FAIL\n"); 4777d36db35SAvi Kivity else 4787d36db35SAvi Kivity print_serial("clc test: PASS\n"); 4797d36db35SAvi Kivity 4807d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 481b3261e48SMohammed Gamal insn_stc, 482b3261e48SMohammed Gamal insn_stc_end - insn_stc); 483b3261e48SMohammed Gamal if (!(outregs.eflags & 1)) 484b3261e48SMohammed Gamal print_serial("stc test: FAIL\n"); 485b3261e48SMohammed Gamal else 486b3261e48SMohammed Gamal print_serial("stc test: PASS\n"); 487b3261e48SMohammed Gamal 488b3261e48SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 4897d36db35SAvi Kivity insn_cli, 4907d36db35SAvi Kivity insn_cli_end - insn_cli); 4917d36db35SAvi Kivity if (outregs.eflags & (1 << 9)) 4927d36db35SAvi Kivity print_serial("cli test: FAIL\n"); 4937d36db35SAvi Kivity else 4947d36db35SAvi Kivity print_serial("cli test: PASS\n"); 4957d36db35SAvi Kivity 4967d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4977d36db35SAvi Kivity insn_sti, 4987d36db35SAvi Kivity insn_sti_end - insn_sti); 4997d36db35SAvi Kivity if (!(outregs.eflags & (1 << 9))) 5007d36db35SAvi Kivity print_serial("sti test: FAIL\n"); 5017d36db35SAvi Kivity else 5027d36db35SAvi Kivity print_serial("sti test: PASS\n"); 5037d36db35SAvi Kivity 5047d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5057d36db35SAvi Kivity insn_cld, 5067d36db35SAvi Kivity insn_cld_end - insn_cld); 5077d36db35SAvi Kivity if (outregs.eflags & (1 << 10)) 5087d36db35SAvi Kivity print_serial("cld test: FAIL\n"); 5097d36db35SAvi Kivity else 5107d36db35SAvi Kivity print_serial("cld test: PASS\n"); 5117d36db35SAvi Kivity 5127d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5137d36db35SAvi Kivity insn_std, 5147d36db35SAvi Kivity insn_std_end - insn_std); 5157d36db35SAvi Kivity if (!(outregs.eflags & (1 << 10))) 5167d36db35SAvi Kivity print_serial("std test: FAIL\n"); 5177d36db35SAvi Kivity else 5187d36db35SAvi Kivity print_serial("std test: PASS\n"); 5197d36db35SAvi Kivity } 5207d36db35SAvi Kivity 5217d36db35SAvi Kivity void test_io(void) 5227d36db35SAvi Kivity { 5237d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 5247d36db35SAvi Kivity MK_INSN(io_test1, "mov $0xff, %al \n\t" 5257d36db35SAvi Kivity "out %al, $0xe0 \n\t" 5267d36db35SAvi Kivity "mov $0x00, %al \n\t" 5277d36db35SAvi Kivity "in $0xe0, %al \n\t"); 5287d36db35SAvi Kivity MK_INSN(io_test2, "mov $0xffff, %ax \n\t" 5297d36db35SAvi Kivity "out %ax, $0xe0 \n\t" 5307d36db35SAvi Kivity "mov $0x0000, %ax \n\t" 5317d36db35SAvi Kivity "in $0xe0, %ax \n\t"); 5327d36db35SAvi Kivity MK_INSN(io_test3, "mov $0xffffffff, %eax \n\t" 5337d36db35SAvi Kivity "out %eax, $0xe0 \n\t" 5347d36db35SAvi Kivity "mov $0x000000, %eax \n\t" 5357d36db35SAvi Kivity "in $0xe0, %eax \n\t"); 5367d36db35SAvi Kivity MK_INSN(io_test4, "mov $0xe0, %dx \n\t" 5377d36db35SAvi Kivity "mov $0xff, %al \n\t" 5387d36db35SAvi Kivity "out %al, %dx \n\t" 5397d36db35SAvi Kivity "mov $0x00, %al \n\t" 5407d36db35SAvi Kivity "in %dx, %al \n\t"); 5417d36db35SAvi Kivity MK_INSN(io_test5, "mov $0xe0, %dx \n\t" 5427d36db35SAvi Kivity "mov $0xffff, %ax \n\t" 5437d36db35SAvi Kivity "out %ax, %dx \n\t" 5447d36db35SAvi Kivity "mov $0x0000, %ax \n\t" 5457d36db35SAvi Kivity "in %dx, %ax \n\t"); 5467d36db35SAvi Kivity MK_INSN(io_test6, "mov $0xe0, %dx \n\t" 5477d36db35SAvi Kivity "mov $0xffffffff, %eax \n\t" 5487d36db35SAvi Kivity "out %eax, %dx \n\t" 5497d36db35SAvi Kivity "mov $0x00000000, %eax \n\t" 5507d36db35SAvi Kivity "in %dx, %eax \n\t"); 5517d36db35SAvi Kivity 5527d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5537d36db35SAvi Kivity insn_io_test1, 5547d36db35SAvi Kivity insn_io_test1_end - insn_io_test1); 5557d36db35SAvi Kivity 5567d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xff) 5577d36db35SAvi Kivity print_serial("I/O test 1: FAIL\n"); 5587d36db35SAvi Kivity else 5597d36db35SAvi Kivity print_serial("I/O test 1: PASS\n"); 5607d36db35SAvi Kivity 5617d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5627d36db35SAvi Kivity insn_io_test2, 5637d36db35SAvi Kivity insn_io_test2_end - insn_io_test2); 5647d36db35SAvi Kivity 5657d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffff) 5667d36db35SAvi Kivity print_serial("I/O test 2: FAIL\n"); 5677d36db35SAvi Kivity else 5687d36db35SAvi Kivity print_serial("I/O test 2: PASS\n"); 5697d36db35SAvi Kivity 5707d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5717d36db35SAvi Kivity insn_io_test3, 5727d36db35SAvi Kivity insn_io_test3_end - insn_io_test3); 5737d36db35SAvi Kivity 5747d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffffffff) 5757d36db35SAvi Kivity print_serial("I/O test 3: FAIL\n"); 5767d36db35SAvi Kivity else 5777d36db35SAvi Kivity print_serial("I/O test 3: PASS\n"); 5787d36db35SAvi Kivity 5797d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5807d36db35SAvi Kivity insn_io_test4, 5817d36db35SAvi Kivity insn_io_test4_end - insn_io_test4); 5827d36db35SAvi Kivity 5837d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xff) 5847d36db35SAvi Kivity print_serial("I/O test 4: FAIL\n"); 5857d36db35SAvi Kivity else 5867d36db35SAvi Kivity print_serial("I/O test 4: PASS\n"); 5877d36db35SAvi Kivity 5887d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5897d36db35SAvi Kivity insn_io_test5, 5907d36db35SAvi Kivity insn_io_test5_end - insn_io_test5); 5917d36db35SAvi Kivity 5927d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffff) 5937d36db35SAvi Kivity print_serial("I/O test 5: FAIL\n"); 5947d36db35SAvi Kivity else 5957d36db35SAvi Kivity print_serial("I/O test 5: PASS\n"); 5967d36db35SAvi Kivity 5977d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5987d36db35SAvi Kivity insn_io_test6, 5997d36db35SAvi Kivity insn_io_test6_end - insn_io_test6); 6007d36db35SAvi Kivity 6017d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffffffff) 6027d36db35SAvi Kivity print_serial("I/O test 6: FAIL\n"); 6037d36db35SAvi Kivity else 6047d36db35SAvi Kivity print_serial("I/O test 6: PASS\n"); 6057d36db35SAvi Kivity } 6067d36db35SAvi Kivity 6077d36db35SAvi Kivity void test_call(void) 6087d36db35SAvi Kivity { 6097d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 6107d36db35SAvi Kivity u32 esp[16]; 6117d36db35SAvi Kivity 6127d36db35SAvi Kivity inregs.esp = (u32)esp; 6137d36db35SAvi Kivity 6147d36db35SAvi Kivity MK_INSN(call1, "mov $test_function, %eax \n\t" 6157d36db35SAvi Kivity "call *%eax\n\t"); 6167d36db35SAvi Kivity MK_INSN(call_near1, "jmp 2f\n\t" 6177d36db35SAvi Kivity "1: mov $0x1234, %eax\n\t" 6187d36db35SAvi Kivity "ret\n\t" 6197d36db35SAvi Kivity "2: call 1b\t"); 6207d36db35SAvi Kivity MK_INSN(call_near2, "call 1f\n\t" 6217d36db35SAvi Kivity "jmp 2f\n\t" 6227d36db35SAvi Kivity "1: mov $0x1234, %eax\n\t" 6237d36db35SAvi Kivity "ret\n\t" 6247d36db35SAvi Kivity "2:\t"); 6257d36db35SAvi Kivity 6267d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6277d36db35SAvi Kivity insn_call1, 6287d36db35SAvi Kivity insn_call1_end - insn_call1); 6297d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 6307d36db35SAvi Kivity print_serial("Call Test 1: FAIL\n"); 6317d36db35SAvi Kivity else 6327d36db35SAvi Kivity print_serial("Call Test 1: PASS\n"); 6337d36db35SAvi Kivity 6347d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6357d36db35SAvi Kivity insn_call_near1, insn_call_near1_end - insn_call_near1); 6367d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 6377d36db35SAvi Kivity print_serial("Call near Test 1: FAIL\n"); 6387d36db35SAvi Kivity else 6397d36db35SAvi Kivity print_serial("Call near Test 1: PASS\n"); 6407d36db35SAvi Kivity 6417d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6427d36db35SAvi Kivity insn_call_near2, insn_call_near2_end - insn_call_near2); 6437d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 6447d36db35SAvi Kivity print_serial("Call near Test 2: FAIL\n"); 6457d36db35SAvi Kivity else 6467d36db35SAvi Kivity print_serial("Call near Test 2: PASS\n"); 6477d36db35SAvi Kivity } 6487d36db35SAvi Kivity 6497d36db35SAvi Kivity void test_jcc_short(void) 6507d36db35SAvi Kivity { 6517d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 6527d36db35SAvi Kivity MK_INSN(jnz_short1, "jnz 1f\n\t" 6537d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 6547d36db35SAvi Kivity "1:\n\t"); 6557d36db35SAvi Kivity MK_INSN(jnz_short2, "1:\n\t" 6567d36db35SAvi Kivity "cmp $0x1234, %eax\n\t" 6577d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 6587d36db35SAvi Kivity "jnz 1b\n\t"); 6597d36db35SAvi Kivity MK_INSN(jmp_short1, "jmp 1f\n\t" 6607d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 6617d36db35SAvi Kivity "1:\n\t"); 6627d36db35SAvi Kivity 6637d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6647d36db35SAvi Kivity insn_jnz_short1, insn_jnz_short1_end - insn_jnz_short1); 6657d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, 0)) 6667d36db35SAvi Kivity print_serial("JNZ short Test 1: FAIL\n"); 6677d36db35SAvi Kivity else 6687d36db35SAvi Kivity print_serial("JNZ short Test 1: PASS\n"); 6697d36db35SAvi Kivity 6707d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6717d36db35SAvi Kivity insn_jnz_short2, insn_jnz_short2_end - insn_jnz_short2); 6727d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6))) 6737d36db35SAvi Kivity print_serial("JNZ short Test 2: FAIL\n"); 6747d36db35SAvi Kivity else 6757d36db35SAvi Kivity print_serial("JNZ short Test 2: PASS\n"); 6767d36db35SAvi Kivity 6777d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6787d36db35SAvi Kivity insn_jmp_short1, insn_jmp_short1_end - insn_jmp_short1); 6797d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, 0)) 6807d36db35SAvi Kivity print_serial("JMP short Test 1: FAIL\n"); 6817d36db35SAvi Kivity else 6827d36db35SAvi Kivity print_serial("JMP short Test 1: PASS\n"); 6837d36db35SAvi Kivity } 6847d36db35SAvi Kivity 6857d36db35SAvi Kivity void test_jcc_near(void) 6867d36db35SAvi Kivity { 6877d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 6887d36db35SAvi Kivity /* encode near jmp manually. gas will not do it if offsets < 127 byte */ 6897d36db35SAvi Kivity MK_INSN(jnz_near1, ".byte 0x0f, 0x85, 0x06, 0x00\n\t" 6907d36db35SAvi Kivity "mov $0x1234, %eax\n\t"); 6917d36db35SAvi Kivity MK_INSN(jnz_near2, "cmp $0x1234, %eax\n\t" 6927d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 6937d36db35SAvi Kivity ".byte 0x0f, 0x85, 0xf0, 0xff\n\t"); 6947d36db35SAvi Kivity MK_INSN(jmp_near1, ".byte 0xE9, 0x06, 0x00\n\t" 6957d36db35SAvi Kivity "mov $0x1234, %eax\n\t"); 6967d36db35SAvi Kivity 6977d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6987d36db35SAvi Kivity insn_jnz_near1, insn_jnz_near1_end - insn_jnz_near1); 6997d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, 0)) 7007d36db35SAvi Kivity print_serial("JNZ near Test 1: FAIL\n"); 7017d36db35SAvi Kivity else 7027d36db35SAvi Kivity print_serial("JNZ near Test 1: PASS\n"); 7037d36db35SAvi Kivity 7047d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7057d36db35SAvi Kivity insn_jnz_near2, insn_jnz_near2_end - insn_jnz_near2); 7067d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6))) 7077d36db35SAvi Kivity print_serial("JNZ near Test 2: FAIL\n"); 7087d36db35SAvi Kivity else 7097d36db35SAvi Kivity print_serial("JNZ near Test 2: PASS\n"); 7107d36db35SAvi Kivity 7117d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7127d36db35SAvi Kivity insn_jmp_near1, insn_jmp_near1_end - insn_jmp_near1); 7137d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, 0)) 7147d36db35SAvi Kivity print_serial("JMP near Test 1: FAIL\n"); 7157d36db35SAvi Kivity else 7167d36db35SAvi Kivity print_serial("JMP near Test 1: PASS\n"); 7177d36db35SAvi Kivity } 7187d36db35SAvi Kivity 7197d36db35SAvi Kivity void test_long_jmp() 7207d36db35SAvi Kivity { 7217d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 7227d36db35SAvi Kivity u32 esp[16]; 7237d36db35SAvi Kivity 7247d36db35SAvi Kivity inregs.esp = (u32)esp; 7257d36db35SAvi Kivity MK_INSN(long_jmp, "call 1f\n\t" 7267d36db35SAvi Kivity "jmp 2f\n\t" 7277d36db35SAvi Kivity "1: jmp $0, $test_function\n\t" 7287d36db35SAvi Kivity "2:\n\t"); 7297d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7307d36db35SAvi Kivity insn_long_jmp, 7317d36db35SAvi Kivity insn_long_jmp_end - insn_long_jmp); 7327d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 7337d36db35SAvi Kivity print_serial("Long JMP Test: FAIL\n"); 7347d36db35SAvi Kivity else 7357d36db35SAvi Kivity print_serial("Long JMP Test: PASS\n"); 7367d36db35SAvi Kivity } 737fa74f8a6SMohammed Gamal 7387d36db35SAvi Kivity void test_push_pop() 7397d36db35SAvi Kivity { 7407d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 7417d36db35SAvi Kivity MK_INSN(push32, "mov $0x12345678, %eax\n\t" 7427d36db35SAvi Kivity "push %eax\n\t" 7437d36db35SAvi Kivity "pop %ebx\n\t"); 7447d36db35SAvi Kivity MK_INSN(push16, "mov $0x1234, %ax\n\t" 7457d36db35SAvi Kivity "push %ax\n\t" 7467d36db35SAvi Kivity "pop %bx\n\t"); 7477d36db35SAvi Kivity 7487d36db35SAvi Kivity MK_INSN(push_es, "mov $0x231, %bx\n\t" //Just write a dummy value to see if it gets overwritten 7497d36db35SAvi Kivity "mov $0x123, %ax\n\t" 7507d36db35SAvi Kivity "mov %ax, %es\n\t" 7517d36db35SAvi Kivity "push %es\n\t" 7527d36db35SAvi Kivity "pop %bx \n\t" 7537d36db35SAvi Kivity ); 7547d36db35SAvi Kivity MK_INSN(pop_es, "push %ax\n\t" 7557d36db35SAvi Kivity "pop %es\n\t" 7567d36db35SAvi Kivity "mov %es, %bx\n\t" 7577d36db35SAvi Kivity ); 7587d36db35SAvi Kivity MK_INSN(push_pop_ss, "push %ss\n\t" 7597d36db35SAvi Kivity "pushw %ax\n\t" 7607d36db35SAvi Kivity "popw %ss\n\t" 7617d36db35SAvi Kivity "mov %ss, %bx\n\t" 7627d36db35SAvi Kivity "pop %ss\n\t" 7637d36db35SAvi Kivity ); 7647d36db35SAvi Kivity MK_INSN(push_pop_fs, "push %fs\n\t" 7657d36db35SAvi Kivity "pushl %eax\n\t" 7667d36db35SAvi Kivity "popl %fs\n\t" 7677d36db35SAvi Kivity "mov %fs, %ebx\n\t" 7687d36db35SAvi Kivity "pop %fs\n\t" 7697d36db35SAvi Kivity ); 7707d36db35SAvi Kivity 7717d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7727d36db35SAvi Kivity insn_push32, 7737d36db35SAvi Kivity insn_push32_end - insn_push32); 7747d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x12345678) 7757d36db35SAvi Kivity print_serial("Push/Pop Test 1: FAIL\n"); 7767d36db35SAvi Kivity else 7777d36db35SAvi Kivity print_serial("Push/Pop Test 1: PASS\n"); 7787d36db35SAvi Kivity 7797d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7807d36db35SAvi Kivity insn_push16, 7817d36db35SAvi Kivity insn_push16_end - insn_push16); 7827d36db35SAvi Kivity 7837d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x1234) 7847d36db35SAvi Kivity print_serial("Push/Pop Test 2: FAIL\n"); 7857d36db35SAvi Kivity else 7867d36db35SAvi Kivity print_serial("Push/Pop Test 2: PASS\n"); 7877d36db35SAvi Kivity 7887d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7897d36db35SAvi Kivity insn_push_es, 7907d36db35SAvi Kivity insn_push_es_end - insn_push_es); 7917d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax || outregs.eax != 0x123) 7927d36db35SAvi Kivity print_serial("Push/Pop Test 3: FAIL\n"); 7937d36db35SAvi Kivity else 7947d36db35SAvi Kivity print_serial("Push/Pop Test 3: PASS\n"); 7957d36db35SAvi Kivity 7967d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7977d36db35SAvi Kivity insn_pop_es, 7987d36db35SAvi Kivity insn_pop_es_end - insn_pop_es); 7997d36db35SAvi Kivity 8007d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 8017d36db35SAvi Kivity print_serial("Push/Pop Test 4: FAIL\n"); 8027d36db35SAvi Kivity else 8037d36db35SAvi Kivity print_serial("Push/Pop Test 4: PASS\n"); 8047d36db35SAvi Kivity 8057d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 8067d36db35SAvi Kivity insn_push_pop_ss, 8077d36db35SAvi Kivity insn_push_pop_ss_end - insn_push_pop_ss); 8087d36db35SAvi Kivity 8097d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 8107d36db35SAvi Kivity print_serial("Push/Pop Test 5: FAIL\n"); 8117d36db35SAvi Kivity else 8127d36db35SAvi Kivity print_serial("Push/Pop Test 5: PASS\n"); 8137d36db35SAvi Kivity 8147d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 8157d36db35SAvi Kivity insn_push_pop_fs, 8167d36db35SAvi Kivity insn_push_pop_fs_end - insn_push_pop_fs); 8177d36db35SAvi Kivity 8187d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 8197d36db35SAvi Kivity print_serial("Push/Pop Test 6: FAIL\n"); 8207d36db35SAvi Kivity else 8217d36db35SAvi Kivity print_serial("Push/Pop Test 6: PASS\n"); 8227d36db35SAvi Kivity } 8237d36db35SAvi Kivity 8247d36db35SAvi Kivity void test_null(void) 8257d36db35SAvi Kivity { 8267d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 8277d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 0, 0); 8287d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 8297d36db35SAvi Kivity print_serial("null test: FAIL\n"); 8307d36db35SAvi Kivity else 8317d36db35SAvi Kivity print_serial("null test: PASS\n"); 8327d36db35SAvi Kivity } 8337d36db35SAvi Kivity 8347d36db35SAvi Kivity struct { 8357d36db35SAvi Kivity char stack[500]; 8367d36db35SAvi Kivity char top[]; 8377d36db35SAvi Kivity } tmp_stack; 8387d36db35SAvi Kivity 8397d36db35SAvi Kivity void test_pusha_popa() 8407d36db35SAvi Kivity { 8417d36db35SAvi 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; 8427d36db35SAvi Kivity 8437d36db35SAvi Kivity MK_INSN(pusha, "pusha\n\t" 8447d36db35SAvi Kivity "pop %edi\n\t" 8457d36db35SAvi Kivity "pop %esi\n\t" 8467d36db35SAvi Kivity "pop %ebp\n\t" 8477d36db35SAvi Kivity "add $4, %esp\n\t" 8487d36db35SAvi Kivity "pop %ebx\n\t" 8497d36db35SAvi Kivity "pop %edx\n\t" 8507d36db35SAvi Kivity "pop %ecx\n\t" 8517d36db35SAvi Kivity "pop %eax\n\t" 8527d36db35SAvi Kivity ); 8537d36db35SAvi Kivity 8547d36db35SAvi Kivity MK_INSN(popa, "push %eax\n\t" 8557d36db35SAvi Kivity "push %ecx\n\t" 8567d36db35SAvi Kivity "push %edx\n\t" 8577d36db35SAvi Kivity "push %ebx\n\t" 8587d36db35SAvi Kivity "push %esp\n\t" 8597d36db35SAvi Kivity "push %ebp\n\t" 8607d36db35SAvi Kivity "push %esi\n\t" 8617d36db35SAvi Kivity "push %edi\n\t" 8627d36db35SAvi Kivity "popa\n\t" 8637d36db35SAvi Kivity ); 8647d36db35SAvi Kivity 8657d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 8667d36db35SAvi Kivity insn_pusha, 8677d36db35SAvi Kivity insn_pusha_end - insn_pusha); 8687d36db35SAvi Kivity 8697d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 8707d36db35SAvi Kivity print_serial("Pusha/Popa Test1: FAIL\n"); 8717d36db35SAvi Kivity else 8727d36db35SAvi Kivity print_serial("Pusha/Popa Test1: PASS\n"); 8737d36db35SAvi Kivity 8747d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 8757d36db35SAvi Kivity insn_popa, 8767d36db35SAvi Kivity insn_popa_end - insn_popa); 8777d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 8787d36db35SAvi Kivity print_serial("Pusha/Popa Test2: FAIL\n"); 8797d36db35SAvi Kivity else 8807d36db35SAvi Kivity print_serial("Pusha/Popa Test2: PASS\n"); 8817d36db35SAvi Kivity } 8827d36db35SAvi Kivity 8837d36db35SAvi Kivity void test_iret() 8847d36db35SAvi Kivity { 8857d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 8867d36db35SAvi Kivity 8877d36db35SAvi Kivity MK_INSN(iret32, "pushf\n\t" 8887d36db35SAvi Kivity "pushl %cs\n\t" 8897d36db35SAvi Kivity "call 1f\n\t" /* a near call will push eip onto the stack */ 8907d36db35SAvi Kivity "jmp 2f\n\t" 8917d36db35SAvi Kivity "1: iret\n\t" 8927d36db35SAvi Kivity "2:\n\t" 8937d36db35SAvi Kivity ); 8947d36db35SAvi Kivity 8957d36db35SAvi Kivity MK_INSN(iret16, "pushfw\n\t" 8967d36db35SAvi Kivity "pushw %cs\n\t" 8977d36db35SAvi Kivity "callw 1f\n\t" 8987d36db35SAvi Kivity "jmp 2f\n\t" 8997d36db35SAvi Kivity "1: iretw\n\t" 9007d36db35SAvi Kivity "2:\n\t"); 9017d36db35SAvi Kivity 9027d36db35SAvi Kivity MK_INSN(iret_flags32, "pushfl\n\t" 9037d36db35SAvi Kivity "popl %eax\n\t" 9047d36db35SAvi Kivity "andl $~0x2, %eax\n\t" 9057d36db35SAvi Kivity "orl $0xffc08028, %eax\n\t" 9067d36db35SAvi Kivity "pushl %eax\n\t" 9077d36db35SAvi Kivity "pushl %cs\n\t" 9087d36db35SAvi Kivity "call 1f\n\t" 9097d36db35SAvi Kivity "jmp 2f\n\t" 9107d36db35SAvi Kivity "1: iret\n\t" 9117d36db35SAvi Kivity "2:\n\t"); 9127d36db35SAvi Kivity 9137d36db35SAvi Kivity MK_INSN(iret_flags16, "pushfw\n\t" 9147d36db35SAvi Kivity "popw %ax\n\t" 9157d36db35SAvi Kivity "and $~0x2, %ax\n\t" 9167d36db35SAvi Kivity "or $0x8028, %ax\n\t" 9177d36db35SAvi Kivity "pushw %ax\n\t" 9187d36db35SAvi Kivity "pushw %cs\n\t" 9197d36db35SAvi Kivity "callw 1f\n\t" 9207d36db35SAvi Kivity "jmp 2f\n\t" 9217d36db35SAvi Kivity "1: iretw\n\t" 9227d36db35SAvi Kivity "2:\n\t"); 9237d36db35SAvi Kivity 9247d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 9257d36db35SAvi Kivity insn_iret32, 9267d36db35SAvi Kivity insn_iret32_end - insn_iret32); 9277d36db35SAvi Kivity 9287d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 9297d36db35SAvi Kivity print_serial("iret Test 1: FAIL\n"); 9307d36db35SAvi Kivity else 9317d36db35SAvi Kivity print_serial("iret Test 1: PASS\n"); 9327d36db35SAvi Kivity 9337d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 9347d36db35SAvi Kivity insn_iret16, 9357d36db35SAvi Kivity insn_iret16_end - insn_iret16); 9367d36db35SAvi Kivity 9377d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 9387d36db35SAvi Kivity print_serial("iret Test 2: FAIL\n"); 9397d36db35SAvi Kivity else 9407d36db35SAvi Kivity print_serial("iret Test 2: PASS\n"); 9417d36db35SAvi Kivity 9427d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 9437d36db35SAvi Kivity insn_iret_flags32, 9447d36db35SAvi Kivity insn_iret_flags32_end - insn_iret_flags32); 9457d36db35SAvi Kivity 9467d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX)) 9477d36db35SAvi Kivity print_serial("iret Test 3: FAIL\n"); 9487d36db35SAvi Kivity else 9497d36db35SAvi Kivity print_serial("iret Test 3: PASS\n"); 9507d36db35SAvi Kivity 9517d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 9527d36db35SAvi Kivity insn_iret_flags16, 9537d36db35SAvi Kivity insn_iret_flags16_end - insn_iret_flags16); 9547d36db35SAvi Kivity 9557d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX)) 9567d36db35SAvi Kivity print_serial("iret Test 4: FAIL\n"); 9577d36db35SAvi Kivity else 9587d36db35SAvi Kivity print_serial("iret Test 4: PASS\n"); 9597d36db35SAvi Kivity } 9607d36db35SAvi Kivity 96196b9ca1eSMohammed Gamal void test_int() 96296b9ca1eSMohammed Gamal { 96396b9ca1eSMohammed Gamal struct regs inregs = { 0 }, outregs; 96496b9ca1eSMohammed Gamal 96596b9ca1eSMohammed Gamal *(u32 *)(0x11 * 4) = 0x1000; /* Store a pointer to address 0x1000 in IDT entry 0x11 */ 96696b9ca1eSMohammed Gamal *(u8 *)(0x1000) = 0xcf; /* 0x1000 contains an IRET instruction */ 96796b9ca1eSMohammed Gamal 96896b9ca1eSMohammed Gamal MK_INSN(int11, "int $0x11\n\t"); 96996b9ca1eSMohammed Gamal 97096b9ca1eSMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 97196b9ca1eSMohammed Gamal insn_int11, 97296b9ca1eSMohammed Gamal insn_int11_end - insn_int11); 97396b9ca1eSMohammed Gamal 97496b9ca1eSMohammed Gamal if (!regs_equal(&inregs, &outregs, 0)) 97596b9ca1eSMohammed Gamal print_serial("int Test 1: FAIL\n"); 97696b9ca1eSMohammed Gamal else 97796b9ca1eSMohammed Gamal print_serial("int Test 1: PASS\n"); 97896b9ca1eSMohammed Gamal } 97996b9ca1eSMohammed Gamal 980fa74f8a6SMohammed Gamal void test_imul() 981fa74f8a6SMohammed Gamal { 982fa74f8a6SMohammed Gamal struct regs inregs = { 0 }, outregs; 983fa74f8a6SMohammed Gamal 984fa74f8a6SMohammed Gamal MK_INSN(imul8_1, "mov $2, %al\n\t" 985fa74f8a6SMohammed Gamal "mov $-4, %cx\n\t" 986fa74f8a6SMohammed Gamal "imul %cl\n\t"); 987fa74f8a6SMohammed Gamal 988fa74f8a6SMohammed Gamal MK_INSN(imul16_1, "mov $2, %ax\n\t" 989fa74f8a6SMohammed Gamal "mov $-4, %cx\n\t" 990fa74f8a6SMohammed Gamal "imul %cx\n\t"); 991fa74f8a6SMohammed Gamal 992fa74f8a6SMohammed Gamal MK_INSN(imul32_1, "mov $2, %eax\n\t" 993fa74f8a6SMohammed Gamal "mov $-4, %ecx\n\t" 994fa74f8a6SMohammed Gamal "imul %ecx\n\t"); 995fa74f8a6SMohammed Gamal 996fa74f8a6SMohammed Gamal MK_INSN(imul8_2, "mov $0x12340002, %eax\n\t" 997fa74f8a6SMohammed Gamal "mov $4, %cx\n\t" 998fa74f8a6SMohammed Gamal "imul %cl\n\t"); 999fa74f8a6SMohammed Gamal 1000fa74f8a6SMohammed Gamal MK_INSN(imul16_2, "mov $2, %ax\n\t" 1001fa74f8a6SMohammed Gamal "mov $4, %cx\n\t" 1002fa74f8a6SMohammed Gamal "imul %cx\n\t"); 1003fa74f8a6SMohammed Gamal 1004fa74f8a6SMohammed Gamal MK_INSN(imul32_2, "mov $2, %eax\n\t" 1005fa74f8a6SMohammed Gamal "mov $4, %ecx\n\t" 1006fa74f8a6SMohammed Gamal "imul %ecx\n\t"); 1007fa74f8a6SMohammed Gamal 1008fa74f8a6SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 1009fa74f8a6SMohammed Gamal insn_imul8_1, 1010fa74f8a6SMohammed Gamal insn_imul8_1_end - insn_imul8_1); 1011fa74f8a6SMohammed Gamal 1012fa74f8a6SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || (outregs.eax & 0xff) != (u8)-8) 1013fa74f8a6SMohammed Gamal print_serial("imul Test 1: FAIL\n"); 1014fa74f8a6SMohammed Gamal else 1015fa74f8a6SMohammed Gamal print_serial("imul Test 1: PASS\n"); 1016fa74f8a6SMohammed Gamal 1017fa74f8a6SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 1018fa74f8a6SMohammed Gamal insn_imul16_1, 1019fa74f8a6SMohammed Gamal insn_imul16_1_end - insn_imul16_1); 1020fa74f8a6SMohammed Gamal 1021fa74f8a6SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u16)-8) 1022fa74f8a6SMohammed Gamal print_serial("imul Test 2: FAIL\n"); 1023fa74f8a6SMohammed Gamal else 1024fa74f8a6SMohammed Gamal print_serial("imul Test 2: PASS\n"); 1025fa74f8a6SMohammed Gamal 1026fa74f8a6SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 1027fa74f8a6SMohammed Gamal insn_imul32_1, 1028fa74f8a6SMohammed Gamal insn_imul32_1_end - insn_imul32_1); 1029fa74f8a6SMohammed Gamal 1030fa74f8a6SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u32)-8) 1031fa74f8a6SMohammed Gamal print_serial("imul Test 3: FAIL\n"); 1032fa74f8a6SMohammed Gamal else 1033fa74f8a6SMohammed Gamal print_serial("imul Test 3: PASS\n"); 1034fa74f8a6SMohammed Gamal 1035fa74f8a6SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 1036fa74f8a6SMohammed Gamal insn_imul8_2, 1037fa74f8a6SMohammed Gamal insn_imul8_2_end - insn_imul8_2); 1038fa74f8a6SMohammed Gamal 1039fa74f8a6SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || (outregs.eax & 0xffff) != 8 || 1040fa74f8a6SMohammed Gamal (outregs.eax & 0xffff0000) != 0x12340000) 1041fa74f8a6SMohammed Gamal print_serial("imul Test 4: FAIL\n"); 1042fa74f8a6SMohammed Gamal else 1043fa74f8a6SMohammed Gamal print_serial("imul Test 4: PASS\n"); 1044fa74f8a6SMohammed Gamal 1045fa74f8a6SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 1046fa74f8a6SMohammed Gamal insn_imul16_2, 1047fa74f8a6SMohammed Gamal insn_imul16_2_end - insn_imul16_2); 1048fa74f8a6SMohammed Gamal 1049fa74f8a6SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 8) 1050fa74f8a6SMohammed Gamal print_serial("imul Test 5: FAIL\n"); 1051fa74f8a6SMohammed Gamal else 1052fa74f8a6SMohammed Gamal print_serial("imul Test 5: PASS\n"); 1053fa74f8a6SMohammed Gamal 1054fa74f8a6SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 1055fa74f8a6SMohammed Gamal insn_imul32_2, 1056fa74f8a6SMohammed Gamal insn_imul32_2_end - insn_imul32_2); 1057fa74f8a6SMohammed Gamal 1058fa74f8a6SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 8) 1059fa74f8a6SMohammed Gamal print_serial("imul Test 6: FAIL\n"); 1060fa74f8a6SMohammed Gamal else 1061fa74f8a6SMohammed Gamal print_serial("imul Test 6: PASS\n"); 1062fa74f8a6SMohammed Gamal } 1063fa74f8a6SMohammed Gamal 106459317bd1SMohammed Gamal void test_mul() 106559317bd1SMohammed Gamal { 106659317bd1SMohammed Gamal struct regs inregs = { 0 }, outregs; 106759317bd1SMohammed Gamal 106859317bd1SMohammed Gamal MK_INSN(mul8, "mov $2, %al\n\t" 106959317bd1SMohammed Gamal "mov $4, %cx\n\t" 107059317bd1SMohammed Gamal "imul %cl\n\t"); 107159317bd1SMohammed Gamal 107259317bd1SMohammed Gamal MK_INSN(mul16, "mov $2, %ax\n\t" 107359317bd1SMohammed Gamal "mov $4, %cx\n\t" 107459317bd1SMohammed Gamal "imul %cx\n\t"); 107559317bd1SMohammed Gamal 107659317bd1SMohammed Gamal MK_INSN(mul32, "mov $2, %eax\n\t" 107759317bd1SMohammed Gamal "mov $4, %ecx\n\t" 107859317bd1SMohammed Gamal "imul %ecx\n\t"); 107959317bd1SMohammed Gamal 108059317bd1SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 108159317bd1SMohammed Gamal insn_mul8, 108259317bd1SMohammed Gamal insn_mul8_end - insn_mul8); 108359317bd1SMohammed Gamal 108459317bd1SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || (outregs.eax & 0xff) != 8) 108559317bd1SMohammed Gamal print_serial("mul Test 1: FAIL\n"); 108659317bd1SMohammed Gamal else 108759317bd1SMohammed Gamal print_serial("mul Test 1: PASS\n"); 108859317bd1SMohammed Gamal 108959317bd1SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 109059317bd1SMohammed Gamal insn_mul16, 109159317bd1SMohammed Gamal insn_mul16_end - insn_mul16); 109259317bd1SMohammed Gamal 109359317bd1SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 8) 109459317bd1SMohammed Gamal print_serial("mul Test 2: FAIL\n"); 109559317bd1SMohammed Gamal else 109659317bd1SMohammed Gamal print_serial("mul Test 2: PASS\n"); 109759317bd1SMohammed Gamal 109859317bd1SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 109959317bd1SMohammed Gamal insn_mul32, 110059317bd1SMohammed Gamal insn_mul32_end - insn_mul32); 110159317bd1SMohammed Gamal 110259317bd1SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 8) 110359317bd1SMohammed Gamal print_serial("mul Test 3: FAIL\n"); 110459317bd1SMohammed Gamal else 110559317bd1SMohammed Gamal print_serial("mul Test 3: PASS\n"); 110659317bd1SMohammed Gamal } 110759317bd1SMohammed Gamal 11080d4c7614SMohammed Gamal void test_div() 11090d4c7614SMohammed Gamal { 11100d4c7614SMohammed Gamal struct regs inregs = { 0 }, outregs; 11110d4c7614SMohammed Gamal 11120d4c7614SMohammed Gamal MK_INSN(div8, "mov $257, %ax\n\t" 11130d4c7614SMohammed Gamal "mov $2, %cl\n\t" 11140d4c7614SMohammed Gamal "div %cl\n\t"); 11150d4c7614SMohammed Gamal 11160d4c7614SMohammed Gamal MK_INSN(div16, "mov $512, %ax\n\t" 11170d4c7614SMohammed Gamal "mov $5, %cx\n\t" 11180d4c7614SMohammed Gamal "div %cx\n\t"); 11190d4c7614SMohammed Gamal 11200d4c7614SMohammed Gamal MK_INSN(div32, "mov $512, %eax\n\t" 11210d4c7614SMohammed Gamal "mov $5, %ecx\n\t" 11220d4c7614SMohammed Gamal "div %ecx\n\t"); 11230d4c7614SMohammed Gamal 11240d4c7614SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 11250d4c7614SMohammed Gamal insn_div8, 11260d4c7614SMohammed Gamal insn_div8_end - insn_div8); 11270d4c7614SMohammed Gamal 11280d4c7614SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 384) 11290d4c7614SMohammed Gamal print_serial("div Test 1: FAIL\n"); 11300d4c7614SMohammed Gamal else 11310d4c7614SMohammed Gamal print_serial("div Test 1: PASS\n"); 11320d4c7614SMohammed Gamal 11330d4c7614SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 11340d4c7614SMohammed Gamal insn_div16, 11350d4c7614SMohammed Gamal insn_div16_end - insn_div16); 11360d4c7614SMohammed Gamal 11370d4c7614SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 102 || 11380d4c7614SMohammed Gamal outregs.edx != 2) 11390d4c7614SMohammed Gamal print_serial("div Test 2: FAIL\n"); 11400d4c7614SMohammed Gamal else 11410d4c7614SMohammed Gamal print_serial("div Test 2: PASS\n"); 11420d4c7614SMohammed Gamal 11430d4c7614SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 11440d4c7614SMohammed Gamal insn_div32, 11450d4c7614SMohammed Gamal insn_div32_end - insn_div32); 11460d4c7614SMohammed Gamal 11470d4c7614SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 102 || 11480d4c7614SMohammed Gamal outregs.edx != 2) 11490d4c7614SMohammed Gamal print_serial("div Test 3: FAIL\n"); 11500d4c7614SMohammed Gamal else 11510d4c7614SMohammed Gamal print_serial("div Test 3: PASS\n"); 11520d4c7614SMohammed Gamal } 11530d4c7614SMohammed Gamal 11540d4c7614SMohammed Gamal void test_idiv() 11550d4c7614SMohammed Gamal { 11560d4c7614SMohammed Gamal struct regs inregs = { 0 }, outregs; 11570d4c7614SMohammed Gamal 11580d4c7614SMohammed Gamal MK_INSN(idiv8, "mov $256, %ax\n\t" 11590d4c7614SMohammed Gamal "mov $-2, %cl\n\t" 11600d4c7614SMohammed Gamal "idiv %cl\n\t"); 11610d4c7614SMohammed Gamal 11620d4c7614SMohammed Gamal MK_INSN(idiv16, "mov $512, %ax\n\t" 11630d4c7614SMohammed Gamal "mov $-2, %cx\n\t" 11640d4c7614SMohammed Gamal "idiv %cx\n\t"); 11650d4c7614SMohammed Gamal 11660d4c7614SMohammed Gamal MK_INSN(idiv32, "mov $512, %eax\n\t" 11670d4c7614SMohammed Gamal "mov $-2, %ecx\n\t" 11680d4c7614SMohammed Gamal "idiv %ecx\n\t"); 11690d4c7614SMohammed Gamal 11700d4c7614SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 11710d4c7614SMohammed Gamal insn_idiv8, 11720d4c7614SMohammed Gamal insn_idiv8_end - insn_idiv8); 11730d4c7614SMohammed Gamal 11740d4c7614SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u8)-128) 11750d4c7614SMohammed Gamal print_serial("idiv Test 1: FAIL\n"); 11760d4c7614SMohammed Gamal else 11770d4c7614SMohammed Gamal print_serial("idiv Test 1: PASS\n"); 11780d4c7614SMohammed Gamal 11790d4c7614SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 11800d4c7614SMohammed Gamal insn_idiv16, 11810d4c7614SMohammed Gamal insn_idiv16_end - insn_idiv16); 11820d4c7614SMohammed Gamal 11830d4c7614SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u16)-256) 11840d4c7614SMohammed Gamal print_serial("idiv Test 2: FAIL\n"); 11850d4c7614SMohammed Gamal else 11860d4c7614SMohammed Gamal print_serial("idiv Test 2: PASS\n"); 11870d4c7614SMohammed Gamal 11880d4c7614SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 11890d4c7614SMohammed Gamal insn_idiv32, 11900d4c7614SMohammed Gamal insn_idiv32_end - insn_idiv32); 11910d4c7614SMohammed Gamal 11920d4c7614SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u32)-256) 11930d4c7614SMohammed Gamal print_serial("idiv Test 3: FAIL\n"); 11940d4c7614SMohammed Gamal else 11950d4c7614SMohammed Gamal print_serial("idiv Test 3: PASS\n"); 11960d4c7614SMohammed Gamal } 11970d4c7614SMohammed Gamal 11986e293cf5SWei Yongjun void test_cbw(void) 11996e293cf5SWei Yongjun { 12006e293cf5SWei Yongjun struct regs inregs = { 0 }, outregs; 12016e293cf5SWei Yongjun 12026e293cf5SWei Yongjun MK_INSN(cbw, "mov $0xFE, %eax \n\t" 12036e293cf5SWei Yongjun "cbw\n\t"); 12046e293cf5SWei Yongjun MK_INSN(cwde, "mov $0xFFFE, %eax \n\t" 12056e293cf5SWei Yongjun "cwde\n\t"); 12066e293cf5SWei Yongjun 12076e293cf5SWei Yongjun exec_in_big_real_mode(&inregs, &outregs, 12086e293cf5SWei Yongjun insn_cbw, 12096e293cf5SWei Yongjun insn_cbw_end - insn_cbw); 12106e293cf5SWei Yongjun if (outregs.eax != 0xFFFE) 12116e293cf5SWei Yongjun print_serial("cbw test1: FAIL\n"); 12126e293cf5SWei Yongjun else 12136e293cf5SWei Yongjun print_serial("cbw test 1: PASS\n"); 12146e293cf5SWei Yongjun 12156e293cf5SWei Yongjun exec_in_big_real_mode(&inregs, &outregs, 12166e293cf5SWei Yongjun insn_cwde, 12176e293cf5SWei Yongjun insn_cwde_end - insn_cwde); 12186e293cf5SWei Yongjun if (outregs.eax != 0xFFFFFFFE) 12196e293cf5SWei Yongjun print_serial("cwde test1: FAIL\n"); 12206e293cf5SWei Yongjun else 12216e293cf5SWei Yongjun print_serial("cwde test 1: PASS\n"); 12226e293cf5SWei Yongjun } 12236e293cf5SWei Yongjun 1224eacef4e2SWei Yongjun void test_loopcc(void) 1225eacef4e2SWei Yongjun { 1226eacef4e2SWei Yongjun struct regs inregs = { 0 }, outregs; 1227eacef4e2SWei Yongjun 1228eacef4e2SWei Yongjun MK_INSN(loop, "mov $10, %ecx\n\t" 1229eacef4e2SWei Yongjun "1: inc %eax\n\t" 1230eacef4e2SWei Yongjun "loop 1b\n\t"); 1231eacef4e2SWei Yongjun 1232eacef4e2SWei Yongjun MK_INSN(loope, "mov $10, %ecx\n\t" 1233eacef4e2SWei Yongjun "mov $1, %eax\n\t" 1234eacef4e2SWei Yongjun "1: dec %eax\n\t" 1235eacef4e2SWei Yongjun "loope 1b\n\t"); 1236eacef4e2SWei Yongjun 1237eacef4e2SWei Yongjun MK_INSN(loopne, "mov $10, %ecx\n\t" 1238eacef4e2SWei Yongjun "mov $5, %eax\n\t" 1239eacef4e2SWei Yongjun "1: dec %eax\n\t" 1240eacef4e2SWei Yongjun "loopne 1b\n\t"); 1241eacef4e2SWei Yongjun 1242eacef4e2SWei Yongjun exec_in_big_real_mode(&inregs, &outregs, 1243eacef4e2SWei Yongjun insn_loop, insn_loop_end - insn_loop); 1244eacef4e2SWei Yongjun if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 10) 1245eacef4e2SWei Yongjun print_serial("LOOPcc short Test 1: FAIL\n"); 1246eacef4e2SWei Yongjun else 1247eacef4e2SWei Yongjun print_serial("LOOPcc short Test 1: PASS\n"); 1248eacef4e2SWei Yongjun 1249eacef4e2SWei Yongjun exec_in_big_real_mode(&inregs, &outregs, 1250eacef4e2SWei Yongjun insn_loope, insn_loope_end - insn_loope); 1251eacef4e2SWei Yongjun if(!regs_equal(&inregs, &outregs, R_AX | R_CX) || 1252eacef4e2SWei Yongjun outregs.eax != -1 || outregs.ecx != 8) 1253eacef4e2SWei Yongjun print_serial("LOOPcc short Test 2: FAIL\n"); 1254eacef4e2SWei Yongjun else 1255eacef4e2SWei Yongjun print_serial("LOOPcc short Test 2: PASS\n"); 1256eacef4e2SWei Yongjun 1257eacef4e2SWei Yongjun exec_in_big_real_mode(&inregs, &outregs, 1258eacef4e2SWei Yongjun insn_loopne, insn_loopne_end - insn_loopne); 1259eacef4e2SWei Yongjun if(!regs_equal(&inregs, &outregs, R_AX | R_CX) || 1260eacef4e2SWei Yongjun outregs.eax != 0 || outregs.ecx != 5) 1261eacef4e2SWei Yongjun print_serial("LOOPcc short Test 3: FAIL\n"); 1262eacef4e2SWei Yongjun else 1263eacef4e2SWei Yongjun print_serial("LOOPcc short Test 3: PASS\n"); 1264eacef4e2SWei Yongjun } 1265eacef4e2SWei Yongjun 12667d36db35SAvi Kivity void realmode_start(void) 12677d36db35SAvi Kivity { 12687d36db35SAvi Kivity test_null(); 12697d36db35SAvi Kivity 12707d36db35SAvi Kivity test_shld(); 12717d36db35SAvi Kivity test_push_pop(); 12727d36db35SAvi Kivity test_pusha_popa(); 12737d36db35SAvi Kivity test_mov_imm(); 12747d36db35SAvi Kivity test_cmp_imm(); 12757d36db35SAvi Kivity test_add_imm(); 12767d36db35SAvi Kivity test_sub_imm(); 12777d36db35SAvi Kivity test_xor_imm(); 12787d36db35SAvi Kivity test_io(); 12797d36db35SAvi Kivity test_eflags_insn(); 12807d36db35SAvi Kivity test_jcc_short(); 12817d36db35SAvi Kivity test_jcc_near(); 12827d36db35SAvi Kivity /* test_call() uses short jump so call it after testing jcc */ 12837d36db35SAvi Kivity test_call(); 12847d36db35SAvi Kivity /* long jmp test uses call near so test it after testing call */ 12857d36db35SAvi Kivity test_long_jmp(); 12867d36db35SAvi Kivity test_xchg(); 12877d36db35SAvi Kivity test_iret(); 128896b9ca1eSMohammed Gamal test_int(); 1289fa74f8a6SMohammed Gamal test_imul(); 129059317bd1SMohammed Gamal test_mul(); 12910d4c7614SMohammed Gamal test_div(); 12920d4c7614SMohammed Gamal test_idiv(); 1293eacef4e2SWei Yongjun test_loopcc(); 12946e293cf5SWei Yongjun test_cbw(); 12957d36db35SAvi Kivity 12967d36db35SAvi Kivity exit(0); 12977d36db35SAvi Kivity } 12987d36db35SAvi Kivity 12997d36db35SAvi Kivity unsigned long long r_gdt[] = { 0, 0x9b000000ffff, 0x93000000ffff }; 13007d36db35SAvi Kivity 13017d36db35SAvi Kivity struct __attribute__((packed)) { 13027d36db35SAvi Kivity unsigned short limit; 13037d36db35SAvi Kivity void *base; 13047d36db35SAvi Kivity } r_gdt_descr = { sizeof(r_gdt) - 1, &r_gdt }; 13057d36db35SAvi Kivity 13067d36db35SAvi Kivity asm( 13077d36db35SAvi Kivity ".section .init \n\t" 13087d36db35SAvi Kivity 13097d36db35SAvi Kivity ".code32 \n\t" 13107d36db35SAvi Kivity 13117d36db35SAvi Kivity "mb_magic = 0x1BADB002 \n\t" 13127d36db35SAvi Kivity "mb_flags = 0x0 \n\t" 13137d36db35SAvi Kivity 13147d36db35SAvi Kivity "# multiboot header \n\t" 13157d36db35SAvi Kivity ".long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) \n\t" 13167d36db35SAvi Kivity 13177d36db35SAvi Kivity ".globl start \n\t" 13187d36db35SAvi Kivity ".data \n\t" 13197d36db35SAvi Kivity ". = . + 4096 \n\t" 13207d36db35SAvi Kivity "stacktop: \n\t" 13217d36db35SAvi Kivity 13227d36db35SAvi Kivity ".text \n\t" 13237d36db35SAvi Kivity "start: \n\t" 13247d36db35SAvi Kivity "lgdt r_gdt_descr \n\t" 13257d36db35SAvi Kivity "ljmp $8, $1f; 1: \n\t" 13267d36db35SAvi Kivity ".code16gcc \n\t" 13277d36db35SAvi Kivity "mov $16, %eax \n\t" 13287d36db35SAvi Kivity "mov %ax, %ds \n\t" 13297d36db35SAvi Kivity "mov %ax, %es \n\t" 13307d36db35SAvi Kivity "mov %ax, %fs \n\t" 13317d36db35SAvi Kivity "mov %ax, %gs \n\t" 13327d36db35SAvi Kivity "mov %ax, %ss \n\t" 13337d36db35SAvi Kivity "mov %cr0, %eax \n\t" 13347d36db35SAvi Kivity "btc $0, %eax \n\t" 13357d36db35SAvi Kivity "mov %eax, %cr0 \n\t" 13367d36db35SAvi Kivity "ljmp $0, $realmode_entry \n\t" 13377d36db35SAvi Kivity 13387d36db35SAvi Kivity "realmode_entry: \n\t" 13397d36db35SAvi Kivity 13407d36db35SAvi Kivity "xor %ax, %ax \n\t" 13417d36db35SAvi Kivity "mov %ax, %ds \n\t" 13427d36db35SAvi Kivity "mov %ax, %es \n\t" 13437d36db35SAvi Kivity "mov %ax, %ss \n\t" 13447d36db35SAvi Kivity "mov %ax, %fs \n\t" 13457d36db35SAvi Kivity "mov %ax, %gs \n\t" 13467d36db35SAvi Kivity "mov $stacktop, %esp\n\t" 13477d36db35SAvi Kivity "ljmp $0, $realmode_start \n\t" 13487d36db35SAvi Kivity 13497d36db35SAvi Kivity ".code16gcc \n\t" 13507d36db35SAvi Kivity ); 1351