Commit 5a91de8c902e8de43d80df2db6f056710d414e56

Authored by bellard
1 parent e3b32540

precise exception support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@189 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 137 additions and 49 deletions
translate-i386.c
... ... @@ -160,7 +160,7 @@ enum {
160 160 };
161 161  
162 162 enum {
163   -#define DEF(s, n) INDEX_op_ ## s,
  163 +#define DEF(s, n, copy_size) INDEX_op_ ## s,
164 164 #include "opc-i386.h"
165 165 #undef DEF
166 166 NB_OPS,
... ... @@ -1215,9 +1215,13 @@ static void gen_setcc(DisasContext *s, int b)
1215 1215 }
1216 1216  
1217 1217 /* move T0 to seg_reg and compute if the CPU state may change */
1218   -static void gen_movl_seg_T0(DisasContext *s, int seg_reg)
  1218 +static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip)
1219 1219 {
1220   - gen_op_movl_seg_T0(seg_reg);
  1220 + if (!s->vm86)
  1221 + gen_op_movl_seg_T0(seg_reg, cur_eip);
  1222 + else
  1223 + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]),
  1224 + offsetof(CPUX86State,seg_cache[seg_reg].base));
1221 1225 if (!s->addseg && seg_reg < R_FS)
1222 1226 s->is_jmp = 2; /* abort translation because the register may
1223 1227 have a non zero base */
... ... @@ -1374,6 +1378,18 @@ static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip)
1374 1378 s->is_jmp = 1;
1375 1379 }
1376 1380  
  1381 +/* an interrupt is different from an exception because of the
  1382 + priviledge checks */
  1383 +static void gen_interrupt(DisasContext *s, int intno,
  1384 + unsigned int cur_eip, unsigned int next_eip)
  1385 +{
  1386 + if (s->cc_op != CC_OP_DYNAMIC)
  1387 + gen_op_set_cc_op(s->cc_op);
  1388 + gen_op_jmp_im(cur_eip);
  1389 + gen_op_raise_interrupt(intno, next_eip);
  1390 + s->is_jmp = 1;
  1391 +}
  1392 +
1377 1393 /* generate a jump to eip. No segment change must happen before as a
1378 1394 direct call to the next block may occur */
1379 1395 static void gen_jmp(DisasContext *s, unsigned int eip)
... ... @@ -1650,28 +1666,28 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
1650 1666 case 6: /* div */
1651 1667 switch(ot) {
1652 1668 case OT_BYTE:
1653   - gen_op_divb_AL_T0();
  1669 + gen_op_divb_AL_T0(pc_start - s->cs_base);
1654 1670 break;
1655 1671 case OT_WORD:
1656   - gen_op_divw_AX_T0();
  1672 + gen_op_divw_AX_T0(pc_start - s->cs_base);
1657 1673 break;
1658 1674 default:
1659 1675 case OT_LONG:
1660   - gen_op_divl_EAX_T0();
  1676 + gen_op_divl_EAX_T0(pc_start - s->cs_base);
1661 1677 break;
1662 1678 }
1663 1679 break;
1664 1680 case 7: /* idiv */
1665 1681 switch(ot) {
1666 1682 case OT_BYTE:
1667   - gen_op_idivb_AL_T0();
  1683 + gen_op_idivb_AL_T0(pc_start - s->cs_base);
1668 1684 break;
1669 1685 case OT_WORD:
1670   - gen_op_idivw_AX_T0();
  1686 + gen_op_idivw_AX_T0(pc_start - s->cs_base);
1671 1687 break;
1672 1688 default:
1673 1689 case OT_LONG:
1674   - gen_op_idivl_EAX_T0();
  1690 + gen_op_idivl_EAX_T0(pc_start - s->cs_base);
1675 1691 break;
1676 1692 }
1677 1693 break;
... ... @@ -1738,7 +1754,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
1738 1754 gen_op_ld_T1_A0[ot]();
1739 1755 gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
1740 1756 gen_op_lduw_T0_A0();
1741   - gen_movl_seg_T0(s, R_CS);
  1757 + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
1742 1758 gen_op_movl_T0_T1();
1743 1759 gen_op_jmp_T0();
1744 1760 s->is_jmp = 1;
... ... @@ -1753,7 +1769,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
1753 1769 gen_op_ld_T1_A0[ot]();
1754 1770 gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
1755 1771 gen_op_lduw_T0_A0();
1756   - gen_movl_seg_T0(s, R_CS);
  1772 + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
