160 |
}; |
}; |
161 |
|
|
162 |
enum { |
enum { |
163 |
#define DEF(s, n) INDEX_op_ ## s, |
#define DEF(s, n, copy_size) INDEX_op_ ## s, |
164 |
#include "opc-i386.h" |
#include "opc-i386.h" |
165 |
#undef DEF |
#undef DEF |
166 |
NB_OPS, |
NB_OPS, |
1215 |
} |
} |
1216 |
|
|
1217 |
/* move T0 to seg_reg and compute if the CPU state may change */ |
/* 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) |
static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) |
1219 |
{ |
{ |
1220 |
gen_op_movl_seg_T0(seg_reg); |
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)); |
1225 |
if (!s->addseg && seg_reg < R_FS) |
if (!s->addseg && seg_reg < R_FS) |
1226 |
s->is_jmp = 2; /* abort translation because the register may |
s->is_jmp = 2; /* abort translation because the register may |
1227 |
have a non zero base */ |
have a non zero base */ |
1378 |
s->is_jmp = 1; |
s->is_jmp = 1; |
1379 |
} |
} |
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 |
|
|
1393 |
/* generate a jump to eip. No segment change must happen before as a |
/* generate a jump to eip. No segment change must happen before as a |
1394 |
direct call to the next block may occur */ |
direct call to the next block may occur */ |
1395 |
static void gen_jmp(DisasContext *s, unsigned int eip) |
static void gen_jmp(DisasContext *s, unsigned int eip) |
1666 |
case 6: /* div */ |
case 6: /* div */ |
1667 |
switch(ot) { |
switch(ot) { |
1668 |
case OT_BYTE: |
case OT_BYTE: |
1669 |
gen_op_divb_AL_T0(); |
gen_op_divb_AL_T0(pc_start - s->cs_base); |
1670 |
break; |
break; |
1671 |
case OT_WORD: |
case OT_WORD: |
1672 |
gen_op_divw_AX_T0(); |
gen_op_divw_AX_T0(pc_start - s->cs_base); |
1673 |
break; |
break; |
1674 |
default: |
default: |
1675 |
case OT_LONG: |
case OT_LONG: |
1676 |
gen_op_divl_EAX_T0(); |
gen_op_divl_EAX_T0(pc_start - s->cs_base); |
1677 |
break; |
break; |
1678 |
} |
} |
1679 |
break; |
break; |
1680 |
case 7: /* idiv */ |
case 7: /* idiv */ |
1681 |
switch(ot) { |
switch(ot) { |
1682 |
case OT_BYTE: |
case OT_BYTE: |
1683 |
gen_op_idivb_AL_T0(); |
gen_op_idivb_AL_T0(pc_start - s->cs_base); |
1684 |
break; |
break; |
1685 |
case OT_WORD: |
case OT_WORD: |
1686 |
gen_op_idivw_AX_T0(); |
gen_op_idivw_AX_T0(pc_start - s->cs_base); |
1687 |
break; |
break; |
1688 |
default: |
default: |
1689 |
case OT_LONG: |
case OT_LONG: |
1690 |
gen_op_idivl_EAX_T0(); |
gen_op_idivl_EAX_T0(pc_start - s->cs_base); |
1691 |
break; |
break; |
1692 |
} |
} |
1693 |
break; |
break; |
1754 |
gen_op_ld_T1_A0[ot](); |
gen_op_ld_T1_A0[ot](); |
1755 |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
1756 |
gen_op_lduw_T0_A0(); |
gen_op_lduw_T0_A0(); |
1757 |
gen_movl_seg_T0(s, R_CS); |
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
1758 |
gen_op_movl_T0_T1(); |
gen_op_movl_T0_T1(); |
1759 |
gen_op_jmp_T0(); |
gen_op_jmp_T0(); |
1760 |
s->is_jmp = 1; |
s->is_jmp = 1; |
1769 |
gen_op_ld_T1_A0[ot](); |
gen_op_ld_T1_A0[ot](); |
1770 |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
1771 |
gen_op_lduw_T0_A0(); |
gen_op_lduw_T0_A0(); |
1772 |
gen_movl_seg_T0(s, R_CS); |
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
1773 |
gen_op_movl_T0_T1(); |
gen_op_movl_T0_T1(); |
1774 |
gen_op_jmp_T0(); |
gen_op_jmp_T0(); |
1775 |
s->is_jmp = 1; |
s->is_jmp = 1; |
1986 |
case 0x17: /* pop ss */ |
case 0x17: /* pop ss */ |
1987 |
case 0x1f: /* pop ds */ |
case 0x1f: /* pop ds */ |
1988 |
gen_pop_T0(s); |
gen_pop_T0(s); |
1989 |
gen_movl_seg_T0(s, b >> 3); |
gen_movl_seg_T0(s, b >> 3, pc_start - s->cs_base); |
1990 |
gen_pop_update(s); |
gen_pop_update(s); |
1991 |
break; |
break; |
1992 |
case 0x1a1: /* pop fs */ |
case 0x1a1: /* pop fs */ |
1993 |
case 0x1a9: /* pop gs */ |
case 0x1a9: /* pop gs */ |
1994 |
gen_pop_T0(s); |
gen_pop_T0(s); |
1995 |
gen_movl_seg_T0(s, (b >> 3) & 7); |
gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base); |
1996 |
gen_pop_update(s); |
gen_pop_update(s); |
1997 |
break; |
break; |
1998 |
|
|
2046 |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); |
2047 |
if (reg >= 6 || reg == R_CS) |
if (reg >= 6 || reg == R_CS) |
2048 |
goto illegal_op; |
goto illegal_op; |
2049 |
gen_movl_seg_T0(s, reg); |
gen_movl_seg_T0(s, reg, pc_start - s->cs_base); |
2050 |
break; |
break; |
2051 |
case 0x8c: /* mov Gv, seg */ |
case 0x8c: /* mov Gv, seg */ |
2052 |
ot = dflag ? OT_LONG : OT_WORD; |
ot = dflag ? OT_LONG : OT_WORD; |
2247 |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
2248 |
/* load the segment first to handle exceptions properly */ |
/* load the segment first to handle exceptions properly */ |
2249 |
gen_op_lduw_T0_A0(); |
gen_op_lduw_T0_A0(); |
2250 |
gen_movl_seg_T0(s, op); |
gen_movl_seg_T0(s, op, pc_start - s->cs_base); |
2251 |
/* then put the data */ |
/* then put the data */ |
2252 |
gen_op_mov_reg_T1[ot][reg](); |
gen_op_mov_reg_T1[ot][reg](); |
2253 |
break; |
break; |
2930 |
gen_pop_update(s); |
gen_pop_update(s); |
2931 |
/* pop selector */ |
/* pop selector */ |
2932 |
gen_pop_T0(s); |
gen_pop_T0(s); |
2933 |
gen_movl_seg_T0(s, R_CS); |
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
2934 |
gen_pop_update(s); |
gen_pop_update(s); |
2935 |
/* add stack offset */ |
/* add stack offset */ |
2936 |
if (s->ss32) |
if (s->ss32) |
2949 |
gen_pop_update(s); |
gen_pop_update(s); |
2950 |
/* pop selector */ |
/* pop selector */ |
2951 |
gen_pop_T0(s); |
gen_pop_T0(s); |
2952 |
gen_movl_seg_T0(s, R_CS); |
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
2953 |
gen_pop_update(s); |
gen_pop_update(s); |
2954 |
s->is_jmp = 1; |
s->is_jmp = 1; |
2955 |
break; |
break; |
2966 |
gen_pop_update(s); |
gen_pop_update(s); |
2967 |
/* pop selector */ |
/* pop selector */ |
2968 |
gen_pop_T0(s); |
gen_pop_T0(s); |
2969 |
gen_movl_seg_T0(s, R_CS); |
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
2970 |
gen_pop_update(s); |
gen_pop_update(s); |
2971 |
/* pop eflags */ |
/* pop eflags */ |
2972 |
gen_pop_T0(s); |
gen_pop_T0(s); |
3011 |
|
|
3012 |
/* change cs and pc */ |
/* change cs and pc */ |
3013 |
gen_op_movl_T0_im(selector); |
gen_op_movl_T0_im(selector); |
3014 |
gen_movl_seg_T0(s, R_CS); |
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
3015 |
gen_op_jmp_im((unsigned long)offset); |
gen_op_jmp_im((unsigned long)offset); |
3016 |
s->is_jmp = 1; |
s->is_jmp = 1; |
3017 |
} |
} |
3034 |
|
|
3035 |
/* change cs and pc */ |
/* change cs and pc */ |
3036 |
gen_op_movl_T0_im(selector); |
gen_op_movl_T0_im(selector); |
3037 |
gen_movl_seg_T0(s, R_CS); |
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
3038 |
gen_op_jmp_im((unsigned long)offset); |
gen_op_jmp_im((unsigned long)offset); |
3039 |
s->is_jmp = 1; |
s->is_jmp = 1; |
3040 |
} |
} |
3271 |
case 0x9b: /* fwait */ |
case 0x9b: /* fwait */ |
3272 |
break; |
break; |
3273 |
case 0xcc: /* int3 */ |
case 0xcc: /* int3 */ |
3274 |
gen_exception(s, EXCP03_INT3, s->pc - s->cs_base); |
gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base); |
3275 |
break; |
break; |
3276 |
case 0xcd: /* int N */ |
case 0xcd: /* int N */ |
3277 |
val = ldub(s->pc++); |
val = ldub(s->pc++); |
3278 |
if (s->cc_op != CC_OP_DYNAMIC) |
/* XXX: add error code for vm86 GPF */ |
3279 |
gen_op_set_cc_op(s->cc_op); |
if (!s->vm86) |
3280 |
gen_op_int_im(val, pc_start - s->cs_base); |
gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); |
3281 |
s->is_jmp = 1; |
else |
3282 |
|
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3283 |
break; |
break; |
3284 |
case 0xce: /* into */ |
case 0xce: /* into */ |
3285 |
if (s->cc_op != CC_OP_DYNAMIC) |
if (s->cc_op != CC_OP_DYNAMIC) |
3326 |
gen_op_mov_reg_T0[ot][reg](); |
gen_op_mov_reg_T0[ot][reg](); |
3327 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
3328 |
if (ot == OT_WORD) |
if (ot == OT_WORD) |
3329 |
gen_op_boundw(); |
gen_op_boundw(pc_start - s->cs_base); |
3330 |
else |
else |
3331 |
gen_op_boundl(); |
gen_op_boundl(pc_start - s->cs_base); |
3332 |
break; |
break; |
3333 |
case 0x1c8 ... 0x1cf: /* bswap reg */ |
case 0x1c8 ... 0x1cf: /* bswap reg */ |
3334 |
reg = b & 7; |
reg = b & 7; |
3687 |
|
|
3688 |
#ifdef DEBUG_DISAS |
#ifdef DEBUG_DISAS |
3689 |
static const char *op_str[] = { |
static const char *op_str[] = { |
3690 |
#define DEF(s, n) #s, |
#define DEF(s, n, copy_size) #s, |
3691 |
#include "opc-i386.h" |
#include "opc-i386.h" |
3692 |
#undef DEF |
#undef DEF |
3693 |
}; |
}; |
3694 |
|
|
3695 |
static uint8_t op_nb_args[] = { |
static uint8_t op_nb_args[] = { |
3696 |
#define DEF(s, n) n, |
#define DEF(s, n, copy_size) n, |
3697 |
#include "opc-i386.h" |
#include "opc-i386.h" |
3698 |
#undef DEF |
#undef DEF |
3699 |
}; |
}; |
3723 |
|
|
3724 |
#endif |
#endif |
3725 |
|
|
|
/* XXX: make this buffer thread safe */ |
|
3726 |
/* XXX: make safe guess about sizes */ |
/* XXX: make safe guess about sizes */ |
3727 |
#define MAX_OP_PER_INSTR 32 |
#define MAX_OP_PER_INSTR 32 |
3728 |
#define OPC_BUF_SIZE 512 |
#define OPC_BUF_SIZE 512 |
3732 |
|
|
3733 |
static uint16_t gen_opc_buf[OPC_BUF_SIZE]; |
static uint16_t gen_opc_buf[OPC_BUF_SIZE]; |
3734 |
static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE]; |
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]; |
3737 |
|
|
3738 |
/* return non zero if the very first instruction is invalid so that |
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for |
3739 |
the virtual CPU can trigger an exception. |
basic block 'tb'. If search_pc is TRUE, also generate PC |
3740 |
|
information for each intermediate instruction. */ |
3741 |
'*code_size_ptr' contains the target code size including the |
static inline int gen_intermediate_code(TranslationBlock *tb, int search_pc) |
|
instruction which triggered an exception, except in case of invalid |
|
|
illegal opcode. It must never exceed one target page. |
|
|
|
|
|
'*gen_code_size_ptr' contains the size of the generated code (host |
|
|
code). |
|
|
*/ |
|
|
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, |
|
|
int *gen_code_size_ptr, |
|
|
uint8_t *pc_start, uint8_t *cs_base, int flags, |
|
|
int *code_size_ptr, TranslationBlock *tb) |
|
3742 |
{ |
{ |
3743 |
DisasContext dc1, *dc = &dc1; |
DisasContext dc1, *dc = &dc1; |
3744 |
uint8_t *pc_ptr; |
uint8_t *pc_ptr; |
3745 |
uint16_t *gen_opc_end; |
uint16_t *gen_opc_end; |
3746 |
int gen_code_size; |
int flags, j, lj; |
3747 |
long ret; |
long ret; |
3748 |
|
uint8_t *pc_start; |
3749 |
|
uint8_t *cs_base; |
3750 |
|
|
3751 |
/* generate intermediate code */ |
/* generate intermediate code */ |
3752 |
|
pc_start = (uint8_t *)tb->pc; |
3753 |
|
cs_base = (uint8_t *)tb->cs_base; |
3754 |
|
flags = tb->flags; |
3755 |
|
|
3756 |
dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; |
dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; |
3757 |
dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; |
dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; |
3758 |
dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; |
dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; |
3771 |
|
|
3772 |
dc->is_jmp = 0; |
dc->is_jmp = 0; |
3773 |
pc_ptr = pc_start; |
pc_ptr = pc_start; |
3774 |
|
lj = -1; |
3775 |
do { |
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 |
|
} |
3786 |
ret = disas_insn(dc, pc_ptr); |
ret = disas_insn(dc, pc_ptr); |
3787 |
if (ret == -1) { |
if (ret == -1) { |
3788 |
/* we trigger an illegal instruction operation only if it |
/* we trigger an illegal instruction operation only if it |
3843 |
fprintf(logfile, "\n"); |
fprintf(logfile, "\n"); |
3844 |
} |
} |
3845 |
#endif |
#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; |
3866 |
|
|
3867 |
/* generate machine code */ |
/* generate machine code */ |
3868 |
tb->tb_next_offset[0] = 0xffff; |
tb->tb_next_offset[0] = 0xffff; |
3869 |
tb->tb_next_offset[1] = 0xffff; |
tb->tb_next_offset[1] = 0xffff; |
3870 |
|
gen_code_buf = tb->tc_ptr; |
3871 |
gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, |
gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, |
3872 |
#ifdef USE_DIRECT_JUMP |
#ifdef USE_DIRECT_JUMP |
3873 |
tb->tb_jmp_offset, |
tb->tb_jmp_offset, |
3876 |
#endif |
#endif |
3877 |
gen_opc_buf, gen_opparam_buf); |
gen_opc_buf, gen_opparam_buf); |
3878 |
flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size)); |
flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size)); |
3879 |
|
|
3880 |
*gen_code_size_ptr = gen_code_size; |
*gen_code_size_ptr = gen_code_size; |
|
*code_size_ptr = pc_ptr - pc_start; |
|
3881 |
#ifdef DEBUG_DISAS |
#ifdef DEBUG_DISAS |
3882 |
if (loglevel) { |
if (loglevel) { |
3883 |
fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); |
fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr); |
3884 |
disas(logfile, gen_code_buf, *gen_code_size_ptr, DISAS_TARGET); |
disas(logfile, gen_code_buf, *gen_code_size_ptr, DISAS_TARGET); |
3885 |
fprintf(logfile, "\n"); |
fprintf(logfile, "\n"); |
3886 |
fflush(logfile); |
fflush(logfile); |
3887 |
} |
} |
3889 |
return 0; |
return 0; |
3890 |
} |
} |
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 |
|
|
3936 |
CPUX86State *cpu_x86_init(void) |
CPUX86State *cpu_x86_init(void) |
3937 |
{ |
{ |
3938 |
CPUX86State *env; |
CPUX86State *env; |