/[dynamips]/trunk/ppc32_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

Contents of /trunk/ppc32_jit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Sat Oct 6 16:45:40 2007 UTC (12 years ago) by dpavlin
File MIME type: text/plain
File size: 35275 byte(s)
make working copy

1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4 *
5 * PPC32 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 "ppc32.h"
22 #include "ppc32_exec.h"
23 #include "ppc32_jit.h"
24 #include "insn_lookup.h"
25 #include "memory.h"
26 #include "ptask.h"
27
28 #include PPC32_ARCH_INC_FILE
29
30 /* Instruction Lookup Table */
31 static insn_lookup_t *ilt = NULL;
32
33 static void *ppc32_jit_get_insn(int index)
34 {
35 return(&ppc32_insn_tags[index]);
36 }
37
38 static int ppc32_jit_chk_lo(struct ppc32_insn_tag *tag,int value)
39 {
40 return((value & tag->mask) == (tag->value & 0xFFFF));
41 }
42
43 static int ppc32_jit_chk_hi(struct ppc32_insn_tag *tag,int value)
44 {
45 return((value & (tag->mask >> 16)) == (tag->value >> 16));
46 }
47
48 /* Initialize instruction lookup table */
49 void ppc32_jit_create_ilt(void)
50 {
51 int i,count;
52
53 for(i=0,count=0;ppc32_insn_tags[i].emit;i++)
54 count++;
55
56 ilt = ilt_create("ppc32j",count,
57 (ilt_get_insn_cbk_t)ppc32_jit_get_insn,
58 (ilt_check_cbk_t)ppc32_jit_chk_lo,
59 (ilt_check_cbk_t)ppc32_jit_chk_hi);
60 }
61
62 /* Initialize the JIT structure */
63 int ppc32_jit_init(cpu_ppc_t *cpu)
64 {
65 insn_exec_page_t *cp;
66 u_char *cp_addr;
67 u_int area_size;
68 size_t len;
69 int i;
70
71 /* JIT mapping for executable pages */
72 len = PPC_JIT_IA_HASH_SIZE * sizeof(void *);
73 cpu->exec_blk_map = m_memalign(4096,len);
74 memset(cpu->exec_blk_map,0,len);
75
76 /* Physical mapping for executable pages */
77 len = PPC_JIT_PHYS_HASH_SIZE * sizeof(void *);
78 cpu->exec_phys_map = m_memalign(4096,len);
79 memset(cpu->exec_phys_map,0,len);
80
81 /* Get area size */
82 if (!(area_size = cpu->vm->exec_area_size))
83 area_size = PPC_EXEC_AREA_SIZE;
84
85 /* Create executable page area */
86 cpu->exec_page_area_size = area_size * 1048576;
87 cpu->exec_page_area = mmap(NULL,cpu->exec_page_area_size,
88 PROT_EXEC|PROT_READ|PROT_WRITE,
89 MAP_SHARED|MAP_ANONYMOUS,-1,(off_t)0);
90
91 if (!cpu->exec_page_area) {
92 fprintf(stderr,
93 "ppc32_jit_init: unable to create exec area (size %lu)\n",
94 (u_long)cpu->exec_page_area_size);
95 return(-1);
96 }
97
98 /* Carve the executable page area */
99 cpu->exec_page_count = cpu->exec_page_area_size / PPC_JIT_BUFSIZE;
100
101 cpu->exec_page_array = calloc(cpu->exec_page_count,
102 sizeof(insn_exec_page_t));
103
104 if (!cpu->exec_page_array) {
105 fprintf(stderr,"ppc32_jit_init: unable to create exec page array\n");
106 return(-1);
107 }
108
109 for(i=0,cp_addr=cpu->exec_page_area;i<cpu->exec_page_count;i++) {
110 cp = &cpu->exec_page_array[i];
111
112 cp->ptr = cp_addr;
113 cp_addr += PPC_JIT_BUFSIZE;
114
115 cp->next = cpu->exec_page_free_list;
116 cpu->exec_page_free_list = cp;
117 }
118
119 printf("CPU%u: carved JIT exec zone of %lu Mb into %lu pages of %u Kb.\n",
120 cpu->gen->id,
121 (u_long)(cpu->exec_page_area_size / 1048576),
122 (u_long)cpu->exec_page_count,PPC_JIT_BUFSIZE / 1024);
123 return(0);
124 }
125
126 /* Flush the JIT */
127 u_int ppc32_jit_flush(cpu_ppc_t *cpu,u_int threshold)
128 {
129 ppc32_jit_tcb_t *p,*next;
130 m_uint32_t ia_hash;
131 u_int count = 0;
132
133 if (!threshold)
134 threshold = (u_int)(-1); /* UINT_MAX not defined everywhere */
135
136 for(p=cpu->tcb_list;p;p=next) {
137 next = p->next;
138
139 if (p->acc_count <= threshold) {
140 ia_hash = ppc32_jit_get_ia_hash(p->start_ia);
141 ppc32_jit_tcb_free(cpu,p,TRUE);
142
143 if (cpu->exec_blk_map[ia_hash] == p)
144 cpu->exec_blk_map[ia_hash] = NULL;
145 count++;
146 }
147 }
148
149 cpu->compiled_pages -= count;
150 return(count);
151 }
152
153 /* Shutdown the JIT */
154 void ppc32_jit_shutdown(cpu_ppc_t *cpu)
155 {
156 ppc32_jit_tcb_t *p,*next;
157
158 /* Flush the JIT */
159 ppc32_jit_flush(cpu,0);
160
161 /* Free the instruction blocks */
162 for(p=cpu->tcb_free_list;p;p=next) {
163 next = p->next;
164 free(p);
165 }
166
167 /* Unmap the executable page area */
168 if (cpu->exec_page_area)
169 munmap(cpu->exec_page_area,cpu->exec_page_area_size);
170
171 /* Free the exec page array */
172 free(cpu->exec_page_array);
173
174 /* Free JIT block mapping */
175 free(cpu->exec_blk_map);
176
177 /* Free physical mapping for executable pages */
178 free(cpu->exec_phys_map);
179 }
180
181 /* Allocate an exec page */
182 static inline insn_exec_page_t *exec_page_alloc(cpu_ppc_t *cpu)
183 {
184 insn_exec_page_t *p;
185 u_int count;
186
187 /* If the free list is empty, flush JIT */
188 if (unlikely(!cpu->exec_page_free_list))
189 {
190 if (cpu->jit_flush_method) {
191 cpu_log(cpu->gen,
192 "JIT","flushing data structures (compiled pages=%u)\n",
193 cpu->compiled_pages);
194 ppc32_jit_flush(cpu,0);
195 } else {
196 count = ppc32_jit_flush(cpu,100);
197 cpu_log(cpu->gen,"JIT","partial JIT flush (count=%u)\n",count);
198
199 if (!cpu->exec_page_free_list)
200 ppc32_jit_flush(cpu,0);
201 }
202
203 /* Use both methods alternatively */
204 cpu->jit_flush_method = 1 - cpu->jit_flush_method;
205 }
206
207 if (unlikely(!(p = cpu->exec_page_free_list)))
208 return NULL;
209
210 cpu->exec_page_free_list = p->next;
211 cpu->exec_page_alloc++;
212 return p;
213 }
214
215 /* Free an exec page and returns it to the pool */
216 static inline void exec_page_free(cpu_ppc_t *cpu,insn_exec_page_t *p)
217 {
218 if (p) {
219 p->next = cpu->exec_page_free_list;
220 cpu->exec_page_free_list = p;
221 cpu->exec_page_alloc--;
222 }
223 }
224
225 /* Find the JIT code emitter for the specified PowerPC instruction */
226 static struct ppc32_insn_tag *insn_tag_find(ppc_insn_t ins)
227 {
228 struct ppc32_insn_tag *tag = NULL;
229 int index;
230
231 index = ilt_lookup(ilt,ins);
232 tag = ppc32_jit_get_insn(index);
233 return tag;
234 }
235
236 /* Fetch a PowerPC instruction */
237 static forced_inline ppc_insn_t insn_fetch(ppc32_jit_tcb_t *b)
238 {
239 return(vmtoh32(b->ppc_code[b->ppc_trans_pos]));
240 }
241
242 #define DEBUG_HREG 0
243
244 /* Show register allocation status */
245 static void ppc32_jit_show_hreg_status(cpu_ppc_t *cpu)
246 {
247 struct hreg_map *map;
248
249 printf("PPC32-JIT: reg status for insn '%s'\n",cpu->jit_hreg_seq_name);
250
251 for(map=cpu->hreg_map_list;map;map=map->next) {
252 switch(map->flags) {
253 case 0:
254 printf(" hreg %d is free, mapped to vreg %d\n",
255 map->hreg,map->vreg);
256 break;
257 case HREG_FLAG_ALLOC_LOCKED:
258 printf(" hreg %d is locked, mapped to vreg %d\n",
259 map->hreg,map->vreg);
260 break;
261 case HREG_FLAG_ALLOC_FORCED:
262 printf(" hreg %d is in forced alloc\n",map->hreg);
263 break;
264 }
265 }
266 }
267
268 /* Extract an host reg mapping from the register list */
269 static void ppc32_jit_extract_hreg(cpu_ppc_t *cpu,struct hreg_map *map)
270 {
271 if (map->prev != NULL)
272 map->prev->next = map->next;
273 else
274 cpu->hreg_map_list = map->next;
275
276 if (map->next != NULL)
277 map->next->prev = map->prev;
278 else
279 cpu->hreg_lru = map->prev;
280 }
281
282 /* Insert a reg map as head of list (as MRU element) */
283 void ppc32_jit_insert_hreg_mru(cpu_ppc_t *cpu,struct hreg_map *map)
284 {
285 map->next = cpu->hreg_map_list;
286 map->prev = NULL;
287
288 if (map->next == NULL) {
289 cpu->hreg_lru = map;
290 } else {
291 map->next->prev = map;
292 }
293
294 cpu->hreg_map_list = map;
295 }
296
297 /* Start register allocation sequence */
298 void ppc32_jit_start_hreg_seq(cpu_ppc_t *cpu,char *insn)
299 {
300 struct hreg_map *map;
301
302 #if DEBUG_HREG
303 printf("Starting hreg_seq insn='%s'\n",insn);
304 #endif
305
306 /* Reset the allocation state of all host registers */
307 for(map=cpu->hreg_map_list;map;map=map->next)
308 map->flags = 0;
309
310 /* Save the instruction name for debugging/error analysis */
311 cpu->jit_hreg_seq_name = insn;
312 }
313
314 /* Close register allocation sequence */
315 void ppc32_jit_close_hreg_seq(cpu_ppc_t *cpu)
316 {
317 #if DEBUG_HREG
318 ppc32_show_hreg_status(cpu);
319 #endif
320 }
321
322 /* Find a free host register to use */
323 static struct hreg_map *ppc32_jit_get_free_hreg(cpu_ppc_t *cpu)
324 {
325 struct hreg_map *map,*oldest_free = NULL;
326
327 for(map=cpu->hreg_lru;map;map=map->prev) {
328 if ((map->vreg == -1) && (map->flags == 0))
329 return map;
330
331 if ((map->flags == 0) && !oldest_free)
332 oldest_free = map;
333 }
334
335 if (!oldest_free) {
336 fprintf(stderr,
337 "ppc32_get_free_hreg: unable to find free reg for insn %s\n",
338 cpu->jit_hreg_seq_name);
339 }
340
341 return oldest_free;
342 }
343
344 /* Allocate an host register */
345 int ppc32_jit_alloc_hreg(cpu_ppc_t *cpu,int ppc_reg)
346 {
347 struct hreg_map *map;
348 int hreg;
349
350 /*
351 * If PPC reg is invalid, the caller requested for a temporary register.
352 */
353 if (ppc_reg == -1) {
354 if ((map = ppc32_jit_get_free_hreg(cpu)) == NULL)
355 return(-1);
356
357 /* Allocate the register and invalidate its PPC mapping if present */
358 map->flags = HREG_FLAG_ALLOC_LOCKED;
359
360 if (map->vreg != -1) {
361 cpu->ppc_reg_map[map->vreg] = -1;
362 map->vreg = -1;
363 }
364
365 return(map->hreg);
366 }
367
368 hreg = cpu->ppc_reg_map[ppc_reg];
369
370 /*
371 * If the PPC register is already mapped to an host register, re-use this
372 * mapping and put this as MRU mapping.
373 */
374 if (hreg != -1) {
375 map = &cpu->hreg_map[hreg];
376 } else {
377 /*
378 * This PPC register has no mapping to host register. Find a free
379 * register.
380 */
381 if ((map = ppc32_jit_get_free_hreg(cpu)) == NULL)
382 return(-1);
383
384 /* Remove the old PPC mapping if present */
385 if (map->vreg != -1)
386 cpu->ppc_reg_map[map->vreg] = -1;
387
388 /* Establish the new mapping */
389 cpu->ppc_reg_map[ppc_reg] = map->hreg;
390 map->vreg = ppc_reg;
391 }
392
393 /* Prevent this register from further allocation in this instruction */
394 map->flags = HREG_FLAG_ALLOC_LOCKED;
395 ppc32_jit_extract_hreg(cpu,map);
396 ppc32_jit_insert_hreg_mru(cpu,map);
397 return(map->hreg);
398 }
399
400 /* Force allocation of an host register */
401 int ppc32_jit_alloc_hreg_forced(cpu_ppc_t *cpu,int hreg)
402 {
403 int ppc_reg;
404
405 ppc_reg = cpu->hreg_map[hreg].vreg;
406
407 /* Check that this register is not already allocated */
408 if (cpu->hreg_map[hreg].flags != 0) {
409 fprintf(stderr,"ppc32_alloc_hreg_forced: trying to force allocation "
410 "of hreg %d (insn %s)\n",
411 hreg,cpu->jit_hreg_seq_name);
412 return(-1);
413 }
414
415 cpu->hreg_map[hreg].flags = HREG_FLAG_ALLOC_FORCED;
416 cpu->hreg_map[hreg].vreg = -1;
417
418 if (ppc_reg != -1)
419 cpu->ppc_reg_map[ppc_reg] = -1;
420
421 return(0);
422 }
423
424 /* Emit a breakpoint if necessary */
425 #if BREAKPOINT_ENABLE
426 static void insn_emit_breakpoint(cpu_ppc_t *cpu,ppc32_jit_tcb_t *b)
427 {
428 m_uint32_t ia;
429 int i;
430
431 ia = b->start_ia+((b->ppc_trans_pos-1)<<2);
432
433 for(i=0;i<PPC32_MAX_BREAKPOINTS;i++)
434 if (ia == cpu->breakpoints[i]) {
435 ppc32_emit_breakpoint(cpu,b);
436 break;
437 }
438 }
439 #endif /* BREAKPOINT_ENABLE */
440
441 /* Fetch a PowerPC instruction and emit corresponding translated code */
442 struct ppc32_insn_tag *ppc32_jit_fetch_and_emit(cpu_ppc_t *cpu,
443 ppc32_jit_tcb_t *block)
444 {
445 struct ppc32_insn_tag *tag;
446 ppc_insn_t code;
447
448 code = insn_fetch(block);
449 tag = insn_tag_find(code);
450 assert(tag);
451
452 tag->emit(cpu,block,code);
453 return tag;
454 }
455
456 /* Add end of JIT block */
457 static void ppc32_jit_tcb_add_end(ppc32_jit_tcb_t *b)
458 {
459 ppc32_set_ia(&b->jit_ptr,b->start_ia+(b->ppc_trans_pos<<2));
460 ppc32_jit_tcb_push_epilog(&b->jit_ptr);
461 }
462
463 /* Record a patch to apply in a compiled block */
464 int ppc32_jit_tcb_record_patch(ppc32_jit_tcb_t *block,jit_op_t *iop,
465 u_char *jit_ptr,m_uint32_t vaddr)
466 {
467 struct ppc32_jit_patch_table *ipt = block->patch_table;
468 struct ppc32_insn_patch *patch;
469
470 /* pc must be 32-bit aligned */
471 if (vaddr & 0x03) {
472 fprintf(stderr,
473 "Block 0x%8.8x: trying to record an invalid IA (0x%8.8x)\n",
474 block->start_ia,vaddr);
475 return(-1);
476 }
477
478 if (!ipt || (ipt->cur_patch >= PPC32_INSN_PATCH_TABLE_SIZE))
479 {
480 /* full table or no table, create a new one */
481 ipt = malloc(sizeof(*ipt));
482 if (!ipt) {
483 fprintf(stderr,"Block 0x%8.8x: unable to create patch table.\n",
484 block->start_ia);
485 return(-1);
486 }
487
488 memset(ipt,0,sizeof(*ipt));
489 ipt->next = block->patch_table;
490 block->patch_table = ipt;
491 }
492
493 #if DEBUG_BLOCK_PATCH
494 printf("Block 0x%8.8x: recording patch [JIT:%p->ppc:0x%8.8x], "
495 "MTP=%d\n",block->start_ia,jit_ptr,vaddr,block->ppc_trans_pos);
496 #endif
497
498 patch = &ipt->patches[ipt->cur_patch];
499 patch->jit_insn = jit_ptr;
500 patch->ppc_ia = vaddr;
501 ipt->cur_patch++;
502
503 patch->next = iop->arg_ptr;
504 iop->arg_ptr = patch;
505 return(0);
506 }
507
508 /* Apply patches for a JIT instruction block */
509 static int ppc32_jit_tcb_apply_patches(cpu_ppc_t *cpu,
510 ppc32_jit_tcb_t *block,
511 jit_op_t *iop)
512 {
513 struct ppc32_insn_patch *patch;
514 u_char *jit_ptr,*jit_dst;
515 u_int pos;
516
517 for(patch=iop->arg_ptr;patch;patch=patch->next) {
518 jit_ptr = (patch->jit_insn - iop->ob_data) + iop->ob_final;
519
520 pos = (patch->ppc_ia & PPC32_MIN_PAGE_IMASK) >> 2;
521 jit_dst = block->jit_insn_ptr[pos];
522
523 if (jit_dst) {
524 #if DEBUG_BLOCK_PATCH
525 printf("Block 0x%8.8x: applying patch "
526 "[JIT:%p->ppc:0x%8.8x=JIT:%p, ]\n",
527 block->start_ia,patch->jit_insn,patch->ppc_ia,jit_dst);
528 #endif
529 ppc32_jit_tcb_set_patch(jit_ptr,jit_dst);
530 } else {
531 printf("Block 0x%8.8x: null dst for patch!\n",block->start_ia);
532 }
533 }
534
535 return(0);
536 }
537
538 /* Free the patch table */
539 static void ppc32_jit_tcb_free_patches(ppc32_jit_tcb_t *block)
540 {
541 struct ppc32_jit_patch_table *p,*next;
542
543 for(p=block->patch_table;p;p=next) {
544 next = p->next;
545 free(p);
546 }
547
548 block->patch_table = NULL;
549 }
550
551 /* Adjust the JIT buffer if its size is not sufficient */
552 static int ppc32_jit_tcb_adjust_buffer(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block)
553 {
554 insn_exec_page_t *new_buffer;
555
556 if ((block->jit_ptr - block->jit_buffer->ptr) <= (PPC_JIT_BUFSIZE - 512))
557 return(0);
558
559 #if DEBUG_BLOCK_CHUNK
560 printf("Block 0x%8.8x: adjusting JIT buffer...\n",block->start_ia);
561 #endif
562
563 if (block->jit_chunk_pos >= PPC_JIT_MAX_CHUNKS) {
564 fprintf(stderr,"Block 0x%8.8x: too many JIT chunks.\n",block->start_ia);
565 return(-1);
566 }
567
568 if (!(new_buffer = exec_page_alloc(cpu)))
569 return(-1);
570
571 /* record the new exec page */
572 block->jit_chunks[block->jit_chunk_pos++] = block->jit_buffer;
573 block->jit_buffer = new_buffer;
574
575 /* jump to the new exec page (link) */
576 ppc32_jit_tcb_set_jump(block->jit_ptr,new_buffer->ptr);
577 block->jit_ptr = new_buffer->ptr;
578 return(0);
579 }
580
581 /* Allocate an instruction block */
582 static inline ppc32_jit_tcb_t *ppc32_jit_tcb_alloc(cpu_ppc_t *cpu)
583 {
584 ppc32_jit_tcb_t *p;
585
586 if (cpu->tcb_free_list) {
587 p = cpu->tcb_free_list;
588 cpu->tcb_free_list = p->next;
589 } else {
590 if (!(p = malloc(sizeof(*p))))
591 return NULL;
592 }
593
594 memset(p,0,sizeof(*p));
595 return p;
596 }
597
598 /* Free the code chunks */
599 static void
600 ppc32_jit_tcb_free_code_chunks(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block)
601 {
602 int i;
603
604 /* Free code pages */
605 for(i=0;i<PPC_JIT_MAX_CHUNKS;i++) {
606 exec_page_free(cpu,block->jit_chunks[i]);
607 block->jit_chunks[i] = NULL;
608 }
609
610 /* Free the current JIT buffer */
611 exec_page_free(cpu,block->jit_buffer);
612 block->jit_buffer = NULL;
613 }
614
615 /* Free an instruction block */
616 void ppc32_jit_tcb_free(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block,
617 int list_removal)
618 {
619 if (block) {
620 if (list_removal) {
621 /* Remove the block from the linked list */
622 if (block->next)
623 block->next->prev = block->prev;
624 else
625 cpu->tcb_last = block->prev;
626
627 if (block->prev)
628 block->prev->next = block->next;
629 else
630 cpu->tcb_list = block->next;
631
632 /* Remove the block from the physical mapping hash table */
633 if (block->phys_pprev) {
634 if (block->phys_next)
635 block->phys_next->phys_pprev = block->phys_pprev;
636
637 *(block->phys_pprev) = block->phys_next;
638
639 block->phys_pprev = NULL;
640 block->phys_next = NULL;
641 }
642 }
643
644 /* Free the patch tables */
645 ppc32_jit_tcb_free_patches(block);
646
647 /* Free code pages */
648 ppc32_jit_tcb_free_code_chunks(cpu,block);
649
650 /* Free the PowerPC-to-native code mapping */
651 free(block->jit_insn_ptr);
652
653 block->next = cpu->tcb_free_list;
654 cpu->tcb_free_list = block;
655 }
656 }
657
658 /* Create an instruction block */
659 static ppc32_jit_tcb_t *ppc32_jit_tcb_create(cpu_ppc_t *cpu,m_uint32_t vaddr)
660 {
661 ppc32_jit_tcb_t *block = NULL;
662 m_uint32_t phys_page;
663
664 if (unlikely(cpu->translate(cpu,cpu->ia,PPC32_MTS_ICACHE,&phys_page)))
665 return NULL;
666
667 if (!(block = ppc32_jit_tcb_alloc(cpu)))
668 goto err_block_alloc;
669
670 block->start_ia = vaddr;
671 block->phys_page = phys_page;
672 block->phys_hash = ppc32_jit_get_phys_hash(phys_page);
673
674 /* Allocate the first JIT buffer */
675 if (!(block->jit_buffer = exec_page_alloc(cpu)))
676 goto err_jit_alloc;
677
678 block->jit_ptr = block->jit_buffer->ptr;
679 block->ppc_code = cpu->mem_op_lookup(cpu,block->start_ia,PPC32_MTS_ICACHE);
680
681 if (!block->ppc_code) {
682 fprintf(stderr,"%% No memory map for code execution at 0x%8.8x\n",
683 block->start_ia);
684 goto err_lookup;
685 }
686
687 #if DEBUG_BLOCK_TIMESTAMP
688 block->tm_first_use = block->tm_last_use = jit_jiffies;
689 #endif
690 return block;
691
692 err_lookup:
693 err_jit_alloc:
694 ppc32_jit_tcb_free(cpu,block,FALSE);
695 err_block_alloc:
696 fprintf(stderr,"%% Unable to create instruction block for vaddr=0x%8.8x\n",
697 vaddr);
698 return NULL;
699 }
700
701 /* ======================================================================== */
702
703 /* Dump a JIT opcode */
704 static void ppc32_op_dump_opcode(jit_op_t *op)
705 {
706 switch(op->opcode) {
707 case JIT_OP_BRANCH_TARGET:
708 printf("branch_target");
709 break;
710 case JIT_OP_BRANCH_JUMP:
711 printf("branch_jump");
712 break;
713 case JIT_OP_EOB:
714 printf("eob");
715 break;
716 case JIT_OP_LOAD_GPR:
717 printf("load_gpr(%d,$%d,r:%d)",
718 op->param[0],op->param[1],op->param[2]);
719 break;
720 case JIT_OP_STORE_GPR:
721 printf("store_gpr(%d,$%d,r:%d)",
722 op->param[0],op->param[1],op->param[2]);
723 break;
724 case JIT_OP_ALTER_HOST_REG:
725 printf("alter_host_reg(%d)",op->param[0]);
726 break;
727 case JIT_OP_UPDATE_FLAGS:
728 printf("update_flags(%d,%s)",
729 op->param[0],(op->param[1] ? "signed" : "unsigned"));
730 break;
731 case JIT_OP_REQUIRE_FLAGS:
732 printf("require_flags(%d)",op->param[0]);
733 break;
734 case JIT_OP_TRASH_FLAGS:
735 printf("trash_flags(%d)",op->param[0]);
736 break;
737 case JIT_OP_INSN_OUTPUT:
738 printf("insn_out(\"%s\")",op->insn_name);
739 break;
740 case JIT_OP_SET_HOST_REG_IMM32:
741 printf("set_host_reg_imm32(%d,0x%8.8x)",op->param[0],op->param[1]);
742 break;
743 default:
744 printf("op(%u)",op->opcode);
745 }
746 }
747
748 /* Dump JIT operations (debugging) */
749 static void ppc32_op_dump(cpu_gen_t *cpu,ppc32_jit_tcb_t *b)
750 {
751 m_uint32_t ia = b->start_ia;
752 jit_op_t *op;
753 int i;
754
755 printf("PPC32-JIT: dump of page 0x%8.8x\n",ia);
756
757 for(i=0;i<PPC32_INSN_PER_PAGE;i++,ia+=sizeof(ppc_insn_t)) {
758 printf(" 0x%8.8x: ", ia);
759
760 for(op=cpu->jit_op_array[i];op;op=op->next) {
761 ppc32_op_dump_opcode(op);
762 printf(" ");
763 }
764
765 printf("\n");
766 }
767
768 printf("\n");
769 }
770
771 /* PPC register mapping */
772 typedef struct {
773 int host_reg;
774 jit_op_t *last_store;
775 m_uint32_t last_store_ia;
776 }ppc_reg_map_t;
777
778 /* Clear register mapping (with PPC register) */
779 static void ppc32_clear_ppc_reg_map(ppc_reg_map_t *ppc_map,int *host_map,
780 int reg)
781 {
782 int i,hreg;
783
784 if (reg == JIT_OP_ALL_REGS) {
785 for(i=0;i<PPC32_GPR_NR;i++) {
786 ppc_map[i].host_reg = JIT_OP_INV_REG;
787 ppc_map[i].last_store = NULL;
788 }
789
790 for(i=0;i<JIT_HOST_NREG;i++)
791 host_map[i] = JIT_OP_INV_REG;
792 } else {
793 hreg = ppc_map[reg].host_reg;
794
795 if (hreg != JIT_OP_INV_REG)
796 host_map[hreg] = JIT_OP_INV_REG;
797
798 ppc_map[reg].host_reg = JIT_OP_INV_REG;
799 ppc_map[reg].last_store = NULL;
800 }
801 }
802
803 /* Clear register mapping (with host register) */
804 static void ppc32_clear_host_reg_map(ppc_reg_map_t *ppc_map,int *host_map,
805 int reg)
806 {
807 int ppc_reg;
808
809 if (host_map[reg] != JIT_OP_INV_REG) {
810 ppc_reg = host_map[reg];
811
812 ppc_map[ppc_reg].host_reg = JIT_OP_INV_REG;
813 ppc_map[ppc_reg].last_store = NULL;
814 host_map[reg] = JIT_OP_INV_REG;
815 }
816 }
817
818 /* Dump register mapping */
819 static void ppc32_dump_reg_map(ppc_reg_map_t *map_array,int *host_map)
820 {
821 int i;
822
823 printf("PPC32-JIT: current register mapping:\n");
824
825 for(i=0;i<PPC32_GPR_NR;i++)
826 printf(" ppc reg %2.2d: %d\n",i,map_array[i].host_reg);
827
828 printf("\n");
829
830 for(i=0;i<JIT_HOST_NREG;i++)
831 printf(" hreg %d: %d\n",i,host_map[i]);
832
833 printf("\n");
834 }
835
836 /* Check register mapping consistency */
837 static int ppc32_check_reg_map(ppc_reg_map_t *map_array,int *host_map)
838 {
839 ppc_reg_map_t *map;
840 int i;
841
842 for(i=0;i<PPC32_GPR_NR;i++) {
843 map = &map_array[i];
844
845 if ((map->host_reg != JIT_OP_INV_REG) && (host_map[map->host_reg] != i))
846 goto error;
847 }
848
849 for(i=0;i<JIT_HOST_NREG;i++) {
850 if ((host_map[i] != JIT_OP_INV_REG) &&
851 (map_array[host_map[i]].host_reg != i))
852 goto error;
853 }
854
855 return(0);
856
857 error:
858 printf("PPC32_JIT: inconsistency in register mapping.\n");
859 ppc32_dump_reg_map(map_array,host_map);
860 exit(1);
861 }
862
863 /* Optimize JIT operations */
864 static void ppc32_op_optimize(cpu_gen_t *cpu,ppc32_jit_tcb_t *b)
865 {
866 ppc_reg_map_t ppc_map[PPC32_GPR_NR],*map;
867 int reg,host_map[JIT_HOST_NREG];
868 jit_op_t *op,*opx,*last_cr_update[8];
869 m_uint32_t cur_ia;
870 int i,j;
871
872 ppc32_clear_ppc_reg_map(ppc_map,host_map,JIT_OP_ALL_REGS);
873
874 for(i=0;i<8;i++)
875 last_cr_update[i] = NULL;
876
877 for(i=0;i<PPC32_INSN_PER_PAGE;i++) {
878 for(op=cpu->jit_op_array[i];op;op=op->next)
879 {
880 //ppc32_check_reg_map(ppc_map,host_map);
881 cur_ia = b->start_ia + (i << 2);
882
883 switch(op->opcode) {
884 /* Clear mapping if end of block or branch target */
885 case JIT_OP_BRANCH_TARGET:
886 case JIT_OP_EOB:
887 ppc32_clear_ppc_reg_map(ppc_map,host_map,JIT_OP_ALL_REGS);
888
889 for(j=0;j<8;j++)
890 last_cr_update[j] = NULL;
891 break;
892
893 /* Branch jump: clear "store" operation status */
894 case JIT_OP_BRANCH_JUMP:
895 for(j=0;j<PPC32_GPR_NR;j++)
896 ppc_map[j].last_store = NULL;
897
898 for(j=0;j<8;j++)
899 last_cr_update[j] = NULL;
900 break;
901
902 /* Alteration of a specific host register */
903 case JIT_OP_ALTER_HOST_REG:
904 reg = op->param[0];
905
906 if (reg != JIT_OP_ALL_REGS) {
907 if (host_map[reg] != JIT_OP_INV_REG)
908 ppc32_clear_ppc_reg_map(ppc_map,host_map,host_map[reg]);
909 } else {
910 ppc32_clear_ppc_reg_map(ppc_map,host_map,JIT_OP_ALL_REGS);
911 }
912 break;
913
914 /* Save reg mapping and last operation */
915 case JIT_OP_STORE_GPR:
916 reg = op->param[0];
917 map = &ppc_map[op->param[1]];
918
919 /* clear old mapping */
920 if (reg != map->host_reg) {
921 ppc32_clear_host_reg_map(ppc_map,host_map,reg);
922 ppc32_clear_ppc_reg_map(ppc_map,host_map,op->param[1]);
923 }
924
925 /* cancel previous store op for this PPC register */
926 if (map->last_store) {
927 map->last_store->param[0] = JIT_OP_INV_REG;
928 map->last_store = NULL;
929 }
930
931 map->host_reg = reg;
932 map->last_store = op;
933 map->last_store_ia = cur_ia;
934 host_map[reg] = op->param[1];
935 break;
936
937 /* Load reg: check if can avoid it */
938 case JIT_OP_LOAD_GPR:
939 reg = op->param[0];
940 map = &ppc_map[op->param[1]];
941
942 if (reg == map->host_reg) {
943 /* Cancel this load */
944 op->param[0] = JIT_OP_INV_REG;
945 } else {
946 /* clear old mapping */
947 ppc32_clear_host_reg_map(ppc_map,host_map,reg);
948 ppc32_clear_ppc_reg_map(ppc_map,host_map,op->param[1]);
949
950 /* Save this reg mapping */
951 map->host_reg = op->param[0];
952 map->last_store = NULL;
953 host_map[op->param[0]] = op->param[1];
954 }
955 break;
956
957 /* Trash flags */
958 case JIT_OP_TRASH_FLAGS:
959 for(j=0;j<8;j++)
960 last_cr_update[j] = NULL;
961 break;
962
963 /* Flags required */
964 case JIT_OP_REQUIRE_FLAGS:
965 if (op->param[0] != JIT_OP_PPC_ALL_FLAGS) {
966 last_cr_update[op->param[0]] = NULL;
967 } else {
968 for(j=0;j<8;j++)
969 last_cr_update[j] = NULL;
970 }
971 break;
972
973 /* Update flags */
974 case JIT_OP_UPDATE_FLAGS:
975 opx = last_cr_update[op->param[0]];
976
977 if (opx != NULL)
978 opx->param[0] = JIT_OP_INV_REG;
979
980 last_cr_update[op->param[0]] = op;
981 break;
982 }
983 }
984 }
985 }
986
987 /* Generate the JIT code for the specified JIT op list */
988 static void ppc32_op_gen_list(ppc32_jit_tcb_t *b,int ipos,jit_op_t *op_list,
989 u_char *jit_start)
990 {
991 jit_op_t *op;
992
993 for(op=op_list;op;op=op->next) {
994 switch(op->opcode) {
995 case JIT_OP_INSN_OUTPUT:
996 ppc32_op_insn_output(b,op);
997 break;
998 case JIT_OP_LOAD_GPR:
999 ppc32_op_load_gpr(b,op);
1000 break;
1001 case JIT_OP_STORE_GPR:
1002 ppc32_op_store_gpr(b,op);
1003 break;
1004 case JIT_OP_UPDATE_FLAGS:
1005 ppc32_op_update_flags(b,op);
1006 break;
1007 case JIT_OP_BRANCH_TARGET:
1008 b->jit_insn_ptr[ipos] = jit_start;
1009 break;
1010 case JIT_OP_MOVE_HOST_REG:
1011 ppc32_op_move_host_reg(b,op);
1012 break;
1013 case JIT_OP_SET_HOST_REG_IMM32:
1014 ppc32_op_set_host_reg_imm32(b,op);
1015 break;
1016 }
1017 }
1018 }
1019
1020 /* Opcode emit start */
1021 static inline void ppc32_op_emit_start(cpu_ppc_t *cpu,ppc32_jit_tcb_t *b)
1022 {
1023 cpu_gen_t *c = cpu->gen;
1024 jit_op_t *op;
1025
1026 if (c->jit_op_array[b->ppc_trans_pos] == NULL)
1027 c->jit_op_current = &c->jit_op_array[b->ppc_trans_pos];
1028 else {
1029 for(op=c->jit_op_array[b->ppc_trans_pos];op;op=op->next)
1030 c->jit_op_current = &op->next;
1031 }
1032 }
1033
1034 /* Generate the JIT code for the current page, given an op list */
1035 static int ppc32_op_gen_page(cpu_ppc_t *cpu,ppc32_jit_tcb_t *b)
1036 {
1037 struct ppc32_insn_tag *tag;
1038 cpu_gen_t *gcpu = cpu->gen;
1039 jit_op_t *iop;
1040 m_uint32_t cur_ia;
1041 u_char *jit_ptr;
1042 int i;
1043
1044 /* Generate JIT opcodes */
1045 for(b->ppc_trans_pos=0;
1046 b->ppc_trans_pos<PPC32_INSN_PER_PAGE;
1047 b->ppc_trans_pos++)
1048 {
1049 ppc32_op_emit_start(cpu,b);
1050
1051 cur_ia = b->start_ia + (b->ppc_trans_pos << 2);
1052
1053 if (ppc32_jit_tcb_get_target_bit(b,cur_ia))
1054 ppc32_op_emit_basic_opcode(cpu,JIT_OP_BRANCH_TARGET);
1055
1056 #if DEBUG_INSN_PERF_CNT
1057 ppc32_inc_perf_counter(cpu);
1058 #endif
1059 #if BREAKPOINT_ENABLE
1060 if (cpu->breakpoints_enabled)
1061 insn_emit_breakpoint(cpu,b);
1062 #endif
1063
1064 if (unlikely(!(tag = ppc32_jit_fetch_and_emit(cpu,b)))) {
1065 fprintf(stderr,"ppc32_op_gen_page: unable to fetch instruction.\n");
1066 return(-1);
1067 }
1068 }
1069
1070 /*
1071 * Mark the first instruction as a potential target, as well as the
1072 * current IA value.
1073 */
1074 ppc32_op_emit_branch_target(cpu,b,b->start_ia);
1075 ppc32_op_emit_branch_target(cpu,b,cpu->ia);
1076
1077 /* Optimize condition register and general registers */
1078 ppc32_op_optimize(gcpu,b);
1079
1080 /* Generate JIT code for each instruction in page */
1081 for(i=0;i<PPC32_INSN_PER_PAGE;i++)
1082 {
1083 jit_ptr = b->jit_ptr;
1084
1085 /* Generate output code */
1086 ppc32_op_gen_list(b,i,gcpu->jit_op_array[i],jit_ptr);
1087
1088 /* Adjust the JIT buffer if its size is not sufficient */
1089 ppc32_jit_tcb_adjust_buffer(cpu,b);
1090 }
1091
1092 /* Apply patches and free opcodes */
1093 for(i=0;i<PPC32_INSN_PER_PAGE;i++) {
1094 for(iop=gcpu->jit_op_array[i];iop;iop=iop->next)
1095 if (iop->opcode == JIT_OP_INSN_OUTPUT)
1096 ppc32_jit_tcb_apply_patches(cpu,b,iop);
1097
1098 jit_op_free_list(gcpu,gcpu->jit_op_array[i]);
1099 gcpu->jit_op_array[i] = NULL;
1100 }
1101
1102 /* Add end of page (returns to caller) */
1103 ppc32_set_page_jump(cpu,b);
1104
1105 /* Free patch tables */
1106 ppc32_jit_tcb_free_patches(b);
1107 return(0);
1108 }
1109
1110 /* ======================================================================== */
1111
1112 /* Compile a PowerPC instruction page */
1113 static inline
1114 ppc32_jit_tcb_t *ppc32_jit_tcb_compile(cpu_ppc_t *cpu,m_uint32_t vaddr)
1115 {
1116 ppc32_jit_tcb_t *block;
1117 m_uint32_t page_addr;
1118
1119 page_addr = vaddr & ~PPC32_MIN_PAGE_IMASK;
1120
1121 if (unlikely(!(block = ppc32_jit_tcb_create(cpu,page_addr)))) {
1122 fprintf(stderr,"insn_page_compile: unable to create JIT block.\n");
1123 return NULL;
1124 }
1125
1126 /* Allocate the array used to convert PPC code ptr to native code ptr */
1127 if (!(block->jit_insn_ptr = calloc(PPC32_INSN_PER_PAGE,sizeof(u_char *)))) {
1128 fprintf(stderr,"insn_page_compile: unable to create JIT mappings.\n");
1129 goto error;
1130 }
1131
1132 /* Compile the page */
1133 if (ppc32_op_gen_page(cpu,block) == -1) {
1134 fprintf(stderr,"insn_page_compile: unable to compile page.\n");
1135 goto error;
1136 }
1137
1138 /* Add the block to the linked list */
1139 block->next = cpu->tcb_list;
1140 block->prev = NULL;
1141
1142 if (cpu->tcb_list)
1143 cpu->tcb_list->prev = block;
1144 else
1145 cpu->tcb_last = block;
1146
1147 cpu->tcb_list = block;
1148
1149 /* Add the block to the physical mapping hash table */
1150 block->phys_next = cpu->exec_phys_map[block->phys_hash];
1151 block->phys_pprev = &cpu->exec_phys_map[block->phys_hash];
1152
1153 if (cpu->exec_phys_map[block->phys_hash] != NULL)
1154 cpu->exec_phys_map[block->phys_hash]->phys_pprev = &block->phys_next;
1155
1156 cpu->exec_phys_map[block->phys_hash] = block;
1157
1158 cpu->compiled_pages++;
1159 return block;
1160
1161 error:
1162 ppc32_jit_tcb_free(cpu,block,FALSE);
1163 return NULL;
1164 }
1165
1166 /* Recompile a page */
1167 int ppc32_jit_tcb_recompile(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block)
1168 {
1169 #if 0
1170 printf("PPC32-JIT: recompiling page 0x%8.8x\n",block->start_ia);
1171 #endif
1172
1173 /* Free old code chunks */
1174 ppc32_jit_tcb_free_code_chunks(cpu,block);
1175
1176 /* Reset code ptr array */
1177 memset(block->jit_insn_ptr,0,PPC32_INSN_PER_PAGE * sizeof(u_char *));
1178
1179 /* Allocate the first JIT buffer */
1180 if (!(block->jit_buffer = exec_page_alloc(cpu)))
1181 return(-1);
1182
1183 /* Recompile the page */
1184 if (ppc32_op_gen_page(cpu,block) == -1) {
1185 fprintf(stderr,"insn_page_compile: unable to recompile page.\n");
1186 return(-1);
1187 }
1188
1189 block->target_undef_cnt = 0;
1190 return(0);
1191 }
1192
1193 /* Run a compiled PowerPC instruction block */
1194 static forced_inline
1195 void ppc32_jit_tcb_run(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block)
1196 {
1197 if (unlikely(cpu->ia & 0x03)) {
1198 fprintf(stderr,"ppc32_jit_tcb_run: Invalid IA 0x%8.8x.\n",cpu->ia);
1199 ppc32_dump_regs(cpu->gen);
1200 ppc32_dump_mmu(cpu->gen);
1201 cpu_stop(cpu->gen);
1202 return;
1203 }
1204
1205 /* Execute JIT compiled code */
1206 ppc32_jit_tcb_exec(cpu,block);
1207 }
1208
1209 /* Execute compiled PowerPC code */
1210 void *ppc32_jit_run_cpu(cpu_gen_t *gen)
1211 {
1212 cpu_ppc_t *cpu = CPU_PPC32(gen);
1213 pthread_t timer_irq_thread;
1214 ppc32_jit_tcb_t *block;
1215 m_uint32_t ia_hash;
1216 int timer_irq_check = 0;
1217
1218 ppc32_jit_init_hreg_mapping(cpu);
1219
1220 if (pthread_create(&timer_irq_thread,NULL,(void *)ppc32_timer_irq_run,cpu))
1221 {
1222 fprintf(stderr,
1223 "VM '%s': unable to create Timer IRQ thread for CPU%u.\n",
1224 cpu->vm->name,gen->id);
1225 cpu_stop(cpu->gen);
1226 return NULL;
1227 }
1228
1229 gen->cpu_thread_running = TRUE;
1230 cpu_exec_loop_set(gen);
1231
1232 start_cpu:
1233 gen->idle_count = 0;
1234
1235 for(;;) {
1236 if (unlikely(gen->state != CPU_STATE_RUNNING))
1237 break;
1238
1239 #if DEBUG_BLOCK_PERF_CNT
1240 cpu->perf_counter++;
1241 #endif
1242 /* Handle virtual idle loop */
1243 if (unlikely(cpu->ia == cpu->idle_pc)) {
1244 if (++gen->idle_count == gen->idle_max) {
1245 cpu_idle_loop(gen);
1246 gen->idle_count = 0;
1247 }
1248 }
1249
1250 /* Handle the virtual CPU clock */
1251 if (++timer_irq_check == cpu->timer_irq_check_itv) {
1252 timer_irq_check = 0;
1253
1254 if (cpu->timer_irq_pending && !cpu->irq_disable &&
1255 (cpu->msr & PPC32_MSR_EE))
1256 {
1257 cpu->timer_irq_armed = 0;
1258 cpu->timer_irq_pending--;
1259
1260 vm_set_irq(cpu->vm,0);
1261 }
1262 }
1263
1264 /* Check IRQs */
1265 if (unlikely(cpu->irq_check))
1266 ppc32_trigger_irq(cpu);
1267
1268 /* Get the JIT block corresponding to IA register */
1269 ia_hash = ppc32_jit_get_ia_hash(cpu->ia);
1270 block = cpu->exec_blk_map[ia_hash];
1271
1272 /* No block found, compile the page */
1273 if (unlikely(!block) || unlikely(!ppc32_jit_tcb_match(cpu,block)))
1274 {
1275 if (block != NULL) {
1276 ppc32_jit_tcb_free(cpu,block,TRUE);
1277 cpu->exec_blk_map[ia_hash] = NULL;
1278 }
1279
1280 block = ppc32_jit_tcb_compile(cpu,cpu->ia);
1281
1282 if (unlikely(!block)) {
1283 fprintf(stderr,
1284 "VM '%s': unable to compile block for CPU%u IA=0x%8.8x\n",
1285 cpu->vm->name,gen->id,cpu->ia);
1286 cpu_stop(gen);
1287 break;
1288 }
1289
1290 cpu->exec_blk_map[ia_hash] = block;
1291 }
1292
1293 #if DEBUG_BLOCK_TIMESTAMP
1294 block->tm_last_use = jit_jiffies++;
1295 #endif
1296 block->acc_count++;
1297 ppc32_jit_tcb_run(cpu,block);
1298 }
1299
1300 if (!cpu->ia) {
1301 cpu_stop(gen);
1302 cpu_log(gen,"JIT","IA=0, halting CPU.\n");
1303 }
1304
1305 /* Check regularly if the CPU has been restarted */
1306 while(gen->cpu_thread_running) {
1307 gen->seq_state++;
1308
1309 switch(gen->state) {
1310 case CPU_STATE_RUNNING:
1311 gen->state = CPU_STATE_RUNNING;
1312 goto start_cpu;
1313
1314 case CPU_STATE_HALTED:
1315 gen->cpu_thread_running = FALSE;
1316 pthread_join(timer_irq_thread,NULL);
1317 break;
1318 }
1319
1320 /* CPU is paused */
1321 usleep(200000);
1322 }
1323
1324 return NULL;
1325 }

  ViewVC Help
Powered by ViewVC 1.1.26