Annotation of cf/mips64_jit.c, revision 1.1.1.12

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.11  root      740:    cpu_exec_loop_set(gen);
                    741:    
1.1.1.4   root      742:  start_cpu:   
1.1.1.9   root      743:    gen->idle_count = 0;
1.1.1.6   root      744: 
1.1       root      745:    for(;;) {
1.1.1.9   root      746:       if (unlikely(gen->state != CPU_STATE_RUNNING))
1.1       root      747:          break;
                    748: 
1.1.1.8   root      749: #if DEBUG_BLOCK_PERF_CNT
                    750:       cpu->perf_counter++;
                    751: #endif
1.1.1.4   root      752:       /* Handle virtual idle loop */
                    753:       if (unlikely(cpu->pc == cpu->idle_pc)) {
1.1.1.9   root      754:          if (++gen->idle_count == gen->idle_max) {
                    755:             cpu_idle_loop(gen);
                    756:             gen->idle_count = 0;
1.1.1.4   root      757:          }
                    758:       }
                    759: 
                    760:       /* Handle the virtual CPU clock */
                    761:       if (++timer_irq_check == cpu->timer_irq_check_itv) {
                    762:          timer_irq_check = 0;
                    763: 
                    764:          if (cpu->timer_irq_pending && !cpu->irq_disable) {
                    765:             mips64_trigger_timer_irq(cpu);
                    766:             mips64_trigger_irq(cpu);
                    767:             cpu->timer_irq_pending--;
                    768:          }
                    769:       }
1.1       root      770: 
1.1.1.10  root      771:       pc_hash = mips64_jit_get_pc_hash(cpu->pc);
                    772:       block = cpu->exec_blk_map[pc_hash];
1.1.1.4   root      773: 
                    774:       /* No block found, compile the page */
1.1.1.9   root      775:       if (unlikely(!block) || unlikely(!mips64_jit_tcb_match(cpu,block))) 
1.1.1.10  root      776:       {        
1.1.1.5   root      777:          if (block != NULL) {
1.1.1.9   root      778:             mips64_jit_tcb_free(cpu,block,TRUE);
1.1.1.10  root      779:             cpu->exec_blk_map[pc_hash] = NULL;
1.1.1.5   root      780:          }
                    781: 
1.1.1.9   root      782:          block = mips64_jit_tcb_compile(cpu,cpu->pc);
1.1.1.4   root      783:          if (unlikely(!block)) {
                    784:             fprintf(stderr,
                    785:                     "VM '%s': unable to compile block for CPU%u PC=0x%llx\n",
1.1.1.9   root      786:                     cpu->vm->name,gen->id,cpu->pc);
                    787:             cpu_stop(gen);
1.1.1.4   root      788:             break;
1.1       root      789:          }
1.1.1.2   root      790: 
1.1.1.10  root      791:          cpu->exec_blk_map[pc_hash] = block;
1.1       root      792:       }
                    793: 
                    794: #if DEBUG_BLOCK_TIMESTAMP
                    795:       block->tm_last_use = jit_jiffies++;
                    796: #endif
                    797:       block->acc_count++;
1.1.1.9   root      798:       mips64_jit_tcb_run(cpu,block);
1.1       root      799:    }
1.1.1.4   root      800:       
1.1       root      801:    if (!cpu->pc) {
1.1.1.9   root      802:       cpu_stop(gen);
                    803:       cpu_log(gen,"JIT","PC=0, halting CPU.\n");
1.1       root      804:    }
                    805: 
1.1.1.4   root      806:    /* Check regularly if the CPU has been restarted */
1.1.1.9   root      807:    while(gen->cpu_thread_running) {
                    808:       gen->seq_state++;
1.1.1.4   root      809: 
1.1.1.9   root      810:       switch(gen->state) {
                    811:          case CPU_STATE_RUNNING:
                    812:             gen->state = CPU_STATE_RUNNING;
1.1.1.4   root      813:             goto start_cpu;
                    814: 
1.1.1.9   root      815:          case CPU_STATE_HALTED:
                    816:             gen->cpu_thread_running = FALSE;
1.1.1.4   root      817:             pthread_join(timer_irq_thread,NULL);
1.1.1.12! root      818:             return NULL;
1.1.1.4   root      819:       }
1.1       root      820:       
1.1.1.4   root      821:       /* CPU is paused */
1.1       root      822:       usleep(200000);
1.1.1.4   root      823:    }
1.1       root      824: 
                    825:    return NULL;
                    826: }

unix.superglobalmegacorp.com

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