📄 tb.c
字号:
#include "armdefs.h"
//teawater 2005-09-12 for gcc-3.3.x compiling, comment below line
//#include "arm2x86_self.h"
extern mem_bank_t *bank_ptr(ARMword addr);
/*ywc 2005-04-22, in armmem.c*/
extern mem_bank_t *insn_bank_ptr(ARMword addr);
//teawater add for new tb manage function 2005.07.10----------------------------
//static uint32_t tb_tbt_size = 0;
//static uint32_t tb_tbp_size = (1024 * 1024 * 32);
#define TB_TBT_SIZE skyeye_config.tb_tbt_size
#define TB_TBP_SIZE skyeye_config.tb_tbp_size
static tb_t *tbt_table = NULL;
static int tbt_table_size = 0;
static uint8_t *tbp_begin = NULL;
static uint8_t *tbp_now = NULL;
static uint32_t tbp_now_size = 0;
static int tbp_dynamic = 0;
static LIST_HEAD(tbp_dynamic_list);
//AJ2D--------------------------------------------------------------------------
#ifdef __FreeBSD__
#define MAP_ANONYMOUS MAP_ANON
#endif
static __inline__ int
translate_word(ARMul_State *state, ARMword insn, uint8_t *tbp)
{
int toplen = 0, len = 0;
ARMword cond, val, op1, shift, rm, rs, rn, rd, sh;
uint8_t *begin = tbp;
//init
begin = tbp;
state->trap = 0;
//teawater change for debug function 2005.07.09---------------------------------
//breakpoint
if (insn == 0xe7ffdefe) {
GEN_OP(tbp, len, op_begin);
gen_op_movl_trap_im_use_T2(state, &tbp, &len, TRAP_BREAKPOINT);
GEN_OP(tbp, len, op_return);
goto out;
}
//AJ2D--------------------------------------------------------------------------
//return if debug || irq || fiq || condition
cond = (insn >> 28) & 0xff;
if (cond == AL || cond == NV) {
GEN_OP(tbp, len, op_begin);
//some insn need it
//if (cond == NV)
// goto translate_word_out;
}
else {
gen_op_movl_Tx_im(state, &tbp, &len, 0, cond);
GEN_OP(tbp, len, op_begin_test_T0);
toplen = len;
}
if (((insn & 0x0e000000) == 0 && (insn & 0x00000090) != 0x90) || ((insn & 0x0e000000) == (1 << 25))) {
ARMword set_cc, logic_cc, shiftop;
if (cond == NV)
goto translate_word_out;
op1 = (insn >> 21) & 0xf;
set_cc = (insn >> 20) & 1;
if ((op1 == 0x8 || op1 == 0xa) && !set_cc) {
//mrs
gen_op_mrs(state, &tbp, &len, insn);
goto translate_word_end;
}
logic_cc = table_logic_cc[op1] & set_cc;
//in arm_arm A 5.1
if (insn & (1 << 25)) {
//immediate operand arm_arm A 5.1.3
val = insn & 0xff;
shift = (uint8_t)((insn >> 8) & 0xf) * 2;
//ror
if (shift)
val = (val >> shift) | (val << (32 - shift));
//op=set val to t1
gen_op_movl_Tx_im(state, &tbp, &len, 1, val);
if (logic_cc && shift) {
//val = ((insn & 0xff) >> (shift - 1)) & 1;
//op=set val[31] to C
if (val >> 31) {
GEN_OP(tbp, len, op_logic_1_sc);
}
else {
GEN_OP(tbp, len, op_logic_0_sc);
}
}
}
else {
//register
rm = (insn) & 0xf;
//op=set rm(0-15) to t1
gen_op_movl_Tx_reg(state, &tbp, &len, 1, rm);
//teawater add check thumb 2005.07.21-------------------------------------------
if (op1 == 0x9 && !set_cc && ((insn >> 8) & 0xf) == 0xf) {
//bx or blx(2)
uint32_t tmp = (insn >> 4) & 0xf;
if (tmp == 0x1) {
//bx
GEN_OP(tbp, len, op_bx_T1);
}
else if (tmp == 0x2){
//blx(2)
GEN_OP(tbp, len, op_blx_T1);
}
if (tmp == 0x1 || tmp == 0x2) {
state->trap = 1;
goto translate_word_end;
}
}
//AJ2D--------------------------------------------------------------------------
shiftop = (insn >> 5) & 3;
if (!(insn & (1 << 4))) {
//imm
shift = (uint8_t)(insn >> 7) & 0x1f;
if (shift != 0) {
//op=shift, & set CF if logic_cc
if (logic_cc) {
gen_op_shift_T1_im_sc(state, &tbp, &len, shiftop, shift);
}
gen_op_shift_T1_im(state, &tbp, &len, shiftop, shift);
}
else {
GEN_OP(tbp, len, op_movl_T2_T1);
GEN_OP(tbp, len, op_shift_T1_0[shiftop]);
if (logic_cc) {
GEN_OP(tbp, len, op_shift_T2_0_sc[shiftop]);
GEN_OP(tbp, len, op_set_cf);
}
}
}
else {
//reg
rs = (insn >> 8) & 0xf;
//op=set rs(0-15) to t0
gen_op_movl_Tx_reg(state, &tbp, &len, 0, rs);
//op=shift, & set CF if logic_cc
if (logic_cc) {
//op=shift & set CF
gen_op_shift_T1_T0_sc(state, &tbp, &len, shiftop);
}
else {
//op=shift
gen_op_shift_T1_T0(state, &tbp, &len, shiftop);
}
}
}
if ((op1 == 0x9 || op1 == 0xb) && !set_cc) {
//msr T1, psr
gen_op_msr(state, &tbp, &len, insn);
goto translate_word_end;
}
//data processing instruction
if (op1 != 0x0f && op1 != 0x0d) { //!mov && !mvn
rn = (insn >> 16) & 0xf;
//op=set rn(0-15) to t0
gen_op_movl_Tx_reg(state, &tbp, &len, 0, rn);
}
rd = (insn >> 12) & 0xf;
arm2x86_get_dp_op[op1](state, &tbp, &len, set_cc, rd);
arm2x86_get_dp_op_setcpsr[op1](state, &tbp, &len, set_cc, rd);
}
else {
//other instructions
op1 = (insn >> 24) & 0xf;
sh = (insn >> 5) & 3;
if (cond == NV) {
if (state->is_v5 && sh >= 12 && sh <= 14) {
//cdp2 ldc2 stc2 mrc2 mcr2 in arm_arm A 4.1.11
}
//teawater add check thumb 2005.07.21-------------------------------------------
else if (state->is_v5 && (op1 == 0xa || op1 == 0xb)) {
//blx(1)
gen_op_movl_trap_im_use_T2(state, &tbp, &len, TRAP_UNPREDICTABLE);
GEN_OP(tbp, len, op_return);
goto out;
}
//AJ2D--------------------------------------------------------------------------
else {
goto translate_word_out;
}
}
if (sh != 0 && (op1 == 0 || op1 == 1)) {
//ldrh strh ldrsh ldrsb
gen_op_ldrhstrh(state, &tbp, &len, insn, sh);
}
else {
arm2x86_get_other_op[op1](state, insn, &tbp, &len);
}
}
translate_word_end:
if (state->trap) {
GEN_OP(tbp, len, op_return);
}
if (toplen && begin) {
//set jmp length of condition code
//begin[toplen-1] = (uint8_t)(len - toplen);
int *p_tmp = (int *)(begin + (toplen - sizeof(int)));
*p_tmp = len - toplen;
}
translate_word_out:
//r15 += 4
if (!state->trap || toplen) {
GEN_OP(tbp, len, op_addpc);
state->trap = 0;
}
//TEA_OUT(GEN_OP(tbp, len, op_return));
out:
if (len > TB_INSN_LEN_MAX) {
fprintf(stderr, "SKYEYE: TB_INSN_LEN_MAX: insn %x len %d > TB_INSN_LEN_MAX %d.\n", insn, len, TB_INSN_LEN_MAX);
exit(-1);
}
/*#ifdef TEA_DEBUG
{
static int insn_max = 0;
if (len > insn_max) {
insn_max = len;
fprintf(stderr, "\nSKYEYE: insn_max = %d.\n", insn_max);
}
}
#endif //TEA_DEBUG*/
return(len);
}
static uint8_t *
tb_translate(ARMul_State * state, ARMword *addr, ARMword *tb_begin_addr, uint8_t *tbp, ARMword *tran_addr, uint8_t **tbp_now)
{
int len;
uint8_t *ret = NULL;
ARMword *tb_end_addr = tb_begin_addr + (TB_LEN - (*tran_addr - TB_ALIGN(*tran_addr))) / sizeof(ARMword);
for( ; tb_begin_addr < tb_end_addr; tb_begin_addr++) {
if (addr == tb_begin_addr) {
ret = tbp;
}
len = translate_word(state, *tb_begin_addr, tbp);
tbp += len;
//teawater change for if trap translate stop 2005.07.23-------------------------
*tran_addr += 4;
if (state->trap && ret) {
break;
}
//AJ2D--------------------------------------------------------------------------
}
//teawater change for if trap translate stop 2005.07.23-------------------------
*tbp_now = tbp;
if (!state->trap) {
GEN_OP(tbp, len, op_return);
}
//AJ2D--------------------------------------------------------------------------
return(ret);
}
static uint8_t *
tb_translate_find(ARMul_State * state, ARMword *addr, ARMword *tb_begin_addr, uint8_t *tbp)
{
int len;
uint8_t *ret = NULL;
ARMword *tb_end_addr = tb_begin_addr + TB_LEN / sizeof(ARMword);
for( ; tb_begin_addr < tb_end_addr; tb_begin_addr++) {
if (addr == tb_begin_addr) {
ret = tbp;
break;
}
len = translate_word(state, *tb_begin_addr, NULL);
tbp += len;
}
return(ret);
}
static inline void
tb_insert_cache(tb_t *tbt, ARMword addr, uint8_t *ret)
{
tb_cache_t *e = malloc(sizeof(tb_cache_t));
if (e) {
uint32_t cache_num = addr & (TB_TBT_CACHE_MAX - 1);
if (!tbt->cache[cache_num].next)
INIT_LIST_HEAD(&tbt->cache[cache_num]);
e->addr = addr;
e->tp = ret;
list_add_tail(&e->list, &tbt->cache[cache_num]);
}
else {
TEA_OUT(fprintf(stderr, "SKYEYE: tb_find: Error allocating mem for cache.\n"));
}
}
static inline uint8_t *
tb_find_cache(tb_t *tbt, ARMword addr)
{
tb_cache_t *e;
struct list_head *list,*n;
uint32_t cache_num = addr & (TB_TBT_CACHE_MAX - 1);
if (tbt->cache[cache_num].next) {
list_for_each_safe(list, n, &tbt->cache[cache_num]) {
e = list_entry(list, tb_cache_t, list);
if (e->addr == addr) {
return(e->tp);
}
}
}
return(NULL);
}
static inline void
tb_clear_cache(tb_t *tbt)
{
tb_cache_t *e;
struct list_head *list,*n;
uint32_t cache_num;
for(cache_num = 0; cache_num < TB_TBT_CACHE_MAX; cache_num++) {
if (tbt->cache[cache_num].next) {
list_for_each_safe(list, n, &tbt->cache[cache_num]) {
e = list_entry(list, tb_cache_t, list);
list_del_init(&e->list);
free(e);
}
}
}
}
static inline void
tb_get_tbp(tb_t *tbt)
{
tb_t *e;
struct list_head *list;
if (tbp_now_size) {
tbt->tbp = tbp_now;
tbp_now += TB_TBP_MAX;
tbp_now_size -= TB_TBP_MAX;
}
else {
//get the oldest tbt from tbp_dynamic_list's head
if (list_empty(&tbp_dynamic_list)) {
fprintf(stderr, "SKYEYE: mem_reset: some bug.\n");
exit(-1);
}
e = list_entry(tbp_dynamic_list.next, tb_t, list);
tbt->tbp = e->tbp;
e->tbp = NULL;
if (e->ted) {
tb_clear_cache(e);
e->ted = 0;
}
list_del_init(&e->list);
}
}
static inline mem_bank_t *
tb_get_mbp(ARMword addr, int *bank_num)
{
mem_bank_t *ret;
ret = insn_bank_ptr(addr);
if(ret) {
*bank_num = ret - skyeye_config.mem.mem_banks;
}
return(ret);
}
uint8_t *
tb_find(ARMul_State * state, ARMword ADDR)
{
uint8_t *ret = NULL;
ARMword addr, align_addr;
ARMword *real_begin_addr, *real_addr;
static ARMword save_align_addr = 0x1;
static tb_t *tbt;
static uint8_t *tbp;
static mem_bank_t *mbp;
static int bank_num = -1;
//get addr & align_addr
if (mmu_v2p_dbct(state,ADDR,&addr)) {
goto out;
}
align_addr = TB_ALIGN(addr);
if (align_addr == save_align_addr) {
goto get_ret;
}
//init
bank_num = -1;
save_align_addr = 0x1;
//get tbt
if (tbt_table_size) {
//dynamic tbt
tbt = &(tbt_table[align_addr & (uint32_t)(tbt_table_size - 1)]);
if (tbt->addr != align_addr) {
if (tbt->ted) {
tb_clear_cache(tbt);
tbt->ted = 0;
}
tbt->addr = align_addr;
}
//get tbt->tbp
if (!tbt->tbp) {
tb_get_tbp(tbt);
}
else {
if (tbp_dynamic) {
list_del_init(&tbt->list);
}
}
}
else {
//static tbt
mbp = tb_get_mbp(align_addr, &bank_num);
if(!mbp) {
goto out;
}
if (!state->mem.tbt[bank_num]) {
if (!tbp_dynamic) {
state->mem.tbp[bank_num] = mmap(NULL, state->mem.rom_size[bank_num] / sizeof(ARMword) * TB_INSN_LEN_MAX + state->mem.rom_size[bank_num] / TB_LEN * op_return.len, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (state->mem.tbp[bank_num] == MAP_FAILED) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -