📄 ppc32_jit.c
字号:
/* * Cisco router simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) * * PPC32 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 "cpu.h"#include "device.h"#include "ppc32.h"#include "ppc32_exec.h"#include "ppc32_jit.h"#include "insn_lookup.h"#include "memory.h"#include "ptask.h"#include PPC32_ARCH_INC_FILE/* Instruction Lookup Table */static insn_lookup_t *ilt = NULL;static void *ppc32_jit_get_insn(int index){ return(&ppc32_insn_tags[index]);}static int ppc32_jit_chk_lo(struct ppc32_insn_tag *tag,int value){ return((value & tag->mask) == (tag->value & 0xFFFF));}static int ppc32_jit_chk_hi(struct ppc32_insn_tag *tag,int value){ return((value & (tag->mask >> 16)) == (tag->value >> 16));}/* Initialize instruction lookup table */void ppc32_jit_create_ilt(void){ int i,count; for(i=0,count=0;ppc32_insn_tags[i].emit;i++) count++; ilt = ilt_create("ppc32j",count, (ilt_get_insn_cbk_t)ppc32_jit_get_insn, (ilt_check_cbk_t)ppc32_jit_chk_lo, (ilt_check_cbk_t)ppc32_jit_chk_hi);}/* Initialize the JIT structure */int ppc32_jit_init(cpu_ppc_t *cpu){ insn_exec_page_t *cp; u_char *cp_addr; u_int area_size; size_t len; int i; /* JIT mapping for executable pages */ len = PPC_JIT_IA_HASH_SIZE * sizeof(void *); cpu->exec_blk_map = m_memalign(4096,len); memset(cpu->exec_blk_map,0,len); /* Physical mapping for executable pages */ len = PPC_JIT_PHYS_HASH_SIZE * 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 = PPC_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, "ppc32_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 / PPC_JIT_BUFSIZE; cpu->exec_page_array = calloc(cpu->exec_page_count, sizeof(insn_exec_page_t)); if (!cpu->exec_page_array) { fprintf(stderr,"ppc32_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 += PPC_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,PPC_JIT_BUFSIZE / 1024); return(0);}/* Flush the JIT */u_int ppc32_jit_flush(cpu_ppc_t *cpu,u_int threshold){ ppc32_jit_tcb_t *p,*next; m_uint32_t ia_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) { ia_hash = ppc32_jit_get_ia_hash(p->start_ia); ppc32_jit_tcb_free(cpu,p,TRUE); if (cpu->exec_blk_map[ia_hash] == p) cpu->exec_blk_map[ia_hash] = NULL; count++; } } cpu->compiled_pages -= count; return(count);}/* Shutdown the JIT */void ppc32_jit_shutdown(cpu_ppc_t *cpu){ ppc32_jit_tcb_t *p,*next; /* Flush the JIT */ ppc32_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 JIT block mapping */ free(cpu->exec_blk_map); /* 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_ppc_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); ppc32_jit_flush(cpu,0); } else { count = ppc32_jit_flush(cpu,100); cpu_log(cpu->gen,"JIT","partial JIT flush (count=%u)\n",count); if (!cpu->exec_page_free_list) ppc32_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_ppc_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 PowerPC instruction */static struct ppc32_insn_tag *insn_tag_find(ppc_insn_t ins){ struct ppc32_insn_tag *tag = NULL; int index; index = ilt_lookup(ilt,ins); tag = ppc32_jit_get_insn(index); return tag;}/* Fetch a PowerPC instruction */static forced_inline ppc_insn_t insn_fetch(ppc32_jit_tcb_t *b){ return(vmtoh32(b->ppc_code[b->ppc_trans_pos]));}#define DEBUG_HREG 0/* Show register allocation status */static void ppc32_jit_show_hreg_status(cpu_ppc_t *cpu){ struct hreg_map *map; printf("PPC32-JIT: reg status for insn '%s'\n",cpu->jit_hreg_seq_name); for(map=cpu->hreg_map_list;map;map=map->next) { switch(map->flags) { case 0: printf(" hreg %d is free, mapped to vreg %d\n", map->hreg,map->vreg); break; case HREG_FLAG_ALLOC_LOCKED: printf(" hreg %d is locked, mapped to vreg %d\n", map->hreg,map->vreg); break; case HREG_FLAG_ALLOC_FORCED: printf(" hreg %d is in forced alloc\n",map->hreg); break; } }}/* Extract an host reg mapping from the register list */static void ppc32_jit_extract_hreg(cpu_ppc_t *cpu,struct hreg_map *map){ if (map->prev != NULL) map->prev->next = map->next; else cpu->hreg_map_list = map->next; if (map->next != NULL) map->next->prev = map->prev; else cpu->hreg_lru = map->prev;}/* Insert a reg map as head of list (as MRU element) */void ppc32_jit_insert_hreg_mru(cpu_ppc_t *cpu,struct hreg_map *map){ map->next = cpu->hreg_map_list; map->prev = NULL; if (map->next == NULL) { cpu->hreg_lru = map; } else { map->next->prev = map; } cpu->hreg_map_list = map;}/* Start register allocation sequence */void ppc32_jit_start_hreg_seq(cpu_ppc_t *cpu,char *insn){ struct hreg_map *map;#if DEBUG_HREG printf("Starting hreg_seq insn='%s'\n",insn);#endif /* Reset the allocation state of all host registers */ for(map=cpu->hreg_map_list;map;map=map->next) map->flags = 0; /* Save the instruction name for debugging/error analysis */ cpu->jit_hreg_seq_name = insn;}/* Close register allocation sequence */void ppc32_jit_close_hreg_seq(cpu_ppc_t *cpu){#if DEBUG_HREG ppc32_show_hreg_status(cpu);#endif}/* Find a free host register to use */static struct hreg_map *ppc32_jit_get_free_hreg(cpu_ppc_t *cpu){ struct hreg_map *map,*oldest_free = NULL; for(map=cpu->hreg_lru;map;map=map->prev) { if ((map->vreg == -1) && (map->flags == 0)) return map; if ((map->flags == 0) && !oldest_free) oldest_free = map; } if (!oldest_free) { fprintf(stderr, "ppc32_get_free_hreg: unable to find free reg for insn %s\n", cpu->jit_hreg_seq_name); } return oldest_free;}/* Allocate an host register */int ppc32_jit_alloc_hreg(cpu_ppc_t *cpu,int ppc_reg){ struct hreg_map *map; int hreg; /* * If PPC reg is invalid, the caller requested for a temporary register. */ if (ppc_reg == -1) { if ((map = ppc32_jit_get_free_hreg(cpu)) == NULL) return(-1); /* Allocate the register and invalidate its PPC mapping if present */ map->flags = HREG_FLAG_ALLOC_LOCKED; if (map->vreg != -1) { cpu->ppc_reg_map[map->vreg] = -1; map->vreg = -1; } return(map->hreg); } hreg = cpu->ppc_reg_map[ppc_reg]; /* * If the PPC register is already mapped to an host register, re-use this * mapping and put this as MRU mapping. */ if (hreg != -1) { map = &cpu->hreg_map[hreg]; } else { /* * This PPC register has no mapping to host register. Find a free * register. */ if ((map = ppc32_jit_get_free_hreg(cpu)) == NULL) return(-1); /* Remove the old PPC mapping if present */ if (map->vreg != -1) cpu->ppc_reg_map[map->vreg] = -1; /* Establish the new mapping */ cpu->ppc_reg_map[ppc_reg] = map->hreg; map->vreg = ppc_reg; } /* Prevent this register from further allocation in this instruction */ map->flags = HREG_FLAG_ALLOC_LOCKED; ppc32_jit_extract_hreg(cpu,map); ppc32_jit_insert_hreg_mru(cpu,map); return(map->hreg);}/* Force allocation of an host register */int ppc32_jit_alloc_hreg_forced(cpu_ppc_t *cpu,int hreg){ int ppc_reg; ppc_reg = cpu->hreg_map[hreg].vreg; /* Check that this register is not already allocated */ if (cpu->hreg_map[hreg].flags != 0) { fprintf(stderr,"ppc32_alloc_hreg_forced: trying to force allocation " "of hreg %d (insn %s)\n", hreg,cpu->jit_hreg_seq_name); return(-1); } cpu->hreg_map[hreg].flags = HREG_FLAG_ALLOC_FORCED; cpu->hreg_map[hreg].vreg = -1; if (ppc_reg != -1) cpu->ppc_reg_map[ppc_reg] = -1; return(0);}/* Emit a breakpoint if necessary */#if BREAKPOINT_ENABLEstatic void insn_emit_breakpoint(cpu_ppc_t *cpu,ppc32_jit_tcb_t *b){ m_uint32_t ia; int i; ia = b->start_ia+((b->ppc_trans_pos-1)<<2); for(i=0;i<PPC32_MAX_BREAKPOINTS;i++) if (ia == cpu->breakpoints[i]) { ppc32_emit_breakpoint(cpu,b); break; }}#endif /* BREAKPOINT_ENABLE *//* Fetch a PowerPC instruction and emit corresponding translated code */struct ppc32_insn_tag *ppc32_jit_fetch_and_emit(cpu_ppc_t *cpu,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -