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 57d4dc402cSAvi Kivity struct insn_desc { 58d4dc402cSAvi Kivity u16 ptr; 59d4dc402cSAvi Kivity u16 len; 60d4dc402cSAvi Kivity }; 61d4dc402cSAvi Kivity 6218253fdeSAvi Kivity static struct regs inregs, outregs; 6318253fdeSAvi Kivity 6418253fdeSAvi Kivity static void exec_in_big_real_mode(struct insn_desc *insn) 657d36db35SAvi Kivity { 667d36db35SAvi Kivity unsigned long tmp; 677d36db35SAvi Kivity static struct regs save; 687d36db35SAvi Kivity int i; 697d36db35SAvi Kivity extern u8 test_insn[], test_insn_end[]; 707d36db35SAvi Kivity 71d4dc402cSAvi Kivity for (i = 0; i < insn->len; ++i) 72d4dc402cSAvi Kivity test_insn[i] = ((u8 *)(unsigned long)insn->ptr)[i]; 737d36db35SAvi Kivity for (; i < test_insn_end - test_insn; ++i) 747d36db35SAvi Kivity test_insn[i] = 0x90; // nop 757d36db35SAvi Kivity 7618253fdeSAvi Kivity save = inregs; 777d36db35SAvi Kivity asm volatile( 787d36db35SAvi Kivity "lgdtl %[gdt_descr] \n\t" 797d36db35SAvi Kivity "mov %%cr0, %[tmp] \n\t" 807d36db35SAvi Kivity "or $1, %[tmp] \n\t" 817d36db35SAvi Kivity "mov %[tmp], %%cr0 \n\t" 827d36db35SAvi Kivity "mov %[bigseg], %%gs \n\t" 837d36db35SAvi Kivity "and $-2, %[tmp] \n\t" 847d36db35SAvi Kivity "mov %[tmp], %%cr0 \n\t" 857d36db35SAvi Kivity 8632001692SAvi Kivity "pushw %[save]+36; popfw \n\t" 877d36db35SAvi Kivity "xchg %%eax, %[save]+0 \n\t" 887d36db35SAvi Kivity "xchg %%ebx, %[save]+4 \n\t" 897d36db35SAvi Kivity "xchg %%ecx, %[save]+8 \n\t" 907d36db35SAvi Kivity "xchg %%edx, %[save]+12 \n\t" 917d36db35SAvi Kivity "xchg %%esi, %[save]+16 \n\t" 927d36db35SAvi Kivity "xchg %%edi, %[save]+20 \n\t" 937d36db35SAvi Kivity "xchg %%esp, %[save]+24 \n\t" 947d36db35SAvi Kivity "xchg %%ebp, %[save]+28 \n\t" 957d36db35SAvi Kivity 967d36db35SAvi Kivity "test_insn: . = . + 32\n\t" 977d36db35SAvi Kivity "test_insn_end: \n\t" 987d36db35SAvi Kivity 997d36db35SAvi Kivity "xchg %%eax, %[save]+0 \n\t" 1007d36db35SAvi Kivity "xchg %%ebx, %[save]+4 \n\t" 1017d36db35SAvi Kivity "xchg %%ecx, %[save]+8 \n\t" 1027d36db35SAvi Kivity "xchg %%edx, %[save]+12 \n\t" 1037d36db35SAvi Kivity "xchg %%esi, %[save]+16 \n\t" 1047d36db35SAvi Kivity "xchg %%edi, %[save]+20 \n\t" 1057d36db35SAvi Kivity "xchg %%esp, %[save]+24 \n\t" 1067d36db35SAvi Kivity "xchg %%ebp, %[save]+28 \n\t" 1077d36db35SAvi Kivity 1087d36db35SAvi Kivity /* Save EFLAGS in outregs*/ 1097d36db35SAvi Kivity "pushfl \n\t" 1107d36db35SAvi Kivity "popl %[save]+36 \n\t" 1117d36db35SAvi Kivity 1127d36db35SAvi Kivity "xor %[tmp], %[tmp] \n\t" 1137d36db35SAvi Kivity "mov %[tmp], %%gs \n\t" 1147d36db35SAvi Kivity : [tmp]"=&r"(tmp), [save]"+m"(save) 1157d36db35SAvi Kivity : [gdt_descr]"m"(gdt_descr), [bigseg]"r"((short)16) 1167d36db35SAvi Kivity : "cc", "memory" 1177d36db35SAvi Kivity ); 11818253fdeSAvi Kivity outregs = save; 1197d36db35SAvi Kivity } 1207d36db35SAvi Kivity 1217d36db35SAvi Kivity #define R_AX 1 1227d36db35SAvi Kivity #define R_BX 2 1237d36db35SAvi Kivity #define R_CX 4 1247d36db35SAvi Kivity #define R_DX 8 1257d36db35SAvi Kivity #define R_SI 16 1267d36db35SAvi Kivity #define R_DI 32 1277d36db35SAvi Kivity #define R_SP 64 1287d36db35SAvi Kivity #define R_BP 128 1297d36db35SAvi Kivity 13018253fdeSAvi Kivity int regs_equal(int ignore) 1317d36db35SAvi Kivity { 13218253fdeSAvi Kivity const u32 *p1 = &inregs.eax, *p2 = &outregs.eax; // yuck 1337d36db35SAvi Kivity int i; 1347d36db35SAvi Kivity 1357d36db35SAvi Kivity for (i = 0; i < 8; ++i) 1367d36db35SAvi Kivity if (!(ignore & (1 << i)) && p1[i] != p2[i]) 1377d36db35SAvi Kivity return 0; 1387d36db35SAvi Kivity return 1; 1397d36db35SAvi Kivity } 1407d36db35SAvi Kivity 1416055ea1fSAvi Kivity static void report(const char *name, u16 regs_ignore, _Bool ok) 14281050840SAvi Kivity { 1436055ea1fSAvi Kivity if (!regs_equal(regs_ignore)) { 1446055ea1fSAvi Kivity ok = 0; 1456055ea1fSAvi Kivity } 14681050840SAvi Kivity print_serial(ok ? "PASS: " : "FAIL: "); 14781050840SAvi Kivity print_serial(name); 14881050840SAvi Kivity print_serial("\n"); 14981050840SAvi Kivity } 15081050840SAvi Kivity 1517d36db35SAvi Kivity #define MK_INSN(name, str) \ 1527d36db35SAvi Kivity asm ( \ 153d4dc402cSAvi Kivity ".pushsection .data.insn \n\t" \ 154d4dc402cSAvi Kivity "insn_" #name ": \n\t" \ 155d4dc402cSAvi Kivity ".word 1001f, 1002f - 1001f \n\t" \ 156d4dc402cSAvi Kivity ".popsection \n\t" \ 157d4dc402cSAvi Kivity ".pushsection .text.insn, \"ax\" \n\t" \ 158d4dc402cSAvi Kivity "1001: \n\t" \ 159d4dc402cSAvi Kivity "insn_code_" #name ": " str " \n\t" \ 160d4dc402cSAvi Kivity "1002: \n\t" \ 161d4dc402cSAvi Kivity ".popsection" \ 1627d36db35SAvi Kivity ); \ 163d4dc402cSAvi Kivity extern struct insn_desc insn_##name; 1647d36db35SAvi Kivity 1657d36db35SAvi Kivity void test_xchg(void) 1667d36db35SAvi Kivity { 1677d36db35SAvi Kivity MK_INSN(xchg_test1, "xchg %eax,%eax\n\t"); 1687d36db35SAvi Kivity MK_INSN(xchg_test2, "xchg %eax,%ebx\n\t"); 1697d36db35SAvi Kivity MK_INSN(xchg_test3, "xchg %eax,%ecx\n\t"); 1707d36db35SAvi Kivity MK_INSN(xchg_test4, "xchg %eax,%edx\n\t"); 1717d36db35SAvi Kivity MK_INSN(xchg_test5, "xchg %eax,%esi\n\t"); 1727d36db35SAvi Kivity MK_INSN(xchg_test6, "xchg %eax,%edi\n\t"); 1737d36db35SAvi Kivity MK_INSN(xchg_test7, "xchg %eax,%ebp\n\t"); 1747d36db35SAvi Kivity MK_INSN(xchg_test8, "xchg %eax,%esp\n\t"); 1757d36db35SAvi Kivity 17618253fdeSAvi Kivity inregs = (struct regs){ .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = 7}; 1777d36db35SAvi Kivity 17818253fdeSAvi Kivity exec_in_big_real_mode(&insn_xchg_test1); 1796055ea1fSAvi Kivity report("xchg 1", 0, 1); 18018253fdeSAvi Kivity 18118253fdeSAvi Kivity exec_in_big_real_mode(&insn_xchg_test2); 1826055ea1fSAvi Kivity report("xchg 2", R_AX | R_BX, 1836055ea1fSAvi Kivity outregs.eax == inregs.ebx && outregs.ebx == inregs.eax); 1847d36db35SAvi Kivity 18518253fdeSAvi Kivity exec_in_big_real_mode(&insn_xchg_test3); 1866055ea1fSAvi Kivity report("xchg 3", R_AX | R_CX, 1876055ea1fSAvi Kivity outregs.eax == inregs.ecx && outregs.ecx == inregs.eax); 1887d36db35SAvi Kivity 18918253fdeSAvi Kivity exec_in_big_real_mode(&insn_xchg_test4); 1906055ea1fSAvi Kivity report("xchg 4", R_AX | R_DX, 1916055ea1fSAvi Kivity outregs.eax == inregs.edx && outregs.edx == inregs.eax); 1927d36db35SAvi Kivity 19318253fdeSAvi Kivity exec_in_big_real_mode(&insn_xchg_test5); 1946055ea1fSAvi Kivity report("xchg 5", R_AX | R_SI, 1956055ea1fSAvi Kivity outregs.eax == inregs.esi && outregs.esi == inregs.eax); 1967d36db35SAvi Kivity 19718253fdeSAvi Kivity exec_in_big_real_mode(&insn_xchg_test6); 1986055ea1fSAvi Kivity report("xchg 6", R_AX | R_DI, 1996055ea1fSAvi Kivity outregs.eax == inregs.edi && outregs.edi == inregs.eax); 2007d36db35SAvi Kivity 20118253fdeSAvi Kivity exec_in_big_real_mode(&insn_xchg_test7); 2026055ea1fSAvi Kivity report("xchg 7", R_AX | R_BP, 2036055ea1fSAvi Kivity outregs.eax == inregs.ebp && outregs.ebp == inregs.eax); 2047d36db35SAvi Kivity 20518253fdeSAvi Kivity exec_in_big_real_mode(&insn_xchg_test8); 2066055ea1fSAvi Kivity report("xchg 8", R_AX | R_SP, 2076055ea1fSAvi Kivity outregs.eax == inregs.esp && outregs.esp == inregs.eax); 2087d36db35SAvi Kivity } 2097d36db35SAvi Kivity 2107d36db35SAvi Kivity void test_shld(void) 2117d36db35SAvi Kivity { 2127d36db35SAvi Kivity MK_INSN(shld_test, "shld $8,%edx,%eax\n\t"); 2137d36db35SAvi Kivity 21418253fdeSAvi Kivity inregs = (struct regs){ .eax = 0xbe, .edx = 0xef000000 }; 21518253fdeSAvi Kivity exec_in_big_real_mode(&insn_shld_test); 2166055ea1fSAvi Kivity report("shld", ~0, outregs.eax == 0xbeef); 2177d36db35SAvi Kivity } 2187d36db35SAvi Kivity 2197d36db35SAvi Kivity void test_mov_imm(void) 2207d36db35SAvi Kivity { 2217d36db35SAvi Kivity MK_INSN(mov_r32_imm_1, "mov $1234567890, %eax"); 2227d36db35SAvi Kivity MK_INSN(mov_r16_imm_1, "mov $1234, %ax"); 2237d36db35SAvi Kivity MK_INSN(mov_r8_imm_1, "mov $0x12, %ah"); 2247d36db35SAvi Kivity MK_INSN(mov_r8_imm_2, "mov $0x34, %al"); 2257d36db35SAvi Kivity MK_INSN(mov_r8_imm_3, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t"); 2267d36db35SAvi Kivity 22718253fdeSAvi Kivity inregs = (struct regs){ 0 }; 22818253fdeSAvi Kivity 22918253fdeSAvi Kivity exec_in_big_real_mode(&insn_mov_r16_imm_1); 2306055ea1fSAvi Kivity report("mov 1", R_AX, outregs.eax == 1234); 2317d36db35SAvi Kivity 2327d36db35SAvi Kivity /* test mov $imm, %eax */ 23318253fdeSAvi Kivity exec_in_big_real_mode(&insn_mov_r32_imm_1); 2346055ea1fSAvi Kivity report("mov 2", R_AX, outregs.eax == 1234567890); 2357d36db35SAvi Kivity 2367d36db35SAvi Kivity /* test mov $imm, %al/%ah */ 23718253fdeSAvi Kivity exec_in_big_real_mode(&insn_mov_r8_imm_1); 2386055ea1fSAvi Kivity report("mov 3", R_AX, outregs.eax == 0x1200); 2397d36db35SAvi Kivity 24018253fdeSAvi Kivity exec_in_big_real_mode(&insn_mov_r8_imm_2); 2416055ea1fSAvi Kivity report("mov 4", R_AX, outregs.eax == 0x34); 2427d36db35SAvi Kivity 24318253fdeSAvi Kivity exec_in_big_real_mode(&insn_mov_r8_imm_3); 2446055ea1fSAvi Kivity report("mov 5", R_AX, outregs.eax == 0x1234); 2457d36db35SAvi Kivity } 2467d36db35SAvi Kivity 2477d36db35SAvi Kivity void test_sub_imm(void) 2487d36db35SAvi Kivity { 2497d36db35SAvi Kivity MK_INSN(sub_r32_imm_1, "mov $1234567890, %eax\n\t" "sub $10, %eax\n\t"); 2507d36db35SAvi Kivity MK_INSN(sub_r16_imm_1, "mov $1234, %ax\n\t" "sub $10, %ax\n\t"); 2517d36db35SAvi Kivity MK_INSN(sub_r8_imm_1, "mov $0x12, %ah\n\t" "sub $0x10, %ah\n\t"); 2527d36db35SAvi Kivity MK_INSN(sub_r8_imm_2, "mov $0x34, %al\n\t" "sub $0x10, %al\n\t"); 2537d36db35SAvi Kivity 25418253fdeSAvi Kivity inregs = (struct regs){ 0 }; 25518253fdeSAvi Kivity 25618253fdeSAvi Kivity exec_in_big_real_mode(&insn_sub_r16_imm_1); 2576055ea1fSAvi Kivity report("sub 1", R_AX, outregs.eax == 1224); 2587d36db35SAvi Kivity 2597d36db35SAvi Kivity /* test mov $imm, %eax */ 26018253fdeSAvi Kivity exec_in_big_real_mode(&insn_sub_r32_imm_1); 2616055ea1fSAvi Kivity report("sub 2", R_AX, outregs.eax == 1234567880); 2627d36db35SAvi Kivity 2637d36db35SAvi Kivity /* test mov $imm, %al/%ah */ 26418253fdeSAvi Kivity exec_in_big_real_mode(&insn_sub_r8_imm_1); 2656055ea1fSAvi Kivity report("sub 3", R_AX, outregs.eax == 0x0200); 2667d36db35SAvi Kivity 26718253fdeSAvi Kivity exec_in_big_real_mode(&insn_sub_r8_imm_2); 2686055ea1fSAvi Kivity report("sub 4", R_AX, outregs.eax == 0x24); 2697d36db35SAvi Kivity } 2707d36db35SAvi Kivity 2717d36db35SAvi Kivity void test_xor_imm(void) 2727d36db35SAvi Kivity { 2737d36db35SAvi Kivity MK_INSN(xor_r32_imm_1, "mov $1234567890, %eax\n\t" "xor $1234567890, %eax\n\t"); 2747d36db35SAvi Kivity MK_INSN(xor_r16_imm_1, "mov $1234, %ax\n\t" "xor $1234, %ax\n\t"); 2757d36db35SAvi Kivity MK_INSN(xor_r8_imm_1, "mov $0x12, %ah\n\t" "xor $0x12, %ah\n\t"); 2767d36db35SAvi Kivity MK_INSN(xor_r8_imm_2, "mov $0x34, %al\n\t" "xor $0x34, %al\n\t"); 2777d36db35SAvi Kivity 27818253fdeSAvi Kivity inregs = (struct regs){ 0 }; 27918253fdeSAvi Kivity 28018253fdeSAvi Kivity exec_in_big_real_mode(&insn_xor_r16_imm_1); 2816055ea1fSAvi Kivity report("xor 1", R_AX, outregs.eax == 0); 2827d36db35SAvi Kivity 2837d36db35SAvi Kivity /* test mov $imm, %eax */ 28418253fdeSAvi Kivity exec_in_big_real_mode(&insn_xor_r32_imm_1); 2856055ea1fSAvi Kivity report("xor 2", R_AX, outregs.eax == 0); 2867d36db35SAvi Kivity 2877d36db35SAvi Kivity /* test mov $imm, %al/%ah */ 28818253fdeSAvi Kivity exec_in_big_real_mode(&insn_xor_r8_imm_1); 2896055ea1fSAvi Kivity report("xor 3", R_AX, outregs.eax == 0); 2907d36db35SAvi Kivity 29118253fdeSAvi Kivity exec_in_big_real_mode(&insn_xor_r8_imm_2); 2926055ea1fSAvi Kivity report("xor 4", R_AX, outregs.eax == 0); 2937d36db35SAvi Kivity } 2947d36db35SAvi Kivity 2957d36db35SAvi Kivity void test_cmp_imm(void) 2967d36db35SAvi Kivity { 2977d36db35SAvi Kivity MK_INSN(cmp_test1, "mov $0x34, %al\n\t" 2987d36db35SAvi Kivity "cmp $0x34, %al\n\t"); 2997d36db35SAvi Kivity MK_INSN(cmp_test2, "mov $0x34, %al\n\t" 3007d36db35SAvi Kivity "cmp $0x39, %al\n\t"); 3017d36db35SAvi Kivity MK_INSN(cmp_test3, "mov $0x34, %al\n\t" 3027d36db35SAvi Kivity "cmp $0x24, %al\n\t"); 3037d36db35SAvi Kivity 30418253fdeSAvi Kivity inregs = (struct regs){ 0 }; 30518253fdeSAvi Kivity 3067d36db35SAvi Kivity /* test cmp imm8 with AL */ 3077d36db35SAvi Kivity /* ZF: (bit 6) Zero Flag becomes 1 if an operation results 3087d36db35SAvi Kivity * in a 0 writeback, or 0 register 3097d36db35SAvi Kivity */ 31018253fdeSAvi Kivity exec_in_big_real_mode(&insn_cmp_test1); 3116055ea1fSAvi Kivity report("cmp 1", ~0, (outregs.eflags & (1<<6)) == (1<<6)); 3127d36db35SAvi Kivity 31318253fdeSAvi Kivity exec_in_big_real_mode(&insn_cmp_test2); 3146055ea1fSAvi Kivity report("cmp 2", ~0, (outregs.eflags & (1<<6)) == 0); 3157d36db35SAvi Kivity 31618253fdeSAvi Kivity exec_in_big_real_mode(&insn_cmp_test3); 3176055ea1fSAvi Kivity report("cmp 3", ~0, (outregs.eflags & (1<<6)) == 0); 3187d36db35SAvi Kivity } 3197d36db35SAvi Kivity 3207d36db35SAvi Kivity void test_add_imm(void) 3217d36db35SAvi Kivity { 3227d36db35SAvi Kivity MK_INSN(add_test1, "mov $0x43211234, %eax \n\t" 3237d36db35SAvi Kivity "add $0x12344321, %eax \n\t"); 3247d36db35SAvi Kivity MK_INSN(add_test2, "mov $0x12, %eax \n\t" 3257d36db35SAvi Kivity "add $0x21, %al\n\t"); 3267d36db35SAvi Kivity 32718253fdeSAvi Kivity inregs = (struct regs){ 0 }; 32818253fdeSAvi Kivity 32918253fdeSAvi Kivity exec_in_big_real_mode(&insn_add_test1); 3306055ea1fSAvi Kivity report("add 1", ~0, outregs.eax == 0x55555555); 3317d36db35SAvi Kivity 33218253fdeSAvi Kivity exec_in_big_real_mode(&insn_add_test2); 3336055ea1fSAvi Kivity report("add 2", ~0, outregs.eax == 0x33); 3347d36db35SAvi Kivity } 3357d36db35SAvi Kivity 3367d36db35SAvi Kivity void test_eflags_insn(void) 3377d36db35SAvi Kivity { 3387d36db35SAvi Kivity MK_INSN(clc, "clc"); 339b3261e48SMohammed Gamal MK_INSN(stc, "stc"); 3407d36db35SAvi Kivity MK_INSN(cli, "cli"); 3417d36db35SAvi Kivity MK_INSN(sti, "sti"); 3427d36db35SAvi Kivity MK_INSN(cld, "cld"); 3437d36db35SAvi Kivity MK_INSN(std, "std"); 3447d36db35SAvi Kivity 34518253fdeSAvi Kivity inregs = (struct regs){ 0 }; 34618253fdeSAvi Kivity 34718253fdeSAvi Kivity exec_in_big_real_mode(&insn_clc); 3486055ea1fSAvi Kivity report("clc", ~0, (outregs.eflags & 1) == 0); 3497d36db35SAvi Kivity 35018253fdeSAvi Kivity exec_in_big_real_mode(&insn_stc); 3516055ea1fSAvi Kivity report("stc", ~0, (outregs.eflags & 1) == 1); 352b3261e48SMohammed Gamal 35318253fdeSAvi Kivity exec_in_big_real_mode(&insn_cli); 3546055ea1fSAvi Kivity report("cli", ~0, !(outregs.eflags & (1 << 9))); 3557d36db35SAvi Kivity 35618253fdeSAvi Kivity exec_in_big_real_mode(&insn_sti); 3576055ea1fSAvi Kivity report("sti", ~0, outregs.eflags & (1 << 9)); 3587d36db35SAvi Kivity 35918253fdeSAvi Kivity exec_in_big_real_mode(&insn_cld); 3606055ea1fSAvi Kivity report("cld", ~0, !(outregs.eflags & (1 << 10))); 3617d36db35SAvi Kivity 36218253fdeSAvi Kivity exec_in_big_real_mode(&insn_std); 3636055ea1fSAvi Kivity report("std", ~0, (outregs.eflags & (1 << 10))); 3647d36db35SAvi Kivity } 3657d36db35SAvi Kivity 3667d36db35SAvi Kivity void test_io(void) 3677d36db35SAvi Kivity { 3687d36db35SAvi Kivity MK_INSN(io_test1, "mov $0xff, %al \n\t" 3697d36db35SAvi Kivity "out %al, $0xe0 \n\t" 3707d36db35SAvi Kivity "mov $0x00, %al \n\t" 3717d36db35SAvi Kivity "in $0xe0, %al \n\t"); 3727d36db35SAvi Kivity MK_INSN(io_test2, "mov $0xffff, %ax \n\t" 3737d36db35SAvi Kivity "out %ax, $0xe0 \n\t" 3747d36db35SAvi Kivity "mov $0x0000, %ax \n\t" 3757d36db35SAvi Kivity "in $0xe0, %ax \n\t"); 3767d36db35SAvi Kivity MK_INSN(io_test3, "mov $0xffffffff, %eax \n\t" 3777d36db35SAvi Kivity "out %eax, $0xe0 \n\t" 3787d36db35SAvi Kivity "mov $0x000000, %eax \n\t" 3797d36db35SAvi Kivity "in $0xe0, %eax \n\t"); 3807d36db35SAvi Kivity MK_INSN(io_test4, "mov $0xe0, %dx \n\t" 3817d36db35SAvi Kivity "mov $0xff, %al \n\t" 3827d36db35SAvi Kivity "out %al, %dx \n\t" 3837d36db35SAvi Kivity "mov $0x00, %al \n\t" 3847d36db35SAvi Kivity "in %dx, %al \n\t"); 3857d36db35SAvi Kivity MK_INSN(io_test5, "mov $0xe0, %dx \n\t" 3867d36db35SAvi Kivity "mov $0xffff, %ax \n\t" 3877d36db35SAvi Kivity "out %ax, %dx \n\t" 3887d36db35SAvi Kivity "mov $0x0000, %ax \n\t" 3897d36db35SAvi Kivity "in %dx, %ax \n\t"); 3907d36db35SAvi Kivity MK_INSN(io_test6, "mov $0xe0, %dx \n\t" 3917d36db35SAvi Kivity "mov $0xffffffff, %eax \n\t" 3927d36db35SAvi Kivity "out %eax, %dx \n\t" 3937d36db35SAvi Kivity "mov $0x00000000, %eax \n\t" 3947d36db35SAvi Kivity "in %dx, %eax \n\t"); 3957d36db35SAvi Kivity 39618253fdeSAvi Kivity inregs = (struct regs){ 0 }; 39718253fdeSAvi Kivity 39818253fdeSAvi Kivity exec_in_big_real_mode(&insn_io_test1); 3996055ea1fSAvi Kivity report("pio 1", R_AX, outregs.eax == 0xff); 4007d36db35SAvi Kivity 40118253fdeSAvi Kivity exec_in_big_real_mode(&insn_io_test2); 4026055ea1fSAvi Kivity report("pio 2", R_AX, outregs.eax == 0xffff); 4037d36db35SAvi Kivity 40418253fdeSAvi Kivity exec_in_big_real_mode(&insn_io_test3); 4056055ea1fSAvi Kivity report("pio 3", R_AX, outregs.eax == 0xffffffff); 4067d36db35SAvi Kivity 40718253fdeSAvi Kivity exec_in_big_real_mode(&insn_io_test4); 4086055ea1fSAvi Kivity report("pio 4", R_AX|R_DX, outregs.eax == 0xff); 4097d36db35SAvi Kivity 41018253fdeSAvi Kivity exec_in_big_real_mode(&insn_io_test5); 4116055ea1fSAvi Kivity report("pio 5", R_AX|R_DX, outregs.eax == 0xffff); 4127d36db35SAvi Kivity 41318253fdeSAvi Kivity exec_in_big_real_mode(&insn_io_test6); 4146055ea1fSAvi Kivity report("pio 6", R_AX|R_DX, outregs.eax == 0xffffffff); 4157d36db35SAvi Kivity } 4167d36db35SAvi Kivity 417c0b7268dSAvi Kivity asm ("retf: lretw"); 418c0b7268dSAvi Kivity extern void retf(); 419c0b7268dSAvi Kivity 4207d36db35SAvi Kivity void test_call(void) 4217d36db35SAvi Kivity { 4227d36db35SAvi Kivity u32 esp[16]; 423c0b7268dSAvi Kivity u32 addr; 4247d36db35SAvi Kivity 42518253fdeSAvi Kivity inregs = (struct regs){ 0 }; 4267d36db35SAvi Kivity inregs.esp = (u32)esp; 4277d36db35SAvi Kivity 4287d36db35SAvi Kivity MK_INSN(call1, "mov $test_function, %eax \n\t" 4297d36db35SAvi Kivity "call *%eax\n\t"); 4307d36db35SAvi Kivity MK_INSN(call_near1, "jmp 2f\n\t" 4317d36db35SAvi Kivity "1: mov $0x1234, %eax\n\t" 4327d36db35SAvi Kivity "ret\n\t" 4337d36db35SAvi Kivity "2: call 1b\t"); 4347d36db35SAvi Kivity MK_INSN(call_near2, "call 1f\n\t" 4357d36db35SAvi Kivity "jmp 2f\n\t" 4367d36db35SAvi Kivity "1: mov $0x1234, %eax\n\t" 4377d36db35SAvi Kivity "ret\n\t" 4387d36db35SAvi Kivity "2:\t"); 439c0b7268dSAvi Kivity MK_INSN(call_far1, "lcallw *(%ebx)\n\t"); 440556d2680SWei Yongjun MK_INSN(call_far2, "lcallw $0, $retf\n\t"); 441c6061817SAvi Kivity MK_INSN(ret_imm, "sub $10, %sp; jmp 2f; 1: retw $10; 2: callw 1b"); 4427d36db35SAvi Kivity 44318253fdeSAvi Kivity exec_in_big_real_mode(&insn_call1); 4446055ea1fSAvi Kivity report("call 1", R_AX, outregs.eax == 0x1234); 4457d36db35SAvi Kivity 44618253fdeSAvi Kivity exec_in_big_real_mode(&insn_call_near1); 4476055ea1fSAvi Kivity report("call near 1", R_AX, outregs.eax == 0x1234); 4487d36db35SAvi Kivity 44918253fdeSAvi Kivity exec_in_big_real_mode(&insn_call_near2); 4506055ea1fSAvi Kivity report("call near 2", R_AX, outregs.eax == 0x1234); 451c0b7268dSAvi Kivity 452c0b7268dSAvi Kivity addr = (((unsigned)retf >> 4) << 16) | ((unsigned)retf & 0x0f); 453c0b7268dSAvi Kivity inregs.ebx = (unsigned)&addr; 45418253fdeSAvi Kivity exec_in_big_real_mode(&insn_call_far1); 4556055ea1fSAvi Kivity report("call far 1", 0, 1); 456c6061817SAvi Kivity 457556d2680SWei Yongjun exec_in_big_real_mode(&insn_call_far2); 458556d2680SWei Yongjun report("call far 2", 0, 1); 459556d2680SWei Yongjun 46018253fdeSAvi Kivity exec_in_big_real_mode(&insn_ret_imm); 4616055ea1fSAvi Kivity report("ret imm 1", 0, 1); 4627d36db35SAvi Kivity } 4637d36db35SAvi Kivity 4647d36db35SAvi Kivity void test_jcc_short(void) 4657d36db35SAvi Kivity { 4667d36db35SAvi Kivity MK_INSN(jnz_short1, "jnz 1f\n\t" 4677d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 4687d36db35SAvi Kivity "1:\n\t"); 4697d36db35SAvi Kivity MK_INSN(jnz_short2, "1:\n\t" 4707d36db35SAvi Kivity "cmp $0x1234, %eax\n\t" 4717d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 4727d36db35SAvi Kivity "jnz 1b\n\t"); 4737d36db35SAvi Kivity MK_INSN(jmp_short1, "jmp 1f\n\t" 4747d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 4757d36db35SAvi Kivity "1:\n\t"); 4767d36db35SAvi Kivity 47718253fdeSAvi Kivity inregs = (struct regs){ 0 }; 4787d36db35SAvi Kivity 47918253fdeSAvi Kivity exec_in_big_real_mode(&insn_jnz_short1); 4806055ea1fSAvi Kivity report("jnz short 1", ~0, 1); 48118253fdeSAvi Kivity 48218253fdeSAvi Kivity exec_in_big_real_mode(&insn_jnz_short2); 4836055ea1fSAvi Kivity report("jnz short 2", R_AX, (outregs.eflags & (1 << 6))); 4847d36db35SAvi Kivity 48518253fdeSAvi Kivity exec_in_big_real_mode(&insn_jmp_short1); 4866055ea1fSAvi Kivity report("jmp short 1", ~0, 1); 4877d36db35SAvi Kivity } 4887d36db35SAvi Kivity 4897d36db35SAvi Kivity void test_jcc_near(void) 4907d36db35SAvi Kivity { 4917d36db35SAvi Kivity /* encode near jmp manually. gas will not do it if offsets < 127 byte */ 4927d36db35SAvi Kivity MK_INSN(jnz_near1, ".byte 0x0f, 0x85, 0x06, 0x00\n\t" 4937d36db35SAvi Kivity "mov $0x1234, %eax\n\t"); 4947d36db35SAvi Kivity MK_INSN(jnz_near2, "cmp $0x1234, %eax\n\t" 4957d36db35SAvi Kivity "mov $0x1234, %eax\n\t" 4967d36db35SAvi Kivity ".byte 0x0f, 0x85, 0xf0, 0xff\n\t"); 4977d36db35SAvi Kivity MK_INSN(jmp_near1, ".byte 0xE9, 0x06, 0x00\n\t" 4987d36db35SAvi Kivity "mov $0x1234, %eax\n\t"); 4997d36db35SAvi Kivity 50018253fdeSAvi Kivity inregs = (struct regs){ 0 }; 5017d36db35SAvi Kivity 50218253fdeSAvi Kivity exec_in_big_real_mode(&insn_jnz_near1); 5036055ea1fSAvi Kivity report("jnz near 1", 0, 1); 50418253fdeSAvi Kivity 50518253fdeSAvi Kivity exec_in_big_real_mode(&insn_jnz_near2); 5066055ea1fSAvi Kivity report("jnz near 2", R_AX, outregs.eflags & (1 << 6)); 5077d36db35SAvi Kivity 50818253fdeSAvi Kivity exec_in_big_real_mode(&insn_jmp_near1); 5096055ea1fSAvi Kivity report("jmp near 1", 0, 1); 5107d36db35SAvi Kivity } 5117d36db35SAvi Kivity 5127d36db35SAvi Kivity void test_long_jmp() 5137d36db35SAvi Kivity { 5147d36db35SAvi Kivity u32 esp[16]; 5157d36db35SAvi Kivity 51618253fdeSAvi Kivity inregs = (struct regs){ 0 }; 5174aa22949SAvi Kivity inregs.esp = (u32)(esp+16); 5187d36db35SAvi Kivity MK_INSN(long_jmp, "call 1f\n\t" 5197d36db35SAvi Kivity "jmp 2f\n\t" 5207d36db35SAvi Kivity "1: jmp $0, $test_function\n\t" 5217d36db35SAvi Kivity "2:\n\t"); 52218253fdeSAvi Kivity exec_in_big_real_mode(&insn_long_jmp); 5236055ea1fSAvi Kivity report("jmp far 1", R_AX, outregs.eax == 0x1234); 5247d36db35SAvi Kivity } 525fa74f8a6SMohammed Gamal 5267d36db35SAvi Kivity void test_push_pop() 5277d36db35SAvi Kivity { 5287d36db35SAvi Kivity MK_INSN(push32, "mov $0x12345678, %eax\n\t" 5297d36db35SAvi Kivity "push %eax\n\t" 5307d36db35SAvi Kivity "pop %ebx\n\t"); 5317d36db35SAvi Kivity MK_INSN(push16, "mov $0x1234, %ax\n\t" 5327d36db35SAvi Kivity "push %ax\n\t" 5337d36db35SAvi Kivity "pop %bx\n\t"); 5347d36db35SAvi Kivity 5357d36db35SAvi Kivity MK_INSN(push_es, "mov $0x231, %bx\n\t" //Just write a dummy value to see if it gets overwritten 5367d36db35SAvi Kivity "mov $0x123, %ax\n\t" 5377d36db35SAvi Kivity "mov %ax, %es\n\t" 5387d36db35SAvi Kivity "push %es\n\t" 5397d36db35SAvi Kivity "pop %bx \n\t" 5407d36db35SAvi Kivity ); 5417d36db35SAvi Kivity MK_INSN(pop_es, "push %ax\n\t" 5427d36db35SAvi Kivity "pop %es\n\t" 5437d36db35SAvi Kivity "mov %es, %bx\n\t" 5447d36db35SAvi Kivity ); 5457d36db35SAvi Kivity MK_INSN(push_pop_ss, "push %ss\n\t" 5467d36db35SAvi Kivity "pushw %ax\n\t" 5477d36db35SAvi Kivity "popw %ss\n\t" 5487d36db35SAvi Kivity "mov %ss, %bx\n\t" 5497d36db35SAvi Kivity "pop %ss\n\t" 5507d36db35SAvi Kivity ); 5517d36db35SAvi Kivity MK_INSN(push_pop_fs, "push %fs\n\t" 5527d36db35SAvi Kivity "pushl %eax\n\t" 5537d36db35SAvi Kivity "popl %fs\n\t" 5547d36db35SAvi Kivity "mov %fs, %ebx\n\t" 5557d36db35SAvi Kivity "pop %fs\n\t" 5567d36db35SAvi Kivity ); 55709b657b6SAvi Kivity MK_INSN(push_pop_high_esp_bits, 55809b657b6SAvi Kivity "xor $0x12340000, %esp \n\t" 55909b657b6SAvi Kivity "push %ax; \n\t" 56009b657b6SAvi Kivity "xor $0x12340000, %esp \n\t" 56109b657b6SAvi Kivity "pop %bx"); 5627d36db35SAvi Kivity 56318253fdeSAvi Kivity inregs = (struct regs){ 0 }; 56418253fdeSAvi Kivity 56518253fdeSAvi Kivity exec_in_big_real_mode(&insn_push32); 5666055ea1fSAvi Kivity report("push/pop 1", R_AX|R_BX, 5676055ea1fSAvi Kivity outregs.eax == outregs.ebx && outregs.eax == 0x12345678); 5687d36db35SAvi Kivity 56918253fdeSAvi Kivity exec_in_big_real_mode(&insn_push16); 5706055ea1fSAvi Kivity report("push/pop 2", R_AX|R_BX, 5716055ea1fSAvi Kivity outregs.eax == outregs.ebx && outregs.eax == 0x1234); 5727d36db35SAvi Kivity 57318253fdeSAvi Kivity exec_in_big_real_mode(&insn_push_es); 5746055ea1fSAvi Kivity report("push/pop 3", R_AX|R_BX, 5756055ea1fSAvi Kivity outregs.ebx == outregs.eax && outregs.eax == 0x123); 5767d36db35SAvi Kivity 57718253fdeSAvi Kivity exec_in_big_real_mode(&insn_pop_es); 5786055ea1fSAvi Kivity report("push/pop 4", R_AX|R_BX, outregs.ebx == outregs.eax); 5797d36db35SAvi Kivity 58018253fdeSAvi Kivity exec_in_big_real_mode(&insn_push_pop_ss); 5816055ea1fSAvi Kivity report("push/pop 5", R_AX|R_BX, outregs.ebx == outregs.eax); 5827d36db35SAvi Kivity 58318253fdeSAvi Kivity exec_in_big_real_mode(&insn_push_pop_fs); 5846055ea1fSAvi Kivity report("push/pop 6", R_AX|R_BX, outregs.ebx == outregs.eax); 58509b657b6SAvi Kivity 58609b657b6SAvi Kivity inregs.eax = 0x9977; 58709b657b6SAvi Kivity inregs.ebx = 0x7799; 58809b657b6SAvi Kivity exec_in_big_real_mode(&insn_push_pop_high_esp_bits); 58909b657b6SAvi Kivity report("push/pop with high bits set in %esp", R_BX, outregs.ebx == 0x9977); 5907d36db35SAvi Kivity } 5917d36db35SAvi Kivity 5927d36db35SAvi Kivity void test_null(void) 5937d36db35SAvi Kivity { 594d4dc402cSAvi Kivity MK_INSN(null, ""); 595d4dc402cSAvi Kivity 59618253fdeSAvi Kivity inregs = (struct regs){ 0 }; 59718253fdeSAvi Kivity 59818253fdeSAvi Kivity exec_in_big_real_mode(&insn_null); 5996055ea1fSAvi Kivity report("null", 0, 1); 6007d36db35SAvi Kivity } 6017d36db35SAvi Kivity 6027d36db35SAvi Kivity struct { 6037d36db35SAvi Kivity char stack[500]; 6047d36db35SAvi Kivity char top[]; 6057d36db35SAvi Kivity } tmp_stack; 6067d36db35SAvi Kivity 6077d36db35SAvi Kivity void test_pusha_popa() 6087d36db35SAvi Kivity { 6097d36db35SAvi Kivity MK_INSN(pusha, "pusha\n\t" 6107d36db35SAvi Kivity "pop %edi\n\t" 6117d36db35SAvi Kivity "pop %esi\n\t" 6127d36db35SAvi Kivity "pop %ebp\n\t" 6137d36db35SAvi Kivity "add $4, %esp\n\t" 6147d36db35SAvi Kivity "pop %ebx\n\t" 6157d36db35SAvi Kivity "pop %edx\n\t" 6167d36db35SAvi Kivity "pop %ecx\n\t" 6177d36db35SAvi Kivity "pop %eax\n\t" 6187d36db35SAvi Kivity ); 6197d36db35SAvi Kivity 6207d36db35SAvi Kivity MK_INSN(popa, "push %eax\n\t" 6217d36db35SAvi Kivity "push %ecx\n\t" 6227d36db35SAvi Kivity "push %edx\n\t" 6237d36db35SAvi Kivity "push %ebx\n\t" 6247d36db35SAvi Kivity "push %esp\n\t" 6257d36db35SAvi Kivity "push %ebp\n\t" 6267d36db35SAvi Kivity "push %esi\n\t" 6277d36db35SAvi Kivity "push %edi\n\t" 6287d36db35SAvi Kivity "popa\n\t" 6297d36db35SAvi Kivity ); 6307d36db35SAvi Kivity 63118253fdeSAvi Kivity inregs = (struct regs){ .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = (unsigned long)&tmp_stack.top }; 6327d36db35SAvi Kivity 63318253fdeSAvi Kivity exec_in_big_real_mode(&insn_pusha); 6346055ea1fSAvi Kivity report("pusha/popa 1", 0, 1); 63518253fdeSAvi Kivity 63618253fdeSAvi Kivity exec_in_big_real_mode(&insn_popa); 6376055ea1fSAvi Kivity report("pusha/popa 1", 0, 1); 6387d36db35SAvi Kivity } 6397d36db35SAvi Kivity 6407d36db35SAvi Kivity void test_iret() 6417d36db35SAvi Kivity { 6427d36db35SAvi Kivity MK_INSN(iret32, "pushf\n\t" 6437d36db35SAvi Kivity "pushl %cs\n\t" 6447d36db35SAvi Kivity "call 1f\n\t" /* a near call will push eip onto the stack */ 6457d36db35SAvi Kivity "jmp 2f\n\t" 6467d36db35SAvi Kivity "1: iret\n\t" 6477d36db35SAvi Kivity "2:\n\t" 6487d36db35SAvi Kivity ); 6497d36db35SAvi Kivity 6507d36db35SAvi Kivity MK_INSN(iret16, "pushfw\n\t" 6517d36db35SAvi Kivity "pushw %cs\n\t" 6527d36db35SAvi Kivity "callw 1f\n\t" 6537d36db35SAvi Kivity "jmp 2f\n\t" 6547d36db35SAvi Kivity "1: iretw\n\t" 6557d36db35SAvi Kivity "2:\n\t"); 6567d36db35SAvi Kivity 6577d36db35SAvi Kivity MK_INSN(iret_flags32, "pushfl\n\t" 6587d36db35SAvi Kivity "popl %eax\n\t" 6597d36db35SAvi Kivity "andl $~0x2, %eax\n\t" 6607d36db35SAvi Kivity "orl $0xffc08028, %eax\n\t" 6617d36db35SAvi Kivity "pushl %eax\n\t" 6627d36db35SAvi Kivity "pushl %cs\n\t" 6637d36db35SAvi Kivity "call 1f\n\t" 6647d36db35SAvi Kivity "jmp 2f\n\t" 6657d36db35SAvi Kivity "1: iret\n\t" 6667d36db35SAvi Kivity "2:\n\t"); 6677d36db35SAvi Kivity 6687d36db35SAvi Kivity MK_INSN(iret_flags16, "pushfw\n\t" 6697d36db35SAvi Kivity "popw %ax\n\t" 6707d36db35SAvi Kivity "and $~0x2, %ax\n\t" 6717d36db35SAvi Kivity "or $0x8028, %ax\n\t" 6727d36db35SAvi Kivity "pushw %ax\n\t" 6737d36db35SAvi Kivity "pushw %cs\n\t" 6747d36db35SAvi Kivity "callw 1f\n\t" 6757d36db35SAvi Kivity "jmp 2f\n\t" 6767d36db35SAvi Kivity "1: iretw\n\t" 6777d36db35SAvi Kivity "2:\n\t"); 6787d36db35SAvi Kivity 67918253fdeSAvi Kivity inregs = (struct regs){ 0 }; 6807d36db35SAvi Kivity 68118253fdeSAvi Kivity exec_in_big_real_mode(&insn_iret32); 6826055ea1fSAvi Kivity report("iret 1", 0, 1); 6837d36db35SAvi Kivity 68418253fdeSAvi Kivity exec_in_big_real_mode(&insn_iret16); 6856055ea1fSAvi Kivity report("iret 2", 0, 1); 6867d36db35SAvi Kivity 68718253fdeSAvi Kivity exec_in_big_real_mode(&insn_iret_flags32); 6886055ea1fSAvi Kivity report("iret 3", R_AX, 1); 68918253fdeSAvi Kivity 69018253fdeSAvi Kivity exec_in_big_real_mode(&insn_iret_flags16); 6916055ea1fSAvi Kivity report("iret 4", R_AX, 1); 6927d36db35SAvi Kivity } 6937d36db35SAvi Kivity 69496b9ca1eSMohammed Gamal void test_int() 69596b9ca1eSMohammed Gamal { 69618253fdeSAvi Kivity inregs = (struct regs){ 0 }; 69796b9ca1eSMohammed Gamal 69896b9ca1eSMohammed Gamal *(u32 *)(0x11 * 4) = 0x1000; /* Store a pointer to address 0x1000 in IDT entry 0x11 */ 69996b9ca1eSMohammed Gamal *(u8 *)(0x1000) = 0xcf; /* 0x1000 contains an IRET instruction */ 70096b9ca1eSMohammed Gamal 70196b9ca1eSMohammed Gamal MK_INSN(int11, "int $0x11\n\t"); 70296b9ca1eSMohammed Gamal 70318253fdeSAvi Kivity exec_in_big_real_mode(&insn_int11); 7046055ea1fSAvi Kivity report("int 1", 0, 1); 70596b9ca1eSMohammed Gamal } 70696b9ca1eSMohammed Gamal 707fa74f8a6SMohammed Gamal void test_imul() 708fa74f8a6SMohammed Gamal { 709fa74f8a6SMohammed Gamal MK_INSN(imul8_1, "mov $2, %al\n\t" 710fa74f8a6SMohammed Gamal "mov $-4, %cx\n\t" 711fa74f8a6SMohammed Gamal "imul %cl\n\t"); 712fa74f8a6SMohammed Gamal 713fa74f8a6SMohammed Gamal MK_INSN(imul16_1, "mov $2, %ax\n\t" 714fa74f8a6SMohammed Gamal "mov $-4, %cx\n\t" 715fa74f8a6SMohammed Gamal "imul %cx\n\t"); 716fa74f8a6SMohammed Gamal 717fa74f8a6SMohammed Gamal MK_INSN(imul32_1, "mov $2, %eax\n\t" 718fa74f8a6SMohammed Gamal "mov $-4, %ecx\n\t" 719fa74f8a6SMohammed Gamal "imul %ecx\n\t"); 720fa74f8a6SMohammed Gamal 721fa74f8a6SMohammed Gamal MK_INSN(imul8_2, "mov $0x12340002, %eax\n\t" 722fa74f8a6SMohammed Gamal "mov $4, %cx\n\t" 723fa74f8a6SMohammed Gamal "imul %cl\n\t"); 724fa74f8a6SMohammed Gamal 725fa74f8a6SMohammed Gamal MK_INSN(imul16_2, "mov $2, %ax\n\t" 726fa74f8a6SMohammed Gamal "mov $4, %cx\n\t" 727fa74f8a6SMohammed Gamal "imul %cx\n\t"); 728fa74f8a6SMohammed Gamal 729fa74f8a6SMohammed Gamal MK_INSN(imul32_2, "mov $2, %eax\n\t" 730fa74f8a6SMohammed Gamal "mov $4, %ecx\n\t" 731fa74f8a6SMohammed Gamal "imul %ecx\n\t"); 732fa74f8a6SMohammed Gamal 73318253fdeSAvi Kivity inregs = (struct regs){ 0 }; 73418253fdeSAvi Kivity 73518253fdeSAvi Kivity exec_in_big_real_mode(&insn_imul8_1); 7366055ea1fSAvi Kivity report("imul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == (u8)-8); 737fa74f8a6SMohammed Gamal 73818253fdeSAvi Kivity exec_in_big_real_mode(&insn_imul16_1); 7396055ea1fSAvi Kivity report("imul 2", R_AX | R_CX | R_DX, outregs.eax == (u16)-8); 740fa74f8a6SMohammed Gamal 74118253fdeSAvi Kivity exec_in_big_real_mode(&insn_imul32_1); 7426055ea1fSAvi Kivity report("imul 3", R_AX | R_CX | R_DX, outregs.eax == (u32)-8); 743fa74f8a6SMohammed Gamal 74418253fdeSAvi Kivity exec_in_big_real_mode(&insn_imul8_2); 7456055ea1fSAvi Kivity report("imul 4", R_AX | R_CX | R_DX, 7466055ea1fSAvi Kivity (outregs.eax & 0xffff) == 8 74781050840SAvi Kivity && (outregs.eax & 0xffff0000) == 0x12340000); 748fa74f8a6SMohammed Gamal 74918253fdeSAvi Kivity exec_in_big_real_mode(&insn_imul16_2); 7506055ea1fSAvi Kivity report("imul 5", R_AX | R_CX | R_DX, outregs.eax == 8); 751fa74f8a6SMohammed Gamal 75218253fdeSAvi Kivity exec_in_big_real_mode(&insn_imul32_2); 7536055ea1fSAvi Kivity report("imul 6", R_AX | R_CX | R_DX, outregs.eax == 8); 754fa74f8a6SMohammed Gamal } 755fa74f8a6SMohammed Gamal 75659317bd1SMohammed Gamal void test_mul() 75759317bd1SMohammed Gamal { 75859317bd1SMohammed Gamal MK_INSN(mul8, "mov $2, %al\n\t" 75959317bd1SMohammed Gamal "mov $4, %cx\n\t" 76059317bd1SMohammed Gamal "imul %cl\n\t"); 76159317bd1SMohammed Gamal 76259317bd1SMohammed Gamal MK_INSN(mul16, "mov $2, %ax\n\t" 76359317bd1SMohammed Gamal "mov $4, %cx\n\t" 76459317bd1SMohammed Gamal "imul %cx\n\t"); 76559317bd1SMohammed Gamal 76659317bd1SMohammed Gamal MK_INSN(mul32, "mov $2, %eax\n\t" 76759317bd1SMohammed Gamal "mov $4, %ecx\n\t" 76859317bd1SMohammed Gamal "imul %ecx\n\t"); 76959317bd1SMohammed Gamal 77018253fdeSAvi Kivity inregs = (struct regs){ 0 }; 77118253fdeSAvi Kivity 77218253fdeSAvi Kivity exec_in_big_real_mode(&insn_mul8); 7736055ea1fSAvi Kivity report("mul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == 8); 77459317bd1SMohammed Gamal 77518253fdeSAvi Kivity exec_in_big_real_mode(&insn_mul16); 7766055ea1fSAvi Kivity report("mul 2", R_AX | R_CX | R_DX, outregs.eax == 8); 77759317bd1SMohammed Gamal 77818253fdeSAvi Kivity exec_in_big_real_mode(&insn_mul32); 7796055ea1fSAvi Kivity report("mul 3", R_AX | R_CX | R_DX, outregs.eax == 8); 78059317bd1SMohammed Gamal } 78159317bd1SMohammed Gamal 7820d4c7614SMohammed Gamal void test_div() 7830d4c7614SMohammed Gamal { 7840d4c7614SMohammed Gamal MK_INSN(div8, "mov $257, %ax\n\t" 7850d4c7614SMohammed Gamal "mov $2, %cl\n\t" 7860d4c7614SMohammed Gamal "div %cl\n\t"); 7870d4c7614SMohammed Gamal 7880d4c7614SMohammed Gamal MK_INSN(div16, "mov $512, %ax\n\t" 7890d4c7614SMohammed Gamal "mov $5, %cx\n\t" 7900d4c7614SMohammed Gamal "div %cx\n\t"); 7910d4c7614SMohammed Gamal 7920d4c7614SMohammed Gamal MK_INSN(div32, "mov $512, %eax\n\t" 7930d4c7614SMohammed Gamal "mov $5, %ecx\n\t" 7940d4c7614SMohammed Gamal "div %ecx\n\t"); 7950d4c7614SMohammed Gamal 79618253fdeSAvi Kivity inregs = (struct regs){ 0 }; 79718253fdeSAvi Kivity 79818253fdeSAvi Kivity exec_in_big_real_mode(&insn_div8); 7996055ea1fSAvi Kivity report("div 1", R_AX | R_CX | R_DX, outregs.eax == 384); 8000d4c7614SMohammed Gamal 80118253fdeSAvi Kivity exec_in_big_real_mode(&insn_div16); 8026055ea1fSAvi Kivity report("div 2", R_AX | R_CX | R_DX, 8036055ea1fSAvi Kivity outregs.eax == 102 && outregs.edx == 2); 8040d4c7614SMohammed Gamal 80518253fdeSAvi Kivity exec_in_big_real_mode(&insn_div32); 8066055ea1fSAvi Kivity report("div 3", R_AX | R_CX | R_DX, 8076055ea1fSAvi Kivity outregs.eax == 102 && outregs.edx == 2); 8080d4c7614SMohammed Gamal } 8090d4c7614SMohammed Gamal 8100d4c7614SMohammed Gamal void test_idiv() 8110d4c7614SMohammed Gamal { 8120d4c7614SMohammed Gamal MK_INSN(idiv8, "mov $256, %ax\n\t" 8130d4c7614SMohammed Gamal "mov $-2, %cl\n\t" 8140d4c7614SMohammed Gamal "idiv %cl\n\t"); 8150d4c7614SMohammed Gamal 8160d4c7614SMohammed Gamal MK_INSN(idiv16, "mov $512, %ax\n\t" 8170d4c7614SMohammed Gamal "mov $-2, %cx\n\t" 8180d4c7614SMohammed Gamal "idiv %cx\n\t"); 8190d4c7614SMohammed Gamal 8200d4c7614SMohammed Gamal MK_INSN(idiv32, "mov $512, %eax\n\t" 8210d4c7614SMohammed Gamal "mov $-2, %ecx\n\t" 8220d4c7614SMohammed Gamal "idiv %ecx\n\t"); 8230d4c7614SMohammed Gamal 82418253fdeSAvi Kivity inregs = (struct regs){ 0 }; 82518253fdeSAvi Kivity 82618253fdeSAvi Kivity exec_in_big_real_mode(&insn_idiv8); 8276055ea1fSAvi Kivity report("idiv 1", R_AX | R_CX | R_DX, outregs.eax == (u8)-128); 8280d4c7614SMohammed Gamal 82918253fdeSAvi Kivity exec_in_big_real_mode(&insn_idiv16); 8306055ea1fSAvi Kivity report("idiv 2", R_AX | R_CX | R_DX, outregs.eax == (u16)-256); 8310d4c7614SMohammed Gamal 83218253fdeSAvi Kivity exec_in_big_real_mode(&insn_idiv32); 8336055ea1fSAvi Kivity report("idiv 3", R_AX | R_CX | R_DX, outregs.eax == (u32)-256); 8340d4c7614SMohammed Gamal } 8350d4c7614SMohammed Gamal 8366e293cf5SWei Yongjun void test_cbw(void) 8376e293cf5SWei Yongjun { 8386e293cf5SWei Yongjun MK_INSN(cbw, "mov $0xFE, %eax \n\t" 8396e293cf5SWei Yongjun "cbw\n\t"); 8406e293cf5SWei Yongjun MK_INSN(cwde, "mov $0xFFFE, %eax \n\t" 8416e293cf5SWei Yongjun "cwde\n\t"); 8426e293cf5SWei Yongjun 84318253fdeSAvi Kivity inregs = (struct regs){ 0 }; 84418253fdeSAvi Kivity 84518253fdeSAvi Kivity exec_in_big_real_mode(&insn_cbw); 8466055ea1fSAvi Kivity report("cbq 1", ~0, outregs.eax == 0xFFFE); 8476e293cf5SWei Yongjun 84818253fdeSAvi Kivity exec_in_big_real_mode(&insn_cwde); 8496055ea1fSAvi Kivity report("cwde 1", ~0, outregs.eax == 0xFFFFFFFE); 8506e293cf5SWei Yongjun } 8516e293cf5SWei Yongjun 852eacef4e2SWei Yongjun void test_loopcc(void) 853eacef4e2SWei Yongjun { 854eacef4e2SWei Yongjun MK_INSN(loop, "mov $10, %ecx\n\t" 855eacef4e2SWei Yongjun "1: inc %eax\n\t" 856eacef4e2SWei Yongjun "loop 1b\n\t"); 857eacef4e2SWei Yongjun 858eacef4e2SWei Yongjun MK_INSN(loope, "mov $10, %ecx\n\t" 859eacef4e2SWei Yongjun "mov $1, %eax\n\t" 860eacef4e2SWei Yongjun "1: dec %eax\n\t" 861eacef4e2SWei Yongjun "loope 1b\n\t"); 862eacef4e2SWei Yongjun 863eacef4e2SWei Yongjun MK_INSN(loopne, "mov $10, %ecx\n\t" 864eacef4e2SWei Yongjun "mov $5, %eax\n\t" 865eacef4e2SWei Yongjun "1: dec %eax\n\t" 866eacef4e2SWei Yongjun "loopne 1b\n\t"); 867eacef4e2SWei Yongjun 86818253fdeSAvi Kivity inregs = (struct regs){ 0 }; 869eacef4e2SWei Yongjun 87018253fdeSAvi Kivity exec_in_big_real_mode(&insn_loop); 8716055ea1fSAvi Kivity report("LOOPcc short 1", R_AX, outregs.eax == 10); 87218253fdeSAvi Kivity 87318253fdeSAvi Kivity exec_in_big_real_mode(&insn_loope); 8746055ea1fSAvi Kivity report("LOOPcc short 2", R_AX | R_CX, 8756055ea1fSAvi Kivity outregs.eax == -1 && outregs.ecx == 8); 876eacef4e2SWei Yongjun 87718253fdeSAvi Kivity exec_in_big_real_mode(&insn_loopne); 8786055ea1fSAvi Kivity report("LOOPcc short 3", R_AX | R_CX, 8796055ea1fSAvi Kivity outregs.eax == 0 && outregs.ecx == 5); 880eacef4e2SWei Yongjun } 881eacef4e2SWei Yongjun 882b274feedSAvi Kivity static void test_das(void) 883b274feedSAvi Kivity { 884b274feedSAvi Kivity short i; 88581050840SAvi Kivity u16 nr_fail = 0; 886b274feedSAvi Kivity static unsigned test_cases[1024] = { 887b274feedSAvi Kivity 0x46000000, 0x8701a000, 0x9710fa00, 0x97119a00, 888b274feedSAvi Kivity 0x02000101, 0x8301a101, 0x9310fb01, 0x93119b01, 889b274feedSAvi Kivity 0x02000202, 0x8301a202, 0x9710fc02, 0x97119c02, 890b274feedSAvi Kivity 0x06000303, 0x8701a303, 0x9310fd03, 0x93119d03, 891b274feedSAvi Kivity 0x02000404, 0x8301a404, 0x9310fe04, 0x93119e04, 892b274feedSAvi Kivity 0x06000505, 0x8701a505, 0x9710ff05, 0x97119f05, 893b274feedSAvi Kivity 0x06000606, 0x8701a606, 0x56100006, 0x9711a006, 894b274feedSAvi Kivity 0x02000707, 0x8301a707, 0x12100107, 0x9311a107, 895b274feedSAvi Kivity 0x02000808, 0x8301a808, 0x12100208, 0x9311a208, 896b274feedSAvi Kivity 0x06000909, 0x8701a909, 0x16100309, 0x9711a309, 897b274feedSAvi Kivity 0x1200040a, 0x9301a40a, 0x1210040a, 0x9311a40a, 898b274feedSAvi Kivity 0x1600050b, 0x9701a50b, 0x1610050b, 0x9711a50b, 899b274feedSAvi Kivity 0x1600060c, 0x9701a60c, 0x1610060c, 0x9711a60c, 900b274feedSAvi Kivity 0x1200070d, 0x9301a70d, 0x1210070d, 0x9311a70d, 901b274feedSAvi Kivity 0x1200080e, 0x9301a80e, 0x1210080e, 0x9311a80e, 902b274feedSAvi Kivity 0x1600090f, 0x9701a90f, 0x1610090f, 0x9711a90f, 903b274feedSAvi Kivity 0x02001010, 0x8301b010, 0x16100a10, 0x9711aa10, 904b274feedSAvi Kivity 0x06001111, 0x8701b111, 0x12100b11, 0x9311ab11, 905b274feedSAvi Kivity 0x06001212, 0x8701b212, 0x16100c12, 0x9711ac12, 906b274feedSAvi Kivity 0x02001313, 0x8301b313, 0x12100d13, 0x9311ad13, 907b274feedSAvi Kivity 0x06001414, 0x8701b414, 0x12100e14, 0x9311ae14, 908b274feedSAvi Kivity 0x02001515, 0x8301b515, 0x16100f15, 0x9711af15, 909b274feedSAvi Kivity 0x02001616, 0x8301b616, 0x12101016, 0x9311b016, 910b274feedSAvi Kivity 0x06001717, 0x8701b717, 0x16101117, 0x9711b117, 911b274feedSAvi Kivity 0x06001818, 0x8701b818, 0x16101218, 0x9711b218, 912b274feedSAvi Kivity 0x02001919, 0x8301b919, 0x12101319, 0x9311b319, 913b274feedSAvi Kivity 0x1600141a, 0x9701b41a, 0x1610141a, 0x9711b41a, 914b274feedSAvi Kivity 0x1200151b, 0x9301b51b, 0x1210151b, 0x9311b51b, 915b274feedSAvi Kivity 0x1200161c, 0x9301b61c, 0x1210161c, 0x9311b61c, 916b274feedSAvi Kivity 0x1600171d, 0x9701b71d, 0x1610171d, 0x9711b71d, 917b274feedSAvi Kivity 0x1600181e, 0x9701b81e, 0x1610181e, 0x9711b81e, 918b274feedSAvi Kivity 0x1200191f, 0x9301b91f, 0x1210191f, 0x9311b91f, 919b274feedSAvi Kivity 0x02002020, 0x8701c020, 0x12101a20, 0x9311ba20, 920b274feedSAvi Kivity 0x06002121, 0x8301c121, 0x16101b21, 0x9711bb21, 921b274feedSAvi Kivity 0x06002222, 0x8301c222, 0x12101c22, 0x9311bc22, 922b274feedSAvi Kivity 0x02002323, 0x8701c323, 0x16101d23, 0x9711bd23, 923b274feedSAvi Kivity 0x06002424, 0x8301c424, 0x16101e24, 0x9711be24, 924b274feedSAvi Kivity 0x02002525, 0x8701c525, 0x12101f25, 0x9311bf25, 925b274feedSAvi Kivity 0x02002626, 0x8701c626, 0x12102026, 0x9711c026, 926b274feedSAvi Kivity 0x06002727, 0x8301c727, 0x16102127, 0x9311c127, 927b274feedSAvi Kivity 0x06002828, 0x8301c828, 0x16102228, 0x9311c228, 928b274feedSAvi Kivity 0x02002929, 0x8701c929, 0x12102329, 0x9711c329, 929b274feedSAvi Kivity 0x1600242a, 0x9301c42a, 0x1610242a, 0x9311c42a, 930b274feedSAvi Kivity 0x1200252b, 0x9701c52b, 0x1210252b, 0x9711c52b, 931b274feedSAvi Kivity 0x1200262c, 0x9701c62c, 0x1210262c, 0x9711c62c, 932b274feedSAvi Kivity 0x1600272d, 0x9301c72d, 0x1610272d, 0x9311c72d, 933b274feedSAvi Kivity 0x1600282e, 0x9301c82e, 0x1610282e, 0x9311c82e, 934b274feedSAvi Kivity 0x1200292f, 0x9701c92f, 0x1210292f, 0x9711c92f, 935b274feedSAvi Kivity 0x06003030, 0x8301d030, 0x12102a30, 0x9711ca30, 936b274feedSAvi Kivity 0x02003131, 0x8701d131, 0x16102b31, 0x9311cb31, 937b274feedSAvi Kivity 0x02003232, 0x8701d232, 0x12102c32, 0x9711cc32, 938b274feedSAvi Kivity 0x06003333, 0x8301d333, 0x16102d33, 0x9311cd33, 939b274feedSAvi Kivity 0x02003434, 0x8701d434, 0x16102e34, 0x9311ce34, 940b274feedSAvi Kivity 0x06003535, 0x8301d535, 0x12102f35, 0x9711cf35, 941b274feedSAvi Kivity 0x06003636, 0x8301d636, 0x16103036, 0x9311d036, 942b274feedSAvi Kivity 0x02003737, 0x8701d737, 0x12103137, 0x9711d137, 943b274feedSAvi Kivity 0x02003838, 0x8701d838, 0x12103238, 0x9711d238, 944b274feedSAvi Kivity 0x06003939, 0x8301d939, 0x16103339, 0x9311d339, 945b274feedSAvi Kivity 0x1200343a, 0x9701d43a, 0x1210343a, 0x9711d43a, 946b274feedSAvi Kivity 0x1600353b, 0x9301d53b, 0x1610353b, 0x9311d53b, 947b274feedSAvi Kivity 0x1600363c, 0x9301d63c, 0x1610363c, 0x9311d63c, 948b274feedSAvi Kivity 0x1200373d, 0x9701d73d, 0x1210373d, 0x9711d73d, 949b274feedSAvi Kivity 0x1200383e, 0x9701d83e, 0x1210383e, 0x9711d83e, 950b274feedSAvi Kivity 0x1600393f, 0x9301d93f, 0x1610393f, 0x9311d93f, 951b274feedSAvi Kivity 0x02004040, 0x8301e040, 0x16103a40, 0x9311da40, 952b274feedSAvi Kivity 0x06004141, 0x8701e141, 0x12103b41, 0x9711db41, 953b274feedSAvi Kivity 0x06004242, 0x8701e242, 0x16103c42, 0x9311dc42, 954b274feedSAvi Kivity 0x02004343, 0x8301e343, 0x12103d43, 0x9711dd43, 955b274feedSAvi Kivity 0x06004444, 0x8701e444, 0x12103e44, 0x9711de44, 956b274feedSAvi Kivity 0x02004545, 0x8301e545, 0x16103f45, 0x9311df45, 957b274feedSAvi Kivity 0x02004646, 0x8301e646, 0x12104046, 0x9311e046, 958b274feedSAvi Kivity 0x06004747, 0x8701e747, 0x16104147, 0x9711e147, 959b274feedSAvi Kivity 0x06004848, 0x8701e848, 0x16104248, 0x9711e248, 960b274feedSAvi Kivity 0x02004949, 0x8301e949, 0x12104349, 0x9311e349, 961b274feedSAvi Kivity 0x1600444a, 0x9701e44a, 0x1610444a, 0x9711e44a, 962b274feedSAvi Kivity 0x1200454b, 0x9301e54b, 0x1210454b, 0x9311e54b, 963b274feedSAvi Kivity 0x1200464c, 0x9301e64c, 0x1210464c, 0x9311e64c, 964b274feedSAvi Kivity 0x1600474d, 0x9701e74d, 0x1610474d, 0x9711e74d, 965b274feedSAvi Kivity 0x1600484e, 0x9701e84e, 0x1610484e, 0x9711e84e, 966b274feedSAvi Kivity 0x1200494f, 0x9301e94f, 0x1210494f, 0x9311e94f, 967b274feedSAvi Kivity 0x06005050, 0x8701f050, 0x12104a50, 0x9311ea50, 968b274feedSAvi Kivity 0x02005151, 0x8301f151, 0x16104b51, 0x9711eb51, 969b274feedSAvi Kivity 0x02005252, 0x8301f252, 0x12104c52, 0x9311ec52, 970b274feedSAvi Kivity 0x06005353, 0x8701f353, 0x16104d53, 0x9711ed53, 971b274feedSAvi Kivity 0x02005454, 0x8301f454, 0x16104e54, 0x9711ee54, 972b274feedSAvi Kivity 0x06005555, 0x8701f555, 0x12104f55, 0x9311ef55, 973b274feedSAvi Kivity 0x06005656, 0x8701f656, 0x16105056, 0x9711f056, 974b274feedSAvi Kivity 0x02005757, 0x8301f757, 0x12105157, 0x9311f157, 975b274feedSAvi Kivity 0x02005858, 0x8301f858, 0x12105258, 0x9311f258, 976b274feedSAvi Kivity 0x06005959, 0x8701f959, 0x16105359, 0x9711f359, 977b274feedSAvi Kivity 0x1200545a, 0x9301f45a, 0x1210545a, 0x9311f45a, 978b274feedSAvi Kivity 0x1600555b, 0x9701f55b, 0x1610555b, 0x9711f55b, 979b274feedSAvi Kivity 0x1600565c, 0x9701f65c, 0x1610565c, 0x9711f65c, 980b274feedSAvi Kivity 0x1200575d, 0x9301f75d, 0x1210575d, 0x9311f75d, 981b274feedSAvi Kivity 0x1200585e, 0x9301f85e, 0x1210585e, 0x9311f85e, 982b274feedSAvi Kivity 0x1600595f, 0x9701f95f, 0x1610595f, 0x9711f95f, 983b274feedSAvi Kivity 0x06006060, 0x47010060, 0x16105a60, 0x9711fa60, 984b274feedSAvi Kivity 0x02006161, 0x03010161, 0x12105b61, 0x9311fb61, 985b274feedSAvi Kivity 0x02006262, 0x03010262, 0x16105c62, 0x9711fc62, 986b274feedSAvi Kivity 0x06006363, 0x07010363, 0x12105d63, 0x9311fd63, 987b274feedSAvi Kivity 0x02006464, 0x03010464, 0x12105e64, 0x9311fe64, 988b274feedSAvi Kivity 0x06006565, 0x07010565, 0x16105f65, 0x9711ff65, 989b274feedSAvi Kivity 0x06006666, 0x07010666, 0x16106066, 0x57110066, 990b274feedSAvi Kivity 0x02006767, 0x03010767, 0x12106167, 0x13110167, 991b274feedSAvi Kivity 0x02006868, 0x03010868, 0x12106268, 0x13110268, 992b274feedSAvi Kivity 0x06006969, 0x07010969, 0x16106369, 0x17110369, 993b274feedSAvi Kivity 0x1200646a, 0x1301046a, 0x1210646a, 0x1311046a, 994b274feedSAvi Kivity 0x1600656b, 0x1701056b, 0x1610656b, 0x1711056b, 995b274feedSAvi Kivity 0x1600666c, 0x1701066c, 0x1610666c, 0x1711066c, 996b274feedSAvi Kivity 0x1200676d, 0x1301076d, 0x1210676d, 0x1311076d, 997b274feedSAvi Kivity 0x1200686e, 0x1301086e, 0x1210686e, 0x1311086e, 998b274feedSAvi Kivity 0x1600696f, 0x1701096f, 0x1610696f, 0x1711096f, 999b274feedSAvi Kivity 0x02007070, 0x03011070, 0x16106a70, 0x17110a70, 1000b274feedSAvi Kivity 0x06007171, 0x07011171, 0x12106b71, 0x13110b71, 1001b274feedSAvi Kivity 0x06007272, 0x07011272, 0x16106c72, 0x17110c72, 1002b274feedSAvi Kivity 0x02007373, 0x03011373, 0x12106d73, 0x13110d73, 1003b274feedSAvi Kivity 0x06007474, 0x07011474, 0x12106e74, 0x13110e74, 1004b274feedSAvi Kivity 0x02007575, 0x03011575, 0x16106f75, 0x17110f75, 1005b274feedSAvi Kivity 0x02007676, 0x03011676, 0x12107076, 0x13111076, 1006b274feedSAvi Kivity 0x06007777, 0x07011777, 0x16107177, 0x17111177, 1007b274feedSAvi Kivity 0x06007878, 0x07011878, 0x16107278, 0x17111278, 1008b274feedSAvi Kivity 0x02007979, 0x03011979, 0x12107379, 0x13111379, 1009b274feedSAvi Kivity 0x1600747a, 0x1701147a, 0x1610747a, 0x1711147a, 1010b274feedSAvi Kivity 0x1200757b, 0x1301157b, 0x1210757b, 0x1311157b, 1011b274feedSAvi Kivity 0x1200767c, 0x1301167c, 0x1210767c, 0x1311167c, 1012b274feedSAvi Kivity 0x1600777d, 0x1701177d, 0x1610777d, 0x1711177d, 1013b274feedSAvi Kivity 0x1600787e, 0x1701187e, 0x1610787e, 0x1711187e, 1014b274feedSAvi Kivity 0x1200797f, 0x1301197f, 0x1210797f, 0x1311197f, 1015b274feedSAvi Kivity 0x82008080, 0x03012080, 0x12107a80, 0x13111a80, 1016b274feedSAvi Kivity 0x86008181, 0x07012181, 0x16107b81, 0x17111b81, 1017b274feedSAvi Kivity 0x86008282, 0x07012282, 0x12107c82, 0x13111c82, 1018b274feedSAvi Kivity 0x82008383, 0x03012383, 0x16107d83, 0x17111d83, 1019b274feedSAvi Kivity 0x86008484, 0x07012484, 0x16107e84, 0x17111e84, 1020b274feedSAvi Kivity 0x82008585, 0x03012585, 0x12107f85, 0x13111f85, 1021b274feedSAvi Kivity 0x82008686, 0x03012686, 0x92108086, 0x13112086, 1022b274feedSAvi Kivity 0x86008787, 0x07012787, 0x96108187, 0x17112187, 1023b274feedSAvi Kivity 0x86008888, 0x07012888, 0x96108288, 0x17112288, 1024b274feedSAvi Kivity 0x82008989, 0x03012989, 0x92108389, 0x13112389, 1025b274feedSAvi Kivity 0x9600848a, 0x1701248a, 0x9610848a, 0x1711248a, 1026b274feedSAvi Kivity 0x9200858b, 0x1301258b, 0x9210858b, 0x1311258b, 1027b274feedSAvi Kivity 0x9200868c, 0x1301268c, 0x9210868c, 0x1311268c, 1028b274feedSAvi Kivity 0x9600878d, 0x1701278d, 0x9610878d, 0x1711278d, 1029b274feedSAvi Kivity 0x9600888e, 0x1701288e, 0x9610888e, 0x1711288e, 1030b274feedSAvi Kivity 0x9200898f, 0x1301298f, 0x9210898f, 0x1311298f, 1031b274feedSAvi Kivity 0x86009090, 0x07013090, 0x92108a90, 0x13112a90, 1032b274feedSAvi Kivity 0x82009191, 0x03013191, 0x96108b91, 0x17112b91, 1033b274feedSAvi Kivity 0x82009292, 0x03013292, 0x92108c92, 0x13112c92, 1034b274feedSAvi Kivity 0x86009393, 0x07013393, 0x96108d93, 0x17112d93, 1035b274feedSAvi Kivity 0x82009494, 0x03013494, 0x96108e94, 0x17112e94, 1036b274feedSAvi Kivity 0x86009595, 0x07013595, 0x92108f95, 0x13112f95, 1037b274feedSAvi Kivity 0x86009696, 0x07013696, 0x96109096, 0x17113096, 1038b274feedSAvi Kivity 0x82009797, 0x03013797, 0x92109197, 0x13113197, 1039b274feedSAvi Kivity 0x82009898, 0x03013898, 0x92109298, 0x13113298, 1040b274feedSAvi Kivity 0x86009999, 0x07013999, 0x96109399, 0x17113399, 1041b274feedSAvi Kivity 0x1300349a, 0x1301349a, 0x1310349a, 0x1311349a, 1042b274feedSAvi Kivity 0x1700359b, 0x1701359b, 0x1710359b, 0x1711359b, 1043b274feedSAvi Kivity 0x1700369c, 0x1701369c, 0x1710369c, 0x1711369c, 1044b274feedSAvi Kivity 0x1300379d, 0x1301379d, 0x1310379d, 0x1311379d, 1045b274feedSAvi Kivity 0x1300389e, 0x1301389e, 0x1310389e, 0x1311389e, 1046b274feedSAvi Kivity 0x1700399f, 0x1701399f, 0x1710399f, 0x1711399f, 1047b274feedSAvi Kivity 0x030040a0, 0x030140a0, 0x17103aa0, 0x17113aa0, 1048b274feedSAvi Kivity 0x070041a1, 0x070141a1, 0x13103ba1, 0x13113ba1, 1049b274feedSAvi Kivity 0x070042a2, 0x070142a2, 0x17103ca2, 0x17113ca2, 1050b274feedSAvi Kivity 0x030043a3, 0x030143a3, 0x13103da3, 0x13113da3, 1051b274feedSAvi Kivity 0x070044a4, 0x070144a4, 0x13103ea4, 0x13113ea4, 1052b274feedSAvi Kivity 0x030045a5, 0x030145a5, 0x17103fa5, 0x17113fa5, 1053b274feedSAvi Kivity 0x030046a6, 0x030146a6, 0x131040a6, 0x131140a6, 1054b274feedSAvi Kivity 0x070047a7, 0x070147a7, 0x171041a7, 0x171141a7, 1055b274feedSAvi Kivity 0x070048a8, 0x070148a8, 0x171042a8, 0x171142a8, 1056b274feedSAvi Kivity 0x030049a9, 0x030149a9, 0x131043a9, 0x131143a9, 1057b274feedSAvi Kivity 0x170044aa, 0x170144aa, 0x171044aa, 0x171144aa, 1058b274feedSAvi Kivity 0x130045ab, 0x130145ab, 0x131045ab, 0x131145ab, 1059b274feedSAvi Kivity 0x130046ac, 0x130146ac, 0x131046ac, 0x131146ac, 1060b274feedSAvi Kivity 0x170047ad, 0x170147ad, 0x171047ad, 0x171147ad, 1061b274feedSAvi Kivity 0x170048ae, 0x170148ae, 0x171048ae, 0x171148ae, 1062b274feedSAvi Kivity 0x130049af, 0x130149af, 0x131049af, 0x131149af, 1063b274feedSAvi Kivity 0x070050b0, 0x070150b0, 0x13104ab0, 0x13114ab0, 1064b274feedSAvi Kivity 0x030051b1, 0x030151b1, 0x17104bb1, 0x17114bb1, 1065b274feedSAvi Kivity 0x030052b2, 0x030152b2, 0x13104cb2, 0x13114cb2, 1066b274feedSAvi Kivity 0x070053b3, 0x070153b3, 0x17104db3, 0x17114db3, 1067b274feedSAvi Kivity 0x030054b4, 0x030154b4, 0x17104eb4, 0x17114eb4, 1068b274feedSAvi Kivity 0x070055b5, 0x070155b5, 0x13104fb5, 0x13114fb5, 1069b274feedSAvi Kivity 0x070056b6, 0x070156b6, 0x171050b6, 0x171150b6, 1070b274feedSAvi Kivity 0x030057b7, 0x030157b7, 0x131051b7, 0x131151b7, 1071b274feedSAvi Kivity 0x030058b8, 0x030158b8, 0x131052b8, 0x131152b8, 1072b274feedSAvi Kivity 0x070059b9, 0x070159b9, 0x171053b9, 0x171153b9, 1073b274feedSAvi Kivity 0x130054ba, 0x130154ba, 0x131054ba, 0x131154ba, 1074b274feedSAvi Kivity 0x170055bb, 0x170155bb, 0x171055bb, 0x171155bb, 1075b274feedSAvi Kivity 0x170056bc, 0x170156bc, 0x171056bc, 0x171156bc, 1076b274feedSAvi Kivity 0x130057bd, 0x130157bd, 0x131057bd, 0x131157bd, 1077b274feedSAvi Kivity 0x130058be, 0x130158be, 0x131058be, 0x131158be, 1078b274feedSAvi Kivity 0x170059bf, 0x170159bf, 0x171059bf, 0x171159bf, 1079b274feedSAvi Kivity 0x070060c0, 0x070160c0, 0x17105ac0, 0x17115ac0, 1080b274feedSAvi Kivity 0x030061c1, 0x030161c1, 0x13105bc1, 0x13115bc1, 1081b274feedSAvi Kivity 0x030062c2, 0x030162c2, 0x17105cc2, 0x17115cc2, 1082b274feedSAvi Kivity 0x070063c3, 0x070163c3, 0x13105dc3, 0x13115dc3, 1083b274feedSAvi Kivity 0x030064c4, 0x030164c4, 0x13105ec4, 0x13115ec4, 1084b274feedSAvi Kivity 0x070065c5, 0x070165c5, 0x17105fc5, 0x17115fc5, 1085b274feedSAvi Kivity 0x070066c6, 0x070166c6, 0x171060c6, 0x171160c6, 1086b274feedSAvi Kivity 0x030067c7, 0x030167c7, 0x131061c7, 0x131161c7, 1087b274feedSAvi Kivity 0x030068c8, 0x030168c8, 0x131062c8, 0x131162c8, 1088b274feedSAvi Kivity 0x070069c9, 0x070169c9, 0x171063c9, 0x171163c9, 1089b274feedSAvi Kivity 0x130064ca, 0x130164ca, 0x131064ca, 0x131164ca, 1090b274feedSAvi Kivity 0x170065cb, 0x170165cb, 0x171065cb, 0x171165cb, 1091b274feedSAvi Kivity 0x170066cc, 0x170166cc, 0x171066cc, 0x171166cc, 1092b274feedSAvi Kivity 0x130067cd, 0x130167cd, 0x131067cd, 0x131167cd, 1093b274feedSAvi Kivity 0x130068ce, 0x130168ce, 0x131068ce, 0x131168ce, 1094b274feedSAvi Kivity 0x170069cf, 0x170169cf, 0x171069cf, 0x171169cf, 1095b274feedSAvi Kivity 0x030070d0, 0x030170d0, 0x17106ad0, 0x17116ad0, 1096b274feedSAvi Kivity 0x070071d1, 0x070171d1, 0x13106bd1, 0x13116bd1, 1097b274feedSAvi Kivity 0x070072d2, 0x070172d2, 0x17106cd2, 0x17116cd2, 1098b274feedSAvi Kivity 0x030073d3, 0x030173d3, 0x13106dd3, 0x13116dd3, 1099b274feedSAvi Kivity 0x070074d4, 0x070174d4, 0x13106ed4, 0x13116ed4, 1100b274feedSAvi Kivity 0x030075d5, 0x030175d5, 0x17106fd5, 0x17116fd5, 1101b274feedSAvi Kivity 0x030076d6, 0x030176d6, 0x131070d6, 0x131170d6, 1102b274feedSAvi Kivity 0x070077d7, 0x070177d7, 0x171071d7, 0x171171d7, 1103b274feedSAvi Kivity 0x070078d8, 0x070178d8, 0x171072d8, 0x171172d8, 1104b274feedSAvi Kivity 0x030079d9, 0x030179d9, 0x131073d9, 0x131173d9, 1105b274feedSAvi Kivity 0x170074da, 0x170174da, 0x171074da, 0x171174da, 1106b274feedSAvi Kivity 0x130075db, 0x130175db, 0x131075db, 0x131175db, 1107b274feedSAvi Kivity 0x130076dc, 0x130176dc, 0x131076dc, 0x131176dc, 1108b274feedSAvi Kivity 0x170077dd, 0x170177dd, 0x171077dd, 0x171177dd, 1109b274feedSAvi Kivity 0x170078de, 0x170178de, 0x171078de, 0x171178de, 1110b274feedSAvi Kivity 0x130079df, 0x130179df, 0x131079df, 0x131179df, 1111b274feedSAvi Kivity 0x830080e0, 0x830180e0, 0x13107ae0, 0x13117ae0, 1112b274feedSAvi Kivity 0x870081e1, 0x870181e1, 0x17107be1, 0x17117be1, 1113b274feedSAvi Kivity 0x870082e2, 0x870182e2, 0x13107ce2, 0x13117ce2, 1114b274feedSAvi Kivity 0x830083e3, 0x830183e3, 0x17107de3, 0x17117de3, 1115b274feedSAvi Kivity 0x870084e4, 0x870184e4, 0x17107ee4, 0x17117ee4, 1116b274feedSAvi Kivity 0x830085e5, 0x830185e5, 0x13107fe5, 0x13117fe5, 1117b274feedSAvi Kivity 0x830086e6, 0x830186e6, 0x931080e6, 0x931180e6, 1118b274feedSAvi Kivity 0x870087e7, 0x870187e7, 0x971081e7, 0x971181e7, 1119b274feedSAvi Kivity 0x870088e8, 0x870188e8, 0x971082e8, 0x971182e8, 1120b274feedSAvi Kivity 0x830089e9, 0x830189e9, 0x931083e9, 0x931183e9, 1121b274feedSAvi Kivity 0x970084ea, 0x970184ea, 0x971084ea, 0x971184ea, 1122b274feedSAvi Kivity 0x930085eb, 0x930185eb, 0x931085eb, 0x931185eb, 1123b274feedSAvi Kivity 0x930086ec, 0x930186ec, 0x931086ec, 0x931186ec, 1124b274feedSAvi Kivity 0x970087ed, 0x970187ed, 0x971087ed, 0x971187ed, 1125b274feedSAvi Kivity 0x970088ee, 0x970188ee, 0x971088ee, 0x971188ee, 1126b274feedSAvi Kivity 0x930089ef, 0x930189ef, 0x931089ef, 0x931189ef, 1127b274feedSAvi Kivity 0x870090f0, 0x870190f0, 0x93108af0, 0x93118af0, 1128b274feedSAvi Kivity 0x830091f1, 0x830191f1, 0x97108bf1, 0x97118bf1, 1129b274feedSAvi Kivity 0x830092f2, 0x830192f2, 0x93108cf2, 0x93118cf2, 1130b274feedSAvi Kivity 0x870093f3, 0x870193f3, 0x97108df3, 0x97118df3, 1131b274feedSAvi Kivity 0x830094f4, 0x830194f4, 0x97108ef4, 0x97118ef4, 1132b274feedSAvi Kivity 0x870095f5, 0x870195f5, 0x93108ff5, 0x93118ff5, 1133b274feedSAvi Kivity 0x870096f6, 0x870196f6, 0x971090f6, 0x971190f6, 1134b274feedSAvi Kivity 0x830097f7, 0x830197f7, 0x931091f7, 0x931191f7, 1135b274feedSAvi Kivity 0x830098f8, 0x830198f8, 0x931092f8, 0x931192f8, 1136b274feedSAvi Kivity 0x870099f9, 0x870199f9, 0x971093f9, 0x971193f9, 1137b274feedSAvi Kivity 0x930094fa, 0x930194fa, 0x931094fa, 0x931194fa, 1138b274feedSAvi Kivity 0x970095fb, 0x970195fb, 0x971095fb, 0x971195fb, 1139b274feedSAvi Kivity 0x970096fc, 0x970196fc, 0x971096fc, 0x971196fc, 1140b274feedSAvi Kivity 0x930097fd, 0x930197fd, 0x931097fd, 0x931197fd, 1141b274feedSAvi Kivity 0x930098fe, 0x930198fe, 0x931098fe, 0x931198fe, 1142b274feedSAvi Kivity 0x970099ff, 0x970199ff, 0x971099ff, 0x971199ff, 1143b274feedSAvi Kivity }; 1144b274feedSAvi Kivity 1145b274feedSAvi Kivity MK_INSN(das, "das"); 1146b274feedSAvi Kivity 114718253fdeSAvi Kivity inregs = (struct regs){ 0 }; 114818253fdeSAvi Kivity 1149b274feedSAvi Kivity for (i = 0; i < 1024; ++i) { 1150b274feedSAvi Kivity unsigned tmp = test_cases[i]; 1151b274feedSAvi Kivity inregs.eax = tmp & 0xff; 1152b274feedSAvi Kivity inregs.eflags = (tmp >> 16) & 0xff; 115318253fdeSAvi Kivity exec_in_big_real_mode(&insn_das); 115418253fdeSAvi Kivity if (!regs_equal(R_AX) 1155b274feedSAvi Kivity || outregs.eax != ((tmp >> 8) & 0xff) 1156b274feedSAvi Kivity || (outregs.eflags & 0xff) != (tmp >> 24)) { 115781050840SAvi Kivity ++nr_fail; 115881050840SAvi Kivity break; 1159b274feedSAvi Kivity } 1160b274feedSAvi Kivity } 11616055ea1fSAvi Kivity report("DAS", ~0, nr_fail == 0); 1162b274feedSAvi Kivity } 1163b274feedSAvi Kivity 11640cbd5b06SMohammed Gamal void test_cwd_cdq() 11650cbd5b06SMohammed Gamal { 11660cbd5b06SMohammed Gamal /* Sign-bit set */ 11670cbd5b06SMohammed Gamal MK_INSN(cwd_1, "mov $0x8000, %ax\n\t" 11680cbd5b06SMohammed Gamal "cwd\n\t"); 11690cbd5b06SMohammed Gamal 11700cbd5b06SMohammed Gamal /* Sign-bit not set */ 11710cbd5b06SMohammed Gamal MK_INSN(cwd_2, "mov $0x1000, %ax\n\t" 11720cbd5b06SMohammed Gamal "cwd\n\t"); 11730cbd5b06SMohammed Gamal 11740cbd5b06SMohammed Gamal /* Sign-bit set */ 11750cbd5b06SMohammed Gamal MK_INSN(cdq_1, "mov $0x80000000, %eax\n\t" 11760cbd5b06SMohammed Gamal "cdq\n\t"); 11770cbd5b06SMohammed Gamal 11780cbd5b06SMohammed Gamal /* Sign-bit not set */ 11790cbd5b06SMohammed Gamal MK_INSN(cdq_2, "mov $0x10000000, %eax\n\t" 11800cbd5b06SMohammed Gamal "cdq\n\t"); 11810cbd5b06SMohammed Gamal 118218253fdeSAvi Kivity inregs = (struct regs){ 0 }; 118318253fdeSAvi Kivity 118418253fdeSAvi Kivity exec_in_big_real_mode(&insn_cwd_1); 11856055ea1fSAvi Kivity report("cwd 1", R_AX | R_DX, 11866055ea1fSAvi Kivity outregs.eax == 0x8000 && outregs.edx == 0xffff); 11870cbd5b06SMohammed Gamal 118818253fdeSAvi Kivity exec_in_big_real_mode(&insn_cwd_2); 11896055ea1fSAvi Kivity report("cwd 2", R_AX | R_DX, 11906055ea1fSAvi Kivity outregs.eax == 0x1000 && outregs.edx == 0); 11910cbd5b06SMohammed Gamal 119218253fdeSAvi Kivity exec_in_big_real_mode(&insn_cdq_1); 11936055ea1fSAvi Kivity report("cdq 1", R_AX | R_DX, 11946055ea1fSAvi Kivity outregs.eax == 0x80000000 && outregs.edx == 0xffffffff); 11950cbd5b06SMohammed Gamal 119618253fdeSAvi Kivity exec_in_big_real_mode(&insn_cdq_2); 11976055ea1fSAvi Kivity report("cdq 2", R_AX | R_DX, 11986055ea1fSAvi Kivity outregs.eax == 0x10000000 && outregs.edx == 0); 11990cbd5b06SMohammed Gamal } 12000cbd5b06SMohammed Gamal 120137f51a4aSWei Yongjun static struct { 120237f51a4aSWei Yongjun void *address; 120337f51a4aSWei Yongjun unsigned short sel; 120437f51a4aSWei Yongjun } __attribute__((packed)) desc = { 120537f51a4aSWei Yongjun (void *)0x1234, 120637f51a4aSWei Yongjun 0x10, 120737f51a4aSWei Yongjun }; 120837f51a4aSWei Yongjun 120937f51a4aSWei Yongjun void test_lds_lss() 121037f51a4aSWei Yongjun { 121137f51a4aSWei Yongjun inregs = (struct regs){ .ebx = (unsigned long)&desc }; 121237f51a4aSWei Yongjun 121337f51a4aSWei Yongjun MK_INSN(lds, "push %ds\n\t" 121437f51a4aSWei Yongjun "lds (%ebx), %eax\n\t" 121537f51a4aSWei Yongjun "mov %ds, %ebx\n\t" 121637f51a4aSWei Yongjun "pop %ds\n\t"); 121737f51a4aSWei Yongjun exec_in_big_real_mode(&insn_lds); 121837f51a4aSWei Yongjun report("lds", R_AX | R_BX, 121937f51a4aSWei Yongjun outregs.eax == (unsigned long)desc.address && 122037f51a4aSWei Yongjun outregs.ebx == desc.sel); 122137f51a4aSWei Yongjun 122237f51a4aSWei Yongjun MK_INSN(les, "push %es\n\t" 122337f51a4aSWei Yongjun "les (%ebx), %eax\n\t" 122437f51a4aSWei Yongjun "mov %es, %ebx\n\t" 122537f51a4aSWei Yongjun "pop %es\n\t"); 122637f51a4aSWei Yongjun exec_in_big_real_mode(&insn_les); 122737f51a4aSWei Yongjun report("les", R_AX | R_BX, 122837f51a4aSWei Yongjun outregs.eax == (unsigned long)desc.address && 122937f51a4aSWei Yongjun outregs.ebx == desc.sel); 123037f51a4aSWei Yongjun 123137f51a4aSWei Yongjun MK_INSN(lfs, "push %fs\n\t" 123237f51a4aSWei Yongjun "lfs (%ebx), %eax\n\t" 123337f51a4aSWei Yongjun "mov %fs, %ebx\n\t" 123437f51a4aSWei Yongjun "pop %fs\n\t"); 123537f51a4aSWei Yongjun exec_in_big_real_mode(&insn_lfs); 123637f51a4aSWei Yongjun report("lfs", R_AX | R_BX, 123737f51a4aSWei Yongjun outregs.eax == (unsigned long)desc.address && 123837f51a4aSWei Yongjun outregs.ebx == desc.sel); 123937f51a4aSWei Yongjun 124037f51a4aSWei Yongjun MK_INSN(lgs, "push %gs\n\t" 124137f51a4aSWei Yongjun "lgs (%ebx), %eax\n\t" 124237f51a4aSWei Yongjun "mov %gs, %ebx\n\t" 124337f51a4aSWei Yongjun "pop %gs\n\t"); 124437f51a4aSWei Yongjun exec_in_big_real_mode(&insn_lgs); 124537f51a4aSWei Yongjun report("lgs", R_AX | R_BX, 124637f51a4aSWei Yongjun outregs.eax == (unsigned long)desc.address && 124737f51a4aSWei Yongjun outregs.ebx == desc.sel); 124837f51a4aSWei Yongjun 124937f51a4aSWei Yongjun MK_INSN(lss, "push %ss\n\t" 125037f51a4aSWei Yongjun "lss (%ebx), %eax\n\t" 125137f51a4aSWei Yongjun "mov %ss, %ebx\n\t" 125237f51a4aSWei Yongjun "pop %ss\n\t"); 125337f51a4aSWei Yongjun exec_in_big_real_mode(&insn_lss); 125437f51a4aSWei Yongjun report("lss", R_AX | R_BX, 125537f51a4aSWei Yongjun outregs.eax == (unsigned long)desc.address && 125637f51a4aSWei Yongjun outregs.ebx == desc.sel); 125737f51a4aSWei Yongjun } 125837f51a4aSWei Yongjun 1259b1c7c575SWei Yongjun void test_jcxz(void) 1260b1c7c575SWei Yongjun { 1261b1c7c575SWei Yongjun MK_INSN(jcxz1, "jcxz 1f\n\t" 1262b1c7c575SWei Yongjun "mov $0x1234, %eax\n\t" 1263b1c7c575SWei Yongjun "1:\n\t"); 1264b1c7c575SWei Yongjun MK_INSN(jcxz2, "mov $0x100, %ecx\n\t" 1265b1c7c575SWei Yongjun "jcxz 1f\n\t" 1266b1c7c575SWei Yongjun "mov $0x1234, %eax\n\t" 1267b1c7c575SWei Yongjun "mov $0, %ecx\n\t" 1268b1c7c575SWei Yongjun "1:\n\t"); 1269b1c7c575SWei Yongjun MK_INSN(jcxz3, "mov $0x10000, %ecx\n\t" 1270b1c7c575SWei Yongjun "jcxz 1f\n\t" 1271b1c7c575SWei Yongjun "mov $0x1234, %eax\n\t" 1272b1c7c575SWei Yongjun "1:\n\t"); 1273b1c7c575SWei Yongjun MK_INSN(jecxz1, "jecxz 1f\n\t" 1274b1c7c575SWei Yongjun "mov $0x1234, %eax\n\t" 1275b1c7c575SWei Yongjun "1:\n\t"); 1276b1c7c575SWei Yongjun MK_INSN(jecxz2, "mov $0x10000, %ecx\n\t" 1277b1c7c575SWei Yongjun "jecxz 1f\n\t" 1278b1c7c575SWei Yongjun "mov $0x1234, %eax\n\t" 1279b1c7c575SWei Yongjun "mov $0, %ecx\n\t" 1280b1c7c575SWei Yongjun "1:\n\t"); 1281b1c7c575SWei Yongjun 1282b1c7c575SWei Yongjun inregs = (struct regs){ 0 }; 1283b1c7c575SWei Yongjun 1284b1c7c575SWei Yongjun exec_in_big_real_mode(&insn_jcxz1); 1285b1c7c575SWei Yongjun report("jcxz short 1", 0, 1); 1286b1c7c575SWei Yongjun 1287b1c7c575SWei Yongjun exec_in_big_real_mode(&insn_jcxz2); 1288b1c7c575SWei Yongjun report("jcxz short 2", R_AX, outregs.eax == 0x1234); 1289b1c7c575SWei Yongjun 1290b1c7c575SWei Yongjun exec_in_big_real_mode(&insn_jcxz3); 1291b1c7c575SWei Yongjun report("jcxz short 3", R_CX, outregs.ecx == 0x10000); 1292b1c7c575SWei Yongjun 1293b1c7c575SWei Yongjun exec_in_big_real_mode(&insn_jecxz1); 1294b1c7c575SWei Yongjun report("jecxz short 1", 0, 1); 1295b1c7c575SWei Yongjun 1296b1c7c575SWei Yongjun exec_in_big_real_mode(&insn_jecxz2); 1297b1c7c575SWei Yongjun report("jecxz short 2", R_AX, outregs.eax == 0x1234); 1298b1c7c575SWei Yongjun } 1299b1c7c575SWei Yongjun 13008f578e98SAvi Kivity static void test_cpuid(void) 13018f578e98SAvi Kivity { 13028f578e98SAvi Kivity MK_INSN(cpuid, "cpuid"); 13038f578e98SAvi Kivity unsigned function = 0x1234; 13048f578e98SAvi Kivity unsigned eax, ebx, ecx, edx; 13058f578e98SAvi Kivity 13068f578e98SAvi Kivity inregs.eax = eax = function; 13078f578e98SAvi Kivity asm("cpuid" : "+a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)); 13088f578e98SAvi Kivity exec_in_big_real_mode(&insn_cpuid); 13098f578e98SAvi Kivity report("cpuid", R_AX|R_BX|R_CX|R_DX, 13108f578e98SAvi Kivity outregs.eax == eax && outregs.ebx == ebx 13118f578e98SAvi Kivity && outregs.ecx == ecx && outregs.edx == edx); 13128f578e98SAvi Kivity } 13138f578e98SAvi Kivity 1314ed93f43bSAvi Kivity static void test_ss_base_for_esp_ebp(void) 1315ed93f43bSAvi Kivity { 1316ed93f43bSAvi Kivity MK_INSN(ssrel1, "mov %ss, %ax; mov %bx, %ss; movl (%ebp), %ebx; mov %ax, %ss"); 1317ed93f43bSAvi Kivity MK_INSN(ssrel2, "mov %ss, %ax; mov %bx, %ss; movl (%ebp,%edi,8), %ebx; mov %ax, %ss"); 1318ed93f43bSAvi Kivity static unsigned array[] = { 0x12345678, 0, 0, 0, 0x87654321 }; 1319ed93f43bSAvi Kivity 1320ed93f43bSAvi Kivity inregs.ebx = 1; 1321ed93f43bSAvi Kivity inregs.ebp = (unsigned)array; 1322ed93f43bSAvi Kivity exec_in_big_real_mode(&insn_ssrel1); 1323ed93f43bSAvi Kivity report("ss relative addressing (1)", R_AX | R_BX, outregs.ebx == 0x87654321); 1324ed93f43bSAvi Kivity inregs.ebx = 1; 1325ed93f43bSAvi Kivity inregs.ebp = (unsigned)array; 1326ed93f43bSAvi Kivity inregs.edi = 0; 1327ed93f43bSAvi Kivity exec_in_big_real_mode(&insn_ssrel2); 1328ed93f43bSAvi Kivity report("ss relative addressing (2)", R_AX | R_BX, outregs.ebx == 0x87654321); 1329ed93f43bSAvi Kivity } 1330ed93f43bSAvi Kivity 1331c2281fa4SAvi Kivity static void test_sgdt_sidt(void) 1332c2281fa4SAvi Kivity { 1333c2281fa4SAvi Kivity MK_INSN(sgdt, "sgdtw (%eax)"); 1334c2281fa4SAvi Kivity MK_INSN(sidt, "sidtw (%eax)"); 1335c2281fa4SAvi Kivity unsigned x, y; 1336c2281fa4SAvi Kivity 1337c2281fa4SAvi Kivity inregs.eax = (unsigned)&y; 1338c2281fa4SAvi Kivity asm volatile("sgdtw %0" : "=m"(x)); 1339c2281fa4SAvi Kivity exec_in_big_real_mode(&insn_sgdt); 1340c2281fa4SAvi Kivity report("sgdt", 0, x == y); 1341c2281fa4SAvi Kivity 1342c2281fa4SAvi Kivity inregs.eax = (unsigned)&y; 1343c2281fa4SAvi Kivity asm volatile("sidtw %0" : "=m"(x)); 1344c2281fa4SAvi Kivity exec_in_big_real_mode(&insn_sidt); 1345c2281fa4SAvi Kivity report("sidt", 0, x == y); 1346c2281fa4SAvi Kivity } 1347c2281fa4SAvi Kivity 13487ae3645aSAvi Kivity static void test_lahf(void) 13497ae3645aSAvi Kivity { 13507ae3645aSAvi Kivity MK_INSN(lahf, "pushfw; mov %al, (%esp); popfw; lahf"); 13517ae3645aSAvi Kivity 13527ae3645aSAvi Kivity inregs.eax = 0xc7; 13537ae3645aSAvi Kivity exec_in_big_real_mode(&insn_lahf); 13547ae3645aSAvi Kivity report("lahf", R_AX, (outregs.eax >> 8) == inregs.eax); 13557ae3645aSAvi Kivity } 13567ae3645aSAvi Kivity 1357fd9ea640SAvi Kivity static void test_movzx_movsx(void) 1358fd9ea640SAvi Kivity { 1359fd9ea640SAvi Kivity MK_INSN(movsx, "movsx %al, %ebx"); 1360fd9ea640SAvi Kivity MK_INSN(movzx, "movzx %al, %ebx"); 13613013e079SGleb Natapov MK_INSN(movzsah, "movsx %ah, %ebx"); 13623013e079SGleb Natapov MK_INSN(movzxah, "movzx %ah, %ebx"); 1363fd9ea640SAvi Kivity 1364fd9ea640SAvi Kivity inregs.eax = 0x1234569c; 13653013e079SGleb Natapov inregs.esp = 0xffff; 1366fd9ea640SAvi Kivity exec_in_big_real_mode(&insn_movsx); 1367fd9ea640SAvi Kivity report("movsx", R_BX, outregs.ebx == (signed char)inregs.eax); 1368fd9ea640SAvi Kivity exec_in_big_real_mode(&insn_movzx); 1369fd9ea640SAvi Kivity report("movzx", R_BX, outregs.ebx == (unsigned char)inregs.eax); 13703013e079SGleb Natapov exec_in_big_real_mode(&insn_movzsah); 13713013e079SGleb Natapov report("movsx ah", R_BX, outregs.ebx == (signed char)(inregs.eax>>8)); 13723013e079SGleb Natapov exec_in_big_real_mode(&insn_movzxah); 13733013e079SGleb Natapov report("movzx ah", R_BX, outregs.ebx == (unsigned char)(inregs.eax >> 8)); 1374fd9ea640SAvi Kivity } 1375fd9ea640SAvi Kivity 1376b493b2e8SAvi Kivity static void test_bswap(void) 1377b493b2e8SAvi Kivity { 1378b493b2e8SAvi Kivity MK_INSN(bswap, "bswap %ecx"); 1379b493b2e8SAvi Kivity 1380b493b2e8SAvi Kivity inregs.ecx = 0x12345678; 1381b493b2e8SAvi Kivity exec_in_big_real_mode(&insn_bswap); 1382b493b2e8SAvi Kivity report("bswap", R_CX, outregs.ecx == 0x78563412); 1383b493b2e8SAvi Kivity } 1384b493b2e8SAvi Kivity 13858cd86387SGleb Natapov static void test_aad(void) 13868cd86387SGleb Natapov { 13878cd86387SGleb Natapov MK_INSN(aad, "aad"); 13888cd86387SGleb Natapov 13898cd86387SGleb Natapov inregs.eax = 0x12345678; 13908cd86387SGleb Natapov exec_in_big_real_mode(&insn_aad); 13918cd86387SGleb Natapov report("aad", R_AX, outregs.eax == 0x123400d4); 13928cd86387SGleb Natapov } 13938cd86387SGleb Natapov 1394*2a9b5718SPaolo Bonzini static void test_aam(void) 1395*2a9b5718SPaolo Bonzini { 1396*2a9b5718SPaolo Bonzini MK_INSN(aam, "aam"); 1397*2a9b5718SPaolo Bonzini 1398*2a9b5718SPaolo Bonzini inregs.eax = 0x76543210; 1399*2a9b5718SPaolo Bonzini exec_in_big_real_mode(&insn_aam); 1400*2a9b5718SPaolo Bonzini report("aam", R_AX, outregs.eax == 0x76540106); 1401*2a9b5718SPaolo Bonzini } 1402*2a9b5718SPaolo Bonzini 1403*2a9b5718SPaolo Bonzini static void test_xlat(void) 1404*2a9b5718SPaolo Bonzini { 1405*2a9b5718SPaolo Bonzini MK_INSN(xlat, "xlat"); 1406*2a9b5718SPaolo Bonzini u8 table[256]; 1407*2a9b5718SPaolo Bonzini int i; 1408*2a9b5718SPaolo Bonzini 1409*2a9b5718SPaolo Bonzini for (i = 0; i < 256; i++) { 1410*2a9b5718SPaolo Bonzini table[i] = i + 1; 1411*2a9b5718SPaolo Bonzini } 1412*2a9b5718SPaolo Bonzini 1413*2a9b5718SPaolo Bonzini inregs.eax = 0x89abcdef; 1414*2a9b5718SPaolo Bonzini inregs.ebx = (u32)table; 1415*2a9b5718SPaolo Bonzini exec_in_big_real_mode(&insn_xlat); 1416*2a9b5718SPaolo Bonzini report("xlat", R_AX, outregs.eax == 0x89abcdf0); 1417*2a9b5718SPaolo Bonzini } 1418*2a9b5718SPaolo Bonzini 1419*2a9b5718SPaolo Bonzini static void test_salc(void) 1420*2a9b5718SPaolo Bonzini { 1421*2a9b5718SPaolo Bonzini MK_INSN(clc_salc, "clc; .byte 0xd6"); 1422*2a9b5718SPaolo Bonzini MK_INSN(stc_salc, "stc; .byte 0xd6"); 1423*2a9b5718SPaolo Bonzini 1424*2a9b5718SPaolo Bonzini inregs.eax = 0x12345678; 1425*2a9b5718SPaolo Bonzini exec_in_big_real_mode(&insn_clc_salc); 1426*2a9b5718SPaolo Bonzini report("salc (1)", R_AX, outregs.eax == 0x12345600); 1427*2a9b5718SPaolo Bonzini exec_in_big_real_mode(&insn_stc_salc); 1428*2a9b5718SPaolo Bonzini report("salc (2)", R_AX, outregs.eax == 0x123456ff); 1429*2a9b5718SPaolo Bonzini } 1430*2a9b5718SPaolo Bonzini 14310987db7aSGleb Natapov static void test_fninit(void) 14320987db7aSGleb Natapov { 14330987db7aSGleb Natapov u16 fcw = -1, fsw = -1; 14340987db7aSGleb Natapov MK_INSN(fninit, "fninit ; fnstsw (%eax) ; fnstcw (%ebx)"); 14350987db7aSGleb Natapov 14360987db7aSGleb Natapov inregs.eax = (u32)&fsw; 14370987db7aSGleb Natapov inregs.ebx = (u32)&fcw; 14380987db7aSGleb Natapov 14390987db7aSGleb Natapov exec_in_big_real_mode(&insn_fninit); 14400987db7aSGleb Natapov report("fninit", 0, fsw == 0 && (fcw & 0x103f) == 0x003f); 14410987db7aSGleb Natapov } 14420987db7aSGleb Natapov 14437d36db35SAvi Kivity void realmode_start(void) 14447d36db35SAvi Kivity { 14457d36db35SAvi Kivity test_null(); 14467d36db35SAvi Kivity 14477d36db35SAvi Kivity test_shld(); 14487d36db35SAvi Kivity test_push_pop(); 14497d36db35SAvi Kivity test_pusha_popa(); 14507d36db35SAvi Kivity test_mov_imm(); 14517d36db35SAvi Kivity test_cmp_imm(); 14527d36db35SAvi Kivity test_add_imm(); 14537d36db35SAvi Kivity test_sub_imm(); 14547d36db35SAvi Kivity test_xor_imm(); 14557d36db35SAvi Kivity test_io(); 14567d36db35SAvi Kivity test_eflags_insn(); 14577d36db35SAvi Kivity test_jcc_short(); 14587d36db35SAvi Kivity test_jcc_near(); 14597d36db35SAvi Kivity /* test_call() uses short jump so call it after testing jcc */ 14607d36db35SAvi Kivity test_call(); 14617d36db35SAvi Kivity /* long jmp test uses call near so test it after testing call */ 14627d36db35SAvi Kivity test_long_jmp(); 14637d36db35SAvi Kivity test_xchg(); 14647d36db35SAvi Kivity test_iret(); 146596b9ca1eSMohammed Gamal test_int(); 1466fa74f8a6SMohammed Gamal test_imul(); 146759317bd1SMohammed Gamal test_mul(); 14680d4c7614SMohammed Gamal test_div(); 14690d4c7614SMohammed Gamal test_idiv(); 1470eacef4e2SWei Yongjun test_loopcc(); 14716e293cf5SWei Yongjun test_cbw(); 14720cbd5b06SMohammed Gamal test_cwd_cdq(); 1473b274feedSAvi Kivity test_das(); 147437f51a4aSWei Yongjun test_lds_lss(); 1475b1c7c575SWei Yongjun test_jcxz(); 14768f578e98SAvi Kivity test_cpuid(); 1477ed93f43bSAvi Kivity test_ss_base_for_esp_ebp(); 1478c2281fa4SAvi Kivity test_sgdt_sidt(); 14797ae3645aSAvi Kivity test_lahf(); 1480fd9ea640SAvi Kivity test_movzx_movsx(); 1481b493b2e8SAvi Kivity test_bswap(); 14828cd86387SGleb Natapov test_aad(); 1483*2a9b5718SPaolo Bonzini test_aam(); 1484*2a9b5718SPaolo Bonzini test_xlat(); 1485*2a9b5718SPaolo Bonzini test_salc(); 14860987db7aSGleb Natapov test_fninit(); 14877d36db35SAvi Kivity 14887d36db35SAvi Kivity exit(0); 14897d36db35SAvi Kivity } 14907d36db35SAvi Kivity 14917d36db35SAvi Kivity unsigned long long r_gdt[] = { 0, 0x9b000000ffff, 0x93000000ffff }; 14927d36db35SAvi Kivity 14937d36db35SAvi Kivity struct __attribute__((packed)) { 14947d36db35SAvi Kivity unsigned short limit; 14957d36db35SAvi Kivity void *base; 14967d36db35SAvi Kivity } r_gdt_descr = { sizeof(r_gdt) - 1, &r_gdt }; 14977d36db35SAvi Kivity 14987d36db35SAvi Kivity asm( 14997d36db35SAvi Kivity ".section .init \n\t" 15007d36db35SAvi Kivity 15017d36db35SAvi Kivity ".code32 \n\t" 15027d36db35SAvi Kivity 15037d36db35SAvi Kivity "mb_magic = 0x1BADB002 \n\t" 15047d36db35SAvi Kivity "mb_flags = 0x0 \n\t" 15057d36db35SAvi Kivity 15067d36db35SAvi Kivity "# multiboot header \n\t" 15077d36db35SAvi Kivity ".long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) \n\t" 15087d36db35SAvi Kivity 15097d36db35SAvi Kivity ".globl start \n\t" 15107d36db35SAvi Kivity ".data \n\t" 15117d36db35SAvi Kivity ". = . + 4096 \n\t" 15127d36db35SAvi Kivity "stacktop: \n\t" 15137d36db35SAvi Kivity 15147d36db35SAvi Kivity ".text \n\t" 15157d36db35SAvi Kivity "start: \n\t" 15167d36db35SAvi Kivity "lgdt r_gdt_descr \n\t" 15177d36db35SAvi Kivity "ljmp $8, $1f; 1: \n\t" 15187d36db35SAvi Kivity ".code16gcc \n\t" 15197d36db35SAvi Kivity "mov $16, %eax \n\t" 15207d36db35SAvi Kivity "mov %ax, %ds \n\t" 15217d36db35SAvi Kivity "mov %ax, %es \n\t" 15227d36db35SAvi Kivity "mov %ax, %fs \n\t" 15237d36db35SAvi Kivity "mov %ax, %gs \n\t" 15247d36db35SAvi Kivity "mov %ax, %ss \n\t" 15257d36db35SAvi Kivity "mov %cr0, %eax \n\t" 15267d36db35SAvi Kivity "btc $0, %eax \n\t" 15277d36db35SAvi Kivity "mov %eax, %cr0 \n\t" 15287d36db35SAvi Kivity "ljmp $0, $realmode_entry \n\t" 15297d36db35SAvi Kivity 15307d36db35SAvi Kivity "realmode_entry: \n\t" 15317d36db35SAvi Kivity 15327d36db35SAvi Kivity "xor %ax, %ax \n\t" 15337d36db35SAvi Kivity "mov %ax, %ds \n\t" 15347d36db35SAvi Kivity "mov %ax, %es \n\t" 15357d36db35SAvi Kivity "mov %ax, %ss \n\t" 15367d36db35SAvi Kivity "mov %ax, %fs \n\t" 15377d36db35SAvi Kivity "mov %ax, %gs \n\t" 15387d36db35SAvi Kivity "mov $stacktop, %esp\n\t" 15397d36db35SAvi Kivity "ljmp $0, $realmode_start \n\t" 15407d36db35SAvi Kivity 15417d36db35SAvi Kivity ".code16gcc \n\t" 15427d36db35SAvi Kivity ); 1543