📄 mips64_jit.c
字号:
block->start_pc,vaddr,block->mips_trans_pos); return(-1); } if (!ipt || (ipt->cur_patch >= MIPS64_INSN_PATCH_TABLE_SIZE)) { /* full table or no table, create a new one */ ipt = malloc(sizeof(*ipt)); if (!ipt) { fprintf(stderr,"Block 0x%8.8llx: unable to create patch table.\n", block->start_pc); 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 */static int mips64_jit_tcb_apply_patches(cpu_mips_t *cpu, mips64_jit_tcb_t *block){ struct mips64_jit_patch_table *ipt; struct mips64_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++) { patch = &ipt->patches[i]; jit_dst = mips64_jit_tcb_get_host_ptr(block,patch->mips_pc); if (jit_dst) {#if DEBUG_BLOCK_PATCH printf("Block 0x%8.8llx: applying patch " "[JIT:%p->mips:0x%8.8llx=JIT:%p]\n", block->start_pc,patch->jit_insn,patch->mips_pc,jit_dst);#endif mips64_jit_tcb_set_patch(patch->jit_insn,jit_dst); } } return(0);}/* Free the patch table */static void mips64_jit_tcb_free_patches(mips64_jit_tcb_t *block){ struct mips64_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 mips64_jit_tcb_adjust_buffer(cpu_mips_t *cpu, mips64_jit_tcb_t *block){ insn_exec_page_t *new_buffer; if ((block->jit_ptr - block->jit_buffer->ptr) <= (MIPS_JIT_BUFSIZE - 512)) return(0);#if DEBUG_BLOCK_CHUNK printf("Block 0x%llx: adjusting JIT buffer...\n",block->start_pc);#endif if (block->jit_chunk_pos >= MIPS_JIT_MAX_CHUNKS) { fprintf(stderr,"Block 0x%llx: too many JIT chunks.\n",block->start_pc); 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) */ mips64_jit_tcb_set_jump(block->jit_ptr,new_buffer->ptr); block->jit_ptr = new_buffer->ptr; return(0);}/* Allocate an instruction block */static inline mips64_jit_tcb_t *mips64_jit_tcb_alloc(cpu_mips_t *cpu){ mips64_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 an instruction block */void mips64_jit_tcb_free(cpu_mips_t *cpu,mips64_jit_tcb_t *block, int list_removal){ int i; 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; } /* Free the patch tables */ mips64_jit_tcb_free_patches(block); /* Free code pages */ for(i=0;i<MIPS_JIT_MAX_CHUNKS;i++) exec_page_free(cpu,block->jit_chunks[i]); /* Free the current JIT buffer */ exec_page_free(cpu,block->jit_buffer); /* Free the MIPS-to-native code mapping */ free(block->jit_insn_ptr); /* Make the block return to the free list */ block->next = cpu->tcb_free_list; cpu->tcb_free_list = block; }}/* Create an instruction block */static mips64_jit_tcb_t *mips64_jit_tcb_create(cpu_mips_t *cpu, m_uint64_t vaddr){ mips64_jit_tcb_t *block = NULL; if (!(block = mips64_jit_tcb_alloc(cpu))) goto err_block_alloc; block->start_pc = vaddr; /* 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->mips_code = cpu->mem_op_lookup(cpu,block->start_pc); if (!block->mips_code) { fprintf(stderr,"%% No memory map for code execution at 0x%llx\n", block->start_pc); 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: mips64_jit_tcb_free(cpu,block,FALSE); err_block_alloc: fprintf(stderr,"%% Unable to create instruction block for vaddr=0x%llx\n", vaddr); return NULL;}/* Compile a MIPS instruction page */static inline mips64_jit_tcb_t *mips64_jit_tcb_compile(cpu_mips_t *cpu,m_uint64_t vaddr){ mips64_jit_tcb_t *block; struct mips64_insn_tag *tag; m_uint64_t page_addr; size_t len; page_addr = vaddr & ~(m_uint64_t)MIPS_MIN_PAGE_IMASK; if (unlikely(!(block = mips64_jit_tcb_create(cpu,page_addr)))) { fprintf(stderr,"insn_page_compile: unable to create JIT block.\n"); return NULL; } /* Allocate the array used to convert MIPS code ptr to native code ptr */ len = MIPS_MIN_PAGE_SIZE / sizeof(mips_insn_t); if (!(block->jit_insn_ptr = calloc(len,sizeof(u_char *)))) { fprintf(stderr,"insn_page_compile: unable to create JIT mappings.\n"); goto error; } /* Emit native code for each instruction */ block->mips_trans_pos = 0; while(block->mips_trans_pos < MIPS_INSN_PER_PAGE) { if (unlikely(!(tag = mips64_jit_fetch_and_emit(cpu,block,0)))) { fprintf(stderr,"insn_page_compile: unable to fetch instruction.\n"); goto error; }#if DEBUG_BLOCK_COMPILE printf("Page 0x%8.8llx: emitted tag 0x%8.8x/0x%8.8x\n", block->start_pc,tag->mask,tag->value);#endif mips64_jit_tcb_adjust_buffer(cpu,block); } mips64_jit_tcb_add_end(block); mips64_jit_tcb_apply_patches(cpu,block); mips64_jit_tcb_free_patches(block); /* Add the block to the linked list */ block->next = cpu->tcb_list; block->prev = NULL; if (cpu->tcb_list) cpu->tcb_list->prev = block; else cpu->tcb_last = block; cpu->tcb_list = block; cpu->compiled_pages++; return block; error: mips64_jit_tcb_free(cpu,block,FALSE); return NULL;}/* Run a compiled MIPS instruction block */static forced_inline void mips64_jit_tcb_run(cpu_mips_t *cpu,mips64_jit_tcb_t *block){#if DEBUG_SYM_TREE struct symbol *sym = NULL; int mark = FALSE;#endif if (unlikely(cpu->pc & 0x03)) { fprintf(stderr,"mips64_jit_tcb_run: Invalid PC 0x%llx.\n",cpu->pc); mips64_dump_regs(cpu->gen); mips64_tlb_dump(cpu->gen); cpu_stop(cpu->gen); return; }#if DEBUG_SYM_TREE if (cpu->sym_trace && cpu->sym_tree) { if ((sym = mips64_sym_lookup(cpu,cpu->pc)) != NULL) { cpu_log(cpu,"mips64_jit_tcb_run(start)", "%s (PC=0x%llx) RA = 0x%llx\na0=0x%llx, " "a1=0x%llx, a2=0x%llx, a3=0x%llx\n", sym->name, cpu->pc, cpu->gpr[MIPS_GPR_RA], cpu->gpr[MIPS_GPR_A0], cpu->gpr[MIPS_GPR_A1], cpu->gpr[MIPS_GPR_A2], cpu->gpr[MIPS_GPR_A3]); mark = TRUE; } }#endif /* Execute JIT compiled code */ mips64_jit_tcb_exec(cpu,block);#if DEBUG_SYM_TREE if (mark) { cpu_log(cpu,"mips64_jit_tcb_run(end)","%s, v0 = 0x%llx\n", sym->name,cpu->gpr[MIPS_GPR_V0]); }#endif}/* Execute compiled MIPS code */void *mips64_jit_run_cpu(cpu_gen_t *gen){ cpu_mips_t *cpu = CPU_MIPS64(gen); pthread_t timer_irq_thread; mips64_jit_tcb_t *block; int timer_irq_check = 0; m_uint32_t pc_hash; if (pthread_create(&timer_irq_thread,NULL, (void *)mips64_timer_irq_run,cpu)) { fprintf(stderr, "VM '%s': unable to create Timer IRQ thread for CPU%u.\n", cpu->vm->name,gen->id); cpu_stop(cpu->gen); return NULL; } gen->cpu_thread_running = TRUE; cpu_exec_loop_set(gen); start_cpu: gen->idle_count = 0; for(;;) { if (unlikely(gen->state != CPU_STATE_RUNNING)) break;#if DEBUG_BLOCK_PERF_CNT cpu->perf_counter++;#endif /* Handle virtual idle loop */ if (unlikely(cpu->pc == cpu->idle_pc)) { if (++gen->idle_count == gen->idle_max) { cpu_idle_loop(gen); gen->idle_count = 0; } } /* Handle the virtual CPU clock */ if (++timer_irq_check == cpu->timer_irq_check_itv) { timer_irq_check = 0; if (cpu->timer_irq_pending && !cpu->irq_disable) { mips64_trigger_timer_irq(cpu); mips64_trigger_irq(cpu); cpu->timer_irq_pending--; } } pc_hash = mips64_jit_get_pc_hash(cpu->pc); block = cpu->exec_blk_map[pc_hash]; /* No block found, compile the page */ if (unlikely(!block) || unlikely(!mips64_jit_tcb_match(cpu,block))) { if (block != NULL) { mips64_jit_tcb_free(cpu,block,TRUE); cpu->exec_blk_map[pc_hash] = NULL; } block = mips64_jit_tcb_compile(cpu,cpu->pc); if (unlikely(!block)) { fprintf(stderr, "VM '%s': unable to compile block for CPU%u PC=0x%llx\n", cpu->vm->name,gen->id,cpu->pc); cpu_stop(gen); break; } cpu->exec_blk_map[pc_hash] = block; }#if DEBUG_BLOCK_TIMESTAMP block->tm_last_use = jit_jiffies++;#endif block->acc_count++; mips64_jit_tcb_run(cpu,block); } if (!cpu->pc) { cpu_stop(gen); cpu_log(gen,"JIT","PC=0, halting CPU.\n"); } /* Check regularly if the CPU has been restarted */ while(gen->cpu_thread_running) { gen->seq_state++; switch(gen->state) { case CPU_STATE_RUNNING: gen->state = CPU_STATE_RUNNING; goto start_cpu; case CPU_STATE_HALTED: gen->cpu_thread_running = FALSE; pthread_join(timer_irq_thread,NULL); return NULL; } /* CPU is paused */ usleep(200000); } return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -