📄 mips64_x86_trans.c
字号:
/* * Cisco router 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 "cpu.h"#include "mips64_jit.h"#include "mips64_x86_trans.h"#include "mips64_cp0.h"#include "memory.h"/* Macros for CPU structure access */#define REG_OFFSET(reg) (OFFSET(cpu_mips_t,gpr[(reg)]))#define CP0_REG_OFFSET(c0reg) (OFFSET(cpu_mips_t,cp0.reg[(c0reg)]))#define MEMOP_OFFSET(op) (OFFSET(cpu_mips_t,mem_op_fn[(op)]))#define DECLARE_INSN(name) \ static int mips64_emit_##name(cpu_mips_t *cpu,mips64_jit_tcb_t *b, \ mips_insn_t insn)/* 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(mips64_jit_tcb_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(mips64_jit_tcb_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(mips64_jit_tcb_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);}/* * Try to branch directly to the specified JIT block without returning to * main loop. */static void mips64_try_direct_far_jump(cpu_mips_t *cpu,mips64_jit_tcb_t *b, m_uint64_t new_pc){ m_uint64_t new_page; m_uint32_t pc_hash,pc_offset; u_char *test1,*test2,*test3,*test4; new_page = new_pc & MIPS_MIN_PAGE_MASK; pc_offset = (new_pc & MIPS_MIN_PAGE_IMASK) >> 2; pc_hash = mips64_jit_get_pc_hash(new_pc); /* Get JIT block info in %edx */ x86_mov_reg_membase(b->jit_ptr,X86_EBX, X86_EDI,OFFSET(cpu_mips_t,exec_blk_map),4); x86_mov_reg_membase(b->jit_ptr,X86_EDX,X86_EBX,pc_hash*sizeof(void *),4); /* no JIT block found ? */ x86_test_reg_reg(b->jit_ptr,X86_EDX,X86_EDX); test1 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_Z, 0, 1); /* Check block PC (lower 32-bits first) */ x86_mov_reg_imm(b->jit_ptr,X86_EAX,(m_uint32_t)new_page); x86_alu_reg_membase(b->jit_ptr,X86_CMP,X86_EAX,X86_EDX, OFFSET(mips64_jit_tcb_t,start_pc)); test2 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_NE, 0, 1); /* Check higher bits... */ x86_mov_reg_imm(b->jit_ptr,X86_ECX,new_page >> 32); x86_alu_reg_membase(b->jit_ptr,X86_CMP,X86_ECX,X86_EDX, OFFSET(mips64_jit_tcb_t,start_pc)+4); test3 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_NE, 0, 1); /* Jump to the code */ x86_mov_reg_membase(b->jit_ptr,X86_ESI, X86_EDX,OFFSET(mips64_jit_tcb_t,jit_insn_ptr),4); x86_mov_reg_membase(b->jit_ptr,X86_EBX, X86_ESI,pc_offset * sizeof(void *),4); x86_test_reg_reg(b->jit_ptr,X86_EBX,X86_EBX); test4 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_Z, 0, 1); x86_jump_reg(b->jit_ptr,X86_EBX); /* Returns to caller... */ x86_patch(test1,b->jit_ptr); x86_patch(test2,b->jit_ptr); x86_patch(test3,b->jit_ptr); x86_patch(test4,b->jit_ptr); mips64_set_pc(b,new_pc); mips64_jit_tcb_push_epilog(b);}/* Set Jump */static void mips64_set_jump(cpu_mips_t *cpu,mips64_jit_tcb_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 && mips64_jit_tcb_local_addr(b,new_pc,&jump_ptr)) { if (jump_ptr) { x86_jump_code(b->jit_ptr,jump_ptr); } else { /* Never jump directly to code in a delay slot */ if (mips64_jit_is_delay_slot(b,new_pc)) { mips64_set_pc(b,new_pc); mips64_jit_tcb_push_epilog(b); return; } mips64_jit_tcb_record_patch(b,b->jit_ptr,new_pc); x86_jump32(b->jit_ptr,0); } } else { if (cpu->exec_blk_direct_jump) { /* Block lookup optimization */ mips64_try_direct_far_jump(cpu,b,new_pc); } else { mips64_set_pc(b,new_pc); mips64_jit_tcb_push_epilog(b); } }}/* Basic C call */static forced_inline void mips64_emit_basic_c_call(mips64_jit_tcb_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(mips64_jit_tcb_t *b,void *f){ mips64_set_pc(b,b->start_pc+((b->mips_trans_pos-1)<<2)); mips64_emit_basic_c_call(b,f);}/* Single-step operation */void mips64_emit_single_step(mips64_jit_tcb_t *b,mips_insn_t insn){ x86_mov_reg_reg(b->jit_ptr,X86_EAX,X86_EDI,4); x86_mov_reg_imm(b->jit_ptr,X86_EDX,insn); mips64_emit_basic_c_call(b,mips64_exec_single_step);}/* Fast memory operation prototype */typedef void (*memop_fast_access)(mips64_jit_tcb_t *b,int target);/* Fast LW */static void mips64_memop_fast_lw(mips64_jit_tcb_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(mips64_jit_tcb_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(mips64_jit_tcb_t *b,int write_op, int opcode,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,*p_exit; test3 = NULL; /* 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 = 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 = mts32_entry */ x86_mov_reg_membase(b->jit_ptr,X86_EDX, X86_EDI,OFFSET(cpu_mips_t,mts_u.mts64_cache), 4); x86_shift_reg_imm(b->jit_ptr,X86_SHL,X86_EAX,5); x86_alu_reg_reg(b->jit_ptr,X86_ADD,X86_EDX,X86_EAX); /* Compare virtual page address (ESI = vpage) */ x86_mov_reg_reg(b->jit_ptr,X86_ESI,X86_EBX,4); x86_alu_reg_imm(b->jit_ptr,X86_AND,X86_ESI,MIPS_MIN_PAGE_MASK); /* Compare the high part of the vaddr */ x86_alu_reg_membase(b->jit_ptr,X86_CMP,X86_ECX,X86_EDX, OFFSET(mts64_entry_t,gvpa)+4); test1 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_NZ, 0, 1); /* Compare the low part of the vaddr */ x86_alu_reg_membase(b->jit_ptr,X86_CMP,X86_ESI,X86_EDX, OFFSET(mts64_entry_t,gvpa)); test2 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_NZ, 0, 1); /* Test if we are writing to a COW page */ if (write_op) { x86_test_membase_imm(b->jit_ptr,X86_EDX,OFFSET(mts64_entry_t,flags), MTS_FLAG_COW); test3 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_NZ, 0, 1); } /* EBX = offset in page, EAX = Host Page Address */ x86_alu_reg_imm(b->jit_ptr,X86_AND,X86_EBX,MIPS_MIN_PAGE_IMASK); x86_mov_reg_membase(b->jit_ptr,X86_EAX,X86_EDX,OFFSET(mts64_entry_t,hpa),4); /* 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); if (test3) x86_patch(test3,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(opcode)); x86_alu_reg_imm(b->jit_ptr,X86_ADD,X86_ESP,12); x86_patch(p_exit,b->jit_ptr);}/* Fast memory operation (32-bit) */static void mips64_emit_memop_fast32(mips64_jit_tcb_t *b,int write_op, int opcode,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,*p_exit; test2 = NULL; /* 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 = mts32_entry */ x86_mov_reg_membase(b->jit_ptr,X86_EDX, X86_EDI,OFFSET(cpu_mips_t,mts_u.mts32_cache), 4); x86_shift_reg_imm(b->jit_ptr,X86_SHL,X86_EAX,4); x86_alu_reg_reg(b->jit_ptr,X86_ADD,X86_EDX,X86_EAX); /* Compare virtual page address (ESI = vpage) */ x86_mov_reg_reg(b->jit_ptr,X86_ESI,X86_EBX,4); x86_alu_reg_imm(b->jit_ptr,X86_AND,X86_ESI,PPC32_MIN_PAGE_MASK); x86_alu_reg_membase(b->jit_ptr,X86_CMP,X86_ESI,X86_EDX, OFFSET(mts32_entry_t,gvpa)); test1 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_NZ, 0, 1); /* Test if we are writing to a COW page */ if (write_op) { x86_test_membase_imm(b->jit_ptr,X86_EDX,OFFSET(mts32_entry_t,flags), MTS_FLAG_COW); test2 = b->jit_ptr; x86_branch8(b->jit_ptr, X86_CC_NZ, 0, 1); } /* EBX = offset in page, EAX = Host Page Address */ x86_alu_reg_imm(b->jit_ptr,X86_AND,X86_EBX,PPC32_MIN_PAGE_IMASK); x86_mov_reg_membase(b->jit_ptr,X86_EAX,X86_EDX,OFFSET(mts32_entry_t,hpa),4); /* 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); if (test2) x86_patch(test2,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(opcode)); x86_alu_reg_imm(b->jit_ptr,X86_ADD,X86_ESP,12); x86_patch(p_exit,b->jit_ptr);}/* Fast memory operation */static void mips64_emit_memop_fast(cpu_mips_t *cpu,mips64_jit_tcb_t *b, int write_op,int opcode, 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,write_op,opcode,base,offset,target, keep_ll_bit,op_handler); break; case 64: mips64_emit_memop_fast64(b,write_op,opcode,base,offset,target, keep_ll_bit,op_handler); break; }}/* Memory operation */static void mips64_emit_memop(mips64_jit_tcb_t *b,int op,int base,int offset, int target,int keep_ll_bit){ m_uint64_t val = sign_extend(offset,16); /* 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);}/* Coprocessor Register transfert operation */static void mips64_emit_cp_xfr_op(mips64_jit_tcb_t *b,int rt,int rd,void *f){ /* update pc */ mips64_set_pc(b,b->start_pc+((b->mips_trans_pos-1)<<2));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -