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"); 465b3261e48SMohammed Gamal MK_INSN(stc, "stc"); 4667d36db35SAvi Kivity MK_INSN(cli, "cli"); 4677d36db35SAvi Kivity MK_INSN(sti, "sti"); 4687d36db35SAvi Kivity MK_INSN(cld, "cld"); 4697d36db35SAvi Kivity MK_INSN(std, "std"); 4707d36db35SAvi Kivity 4717d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4727d36db35SAvi Kivity insn_clc, 4737d36db35SAvi Kivity insn_clc_end - insn_clc); 4747d36db35SAvi Kivity if (outregs.eflags & 1) 4757d36db35SAvi Kivity print_serial("clc test: FAIL\n"); 4767d36db35SAvi Kivity else 4777d36db35SAvi Kivity print_serial("clc test: PASS\n"); 4787d36db35SAvi Kivity 4797d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 480b3261e48SMohammed Gamal insn_stc, 481b3261e48SMohammed Gamal insn_stc_end - insn_stc); 482b3261e48SMohammed Gamal if (!(outregs.eflags & 1)) 483b3261e48SMohammed Gamal print_serial("stc test: FAIL\n"); 484b3261e48SMohammed Gamal else 485b3261e48SMohammed Gamal print_serial("stc test: PASS\n"); 486b3261e48SMohammed Gamal 487b3261e48SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 4887d36db35SAvi Kivity insn_cli, 4897d36db35SAvi Kivity insn_cli_end - insn_cli); 4907d36db35SAvi Kivity if (outregs.eflags & (1 << 9)) 4917d36db35SAvi Kivity print_serial("cli test: FAIL\n"); 4927d36db35SAvi Kivity else 4937d36db35SAvi Kivity print_serial("cli test: PASS\n"); 4947d36db35SAvi Kivity 4957d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 4967d36db35SAvi Kivity insn_sti, 4977d36db35SAvi Kivity insn_sti_end - insn_sti); 4987d36db35SAvi Kivity if (!(outregs.eflags & (1 << 9))) 4997d36db35SAvi Kivity print_serial("sti test: FAIL\n"); 5007d36db35SAvi Kivity else 5017d36db35SAvi Kivity print_serial("sti test: PASS\n"); 5027d36db35SAvi Kivity 5037d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5047d36db35SAvi Kivity insn_cld, 5057d36db35SAvi Kivity insn_cld_end - insn_cld); 5067d36db35SAvi Kivity if (outregs.eflags & (1 << 10)) 5077d36db35SAvi Kivity print_serial("cld test: FAIL\n"); 5087d36db35SAvi Kivity else 5097d36db35SAvi Kivity print_serial("cld test: PASS\n"); 5107d36db35SAvi Kivity 5117d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5127d36db35SAvi Kivity insn_std, 5137d36db35SAvi Kivity insn_std_end - insn_std); 5147d36db35SAvi Kivity if (!(outregs.eflags & (1 << 10))) 5157d36db35SAvi Kivity print_serial("std test: FAIL\n"); 5167d36db35SAvi Kivity else 5177d36db35SAvi Kivity print_serial("std test: PASS\n"); 5187d36db35SAvi Kivity } 5197d36db35SAvi Kivity 5207d36db35SAvi Kivity void test_io(void) 5217d36db35SAvi Kivity { 5227d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 5237d36db35SAvi Kivity MK_INSN(io_test1, "mov $0xff, %al \n\t" 5247d36db35SAvi Kivity "out %al, $0xe0 \n\t" 5257d36db35SAvi Kivity "mov $0x00, %al \n\t" 5267d36db35SAvi Kivity "in $0xe0, %al \n\t"); 5277d36db35SAvi Kivity MK_INSN(io_test2, "mov $0xffff, %ax \n\t" 5287d36db35SAvi Kivity "out %ax, $0xe0 \n\t" 5297d36db35SAvi Kivity "mov $0x0000, %ax \n\t" 5307d36db35SAvi Kivity "in $0xe0, %ax \n\t"); 5317d36db35SAvi Kivity MK_INSN(io_test3, "mov $0xffffffff, %eax \n\t" 5327d36db35SAvi Kivity "out %eax, $0xe0 \n\t" 5337d36db35SAvi Kivity "mov $0x000000, %eax \n\t" 5347d36db35SAvi Kivity "in $0xe0, %eax \n\t"); 5357d36db35SAvi Kivity MK_INSN(io_test4, "mov $0xe0, %dx \n\t" 5367d36db35SAvi Kivity "mov $0xff, %al \n\t" 5377d36db35SAvi Kivity "out %al, %dx \n\t" 5387d36db35SAvi Kivity "mov $0x00, %al \n\t" 5397d36db35SAvi Kivity "in %dx, %al \n\t"); 5407d36db35SAvi Kivity MK_INSN(io_test5, "mov $0xe0, %dx \n\t" 5417d36db35SAvi Kivity "mov $0xffff, %ax \n\t" 5427d36db35SAvi Kivity "out %ax, %dx \n\t" 5437d36db35SAvi Kivity "mov $0x0000, %ax \n\t" 5447d36db35SAvi Kivity "in %dx, %ax \n\t"); 5457d36db35SAvi Kivity MK_INSN(io_test6, "mov $0xe0, %dx \n\t" 5467d36db35SAvi Kivity "mov $0xffffffff, %eax \n\t" 5477d36db35SAvi Kivity "out %eax, %dx \n\t" 5487d36db35SAvi Kivity "mov $0x00000000, %eax \n\t" 5497d36db35SAvi Kivity "in %dx, %eax \n\t"); 5507d36db35SAvi Kivity 5517d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5527d36db35SAvi Kivity insn_io_test1, 5537d36db35SAvi Kivity insn_io_test1_end - insn_io_test1); 5547d36db35SAvi Kivity 5557d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xff) 5567d36db35SAvi Kivity print_serial("I/O test 1: FAIL\n"); 5577d36db35SAvi Kivity else 5587d36db35SAvi Kivity print_serial("I/O test 1: PASS\n"); 5597d36db35SAvi Kivity 5607d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5617d36db35SAvi Kivity insn_io_test2, 5627d36db35SAvi Kivity insn_io_test2_end - insn_io_test2); 5637d36db35SAvi Kivity 5647d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffff) 5657d36db35SAvi Kivity print_serial("I/O test 2: FAIL\n"); 5667d36db35SAvi Kivity else 5677d36db35SAvi Kivity print_serial("I/O test 2: PASS\n"); 5687d36db35SAvi Kivity 5697d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5707d36db35SAvi Kivity insn_io_test3, 5717d36db35SAvi Kivity insn_io_test3_end - insn_io_test3); 5727d36db35SAvi Kivity 5737d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffffffff) 5747d36db35SAvi Kivity print_serial("I/O test 3: FAIL\n"); 5757d36db35SAvi Kivity else 5767d36db35SAvi Kivity print_serial("I/O test 3: PASS\n"); 5777d36db35SAvi Kivity 5787d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5797d36db35SAvi Kivity insn_io_test4, 5807d36db35SAvi Kivity insn_io_test4_end - insn_io_test4); 5817d36db35SAvi Kivity 5827d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xff) 5837d36db35SAvi Kivity print_serial("I/O test 4: FAIL\n"); 5847d36db35SAvi Kivity else 5857d36db35SAvi Kivity print_serial("I/O test 4: PASS\n"); 5867d36db35SAvi Kivity 5877d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5887d36db35SAvi Kivity insn_io_test5, 5897d36db35SAvi Kivity insn_io_test5_end - insn_io_test5); 5907d36db35SAvi Kivity 5917d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffff) 5927d36db35SAvi Kivity print_serial("I/O test 5: FAIL\n"); 5937d36db35SAvi Kivity else 5947d36db35SAvi Kivity print_serial("I/O test 5: PASS\n"); 5957d36db35SAvi Kivity 5967d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 5977d36db35SAvi Kivity insn_io_test6, 5987d36db35SAvi Kivity insn_io_test6_end - insn_io_test6); 5997d36db35SAvi Kivity 6007d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffffffff) 6017d36db35SAvi Kivity print_serial("I/O test 6: FAIL\n"); 6027d36db35SAvi Kivity else 6037d36db35SAvi Kivity print_serial("I/O test 6: PASS\n"); 6047d36db35SAvi Kivity } 6057d36db35SAvi Kivity 6067d36db35SAvi Kivity void test_call(void) 6077d36db35SAvi Kivity { 6087d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 6097d36db35SAvi Kivity u32 esp[16]; 6107d36db35SAvi Kivity 6117d36db35SAvi Kivity inregs.esp = (u32)esp; 6127d36db35SAvi Kivity 6137d36db35SAvi Kivity MK_INSN(call1, "mov $test_function, %eax \n\t" 6147d36db35SAvi Kivity "call *%eax\n\t"); 6157d36db35SAvi Kivity MK_INSN(call_near1, "jmp 2f\n\t" 6167d36db35SAvi Kivity "1: mov $0x1234, %eax\n\t" 6177d36db35SAvi Kivity "ret\n\t" 6187d36db35SAvi Kivity "2: call 1b\t"); 6197d36db35SAvi Kivity MK_INSN(call_near2, "call 1f\n\t" 6207d36db35SAvi Kivity "jmp 2f\n\t" 6217d36db35SAvi Kivity "1: mov $0x1234, %eax\n\t" 6227d36db35SAvi Kivity "ret\n\t" 6237d36db35SAvi Kivity "2:\t"); 6247d36db35SAvi Kivity 6257d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6267d36db35SAvi Kivity insn_call1, 6277d36db35SAvi Kivity insn_call1_end - insn_call1); 6287d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 6297d36db35SAvi Kivity print_serial("Call Test 1: FAIL\n"); 6307d36db35SAvi Kivity else 6317d36db35SAvi Kivity print_serial("Call Test 1: PASS\n"); 6327d36db35SAvi Kivity 6337d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6347d36db35SAvi Kivity insn_call_near1, insn_call_near1_end - insn_call_near1); 6357d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 6367d36db35SAvi Kivity print_serial("Call near Test 1: FAIL\n"); 6377d36db35SAvi Kivity else 6387d36db35SAvi Kivity print_serial("Call near Test 1: PASS\n"); 6397d36db35SAvi Kivity 6407d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6417d36db35SAvi Kivity insn_call_near2, insn_call_near2_end - insn_call_near2); 6427d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 6437d36db35SAvi Kivity print_serial("Call near Test 2: FAIL\n"); 6447d36db35SAvi Kivity else 6457d36db35SAvi Kivity print_serial("Call near Test 2: PASS\n"); 6467d36db35SAvi Kivity } 6477d36db35SAvi Kivity 6487d36db35SAvi Kivity void test_jcc_short(void) 6497d36db35SAvi Kivity { 6507d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 6517d36db35SAvi Kivity MK_INSN(jnz_short1, "jnz 1f\n\t" 6527d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 6537d36db35SAvi Kivity "1:\n\t"); 6547d36db35SAvi Kivity MK_INSN(jnz_short2, "1:\n\t" 6557d36db35SAvi Kivity "cmp $0x1234, %eax\n\t" 6567d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 6577d36db35SAvi Kivity "jnz 1b\n\t"); 6587d36db35SAvi Kivity MK_INSN(jmp_short1, "jmp 1f\n\t" 6597d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 6607d36db35SAvi Kivity "1:\n\t"); 6617d36db35SAvi Kivity 6627d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6637d36db35SAvi Kivity insn_jnz_short1, insn_jnz_short1_end - insn_jnz_short1); 6647d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, 0)) 6657d36db35SAvi Kivity print_serial("JNZ short Test 1: FAIL\n"); 6667d36db35SAvi Kivity else 6677d36db35SAvi Kivity print_serial("JNZ short Test 1: PASS\n"); 6687d36db35SAvi Kivity 6697d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6707d36db35SAvi Kivity insn_jnz_short2, insn_jnz_short2_end - insn_jnz_short2); 6717d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6))) 6727d36db35SAvi Kivity print_serial("JNZ short Test 2: FAIL\n"); 6737d36db35SAvi Kivity else 6747d36db35SAvi Kivity print_serial("JNZ short Test 2: PASS\n"); 6757d36db35SAvi Kivity 6767d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6777d36db35SAvi Kivity insn_jmp_short1, insn_jmp_short1_end - insn_jmp_short1); 6787d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, 0)) 6797d36db35SAvi Kivity print_serial("JMP short Test 1: FAIL\n"); 6807d36db35SAvi Kivity else 6817d36db35SAvi Kivity print_serial("JMP short Test 1: PASS\n"); 6827d36db35SAvi Kivity } 6837d36db35SAvi Kivity 6847d36db35SAvi Kivity void test_jcc_near(void) 6857d36db35SAvi Kivity { 6867d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 6877d36db35SAvi Kivity /* encode near jmp manually. gas will not do it if offsets < 127 byte */ 6887d36db35SAvi Kivity MK_INSN(jnz_near1, ".byte 0x0f, 0x85, 0x06, 0x00\n\t" 6897d36db35SAvi Kivity "mov $0x1234, %eax\n\t"); 6907d36db35SAvi Kivity MK_INSN(jnz_near2, "cmp $0x1234, %eax\n\t" 6917d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 6927d36db35SAvi Kivity ".byte 0x0f, 0x85, 0xf0, 0xff\n\t"); 6937d36db35SAvi Kivity MK_INSN(jmp_near1, ".byte 0xE9, 0x06, 0x00\n\t" 6947d36db35SAvi Kivity "mov $0x1234, %eax\n\t"); 6957d36db35SAvi Kivity 6967d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 6977d36db35SAvi Kivity insn_jnz_near1, insn_jnz_near1_end - insn_jnz_near1); 6987d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, 0)) 6997d36db35SAvi Kivity print_serial("JNZ near Test 1: FAIL\n"); 7007d36db35SAvi Kivity else 7017d36db35SAvi Kivity print_serial("JNZ near Test 1: PASS\n"); 7027d36db35SAvi Kivity 7037d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7047d36db35SAvi Kivity insn_jnz_near2, insn_jnz_near2_end - insn_jnz_near2); 7057d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6))) 7067d36db35SAvi Kivity print_serial("JNZ near Test 2: FAIL\n"); 7077d36db35SAvi Kivity else 7087d36db35SAvi Kivity print_serial("JNZ near Test 2: PASS\n"); 7097d36db35SAvi Kivity 7107d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7117d36db35SAvi Kivity insn_jmp_near1, insn_jmp_near1_end - insn_jmp_near1); 7127d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, 0)) 7137d36db35SAvi Kivity print_serial("JMP near Test 1: FAIL\n"); 7147d36db35SAvi Kivity else 7157d36db35SAvi Kivity print_serial("JMP near Test 1: PASS\n"); 7167d36db35SAvi Kivity } 7177d36db35SAvi Kivity 7187d36db35SAvi Kivity void test_long_jmp() 7197d36db35SAvi Kivity { 7207d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 7217d36db35SAvi Kivity u32 esp[16]; 7227d36db35SAvi Kivity 7237d36db35SAvi Kivity inregs.esp = (u32)esp; 7247d36db35SAvi Kivity MK_INSN(long_jmp, "call 1f\n\t" 7257d36db35SAvi Kivity "jmp 2f\n\t" 7267d36db35SAvi Kivity "1: jmp $0, $test_function\n\t" 7277d36db35SAvi Kivity "2:\n\t"); 7287d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7297d36db35SAvi Kivity insn_long_jmp, 7307d36db35SAvi Kivity insn_long_jmp_end - insn_long_jmp); 7317d36db35SAvi Kivity if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 7327d36db35SAvi Kivity print_serial("Long JMP Test: FAIL\n"); 7337d36db35SAvi Kivity else 7347d36db35SAvi Kivity print_serial("Long JMP Test: PASS\n"); 7357d36db35SAvi Kivity } 736fa74f8a6SMohammed Gamal 7377d36db35SAvi Kivity void test_push_pop() 7387d36db35SAvi Kivity { 7397d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 7407d36db35SAvi Kivity MK_INSN(push32, "mov $0x12345678, %eax\n\t" 7417d36db35SAvi Kivity "push %eax\n\t" 7427d36db35SAvi Kivity "pop %ebx\n\t"); 7437d36db35SAvi Kivity MK_INSN(push16, "mov $0x1234, %ax\n\t" 7447d36db35SAvi Kivity "push %ax\n\t" 7457d36db35SAvi Kivity "pop %bx\n\t"); 7467d36db35SAvi Kivity 7477d36db35SAvi Kivity MK_INSN(push_es, "mov $0x231, %bx\n\t" //Just write a dummy value to see if it gets overwritten 7487d36db35SAvi Kivity "mov $0x123, %ax\n\t" 7497d36db35SAvi Kivity "mov %ax, %es\n\t" 7507d36db35SAvi Kivity "push %es\n\t" 7517d36db35SAvi Kivity "pop %bx \n\t" 7527d36db35SAvi Kivity ); 7537d36db35SAvi Kivity MK_INSN(pop_es, "push %ax\n\t" 7547d36db35SAvi Kivity "pop %es\n\t" 7557d36db35SAvi Kivity "mov %es, %bx\n\t" 7567d36db35SAvi Kivity ); 7577d36db35SAvi Kivity MK_INSN(push_pop_ss, "push %ss\n\t" 7587d36db35SAvi Kivity "pushw %ax\n\t" 7597d36db35SAvi Kivity "popw %ss\n\t" 7607d36db35SAvi Kivity "mov %ss, %bx\n\t" 7617d36db35SAvi Kivity "pop %ss\n\t" 7627d36db35SAvi Kivity ); 7637d36db35SAvi Kivity MK_INSN(push_pop_fs, "push %fs\n\t" 7647d36db35SAvi Kivity "pushl %eax\n\t" 7657d36db35SAvi Kivity "popl %fs\n\t" 7667d36db35SAvi Kivity "mov %fs, %ebx\n\t" 7677d36db35SAvi Kivity "pop %fs\n\t" 7687d36db35SAvi Kivity ); 7697d36db35SAvi Kivity 7707d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7717d36db35SAvi Kivity insn_push32, 7727d36db35SAvi Kivity insn_push32_end - insn_push32); 7737d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x12345678) 7747d36db35SAvi Kivity print_serial("Push/Pop Test 1: FAIL\n"); 7757d36db35SAvi Kivity else 7767d36db35SAvi Kivity print_serial("Push/Pop Test 1: PASS\n"); 7777d36db35SAvi Kivity 7787d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7797d36db35SAvi Kivity insn_push16, 7807d36db35SAvi Kivity insn_push16_end - insn_push16); 7817d36db35SAvi Kivity 7827d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x1234) 7837d36db35SAvi Kivity print_serial("Push/Pop Test 2: FAIL\n"); 7847d36db35SAvi Kivity else 7857d36db35SAvi Kivity print_serial("Push/Pop Test 2: PASS\n"); 7867d36db35SAvi Kivity 7877d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7887d36db35SAvi Kivity insn_push_es, 7897d36db35SAvi Kivity insn_push_es_end - insn_push_es); 7907d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax || outregs.eax != 0x123) 7917d36db35SAvi Kivity print_serial("Push/Pop Test 3: FAIL\n"); 7927d36db35SAvi Kivity else 7937d36db35SAvi Kivity print_serial("Push/Pop Test 3: PASS\n"); 7947d36db35SAvi Kivity 7957d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 7967d36db35SAvi Kivity insn_pop_es, 7977d36db35SAvi Kivity insn_pop_es_end - insn_pop_es); 7987d36db35SAvi Kivity 7997d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 8007d36db35SAvi Kivity print_serial("Push/Pop Test 4: FAIL\n"); 8017d36db35SAvi Kivity else 8027d36db35SAvi Kivity print_serial("Push/Pop Test 4: PASS\n"); 8037d36db35SAvi Kivity 8047d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 8057d36db35SAvi Kivity insn_push_pop_ss, 8067d36db35SAvi Kivity insn_push_pop_ss_end - insn_push_pop_ss); 8077d36db35SAvi Kivity 8087d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 8097d36db35SAvi Kivity print_serial("Push/Pop Test 5: FAIL\n"); 8107d36db35SAvi Kivity else 8117d36db35SAvi Kivity print_serial("Push/Pop Test 5: PASS\n"); 8127d36db35SAvi Kivity 8137d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 8147d36db35SAvi Kivity insn_push_pop_fs, 8157d36db35SAvi Kivity insn_push_pop_fs_end - insn_push_pop_fs); 8167d36db35SAvi Kivity 8177d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 8187d36db35SAvi Kivity print_serial("Push/Pop Test 6: FAIL\n"); 8197d36db35SAvi Kivity else 8207d36db35SAvi Kivity print_serial("Push/Pop Test 6: PASS\n"); 8217d36db35SAvi Kivity } 8227d36db35SAvi Kivity 8237d36db35SAvi Kivity void test_null(void) 8247d36db35SAvi Kivity { 8257d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 8267d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 0, 0); 8277d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 8287d36db35SAvi Kivity print_serial("null test: FAIL\n"); 8297d36db35SAvi Kivity else 8307d36db35SAvi Kivity print_serial("null test: PASS\n"); 8317d36db35SAvi Kivity } 8327d36db35SAvi Kivity 8337d36db35SAvi Kivity struct { 8347d36db35SAvi Kivity char stack[500]; 8357d36db35SAvi Kivity char top[]; 8367d36db35SAvi Kivity } tmp_stack; 8377d36db35SAvi Kivity 8387d36db35SAvi Kivity void test_pusha_popa() 8397d36db35SAvi Kivity { 8407d36db35SAvi 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; 8417d36db35SAvi Kivity 8427d36db35SAvi Kivity MK_INSN(pusha, "pusha\n\t" 8437d36db35SAvi Kivity "pop %edi\n\t" 8447d36db35SAvi Kivity "pop %esi\n\t" 8457d36db35SAvi Kivity "pop %ebp\n\t" 8467d36db35SAvi Kivity "add $4, %esp\n\t" 8477d36db35SAvi Kivity "pop %ebx\n\t" 8487d36db35SAvi Kivity "pop %edx\n\t" 8497d36db35SAvi Kivity "pop %ecx\n\t" 8507d36db35SAvi Kivity "pop %eax\n\t" 8517d36db35SAvi Kivity ); 8527d36db35SAvi Kivity 8537d36db35SAvi Kivity MK_INSN(popa, "push %eax\n\t" 8547d36db35SAvi Kivity "push %ecx\n\t" 8557d36db35SAvi Kivity "push %edx\n\t" 8567d36db35SAvi Kivity "push %ebx\n\t" 8577d36db35SAvi Kivity "push %esp\n\t" 8587d36db35SAvi Kivity "push %ebp\n\t" 8597d36db35SAvi Kivity "push %esi\n\t" 8607d36db35SAvi Kivity "push %edi\n\t" 8617d36db35SAvi Kivity "popa\n\t" 8627d36db35SAvi Kivity ); 8637d36db35SAvi Kivity 8647d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 8657d36db35SAvi Kivity insn_pusha, 8667d36db35SAvi Kivity insn_pusha_end - insn_pusha); 8677d36db35SAvi Kivity 8687d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 8697d36db35SAvi Kivity print_serial("Pusha/Popa Test1: FAIL\n"); 8707d36db35SAvi Kivity else 8717d36db35SAvi Kivity print_serial("Pusha/Popa Test1: PASS\n"); 8727d36db35SAvi Kivity 8737d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 8747d36db35SAvi Kivity insn_popa, 8757d36db35SAvi Kivity insn_popa_end - insn_popa); 8767d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 8777d36db35SAvi Kivity print_serial("Pusha/Popa Test2: FAIL\n"); 8787d36db35SAvi Kivity else 8797d36db35SAvi Kivity print_serial("Pusha/Popa Test2: PASS\n"); 8807d36db35SAvi Kivity } 8817d36db35SAvi Kivity 8827d36db35SAvi Kivity void test_iret() 8837d36db35SAvi Kivity { 8847d36db35SAvi Kivity struct regs inregs = { 0 }, outregs; 8857d36db35SAvi Kivity 8867d36db35SAvi Kivity MK_INSN(iret32, "pushf\n\t" 8877d36db35SAvi Kivity "pushl %cs\n\t" 8887d36db35SAvi Kivity "call 1f\n\t" /* a near call will push eip onto the stack */ 8897d36db35SAvi Kivity "jmp 2f\n\t" 8907d36db35SAvi Kivity "1: iret\n\t" 8917d36db35SAvi Kivity "2:\n\t" 8927d36db35SAvi Kivity ); 8937d36db35SAvi Kivity 8947d36db35SAvi Kivity MK_INSN(iret16, "pushfw\n\t" 8957d36db35SAvi Kivity "pushw %cs\n\t" 8967d36db35SAvi Kivity "callw 1f\n\t" 8977d36db35SAvi Kivity "jmp 2f\n\t" 8987d36db35SAvi Kivity "1: iretw\n\t" 8997d36db35SAvi Kivity "2:\n\t"); 9007d36db35SAvi Kivity 9017d36db35SAvi Kivity MK_INSN(iret_flags32, "pushfl\n\t" 9027d36db35SAvi Kivity "popl %eax\n\t" 9037d36db35SAvi Kivity "andl $~0x2, %eax\n\t" 9047d36db35SAvi Kivity "orl $0xffc08028, %eax\n\t" 9057d36db35SAvi Kivity "pushl %eax\n\t" 9067d36db35SAvi Kivity "pushl %cs\n\t" 9077d36db35SAvi Kivity "call 1f\n\t" 9087d36db35SAvi Kivity "jmp 2f\n\t" 9097d36db35SAvi Kivity "1: iret\n\t" 9107d36db35SAvi Kivity "2:\n\t"); 9117d36db35SAvi Kivity 9127d36db35SAvi Kivity MK_INSN(iret_flags16, "pushfw\n\t" 9137d36db35SAvi Kivity "popw %ax\n\t" 9147d36db35SAvi Kivity "and $~0x2, %ax\n\t" 9157d36db35SAvi Kivity "or $0x8028, %ax\n\t" 9167d36db35SAvi Kivity "pushw %ax\n\t" 9177d36db35SAvi Kivity "pushw %cs\n\t" 9187d36db35SAvi Kivity "callw 1f\n\t" 9197d36db35SAvi Kivity "jmp 2f\n\t" 9207d36db35SAvi Kivity "1: iretw\n\t" 9217d36db35SAvi Kivity "2:\n\t"); 9227d36db35SAvi Kivity 9237d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 9247d36db35SAvi Kivity insn_iret32, 9257d36db35SAvi Kivity insn_iret32_end - insn_iret32); 9267d36db35SAvi Kivity 9277d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 9287d36db35SAvi Kivity print_serial("iret Test 1: FAIL\n"); 9297d36db35SAvi Kivity else 9307d36db35SAvi Kivity print_serial("iret Test 1: PASS\n"); 9317d36db35SAvi Kivity 9327d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 9337d36db35SAvi Kivity insn_iret16, 9347d36db35SAvi Kivity insn_iret16_end - insn_iret16); 9357d36db35SAvi Kivity 9367d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, 0)) 9377d36db35SAvi Kivity print_serial("iret Test 2: FAIL\n"); 9387d36db35SAvi Kivity else 9397d36db35SAvi Kivity print_serial("iret Test 2: PASS\n"); 9407d36db35SAvi Kivity 9417d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 9427d36db35SAvi Kivity insn_iret_flags32, 9437d36db35SAvi Kivity insn_iret_flags32_end - insn_iret_flags32); 9447d36db35SAvi Kivity 9457d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX)) 9467d36db35SAvi Kivity print_serial("iret Test 3: FAIL\n"); 9477d36db35SAvi Kivity else 9487d36db35SAvi Kivity print_serial("iret Test 3: PASS\n"); 9497d36db35SAvi Kivity 9507d36db35SAvi Kivity exec_in_big_real_mode(&inregs, &outregs, 9517d36db35SAvi Kivity insn_iret_flags16, 9527d36db35SAvi Kivity insn_iret_flags16_end - insn_iret_flags16); 9537d36db35SAvi Kivity 9547d36db35SAvi Kivity if (!regs_equal(&inregs, &outregs, R_AX)) 9557d36db35SAvi Kivity print_serial("iret Test 4: FAIL\n"); 9567d36db35SAvi Kivity else 9577d36db35SAvi Kivity print_serial("iret Test 4: PASS\n"); 9587d36db35SAvi Kivity } 9597d36db35SAvi Kivity 96096b9ca1eSMohammed Gamal void test_int() 96196b9ca1eSMohammed Gamal { 96296b9ca1eSMohammed Gamal struct regs inregs = { 0 }, outregs; 96396b9ca1eSMohammed Gamal 96496b9ca1eSMohammed Gamal *(u32 *)(0x11 * 4) = 0x1000; /* Store a pointer to address 0x1000 in IDT entry 0x11 */ 96596b9ca1eSMohammed Gamal *(u8 *)(0x1000) = 0xcf; /* 0x1000 contains an IRET instruction */ 96696b9ca1eSMohammed Gamal 96796b9ca1eSMohammed Gamal MK_INSN(int11, "int $0x11\n\t"); 96896b9ca1eSMohammed Gamal 96996b9ca1eSMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 97096b9ca1eSMohammed Gamal insn_int11, 97196b9ca1eSMohammed Gamal insn_int11_end - insn_int11); 97296b9ca1eSMohammed Gamal 97396b9ca1eSMohammed Gamal if (!regs_equal(&inregs, &outregs, 0)) 97496b9ca1eSMohammed Gamal print_serial("int Test 1: FAIL\n"); 97596b9ca1eSMohammed Gamal else 97696b9ca1eSMohammed Gamal print_serial("int Test 1: PASS\n"); 97796b9ca1eSMohammed Gamal } 97896b9ca1eSMohammed Gamal 979fa74f8a6SMohammed Gamal void test_imul() 980fa74f8a6SMohammed Gamal { 981fa74f8a6SMohammed Gamal struct regs inregs = { 0 }, outregs; 982fa74f8a6SMohammed Gamal 983fa74f8a6SMohammed Gamal MK_INSN(imul8_1, "mov $2, %al\n\t" 984fa74f8a6SMohammed Gamal "mov $-4, %cx\n\t" 985fa74f8a6SMohammed Gamal "imul %cl\n\t"); 986fa74f8a6SMohammed Gamal 987fa74f8a6SMohammed Gamal MK_INSN(imul16_1, "mov $2, %ax\n\t" 988fa74f8a6SMohammed Gamal "mov $-4, %cx\n\t" 989fa74f8a6SMohammed Gamal "imul %cx\n\t"); 990fa74f8a6SMohammed Gamal 991fa74f8a6SMohammed Gamal MK_INSN(imul32_1, "mov $2, %eax\n\t" 992fa74f8a6SMohammed Gamal "mov $-4, %ecx\n\t" 993fa74f8a6SMohammed Gamal "imul %ecx\n\t"); 994fa74f8a6SMohammed Gamal 995fa74f8a6SMohammed Gamal MK_INSN(imul8_2, "mov $0x12340002, %eax\n\t" 996fa74f8a6SMohammed Gamal "mov $4, %cx\n\t" 997fa74f8a6SMohammed Gamal "imul %cl\n\t"); 998fa74f8a6SMohammed Gamal 999fa74f8a6SMohammed Gamal MK_INSN(imul16_2, "mov $2, %ax\n\t" 1000fa74f8a6SMohammed Gamal "mov $4, %cx\n\t" 1001fa74f8a6SMohammed Gamal "imul %cx\n\t"); 1002fa74f8a6SMohammed Gamal 1003fa74f8a6SMohammed Gamal MK_INSN(imul32_2, "mov $2, %eax\n\t" 1004fa74f8a6SMohammed Gamal "mov $4, %ecx\n\t" 1005fa74f8a6SMohammed Gamal "imul %ecx\n\t"); 1006fa74f8a6SMohammed Gamal 1007fa74f8a6SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 1008fa74f8a6SMohammed Gamal insn_imul8_1, 1009fa74f8a6SMohammed Gamal insn_imul8_1_end - insn_imul8_1); 1010fa74f8a6SMohammed Gamal 1011fa74f8a6SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || (outregs.eax & 0xff) != (u8)-8) 1012fa74f8a6SMohammed Gamal print_serial("imul Test 1: FAIL\n"); 1013fa74f8a6SMohammed Gamal else 1014fa74f8a6SMohammed Gamal print_serial("imul Test 1: PASS\n"); 1015fa74f8a6SMohammed Gamal 1016fa74f8a6SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 1017fa74f8a6SMohammed Gamal insn_imul16_1, 1018fa74f8a6SMohammed Gamal insn_imul16_1_end - insn_imul16_1); 1019fa74f8a6SMohammed Gamal 1020fa74f8a6SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u16)-8) 1021fa74f8a6SMohammed Gamal print_serial("imul Test 2: FAIL\n"); 1022fa74f8a6SMohammed Gamal else 1023fa74f8a6SMohammed Gamal print_serial("imul Test 2: PASS\n"); 1024fa74f8a6SMohammed Gamal 1025fa74f8a6SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 1026fa74f8a6SMohammed Gamal insn_imul32_1, 1027fa74f8a6SMohammed Gamal insn_imul32_1_end - insn_imul32_1); 1028fa74f8a6SMohammed Gamal 1029fa74f8a6SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u32)-8) 1030fa74f8a6SMohammed Gamal print_serial("imul Test 3: FAIL\n"); 1031fa74f8a6SMohammed Gamal else 1032fa74f8a6SMohammed Gamal print_serial("imul Test 3: PASS\n"); 1033fa74f8a6SMohammed Gamal 1034fa74f8a6SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 1035fa74f8a6SMohammed Gamal insn_imul8_2, 1036fa74f8a6SMohammed Gamal insn_imul8_2_end - insn_imul8_2); 1037fa74f8a6SMohammed Gamal 1038fa74f8a6SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || (outregs.eax & 0xffff) != 8 || 1039fa74f8a6SMohammed Gamal (outregs.eax & 0xffff0000) != 0x12340000) 1040fa74f8a6SMohammed Gamal print_serial("imul Test 4: FAIL\n"); 1041fa74f8a6SMohammed Gamal else 1042fa74f8a6SMohammed Gamal print_serial("imul Test 4: PASS\n"); 1043fa74f8a6SMohammed Gamal 1044fa74f8a6SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 1045fa74f8a6SMohammed Gamal insn_imul16_2, 1046fa74f8a6SMohammed Gamal insn_imul16_2_end - insn_imul16_2); 1047fa74f8a6SMohammed Gamal 1048fa74f8a6SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 8) 1049fa74f8a6SMohammed Gamal print_serial("imul Test 5: FAIL\n"); 1050fa74f8a6SMohammed Gamal else 1051fa74f8a6SMohammed Gamal print_serial("imul Test 5: PASS\n"); 1052fa74f8a6SMohammed Gamal 1053fa74f8a6SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 1054fa74f8a6SMohammed Gamal insn_imul32_2, 1055fa74f8a6SMohammed Gamal insn_imul32_2_end - insn_imul32_2); 1056fa74f8a6SMohammed Gamal 1057fa74f8a6SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 8) 1058fa74f8a6SMohammed Gamal print_serial("imul Test 6: FAIL\n"); 1059fa74f8a6SMohammed Gamal else 1060fa74f8a6SMohammed Gamal print_serial("imul Test 6: PASS\n"); 1061fa74f8a6SMohammed Gamal } 1062fa74f8a6SMohammed Gamal 106359317bd1SMohammed Gamal void test_mul() 106459317bd1SMohammed Gamal { 106559317bd1SMohammed Gamal struct regs inregs = { 0 }, outregs; 106659317bd1SMohammed Gamal 106759317bd1SMohammed Gamal MK_INSN(mul8, "mov $2, %al\n\t" 106859317bd1SMohammed Gamal "mov $4, %cx\n\t" 106959317bd1SMohammed Gamal "imul %cl\n\t"); 107059317bd1SMohammed Gamal 107159317bd1SMohammed Gamal MK_INSN(mul16, "mov $2, %ax\n\t" 107259317bd1SMohammed Gamal "mov $4, %cx\n\t" 107359317bd1SMohammed Gamal "imul %cx\n\t"); 107459317bd1SMohammed Gamal 107559317bd1SMohammed Gamal MK_INSN(mul32, "mov $2, %eax\n\t" 107659317bd1SMohammed Gamal "mov $4, %ecx\n\t" 107759317bd1SMohammed Gamal "imul %ecx\n\t"); 107859317bd1SMohammed Gamal 107959317bd1SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 108059317bd1SMohammed Gamal insn_mul8, 108159317bd1SMohammed Gamal insn_mul8_end - insn_mul8); 108259317bd1SMohammed Gamal 108359317bd1SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || (outregs.eax & 0xff) != 8) 108459317bd1SMohammed Gamal print_serial("mul Test 1: FAIL\n"); 108559317bd1SMohammed Gamal else 108659317bd1SMohammed Gamal print_serial("mul Test 1: PASS\n"); 108759317bd1SMohammed Gamal 108859317bd1SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 108959317bd1SMohammed Gamal insn_mul16, 109059317bd1SMohammed Gamal insn_mul16_end - insn_mul16); 109159317bd1SMohammed Gamal 109259317bd1SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 8) 109359317bd1SMohammed Gamal print_serial("mul Test 2: FAIL\n"); 109459317bd1SMohammed Gamal else 109559317bd1SMohammed Gamal print_serial("mul Test 2: PASS\n"); 109659317bd1SMohammed Gamal 109759317bd1SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 109859317bd1SMohammed Gamal insn_mul32, 109959317bd1SMohammed Gamal insn_mul32_end - insn_mul32); 110059317bd1SMohammed Gamal 110159317bd1SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 8) 110259317bd1SMohammed Gamal print_serial("mul Test 3: FAIL\n"); 110359317bd1SMohammed Gamal else 110459317bd1SMohammed Gamal print_serial("mul Test 3: PASS\n"); 110559317bd1SMohammed Gamal } 110659317bd1SMohammed Gamal 11070d4c7614SMohammed Gamal void test_div() 11080d4c7614SMohammed Gamal { 11090d4c7614SMohammed Gamal struct regs inregs = { 0 }, outregs; 11100d4c7614SMohammed Gamal 11110d4c7614SMohammed Gamal MK_INSN(div8, "mov $257, %ax\n\t" 11120d4c7614SMohammed Gamal "mov $2, %cl\n\t" 11130d4c7614SMohammed Gamal "div %cl\n\t"); 11140d4c7614SMohammed Gamal 11150d4c7614SMohammed Gamal MK_INSN(div16, "mov $512, %ax\n\t" 11160d4c7614SMohammed Gamal "mov $5, %cx\n\t" 11170d4c7614SMohammed Gamal "div %cx\n\t"); 11180d4c7614SMohammed Gamal 11190d4c7614SMohammed Gamal MK_INSN(div32, "mov $512, %eax\n\t" 11200d4c7614SMohammed Gamal "mov $5, %ecx\n\t" 11210d4c7614SMohammed Gamal "div %ecx\n\t"); 11220d4c7614SMohammed Gamal 11230d4c7614SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 11240d4c7614SMohammed Gamal insn_div8, 11250d4c7614SMohammed Gamal insn_div8_end - insn_div8); 11260d4c7614SMohammed Gamal 11270d4c7614SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 384) 11280d4c7614SMohammed Gamal print_serial("div Test 1: FAIL\n"); 11290d4c7614SMohammed Gamal else 11300d4c7614SMohammed Gamal print_serial("div Test 1: PASS\n"); 11310d4c7614SMohammed Gamal 11320d4c7614SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 11330d4c7614SMohammed Gamal insn_div16, 11340d4c7614SMohammed Gamal insn_div16_end - insn_div16); 11350d4c7614SMohammed Gamal 11360d4c7614SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 102 || 11370d4c7614SMohammed Gamal outregs.edx != 2) 11380d4c7614SMohammed Gamal print_serial("div Test 2: FAIL\n"); 11390d4c7614SMohammed Gamal else 11400d4c7614SMohammed Gamal print_serial("div Test 2: PASS\n"); 11410d4c7614SMohammed Gamal 11420d4c7614SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 11430d4c7614SMohammed Gamal insn_div32, 11440d4c7614SMohammed Gamal insn_div32_end - insn_div32); 11450d4c7614SMohammed Gamal 11460d4c7614SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 102 || 11470d4c7614SMohammed Gamal outregs.edx != 2) 11480d4c7614SMohammed Gamal print_serial("div Test 3: FAIL\n"); 11490d4c7614SMohammed Gamal else 11500d4c7614SMohammed Gamal print_serial("div Test 3: PASS\n"); 11510d4c7614SMohammed Gamal } 11520d4c7614SMohammed Gamal 11530d4c7614SMohammed Gamal void test_idiv() 11540d4c7614SMohammed Gamal { 11550d4c7614SMohammed Gamal struct regs inregs = { 0 }, outregs; 11560d4c7614SMohammed Gamal 11570d4c7614SMohammed Gamal MK_INSN(idiv8, "mov $256, %ax\n\t" 11580d4c7614SMohammed Gamal "mov $-2, %cl\n\t" 11590d4c7614SMohammed Gamal "idiv %cl\n\t"); 11600d4c7614SMohammed Gamal 11610d4c7614SMohammed Gamal MK_INSN(idiv16, "mov $512, %ax\n\t" 11620d4c7614SMohammed Gamal "mov $-2, %cx\n\t" 11630d4c7614SMohammed Gamal "idiv %cx\n\t"); 11640d4c7614SMohammed Gamal 11650d4c7614SMohammed Gamal MK_INSN(idiv32, "mov $512, %eax\n\t" 11660d4c7614SMohammed Gamal "mov $-2, %ecx\n\t" 11670d4c7614SMohammed Gamal "idiv %ecx\n\t"); 11680d4c7614SMohammed Gamal 11690d4c7614SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 11700d4c7614SMohammed Gamal insn_idiv8, 11710d4c7614SMohammed Gamal insn_idiv8_end - insn_idiv8); 11720d4c7614SMohammed Gamal 11730d4c7614SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u8)-128) 11740d4c7614SMohammed Gamal print_serial("idiv Test 1: FAIL\n"); 11750d4c7614SMohammed Gamal else 11760d4c7614SMohammed Gamal print_serial("idiv Test 1: PASS\n"); 11770d4c7614SMohammed Gamal 11780d4c7614SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 11790d4c7614SMohammed Gamal insn_idiv16, 11800d4c7614SMohammed Gamal insn_idiv16_end - insn_idiv16); 11810d4c7614SMohammed Gamal 11820d4c7614SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u16)-256) 11830d4c7614SMohammed Gamal print_serial("idiv Test 2: FAIL\n"); 11840d4c7614SMohammed Gamal else 11850d4c7614SMohammed Gamal print_serial("idiv Test 2: PASS\n"); 11860d4c7614SMohammed Gamal 11870d4c7614SMohammed Gamal exec_in_big_real_mode(&inregs, &outregs, 11880d4c7614SMohammed Gamal insn_idiv32, 11890d4c7614SMohammed Gamal insn_idiv32_end - insn_idiv32); 11900d4c7614SMohammed Gamal 11910d4c7614SMohammed Gamal if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u32)-256) 11920d4c7614SMohammed Gamal print_serial("idiv Test 3: FAIL\n"); 11930d4c7614SMohammed Gamal else 11940d4c7614SMohammed Gamal print_serial("idiv Test 3: PASS\n"); 11950d4c7614SMohammed Gamal } 11960d4c7614SMohammed Gamal 11976e293cf5SWei Yongjun void test_cbw(void) 11986e293cf5SWei Yongjun { 11996e293cf5SWei Yongjun struct regs inregs = { 0 }, outregs; 12006e293cf5SWei Yongjun 12016e293cf5SWei Yongjun MK_INSN(cbw, "mov $0xFE, %eax \n\t" 12026e293cf5SWei Yongjun "cbw\n\t"); 12036e293cf5SWei Yongjun MK_INSN(cwde, "mov $0xFFFE, %eax \n\t" 12046e293cf5SWei Yongjun "cwde\n\t"); 12056e293cf5SWei Yongjun 12066e293cf5SWei Yongjun exec_in_big_real_mode(&inregs, &outregs, 12076e293cf5SWei Yongjun insn_cbw, 12086e293cf5SWei Yongjun insn_cbw_end - insn_cbw); 12096e293cf5SWei Yongjun if (outregs.eax != 0xFFFE) 12106e293cf5SWei Yongjun print_serial("cbw test1: FAIL\n"); 12116e293cf5SWei Yongjun else 12126e293cf5SWei Yongjun print_serial("cbw test 1: PASS\n"); 12136e293cf5SWei Yongjun 12146e293cf5SWei Yongjun exec_in_big_real_mode(&inregs, &outregs, 12156e293cf5SWei Yongjun insn_cwde, 12166e293cf5SWei Yongjun insn_cwde_end - insn_cwde); 12176e293cf5SWei Yongjun if (outregs.eax != 0xFFFFFFFE) 12186e293cf5SWei Yongjun print_serial("cwde test1: FAIL\n"); 12196e293cf5SWei Yongjun else 12206e293cf5SWei Yongjun print_serial("cwde test 1: PASS\n"); 12216e293cf5SWei Yongjun } 12226e293cf5SWei Yongjun 1223*eacef4e2SWei Yongjun void test_loopcc(void) 1224*eacef4e2SWei Yongjun { 1225*eacef4e2SWei Yongjun struct regs inregs = { 0 }, outregs; 1226*eacef4e2SWei Yongjun 1227*eacef4e2SWei Yongjun MK_INSN(loop, "mov $10, %ecx\n\t" 1228*eacef4e2SWei Yongjun "1: inc %eax\n\t" 1229*eacef4e2SWei Yongjun "loop 1b\n\t"); 1230*eacef4e2SWei Yongjun 1231*eacef4e2SWei Yongjun MK_INSN(loope, "mov $10, %ecx\n\t" 1232*eacef4e2SWei Yongjun "mov $1, %eax\n\t" 1233*eacef4e2SWei Yongjun "1: dec %eax\n\t" 1234*eacef4e2SWei Yongjun "loope 1b\n\t"); 1235*eacef4e2SWei Yongjun 1236*eacef4e2SWei Yongjun MK_INSN(loopne, "mov $10, %ecx\n\t" 1237*eacef4e2SWei Yongjun "mov $5, %eax\n\t" 1238*eacef4e2SWei Yongjun "1: dec %eax\n\t" 1239*eacef4e2SWei Yongjun "loopne 1b\n\t"); 1240*eacef4e2SWei Yongjun 1241*eacef4e2SWei Yongjun exec_in_big_real_mode(&inregs, &outregs, 1242*eacef4e2SWei Yongjun insn_loop, insn_loop_end - insn_loop); 1243*eacef4e2SWei Yongjun if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 10) 1244*eacef4e2SWei Yongjun print_serial("LOOPcc short Test 1: FAIL\n"); 1245*eacef4e2SWei Yongjun else 1246*eacef4e2SWei Yongjun print_serial("LOOPcc short Test 1: PASS\n"); 1247*eacef4e2SWei Yongjun 1248*eacef4e2SWei Yongjun exec_in_big_real_mode(&inregs, &outregs, 1249*eacef4e2SWei Yongjun insn_loope, insn_loope_end - insn_loope); 1250*eacef4e2SWei Yongjun if(!regs_equal(&inregs, &outregs, R_AX | R_CX) || 1251*eacef4e2SWei Yongjun outregs.eax != -1 || outregs.ecx != 8) 1252*eacef4e2SWei Yongjun print_serial("LOOPcc short Test 2: FAIL\n"); 1253*eacef4e2SWei Yongjun else 1254*eacef4e2SWei Yongjun print_serial("LOOPcc short Test 2: PASS\n"); 1255*eacef4e2SWei Yongjun 1256*eacef4e2SWei Yongjun exec_in_big_real_mode(&inregs, &outregs, 1257*eacef4e2SWei Yongjun insn_loopne, insn_loopne_end - insn_loopne); 1258*eacef4e2SWei Yongjun if(!regs_equal(&inregs, &outregs, R_AX | R_CX) || 1259*eacef4e2SWei Yongjun outregs.eax != 0 || outregs.ecx != 5) 1260*eacef4e2SWei Yongjun print_serial("LOOPcc short Test 3: FAIL\n"); 1261*eacef4e2SWei Yongjun else 1262*eacef4e2SWei Yongjun print_serial("LOOPcc short Test 3: PASS\n"); 1263*eacef4e2SWei Yongjun } 1264*eacef4e2SWei Yongjun 12657d36db35SAvi Kivity void realmode_start(void) 12667d36db35SAvi Kivity { 12677d36db35SAvi Kivity test_null(); 12687d36db35SAvi Kivity 12697d36db35SAvi Kivity test_shld(); 12707d36db35SAvi Kivity test_push_pop(); 12717d36db35SAvi Kivity test_pusha_popa(); 12727d36db35SAvi Kivity test_mov_imm(); 12737d36db35SAvi Kivity test_cmp_imm(); 12747d36db35SAvi Kivity test_add_imm(); 12757d36db35SAvi Kivity test_sub_imm(); 12767d36db35SAvi Kivity test_xor_imm(); 12777d36db35SAvi Kivity test_io(); 12787d36db35SAvi Kivity test_eflags_insn(); 12797d36db35SAvi Kivity test_jcc_short(); 12807d36db35SAvi Kivity test_jcc_near(); 12817d36db35SAvi Kivity /* test_call() uses short jump so call it after testing jcc */ 12827d36db35SAvi Kivity test_call(); 12837d36db35SAvi Kivity /* long jmp test uses call near so test it after testing call */ 12847d36db35SAvi Kivity test_long_jmp(); 12857d36db35SAvi Kivity test_xchg(); 12867d36db35SAvi Kivity test_iret(); 128796b9ca1eSMohammed Gamal test_int(); 1288fa74f8a6SMohammed Gamal test_imul(); 128959317bd1SMohammed Gamal test_mul(); 12900d4c7614SMohammed Gamal test_div(); 12910d4c7614SMohammed Gamal test_idiv(); 1292*eacef4e2SWei Yongjun test_loopcc(); 12936e293cf5SWei Yongjun test_cbw(); 12947d36db35SAvi Kivity 12957d36db35SAvi Kivity exit(0); 12967d36db35SAvi Kivity } 12977d36db35SAvi Kivity 12987d36db35SAvi Kivity unsigned long long r_gdt[] = { 0, 0x9b000000ffff, 0x93000000ffff }; 12997d36db35SAvi Kivity 13007d36db35SAvi Kivity struct __attribute__((packed)) { 13017d36db35SAvi Kivity unsigned short limit; 13027d36db35SAvi Kivity void *base; 13037d36db35SAvi Kivity } r_gdt_descr = { sizeof(r_gdt) - 1, &r_gdt }; 13047d36db35SAvi Kivity 13057d36db35SAvi Kivity asm( 13067d36db35SAvi Kivity ".section .init \n\t" 13077d36db35SAvi Kivity 13087d36db35SAvi Kivity ".code32 \n\t" 13097d36db35SAvi Kivity 13107d36db35SAvi Kivity "mb_magic = 0x1BADB002 \n\t" 13117d36db35SAvi Kivity "mb_flags = 0x0 \n\t" 13127d36db35SAvi Kivity 13137d36db35SAvi Kivity "# multiboot header \n\t" 13147d36db35SAvi Kivity ".long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) \n\t" 13157d36db35SAvi Kivity 13167d36db35SAvi Kivity ".globl start \n\t" 13177d36db35SAvi Kivity ".data \n\t" 13187d36db35SAvi Kivity ". = . + 4096 \n\t" 13197d36db35SAvi Kivity "stacktop: \n\t" 13207d36db35SAvi Kivity 13217d36db35SAvi Kivity ".text \n\t" 13227d36db35SAvi Kivity "start: \n\t" 13237d36db35SAvi Kivity "lgdt r_gdt_descr \n\t" 13247d36db35SAvi Kivity "ljmp $8, $1f; 1: \n\t" 13257d36db35SAvi Kivity ".code16gcc \n\t" 13267d36db35SAvi Kivity "mov $16, %eax \n\t" 13277d36db35SAvi Kivity "mov %ax, %ds \n\t" 13287d36db35SAvi Kivity "mov %ax, %es \n\t" 13297d36db35SAvi Kivity "mov %ax, %fs \n\t" 13307d36db35SAvi Kivity "mov %ax, %gs \n\t" 13317d36db35SAvi Kivity "mov %ax, %ss \n\t" 13327d36db35SAvi Kivity "mov %cr0, %eax \n\t" 13337d36db35SAvi Kivity "btc $0, %eax \n\t" 13347d36db35SAvi Kivity "mov %eax, %cr0 \n\t" 13357d36db35SAvi Kivity "ljmp $0, $realmode_entry \n\t" 13367d36db35SAvi Kivity 13377d36db35SAvi Kivity "realmode_entry: \n\t" 13387d36db35SAvi Kivity 13397d36db35SAvi Kivity "xor %ax, %ax \n\t" 13407d36db35SAvi Kivity "mov %ax, %ds \n\t" 13417d36db35SAvi Kivity "mov %ax, %es \n\t" 13427d36db35SAvi Kivity "mov %ax, %ss \n\t" 13437d36db35SAvi Kivity "mov %ax, %fs \n\t" 13447d36db35SAvi Kivity "mov %ax, %gs \n\t" 13457d36db35SAvi Kivity "mov $stacktop, %esp\n\t" 13467d36db35SAvi Kivity "ljmp $0, $realmode_start \n\t" 13477d36db35SAvi Kivity 13487d36db35SAvi Kivity ".code16gcc \n\t" 13497d36db35SAvi Kivity ); 1350