VirtualBox

root/trunk/src/recompiler/exec.c

Revision 13185, 79.3 kB (checked in by vboxsync, 3 months ago)

VBoxREM: export the tb statistics.

  • Property svn:eol-style set to native
Line 
1 /*
2  *  virtual page mapping and translated block handling
3  *
4  *  Copyright (c) 2003 Fabrice Bellard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 /*
22  * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
23  * other than GPL or LGPL is available it will apply instead, Sun elects to use only
24  * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
25  * a choice of LGPL license versions is made available with the language indicating
26  * that LGPLv2 or any later version may be used, or where a choice of which version
27  * of the LGPL is applied is otherwise unspecified.
28  */
29 #include "config.h"
30 #ifndef VBOX
31 #ifdef _WIN32
32 #include <windows.h>
33 #else
34 #include <sys/types.h>
35 #include <sys/mman.h>
36 #endif
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include <inttypes.h>
44 #else /* VBOX */
45 # include <stdlib.h>
46 # include <stdio.h>
47 # include <inttypes.h>
48 # include <iprt/alloc.h>
49 # include <iprt/string.h>
50 # include <iprt/param.h>
51 # include <VBox/pgm.h> /* PGM_DYNAMIC_RAM_ALLOC */
52 #endif /* VBOX */
53
54 #include "cpu.h"
55 #include "exec-all.h"
56 #if defined(CONFIG_USER_ONLY)
57 #include <qemu.h>
58 #endif
59
60 //#define DEBUG_TB_INVALIDATE
61 //#define DEBUG_FLUSH
62 //#define DEBUG_TLB
63 //#define DEBUG_UNASSIGNED
64
65 /* make various TB consistency checks */
66 //#define DEBUG_TB_CHECK
67 //#define DEBUG_TLB_CHECK
68
69 #if !defined(CONFIG_USER_ONLY)
70 /* TB consistency checks only implemented for usermode emulation.  */
71 #undef DEBUG_TB_CHECK
72 #endif
73
74 /* threshold to flush the translated code buffer */
75 #define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
76
77 #define SMC_BITMAP_USE_THRESHOLD 10
78
79 #define MMAP_AREA_START        0x00000000
80 #define MMAP_AREA_END          0xa8000000
81
82 #if defined(TARGET_SPARC64)
83 #define TARGET_PHYS_ADDR_SPACE_BITS 41
84 #elif defined(TARGET_PPC64)
85 #define TARGET_PHYS_ADDR_SPACE_BITS 42
86 #else
87 /* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
88 #define TARGET_PHYS_ADDR_SPACE_BITS 32
89 #endif
90
91 TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
92 TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
93 int nb_tbs;
94 /* any access to the tbs or the page table must use this lock */
95 spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
96
97 uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]
98 #if defined(__MINGW32__)
99     __attribute__((aligned (16)));
100 #else
101     __attribute__((aligned (32)));
102 #endif
103 uint8_t *code_gen_ptr;
104
105 #ifndef VBOX
106 int phys_ram_size;
107 int phys_ram_fd;
108 int phys_ram_size;
109 #else /* VBOX */
110 RTGCPHYS phys_ram_size;
111 /* we have memory ranges (the high PC-BIOS mapping) which
112    causes some pages to fall outside the dirty map here. */
113 uint32_t phys_ram_dirty_size;
114 #endif /* VBOX */
115 #if !defined(VBOX)
116 uint8_t *phys_ram_base;
117 #endif
118 uint8_t *phys_ram_dirty;
119
120 CPUState *first_cpu;
121 /* current CPU in the current thread. It is only valid inside
122    cpu_exec() */
123 CPUState *cpu_single_env;
124
125 typedef struct PageDesc {
126     /* list of TBs intersecting this ram page */
127     TranslationBlock *first_tb;
128     /* in order to optimize self modifying code, we count the number
129        of lookups we do to a given page to use a bitmap */
130     unsigned int code_write_count;
131     uint8_t *code_bitmap;
132 #if defined(CONFIG_USER_ONLY)
133     unsigned long flags;
134 #endif
135 } PageDesc;
136
137 typedef struct PhysPageDesc {
138     /* offset in host memory of the page + io_index in the low 12 bits */
139     uint32_t phys_offset;
140 } PhysPageDesc;
141
142 #define L2_BITS 10
143 #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
144
145 #define L1_SIZE (1 << L1_BITS)
146 #define L2_SIZE (1 << L2_BITS)
147
148 static void io_mem_init(void);
149
150 unsigned long qemu_real_host_page_size;
151 unsigned long qemu_host_page_bits;
152 unsigned long qemu_host_page_size;
153 unsigned long qemu_host_page_mask;
154
155 /* XXX: for system emulation, it could just be an array */
156 static PageDesc *l1_map[L1_SIZE];
157 PhysPageDesc **l1_phys_map;
158
159 /* io memory support */
160 CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
161 CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
162 void *io_mem_opaque[IO_MEM_NB_ENTRIES];
163 static int io_mem_nb;
164
165 #ifndef VBOX
166 /* log support */
167 char *logfilename = "/tmp/qemu.log";
168 #endif /* !VBOX */
169 FILE *logfile;
170 int loglevel;
171
172 /* statistics */
173 #ifndef VBOX
174 static int tlb_flush_count;
175 static int tb_flush_count;
176 static int tb_phys_invalidate_count;
177 #else  /* VBOX */
178 # ifdef VBOX_WITH_STATISTICS
179 uint32_t tlb_flush_count;
180 uint32_t tb_flush_count;
181 uint32_t tb_phys_invalidate_count;
182 # endif
183 #endif /* VBOX */
184
185 static void page_init(void)
186 {
187     /* NOTE: we can always suppose that qemu_host_page_size >=
188        TARGET_PAGE_SIZE */
189 #ifdef VBOX
190     RTMemProtect(code_gen_buffer, sizeof(code_gen_buffer),
191                  RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
192     qemu_real_host_page_size = PAGE_SIZE;
193 #else /* !VBOX */
194 #ifdef _WIN32
195     {
196         SYSTEM_INFO system_info;
197         DWORD old_protect;
198
199         GetSystemInfo(&system_info);
200         qemu_real_host_page_size = system_info.dwPageSize;
201
202         VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
203                        PAGE_EXECUTE_READWRITE, &old_protect);
204     }
205 #else
206     qemu_real_host_page_size = getpagesize();
207     {
208         unsigned long start, end;
209
210         start = (unsigned long)code_gen_buffer;
211         start &= ~(qemu_real_host_page_size - 1);
212
213         end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
214         end += qemu_real_host_page_size - 1;
215         end &= ~(qemu_real_host_page_size - 1);
216
217         mprotect((void *)start, end - start,
218                  PROT_READ | PROT_WRITE | PROT_EXEC);
219     }
220 #endif
221 #endif /* !VBOX */
222
223     if (qemu_host_page_size == 0)
224         qemu_host_page_size = qemu_real_host_page_size;
225     if (qemu_host_page_size < TARGET_PAGE_SIZE)
226         qemu_host_page_size = TARGET_PAGE_SIZE;
227     qemu_host_page_bits = 0;
228     while ((1 << qemu_host_page_bits) < qemu_host_page_size)
229         qemu_host_page_bits++;
230     qemu_host_page_mask = ~(qemu_host_page_size - 1);
231     l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
232     memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
233 }
234
235 static inline PageDesc *page_find_alloc(unsigned int index)
236 {
237     PageDesc **lp, *p;
238
239     lp = &l1_map[index >> L2_BITS];
240     p = *lp;
241     if (!p) {
242         /* allocate if not found */
243         p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
244         memset(p, 0, sizeof(PageDesc) * L2_SIZE);
245         *lp = p;
246     }
247     return p + (index & (L2_SIZE - 1));
248 }
249
250 static inline PageDesc *page_find(unsigned int index)
251 {
252     PageDesc *p;
253
254     p = l1_map[index >> L2_BITS];
255     if (!p)
256         return 0;
257     return p + (index & (L2_SIZE - 1));
258 }
259
260 static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
261 {
262     void **lp, **p;
263     PhysPageDesc *pd;
264
265     p = (void **)l1_phys_map;
266 #if TARGET_PHYS_ADDR_SPACE_BITS > 32
267
268 #if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
269 #error unsupported TARGET_PHYS_ADDR_SPACE_BITS
270 #endif
271     lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
272     p = *lp;
273     if (!p) {
274         /* allocate if not found */
275         if (!alloc)
276             return NULL;
277         p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
278         memset(p, 0, sizeof(void *) * L1_SIZE);
279         *lp = p;
280     }
281 #endif
282     lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
283     pd = *lp;
284     if (!pd) {
285         int i;
286         /* allocate if not found */
287         if (!alloc)
288             return NULL;
289         pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
290         *lp = pd;
291         for (i = 0; i < L2_SIZE; i++)
292           pd[i].phys_offset = IO_MEM_UNASSIGNED;
293     }
294 #if defined(VBOX) && !defined(VBOX_WITH_NEW_PHYS_CODE)
295     pd = ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
296     if (RT_UNLIKELY((pd->phys_offset & ~TARGET_PAGE_MASK) == IO_MEM_RAM_MISSING))
297         remR3GrowDynRange(pd->phys_offset & TARGET_PAGE_MASK);
298     return pd;
299 #else
300     return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
301 #endif
302 }
303
304 static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
305 {
306     return phys_page_find_alloc(index, 0);
307 }
308
309 #if !defined(CONFIG_USER_ONLY)
310 static void tlb_protect_code(ram_addr_t ram_addr);
311 static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
312                                     target_ulong vaddr);
313 #endif
314
315 void cpu_exec_init(CPUState *env)
316 {
317     CPUState **penv;
318     int cpu_index;
319
320     if (!code_gen_ptr) {
321         code_gen_ptr = code_gen_buffer;
322         page_init();
323         io_mem_init();
324     }
325     env->next_cpu = NULL;
326     penv = &first_cpu;
327     cpu_index = 0;
328     while (*penv != NULL) {
329         penv = (CPUState **)&(*penv)->next_cpu;
330         cpu_index++;
331     }
332     env->cpu_index = cpu_index;
333     *penv = env;
334 }
335
336 static inline void invalidate_page_bitmap(PageDesc *p)
337 {
338     if (p->code_bitmap) {
339         qemu_free(p->code_bitmap);
340         p->code_bitmap = NULL;
341     }
342     p->code_write_count = 0;
343 }
344
345 /* set to NULL all the 'first_tb' fields in all PageDescs */
346 static void page_flush_tb(void)
347 {
348     int i, j;
349     PageDesc *p;
350
351     for(i = 0; i < L1_SIZE; i++) {
352         p = l1_map[i];
353         if (p) {
354             for(j = 0; j < L2_SIZE; j++) {
355                 p->first_tb = NULL;
356                 invalidate_page_bitmap(p);
357                 p++;
358             }
359         }
360     }
361 }
362
363 /* flush all the translation blocks */
364 /* XXX: tb_flush is currently not thread safe */
365 void tb_flush(CPUState *env1)
366 {
367     CPUState *env;
368 #if defined(DEBUG_FLUSH)
369     printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
370            code_gen_ptr - code_gen_buffer,
371            nb_tbs,
372            nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
373 #endif
374     nb_tbs = 0;
375
376     for(env = first_cpu; env != NULL; env = env->next_cpu) {
377         memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
378     }
379
380     memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
381     page_flush_tb();
382
383     code_gen_ptr = code_gen_buffer;
384     /* XXX: flush processor icache at this point if cache flush is
385        expensive */
386 #if !defined(VBOX) || defined(VBOX_WITH_STATISTICS)
387     tb_flush_count++;
388 #endif
389 }
390
391 #ifdef DEBUG_TB_CHECK
392
393 static void tb_invalidate_check(unsigned long address)
394 {
395     TranslationBlock *tb;
396     int i;
397     address &= TARGET_PAGE_MASK;
398     for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
399         for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
400             if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
401                   address >= tb->pc + tb->size)) {
402                 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
403                        address, (long)tb->pc, tb->size);
404             }
405         }
406     }
407 }
408
409 /* verify that all the pages have correct rights for code */
410 static void tb_page_check(void)
411 {
412     TranslationBlock *tb;
413     int i, flags1, flags2;
414
415     for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
416         for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
417             flags1 = page_get_flags(tb->pc);
418             flags2 = page_get_flags(tb->pc + tb->size - 1);
419             if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
420                 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
421                        (long)tb->pc, tb->size, flags1, flags2);
422             }
423         }
424     }
425 }
426
427 void tb_jmp_check(TranslationBlock *tb)
428 {
429     TranslationBlock *tb1;
430     unsigned int n1;
431
432     /* suppress any remaining jumps to this TB */
433     tb1 = tb->jmp_first;
434     for(;;) {
435         n1 = (long)tb1 & 3;
436         tb1 = (TranslationBlock *)((long)tb1 & ~3);
437         if (n1 == 2)
438             break;
439         tb1 = tb1->jmp_next[n1];
440     }
441     /* check end of list */
442     if (tb1 != tb) {
443         printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
444     }
445 }
446
447 #endif
448
449 /* invalidate one TB */
450 static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
451                              int next_offset)
452 {
453     TranslationBlock *tb1;
454     for(;;) {
455         tb1 = *ptb;
456         if (tb1 == tb) {
457             *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
458             break;
459         }
460         ptb = (TranslationBlock **)((char *)tb1 + next_offset);
461     }
462 }
463
464 static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
465 {
466     TranslationBlock *tb1;
467     unsigned int n1;
468
469     for(;;) {
470         tb1 = *ptb;
471         n1 = (long)tb1 & 3;
472         tb1 = (TranslationBlock *)((long)tb1 & ~3);
473         if (tb1 == tb) {
474             *ptb = tb1->page_next[n1];
475             break;
476         }
477         ptb = &tb1->page_next[n1];
478     }
479 }
480
481 static inline void tb_jmp_remove(TranslationBlock *tb, int n)
482 {
483     TranslationBlock *tb1, **ptb;
484     unsigned int n1;
485
486     ptb = &tb->jmp_next[n];
487     tb1 = *ptb;
488     if (tb1) {
489         /* find tb(n) in circular list */
490         for(;;) {
491             tb1 = *ptb;
492             n1 = (long)tb1 & 3;
493             tb1 = (TranslationBlock *)((long)tb1 & ~3);
494             if (n1 == n && tb1 == tb)
495                 break;
496             if (n1 == 2) {
497                 ptb = &tb1->jmp_first;
498             } else {
499                 ptb = &tb1->jmp_next[n1];
500             }
501         }
502         /* now we can suppress tb(n) from the list */
503         *ptb = tb->jmp_next[n];
504
505         tb->jmp_next[n] = NULL;
506     }
507 }
508
509 /* reset the jump entry 'n' of a TB so that it is not chained to
510    another TB */
511 static inline void tb_reset_jump(TranslationBlock *tb, int n)
512 {
513     tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
514 }
515
516 static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
517 {
518     CPUState *env;
519     PageDesc *p;
520     unsigned int h, n1;
521     target_ulong phys_pc;
522     TranslationBlock *tb1, *tb2;
523
524     /* remove the TB from the hash list */
525     phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
526     h = tb_phys_hash_func(phys_pc);
527     tb_remove(&tb_phys_hash[h], tb,
528               offsetof(TranslationBlock, phys_hash_next));
529
530     /* remove the TB from the page list */
531     if (tb->page_addr[0] != page_addr) {
532         p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
533         tb_page_remove(&p->first_tb, tb);
534         invalidate_page_bitmap(p);
535     }
536     if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
537         p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
538         tb_page_remove(&p->first_tb, tb);
539         invalidate_page_bitmap(p);
540     }
541
542     tb_invalidated_flag = 1;
543
544     /* remove the TB from the hash list */
545     h = tb_jmp_cache_hash_func(tb->pc);
546     for(env = first_cpu; env != NULL; env = env->next_cpu) {
547         if (env->tb_jmp_cache[h] == tb)
548             env->tb_jmp_cache[h] = NULL;
549     }
550
551     /* suppress this TB from the two jump lists */
552     tb_jmp_remove(tb, 0);
553     tb_jmp_remove(tb, 1);
554
555     /* suppress any remaining jumps to this TB */
556     tb1 = tb->jmp_first;
557     for(;;) {
558         n1 = (long)tb1 & 3;
559         if (n1 == 2)
560             break;
561         tb1 = (TranslationBlock *)((long)tb1 & ~3);
562         tb2 = tb1->jmp_next[n1];
563         tb_reset_jump(tb1, n1);
564         tb1->jmp_next[n1] = NULL;
565         tb1 = tb2;
566     }
567     tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
568
569 #if !defined(VBOX) || defined(VBOX_WITH_STATISTICS)
570     tb_phys_invalidate_count++;
571 #endif
572 }
573
574 #ifdef VBOX
575 void tb_invalidate_virt(CPUState *env, uint32_t eip)
576 {
577 # if 1
578     tb_flush(env);
579 # else
580     uint8_t *cs_base, *pc;
581     unsigned int flags, h, phys_pc;
582     TranslationBlock *tb, **ptb;
583
584     flags = env->hflags;
585     flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
586     cs_base = env->segs[R_CS].base;
587     pc = cs_base + eip;
588
589     tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
590                  flags);
591
592     if(tb)
593     {
594 ifdef DEBUG
595         printf("invalidating TB (%08X) at %08X\n", tb, eip);
596 endif
597         tb_invalidate(tb);
598         //Note: this will leak TBs, but the whole cache will be flushed
599         //      when it happens too often
600         tb->pc = 0;
601         tb->cs_base = 0;
602         tb->flags = 0;
603     }
604 # endif
605 }
606
607 # ifdef VBOX_STRICT
608 /**
609  * Gets the page offset.
610  */
611 unsigned long get_phys_page_offset(target_ulong addr)
612 {
613     PhysPageDesc *p = phys_page_find(addr >> TARGET_PAGE_BITS);
614     return p ? p->phys_offset : 0;
615 }
616 # endif /* VBOX_STRICT */
617 #endif /* VBOX */
618
619 static inline void set_bits(uint8_t *tab, int start, int len)
620 {
621     int end, mask, end1;
622
623     end = start + len;
624     tab += start >> 3;
625     mask = 0xff << (start & 7);
626     if ((start & ~7) == (end & ~7)) {
627         if (start < end) {
628             mask &= ~(0xff << (end & 7));
629             *tab |= mask;
630         }
631     } else {
632         *tab++ |= mask;
633         start = (start + 8) & ~7;
634         end1 = end & ~7;
635         while (start < end1) {
636             *tab++ = 0xff;
637             start += 8;
638         }
639         if (start < end) {
640             mask = ~(0xff << (end & 7));
641             *tab |= mask;
642         }
643     }
644 }
645
646 static void build_page_bitmap(PageDesc *p)
647 {
648     int n, tb_start, tb_end;
649     TranslationBlock *tb;
650
651     p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
652     if (!p->code_bitmap)
653         return;
654     memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
655
656     tb = p->first_tb;
657     while (tb != NULL) {
658         n = (long)tb & 3;
659         tb = (TranslationBlock *)((long)tb & ~3);
660         /* NOTE: this is subtle as a TB may span two physical pages */
661         if (n == 0) {
662             /* NOTE: tb_end may be after the end of the page, but
663                it is not a problem */
664             tb_start = tb->pc & ~TARGET_PAGE_MASK;
665             tb_end = tb_start + tb->size;
666             if (tb_end > TARGET_PAGE_SIZE)
667                 tb_end = TARGET_PAGE_SIZE;
668         } else {
669             tb_start = 0;
670             tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
671         }
672         set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
673         tb = tb->page_next[n];
674     }
675 }
676
677 #ifdef TARGET_HAS_PRECISE_SMC
678
679 static void tb_gen_code(CPUState *env,
680                         target_ulong pc, target_ulong cs_base, int flags,
681                         int cflags)
682 {
683     TranslationBlock *tb;
684     uint8_t *tc_ptr;
685     target_ulong phys_pc, phys_page2, virt_page2;
686     int code_gen_size;
687
688     phys_pc = get_phys_addr_code(env, pc);
689     tb = tb_alloc(pc);
690     if (!tb) {
691         /* flush must be done */
692         tb_flush(env);
693         /* cannot fail at this point */
694         tb = tb_alloc(pc);
695     }
696     tc_ptr = code_gen_ptr;
697     tb->tc_ptr = tc_ptr;
698     tb->cs_base = cs_base;
699     tb->flags = flags;
700     tb->cflags = cflags;
701     cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
702     code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
703
704     /* check next page if needed */
705     virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
706     phys_page2 = -1;
707     if ((pc & TARGET_PAGE_MASK) != virt_page2) {
708         phys_page2 = get_phys_addr_code(env, virt_page2);
709     }
710     tb_link_phys(tb, phys_pc, phys_page2);
711 }
712 #endif
713
714 /* invalidate all TBs which intersect with the target physical page
715    starting in range [start;end[. NOTE: start and end must refer to
716    the same physical page. 'is_cpu_write_access' should be true if called
717    from a real cpu write access: the virtual CPU will exit the current
718    TB if code is modified inside this TB. */
719 void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
720                                    int is_cpu_write_access)
721 {
722     int n, current_tb_modified, current_tb_not_found, current_flags;
723     CPUState *env = cpu_single_env;
724     PageDesc *p;
725     TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
726     target_ulong tb_start, tb_end;
727     target_ulong current_pc, current_cs_base;
728
729     p = page_find(start >> TARGET_PAGE_BITS);
730     if (!p)
731         return;
732     if (!p->code_bitmap &&
733         ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
734         is_cpu_write_access) {
735         /* build code bitmap */
736         build_page_bitmap(p);
737     }
738
739     /* we remove all the TBs in the range [start, end[ */
740     /* XXX: see if in some cases it could be faster to invalidate all the code */
741     current_tb_not_found = is_cpu_write_access;
742     current_tb_modified = 0;
743     current_tb = NULL; /* avoid warning */
744     current_pc = 0; /* avoid warning */
745     current_cs_base = 0; /* avoid warning */
746     current_flags = 0; /* avoid warning */
747     tb = p->first_tb;
748     while (tb != NULL) {
749         n = (long)tb & 3;
750         tb = (TranslationBlock *)((long)tb & ~3);
751         tb_next = tb->page_next[n];
752         /* NOTE: this is subtle as a TB may span two physical pages */
753         if (n == 0) {
754             /* NOTE: tb_end may be after the end of the page, but
755                it is not a problem */
756             tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
757             tb_end = tb_start + tb->size;
758         } else {
759             tb_start = tb->page_addr[1];
760             tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
761         }
762         if (!(tb_end <= start || tb_start >= end)) {
763 #ifdef TARGET_HAS_PRECISE_SMC
764             if (current_tb_not_found) {
765                 current_tb_not_found = 0;
766                 current_tb = NULL;
767                 if (env->mem_write_pc) {
768                     /* now we have a real cpu fault */
769                     current_tb = tb_find_pc(env->mem_write_pc);
770                 }
771             }
772             if (current_tb == tb &&
773                 !(current_tb->cflags & CF_SINGLE_INSN)) {
774                 /* If we are modifying the current TB, we must stop
775                 its execution. We could be more precise by checking
776                 that the modification is after the current PC, but it
777                 would require a specialized function to partially
778                 restore the CPU state */
779
780                 current_tb_modified = 1;
781                 cpu_restore_state(current_tb, env,
782                                   env->mem_write_pc, NULL);
783 #if defined(TARGET_I386)
784                 current_flags = env->hflags;
785                 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
786                 current_cs_base = (target_ulong)env->segs[R_CS].base;
787                 current_pc = current_cs_base + env->eip;
788 #else
789 #error unsupported CPU
790 #endif
791             }
792 #endif /* TARGET_HAS_PRECISE_SMC */
793             /* we need to do that to handle the case where a signal
794                occurs while doing tb_phys_invalidate() */
795             saved_tb = NULL;
796             if (env) {
797                 saved_tb = env->current_tb;
798                 env->current_tb = NULL;
799             }
800             tb_phys_invalidate(tb, -1);
801             if (env) {
802                 env->current_tb = saved_tb;
803                 if (env->interrupt_request && env->current_tb)
804                     cpu_interrupt(env, env->interrupt_request);
805             }
806         }
807         tb = tb_next;
808     }
809 #if !defined(CONFIG_USER_ONLY)
810     /* if no code remaining, no need to continue to use slow writes */
811     if (!p->first_tb) {
812         invalidate_page_bitmap(p);
813         if (is_cpu_write_access) {
814             tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
815         }
816     }
817 #endif
818 #ifdef TARGET_HAS_PRECISE_SMC
819     if (current_tb_modified) {
820         /* we generate a block containing just the instruction
821            modifying the memory. It will ensure that it cannot modify
822            itself */
823         env->current_tb = NULL;
824         tb_gen_code(env, current_pc, current_cs_base, current_flags,
825                     CF_SINGLE_INSN);
826         cpu_resume_from_signal(env, NULL);
827     }
828 #endif
829 }
830
831 /* len must be <= 8 and start must be a multiple of len */
832 static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
833 {
834     PageDesc *p;
835     int offset, b;
836 #if 0
837     if (1) {
838         if (loglevel) {
839             fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
840                    cpu_single_env->mem_write_vaddr, len,
841                    cpu_single_env->eip,
842                    cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
843         }
844     }
845 #endif
846     p = page_find(start >> TARGET_PAGE_BITS);
847     if (!p)
848         return;
849     if (p->code_bitmap) {
850         offset = start & ~TARGET_PAGE_MASK;
851         b = p->code_bitmap[offset >> 3] >> (offset & 7);
852         if (b & ((1 << len) - 1))
853             goto do_invalidate;
854     } else {
855     do_invalidate:
856         tb_invalidate_phys_page_range(start, start + len, 1);
857     }
858 }
859
860 #if !defined(CONFIG_SOFTMMU)
861 static void tb_invalidate_phys_page(target_ulong addr,
862                                     unsigned long pc, void *puc)
863 {
864     int n, current_flags, current_tb_modified;
865     target_ulong current_pc, current_cs_base;
866     PageDesc *p;
867     TranslationBlock *tb, *current_tb;
868 #ifdef TARGET_HAS_PRECISE_SMC
869     CPUState *env = cpu_single_env;
870 #endif
871
872     addr &= TARGET_PAGE_MASK;
873     p = page_find(addr >> TARGET_PAGE_BITS);
874     if (!p)
875         return;
876     tb = p->first_tb;
877     current_tb_modified = 0;
878     current_tb = NULL;
879     current_pc = 0; /* avoid warning */
880     current_cs_base = 0; /* avoid warning */
881     current_flags = 0; /* avoid warning */
882 #ifdef TARGET_HAS_PRECISE_SMC
883     if (tb && pc != 0) {
884         current_tb = tb_find_pc(pc);
885     }
886 #endif
887     while (tb != NULL) {
888         n = (long)tb & 3;
889         tb = (TranslationBlock *)((long)tb & ~3);
890 #ifdef TARGET_HAS_PRECISE_SMC
891         if (current_tb == tb &&
892             !(current_tb->cflags & CF_SINGLE_INSN)) {
893                 /* If we are modifying the current TB, we must stop
894                    its execution. We could be more precise by checking
895                    that the modification is after the current PC, but it
896                    would require a specialized function to partially
897                    restore the CPU state */
898
899             current_tb_modified = 1;
900             cpu_restore_state(current_tb, env, pc, puc);
901 #if defined(TARGET_I386)
902             current_flags = env->hflags;
903             current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
904             current_cs_base = (target_ulong)env->segs[R_CS].base;
905             current_pc = current_cs_base + env->eip;
906 #else
907 #error unsupported CPU
908 #endif
909         }
910 #endif /* TARGET_HAS_PRECISE_SMC */
911         tb_phys_invalidate(tb, addr);
912         tb = tb->page_next[n];
913     }
914     p->first_tb = NULL;
915 #ifdef TARGET_HAS_PRECISE_SMC
916     if (current_tb_modified) {
917         /* we generate a block containing just the instruction
918            modifying the memory. It will ensure that it cannot modify
919            itself */
920         env->current_tb = NULL;
921         tb_gen_code(env, current_pc, current_cs_base, current_flags,
922                     CF_SINGLE_INSN);
923         cpu_resume_from_signal(env, puc);
924     }
925 #endif
926 }
927 #endif
928
929 /* add the tb in the target page and protect it if necessary */
930 static inline void tb_alloc_page(TranslationBlock *tb,
931                                  unsigned int n, target_ulong page_addr)
932 {
933     PageDesc *p;
934     TranslationBlock *last_first_tb;
935
936     tb->page_addr[n] = page_addr;
937     p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
938     tb->page_next[n] = p->first_tb;
939     last_first_tb = p->first_tb;
940     p->first_tb = (TranslationBlock *)((long)tb | n);
941     invalidate_page_bitmap(p);
942
943 #if defined(TARGET_HAS_SMC) || 1
944
945 #if defined(CONFIG_USER_ONLY)
946     if (p->flags & PAGE_WRITE) {
947         target_ulong addr;
948         PageDesc *p2;
949         int prot;