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