xref: /qemu/system/physmem.c (revision b8076a748d52db5f5258c29fe342b8593a0b9914)
154936004Sbellard /*
2fd6ce8f6Sbellard  *  virtual page mapping and translated block handling
354936004Sbellard  *
454936004Sbellard  *  Copyright (c) 2003 Fabrice Bellard
554936004Sbellard  *
654936004Sbellard  * This library is free software; you can redistribute it and/or
754936004Sbellard  * modify it under the terms of the GNU Lesser General Public
854936004Sbellard  * License as published by the Free Software Foundation; either
954936004Sbellard  * version 2 of the License, or (at your option) any later version.
1054936004Sbellard  *
1154936004Sbellard  * This library is distributed in the hope that it will be useful,
1254936004Sbellard  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1354936004Sbellard  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1454936004Sbellard  * Lesser General Public License for more details.
1554936004Sbellard  *
1654936004Sbellard  * You should have received a copy of the GNU Lesser General Public
1754936004Sbellard  * License along with this library; if not, write to the Free Software
1854936004Sbellard  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1954936004Sbellard  */
2067b915a5Sbellard #include "config.h"
21d5a8f07cSbellard #ifdef _WIN32
22d5a8f07cSbellard #include <windows.h>
23d5a8f07cSbellard #else
24a98d49b1Sbellard #include <sys/types.h>
25d5a8f07cSbellard #include <sys/mman.h>
26d5a8f07cSbellard #endif
2754936004Sbellard #include <stdlib.h>
2854936004Sbellard #include <stdio.h>
2954936004Sbellard #include <stdarg.h>
3054936004Sbellard #include <string.h>
3154936004Sbellard #include <errno.h>
3254936004Sbellard #include <unistd.h>
3354936004Sbellard #include <inttypes.h>
3454936004Sbellard 
356180a181Sbellard #include "cpu.h"
366180a181Sbellard #include "exec-all.h"
3754936004Sbellard 
38fd6ce8f6Sbellard //#define DEBUG_TB_INVALIDATE
3966e85a21Sbellard //#define DEBUG_FLUSH
409fa3e853Sbellard //#define DEBUG_TLB
41fd6ce8f6Sbellard 
42fd6ce8f6Sbellard /* make various TB consistency checks */
43fd6ce8f6Sbellard //#define DEBUG_TB_CHECK
4498857888Sbellard //#define DEBUG_TLB_CHECK
45fd6ce8f6Sbellard 
46fd6ce8f6Sbellard /* threshold to flush the translated code buffer */
47fd6ce8f6Sbellard #define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
48fd6ce8f6Sbellard 
499fa3e853Sbellard #define SMC_BITMAP_USE_THRESHOLD 10
509fa3e853Sbellard 
519fa3e853Sbellard #define MMAP_AREA_START        0x00000000
529fa3e853Sbellard #define MMAP_AREA_END          0xa8000000
53fd6ce8f6Sbellard 
54fd6ce8f6Sbellard TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
55fd6ce8f6Sbellard TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
569fa3e853Sbellard TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
57fd6ce8f6Sbellard int nb_tbs;
58eb51d102Sbellard /* any access to the tbs or the page table must use this lock */
59eb51d102Sbellard spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
60fd6ce8f6Sbellard 
61b8076a74Sbellard uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
62fd6ce8f6Sbellard uint8_t *code_gen_ptr;
63fd6ce8f6Sbellard 
649fa3e853Sbellard int phys_ram_size;
659fa3e853Sbellard int phys_ram_fd;
669fa3e853Sbellard uint8_t *phys_ram_base;
671ccde1cbSbellard uint8_t *phys_ram_dirty;
689fa3e853Sbellard 
6954936004Sbellard typedef struct PageDesc {
7092e873b9Sbellard     /* list of TBs intersecting this ram page */
71fd6ce8f6Sbellard     TranslationBlock *first_tb;
729fa3e853Sbellard     /* in order to optimize self modifying code, we count the number
739fa3e853Sbellard        of lookups we do to a given page to use a bitmap */
749fa3e853Sbellard     unsigned int code_write_count;
759fa3e853Sbellard     uint8_t *code_bitmap;
769fa3e853Sbellard #if defined(CONFIG_USER_ONLY)
779fa3e853Sbellard     unsigned long flags;
789fa3e853Sbellard #endif
7954936004Sbellard } PageDesc;
8054936004Sbellard 
8192e873b9Sbellard typedef struct PhysPageDesc {
8292e873b9Sbellard     /* offset in host memory of the page + io_index in the low 12 bits */
8392e873b9Sbellard     unsigned long phys_offset;
8492e873b9Sbellard } PhysPageDesc;
8592e873b9Sbellard 
869fa3e853Sbellard typedef struct VirtPageDesc {
879fa3e853Sbellard     /* physical address of code page. It is valid only if 'valid_tag'
889fa3e853Sbellard        matches 'virt_valid_tag' */
899fa3e853Sbellard     target_ulong phys_addr;
909fa3e853Sbellard     unsigned int valid_tag;
919fa3e853Sbellard #if !defined(CONFIG_SOFTMMU)
929fa3e853Sbellard     /* original page access rights. It is valid only if 'valid_tag'
939fa3e853Sbellard        matches 'virt_valid_tag' */
949fa3e853Sbellard     unsigned int prot;
959fa3e853Sbellard #endif
969fa3e853Sbellard } VirtPageDesc;
979fa3e853Sbellard 
9854936004Sbellard #define L2_BITS 10
9954936004Sbellard #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
10054936004Sbellard 
10154936004Sbellard #define L1_SIZE (1 << L1_BITS)
10254936004Sbellard #define L2_SIZE (1 << L2_BITS)
10354936004Sbellard 
10433417e70Sbellard static void io_mem_init(void);
105fd6ce8f6Sbellard 
10683fb7adfSbellard unsigned long qemu_real_host_page_size;
10783fb7adfSbellard unsigned long qemu_host_page_bits;
10883fb7adfSbellard unsigned long qemu_host_page_size;
10983fb7adfSbellard unsigned long qemu_host_page_mask;
11054936004Sbellard 
11192e873b9Sbellard /* XXX: for system emulation, it could just be an array */
11254936004Sbellard static PageDesc *l1_map[L1_SIZE];
1130a962c02Sbellard PhysPageDesc **l1_phys_map;
11454936004Sbellard 
1159fa3e853Sbellard #if !defined(CONFIG_USER_ONLY)
1169fa3e853Sbellard static VirtPageDesc *l1_virt_map[L1_SIZE];
1179fa3e853Sbellard static unsigned int virt_valid_tag;
1189fa3e853Sbellard #endif
1199fa3e853Sbellard 
12033417e70Sbellard /* io memory support */
12133417e70Sbellard CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
12233417e70Sbellard CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
123a4193c8aSbellard void *io_mem_opaque[IO_MEM_NB_ENTRIES];
12433417e70Sbellard static int io_mem_nb;
12533417e70Sbellard 
12634865134Sbellard /* log support */
12734865134Sbellard char *logfilename = "/tmp/qemu.log";
12834865134Sbellard FILE *logfile;
12934865134Sbellard int loglevel;
13034865134Sbellard 
131e3db7226Sbellard /* statistics */
132e3db7226Sbellard static int tlb_flush_count;
133e3db7226Sbellard static int tb_flush_count;
134e3db7226Sbellard static int tb_phys_invalidate_count;
135e3db7226Sbellard 
136b346ff46Sbellard static void page_init(void)
13754936004Sbellard {
13883fb7adfSbellard     /* NOTE: we can always suppose that qemu_host_page_size >=
13954936004Sbellard        TARGET_PAGE_SIZE */
14067b915a5Sbellard #ifdef _WIN32
141d5a8f07cSbellard     {
142d5a8f07cSbellard         SYSTEM_INFO system_info;
143d5a8f07cSbellard         DWORD old_protect;
144d5a8f07cSbellard 
145d5a8f07cSbellard         GetSystemInfo(&system_info);
146d5a8f07cSbellard         qemu_real_host_page_size = system_info.dwPageSize;
147d5a8f07cSbellard 
148d5a8f07cSbellard         VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
149d5a8f07cSbellard                        PAGE_EXECUTE_READWRITE, &old_protect);
150d5a8f07cSbellard     }
15167b915a5Sbellard #else
15283fb7adfSbellard     qemu_real_host_page_size = getpagesize();
153d5a8f07cSbellard     {
154d5a8f07cSbellard         unsigned long start, end;
155d5a8f07cSbellard 
156d5a8f07cSbellard         start = (unsigned long)code_gen_buffer;
157d5a8f07cSbellard         start &= ~(qemu_real_host_page_size - 1);
158d5a8f07cSbellard 
159d5a8f07cSbellard         end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
160d5a8f07cSbellard         end += qemu_real_host_page_size - 1;
161d5a8f07cSbellard         end &= ~(qemu_real_host_page_size - 1);
162d5a8f07cSbellard 
163d5a8f07cSbellard         mprotect((void *)start, end - start,
164d5a8f07cSbellard                  PROT_READ | PROT_WRITE | PROT_EXEC);
165d5a8f07cSbellard     }
16667b915a5Sbellard #endif
167d5a8f07cSbellard 
16883fb7adfSbellard     if (qemu_host_page_size == 0)
16983fb7adfSbellard         qemu_host_page_size = qemu_real_host_page_size;
17083fb7adfSbellard     if (qemu_host_page_size < TARGET_PAGE_SIZE)
17183fb7adfSbellard         qemu_host_page_size = TARGET_PAGE_SIZE;
17283fb7adfSbellard     qemu_host_page_bits = 0;
17383fb7adfSbellard     while ((1 << qemu_host_page_bits) < qemu_host_page_size)
17483fb7adfSbellard         qemu_host_page_bits++;
17583fb7adfSbellard     qemu_host_page_mask = ~(qemu_host_page_size - 1);
1769fa3e853Sbellard #if !defined(CONFIG_USER_ONLY)
1779fa3e853Sbellard     virt_valid_tag = 1;
1789fa3e853Sbellard #endif
1790a962c02Sbellard     l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(PhysPageDesc *));
1800a962c02Sbellard     memset(l1_phys_map, 0, L1_SIZE * sizeof(PhysPageDesc *));
18154936004Sbellard }
18254936004Sbellard 
183fd6ce8f6Sbellard static inline PageDesc *page_find_alloc(unsigned int index)
18454936004Sbellard {
18554936004Sbellard     PageDesc **lp, *p;
18654936004Sbellard 
18754936004Sbellard     lp = &l1_map[index >> L2_BITS];
18854936004Sbellard     p = *lp;
18954936004Sbellard     if (!p) {
19054936004Sbellard         /* allocate if not found */
19159817ccbSbellard         p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
192fd6ce8f6Sbellard         memset(p, 0, sizeof(PageDesc) * L2_SIZE);
19354936004Sbellard         *lp = p;
19454936004Sbellard     }
19554936004Sbellard     return p + (index & (L2_SIZE - 1));
19654936004Sbellard }
19754936004Sbellard 
198fd6ce8f6Sbellard static inline PageDesc *page_find(unsigned int index)
19954936004Sbellard {
20054936004Sbellard     PageDesc *p;
20154936004Sbellard 
20254936004Sbellard     p = l1_map[index >> L2_BITS];
20354936004Sbellard     if (!p)
20454936004Sbellard         return 0;
205fd6ce8f6Sbellard     return p + (index & (L2_SIZE - 1));
20654936004Sbellard }
20754936004Sbellard 
20892e873b9Sbellard static inline PhysPageDesc *phys_page_find_alloc(unsigned int index)
20992e873b9Sbellard {
21092e873b9Sbellard     PhysPageDesc **lp, *p;
21192e873b9Sbellard 
21292e873b9Sbellard     lp = &l1_phys_map[index >> L2_BITS];
21392e873b9Sbellard     p = *lp;
21492e873b9Sbellard     if (!p) {
21592e873b9Sbellard         /* allocate if not found */
2160a962c02Sbellard         p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
21792e873b9Sbellard         memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
21892e873b9Sbellard         *lp = p;
21992e873b9Sbellard     }
22092e873b9Sbellard     return p + (index & (L2_SIZE - 1));
22192e873b9Sbellard }
22292e873b9Sbellard 
22392e873b9Sbellard static inline PhysPageDesc *phys_page_find(unsigned int index)
22492e873b9Sbellard {
22592e873b9Sbellard     PhysPageDesc *p;
22692e873b9Sbellard 
22792e873b9Sbellard     p = l1_phys_map[index >> L2_BITS];
22892e873b9Sbellard     if (!p)
22992e873b9Sbellard         return 0;
23092e873b9Sbellard     return p + (index & (L2_SIZE - 1));
23192e873b9Sbellard }
23292e873b9Sbellard 
2339fa3e853Sbellard #if !defined(CONFIG_USER_ONLY)
2344f2ac237Sbellard static void tlb_protect_code(CPUState *env, target_ulong addr);
2354f2ac237Sbellard static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr);
236fd6ce8f6Sbellard 
2379fa3e853Sbellard static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
2389fa3e853Sbellard {
2399fa3e853Sbellard     VirtPageDesc **lp, *p;
2409fa3e853Sbellard 
241c27004ecSbellard     /* XXX: should not truncate for 64 bit addresses */
242c27004ecSbellard #if TARGET_LONG_BITS > 32
243c27004ecSbellard     index &= (L1_SIZE - 1);
244c27004ecSbellard #endif
2459fa3e853Sbellard     lp = &l1_virt_map[index >> L2_BITS];
2469fa3e853Sbellard     p = *lp;
2479fa3e853Sbellard     if (!p) {
2489fa3e853Sbellard         /* allocate if not found */
24959817ccbSbellard         p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE);
2509fa3e853Sbellard         memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE);
2519fa3e853Sbellard         *lp = p;
2529fa3e853Sbellard     }
2539fa3e853Sbellard     return p + (index & (L2_SIZE - 1));
2549fa3e853Sbellard }
2559fa3e853Sbellard 
2569fa3e853Sbellard static inline VirtPageDesc *virt_page_find(unsigned int index)
2579fa3e853Sbellard {
2589fa3e853Sbellard     VirtPageDesc *p;
2599fa3e853Sbellard 
2609fa3e853Sbellard     p = l1_virt_map[index >> L2_BITS];
261fd6ce8f6Sbellard     if (!p)
262fd6ce8f6Sbellard         return 0;
2639fa3e853Sbellard     return p + (index & (L2_SIZE - 1));
264fd6ce8f6Sbellard }
265fd6ce8f6Sbellard 
2669fa3e853Sbellard static void virt_page_flush(void)
26754936004Sbellard {
2689fa3e853Sbellard     int i, j;
2699fa3e853Sbellard     VirtPageDesc *p;
27054936004Sbellard 
2719fa3e853Sbellard     virt_valid_tag++;
2729fa3e853Sbellard 
2739fa3e853Sbellard     if (virt_valid_tag == 0) {
2749fa3e853Sbellard         virt_valid_tag = 1;
2759fa3e853Sbellard         for(i = 0; i < L1_SIZE; i++) {
2769fa3e853Sbellard             p = l1_virt_map[i];
2779fa3e853Sbellard             if (p) {
2789fa3e853Sbellard                 for(j = 0; j < L2_SIZE; j++)
2799fa3e853Sbellard                     p[j].valid_tag = 0;
280fd6ce8f6Sbellard             }
28154936004Sbellard         }
28254936004Sbellard     }
2839fa3e853Sbellard }
2849fa3e853Sbellard #else
2859fa3e853Sbellard static void virt_page_flush(void)
2869fa3e853Sbellard {
2879fa3e853Sbellard }
2889fa3e853Sbellard #endif
289fd6ce8f6Sbellard 
290b346ff46Sbellard void cpu_exec_init(void)
291fd6ce8f6Sbellard {
292fd6ce8f6Sbellard     if (!code_gen_ptr) {
293fd6ce8f6Sbellard         code_gen_ptr = code_gen_buffer;
294b346ff46Sbellard         page_init();
29533417e70Sbellard         io_mem_init();
296fd6ce8f6Sbellard     }
297fd6ce8f6Sbellard }
298fd6ce8f6Sbellard 
2999fa3e853Sbellard static inline void invalidate_page_bitmap(PageDesc *p)
3009fa3e853Sbellard {
3019fa3e853Sbellard     if (p->code_bitmap) {
30259817ccbSbellard         qemu_free(p->code_bitmap);
3039fa3e853Sbellard         p->code_bitmap = NULL;
3049fa3e853Sbellard     }
3059fa3e853Sbellard     p->code_write_count = 0;
3069fa3e853Sbellard }
3079fa3e853Sbellard 
308fd6ce8f6Sbellard /* set to NULL all the 'first_tb' fields in all PageDescs */
309fd6ce8f6Sbellard static void page_flush_tb(void)
310fd6ce8f6Sbellard {
311fd6ce8f6Sbellard     int i, j;
312fd6ce8f6Sbellard     PageDesc *p;
313fd6ce8f6Sbellard 
314fd6ce8f6Sbellard     for(i = 0; i < L1_SIZE; i++) {
315fd6ce8f6Sbellard         p = l1_map[i];
316fd6ce8f6Sbellard         if (p) {
3179fa3e853Sbellard             for(j = 0; j < L2_SIZE; j++) {
3189fa3e853Sbellard                 p->first_tb = NULL;
3199fa3e853Sbellard                 invalidate_page_bitmap(p);
3209fa3e853Sbellard                 p++;
3219fa3e853Sbellard             }
322fd6ce8f6Sbellard         }
323fd6ce8f6Sbellard     }
324fd6ce8f6Sbellard }
325fd6ce8f6Sbellard 
326fd6ce8f6Sbellard /* flush all the translation blocks */
327d4e8164fSbellard /* XXX: tb_flush is currently not thread safe */
3280124311eSbellard void tb_flush(CPUState *env)
329fd6ce8f6Sbellard {
3300124311eSbellard #if defined(DEBUG_FLUSH)
331fd6ce8f6Sbellard     printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
332fd6ce8f6Sbellard            code_gen_ptr - code_gen_buffer,
333fd6ce8f6Sbellard            nb_tbs,
3340124311eSbellard            nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
335fd6ce8f6Sbellard #endif
336fd6ce8f6Sbellard     nb_tbs = 0;
3378a8a608fSbellard     memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
3389fa3e853Sbellard     virt_page_flush();
3399fa3e853Sbellard 
3408a8a608fSbellard     memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
341fd6ce8f6Sbellard     page_flush_tb();
3429fa3e853Sbellard 
343fd6ce8f6Sbellard     code_gen_ptr = code_gen_buffer;
344d4e8164fSbellard     /* XXX: flush processor icache at this point if cache flush is
345d4e8164fSbellard        expensive */
346e3db7226Sbellard     tb_flush_count++;
347fd6ce8f6Sbellard }
348fd6ce8f6Sbellard 
349fd6ce8f6Sbellard #ifdef DEBUG_TB_CHECK
350fd6ce8f6Sbellard 
351fd6ce8f6Sbellard static void tb_invalidate_check(unsigned long address)
352fd6ce8f6Sbellard {
353fd6ce8f6Sbellard     TranslationBlock *tb;
354fd6ce8f6Sbellard     int i;
355fd6ce8f6Sbellard     address &= TARGET_PAGE_MASK;
356fd6ce8f6Sbellard     for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
357fd6ce8f6Sbellard         for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
358fd6ce8f6Sbellard             if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
359fd6ce8f6Sbellard                   address >= tb->pc + tb->size)) {
360fd6ce8f6Sbellard                 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
361fd6ce8f6Sbellard                        address, tb->pc, tb->size);
362fd6ce8f6Sbellard             }
363fd6ce8f6Sbellard         }
364fd6ce8f6Sbellard     }
365fd6ce8f6Sbellard }
366fd6ce8f6Sbellard 
367fd6ce8f6Sbellard /* verify that all the pages have correct rights for code */
368fd6ce8f6Sbellard static void tb_page_check(void)
369fd6ce8f6Sbellard {
370fd6ce8f6Sbellard     TranslationBlock *tb;
371fd6ce8f6Sbellard     int i, flags1, flags2;
372fd6ce8f6Sbellard 
373fd6ce8f6Sbellard     for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
374fd6ce8f6Sbellard         for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
375fd6ce8f6Sbellard             flags1 = page_get_flags(tb->pc);
376fd6ce8f6Sbellard             flags2 = page_get_flags(tb->pc + tb->size - 1);
377fd6ce8f6Sbellard             if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
378fd6ce8f6Sbellard                 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
379fd6ce8f6Sbellard                        tb->pc, tb->size, flags1, flags2);
380fd6ce8f6Sbellard             }
381fd6ce8f6Sbellard         }
382fd6ce8f6Sbellard     }
383fd6ce8f6Sbellard }
384fd6ce8f6Sbellard 
385d4e8164fSbellard void tb_jmp_check(TranslationBlock *tb)
386d4e8164fSbellard {
387d4e8164fSbellard     TranslationBlock *tb1;
388d4e8164fSbellard     unsigned int n1;
389d4e8164fSbellard 
390d4e8164fSbellard     /* suppress any remaining jumps to this TB */
391d4e8164fSbellard     tb1 = tb->jmp_first;
392d4e8164fSbellard     for(;;) {
393d4e8164fSbellard         n1 = (long)tb1 & 3;
394d4e8164fSbellard         tb1 = (TranslationBlock *)((long)tb1 & ~3);
395d4e8164fSbellard         if (n1 == 2)
396d4e8164fSbellard             break;
397d4e8164fSbellard         tb1 = tb1->jmp_next[n1];
398d4e8164fSbellard     }
399d4e8164fSbellard     /* check end of list */
400d4e8164fSbellard     if (tb1 != tb) {
401d4e8164fSbellard         printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
402d4e8164fSbellard     }
403d4e8164fSbellard }
404d4e8164fSbellard 
405fd6ce8f6Sbellard #endif
406fd6ce8f6Sbellard 
407fd6ce8f6Sbellard /* invalidate one TB */
408fd6ce8f6Sbellard static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
409fd6ce8f6Sbellard                              int next_offset)
410fd6ce8f6Sbellard {
411fd6ce8f6Sbellard     TranslationBlock *tb1;
412fd6ce8f6Sbellard     for(;;) {
413fd6ce8f6Sbellard         tb1 = *ptb;
414fd6ce8f6Sbellard         if (tb1 == tb) {
415fd6ce8f6Sbellard             *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
416fd6ce8f6Sbellard             break;
417fd6ce8f6Sbellard         }
418fd6ce8f6Sbellard         ptb = (TranslationBlock **)((char *)tb1 + next_offset);
419fd6ce8f6Sbellard     }
420fd6ce8f6Sbellard }
421fd6ce8f6Sbellard 
4229fa3e853Sbellard static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
4239fa3e853Sbellard {
4249fa3e853Sbellard     TranslationBlock *tb1;
4259fa3e853Sbellard     unsigned int n1;
4269fa3e853Sbellard 
4279fa3e853Sbellard     for(;;) {
4289fa3e853Sbellard         tb1 = *ptb;
4299fa3e853Sbellard         n1 = (long)tb1 & 3;
4309fa3e853Sbellard         tb1 = (TranslationBlock *)((long)tb1 & ~3);
4319fa3e853Sbellard         if (tb1 == tb) {
4329fa3e853Sbellard             *ptb = tb1->page_next[n1];
4339fa3e853Sbellard             break;
4349fa3e853Sbellard         }
4359fa3e853Sbellard         ptb = &tb1->page_next[n1];
4369fa3e853Sbellard     }
4379fa3e853Sbellard }
4389fa3e853Sbellard 
439d4e8164fSbellard static inline void tb_jmp_remove(TranslationBlock *tb, int n)
440d4e8164fSbellard {
441d4e8164fSbellard     TranslationBlock *tb1, **ptb;
442d4e8164fSbellard     unsigned int n1;
443d4e8164fSbellard 
444d4e8164fSbellard     ptb = &tb->jmp_next[n];
445d4e8164fSbellard     tb1 = *ptb;
446d4e8164fSbellard     if (tb1) {
447d4e8164fSbellard         /* find tb(n) in circular list */
448d4e8164fSbellard         for(;;) {
449d4e8164fSbellard             tb1 = *ptb;
450d4e8164fSbellard             n1 = (long)tb1 & 3;
451d4e8164fSbellard             tb1 = (TranslationBlock *)((long)tb1 & ~3);
452d4e8164fSbellard             if (n1 == n && tb1 == tb)
453d4e8164fSbellard                 break;
454d4e8164fSbellard             if (n1 == 2) {
455d4e8164fSbellard                 ptb = &tb1->jmp_first;
456d4e8164fSbellard             } else {
457d4e8164fSbellard                 ptb = &tb1->jmp_next[n1];
458d4e8164fSbellard             }
459d4e8164fSbellard         }
460d4e8164fSbellard         /* now we can suppress tb(n) from the list */
461d4e8164fSbellard         *ptb = tb->jmp_next[n];
462d4e8164fSbellard 
463d4e8164fSbellard         tb->jmp_next[n] = NULL;
464d4e8164fSbellard     }
465d4e8164fSbellard }
466d4e8164fSbellard 
467d4e8164fSbellard /* reset the jump entry 'n' of a TB so that it is not chained to
468d4e8164fSbellard    another TB */
469d4e8164fSbellard static inline void tb_reset_jump(TranslationBlock *tb, int n)
470d4e8164fSbellard {
471d4e8164fSbellard     tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
472d4e8164fSbellard }
473d4e8164fSbellard 
4749fa3e853Sbellard static inline void tb_invalidate(TranslationBlock *tb)
475fd6ce8f6Sbellard {
476d4e8164fSbellard     unsigned int h, n1;
4779fa3e853Sbellard     TranslationBlock *tb1, *tb2, **ptb;
478fd6ce8f6Sbellard 
47936bdbe54Sbellard     tb_invalidated_flag = 1;
48036bdbe54Sbellard 
481fd6ce8f6Sbellard     /* remove the TB from the hash list */
482fd6ce8f6Sbellard     h = tb_hash_func(tb->pc);
4839fa3e853Sbellard     ptb = &tb_hash[h];
4849fa3e853Sbellard     for(;;) {
4859fa3e853Sbellard         tb1 = *ptb;
4869fa3e853Sbellard         /* NOTE: the TB is not necessarily linked in the hash. It
4879fa3e853Sbellard            indicates that it is not currently used */
4889fa3e853Sbellard         if (tb1 == NULL)
4899fa3e853Sbellard             return;
4909fa3e853Sbellard         if (tb1 == tb) {
4919fa3e853Sbellard             *ptb = tb1->hash_next;
4929fa3e853Sbellard             break;
493fd6ce8f6Sbellard         }
4949fa3e853Sbellard         ptb = &tb1->hash_next;
495fd6ce8f6Sbellard     }
496d4e8164fSbellard 
497d4e8164fSbellard     /* suppress this TB from the two jump lists */
498d4e8164fSbellard     tb_jmp_remove(tb, 0);
499d4e8164fSbellard     tb_jmp_remove(tb, 1);
500d4e8164fSbellard 
501d4e8164fSbellard     /* suppress any remaining jumps to this TB */
502d4e8164fSbellard     tb1 = tb->jmp_first;
503d4e8164fSbellard     for(;;) {
504d4e8164fSbellard         n1 = (long)tb1 & 3;
505d4e8164fSbellard         if (n1 == 2)
506d4e8164fSbellard             break;
507d4e8164fSbellard         tb1 = (TranslationBlock *)((long)tb1 & ~3);
508d4e8164fSbellard         tb2 = tb1->jmp_next[n1];
509d4e8164fSbellard         tb_reset_jump(tb1, n1);
510d4e8164fSbellard         tb1->jmp_next[n1] = NULL;
511d4e8164fSbellard         tb1 = tb2;
512d4e8164fSbellard     }
513d4e8164fSbellard     tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
514fd6ce8f6Sbellard }
515fd6ce8f6Sbellard 
5169fa3e853Sbellard static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
517fd6ce8f6Sbellard {
518fd6ce8f6Sbellard     PageDesc *p;
5199fa3e853Sbellard     unsigned int h;
5209fa3e853Sbellard     target_ulong phys_pc;
521fd6ce8f6Sbellard 
5229fa3e853Sbellard     /* remove the TB from the hash list */
5239fa3e853Sbellard     phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
5249fa3e853Sbellard     h = tb_phys_hash_func(phys_pc);
5259fa3e853Sbellard     tb_remove(&tb_phys_hash[h], tb,
5269fa3e853Sbellard               offsetof(TranslationBlock, phys_hash_next));
5279fa3e853Sbellard 
5289fa3e853Sbellard     /* remove the TB from the page list */
5299fa3e853Sbellard     if (tb->page_addr[0] != page_addr) {
5309fa3e853Sbellard         p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
5319fa3e853Sbellard         tb_page_remove(&p->first_tb, tb);
5329fa3e853Sbellard         invalidate_page_bitmap(p);
5339fa3e853Sbellard     }
5349fa3e853Sbellard     if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
5359fa3e853Sbellard         p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
5369fa3e853Sbellard         tb_page_remove(&p->first_tb, tb);
5379fa3e853Sbellard         invalidate_page_bitmap(p);
5389fa3e853Sbellard     }
5399fa3e853Sbellard 
5409fa3e853Sbellard     tb_invalidate(tb);
541e3db7226Sbellard     tb_phys_invalidate_count++;
5429fa3e853Sbellard }
5439fa3e853Sbellard 
5449fa3e853Sbellard static inline void set_bits(uint8_t *tab, int start, int len)
5459fa3e853Sbellard {
5469fa3e853Sbellard     int end, mask, end1;
5479fa3e853Sbellard 
5489fa3e853Sbellard     end = start + len;
5499fa3e853Sbellard     tab += start >> 3;
5509fa3e853Sbellard     mask = 0xff << (start & 7);
5519fa3e853Sbellard     if ((start & ~7) == (end & ~7)) {
5529fa3e853Sbellard         if (start < end) {
5539fa3e853Sbellard             mask &= ~(0xff << (end & 7));
5549fa3e853Sbellard             *tab |= mask;
5559fa3e853Sbellard         }
5569fa3e853Sbellard     } else {
5579fa3e853Sbellard         *tab++ |= mask;
5589fa3e853Sbellard         start = (start + 8) & ~7;
5599fa3e853Sbellard         end1 = end & ~7;
5609fa3e853Sbellard         while (start < end1) {
5619fa3e853Sbellard             *tab++ = 0xff;
5629fa3e853Sbellard             start += 8;
5639fa3e853Sbellard         }
5649fa3e853Sbellard         if (start < end) {
5659fa3e853Sbellard             mask = ~(0xff << (end & 7));
5669fa3e853Sbellard             *tab |= mask;
5679fa3e853Sbellard         }
5689fa3e853Sbellard     }
5699fa3e853Sbellard }
5709fa3e853Sbellard 
5719fa3e853Sbellard static void build_page_bitmap(PageDesc *p)
5729fa3e853Sbellard {
5739fa3e853Sbellard     int n, tb_start, tb_end;
5749fa3e853Sbellard     TranslationBlock *tb;
5759fa3e853Sbellard 
57659817ccbSbellard     p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
5779fa3e853Sbellard     if (!p->code_bitmap)
5789fa3e853Sbellard         return;
5799fa3e853Sbellard     memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
5809fa3e853Sbellard 
5819fa3e853Sbellard     tb = p->first_tb;
5829fa3e853Sbellard     while (tb != NULL) {
5839fa3e853Sbellard         n = (long)tb & 3;
5849fa3e853Sbellard         tb = (TranslationBlock *)((long)tb & ~3);
5859fa3e853Sbellard         /* NOTE: this is subtle as a TB may span two physical pages */
5869fa3e853Sbellard         if (n == 0) {
5879fa3e853Sbellard             /* NOTE: tb_end may be after the end of the page, but
5889fa3e853Sbellard                it is not a problem */
5899fa3e853Sbellard             tb_start = tb->pc & ~TARGET_PAGE_MASK;
5909fa3e853Sbellard             tb_end = tb_start + tb->size;
5919fa3e853Sbellard             if (tb_end > TARGET_PAGE_SIZE)
5929fa3e853Sbellard                 tb_end = TARGET_PAGE_SIZE;
5939fa3e853Sbellard         } else {
5949fa3e853Sbellard             tb_start = 0;
5959fa3e853Sbellard             tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
5969fa3e853Sbellard         }
5979fa3e853Sbellard         set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
5989fa3e853Sbellard         tb = tb->page_next[n];
5999fa3e853Sbellard     }
6009fa3e853Sbellard }
6019fa3e853Sbellard 
602d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC
603d720b93dSbellard 
604d720b93dSbellard static void tb_gen_code(CPUState *env,
605d720b93dSbellard                         target_ulong pc, target_ulong cs_base, int flags,
606d720b93dSbellard                         int cflags)
607d720b93dSbellard {
608d720b93dSbellard     TranslationBlock *tb;
609d720b93dSbellard     uint8_t *tc_ptr;
610d720b93dSbellard     target_ulong phys_pc, phys_page2, virt_page2;
611d720b93dSbellard     int code_gen_size;
612d720b93dSbellard 
613c27004ecSbellard     phys_pc = get_phys_addr_code(env, pc);
614c27004ecSbellard     tb = tb_alloc(pc);
615d720b93dSbellard     if (!tb) {
616d720b93dSbellard         /* flush must be done */
617d720b93dSbellard         tb_flush(env);
618d720b93dSbellard         /* cannot fail at this point */
619c27004ecSbellard         tb = tb_alloc(pc);
620d720b93dSbellard     }
621d720b93dSbellard     tc_ptr = code_gen_ptr;
622d720b93dSbellard     tb->tc_ptr = tc_ptr;
623d720b93dSbellard     tb->cs_base = cs_base;
624d720b93dSbellard     tb->flags = flags;
625d720b93dSbellard     tb->cflags = cflags;
626d720b93dSbellard     cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
627d720b93dSbellard     code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
628d720b93dSbellard 
629d720b93dSbellard     /* check next page if needed */
630c27004ecSbellard     virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
631d720b93dSbellard     phys_page2 = -1;
632c27004ecSbellard     if ((pc & TARGET_PAGE_MASK) != virt_page2) {
633d720b93dSbellard         phys_page2 = get_phys_addr_code(env, virt_page2);
634d720b93dSbellard     }
635d720b93dSbellard     tb_link_phys(tb, phys_pc, phys_page2);
636d720b93dSbellard }
637d720b93dSbellard #endif
638d720b93dSbellard 
6399fa3e853Sbellard /* invalidate all TBs which intersect with the target physical page
6409fa3e853Sbellard    starting in range [start;end[. NOTE: start and end must refer to
641d720b93dSbellard    the same physical page. 'is_cpu_write_access' should be true if called
642d720b93dSbellard    from a real cpu write access: the virtual CPU will exit the current
643d720b93dSbellard    TB if code is modified inside this TB. */
644d720b93dSbellard void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
645d720b93dSbellard                                    int is_cpu_write_access)
6469fa3e853Sbellard {
647d720b93dSbellard     int n, current_tb_modified, current_tb_not_found, current_flags;
648d720b93dSbellard     CPUState *env = cpu_single_env;
6499fa3e853Sbellard     PageDesc *p;
650ea1c1802Sbellard     TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
6519fa3e853Sbellard     target_ulong tb_start, tb_end;
652d720b93dSbellard     target_ulong current_pc, current_cs_base;
6539fa3e853Sbellard 
6549fa3e853Sbellard     p = page_find(start >> TARGET_PAGE_BITS);
6559fa3e853Sbellard     if (!p)
6569fa3e853Sbellard         return;
6579fa3e853Sbellard     if (!p->code_bitmap &&
658d720b93dSbellard         ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
659d720b93dSbellard         is_cpu_write_access) {
6609fa3e853Sbellard         /* build code bitmap */
6619fa3e853Sbellard         build_page_bitmap(p);
6629fa3e853Sbellard     }
6639fa3e853Sbellard 
6649fa3e853Sbellard     /* we remove all the TBs in the range [start, end[ */
6659fa3e853Sbellard     /* XXX: see if in some cases it could be faster to invalidate all the code */
666d720b93dSbellard     current_tb_not_found = is_cpu_write_access;
667d720b93dSbellard     current_tb_modified = 0;
668d720b93dSbellard     current_tb = NULL; /* avoid warning */
669d720b93dSbellard     current_pc = 0; /* avoid warning */
670d720b93dSbellard     current_cs_base = 0; /* avoid warning */
671d720b93dSbellard     current_flags = 0; /* avoid warning */
6729fa3e853Sbellard     tb = p->first_tb;
6739fa3e853Sbellard     while (tb != NULL) {
6749fa3e853Sbellard         n = (long)tb & 3;
6759fa3e853Sbellard         tb = (TranslationBlock *)((long)tb & ~3);
6769fa3e853Sbellard         tb_next = tb->page_next[n];
6779fa3e853Sbellard         /* NOTE: this is subtle as a TB may span two physical pages */
6789fa3e853Sbellard         if (n == 0) {
6799fa3e853Sbellard             /* NOTE: tb_end may be after the end of the page, but
6809fa3e853Sbellard                it is not a problem */
6819fa3e853Sbellard             tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
6829fa3e853Sbellard             tb_end = tb_start + tb->size;
6839fa3e853Sbellard         } else {
6849fa3e853Sbellard             tb_start = tb->page_addr[1];
6859fa3e853Sbellard             tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
6869fa3e853Sbellard         }
6879fa3e853Sbellard         if (!(tb_end <= start || tb_start >= end)) {
688d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC
689d720b93dSbellard             if (current_tb_not_found) {
690d720b93dSbellard                 current_tb_not_found = 0;
691d720b93dSbellard                 current_tb = NULL;
692d720b93dSbellard                 if (env->mem_write_pc) {
693d720b93dSbellard                     /* now we have a real cpu fault */
694d720b93dSbellard                     current_tb = tb_find_pc(env->mem_write_pc);
695d720b93dSbellard                 }
696d720b93dSbellard             }
697d720b93dSbellard             if (current_tb == tb &&
698d720b93dSbellard                 !(current_tb->cflags & CF_SINGLE_INSN)) {
699d720b93dSbellard                 /* If we are modifying the current TB, we must stop
700d720b93dSbellard                 its execution. We could be more precise by checking
701d720b93dSbellard                 that the modification is after the current PC, but it
702d720b93dSbellard                 would require a specialized function to partially
703d720b93dSbellard                 restore the CPU state */
704d720b93dSbellard 
705d720b93dSbellard                 current_tb_modified = 1;
706d720b93dSbellard                 cpu_restore_state(current_tb, env,
707d720b93dSbellard                                   env->mem_write_pc, NULL);
708d720b93dSbellard #if defined(TARGET_I386)
709d720b93dSbellard                 current_flags = env->hflags;
710d720b93dSbellard                 current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
711d720b93dSbellard                 current_cs_base = (target_ulong)env->segs[R_CS].base;
712d720b93dSbellard                 current_pc = current_cs_base + env->eip;
713d720b93dSbellard #else
714d720b93dSbellard #error unsupported CPU
715d720b93dSbellard #endif
716d720b93dSbellard             }
717d720b93dSbellard #endif /* TARGET_HAS_PRECISE_SMC */
718ea1c1802Sbellard             saved_tb = env->current_tb;
719ea1c1802Sbellard             env->current_tb = NULL;
7209fa3e853Sbellard             tb_phys_invalidate(tb, -1);
721ea1c1802Sbellard             env->current_tb = saved_tb;
722ea1c1802Sbellard             if (env->interrupt_request && env->current_tb)
723ea1c1802Sbellard                 cpu_interrupt(env, env->interrupt_request);
7249fa3e853Sbellard         }
7259fa3e853Sbellard         tb = tb_next;
7269fa3e853Sbellard     }
7279fa3e853Sbellard #if !defined(CONFIG_USER_ONLY)
7289fa3e853Sbellard     /* if no code remaining, no need to continue to use slow writes */
7299fa3e853Sbellard     if (!p->first_tb) {
7309fa3e853Sbellard         invalidate_page_bitmap(p);
731d720b93dSbellard         if (is_cpu_write_access) {
732d720b93dSbellard             tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
733d720b93dSbellard         }
734d720b93dSbellard     }
735d720b93dSbellard #endif
736d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC
737d720b93dSbellard     if (current_tb_modified) {
738d720b93dSbellard         /* we generate a block containing just the instruction
739d720b93dSbellard            modifying the memory. It will ensure that it cannot modify
740d720b93dSbellard            itself */
741ea1c1802Sbellard         env->current_tb = NULL;
742d720b93dSbellard         tb_gen_code(env, current_pc, current_cs_base, current_flags,
743d720b93dSbellard                     CF_SINGLE_INSN);
744d720b93dSbellard         cpu_resume_from_signal(env, NULL);
7459fa3e853Sbellard     }
7469fa3e853Sbellard #endif
7479fa3e853Sbellard }
7489fa3e853Sbellard 
7499fa3e853Sbellard /* len must be <= 8 and start must be a multiple of len */
750d720b93dSbellard static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
7519fa3e853Sbellard {
7529fa3e853Sbellard     PageDesc *p;
7539fa3e853Sbellard     int offset, b;
75459817ccbSbellard #if 0
755a4193c8aSbellard     if (1) {
756a4193c8aSbellard         if (loglevel) {
757a4193c8aSbellard             fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
758a4193c8aSbellard                    cpu_single_env->mem_write_vaddr, len,
759a4193c8aSbellard                    cpu_single_env->eip,
760a4193c8aSbellard                    cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
761a4193c8aSbellard         }
76259817ccbSbellard     }
76359817ccbSbellard #endif
7649fa3e853Sbellard     p = page_find(start >> TARGET_PAGE_BITS);
7659fa3e853Sbellard     if (!p)
7669fa3e853Sbellard         return;
7679fa3e853Sbellard     if (p->code_bitmap) {
7689fa3e853Sbellard         offset = start & ~TARGET_PAGE_MASK;
7699fa3e853Sbellard         b = p->code_bitmap[offset >> 3] >> (offset & 7);
7709fa3e853Sbellard         if (b & ((1 << len) - 1))
7719fa3e853Sbellard             goto do_invalidate;
7729fa3e853Sbellard     } else {
7739fa3e853Sbellard     do_invalidate:
774d720b93dSbellard         tb_invalidate_phys_page_range(start, start + len, 1);
7759fa3e853Sbellard     }
7769fa3e853Sbellard }
7779fa3e853Sbellard 
7789fa3e853Sbellard #if !defined(CONFIG_SOFTMMU)
779d720b93dSbellard static void tb_invalidate_phys_page(target_ulong addr,
780d720b93dSbellard                                     unsigned long pc, void *puc)
7819fa3e853Sbellard {
782d720b93dSbellard     int n, current_flags, current_tb_modified;
783d720b93dSbellard     target_ulong current_pc, current_cs_base;
7849fa3e853Sbellard     PageDesc *p;
785d720b93dSbellard     TranslationBlock *tb, *current_tb;
786d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC
787d720b93dSbellard     CPUState *env = cpu_single_env;
788d720b93dSbellard #endif
7899fa3e853Sbellard 
7909fa3e853Sbellard     addr &= TARGET_PAGE_MASK;
7919fa3e853Sbellard     p = page_find(addr >> TARGET_PAGE_BITS);
792fd6ce8f6Sbellard     if (!p)
793fd6ce8f6Sbellard         return;
794fd6ce8f6Sbellard     tb = p->first_tb;
795d720b93dSbellard     current_tb_modified = 0;
796d720b93dSbellard     current_tb = NULL;
797d720b93dSbellard     current_pc = 0; /* avoid warning */
798d720b93dSbellard     current_cs_base = 0; /* avoid warning */
799d720b93dSbellard     current_flags = 0; /* avoid warning */
800d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC
801d720b93dSbellard     if (tb && pc != 0) {
802d720b93dSbellard         current_tb = tb_find_pc(pc);
803d720b93dSbellard     }
804d720b93dSbellard #endif
805fd6ce8f6Sbellard     while (tb != NULL) {
8069fa3e853Sbellard         n = (long)tb & 3;
8079fa3e853Sbellard         tb = (TranslationBlock *)((long)tb & ~3);
808d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC
809d720b93dSbellard         if (current_tb == tb &&
810d720b93dSbellard             !(current_tb->cflags & CF_SINGLE_INSN)) {
811d720b93dSbellard                 /* If we are modifying the current TB, we must stop
812d720b93dSbellard                    its execution. We could be more precise by checking
813d720b93dSbellard                    that the modification is after the current PC, but it
814d720b93dSbellard                    would require a specialized function to partially
815d720b93dSbellard                    restore the CPU state */
816d720b93dSbellard 
817d720b93dSbellard             current_tb_modified = 1;
818d720b93dSbellard             cpu_restore_state(current_tb, env, pc, puc);
819d720b93dSbellard #if defined(TARGET_I386)
820d720b93dSbellard             current_flags = env->hflags;
821d720b93dSbellard             current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
822d720b93dSbellard             current_cs_base = (target_ulong)env->segs[R_CS].base;
823d720b93dSbellard             current_pc = current_cs_base + env->eip;
824d720b93dSbellard #else
825d720b93dSbellard #error unsupported CPU
826d720b93dSbellard #endif
827d720b93dSbellard         }
828d720b93dSbellard #endif /* TARGET_HAS_PRECISE_SMC */
8299fa3e853Sbellard         tb_phys_invalidate(tb, addr);
8309fa3e853Sbellard         tb = tb->page_next[n];
831fd6ce8f6Sbellard     }
832fd6ce8f6Sbellard     p->first_tb = NULL;
833d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC
834d720b93dSbellard     if (current_tb_modified) {
835d720b93dSbellard         /* we generate a block containing just the instruction
836d720b93dSbellard            modifying the memory. It will ensure that it cannot modify
837d720b93dSbellard            itself */
838ea1c1802Sbellard         env->current_tb = NULL;
839d720b93dSbellard         tb_gen_code(env, current_pc, current_cs_base, current_flags,
840d720b93dSbellard                     CF_SINGLE_INSN);
841d720b93dSbellard         cpu_resume_from_signal(env, puc);
842d720b93dSbellard     }
843d720b93dSbellard #endif
844fd6ce8f6Sbellard }
8459fa3e853Sbellard #endif
846fd6ce8f6Sbellard 
847fd6ce8f6Sbellard /* add the tb in the target page and protect it if necessary */
8489fa3e853Sbellard static inline void tb_alloc_page(TranslationBlock *tb,
8499fa3e853Sbellard                                  unsigned int n, unsigned int page_addr)
850fd6ce8f6Sbellard {
851fd6ce8f6Sbellard     PageDesc *p;
8529fa3e853Sbellard     TranslationBlock *last_first_tb;
8539fa3e853Sbellard 
8549fa3e853Sbellard     tb->page_addr[n] = page_addr;
8559fa3e853Sbellard     p = page_find(page_addr >> TARGET_PAGE_BITS);
8569fa3e853Sbellard     tb->page_next[n] = p->first_tb;
8579fa3e853Sbellard     last_first_tb = p->first_tb;
8589fa3e853Sbellard     p->first_tb = (TranslationBlock *)((long)tb | n);
8599fa3e853Sbellard     invalidate_page_bitmap(p);
8609fa3e853Sbellard 
861107db443Sbellard #if defined(TARGET_HAS_SMC) || 1
862d720b93dSbellard 
8639fa3e853Sbellard #if defined(CONFIG_USER_ONLY)
8649fa3e853Sbellard     if (p->flags & PAGE_WRITE) {
8659fa3e853Sbellard         unsigned long host_start, host_end, addr;
866fd6ce8f6Sbellard         int prot;
867fd6ce8f6Sbellard 
868fd6ce8f6Sbellard         /* force the host page as non writable (writes will have a
869fd6ce8f6Sbellard            page fault + mprotect overhead) */
87083fb7adfSbellard         host_start = page_addr & qemu_host_page_mask;
87183fb7adfSbellard         host_end = host_start + qemu_host_page_size;
872fd6ce8f6Sbellard         prot = 0;
873fd6ce8f6Sbellard         for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
874fd6ce8f6Sbellard             prot |= page_get_flags(addr);
87583fb7adfSbellard         mprotect((void *)host_start, qemu_host_page_size,
876fd6ce8f6Sbellard                  (prot & PAGE_BITS) & ~PAGE_WRITE);
877fd6ce8f6Sbellard #ifdef DEBUG_TB_INVALIDATE
878fd6ce8f6Sbellard         printf("protecting code page: 0x%08lx\n",
879fd6ce8f6Sbellard                host_start);
880fd6ce8f6Sbellard #endif
881fd6ce8f6Sbellard         p->flags &= ~PAGE_WRITE;
882fd6ce8f6Sbellard     }
8839fa3e853Sbellard #else
8849fa3e853Sbellard     /* if some code is already present, then the pages are already
8859fa3e853Sbellard        protected. So we handle the case where only the first TB is
8869fa3e853Sbellard        allocated in a physical page */
8879fa3e853Sbellard     if (!last_first_tb) {
8889fa3e853Sbellard         target_ulong virt_addr;
8899fa3e853Sbellard 
8909fa3e853Sbellard         virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS);
8919fa3e853Sbellard         tlb_protect_code(cpu_single_env, virt_addr);
8929fa3e853Sbellard     }
8939fa3e853Sbellard #endif
894d720b93dSbellard 
895d720b93dSbellard #endif /* TARGET_HAS_SMC */
896fd6ce8f6Sbellard }
897fd6ce8f6Sbellard 
898fd6ce8f6Sbellard /* Allocate a new translation block. Flush the translation buffer if
899fd6ce8f6Sbellard    too many translation blocks or too much generated code. */
900c27004ecSbellard TranslationBlock *tb_alloc(target_ulong pc)
901fd6ce8f6Sbellard {
902fd6ce8f6Sbellard     TranslationBlock *tb;
903fd6ce8f6Sbellard 
904fd6ce8f6Sbellard     if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
905fd6ce8f6Sbellard         (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
906d4e8164fSbellard         return NULL;
907fd6ce8f6Sbellard     tb = &tbs[nb_tbs++];
908fd6ce8f6Sbellard     tb->pc = pc;
909b448f2f3Sbellard     tb->cflags = 0;
910d4e8164fSbellard     return tb;
911d4e8164fSbellard }
912d4e8164fSbellard 
9139fa3e853Sbellard /* add a new TB and link it to the physical page tables. phys_page2 is
9149fa3e853Sbellard    (-1) to indicate that only one page contains the TB. */
9159fa3e853Sbellard void tb_link_phys(TranslationBlock *tb,
9169fa3e853Sbellard                   target_ulong phys_pc, target_ulong phys_page2)
917d4e8164fSbellard {
9189fa3e853Sbellard     unsigned int h;
9199fa3e853Sbellard     TranslationBlock **ptb;
9209fa3e853Sbellard 
9219fa3e853Sbellard     /* add in the physical hash table */
9229fa3e853Sbellard     h = tb_phys_hash_func(phys_pc);
9239fa3e853Sbellard     ptb = &tb_phys_hash[h];
9249fa3e853Sbellard     tb->phys_hash_next = *ptb;
9259fa3e853Sbellard     *ptb = tb;
926fd6ce8f6Sbellard 
927fd6ce8f6Sbellard     /* add in the page list */
9289fa3e853Sbellard     tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
9299fa3e853Sbellard     if (phys_page2 != -1)
9309fa3e853Sbellard         tb_alloc_page(tb, 1, phys_page2);
9319fa3e853Sbellard     else
9329fa3e853Sbellard         tb->page_addr[1] = -1;
93361382a50Sbellard #ifdef DEBUG_TB_CHECK
93461382a50Sbellard     tb_page_check();
93561382a50Sbellard #endif
9369fa3e853Sbellard }
9379fa3e853Sbellard 
9389fa3e853Sbellard /* link the tb with the other TBs */
9399fa3e853Sbellard void tb_link(TranslationBlock *tb)
9409fa3e853Sbellard {
9419fa3e853Sbellard #if !defined(CONFIG_USER_ONLY)
9429fa3e853Sbellard     {
9439fa3e853Sbellard         VirtPageDesc *vp;
9449fa3e853Sbellard         target_ulong addr;
9459fa3e853Sbellard 
9469fa3e853Sbellard         /* save the code memory mappings (needed to invalidate the code) */
9479fa3e853Sbellard         addr = tb->pc & TARGET_PAGE_MASK;
9489fa3e853Sbellard         vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
94998857888Sbellard #ifdef DEBUG_TLB_CHECK
95098857888Sbellard         if (vp->valid_tag == virt_valid_tag &&
95198857888Sbellard             vp->phys_addr != tb->page_addr[0]) {
95298857888Sbellard             printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
95398857888Sbellard                    addr, tb->page_addr[0], vp->phys_addr);
95498857888Sbellard         }
95598857888Sbellard #endif
9569fa3e853Sbellard         vp->phys_addr = tb->page_addr[0];
95759817ccbSbellard         if (vp->valid_tag != virt_valid_tag) {
9589fa3e853Sbellard             vp->valid_tag = virt_valid_tag;
95959817ccbSbellard #if !defined(CONFIG_SOFTMMU)
96059817ccbSbellard             vp->prot = 0;
96159817ccbSbellard #endif
96259817ccbSbellard         }
9639fa3e853Sbellard 
9649fa3e853Sbellard         if (tb->page_addr[1] != -1) {
9659fa3e853Sbellard             addr += TARGET_PAGE_SIZE;
9669fa3e853Sbellard             vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
96798857888Sbellard #ifdef DEBUG_TLB_CHECK
96898857888Sbellard             if (vp->valid_tag == virt_valid_tag &&
96998857888Sbellard                 vp->phys_addr != tb->page_addr[1]) {
97098857888Sbellard                 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
97198857888Sbellard                        addr, tb->page_addr[1], vp->phys_addr);
97298857888Sbellard             }
97398857888Sbellard #endif
9749fa3e853Sbellard             vp->phys_addr = tb->page_addr[1];
97559817ccbSbellard             if (vp->valid_tag != virt_valid_tag) {
9769fa3e853Sbellard                 vp->valid_tag = virt_valid_tag;
97759817ccbSbellard #if !defined(CONFIG_SOFTMMU)
97859817ccbSbellard                 vp->prot = 0;
97959817ccbSbellard #endif
98059817ccbSbellard             }
9819fa3e853Sbellard         }
9829fa3e853Sbellard     }
9839fa3e853Sbellard #endif
9849fa3e853Sbellard 
985d4e8164fSbellard     tb->jmp_first = (TranslationBlock *)((long)tb | 2);
986d4e8164fSbellard     tb->jmp_next[0] = NULL;
987d4e8164fSbellard     tb->jmp_next[1] = NULL;
988b448f2f3Sbellard #ifdef USE_CODE_COPY
989b448f2f3Sbellard     tb->cflags &= ~CF_FP_USED;
990b448f2f3Sbellard     if (tb->cflags & CF_TB_FP_USED)
991b448f2f3Sbellard         tb->cflags |= CF_FP_USED;
992b448f2f3Sbellard #endif
993d4e8164fSbellard 
994d4e8164fSbellard     /* init original jump addresses */
995d4e8164fSbellard     if (tb->tb_next_offset[0] != 0xffff)
996d4e8164fSbellard         tb_reset_jump(tb, 0);
997d4e8164fSbellard     if (tb->tb_next_offset[1] != 0xffff)
998d4e8164fSbellard         tb_reset_jump(tb, 1);
999fd6ce8f6Sbellard }
1000fd6ce8f6Sbellard 
1001a513fe19Sbellard /* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
1002a513fe19Sbellard    tb[1].tc_ptr. Return NULL if not found */
1003a513fe19Sbellard TranslationBlock *tb_find_pc(unsigned long tc_ptr)
1004a513fe19Sbellard {
1005a513fe19Sbellard     int m_min, m_max, m;
1006a513fe19Sbellard     unsigned long v;
1007a513fe19Sbellard     TranslationBlock *tb;
1008a513fe19Sbellard 
1009a513fe19Sbellard     if (nb_tbs <= 0)
1010a513fe19Sbellard         return NULL;
1011a513fe19Sbellard     if (tc_ptr < (unsigned long)code_gen_buffer ||
1012a513fe19Sbellard         tc_ptr >= (unsigned long)code_gen_ptr)
1013a513fe19Sbellard         return NULL;
1014a513fe19Sbellard     /* binary search (cf Knuth) */
1015a513fe19Sbellard     m_min = 0;
1016a513fe19Sbellard     m_max = nb_tbs - 1;
1017a513fe19Sbellard     while (m_min <= m_max) {
1018a513fe19Sbellard         m = (m_min + m_max) >> 1;
1019a513fe19Sbellard         tb = &tbs[m];
1020a513fe19Sbellard         v = (unsigned long)tb->tc_ptr;
1021a513fe19Sbellard         if (v == tc_ptr)
1022a513fe19Sbellard             return tb;
1023a513fe19Sbellard         else if (tc_ptr < v) {
1024a513fe19Sbellard             m_max = m - 1;
1025a513fe19Sbellard         } else {
1026a513fe19Sbellard             m_min = m + 1;
1027a513fe19Sbellard         }
1028a513fe19Sbellard     }
1029a513fe19Sbellard     return &tbs[m_max];
1030a513fe19Sbellard }
10317501267eSbellard 
1032ea041c0eSbellard static void tb_reset_jump_recursive(TranslationBlock *tb);
1033ea041c0eSbellard 
1034ea041c0eSbellard static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
1035ea041c0eSbellard {
1036ea041c0eSbellard     TranslationBlock *tb1, *tb_next, **ptb;
1037ea041c0eSbellard     unsigned int n1;
1038ea041c0eSbellard 
1039ea041c0eSbellard     tb1 = tb->jmp_next[n];
1040ea041c0eSbellard     if (tb1 != NULL) {
1041ea041c0eSbellard         /* find head of list */
1042ea041c0eSbellard         for(;;) {
1043ea041c0eSbellard             n1 = (long)tb1 & 3;
1044ea041c0eSbellard             tb1 = (TranslationBlock *)((long)tb1 & ~3);
1045ea041c0eSbellard             if (n1 == 2)
1046ea041c0eSbellard                 break;
1047ea041c0eSbellard             tb1 = tb1->jmp_next[n1];
1048ea041c0eSbellard         }
1049ea041c0eSbellard         /* we are now sure now that tb jumps to tb1 */
1050ea041c0eSbellard         tb_next = tb1;
1051ea041c0eSbellard 
1052ea041c0eSbellard         /* remove tb from the jmp_first list */
1053ea041c0eSbellard         ptb = &tb_next->jmp_first;
1054ea041c0eSbellard         for(;;) {
1055ea041c0eSbellard             tb1 = *ptb;
1056ea041c0eSbellard             n1 = (long)tb1 & 3;
1057ea041c0eSbellard             tb1 = (TranslationBlock *)((long)tb1 & ~3);
1058ea041c0eSbellard             if (n1 == n && tb1 == tb)
1059ea041c0eSbellard                 break;
1060ea041c0eSbellard             ptb = &tb1->jmp_next[n1];
1061ea041c0eSbellard         }
1062ea041c0eSbellard         *ptb = tb->jmp_next[n];
1063ea041c0eSbellard         tb->jmp_next[n] = NULL;
1064ea041c0eSbellard 
1065ea041c0eSbellard         /* suppress the jump to next tb in generated code */
1066ea041c0eSbellard         tb_reset_jump(tb, n);
1067ea041c0eSbellard 
10680124311eSbellard         /* suppress jumps in the tb on which we could have jumped */
1069ea041c0eSbellard         tb_reset_jump_recursive(tb_next);
1070ea041c0eSbellard     }
1071ea041c0eSbellard }
1072ea041c0eSbellard 
1073ea041c0eSbellard static void tb_reset_jump_recursive(TranslationBlock *tb)
1074ea041c0eSbellard {
1075ea041c0eSbellard     tb_reset_jump_recursive2(tb, 0);
1076ea041c0eSbellard     tb_reset_jump_recursive2(tb, 1);
1077ea041c0eSbellard }
1078ea041c0eSbellard 
1079c27004ecSbellard #if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
1080d720b93dSbellard static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1081d720b93dSbellard {
1082d720b93dSbellard     target_ulong phys_addr;
1083d720b93dSbellard 
1084d720b93dSbellard     phys_addr = cpu_get_phys_page_debug(env, pc);
1085d720b93dSbellard     tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
1086d720b93dSbellard }
1087c27004ecSbellard #endif
1088d720b93dSbellard 
1089c33a346eSbellard /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1090c33a346eSbellard    breakpoint is reached */
10912e12669aSbellard int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
10924c3a88a2Sbellard {
1093e95c8d51Sbellard #if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
10944c3a88a2Sbellard     int i;
10954c3a88a2Sbellard 
10964c3a88a2Sbellard     for(i = 0; i < env->nb_breakpoints; i++) {
10974c3a88a2Sbellard         if (env->breakpoints[i] == pc)
10984c3a88a2Sbellard             return 0;
10994c3a88a2Sbellard     }
11004c3a88a2Sbellard 
11014c3a88a2Sbellard     if (env->nb_breakpoints >= MAX_BREAKPOINTS)
11024c3a88a2Sbellard         return -1;
11034c3a88a2Sbellard     env->breakpoints[env->nb_breakpoints++] = pc;
1104d720b93dSbellard 
1105d720b93dSbellard     breakpoint_invalidate(env, pc);
11064c3a88a2Sbellard     return 0;
11074c3a88a2Sbellard #else
11084c3a88a2Sbellard     return -1;
11094c3a88a2Sbellard #endif
11104c3a88a2Sbellard }
11114c3a88a2Sbellard 
11124c3a88a2Sbellard /* remove a breakpoint */
11132e12669aSbellard int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
11144c3a88a2Sbellard {
1115e95c8d51Sbellard #if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
11164c3a88a2Sbellard     int i;
11174c3a88a2Sbellard     for(i = 0; i < env->nb_breakpoints; i++) {
11184c3a88a2Sbellard         if (env->breakpoints[i] == pc)
11194c3a88a2Sbellard             goto found;
11204c3a88a2Sbellard     }
11214c3a88a2Sbellard     return -1;
11224c3a88a2Sbellard  found:
11234c3a88a2Sbellard     memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
11244c3a88a2Sbellard             (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
11254c3a88a2Sbellard     env->nb_breakpoints--;
1126d720b93dSbellard 
1127d720b93dSbellard     breakpoint_invalidate(env, pc);
11284c3a88a2Sbellard     return 0;
11294c3a88a2Sbellard #else
11304c3a88a2Sbellard     return -1;
11314c3a88a2Sbellard #endif
11324c3a88a2Sbellard }
11334c3a88a2Sbellard 
1134c33a346eSbellard /* enable or disable single step mode. EXCP_DEBUG is returned by the
1135c33a346eSbellard    CPU loop after each instruction */
1136c33a346eSbellard void cpu_single_step(CPUState *env, int enabled)
1137c33a346eSbellard {
1138e95c8d51Sbellard #if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
1139c33a346eSbellard     if (env->singlestep_enabled != enabled) {
1140c33a346eSbellard         env->singlestep_enabled = enabled;
1141c33a346eSbellard         /* must flush all the translated code to avoid inconsistancies */
11429fa3e853Sbellard         /* XXX: only flush what is necessary */
11430124311eSbellard         tb_flush(env);
1144c33a346eSbellard     }
1145c33a346eSbellard #endif
1146c33a346eSbellard }
1147c33a346eSbellard 
114834865134Sbellard /* enable or disable low levels log */
114934865134Sbellard void cpu_set_log(int log_flags)
115034865134Sbellard {
115134865134Sbellard     loglevel = log_flags;
115234865134Sbellard     if (loglevel && !logfile) {
115334865134Sbellard         logfile = fopen(logfilename, "w");
115434865134Sbellard         if (!logfile) {
115534865134Sbellard             perror(logfilename);
115634865134Sbellard             _exit(1);
115734865134Sbellard         }
11589fa3e853Sbellard #if !defined(CONFIG_SOFTMMU)
11599fa3e853Sbellard         /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
11609fa3e853Sbellard         {
11619fa3e853Sbellard             static uint8_t logfile_buf[4096];
11629fa3e853Sbellard             setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
11639fa3e853Sbellard         }
11649fa3e853Sbellard #else
116534865134Sbellard         setvbuf(logfile, NULL, _IOLBF, 0);
11669fa3e853Sbellard #endif
116734865134Sbellard     }
116834865134Sbellard }
116934865134Sbellard 
117034865134Sbellard void cpu_set_log_filename(const char *filename)
117134865134Sbellard {
117234865134Sbellard     logfilename = strdup(filename);
117334865134Sbellard }
1174c33a346eSbellard 
11750124311eSbellard /* mask must never be zero, except for A20 change call */
117668a79315Sbellard void cpu_interrupt(CPUState *env, int mask)
1177ea041c0eSbellard {
1178ea041c0eSbellard     TranslationBlock *tb;
1179ee8b7021Sbellard     static int interrupt_lock;
1180ea041c0eSbellard 
118168a79315Sbellard     env->interrupt_request |= mask;
1182ea041c0eSbellard     /* if the cpu is currently executing code, we must unlink it and
1183ea041c0eSbellard        all the potentially executing TB */
1184ea041c0eSbellard     tb = env->current_tb;
1185ee8b7021Sbellard     if (tb && !testandset(&interrupt_lock)) {
1186ee8b7021Sbellard         env->current_tb = NULL;
1187ea041c0eSbellard         tb_reset_jump_recursive(tb);
1188ee8b7021Sbellard         interrupt_lock = 0;
1189ea041c0eSbellard     }
1190ea041c0eSbellard }
1191ea041c0eSbellard 
1192b54ad049Sbellard void cpu_reset_interrupt(CPUState *env, int mask)
1193b54ad049Sbellard {
1194b54ad049Sbellard     env->interrupt_request &= ~mask;
1195b54ad049Sbellard }
1196b54ad049Sbellard 
1197f193c797Sbellard CPULogItem cpu_log_items[] = {
1198f193c797Sbellard     { CPU_LOG_TB_OUT_ASM, "out_asm",
1199f193c797Sbellard       "show generated host assembly code for each compiled TB" },
1200f193c797Sbellard     { CPU_LOG_TB_IN_ASM, "in_asm",
1201f193c797Sbellard       "show target assembly code for each compiled TB" },
1202f193c797Sbellard     { CPU_LOG_TB_OP, "op",
1203f193c797Sbellard       "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1204f193c797Sbellard #ifdef TARGET_I386
1205f193c797Sbellard     { CPU_LOG_TB_OP_OPT, "op_opt",
1206f193c797Sbellard       "show micro ops after optimization for each compiled TB" },
1207f193c797Sbellard #endif
1208f193c797Sbellard     { CPU_LOG_INT, "int",
1209f193c797Sbellard       "show interrupts/exceptions in short format" },
1210f193c797Sbellard     { CPU_LOG_EXEC, "exec",
1211f193c797Sbellard       "show trace before each executed TB (lots of logs)" },
12129fddaa0cSbellard     { CPU_LOG_TB_CPU, "cpu",
12139fddaa0cSbellard       "show CPU state before bloc translation" },
1214f193c797Sbellard #ifdef TARGET_I386
1215f193c797Sbellard     { CPU_LOG_PCALL, "pcall",
1216f193c797Sbellard       "show protected mode far calls/returns/exceptions" },
1217f193c797Sbellard #endif
12188e3a9fd2Sbellard #ifdef DEBUG_IOPORT
1219fd872598Sbellard     { CPU_LOG_IOPORT, "ioport",
1220fd872598Sbellard       "show all i/o ports accesses" },
12218e3a9fd2Sbellard #endif
1222f193c797Sbellard     { 0, NULL, NULL },
1223f193c797Sbellard };
1224f193c797Sbellard 
1225f193c797Sbellard static int cmp1(const char *s1, int n, const char *s2)
1226f193c797Sbellard {
1227f193c797Sbellard     if (strlen(s2) != n)
1228f193c797Sbellard         return 0;
1229f193c797Sbellard     return memcmp(s1, s2, n) == 0;
1230f193c797Sbellard }
1231f193c797Sbellard 
1232f193c797Sbellard /* takes a comma separated list of log masks. Return 0 if error. */
1233f193c797Sbellard int cpu_str_to_log_mask(const char *str)
1234f193c797Sbellard {
1235f193c797Sbellard     CPULogItem *item;
1236f193c797Sbellard     int mask;
1237f193c797Sbellard     const char *p, *p1;
1238f193c797Sbellard 
1239f193c797Sbellard     p = str;
1240f193c797Sbellard     mask = 0;
1241f193c797Sbellard     for(;;) {
1242f193c797Sbellard         p1 = strchr(p, ',');
1243f193c797Sbellard         if (!p1)
1244f193c797Sbellard             p1 = p + strlen(p);
12458e3a9fd2Sbellard 	if(cmp1(p,p1-p,"all")) {
12468e3a9fd2Sbellard 		for(item = cpu_log_items; item->mask != 0; item++) {
12478e3a9fd2Sbellard 			mask |= item->mask;
12488e3a9fd2Sbellard 		}
12498e3a9fd2Sbellard 	} else {
1250f193c797Sbellard         for(item = cpu_log_items; item->mask != 0; item++) {
1251f193c797Sbellard             if (cmp1(p, p1 - p, item->name))
1252f193c797Sbellard                 goto found;
1253f193c797Sbellard         }
1254f193c797Sbellard         return 0;
12558e3a9fd2Sbellard 	}
1256f193c797Sbellard     found:
1257f193c797Sbellard         mask |= item->mask;
1258f193c797Sbellard         if (*p1 != ',')
1259f193c797Sbellard             break;
1260f193c797Sbellard         p = p1 + 1;
1261f193c797Sbellard     }
1262f193c797Sbellard     return mask;
1263f193c797Sbellard }
1264ea041c0eSbellard 
12657501267eSbellard void cpu_abort(CPUState *env, const char *fmt, ...)
12667501267eSbellard {
12677501267eSbellard     va_list ap;
12687501267eSbellard 
12697501267eSbellard     va_start(ap, fmt);
12707501267eSbellard     fprintf(stderr, "qemu: fatal: ");
12717501267eSbellard     vfprintf(stderr, fmt, ap);
12727501267eSbellard     fprintf(stderr, "\n");
12737501267eSbellard #ifdef TARGET_I386
12747fe48483Sbellard     cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
12757fe48483Sbellard #else
12767fe48483Sbellard     cpu_dump_state(env, stderr, fprintf, 0);
12777501267eSbellard #endif
12787501267eSbellard     va_end(ap);
12797501267eSbellard     abort();
12807501267eSbellard }
12817501267eSbellard 
12820124311eSbellard #if !defined(CONFIG_USER_ONLY)
12830124311eSbellard 
1284ee8b7021Sbellard /* NOTE: if flush_global is true, also flush global entries (not
1285ee8b7021Sbellard    implemented yet) */
1286ee8b7021Sbellard void tlb_flush(CPUState *env, int flush_global)
128733417e70Sbellard {
128833417e70Sbellard     int i;
12890124311eSbellard 
12909fa3e853Sbellard #if defined(DEBUG_TLB)
12919fa3e853Sbellard     printf("tlb_flush:\n");
12929fa3e853Sbellard #endif
12930124311eSbellard     /* must reset current TB so that interrupts cannot modify the
12940124311eSbellard        links while we are modifying them */
12950124311eSbellard     env->current_tb = NULL;
12960124311eSbellard 
129733417e70Sbellard     for(i = 0; i < CPU_TLB_SIZE; i++) {
129833417e70Sbellard         env->tlb_read[0][i].address = -1;
129933417e70Sbellard         env->tlb_write[0][i].address = -1;
130033417e70Sbellard         env->tlb_read[1][i].address = -1;
130133417e70Sbellard         env->tlb_write[1][i].address = -1;
130233417e70Sbellard     }
13039fa3e853Sbellard 
13049fa3e853Sbellard     virt_page_flush();
13058a8a608fSbellard     memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
13069fa3e853Sbellard 
13079fa3e853Sbellard #if !defined(CONFIG_SOFTMMU)
13089fa3e853Sbellard     munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
13099fa3e853Sbellard #endif
13100a962c02Sbellard #ifdef USE_KQEMU
13110a962c02Sbellard     if (env->kqemu_enabled) {
13120a962c02Sbellard         kqemu_flush(env, flush_global);
13130a962c02Sbellard     }
13140a962c02Sbellard #endif
1315e3db7226Sbellard     tlb_flush_count++;
131633417e70Sbellard }
131733417e70Sbellard 
1318274da6b2Sbellard static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
131961382a50Sbellard {
132061382a50Sbellard     if (addr == (tlb_entry->address &
132161382a50Sbellard                  (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
132261382a50Sbellard         tlb_entry->address = -1;
132361382a50Sbellard }
132461382a50Sbellard 
13252e12669aSbellard void tlb_flush_page(CPUState *env, target_ulong addr)
132633417e70Sbellard {
13279fa3e853Sbellard     int i, n;
13289fa3e853Sbellard     VirtPageDesc *vp;
13299fa3e853Sbellard     PageDesc *p;
13309fa3e853Sbellard     TranslationBlock *tb;
13310124311eSbellard 
13329fa3e853Sbellard #if defined(DEBUG_TLB)
13339fa3e853Sbellard     printf("tlb_flush_page: 0x%08x\n", addr);
13349fa3e853Sbellard #endif
13350124311eSbellard     /* must reset current TB so that interrupts cannot modify the
13360124311eSbellard        links while we are modifying them */
13370124311eSbellard     env->current_tb = NULL;
133833417e70Sbellard 
133961382a50Sbellard     addr &= TARGET_PAGE_MASK;
134033417e70Sbellard     i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
134161382a50Sbellard     tlb_flush_entry(&env->tlb_read[0][i], addr);
134261382a50Sbellard     tlb_flush_entry(&env->tlb_write[0][i], addr);
134361382a50Sbellard     tlb_flush_entry(&env->tlb_read[1][i], addr);
134461382a50Sbellard     tlb_flush_entry(&env->tlb_write[1][i], addr);
13450124311eSbellard 
13469fa3e853Sbellard     /* remove from the virtual pc hash table all the TB at this
13479fa3e853Sbellard        virtual address */
13489fa3e853Sbellard 
13499fa3e853Sbellard     vp = virt_page_find(addr >> TARGET_PAGE_BITS);
13509fa3e853Sbellard     if (vp && vp->valid_tag == virt_valid_tag) {
13519fa3e853Sbellard         p = page_find(vp->phys_addr >> TARGET_PAGE_BITS);
13529fa3e853Sbellard         if (p) {
13539fa3e853Sbellard             /* we remove all the links to the TBs in this virtual page */
13549fa3e853Sbellard             tb = p->first_tb;
13559fa3e853Sbellard             while (tb != NULL) {
13569fa3e853Sbellard                 n = (long)tb & 3;
13579fa3e853Sbellard                 tb = (TranslationBlock *)((long)tb & ~3);
13589fa3e853Sbellard                 if ((tb->pc & TARGET_PAGE_MASK) == addr ||
13599fa3e853Sbellard                     ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) {
13609fa3e853Sbellard                     tb_invalidate(tb);
13619fa3e853Sbellard                 }
13629fa3e853Sbellard                 tb = tb->page_next[n];
13639fa3e853Sbellard             }
13640124311eSbellard         }
136598857888Sbellard         vp->valid_tag = 0;
136661382a50Sbellard     }
136761382a50Sbellard 
13689fa3e853Sbellard #if !defined(CONFIG_SOFTMMU)
13699fa3e853Sbellard     if (addr < MMAP_AREA_END)
13709fa3e853Sbellard         munmap((void *)addr, TARGET_PAGE_SIZE);
13719fa3e853Sbellard #endif
13720a962c02Sbellard #ifdef USE_KQEMU
13730a962c02Sbellard     if (env->kqemu_enabled) {
13740a962c02Sbellard         kqemu_flush_page(env, addr);
13750a962c02Sbellard     }
13760a962c02Sbellard #endif
13779fa3e853Sbellard }
13789fa3e853Sbellard 
13794f2ac237Sbellard static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
13809fa3e853Sbellard {
13819fa3e853Sbellard     if (addr == (tlb_entry->address &
13829fa3e853Sbellard                  (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
138398857888Sbellard         (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE &&
138498857888Sbellard         (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
13851ccde1cbSbellard         tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_CODE;
13869fa3e853Sbellard     }
13879fa3e853Sbellard }
13889fa3e853Sbellard 
13899fa3e853Sbellard /* update the TLBs so that writes to code in the virtual page 'addr'
13909fa3e853Sbellard    can be detected */
13914f2ac237Sbellard static void tlb_protect_code(CPUState *env, target_ulong addr)
139261382a50Sbellard {
139361382a50Sbellard     int i;
139461382a50Sbellard 
139561382a50Sbellard     addr &= TARGET_PAGE_MASK;
139661382a50Sbellard     i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
13979fa3e853Sbellard     tlb_protect_code1(&env->tlb_write[0][i], addr);
13989fa3e853Sbellard     tlb_protect_code1(&env->tlb_write[1][i], addr);
13999fa3e853Sbellard #if !defined(CONFIG_SOFTMMU)
14009fa3e853Sbellard     /* NOTE: as we generated the code for this page, it is already at
14019fa3e853Sbellard        least readable */
14029fa3e853Sbellard     if (addr < MMAP_AREA_END)
14039fa3e853Sbellard         mprotect((void *)addr, TARGET_PAGE_SIZE, PROT_READ);
14049fa3e853Sbellard #endif
14059fa3e853Sbellard }
14069fa3e853Sbellard 
14079fa3e853Sbellard static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry,
14084f2ac237Sbellard                                        unsigned long phys_addr)
14099fa3e853Sbellard {
14109fa3e853Sbellard     if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE &&
14119fa3e853Sbellard         ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) {
14121ccde1cbSbellard         tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
14139fa3e853Sbellard     }
14149fa3e853Sbellard }
14159fa3e853Sbellard 
14169fa3e853Sbellard /* update the TLB so that writes in physical page 'phys_addr' are no longer
14179fa3e853Sbellard    tested self modifying code */
14184f2ac237Sbellard static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr)
14199fa3e853Sbellard {
14209fa3e853Sbellard     int i;
14219fa3e853Sbellard 
14229fa3e853Sbellard     phys_addr &= TARGET_PAGE_MASK;
14231ccde1cbSbellard     phys_addr += (long)phys_ram_base;
14241ccde1cbSbellard     i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
14259fa3e853Sbellard     tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr);
14269fa3e853Sbellard     tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr);
14279fa3e853Sbellard }
14289fa3e853Sbellard 
14291ccde1cbSbellard static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
14301ccde1cbSbellard                                          unsigned long start, unsigned long length)
14311ccde1cbSbellard {
14321ccde1cbSbellard     unsigned long addr;
14331ccde1cbSbellard     if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
14341ccde1cbSbellard         addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
14351ccde1cbSbellard         if ((addr - start) < length) {
14361ccde1cbSbellard             tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
14371ccde1cbSbellard         }
14381ccde1cbSbellard     }
14391ccde1cbSbellard }
14401ccde1cbSbellard 
14410a962c02Sbellard void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end,
14420a962c02Sbellard                                      int dirty_flags)
14431ccde1cbSbellard {
14441ccde1cbSbellard     CPUState *env;
14454f2ac237Sbellard     unsigned long length, start1;
14460a962c02Sbellard     int i, mask, len;
14470a962c02Sbellard     uint8_t *p;
14481ccde1cbSbellard 
14491ccde1cbSbellard     start &= TARGET_PAGE_MASK;
14501ccde1cbSbellard     end = TARGET_PAGE_ALIGN(end);
14511ccde1cbSbellard 
14521ccde1cbSbellard     length = end - start;
14531ccde1cbSbellard     if (length == 0)
14541ccde1cbSbellard         return;
14550a962c02Sbellard     mask = ~dirty_flags;
14560a962c02Sbellard     p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
14570a962c02Sbellard     len = length >> TARGET_PAGE_BITS;
14580a962c02Sbellard     for(i = 0; i < len; i++)
14590a962c02Sbellard         p[i] &= mask;
14601ccde1cbSbellard 
14611ccde1cbSbellard     env = cpu_single_env;
14621ccde1cbSbellard     /* we modify the TLB cache so that the dirty bit will be set again
14631ccde1cbSbellard        when accessing the range */
146459817ccbSbellard     start1 = start + (unsigned long)phys_ram_base;
14651ccde1cbSbellard     for(i = 0; i < CPU_TLB_SIZE; i++)
146659817ccbSbellard         tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
14671ccde1cbSbellard     for(i = 0; i < CPU_TLB_SIZE; i++)
146859817ccbSbellard         tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
146959817ccbSbellard 
147059817ccbSbellard #if !defined(CONFIG_SOFTMMU)
147159817ccbSbellard     /* XXX: this is expensive */
147259817ccbSbellard     {
147359817ccbSbellard         VirtPageDesc *p;
147459817ccbSbellard         int j;
147559817ccbSbellard         target_ulong addr;
147659817ccbSbellard 
147759817ccbSbellard         for(i = 0; i < L1_SIZE; i++) {
147859817ccbSbellard             p = l1_virt_map[i];
147959817ccbSbellard             if (p) {
148059817ccbSbellard                 addr = i << (TARGET_PAGE_BITS + L2_BITS);
148159817ccbSbellard                 for(j = 0; j < L2_SIZE; j++) {
148259817ccbSbellard                     if (p->valid_tag == virt_valid_tag &&
148359817ccbSbellard                         p->phys_addr >= start && p->phys_addr < end &&
148459817ccbSbellard                         (p->prot & PROT_WRITE)) {
148559817ccbSbellard                         if (addr < MMAP_AREA_END) {
148659817ccbSbellard                             mprotect((void *)addr, TARGET_PAGE_SIZE,
148759817ccbSbellard                                      p->prot & ~PROT_WRITE);
148859817ccbSbellard                         }
148959817ccbSbellard                     }
149059817ccbSbellard                     addr += TARGET_PAGE_SIZE;
149159817ccbSbellard                     p++;
149259817ccbSbellard                 }
149359817ccbSbellard             }
149459817ccbSbellard         }
149559817ccbSbellard     }
149659817ccbSbellard #endif
14971ccde1cbSbellard }
14981ccde1cbSbellard 
14991ccde1cbSbellard static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
15001ccde1cbSbellard                                     unsigned long start)
15011ccde1cbSbellard {
15021ccde1cbSbellard     unsigned long addr;
15031ccde1cbSbellard     if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
15041ccde1cbSbellard         addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
15051ccde1cbSbellard         if (addr == start) {
15061ccde1cbSbellard             tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
15071ccde1cbSbellard         }
15081ccde1cbSbellard     }
15091ccde1cbSbellard }
15101ccde1cbSbellard 
15111ccde1cbSbellard /* update the TLB corresponding to virtual page vaddr and phys addr
15121ccde1cbSbellard    addr so that it is no longer dirty */
15131ccde1cbSbellard static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
15141ccde1cbSbellard {
15151ccde1cbSbellard     CPUState *env = cpu_single_env;
15161ccde1cbSbellard     int i;
15171ccde1cbSbellard 
15180a962c02Sbellard     phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 0xff;
15191ccde1cbSbellard 
15201ccde1cbSbellard     addr &= TARGET_PAGE_MASK;
15211ccde1cbSbellard     i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
15221ccde1cbSbellard     tlb_set_dirty1(&env->tlb_write[0][i], addr);
15231ccde1cbSbellard     tlb_set_dirty1(&env->tlb_write[1][i], addr);
15241ccde1cbSbellard }
15251ccde1cbSbellard 
152659817ccbSbellard /* add a new TLB entry. At most one entry for a given virtual address
152759817ccbSbellard    is permitted. Return 0 if OK or 2 if the page could not be mapped
152859817ccbSbellard    (can only happen in non SOFTMMU mode for I/O pages or pages
152959817ccbSbellard    conflicting with the host address space). */
15302e12669aSbellard int tlb_set_page(CPUState *env, target_ulong vaddr,
15312e12669aSbellard                  target_phys_addr_t paddr, int prot,
15329fa3e853Sbellard                  int is_user, int is_softmmu)
15339fa3e853Sbellard {
153492e873b9Sbellard     PhysPageDesc *p;
15354f2ac237Sbellard     unsigned long pd;
15369fa3e853Sbellard     TranslationBlock *first_tb;
15379fa3e853Sbellard     unsigned int index;
15384f2ac237Sbellard     target_ulong address;
15394f2ac237Sbellard     unsigned long addend;
15409fa3e853Sbellard     int ret;
15419fa3e853Sbellard 
154292e873b9Sbellard     p = phys_page_find(paddr >> TARGET_PAGE_BITS);
154392e873b9Sbellard     first_tb = NULL;
15449fa3e853Sbellard     if (!p) {
15459fa3e853Sbellard         pd = IO_MEM_UNASSIGNED;
15469fa3e853Sbellard     } else {
154792e873b9Sbellard         PageDesc *p1;
15489fa3e853Sbellard         pd = p->phys_offset;
154992e873b9Sbellard         if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
155092e873b9Sbellard             /* NOTE: we also allocate the page at this stage */
155192e873b9Sbellard             p1 = page_find_alloc(pd >> TARGET_PAGE_BITS);
155292e873b9Sbellard             first_tb = p1->first_tb;
155392e873b9Sbellard         }
15549fa3e853Sbellard     }
15559fa3e853Sbellard #if defined(DEBUG_TLB)
15569fa3e853Sbellard     printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
15579fa3e853Sbellard            vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd);
15589fa3e853Sbellard #endif
15599fa3e853Sbellard 
15609fa3e853Sbellard     ret = 0;
15619fa3e853Sbellard #if !defined(CONFIG_SOFTMMU)
15629fa3e853Sbellard     if (is_softmmu)
15639fa3e853Sbellard #endif
15649fa3e853Sbellard     {
15659fa3e853Sbellard         if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
15669fa3e853Sbellard             /* IO memory case */
15679fa3e853Sbellard             address = vaddr | pd;
15689fa3e853Sbellard             addend = paddr;
15699fa3e853Sbellard         } else {
15709fa3e853Sbellard             /* standard memory */
15719fa3e853Sbellard             address = vaddr;
15729fa3e853Sbellard             addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
15739fa3e853Sbellard         }
15749fa3e853Sbellard 
15759fa3e853Sbellard         index = (vaddr >> 12) & (CPU_TLB_SIZE - 1);
15769fa3e853Sbellard         addend -= vaddr;
157767b915a5Sbellard         if (prot & PAGE_READ) {
15789fa3e853Sbellard             env->tlb_read[is_user][index].address = address;
15799fa3e853Sbellard             env->tlb_read[is_user][index].addend = addend;
15809fa3e853Sbellard         } else {
15819fa3e853Sbellard             env->tlb_read[is_user][index].address = -1;
15829fa3e853Sbellard             env->tlb_read[is_user][index].addend = -1;
15839fa3e853Sbellard         }
158467b915a5Sbellard         if (prot & PAGE_WRITE) {
15859fa3e853Sbellard             if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
15869fa3e853Sbellard                 /* ROM: access is ignored (same as unassigned) */
15879fa3e853Sbellard                 env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
15881ccde1cbSbellard                 env->tlb_write[is_user][index].addend = addend;
1589d720b93dSbellard             } else
1590d720b93dSbellard                 /* XXX: the PowerPC code seems not ready to handle
1591d720b93dSbellard                    self modifying code with DCBI */
1592d720b93dSbellard #if defined(TARGET_HAS_SMC) || 1
1593d720b93dSbellard             if (first_tb) {
15949fa3e853Sbellard                 /* if code is present, we use a specific memory
15959fa3e853Sbellard                    handler. It works only for physical memory access */
15969fa3e853Sbellard                 env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE;
15971ccde1cbSbellard                 env->tlb_write[is_user][index].addend = addend;
1598d720b93dSbellard             } else
1599d720b93dSbellard #endif
1600d720b93dSbellard             if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
16011ccde1cbSbellard                        !cpu_physical_memory_is_dirty(pd)) {
16021ccde1cbSbellard                 env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
16031ccde1cbSbellard                 env->tlb_write[is_user][index].addend = addend;
16049fa3e853Sbellard             } else {
16059fa3e853Sbellard                 env->tlb_write[is_user][index].address = address;
16069fa3e853Sbellard                 env->tlb_write[is_user][index].addend = addend;
16079fa3e853Sbellard             }
16089fa3e853Sbellard         } else {
16099fa3e853Sbellard             env->tlb_write[is_user][index].address = -1;
16109fa3e853Sbellard             env->tlb_write[is_user][index].addend = -1;
16119fa3e853Sbellard         }
16129fa3e853Sbellard     }
16139fa3e853Sbellard #if !defined(CONFIG_SOFTMMU)
16149fa3e853Sbellard     else {
16159fa3e853Sbellard         if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
16169fa3e853Sbellard             /* IO access: no mapping is done as it will be handled by the
16179fa3e853Sbellard                soft MMU */
16189fa3e853Sbellard             if (!(env->hflags & HF_SOFTMMU_MASK))
16199fa3e853Sbellard                 ret = 2;
16209fa3e853Sbellard         } else {
16219fa3e853Sbellard             void *map_addr;
162259817ccbSbellard 
162359817ccbSbellard             if (vaddr >= MMAP_AREA_END) {
162459817ccbSbellard                 ret = 2;
162559817ccbSbellard             } else {
16269fa3e853Sbellard                 if (prot & PROT_WRITE) {
162759817ccbSbellard                     if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
1628d720b93dSbellard #if defined(TARGET_HAS_SMC) || 1
162959817ccbSbellard                         first_tb ||
1630d720b93dSbellard #endif
163159817ccbSbellard                         ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
163259817ccbSbellard                          !cpu_physical_memory_is_dirty(pd))) {
16339fa3e853Sbellard                         /* ROM: we do as if code was inside */
16349fa3e853Sbellard                         /* if code is present, we only map as read only and save the
16359fa3e853Sbellard                            original mapping */
16369fa3e853Sbellard                         VirtPageDesc *vp;
16379fa3e853Sbellard 
16389fa3e853Sbellard                         vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS);
16399fa3e853Sbellard                         vp->phys_addr = pd;
16409fa3e853Sbellard                         vp->prot = prot;
16419fa3e853Sbellard                         vp->valid_tag = virt_valid_tag;
16429fa3e853Sbellard                         prot &= ~PAGE_WRITE;
16439fa3e853Sbellard                     }
16449fa3e853Sbellard                 }
16459fa3e853Sbellard                 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
16469fa3e853Sbellard                                 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
16479fa3e853Sbellard                 if (map_addr == MAP_FAILED) {
16489fa3e853Sbellard                     cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
16499fa3e853Sbellard                               paddr, vaddr);
16509fa3e853Sbellard                 }
16519fa3e853Sbellard             }
16529fa3e853Sbellard         }
165359817ccbSbellard     }
16549fa3e853Sbellard #endif
16559fa3e853Sbellard     return ret;
16569fa3e853Sbellard }
16579fa3e853Sbellard 
16589fa3e853Sbellard /* called from signal handler: invalidate the code and unprotect the
16599fa3e853Sbellard    page. Return TRUE if the fault was succesfully handled. */
1660d720b93dSbellard int page_unprotect(unsigned long addr, unsigned long pc, void *puc)
16619fa3e853Sbellard {
16629fa3e853Sbellard #if !defined(CONFIG_SOFTMMU)
16639fa3e853Sbellard     VirtPageDesc *vp;
16649fa3e853Sbellard 
16659fa3e853Sbellard #if defined(DEBUG_TLB)
16669fa3e853Sbellard     printf("page_unprotect: addr=0x%08x\n", addr);
16679fa3e853Sbellard #endif
16689fa3e853Sbellard     addr &= TARGET_PAGE_MASK;
166959817ccbSbellard 
167059817ccbSbellard     /* if it is not mapped, no need to worry here */
167159817ccbSbellard     if (addr >= MMAP_AREA_END)
167259817ccbSbellard         return 0;
16739fa3e853Sbellard     vp = virt_page_find(addr >> TARGET_PAGE_BITS);
16749fa3e853Sbellard     if (!vp)
16759fa3e853Sbellard         return 0;
16769fa3e853Sbellard     /* NOTE: in this case, validate_tag is _not_ tested as it
16779fa3e853Sbellard        validates only the code TLB */
16789fa3e853Sbellard     if (vp->valid_tag != virt_valid_tag)
16799fa3e853Sbellard         return 0;
16809fa3e853Sbellard     if (!(vp->prot & PAGE_WRITE))
16819fa3e853Sbellard         return 0;
16829fa3e853Sbellard #if defined(DEBUG_TLB)
16839fa3e853Sbellard     printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
16849fa3e853Sbellard            addr, vp->phys_addr, vp->prot);
16859fa3e853Sbellard #endif
168659817ccbSbellard     if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
168759817ccbSbellard         cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
168859817ccbSbellard                   (unsigned long)addr, vp->prot);
1689d720b93dSbellard     /* set the dirty bit */
16900a962c02Sbellard     phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
1691d720b93dSbellard     /* flush the code inside */
1692d720b93dSbellard     tb_invalidate_phys_page(vp->phys_addr, pc, puc);
16939fa3e853Sbellard     return 1;
16949fa3e853Sbellard #else
16959fa3e853Sbellard     return 0;
16969fa3e853Sbellard #endif
169733417e70Sbellard }
169833417e70Sbellard 
16990124311eSbellard #else
17000124311eSbellard 
1701ee8b7021Sbellard void tlb_flush(CPUState *env, int flush_global)
17020124311eSbellard {
17030124311eSbellard }
17040124311eSbellard 
17052e12669aSbellard void tlb_flush_page(CPUState *env, target_ulong addr)
17060124311eSbellard {
17070124311eSbellard }
17080124311eSbellard 
17092e12669aSbellard int tlb_set_page(CPUState *env, target_ulong vaddr,
17102e12669aSbellard                  target_phys_addr_t paddr, int prot,
17119fa3e853Sbellard                  int is_user, int is_softmmu)
171233417e70Sbellard {
17139fa3e853Sbellard     return 0;
171433417e70Sbellard }
171533417e70Sbellard 
17169fa3e853Sbellard /* dump memory mappings */
17179fa3e853Sbellard void page_dump(FILE *f)
171833417e70Sbellard {
17199fa3e853Sbellard     unsigned long start, end;
17209fa3e853Sbellard     int i, j, prot, prot1;
17219fa3e853Sbellard     PageDesc *p;
17229fa3e853Sbellard 
17239fa3e853Sbellard     fprintf(f, "%-8s %-8s %-8s %s\n",
17249fa3e853Sbellard             "start", "end", "size", "prot");
17259fa3e853Sbellard     start = -1;
17269fa3e853Sbellard     end = -1;
17279fa3e853Sbellard     prot = 0;
17289fa3e853Sbellard     for(i = 0; i <= L1_SIZE; i++) {
17299fa3e853Sbellard         if (i < L1_SIZE)
17309fa3e853Sbellard             p = l1_map[i];
17319fa3e853Sbellard         else
17329fa3e853Sbellard             p = NULL;
17339fa3e853Sbellard         for(j = 0;j < L2_SIZE; j++) {
173433417e70Sbellard             if (!p)
17359fa3e853Sbellard                 prot1 = 0;
17369fa3e853Sbellard             else
17379fa3e853Sbellard                 prot1 = p[j].flags;
17389fa3e853Sbellard             if (prot1 != prot) {
17399fa3e853Sbellard                 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
17409fa3e853Sbellard                 if (start != -1) {
17419fa3e853Sbellard                     fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
17429fa3e853Sbellard                             start, end, end - start,
17439fa3e853Sbellard                             prot & PAGE_READ ? 'r' : '-',
17449fa3e853Sbellard                             prot & PAGE_WRITE ? 'w' : '-',
17459fa3e853Sbellard                             prot & PAGE_EXEC ? 'x' : '-');
174633417e70Sbellard                 }
17479fa3e853Sbellard                 if (prot1 != 0)
17489fa3e853Sbellard                     start = end;
17499fa3e853Sbellard                 else
17509fa3e853Sbellard                     start = -1;
17519fa3e853Sbellard                 prot = prot1;
17529fa3e853Sbellard             }
17539fa3e853Sbellard             if (!p)
17549fa3e853Sbellard                 break;
17559fa3e853Sbellard         }
17569fa3e853Sbellard     }
17579fa3e853Sbellard }
17589fa3e853Sbellard 
17599fa3e853Sbellard int page_get_flags(unsigned long address)
17609fa3e853Sbellard {
17619fa3e853Sbellard     PageDesc *p;
17629fa3e853Sbellard 
17639fa3e853Sbellard     p = page_find(address >> TARGET_PAGE_BITS);
17649fa3e853Sbellard     if (!p)
17659fa3e853Sbellard         return 0;
17669fa3e853Sbellard     return p->flags;
17679fa3e853Sbellard }
17689fa3e853Sbellard 
17699fa3e853Sbellard /* modify the flags of a page and invalidate the code if
17709fa3e853Sbellard    necessary. The flag PAGE_WRITE_ORG is positionned automatically
17719fa3e853Sbellard    depending on PAGE_WRITE */
17729fa3e853Sbellard void page_set_flags(unsigned long start, unsigned long end, int flags)
17739fa3e853Sbellard {
17749fa3e853Sbellard     PageDesc *p;
17759fa3e853Sbellard     unsigned long addr;
17769fa3e853Sbellard 
17779fa3e853Sbellard     start = start & TARGET_PAGE_MASK;
17789fa3e853Sbellard     end = TARGET_PAGE_ALIGN(end);
17799fa3e853Sbellard     if (flags & PAGE_WRITE)
17809fa3e853Sbellard         flags |= PAGE_WRITE_ORG;
17819fa3e853Sbellard     spin_lock(&tb_lock);
17829fa3e853Sbellard     for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
17839fa3e853Sbellard         p = page_find_alloc(addr >> TARGET_PAGE_BITS);
17849fa3e853Sbellard         /* if the write protection is set, then we invalidate the code
17859fa3e853Sbellard            inside */
17869fa3e853Sbellard         if (!(p->flags & PAGE_WRITE) &&
17879fa3e853Sbellard             (flags & PAGE_WRITE) &&
17889fa3e853Sbellard             p->first_tb) {
1789d720b93dSbellard             tb_invalidate_phys_page(addr, 0, NULL);
17909fa3e853Sbellard         }
17919fa3e853Sbellard         p->flags = flags;
17929fa3e853Sbellard     }
17939fa3e853Sbellard     spin_unlock(&tb_lock);
17949fa3e853Sbellard }
17959fa3e853Sbellard 
17969fa3e853Sbellard /* called from signal handler: invalidate the code and unprotect the
17979fa3e853Sbellard    page. Return TRUE if the fault was succesfully handled. */
1798d720b93dSbellard int page_unprotect(unsigned long address, unsigned long pc, void *puc)
17999fa3e853Sbellard {
18009fa3e853Sbellard     unsigned int page_index, prot, pindex;
18019fa3e853Sbellard     PageDesc *p, *p1;
18029fa3e853Sbellard     unsigned long host_start, host_end, addr;
18039fa3e853Sbellard 
180483fb7adfSbellard     host_start = address & qemu_host_page_mask;
18059fa3e853Sbellard     page_index = host_start >> TARGET_PAGE_BITS;
18069fa3e853Sbellard     p1 = page_find(page_index);
18079fa3e853Sbellard     if (!p1)
18089fa3e853Sbellard         return 0;
180983fb7adfSbellard     host_end = host_start + qemu_host_page_size;
18109fa3e853Sbellard     p = p1;
18119fa3e853Sbellard     prot = 0;
18129fa3e853Sbellard     for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
18139fa3e853Sbellard         prot |= p->flags;
18149fa3e853Sbellard         p++;
18159fa3e853Sbellard     }
18169fa3e853Sbellard     /* if the page was really writable, then we change its
18179fa3e853Sbellard        protection back to writable */
18189fa3e853Sbellard     if (prot & PAGE_WRITE_ORG) {
18199fa3e853Sbellard         pindex = (address - host_start) >> TARGET_PAGE_BITS;
18209fa3e853Sbellard         if (!(p1[pindex].flags & PAGE_WRITE)) {
182183fb7adfSbellard             mprotect((void *)host_start, qemu_host_page_size,
18229fa3e853Sbellard                      (prot & PAGE_BITS) | PAGE_WRITE);
18239fa3e853Sbellard             p1[pindex].flags |= PAGE_WRITE;
18249fa3e853Sbellard             /* and since the content will be modified, we must invalidate
18259fa3e853Sbellard                the corresponding translated code. */
1826d720b93dSbellard             tb_invalidate_phys_page(address, pc, puc);
18279fa3e853Sbellard #ifdef DEBUG_TB_CHECK
18289fa3e853Sbellard             tb_invalidate_check(address);
18299fa3e853Sbellard #endif
18309fa3e853Sbellard             return 1;
18319fa3e853Sbellard         }
18329fa3e853Sbellard     }
18339fa3e853Sbellard     return 0;
18349fa3e853Sbellard }
18359fa3e853Sbellard 
18369fa3e853Sbellard /* call this function when system calls directly modify a memory area */
18379fa3e853Sbellard void page_unprotect_range(uint8_t *data, unsigned long data_size)
18389fa3e853Sbellard {
18399fa3e853Sbellard     unsigned long start, end, addr;
18409fa3e853Sbellard 
18419fa3e853Sbellard     start = (unsigned long)data;
18429fa3e853Sbellard     end = start + data_size;
18439fa3e853Sbellard     start &= TARGET_PAGE_MASK;
18449fa3e853Sbellard     end = TARGET_PAGE_ALIGN(end);
18459fa3e853Sbellard     for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1846d720b93dSbellard         page_unprotect(addr, 0, NULL);
18479fa3e853Sbellard     }
18489fa3e853Sbellard }
18499fa3e853Sbellard 
18501ccde1cbSbellard static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
18511ccde1cbSbellard {
18521ccde1cbSbellard }
18539fa3e853Sbellard #endif /* defined(CONFIG_USER_ONLY) */
185433417e70Sbellard 
185533417e70Sbellard /* register physical memory. 'size' must be a multiple of the target
185633417e70Sbellard    page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
185733417e70Sbellard    io memory page */
18582e12669aSbellard void cpu_register_physical_memory(target_phys_addr_t start_addr,
18592e12669aSbellard                                   unsigned long size,
18602e12669aSbellard                                   unsigned long phys_offset)
186133417e70Sbellard {
186233417e70Sbellard     unsigned long addr, end_addr;
186392e873b9Sbellard     PhysPageDesc *p;
186433417e70Sbellard 
18655fd386f6Sbellard     size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
186633417e70Sbellard     end_addr = start_addr + size;
18675fd386f6Sbellard     for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
186892e873b9Sbellard         p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS);
18699fa3e853Sbellard         p->phys_offset = phys_offset;
18709fa3e853Sbellard         if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
187133417e70Sbellard             phys_offset += TARGET_PAGE_SIZE;
187233417e70Sbellard     }
187333417e70Sbellard }
187433417e70Sbellard 
1875a4193c8aSbellard static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
187633417e70Sbellard {
187733417e70Sbellard     return 0;
187833417e70Sbellard }
187933417e70Sbellard 
1880a4193c8aSbellard static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
188133417e70Sbellard {
188233417e70Sbellard }
188333417e70Sbellard 
188433417e70Sbellard static CPUReadMemoryFunc *unassigned_mem_read[3] = {
188533417e70Sbellard     unassigned_mem_readb,
188633417e70Sbellard     unassigned_mem_readb,
188733417e70Sbellard     unassigned_mem_readb,
188833417e70Sbellard };
188933417e70Sbellard 
189033417e70Sbellard static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
189133417e70Sbellard     unassigned_mem_writeb,
189233417e70Sbellard     unassigned_mem_writeb,
189333417e70Sbellard     unassigned_mem_writeb,
189433417e70Sbellard };
189533417e70Sbellard 
18969fa3e853Sbellard /* self modifying code support in soft mmu mode : writing to a page
18979fa3e853Sbellard    containing code comes to these functions */
18989fa3e853Sbellard 
1899a4193c8aSbellard static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
19009fa3e853Sbellard {
19011ccde1cbSbellard     unsigned long phys_addr;
19021ccde1cbSbellard 
1903274da6b2Sbellard     phys_addr = addr - (unsigned long)phys_ram_base;
19049fa3e853Sbellard #if !defined(CONFIG_USER_ONLY)
1905d720b93dSbellard     tb_invalidate_phys_page_fast(phys_addr, 1);
19069fa3e853Sbellard #endif
1907c27004ecSbellard     stb_p((uint8_t *)(long)addr, val);
19080a962c02Sbellard     phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
19099fa3e853Sbellard }
19109fa3e853Sbellard 
1911a4193c8aSbellard static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
19129fa3e853Sbellard {
19131ccde1cbSbellard     unsigned long phys_addr;
19141ccde1cbSbellard 
1915274da6b2Sbellard     phys_addr = addr - (unsigned long)phys_ram_base;
19169fa3e853Sbellard #if !defined(CONFIG_USER_ONLY)
1917d720b93dSbellard     tb_invalidate_phys_page_fast(phys_addr, 2);
19189fa3e853Sbellard #endif
1919c27004ecSbellard     stw_p((uint8_t *)(long)addr, val);
19200a962c02Sbellard     phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
19219fa3e853Sbellard }
19229fa3e853Sbellard 
1923a4193c8aSbellard static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
19249fa3e853Sbellard {
19251ccde1cbSbellard     unsigned long phys_addr;
19261ccde1cbSbellard 
1927274da6b2Sbellard     phys_addr = addr - (unsigned long)phys_ram_base;
19289fa3e853Sbellard #if !defined(CONFIG_USER_ONLY)
1929d720b93dSbellard     tb_invalidate_phys_page_fast(phys_addr, 4);
19309fa3e853Sbellard #endif
1931c27004ecSbellard     stl_p((uint8_t *)(long)addr, val);
19320a962c02Sbellard     phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff;
19339fa3e853Sbellard }
19349fa3e853Sbellard 
19359fa3e853Sbellard static CPUReadMemoryFunc *code_mem_read[3] = {
19369fa3e853Sbellard     NULL, /* never used */
19379fa3e853Sbellard     NULL, /* never used */
19389fa3e853Sbellard     NULL, /* never used */
19399fa3e853Sbellard };
19409fa3e853Sbellard 
19419fa3e853Sbellard static CPUWriteMemoryFunc *code_mem_write[3] = {
19429fa3e853Sbellard     code_mem_writeb,
19439fa3e853Sbellard     code_mem_writew,
19449fa3e853Sbellard     code_mem_writel,
19459fa3e853Sbellard };
194633417e70Sbellard 
1947a4193c8aSbellard static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
19481ccde1cbSbellard {
1949c27004ecSbellard     stb_p((uint8_t *)(long)addr, val);
1950d720b93dSbellard     tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
19511ccde1cbSbellard }
19521ccde1cbSbellard 
1953a4193c8aSbellard static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
19541ccde1cbSbellard {
1955c27004ecSbellard     stw_p((uint8_t *)(long)addr, val);
1956d720b93dSbellard     tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
19571ccde1cbSbellard }
19581ccde1cbSbellard 
1959a4193c8aSbellard static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
19601ccde1cbSbellard {
1961c27004ecSbellard     stl_p((uint8_t *)(long)addr, val);
1962d720b93dSbellard     tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
19631ccde1cbSbellard }
19641ccde1cbSbellard 
19651ccde1cbSbellard static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
19661ccde1cbSbellard     notdirty_mem_writeb,
19671ccde1cbSbellard     notdirty_mem_writew,
19681ccde1cbSbellard     notdirty_mem_writel,
19691ccde1cbSbellard };
19701ccde1cbSbellard 
197133417e70Sbellard static void io_mem_init(void)
197233417e70Sbellard {
1973a4193c8aSbellard     cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write, NULL);
1974a4193c8aSbellard     cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
1975a4193c8aSbellard     cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write, NULL);
1976a4193c8aSbellard     cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write, NULL);
19771ccde1cbSbellard     io_mem_nb = 5;
19781ccde1cbSbellard 
19791ccde1cbSbellard     /* alloc dirty bits array */
19800a962c02Sbellard     phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
198133417e70Sbellard }
198233417e70Sbellard 
198333417e70Sbellard /* mem_read and mem_write are arrays of functions containing the
198433417e70Sbellard    function to access byte (index 0), word (index 1) and dword (index
198533417e70Sbellard    2). All functions must be supplied. If io_index is non zero, the
198633417e70Sbellard    corresponding io zone is modified. If it is zero, a new io zone is
198733417e70Sbellard    allocated. The return value can be used with
198833417e70Sbellard    cpu_register_physical_memory(). (-1) is returned if error. */
198933417e70Sbellard int cpu_register_io_memory(int io_index,
199033417e70Sbellard                            CPUReadMemoryFunc **mem_read,
1991a4193c8aSbellard                            CPUWriteMemoryFunc **mem_write,
1992a4193c8aSbellard                            void *opaque)
199333417e70Sbellard {
199433417e70Sbellard     int i;
199533417e70Sbellard 
199633417e70Sbellard     if (io_index <= 0) {
199733417e70Sbellard         if (io_index >= IO_MEM_NB_ENTRIES)
199833417e70Sbellard             return -1;
199933417e70Sbellard         io_index = io_mem_nb++;
200033417e70Sbellard     } else {
200133417e70Sbellard         if (io_index >= IO_MEM_NB_ENTRIES)
200233417e70Sbellard             return -1;
200333417e70Sbellard     }
200433417e70Sbellard 
200533417e70Sbellard     for(i = 0;i < 3; i++) {
200633417e70Sbellard         io_mem_read[io_index][i] = mem_read[i];
200733417e70Sbellard         io_mem_write[io_index][i] = mem_write[i];
200833417e70Sbellard     }
2009a4193c8aSbellard     io_mem_opaque[io_index] = opaque;
201033417e70Sbellard     return io_index << IO_MEM_SHIFT;
201133417e70Sbellard }
201261382a50Sbellard 
20138926b517Sbellard CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
20148926b517Sbellard {
20158926b517Sbellard     return io_mem_write[io_index >> IO_MEM_SHIFT];
20168926b517Sbellard }
20178926b517Sbellard 
20188926b517Sbellard CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
20198926b517Sbellard {
20208926b517Sbellard     return io_mem_read[io_index >> IO_MEM_SHIFT];
20218926b517Sbellard }
20228926b517Sbellard 
202313eb76e0Sbellard /* physical memory access (slow version, mainly for debug) */
202413eb76e0Sbellard #if defined(CONFIG_USER_ONLY)
20252e12669aSbellard void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
202613eb76e0Sbellard                             int len, int is_write)
202713eb76e0Sbellard {
202813eb76e0Sbellard     int l, flags;
202913eb76e0Sbellard     target_ulong page;
203013eb76e0Sbellard 
203113eb76e0Sbellard     while (len > 0) {
203213eb76e0Sbellard         page = addr & TARGET_PAGE_MASK;
203313eb76e0Sbellard         l = (page + TARGET_PAGE_SIZE) - addr;
203413eb76e0Sbellard         if (l > len)
203513eb76e0Sbellard             l = len;
203613eb76e0Sbellard         flags = page_get_flags(page);
203713eb76e0Sbellard         if (!(flags & PAGE_VALID))
203813eb76e0Sbellard             return;
203913eb76e0Sbellard         if (is_write) {
204013eb76e0Sbellard             if (!(flags & PAGE_WRITE))
204113eb76e0Sbellard                 return;
204213eb76e0Sbellard             memcpy((uint8_t *)addr, buf, len);
204313eb76e0Sbellard         } else {
204413eb76e0Sbellard             if (!(flags & PAGE_READ))
204513eb76e0Sbellard                 return;
204613eb76e0Sbellard             memcpy(buf, (uint8_t *)addr, len);
204713eb76e0Sbellard         }
204813eb76e0Sbellard         len -= l;
204913eb76e0Sbellard         buf += l;
205013eb76e0Sbellard         addr += l;
205113eb76e0Sbellard     }
205213eb76e0Sbellard }
20538df1cd07Sbellard 
20548df1cd07Sbellard /* never used */
20558df1cd07Sbellard uint32_t ldl_phys(target_phys_addr_t addr)
20568df1cd07Sbellard {
20578df1cd07Sbellard     return 0;
20588df1cd07Sbellard }
20598df1cd07Sbellard 
20608df1cd07Sbellard void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
20618df1cd07Sbellard {
20628df1cd07Sbellard }
20638df1cd07Sbellard 
20648df1cd07Sbellard void stl_phys(target_phys_addr_t addr, uint32_t val)
20658df1cd07Sbellard {
20668df1cd07Sbellard }
20678df1cd07Sbellard 
206813eb76e0Sbellard #else
20692e12669aSbellard void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
207013eb76e0Sbellard                             int len, int is_write)
207113eb76e0Sbellard {
207213eb76e0Sbellard     int l, io_index;
207313eb76e0Sbellard     uint8_t *ptr;
207413eb76e0Sbellard     uint32_t val;
20752e12669aSbellard     target_phys_addr_t page;
20762e12669aSbellard     unsigned long pd;
207792e873b9Sbellard     PhysPageDesc *p;
207813eb76e0Sbellard 
207913eb76e0Sbellard     while (len > 0) {
208013eb76e0Sbellard         page = addr & TARGET_PAGE_MASK;
208113eb76e0Sbellard         l = (page + TARGET_PAGE_SIZE) - addr;
208213eb76e0Sbellard         if (l > len)
208313eb76e0Sbellard             l = len;
208492e873b9Sbellard         p = phys_page_find(page >> TARGET_PAGE_BITS);
208513eb76e0Sbellard         if (!p) {
208613eb76e0Sbellard             pd = IO_MEM_UNASSIGNED;
208713eb76e0Sbellard         } else {
208813eb76e0Sbellard             pd = p->phys_offset;
208913eb76e0Sbellard         }
209013eb76e0Sbellard 
209113eb76e0Sbellard         if (is_write) {
209213eb76e0Sbellard             if ((pd & ~TARGET_PAGE_MASK) != 0) {
209313eb76e0Sbellard                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
209413eb76e0Sbellard                 if (l >= 4 && ((addr & 3) == 0)) {
209513eb76e0Sbellard                     /* 32 bit read access */
2096c27004ecSbellard                     val = ldl_p(buf);
2097a4193c8aSbellard                     io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
209813eb76e0Sbellard                     l = 4;
209913eb76e0Sbellard                 } else if (l >= 2 && ((addr & 1) == 0)) {
210013eb76e0Sbellard                     /* 16 bit read access */
2101c27004ecSbellard                     val = lduw_p(buf);
2102a4193c8aSbellard                     io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
210313eb76e0Sbellard                     l = 2;
210413eb76e0Sbellard                 } else {
210513eb76e0Sbellard                     /* 8 bit access */
2106c27004ecSbellard                     val = ldub_p(buf);
2107a4193c8aSbellard                     io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
210813eb76e0Sbellard                     l = 1;
210913eb76e0Sbellard                 }
211013eb76e0Sbellard             } else {
2111b448f2f3Sbellard                 unsigned long addr1;
2112b448f2f3Sbellard                 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
211313eb76e0Sbellard                 /* RAM case */
2114b448f2f3Sbellard                 ptr = phys_ram_base + addr1;
211513eb76e0Sbellard                 memcpy(ptr, buf, l);
2116b448f2f3Sbellard                 /* invalidate code */
2117b448f2f3Sbellard                 tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2118b448f2f3Sbellard                 /* set dirty bit */
21190a962c02Sbellard                 phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff;
212013eb76e0Sbellard             }
212113eb76e0Sbellard         } else {
212213eb76e0Sbellard             if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
212313eb76e0Sbellard                 (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
212413eb76e0Sbellard                 /* I/O case */
212513eb76e0Sbellard                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
212613eb76e0Sbellard                 if (l >= 4 && ((addr & 3) == 0)) {
212713eb76e0Sbellard                     /* 32 bit read access */
2128a4193c8aSbellard                     val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2129c27004ecSbellard                     stl_p(buf, val);
213013eb76e0Sbellard                     l = 4;
213113eb76e0Sbellard                 } else if (l >= 2 && ((addr & 1) == 0)) {
213213eb76e0Sbellard                     /* 16 bit read access */
2133a4193c8aSbellard                     val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
2134c27004ecSbellard                     stw_p(buf, val);
213513eb76e0Sbellard                     l = 2;
213613eb76e0Sbellard                 } else {
213713eb76e0Sbellard                     /* 8 bit access */
2138a4193c8aSbellard                     val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
2139c27004ecSbellard                     stb_p(buf, val);
214013eb76e0Sbellard                     l = 1;
214113eb76e0Sbellard                 }
214213eb76e0Sbellard             } else {
214313eb76e0Sbellard                 /* RAM case */
214413eb76e0Sbellard                 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
214513eb76e0Sbellard                     (addr & ~TARGET_PAGE_MASK);
214613eb76e0Sbellard                 memcpy(buf, ptr, l);
214713eb76e0Sbellard             }
214813eb76e0Sbellard         }
214913eb76e0Sbellard         len -= l;
215013eb76e0Sbellard         buf += l;
215113eb76e0Sbellard         addr += l;
215213eb76e0Sbellard     }
215313eb76e0Sbellard }
21548df1cd07Sbellard 
21558df1cd07Sbellard /* warning: addr must be aligned */
21568df1cd07Sbellard uint32_t ldl_phys(target_phys_addr_t addr)
21578df1cd07Sbellard {
21588df1cd07Sbellard     int io_index;
21598df1cd07Sbellard     uint8_t *ptr;
21608df1cd07Sbellard     uint32_t val;
21618df1cd07Sbellard     unsigned long pd;
21628df1cd07Sbellard     PhysPageDesc *p;
21638df1cd07Sbellard 
21648df1cd07Sbellard     p = phys_page_find(addr >> TARGET_PAGE_BITS);
21658df1cd07Sbellard     if (!p) {
21668df1cd07Sbellard         pd = IO_MEM_UNASSIGNED;
21678df1cd07Sbellard     } else {
21688df1cd07Sbellard         pd = p->phys_offset;
21698df1cd07Sbellard     }
21708df1cd07Sbellard 
21718df1cd07Sbellard     if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
21728df1cd07Sbellard         (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
21738df1cd07Sbellard         /* I/O case */
21748df1cd07Sbellard         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
21758df1cd07Sbellard         val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
21768df1cd07Sbellard     } else {
21778df1cd07Sbellard         /* RAM case */
21788df1cd07Sbellard         ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
21798df1cd07Sbellard             (addr & ~TARGET_PAGE_MASK);
21808df1cd07Sbellard         val = ldl_p(ptr);
21818df1cd07Sbellard     }
21828df1cd07Sbellard     return val;
21838df1cd07Sbellard }
21848df1cd07Sbellard 
21858df1cd07Sbellard /* warning: addr must be aligned. The ram page is not masked as dirty
21868df1cd07Sbellard    and the code inside is not invalidated. It is useful if the dirty
21878df1cd07Sbellard    bits are used to track modified PTEs */
21888df1cd07Sbellard void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
21898df1cd07Sbellard {
21908df1cd07Sbellard     int io_index;
21918df1cd07Sbellard     uint8_t *ptr;
21928df1cd07Sbellard     unsigned long pd;
21938df1cd07Sbellard     PhysPageDesc *p;
21948df1cd07Sbellard 
21958df1cd07Sbellard     p = phys_page_find(addr >> TARGET_PAGE_BITS);
21968df1cd07Sbellard     if (!p) {
21978df1cd07Sbellard         pd = IO_MEM_UNASSIGNED;
21988df1cd07Sbellard     } else {
21998df1cd07Sbellard         pd = p->phys_offset;
22008df1cd07Sbellard     }
22018df1cd07Sbellard 
22028df1cd07Sbellard     if ((pd & ~TARGET_PAGE_MASK) != 0) {
22038df1cd07Sbellard         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
22048df1cd07Sbellard         io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
22058df1cd07Sbellard     } else {
22068df1cd07Sbellard         ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
22078df1cd07Sbellard             (addr & ~TARGET_PAGE_MASK);
22088df1cd07Sbellard         stl_p(ptr, val);
22098df1cd07Sbellard     }
22108df1cd07Sbellard }
22118df1cd07Sbellard 
22128df1cd07Sbellard /* warning: addr must be aligned */
22138df1cd07Sbellard /* XXX: optimize code invalidation test */
22148df1cd07Sbellard void stl_phys(target_phys_addr_t addr, uint32_t val)
22158df1cd07Sbellard {
22168df1cd07Sbellard     int io_index;
22178df1cd07Sbellard     uint8_t *ptr;
22188df1cd07Sbellard     unsigned long pd;
22198df1cd07Sbellard     PhysPageDesc *p;
22208df1cd07Sbellard 
22218df1cd07Sbellard     p = phys_page_find(addr >> TARGET_PAGE_BITS);
22228df1cd07Sbellard     if (!p) {
22238df1cd07Sbellard         pd = IO_MEM_UNASSIGNED;
22248df1cd07Sbellard     } else {
22258df1cd07Sbellard         pd = p->phys_offset;
22268df1cd07Sbellard     }
22278df1cd07Sbellard 
22288df1cd07Sbellard     if ((pd & ~TARGET_PAGE_MASK) != 0) {
22298df1cd07Sbellard         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
22308df1cd07Sbellard         io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
22318df1cd07Sbellard     } else {
22328df1cd07Sbellard         unsigned long addr1;
22338df1cd07Sbellard         addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
22348df1cd07Sbellard         /* RAM case */
22358df1cd07Sbellard         ptr = phys_ram_base + addr1;
22368df1cd07Sbellard         stl_p(ptr, val);
22378df1cd07Sbellard         /* invalidate code */
22388df1cd07Sbellard         tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
22398df1cd07Sbellard         /* set dirty bit */
22400a962c02Sbellard         phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff;
22418df1cd07Sbellard     }
22428df1cd07Sbellard }
22438df1cd07Sbellard 
224413eb76e0Sbellard #endif
224513eb76e0Sbellard 
224613eb76e0Sbellard /* virtual memory access for debug */
2247b448f2f3Sbellard int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
2248b448f2f3Sbellard                         uint8_t *buf, int len, int is_write)
224913eb76e0Sbellard {
225013eb76e0Sbellard     int l;
225113eb76e0Sbellard     target_ulong page, phys_addr;
225213eb76e0Sbellard 
225313eb76e0Sbellard     while (len > 0) {
225413eb76e0Sbellard         page = addr & TARGET_PAGE_MASK;
225513eb76e0Sbellard         phys_addr = cpu_get_phys_page_debug(env, page);
225613eb76e0Sbellard         /* if no physical page mapped, return an error */
225713eb76e0Sbellard         if (phys_addr == -1)
225813eb76e0Sbellard             return -1;
225913eb76e0Sbellard         l = (page + TARGET_PAGE_SIZE) - addr;
226013eb76e0Sbellard         if (l > len)
226113eb76e0Sbellard             l = len;
2262b448f2f3Sbellard         cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
2263b448f2f3Sbellard                                buf, l, is_write);
226413eb76e0Sbellard         len -= l;
226513eb76e0Sbellard         buf += l;
226613eb76e0Sbellard         addr += l;
226713eb76e0Sbellard     }
226813eb76e0Sbellard     return 0;
226913eb76e0Sbellard }
227013eb76e0Sbellard 
2271e3db7226Sbellard void dump_exec_info(FILE *f,
2272e3db7226Sbellard                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2273e3db7226Sbellard {
2274e3db7226Sbellard     int i, target_code_size, max_target_code_size;
2275e3db7226Sbellard     int direct_jmp_count, direct_jmp2_count, cross_page;
2276e3db7226Sbellard     TranslationBlock *tb;
2277e3db7226Sbellard 
2278e3db7226Sbellard     target_code_size = 0;
2279e3db7226Sbellard     max_target_code_size = 0;
2280e3db7226Sbellard     cross_page = 0;
2281e3db7226Sbellard     direct_jmp_count = 0;
2282e3db7226Sbellard     direct_jmp2_count = 0;
2283e3db7226Sbellard     for(i = 0; i < nb_tbs; i++) {
2284e3db7226Sbellard         tb = &tbs[i];
2285e3db7226Sbellard         target_code_size += tb->size;
2286e3db7226Sbellard         if (tb->size > max_target_code_size)
2287e3db7226Sbellard             max_target_code_size = tb->size;
2288e3db7226Sbellard         if (tb->page_addr[1] != -1)
2289e3db7226Sbellard             cross_page++;
2290e3db7226Sbellard         if (tb->tb_next_offset[0] != 0xffff) {
2291e3db7226Sbellard             direct_jmp_count++;
2292e3db7226Sbellard             if (tb->tb_next_offset[1] != 0xffff) {
2293e3db7226Sbellard                 direct_jmp2_count++;
2294e3db7226Sbellard             }
2295e3db7226Sbellard         }
2296e3db7226Sbellard     }
2297e3db7226Sbellard     /* XXX: avoid using doubles ? */
2298e3db7226Sbellard     cpu_fprintf(f, "TB count            %d\n", nb_tbs);
2299e3db7226Sbellard     cpu_fprintf(f, "TB avg target size  %d max=%d bytes\n",
2300e3db7226Sbellard                 nb_tbs ? target_code_size / nb_tbs : 0,
2301e3db7226Sbellard                 max_target_code_size);
2302e3db7226Sbellard     cpu_fprintf(f, "TB avg host size    %d bytes (expansion ratio: %0.1f)\n",
2303e3db7226Sbellard                 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2304e3db7226Sbellard                 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2305e3db7226Sbellard     cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
2306e3db7226Sbellard             cross_page,
2307e3db7226Sbellard             nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2308e3db7226Sbellard     cpu_fprintf(f, "direct jump count   %d (%d%%) (2 jumps=%d %d%%)\n",
2309e3db7226Sbellard                 direct_jmp_count,
2310e3db7226Sbellard                 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2311e3db7226Sbellard                 direct_jmp2_count,
2312e3db7226Sbellard                 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2313e3db7226Sbellard     cpu_fprintf(f, "TB flush count      %d\n", tb_flush_count);
2314e3db7226Sbellard     cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2315e3db7226Sbellard     cpu_fprintf(f, "TLB flush count     %d\n", tlb_flush_count);
2316e3db7226Sbellard }
2317e3db7226Sbellard 
231861382a50Sbellard #if !defined(CONFIG_USER_ONLY)
231961382a50Sbellard 
232061382a50Sbellard #define MMUSUFFIX _cmmu
232161382a50Sbellard #define GETPC() NULL
232261382a50Sbellard #define env cpu_single_env
2323b769d8feSbellard #define SOFTMMU_CODE_ACCESS
232461382a50Sbellard 
232561382a50Sbellard #define SHIFT 0
232661382a50Sbellard #include "softmmu_template.h"
232761382a50Sbellard 
232861382a50Sbellard #define SHIFT 1
232961382a50Sbellard #include "softmmu_template.h"
233061382a50Sbellard 
233161382a50Sbellard #define SHIFT 2
233261382a50Sbellard #include "softmmu_template.h"
233361382a50Sbellard 
233461382a50Sbellard #define SHIFT 3
233561382a50Sbellard #include "softmmu_template.h"
233661382a50Sbellard 
233761382a50Sbellard #undef env
233861382a50Sbellard 
233961382a50Sbellard #endif
2340