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