1757 1773 gen_op_movl_T0_T1();
1758 1774 gen_op_jmp_T0();
1759 1775 s->is_jmp = 1;
... ... @@ -1970,13 +1986,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
1970 1986 case 0x17: /* pop ss */
1971 1987 case 0x1f: /* pop ds */
1972 1988 gen_pop_T0(s);
1973   - gen_movl_seg_T0(s, b >> 3);
  1989 + gen_movl_seg_T0(s, b >> 3, pc_start - s->cs_base);
1974 1990 gen_pop_update(s);
1975 1991 break;
1976 1992 case 0x1a1: /* pop fs */
1977 1993 case 0x1a9: /* pop gs */
1978 1994 gen_pop_T0(s);
1979   - gen_movl_seg_T0(s, (b >> 3) & 7);
  1995 + gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base);
1980 1996 gen_pop_update(s);
1981 1997 break;
1982 1998  
... ... @@ -2030,7 +2046,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
2030 2046 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
2031 2047 if (reg >= 6 || reg == R_CS)
2032 2048 goto illegal_op;
2033   - gen_movl_seg_T0(s, reg);
  2049 + gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
2034 2050 break;
2035 2051 case 0x8c: /* mov Gv, seg */
2036 2052 ot = dflag ? OT_LONG : OT_WORD;
... ... @@ -2231,7 +2247,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
2231 2247 gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
2232 2248 /* load the segment first to handle exceptions properly */
2233 2249 gen_op_lduw_T0_A0();
2234   - gen_movl_seg_T0(s, op);
  2250 + gen_movl_seg_T0(s, op, pc_start - s->cs_base);
2235 2251 /* then put the data */
2236 2252 gen_op_mov_reg_T1[ot][reg]();
2237 2253 break;
... ... @@ -2914,7 +2930,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
2914 2930 gen_pop_update(s);
2915 2931 /* pop selector */
2916 2932 gen_pop_T0(s);
2917   - gen_movl_seg_T0(s, R_CS);
  2933 + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
2918 2934 gen_pop_update(s);
2919 2935 /* add stack offset */
2920 2936 if (s->ss32)
... ... @@ -2933,7 +2949,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
2933 2949 gen_pop_update(s);
2934 2950 /* pop selector */
2935 2951 gen_pop_T0(s);
2936   - gen_movl_seg_T0(s, R_CS);
  2952 + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
2937 2953 gen_pop_update(s);
2938 2954 s->is_jmp = 1;
2939 2955 break;
... ... @@ -2950,7 +2966,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
2950 2966 gen_pop_update(s);
2951 2967 /* pop selector */
2952 2968 gen_pop_T0(s);
2953   - gen_movl_seg_T0(s, R_CS);
  2969 + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
2954 2970 gen_pop_update(s);
2955 2971 /* pop eflags */
2956 2972 gen_pop_T0(s);
... ... @@ -2995,7 +3011,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
2995 3011  
2996 3012 /* change cs and pc */
2997 3013 gen_op_movl_T0_im(selector);
2998   - gen_movl_seg_T0(s, R_CS);
  3014 + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
2999 3015 gen_op_jmp_im((unsigned long)offset);
3000 3016 s->is_jmp = 1;
3001 3017 }
... ... @@ -3018,7 +3034,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
3018 3034  
3019 3035 /* change cs and pc */
3020 3036 gen_op_movl_T0_im(selector);
3021   - gen_movl_seg_T0(s, R_CS);
  3037 + gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
3022 3038 gen_op_jmp_im((unsigned long)offset);
3023 3039 s->is_jmp = 1;
3024 3040 }
... ... @@ -3255,14 +3271,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
3255 3271 case 0x9b: /* fwait */
3256 3272 break;
3257 3273 case 0xcc: /* int3 */
3258   - gen_exception(s, EXCP03_INT3, s->pc - s->cs_base);
  3274 + gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
3259 3275 break;
3260 3276 case 0xcd: /* int N */
3261 3277 val = ldub(s->pc++);
3262   - if (s->cc_op != CC_OP_DYNAMIC)
3263   - gen_op_set_cc_op(s->cc_op);
3264   - gen_op_int_im(val, pc_start - s->cs_base);
3265   - s->is_jmp = 1;
  3278 + /* XXX: add error code for vm86 GPF */
  3279 + if (!s->vm86)
  3280 + gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
  3281 + else
  3282 + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3266 3283 break;
3267 3284 case 0xce: /* into */
3268 3285 if (s->cc_op != CC_OP_DYNAMIC)
... ... @@ -3309,9 +3326,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
3309 3326 gen_op_mov_reg_T0[ot][reg]();
3310 3327 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3311 3328 if (ot == OT_WORD)
3312   - gen_op_boundw();
  3329 + gen_op_boundw(pc_start - s->cs_base);
3313 3330 else
3314   - gen_op_boundl();
  3331 + gen_op_boundl(pc_start - s->cs_base);
3315 3332 break;
3316 3333 case 0x1c8 ... 0x1cf: /* bswap reg */
3317 3334 reg = b & 7;
... ... @@ -3670,13 +3687,13 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len)
3670 3687  
3671 3688 #ifdef DEBUG_DISAS
3672 3689 static const char *op_str[] = {
3673   -#define DEF(s, n) #s,
  3690 +#define DEF(s, n, copy_size) #s,
3674 3691 #include "opc-i386.h"
3675 3692 #undef DEF
3676 3693 };
3677 3694  
3678 3695 static uint8_t op_nb_args[] = {
3679   -#define DEF(s, n) n,
  3696 +#define DEF(s, n, copy_size) n,
3680 3697 #include "opc-i386.h"
3681 3698 #undef DEF
3682 3699 };
... ... @@ -3706,7 +3723,6 @@ static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
3706 3723  
3707 3724 #endif
3708 3725  
3709   -/* XXX: make this buffer thread safe */
3710 3726 /* XXX: make safe guess about sizes */
3711 3727 #define MAX_OP_PER_INSTR 32
3712 3728 #define OPC_BUF_SIZE 512
... ... @@ -3716,30 +3732,27 @@ static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
3716 3732  
3717 3733 static uint16_t gen_opc_buf[OPC_BUF_SIZE];
3718 3734 static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
  3735 +static uint32_t gen_opc_pc[OPC_BUF_SIZE];
  3736 +static uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
3719 3737  
3720   -/* return non zero if the very first instruction is invalid so that
3721   - the virtual CPU can trigger an exception.
3722   -
3723   - '*code_size_ptr' contains the target code size including the
3724   - instruction which triggered an exception, except in case of invalid
3725   - illegal opcode. It must never exceed one target page.
3726   -
3727   - '*gen_code_size_ptr' contains the size of the generated code (host
3728   - code).
3729   -*/
3730   -int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
3731   - int *gen_code_size_ptr,
3732   - uint8_t *pc_start, uint8_t *cs_base, int flags,
3733   - int *code_size_ptr, TranslationBlock *tb)
  3738 +/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
  3739 + basic block 'tb'. If search_pc is TRUE, also generate PC
  3740 + information for each intermediate instruction. */
  3741 +static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc)
3734 3742 {
3735 3743 DisasContext dc1, *dc = &dc1;
3736 3744 uint8_t *pc_ptr;
3737 3745 uint16_t *gen_opc_end;
3738   - int gen_code_size;
  3746 + int flags, j, lj;
3739 3747 long ret;
  3748 + uint8_t *pc_start;
  3749 + uint8_t *cs_base;
3740 3750  
3741 3751 /* generate intermediate code */
3742   -
  3752 + pc_start = (uint8_t *)tb->pc;
  3753 + cs_base = (uint8_t *)tb->cs_base;
  3754 + flags = tb->flags;
  3755 +
3743 3756 dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1;
3744 3757 dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1;
3745 3758 dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1;
... ... @@ -3758,7 +3771,18 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
3758 3771  
3759 3772 dc->is_jmp = 0;
3760 3773 pc_ptr = pc_start;
  3774 + lj = -1;
3761 3775 do {
  3776 + if (search_pc) {
  3777 + j = gen_opc_ptr - gen_opc_buf;
  3778 + if (lj < j) {
  3779 + lj++;
  3780 + while (lj < j)
  3781 + gen_opc_instr_start[lj++] = 0;
  3782 + gen_opc_pc[lj] = (uint32_t)pc_ptr;
  3783 + gen_opc_instr_start[lj] = 1;
  3784 + }
  3785 + }
3762 3786 ret = disas_insn(dc, pc_ptr);
3763 3787 if (ret == -1) {
3764 3788 /* we trigger an illegal instruction operation only if it
... ... @@ -3819,10 +3843,31 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
3819 3843 fprintf(logfile, "\n");
3820 3844 }
3821 3845 #endif
  3846 + if (!search_pc)
  3847 + tb->size = pc_ptr - pc_start;
  3848 + return 0;
  3849 +}
  3850 +
  3851 +
  3852 +/* return non zero if the very first instruction is invalid so that
  3853 + the virtual CPU can trigger an exception.
  3854 +
  3855 + '*gen_code_size_ptr' contains the size of the generated code (host
  3856 + code).
  3857 +*/
  3858 +int cpu_x86_gen_code(TranslationBlock *tb,
  3859 + int max_code_size, int *gen_code_size_ptr)
  3860 +{
  3861 + uint8_t *gen_code_buf;
  3862 + int gen_code_size;
  3863 +
  3864 + if (gen_intermediate_code(tb, 0) < 0)
  3865 + return -1;
3822 3866  
3823 3867 /* generate machine code */
3824 3868 tb->tb_next_offset[0] = 0xffff;
3825 3869 tb->tb_next_offset[1] = 0xffff;
  3870 + gen_code_buf = tb->tc_ptr;
3826 3871 gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
3827 3872 #ifdef USE_DIRECT_JUMP
3828 3873 tb->tb_jmp_offset,
... ... @@ -3831,13 +3876,12 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
3831 3876 #endif
3832 3877 gen_opc_buf, gen_opparam_buf);
3833 3878 flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size));
3834   -
  3879 +
3835 3880 *gen_code_size_ptr = gen_code_size;
3836   - *code_size_ptr = pc_ptr - pc_start;
3837 3881 #ifdef DEBUG_DISAS
3838 3882 if (loglevel) {
3839 3883 fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
3840   - disas(logfile, gen_code_buf, *gen_code_size_ptr, DISAS_TARGET);
  3884 + disas(logfile, gen_code_buf, *gen_code_size_ptr, DISAS_TARGET);
3841 3885 fprintf(logfile, "\n");
3842 3886 fflush(logfile);
3843 3887 }
... ... @@ -3845,6 +3889,50 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
3845 3889 return 0;
3846 3890 }
3847 3891  
  3892 +static const unsigned short opc_copy_size[] = {
  3893 +#define DEF(s, n, copy_size) copy_size,
  3894 +#include "opc-i386.h"
  3895 +#undef DEF
  3896 +};
  3897 +
  3898 +/* The simulated PC corresponding to
  3899 + 'searched_pc' in the generated code is searched. 0 is returned if
  3900 + found. *found_pc contains the found PC.
  3901 + */
  3902 +int cpu_x86_search_pc(TranslationBlock *tb,
  3903 + uint32_t *found_pc, unsigned long searched_pc)
  3904 +{
  3905 + int j, c;
  3906 + unsigned long tc_ptr;
  3907 + uint16_t *opc_ptr;
  3908 +
  3909 + if (gen_intermediate_code(tb, 1) < 0)
  3910 + return -1;
  3911 +
  3912 + /* find opc index corresponding to search_pc */
  3913 + tc_ptr = (unsigned long)tb->tc_ptr;
  3914 + if (searched_pc < tc_ptr)
  3915 + return -1;
  3916 + j = 0;
  3917 + opc_ptr = gen_opc_buf;
  3918 + for(;;) {
  3919 + c = *opc_ptr;
  3920 + if (c == INDEX_op_end)
  3921 + return -1;
  3922 + tc_ptr += opc_copy_size[c];
  3923 + if (searched_pc < tc_ptr)
  3924 + break;
  3925 + opc_ptr++;
  3926 + }
  3927 + j = opc_ptr - gen_opc_buf;
  3928 + /* now find start of instruction before */
  3929 + while (gen_opc_instr_start[j] == 0)
  3930 + j--;
  3931 + *found_pc = gen_opc_pc[j];
  3932 + return 0;
  3933 +}
  3934 +
  3935 +
3848 3936 CPUX86State *cpu_x86_init(void)
3849 3937 {
3850 3938 CPUX86State *env;
... ...