1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2008 Christophe Fillot (cf@utc.fr)
4 *
5 * Translation Sharing Groups.
6 */
7 #define _GNU_SOURCE
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <pthread.h>
15 #include <sys/types.h>
16 #include <assert.h>
17
18 #include "device.h"
19 #include "pci_dev.h"
20 #include "pci_io.h"
21 #include "cpu.h"
22 #include "vm.h"
23 #include "tcb.h"
24
25 #define DEBUG_JIT_FLUSH 0
26 #define DEBUG_JIT_BUFFER_ADJUST 0
27 #define DEBUG_JIT_PATCH 0
28
29 /* Size of a JIT page */
30 #define TC_JIT_PAGE_SIZE 32768
31
32 /* CPU provisionning */
33 #ifndef __CYGWIN__
34 #define TSG_EXEC_AREA_SINGLE_CPU 64
35 #else
36 #define TSG_EXEC_AREA_SINGLE_CPU 16
37 #endif
38 #define TSG_EXEC_AREA_SHARED 64
39
40 /* Minimal number of exec pages to have to satisfy an allocation request */
41 #define TCB_MIN_EXEC_PAGES (2 * TCB_DESC_MAX_CHUNKS)
42
43 /* Maximum number of translation sharing groups */
44 #define TSG_MAX_GROUPS 128
45
46 /* Hash table to retrieve Translated Code descriptors from their checksums */
47 #define TC_HASH_BITS 16
48 #define TC_HASH_SIZE (1 << TC_HASH_BITS)
49 #define TC_HASH_MASK (TC_HASH_SIZE - 1)
50
51 typedef struct tsg tsg_t;
52 struct tsg {
53 /* Lock to synchronize multiple CPU accesses */
54 pthread_mutex_t lock;
55 pthread_mutexattr_t lock_attr;
56
57 /* Hash table to retrieve Translated Code */
58 cpu_tc_t **tc_hash;
59
60 /* Free list of TC descriptors */
61 cpu_tc_t *tc_free_list;
62
63 /* List of CPUs attached to this group */
64 cpu_gen_t *cpu_list;
65
66 /* Exec page allocator */
67 void *exec_area;
68
69 insn_exec_page_t *exec_page_array;
70 insn_exec_page_t *exec_page_free_list;
71
72 size_t exec_area_alloc_size;
73 u_int exec_page_alloc,exec_page_total;
74 u_int exec_area_full;
75 };
76
77 #define TSG_LOCK(g) pthread_mutex_lock(&(g)->lock)
78 #define TSG_UNLOCK(g) pthread_mutex_unlock(&(g)->lock)
79
80 /* TCB groups */
81 static tsg_t *tsg_array[TSG_MAX_GROUPS];
82
83 /* forward prototype declarations */
84 int tsg_remove_single_desc(cpu_gen_t *cpu);
85 static int tc_free(tsg_t *tsg,cpu_tc_t *tc);
86
87 /* Create a new exec area */
exec_page_create_area(tsg_t * tsg)88 static int exec_page_create_area(tsg_t *tsg)
89 {
90 size_t area_size,page_count;
91 insn_exec_page_t *cp;
92 u_char *cp_addr;
93 int i;
94
95 /* Area already created */
96 if (tsg->exec_area != NULL)
97 return(0);
98
99 /* Allocate an executable area through MMAP */
100 area_size = tsg->exec_area_alloc_size * 1048756;
101 tsg->exec_area = memzone_map_exec_area(area_size);
102
103 if (!tsg->exec_area) {
104 perror("exec_page_create_area: mmap");
105 goto err_mmap;
106 }
107
108 /* Create the page array */
109 page_count = area_size / TC_JIT_PAGE_SIZE;
110 tsg->exec_page_array = calloc(page_count,sizeof(insn_exec_page_t));
111
112 if (!tsg->exec_page_array)
113 goto err_array;
114
115 for(i=0,cp_addr=tsg->exec_area;i<page_count;i++) {
116 cp = &tsg->exec_page_array[i];
117
118 cp->ptr = cp_addr;
119 cp_addr += TC_JIT_PAGE_SIZE;
120
121 tsg->exec_page_total++;
122
123 cp->next = tsg->exec_page_free_list;
124 tsg->exec_page_free_list = cp;
125 }
126
127 return(0);
128
129 err_array:
130 memzone_unmap(tsg->exec_area,area_size);
131 err_mmap:
132 return(-1);
133 }
134
135 /* Allocate an exec page */
exec_page_alloc(cpu_gen_t * cpu)136 static insn_exec_page_t *exec_page_alloc(cpu_gen_t *cpu)
137 {
138 tsg_t *tsg = tsg_array[cpu->tsg];
139 insn_exec_page_t *p;
140 _maybe_used int count;
141
142 TSG_LOCK(tsg);
143
144 //tcb_desc_check_consistency(tcbg);
145
146 /*
147 * If the free list is empty, try to increase exec area capacity, then
148 * flush JIT for the requesting CPU.
149 */
150 if (unlikely(!(p = tsg->exec_page_free_list))) {
151 count = tsg_remove_single_desc(cpu);
152 #if DEBUG_JIT_FLUSH
153 cpu_log(cpu,"JIT","flushed %d TCB\n",count);
154 #endif
155
156 if (unlikely(!(p = tsg->exec_page_free_list)))
157 tsg->exec_area_full = TRUE;
158 }
159
160 /* If the area is full, stop allocating pages and free TCB */
161 if (tsg->exec_area_full) {
162 cpu_jit_tcb_flush_all(cpu);
163
164 /* if we get >= 25% of free pages, we can reallocate */
165 if (tsg->exec_page_total >= (tsg->exec_page_alloc * 4)) {
166 tsg->exec_area_full = FALSE;
167 }
168
169 TSG_UNLOCK(tsg);
170 return NULL;
171 }
172
173 tsg->exec_page_free_list = p->next;
174 tsg->exec_page_alloc++;
175 TSG_UNLOCK(tsg);
176 return p;
177 }
178
179 /*
180 * Free an exec page and returns it to the pool.
181 * Note: the lock is already taken when exec_page_free() is called.
182 */
exec_page_free(tsg_t * tcbg,insn_exec_page_t * p)183 static inline void exec_page_free(tsg_t *tcbg,insn_exec_page_t *p)
184 {
185 if (p != NULL) {
186 p->next = tcbg->exec_page_free_list;
187 tcbg->exec_page_free_list = p;
188 tcbg->exec_page_alloc--;
189 }
190 }
191
192 /* Allocate a free TCB group */
tsg_alloc(void)193 int tsg_alloc(void)
194 {
195 int i;
196
197 for(i=0;i<TSG_MAX_GROUPS;i++)
198 if (tsg_array[i] == NULL)
199 return(i);
200
201 return(-1);
202 }
203
204 /* Create a translation sharing group */
tsg_create(int id,size_t alloc_size)205 int tsg_create(int id,size_t alloc_size)
206 {
207 tsg_t *tsg;
208
209 /* If the group is already initialized, skip it */
210 if (tsg_array[id] != NULL)
211 return(0);
212
213 /* Allocate the holding structure */
214 if (!(tsg = malloc(sizeof(*tsg))))
215 return(-1);
216
217 memset(tsg,0,sizeof(*tsg));
218 tsg->exec_area_full = FALSE;
219 tsg->exec_area_alloc_size = alloc_size;
220
221 /* Create the TC hash table */
222 if (!(tsg->tc_hash = calloc(sizeof(cpu_tc_t *),TC_HASH_SIZE)))
223 goto err_hash;
224
225 /* Create the exec page area */
226 if (exec_page_create_area(tsg) == -1)
227 goto err_area;
228
229 tsg_array[id] = tsg;
230
231 pthread_mutexattr_init(&tsg->lock_attr);
232 pthread_mutexattr_settype(&tsg->lock_attr,PTHREAD_MUTEX_RECURSIVE);
233 pthread_mutex_init(&tsg->lock,&tsg->lock_attr);
234 return(0);
235
236 err_area:
237 free(tsg->tc_hash);
238 err_hash:
239 free(tsg);
240 return(-1);
241 }
242
243 /* Bind a CPU to a TSG - If the group isn't specified, create one */
tsg_bind_cpu(cpu_gen_t * cpu)244 int tsg_bind_cpu(cpu_gen_t *cpu)
245 {
246 tsg_t *tsg;
247 ssize_t alloc_size;
248
249 if (cpu->tsg == -1) {
250 cpu->tsg = tsg_alloc();
251
252 if (cpu->tsg == -1)
253 return(-1);
254
255 alloc_size = TSG_EXEC_AREA_SINGLE_CPU;
256 } else {
257 alloc_size = TSG_EXEC_AREA_SHARED;
258 }
259
260 if (tsg_create(cpu->tsg,alloc_size) == -1)
261 return(-1);
262
263 tsg = tsg_array[cpu->tsg];
264 M_LIST_ADD(cpu,tsg->cpu_list,tsg);
265 return(0);
266 }
267
268 /* Unbind a CPU from a TSG - release all resources used */
tsg_unbind_cpu(cpu_gen_t * cpu)269 int tsg_unbind_cpu(cpu_gen_t *cpu)
270 {
271 tsg_t *tsg = tsg_array[cpu->tsg];
272 cpu_tb_t *tb,*next;
273
274 if (cpu->tsg == -1)
275 return(-1);
276
277 /* Free all descriptors in free list */
278 for(tb=cpu->tb_free_list;tb;tb=next) {
279 next = tb->tb_next;
280 free(tb);
281 }
282
283 /* Free all descriptors currently in use */
284 for(tb=cpu->tb_list;tb;tb=next) {
285 next = tb->tb_next;
286 tb_free(cpu,tb);
287 free(tb);
288 }
289
290 cpu->tb_list = NULL;
291 cpu->tb_free_list = NULL;
292
293 TSG_LOCK(tsg);
294 M_LIST_REMOVE(cpu,tsg);
295 TSG_UNLOCK(tsg);
296 return(0);
297 }
298
299 /* Create a JIT chunk */
tc_alloc_jit_chunk(cpu_gen_t * cpu,cpu_tc_t * tc)300 int tc_alloc_jit_chunk(cpu_gen_t *cpu,cpu_tc_t *tc)
301 {
302 insn_exec_page_t *chunk;
303
304 if (tc->jit_chunk_pos >= TC_MAX_CHUNKS) {
305 cpu_log(cpu,"JIT","TC 0x%8.8llx: too many chunks.\n",tc->vaddr);
306 return(-1);
307 }
308
309 if (!(chunk = exec_page_alloc(cpu)))
310 return(-1);
311
312 tc->jit_chunks[tc->jit_chunk_pos++] = chunk;
313 tc->jit_buffer = chunk;
314 return(0);
315 }
316
317 /* Free JIT chunks allocated for a TC descriptor */
tc_free_jit_chunks(tsg_t * tsg,cpu_tc_t * tc)318 static void tc_free_jit_chunks(tsg_t *tsg,cpu_tc_t *tc)
319 {
320 int i;
321
322 for(i=0;i<tc->jit_chunk_pos;i++) {
323 exec_page_free(tsg,tc->jit_chunks[i]);
324 tc->jit_chunks[i] = NULL;
325 }
326 }
327
328 /* Remove the TC descriptor from the TSG hash table */
tc_remove_from_hash(cpu_tc_t * tc)329 static inline void tc_remove_from_hash(cpu_tc_t *tc)
330 {
331 M_LIST_REMOVE(tc,hash);
332 }
333
334 /*
335 * Add a TC descriptor as local to the specified CPU.
336 * This occurs when the descriptor has just been created and is not shared.
337 * It allows to free pages easily in case of contention.
338 */
tc_add_cpu_local(cpu_gen_t * cpu,cpu_tc_t * tc)339 static inline void tc_add_cpu_local(cpu_gen_t *cpu,cpu_tc_t *tc)
340 {
341 M_LIST_ADD(tc,cpu->tc_local_list,sc);
342 }
343
344 /*
345 * Remove a TC descriptor from a local list of a CPU. It happens when the TC
346 * becomes shared between different virtual CPUs.
347 */
tc_remove_cpu_local(cpu_tc_t * tc)348 static inline void tc_remove_cpu_local(cpu_tc_t *tc)
349 {
350 M_LIST_REMOVE(tc,sc);
351 }
352
353 /* Free a TC descriptor */
tc_free(tsg_t * tsg,cpu_tc_t * tc)354 static int tc_free(tsg_t *tsg,cpu_tc_t *tc)
355 {
356 TSG_LOCK(tsg);
357
358 tc->ref_count--;
359 assert(tc->ref_count >= 0);
360
361 if (tc->ref_count == 0) {
362 tc->flags &= ~TC_FLAG_VALID;
363
364 tc_free_patches(tc);
365
366 tc_remove_from_hash(tc);
367 tc_remove_cpu_local(tc);
368 tc_free_jit_chunks(tsg,tc);
369 free(tc->jit_insn_ptr);
370
371 tc->sc_next = tsg->tc_free_list;
372 tsg->tc_free_list = tc;
373 TSG_UNLOCK(tsg);
374 return(TRUE);
375 }
376
377 /* not yet deleted */
378 TSG_UNLOCK(tsg);
379 return(FALSE);
380 }
381
382 /* Allocate a new TC descriptor */
tc_alloc(cpu_gen_t * cpu,m_uint64_t vaddr,m_uint32_t exec_state)383 cpu_tc_t *tc_alloc(cpu_gen_t *cpu,m_uint64_t vaddr,m_uint32_t exec_state)
384 {
385 tsg_t *tsg = tsg_array[cpu->tsg];
386 cpu_tc_t *tc;
387 size_t len;
388
389 TSG_LOCK(tsg);
390 if (tsg->tc_free_list) {
391 tc = tsg->tc_free_list;
392 tsg->tc_free_list = tc->sc_next;
393 } else {
394 if (!(tc = malloc(sizeof(*tc))))
395 return NULL;
396 }
397 TSG_UNLOCK(tsg);
398
399 memset(tc,0,sizeof(*tc));
400 tc->vaddr = vaddr;
401 tc->exec_state = exec_state;
402 tc->ref_count = 1;
403
404 /*
405 * Allocate the array used to convert target code ptr to native code ptr,
406 * and create the first JIT buffer.
407 */
408 len = VM_PAGE_SIZE / sizeof(m_uint32_t);
409
410 if (!(tc->jit_insn_ptr = calloc(len,sizeof(u_char *))) ||
411 (tc_alloc_jit_chunk(cpu,tc) == -1))
412 {
413 tc_free(tsg,tc);
414 return NULL;
415 }
416
417 tc->jit_ptr = tc->jit_buffer->ptr;
418 return tc;
419 }
420
421 /* Compute a checksum on a page */
tsg_checksum_page(void * page,ssize_t size)422 tsg_checksum_t tsg_checksum_page(void *page,ssize_t size)
423 {
424 tsg_checksum_t cksum = 0;
425 m_uint64_t *ptr = page;
426
427 while(size > 0) {
428 cksum ^= *ptr;
429 ptr++;
430 size -= sizeof(m_uint64_t);
431 }
432 return(cksum);
433 }
434
435 /* Compute a hash on the specified checksum */
tsg_cksum_hash(tsg_checksum_t cksum)436 static inline u_int tsg_cksum_hash(tsg_checksum_t cksum)
437 {
438 tsg_checksum_t tmp;
439
440 tmp = cksum ^ (cksum >> 17) ^ (cksum >> 23);
441 return((u_int)(tmp & TC_HASH_MASK));
442 }
443
444 /* Compare physical pages */
tb_compare_page(cpu_tb_t * tb1,cpu_tb_t * tb2)445 static inline int tb_compare_page(cpu_tb_t *tb1,cpu_tb_t *tb2)
446 {
447 if (tb1->target_code == tb2->target_code)
448 return(0);
449
450 return(memcmp(tb1->target_code,tb2->target_code,VM_PAGE_SIZE));
451 }
452
453 /* Compare 2 TBs */
tb_compare(cpu_tb_t * tb1,cpu_tb_t * tb2)454 static forced_inline int tb_compare(cpu_tb_t *tb1,cpu_tb_t *tb2)
455 {
456 return((tb1->vaddr == tb2->vaddr) &&
457 (tb1->exec_state == tb2->exec_state));
458 }
459
460 /* Try to find a TC descriptor to share generated code */
tc_find_shared(cpu_gen_t * cpu,cpu_tb_t * tb)461 int tc_find_shared(cpu_gen_t *cpu,cpu_tb_t *tb)
462 {
463 tsg_t *tsg = tsg_array[cpu->tsg];
464 cpu_tb_t *p;
465 cpu_tc_t *tc;
466 u_int hash_bucket;
467
468 TSG_LOCK(tsg);
469
470 assert(tb->target_code != NULL);
471
472 hash_bucket = tsg_cksum_hash(tb->checksum);
473 for(tc=tsg->tc_hash[hash_bucket];tc;tc=tc->hash_next)
474 {
475 assert(tc->flags & TC_FLAG_VALID);
476
477 if (tc->checksum == tb->checksum) {
478 for(p=tc->tb_list;p;p=p->tb_dl_next) {
479 //assert(p->flags & TCB_FLAG_VALID);
480
481 if (!(p->flags & TB_FLAG_VALID)) {
482 tb_dump(tb);
483 abort();
484 }
485
486 if (tb_compare(tb,p) && !tb_compare_page(tb,p))
487 {
488 /* matching page, we can share the code */
489 tc->ref_count++;
490 tb->tc = tc;
491 tc_remove_cpu_local(tc);
492 M_LIST_ADD(tb,tc->tb_list,tb_dl);
493 tb_enable(cpu,tb);
494
495 TSG_UNLOCK(tsg);
496 return(TSG_LOOKUP_SHARED);
497 }
498 }
499 }
500 }
501
502 /* A new TCB descriptor must be created */
503 TSG_UNLOCK(tsg);
504 return(TSG_LOOKUP_NEW);
505 }
506
507 /* Register a newly compiled TCB descriptor */
tc_register(cpu_gen_t * cpu,cpu_tb_t * tb,cpu_tc_t * tc)508 void tc_register(cpu_gen_t *cpu,cpu_tb_t *tb,cpu_tc_t *tc)
509 {
510 tsg_t *tsg = tsg_array[cpu->tsg];
511 u_int hash_bucket = tsg_cksum_hash(tb->checksum);
512
513 tb->tc = tc;
514 tc->checksum = tb->checksum;
515
516 TSG_LOCK(tsg);
517 tc_add_cpu_local(cpu,tc);
518 M_LIST_ADD(tb,tc->tb_list,tb_dl);
519 M_LIST_ADD(tc,tsg->tc_hash[hash_bucket],hash);
520 tc->flags |= TC_FLAG_VALID;
521 TSG_UNLOCK(tsg);
522 }
523
524 /* Remove all TC descriptors belonging to a single CPU (ie not shared) */
tsg_remove_single_desc(cpu_gen_t * cpu)525 int tsg_remove_single_desc(cpu_gen_t *cpu)
526 {
527 cpu_tc_t *tc,*next;
528 int count = 0;
529
530 for(tc=cpu->tc_local_list;tc;tc=next) {
531 next = tc->sc_next;
532
533 assert(tc->ref_count == 1);
534 assert(tc->tb_list->tb_dl_next == NULL);
535
536 tb_free(cpu,tc->tb_list);
537 count++;
538 }
539
540 cpu->tc_local_list = NULL;
541 return(count);
542 }
543
544 /* Dump a TCB */
tb_dump(cpu_tb_t * tb)545 void tb_dump(cpu_tb_t *tb)
546 {
547 printf("TB 0x%8.8llx:\n",tb->vaddr);
548 printf(" - flags : 0x%4.4x\n",tb->flags);
549 printf(" - checksum : 0x%16.16llx\n",tb->checksum);
550 printf(" - target_code : %p\n",tb->target_code);
551 printf(" - virt_hash : 0x%8.8x\n",tb->virt_hash);
552 printf(" - phys_hash : 0x%8.8x\n",tb->phys_hash);
553 printf(" - phys_page : 0x%8.8x\n",tb->phys_page);
554 printf(" - tc : %p\n",tb->tc);
555 printf(" - tb_LIST : (%p,%p)\n",tb->tb_pprev,tb->tb_next);
556 printf(" - tcb_dl_LIST : (%p,%p)\n",tb->tb_dl_pprev,tb->tb_dl_next);
557 printf(" - phys_LIST : (%p,%p)\n",tb->phys_pprev,tb->phys_next);
558 }
559
560 /* Dump a TCB descriptor */
tc_dump(cpu_tc_t * tc)561 void tc_dump(cpu_tc_t *tc)
562 {
563 printf("TC 0x%8.8llx:\n",tc->vaddr);
564 printf(" - flags : 0x%4.4x\n",tc->flags);
565 printf(" - checksum : 0x%8.8llx\n",tc->checksum);
566 printf(" - ref_count : %u\n",tc->ref_count);
567 printf(" - tb_list : %p\n",tc->tb_list);
568 printf(" - hash_LIST : (%p,%p)\n",tc->hash_pprev,tc->hash_next);
569 printf(" - sc_LIST : (%p,%p)\n",tc->sc_pprev,tc->sc_next);
570 }
571
572 /* Consistency check */
tc_check_consistency(cpu_gen_t * cpu)573 int tc_check_consistency(cpu_gen_t *cpu)
574 {
575 tsg_t *tsg = tsg_array[cpu->tsg];
576 cpu_tb_t *tb;
577 cpu_tc_t *tc;
578 int i,err=0;
579
580 TSG_LOCK(tsg);
581
582 for(i=0;i<TC_HASH_SIZE;i++) {
583 for(tc=tsg->tc_hash[i];tc;tc=tc->hash_next) {
584 if (!(tc->flags & TC_FLAG_VALID)) {
585 cpu_log(cpu,"JIT",
586 "consistency error: TC 0x%8.8llx (flags=0x%x)\n",
587 tc->vaddr,tc->flags);
588 tc_dump(tc);
589 err++;
590 }
591
592 for(tb=tc->tb_list;tb;tb=tb->tb_dl_next) {
593 if (!(tb->flags & TB_FLAG_VALID)) {
594 cpu_log(cpu,"JIT",
595 "consistency error: TB 0x%8.8llx (flags=0x%x)\n",
596 tb->vaddr,tb->flags);
597 err++;
598
599 tb_dump(tb);
600 }
601 }
602 }
603 }
604
605 TSG_UNLOCK(tsg);
606
607 if (err > 0) {
608 printf("TSG %d: internal consistency error (%d pb detected)\n",
609 cpu->tsg,err);
610 }
611
612 return(err);
613 }
614
615
616 /* Statistics: compute number of shared pages in a translation group */
tsg_get_stats(tsg_t * tsg,struct tsg_stats * s)617 static int tsg_get_stats(tsg_t *tsg,struct tsg_stats *s)
618 {
619 cpu_tc_t *tc;
620 int i;
621
622 s->shared_tc = s->total_tc = 0;
623 s->shared_pages = 0;
624
625 if (!tsg)
626 return(-1);
627
628 for(i=0;i<TC_HASH_SIZE;i++) {
629 for(tc=tsg->tc_hash[i];tc;tc=tc->hash_next) {
630 if (tc->ref_count > 1) {
631 s->shared_pages += tc->jit_chunk_pos;
632 s->shared_tc++;
633 }
634
635 s->total_tc++;
636 }
637 }
638
639 return(0);
640 }
641
642 /* Show statistics about all translation groups */
tsg_show_stats(void)643 void tsg_show_stats(void)
644 {
645 struct tsg_stats s;
646 int i;
647
648 printf("\nTSG statistics:\n\n");
649
650 printf(" ID Shared TC Total TC Alloc.Pages Shared Pages Total Pages\n");
651
652 for(i=0;i<TSG_MAX_GROUPS;i++) {
653 if (!tsg_get_stats(tsg_array[i],&s)) {
654 printf(" %3d %8u %8u %8u %8u %8u\n",
655 i,s.shared_tc,s.total_tc,
656 tsg_array[i]->exec_page_alloc,
657 s.shared_pages,
658 tsg_array[i]->exec_page_total);
659 }
660 }
661
662 printf("\n");
663 }
664
665 /* Adjust the JIT buffer if its size is not sufficient */
tc_adjust_jit_buffer(cpu_gen_t * cpu,cpu_tc_t * tc,void (* set_jump)(u_char ** insn,u_char * dst))666 int tc_adjust_jit_buffer(cpu_gen_t *cpu,cpu_tc_t *tc,
667 void (*set_jump)(u_char **insn,u_char *dst))
668 {
669 assert((tc->jit_ptr - tc->jit_buffer->ptr) < TC_JIT_PAGE_SIZE);
670
671 if ((tc->jit_ptr - tc->jit_buffer->ptr) <= (TC_JIT_PAGE_SIZE - 512))
672 return(0);
673
674 #if DEBUG_JIT_BUFFER_ADJUST
675 cpu_log(cpu,"JIT",
676 "TC 0x%8.8llx: adjusting JIT buffer (cur=%p,start=%p,delta=%u)\n",
677 tc->vaddr,tc->jit_ptr,tc->jit_buffer->ptr,
678 TC_JIT_PAGE_SIZE - (tc->jit_ptr-tc->jit_buffer->ptr));
679 #endif
680
681 /*
682 * If we cannot allocate a new chunk, free the complete descriptor and
683 * return an error so that the caller uses non-JIT mode for this TCB.
684 */
685 if (tc_alloc_jit_chunk(cpu,tc) == -1) {
686 tc_free(tsg_array[cpu->tsg],tc);
687 return(-1);
688 }
689
690 /* jump to the new exec page (link) */
691 set_jump(&tc->jit_ptr,tc->jit_buffer->ptr);
692 tc->jit_ptr = tc->jit_buffer->ptr;
693 return(0);
694 }
695
696 /* Record a patch to apply in a compiled block */
tc_record_patch(cpu_gen_t * cpu,cpu_tc_t * tc,u_char * jit_ptr,m_uint64_t vaddr)697 struct insn_patch *tc_record_patch(cpu_gen_t *cpu,cpu_tc_t *tc,
698 u_char *jit_ptr,m_uint64_t vaddr)
699 {
700 struct insn_patch_table *ipt = tc->patch_table;
701 struct insn_patch *patch;
702
703 /* vaddr must be 32-bit aligned */
704 if (vaddr & 0x03) {
705 cpu_log(cpu,"JIT",
706 "TC 0x%8.8llx: trying to record an invalid vaddr (0x%8.8llx)\n",
707 tc->vaddr,vaddr);
708 return NULL;
709 }
710
711 if (!ipt || (ipt->cur_patch >= INSN_PATCH_TABLE_SIZE))
712 {
713 /* full table or no table, create a new one */
714 ipt = malloc(sizeof(*ipt));
715 if (!ipt) {
716 cpu_log(cpu,"JIT","TC 0x%8.8llx: unable to create patch table.\n",
717 tc->vaddr);
718 return NULL;
719 }
720
721 memset(ipt,0,sizeof(*ipt));
722 ipt->next = tc->patch_table;
723 tc->patch_table = ipt;
724 }
725
726 #if DEBUG_JIT_PATCH
727 printf("TC 0x%8.8llx: recording patch [host %p -> target:0x%8.8llx], "
728 "TP=%d\n",tc->vaddr,jit_ptr,vaddr,tc->trans_pos);
729 #endif
730
731 patch = &ipt->patches[ipt->cur_patch];
732 patch->jit_insn = jit_ptr;
733 patch->vaddr = vaddr;
734 ipt->cur_patch++;
735
736 return patch;
737 }
738
739 /* Apply all patches */
tc_apply_patches(cpu_tc_t * tc,void (* set_patch)(u_char * insn,u_char * dst))740 int tc_apply_patches(cpu_tc_t *tc,void (*set_patch)(u_char *insn,u_char *dst))
741 {
742 struct insn_patch_table *ipt;
743 struct insn_patch *patch;
744 u_char *jit_dst;
745 int i;
746
747 for(ipt=tc->patch_table;ipt;ipt=ipt->next)
748 for(i=0;i<ipt->cur_patch;i++)
749 {
750 patch = &ipt->patches[i];
751 jit_dst = tc_get_host_ptr(tc,patch->vaddr);
752
753 if (jit_dst) {
754 #if DEBUG_JIT_PATCH
755 printf("TC 0x%8.8llx: applying patch "
756 "[host %p -> target 0x%8.8llx=JIT:%p]\n",
757 tc->vaddr,patch->jit_insn,patch->vaddr,jit_dst);
758 #endif
759 set_patch(patch->jit_insn,jit_dst);
760 }
761 }
762
763 return(0);
764 }
765
766 /* Free the patch table */
tc_free_patches(cpu_tc_t * tc)767 void tc_free_patches(cpu_tc_t *tc)
768 {
769 struct insn_patch_table *p,*next;
770
771 for(p=tc->patch_table;p;p=next) {
772 next = p->next;
773 free(p);
774 }
775
776 tc->patch_table = NULL;
777 }
778
779 /* Initialize the JIT structures of a CPU */
cpu_jit_init(cpu_gen_t * cpu,size_t virt_hash_size,size_t phys_hash_size)780 int cpu_jit_init(cpu_gen_t *cpu,size_t virt_hash_size,size_t phys_hash_size)
781 {
782 size_t len;
783
784 /* Virtual address mapping for TCB */
785 len = virt_hash_size * sizeof(void *);
786 cpu->tb_virt_hash = m_memalign(4096,len);
787 memset(cpu->tb_virt_hash,0,len);
788
789 /* Physical address mapping for TCB */
790 len = phys_hash_size * sizeof(void *);
791 cpu->tb_phys_hash = m_memalign(4096,len);
792 memset(cpu->tb_phys_hash,0,len);
793
794 return(0);
795 }
796
797 /* Shutdown the JIT structures of a CPU */
cpu_jit_shutdown(cpu_gen_t * cpu)798 void cpu_jit_shutdown(cpu_gen_t *cpu)
799 {
800 tsg_unbind_cpu(cpu);
801
802 /* Free virtual and physical hash tables */
803 free(cpu->tb_virt_hash);
804 free(cpu->tb_phys_hash);
805
806 cpu->tb_virt_hash = NULL;
807 cpu->tb_phys_hash = NULL;
808 }
809
810 /* Allocate a new TB */
tb_alloc(cpu_gen_t * cpu,m_uint64_t vaddr,u_int exec_state)811 cpu_tb_t *tb_alloc(cpu_gen_t *cpu,m_uint64_t vaddr,u_int exec_state)
812 {
813 cpu_tb_t *tb;
814
815 if (cpu->tb_free_list) {
816 tb = cpu->tb_free_list;
817 cpu->tb_free_list = tb->tb_next;
818 } else {
819 if (!(tb = malloc(sizeof(*tb))))
820 return NULL;
821 }
822
823 memset(tb,0,sizeof(*tb));
824 tb->vaddr = vaddr;
825 tb->exec_state = exec_state;
826 return tb;
827 }
828
829 /* Free a Translation Block */
tb_free(cpu_gen_t * cpu,cpu_tb_t * tb)830 void tb_free(cpu_gen_t *cpu,cpu_tb_t *tb)
831 {
832 tsg_t *tsg = tsg_array[cpu->tsg];
833
834 /* Remove this TB from the TB list bound to a TC descriptor */
835 TSG_LOCK(tsg);
836 M_LIST_REMOVE(tb,tb_dl);
837 TSG_UNLOCK(tsg);
838
839 /* Release the TC descriptor first */
840 if (tb->tc != NULL)
841 tc_free(tsg,tb->tc);
842
843 /* Remove the block from the CPU TCB list */
844 M_LIST_REMOVE(tb,tb);
845
846 /* Remove the block from the CPU physical mapping hash table */
847 M_LIST_REMOVE(tb,phys);
848
849 /* Invalidate the entry in hash table for virtual addresses */
850 if (cpu->tb_virt_hash[tb->virt_hash] == tb)
851 cpu->tb_virt_hash[tb->virt_hash] = NULL;
852
853 /* Make the block return to the free list */
854 memset(tb,0,sizeof(*tb));
855 tb->tb_next = cpu->tb_free_list;
856 cpu->tb_free_list = tb;
857 }
858
859 /* Enable a Tranlsation Block */
tb_enable(cpu_gen_t * cpu,cpu_tb_t * tb)860 void tb_enable(cpu_gen_t *cpu,cpu_tb_t *tb)
861 {
862 M_LIST_ADD(tb,cpu->tb_list,tb);
863 M_LIST_ADD(tb,cpu->tb_phys_hash[tb->phys_hash],phys);
864 tb->flags |= TB_FLAG_VALID;
865 }
866
867 /* Flush all TCB of a virtual CPU */
cpu_jit_tcb_flush_all(cpu_gen_t * cpu)868 void cpu_jit_tcb_flush_all(cpu_gen_t *cpu)
869 {
870 cpu_tb_t *tb,*next;
871
872 for(tb=cpu->tb_list;tb;tb=next) {
873 next = tb->tb_next;
874 tb_free(cpu,tb);
875 }
876
877 assert(cpu->tb_list == NULL);
878 }
879
880 /* Mark a TB as containing self-modifying code */
tb_mark_smc(cpu_gen_t * cpu,cpu_tb_t * tb)881 void tb_mark_smc(cpu_gen_t *cpu,cpu_tb_t *tb)
882 {
883 if (tb->flags & TB_FLAG_SMC)
884 return; /* already done */
885
886 tb->flags |= TB_FLAG_SMC;
887
888 if (tb->tc != NULL) {
889 tc_free(tsg_array[cpu->tsg],tb->tc);
890 tb->tc = NULL;
891 }
892 }
893
894 /* Handle write access on an executable page */
cpu_jit_write_on_exec_page(cpu_gen_t * cpu,m_uint32_t wr_phys_page,m_uint32_t wr_hp,m_uint32_t ip_phys_page)895 void cpu_jit_write_on_exec_page(cpu_gen_t *cpu,
896 m_uint32_t wr_phys_page,
897 m_uint32_t wr_hp,
898 m_uint32_t ip_phys_page)
899 {
900 cpu_tb_t *tb,**tbp,*tb_next;
901
902 if (wr_phys_page != ip_phys_page) {
903 /* Clear all TCB matching the physical page being modified */
904 for(tbp=&cpu->tb_phys_hash[wr_hp];*tbp;)
905 if ((*tbp)->phys_page == wr_phys_page) {
906 tb_next = (*tbp)->phys_next;
907 tb_free(cpu,(*tbp));
908 *tbp = tb_next;
909 } else {
910 tbp = &(*tbp)->phys_next;
911 }
912 } else {
913 /* Self-modifying page */
914 for(tb=cpu->tb_phys_hash[wr_hp];tb;tb=tb->phys_next)
915 if (tb->phys_page == wr_phys_page)
916 tb_mark_smc(cpu,tb);
917
918 cpu_exec_loop_enter(cpu);
919 }
920 }
921