📄 mips64_jit.c
字号:
/* * Cisco router simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) * * MIPS64 JIT compiler. */#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 <signal.h>#include <fcntl.h>#include <assert.h>#include "sbox.h"#include "cpu.h"#include "device.h"#include "mips64.h"#include "mips64_cp0.h"#include "mips64_exec.h"#include "mips64_jit.h"#include "insn_lookup.h"#include "memory.h"#include "ptask.h"#include MIPS64_ARCH_INC_FILE#if DEBUG_BLOCK_TIMESTAMPstatic volatile m_uint64_t jit_jiffies = 0;#endif/* MIPS jump instructions for block scan */struct mips64_insn_jump mips64_insn_jumps[] = { { "b" , 0xffff0000, 0x10000000, 16, 1 }, { "bal" , 0xffff0000, 0x04110000, 16, 1 }, { "beq" , 0xfc000000, 0x10000000, 16, 1 }, { "beql" , 0xfc000000, 0x50000000, 16, 1 }, { "bgez" , 0xfc1f0000, 0x04010000, 16, 1 }, { "bgezl" , 0xfc1f0000, 0x04030000, 16, 1 }, { "bgezal" , 0xfc1f0000, 0x04110000, 16, 1 }, { "bgezall" , 0xfc1f0000, 0x04130000, 16, 1 }, { "bgtz" , 0xfc1f0000, 0x1c000000, 16, 1 }, { "bgtzl" , 0xfc1f0000, 0x5c000000, 16, 1 }, { "blez" , 0xfc1f0000, 0x18000000, 16, 1 }, { "blezl" , 0xfc1f0000, 0x58000000, 16, 1 }, { "bltz" , 0xfc1f0000, 0x04000000, 16, 1 }, { "bltzl" , 0xfc1f0000, 0x04020000, 16, 1 }, { "bltzal" , 0xfc1f0000, 0x04100000, 16, 1 }, { "bltzall" , 0xfc1f0000, 0x04120000, 16, 1 }, { "bne" , 0xfc000000, 0x14000000, 16, 1 }, { "bnel" , 0xfc000000, 0x54000000, 16, 1 }, { "j" , 0xfc000000, 0x08000000, 26, 0 }, { NULL , 0x00000000, 0x00000000, 0, 0 },};/* Instruction Lookup Table */static insn_lookup_t *ilt = NULL;static void *mips64_jit_get_insn(int index){ return(&mips64_insn_tags[index]);}static int mips64_jit_chk_lo(struct mips64_insn_tag *tag,int value){ return((value & tag->mask) == (tag->value & 0xFFFF));}static int mips64_jit_chk_hi(struct mips64_insn_tag *tag,int value){ return((value & (tag->mask >> 16)) == (tag->value >> 16));}/* Initialize instruction lookup table */void mips64_jit_create_ilt(void){ int i,count; for(i=0,count=0;mips64_insn_tags[i].emit;i++) count++; ilt = ilt_create("mips64j",count, (ilt_get_insn_cbk_t)mips64_jit_get_insn, (ilt_check_cbk_t)mips64_jit_chk_lo, (ilt_check_cbk_t)mips64_jit_chk_hi);}/* Initialize the JIT structure */int mips64_jit_init(cpu_mips_t *cpu){ insn_exec_page_t *cp; u_char *cp_addr; u_int area_size; size_t len; int i; /* Physical mapping for executable pages */ len = MIPS_JIT_PC_HASH_SIZE * sizeof(void *); cpu->exec_blk_map = m_memalign(4096,len); memset(cpu->exec_blk_map,0,len); /* Get area size */ if (!(area_size = cpu->vm->exec_area_size)) area_size = MIPS_EXEC_AREA_SIZE; /* Create executable page area */ cpu->exec_page_area_size = area_size * 1048576; cpu->exec_page_area = mmap(NULL,cpu->exec_page_area_size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS,-1,(off_t)0); if (!cpu->exec_page_area) { fprintf(stderr, "mips64_jit_init: unable to create exec area (size %lu)\n", (u_long)cpu->exec_page_area_size); return(-1); } /* Carve the executable page area */ cpu->exec_page_count = cpu->exec_page_area_size / MIPS_JIT_BUFSIZE; cpu->exec_page_array = calloc(cpu->exec_page_count, sizeof(insn_exec_page_t)); if (!cpu->exec_page_array) { fprintf(stderr,"mips64_jit_init: unable to create exec page array\n"); return(-1); } for(i=0,cp_addr=cpu->exec_page_area;i<cpu->exec_page_count;i++) { cp = &cpu->exec_page_array[i]; cp->ptr = cp_addr; cp_addr += MIPS_JIT_BUFSIZE; cp->next = cpu->exec_page_free_list; cpu->exec_page_free_list = cp; } printf("CPU%u: carved JIT exec zone of %lu Mb into %lu pages of %u Kb.\n", cpu->gen->id, (u_long)(cpu->exec_page_area_size / 1048576), (u_long)cpu->exec_page_count,MIPS_JIT_BUFSIZE / 1024); return(0);}/* Flush the JIT */u_int mips64_jit_flush(cpu_mips_t *cpu,u_int threshold){ mips64_jit_tcb_t *p,*next; m_uint32_t pc_hash; u_int count = 0; if (!threshold) threshold = (u_int)(-1); /* UINT_MAX not defined everywhere */ for(p=cpu->tcb_list;p;p=next) { next = p->next; if (p->acc_count <= threshold) { pc_hash = mips64_jit_get_pc_hash(p->start_pc); cpu->exec_blk_map[pc_hash] = NULL; mips64_jit_tcb_free(cpu,p,TRUE); count++; } } cpu->compiled_pages -= count; return(count);}/* Shutdown the JIT */void mips64_jit_shutdown(cpu_mips_t *cpu){ mips64_jit_tcb_t *p,*next; /* Flush the JIT */ mips64_jit_flush(cpu,0); /* Free the instruction blocks */ for(p=cpu->tcb_free_list;p;p=next) { next = p->next; free(p); } /* Unmap the executable page area */ if (cpu->exec_page_area) munmap(cpu->exec_page_area,cpu->exec_page_area_size); /* Free the exec page array */ free(cpu->exec_page_array); /* Free physical mapping for executable pages */ free(cpu->exec_blk_map); }/* Allocate an exec page */static inline insn_exec_page_t *exec_page_alloc(cpu_mips_t *cpu){ insn_exec_page_t *p; u_int count; /* If the free list is empty, flush JIT */ if (unlikely(!cpu->exec_page_free_list)) { if (cpu->jit_flush_method) { cpu_log(cpu->gen, "JIT","flushing data structures (compiled pages=%u)\n", cpu->compiled_pages); mips64_jit_flush(cpu,0); } else { count = mips64_jit_flush(cpu,100); cpu_log(cpu->gen,"JIT","partial JIT flush (count=%u)\n",count); if (!cpu->exec_page_free_list) mips64_jit_flush(cpu,0); } /* Use both methods alternatively */ cpu->jit_flush_method = 1 - cpu->jit_flush_method; } if (unlikely(!(p = cpu->exec_page_free_list))) return NULL; cpu->exec_page_free_list = p->next; cpu->exec_page_alloc++; return p;}/* Free an exec page and returns it to the pool */static inline void exec_page_free(cpu_mips_t *cpu,insn_exec_page_t *p){ if (p) { p->next = cpu->exec_page_free_list; cpu->exec_page_free_list = p; cpu->exec_page_alloc--; }}/* Find the JIT code emitter for the specified MIPS instruction */static struct mips64_insn_tag *insn_tag_find(mips_insn_t ins){ struct mips64_insn_tag *tag = NULL; int index; index = ilt_lookup(ilt,ins); tag = mips64_jit_get_insn(index); return tag;}/* Check if the specified MIPS instruction is a jump */static struct mips64_insn_jump *insn_jump_find(mips_insn_t ins){ struct mips64_insn_jump *jump = NULL; int i; for(i=0;mips64_insn_jumps[i].name;i++) if ((ins & mips64_insn_jumps[i].mask) == mips64_insn_jumps[i].value) { jump = &mips64_insn_jumps[i]; break; } return(jump);}/* Fetch a MIPS instruction */static forced_inline mips_insn_t insn_fetch(mips64_jit_tcb_t *b){ return(vmtoh32(b->mips_code[b->mips_trans_pos]));}/* Emit a breakpoint if necessary */#if BREAKPOINT_ENABLEstatic void insn_emit_breakpoint(cpu_mips_t *cpu,mips64_jit_tcb_t *b){ m_uint64_t pc; int i; pc = b->start_pc+((b->mips_trans_pos-1)<<2); for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++) if (pc == cpu->breakpoints[i]) { mips64_emit_breakpoint(b); break; }}#endif /* BREAKPOINT_ENABLE *//* Get host pointer for the physical address */static inline void *physmem_get_hptr(vm_instance_t *vm,m_uint64_t paddr, u_int op_size,u_int op_type, m_uint64_t *data){ struct vdevice *dev; m_uint32_t offset; void *ptr; int cow; if (!(dev = dev_lookup(vm,paddr,FALSE))) return NULL; if (dev->flags & VDEVICE_FLAG_SPARSE) { ptr = (void *)dev_sparse_get_host_addr(vm,dev,paddr,op_type,&cow); if (!ptr) return NULL; return(ptr + (paddr & VM_PAGE_IMASK)); } if ((dev->host_addr != 0) && !(dev->flags & VDEVICE_FLAG_NO_MTS_MMAP)) return((void *)dev->host_addr + (paddr - dev->phys_addr)); if (op_size == 0) return NULL; offset = paddr - dev->phys_addr; return(dev->handler(vm->boot_cpu,dev,offset,op_size,op_type,data));}/* Check if an instruction is in a delay slot or not */int mips64_jit_is_delay_slot(mips64_jit_tcb_t *b,m_uint64_t pc){ struct mips64_insn_tag *tag; m_uint32_t offset,insn; offset = (pc - b->start_pc) >> 2; if (!offset) return(FALSE); /* Fetch the previous instruction to determine if it is a jump */ insn = vmtoh32(b->mips_code[offset-1]); tag = insn_tag_find(insn); assert(tag != NULL); return(!tag->delay_slot);}/* Fetch a MIPS instruction and emit corresponding translated code */struct mips64_insn_tag *mips64_jit_fetch_and_emit(cpu_mips_t *cpu, mips64_jit_tcb_t *block, int delay_slot){ struct mips64_insn_tag *tag; mips_insn_t code; code = insn_fetch(block); tag = insn_tag_find(code); assert(tag); /* Branch-delay slot is in another page: slow exec */ if ((block->mips_trans_pos == (MIPS_INSN_PER_PAGE-1)) && !tag->delay_slot) { block->jit_insn_ptr[block->mips_trans_pos] = block->jit_ptr; mips64_set_pc(block,block->start_pc + (block->mips_trans_pos << 2)); mips64_emit_single_step(block,code); mips64_jit_tcb_push_epilog(block); block->mips_trans_pos++; return tag; } if (delay_slot && !tag->delay_slot) { mips64_emit_invalid_delay_slot(block); return NULL; } if (!delay_slot) block->jit_insn_ptr[block->mips_trans_pos] = block->jit_ptr; if (delay_slot != 2) block->mips_trans_pos++;#if DEBUG_INSN_PERF_CNT mips64_inc_perf_counter(block);#endif if (!delay_slot) { /* Check for IRQs + Increment count register before jumps */ if (!tag->delay_slot) { mips64_inc_cp0_count_reg(block); mips64_check_pending_irq(block); } }#if BREAKPOINT_ENABLE if (cpu->breakpoints_enabled) insn_emit_breakpoint(cpu,block);#endif tag->emit(cpu,block,code); return tag;}/* Add end of JIT block */static void mips64_jit_tcb_add_end(mips64_jit_tcb_t *b){ mips64_set_pc(b,b->start_pc+(b->mips_trans_pos<<2)); mips64_jit_tcb_push_epilog(b);}/* Record a patch to apply in a compiled block */int mips64_jit_tcb_record_patch(mips64_jit_tcb_t *block,u_char *jit_ptr, m_uint64_t vaddr){ struct mips64_jit_patch_table *ipt = block->patch_table; struct mips64_insn_patch *patch; /* pc must be 32-bit aligned */ if (vaddr & 0x03) { fprintf(stderr,"Block 0x%8.8llx: trying to record an invalid PC " "(0x%8.8llx) - mips_trans_pos=%d.\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -