Annotation of cf/mips64_jit.c, revision 1.1.1.4

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.