|
|
1.1 root 1: /* 1.1.1.9 root 2: * Cisco router simulation platform. 1.1 root 3: * Copyright (c) 2005,2006 Christophe Fillot ([email protected]) 4: * 5: * MIPS64 JIT compiler. 6: */ 7: 8: #include <stdio.h> 9: #include <stdlib.h> 10: #include <unistd.h> 11: #include <string.h> 12: #include <sys/types.h> 13: #include <sys/stat.h> 14: #include <sys/mman.h> 15: #include <signal.h> 16: #include <fcntl.h> 17: #include <assert.h> 18: 1.1.1.10! root 19: #include "sbox.h" 1.1 root 20: #include "cpu.h" 21: #include "device.h" 1.1.1.4 root 22: #include "mips64.h" 1.1.1.9 root 23: #include "mips64_cp0.h" 1.1 root 24: #include "mips64_exec.h" 1.1.1.9 root 25: #include "mips64_jit.h" 1.1 root 26: #include "insn_lookup.h" 1.1.1.9 root 27: #include "memory.h" 1.1 root 28: #include "ptask.h" 29: 1.1.1.9 root 30: #include MIPS64_ARCH_INC_FILE 31: 1.1 root 32: #if DEBUG_BLOCK_TIMESTAMP 33: static volatile m_uint64_t jit_jiffies = 0; 34: #endif 35: 36: /* MIPS jump instructions for block scan */ 1.1.1.9 root 37: struct mips64_insn_jump mips64_insn_jumps[] = { 1.1 root 38: { "b" , 0xffff0000, 0x10000000, 16, 1 }, 39: { "bal" , 0xffff0000, 0x04110000, 16, 1 }, 40: { "beq" , 0xfc000000, 0x10000000, 16, 1 }, 41: { "beql" , 0xfc000000, 0x50000000, 16, 1 }, 42: { "bgez" , 0xfc1f0000, 0x04010000, 16, 1 }, 43: { "bgezl" , 0xfc1f0000, 0x04030000, 16, 1 }, 44: { "bgezal" , 0xfc1f0000, 0x04110000, 16, 1 }, 45: { "bgezall" , 0xfc1f0000, 0x04130000, 16, 1 }, 46: { "bgtz" , 0xfc1f0000, 0x1c000000, 16, 1 }, 47: { "bgtzl" , 0xfc1f0000, 0x5c000000, 16, 1 }, 48: { "blez" , 0xfc1f0000, 0x18000000, 16, 1 }, 49: { "blezl" , 0xfc1f0000, 0x58000000, 16, 1 }, 50: { "bltz" , 0xfc1f0000, 0x04000000, 16, 1 }, 51: { "bltzl" , 0xfc1f0000, 0x04020000, 16, 1 }, 52: { "bltzal" , 0xfc1f0000, 0x04100000, 16, 1 }, 53: { "bltzall" , 0xfc1f0000, 0x04120000, 16, 1 }, 54: { "bne" , 0xfc000000, 0x14000000, 16, 1 }, 55: { "bnel" , 0xfc000000, 0x54000000, 16, 1 }, 56: { "j" , 0xfc000000, 0x08000000, 26, 0 }, 57: { NULL , 0x00000000, 0x00000000, 0, 0 }, 58: }; 59: 60: /* Instruction Lookup Table */ 61: static insn_lookup_t *ilt = NULL; 62: 63: static void *mips64_jit_get_insn(int index) 64: { 65: return(&mips64_insn_tags[index]); 66: } 67: 1.1.1.9 root 68: static int mips64_jit_chk_lo(struct mips64_insn_tag *tag,int value) 1.1 root 69: { 70: return((value & tag->mask) == (tag->value & 0xFFFF)); 71: } 72: 1.1.1.9 root 73: static int mips64_jit_chk_hi(struct mips64_insn_tag *tag,int value) 1.1 root 74: { 75: return((value & (tag->mask >> 16)) == (tag->value >> 16)); 76: } 77: 78: /* Initialize instruction lookup table */ 79: void mips64_jit_create_ilt(void) 80: { 81: int i,count; 82: 83: for(i=0,count=0;mips64_insn_tags[i].emit;i++) 84: count++; 85: 1.1.1.10! root 86: ilt = ilt_create("mips64j",count, 1.1 root 87: (ilt_get_insn_cbk_t)mips64_jit_get_insn, 88: (ilt_check_cbk_t)mips64_jit_chk_lo, 89: (ilt_check_cbk_t)mips64_jit_chk_hi); 90: } 91: 1.1.1.4 root 92: /* Initialize the JIT structure */ 93: int mips64_jit_init(cpu_mips_t *cpu) 1.1.1.2 root 94: { 1.1.1.4 root 95: insn_exec_page_t *cp; 96: u_char *cp_addr; 97: u_int area_size; 98: size_t len; 99: int i; 100: 101: /* Physical mapping for executable pages */ 1.1.1.10! root 102: len = MIPS_JIT_PC_HASH_SIZE * sizeof(void *); ! 103: cpu->exec_blk_map = m_memalign(4096,len); ! 104: memset(cpu->exec_blk_map,0,len); 1.1.1.4 root 105: 106: /* Get area size */ 107: if (!(area_size = cpu->vm->exec_area_size)) 108: area_size = MIPS_EXEC_AREA_SIZE; 109: 110: /* Create executable page area */ 111: cpu->exec_page_area_size = area_size * 1048576; 112: cpu->exec_page_area = mmap(NULL,cpu->exec_page_area_size, 113: PROT_EXEC|PROT_READ|PROT_WRITE, 114: MAP_SHARED|MAP_ANONYMOUS,-1,(off_t)0); 115: 116: if (!cpu->exec_page_area) { 117: fprintf(stderr, 118: "mips64_jit_init: unable to create exec area (size %lu)\n", 119: (u_long)cpu->exec_page_area_size); 120: return(-1); 121: } 122: 123: /* Carve the executable page area */ 124: cpu->exec_page_count = cpu->exec_page_area_size / MIPS_JIT_BUFSIZE; 125: 126: cpu->exec_page_array = calloc(cpu->exec_page_count, 127: sizeof(insn_exec_page_t)); 1.1.1.2 root 128: 1.1.1.4 root 129: if (!cpu->exec_page_array) { 130: fprintf(stderr,"mips64_jit_init: unable to create exec page array\n"); 131: return(-1); 132: } 133: 134: for(i=0,cp_addr=cpu->exec_page_area;i<cpu->exec_page_count;i++) { 135: cp = &cpu->exec_page_array[i]; 136: 137: cp->ptr = cp_addr; 138: cp_addr += MIPS_JIT_BUFSIZE; 1.1.1.2 root 139: 1.1.1.4 root 140: cp->next = cpu->exec_page_free_list; 141: cpu->exec_page_free_list = cp; 1.1.1.2 root 142: } 1.1.1.4 root 143: 144: printf("CPU%u: carved JIT exec zone of %lu Mb into %lu pages of %u Kb.\n", 1.1.1.9 root 145: cpu->gen->id, 146: (u_long)(cpu->exec_page_area_size / 1048576), 1.1.1.4 root 147: (u_long)cpu->exec_page_count,MIPS_JIT_BUFSIZE / 1024); 148: return(0); 1.1.1.2 root 149: } 150: 1.1.1.4 root 151: /* Flush the JIT */ 152: u_int mips64_jit_flush(cpu_mips_t *cpu,u_int threshold) 1.1.1.2 root 153: { 1.1.1.9 root 154: mips64_jit_tcb_t *p,*next; 1.1.1.10! root 155: m_uint32_t pc_hash; 1.1.1.4 root 156: u_int count = 0; 157: 158: if (!threshold) 159: threshold = (u_int)(-1); /* UINT_MAX not defined everywhere */ 1.1.1.2 root 160: 1.1.1.9 root 161: for(p=cpu->tcb_list;p;p=next) { 1.1.1.4 root 162: next = p->next; 163: 164: if (p->acc_count <= threshold) { 1.1.1.10! root 165: pc_hash = mips64_jit_get_pc_hash(p->start_pc); ! 166: cpu->exec_blk_map[pc_hash] = NULL; 1.1.1.9 root 167: mips64_jit_tcb_free(cpu,p,TRUE); 1.1.1.4 root 168: count++; 169: } 1.1.1.2 root 170: } 1.1.1.4 root 171: 172: cpu->compiled_pages -= count; 173: return(count); 174: } 175: 176: /* Shutdown the JIT */ 177: void mips64_jit_shutdown(cpu_mips_t *cpu) 178: { 1.1.1.9 root 179: mips64_jit_tcb_t *p,*next; 1.1.1.4 root 180: 181: /* Flush the JIT */ 182: mips64_jit_flush(cpu,0); 183: 184: /* Free the instruction blocks */ 1.1.1.9 root 185: for(p=cpu->tcb_free_list;p;p=next) { 1.1.1.4 root 186: next = p->next; 187: free(p); 188: } 189: 190: /* Unmap the executable page area */ 191: if (cpu->exec_page_area) 192: munmap(cpu->exec_page_area,cpu->exec_page_area_size); 193: 194: /* Free the exec page array */ 195: free(cpu->exec_page_array); 196: 197: /* Free physical mapping for executable pages */ 1.1.1.10! root 198: free(cpu->exec_blk_map); 1.1.1.2 root 199: } 200: 1.1.1.4 root 201: /* Allocate an exec page */ 202: static inline insn_exec_page_t *exec_page_alloc(cpu_mips_t *cpu) 1.1.1.2 root 203: { 1.1.1.4 root 204: insn_exec_page_t *p; 205: u_int count; 1.1.1.2 root 206: 1.1.1.4 root 207: /* If the free list is empty, flush JIT */ 208: if (unlikely(!cpu->exec_page_free_list)) 209: { 210: if (cpu->jit_flush_method) { 1.1.1.9 root 211: cpu_log(cpu->gen, 212: "JIT","flushing data structures (compiled pages=%u)\n", 1.1.1.4 root 213: cpu->compiled_pages); 214: mips64_jit_flush(cpu,0); 215: } else { 216: count = mips64_jit_flush(cpu,100); 1.1.1.9 root 217: cpu_log(cpu->gen,"JIT","partial JIT flush (count=%u)\n",count); 1.1.1.4 root 218: 219: if (!cpu->exec_page_free_list) 220: mips64_jit_flush(cpu,0); 1.1.1.2 root 221: } 1.1.1.4 root 222: 223: /* Use both methods alternatively */ 224: cpu->jit_flush_method = 1 - cpu->jit_flush_method; 225: } 226: 227: if (unlikely(!(p = cpu->exec_page_free_list))) 228: return NULL; 229: 230: cpu->exec_page_free_list = p->next; 231: cpu->exec_page_alloc++; 232: return p; 233: } 234: 235: /* Free an exec page and returns it to the pool */ 236: static inline void exec_page_free(cpu_mips_t *cpu,insn_exec_page_t *p) 237: { 238: if (p) { 239: p->next = cpu->exec_page_free_list; 240: cpu->exec_page_free_list = p; 241: cpu->exec_page_alloc--; 1.1.1.2 root 242: } 243: } 244: 1.1 root 245: /* Find the JIT code emitter for the specified MIPS instruction */ 1.1.1.9 root 246: static struct mips64_insn_tag *insn_tag_find(mips_insn_t ins) 1.1 root 247: { 1.1.1.9 root 248: struct mips64_insn_tag *tag = NULL; 1.1 root 249: int index; 250: 251: index = ilt_lookup(ilt,ins); 252: tag = mips64_jit_get_insn(index); 253: return tag; 254: } 255: 256: /* Check if the specified MIPS instruction is a jump */ 1.1.1.9 root 257: static struct mips64_insn_jump *insn_jump_find(mips_insn_t ins) 1.1 root 258: { 1.1.1.9 root 259: struct mips64_insn_jump *jump = NULL; 1.1 root 260: int i; 261: 262: for(i=0;mips64_insn_jumps[i].name;i++) 263: if ((ins & mips64_insn_jumps[i].mask) == mips64_insn_jumps[i].value) { 264: jump = &mips64_insn_jumps[i]; 265: break; 266: } 267: 268: return(jump); 269: } 270: 271: /* Fetch a MIPS instruction */ 1.1.1.9 root 272: static forced_inline mips_insn_t insn_fetch(mips64_jit_tcb_t *b) 1.1 root 273: { 274: return(vmtoh32(b->mips_code[b->mips_trans_pos])); 275: } 276: 277: /* Emit a breakpoint if necessary */ 1.1.1.4 root 278: #if BREAKPOINT_ENABLE 1.1.1.9 root 279: static void insn_emit_breakpoint(cpu_mips_t *cpu,mips64_jit_tcb_t *b) 1.1 root 280: { 281: m_uint64_t pc; 282: int i; 283: 284: pc = b->start_pc+((b->mips_trans_pos-1)<<2); 285: 286: for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++) 287: if (pc == cpu->breakpoints[i]) { 288: mips64_emit_breakpoint(b); 289: break; 290: } 291: } 1.1.1.4 root 292: #endif /* BREAKPOINT_ENABLE */ 1.1 root 293: 1.1.1.9 root 294: /* Get host pointer for the physical address */ 295: static inline void *physmem_get_hptr(vm_instance_t *vm,m_uint64_t paddr, 296: u_int op_size,u_int op_type, 297: m_uint64_t *data) 298: { 299: struct vdevice *dev; 300: m_uint32_t offset; 301: void *ptr; 302: int cow; 303: 304: if (!(dev = dev_lookup(vm,paddr,FALSE))) 305: return NULL; 306: 307: if (dev->flags & VDEVICE_FLAG_SPARSE) { 308: ptr = (void *)dev_sparse_get_host_addr(vm,dev,paddr,op_type,&cow); 309: if (!ptr) return NULL; 310: 311: return(ptr + (paddr & VM_PAGE_IMASK)); 312: } 313: 314: if ((dev->host_addr != 0) && !(dev->flags & VDEVICE_FLAG_NO_MTS_MMAP)) 315: return((void *)dev->host_addr + (paddr - dev->phys_addr)); 316: 317: if (op_size == 0) 318: return NULL; 319: 320: offset = paddr - dev->phys_addr; 321: return(dev->handler(vm->boot_cpu,dev,offset,op_size,op_type,data)); 322: } 323: 1.1.1.10! root 324: /* Check if an instruction is in a delay slot or not */ ! 325: int mips64_jit_is_delay_slot(mips64_jit_tcb_t *b,m_uint64_t pc) ! 326: { ! 327: struct mips64_insn_tag *tag; ! 328: m_uint32_t offset,insn; ! 329: ! 330: offset = (pc - b->start_pc) >> 2; ! 331: ! 332: if (!offset) ! 333: return(FALSE); ! 334: ! 335: /* Fetch the previous instruction to determine if it is a jump */ ! 336: insn = vmtoh32(b->mips_code[offset-1]); ! 337: tag = insn_tag_find(insn); ! 338: assert(tag != NULL); ! 339: return(!tag->delay_slot); ! 340: } ! 341: 1.1 root 342: /* Fetch a MIPS instruction and emit corresponding translated code */ 1.1.1.9 root 343: struct mips64_insn_tag *mips64_jit_fetch_and_emit(cpu_mips_t *cpu, 344: mips64_jit_tcb_t *block, 345: int delay_slot) 1.1 root 346: { 1.1.1.9 root 347: struct mips64_insn_tag *tag; 1.1 root 348: mips_insn_t code; 349: 350: code = insn_fetch(block); 351: tag = insn_tag_find(code); 352: assert(tag); 1.1.1.9 root 353: 354: /* Branch-delay slot is in another page: slow exec */ 355: if ((block->mips_trans_pos == (MIPS_INSN_PER_PAGE-1)) && !tag->delay_slot) { 356: block->jit_insn_ptr[block->mips_trans_pos] = block->jit_ptr; 357: 358: mips64_set_pc(block,block->start_pc + (block->mips_trans_pos << 2)); 359: mips64_emit_single_step(block,code); 360: mips64_jit_tcb_push_epilog(block); 361: block->mips_trans_pos++; 362: return tag; 363: } 364: 1.1 root 365: if (delay_slot && !tag->delay_slot) { 1.1.1.4 root 366: mips64_emit_invalid_delay_slot(block); 1.1 root 367: return NULL; 368: } 369: 1.1.1.9 root 370: if (!delay_slot) 1.1 root 371: block->jit_insn_ptr[block->mips_trans_pos] = block->jit_ptr; 372: 373: if (delay_slot != 2) 374: block->mips_trans_pos++; 375: 1.1.1.8 root 376: #if DEBUG_INSN_PERF_CNT 1.1.1.4 root 377: mips64_inc_perf_counter(block); 378: #endif 1.1 root 379: 1.1.1.4 root 380: if (!delay_slot) { 381: /* Check for IRQs + Increment count register before jumps */ 382: if (!tag->delay_slot) { 383: mips64_inc_cp0_count_reg(block); 384: mips64_check_pending_irq(block); 385: } 386: } 1.1 root 387: 1.1.1.3 root 388: #if BREAKPOINT_ENABLE 389: if (cpu->breakpoints_enabled) 390: insn_emit_breakpoint(cpu,block); 391: #endif 392: 1.1 root 393: tag->emit(cpu,block,code); 394: return tag; 395: } 396: 397: /* Add end of JIT block */ 1.1.1.9 root 398: static void mips64_jit_tcb_add_end(mips64_jit_tcb_t *b) 1.1 root 399: { 400: mips64_set_pc(b,b->start_pc+(b->mips_trans_pos<<2)); 1.1.1.9 root 401: mips64_jit_tcb_push_epilog(b); 1.1 root 402: } 403: 404: /* Record a patch to apply in a compiled block */ 1.1.1.9 root 405: int mips64_jit_tcb_record_patch(mips64_jit_tcb_t *block,u_char *jit_ptr, 406: m_uint64_t vaddr) 1.1 root 407: { 1.1.1.9 root 408: struct mips64_jit_patch_table *ipt = block->patch_table; 409: struct mips64_insn_patch *patch; 1.1 root 410: 411: /* pc must be 32-bit aligned */ 412: if (vaddr & 0x03) { 413: fprintf(stderr,"Block 0x%8.8llx: trying to record an invalid PC " 414: "(0x%8.8llx) - mips_trans_pos=%d.\n", 415: block->start_pc,vaddr,block->mips_trans_pos); 416: return(-1); 417: } 418: 1.1.1.9 root 419: if (!ipt || (ipt->cur_patch >= MIPS64_INSN_PATCH_TABLE_SIZE)) 1.1 root 420: { 421: /* full table or no table, create a new one */ 422: ipt = malloc(sizeof(*ipt)); 423: if (!ipt) { 1.1.1.9 root 424: fprintf(stderr,"Block 0x%8.8llx: unable to create patch table.\n", 425: block->start_pc); 1.1 root 426: return(-1); 427: } 428: 429: memset(ipt,0,sizeof(*ipt)); 430: ipt->next = block->patch_table; 431: block->patch_table = ipt; 432: } 433: 434: #if DEBUG_BLOCK_PATCH 435: printf("Block 0x%8.8llx: recording patch [JIT:%p->mips:0x%8.8llx], " 436: "MTP=%d\n",block->start_pc,jit_ptr,vaddr,block->mips_trans_pos); 437: #endif 438: 439: patch = &ipt->patches[ipt->cur_patch]; 440: patch->jit_insn = jit_ptr; 441: patch->mips_pc = vaddr; 442: ipt->cur_patch++; 443: return(0); 444: } 445: 446: /* Apply all patches */ 1.1.1.9 root 447: static int mips64_jit_tcb_apply_patches(cpu_mips_t *cpu, 448: mips64_jit_tcb_t *block) 1.1 root 449: { 1.1.1.9 root 450: struct mips64_jit_patch_table *ipt; 451: struct mips64_insn_patch *patch; 1.1 root 452: u_char *jit_dst; 453: int i; 454: 455: for(ipt=block->patch_table;ipt;ipt=ipt->next) 456: for(i=0;i<ipt->cur_patch;i++) 457: { 458: patch = &ipt->patches[i]; 1.1.1.9 root 459: jit_dst = mips64_jit_tcb_get_host_ptr(block,patch->mips_pc); 1.1 root 460: 1.1.1.4 root 461: if (jit_dst) { 1.1 root 462: #if DEBUG_BLOCK_PATCH 1.1.1.4 root 463: printf("Block 0x%8.8llx: applying patch " 464: "[JIT:%p->mips:0x%8.8llx=JIT:%p]\n", 465: block->start_pc,patch->jit_insn,patch->mips_pc,jit_dst); 1.1 root 466: #endif 1.1.1.9 root 467: mips64_jit_tcb_set_patch(patch->jit_insn,jit_dst); 1.1 root 468: } 469: } 470: 471: return(0); 472: } 473: 1.1.1.4 root 474: /* Free the patch table */ 1.1.1.9 root 475: static void mips64_jit_tcb_free_patches(mips64_jit_tcb_t *block) 1.1.1.4 root 476: { 1.1.1.9 root 477: struct mips64_jit_patch_table *p,*next; 1.1.1.4 root 478: 479: for(p=block->patch_table;p;p=next) { 480: next = p->next; 481: free(p); 482: } 483: 484: block->patch_table = NULL; 485: } 486: 1.1 root 487: /* Adjust the JIT buffer if its size is not sufficient */ 1.1.1.9 root 488: static int mips64_jit_tcb_adjust_buffer(cpu_mips_t *cpu, 489: mips64_jit_tcb_t *block) 1.1 root 490: { 1.1.1.4 root 491: insn_exec_page_t *new_buffer; 1.1 root 492: 1.1.1.4 root 493: if ((block->jit_ptr - block->jit_buffer->ptr) <= (MIPS_JIT_BUFSIZE - 512)) 1.1 root 494: return(0); 495: 496: #if DEBUG_BLOCK_CHUNK 497: printf("Block 0x%llx: adjusting JIT buffer...\n",block->start_pc); 498: #endif 499: 1.1.1.9 root 500: if (block->jit_chunk_pos >= MIPS_JIT_MAX_CHUNKS) { 1.1 root 501: fprintf(stderr,"Block 0x%llx: too many JIT chunks.\n",block->start_pc); 502: return(-1); 503: } 504: 1.1.1.4 root 505: if (!(new_buffer = exec_page_alloc(cpu))) 1.1 root 506: return(-1); 507: 1.1.1.4 root 508: /* record the new exec page */ 509: block->jit_chunks[block->jit_chunk_pos++] = block->jit_buffer; 510: block->jit_buffer = new_buffer; 511: 512: /* jump to the new exec page (link) */ 1.1.1.9 root 513: mips64_jit_tcb_set_jump(block->jit_ptr,new_buffer->ptr); 1.1.1.4 root 514: block->jit_ptr = new_buffer->ptr; 1.1 root 515: return(0); 516: } 517: 1.1.1.4 root 518: /* Allocate an instruction block */ 1.1.1.9 root 519: static inline mips64_jit_tcb_t *mips64_jit_tcb_alloc(cpu_mips_t *cpu) 1.1 root 520: { 1.1.1.9 root 521: mips64_jit_tcb_t *p; 1.1 root 522: 1.1.1.9 root 523: if (cpu->tcb_free_list) { 524: p = cpu->tcb_free_list; 525: cpu->tcb_free_list = p->next; 1.1.1.4 root 526: } else { 527: if (!(p = malloc(sizeof(*p)))) 528: return NULL; 529: } 1.1 root 530: 1.1.1.4 root 531: memset(p,0,sizeof(*p)); 532: return p; 533: } 1.1 root 534: 1.1.1.4 root 535: /* Free an instruction block */ 1.1.1.9 root 536: void mips64_jit_tcb_free(cpu_mips_t *cpu,mips64_jit_tcb_t *block, 537: int list_removal) 1.1.1.4 root 538: { 539: int i; 1.1 root 540: 1.1.1.4 root 541: if (block) { 542: if (list_removal) { 543: /* Remove the block from the linked list */ 544: if (block->next) 545: block->next->prev = block->prev; 546: else 1.1.1.9 root 547: cpu->tcb_last = block->prev; 1.1.1.4 root 548: 549: if (block->prev) 550: block->prev->next = block->next; 551: else 1.1.1.9 root 552: cpu->tcb_list = block->next; 1.1 root 553: } 554: 1.1.1.4 root 555: /* Free the patch tables */ 1.1.1.9 root 556: mips64_jit_tcb_free_patches(block); 1.1 root 557: 1.1.1.4 root 558: /* Free code pages */ 1.1.1.9 root 559: for(i=0;i<MIPS_JIT_MAX_CHUNKS;i++) 1.1.1.4 root 560: exec_page_free(cpu,block->jit_chunks[i]); 1.1 root 561: 1.1.1.4 root 562: /* Free the current JIT buffer */ 563: exec_page_free(cpu,block->jit_buffer); 1.1 root 564: 1.1.1.4 root 565: /* Free the MIPS-to-native code mapping */ 566: free(block->jit_insn_ptr); 1.1 root 567: 1.1.1.4 root 568: /* Make the block return to the free list */ 1.1.1.9 root 569: block->next = cpu->tcb_free_list; 570: cpu->tcb_free_list = block; 1.1 root 571: } 1.1.1.4 root 572: } 1.1 root 573: 1.1.1.4 root 574: /* Create an instruction block */ 1.1.1.9 root 575: static mips64_jit_tcb_t *mips64_jit_tcb_create(cpu_mips_t *cpu, 576: m_uint64_t vaddr) 1.1.1.4 root 577: { 1.1.1.9 root 578: mips64_jit_tcb_t *block = NULL; 1.1 root 579: 1.1.1.9 root 580: if (!(block = mips64_jit_tcb_alloc(cpu))) 1.1.1.4 root 581: goto err_block_alloc; 582: 583: block->start_pc = vaddr; 1.1 root 584: 1.1.1.4 root 585: /* Allocate the first JIT buffer */ 586: if (!(block->jit_buffer = exec_page_alloc(cpu))) 587: goto err_jit_alloc; 1.1 root 588: 1.1.1.4 root 589: block->jit_ptr = block->jit_buffer->ptr; 590: block->mips_code = cpu->mem_op_lookup(cpu,block->start_pc); 591: 592: if (!block->mips_code) { 593: fprintf(stderr,"%% No memory map for code execution at 0x%llx\n", 594: block->start_pc); 595: goto err_lookup; 596: } 597: 598: #if DEBUG_BLOCK_TIMESTAMP 599: block->tm_first_use = block->tm_last_use = jit_jiffies; 1.1 root 600: #endif 1.1.1.4 root 601: return block; 1.1 root 602: 1.1.1.4 root 603: err_lookup: 604: err_jit_alloc: 1.1.1.9 root 605: mips64_jit_tcb_free(cpu,block,FALSE); 1.1.1.4 root 606: err_block_alloc: 607: fprintf(stderr,"%% Unable to create instruction block for vaddr=0x%llx\n", 608: vaddr); 609: return NULL; 1.1 root 610: } 611: 1.1.1.4 root 612: /* Compile a MIPS instruction page */ 1.1.1.9 root 613: static inline 614: mips64_jit_tcb_t *mips64_jit_tcb_compile(cpu_mips_t *cpu,m_uint64_t vaddr) 1.1 root 615: { 1.1.1.9 root 616: mips64_jit_tcb_t *block; 617: struct mips64_insn_tag *tag; 1.1.1.4 root 618: m_uint64_t page_addr; 619: size_t len; 620: 621: page_addr = vaddr & ~(m_uint64_t)MIPS_MIN_PAGE_IMASK; 622: 1.1.1.9 root 623: if (unlikely(!(block = mips64_jit_tcb_create(cpu,page_addr)))) { 1.1.1.4 root 624: fprintf(stderr,"insn_page_compile: unable to create JIT block.\n"); 625: return NULL; 626: } 627: 628: /* Allocate the array used to convert MIPS code ptr to native code ptr */ 629: len = MIPS_MIN_PAGE_SIZE / sizeof(mips_insn_t); 630: 631: if (!(block->jit_insn_ptr = calloc(len,sizeof(u_char *)))) { 632: fprintf(stderr,"insn_page_compile: unable to create JIT mappings.\n"); 633: goto error; 634: } 1.1 root 635: 1.1.1.4 root 636: /* Emit native code for each instruction */ 1.1 root 637: block->mips_trans_pos = 0; 638: 1.1.1.9 root 639: while(block->mips_trans_pos < MIPS_INSN_PER_PAGE) 1.1 root 640: { 1.1.1.9 root 641: if (unlikely(!(tag = mips64_jit_fetch_and_emit(cpu,block,0)))) { 1.1.1.4 root 642: fprintf(stderr,"insn_page_compile: unable to fetch instruction.\n"); 643: goto error; 644: } 1.1 root 645: 646: #if DEBUG_BLOCK_COMPILE 1.1.1.4 root 647: printf("Page 0x%8.8llx: emitted tag 0x%8.8x/0x%8.8x\n", 1.1 root 648: block->start_pc,tag->mask,tag->value); 649: #endif 650: 1.1.1.9 root 651: mips64_jit_tcb_adjust_buffer(cpu,block); 1.1 root 652: } 653: 1.1.1.9 root 654: mips64_jit_tcb_add_end(block); 655: mips64_jit_tcb_apply_patches(cpu,block); 656: mips64_jit_tcb_free_patches(block); 1.1 root 657: 1.1.1.4 root 658: /* Add the block to the linked list */ 1.1.1.9 root 659: block->next = cpu->tcb_list; 1.1.1.4 root 660: block->prev = NULL; 661: 1.1.1.9 root 662: if (cpu->tcb_list) 663: cpu->tcb_list->prev = block; 1.1.1.4 root 664: else 1.1.1.9 root 665: cpu->tcb_last = block; 1.1 root 666: 1.1.1.9 root 667: cpu->tcb_list = block; 1.1.1.2 root 668: 1.1.1.4 root 669: cpu->compiled_pages++; 1.1 root 670: return block; 1.1.1.4 root 671: 672: error: 1.1.1.9 root 673: mips64_jit_tcb_free(cpu,block,FALSE); 1.1.1.4 root 674: return NULL; 1.1 root 675: } 676: 677: /* Run a compiled MIPS instruction block */ 1.1.1.9 root 678: static forced_inline 679: void mips64_jit_tcb_run(cpu_mips_t *cpu,mips64_jit_tcb_t *block) 1.1 root 680: { 681: #if DEBUG_SYM_TREE 682: struct symbol *sym = NULL; 683: int mark = FALSE; 684: #endif 685: 686: if (unlikely(cpu->pc & 0x03)) { 1.1.1.9 root 687: fprintf(stderr,"mips64_jit_tcb_run: Invalid PC 0x%llx.\n",cpu->pc); 688: mips64_dump_regs(cpu->gen); 689: mips64_tlb_dump(cpu->gen); 690: cpu_stop(cpu->gen); 1.1.1.4 root 691: return; 1.1 root 692: } 693: 694: #if DEBUG_SYM_TREE 1.1.1.4 root 695: if (cpu->sym_trace && cpu->sym_tree) 1.1 root 696: { 1.1.1.4 root 697: if ((sym = mips64_sym_lookup(cpu,cpu->pc)) != NULL) { 1.1.1.9 root 698: cpu_log(cpu,"mips64_jit_tcb_run(start)", 1.1.1.4 root 699: "%s (PC=0x%llx) RA = 0x%llx\na0=0x%llx, " 1.1 root 700: "a1=0x%llx, a2=0x%llx, a3=0x%llx\n", 701: sym->name, cpu->pc, cpu->gpr[MIPS_GPR_RA], 702: cpu->gpr[MIPS_GPR_A0], cpu->gpr[MIPS_GPR_A1], 703: cpu->gpr[MIPS_GPR_A2], cpu->gpr[MIPS_GPR_A3]); 704: mark = TRUE; 705: } 706: } 707: #endif 708: 709: /* Execute JIT compiled code */ 1.1.1.9 root 710: mips64_jit_tcb_exec(cpu,block); 1.1 root 711: 712: #if DEBUG_SYM_TREE 713: if (mark) { 1.1.1.9 root 714: cpu_log(cpu,"mips64_jit_tcb_run(end)","%s, v0 = 0x%llx\n", 1.1 root 715: sym->name,cpu->gpr[MIPS_GPR_V0]); 716: } 717: #endif 718: } 719: 1.1.1.9 root 720: /* Execute compiled MIPS code */ 721: void *mips64_jit_run_cpu(cpu_gen_t *gen) 722: { 723: cpu_mips_t *cpu = CPU_MIPS64(gen); 1.1.1.4 root 724: pthread_t timer_irq_thread; 1.1.1.9 root 725: mips64_jit_tcb_t *block; 1.1.1.4 root 726: int timer_irq_check = 0; 1.1.1.10! root 727: m_uint32_t pc_hash; 1.1 root 728: 1.1.1.4 root 729: if (pthread_create(&timer_irq_thread,NULL, 730: (void *)mips64_timer_irq_run,cpu)) 731: { 1.1.1.7 root 732: fprintf(stderr, 733: "VM '%s': unable to create Timer IRQ thread for CPU%u.\n", 1.1.1.9 root 734: cpu->vm->name,gen->id); 735: cpu_stop(cpu->gen); 1.1.1.4 root 736: return NULL; 737: } 738: 1.1.1.9 root 739: gen->cpu_thread_running = TRUE; 1.1.1.4 root 740: start_cpu: 1.1.1.9 root 741: gen->idle_count = 0; 1.1.1.6 root 742: 1.1 root 743: for(;;) { 1.1.1.9 root 744: if (unlikely(gen->state != CPU_STATE_RUNNING)) 1.1 root 745: break; 746: 1.1.1.8 root 747: #if DEBUG_BLOCK_PERF_CNT 748: cpu->perf_counter++; 749: #endif 1.1.1.4 root 750: /* Handle virtual idle loop */ 751: if (unlikely(cpu->pc == cpu->idle_pc)) { 1.1.1.9 root 752: if (++gen->idle_count == gen->idle_max) { 753: cpu_idle_loop(gen); 754: gen->idle_count = 0; 1.1.1.4 root 755: } 756: } 757: 758: /* Handle the virtual CPU clock */ 759: if (++timer_irq_check == cpu->timer_irq_check_itv) { 760: timer_irq_check = 0; 761: 762: if (cpu->timer_irq_pending && !cpu->irq_disable) { 763: mips64_trigger_timer_irq(cpu); 764: mips64_trigger_irq(cpu); 765: cpu->timer_irq_pending--; 766: } 767: } 1.1 root 768: 1.1.1.10! root 769: pc_hash = mips64_jit_get_pc_hash(cpu->pc); ! 770: block = cpu->exec_blk_map[pc_hash]; 1.1.1.4 root 771: 772: /* No block found, compile the page */ 1.1.1.9 root 773: if (unlikely(!block) || unlikely(!mips64_jit_tcb_match(cpu,block))) 1.1.1.10! root 774: { 1.1.1.5 root 775: if (block != NULL) { 1.1.1.9 root 776: mips64_jit_tcb_free(cpu,block,TRUE); 1.1.1.10! root 777: cpu->exec_blk_map[pc_hash] = NULL; 1.1.1.5 root 778: } 779: 1.1.1.9 root 780: block = mips64_jit_tcb_compile(cpu,cpu->pc); 1.1.1.4 root 781: if (unlikely(!block)) { 782: fprintf(stderr, 783: "VM '%s': unable to compile block for CPU%u PC=0x%llx\n", 1.1.1.9 root 784: cpu->vm->name,gen->id,cpu->pc); 785: cpu_stop(gen); 1.1.1.4 root 786: break; 1.1 root 787: } 1.1.1.2 root 788: 1.1.1.10! root 789: cpu->exec_blk_map[pc_hash] = block; 1.1 root 790: } 791: 792: #if DEBUG_BLOCK_TIMESTAMP 793: block->tm_last_use = jit_jiffies++; 794: #endif 795: block->acc_count++; 1.1.1.9 root 796: mips64_jit_tcb_run(cpu,block); 1.1 root 797: } 1.1.1.4 root 798: 1.1 root 799: if (!cpu->pc) { 1.1.1.9 root 800: cpu_stop(gen); 801: cpu_log(gen,"JIT","PC=0, halting CPU.\n"); 1.1 root 802: } 803: 1.1.1.4 root 804: /* Check regularly if the CPU has been restarted */ 1.1.1.9 root 805: while(gen->cpu_thread_running) { 806: gen->seq_state++; 1.1.1.4 root 807: 1.1.1.9 root 808: switch(gen->state) { 809: case CPU_STATE_RUNNING: 810: gen->state = CPU_STATE_RUNNING; 1.1.1.4 root 811: goto start_cpu; 812: 1.1.1.9 root 813: case CPU_STATE_HALTED: 814: gen->cpu_thread_running = FALSE; 1.1.1.4 root 815: pthread_join(timer_irq_thread,NULL); 816: break; 817: } 1.1 root 818: 1.1.1.4 root 819: /* CPU is paused */ 1.1 root 820: usleep(200000); 1.1.1.4 root 821: } 1.1 root 822: 823: return NULL; 824: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.