/[dynamips]/upstream/dynamips-0.2.6-RC3/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 /upstream/dynamips-0.2.6-RC3/mips64_jit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (hide annotations)
Sat Oct 6 16:06:49 2007 UTC (13 years ago) by dpavlin
File MIME type: text/plain
File size: 20515 byte(s)
dynamips-0.2.6-RC3

1 dpavlin 1 /*
2     * Cisco 7200 (Predator) simulation platform.
3     * 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 ARCH_INC_FILE
20    
21     #include "rbtree.h"
22     #include "cp0.h"
23     #include "memory.h"
24     #include "cpu.h"
25     #include "device.h"
26     #include "mips64.h"
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    
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     cpu->id,(u_long)(cpu->exec_page_area_size / 1048576),
145     (u_long)cpu->exec_page_count,MIPS_JIT_BUFSIZE / 1024);
146     return(0);
147     }
148    
149     /* Flush the JIT */
150     u_int mips64_jit_flush(cpu_mips_t *cpu,u_int threshold)
151     {
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 */
157    
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     }
166     }
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);
195     }
196    
197     /* Allocate an exec page */
198     static inline insn_exec_page_t *exec_page_alloc(cpu_mips_t *cpu)
199     {
200     insn_exec_page_t *p;
201     u_int count;
202    
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);
216     }
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--;
237     }
238     }
239    
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 */
267     static forced_inline mips_insn_t insn_fetch(insn_block_t *b)
268     {
269     return(vmtoh32(b->mips_code[b->mips_trans_pos]));
270     }
271    
272     /* Emit a breakpoint if necessary */
273     #if BREAKPOINT_ENABLE
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     }
287     #endif /* BREAKPOINT_ENABLE */
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) {
301     mips64_emit_invalid_delay_slot(block);
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    
312     #if DEBUG_PERF_COUNTER
313     mips64_inc_perf_counter(block);
314     #endif
315    
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     }
323    
324     #if BREAKPOINT_ENABLE
325     if (cpu->breakpoints_enabled)
326     insn_emit_breakpoint(cpu,block);
327     #endif
328    
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    
395     if (jit_dst) {
396     #if DEBUG_BLOCK_PATCH
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);
400     #endif
401     insn_block_set_patch(patch->jit_insn,jit_dst);
402     }
403     }
404    
405     return(0);
406     }
407    
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    
421     /* Adjust the JIT buffer if its size is not sufficient */
422     int insn_block_adjust_jit_buffer(cpu_mips_t *cpu,insn_block_t *block)
423     {
424     insn_exec_page_t *new_buffer;
425    
426     if ((block->jit_ptr - block->jit_buffer->ptr) <= (MIPS_JIT_BUFSIZE - 512))
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    
438     if (!(new_buffer = exec_page_alloc(cpu)))
439     return(-1);
440    
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;
448     return(0);
449     }
450    
451     /* Allocate an instruction block */
452     static inline insn_block_t *insn_block_alloc(cpu_mips_t *cpu)
453     {
454     insn_block_t *p;
455    
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     }
463    
464     memset(p,0,sizeof(*p));
465     return p;
466     }
467    
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;
472    
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;
485     }
486    
487     /* Free the patch tables */
488     insn_block_free_patches(block);
489    
490     /* Free code pages */
491     for(i=0;i<INSN_MAX_CHUNKS;i++)
492     exec_page_free(cpu,block->jit_chunks[i]);
493    
494     /* Free the current JIT buffer */
495     exec_page_free(cpu,block->jit_buffer);
496    
497     /* Free the MIPS-to-native code mapping */
498     free(block->jit_insn_ptr);
499    
500     /* Make the block return to the free list */
501     block->next = cpu->insn_block_free_list;
502     cpu->insn_block_free_list = block;
503     }
504     }
505    
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;
510    
511     if (!(block = insn_block_alloc(cpu)))
512     goto err_block_alloc;
513    
514     block->start_pc = vaddr;
515    
516     /* Allocate the first JIT buffer */
517     if (!(block->jit_buffer = exec_page_alloc(cpu)))
518     goto err_jit_alloc;
519    
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;
531     #endif
532     return block;
533    
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;
541     }
542    
543     /* Compile a MIPS instruction page */
544     static inline insn_block_t *insn_page_compile(cpu_mips_t *cpu,m_uint64_t vaddr)
545     {
546     m_uint64_t page_addr;
547     insn_block_t *block;
548     struct insn_tag *tag;
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     }
565    
566     /* Emit native code for each instruction */
567     block->mips_trans_pos = 0;
568    
569     while(block->mips_trans_pos < (MIPS_MIN_PAGE_SIZE/sizeof(mips_insn_t)))
570     {
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     }
575    
576     #if DEBUG_BLOCK_COMPILE
577     printf("Page 0x%8.8llx: emitted tag 0x%8.8x/0x%8.8x\n",
578     block->start_pc,tag->mask,tag->value);
579     #endif
580    
581     insn_block_adjust_jit_buffer(cpu,block);
582     }
583    
584     insn_block_add_end(block);
585     insn_block_apply_patches(cpu,block);
586     insn_block_free_patches(block);
587    
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;
596    
597     cpu->insn_block_list = block;
598    
599     cpu->compiled_pages++;
600     return block;
601    
602     error:
603     insn_block_free(cpu,block,FALSE);
604     return NULL;
605     }
606    
607     /* Run a compiled MIPS instruction block */
608     static forced_inline void insn_block_run(cpu_mips_t *cpu,insn_block_t *block)
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);
618     tlb_dump(cpu);
619     cpu_stop(cpu);
620     return;
621     }
622    
623     #if DEBUG_SYM_TREE
624     if (cpu->sym_trace && cpu->sym_tree)
625     {
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, "
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) {
643     cpu_log(cpu,"insn_block_run(end)","%s, v0 = 0x%llx\n",
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     {
653     if ((vaddr >= block->start_pc) &&
654     ((vaddr - block->start_pc) < MIPS_MIN_PAGE_SIZE))
655     {
656     *jit_addr = insn_block_get_jit_ptr(block,vaddr);
657     return(1);
658     }
659    
660     return(0);
661     }
662    
663 dpavlin 2 /* 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    
672 dpavlin 1 /* Execute a compiled MIPS code */
673     void *insn_block_execute(cpu_mips_t *cpu)
674     {
675     pthread_t timer_irq_thread;
676     insn_block_t *block;
677     m_uint32_t phys_page;
678     int timer_irq_check = 0;
679    
680     if (pthread_create(&timer_irq_thread,NULL,
681     (void *)mips64_timer_irq_run,cpu))
682     {
683 dpavlin 4 fprintf(stderr,
684     "VM '%s': unable to create Timer IRQ thread for CPU%u.\n",
685 dpavlin 1 cpu->vm->name,cpu->id);
686     cpu_stop(cpu);
687     return NULL;
688     }
689    
690     cpu->cpu_thread_running = TRUE;
691 dpavlin 3
692 dpavlin 1 start_cpu:
693 dpavlin 3 cpu->idle_count = 0;
694    
695 dpavlin 1 for(;;) {
696 dpavlin 2 if (unlikely(cpu->state != MIPS_CPU_RUNNING))
697 dpavlin 1 break;
698    
699     /* Handle virtual idle loop */
700     if (unlikely(cpu->pc == cpu->idle_pc)) {
701 dpavlin 3 if (++cpu->idle_count == cpu->idle_max) {
702 dpavlin 1 mips64_idle_loop(cpu);
703 dpavlin 3 cpu->idle_count = 0;
704 dpavlin 1 }
705     }
706    
707     /* Handle the virtual CPU clock */
708     if (++timer_irq_check == cpu->timer_irq_check_itv) {
709     timer_irq_check = 0;
710    
711     if (cpu->timer_irq_pending && !cpu->irq_disable) {
712     mips64_trigger_timer_irq(cpu);
713     mips64_trigger_irq(cpu);
714     cpu->timer_irq_pending--;
715     }
716     }
717    
718     /* Get the physical page address corresponding to PC register */
719     if (unlikely(cpu->translate(cpu,cpu->pc,&phys_page))) {
720     fprintf(stderr,"VM '%s': no physical page for CPU%u PC=0x%llx\n",
721     cpu->vm->name,cpu->id,cpu->pc);
722     cpu_stop(cpu);
723     break;
724     }
725    
726     block = cpu->exec_phys_map[phys_page];
727    
728     /* No block found, compile the page */
729 dpavlin 2 if (unlikely(!block) || unlikely(!insn_block_match(cpu,block)))
730     {
731     if (block != NULL) {
732     insn_block_free(cpu,block,TRUE);
733     cpu->exec_phys_map[phys_page] = NULL;
734     }
735    
736 dpavlin 1 block = insn_page_compile(cpu,cpu->pc);
737     if (unlikely(!block)) {
738     fprintf(stderr,
739     "VM '%s': unable to compile block for CPU%u PC=0x%llx\n",
740     cpu->vm->name,cpu->id,cpu->pc);
741     cpu_stop(cpu);
742     break;
743     }
744    
745     block->phys_page = phys_page;
746     cpu->exec_phys_map[phys_page] = block;
747     }
748    
749     #if DEBUG_BLOCK_TIMESTAMP
750     block->tm_last_use = jit_jiffies++;
751     #endif
752     block->acc_count++;
753     insn_block_run(cpu,block);
754     }
755    
756     if (!cpu->pc) {
757     cpu_stop(cpu);
758     cpu_log(cpu,"JIT","PC=0, halting CPU.\n");
759     }
760    
761     /* Check regularly if the CPU has been restarted */
762     while(cpu->cpu_thread_running) {
763     cpu->seq_state++;
764    
765     switch(cpu->state) {
766     case MIPS_CPU_RUNNING:
767     cpu->state = MIPS_CPU_RUNNING;
768     goto start_cpu;
769    
770     case MIPS_CPU_HALTED:
771     cpu->cpu_thread_running = FALSE;
772     pthread_join(timer_irq_thread,NULL);
773     break;
774     }
775    
776     /* CPU is paused */
777     usleep(200000);
778     }
779    
780     return NULL;
781     }

  ViewVC Help
Powered by ViewVC 1.1.26