/[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 7 - (hide annotations)
Sat Oct 6 16:23:47 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC1/mips64_jit.c
File MIME type: text/plain
File size: 22502 byte(s)
dynamips-0.2.7-RC1

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     #include "cpu.h"
20     #include "device.h"
21     #include "mips64.h"
22 dpavlin 7 #include "mips64_cp0.h"
23 dpavlin 1 #include "mips64_exec.h"
24 dpavlin 7 #include "mips64_jit.h"
25 dpavlin 1 #include "insn_lookup.h"
26 dpavlin 7 #include "memory.h"
27 dpavlin 1 #include "ptask.h"
28    
29 dpavlin 7 #include MIPS64_ARCH_INC_FILE
30    
31 dpavlin 1 #if DEBUG_BLOCK_TIMESTAMP
32     static volatile m_uint64_t jit_jiffies = 0;
33     #endif
34    
35     /* MIPS jump instructions for block scan */
36 dpavlin 7 struct mips64_insn_jump mips64_insn_jumps[] = {
37 dpavlin 1 { "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 dpavlin 7 static int mips64_jit_chk_lo(struct mips64_insn_tag *tag,int value)
68 dpavlin 1 {
69     return((value & tag->mask) == (tag->value & 0xFFFF));
70     }
71    
72 dpavlin 7 static int mips64_jit_chk_hi(struct mips64_insn_tag *tag,int value)
73 dpavlin 1 {
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 dpavlin 7 ilt = ilt_create(count+1,
86 dpavlin 1 (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    
91     /* Initialize the JIT structure */
92     int mips64_jit_init(cpu_mips_t *cpu)
93     {
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));
127    
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;
138    
139     cp->next = cpu->exec_page_free_list;
140     cpu->exec_page_free_list = cp;
141     }
142    
143     printf("CPU%u: carved JIT exec zone of %lu Mb into %lu pages of %u Kb.\n",
144 dpavlin 7 cpu->gen->id,
145     (u_long)(cpu->exec_page_area_size / 1048576),
146 dpavlin 1 (u_long)cpu->exec_page_count,MIPS_JIT_BUFSIZE / 1024);
147     return(0);
148     }
149    
150     /* Flush the JIT */
151     u_int mips64_jit_flush(cpu_mips_t *cpu,u_int threshold)
152     {
153 dpavlin 7 mips64_jit_tcb_t *p,*next;
154 dpavlin 1 u_int count = 0;
155    
156     if (!threshold)
157     threshold = (u_int)(-1); /* UINT_MAX not defined everywhere */
158    
159 dpavlin 7 for(p=cpu->tcb_list;p;p=next) {
160 dpavlin 1 next = p->next;
161    
162     if (p->acc_count <= threshold) {
163     cpu->exec_phys_map[p->phys_page] = NULL;
164 dpavlin 7 mips64_jit_tcb_free(cpu,p,TRUE);
165 dpavlin 1 count++;
166     }
167     }
168    
169     cpu->compiled_pages -= count;
170     return(count);
171     }
172    
173     /* Shutdown the JIT */
174     void mips64_jit_shutdown(cpu_mips_t *cpu)
175     {
176 dpavlin 7 mips64_jit_tcb_t *p,*next;
177 dpavlin 1
178     /* Flush the JIT */
179     mips64_jit_flush(cpu,0);
180    
181     /* Free the instruction blocks */
182 dpavlin 7 for(p=cpu->tcb_free_list;p;p=next) {
183 dpavlin 1 next = p->next;
184     free(p);
185     }
186    
187     /* Unmap the executable page area */
188     if (cpu->exec_page_area)
189     munmap(cpu->exec_page_area,cpu->exec_page_area_size);
190    
191     /* Free the exec page array */
192     free(cpu->exec_page_array);
193    
194     /* Free physical mapping for executable pages */
195     free(cpu->exec_phys_map);
196     }
197    
198     /* Allocate an exec page */
199     static inline insn_exec_page_t *exec_page_alloc(cpu_mips_t *cpu)
200     {
201     insn_exec_page_t *p;
202     u_int count;
203    
204     /* If the free list is empty, flush JIT */
205     if (unlikely(!cpu->exec_page_free_list))
206     {
207     if (cpu->jit_flush_method) {
208 dpavlin 7 cpu_log(cpu->gen,
209     "JIT","flushing data structures (compiled pages=%u)\n",
210 dpavlin 1 cpu->compiled_pages);
211     mips64_jit_flush(cpu,0);
212     } else {
213     count = mips64_jit_flush(cpu,100);
214 dpavlin 7 cpu_log(cpu->gen,"JIT","partial JIT flush (count=%u)\n",count);
215 dpavlin 1
216     if (!cpu->exec_page_free_list)
217     mips64_jit_flush(cpu,0);
218     }
219    
220     /* Use both methods alternatively */
221     cpu->jit_flush_method = 1 - cpu->jit_flush_method;
222     }
223    
224     if (unlikely(!(p = cpu->exec_page_free_list)))
225     return NULL;
226    
227     cpu->exec_page_free_list = p->next;
228     cpu->exec_page_alloc++;
229     return p;
230     }
231    
232     /* Free an exec page and returns it to the pool */
233     static inline void exec_page_free(cpu_mips_t *cpu,insn_exec_page_t *p)
234     {
235     if (p) {
236     p->next = cpu->exec_page_free_list;
237     cpu->exec_page_free_list = p;
238     cpu->exec_page_alloc--;
239     }
240     }
241    
242     /* Find the JIT code emitter for the specified MIPS instruction */
243 dpavlin 7 static struct mips64_insn_tag *insn_tag_find(mips_insn_t ins)
244 dpavlin 1 {
245 dpavlin 7 struct mips64_insn_tag *tag = NULL;
246 dpavlin 1 int index;
247    
248     index = ilt_lookup(ilt,ins);
249     tag = mips64_jit_get_insn(index);
250     return tag;
251     }
252    
253     /* Check if the specified MIPS instruction is a jump */
254 dpavlin 7 static struct mips64_insn_jump *insn_jump_find(mips_insn_t ins)
255 dpavlin 1 {
256 dpavlin 7 struct mips64_insn_jump *jump = NULL;
257 dpavlin 1 int i;
258    
259     for(i=0;mips64_insn_jumps[i].name;i++)
260     if ((ins & mips64_insn_jumps[i].mask) == mips64_insn_jumps[i].value) {
261     jump = &mips64_insn_jumps[i];
262     break;
263     }
264    
265     return(jump);
266     }
267    
268     /* Fetch a MIPS instruction */
269 dpavlin 7 static forced_inline mips_insn_t insn_fetch(mips64_jit_tcb_t *b)
270 dpavlin 1 {
271     return(vmtoh32(b->mips_code[b->mips_trans_pos]));
272     }
273    
274     /* Emit a breakpoint if necessary */
275     #if BREAKPOINT_ENABLE
276 dpavlin 7 static void insn_emit_breakpoint(cpu_mips_t *cpu,mips64_jit_tcb_t *b)
277 dpavlin 1 {
278     m_uint64_t pc;
279     int i;
280    
281     pc = b->start_pc+((b->mips_trans_pos-1)<<2);
282    
283     for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
284     if (pc == cpu->breakpoints[i]) {
285     mips64_emit_breakpoint(b);
286     break;
287     }
288     }
289     #endif /* BREAKPOINT_ENABLE */
290    
291 dpavlin 7 /* Get host pointer for the physical address */
292     static inline void *physmem_get_hptr(vm_instance_t *vm,m_uint64_t paddr,
293     u_int op_size,u_int op_type,
294     m_uint64_t *data)
295     {
296     struct vdevice *dev;
297     m_uint32_t offset;
298     void *ptr;
299     int cow;
300    
301     if (!(dev = dev_lookup(vm,paddr,FALSE)))
302     return NULL;
303    
304     if (dev->flags & VDEVICE_FLAG_SPARSE) {
305     ptr = (void *)dev_sparse_get_host_addr(vm,dev,paddr,op_type,&cow);
306     if (!ptr) return NULL;
307    
308     return(ptr + (paddr & VM_PAGE_IMASK));
309     }
310    
311     if ((dev->host_addr != 0) && !(dev->flags & VDEVICE_FLAG_NO_MTS_MMAP))
312     return((void *)dev->host_addr + (paddr - dev->phys_addr));
313    
314     if (op_size == 0)
315     return NULL;
316    
317     offset = paddr - dev->phys_addr;
318     return(dev->handler(vm->boot_cpu,dev,offset,op_size,op_type,data));
319     }
320    
321 dpavlin 1 /* Fetch a MIPS instruction and emit corresponding translated code */
322 dpavlin 7 struct mips64_insn_tag *mips64_jit_fetch_and_emit(cpu_mips_t *cpu,
323     mips64_jit_tcb_t *block,
324     int delay_slot)
325 dpavlin 1 {
326 dpavlin 7 struct mips64_insn_tag *tag;
327 dpavlin 1 mips_insn_t code;
328    
329     code = insn_fetch(block);
330     tag = insn_tag_find(code);
331     assert(tag);
332 dpavlin 7
333     /* Branch-delay slot is in another page: slow exec */
334     if ((block->mips_trans_pos == (MIPS_INSN_PER_PAGE-1)) && !tag->delay_slot) {
335     block->jit_insn_ptr[block->mips_trans_pos] = block->jit_ptr;
336    
337     mips64_set_pc(block,block->start_pc + (block->mips_trans_pos << 2));
338     mips64_emit_single_step(block,code);
339     mips64_jit_tcb_push_epilog(block);
340     block->mips_trans_pos++;
341     return tag;
342     }
343    
344 dpavlin 1 if (delay_slot && !tag->delay_slot) {
345     mips64_emit_invalid_delay_slot(block);
346     return NULL;
347     }
348    
349 dpavlin 7 if (!delay_slot)
350 dpavlin 1 block->jit_insn_ptr[block->mips_trans_pos] = block->jit_ptr;
351    
352     if (delay_slot != 2)
353     block->mips_trans_pos++;
354    
355 dpavlin 5 #if DEBUG_INSN_PERF_CNT
356 dpavlin 1 mips64_inc_perf_counter(block);
357     #endif
358    
359     if (!delay_slot) {
360     /* Check for IRQs + Increment count register before jumps */
361     if (!tag->delay_slot) {
362     mips64_inc_cp0_count_reg(block);
363     mips64_check_pending_irq(block);
364     }
365     }
366    
367     #if BREAKPOINT_ENABLE
368     if (cpu->breakpoints_enabled)
369     insn_emit_breakpoint(cpu,block);
370     #endif
371    
372     tag->emit(cpu,block,code);
373     return tag;
374     }
375    
376     /* Add end of JIT block */
377 dpavlin 7 static void mips64_jit_tcb_add_end(mips64_jit_tcb_t *b)
378 dpavlin 1 {
379     mips64_set_pc(b,b->start_pc+(b->mips_trans_pos<<2));
380 dpavlin 7 mips64_jit_tcb_push_epilog(b);
381 dpavlin 1 }
382    
383     /* Record a patch to apply in a compiled block */
384 dpavlin 7 int mips64_jit_tcb_record_patch(mips64_jit_tcb_t *block,u_char *jit_ptr,
385     m_uint64_t vaddr)
386 dpavlin 1 {
387 dpavlin 7 struct mips64_jit_patch_table *ipt = block->patch_table;
388     struct mips64_insn_patch *patch;
389 dpavlin 1
390     /* pc must be 32-bit aligned */
391     if (vaddr & 0x03) {
392     fprintf(stderr,"Block 0x%8.8llx: trying to record an invalid PC "
393     "(0x%8.8llx) - mips_trans_pos=%d.\n",
394     block->start_pc,vaddr,block->mips_trans_pos);
395     return(-1);
396     }
397    
398 dpavlin 7 if (!ipt || (ipt->cur_patch >= MIPS64_INSN_PATCH_TABLE_SIZE))
399 dpavlin 1 {
400     /* full table or no table, create a new one */
401     ipt = malloc(sizeof(*ipt));
402     if (!ipt) {
403 dpavlin 7 fprintf(stderr,"Block 0x%8.8llx: unable to create patch table.\n",
404     block->start_pc);
405 dpavlin 1 return(-1);
406     }
407    
408     memset(ipt,0,sizeof(*ipt));
409     ipt->next = block->patch_table;
410     block->patch_table = ipt;
411     }
412    
413     #if DEBUG_BLOCK_PATCH
414     printf("Block 0x%8.8llx: recording patch [JIT:%p->mips:0x%8.8llx], "
415     "MTP=%d\n",block->start_pc,jit_ptr,vaddr,block->mips_trans_pos);
416     #endif
417    
418     patch = &ipt->patches[ipt->cur_patch];
419     patch->jit_insn = jit_ptr;
420     patch->mips_pc = vaddr;
421     ipt->cur_patch++;
422     return(0);
423     }
424    
425     /* Apply all patches */
426 dpavlin 7 static int mips64_jit_tcb_apply_patches(cpu_mips_t *cpu,
427     mips64_jit_tcb_t *block)
428 dpavlin 1 {
429 dpavlin 7 struct mips64_jit_patch_table *ipt;
430     struct mips64_insn_patch *patch;
431 dpavlin 1 u_char *jit_dst;
432     int i;
433    
434     for(ipt=block->patch_table;ipt;ipt=ipt->next)
435     for(i=0;i<ipt->cur_patch;i++)
436     {
437     patch = &ipt->patches[i];
438 dpavlin 7 jit_dst = mips64_jit_tcb_get_host_ptr(block,patch->mips_pc);
439 dpavlin 1
440     if (jit_dst) {
441     #if DEBUG_BLOCK_PATCH
442     printf("Block 0x%8.8llx: applying patch "
443     "[JIT:%p->mips:0x%8.8llx=JIT:%p]\n",
444     block->start_pc,patch->jit_insn,patch->mips_pc,jit_dst);
445     #endif
446 dpavlin 7 mips64_jit_tcb_set_patch(patch->jit_insn,jit_dst);
447 dpavlin 1 }
448     }
449    
450     return(0);
451     }
452    
453     /* Free the patch table */
454 dpavlin 7 static void mips64_jit_tcb_free_patches(mips64_jit_tcb_t *block)
455 dpavlin 1 {
456 dpavlin 7 struct mips64_jit_patch_table *p,*next;
457 dpavlin 1
458     for(p=block->patch_table;p;p=next) {
459     next = p->next;
460     free(p);
461     }
462    
463     block->patch_table = NULL;
464     }
465    
466     /* Adjust the JIT buffer if its size is not sufficient */
467 dpavlin 7 static int mips64_jit_tcb_adjust_buffer(cpu_mips_t *cpu,
468     mips64_jit_tcb_t *block)
469 dpavlin 1 {
470     insn_exec_page_t *new_buffer;
471    
472     if ((block->jit_ptr - block->jit_buffer->ptr) <= (MIPS_JIT_BUFSIZE - 512))
473     return(0);
474    
475     #if DEBUG_BLOCK_CHUNK
476     printf("Block 0x%llx: adjusting JIT buffer...\n",block->start_pc);
477     #endif
478    
479 dpavlin 7 if (block->jit_chunk_pos >= MIPS_JIT_MAX_CHUNKS) {
480 dpavlin 1 fprintf(stderr,"Block 0x%llx: too many JIT chunks.\n",block->start_pc);
481     return(-1);
482     }
483    
484     if (!(new_buffer = exec_page_alloc(cpu)))
485     return(-1);
486    
487     /* record the new exec page */
488     block->jit_chunks[block->jit_chunk_pos++] = block->jit_buffer;
489     block->jit_buffer = new_buffer;
490    
491     /* jump to the new exec page (link) */
492 dpavlin 7 mips64_jit_tcb_set_jump(block->jit_ptr,new_buffer->ptr);
493 dpavlin 1 block->jit_ptr = new_buffer->ptr;
494     return(0);
495     }
496    
497     /* Allocate an instruction block */
498 dpavlin 7 static inline mips64_jit_tcb_t *mips64_jit_tcb_alloc(cpu_mips_t *cpu)
499 dpavlin 1 {
500 dpavlin 7 mips64_jit_tcb_t *p;
501 dpavlin 1
502 dpavlin 7 if (cpu->tcb_free_list) {
503     p = cpu->tcb_free_list;
504     cpu->tcb_free_list = p->next;
505 dpavlin 1 } else {
506     if (!(p = malloc(sizeof(*p))))
507     return NULL;
508     }
509    
510     memset(p,0,sizeof(*p));
511     return p;
512     }
513    
514     /* Free an instruction block */
515 dpavlin 7 void mips64_jit_tcb_free(cpu_mips_t *cpu,mips64_jit_tcb_t *block,
516     int list_removal)
517 dpavlin 1 {
518     int i;
519    
520     if (block) {
521     if (list_removal) {
522     /* Remove the block from the linked list */
523     if (block->next)
524     block->next->prev = block->prev;
525     else
526 dpavlin 7 cpu->tcb_last = block->prev;
527 dpavlin 1
528     if (block->prev)
529     block->prev->next = block->next;
530     else
531 dpavlin 7 cpu->tcb_list = block->next;
532 dpavlin 1 }
533    
534     /* Free the patch tables */
535 dpavlin 7 mips64_jit_tcb_free_patches(block);
536 dpavlin 1
537     /* Free code pages */
538 dpavlin 7 for(i=0;i<MIPS_JIT_MAX_CHUNKS;i++)
539 dpavlin 1 exec_page_free(cpu,block->jit_chunks[i]);
540    
541     /* Free the current JIT buffer */
542     exec_page_free(cpu,block->jit_buffer);
543    
544     /* Free the MIPS-to-native code mapping */
545     free(block->jit_insn_ptr);
546    
547     /* Make the block return to the free list */
548 dpavlin 7 block->next = cpu->tcb_free_list;
549     cpu->tcb_free_list = block;
550 dpavlin 1 }
551     }
552    
553     /* Create an instruction block */
554 dpavlin 7 static mips64_jit_tcb_t *mips64_jit_tcb_create(cpu_mips_t *cpu,
555     m_uint64_t vaddr)
556 dpavlin 1 {
557 dpavlin 7 mips64_jit_tcb_t *block = NULL;
558 dpavlin 1
559 dpavlin 7 if (!(block = mips64_jit_tcb_alloc(cpu)))
560 dpavlin 1 goto err_block_alloc;
561    
562     block->start_pc = vaddr;
563    
564     /* Allocate the first JIT buffer */
565     if (!(block->jit_buffer = exec_page_alloc(cpu)))
566     goto err_jit_alloc;
567    
568     block->jit_ptr = block->jit_buffer->ptr;
569     block->mips_code = cpu->mem_op_lookup(cpu,block->start_pc);
570    
571     if (!block->mips_code) {
572     fprintf(stderr,"%% No memory map for code execution at 0x%llx\n",
573     block->start_pc);
574     goto err_lookup;
575     }
576    
577     #if DEBUG_BLOCK_TIMESTAMP
578     block->tm_first_use = block->tm_last_use = jit_jiffies;
579     #endif
580     return block;
581    
582     err_lookup:
583     err_jit_alloc:
584 dpavlin 7 mips64_jit_tcb_free(cpu,block,FALSE);
585 dpavlin 1 err_block_alloc:
586     fprintf(stderr,"%% Unable to create instruction block for vaddr=0x%llx\n",
587     vaddr);
588     return NULL;
589     }
590    
591     /* Compile a MIPS instruction page */
592 dpavlin 7 static inline
593     mips64_jit_tcb_t *mips64_jit_tcb_compile(cpu_mips_t *cpu,m_uint64_t vaddr)
594 dpavlin 1 {
595 dpavlin 7 mips64_jit_tcb_t *block;
596     struct mips64_insn_tag *tag;
597 dpavlin 1 m_uint64_t page_addr;
598     size_t len;
599    
600     page_addr = vaddr & ~(m_uint64_t)MIPS_MIN_PAGE_IMASK;
601    
602 dpavlin 7 if (unlikely(!(block = mips64_jit_tcb_create(cpu,page_addr)))) {
603 dpavlin 1 fprintf(stderr,"insn_page_compile: unable to create JIT block.\n");
604     return NULL;
605     }
606    
607     /* Allocate the array used to convert MIPS code ptr to native code ptr */
608     len = MIPS_MIN_PAGE_SIZE / sizeof(mips_insn_t);
609    
610     if (!(block->jit_insn_ptr = calloc(len,sizeof(u_char *)))) {
611     fprintf(stderr,"insn_page_compile: unable to create JIT mappings.\n");
612     goto error;
613     }
614    
615     /* Emit native code for each instruction */
616     block->mips_trans_pos = 0;
617    
618 dpavlin 7 while(block->mips_trans_pos < MIPS_INSN_PER_PAGE)
619 dpavlin 1 {
620 dpavlin 7 if (unlikely(!(tag = mips64_jit_fetch_and_emit(cpu,block,0)))) {
621 dpavlin 1 fprintf(stderr,"insn_page_compile: unable to fetch instruction.\n");
622     goto error;
623     }
624    
625     #if DEBUG_BLOCK_COMPILE
626     printf("Page 0x%8.8llx: emitted tag 0x%8.8x/0x%8.8x\n",
627     block->start_pc,tag->mask,tag->value);
628     #endif
629    
630 dpavlin 7 mips64_jit_tcb_adjust_buffer(cpu,block);
631 dpavlin 1 }
632    
633 dpavlin 7 mips64_jit_tcb_add_end(block);
634     mips64_jit_tcb_apply_patches(cpu,block);
635     mips64_jit_tcb_free_patches(block);
636 dpavlin 1
637     /* Add the block to the linked list */
638 dpavlin 7 block->next = cpu->tcb_list;
639 dpavlin 1 block->prev = NULL;
640    
641 dpavlin 7 if (cpu->tcb_list)
642     cpu->tcb_list->prev = block;
643 dpavlin 1 else
644 dpavlin 7 cpu->tcb_last = block;
645 dpavlin 1
646 dpavlin 7 cpu->tcb_list = block;
647 dpavlin 1
648     cpu->compiled_pages++;
649     return block;
650    
651     error:
652 dpavlin 7 mips64_jit_tcb_free(cpu,block,FALSE);
653 dpavlin 1 return NULL;
654     }
655    
656     /* Run a compiled MIPS instruction block */
657 dpavlin 7 static forced_inline
658     void mips64_jit_tcb_run(cpu_mips_t *cpu,mips64_jit_tcb_t *block)
659 dpavlin 1 {
660     #if DEBUG_SYM_TREE
661     struct symbol *sym = NULL;
662     int mark = FALSE;
663     #endif
664    
665     if (unlikely(cpu->pc & 0x03)) {
666 dpavlin 7 fprintf(stderr,"mips64_jit_tcb_run: Invalid PC 0x%llx.\n",cpu->pc);
667     mips64_dump_regs(cpu->gen);
668     mips64_tlb_dump(cpu->gen);
669     cpu_stop(cpu->gen);
670 dpavlin 1 return;
671     }
672    
673     #if DEBUG_SYM_TREE
674     if (cpu->sym_trace && cpu->sym_tree)
675     {
676     if ((sym = mips64_sym_lookup(cpu,cpu->pc)) != NULL) {
677 dpavlin 7 cpu_log(cpu,"mips64_jit_tcb_run(start)",
678 dpavlin 1 "%s (PC=0x%llx) RA = 0x%llx\na0=0x%llx, "
679     "a1=0x%llx, a2=0x%llx, a3=0x%llx\n",
680     sym->name, cpu->pc, cpu->gpr[MIPS_GPR_RA],
681     cpu->gpr[MIPS_GPR_A0], cpu->gpr[MIPS_GPR_A1],
682     cpu->gpr[MIPS_GPR_A2], cpu->gpr[MIPS_GPR_A3]);
683     mark = TRUE;
684     }
685     }
686     #endif
687    
688     /* Execute JIT compiled code */
689 dpavlin 7 mips64_jit_tcb_exec(cpu,block);
690 dpavlin 1
691     #if DEBUG_SYM_TREE
692     if (mark) {
693 dpavlin 7 cpu_log(cpu,"mips64_jit_tcb_run(end)","%s, v0 = 0x%llx\n",
694 dpavlin 1 sym->name,cpu->gpr[MIPS_GPR_V0]);
695     }
696     #endif
697     }
698    
699     /* Check if the specified address belongs to the specified block */
700 dpavlin 7 int mips64_jit_tcb_local_addr(mips64_jit_tcb_t *block,m_uint64_t vaddr,
701     u_char **jit_addr)
702 dpavlin 1 {
703     if ((vaddr >= block->start_pc) &&
704     ((vaddr - block->start_pc) < MIPS_MIN_PAGE_SIZE))
705     {
706 dpavlin 7 *jit_addr = mips64_jit_tcb_get_host_ptr(block,vaddr);
707 dpavlin 1 return(1);
708     }
709    
710     return(0);
711     }
712    
713 dpavlin 2 /* Check if PC register matches the compiled block virtual address */
714 dpavlin 7 static forced_inline
715     int mips64_jit_tcb_match(cpu_mips_t *cpu,mips64_jit_tcb_t *block)
716 dpavlin 2 {
717     m_uint64_t vpage;
718    
719     vpage = cpu->pc & ~(m_uint64_t)MIPS_MIN_PAGE_IMASK;
720     return(block->start_pc == vpage);
721     }
722    
723 dpavlin 7 /* Execute compiled MIPS code */
724     void *mips64_jit_run_cpu(cpu_gen_t *gen)
725     {
726     cpu_mips_t *cpu = CPU_MIPS64(gen);
727 dpavlin 1 pthread_t timer_irq_thread;
728 dpavlin 7 mips64_jit_tcb_t *block;
729 dpavlin 1 m_uint32_t phys_page;
730     int timer_irq_check = 0;
731    
732     if (pthread_create(&timer_irq_thread,NULL,
733     (void *)mips64_timer_irq_run,cpu))
734     {
735 dpavlin 4 fprintf(stderr,
736     "VM '%s': unable to create Timer IRQ thread for CPU%u.\n",
737 dpavlin 7 cpu->vm->name,gen->id);
738     cpu_stop(cpu->gen);
739 dpavlin 1 return NULL;
740     }
741    
742 dpavlin 7 gen->cpu_thread_running = TRUE;
743 dpavlin 3
744 dpavlin 1 start_cpu:
745 dpavlin 7 gen->idle_count = 0;
746 dpavlin 3
747 dpavlin 1 for(;;) {
748 dpavlin 7 if (unlikely(gen->state != CPU_STATE_RUNNING))
749 dpavlin 1 break;
750    
751 dpavlin 5 #if DEBUG_BLOCK_PERF_CNT
752     cpu->perf_counter++;
753     #endif
754 dpavlin 1 /* Handle virtual idle loop */
755     if (unlikely(cpu->pc == cpu->idle_pc)) {
756 dpavlin 7 if (++gen->idle_count == gen->idle_max) {
757     cpu_idle_loop(gen);
758     gen->idle_count = 0;
759 dpavlin 1 }
760     }
761    
762     /* Handle the virtual CPU clock */
763     if (++timer_irq_check == cpu->timer_irq_check_itv) {
764     timer_irq_check = 0;
765    
766     if (cpu->timer_irq_pending && !cpu->irq_disable) {
767     mips64_trigger_timer_irq(cpu);
768     mips64_trigger_irq(cpu);
769     cpu->timer_irq_pending--;
770     }
771     }
772    
773     /* Get the physical page address corresponding to PC register */
774     if (unlikely(cpu->translate(cpu,cpu->pc,&phys_page))) {
775     fprintf(stderr,"VM '%s': no physical page for CPU%u PC=0x%llx\n",
776 dpavlin 7 cpu->vm->name,gen->id,cpu->pc);
777     cpu_stop(gen);
778 dpavlin 1 break;
779     }
780    
781     block = cpu->exec_phys_map[phys_page];
782    
783     /* No block found, compile the page */
784 dpavlin 7 if (unlikely(!block) || unlikely(!mips64_jit_tcb_match(cpu,block)))
785 dpavlin 2 {
786     if (block != NULL) {
787 dpavlin 7 mips64_jit_tcb_free(cpu,block,TRUE);
788 dpavlin 2 cpu->exec_phys_map[phys_page] = NULL;
789     }
790    
791 dpavlin 7 block = mips64_jit_tcb_compile(cpu,cpu->pc);
792 dpavlin 1 if (unlikely(!block)) {
793     fprintf(stderr,
794     "VM '%s': unable to compile block for CPU%u PC=0x%llx\n",
795 dpavlin 7 cpu->vm->name,gen->id,cpu->pc);
796     cpu_stop(gen);
797 dpavlin 1 break;
798     }
799    
800     block->phys_page = phys_page;
801     cpu->exec_phys_map[phys_page] = block;
802     }
803    
804     #if DEBUG_BLOCK_TIMESTAMP
805     block->tm_last_use = jit_jiffies++;
806     #endif
807     block->acc_count++;
808 dpavlin 7 mips64_jit_tcb_run(cpu,block);
809 dpavlin 1 }
810    
811     if (!cpu->pc) {
812 dpavlin 7 cpu_stop(gen);
813     cpu_log(gen,"JIT","PC=0, halting CPU.\n");
814 dpavlin 1 }
815    
816     /* Check regularly if the CPU has been restarted */
817 dpavlin 7 while(gen->cpu_thread_running) {
818     gen->seq_state++;
819 dpavlin 1
820 dpavlin 7 switch(gen->state) {
821     case CPU_STATE_RUNNING:
822     gen->state = CPU_STATE_RUNNING;
823 dpavlin 1 goto start_cpu;
824    
825 dpavlin 7 case CPU_STATE_HALTED:
826     gen->cpu_thread_running = FALSE;
827 dpavlin 1 pthread_join(timer_irq_thread,NULL);
828     break;
829     }
830    
831     /* CPU is paused */
832     usleep(200000);
833     }
834    
835     return NULL;
836     }

  ViewVC Help
Powered by ViewVC 1.1.26