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