📄 mips64_jit.c
字号:
/* * Cisco 7200 (Predator) 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 ARCH_INC_FILE#include "rbtree.h"#include "cp0.h"#include "memory.h"#include "cpu.h"#include "device.h"#include "mips64.h"#include "mips64_exec.h"#include "insn_lookup.h"#include "ptask.h"#if DEBUG_BLOCK_TIMESTAMPstatic volatile m_uint64_t jit_jiffies = 0;#endif/* MIPS jump instructions for block scan */struct 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 insn_tag *tag,int value){ return((value & tag->mask) == (tag->value & 0xFFFF));}static int mips64_jit_chk_hi(struct 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(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 = 1048576 * sizeof(void *); cpu->exec_phys_map = m_memalign(4096,len); memset(cpu->exec_phys_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->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){ insn_block_t *p,*next; u_int count = 0; if (!threshold) threshold = (u_int)(-1); /* UINT_MAX not defined everywhere */ for(p=cpu->insn_block_list;p;p=next) { next = p->next; if (p->acc_count <= threshold) { cpu->exec_phys_map[p->phys_page] = NULL; insn_block_free(cpu,p,TRUE); count++; } } cpu->compiled_pages -= count; return(count);}/* Shutdown the JIT */void mips64_jit_shutdown(cpu_mips_t *cpu){ insn_block_t *p,*next; /* Flush the JIT */ mips64_jit_flush(cpu,0); /* Free the instruction blocks */ for(p=cpu->insn_block_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_phys_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,"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,"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 */struct insn_tag *insn_tag_find(mips_insn_t ins){ struct 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 */struct insn_jump *insn_jump_find(mips_insn_t ins){ struct 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(insn_block_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,insn_block_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 *//* Fetch a MIPS instruction and emit corresponding translated code */struct insn_tag *insn_fetch_and_emit(cpu_mips_t *cpu,insn_block_t *block, int delay_slot){ struct insn_tag *tag; mips_insn_t code; code = insn_fetch(block); tag = insn_tag_find(code); assert(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_PERF_COUNTER 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 */void insn_block_add_end(insn_block_t *b){ mips64_set_pc(b,b->start_pc+(b->mips_trans_pos<<2)); insn_block_push_epilog(b);}/* Record a patch to apply in a compiled block */int insn_block_record_patch(insn_block_t *block,u_char *jit_ptr, m_uint64_t vaddr){ struct insn_patch_table *ipt = block->patch_table; struct 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", block->start_pc,vaddr,block->mips_trans_pos); return(-1); } if (!ipt || (ipt->cur_patch >= INSN_PATCH_TABLE_SIZE)) { /* full table or no table, create a new one */ ipt = malloc(sizeof(*ipt)); if (!ipt) { fprintf(stderr,"%% Unable to create patch table.\n"); return(-1); } memset(ipt,0,sizeof(*ipt)); ipt->next = block->patch_table; block->patch_table = ipt; }#if DEBUG_BLOCK_PATCH printf("Block 0x%8.8llx: recording patch [JIT:%p->mips:0x%8.8llx], " "MTP=%d\n",block->start_pc,jit_ptr,vaddr,block->mips_trans_pos);#endif patch = &ipt->patches[ipt->cur_patch]; patch->jit_insn = jit_ptr; patch->mips_pc = vaddr; ipt->cur_patch++; return(0);}/* Apply all patches */int insn_block_apply_patches(cpu_mips_t *cpu,insn_block_t *block){ struct insn_patch_table *ipt; struct insn_patch *patch; u_char *jit_dst; int i; for(ipt=block->patch_table;ipt;ipt=ipt->next) for(i=0;i<ipt->cur_patch;i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -