Commit 5a91de8c902e8de43d80df2db6f056710d414e56
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,7 +160,7 @@ enum { | ||
| 160 | }; | 160 | }; |
| 161 | 161 | ||
| 162 | enum { | 162 | enum { |
| 163 | -#define DEF(s, n) INDEX_op_ ## s, | 163 | +#define DEF(s, n, copy_size) INDEX_op_ ## s, |
| 164 | #include "opc-i386.h" | 164 | #include "opc-i386.h" |
| 165 | #undef DEF | 165 | #undef DEF |
| 166 | NB_OPS, | 166 | NB_OPS, |
| @@ -1215,9 +1215,13 @@ static void gen_setcc(DisasContext *s, int b) | @@ -1215,9 +1215,13 @@ static void gen_setcc(DisasContext *s, int b) | ||
| 1215 | } | 1215 | } |
| 1216 | 1216 | ||
| 1217 | /* move T0 to seg_reg and compute if the CPU state may change */ | 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 | if (!s->addseg && seg_reg < R_FS) | 1225 | if (!s->addseg && seg_reg < R_FS) |
| 1222 | s->is_jmp = 2; /* abort translation because the register may | 1226 | s->is_jmp = 2; /* abort translation because the register may |
| 1223 | have a non zero base */ | 1227 | have a non zero base */ |
| @@ -1374,6 +1378,18 @@ static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) | @@ -1374,6 +1378,18 @@ static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) | ||
| 1374 | s->is_jmp = 1; | 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 | /* generate a jump to eip. No segment change must happen before as a | 1393 | /* generate a jump to eip. No segment change must happen before as a |
| 1378 | direct call to the next block may occur */ | 1394 | direct call to the next block may occur */ |
| 1379 | static void gen_jmp(DisasContext *s, unsigned int eip) | 1395 | static void gen_jmp(DisasContext *s, unsigned int eip) |
| @@ -1650,28 +1666,28 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -1650,28 +1666,28 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 1650 | case 6: /* div */ | 1666 | case 6: /* div */ |
| 1651 | switch(ot) { | 1667 | switch(ot) { |
| 1652 | case OT_BYTE: | 1668 | case OT_BYTE: |
| 1653 | - gen_op_divb_AL_T0(); | 1669 | + gen_op_divb_AL_T0(pc_start - s->cs_base); |
| 1654 | break; | 1670 | break; |
| 1655 | case OT_WORD: | 1671 | case OT_WORD: |
| 1656 | - gen_op_divw_AX_T0(); | 1672 | + gen_op_divw_AX_T0(pc_start - s->cs_base); |
| 1657 | break; | 1673 | break; |
| 1658 | default: | 1674 | default: |
| 1659 | case OT_LONG: | 1675 | case OT_LONG: |
| 1660 | - gen_op_divl_EAX_T0(); | 1676 | + gen_op_divl_EAX_T0(pc_start - s->cs_base); |
| 1661 | break; | 1677 | break; |
| 1662 | } | 1678 | } |
| 1663 | break; | 1679 | break; |
| 1664 | case 7: /* idiv */ | 1680 | case 7: /* idiv */ |
| 1665 | switch(ot) { | 1681 | switch(ot) { |
| 1666 | case OT_BYTE: | 1682 | case OT_BYTE: |
| 1667 | - gen_op_idivb_AL_T0(); | 1683 | + gen_op_idivb_AL_T0(pc_start - s->cs_base); |
| 1668 | break; | 1684 | break; |
| 1669 | case OT_WORD: | 1685 | case OT_WORD: |
| 1670 | - gen_op_idivw_AX_T0(); | 1686 | + gen_op_idivw_AX_T0(pc_start - s->cs_base); |
| 1671 | break; | 1687 | break; |
| 1672 | default: | 1688 | default: |
| 1673 | case OT_LONG: | 1689 | case OT_LONG: |
| 1674 | - gen_op_idivl_EAX_T0(); | 1690 | + gen_op_idivl_EAX_T0(pc_start - s->cs_base); |
| 1675 | break; | 1691 | break; |
| 1676 | } | 1692 | } |
| 1677 | break; | 1693 | break; |
| @@ -1738,7 +1754,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -1738,7 +1754,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 1738 | gen_op_ld_T1_A0[ot](); | 1754 | gen_op_ld_T1_A0[ot](); |
| 1739 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); | 1755 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
| 1740 | gen_op_lduw_T0_A0(); | 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 | gen_op_movl_T0_T1(); | 1758 | gen_op_movl_T0_T1(); |
| 1743 | gen_op_jmp_T0(); | 1759 | gen_op_jmp_T0(); |
| 1744 | s->is_jmp = 1; | 1760 | s->is_jmp = 1; |
| @@ -1753,7 +1769,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -1753,7 +1769,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 1753 | gen_op_ld_T1_A0[ot](); | 1769 | gen_op_ld_T1_A0[ot](); |
| 1754 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); | 1770 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
| 1755 | gen_op_lduw_T0_A0(); | 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 | gen_op_movl_T0_T1(); | 1773 | gen_op_movl_T0_T1(); |
| 1758 | gen_op_jmp_T0(); | 1774 | gen_op_jmp_T0(); |
| 1759 | s->is_jmp = 1; | 1775 | s->is_jmp = 1; |
| @@ -1970,13 +1986,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -1970,13 +1986,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 1970 | case 0x17: /* pop ss */ | 1986 | case 0x17: /* pop ss */ |
| 1971 | case 0x1f: /* pop ds */ | 1987 | case 0x1f: /* pop ds */ |
| 1972 | gen_pop_T0(s); | 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 | gen_pop_update(s); | 1990 | gen_pop_update(s); |
| 1975 | break; | 1991 | break; |
| 1976 | case 0x1a1: /* pop fs */ | 1992 | case 0x1a1: /* pop fs */ |
| 1977 | case 0x1a9: /* pop gs */ | 1993 | case 0x1a9: /* pop gs */ |
| 1978 | gen_pop_T0(s); | 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 | gen_pop_update(s); | 1996 | gen_pop_update(s); |
| 1981 | break; | 1997 | break; |
| 1982 | 1998 | ||
| @@ -2030,7 +2046,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2030,7 +2046,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 2030 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); | 2046 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); |
| 2031 | if (reg >= 6 || reg == R_CS) | 2047 | if (reg >= 6 || reg == R_CS) |
| 2032 | goto illegal_op; | 2048 | goto illegal_op; |
| 2033 | - gen_movl_seg_T0(s, reg); | 2049 | + gen_movl_seg_T0(s, reg, pc_start - s->cs_base); |
| 2034 | break; | 2050 | break; |
| 2035 | case 0x8c: /* mov Gv, seg */ | 2051 | case 0x8c: /* mov Gv, seg */ |
| 2036 | ot = dflag ? OT_LONG : OT_WORD; | 2052 | ot = dflag ? OT_LONG : OT_WORD; |
| @@ -2231,7 +2247,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2231,7 +2247,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 2231 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); | 2247 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
| 2232 | /* load the segment first to handle exceptions properly */ | 2248 | /* load the segment first to handle exceptions properly */ |
| 2233 | gen_op_lduw_T0_A0(); | 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 | /* then put the data */ | 2251 | /* then put the data */ |
| 2236 | gen_op_mov_reg_T1[ot][reg](); | 2252 | gen_op_mov_reg_T1[ot][reg](); |
| 2237 | break; | 2253 | break; |
| @@ -2914,7 +2930,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2914,7 +2930,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 2914 | gen_pop_update(s); | 2930 | gen_pop_update(s); |
| 2915 | /* pop selector */ | 2931 | /* pop selector */ |
| 2916 | gen_pop_T0(s); | 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 | gen_pop_update(s); | 2934 | gen_pop_update(s); |
| 2919 | /* add stack offset */ | 2935 | /* add stack offset */ |
| 2920 | if (s->ss32) | 2936 | if (s->ss32) |
| @@ -2933,7 +2949,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2933,7 +2949,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 2933 | gen_pop_update(s); | 2949 | gen_pop_update(s); |
| 2934 | /* pop selector */ | 2950 | /* pop selector */ |
| 2935 | gen_pop_T0(s); | 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 | gen_pop_update(s); | 2953 | gen_pop_update(s); |
| 2938 | s->is_jmp = 1; | 2954 | s->is_jmp = 1; |
| 2939 | break; | 2955 | break; |
| @@ -2950,7 +2966,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2950,7 +2966,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 2950 | gen_pop_update(s); | 2966 | gen_pop_update(s); |
| 2951 | /* pop selector */ | 2967 | /* pop selector */ |
| 2952 | gen_pop_T0(s); | 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 | gen_pop_update(s); | 2970 | gen_pop_update(s); |
| 2955 | /* pop eflags */ | 2971 | /* pop eflags */ |
| 2956 | gen_pop_T0(s); | 2972 | gen_pop_T0(s); |
| @@ -2995,7 +3011,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2995,7 +3011,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 2995 | 3011 | ||
| 2996 | /* change cs and pc */ | 3012 | /* change cs and pc */ |
| 2997 | gen_op_movl_T0_im(selector); | 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 | gen_op_jmp_im((unsigned long)offset); | 3015 | gen_op_jmp_im((unsigned long)offset); |
| 3000 | s->is_jmp = 1; | 3016 | s->is_jmp = 1; |
| 3001 | } | 3017 | } |
| @@ -3018,7 +3034,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3018,7 +3034,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 3018 | 3034 | ||
| 3019 | /* change cs and pc */ | 3035 | /* change cs and pc */ |
| 3020 | gen_op_movl_T0_im(selector); | 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 | gen_op_jmp_im((unsigned long)offset); | 3038 | gen_op_jmp_im((unsigned long)offset); |
| 3023 | s->is_jmp = 1; | 3039 | s->is_jmp = 1; |
| 3024 | } | 3040 | } |
| @@ -3255,14 +3271,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3255,14 +3271,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 3255 | case 0x9b: /* fwait */ | 3271 | case 0x9b: /* fwait */ |
| 3256 | break; | 3272 | break; |
| 3257 | case 0xcc: /* int3 */ | 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 | break; | 3275 | break; |
| 3260 | case 0xcd: /* int N */ | 3276 | case 0xcd: /* int N */ |
| 3261 | val = ldub(s->pc++); | 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 | break; | 3283 | break; |
| 3267 | case 0xce: /* into */ | 3284 | case 0xce: /* into */ |
| 3268 | if (s->cc_op != CC_OP_DYNAMIC) | 3285 | if (s->cc_op != CC_OP_DYNAMIC) |
| @@ -3309,9 +3326,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -3309,9 +3326,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
| 3309 | gen_op_mov_reg_T0[ot][reg](); | 3326 | gen_op_mov_reg_T0[ot][reg](); |
| 3310 | gen_lea_modrm(s, modrm, ®_addr, &offset_addr); | 3327 | gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
| 3311 | if (ot == OT_WORD) | 3328 | if (ot == OT_WORD) |
| 3312 | - gen_op_boundw(); | 3329 | + gen_op_boundw(pc_start - s->cs_base); |
| 3313 | else | 3330 | else |
| 3314 | - gen_op_boundl(); | 3331 | + gen_op_boundl(pc_start - s->cs_base); |
| 3315 | break; | 3332 | break; |
| 3316 | case 0x1c8 ... 0x1cf: /* bswap reg */ | 3333 | case 0x1c8 ... 0x1cf: /* bswap reg */ |
| 3317 | reg = b & 7; | 3334 | reg = b & 7; |
| @@ -3670,13 +3687,13 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) | @@ -3670,13 +3687,13 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) | ||
| 3670 | 3687 | ||
| 3671 | #ifdef DEBUG_DISAS | 3688 | #ifdef DEBUG_DISAS |
| 3672 | static const char *op_str[] = { | 3689 | static const char *op_str[] = { |
| 3673 | -#define DEF(s, n) #s, | 3690 | +#define DEF(s, n, copy_size) #s, |
| 3674 | #include "opc-i386.h" | 3691 | #include "opc-i386.h" |
| 3675 | #undef DEF | 3692 | #undef DEF |
| 3676 | }; | 3693 | }; |
| 3677 | 3694 | ||
| 3678 | static uint8_t op_nb_args[] = { | 3695 | static uint8_t op_nb_args[] = { |
| 3679 | -#define DEF(s, n) n, | 3696 | +#define DEF(s, n, copy_size) n, |
| 3680 | #include "opc-i386.h" | 3697 | #include "opc-i386.h" |
| 3681 | #undef DEF | 3698 | #undef DEF |
| 3682 | }; | 3699 | }; |
| @@ -3706,7 +3723,6 @@ static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) | @@ -3706,7 +3723,6 @@ static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) | ||
| 3706 | 3723 | ||
| 3707 | #endif | 3724 | #endif |
| 3708 | 3725 | ||
| 3709 | -/* XXX: make this buffer thread safe */ | ||
| 3710 | /* XXX: make safe guess about sizes */ | 3726 | /* XXX: make safe guess about sizes */ |
| 3711 | #define MAX_OP_PER_INSTR 32 | 3727 | #define MAX_OP_PER_INSTR 32 |
| 3712 | #define OPC_BUF_SIZE 512 | 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,30 +3732,27 @@ static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf) | ||
| 3716 | 3732 | ||
| 3717 | static uint16_t gen_opc_buf[OPC_BUF_SIZE]; | 3733 | static uint16_t gen_opc_buf[OPC_BUF_SIZE]; |
| 3718 | static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; | 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 | DisasContext dc1, *dc = &dc1; | 3743 | DisasContext dc1, *dc = &dc1; |
| 3736 | uint8_t *pc_ptr; | 3744 | uint8_t *pc_ptr; |
| 3737 | uint16_t *gen_opc_end; | 3745 | uint16_t *gen_opc_end; |
| 3738 | - int gen_code_size; | 3746 | + int flags, j, lj; |
| 3739 | long ret; | 3747 | long ret; |
| 3748 | + uint8_t *pc_start; | ||
| 3749 | + uint8_t *cs_base; | ||
| 3740 | 3750 | ||
| 3741 | /* generate intermediate code */ | 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 | dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; | 3756 | dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; |
| 3744 | dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; | 3757 | dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; |
| 3745 | dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; | 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,7 +3771,18 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | ||
| 3758 | 3771 | ||
| 3759 | dc->is_jmp = 0; | 3772 | dc->is_jmp = 0; |
| 3760 | pc_ptr = pc_start; | 3773 | pc_ptr = pc_start; |
| 3774 | + lj = -1; | ||
| 3761 | do { | 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 | ret = disas_insn(dc, pc_ptr); | 3786 | ret = disas_insn(dc, pc_ptr); |
| 3763 | if (ret == -1) { | 3787 | if (ret == -1) { |
| 3764 | /* we trigger an illegal instruction operation only if it | 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,10 +3843,31 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | ||
| 3819 | fprintf(logfile, "\n"); | 3843 | fprintf(logfile, "\n"); |
| 3820 | } | 3844 | } |
| 3821 | #endif | 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 | /* generate machine code */ | 3867 | /* generate machine code */ |
| 3824 | tb->tb_next_offset[0] = 0xffff; | 3868 | tb->tb_next_offset[0] = 0xffff; |
| 3825 | tb->tb_next_offset[1] = 0xffff; | 3869 | tb->tb_next_offset[1] = 0xffff; |
| 3870 | + gen_code_buf = tb->tc_ptr; | ||
| 3826 | gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, | 3871 | gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, |
| 3827 | #ifdef USE_DIRECT_JUMP | 3872 | #ifdef USE_DIRECT_JUMP |
| 3828 | tb->tb_jmp_offset, | 3873 | tb->tb_jmp_offset, |
| @@ -3831,13 +3876,12 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | @@ -3831,13 +3876,12 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | ||
| 3831 | #endif | 3876 | #endif |
| 3832 | gen_opc_buf, gen_opparam_buf); | 3877 | gen_opc_buf, gen_opparam_buf); |
| 3833 | flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size)); | 3878 | flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size)); |
| 3834 | - | 3879 | + |
| 3835 | *gen_code_size_ptr = gen_code_size; | 3880 | *gen_code_size_ptr = gen_code_size; |
| 3836 | - *code_size_ptr = pc_ptr - pc_start; | ||
| 3837 | #ifdef DEBUG_DISAS | 3881 | #ifdef DEBUG_DISAS |
| 3838 | if (loglevel) { | 3882 | if (loglevel) { |
| 3839 | fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); | 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 | fprintf(logfile, "\n"); | 3885 | fprintf(logfile, "\n"); |
| 3842 | fflush(logfile); | 3886 | fflush(logfile); |
| 3843 | } | 3887 | } |
| @@ -3845,6 +3889,50 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | @@ -3845,6 +3889,50 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | ||
| 3845 | return 0; | 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 | CPUX86State *cpu_x86_init(void) | 3936 | CPUX86State *cpu_x86_init(void) |
| 3849 | { | 3937 | { |
| 3850 | CPUX86State *env; | 3938 | CPUX86State *env; |