Annotation of cf/mips64_jit.c, revision 1.1.1.7

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: 
1.1.1.5   root      663: /* Check if PC register matches the compiled block virtual address */
                    664: static forced_inline int insn_block_match(cpu_mips_t *cpu,insn_block_t *block)
                    665: {
                    666:    m_uint64_t vpage;
                    667: 
                    668:    vpage = cpu->pc & ~(m_uint64_t)MIPS_MIN_PAGE_IMASK;
                    669:    return(block->start_pc == vpage);
                    670: }
                    671: 
1.1       root      672: /* Execute a compiled MIPS code */
                    673: void *insn_block_execute(cpu_mips_t *cpu)
1.1.1.4   root      674: {  
                    675:    pthread_t timer_irq_thread;
1.1       root      676:    insn_block_t *block;
1.1.1.4   root      677:    m_uint32_t phys_page;
                    678:    int timer_irq_check = 0;
1.1       root      679: 
1.1.1.4   root      680:    if (pthread_create(&timer_irq_thread,NULL,
                    681:                       (void *)mips64_timer_irq_run,cpu)) 
                    682:    {
1.1.1.7 ! root      683:       fprintf(stderr,
        !           684:               "VM '%s': unable to create Timer IRQ thread for CPU%u.\n",
1.1.1.4   root      685:               cpu->vm->name,cpu->id);
                    686:       cpu_stop(cpu);
                    687:       return NULL;
                    688:    }
                    689: 
                    690:    cpu->cpu_thread_running = TRUE;
1.1.1.6   root      691: 
1.1.1.4   root      692:  start_cpu:   
1.1.1.6   root      693:    cpu->idle_count = 0;
                    694: 
1.1       root      695:    for(;;) {
1.1.1.5   root      696:       if (unlikely(cpu->state != MIPS_CPU_RUNNING))
1.1       root      697:          break;
                    698: 
1.1.1.4   root      699:       /* Handle virtual idle loop */
                    700:       if (unlikely(cpu->pc == cpu->idle_pc)) {
1.1.1.6   root      701:          if (++cpu->idle_count == cpu->idle_max) {
1.1.1.4   root      702:             mips64_idle_loop(cpu);
1.1.1.6   root      703:             cpu->idle_count = 0;
1.1.1.4   root      704:          }
                    705:       }
                    706: 
                    707:       /* Handle the virtual CPU clock */
                    708:       if (++timer_irq_check == cpu->timer_irq_check_itv) {
                    709:          timer_irq_check = 0;
                    710: 
                    711:          if (cpu->timer_irq_pending && !cpu->irq_disable) {
                    712:             mips64_trigger_timer_irq(cpu);
                    713:             mips64_trigger_irq(cpu);
                    714:             cpu->timer_irq_pending--;
                    715:          }
                    716:       }
1.1       root      717: 
1.1.1.4   root      718:       /* Get the physical page address corresponding to PC register */
                    719:       if (unlikely(cpu->translate(cpu,cpu->pc,&phys_page))) {
                    720:          fprintf(stderr,"VM '%s': no physical page for CPU%u PC=0x%llx\n",
                    721:                  cpu->vm->name,cpu->id,cpu->pc);
                    722:          cpu_stop(cpu);
                    723:          break;
                    724:       }
1.1.1.2   root      725: 
1.1.1.4   root      726:       block = cpu->exec_phys_map[phys_page];
                    727: 
                    728:       /* No block found, compile the page */
1.1.1.5   root      729:       if (unlikely(!block) || unlikely(!insn_block_match(cpu,block))) 
                    730:       {
                    731:          if (block != NULL) {
                    732:             insn_block_free(cpu,block,TRUE);
                    733:             cpu->exec_phys_map[phys_page] = NULL;
                    734:          }
                    735: 
1.1.1.4   root      736:          block = insn_page_compile(cpu,cpu->pc);
                    737:          if (unlikely(!block)) {
                    738:             fprintf(stderr,
                    739:                     "VM '%s': unable to compile block for CPU%u PC=0x%llx\n",
                    740:                     cpu->vm->name,cpu->id,cpu->pc);
                    741:             cpu_stop(cpu);
                    742:             break;
1.1       root      743:          }
1.1.1.2   root      744: 
1.1.1.4   root      745:          block->phys_page = phys_page;
                    746:          cpu->exec_phys_map[phys_page] = block;
1.1       root      747:       }
                    748: 
                    749: #if DEBUG_BLOCK_TIMESTAMP
                    750:       block->tm_last_use = jit_jiffies++;
                    751: #endif
                    752:       block->acc_count++;
                    753:       insn_block_run(cpu,block);
                    754:    }
1.1.1.4   root      755:       
1.1       root      756:    if (!cpu->pc) {
                    757:       cpu_stop(cpu);
1.1.1.4   root      758:       cpu_log(cpu,"JIT","PC=0, halting CPU.\n");
1.1       root      759:    }
                    760: 
1.1.1.4   root      761:    /* Check regularly if the CPU has been restarted */
                    762:    while(cpu->cpu_thread_running) {
                    763:       cpu->seq_state++;
                    764: 
                    765:       switch(cpu->state) {
                    766:          case MIPS_CPU_RUNNING:
                    767:             cpu->state = MIPS_CPU_RUNNING;
                    768:             goto start_cpu;
                    769: 
                    770:          case MIPS_CPU_HALTED:
                    771:             cpu->cpu_thread_running = FALSE;
                    772:             pthread_join(timer_irq_thread,NULL);
                    773:             break;
                    774:       }
1.1       root      775:       
1.1.1.4   root      776:       /* CPU is paused */
1.1       root      777:       usleep(200000);
1.1.1.4   root      778:    }
1.1       root      779: 
                    780:    return NULL;
                    781: }

unix.superglobalmegacorp.com

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