|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.