📄 ppc32_jit.c
字号:
ppc32_jit_tcb_t *block){ struct ppc32_insn_tag *tag; ppc_insn_t code; code = insn_fetch(block); tag = insn_tag_find(code); assert(tag); tag->emit(cpu,block,code); return tag;}/* Add end of JIT block */static void ppc32_jit_tcb_add_end(ppc32_jit_tcb_t *b){ ppc32_set_ia(&b->jit_ptr,b->start_ia+(b->ppc_trans_pos<<2)); ppc32_jit_tcb_push_epilog(&b->jit_ptr);}/* Record a patch to apply in a compiled block */int ppc32_jit_tcb_record_patch(ppc32_jit_tcb_t *block,jit_op_t *iop, u_char *jit_ptr,m_uint32_t vaddr){ struct ppc32_jit_patch_table *ipt = block->patch_table; struct ppc32_insn_patch *patch; /* pc must be 32-bit aligned */ if (vaddr & 0x03) { fprintf(stderr, "Block 0x%8.8x: trying to record an invalid IA (0x%8.8x)\n", block->start_ia,vaddr); return(-1); } if (!ipt || (ipt->cur_patch >= PPC32_INSN_PATCH_TABLE_SIZE)) { /* full table or no table, create a new one */ ipt = malloc(sizeof(*ipt)); if (!ipt) { fprintf(stderr,"Block 0x%8.8x: unable to create patch table.\n", block->start_ia); return(-1); } memset(ipt,0,sizeof(*ipt)); ipt->next = block->patch_table; block->patch_table = ipt; }#if DEBUG_BLOCK_PATCH printf("Block 0x%8.8x: recording patch [JIT:%p->ppc:0x%8.8x], " "MTP=%d\n",block->start_ia,jit_ptr,vaddr,block->ppc_trans_pos);#endif patch = &ipt->patches[ipt->cur_patch]; patch->jit_insn = jit_ptr; patch->ppc_ia = vaddr; ipt->cur_patch++; patch->next = iop->arg_ptr; iop->arg_ptr = patch; return(0);}/* Apply patches for a JIT instruction block */static int ppc32_jit_tcb_apply_patches(cpu_ppc_t *cpu, ppc32_jit_tcb_t *block, jit_op_t *iop){ struct ppc32_insn_patch *patch; u_char *jit_ptr,*jit_dst; u_int pos; for(patch=iop->arg_ptr;patch;patch=patch->next) { jit_ptr = (patch->jit_insn - iop->ob_data) + iop->ob_final; pos = (patch->ppc_ia & PPC32_MIN_PAGE_IMASK) >> 2; jit_dst = block->jit_insn_ptr[pos]; if (jit_dst) {#if DEBUG_BLOCK_PATCH printf("Block 0x%8.8x: applying patch " "[JIT:%p->ppc:0x%8.8x=JIT:%p, ]\n", block->start_ia,patch->jit_insn,patch->ppc_ia,jit_dst);#endif ppc32_jit_tcb_set_patch(jit_ptr,jit_dst); } else { printf("Block 0x%8.8x: null dst for patch!\n",block->start_ia); } } return(0);}/* Free the patch table */static void ppc32_jit_tcb_free_patches(ppc32_jit_tcb_t *block){ struct ppc32_jit_patch_table *p,*next; for(p=block->patch_table;p;p=next) { next = p->next; free(p); } block->patch_table = NULL;}/* Adjust the JIT buffer if its size is not sufficient */static int ppc32_jit_tcb_adjust_buffer(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block){ insn_exec_page_t *new_buffer; if ((block->jit_ptr - block->jit_buffer->ptr) <= (PPC_JIT_BUFSIZE - 512)) return(0);#if DEBUG_BLOCK_CHUNK printf("Block 0x%8.8x: adjusting JIT buffer...\n",block->start_ia);#endif if (block->jit_chunk_pos >= PPC_JIT_MAX_CHUNKS) { fprintf(stderr,"Block 0x%8.8x: too many JIT chunks.\n",block->start_ia); return(-1); } if (!(new_buffer = exec_page_alloc(cpu))) return(-1); /* record the new exec page */ block->jit_chunks[block->jit_chunk_pos++] = block->jit_buffer; block->jit_buffer = new_buffer; /* jump to the new exec page (link) */ ppc32_jit_tcb_set_jump(block->jit_ptr,new_buffer->ptr); block->jit_ptr = new_buffer->ptr; return(0);}/* Allocate an instruction block */static inline ppc32_jit_tcb_t *ppc32_jit_tcb_alloc(cpu_ppc_t *cpu){ ppc32_jit_tcb_t *p; if (cpu->tcb_free_list) { p = cpu->tcb_free_list; cpu->tcb_free_list = p->next; } else { if (!(p = malloc(sizeof(*p)))) return NULL; } memset(p,0,sizeof(*p)); return p;}/* Free the code chunks */static void ppc32_jit_tcb_free_code_chunks(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block){ int i; /* Free code pages */ for(i=0;i<PPC_JIT_MAX_CHUNKS;i++) { exec_page_free(cpu,block->jit_chunks[i]); block->jit_chunks[i] = NULL; } /* Free the current JIT buffer */ exec_page_free(cpu,block->jit_buffer); block->jit_buffer = NULL;}/* Free an instruction block */void ppc32_jit_tcb_free(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block, int list_removal){ if (block) { if (list_removal) { /* Remove the block from the linked list */ if (block->next) block->next->prev = block->prev; else cpu->tcb_last = block->prev; if (block->prev) block->prev->next = block->next; else cpu->tcb_list = block->next; /* Remove the block from the physical mapping hash table */ if (block->phys_pprev) { if (block->phys_next) block->phys_next->phys_pprev = block->phys_pprev; *(block->phys_pprev) = block->phys_next; block->phys_pprev = NULL; block->phys_next = NULL; } } /* Free the patch tables */ ppc32_jit_tcb_free_patches(block); /* Free code pages */ ppc32_jit_tcb_free_code_chunks(cpu,block); /* Free the PowerPC-to-native code mapping */ free(block->jit_insn_ptr); block->next = cpu->tcb_free_list; cpu->tcb_free_list = block; }}/* Create an instruction block */static ppc32_jit_tcb_t *ppc32_jit_tcb_create(cpu_ppc_t *cpu,m_uint32_t vaddr){ ppc32_jit_tcb_t *block = NULL; m_uint32_t phys_page; if (unlikely(cpu->translate(cpu,cpu->ia,PPC32_MTS_ICACHE,&phys_page))) return NULL; if (!(block = ppc32_jit_tcb_alloc(cpu))) goto err_block_alloc; block->start_ia = vaddr; block->phys_page = phys_page; block->phys_hash = ppc32_jit_get_phys_hash(phys_page); /* Allocate the first JIT buffer */ if (!(block->jit_buffer = exec_page_alloc(cpu))) goto err_jit_alloc; block->jit_ptr = block->jit_buffer->ptr; block->ppc_code = cpu->mem_op_lookup(cpu,block->start_ia,PPC32_MTS_ICACHE); if (!block->ppc_code) { fprintf(stderr,"%% No memory map for code execution at 0x%8.8x\n", block->start_ia); goto err_lookup; }#if DEBUG_BLOCK_TIMESTAMP block->tm_first_use = block->tm_last_use = jit_jiffies;#endif return block; err_lookup: err_jit_alloc: ppc32_jit_tcb_free(cpu,block,FALSE); err_block_alloc: fprintf(stderr,"%% Unable to create instruction block for vaddr=0x%8.8x\n", vaddr); return NULL;}/* ======================================================================== *//* Dump a JIT opcode */static void ppc32_op_dump_opcode(jit_op_t *op){ switch(op->opcode) { case JIT_OP_BRANCH_TARGET: printf("branch_target"); break; case JIT_OP_BRANCH_JUMP: printf("branch_jump"); break; case JIT_OP_EOB: printf("eob"); break; case JIT_OP_LOAD_GPR: printf("load_gpr(%d,$%d,r:%d)", op->param[0],op->param[1],op->param[2]); break; case JIT_OP_STORE_GPR: printf("store_gpr(%d,$%d,r:%d)", op->param[0],op->param[1],op->param[2]); break; case JIT_OP_ALTER_HOST_REG: printf("alter_host_reg(%d)",op->param[0]); break; case JIT_OP_UPDATE_FLAGS: printf("update_flags(%d,%s)", op->param[0],(op->param[1] ? "signed" : "unsigned")); break; case JIT_OP_REQUIRE_FLAGS: printf("require_flags(%d)",op->param[0]); break; case JIT_OP_TRASH_FLAGS: printf("trash_flags(%d)",op->param[0]); break; case JIT_OP_INSN_OUTPUT: printf("insn_out(\"%s\")",op->insn_name); break; case JIT_OP_SET_HOST_REG_IMM32: printf("set_host_reg_imm32(%d,0x%8.8x)",op->param[0],op->param[1]); break; default: printf("op(%u)",op->opcode); }}/* Dump JIT operations (debugging) */static void ppc32_op_dump(cpu_gen_t *cpu,ppc32_jit_tcb_t *b){ m_uint32_t ia = b->start_ia; jit_op_t *op; int i; printf("PPC32-JIT: dump of page 0x%8.8x\n",ia); for(i=0;i<PPC32_INSN_PER_PAGE;i++,ia+=sizeof(ppc_insn_t)) { printf(" 0x%8.8x: ", ia); for(op=cpu->jit_op_array[i];op;op=op->next) { ppc32_op_dump_opcode(op); printf(" "); } printf("\n"); } printf("\n");}/* PPC register mapping */typedef struct { int host_reg; jit_op_t *last_store; m_uint32_t last_store_ia;}ppc_reg_map_t;/* Clear register mapping (with PPC register) */static void ppc32_clear_ppc_reg_map(ppc_reg_map_t *ppc_map,int *host_map, int reg){ int i,hreg; if (reg == JIT_OP_ALL_REGS) { for(i=0;i<PPC32_GPR_NR;i++) { ppc_map[i].host_reg = JIT_OP_INV_REG; ppc_map[i].last_store = NULL; } for(i=0;i<JIT_HOST_NREG;i++) host_map[i] = JIT_OP_INV_REG; } else { hreg = ppc_map[reg].host_reg; if (hreg != JIT_OP_INV_REG) host_map[hreg] = JIT_OP_INV_REG; ppc_map[reg].host_reg = JIT_OP_INV_REG; ppc_map[reg].last_store = NULL; }}/* Clear register mapping (with host register) */static void ppc32_clear_host_reg_map(ppc_reg_map_t *ppc_map,int *host_map, int reg){ int ppc_reg; if (host_map[reg] != JIT_OP_INV_REG) { ppc_reg = host_map[reg]; ppc_map[ppc_reg].host_reg = JIT_OP_INV_REG; ppc_map[ppc_reg].last_store = NULL; host_map[reg] = JIT_OP_INV_REG; }}/* Dump register mapping */static void ppc32_dump_reg_map(ppc_reg_map_t *map_array,int *host_map){ int i; printf("PPC32-JIT: current register mapping:\n"); for(i=0;i<PPC32_GPR_NR;i++) printf(" ppc reg %2.2d: %d\n",i,map_array[i].host_reg); printf("\n"); for(i=0;i<JIT_HOST_NREG;i++) printf(" hreg %d: %d\n",i,host_map[i]); printf("\n");}/* Check register mapping consistency */static int ppc32_check_reg_map(ppc_reg_map_t *map_array,int *host_map){ ppc_reg_map_t *map; int i; for(i=0;i<PPC32_GPR_NR;i++) { map = &map_array[i]; if ((map->host_reg != JIT_OP_INV_REG) && (host_map[map->host_reg] != i)) goto error; } for(i=0;i<JIT_HOST_NREG;i++) { if ((host_map[i] != JIT_OP_INV_REG) && (map_array[host_map[i]].host_reg != i)) goto error; } return(0); error: printf("PPC32_JIT: inconsistency in register mapping.\n"); ppc32_dump_reg_map(map_array,host_map); exit(1);}/* Optimize JIT operations */static void ppc32_op_optimize(cpu_gen_t *cpu,ppc32_jit_tcb_t *b){ ppc_reg_map_t ppc_map[PPC32_GPR_NR],*map; int reg,host_map[JIT_HOST_NREG]; jit_op_t *op,*opx,*last_cr_update[8]; m_uint32_t cur_ia; int i,j; ppc32_clear_ppc_reg_map(ppc_map,host_map,JIT_OP_ALL_REGS); for(i=0;i<8;i++) last_cr_update[i] = NULL; for(i=0;i<PPC32_INSN_PER_PAGE;i++) { for(op=cpu->jit_op_array[i];op;op=op->next) { //ppc32_check_reg_map(ppc_map,host_map); cur_ia = b->start_ia + (i << 2); switch(op->opcode) { /* Clear mapping if end of block or branch target */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -