📄 x86_trans.c
字号:
/* * Cisco 7200 (Predator) simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/mman.h>#include <fcntl.h>#include "x86_trans.h"#include "cp0.h"#include "memory.h"/* Set an IRQ */void mips64_set_irq(cpu_mips_t *cpu,m_uint8_t irq){ m_uint32_t m; m = (1 << (irq + MIPS_CP0_CAUSE_ISHIFT)) & MIPS_CP0_CAUSE_IMASK; atomic_or(&cpu->irq_cause,m);}/* Clear an IRQ */void mips64_clear_irq(cpu_mips_t *cpu,m_uint8_t irq){ m_uint32_t m; m = (1 << (irq + MIPS_CP0_CAUSE_ISHIFT)) & MIPS_CP0_CAUSE_IMASK; atomic_and(&cpu->irq_cause,~m); if (!cpu->irq_cause) cpu->irq_pending = 0;}/* Load a 64 bit immediate value */static inline void mips64_load_imm(insn_block_t *b, u_int hi_reg,u_int lo_reg, m_uint64_t value){ m_uint32_t hi_val = value >> 32; m_uint32_t lo_val = value & 0xffffffff; if (lo_val) x86_mov_reg_imm(b->jit_ptr,lo_reg,lo_val); else x86_alu_reg_reg(b->jit_ptr,X86_XOR,lo_reg,lo_reg); if (hi_val) x86_mov_reg_imm(b->jit_ptr,hi_reg,hi_val); else x86_alu_reg_reg(b->jit_ptr,X86_XOR,hi_reg,hi_reg);}/* Set the Pointer Counter (PC) register */void mips64_set_pc(insn_block_t *b,m_uint64_t new_pc){ x86_mov_membase_imm(b->jit_ptr,X86_EDI,OFFSET(cpu_mips_t,pc), new_pc & 0xFFFFFFFF,4); x86_mov_membase_imm(b->jit_ptr,X86_EDI,OFFSET(cpu_mips_t,pc)+4, new_pc >> 32,4);}/* Set the Return Address (RA) register */void mips64_set_ra(insn_block_t *b,m_uint64_t ret_pc){ mips64_load_imm(b,X86_EDX,X86_EAX,ret_pc); x86_mov_membase_reg(b->jit_ptr,X86_EDI,REG_OFFSET(MIPS_GPR_RA),X86_EAX,4); x86_mov_membase_reg(b->jit_ptr,X86_EDI,REG_OFFSET(MIPS_GPR_RA)+4,X86_EDX,4);}/* Set Jump */static void mips64_set_jump(cpu_mips_t *cpu,insn_block_t *b,m_uint64_t new_pc, int local_jump){ int return_to_caller = FALSE; u_char *jump_ptr; if (cpu->sym_trace && !local_jump) return_to_caller = TRUE; if (!return_to_caller && insn_block_local_addr(b,new_pc,&jump_ptr)) { if (jump_ptr) { x86_jump_code(b->jit_ptr,jump_ptr); } else { insn_block_record_patch(b,b->jit_ptr,new_pc); x86_jump32(b->jit_ptr,0); } } else { /* save PC */ mips64_set_pc(b,new_pc); /* address is in another block, for now, returns to caller */ insn_block_push_epilog(b); }}/* Basic C call */static forced_inline void mips64_emit_basic_c_call(insn_block_t *b,void *f){ x86_mov_reg_imm(b->jit_ptr,X86_EBX,f); x86_call_reg(b->jit_ptr,X86_EBX);}/* Emit a simple call to a C function without any parameter */static void mips64_emit_c_call(insn_block_t *b,void *f){ mips64_set_pc(b,b->start_pc+((b->mips_trans_pos-1)<<2)); mips64_emit_basic_c_call(b,f);}/* Fast memory operation prototype */typedef void (*memop_fast_access)(insn_block_t *b,int target);/* Fast LW */static void mips64_memop_fast_lw(insn_block_t *b,int target){ x86_mov_reg_memindex(b->jit_ptr,X86_EAX,X86_EAX,0,X86_EBX,0,4); x86_bswap(b->jit_ptr,X86_EAX); x86_cdq(b->jit_ptr); x86_mov_membase_reg(b->jit_ptr,X86_EDI,REG_OFFSET(target),X86_EAX,4); x86_mov_membase_reg(b->jit_ptr,X86_EDI,REG_OFFSET(target)+4,X86_EDX,4);}/* Fast SW */static void mips64_memop_fast_sw(insn_block_t *b,int target){ x86_mov_reg_membase(b->jit_ptr,X86_EDX,X86_EDI,REG_OFFSET(target),4); x86_bswap(b->jit_ptr,X86_EDX); x86_mov_memindex_reg(b->jit_ptr,X86_EAX,0,X86_EBX,0,X86_EDX,4);}/* Fast memory operation (64-bit) */static void mips64_emit_memop_fast64(insn_block_t *b,int op, int base,int offset, int target,int keep_ll_bit, memop_fast_access op_handler){ m_uint64_t val = sign_extend(offset,16); u_char *test1,*test2,*test3,*test4; u_char *p_exception,*p_exit; /* ECX:EBX = sign-extended offset */ mips64_load_imm(b,X86_ECX,X86_EBX,val); /* ECX:EBX = GPR[base] + sign-extended offset */ x86_alu_reg_membase(b->jit_ptr,X86_ADD,X86_EBX,X86_EDI,REG_OFFSET(base)); x86_alu_reg_membase(b->jit_ptr,X86_ADC,X86_ECX,X86_EDI,REG_OFFSET(base)+4); /* EAX = mts64_entry index */ x86_mov_reg_reg(b->jit_ptr,X86_EAX,X86_EBX,4); x86_shift_reg_imm(b->jit_ptr,X86_SHR,X86_EAX,MTS64_HASH_SHIFT); x86_alu_reg_imm(b->jit_ptr,X86_AND,X86_EAX,MTS64_HASH_MASK); /* EDX = mts_cache */ x86_mov_reg_membase(b->jit_ptr,X86_EDX, X86_EDI,OFFSET(cpu_mips_t,mts_cache),4); /* ESI = mts64_entry */ x86_mov_reg_memindex(b->jit_ptr,X86_ESI,X86_EDX,0,X86_EAX,2,4); x86_test_reg_reg(b->jit_ptr,X86_ESI,X86_ESI); /* slow lookup */ test1 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_Z, 0, 1); /* Compare the high part of the vaddr */ x86_alu_reg_membase(b->jit_ptr,X86_CMP,X86_ECX,X86_ESI, OFFSET(mts64_entry_t,start)+4); test2 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_NZ, 0, 1); /* EAX = entry mask, compare low part of the vaddr */ x86_mov_reg_membase(b->jit_ptr,X86_EAX, X86_ESI,OFFSET(mts64_entry_t,mask),4); x86_alu_reg_reg(b->jit_ptr,X86_AND,X86_EAX,X86_EBX); x86_alu_reg_membase(b->jit_ptr,X86_CMP,X86_EAX,X86_ESI, OFFSET(mts64_entry_t,start)); test3 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_NZ, 0, 1); /* Ok, we have the good entry. Test if this is a device */ x86_mov_reg_membase(b->jit_ptr,X86_EAX, X86_ESI,OFFSET(mts64_entry_t,action),4); x86_mov_reg_reg(b->jit_ptr,X86_EDX,X86_EAX,4); x86_alu_reg_imm(b->jit_ptr,X86_AND,X86_EDX,MTS_DEV_MASK); test4 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_NZ, 0, 1); /* EAX = action */ x86_alu_reg_imm(b->jit_ptr,X86_AND,X86_EAX,MTS_ADDR_MASK); /* Compute offset */ x86_alu_reg_membase(b->jit_ptr,X86_SUB,X86_EBX, X86_ESI,OFFSET(mts64_entry_t,start)); /* Memory access */ op_handler(b,target); p_exit = b->jit_ptr; x86_jump8(b->jit_ptr,0); /* === Slow lookup === */ x86_patch(test1,b->jit_ptr); x86_patch(test2,b->jit_ptr); x86_patch(test3,b->jit_ptr); x86_patch(test4,b->jit_ptr); /* Update PC (ECX:EBX = vaddr) */ x86_mov_reg_reg(b->jit_ptr,X86_ESI,X86_EBX,4); mips64_set_pc(b,b->start_pc+((b->mips_trans_pos-1)<<2)); x86_mov_reg_reg(b->jit_ptr,X86_EDX,X86_ESI,4); /* EBX = target register */ x86_mov_reg_imm(b->jit_ptr,X86_EBX,target); /* EAX = CPU instance pointer */ x86_mov_reg_reg(b->jit_ptr,X86_EAX,X86_EDI,4); /* * Push parameters on stack and call memory function. * Keep the stack aligned on a 16-byte boundary for Darwin/x86. */ x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,8); x86_push_reg(b->jit_ptr,X86_EBX); x86_call_membase(b->jit_ptr,X86_EDI,MEMOP_OFFSET(op)); x86_alu_reg_imm(b->jit_ptr,X86_ADD,X86_ESP,12); /* Check for exception */ x86_test_reg_reg(b->jit_ptr,X86_EAX,X86_EAX); p_exception = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_Z, 0, 1); insn_block_push_epilog(b); x86_patch(p_exit,b->jit_ptr); x86_patch(p_exception,b->jit_ptr);}/* Fast memory operation (32-bit) */static void mips64_emit_memop_fast32(insn_block_t *b,int op, int base,int offset, int target,int keep_ll_bit, memop_fast_access op_handler){ m_uint32_t val = sign_extend(offset,16); u_char *test1,*test2,*test3; u_char *p_exception,*p_exit; /* EBX = sign-extended offset */ x86_mov_reg_imm(b->jit_ptr,X86_EBX,val); /* EBX = GPR[base] + sign-extended offset */ x86_alu_reg_membase(b->jit_ptr,X86_ADD,X86_EBX,X86_EDI,REG_OFFSET(base)); /* EAX = mts32_entry index */ x86_mov_reg_reg(b->jit_ptr,X86_EAX,X86_EBX,4); x86_shift_reg_imm(b->jit_ptr,X86_SHR,X86_EAX,MTS32_HASH_SHIFT); x86_alu_reg_imm(b->jit_ptr,X86_AND,X86_EAX,MTS32_HASH_MASK); /* EDX = mts_cache */ x86_mov_reg_membase(b->jit_ptr,X86_EDX, X86_EDI,OFFSET(cpu_mips_t,mts_cache),4); /* ESI = mts32_entry */ x86_mov_reg_memindex(b->jit_ptr,X86_ESI,X86_EDX,0,X86_EAX,2,4); x86_test_reg_reg(b->jit_ptr,X86_ESI,X86_ESI); /* slow lookup */ test1 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_Z, 0, 1); /* ECX = entry mask, compare the virtual addresses */ x86_mov_reg_membase(b->jit_ptr,X86_ECX, X86_ESI,OFFSET(mts32_entry_t,mask),4); x86_alu_reg_reg(b->jit_ptr,X86_AND,X86_ECX,X86_EBX); x86_alu_reg_membase(b->jit_ptr,X86_CMP,X86_ECX,X86_ESI, OFFSET(mts32_entry_t,start)); test2 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_NZ, 0, 1); /* Ok, we have the good entry. Test if this is a device */ x86_mov_reg_membase(b->jit_ptr,X86_EAX, X86_ESI,OFFSET(mts32_entry_t,action),4); x86_mov_reg_reg(b->jit_ptr,X86_EDX,X86_EAX,4); x86_alu_reg_imm(b->jit_ptr,X86_AND,X86_EDX,MTS_DEV_MASK); test3 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_NZ, 0, 1); /* EAX = action */ x86_alu_reg_imm(b->jit_ptr,X86_AND,X86_EAX,MTS_ADDR_MASK); /* Compute offset */ x86_alu_reg_membase(b->jit_ptr,X86_SUB,X86_EBX, X86_ESI,OFFSET(mts32_entry_t,start)); /* Memory access */ op_handler(b,target); p_exit = b->jit_ptr; x86_jump8(b->jit_ptr,0); /* === Slow lookup === */ x86_patch(test1,b->jit_ptr); x86_patch(test2,b->jit_ptr); x86_patch(test3,b->jit_ptr); /* Update PC (EBX = vaddr) */ mips64_set_pc(b,b->start_pc+((b->mips_trans_pos-1)<<2)); /* Sign-extend virtual address and put vaddr in ECX:EDX */ x86_mov_reg_reg(b->jit_ptr,X86_EAX,X86_EBX,4); x86_cdq(b->jit_ptr); x86_mov_reg_reg(b->jit_ptr,X86_ECX,X86_EDX,4); x86_mov_reg_reg(b->jit_ptr,X86_EDX,X86_EAX,4); /* EBX = target register */ x86_mov_reg_imm(b->jit_ptr,X86_EBX,target); /* EAX = CPU instance pointer */ x86_mov_reg_reg(b->jit_ptr,X86_EAX,X86_EDI,4); /* * Push parameters on stack and call memory function. * Keep the stack aligned on a 16-byte boundary for Darwin/x86. */ x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,8); x86_push_reg(b->jit_ptr,X86_EBX); x86_call_membase(b->jit_ptr,X86_EDI,MEMOP_OFFSET(op)); x86_alu_reg_imm(b->jit_ptr,X86_ADD,X86_ESP,12); /* Check for exception */ x86_test_reg_reg(b->jit_ptr,X86_EAX,X86_EAX); p_exception = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_Z, 0, 1); insn_block_push_epilog(b); x86_patch(p_exit,b->jit_ptr); x86_patch(p_exception,b->jit_ptr);}/* Fast memory operation */static void mips64_emit_memop_fast(cpu_mips_t *cpu,insn_block_t *b,int op, int base,int offset, int target,int keep_ll_bit, memop_fast_access op_handler){ switch(cpu->addr_mode) { case 32: mips64_emit_memop_fast32(b,op,base,offset,target,keep_ll_bit, op_handler); break; case 64: mips64_emit_memop_fast64(b,op,base,offset,target,keep_ll_bit, op_handler); break; }}/* Memory operation */static void mips64_emit_memop(insn_block_t *b,int op,int base,int offset, int target,int keep_ll_bit){ m_uint64_t val = sign_extend(offset,16); u_char *test1; /* Save PC for exception handling */ mips64_set_pc(b,b->start_pc+((b->mips_trans_pos-1)<<2)); if (!keep_ll_bit) { x86_clear_reg(b->jit_ptr,X86_EAX); x86_mov_membase_reg(b->jit_ptr,X86_EDI,OFFSET(cpu_mips_t,ll_bit), X86_EAX,4); } /* ECX:EDX = sign-extended offset */ mips64_load_imm(b,X86_ECX,X86_EDX,val); /* ECX:EDX = GPR[base] + sign-extended offset */ x86_alu_reg_membase(b->jit_ptr,X86_ADD,X86_EDX,X86_EDI,REG_OFFSET(base)); x86_alu_reg_membase(b->jit_ptr,X86_ADC,X86_ECX,X86_EDI,REG_OFFSET(base)+4); /* EBX = target register */ x86_mov_reg_imm(b->jit_ptr,X86_EBX,target); /* EAX = CPU instance pointer */ x86_mov_reg_reg(b->jit_ptr,X86_EAX,X86_EDI,4); /* * Push parameters on stack and call memory function. * Keep the stack aligned on a 16-byte boundary for Darwin/x86. */ x86_alu_reg_imm(b->jit_ptr,X86_SUB,X86_ESP,8); x86_push_reg(b->jit_ptr,X86_EBX); x86_call_membase(b->jit_ptr,X86_EDI,MEMOP_OFFSET(op)); x86_alu_reg_imm(b->jit_ptr,X86_ADD,X86_ESP,12); /* Exception ? */ x86_test_reg_reg(b->jit_ptr,X86_EAX,X86_EAX); test1 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_Z, 0, 1); insn_block_push_epilog(b); x86_patch(test1,b->jit_ptr);}/* Coprocessor Register transfert operation */static void mips64_emit_cp_xfr_op(insn_block_t *b,int rt,int rd,void *f){ /* update pc */ mips64_set_pc(b,b->start_pc+((b->mips_trans_pos-1)<<2)); /* cp0 register */ x86_mov_reg_imm(b->jit_ptr,X86_ECX,rd); /* gpr */ x86_mov_reg_imm(b->jit_ptr,X86_EDX,rt); /* cpu instance */ x86_mov_reg_reg(b->jit_ptr,X86_EAX,X86_EDI,4); mips64_emit_basic_c_call(b,f);}/* Virtual Breakpoint */void mips64_emit_breakpoint(insn_block_t *b){ x86_mov_reg_reg(b->jit_ptr,X86_EAX,X86_EDI,4); mips64_emit_c_call(b,mips64_run_breakpoint);}/* Unknown opcode handler */static asmlinkage void mips64_unknown_opcode(cpu_mips_t *cpu,m_uint32_t opcode){ printf("MIPS64: unhandled opcode 0x%8.8x at 0x%llx (ra=0x%llx)\n", opcode,cpu->pc,cpu->gpr[MIPS_GPR_RA]); mips64_dump_regs(cpu);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -