31 |
|
|
32 |
#define IN_OP_I386 |
#define IN_OP_I386 |
33 |
#include "cpu-i386.h" |
#include "cpu-i386.h" |
34 |
|
#include "exec.h" |
35 |
|
|
36 |
/* XXX: move that elsewhere */ |
/* XXX: move that elsewhere */ |
37 |
static uint16_t *gen_opc_ptr; |
static uint16_t *gen_opc_ptr; |
38 |
static uint32_t *gen_opparam_ptr; |
static uint32_t *gen_opparam_ptr; |
39 |
int __op_param1, __op_param2, __op_param3; |
int __op_param1, __op_param2, __op_param3; |
40 |
|
#ifdef USE_DIRECT_JUMP |
41 |
|
int __op_jmp0, __op_jmp1; |
42 |
|
#endif |
43 |
|
|
44 |
#ifdef __i386__ |
#ifdef __i386__ |
45 |
static inline void flush_icache_range(unsigned long start, unsigned long stop) |
static inline void flush_icache_range(unsigned long start, unsigned long stop) |
71 |
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); |
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); |
72 |
|
|
73 |
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { |
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { |
74 |
asm ("dcbst 0,%0;" : : "r"(p) : "memory"); |
asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); |
75 |
} |
} |
76 |
asm ("sync"); |
asm volatile ("sync" : : : "memory"); |
77 |
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { |
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) { |
78 |
asm ("icbi 0,%0; sync;" : : "r"(p) : "memory"); |
asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); |
79 |
} |
} |
80 |
asm ("sync"); |
asm volatile ("sync" : : : "memory"); |
81 |
asm ("isync"); |
asm volatile ("isync" : : : "memory"); |
82 |
} |
} |
83 |
#endif |
#endif |
84 |
|
|
133 |
int cpl; |
int cpl; |
134 |
int iopl; |
int iopl; |
135 |
int tf; /* TF cpu flag */ |
int tf; /* TF cpu flag */ |
136 |
|
TranslationBlock *tb; |
137 |
} DisasContext; |
} DisasContext; |
138 |
|
|
139 |
/* i386 arith/logic operations */ |
/* i386 arith/logic operations */ |
197 |
typedef void (GenOpFunc)(void); |
typedef void (GenOpFunc)(void); |
198 |
typedef void (GenOpFunc1)(long); |
typedef void (GenOpFunc1)(long); |
199 |
typedef void (GenOpFunc2)(long, long); |
typedef void (GenOpFunc2)(long, long); |
200 |
|
typedef void (GenOpFunc3)(long, long, long); |
201 |
|
|
202 |
static GenOpFunc *gen_op_mov_reg_T0[3][8] = { |
static GenOpFunc *gen_op_mov_reg_T0[3][8] = { |
203 |
[OT_BYTE] = { |
[OT_BYTE] = { |
705 |
JCC_LE, |
JCC_LE, |
706 |
}; |
}; |
707 |
|
|
708 |
static GenOpFunc2 *gen_jcc_slow[8] = { |
static GenOpFunc3 *gen_jcc_sub[3][8] = { |
|
gen_op_jo_cc, |
|
|
gen_op_jb_cc, |
|
|
gen_op_jz_cc, |
|
|
gen_op_jbe_cc, |
|
|
gen_op_js_cc, |
|
|
gen_op_jp_cc, |
|
|
gen_op_jl_cc, |
|
|
gen_op_jle_cc, |
|
|
}; |
|
|
|
|
|
static GenOpFunc2 *gen_jcc_sub[3][8] = { |
|
709 |
[OT_BYTE] = { |
[OT_BYTE] = { |
710 |
NULL, |
NULL, |
711 |
gen_op_jb_subb, |
gen_op_jb_subb, |
1085 |
|
|
1086 |
static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) |
static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) |
1087 |
{ |
{ |
1088 |
|
TranslationBlock *tb; |
1089 |
int inv, jcc_op; |
int inv, jcc_op; |
1090 |
GenOpFunc2 *func; |
GenOpFunc3 *func; |
1091 |
|
|
1092 |
inv = b & 1; |
inv = b & 1; |
1093 |
jcc_op = (b >> 1) & 7; |
jcc_op = (b >> 1) & 7; |
1097 |
case CC_OP_SUBW: |
case CC_OP_SUBW: |
1098 |
case CC_OP_SUBL: |
case CC_OP_SUBL: |
1099 |
func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; |
func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; |
|
if (!func) |
|
|
goto slow_jcc; |
|
1100 |
break; |
break; |
1101 |
|
|
1102 |
/* some jumps are easy to compute */ |
/* some jumps are easy to compute */ |
1132 |
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; |
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; |
1133 |
break; |
break; |
1134 |
default: |
default: |
1135 |
goto slow_jcc; |
func = NULL; |
1136 |
|
break; |
1137 |
} |
} |
1138 |
break; |
break; |
1139 |
default: |
default: |
1140 |
slow_jcc: |
func = NULL; |
|
if (s->cc_op != CC_OP_DYNAMIC) |
|
|
gen_op_set_cc_op(s->cc_op); |
|
|
func = gen_jcc_slow[jcc_op]; |
|
1141 |
break; |
break; |
1142 |
} |
} |
1143 |
|
|
1144 |
|
if (s->cc_op != CC_OP_DYNAMIC) |
1145 |
|
gen_op_set_cc_op(s->cc_op); |
1146 |
|
|
1147 |
|
if (!func) { |
1148 |
|
gen_setcc_slow[jcc_op](); |
1149 |
|
func = gen_op_jcc; |
1150 |
|
} |
1151 |
|
|
1152 |
|
tb = s->tb; |
1153 |
if (!inv) { |
if (!inv) { |
1154 |
func(val, next_eip); |
func((long)tb, val, next_eip); |
1155 |
} else { |
} else { |
1156 |
func(next_eip, val); |
func((long)tb, next_eip, val); |
1157 |
} |
} |
1158 |
|
s->is_jmp = 3; |
1159 |
} |
} |
1160 |
|
|
1161 |
static void gen_setcc(DisasContext *s, int b) |
static void gen_setcc(DisasContext *s, int b) |
1375 |
s->is_jmp = 1; |
s->is_jmp = 1; |
1376 |
} |
} |
1377 |
|
|
1378 |
|
/* generate a jump to eip. No segment change must happen before as a |
1379 |
|
direct call to the next block may occur */ |
1380 |
|
static void gen_jmp(DisasContext *s, unsigned int eip) |
1381 |
|
{ |
1382 |
|
TranslationBlock *tb = s->tb; |
1383 |
|
|
1384 |
|
if (s->cc_op != CC_OP_DYNAMIC) |
1385 |
|
gen_op_set_cc_op(s->cc_op); |
1386 |
|
gen_op_jmp_tb_next((long)tb, eip); |
1387 |
|
s->is_jmp = 3; |
1388 |
|
} |
1389 |
|
|
1390 |
/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr |
/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr |
1391 |
is set to true if the instruction sets the PC (last instruction of |
is set to true if the instruction sets the PC (last instruction of |
1392 |
a basic block) */ |
a basic block) */ |
2979 |
val &= 0xffff; |
val &= 0xffff; |
2980 |
gen_op_movl_T0_im(next_eip); |
gen_op_movl_T0_im(next_eip); |
2981 |
gen_push_T0(s); |
gen_push_T0(s); |
2982 |
gen_op_jmp_im(val); |
gen_jmp(s, val); |
|
s->is_jmp = 1; |
|
2983 |
} |
} |
2984 |
break; |
break; |
2985 |
case 0x9a: /* lcall im */ |
case 0x9a: /* lcall im */ |
3010 |
val += s->pc - s->cs_base; |
val += s->pc - s->cs_base; |
3011 |
if (s->dflag == 0) |
if (s->dflag == 0) |
3012 |
val = val & 0xffff; |
val = val & 0xffff; |
3013 |
gen_op_jmp_im(val); |
gen_jmp(s, val); |
|
s->is_jmp = 1; |
|
3014 |
break; |
break; |
3015 |
case 0xea: /* ljmp im */ |
case 0xea: /* ljmp im */ |
3016 |
{ |
{ |
3032 |
val += s->pc - s->cs_base; |
val += s->pc - s->cs_base; |
3033 |
if (s->dflag == 0) |
if (s->dflag == 0) |
3034 |
val = val & 0xffff; |
val = val & 0xffff; |
3035 |
gen_op_jmp_im(val); |
gen_jmp(s, val); |
|
s->is_jmp = 1; |
|
3036 |
break; |
break; |
3037 |
case 0x70 ... 0x7f: /* jcc Jb */ |
case 0x70 ... 0x7f: /* jcc Jb */ |
3038 |
val = (int8_t)insn_get(s, OT_BYTE); |
val = (int8_t)insn_get(s, OT_BYTE); |
3049 |
if (s->dflag == 0) |
if (s->dflag == 0) |
3050 |
val &= 0xffff; |
val &= 0xffff; |
3051 |
gen_jcc(s, b, val, next_eip); |
gen_jcc(s, b, val, next_eip); |
|
s->is_jmp = 1; |
|
3052 |
break; |
break; |
3053 |
|
|
3054 |
case 0x190 ... 0x19f: /* setcc Gv */ |
case 0x190 ... 0x19f: /* setcc Gv */ |
3404 |
|
|
3405 |
[INDEX_op_into] = CC_O, |
[INDEX_op_into] = CC_O, |
3406 |
|
|
|
[INDEX_op_jo_cc] = CC_O, |
|
|
[INDEX_op_jb_cc] = CC_C, |
|
|
[INDEX_op_jz_cc] = CC_Z, |
|
|
[INDEX_op_jbe_cc] = CC_Z | CC_C, |
|
|
[INDEX_op_js_cc] = CC_S, |
|
|
[INDEX_op_jp_cc] = CC_P, |
|
|
[INDEX_op_jl_cc] = CC_O | CC_S, |
|
|
[INDEX_op_jle_cc] = CC_O | CC_S | CC_Z, |
|
|
|
|
3407 |
[INDEX_op_jb_subb] = CC_C, |
[INDEX_op_jb_subb] = CC_C, |
3408 |
[INDEX_op_jb_subw] = CC_C, |
[INDEX_op_jb_subw] = CC_C, |
3409 |
[INDEX_op_jb_subl] = CC_C, |
[INDEX_op_jb_subl] = CC_C, |
3732 |
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, |
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, |
3733 |
int *gen_code_size_ptr, |
int *gen_code_size_ptr, |
3734 |
uint8_t *pc_start, uint8_t *cs_base, int flags, |
uint8_t *pc_start, uint8_t *cs_base, int flags, |
3735 |
int *code_size_ptr) |
int *code_size_ptr, TranslationBlock *tb) |
3736 |
{ |
{ |
3737 |
DisasContext dc1, *dc = &dc1; |
DisasContext dc1, *dc = &dc1; |
3738 |
uint8_t *pc_ptr; |
uint8_t *pc_ptr; |
3752 |
dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1; |
dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1; |
3753 |
dc->cc_op = CC_OP_DYNAMIC; |
dc->cc_op = CC_OP_DYNAMIC; |
3754 |
dc->cs_base = cs_base; |
dc->cs_base = cs_base; |
3755 |
|
dc->tb = tb; |
3756 |
|
|
3757 |
gen_opc_ptr = gen_opc_buf; |
gen_opc_ptr = gen_opc_buf; |
3758 |
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
3779 |
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && |
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && |
3780 |
(pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32)); |
(pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32)); |
3781 |
/* we must store the eflags state if it is not already done */ |
/* we must store the eflags state if it is not already done */ |
3782 |
if (dc->cc_op != CC_OP_DYNAMIC) |
if (dc->is_jmp != 3) { |
3783 |
gen_op_set_cc_op(dc->cc_op); |
if (dc->cc_op != CC_OP_DYNAMIC) |
3784 |
if (dc->is_jmp != 1) { |
gen_op_set_cc_op(dc->cc_op); |
3785 |
/* we add an additionnal jmp to update the simulated PC */ |
if (dc->is_jmp != 1) { |
3786 |
gen_op_jmp_im(ret - (unsigned long)dc->cs_base); |
/* we add an additionnal jmp to update the simulated PC */ |
3787 |
|
gen_op_jmp_im(ret - (unsigned long)dc->cs_base); |
3788 |
|
} |
3789 |
} |
} |
3790 |
if (dc->tf) { |
if (dc->tf) { |
3791 |
gen_op_raise_exception(EXCP01_SSTP); |
gen_op_raise_exception(EXCP01_SSTP); |
3792 |
} |
} |
3793 |
|
if (dc->is_jmp != 3) { |
3794 |
|
/* indicate that the hash table must be used to find the next TB */ |
3795 |
|
gen_op_movl_T0_0(); |
3796 |
|
} |
3797 |
|
|
3798 |
*gen_opc_ptr = INDEX_op_end; |
*gen_opc_ptr = INDEX_op_end; |
3799 |
|
|
3823 |
#endif |
#endif |
3824 |
|
|
3825 |
/* generate machine code */ |
/* generate machine code */ |
3826 |
gen_code_size = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf); |
tb->tb_next_offset[0] = 0xffff; |
3827 |
|
tb->tb_next_offset[1] = 0xffff; |
3828 |
|
gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset, |
3829 |
|
#ifdef USE_DIRECT_JUMP |
3830 |
|
tb->tb_jmp_offset, |
3831 |
|
#else |
3832 |
|
NULL, |
3833 |
|
#endif |
3834 |
|
gen_opc_buf, gen_opparam_buf); |
3835 |
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)); |
3836 |
|
|
3837 |
*gen_code_size_ptr = gen_code_size; |
*gen_code_size_ptr = gen_code_size; |
3838 |
*code_size_ptr = pc_ptr - pc_start; |
*code_size_ptr = pc_ptr - pc_start; |
3839 |
#ifdef DEBUG_DISAS |
#ifdef DEBUG_DISAS |