/[dynamips]/trunk/mips64_jit.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/mips64_jit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Sat Oct 6 16:29:14 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7/mips64_jit.c
File MIME type: text/plain
File size: 22103 byte(s)
dynamips-0.2.7

1 dpavlin 1 /*
2 dpavlin 7 * Cisco router simulation platform.
3 dpavlin 1 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
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 dpavlin 8 #include "sbox.h"
20 dpavlin 1 #include "cpu.h"
21     #include "device.h"
22     #include "mips64.h"
23 dpavlin 7 #include "mips64_cp0.h"
24 dpavlin 1 #include "mips64_exec.h"
25 dpavlin 7 #include "mips64_jit.h"
26 dpavlin 1 #include "insn_lookup.h"
27 dpavlin 7 #include "memory.h"
28 dpavlin 1 #include "ptask.h"
29    
30 dpavlin 7 #include MIPS64_ARCH_INC_FILE
31    
32 dpavlin 1 #if DEBUG_BLOCK_TIMESTAMP
33     static volatile m_uint64_t jit_jiffies = 0;
34     #endif
35    
36     /* MIPS jump instructions for block scan */
37 dpavlin 7 struct mips64_insn_jump mips64_insn_jumps[] = {
38 dpavlin 1 { "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    
68 dpavlin 7 static int mips64_jit_chk_lo(struct mips64_insn_tag *tag,int value)
69 dpavlin 1 {
70     return((value & tag->mask) == (tag->value & 0xFFFF));
71     }
72    
73 dpavlin 7 static int mips64_jit_chk_hi(struct mips64_insn_tag *tag,int value)
74 dpavlin 1 {
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    
86 dpavlin 8 ilt = ilt_create("mips64j",count,
87 dpavlin 1 (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    
92     /* Initialize the JIT structure */
93     int mips64_jit_init(cpu_mips_t *cpu)
94     {
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 */
102 dpavlin 8 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);
105 dpavlin 1
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));
128    
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;
139    
140     cp->next = cpu->exec_page_free_list;
141     cpu->exec_page_free_list = cp;
142     }
143    
144     printf("CPU%u: carved JIT exec zone of %lu Mb into %lu pages of %u Kb.\n",
145 dpavlin 7 cpu->gen->id,
146     (u_long)(cpu->exec_page_area_size / 1048576),
147 dpavlin 1 (u_long)cpu->exec_page_count,MIPS_JIT_BUFSIZE / 1024);
148     return(0);
149     }
150    
151     /* Flush the JIT */
152     u_int mips64_jit_flush(cpu_mips_t *cpu,u_int threshold)
153     {
154 dpavlin 7 mips64_jit_tcb_t *p,*next;
155 dpavlin 8 m_uint32_t pc_hash;
156 dpavlin 1 u_int count = 0;
157    
158     if (!threshold)
159     threshold = (u_int)(-1); /* UINT_MAX not defined everywhere */
160    
161 dpavlin 7 for(p=cpu->tcb_list;p;p=next) {
162 dpavlin 1 next = p->next;
163    
164     if (p->acc_count <= threshold) {
165 dpavlin 8 pc_hash = mips64_jit_get_pc_hash(p->start_pc);
166     cpu->exec_blk_map[pc_hash] = NULL;
167 dpavlin 7 mips64_jit_tcb_free(cpu,p,TRUE);
168 dpavlin 1 count++;
169     }
170     }
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     {
179 dpavlin 7 mips64_jit_tcb_t *p,*next;
180 dpavlin 1
181     /* Flush the JIT */
182     mips64_jit_flush(cpu,0);
183    
184     /* Free the instruction blocks */
185 dpavlin 7 for(p=cpu->tcb_free_list;p;p=next) {
186 dpavlin 1 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 */
198 dpavlin 8 free(cpu->exec_blk_map);
199 dpavlin 1 }
200    
201     /* Allocate an exec page */
202     static inline insn_exec_page_t *exec_page_alloc(cpu_mips_t *cpu)
203     {
204     insn_exec_page_t *p;
205     u_int count;
206    
207     /* If the free list is empty, flush JIT */
208     if (unlikely(!cpu->exec_page_free_list))
209     {
210     if (cpu->jit_flush_method) {
211 dpavlin 7 cpu_log(cpu->gen,
212     "JIT","flushing data structures (compiled pages=%u)\n",
213 dpavlin 1 cpu->compiled_pages);
214     mips64_jit_flush(cpu,0);
215     } else {
216     count = mips64_jit_flush(cpu,100);
217 dpavlin 7 cpu_log(cpu->gen,"JIT","partial JIT flush (count=%u)\n",count);
218 dpavlin 1
219     if (!cpu->exec_page_free_list)
220     mips64_jit_flush(cpu,0);
221     }
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--;
242     }
243     }
244    
245     /* Find the JIT code emitter for the specified MIPS instruction */
246 dpavlin 7 static struct mips64_insn_tag *insn_tag_find(mips_insn_t ins)
247 dpavlin 1 {
248 dpavlin 7 struct mips64_insn_tag *tag = NULL;
249 dpavlin 1 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 */
257 dpavlin 7 static struct mips64_insn_jump *insn_jump_find(mips_insn_t ins)
258 dpavlin 1 {
259 dpavlin 7 struct mips64_insn_jump *jump = NULL;
260 dpavlin 1 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 */
272 dpavlin 7 static forced_inline mips_insn_t insn_fetch(mips64_jit_tcb_t *b)
273 dpavlin 1 {
274     return(vmtoh32(b->mips_code[b->mips_trans_pos]));
275     }
276    
277     /* Emit a breakpoint if necessary */
278     #if BREAKPOINT_ENABLE
279 dpavlin 7 static void insn_emit_breakpoint(cpu_mips_t *cpu,mips64_jit_tcb_t *b)
280 dpavlin 1 {
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     }
292     #endif /* BREAKPOINT_ENABLE */
293    
294 dpavlin 7 /* 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    
324 dpavlin 8 /* 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    
342 dpavlin 1 /* Fetch a MIPS instruction and emit corresponding translated code */
343 dpavlin 7 struct mips64_insn_tag *mips64_jit_fetch_and_emit(cpu_mips_t *cpu,
344     mips64_jit_tcb_t *block,
345     int delay_slot)
346 dpavlin 1 {
347 dpavlin 7 struct mips64_insn_tag *tag;
348 dpavlin 1 mips_insn_t code;
349    
350     code = insn_fetch(block);
351     tag = insn_tag_find(code);
352     assert(tag);
353 dpavlin 7
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    
365 dpavlin 1 if (delay_slot && !tag->delay_slot) {
366     mips64_emit_invalid_delay_slot(block);
367     return NULL;
368     }
369    
370 dpavlin 7 if (!delay_slot)
371 dpavlin 1 block->jit_insn_ptr[block->mips_trans_pos] = block->jit_ptr;
372    
373     if (delay_slot != 2)
374     block->mips_trans_pos++;
375    
376 dpavlin 5 #if DEBUG_INSN_PERF_CNT
377 dpavlin 1 mips64_inc_perf_counter(block);
378     #endif
379    
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     }
387    
388     #if BREAKPOINT_ENABLE
389     if (cpu->breakpoints_enabled)
390     insn_emit_breakpoint(cpu,block);
391     #endif
392    
393     tag->emit(cpu,block,code);
394     return tag;
395     }
396    
397     /* Add end of JIT block */
398 dpavlin 7 static void mips64_jit_tcb_add_end(mips64_jit_tcb_t *b)
399 dpavlin 1 {
400     mips64_set_pc(b,b->start_pc+(b->mips_trans_pos<<2));
401 dpavlin 7 mips64_jit_tcb_push_epilog(b);
402 dpavlin 1 }
403    
404     /* Record a patch to apply in a compiled block */
405 dpavlin 7 int mips64_jit_tcb_record_patch(mips64_jit_tcb_t *block,u_char *jit_ptr,
406     m_uint64_t vaddr)
407 dpavlin 1 {
408 dpavlin 7 struct mips64_jit_patch_table *ipt = block->patch_table;
409     struct mips64_insn_patch *patch;
410 dpavlin 1
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    
419 dpavlin 7 if (!ipt || (ipt->cur_patch >= MIPS64_INSN_PATCH_TABLE_SIZE))
420 dpavlin 1 {
421     /* full table or no table, create a new one */
422     ipt = malloc(sizeof(*ipt));
423     if (!ipt) {
424 dpavlin 7 fprintf(stderr,"Block 0x%8.8llx: unable to create patch table.\n",
425     block->start_pc);
426 dpavlin 1 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 */
447 dpavlin 7 static int mips64_jit_tcb_apply_patches(cpu_mips_t *cpu,
448     mips64_jit_tcb_t *block)
449 dpavlin 1 {
450 dpavlin 7 struct mips64_jit_patch_table *ipt;
451     struct mips64_insn_patch *patch;
452 dpavlin 1 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];
459 dpavlin 7 jit_dst = mips64_jit_tcb_get_host_ptr(block,patch->mips_pc);
460 dpavlin 1
461     if (jit_dst) {
462     #if DEBUG_BLOCK_PATCH
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);
466     #endif
467 dpavlin 7 mips64_jit_tcb_set_patch(patch->jit_insn,jit_dst);
468 dpavlin 1 }
469     }
470    
471     return(0);
472     }
473    
474     /* Free the patch table */
475 dpavlin 7 static void mips64_jit_tcb_free_patches(mips64_jit_tcb_t *block)
476 dpavlin 1 {
477 dpavlin 7 struct mips64_jit_patch_table *p,*next;
478 dpavlin 1
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    
487     /* Adjust the JIT buffer if its size is not sufficient */
488 dpavlin 7 static int mips64_jit_tcb_adjust_buffer(cpu_mips_t *cpu,
489     mips64_jit_tcb_t *block)
490 dpavlin 1 {
491     insn_exec_page_t *new_buffer;
492    
493     if ((block->jit_ptr - block->jit_buffer->ptr) <= (MIPS_JIT_BUFSIZE - 512))
494     return(0);
495    
496     #if DEBUG_BLOCK_CHUNK
497     printf("Block 0x%llx: adjusting JIT buffer...\n",block->start_pc);
498     #endif
499    
500 dpavlin 7 if (block->jit_chunk_pos >= MIPS_JIT_MAX_CHUNKS) {
501 dpavlin 1 fprintf(stderr,"Block 0x%llx: too many JIT chunks.\n",block->start_pc);
502     return(-1);
503     }
504    
505     if (!(new_buffer = exec_page_alloc(cpu)))
506     return(-1);
507    
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) */
513 dpavlin 7 mips64_jit_tcb_set_jump(block->jit_ptr,new_buffer->ptr);
514 dpavlin 1 block->jit_ptr = new_buffer->ptr;
515     return(0);
516     }
517    
518     /* Allocate an instruction block */
519 dpavlin 7 static inline mips64_jit_tcb_t *mips64_jit_tcb_alloc(cpu_mips_t *cpu)
520 dpavlin 1 {
521 dpavlin 7 mips64_jit_tcb_t *p;
522 dpavlin 1
523 dpavlin 7 if (cpu->tcb_free_list) {
524     p = cpu->tcb_free_list;
525     cpu->tcb_free_list = p->next;
526 dpavlin 1 } else {
527     if (!(p = malloc(sizeof(*p))))
528     return NULL;
529     }
530    
531     memset(p,0,sizeof(*p));
532     return p;
533     }
534    
535     /* Free an instruction block */
536 dpavlin 7 void mips64_jit_tcb_free(cpu_mips_t *cpu,mips64_jit_tcb_t *block,
537     int list_removal)
538 dpavlin 1 {
539     int i;
540    
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
547 dpavlin 7 cpu->tcb_last = block->prev;
548 dpavlin 1
549     if (block->prev)
550     block->prev->next = block->next;
551     else
552 dpavlin 7 cpu->tcb_list = block->next;
553 dpavlin 1 }
554    
555     /* Free the patch tables */
556 dpavlin 7 mips64_jit_tcb_free_patches(block);
557 dpavlin 1
558     /* Free code pages */
559 dpavlin 7 for(i=0;i<MIPS_JIT_MAX_CHUNKS;i++)
560 dpavlin 1 exec_page_free(cpu,block->jit_chunks[i]);
561    
562     /* Free the current JIT buffer */
563     exec_page_free(cpu,block->jit_buffer);
564    
565     /* Free the MIPS-to-native code mapping */
566     free(block->jit_insn_ptr);
567    
568     /* Make the block return to the free list */
569 dpavlin 7 block->next = cpu->tcb_free_list;
570     cpu->tcb_free_list = block;
571 dpavlin 1 }
572     }
573    
574     /* Create an instruction block */
575 dpavlin 7 static mips64_jit_tcb_t *mips64_jit_tcb_create(cpu_mips_t *cpu,
576     m_uint64_t vaddr)
577 dpavlin 1 {
578 dpavlin 7 mips64_jit_tcb_t *block = NULL;
579 dpavlin 1
580 dpavlin 7 if (!(block = mips64_jit_tcb_alloc(cpu)))
581 dpavlin 1 goto err_block_alloc;
582    
583     block->start_pc = vaddr;
584    
585     /* Allocate the first JIT buffer */
586     if (!(block->jit_buffer = exec_page_alloc(cpu)))
587     goto err_jit_alloc;
588    
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;
600     #endif
601     return block;
602    
603     err_lookup:
604     err_jit_alloc:
605 dpavlin 7 mips64_jit_tcb_free(cpu,block,FALSE);
606 dpavlin 1 err_block_alloc:
607     fprintf(stderr,"%% Unable to create instruction block for vaddr=0x%llx\n",
608     vaddr);
609     return NULL;
610     }
611    
612     /* Compile a MIPS instruction page */
613 dpavlin 7 static inline
614     mips64_jit_tcb_t *mips64_jit_tcb_compile(cpu_mips_t *cpu,m_uint64_t vaddr)
615 dpavlin 1 {
616 dpavlin 7 mips64_jit_tcb_t *block;
617     struct mips64_insn_tag *tag;
618 dpavlin 1 m_uint64_t page_addr;
619     size_t len;
620    
621     page_addr = vaddr & ~(m_uint64_t)MIPS_MIN_PAGE_IMASK;
622    
623 dpavlin 7 if (unlikely(!(block = mips64_jit_tcb_create(cpu,page_addr)))) {
624 dpavlin 1 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     }
635    
636     /* Emit native code for each instruction */
637     block->mips_trans_pos = 0;
638    
639 dpavlin 7 while(block->mips_trans_pos < MIPS_INSN_PER_PAGE)
640 dpavlin 1 {
641 dpavlin 7 if (unlikely(!(tag = mips64_jit_fetch_and_emit(cpu,block,0)))) {
642 dpavlin 1 fprintf(stderr,"insn_page_compile: unable to fetch instruction.\n");
643     goto error;
644     }
645    
646     #if DEBUG_BLOCK_COMPILE
647     printf("Page 0x%8.8llx: emitted tag 0x%8.8x/0x%8.8x\n",
648     block->start_pc,tag->mask,tag->value);
649     #endif
650    
651 dpavlin 7 mips64_jit_tcb_adjust_buffer(cpu,block);
652 dpavlin 1 }
653    
654 dpavlin 7 mips64_jit_tcb_add_end(block);
655     mips64_jit_tcb_apply_patches(cpu,block);
656     mips64_jit_tcb_free_patches(block);
657 dpavlin 1
658     /* Add the block to the linked list */
659 dpavlin 7 block->next = cpu->tcb_list;
660 dpavlin 1 block->prev = NULL;
661    
662 dpavlin 7 if (cpu->tcb_list)
663     cpu->tcb_list->prev = block;
664 dpavlin 1 else
665 dpavlin 7 cpu->tcb_last = block;
666 dpavlin 1
667 dpavlin 7 cpu->tcb_list = block;
668 dpavlin 1
669     cpu->compiled_pages++;
670     return block;
671    
672     error:
673 dpavlin 7 mips64_jit_tcb_free(cpu,block,FALSE);
674 dpavlin 1 return NULL;
675     }
676    
677     /* Run a compiled MIPS instruction block */
678 dpavlin 7 static forced_inline
679     void mips64_jit_tcb_run(cpu_mips_t *cpu,mips64_jit_tcb_t *block)
680 dpavlin 1 {
681     #if DEBUG_SYM_TREE
682     struct symbol *sym = NULL;
683     int mark = FALSE;
684     #endif
685    
686     if (unlikely(cpu->pc & 0x03)) {
687 dpavlin 7 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);
691 dpavlin 1 return;
692     }
693    
694     #if DEBUG_SYM_TREE
695     if (cpu->sym_trace && cpu->sym_tree)
696     {
697     if ((sym = mips64_sym_lookup(cpu,cpu->pc)) != NULL) {
698 dpavlin 7 cpu_log(cpu,"mips64_jit_tcb_run(start)",
699 dpavlin 1 "%s (PC=0x%llx) RA = 0x%llx\na0=0x%llx, "
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 */
710 dpavlin 7 mips64_jit_tcb_exec(cpu,block);
711 dpavlin 1
712     #if DEBUG_SYM_TREE
713     if (mark) {
714 dpavlin 7 cpu_log(cpu,"mips64_jit_tcb_run(end)","%s, v0 = 0x%llx\n",
715 dpavlin 1 sym->name,cpu->gpr[MIPS_GPR_V0]);
716     }
717     #endif
718     }
719    
720 dpavlin 7 /* Execute compiled MIPS code */
721     void *mips64_jit_run_cpu(cpu_gen_t *gen)
722     {
723     cpu_mips_t *cpu = CPU_MIPS64(gen);
724 dpavlin 1 pthread_t timer_irq_thread;
725 dpavlin 7 mips64_jit_tcb_t *block;
726 dpavlin 1 int timer_irq_check = 0;
727 dpavlin 8 m_uint32_t pc_hash;
728 dpavlin 1
729     if (pthread_create(&timer_irq_thread,NULL,
730     (void *)mips64_timer_irq_run,cpu))
731     {
732 dpavlin 4 fprintf(stderr,
733     "VM '%s': unable to create Timer IRQ thread for CPU%u.\n",
734 dpavlin 7 cpu->vm->name,gen->id);
735     cpu_stop(cpu->gen);
736 dpavlin 1 return NULL;
737     }
738    
739 dpavlin 7 gen->cpu_thread_running = TRUE;
740 dpavlin 1 start_cpu:
741 dpavlin 7 gen->idle_count = 0;
742 dpavlin 3
743 dpavlin 1 for(;;) {
744 dpavlin 7 if (unlikely(gen->state != CPU_STATE_RUNNING))
745 dpavlin 1 break;
746    
747 dpavlin 5 #if DEBUG_BLOCK_PERF_CNT
748     cpu->perf_counter++;
749     #endif
750 dpavlin 1 /* Handle virtual idle loop */
751     if (unlikely(cpu->pc == cpu->idle_pc)) {
752 dpavlin 7 if (++gen->idle_count == gen->idle_max) {
753     cpu_idle_loop(gen);
754     gen->idle_count = 0;
755 dpavlin 1 }
756     }
757    
758     /* Handle the virtual CPU clock */
759     if (++timer_irq_check == cpu->timer_irq_check_itv) {
760     timer_irq_check = 0;
761    
762     if (cpu->timer_irq_pending && !cpu->irq_disable) {
763     mips64_trigger_timer_irq(cpu);
764     mips64_trigger_irq(cpu);
765     cpu->timer_irq_pending--;
766     }
767     }
768    
769 dpavlin 8 pc_hash = mips64_jit_get_pc_hash(cpu->pc);
770     block = cpu->exec_blk_map[pc_hash];
771 dpavlin 1
772     /* No block found, compile the page */
773 dpavlin 7 if (unlikely(!block) || unlikely(!mips64_jit_tcb_match(cpu,block)))
774 dpavlin 8 {
775 dpavlin 2 if (block != NULL) {
776 dpavlin 7 mips64_jit_tcb_free(cpu,block,TRUE);
777 dpavlin 8 cpu->exec_blk_map[pc_hash] = NULL;
778 dpavlin 2 }
779    
780 dpavlin 7 block = mips64_jit_tcb_compile(cpu,cpu->pc);
781 dpavlin 1 if (unlikely(!block)) {
782     fprintf(stderr,
783     "VM '%s': unable to compile block for CPU%u PC=0x%llx\n",
784 dpavlin 7 cpu->vm->name,gen->id,cpu->pc);
785     cpu_stop(gen);
786 dpavlin 1 break;
787     }
788    
789 dpavlin 8 cpu->exec_blk_map[pc_hash] = block;
790 dpavlin 1 }
791    
792     #if DEBUG_BLOCK_TIMESTAMP
793     block->tm_last_use = jit_jiffies++;
794     #endif
795     block->acc_count++;
796 dpavlin 7 mips64_jit_tcb_run(cpu,block);
797 dpavlin 1 }
798    
799     if (!cpu->pc) {
800 dpavlin 7 cpu_stop(gen);
801     cpu_log(gen,"JIT","PC=0, halting CPU.\n");
802 dpavlin 1 }
803    
804     /* Check regularly if the CPU has been restarted */
805 dpavlin 7 while(gen->cpu_thread_running) {
806     gen->seq_state++;
807 dpavlin 1
808 dpavlin 7 switch(gen->state) {
809     case CPU_STATE_RUNNING:
810     gen->state = CPU_STATE_RUNNING;
811 dpavlin 1 goto start_cpu;
812    
813 dpavlin 7 case CPU_STATE_HALTED:
814     gen->cpu_thread_running = FALSE;
815 dpavlin 1 pthread_join(timer_irq_thread,NULL);
816     break;
817     }
818    
819     /* CPU is paused */
820     usleep(200000);
821     }
822    
823     return NULL;
824     }

  ViewVC Help
Powered by ViewVC 1.1.26