Statistics
| Branch: | Revision:

root / exec.c @ 5dcb6b91

History | View | Annotate | Download (78.3 kB)

1 54936004 bellard
/*
2 fd6ce8f6 bellard
 *  virtual page mapping and translated block handling
3 54936004 bellard
 * 
4 54936004 bellard
 *  Copyright (c) 2003 Fabrice Bellard
5 54936004 bellard
 *
6 54936004 bellard
 * This library is free software; you can redistribute it and/or
7 54936004 bellard
 * modify it under the terms of the GNU Lesser General Public
8 54936004 bellard
 * License as published by the Free Software Foundation; either
9 54936004 bellard
 * version 2 of the License, or (at your option) any later version.
10 54936004 bellard
 *
11 54936004 bellard
 * This library is distributed in the hope that it will be useful,
12 54936004 bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 54936004 bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 54936004 bellard
 * Lesser General Public License for more details.
15 54936004 bellard
 *
16 54936004 bellard
 * You should have received a copy of the GNU Lesser General Public
17 54936004 bellard
 * License along with this library; if not, write to the Free Software
18 54936004 bellard
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 54936004 bellard
 */
20 67b915a5 bellard
#include "config.h"
21 d5a8f07c bellard
#ifdef _WIN32
22 d5a8f07c bellard
#include <windows.h>
23 d5a8f07c bellard
#else
24 a98d49b1 bellard
#include <sys/types.h>
25 d5a8f07c bellard
#include <sys/mman.h>
26 d5a8f07c bellard
#endif
27 54936004 bellard
#include <stdlib.h>
28 54936004 bellard
#include <stdio.h>
29 54936004 bellard
#include <stdarg.h>
30 54936004 bellard
#include <string.h>
31 54936004 bellard
#include <errno.h>
32 54936004 bellard
#include <unistd.h>
33 54936004 bellard
#include <inttypes.h>
34 54936004 bellard
35 6180a181 bellard
#include "cpu.h"
36 6180a181 bellard
#include "exec-all.h"
37 53a5960a pbrook
#if defined(CONFIG_USER_ONLY)
38 53a5960a pbrook
#include <qemu.h>
39 53a5960a pbrook
#endif
40 54936004 bellard
41 fd6ce8f6 bellard
//#define DEBUG_TB_INVALIDATE
42 66e85a21 bellard
//#define DEBUG_FLUSH
43 9fa3e853 bellard
//#define DEBUG_TLB
44 67d3b957 pbrook
//#define DEBUG_UNASSIGNED
45 fd6ce8f6 bellard
46 fd6ce8f6 bellard
/* make various TB consistency checks */
47 fd6ce8f6 bellard
//#define DEBUG_TB_CHECK 
48 98857888 bellard
//#define DEBUG_TLB_CHECK 
49 fd6ce8f6 bellard
50 1196be37 ths
//#define DEBUG_IOPORT
51 1196be37 ths
52 99773bd4 pbrook
#if !defined(CONFIG_USER_ONLY)
53 99773bd4 pbrook
/* TB consistency checks only implemented for usermode emulation.  */
54 99773bd4 pbrook
#undef DEBUG_TB_CHECK
55 99773bd4 pbrook
#endif
56 99773bd4 pbrook
57 fd6ce8f6 bellard
/* threshold to flush the translated code buffer */
58 fd6ce8f6 bellard
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
59 fd6ce8f6 bellard
60 9fa3e853 bellard
#define SMC_BITMAP_USE_THRESHOLD 10
61 9fa3e853 bellard
62 9fa3e853 bellard
#define MMAP_AREA_START        0x00000000
63 9fa3e853 bellard
#define MMAP_AREA_END          0xa8000000
64 fd6ce8f6 bellard
65 108c49b8 bellard
#if defined(TARGET_SPARC64)
66 108c49b8 bellard
#define TARGET_PHYS_ADDR_SPACE_BITS 41
67 5dcb6b91 blueswir1
#elif defined(TARGET_SPARC)
68 5dcb6b91 blueswir1
#define TARGET_PHYS_ADDR_SPACE_BITS 36
69 bedb69ea j_mayer
#elif defined(TARGET_ALPHA)
70 bedb69ea j_mayer
#define TARGET_PHYS_ADDR_SPACE_BITS 42
71 bedb69ea j_mayer
#define TARGET_VIRT_ADDR_SPACE_BITS 42
72 108c49b8 bellard
#elif defined(TARGET_PPC64)
73 108c49b8 bellard
#define TARGET_PHYS_ADDR_SPACE_BITS 42
74 108c49b8 bellard
#else
75 108c49b8 bellard
/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
76 108c49b8 bellard
#define TARGET_PHYS_ADDR_SPACE_BITS 32
77 108c49b8 bellard
#endif
78 108c49b8 bellard
79 fd6ce8f6 bellard
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
80 9fa3e853 bellard
TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
81 fd6ce8f6 bellard
int nb_tbs;
82 eb51d102 bellard
/* any access to the tbs or the page table must use this lock */
83 eb51d102 bellard
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
84 fd6ce8f6 bellard
85 b8076a74 bellard
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
86 fd6ce8f6 bellard
uint8_t *code_gen_ptr;
87 fd6ce8f6 bellard
88 9fa3e853 bellard
int phys_ram_size;
89 9fa3e853 bellard
int phys_ram_fd;
90 9fa3e853 bellard
uint8_t *phys_ram_base;
91 1ccde1cb bellard
uint8_t *phys_ram_dirty;
92 e9a1ab19 bellard
static ram_addr_t phys_ram_alloc_offset = 0;
93 9fa3e853 bellard
94 6a00d601 bellard
CPUState *first_cpu;
95 6a00d601 bellard
/* current CPU in the current thread. It is only valid inside
96 6a00d601 bellard
   cpu_exec() */
97 6a00d601 bellard
CPUState *cpu_single_env; 
98 6a00d601 bellard
99 54936004 bellard
typedef struct PageDesc {
100 92e873b9 bellard
    /* list of TBs intersecting this ram page */
101 fd6ce8f6 bellard
    TranslationBlock *first_tb;
102 9fa3e853 bellard
    /* in order to optimize self modifying code, we count the number
103 9fa3e853 bellard
       of lookups we do to a given page to use a bitmap */
104 9fa3e853 bellard
    unsigned int code_write_count;
105 9fa3e853 bellard
    uint8_t *code_bitmap;
106 9fa3e853 bellard
#if defined(CONFIG_USER_ONLY)
107 9fa3e853 bellard
    unsigned long flags;
108 9fa3e853 bellard
#endif
109 54936004 bellard
} PageDesc;
110 54936004 bellard
111 92e873b9 bellard
typedef struct PhysPageDesc {
112 92e873b9 bellard
    /* offset in host memory of the page + io_index in the low 12 bits */
113 e04f40b5 bellard
    uint32_t phys_offset;
114 92e873b9 bellard
} PhysPageDesc;
115 92e873b9 bellard
116 54936004 bellard
#define L2_BITS 10
117 bedb69ea j_mayer
#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
118 bedb69ea j_mayer
/* XXX: this is a temporary hack for alpha target.
119 bedb69ea j_mayer
 *      In the future, this is to be replaced by a multi-level table
120 bedb69ea j_mayer
 *      to actually be able to handle the complete 64 bits address space.
121 bedb69ea j_mayer
 */
122 bedb69ea j_mayer
#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
123 bedb69ea j_mayer
#else
124 54936004 bellard
#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
125 bedb69ea j_mayer
#endif
126 54936004 bellard
127 54936004 bellard
#define L1_SIZE (1 << L1_BITS)
128 54936004 bellard
#define L2_SIZE (1 << L2_BITS)
129 54936004 bellard
130 33417e70 bellard
static void io_mem_init(void);
131 fd6ce8f6 bellard
132 83fb7adf bellard
unsigned long qemu_real_host_page_size;
133 83fb7adf bellard
unsigned long qemu_host_page_bits;
134 83fb7adf bellard
unsigned long qemu_host_page_size;
135 83fb7adf bellard
unsigned long qemu_host_page_mask;
136 54936004 bellard
137 92e873b9 bellard
/* XXX: for system emulation, it could just be an array */
138 54936004 bellard
static PageDesc *l1_map[L1_SIZE];
139 0a962c02 bellard
PhysPageDesc **l1_phys_map;
140 54936004 bellard
141 33417e70 bellard
/* io memory support */
142 33417e70 bellard
CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
143 33417e70 bellard
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
144 a4193c8a bellard
void *io_mem_opaque[IO_MEM_NB_ENTRIES];
145 33417e70 bellard
static int io_mem_nb;
146 6658ffb8 pbrook
#if defined(CONFIG_SOFTMMU)
147 6658ffb8 pbrook
static int io_mem_watch;
148 6658ffb8 pbrook
#endif
149 33417e70 bellard
150 34865134 bellard
/* log support */
151 34865134 bellard
char *logfilename = "/tmp/qemu.log";
152 34865134 bellard
FILE *logfile;
153 34865134 bellard
int loglevel;
154 34865134 bellard
155 e3db7226 bellard
/* statistics */
156 e3db7226 bellard
static int tlb_flush_count;
157 e3db7226 bellard
static int tb_flush_count;
158 e3db7226 bellard
static int tb_phys_invalidate_count;
159 e3db7226 bellard
160 b346ff46 bellard
static void page_init(void)
161 54936004 bellard
{
162 83fb7adf bellard
    /* NOTE: we can always suppose that qemu_host_page_size >=
163 54936004 bellard
       TARGET_PAGE_SIZE */
164 67b915a5 bellard
#ifdef _WIN32
165 d5a8f07c bellard
    {
166 d5a8f07c bellard
        SYSTEM_INFO system_info;
167 d5a8f07c bellard
        DWORD old_protect;
168 d5a8f07c bellard
        
169 d5a8f07c bellard
        GetSystemInfo(&system_info);
170 d5a8f07c bellard
        qemu_real_host_page_size = system_info.dwPageSize;
171 d5a8f07c bellard
        
172 d5a8f07c bellard
        VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
173 d5a8f07c bellard
                       PAGE_EXECUTE_READWRITE, &old_protect);
174 d5a8f07c bellard
    }
175 67b915a5 bellard
#else
176 83fb7adf bellard
    qemu_real_host_page_size = getpagesize();
177 d5a8f07c bellard
    {
178 d5a8f07c bellard
        unsigned long start, end;
179 d5a8f07c bellard
180 d5a8f07c bellard
        start = (unsigned long)code_gen_buffer;
181 d5a8f07c bellard
        start &= ~(qemu_real_host_page_size - 1);
182 d5a8f07c bellard
        
183 d5a8f07c bellard
        end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
184 d5a8f07c bellard
        end += qemu_real_host_page_size - 1;
185 d5a8f07c bellard
        end &= ~(qemu_real_host_page_size - 1);
186 d5a8f07c bellard
        
187 d5a8f07c bellard
        mprotect((void *)start, end - start, 
188 d5a8f07c bellard
                 PROT_READ | PROT_WRITE | PROT_EXEC);
189 d5a8f07c bellard
    }
190 67b915a5 bellard
#endif
191 d5a8f07c bellard
192 83fb7adf bellard
    if (qemu_host_page_size == 0)
193 83fb7adf bellard
        qemu_host_page_size = qemu_real_host_page_size;
194 83fb7adf bellard
    if (qemu_host_page_size < TARGET_PAGE_SIZE)
195 83fb7adf bellard
        qemu_host_page_size = TARGET_PAGE_SIZE;
196 83fb7adf bellard
    qemu_host_page_bits = 0;
197 83fb7adf bellard
    while ((1 << qemu_host_page_bits) < qemu_host_page_size)
198 83fb7adf bellard
        qemu_host_page_bits++;
199 83fb7adf bellard
    qemu_host_page_mask = ~(qemu_host_page_size - 1);
200 108c49b8 bellard
    l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
201 108c49b8 bellard
    memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
202 54936004 bellard
}
203 54936004 bellard
204 fd6ce8f6 bellard
static inline PageDesc *page_find_alloc(unsigned int index)
205 54936004 bellard
{
206 54936004 bellard
    PageDesc **lp, *p;
207 54936004 bellard
208 54936004 bellard
    lp = &l1_map[index >> L2_BITS];
209 54936004 bellard
    p = *lp;
210 54936004 bellard
    if (!p) {
211 54936004 bellard
        /* allocate if not found */
212 59817ccb bellard
        p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
213 fd6ce8f6 bellard
        memset(p, 0, sizeof(PageDesc) * L2_SIZE);
214 54936004 bellard
        *lp = p;
215 54936004 bellard
    }
216 54936004 bellard
    return p + (index & (L2_SIZE - 1));
217 54936004 bellard
}
218 54936004 bellard
219 fd6ce8f6 bellard
static inline PageDesc *page_find(unsigned int index)
220 54936004 bellard
{
221 54936004 bellard
    PageDesc *p;
222 54936004 bellard
223 54936004 bellard
    p = l1_map[index >> L2_BITS];
224 54936004 bellard
    if (!p)
225 54936004 bellard
        return 0;
226 fd6ce8f6 bellard
    return p + (index & (L2_SIZE - 1));
227 fd6ce8f6 bellard
}
228 fd6ce8f6 bellard
229 108c49b8 bellard
static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
230 92e873b9 bellard
{
231 108c49b8 bellard
    void **lp, **p;
232 e3f4e2a4 pbrook
    PhysPageDesc *pd;
233 92e873b9 bellard
234 108c49b8 bellard
    p = (void **)l1_phys_map;
235 108c49b8 bellard
#if TARGET_PHYS_ADDR_SPACE_BITS > 32
236 108c49b8 bellard
237 108c49b8 bellard
#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
238 108c49b8 bellard
#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
239 108c49b8 bellard
#endif
240 108c49b8 bellard
    lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
241 92e873b9 bellard
    p = *lp;
242 92e873b9 bellard
    if (!p) {
243 92e873b9 bellard
        /* allocate if not found */
244 108c49b8 bellard
        if (!alloc)
245 108c49b8 bellard
            return NULL;
246 108c49b8 bellard
        p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
247 108c49b8 bellard
        memset(p, 0, sizeof(void *) * L1_SIZE);
248 108c49b8 bellard
        *lp = p;
249 108c49b8 bellard
    }
250 108c49b8 bellard
#endif
251 108c49b8 bellard
    lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
252 e3f4e2a4 pbrook
    pd = *lp;
253 e3f4e2a4 pbrook
    if (!pd) {
254 e3f4e2a4 pbrook
        int i;
255 108c49b8 bellard
        /* allocate if not found */
256 108c49b8 bellard
        if (!alloc)
257 108c49b8 bellard
            return NULL;
258 e3f4e2a4 pbrook
        pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
259 e3f4e2a4 pbrook
        *lp = pd;
260 e3f4e2a4 pbrook
        for (i = 0; i < L2_SIZE; i++)
261 e3f4e2a4 pbrook
          pd[i].phys_offset = IO_MEM_UNASSIGNED;
262 92e873b9 bellard
    }
263 e3f4e2a4 pbrook
    return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
264 92e873b9 bellard
}
265 92e873b9 bellard
266 108c49b8 bellard
static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
267 92e873b9 bellard
{
268 108c49b8 bellard
    return phys_page_find_alloc(index, 0);
269 92e873b9 bellard
}
270 92e873b9 bellard
271 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
272 6a00d601 bellard
static void tlb_protect_code(ram_addr_t ram_addr);
273 3a7d929e bellard
static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, 
274 3a7d929e bellard
                                    target_ulong vaddr);
275 9fa3e853 bellard
#endif
276 fd6ce8f6 bellard
277 6a00d601 bellard
void cpu_exec_init(CPUState *env)
278 fd6ce8f6 bellard
{
279 6a00d601 bellard
    CPUState **penv;
280 6a00d601 bellard
    int cpu_index;
281 6a00d601 bellard
282 fd6ce8f6 bellard
    if (!code_gen_ptr) {
283 fd6ce8f6 bellard
        code_gen_ptr = code_gen_buffer;
284 b346ff46 bellard
        page_init();
285 33417e70 bellard
        io_mem_init();
286 fd6ce8f6 bellard
    }
287 6a00d601 bellard
    env->next_cpu = NULL;
288 6a00d601 bellard
    penv = &first_cpu;
289 6a00d601 bellard
    cpu_index = 0;
290 6a00d601 bellard
    while (*penv != NULL) {
291 6a00d601 bellard
        penv = (CPUState **)&(*penv)->next_cpu;
292 6a00d601 bellard
        cpu_index++;
293 6a00d601 bellard
    }
294 6a00d601 bellard
    env->cpu_index = cpu_index;
295 6658ffb8 pbrook
    env->nb_watchpoints = 0;
296 6a00d601 bellard
    *penv = env;
297 fd6ce8f6 bellard
}
298 fd6ce8f6 bellard
299 9fa3e853 bellard
static inline void invalidate_page_bitmap(PageDesc *p)
300 9fa3e853 bellard
{
301 9fa3e853 bellard
    if (p->code_bitmap) {
302 59817ccb bellard
        qemu_free(p->code_bitmap);
303 9fa3e853 bellard
        p->code_bitmap = NULL;
304 9fa3e853 bellard
    }
305 9fa3e853 bellard
    p->code_write_count = 0;
306 9fa3e853 bellard
}
307 9fa3e853 bellard
308 fd6ce8f6 bellard
/* set to NULL all the 'first_tb' fields in all PageDescs */
309 fd6ce8f6 bellard
static void page_flush_tb(void)
310 fd6ce8f6 bellard
{
311 fd6ce8f6 bellard
    int i, j;
312 fd6ce8f6 bellard
    PageDesc *p;
313 fd6ce8f6 bellard
314 fd6ce8f6 bellard
    for(i = 0; i < L1_SIZE; i++) {
315 fd6ce8f6 bellard
        p = l1_map[i];
316 fd6ce8f6 bellard
        if (p) {
317 9fa3e853 bellard
            for(j = 0; j < L2_SIZE; j++) {
318 9fa3e853 bellard
                p->first_tb = NULL;
319 9fa3e853 bellard
                invalidate_page_bitmap(p);
320 9fa3e853 bellard
                p++;
321 9fa3e853 bellard
            }
322 fd6ce8f6 bellard
        }
323 fd6ce8f6 bellard
    }
324 fd6ce8f6 bellard
}
325 fd6ce8f6 bellard
326 fd6ce8f6 bellard
/* flush all the translation blocks */
327 d4e8164f bellard
/* XXX: tb_flush is currently not thread safe */
328 6a00d601 bellard
void tb_flush(CPUState *env1)
329 fd6ce8f6 bellard
{
330 6a00d601 bellard
    CPUState *env;
331 0124311e bellard
#if defined(DEBUG_FLUSH)
332 fd6ce8f6 bellard
    printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
333 fd6ce8f6 bellard
           code_gen_ptr - code_gen_buffer, 
334 fd6ce8f6 bellard
           nb_tbs, 
335 0124311e bellard
           nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
336 fd6ce8f6 bellard
#endif
337 fd6ce8f6 bellard
    nb_tbs = 0;
338 6a00d601 bellard
    
339 6a00d601 bellard
    for(env = first_cpu; env != NULL; env = env->next_cpu) {
340 6a00d601 bellard
        memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
341 6a00d601 bellard
    }
342 9fa3e853 bellard
343 8a8a608f bellard
    memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
344 fd6ce8f6 bellard
    page_flush_tb();
345 9fa3e853 bellard
346 fd6ce8f6 bellard
    code_gen_ptr = code_gen_buffer;
347 d4e8164f bellard
    /* XXX: flush processor icache at this point if cache flush is
348 d4e8164f bellard
       expensive */
349 e3db7226 bellard
    tb_flush_count++;
350 fd6ce8f6 bellard
}
351 fd6ce8f6 bellard
352 fd6ce8f6 bellard
#ifdef DEBUG_TB_CHECK
353 fd6ce8f6 bellard
354 bc98a7ef j_mayer
static void tb_invalidate_check(target_ulong address)
355 fd6ce8f6 bellard
{
356 fd6ce8f6 bellard
    TranslationBlock *tb;
357 fd6ce8f6 bellard
    int i;
358 fd6ce8f6 bellard
    address &= TARGET_PAGE_MASK;
359 99773bd4 pbrook
    for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
360 99773bd4 pbrook
        for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
361 fd6ce8f6 bellard
            if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
362 fd6ce8f6 bellard
                  address >= tb->pc + tb->size)) {
363 fd6ce8f6 bellard
                printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
364 99773bd4 pbrook
                       address, (long)tb->pc, tb->size);
365 fd6ce8f6 bellard
            }
366 fd6ce8f6 bellard
        }
367 fd6ce8f6 bellard
    }
368 fd6ce8f6 bellard
}
369 fd6ce8f6 bellard
370 fd6ce8f6 bellard
/* verify that all the pages have correct rights for code */
371 fd6ce8f6 bellard
static void tb_page_check(void)
372 fd6ce8f6 bellard
{
373 fd6ce8f6 bellard
    TranslationBlock *tb;
374 fd6ce8f6 bellard
    int i, flags1, flags2;
375 fd6ce8f6 bellard
    
376 99773bd4 pbrook
    for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
377 99773bd4 pbrook
        for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
378 fd6ce8f6 bellard
            flags1 = page_get_flags(tb->pc);
379 fd6ce8f6 bellard
            flags2 = page_get_flags(tb->pc + tb->size - 1);
380 fd6ce8f6 bellard
            if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
381 fd6ce8f6 bellard
                printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
382 99773bd4 pbrook
                       (long)tb->pc, tb->size, flags1, flags2);
383 fd6ce8f6 bellard
            }
384 fd6ce8f6 bellard
        }
385 fd6ce8f6 bellard
    }
386 fd6ce8f6 bellard
}
387 fd6ce8f6 bellard
388 d4e8164f bellard
void tb_jmp_check(TranslationBlock *tb)
389 d4e8164f bellard
{
390 d4e8164f bellard
    TranslationBlock *tb1;
391 d4e8164f bellard
    unsigned int n1;
392 d4e8164f bellard
393 d4e8164f bellard
    /* suppress any remaining jumps to this TB */
394 d4e8164f bellard
    tb1 = tb->jmp_first;
395 d4e8164f bellard
    for(;;) {
396 d4e8164f bellard
        n1 = (long)tb1 & 3;
397 d4e8164f bellard
        tb1 = (TranslationBlock *)((long)tb1 & ~3);
398 d4e8164f bellard
        if (n1 == 2)
399 d4e8164f bellard
            break;
400 d4e8164f bellard
        tb1 = tb1->jmp_next[n1];
401 d4e8164f bellard
    }
402 d4e8164f bellard
    /* check end of list */
403 d4e8164f bellard
    if (tb1 != tb) {
404 d4e8164f bellard
        printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
405 d4e8164f bellard
    }
406 d4e8164f bellard
}
407 d4e8164f bellard
408 fd6ce8f6 bellard
#endif
409 fd6ce8f6 bellard
410 fd6ce8f6 bellard
/* invalidate one TB */
411 fd6ce8f6 bellard
static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
412 fd6ce8f6 bellard
                             int next_offset)
413 fd6ce8f6 bellard
{
414 fd6ce8f6 bellard
    TranslationBlock *tb1;
415 fd6ce8f6 bellard
    for(;;) {
416 fd6ce8f6 bellard
        tb1 = *ptb;
417 fd6ce8f6 bellard
        if (tb1 == tb) {
418 fd6ce8f6 bellard
            *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
419 fd6ce8f6 bellard
            break;
420 fd6ce8f6 bellard
        }
421 fd6ce8f6 bellard
        ptb = (TranslationBlock **)((char *)tb1 + next_offset);
422 fd6ce8f6 bellard
    }
423 fd6ce8f6 bellard
}
424 fd6ce8f6 bellard
425 9fa3e853 bellard
static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
426 9fa3e853 bellard
{
427 9fa3e853 bellard
    TranslationBlock *tb1;
428 9fa3e853 bellard
    unsigned int n1;
429 9fa3e853 bellard
430 9fa3e853 bellard
    for(;;) {
431 9fa3e853 bellard
        tb1 = *ptb;
432 9fa3e853 bellard
        n1 = (long)tb1 & 3;
433 9fa3e853 bellard
        tb1 = (TranslationBlock *)((long)tb1 & ~3);
434 9fa3e853 bellard
        if (tb1 == tb) {
435 9fa3e853 bellard
            *ptb = tb1->page_next[n1];
436 9fa3e853 bellard
            break;
437 9fa3e853 bellard
        }
438 9fa3e853 bellard
        ptb = &tb1->page_next[n1];
439 9fa3e853 bellard
    }
440 9fa3e853 bellard
}
441 9fa3e853 bellard
442 d4e8164f bellard
static inline void tb_jmp_remove(TranslationBlock *tb, int n)
443 d4e8164f bellard
{
444 d4e8164f bellard
    TranslationBlock *tb1, **ptb;
445 d4e8164f bellard
    unsigned int n1;
446 d4e8164f bellard
447 d4e8164f bellard
    ptb = &tb->jmp_next[n];
448 d4e8164f bellard
    tb1 = *ptb;
449 d4e8164f bellard
    if (tb1) {
450 d4e8164f bellard
        /* find tb(n) in circular list */
451 d4e8164f bellard
        for(;;) {
452 d4e8164f bellard
            tb1 = *ptb;
453 d4e8164f bellard
            n1 = (long)tb1 & 3;
454 d4e8164f bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
455 d4e8164f bellard
            if (n1 == n && tb1 == tb)
456 d4e8164f bellard
                break;
457 d4e8164f bellard
            if (n1 == 2) {
458 d4e8164f bellard
                ptb = &tb1->jmp_first;
459 d4e8164f bellard
            } else {
460 d4e8164f bellard
                ptb = &tb1->jmp_next[n1];
461 d4e8164f bellard
            }
462 d4e8164f bellard
        }
463 d4e8164f bellard
        /* now we can suppress tb(n) from the list */
464 d4e8164f bellard
        *ptb = tb->jmp_next[n];
465 d4e8164f bellard
466 d4e8164f bellard
        tb->jmp_next[n] = NULL;
467 d4e8164f bellard
    }
468 d4e8164f bellard
}
469 d4e8164f bellard
470 d4e8164f bellard
/* reset the jump entry 'n' of a TB so that it is not chained to
471 d4e8164f bellard
   another TB */
472 d4e8164f bellard
static inline void tb_reset_jump(TranslationBlock *tb, int n)
473 d4e8164f bellard
{
474 d4e8164f bellard
    tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
475 d4e8164f bellard
}
476 d4e8164f bellard
477 8a40a180 bellard
static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
478 fd6ce8f6 bellard
{
479 6a00d601 bellard
    CPUState *env;
480 8a40a180 bellard
    PageDesc *p;
481 d4e8164f bellard
    unsigned int h, n1;
482 8a40a180 bellard
    target_ulong phys_pc;
483 8a40a180 bellard
    TranslationBlock *tb1, *tb2;
484 d4e8164f bellard
    
485 8a40a180 bellard
    /* remove the TB from the hash list */
486 8a40a180 bellard
    phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
487 8a40a180 bellard
    h = tb_phys_hash_func(phys_pc);
488 8a40a180 bellard
    tb_remove(&tb_phys_hash[h], tb, 
489 8a40a180 bellard
              offsetof(TranslationBlock, phys_hash_next));
490 8a40a180 bellard
491 8a40a180 bellard
    /* remove the TB from the page list */
492 8a40a180 bellard
    if (tb->page_addr[0] != page_addr) {
493 8a40a180 bellard
        p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
494 8a40a180 bellard
        tb_page_remove(&p->first_tb, tb);
495 8a40a180 bellard
        invalidate_page_bitmap(p);
496 8a40a180 bellard
    }
497 8a40a180 bellard
    if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
498 8a40a180 bellard
        p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
499 8a40a180 bellard
        tb_page_remove(&p->first_tb, tb);
500 8a40a180 bellard
        invalidate_page_bitmap(p);
501 8a40a180 bellard
    }
502 8a40a180 bellard
503 36bdbe54 bellard
    tb_invalidated_flag = 1;
504 59817ccb bellard
505 fd6ce8f6 bellard
    /* remove the TB from the hash list */
506 8a40a180 bellard
    h = tb_jmp_cache_hash_func(tb->pc);
507 6a00d601 bellard
    for(env = first_cpu; env != NULL; env = env->next_cpu) {
508 6a00d601 bellard
        if (env->tb_jmp_cache[h] == tb)
509 6a00d601 bellard
            env->tb_jmp_cache[h] = NULL;
510 6a00d601 bellard
    }
511 d4e8164f bellard
512 d4e8164f bellard
    /* suppress this TB from the two jump lists */
513 d4e8164f bellard
    tb_jmp_remove(tb, 0);
514 d4e8164f bellard
    tb_jmp_remove(tb, 1);
515 d4e8164f bellard
516 d4e8164f bellard
    /* suppress any remaining jumps to this TB */
517 d4e8164f bellard
    tb1 = tb->jmp_first;
518 d4e8164f bellard
    for(;;) {
519 d4e8164f bellard
        n1 = (long)tb1 & 3;
520 d4e8164f bellard
        if (n1 == 2)
521 d4e8164f bellard
            break;
522 d4e8164f bellard
        tb1 = (TranslationBlock *)((long)tb1 & ~3);
523 d4e8164f bellard
        tb2 = tb1->jmp_next[n1];
524 d4e8164f bellard
        tb_reset_jump(tb1, n1);
525 d4e8164f bellard
        tb1->jmp_next[n1] = NULL;
526 d4e8164f bellard
        tb1 = tb2;
527 d4e8164f bellard
    }
528 d4e8164f bellard
    tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
529 9fa3e853 bellard
530 e3db7226 bellard
    tb_phys_invalidate_count++;
531 9fa3e853 bellard
}
532 9fa3e853 bellard
533 9fa3e853 bellard
static inline void set_bits(uint8_t *tab, int start, int len)
534 9fa3e853 bellard
{
535 9fa3e853 bellard
    int end, mask, end1;
536 9fa3e853 bellard
537 9fa3e853 bellard
    end = start + len;
538 9fa3e853 bellard
    tab += start >> 3;
539 9fa3e853 bellard
    mask = 0xff << (start & 7);
540 9fa3e853 bellard
    if ((start & ~7) == (end & ~7)) {
541 9fa3e853 bellard
        if (start < end) {
542 9fa3e853 bellard
            mask &= ~(0xff << (end & 7));
543 9fa3e853 bellard
            *tab |= mask;
544 9fa3e853 bellard
        }
545 9fa3e853 bellard
    } else {
546 9fa3e853 bellard
        *tab++ |= mask;
547 9fa3e853 bellard
        start = (start + 8) & ~7;
548 9fa3e853 bellard
        end1 = end & ~7;
549 9fa3e853 bellard
        while (start < end1) {
550 9fa3e853 bellard
            *tab++ = 0xff;
551 9fa3e853 bellard
            start += 8;
552 9fa3e853 bellard
        }
553 9fa3e853 bellard
        if (start < end) {
554 9fa3e853 bellard
            mask = ~(0xff << (end & 7));
555 9fa3e853 bellard
            *tab |= mask;
556 9fa3e853 bellard
        }
557 9fa3e853 bellard
    }
558 9fa3e853 bellard
}
559 9fa3e853 bellard
560 9fa3e853 bellard
static void build_page_bitmap(PageDesc *p)
561 9fa3e853 bellard
{
562 9fa3e853 bellard
    int n, tb_start, tb_end;
563 9fa3e853 bellard
    TranslationBlock *tb;
564 9fa3e853 bellard
    
565 59817ccb bellard
    p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
566 9fa3e853 bellard
    if (!p->code_bitmap)
567 9fa3e853 bellard
        return;
568 9fa3e853 bellard
    memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
569 9fa3e853 bellard
570 9fa3e853 bellard
    tb = p->first_tb;
571 9fa3e853 bellard
    while (tb != NULL) {
572 9fa3e853 bellard
        n = (long)tb & 3;
573 9fa3e853 bellard
        tb = (TranslationBlock *)((long)tb & ~3);
574 9fa3e853 bellard
        /* NOTE: this is subtle as a TB may span two physical pages */
575 9fa3e853 bellard
        if (n == 0) {
576 9fa3e853 bellard
            /* NOTE: tb_end may be after the end of the page, but
577 9fa3e853 bellard
               it is not a problem */
578 9fa3e853 bellard
            tb_start = tb->pc & ~TARGET_PAGE_MASK;
579 9fa3e853 bellard
            tb_end = tb_start + tb->size;
580 9fa3e853 bellard
            if (tb_end > TARGET_PAGE_SIZE)
581 9fa3e853 bellard
                tb_end = TARGET_PAGE_SIZE;
582 9fa3e853 bellard
        } else {
583 9fa3e853 bellard
            tb_start = 0;
584 9fa3e853 bellard
            tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
585 9fa3e853 bellard
        }
586 9fa3e853 bellard
        set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
587 9fa3e853 bellard
        tb = tb->page_next[n];
588 9fa3e853 bellard
    }
589 9fa3e853 bellard
}
590 9fa3e853 bellard
591 d720b93d bellard
#ifdef TARGET_HAS_PRECISE_SMC
592 d720b93d bellard
593 d720b93d bellard
static void tb_gen_code(CPUState *env, 
594 d720b93d bellard
                        target_ulong pc, target_ulong cs_base, int flags,
595 d720b93d bellard
                        int cflags)
596 d720b93d bellard
{
597 d720b93d bellard
    TranslationBlock *tb;
598 d720b93d bellard
    uint8_t *tc_ptr;
599 d720b93d bellard
    target_ulong phys_pc, phys_page2, virt_page2;
600 d720b93d bellard
    int code_gen_size;
601 d720b93d bellard
602 c27004ec bellard
    phys_pc = get_phys_addr_code(env, pc);
603 c27004ec bellard
    tb = tb_alloc(pc);
604 d720b93d bellard
    if (!tb) {
605 d720b93d bellard
        /* flush must be done */
606 d720b93d bellard
        tb_flush(env);
607 d720b93d bellard
        /* cannot fail at this point */
608 c27004ec bellard
        tb = tb_alloc(pc);
609 d720b93d bellard
    }
610 d720b93d bellard
    tc_ptr = code_gen_ptr;
611 d720b93d bellard
    tb->tc_ptr = tc_ptr;
612 d720b93d bellard
    tb->cs_base = cs_base;
613 d720b93d bellard
    tb->flags = flags;
614 d720b93d bellard
    tb->cflags = cflags;
615 d720b93d bellard
    cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
616 d720b93d bellard
    code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
617 d720b93d bellard
    
618 d720b93d bellard
    /* check next page if needed */
619 c27004ec bellard
    virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
620 d720b93d bellard
    phys_page2 = -1;
621 c27004ec bellard
    if ((pc & TARGET_PAGE_MASK) != virt_page2) {
622 d720b93d bellard
        phys_page2 = get_phys_addr_code(env, virt_page2);
623 d720b93d bellard
    }
624 d720b93d bellard
    tb_link_phys(tb, phys_pc, phys_page2);
625 d720b93d bellard
}
626 d720b93d bellard
#endif
627 d720b93d bellard
    
628 9fa3e853 bellard
/* invalidate all TBs which intersect with the target physical page
629 9fa3e853 bellard
   starting in range [start;end[. NOTE: start and end must refer to
630 d720b93d bellard
   the same physical page. 'is_cpu_write_access' should be true if called
631 d720b93d bellard
   from a real cpu write access: the virtual CPU will exit the current
632 d720b93d bellard
   TB if code is modified inside this TB. */
633 d720b93d bellard
void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, 
634 d720b93d bellard
                                   int is_cpu_write_access)
635 d720b93d bellard
{
636 d720b93d bellard
    int n, current_tb_modified, current_tb_not_found, current_flags;
637 d720b93d bellard
    CPUState *env = cpu_single_env;
638 9fa3e853 bellard
    PageDesc *p;
639 ea1c1802 bellard
    TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
640 9fa3e853 bellard
    target_ulong tb_start, tb_end;
641 d720b93d bellard
    target_ulong current_pc, current_cs_base;
642 9fa3e853 bellard
643 9fa3e853 bellard
    p = page_find(start >> TARGET_PAGE_BITS);
644 9fa3e853 bellard
    if (!p) 
645 9fa3e853 bellard
        return;
646 9fa3e853 bellard
    if (!p->code_bitmap && 
647 d720b93d bellard
        ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
648 d720b93d bellard
        is_cpu_write_access) {
649 9fa3e853 bellard
        /* build code bitmap */
650 9fa3e853 bellard
        build_page_bitmap(p);
651 9fa3e853 bellard
    }
652 9fa3e853 bellard
653 9fa3e853 bellard
    /* we remove all the TBs in the range [start, end[ */
654 9fa3e853 bellard
    /* XXX: see if in some cases it could be faster to invalidate all the code */
655 d720b93d bellard
    current_tb_not_found = is_cpu_write_access;
656 d720b93d bellard
    current_tb_modified = 0;
657 d720b93d bellard
    current_tb = NULL; /* avoid warning */
658 d720b93d bellard
    current_pc = 0; /* avoid warning */
659 d720b93d bellard
    current_cs_base = 0; /* avoid warning */
660 d720b93d bellard
    current_flags = 0; /* avoid warning */
661 9fa3e853 bellard
    tb = p->first_tb;
662 9fa3e853 bellard
    while (tb != NULL) {
663 9fa3e853 bellard
        n = (long)tb & 3;
664 9fa3e853 bellard
        tb = (TranslationBlock *)((long)tb & ~3);
665 9fa3e853 bellard
        tb_next = tb->page_next[n];
666 9fa3e853 bellard
        /* NOTE: this is subtle as a TB may span two physical pages */
667 9fa3e853 bellard
        if (n == 0) {
668 9fa3e853 bellard
            /* NOTE: tb_end may be after the end of the page, but
669 9fa3e853 bellard
               it is not a problem */
670 9fa3e853 bellard
            tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
671 9fa3e853 bellard
            tb_end = tb_start + tb->size;
672 9fa3e853 bellard
        } else {
673 9fa3e853 bellard
            tb_start = tb->page_addr[1];
674 9fa3e853 bellard
            tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
675 9fa3e853 bellard
        }
676 9fa3e853 bellard
        if (!(tb_end <= start || tb_start >= end)) {
677 d720b93d bellard
#ifdef TARGET_HAS_PRECISE_SMC
678 d720b93d bellard
            if (current_tb_not_found) {
679 d720b93d bellard
                current_tb_not_found = 0;
680 d720b93d bellard
                current_tb = NULL;
681 d720b93d bellard
                if (env->mem_write_pc) {
682 d720b93d bellard
                    /* now we have a real cpu fault */
683 d720b93d bellard
                    current_tb = tb_find_pc(env->mem_write_pc);
684 d720b93d bellard
                }
685 d720b93d bellard
            }
686 d720b93d bellard
            if (current_tb == tb &&
687 d720b93d bellard
                !(current_tb->cflags & CF_SINGLE_INSN)) {
688 d720b93d bellard
                /* If we are modifying the current TB, we must stop
689 d720b93d bellard
                its execution. We could be more precise by checking
690 d720b93d bellard
                that the modification is after the current PC, but it
691 d720b93d bellard
                would require a specialized function to partially
692 d720b93d bellard
                restore the CPU state */
693 d720b93d bellard
                
694 d720b93d bellard
                current_tb_modified = 1;
695 d720b93d bellard
                cpu_restore_state(current_tb, env, 
696 d720b93d bellard
                                  env->mem_write_pc, NULL);
697 d720b93d bellard
#if defined(TARGET_I386)
698 d720b93d bellard
                current_flags = env->hflags;
699 d720b93d bellard
                current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
700 d720b93d bellard
                current_cs_base = (target_ulong)env->segs[R_CS].base;
701 d720b93d bellard
                current_pc = current_cs_base + env->eip;
702 d720b93d bellard
#else
703 d720b93d bellard
#error unsupported CPU
704 d720b93d bellard
#endif
705 d720b93d bellard
            }
706 d720b93d bellard
#endif /* TARGET_HAS_PRECISE_SMC */
707 6f5a9f7e bellard
            /* we need to do that to handle the case where a signal
708 6f5a9f7e bellard
               occurs while doing tb_phys_invalidate() */
709 6f5a9f7e bellard
            saved_tb = NULL;
710 6f5a9f7e bellard
            if (env) {
711 6f5a9f7e bellard
                saved_tb = env->current_tb;
712 6f5a9f7e bellard
                env->current_tb = NULL;
713 6f5a9f7e bellard
            }
714 9fa3e853 bellard
            tb_phys_invalidate(tb, -1);
715 6f5a9f7e bellard
            if (env) {
716 6f5a9f7e bellard
                env->current_tb = saved_tb;
717 6f5a9f7e bellard
                if (env->interrupt_request && env->current_tb)
718 6f5a9f7e bellard
                    cpu_interrupt(env, env->interrupt_request);
719 6f5a9f7e bellard
            }
720 9fa3e853 bellard
        }
721 9fa3e853 bellard
        tb = tb_next;
722 9fa3e853 bellard
    }
723 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
724 9fa3e853 bellard
    /* if no code remaining, no need to continue to use slow writes */
725 9fa3e853 bellard
    if (!p->first_tb) {
726 9fa3e853 bellard
        invalidate_page_bitmap(p);
727 d720b93d bellard
        if (is_cpu_write_access) {
728 d720b93d bellard
            tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
729 d720b93d bellard
        }
730 d720b93d bellard
    }
731 d720b93d bellard
#endif
732 d720b93d bellard
#ifdef TARGET_HAS_PRECISE_SMC
733 d720b93d bellard
    if (current_tb_modified) {
734 d720b93d bellard
        /* we generate a block containing just the instruction
735 d720b93d bellard
           modifying the memory. It will ensure that it cannot modify
736 d720b93d bellard
           itself */
737 ea1c1802 bellard
        env->current_tb = NULL;
738 d720b93d bellard
        tb_gen_code(env, current_pc, current_cs_base, current_flags, 
739 d720b93d bellard
                    CF_SINGLE_INSN);
740 d720b93d bellard
        cpu_resume_from_signal(env, NULL);
741 9fa3e853 bellard
    }
742 fd6ce8f6 bellard
#endif
743 9fa3e853 bellard
}
744 fd6ce8f6 bellard
745 9fa3e853 bellard
/* len must be <= 8 and start must be a multiple of len */
746 d720b93d bellard
static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
747 9fa3e853 bellard
{
748 9fa3e853 bellard
    PageDesc *p;
749 9fa3e853 bellard
    int offset, b;
750 59817ccb bellard
#if 0
751 a4193c8a bellard
    if (1) {
752 a4193c8a bellard
        if (loglevel) {
753 a4193c8a bellard
            fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n", 
754 a4193c8a bellard
                   cpu_single_env->mem_write_vaddr, len, 
755 a4193c8a bellard
                   cpu_single_env->eip, 
756 a4193c8a bellard
                   cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
757 a4193c8a bellard
        }
758 59817ccb bellard
    }
759 59817ccb bellard
#endif
760 9fa3e853 bellard
    p = page_find(start >> TARGET_PAGE_BITS);
761 9fa3e853 bellard
    if (!p) 
762 9fa3e853 bellard
        return;
763 9fa3e853 bellard
    if (p->code_bitmap) {
764 9fa3e853 bellard
        offset = start & ~TARGET_PAGE_MASK;
765 9fa3e853 bellard
        b = p->code_bitmap[offset >> 3] >> (offset & 7);
766 9fa3e853 bellard
        if (b & ((1 << len) - 1))
767 9fa3e853 bellard
            goto do_invalidate;
768 9fa3e853 bellard
    } else {
769 9fa3e853 bellard
    do_invalidate:
770 d720b93d bellard
        tb_invalidate_phys_page_range(start, start + len, 1);
771 9fa3e853 bellard
    }
772 9fa3e853 bellard
}
773 9fa3e853 bellard
774 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
775 d720b93d bellard
static void tb_invalidate_phys_page(target_ulong addr, 
776 d720b93d bellard
                                    unsigned long pc, void *puc)
777 9fa3e853 bellard
{
778 d720b93d bellard
    int n, current_flags, current_tb_modified;
779 d720b93d bellard
    target_ulong current_pc, current_cs_base;
780 9fa3e853 bellard
    PageDesc *p;
781 d720b93d bellard
    TranslationBlock *tb, *current_tb;
782 d720b93d bellard
#ifdef TARGET_HAS_PRECISE_SMC
783 d720b93d bellard
    CPUState *env = cpu_single_env;
784 d720b93d bellard
#endif
785 9fa3e853 bellard
786 9fa3e853 bellard
    addr &= TARGET_PAGE_MASK;
787 9fa3e853 bellard
    p = page_find(addr >> TARGET_PAGE_BITS);
788 9fa3e853 bellard
    if (!p) 
789 9fa3e853 bellard
        return;
790 9fa3e853 bellard
    tb = p->first_tb;
791 d720b93d bellard
    current_tb_modified = 0;
792 d720b93d bellard
    current_tb = NULL;
793 d720b93d bellard
    current_pc = 0; /* avoid warning */
794 d720b93d bellard
    current_cs_base = 0; /* avoid warning */
795 d720b93d bellard
    current_flags = 0; /* avoid warning */
796 d720b93d bellard
#ifdef TARGET_HAS_PRECISE_SMC
797 d720b93d bellard
    if (tb && pc != 0) {
798 d720b93d bellard
        current_tb = tb_find_pc(pc);
799 d720b93d bellard
    }
800 d720b93d bellard
#endif
801 9fa3e853 bellard
    while (tb != NULL) {
802 9fa3e853 bellard
        n = (long)tb & 3;
803 9fa3e853 bellard
        tb = (TranslationBlock *)((long)tb & ~3);
804 d720b93d bellard
#ifdef TARGET_HAS_PRECISE_SMC
805 d720b93d bellard
        if (current_tb == tb &&
806 d720b93d bellard
            !(current_tb->cflags & CF_SINGLE_INSN)) {
807 d720b93d bellard
                /* If we are modifying the current TB, we must stop
808 d720b93d bellard
                   its execution. We could be more precise by checking
809 d720b93d bellard
                   that the modification is after the current PC, but it
810 d720b93d bellard
                   would require a specialized function to partially
811 d720b93d bellard
                   restore the CPU state */
812 d720b93d bellard
            
813 d720b93d bellard
            current_tb_modified = 1;
814 d720b93d bellard
            cpu_restore_state(current_tb, env, pc, puc);
815 d720b93d bellard
#if defined(TARGET_I386)
816 d720b93d bellard
            current_flags = env->hflags;
817 d720b93d bellard
            current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
818 d720b93d bellard
            current_cs_base = (target_ulong)env->segs[R_CS].base;
819 d720b93d bellard
            current_pc = current_cs_base + env->eip;
820 d720b93d bellard
#else
821 d720b93d bellard
#error unsupported CPU
822 d720b93d bellard
#endif
823 d720b93d bellard
        }
824 d720b93d bellard
#endif /* TARGET_HAS_PRECISE_SMC */
825 9fa3e853 bellard
        tb_phys_invalidate(tb, addr);
826 9fa3e853 bellard
        tb = tb->page_next[n];
827 9fa3e853 bellard
    }
828 fd6ce8f6 bellard
    p->first_tb = NULL;
829 d720b93d bellard
#ifdef TARGET_HAS_PRECISE_SMC
830 d720b93d bellard
    if (current_tb_modified) {
831 d720b93d bellard
        /* we generate a block containing just the instruction
832 d720b93d bellard
           modifying the memory. It will ensure that it cannot modify
833 d720b93d bellard
           itself */
834 ea1c1802 bellard
        env->current_tb = NULL;
835 d720b93d bellard
        tb_gen_code(env, current_pc, current_cs_base, current_flags, 
836 d720b93d bellard
                    CF_SINGLE_INSN);
837 d720b93d bellard
        cpu_resume_from_signal(env, puc);
838 d720b93d bellard
    }
839 d720b93d bellard
#endif
840 fd6ce8f6 bellard
}
841 9fa3e853 bellard
#endif
842 fd6ce8f6 bellard
843 fd6ce8f6 bellard
/* add the tb in the target page and protect it if necessary */
844 9fa3e853 bellard
static inline void tb_alloc_page(TranslationBlock *tb, 
845 53a5960a pbrook
                                 unsigned int n, target_ulong page_addr)
846 fd6ce8f6 bellard
{
847 fd6ce8f6 bellard
    PageDesc *p;
848 9fa3e853 bellard
    TranslationBlock *last_first_tb;
849 9fa3e853 bellard
850 9fa3e853 bellard
    tb->page_addr[n] = page_addr;
851 3a7d929e bellard
    p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
852 9fa3e853 bellard
    tb->page_next[n] = p->first_tb;
853 9fa3e853 bellard
    last_first_tb = p->first_tb;
854 9fa3e853 bellard
    p->first_tb = (TranslationBlock *)((long)tb | n);
855 9fa3e853 bellard
    invalidate_page_bitmap(p);
856 fd6ce8f6 bellard
857 107db443 bellard
#if defined(TARGET_HAS_SMC) || 1
858 d720b93d bellard
859 9fa3e853 bellard
#if defined(CONFIG_USER_ONLY)
860 fd6ce8f6 bellard
    if (p->flags & PAGE_WRITE) {
861 53a5960a pbrook
        target_ulong addr;
862 53a5960a pbrook
        PageDesc *p2;
863 9fa3e853 bellard
        int prot;
864 9fa3e853 bellard
865 fd6ce8f6 bellard
        /* force the host page as non writable (writes will have a
866 fd6ce8f6 bellard
           page fault + mprotect overhead) */
867 53a5960a pbrook
        page_addr &= qemu_host_page_mask;
868 fd6ce8f6 bellard
        prot = 0;
869 53a5960a pbrook
        for(addr = page_addr; addr < page_addr + qemu_host_page_size;
870 53a5960a pbrook
            addr += TARGET_PAGE_SIZE) {
871 53a5960a pbrook
872 53a5960a pbrook
            p2 = page_find (addr >> TARGET_PAGE_BITS);
873 53a5960a pbrook
            if (!p2)
874 53a5960a pbrook
                continue;
875 53a5960a pbrook
            prot |= p2->flags;
876 53a5960a pbrook
            p2->flags &= ~PAGE_WRITE;
877 53a5960a pbrook
            page_get_flags(addr);
878 53a5960a pbrook
          }
879 53a5960a pbrook
        mprotect(g2h(page_addr), qemu_host_page_size, 
880 fd6ce8f6 bellard
                 (prot & PAGE_BITS) & ~PAGE_WRITE);
881 fd6ce8f6 bellard
#ifdef DEBUG_TB_INVALIDATE
882 fd6ce8f6 bellard
        printf("protecting code page: 0x%08lx\n", 
883 53a5960a pbrook
               page_addr);
884 fd6ce8f6 bellard
#endif
885 fd6ce8f6 bellard
    }
886 9fa3e853 bellard
#else
887 9fa3e853 bellard
    /* if some code is already present, then the pages are already
888 9fa3e853 bellard
       protected. So we handle the case where only the first TB is
889 9fa3e853 bellard
       allocated in a physical page */
890 9fa3e853 bellard
    if (!last_first_tb) {
891 6a00d601 bellard
        tlb_protect_code(page_addr);
892 9fa3e853 bellard
    }
893 9fa3e853 bellard
#endif
894 d720b93d bellard
895 d720b93d bellard
#endif /* TARGET_HAS_SMC */
896 fd6ce8f6 bellard
}
897 fd6ce8f6 bellard
898 fd6ce8f6 bellard
/* Allocate a new translation block. Flush the translation buffer if
899 fd6ce8f6 bellard
   too many translation blocks or too much generated code. */
900 c27004ec bellard
TranslationBlock *tb_alloc(target_ulong pc)
901 fd6ce8f6 bellard
{
902 fd6ce8f6 bellard
    TranslationBlock *tb;
903 fd6ce8f6 bellard
904 fd6ce8f6 bellard
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
905 fd6ce8f6 bellard
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
906 d4e8164f bellard
        return NULL;
907 fd6ce8f6 bellard
    tb = &tbs[nb_tbs++];
908 fd6ce8f6 bellard
    tb->pc = pc;
909 b448f2f3 bellard
    tb->cflags = 0;
910 d4e8164f bellard
    return tb;
911 d4e8164f bellard
}
912 d4e8164f bellard
913 9fa3e853 bellard
/* add a new TB and link it to the physical page tables. phys_page2 is
914 9fa3e853 bellard
   (-1) to indicate that only one page contains the TB. */
915 9fa3e853 bellard
void tb_link_phys(TranslationBlock *tb, 
916 9fa3e853 bellard
                  target_ulong phys_pc, target_ulong phys_page2)
917 d4e8164f bellard
{
918 9fa3e853 bellard
    unsigned int h;
919 9fa3e853 bellard
    TranslationBlock **ptb;
920 9fa3e853 bellard
921 9fa3e853 bellard
    /* add in the physical hash table */
922 9fa3e853 bellard
    h = tb_phys_hash_func(phys_pc);
923 9fa3e853 bellard
    ptb = &tb_phys_hash[h];
924 9fa3e853 bellard
    tb->phys_hash_next = *ptb;
925 9fa3e853 bellard
    *ptb = tb;
926 fd6ce8f6 bellard
927 fd6ce8f6 bellard
    /* add in the page list */
928 9fa3e853 bellard
    tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
929 9fa3e853 bellard
    if (phys_page2 != -1)
930 9fa3e853 bellard
        tb_alloc_page(tb, 1, phys_page2);
931 9fa3e853 bellard
    else
932 9fa3e853 bellard
        tb->page_addr[1] = -1;
933 9fa3e853 bellard
934 d4e8164f bellard
    tb->jmp_first = (TranslationBlock *)((long)tb | 2);
935 d4e8164f bellard
    tb->jmp_next[0] = NULL;
936 d4e8164f bellard
    tb->jmp_next[1] = NULL;
937 b448f2f3 bellard
#ifdef USE_CODE_COPY
938 b448f2f3 bellard
    tb->cflags &= ~CF_FP_USED;
939 b448f2f3 bellard
    if (tb->cflags & CF_TB_FP_USED)
940 b448f2f3 bellard
        tb->cflags |= CF_FP_USED;
941 b448f2f3 bellard
#endif
942 d4e8164f bellard
943 d4e8164f bellard
    /* init original jump addresses */
944 d4e8164f bellard
    if (tb->tb_next_offset[0] != 0xffff)
945 d4e8164f bellard
        tb_reset_jump(tb, 0);
946 d4e8164f bellard
    if (tb->tb_next_offset[1] != 0xffff)
947 d4e8164f bellard
        tb_reset_jump(tb, 1);
948 8a40a180 bellard
949 8a40a180 bellard
#ifdef DEBUG_TB_CHECK
950 8a40a180 bellard
    tb_page_check();
951 8a40a180 bellard
#endif
952 fd6ce8f6 bellard
}
953 fd6ce8f6 bellard
954 9fa3e853 bellard
/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
955 9fa3e853 bellard
   tb[1].tc_ptr. Return NULL if not found */
956 9fa3e853 bellard
TranslationBlock *tb_find_pc(unsigned long tc_ptr)
957 fd6ce8f6 bellard
{
958 9fa3e853 bellard
    int m_min, m_max, m;
959 9fa3e853 bellard
    unsigned long v;
960 9fa3e853 bellard
    TranslationBlock *tb;
961 a513fe19 bellard
962 a513fe19 bellard
    if (nb_tbs <= 0)
963 a513fe19 bellard
        return NULL;
964 a513fe19 bellard
    if (tc_ptr < (unsigned long)code_gen_buffer ||
965 a513fe19 bellard
        tc_ptr >= (unsigned long)code_gen_ptr)
966 a513fe19 bellard
        return NULL;
967 a513fe19 bellard
    /* binary search (cf Knuth) */
968 a513fe19 bellard
    m_min = 0;
969 a513fe19 bellard
    m_max = nb_tbs - 1;
970 a513fe19 bellard
    while (m_min <= m_max) {
971 a513fe19 bellard
        m = (m_min + m_max) >> 1;
972 a513fe19 bellard
        tb = &tbs[m];
973 a513fe19 bellard
        v = (unsigned long)tb->tc_ptr;
974 a513fe19 bellard
        if (v == tc_ptr)
975 a513fe19 bellard
            return tb;
976 a513fe19 bellard
        else if (tc_ptr < v) {
977 a513fe19 bellard
            m_max = m - 1;
978 a513fe19 bellard
        } else {
979 a513fe19 bellard
            m_min = m + 1;
980 a513fe19 bellard
        }
981 a513fe19 bellard
    } 
982 a513fe19 bellard
    return &tbs[m_max];
983 a513fe19 bellard
}
984 7501267e bellard
985 ea041c0e bellard
static void tb_reset_jump_recursive(TranslationBlock *tb);
986 ea041c0e bellard
987 ea041c0e bellard
static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
988 ea041c0e bellard
{
989 ea041c0e bellard
    TranslationBlock *tb1, *tb_next, **ptb;
990 ea041c0e bellard
    unsigned int n1;
991 ea041c0e bellard
992 ea041c0e bellard
    tb1 = tb->jmp_next[n];
993 ea041c0e bellard
    if (tb1 != NULL) {
994 ea041c0e bellard
        /* find head of list */
995 ea041c0e bellard
        for(;;) {
996 ea041c0e bellard
            n1 = (long)tb1 & 3;
997 ea041c0e bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
998 ea041c0e bellard
            if (n1 == 2)
999 ea041c0e bellard
                break;
1000 ea041c0e bellard
            tb1 = tb1->jmp_next[n1];
1001 ea041c0e bellard
        }
1002 ea041c0e bellard
        /* we are now sure now that tb jumps to tb1 */
1003 ea041c0e bellard
        tb_next = tb1;
1004 ea041c0e bellard
1005 ea041c0e bellard
        /* remove tb from the jmp_first list */
1006 ea041c0e bellard
        ptb = &tb_next->jmp_first;
1007 ea041c0e bellard
        for(;;) {
1008 ea041c0e bellard
            tb1 = *ptb;
1009 ea041c0e bellard
            n1 = (long)tb1 & 3;
1010 ea041c0e bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
1011 ea041c0e bellard
            if (n1 == n && tb1 == tb)
1012 ea041c0e bellard
                break;
1013 ea041c0e bellard
            ptb = &tb1->jmp_next[n1];
1014 ea041c0e bellard
        }
1015 ea041c0e bellard
        *ptb = tb->jmp_next[n];
1016 ea041c0e bellard
        tb->jmp_next[n] = NULL;
1017 ea041c0e bellard
        
1018 ea041c0e bellard
        /* suppress the jump to next tb in generated code */
1019 ea041c0e bellard
        tb_reset_jump(tb, n);
1020 ea041c0e bellard
1021 0124311e bellard
        /* suppress jumps in the tb on which we could have jumped */
1022 ea041c0e bellard
        tb_reset_jump_recursive(tb_next);
1023 ea041c0e bellard
    }
1024 ea041c0e bellard
}
1025 ea041c0e bellard
1026 ea041c0e bellard
static void tb_reset_jump_recursive(TranslationBlock *tb)
1027 ea041c0e bellard
{
1028 ea041c0e bellard
    tb_reset_jump_recursive2(tb, 0);
1029 ea041c0e bellard
    tb_reset_jump_recursive2(tb, 1);
1030 ea041c0e bellard
}
1031 ea041c0e bellard
1032 1fddef4b bellard
#if defined(TARGET_HAS_ICE)
1033 d720b93d bellard
static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1034 d720b93d bellard
{
1035 9b3c35e0 j_mayer
    target_phys_addr_t addr;
1036 9b3c35e0 j_mayer
    target_ulong pd;
1037 c2f07f81 pbrook
    ram_addr_t ram_addr;
1038 c2f07f81 pbrook
    PhysPageDesc *p;
1039 d720b93d bellard
1040 c2f07f81 pbrook
    addr = cpu_get_phys_page_debug(env, pc);
1041 c2f07f81 pbrook
    p = phys_page_find(addr >> TARGET_PAGE_BITS);
1042 c2f07f81 pbrook
    if (!p) {
1043 c2f07f81 pbrook
        pd = IO_MEM_UNASSIGNED;
1044 c2f07f81 pbrook
    } else {
1045 c2f07f81 pbrook
        pd = p->phys_offset;
1046 c2f07f81 pbrook
    }
1047 c2f07f81 pbrook
    ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
1048 706cd4b5 pbrook
    tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
1049 d720b93d bellard
}
1050 c27004ec bellard
#endif
1051 d720b93d bellard
1052 6658ffb8 pbrook
/* Add a watchpoint.  */
1053 6658ffb8 pbrook
int  cpu_watchpoint_insert(CPUState *env, target_ulong addr)
1054 6658ffb8 pbrook
{
1055 6658ffb8 pbrook
    int i;
1056 6658ffb8 pbrook
1057 6658ffb8 pbrook
    for (i = 0; i < env->nb_watchpoints; i++) {
1058 6658ffb8 pbrook
        if (addr == env->watchpoint[i].vaddr)
1059 6658ffb8 pbrook
            return 0;
1060 6658ffb8 pbrook
    }
1061 6658ffb8 pbrook
    if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1062 6658ffb8 pbrook
        return -1;
1063 6658ffb8 pbrook
1064 6658ffb8 pbrook
    i = env->nb_watchpoints++;
1065 6658ffb8 pbrook
    env->watchpoint[i].vaddr = addr;
1066 6658ffb8 pbrook
    tlb_flush_page(env, addr);
1067 6658ffb8 pbrook
    /* FIXME: This flush is needed because of the hack to make memory ops
1068 6658ffb8 pbrook
       terminate the TB.  It can be removed once the proper IO trap and
1069 6658ffb8 pbrook
       re-execute bits are in.  */
1070 6658ffb8 pbrook
    tb_flush(env);
1071 6658ffb8 pbrook
    return i;
1072 6658ffb8 pbrook
}
1073 6658ffb8 pbrook
1074 6658ffb8 pbrook
/* Remove a watchpoint.  */
1075 6658ffb8 pbrook
int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
1076 6658ffb8 pbrook
{
1077 6658ffb8 pbrook
    int i;
1078 6658ffb8 pbrook
1079 6658ffb8 pbrook
    for (i = 0; i < env->nb_watchpoints; i++) {
1080 6658ffb8 pbrook
        if (addr == env->watchpoint[i].vaddr) {
1081 6658ffb8 pbrook
            env->nb_watchpoints--;
1082 6658ffb8 pbrook
            env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1083 6658ffb8 pbrook
            tlb_flush_page(env, addr);
1084 6658ffb8 pbrook
            return 0;
1085 6658ffb8 pbrook
        }
1086 6658ffb8 pbrook
    }
1087 6658ffb8 pbrook
    return -1;
1088 6658ffb8 pbrook
}
1089 6658ffb8 pbrook
1090 c33a346e bellard
/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1091 c33a346e bellard
   breakpoint is reached */
1092 2e12669a bellard
int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
1093 4c3a88a2 bellard
{
1094 1fddef4b bellard
#if defined(TARGET_HAS_ICE)
1095 4c3a88a2 bellard
    int i;
1096 d720b93d bellard
    
1097 4c3a88a2 bellard
    for(i = 0; i < env->nb_breakpoints; i++) {
1098 4c3a88a2 bellard
        if (env->breakpoints[i] == pc)
1099 4c3a88a2 bellard
            return 0;
1100 4c3a88a2 bellard
    }
1101 4c3a88a2 bellard
1102 4c3a88a2 bellard
    if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1103 4c3a88a2 bellard
        return -1;
1104 4c3a88a2 bellard
    env->breakpoints[env->nb_breakpoints++] = pc;
1105 d720b93d bellard
    
1106 d720b93d bellard
    breakpoint_invalidate(env, pc);
1107 4c3a88a2 bellard
    return 0;
1108 4c3a88a2 bellard
#else
1109 4c3a88a2 bellard
    return -1;
1110 4c3a88a2 bellard
#endif
1111 4c3a88a2 bellard
}
1112 4c3a88a2 bellard
1113 4c3a88a2 bellard
/* remove a breakpoint */
1114 2e12669a bellard
int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
1115 4c3a88a2 bellard
{
1116 1fddef4b bellard
#if defined(TARGET_HAS_ICE)
1117 4c3a88a2 bellard
    int i;
1118 4c3a88a2 bellard
    for(i = 0; i < env->nb_breakpoints; i++) {
1119 4c3a88a2 bellard
        if (env->breakpoints[i] == pc)
1120 4c3a88a2 bellard
            goto found;
1121 4c3a88a2 bellard
    }
1122 4c3a88a2 bellard
    return -1;
1123 4c3a88a2 bellard
 found:
1124 4c3a88a2 bellard
    env->nb_breakpoints--;
1125 1fddef4b bellard
    if (i < env->nb_breakpoints)
1126 1fddef4b bellard
      env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
1127 d720b93d bellard
1128 d720b93d bellard
    breakpoint_invalidate(env, pc);
1129 4c3a88a2 bellard
    return 0;
1130 4c3a88a2 bellard
#else
1131 4c3a88a2 bellard
    return -1;
1132 4c3a88a2 bellard
#endif
1133 4c3a88a2 bellard
}
1134 4c3a88a2 bellard
1135 c33a346e bellard
/* enable or disable single step mode. EXCP_DEBUG is returned by the
1136 c33a346e bellard
   CPU loop after each instruction */
1137 c33a346e bellard
void cpu_single_step(CPUState *env, int enabled)
1138 c33a346e bellard
{
1139 1fddef4b bellard
#if defined(TARGET_HAS_ICE)
1140 c33a346e bellard
    if (env->singlestep_enabled != enabled) {
1141 c33a346e bellard
        env->singlestep_enabled = enabled;
1142 c33a346e bellard
        /* must flush all the translated code to avoid inconsistancies */
1143 9fa3e853 bellard
        /* XXX: only flush what is necessary */
1144 0124311e bellard
        tb_flush(env);
1145 c33a346e bellard
    }
1146 c33a346e bellard
#endif
1147 c33a346e bellard
}
1148 c33a346e bellard
1149 34865134 bellard
/* enable or disable low levels log */
1150 34865134 bellard
void cpu_set_log(int log_flags)
1151 34865134 bellard
{
1152 34865134 bellard
    loglevel = log_flags;
1153 34865134 bellard
    if (loglevel && !logfile) {
1154 34865134 bellard
        logfile = fopen(logfilename, "w");
1155 34865134 bellard
        if (!logfile) {
1156 34865134 bellard
            perror(logfilename);
1157 34865134 bellard
            _exit(1);
1158 34865134 bellard
        }
1159 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
1160 9fa3e853 bellard
        /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
1161 9fa3e853 bellard
        {
1162 9fa3e853 bellard
            static uint8_t logfile_buf[4096];
1163 9fa3e853 bellard
            setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
1164 9fa3e853 bellard
        }
1165 9fa3e853 bellard
#else
1166 34865134 bellard
        setvbuf(logfile, NULL, _IOLBF, 0);
1167 9fa3e853 bellard
#endif
1168 34865134 bellard
    }
1169 34865134 bellard
}
1170 34865134 bellard
1171 34865134 bellard
void cpu_set_log_filename(const char *filename)
1172 34865134 bellard
{
1173 34865134 bellard
    logfilename = strdup(filename);
1174 34865134 bellard
}
1175 c33a346e bellard
1176 0124311e bellard
/* mask must never be zero, except for A20 change call */
1177 68a79315 bellard
void cpu_interrupt(CPUState *env, int mask)
1178 ea041c0e bellard
{
1179 ea041c0e bellard
    TranslationBlock *tb;
1180 ee8b7021 bellard
    static int interrupt_lock;
1181 59817ccb bellard
1182 68a79315 bellard
    env->interrupt_request |= mask;
1183 ea041c0e bellard
    /* if the cpu is currently executing code, we must unlink it and
1184 ea041c0e bellard
       all the potentially executing TB */
1185 ea041c0e bellard
    tb = env->current_tb;
1186 ee8b7021 bellard
    if (tb && !testandset(&interrupt_lock)) {
1187 ee8b7021 bellard
        env->current_tb = NULL;
1188 ea041c0e bellard
        tb_reset_jump_recursive(tb);
1189 ee8b7021 bellard
        interrupt_lock = 0;
1190 ea041c0e bellard
    }
1191 ea041c0e bellard
}
1192 ea041c0e bellard
1193 b54ad049 bellard
void cpu_reset_interrupt(CPUState *env, int mask)
1194 b54ad049 bellard
{
1195 b54ad049 bellard
    env->interrupt_request &= ~mask;
1196 b54ad049 bellard
}
1197 b54ad049 bellard
1198 f193c797 bellard
CPULogItem cpu_log_items[] = {
1199 f193c797 bellard
    { CPU_LOG_TB_OUT_ASM, "out_asm", 
1200 f193c797 bellard
      "show generated host assembly code for each compiled TB" },
1201 f193c797 bellard
    { CPU_LOG_TB_IN_ASM, "in_asm",
1202 f193c797 bellard
      "show target assembly code for each compiled TB" },
1203 f193c797 bellard
    { CPU_LOG_TB_OP, "op", 
1204 f193c797 bellard
      "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
1205 f193c797 bellard
#ifdef TARGET_I386
1206 f193c797 bellard
    { CPU_LOG_TB_OP_OPT, "op_opt",
1207 f193c797 bellard
      "show micro ops after optimization for each compiled TB" },
1208 f193c797 bellard
#endif
1209 f193c797 bellard
    { CPU_LOG_INT, "int",
1210 f193c797 bellard
      "show interrupts/exceptions in short format" },
1211 f193c797 bellard
    { CPU_LOG_EXEC, "exec",
1212 f193c797 bellard
      "show trace before each executed TB (lots of logs)" },
1213 9fddaa0c bellard
    { CPU_LOG_TB_CPU, "cpu",
1214 9fddaa0c bellard
      "show CPU state before bloc translation" },
1215 f193c797 bellard
#ifdef TARGET_I386
1216 f193c797 bellard
    { CPU_LOG_PCALL, "pcall",
1217 f193c797 bellard
      "show protected mode far calls/returns/exceptions" },
1218 f193c797 bellard
#endif
1219 8e3a9fd2 bellard
#ifdef DEBUG_IOPORT
1220 fd872598 bellard
    { CPU_LOG_IOPORT, "ioport",
1221 fd872598 bellard
      "show all i/o ports accesses" },
1222 8e3a9fd2 bellard
#endif
1223 f193c797 bellard
    { 0, NULL, NULL },
1224 f193c797 bellard
};
1225 f193c797 bellard
1226 f193c797 bellard
static int cmp1(const char *s1, int n, const char *s2)
1227 f193c797 bellard
{
1228 f193c797 bellard
    if (strlen(s2) != n)
1229 f193c797 bellard
        return 0;
1230 f193c797 bellard
    return memcmp(s1, s2, n) == 0;
1231 f193c797 bellard
}
1232 f193c797 bellard
      
1233 f193c797 bellard
/* takes a comma separated list of log masks. Return 0 if error. */
1234 f193c797 bellard
int cpu_str_to_log_mask(const char *str)
1235 f193c797 bellard
{
1236 f193c797 bellard
    CPULogItem *item;
1237 f193c797 bellard
    int mask;
1238 f193c797 bellard
    const char *p, *p1;
1239 f193c797 bellard
1240 f193c797 bellard
    p = str;
1241 f193c797 bellard
    mask = 0;
1242 f193c797 bellard
    for(;;) {
1243 f193c797 bellard
        p1 = strchr(p, ',');
1244 f193c797 bellard
        if (!p1)
1245 f193c797 bellard
            p1 = p + strlen(p);
1246 8e3a9fd2 bellard
        if(cmp1(p,p1-p,"all")) {
1247 8e3a9fd2 bellard
                for(item = cpu_log_items; item->mask != 0; item++) {
1248 8e3a9fd2 bellard
                        mask |= item->mask;
1249 8e3a9fd2 bellard
                }
1250 8e3a9fd2 bellard
        } else {
1251 f193c797 bellard
        for(item = cpu_log_items; item->mask != 0; item++) {
1252 f193c797 bellard
            if (cmp1(p, p1 - p, item->name))
1253 f193c797 bellard
                goto found;
1254 f193c797 bellard
        }
1255 f193c797 bellard
        return 0;
1256 8e3a9fd2 bellard
        }
1257 f193c797 bellard
    found:
1258 f193c797 bellard
        mask |= item->mask;
1259 f193c797 bellard
        if (*p1 != ',')
1260 f193c797 bellard
            break;
1261 f193c797 bellard
        p = p1 + 1;
1262 f193c797 bellard
    }
1263 f193c797 bellard
    return mask;
1264 f193c797 bellard
}
1265 ea041c0e bellard
1266 7501267e bellard
void cpu_abort(CPUState *env, const char *fmt, ...)
1267 7501267e bellard
{
1268 7501267e bellard
    va_list ap;
1269 7501267e bellard
1270 7501267e bellard
    va_start(ap, fmt);
1271 7501267e bellard
    fprintf(stderr, "qemu: fatal: ");
1272 7501267e bellard
    vfprintf(stderr, fmt, ap);
1273 7501267e bellard
    fprintf(stderr, "\n");
1274 7501267e bellard
#ifdef TARGET_I386
1275 7fe48483 bellard
    cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
1276 7fe48483 bellard
#else
1277 7fe48483 bellard
    cpu_dump_state(env, stderr, fprintf, 0);
1278 7501267e bellard
#endif
1279 7501267e bellard
    va_end(ap);
1280 7501267e bellard
    abort();
1281 7501267e bellard
}
1282 7501267e bellard
1283 c5be9f08 ths
CPUState *cpu_copy(CPUState *env)
1284 c5be9f08 ths
{
1285 c5be9f08 ths
    CPUState *new_env = cpu_init();
1286 c5be9f08 ths
    /* preserve chaining and index */
1287 c5be9f08 ths
    CPUState *next_cpu = new_env->next_cpu;
1288 c5be9f08 ths
    int cpu_index = new_env->cpu_index;
1289 c5be9f08 ths
    memcpy(new_env, env, sizeof(CPUState));
1290 c5be9f08 ths
    new_env->next_cpu = next_cpu;
1291 c5be9f08 ths
    new_env->cpu_index = cpu_index;
1292 c5be9f08 ths
    return new_env;
1293 c5be9f08 ths
}
1294 c5be9f08 ths
1295 0124311e bellard
#if !defined(CONFIG_USER_ONLY)
1296 0124311e bellard
1297 ee8b7021 bellard
/* NOTE: if flush_global is true, also flush global entries (not
1298 ee8b7021 bellard
   implemented yet) */
1299 ee8b7021 bellard
void tlb_flush(CPUState *env, int flush_global)
1300 33417e70 bellard
{
1301 33417e70 bellard
    int i;
1302 0124311e bellard
1303 9fa3e853 bellard
#if defined(DEBUG_TLB)
1304 9fa3e853 bellard
    printf("tlb_flush:\n");
1305 9fa3e853 bellard
#endif
1306 0124311e bellard
    /* must reset current TB so that interrupts cannot modify the
1307 0124311e bellard
       links while we are modifying them */
1308 0124311e bellard
    env->current_tb = NULL;
1309 0124311e bellard
1310 33417e70 bellard
    for(i = 0; i < CPU_TLB_SIZE; i++) {
1311 84b7b8e7 bellard
        env->tlb_table[0][i].addr_read = -1;
1312 84b7b8e7 bellard
        env->tlb_table[0][i].addr_write = -1;
1313 84b7b8e7 bellard
        env->tlb_table[0][i].addr_code = -1;
1314 84b7b8e7 bellard
        env->tlb_table[1][i].addr_read = -1;
1315 84b7b8e7 bellard
        env->tlb_table[1][i].addr_write = -1;
1316 84b7b8e7 bellard
        env->tlb_table[1][i].addr_code = -1;
1317 6fa4cea9 j_mayer
#if (NB_MMU_MODES >= 3)
1318 6fa4cea9 j_mayer
        env->tlb_table[2][i].addr_read = -1;
1319 6fa4cea9 j_mayer
        env->tlb_table[2][i].addr_write = -1;
1320 6fa4cea9 j_mayer
        env->tlb_table[2][i].addr_code = -1;
1321 6fa4cea9 j_mayer
#if (NB_MMU_MODES == 4)
1322 6fa4cea9 j_mayer
        env->tlb_table[3][i].addr_read = -1;
1323 6fa4cea9 j_mayer
        env->tlb_table[3][i].addr_write = -1;
1324 6fa4cea9 j_mayer
        env->tlb_table[3][i].addr_code = -1;
1325 6fa4cea9 j_mayer
#endif
1326 6fa4cea9 j_mayer
#endif
1327 33417e70 bellard
    }
1328 9fa3e853 bellard
1329 8a40a180 bellard
    memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
1330 9fa3e853 bellard
1331 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
1332 9fa3e853 bellard
    munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1333 9fa3e853 bellard
#endif
1334 0a962c02 bellard
#ifdef USE_KQEMU
1335 0a962c02 bellard
    if (env->kqemu_enabled) {
1336 0a962c02 bellard
        kqemu_flush(env, flush_global);
1337 0a962c02 bellard
    }
1338 0a962c02 bellard
#endif
1339 e3db7226 bellard
    tlb_flush_count++;
1340 33417e70 bellard
}
1341 33417e70 bellard
1342 274da6b2 bellard
static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
1343 61382a50 bellard
{
1344 84b7b8e7 bellard
    if (addr == (tlb_entry->addr_read & 
1345 84b7b8e7 bellard
                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1346 84b7b8e7 bellard
        addr == (tlb_entry->addr_write & 
1347 84b7b8e7 bellard
                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
1348 84b7b8e7 bellard
        addr == (tlb_entry->addr_code & 
1349 84b7b8e7 bellard
                 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1350 84b7b8e7 bellard
        tlb_entry->addr_read = -1;
1351 84b7b8e7 bellard
        tlb_entry->addr_write = -1;
1352 84b7b8e7 bellard
        tlb_entry->addr_code = -1;
1353 84b7b8e7 bellard
    }
1354 61382a50 bellard
}
1355 61382a50 bellard
1356 2e12669a bellard
void tlb_flush_page(CPUState *env, target_ulong addr)
1357 33417e70 bellard
{
1358 8a40a180 bellard
    int i;
1359 9fa3e853 bellard
    TranslationBlock *tb;
1360 0124311e bellard
1361 9fa3e853 bellard
#if defined(DEBUG_TLB)
1362 108c49b8 bellard
    printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
1363 9fa3e853 bellard
#endif
1364 0124311e bellard
    /* must reset current TB so that interrupts cannot modify the
1365 0124311e bellard
       links while we are modifying them */
1366 0124311e bellard
    env->current_tb = NULL;
1367 61382a50 bellard
1368 61382a50 bellard
    addr &= TARGET_PAGE_MASK;
1369 61382a50 bellard
    i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1370 84b7b8e7 bellard
    tlb_flush_entry(&env->tlb_table[0][i], addr);
1371 84b7b8e7 bellard
    tlb_flush_entry(&env->tlb_table[1][i], addr);
1372 6fa4cea9 j_mayer
#if (NB_MMU_MODES >= 3)
1373 6fa4cea9 j_mayer
    tlb_flush_entry(&env->tlb_table[2][i], addr);
1374 6fa4cea9 j_mayer
#if (NB_MMU_MODES == 4)
1375 6fa4cea9 j_mayer
    tlb_flush_entry(&env->tlb_table[3][i], addr);
1376 6fa4cea9 j_mayer
#endif
1377 6fa4cea9 j_mayer
#endif
1378 0124311e bellard
1379 b362e5e0 pbrook
    /* Discard jump cache entries for any tb which might potentially
1380 b362e5e0 pbrook
       overlap the flushed page.  */
1381 b362e5e0 pbrook
    i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
1382 b362e5e0 pbrook
    memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
1383 b362e5e0 pbrook
1384 b362e5e0 pbrook
    i = tb_jmp_cache_hash_page(addr);
1385 b362e5e0 pbrook
    memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb));
1386 9fa3e853 bellard
1387 0124311e bellard
#if !defined(CONFIG_SOFTMMU)
1388 9fa3e853 bellard
    if (addr < MMAP_AREA_END)
1389 0124311e bellard
        munmap((void *)addr, TARGET_PAGE_SIZE);
1390 61382a50 bellard
#endif
1391 0a962c02 bellard
#ifdef USE_KQEMU
1392 0a962c02 bellard
    if (env->kqemu_enabled) {
1393 0a962c02 bellard
        kqemu_flush_page(env, addr);
1394 0a962c02 bellard
    }
1395 0a962c02 bellard
#endif
1396 9fa3e853 bellard
}
1397 9fa3e853 bellard
1398 9fa3e853 bellard
/* update the TLBs so that writes to code in the virtual page 'addr'
1399 9fa3e853 bellard
   can be detected */
1400 6a00d601 bellard
static void tlb_protect_code(ram_addr_t ram_addr)
1401 9fa3e853 bellard
{
1402 6a00d601 bellard
    cpu_physical_memory_reset_dirty(ram_addr, 
1403 6a00d601 bellard
                                    ram_addr + TARGET_PAGE_SIZE,
1404 6a00d601 bellard
                                    CODE_DIRTY_FLAG);
1405 9fa3e853 bellard
}
1406 9fa3e853 bellard
1407 9fa3e853 bellard
/* update the TLB so that writes in physical page 'phys_addr' are no longer
1408 3a7d929e bellard
   tested for self modifying code */
1409 3a7d929e bellard
static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, 
1410 3a7d929e bellard
                                    target_ulong vaddr)
1411 9fa3e853 bellard
{
1412 3a7d929e bellard
    phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
1413 1ccde1cb bellard
}
1414 1ccde1cb bellard
1415 1ccde1cb bellard
static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, 
1416 1ccde1cb bellard
                                         unsigned long start, unsigned long length)
1417 1ccde1cb bellard
{
1418 1ccde1cb bellard
    unsigned long addr;
1419 84b7b8e7 bellard
    if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1420 84b7b8e7 bellard
        addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
1421 1ccde1cb bellard
        if ((addr - start) < length) {
1422 84b7b8e7 bellard
            tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1423 1ccde1cb bellard
        }
1424 1ccde1cb bellard
    }
1425 1ccde1cb bellard
}
1426 1ccde1cb bellard
1427 3a7d929e bellard
void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
1428 0a962c02 bellard
                                     int dirty_flags)
1429 1ccde1cb bellard
{
1430 1ccde1cb bellard
    CPUState *env;
1431 4f2ac237 bellard
    unsigned long length, start1;
1432 0a962c02 bellard
    int i, mask, len;
1433 0a962c02 bellard
    uint8_t *p;
1434 1ccde1cb bellard
1435 1ccde1cb bellard
    start &= TARGET_PAGE_MASK;
1436 1ccde1cb bellard
    end = TARGET_PAGE_ALIGN(end);
1437 1ccde1cb bellard
1438 1ccde1cb bellard
    length = end - start;
1439 1ccde1cb bellard
    if (length == 0)
1440 1ccde1cb bellard
        return;
1441 0a962c02 bellard
    len = length >> TARGET_PAGE_BITS;
1442 3a7d929e bellard
#ifdef USE_KQEMU
1443 6a00d601 bellard
    /* XXX: should not depend on cpu context */
1444 6a00d601 bellard
    env = first_cpu;
1445 3a7d929e bellard
    if (env->kqemu_enabled) {
1446 f23db169 bellard
        ram_addr_t addr;
1447 f23db169 bellard
        addr = start;
1448 f23db169 bellard
        for(i = 0; i < len; i++) {
1449 f23db169 bellard
            kqemu_set_notdirty(env, addr);
1450 f23db169 bellard
            addr += TARGET_PAGE_SIZE;
1451 f23db169 bellard
        }
1452 3a7d929e bellard
    }
1453 3a7d929e bellard
#endif
1454 f23db169 bellard
    mask = ~dirty_flags;
1455 f23db169 bellard
    p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
1456 f23db169 bellard
    for(i = 0; i < len; i++)
1457 f23db169 bellard
        p[i] &= mask;
1458 f23db169 bellard
1459 1ccde1cb bellard
    /* we modify the TLB cache so that the dirty bit will be set again
1460 1ccde1cb bellard
       when accessing the range */
1461 59817ccb bellard
    start1 = start + (unsigned long)phys_ram_base;
1462 6a00d601 bellard
    for(env = first_cpu; env != NULL; env = env->next_cpu) {
1463 6a00d601 bellard
        for(i = 0; i < CPU_TLB_SIZE; i++)
1464 84b7b8e7 bellard
            tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
1465 6a00d601 bellard
        for(i = 0; i < CPU_TLB_SIZE; i++)
1466 84b7b8e7 bellard
            tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
1467 6fa4cea9 j_mayer
#if (NB_MMU_MODES >= 3)
1468 6fa4cea9 j_mayer
        for(i = 0; i < CPU_TLB_SIZE; i++)
1469 6fa4cea9 j_mayer
            tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
1470 6fa4cea9 j_mayer
#if (NB_MMU_MODES == 4)
1471 6fa4cea9 j_mayer
        for(i = 0; i < CPU_TLB_SIZE; i++)
1472 6fa4cea9 j_mayer
            tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
1473 6fa4cea9 j_mayer
#endif
1474 6fa4cea9 j_mayer
#endif
1475 6a00d601 bellard
    }
1476 59817ccb bellard
1477 59817ccb bellard
#if !defined(CONFIG_SOFTMMU)
1478 59817ccb bellard
    /* XXX: this is expensive */
1479 59817ccb bellard
    {
1480 59817ccb bellard
        VirtPageDesc *p;
1481 59817ccb bellard
        int j;
1482 59817ccb bellard
        target_ulong addr;
1483 59817ccb bellard
1484 59817ccb bellard
        for(i = 0; i < L1_SIZE; i++) {
1485 59817ccb bellard
            p = l1_virt_map[i];
1486 59817ccb bellard
            if (p) {
1487 59817ccb bellard
                addr = i << (TARGET_PAGE_BITS + L2_BITS);
1488 59817ccb bellard
                for(j = 0; j < L2_SIZE; j++) {
1489 59817ccb bellard
                    if (p->valid_tag == virt_valid_tag &&
1490 59817ccb bellard
                        p->phys_addr >= start && p->phys_addr < end &&
1491 59817ccb bellard
                        (p->prot & PROT_WRITE)) {
1492 59817ccb bellard
                        if (addr < MMAP_AREA_END) {
1493 59817ccb bellard
                            mprotect((void *)addr, TARGET_PAGE_SIZE, 
1494 59817ccb bellard
                                     p->prot & ~PROT_WRITE);
1495 59817ccb bellard
                        }
1496 59817ccb bellard
                    }
1497 59817ccb bellard
                    addr += TARGET_PAGE_SIZE;
1498 59817ccb bellard
                    p++;
1499 59817ccb bellard
                }
1500 59817ccb bellard
            }
1501 59817ccb bellard
        }
1502 59817ccb bellard
    }
1503 59817ccb bellard
#endif
1504 1ccde1cb bellard
}
1505 1ccde1cb bellard
1506 3a7d929e bellard
static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1507 3a7d929e bellard
{
1508 3a7d929e bellard
    ram_addr_t ram_addr;
1509 3a7d929e bellard
1510 84b7b8e7 bellard
    if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1511 84b7b8e7 bellard
        ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + 
1512 3a7d929e bellard
            tlb_entry->addend - (unsigned long)phys_ram_base;
1513 3a7d929e bellard
        if (!cpu_physical_memory_is_dirty(ram_addr)) {
1514 84b7b8e7 bellard
            tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
1515 3a7d929e bellard
        }
1516 3a7d929e bellard
    }
1517 3a7d929e bellard
}
1518 3a7d929e bellard
1519 3a7d929e bellard
/* update the TLB according to the current state of the dirty bits */
1520 3a7d929e bellard
void cpu_tlb_update_dirty(CPUState *env)
1521 3a7d929e bellard
{
1522 3a7d929e bellard
    int i;
1523 3a7d929e bellard
    for(i = 0; i < CPU_TLB_SIZE; i++)
1524 84b7b8e7 bellard
        tlb_update_dirty(&env->tlb_table[0][i]);
1525 3a7d929e bellard
    for(i = 0; i < CPU_TLB_SIZE; i++)
1526 84b7b8e7 bellard
        tlb_update_dirty(&env->tlb_table[1][i]);
1527 6fa4cea9 j_mayer
#if (NB_MMU_MODES >= 3)
1528 6fa4cea9 j_mayer
    for(i = 0; i < CPU_TLB_SIZE; i++)
1529 6fa4cea9 j_mayer
        tlb_update_dirty(&env->tlb_table[2][i]);
1530 6fa4cea9 j_mayer
#if (NB_MMU_MODES == 4)
1531 6fa4cea9 j_mayer
    for(i = 0; i < CPU_TLB_SIZE; i++)
1532 6fa4cea9 j_mayer
        tlb_update_dirty(&env->tlb_table[3][i]);
1533 6fa4cea9 j_mayer
#endif
1534 6fa4cea9 j_mayer
#endif
1535 3a7d929e bellard
}
1536 3a7d929e bellard
1537 1ccde1cb bellard
static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, 
1538 108c49b8 bellard
                                  unsigned long start)
1539 1ccde1cb bellard
{
1540 1ccde1cb bellard
    unsigned long addr;
1541 84b7b8e7 bellard
    if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1542 84b7b8e7 bellard
        addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
1543 1ccde1cb bellard
        if (addr == start) {
1544 84b7b8e7 bellard
            tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
1545 1ccde1cb bellard
        }
1546 1ccde1cb bellard
    }
1547 1ccde1cb bellard
}
1548 1ccde1cb bellard
1549 1ccde1cb bellard
/* update the TLB corresponding to virtual page vaddr and phys addr
1550 1ccde1cb bellard
   addr so that it is no longer dirty */
1551 6a00d601 bellard
static inline void tlb_set_dirty(CPUState *env,
1552 6a00d601 bellard
                                 unsigned long addr, target_ulong vaddr)
1553 1ccde1cb bellard
{
1554 1ccde1cb bellard
    int i;
1555 1ccde1cb bellard
1556 1ccde1cb bellard
    addr &= TARGET_PAGE_MASK;
1557 1ccde1cb bellard
    i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1558 84b7b8e7 bellard
    tlb_set_dirty1(&env->tlb_table[0][i], addr);
1559 84b7b8e7 bellard
    tlb_set_dirty1(&env->tlb_table[1][i], addr);
1560 6fa4cea9 j_mayer
#if (NB_MMU_MODES >= 3)
1561 6fa4cea9 j_mayer
    tlb_set_dirty1(&env->tlb_table[2][i], addr);
1562 6fa4cea9 j_mayer
#if (NB_MMU_MODES == 4)
1563 6fa4cea9 j_mayer
    tlb_set_dirty1(&env->tlb_table[3][i], addr);
1564 6fa4cea9 j_mayer
#endif
1565 6fa4cea9 j_mayer
#endif
1566 9fa3e853 bellard
}
1567 9fa3e853 bellard
1568 59817ccb bellard
/* add a new TLB entry. At most one entry for a given virtual address
1569 59817ccb bellard
   is permitted. Return 0 if OK or 2 if the page could not be mapped
1570 59817ccb bellard
   (can only happen in non SOFTMMU mode for I/O pages or pages
1571 59817ccb bellard
   conflicting with the host address space). */
1572 84b7b8e7 bellard
int tlb_set_page_exec(CPUState *env, target_ulong vaddr, 
1573 84b7b8e7 bellard
                      target_phys_addr_t paddr, int prot, 
1574 84b7b8e7 bellard
                      int is_user, int is_softmmu)
1575 9fa3e853 bellard
{
1576 92e873b9 bellard
    PhysPageDesc *p;
1577 4f2ac237 bellard
    unsigned long pd;
1578 9fa3e853 bellard
    unsigned int index;
1579 4f2ac237 bellard
    target_ulong address;
1580 108c49b8 bellard
    target_phys_addr_t addend;
1581 9fa3e853 bellard
    int ret;
1582 84b7b8e7 bellard
    CPUTLBEntry *te;
1583 6658ffb8 pbrook
    int i;
1584 9fa3e853 bellard
1585 92e873b9 bellard
    p = phys_page_find(paddr >> TARGET_PAGE_BITS);
1586 9fa3e853 bellard
    if (!p) {
1587 9fa3e853 bellard
        pd = IO_MEM_UNASSIGNED;
1588 9fa3e853 bellard
    } else {
1589 9fa3e853 bellard
        pd = p->phys_offset;
1590 9fa3e853 bellard
    }
1591 9fa3e853 bellard
#if defined(DEBUG_TLB)
1592 3a7d929e bellard
    printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n",
1593 84b7b8e7 bellard
           vaddr, (int)paddr, prot, is_user, is_softmmu, pd);
1594 9fa3e853 bellard
#endif
1595 9fa3e853 bellard
1596 9fa3e853 bellard
    ret = 0;
1597 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
1598 9fa3e853 bellard
    if (is_softmmu) 
1599 9fa3e853 bellard
#endif
1600 9fa3e853 bellard
    {
1601 2a4188a3 bellard
        if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
1602 9fa3e853 bellard
            /* IO memory case */
1603 9fa3e853 bellard
            address = vaddr | pd;
1604 9fa3e853 bellard
            addend = paddr;
1605 9fa3e853 bellard
        } else {
1606 9fa3e853 bellard
            /* standard memory */
1607 9fa3e853 bellard
            address = vaddr;
1608 9fa3e853 bellard
            addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1609 9fa3e853 bellard
        }
1610 6658ffb8 pbrook
1611 6658ffb8 pbrook
        /* Make accesses to pages with watchpoints go via the
1612 6658ffb8 pbrook
           watchpoint trap routines.  */
1613 6658ffb8 pbrook
        for (i = 0; i < env->nb_watchpoints; i++) {
1614 6658ffb8 pbrook
            if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
1615 6658ffb8 pbrook
                if (address & ~TARGET_PAGE_MASK) {
1616 6658ffb8 pbrook
                    env->watchpoint[i].is_ram = 0;
1617 6658ffb8 pbrook
                    address = vaddr | io_mem_watch;
1618 6658ffb8 pbrook
                } else {
1619 6658ffb8 pbrook
                    env->watchpoint[i].is_ram = 1;
1620 6658ffb8 pbrook
                    /* TODO: Figure out how to make read watchpoints coexist
1621 6658ffb8 pbrook
                       with code.  */
1622 6658ffb8 pbrook
                    pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
1623 6658ffb8 pbrook
                }
1624 6658ffb8 pbrook
            }
1625 6658ffb8 pbrook
        }
1626 9fa3e853 bellard
        
1627 90f18422 bellard
        index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1628 9fa3e853 bellard
        addend -= vaddr;
1629 84b7b8e7 bellard
        te = &env->tlb_table[is_user][index];
1630 84b7b8e7 bellard
        te->addend = addend;
1631 67b915a5 bellard
        if (prot & PAGE_READ) {
1632 84b7b8e7 bellard
            te->addr_read = address;
1633 84b7b8e7 bellard
        } else {
1634 84b7b8e7 bellard
            te->addr_read = -1;
1635 84b7b8e7 bellard
        }
1636 84b7b8e7 bellard
        if (prot & PAGE_EXEC) {
1637 84b7b8e7 bellard
            te->addr_code = address;
1638 9fa3e853 bellard
        } else {
1639 84b7b8e7 bellard
            te->addr_code = -1;
1640 9fa3e853 bellard
        }
1641 67b915a5 bellard
        if (prot & PAGE_WRITE) {
1642 856074ec bellard
            if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || 
1643 856074ec bellard
                (pd & IO_MEM_ROMD)) {
1644 856074ec bellard
                /* write access calls the I/O callback */
1645 856074ec bellard
                te->addr_write = vaddr | 
1646 856074ec bellard
                    (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
1647 3a7d929e bellard
            } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && 
1648 1ccde1cb bellard
                       !cpu_physical_memory_is_dirty(pd)) {
1649 84b7b8e7 bellard
                te->addr_write = vaddr | IO_MEM_NOTDIRTY;
1650 9fa3e853 bellard
            } else {
1651 84b7b8e7 bellard
                te->addr_write = address;
1652 9fa3e853 bellard
            }
1653 9fa3e853 bellard
        } else {
1654 84b7b8e7 bellard
            te->addr_write = -1;
1655 9fa3e853 bellard
        }
1656 9fa3e853 bellard
    }
1657 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
1658 9fa3e853 bellard
    else {
1659 9fa3e853 bellard
        if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1660 9fa3e853 bellard
            /* IO access: no mapping is done as it will be handled by the
1661 9fa3e853 bellard
               soft MMU */
1662 9fa3e853 bellard
            if (!(env->hflags & HF_SOFTMMU_MASK))
1663 9fa3e853 bellard
                ret = 2;
1664 9fa3e853 bellard
        } else {
1665 9fa3e853 bellard
            void *map_addr;
1666 59817ccb bellard
1667 59817ccb bellard
            if (vaddr >= MMAP_AREA_END) {
1668 59817ccb bellard
                ret = 2;
1669 59817ccb bellard
            } else {
1670 59817ccb bellard
                if (prot & PROT_WRITE) {
1671 59817ccb bellard
                    if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || 
1672 d720b93d bellard
#if defined(TARGET_HAS_SMC) || 1
1673 59817ccb bellard
                        first_tb ||
1674 d720b93d bellard
#endif
1675 59817ccb bellard
                        ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && 
1676 59817ccb bellard
                         !cpu_physical_memory_is_dirty(pd))) {
1677 59817ccb bellard
                        /* ROM: we do as if code was inside */
1678 59817ccb bellard
                        /* if code is present, we only map as read only and save the
1679 59817ccb bellard
                           original mapping */
1680 59817ccb bellard
                        VirtPageDesc *vp;
1681 59817ccb bellard
                        
1682 90f18422 bellard
                        vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
1683 59817ccb bellard
                        vp->phys_addr = pd;
1684 59817ccb bellard
                        vp->prot = prot;
1685 59817ccb bellard
                        vp->valid_tag = virt_valid_tag;
1686 59817ccb bellard
                        prot &= ~PAGE_WRITE;
1687 59817ccb bellard
                    }
1688 59817ccb bellard
                }
1689 59817ccb bellard
                map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot, 
1690 59817ccb bellard
                                MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1691 59817ccb bellard
                if (map_addr == MAP_FAILED) {
1692 59817ccb bellard
                    cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1693 59817ccb bellard
                              paddr, vaddr);
1694 9fa3e853 bellard
                }
1695 9fa3e853 bellard
            }
1696 9fa3e853 bellard
        }
1697 9fa3e853 bellard
    }
1698 9fa3e853 bellard
#endif
1699 9fa3e853 bellard
    return ret;
1700 9fa3e853 bellard
}
1701 9fa3e853 bellard
1702 9fa3e853 bellard
/* called from signal handler: invalidate the code and unprotect the
1703 9fa3e853 bellard
   page. Return TRUE if the fault was succesfully handled. */
1704 53a5960a pbrook
int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
1705 9fa3e853 bellard
{
1706 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
1707 9fa3e853 bellard
    VirtPageDesc *vp;
1708 9fa3e853 bellard
1709 9fa3e853 bellard
#if defined(DEBUG_TLB)
1710 9fa3e853 bellard
    printf("page_unprotect: addr=0x%08x\n", addr);
1711 9fa3e853 bellard
#endif
1712 9fa3e853 bellard
    addr &= TARGET_PAGE_MASK;
1713 59817ccb bellard
1714 59817ccb bellard
    /* if it is not mapped, no need to worry here */
1715 59817ccb bellard
    if (addr >= MMAP_AREA_END)
1716 59817ccb bellard
        return 0;
1717 9fa3e853 bellard
    vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1718 9fa3e853 bellard
    if (!vp)
1719 9fa3e853 bellard
        return 0;
1720 9fa3e853 bellard
    /* NOTE: in this case, validate_tag is _not_ tested as it
1721 9fa3e853 bellard
       validates only the code TLB */
1722 9fa3e853 bellard
    if (vp->valid_tag != virt_valid_tag)
1723 9fa3e853 bellard
        return 0;
1724 9fa3e853 bellard
    if (!(vp->prot & PAGE_WRITE))
1725 9fa3e853 bellard
        return 0;
1726 9fa3e853 bellard
#if defined(DEBUG_TLB)
1727 9fa3e853 bellard
    printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n", 
1728 9fa3e853 bellard
           addr, vp->phys_addr, vp->prot);
1729 9fa3e853 bellard
#endif
1730 59817ccb bellard
    if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1731 59817ccb bellard
        cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1732 59817ccb bellard
                  (unsigned long)addr, vp->prot);
1733 d720b93d bellard
    /* set the dirty bit */
1734 0a962c02 bellard
    phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
1735 d720b93d bellard
    /* flush the code inside */
1736 d720b93d bellard
    tb_invalidate_phys_page(vp->phys_addr, pc, puc);
1737 9fa3e853 bellard
    return 1;
1738 9fa3e853 bellard
#else
1739 9fa3e853 bellard
    return 0;
1740 9fa3e853 bellard
#endif
1741 33417e70 bellard
}
1742 33417e70 bellard
1743 0124311e bellard
#else
1744 0124311e bellard
1745 ee8b7021 bellard
void tlb_flush(CPUState *env, int flush_global)
1746 0124311e bellard
{
1747 0124311e bellard
}
1748 0124311e bellard
1749 2e12669a bellard
void tlb_flush_page(CPUState *env, target_ulong addr)
1750 0124311e bellard
{
1751 0124311e bellard
}
1752 0124311e bellard
1753 84b7b8e7 bellard
int tlb_set_page_exec(CPUState *env, target_ulong vaddr, 
1754 84b7b8e7 bellard
                      target_phys_addr_t paddr, int prot, 
1755 84b7b8e7 bellard
                      int is_user, int is_softmmu)
1756 9fa3e853 bellard
{
1757 9fa3e853 bellard
    return 0;
1758 9fa3e853 bellard
}
1759 0124311e bellard
1760 9fa3e853 bellard
/* dump memory mappings */
1761 9fa3e853 bellard
void page_dump(FILE *f)
1762 33417e70 bellard
{
1763 9fa3e853 bellard
    unsigned long start, end;
1764 9fa3e853 bellard
    int i, j, prot, prot1;
1765 9fa3e853 bellard
    PageDesc *p;
1766 33417e70 bellard
1767 9fa3e853 bellard
    fprintf(f, "%-8s %-8s %-8s %s\n",
1768 9fa3e853 bellard
            "start", "end", "size", "prot");
1769 9fa3e853 bellard
    start = -1;
1770 9fa3e853 bellard
    end = -1;
1771 9fa3e853 bellard
    prot = 0;
1772 9fa3e853 bellard
    for(i = 0; i <= L1_SIZE; i++) {
1773 9fa3e853 bellard
        if (i < L1_SIZE)
1774 9fa3e853 bellard
            p = l1_map[i];
1775 9fa3e853 bellard
        else
1776 9fa3e853 bellard
            p = NULL;
1777 9fa3e853 bellard
        for(j = 0;j < L2_SIZE; j++) {
1778 9fa3e853 bellard
            if (!p)
1779 9fa3e853 bellard
                prot1 = 0;
1780 9fa3e853 bellard
            else
1781 9fa3e853 bellard
                prot1 = p[j].flags;
1782 9fa3e853 bellard
            if (prot1 != prot) {
1783 9fa3e853 bellard
                end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1784 9fa3e853 bellard
                if (start != -1) {
1785 9fa3e853 bellard
                    fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1786 9fa3e853 bellard
                            start, end, end - start, 
1787 9fa3e853 bellard
                            prot & PAGE_READ ? 'r' : '-',
1788 9fa3e853 bellard
                            prot & PAGE_WRITE ? 'w' : '-',
1789 9fa3e853 bellard
                            prot & PAGE_EXEC ? 'x' : '-');
1790 9fa3e853 bellard
                }
1791 9fa3e853 bellard
                if (prot1 != 0)
1792 9fa3e853 bellard
                    start = end;
1793 9fa3e853 bellard
                else
1794 9fa3e853 bellard
                    start = -1;
1795 9fa3e853 bellard
                prot = prot1;
1796 9fa3e853 bellard
            }
1797 9fa3e853 bellard
            if (!p)
1798 9fa3e853 bellard
                break;
1799 9fa3e853 bellard
        }
1800 33417e70 bellard
    }
1801 33417e70 bellard
}
1802 33417e70 bellard
1803 53a5960a pbrook
int page_get_flags(target_ulong address)
1804 33417e70 bellard
{
1805 9fa3e853 bellard
    PageDesc *p;
1806 9fa3e853 bellard
1807 9fa3e853 bellard
    p = page_find(address >> TARGET_PAGE_BITS);
1808 33417e70 bellard
    if (!p)
1809 9fa3e853 bellard
        return 0;
1810 9fa3e853 bellard
    return p->flags;
1811 9fa3e853 bellard
}
1812 9fa3e853 bellard
1813 9fa3e853 bellard
/* modify the flags of a page and invalidate the code if
1814 9fa3e853 bellard
   necessary. The flag PAGE_WRITE_ORG is positionned automatically
1815 9fa3e853 bellard
   depending on PAGE_WRITE */
1816 53a5960a pbrook
void page_set_flags(target_ulong start, target_ulong end, int flags)
1817 9fa3e853 bellard
{
1818 9fa3e853 bellard
    PageDesc *p;
1819 53a5960a pbrook
    target_ulong addr;
1820 9fa3e853 bellard
1821 9fa3e853 bellard
    start = start & TARGET_PAGE_MASK;
1822 9fa3e853 bellard
    end = TARGET_PAGE_ALIGN(end);
1823 9fa3e853 bellard
    if (flags & PAGE_WRITE)
1824 9fa3e853 bellard
        flags |= PAGE_WRITE_ORG;
1825 9fa3e853 bellard
    spin_lock(&tb_lock);
1826 9fa3e853 bellard
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1827 9fa3e853 bellard
        p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1828 9fa3e853 bellard
        /* if the write protection is set, then we invalidate the code
1829 9fa3e853 bellard
           inside */
1830 9fa3e853 bellard
        if (!(p->flags & PAGE_WRITE) && 
1831 9fa3e853 bellard
            (flags & PAGE_WRITE) &&
1832 9fa3e853 bellard
            p->first_tb) {
1833 d720b93d bellard
            tb_invalidate_phys_page(addr, 0, NULL);
1834 9fa3e853 bellard
        }
1835 9fa3e853 bellard
        p->flags = flags;
1836 9fa3e853 bellard
    }
1837 9fa3e853 bellard
    spin_unlock(&tb_lock);
1838 33417e70 bellard
}
1839 33417e70 bellard
1840 9fa3e853 bellard
/* called from signal handler: invalidate the code and unprotect the
1841 9fa3e853 bellard
   page. Return TRUE if the fault was succesfully handled. */
1842 53a5960a pbrook
int page_unprotect(target_ulong address, unsigned long pc, void *puc)
1843 9fa3e853 bellard
{
1844 9fa3e853 bellard
    unsigned int page_index, prot, pindex;
1845 9fa3e853 bellard
    PageDesc *p, *p1;
1846 53a5960a pbrook
    target_ulong host_start, host_end, addr;
1847 9fa3e853 bellard
1848 83fb7adf bellard
    host_start = address & qemu_host_page_mask;
1849 9fa3e853 bellard
    page_index = host_start >> TARGET_PAGE_BITS;
1850 9fa3e853 bellard
    p1 = page_find(page_index);
1851 9fa3e853 bellard
    if (!p1)
1852 9fa3e853 bellard
        return 0;
1853 83fb7adf bellard
    host_end = host_start + qemu_host_page_size;
1854 9fa3e853 bellard
    p = p1;
1855 9fa3e853 bellard
    prot = 0;
1856 9fa3e853 bellard
    for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1857 9fa3e853 bellard
        prot |= p->flags;
1858 9fa3e853 bellard
        p++;
1859 9fa3e853 bellard
    }
1860 9fa3e853 bellard
    /* if the page was really writable, then we change its
1861 9fa3e853 bellard
       protection back to writable */
1862 9fa3e853 bellard
    if (prot & PAGE_WRITE_ORG) {
1863 9fa3e853 bellard
        pindex = (address - host_start) >> TARGET_PAGE_BITS;
1864 9fa3e853 bellard
        if (!(p1[pindex].flags & PAGE_WRITE)) {
1865 53a5960a pbrook
            mprotect((void *)g2h(host_start), qemu_host_page_size, 
1866 9fa3e853 bellard
                     (prot & PAGE_BITS) | PAGE_WRITE);
1867 9fa3e853 bellard
            p1[pindex].flags |= PAGE_WRITE;
1868 9fa3e853 bellard
            /* and since the content will be modified, we must invalidate
1869 9fa3e853 bellard
               the corresponding translated code. */
1870 d720b93d bellard
            tb_invalidate_phys_page(address, pc, puc);
1871 9fa3e853 bellard
#ifdef DEBUG_TB_CHECK
1872 9fa3e853 bellard
            tb_invalidate_check(address);
1873 9fa3e853 bellard
#endif
1874 9fa3e853 bellard
            return 1;
1875 9fa3e853 bellard
        }
1876 9fa3e853 bellard
    }
1877 9fa3e853 bellard
    return 0;
1878 9fa3e853 bellard
}
1879 9fa3e853 bellard
1880 9fa3e853 bellard
/* call this function when system calls directly modify a memory area */
1881 53a5960a pbrook
/* ??? This should be redundant now we have lock_user.  */
1882 53a5960a pbrook
void page_unprotect_range(target_ulong data, target_ulong data_size)
1883 9fa3e853 bellard
{
1884 53a5960a pbrook
    target_ulong start, end, addr;
1885 9fa3e853 bellard
1886 53a5960a pbrook
    start = data;
1887 9fa3e853 bellard
    end = start + data_size;
1888 9fa3e853 bellard
    start &= TARGET_PAGE_MASK;
1889 9fa3e853 bellard
    end = TARGET_PAGE_ALIGN(end);
1890 9fa3e853 bellard
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1891 d720b93d bellard
        page_unprotect(addr, 0, NULL);
1892 9fa3e853 bellard
    }
1893 9fa3e853 bellard
}
1894 9fa3e853 bellard
1895 6a00d601 bellard
static inline void tlb_set_dirty(CPUState *env,
1896 6a00d601 bellard
                                 unsigned long addr, target_ulong vaddr)
1897 1ccde1cb bellard
{
1898 1ccde1cb bellard
}
1899 9fa3e853 bellard
#endif /* defined(CONFIG_USER_ONLY) */
1900 9fa3e853 bellard
1901 33417e70 bellard
/* register physical memory. 'size' must be a multiple of the target
1902 33417e70 bellard
   page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1903 33417e70 bellard
   io memory page */
1904 2e12669a bellard
void cpu_register_physical_memory(target_phys_addr_t start_addr, 
1905 2e12669a bellard
                                  unsigned long size,
1906 2e12669a bellard
                                  unsigned long phys_offset)
1907 33417e70 bellard
{
1908 108c49b8 bellard
    target_phys_addr_t addr, end_addr;
1909 92e873b9 bellard
    PhysPageDesc *p;
1910 9d42037b bellard
    CPUState *env;
1911 33417e70 bellard
1912 5fd386f6 bellard
    size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
1913 33417e70 bellard
    end_addr = start_addr + size;
1914 5fd386f6 bellard
    for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
1915 108c49b8 bellard
        p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
1916 9fa3e853 bellard
        p->phys_offset = phys_offset;
1917 2a4188a3 bellard
        if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
1918 2a4188a3 bellard
            (phys_offset & IO_MEM_ROMD))
1919 33417e70 bellard
            phys_offset += TARGET_PAGE_SIZE;
1920 33417e70 bellard
    }
1921 9d42037b bellard
    
1922 9d42037b bellard
    /* since each CPU stores ram addresses in its TLB cache, we must
1923 9d42037b bellard
       reset the modified entries */
1924 9d42037b bellard
    /* XXX: slow ! */
1925 9d42037b bellard
    for(env = first_cpu; env != NULL; env = env->next_cpu) {
1926 9d42037b bellard
        tlb_flush(env, 1);
1927 9d42037b bellard
    }
1928 33417e70 bellard
}
1929 33417e70 bellard
1930 ba863458 bellard
/* XXX: temporary until new memory mapping API */
1931 ba863458 bellard
uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
1932 ba863458 bellard
{
1933 ba863458 bellard
    PhysPageDesc *p;
1934 ba863458 bellard
1935 ba863458 bellard
    p = phys_page_find(addr >> TARGET_PAGE_BITS);
1936 ba863458 bellard
    if (!p)
1937 ba863458 bellard
        return IO_MEM_UNASSIGNED;
1938 ba863458 bellard
    return p->phys_offset;
1939 ba863458 bellard
}
1940 ba863458 bellard
1941 e9a1ab19 bellard
/* XXX: better than nothing */
1942 e9a1ab19 bellard
ram_addr_t qemu_ram_alloc(unsigned int size)
1943 e9a1ab19 bellard
{
1944 e9a1ab19 bellard
    ram_addr_t addr;
1945 e9a1ab19 bellard
    if ((phys_ram_alloc_offset + size) >= phys_ram_size) {
1946 e9a1ab19 bellard
        fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n", 
1947 e9a1ab19 bellard
                size, phys_ram_size);
1948 e9a1ab19 bellard
        abort();
1949 e9a1ab19 bellard
    }
1950 e9a1ab19 bellard
    addr = phys_ram_alloc_offset;
1951 e9a1ab19 bellard
    phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
1952 e9a1ab19 bellard
    return addr;
1953 e9a1ab19 bellard
}
1954 e9a1ab19 bellard
1955 e9a1ab19 bellard
void qemu_ram_free(ram_addr_t addr)
1956 e9a1ab19 bellard
{
1957 e9a1ab19 bellard
}
1958 e9a1ab19 bellard
1959 a4193c8a bellard
static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
1960 33417e70 bellard
{
1961 67d3b957 pbrook
#ifdef DEBUG_UNASSIGNED
1962 6c36d3fa blueswir1
    printf("Unassigned mem read " TARGET_FMT_lx "\n", addr);
1963 67d3b957 pbrook
#endif
1964 b4f0a316 blueswir1
#ifdef TARGET_SPARC
1965 6c36d3fa blueswir1
    do_unassigned_access(addr, 0, 0, 0);
1966 b4f0a316 blueswir1
#endif
1967 33417e70 bellard
    return 0;
1968 33417e70 bellard
}
1969 33417e70 bellard
1970 a4193c8a bellard
static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
1971 33417e70 bellard
{
1972 67d3b957 pbrook
#ifdef DEBUG_UNASSIGNED
1973 6c36d3fa blueswir1
    printf("Unassigned mem write " TARGET_FMT_lx " = 0x%x\n", addr, val);
1974 67d3b957 pbrook
#endif
1975 b4f0a316 blueswir1
#ifdef TARGET_SPARC
1976 6c36d3fa blueswir1
    do_unassigned_access(addr, 1, 0, 0);
1977 b4f0a316 blueswir1
#endif
1978 33417e70 bellard
}
1979 33417e70 bellard
1980 33417e70 bellard
static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1981 33417e70 bellard
    unassigned_mem_readb,
1982 33417e70 bellard
    unassigned_mem_readb,
1983 33417e70 bellard
    unassigned_mem_readb,
1984 33417e70 bellard
};
1985 33417e70 bellard
1986 33417e70 bellard
static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1987 33417e70 bellard
    unassigned_mem_writeb,
1988 33417e70 bellard
    unassigned_mem_writeb,
1989 33417e70 bellard
    unassigned_mem_writeb,
1990 33417e70 bellard
};
1991 33417e70 bellard
1992 3a7d929e bellard
static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
1993 9fa3e853 bellard
{
1994 3a7d929e bellard
    unsigned long ram_addr;
1995 3a7d929e bellard
    int dirty_flags;
1996 3a7d929e bellard
    ram_addr = addr - (unsigned long)phys_ram_base;
1997 3a7d929e bellard
    dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
1998 3a7d929e bellard
    if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1999 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
2000 3a7d929e bellard
        tb_invalidate_phys_page_fast(ram_addr, 1);
2001 3a7d929e bellard
        dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2002 9fa3e853 bellard
#endif
2003 3a7d929e bellard
    }
2004 c27004ec bellard
    stb_p((uint8_t *)(long)addr, val);
2005 f32fc648 bellard
#ifdef USE_KQEMU
2006 f32fc648 bellard
    if (cpu_single_env->kqemu_enabled &&
2007 f32fc648 bellard
        (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2008 f32fc648 bellard
        kqemu_modify_page(cpu_single_env, ram_addr);
2009 f32fc648 bellard
#endif
2010 f23db169 bellard
    dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2011 f23db169 bellard
    phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2012 f23db169 bellard
    /* we remove the notdirty callback only if the code has been
2013 f23db169 bellard
       flushed */
2014 f23db169 bellard
    if (dirty_flags == 0xff)
2015 6a00d601 bellard
        tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
2016 9fa3e853 bellard
}
2017 9fa3e853 bellard
2018 3a7d929e bellard
static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
2019 9fa3e853 bellard
{
2020 3a7d929e bellard
    unsigned long ram_addr;
2021 3a7d929e bellard
    int dirty_flags;
2022 3a7d929e bellard
    ram_addr = addr - (unsigned long)phys_ram_base;
2023 3a7d929e bellard
    dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2024 3a7d929e bellard
    if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2025 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
2026 3a7d929e bellard
        tb_invalidate_phys_page_fast(ram_addr, 2);
2027 3a7d929e bellard
        dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2028 9fa3e853 bellard
#endif
2029 3a7d929e bellard
    }
2030 c27004ec bellard
    stw_p((uint8_t *)(long)addr, val);
2031 f32fc648 bellard
#ifdef USE_KQEMU
2032 f32fc648 bellard
    if (cpu_single_env->kqemu_enabled &&
2033 f32fc648 bellard
        (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2034 f32fc648 bellard
        kqemu_modify_page(cpu_single_env, ram_addr);
2035 f32fc648 bellard
#endif
2036 f23db169 bellard
    dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2037 f23db169 bellard
    phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2038 f23db169 bellard
    /* we remove the notdirty callback only if the code has been
2039 f23db169 bellard
       flushed */
2040 f23db169 bellard
    if (dirty_flags == 0xff)
2041 6a00d601 bellard
        tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
2042 9fa3e853 bellard
}
2043 9fa3e853 bellard
2044 3a7d929e bellard
static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
2045 9fa3e853 bellard
{
2046 3a7d929e bellard
    unsigned long ram_addr;
2047 3a7d929e bellard
    int dirty_flags;
2048 3a7d929e bellard
    ram_addr = addr - (unsigned long)phys_ram_base;
2049 3a7d929e bellard
    dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2050 3a7d929e bellard
    if (!(dirty_flags & CODE_DIRTY_FLAG)) {
2051 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
2052 3a7d929e bellard
        tb_invalidate_phys_page_fast(ram_addr, 4);
2053 3a7d929e bellard
        dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
2054 9fa3e853 bellard
#endif
2055 3a7d929e bellard
    }
2056 c27004ec bellard
    stl_p((uint8_t *)(long)addr, val);
2057 f32fc648 bellard
#ifdef USE_KQEMU
2058 f32fc648 bellard
    if (cpu_single_env->kqemu_enabled &&
2059 f32fc648 bellard
        (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
2060 f32fc648 bellard
        kqemu_modify_page(cpu_single_env, ram_addr);
2061 f32fc648 bellard
#endif
2062 f23db169 bellard
    dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
2063 f23db169 bellard
    phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
2064 f23db169 bellard
    /* we remove the notdirty callback only if the code has been
2065 f23db169 bellard
       flushed */
2066 f23db169 bellard
    if (dirty_flags == 0xff)
2067 6a00d601 bellard
        tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
2068 9fa3e853 bellard
}
2069 9fa3e853 bellard
2070 3a7d929e bellard
static CPUReadMemoryFunc *error_mem_read[3] = {
2071 9fa3e853 bellard
    NULL, /* never used */
2072 9fa3e853 bellard
    NULL, /* never used */
2073 9fa3e853 bellard
    NULL, /* never used */
2074 9fa3e853 bellard
};
2075 9fa3e853 bellard
2076 1ccde1cb bellard
static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
2077 1ccde1cb bellard
    notdirty_mem_writeb,
2078 1ccde1cb bellard
    notdirty_mem_writew,
2079 1ccde1cb bellard
    notdirty_mem_writel,
2080 1ccde1cb bellard
};
2081 1ccde1cb bellard
2082 6658ffb8 pbrook
#if defined(CONFIG_SOFTMMU)
2083 6658ffb8 pbrook
/* Watchpoint access routines.  Watchpoints are inserted using TLB tricks,
2084 6658ffb8 pbrook
   so these check for a hit then pass through to the normal out-of-line
2085 6658ffb8 pbrook
   phys routines.  */
2086 6658ffb8 pbrook
static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2087 6658ffb8 pbrook
{
2088 6658ffb8 pbrook
    return ldub_phys(addr);
2089 6658ffb8 pbrook
}
2090 6658ffb8 pbrook
2091 6658ffb8 pbrook
static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2092 6658ffb8 pbrook
{
2093 6658ffb8 pbrook
    return lduw_phys(addr);
2094 6658ffb8 pbrook
}
2095 6658ffb8 pbrook
2096 6658ffb8 pbrook
static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2097 6658ffb8 pbrook
{
2098 6658ffb8 pbrook
    return ldl_phys(addr);
2099 6658ffb8 pbrook
}
2100 6658ffb8 pbrook
2101 6658ffb8 pbrook
/* Generate a debug exception if a watchpoint has been hit.
2102 6658ffb8 pbrook
   Returns the real physical address of the access.  addr will be a host
2103 6658ffb8 pbrook
   address in the is_ram case.  */
2104 6658ffb8 pbrook
static target_ulong check_watchpoint(target_phys_addr_t addr)
2105 6658ffb8 pbrook
{
2106 6658ffb8 pbrook
    CPUState *env = cpu_single_env;
2107 6658ffb8 pbrook
    target_ulong watch;
2108 6658ffb8 pbrook
    target_ulong retaddr;
2109 6658ffb8 pbrook
    int i;
2110 6658ffb8 pbrook
2111 6658ffb8 pbrook
    retaddr = addr;
2112 6658ffb8 pbrook
    for (i = 0; i < env->nb_watchpoints; i++) {
2113 6658ffb8 pbrook
        watch = env->watchpoint[i].vaddr;
2114 6658ffb8 pbrook
        if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
2115 6658ffb8 pbrook
            if (env->watchpoint[i].is_ram)
2116 6658ffb8 pbrook
                retaddr = addr - (unsigned long)phys_ram_base;
2117 6658ffb8 pbrook
            if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
2118 6658ffb8 pbrook
                cpu_single_env->watchpoint_hit = i + 1;
2119 6658ffb8 pbrook
                cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
2120 6658ffb8 pbrook
                break;
2121 6658ffb8 pbrook
            }
2122 6658ffb8 pbrook
        }
2123 6658ffb8 pbrook
    }
2124 6658ffb8 pbrook
    return retaddr;
2125 6658ffb8 pbrook
}
2126 6658ffb8 pbrook
2127 6658ffb8 pbrook
static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2128 6658ffb8 pbrook
                             uint32_t val)
2129 6658ffb8 pbrook
{
2130 6658ffb8 pbrook
    addr = check_watchpoint(addr);
2131 6658ffb8 pbrook
    stb_phys(addr, val);
2132 6658ffb8 pbrook
}
2133 6658ffb8 pbrook
2134 6658ffb8 pbrook
static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2135 6658ffb8 pbrook
                             uint32_t val)
2136 6658ffb8 pbrook
{
2137 6658ffb8 pbrook
    addr = check_watchpoint(addr);
2138 6658ffb8 pbrook
    stw_phys(addr, val);
2139 6658ffb8 pbrook
}
2140 6658ffb8 pbrook
2141 6658ffb8 pbrook
static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2142 6658ffb8 pbrook
                             uint32_t val)
2143 6658ffb8 pbrook
{
2144 6658ffb8 pbrook
    addr = check_watchpoint(addr);
2145 6658ffb8 pbrook
    stl_phys(addr, val);
2146 6658ffb8 pbrook
}
2147 6658ffb8 pbrook
2148 6658ffb8 pbrook
static CPUReadMemoryFunc *watch_mem_read[3] = {
2149 6658ffb8 pbrook
    watch_mem_readb,
2150 6658ffb8 pbrook
    watch_mem_readw,
2151 6658ffb8 pbrook
    watch_mem_readl,
2152 6658ffb8 pbrook
};
2153 6658ffb8 pbrook
2154 6658ffb8 pbrook
static CPUWriteMemoryFunc *watch_mem_write[3] = {
2155 6658ffb8 pbrook
    watch_mem_writeb,
2156 6658ffb8 pbrook
    watch_mem_writew,
2157 6658ffb8 pbrook
    watch_mem_writel,
2158 6658ffb8 pbrook
};
2159 6658ffb8 pbrook
#endif
2160 6658ffb8 pbrook
2161 33417e70 bellard
static void io_mem_init(void)
2162 33417e70 bellard
{
2163 3a7d929e bellard
    cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
2164 a4193c8a bellard
    cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
2165 3a7d929e bellard
    cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
2166 1ccde1cb bellard
    io_mem_nb = 5;
2167 1ccde1cb bellard
2168 6658ffb8 pbrook
#if defined(CONFIG_SOFTMMU)
2169 6658ffb8 pbrook
    io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
2170 6658ffb8 pbrook
                                          watch_mem_write, NULL);
2171 6658ffb8 pbrook
#endif
2172 1ccde1cb bellard
    /* alloc dirty bits array */
2173 0a962c02 bellard
    phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
2174 3a7d929e bellard
    memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
2175 33417e70 bellard
}
2176 33417e70 bellard
2177 33417e70 bellard
/* mem_read and mem_write are arrays of functions containing the
2178 33417e70 bellard
   function to access byte (index 0), word (index 1) and dword (index
2179 33417e70 bellard
   2). All functions must be supplied. If io_index is non zero, the
2180 33417e70 bellard
   corresponding io zone is modified. If it is zero, a new io zone is
2181 33417e70 bellard
   allocated. The return value can be used with
2182 33417e70 bellard
   cpu_register_physical_memory(). (-1) is returned if error. */
2183 33417e70 bellard
int cpu_register_io_memory(int io_index,
2184 33417e70 bellard
                           CPUReadMemoryFunc **mem_read,
2185 a4193c8a bellard
                           CPUWriteMemoryFunc **mem_write,
2186 a4193c8a bellard
                           void *opaque)
2187 33417e70 bellard
{
2188 33417e70 bellard
    int i;
2189 33417e70 bellard
2190 33417e70 bellard
    if (io_index <= 0) {
2191 b5ff1b31 bellard
        if (io_mem_nb >= IO_MEM_NB_ENTRIES)
2192 33417e70 bellard
            return -1;
2193 33417e70 bellard
        io_index = io_mem_nb++;
2194 33417e70 bellard
    } else {
2195 33417e70 bellard
        if (io_index >= IO_MEM_NB_ENTRIES)
2196 33417e70 bellard
            return -1;
2197 33417e70 bellard
    }
2198 b5ff1b31 bellard
2199 33417e70 bellard
    for(i = 0;i < 3; i++) {
2200 33417e70 bellard
        io_mem_read[io_index][i] = mem_read[i];
2201 33417e70 bellard
        io_mem_write[io_index][i] = mem_write[i];
2202 33417e70 bellard
    }
2203 a4193c8a bellard
    io_mem_opaque[io_index] = opaque;
2204 33417e70 bellard
    return io_index << IO_MEM_SHIFT;
2205 33417e70 bellard
}
2206 61382a50 bellard
2207 8926b517 bellard
CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
2208 8926b517 bellard
{
2209 8926b517 bellard
    return io_mem_write[io_index >> IO_MEM_SHIFT];
2210 8926b517 bellard
}
2211 8926b517 bellard
2212 8926b517 bellard
CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
2213 8926b517 bellard
{
2214 8926b517 bellard
    return io_mem_read[io_index >> IO_MEM_SHIFT];
2215 8926b517 bellard
}
2216 8926b517 bellard
2217 13eb76e0 bellard
/* physical memory access (slow version, mainly for debug) */
2218 13eb76e0 bellard
#if defined(CONFIG_USER_ONLY)
2219 2e12669a bellard
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
2220 13eb76e0 bellard
                            int len, int is_write)
2221 13eb76e0 bellard
{
2222 13eb76e0 bellard
    int l, flags;
2223 13eb76e0 bellard
    target_ulong page;
2224 53a5960a pbrook
    void * p;
2225 13eb76e0 bellard
2226 13eb76e0 bellard
    while (len > 0) {
2227 13eb76e0 bellard
        page = addr & TARGET_PAGE_MASK;
2228 13eb76e0 bellard
        l = (page + TARGET_PAGE_SIZE) - addr;
2229 13eb76e0 bellard
        if (l > len)
2230 13eb76e0 bellard
            l = len;
2231 13eb76e0 bellard
        flags = page_get_flags(page);
2232 13eb76e0 bellard
        if (!(flags & PAGE_VALID))
2233 13eb76e0 bellard
            return;
2234 13eb76e0 bellard
        if (is_write) {
2235 13eb76e0 bellard
            if (!(flags & PAGE_WRITE))
2236 13eb76e0 bellard
                return;
2237 53a5960a pbrook
            p = lock_user(addr, len, 0);
2238 53a5960a pbrook
            memcpy(p, buf, len);
2239 53a5960a pbrook
            unlock_user(p, addr, len);
2240 13eb76e0 bellard
        } else {
2241 13eb76e0 bellard
            if (!(flags & PAGE_READ))
2242 13eb76e0 bellard
                return;
2243 53a5960a pbrook
            p = lock_user(addr, len, 1);
2244 53a5960a pbrook
            memcpy(buf, p, len);
2245 53a5960a pbrook
            unlock_user(p, addr, 0);
2246 13eb76e0 bellard
        }
2247 13eb76e0 bellard
        len -= l;
2248 13eb76e0 bellard
        buf += l;
2249 13eb76e0 bellard
        addr += l;
2250 13eb76e0 bellard
    }
2251 13eb76e0 bellard
}
2252 8df1cd07 bellard
2253 13eb76e0 bellard
#else
2254 2e12669a bellard
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
2255 13eb76e0 bellard
                            int len, int is_write)
2256 13eb76e0 bellard
{
2257 13eb76e0 bellard
    int l, io_index;
2258 13eb76e0 bellard
    uint8_t *ptr;
2259 13eb76e0 bellard
    uint32_t val;
2260 2e12669a bellard
    target_phys_addr_t page;
2261 2e12669a bellard
    unsigned long pd;
2262 92e873b9 bellard
    PhysPageDesc *p;
2263 13eb76e0 bellard
    
2264 13eb76e0 bellard
    while (len > 0) {
2265 13eb76e0 bellard
        page = addr & TARGET_PAGE_MASK;
2266 13eb76e0 bellard
        l = (page + TARGET_PAGE_SIZE) - addr;
2267 13eb76e0 bellard
        if (l > len)
2268 13eb76e0 bellard
            l = len;
2269 92e873b9 bellard
        p = phys_page_find(page >> TARGET_PAGE_BITS);
2270 13eb76e0 bellard
        if (!p) {
2271 13eb76e0 bellard
            pd = IO_MEM_UNASSIGNED;
2272 13eb76e0 bellard
        } else {
2273 13eb76e0 bellard
            pd = p->phys_offset;
2274 13eb76e0 bellard
        }
2275 13eb76e0 bellard
        
2276 13eb76e0 bellard
        if (is_write) {
2277 3a7d929e bellard
            if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2278 13eb76e0 bellard
                io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2279 6a00d601 bellard
                /* XXX: could force cpu_single_env to NULL to avoid
2280 6a00d601 bellard
                   potential bugs */
2281 13eb76e0 bellard
                if (l >= 4 && ((addr & 3) == 0)) {
2282 1c213d19 bellard
                    /* 32 bit write access */
2283 c27004ec bellard
                    val = ldl_p(buf);
2284 a4193c8a bellard
                    io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2285 13eb76e0 bellard
                    l = 4;
2286 13eb76e0 bellard
                } else if (l >= 2 && ((addr & 1) == 0)) {
2287 1c213d19 bellard
                    /* 16 bit write access */
2288 c27004ec bellard
                    val = lduw_p(buf);
2289 a4193c8a bellard
                    io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
2290 13eb76e0 bellard
                    l = 2;
2291 13eb76e0 bellard
                } else {
2292 1c213d19 bellard
                    /* 8 bit write access */
2293 c27004ec bellard
                    val = ldub_p(buf);
2294 a4193c8a bellard
                    io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
2295 13eb76e0 bellard
                    l = 1;
2296 13eb76e0 bellard
                }
2297 13eb76e0 bellard
            } else {
2298 b448f2f3 bellard
                unsigned long addr1;
2299 b448f2f3 bellard
                addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2300 13eb76e0 bellard
                /* RAM case */
2301 b448f2f3 bellard
                ptr = phys_ram_base + addr1;
2302 13eb76e0 bellard
                memcpy(ptr, buf, l);
2303 3a7d929e bellard
                if (!cpu_physical_memory_is_dirty(addr1)) {
2304 3a7d929e bellard
                    /* invalidate code */
2305 3a7d929e bellard
                    tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
2306 3a7d929e bellard
                    /* set dirty bit */
2307 f23db169 bellard
                    phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= 
2308 f23db169 bellard
                        (0xff & ~CODE_DIRTY_FLAG);
2309 3a7d929e bellard
                }
2310 13eb76e0 bellard
            }
2311 13eb76e0 bellard
        } else {
2312 2a4188a3 bellard
            if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && 
2313 2a4188a3 bellard
                !(pd & IO_MEM_ROMD)) {
2314 13eb76e0 bellard
                /* I/O case */
2315 13eb76e0 bellard
                io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2316 13eb76e0 bellard
                if (l >= 4 && ((addr & 3) == 0)) {
2317 13eb76e0 bellard
                    /* 32 bit read access */
2318 a4193c8a bellard
                    val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2319 c27004ec bellard
                    stl_p(buf, val);
2320 13eb76e0 bellard
                    l = 4;
2321 13eb76e0 bellard
                } else if (l >= 2 && ((addr & 1) == 0)) {
2322 13eb76e0 bellard
                    /* 16 bit read access */
2323 a4193c8a bellard
                    val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
2324 c27004ec bellard
                    stw_p(buf, val);
2325 13eb76e0 bellard
                    l = 2;
2326 13eb76e0 bellard
                } else {
2327 1c213d19 bellard
                    /* 8 bit read access */
2328 a4193c8a bellard
                    val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
2329 c27004ec bellard
                    stb_p(buf, val);
2330 13eb76e0 bellard
                    l = 1;
2331 13eb76e0 bellard
                }
2332 13eb76e0 bellard
            } else {
2333 13eb76e0 bellard
                /* RAM case */
2334 13eb76e0 bellard
                ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
2335 13eb76e0 bellard
                    (addr & ~TARGET_PAGE_MASK);
2336 13eb76e0 bellard
                memcpy(buf, ptr, l);
2337 13eb76e0 bellard
            }
2338 13eb76e0 bellard
        }
2339 13eb76e0 bellard
        len -= l;
2340 13eb76e0 bellard
        buf += l;
2341 13eb76e0 bellard
        addr += l;
2342 13eb76e0 bellard
    }
2343 13eb76e0 bellard
}
2344 8df1cd07 bellard
2345 d0ecd2aa bellard
/* used for ROM loading : can write in RAM and ROM */
2346 d0ecd2aa bellard
void cpu_physical_memory_write_rom(target_phys_addr_t addr, 
2347 d0ecd2aa bellard
                                   const uint8_t *buf, int len)
2348 d0ecd2aa bellard
{
2349 d0ecd2aa bellard
    int l;
2350 d0ecd2aa bellard
    uint8_t *ptr;
2351 d0ecd2aa bellard
    target_phys_addr_t page;
2352 d0ecd2aa bellard
    unsigned long pd;
2353 d0ecd2aa bellard
    PhysPageDesc *p;
2354 d0ecd2aa bellard
    
2355 d0ecd2aa bellard
    while (len > 0) {
2356 d0ecd2aa bellard
        page = addr & TARGET_PAGE_MASK;
2357 d0ecd2aa bellard
        l = (page + TARGET_PAGE_SIZE) - addr;
2358 d0ecd2aa bellard
        if (l > len)
2359 d0ecd2aa bellard
            l = len;
2360 d0ecd2aa bellard
        p = phys_page_find(page >> TARGET_PAGE_BITS);
2361 d0ecd2aa bellard
        if (!p) {
2362 d0ecd2aa bellard
            pd = IO_MEM_UNASSIGNED;
2363 d0ecd2aa bellard
        } else {
2364 d0ecd2aa bellard
            pd = p->phys_offset;
2365 d0ecd2aa bellard
        }
2366 d0ecd2aa bellard
        
2367 d0ecd2aa bellard
        if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
2368 2a4188a3 bellard
            (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
2369 2a4188a3 bellard
            !(pd & IO_MEM_ROMD)) {
2370 d0ecd2aa bellard
            /* do nothing */
2371 d0ecd2aa bellard
        } else {
2372 d0ecd2aa bellard
            unsigned long addr1;
2373 d0ecd2aa bellard
            addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2374 d0ecd2aa bellard
            /* ROM/RAM case */
2375 d0ecd2aa bellard
            ptr = phys_ram_base + addr1;
2376 d0ecd2aa bellard
            memcpy(ptr, buf, l);
2377 d0ecd2aa bellard
        }
2378 d0ecd2aa bellard
        len -= l;
2379 d0ecd2aa bellard
        buf += l;
2380 d0ecd2aa bellard
        addr += l;
2381 d0ecd2aa bellard
    }
2382 d0ecd2aa bellard
}
2383 d0ecd2aa bellard
2384 d0ecd2aa bellard
2385 8df1cd07 bellard
/* warning: addr must be aligned */
2386 8df1cd07 bellard
uint32_t ldl_phys(target_phys_addr_t addr)
2387 8df1cd07 bellard
{
2388 8df1cd07 bellard
    int io_index;
2389 8df1cd07 bellard
    uint8_t *ptr;
2390 8df1cd07 bellard
    uint32_t val;
2391 8df1cd07 bellard
    unsigned long pd;
2392 8df1cd07 bellard
    PhysPageDesc *p;
2393 8df1cd07 bellard
2394 8df1cd07 bellard
    p = phys_page_find(addr >> TARGET_PAGE_BITS);
2395 8df1cd07 bellard
    if (!p) {
2396 8df1cd07 bellard
        pd = IO_MEM_UNASSIGNED;
2397 8df1cd07 bellard
    } else {
2398 8df1cd07 bellard
        pd = p->phys_offset;
2399 8df1cd07 bellard
    }
2400 8df1cd07 bellard
        
2401 2a4188a3 bellard
    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && 
2402 2a4188a3 bellard
        !(pd & IO_MEM_ROMD)) {
2403 8df1cd07 bellard
        /* I/O case */
2404 8df1cd07 bellard
        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2405 8df1cd07 bellard
        val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2406 8df1cd07 bellard
    } else {
2407 8df1cd07 bellard
        /* RAM case */
2408 8df1cd07 bellard
        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
2409 8df1cd07 bellard
            (addr & ~TARGET_PAGE_MASK);
2410 8df1cd07 bellard
        val = ldl_p(ptr);
2411 8df1cd07 bellard
    }
2412 8df1cd07 bellard
    return val;
2413 8df1cd07 bellard
}
2414 8df1cd07 bellard
2415 84b7b8e7 bellard
/* warning: addr must be aligned */
2416 84b7b8e7 bellard
uint64_t ldq_phys(target_phys_addr_t addr)
2417 84b7b8e7 bellard
{
2418 84b7b8e7 bellard
    int io_index;
2419 84b7b8e7 bellard
    uint8_t *ptr;
2420 84b7b8e7 bellard
    uint64_t val;
2421 84b7b8e7 bellard
    unsigned long pd;
2422 84b7b8e7 bellard
    PhysPageDesc *p;
2423 84b7b8e7 bellard
2424 84b7b8e7 bellard
    p = phys_page_find(addr >> TARGET_PAGE_BITS);
2425 84b7b8e7 bellard
    if (!p) {
2426 84b7b8e7 bellard
        pd = IO_MEM_UNASSIGNED;
2427 84b7b8e7 bellard
    } else {
2428 84b7b8e7 bellard
        pd = p->phys_offset;
2429 84b7b8e7 bellard
    }
2430 84b7b8e7 bellard
        
2431 2a4188a3 bellard
    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
2432 2a4188a3 bellard
        !(pd & IO_MEM_ROMD)) {
2433 84b7b8e7 bellard
        /* I/O case */
2434 84b7b8e7 bellard
        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2435 84b7b8e7 bellard
#ifdef TARGET_WORDS_BIGENDIAN
2436 84b7b8e7 bellard
        val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
2437 84b7b8e7 bellard
        val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
2438 84b7b8e7 bellard
#else
2439 84b7b8e7 bellard
        val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
2440 84b7b8e7 bellard
        val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
2441 84b7b8e7 bellard
#endif
2442 84b7b8e7 bellard
    } else {
2443 84b7b8e7 bellard
        /* RAM case */
2444 84b7b8e7 bellard
        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
2445 84b7b8e7 bellard
            (addr & ~TARGET_PAGE_MASK);
2446 84b7b8e7 bellard
        val = ldq_p(ptr);
2447 84b7b8e7 bellard
    }
2448 84b7b8e7 bellard
    return val;
2449 84b7b8e7 bellard
}
2450 84b7b8e7 bellard
2451 aab33094 bellard
/* XXX: optimize */
2452 aab33094 bellard
uint32_t ldub_phys(target_phys_addr_t addr)
2453 aab33094 bellard
{
2454 aab33094 bellard
    uint8_t val;
2455 aab33094 bellard
    cpu_physical_memory_read(addr, &val, 1);
2456 aab33094 bellard
    return val;
2457 aab33094 bellard
}
2458 aab33094 bellard
2459 aab33094 bellard
/* XXX: optimize */
2460 aab33094 bellard
uint32_t lduw_phys(target_phys_addr_t addr)
2461 aab33094 bellard
{
2462 aab33094 bellard
    uint16_t val;
2463 aab33094 bellard
    cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
2464 aab33094 bellard
    return tswap16(val);
2465 aab33094 bellard
}
2466 aab33094 bellard
2467 8df1cd07 bellard
/* warning: addr must be aligned. The ram page is not masked as dirty
2468 8df1cd07 bellard
   and the code inside is not invalidated. It is useful if the dirty
2469 8df1cd07 bellard
   bits are used to track modified PTEs */
2470 8df1cd07 bellard
void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
2471 8df1cd07 bellard
{
2472 8df1cd07 bellard
    int io_index;
2473 8df1cd07 bellard
    uint8_t *ptr;
2474 8df1cd07 bellard
    unsigned long pd;
2475 8df1cd07 bellard
    PhysPageDesc *p;
2476 8df1cd07 bellard
2477 8df1cd07 bellard
    p = phys_page_find(addr >> TARGET_PAGE_BITS);
2478 8df1cd07 bellard
    if (!p) {
2479 8df1cd07 bellard
        pd = IO_MEM_UNASSIGNED;
2480 8df1cd07 bellard
    } else {
2481 8df1cd07 bellard
        pd = p->phys_offset;
2482 8df1cd07 bellard
    }
2483 8df1cd07 bellard
        
2484 3a7d929e bellard
    if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2485 8df1cd07 bellard
        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2486 8df1cd07 bellard
        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2487 8df1cd07 bellard
    } else {
2488 8df1cd07 bellard
        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
2489 8df1cd07 bellard
            (addr & ~TARGET_PAGE_MASK);
2490 8df1cd07 bellard
        stl_p(ptr, val);
2491 8df1cd07 bellard
    }
2492 8df1cd07 bellard
}
2493 8df1cd07 bellard
2494 bc98a7ef j_mayer
void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
2495 bc98a7ef j_mayer
{
2496 bc98a7ef j_mayer
    int io_index;
2497 bc98a7ef j_mayer
    uint8_t *ptr;
2498 bc98a7ef j_mayer
    unsigned long pd;
2499 bc98a7ef j_mayer
    PhysPageDesc *p;
2500 bc98a7ef j_mayer
2501 bc98a7ef j_mayer
    p = phys_page_find(addr >> TARGET_PAGE_BITS);
2502 bc98a7ef j_mayer
    if (!p) {
2503 bc98a7ef j_mayer
        pd = IO_MEM_UNASSIGNED;
2504 bc98a7ef j_mayer
    } else {
2505 bc98a7ef j_mayer
        pd = p->phys_offset;
2506 bc98a7ef j_mayer
    }
2507 bc98a7ef j_mayer
        
2508 bc98a7ef j_mayer
    if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2509 bc98a7ef j_mayer
        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2510 bc98a7ef j_mayer
#ifdef TARGET_WORDS_BIGENDIAN
2511 bc98a7ef j_mayer
        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
2512 bc98a7ef j_mayer
        io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
2513 bc98a7ef j_mayer
#else
2514 bc98a7ef j_mayer
        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2515 bc98a7ef j_mayer
        io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
2516 bc98a7ef j_mayer
#endif
2517 bc98a7ef j_mayer
    } else {
2518 bc98a7ef j_mayer
        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
2519 bc98a7ef j_mayer
            (addr & ~TARGET_PAGE_MASK);
2520 bc98a7ef j_mayer
        stq_p(ptr, val);
2521 bc98a7ef j_mayer
    }
2522 bc98a7ef j_mayer
}
2523 bc98a7ef j_mayer
2524 8df1cd07 bellard
/* warning: addr must be aligned */
2525 8df1cd07 bellard
void stl_phys(target_phys_addr_t addr, uint32_t val)
2526 8df1cd07 bellard
{
2527 8df1cd07 bellard
    int io_index;
2528 8df1cd07 bellard
    uint8_t *ptr;
2529 8df1cd07 bellard
    unsigned long pd;
2530 8df1cd07 bellard
    PhysPageDesc *p;
2531 8df1cd07 bellard
2532 8df1cd07 bellard
    p = phys_page_find(addr >> TARGET_PAGE_BITS);
2533 8df1cd07 bellard
    if (!p) {
2534 8df1cd07 bellard
        pd = IO_MEM_UNASSIGNED;
2535 8df1cd07 bellard
    } else {
2536 8df1cd07 bellard
        pd = p->phys_offset;
2537 8df1cd07 bellard
    }
2538 8df1cd07 bellard
        
2539 3a7d929e bellard
    if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
2540 8df1cd07 bellard
        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
2541 8df1cd07 bellard
        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
2542 8df1cd07 bellard
    } else {
2543 8df1cd07 bellard
        unsigned long addr1;
2544 8df1cd07 bellard
        addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
2545 8df1cd07 bellard
        /* RAM case */
2546 8df1cd07 bellard
        ptr = phys_ram_base + addr1;
2547 8df1cd07 bellard
        stl_p(ptr, val);
2548 3a7d929e bellard
        if (!cpu_physical_memory_is_dirty(addr1)) {
2549 3a7d929e bellard
            /* invalidate code */
2550 3a7d929e bellard
            tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
2551 3a7d929e bellard
            /* set dirty bit */
2552 f23db169 bellard
            phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
2553 f23db169 bellard
                (0xff & ~CODE_DIRTY_FLAG);
2554 3a7d929e bellard
        }
2555 8df1cd07 bellard
    }
2556 8df1cd07 bellard
}
2557 8df1cd07 bellard
2558 aab33094 bellard
/* XXX: optimize */
2559 aab33094 bellard
void stb_phys(target_phys_addr_t addr, uint32_t val)
2560 aab33094 bellard
{
2561 aab33094 bellard
    uint8_t v = val;
2562 aab33094 bellard
    cpu_physical_memory_write(addr, &v, 1);
2563 aab33094 bellard
}
2564 aab33094 bellard
2565 aab33094 bellard
/* XXX: optimize */
2566 aab33094 bellard
void stw_phys(target_phys_addr_t addr, uint32_t val)
2567 aab33094 bellard
{
2568 aab33094 bellard
    uint16_t v = tswap16(val);
2569 aab33094 bellard
    cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
2570 aab33094 bellard
}
2571 aab33094 bellard
2572 aab33094 bellard
/* XXX: optimize */
2573 aab33094 bellard
void stq_phys(target_phys_addr_t addr, uint64_t val)
2574 aab33094 bellard
{
2575 aab33094 bellard
    val = tswap64(val);
2576 aab33094 bellard
    cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
2577 aab33094 bellard
}
2578 aab33094 bellard
2579 13eb76e0 bellard
#endif
2580 13eb76e0 bellard
2581 13eb76e0 bellard
/* virtual memory access for debug */
2582 b448f2f3 bellard
int cpu_memory_rw_debug(CPUState *env, target_ulong addr, 
2583 b448f2f3 bellard
                        uint8_t *buf, int len, int is_write)
2584 13eb76e0 bellard
{
2585 13eb76e0 bellard
    int l;
2586 9b3c35e0 j_mayer
    target_phys_addr_t phys_addr;
2587 9b3c35e0 j_mayer
    target_ulong page;
2588 13eb76e0 bellard
2589 13eb76e0 bellard
    while (len > 0) {
2590 13eb76e0 bellard
        page = addr & TARGET_PAGE_MASK;
2591 13eb76e0 bellard
        phys_addr = cpu_get_phys_page_debug(env, page);
2592 13eb76e0 bellard
        /* if no physical page mapped, return an error */
2593 13eb76e0 bellard
        if (phys_addr == -1)
2594 13eb76e0 bellard
            return -1;
2595 13eb76e0 bellard
        l = (page + TARGET_PAGE_SIZE) - addr;
2596 13eb76e0 bellard
        if (l > len)
2597 13eb76e0 bellard
            l = len;
2598 b448f2f3 bellard
        cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK), 
2599 b448f2f3 bellard
                               buf, l, is_write);
2600 13eb76e0 bellard
        len -= l;
2601 13eb76e0 bellard
        buf += l;
2602 13eb76e0 bellard
        addr += l;
2603 13eb76e0 bellard
    }
2604 13eb76e0 bellard
    return 0;
2605 13eb76e0 bellard
}
2606 13eb76e0 bellard
2607 e3db7226 bellard
void dump_exec_info(FILE *f,
2608 e3db7226 bellard
                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
2609 e3db7226 bellard
{
2610 e3db7226 bellard
    int i, target_code_size, max_target_code_size;
2611 e3db7226 bellard
    int direct_jmp_count, direct_jmp2_count, cross_page;
2612 e3db7226 bellard
    TranslationBlock *tb;
2613 e3db7226 bellard
    
2614 e3db7226 bellard
    target_code_size = 0;
2615 e3db7226 bellard
    max_target_code_size = 0;
2616 e3db7226 bellard
    cross_page = 0;
2617 e3db7226 bellard
    direct_jmp_count = 0;
2618 e3db7226 bellard
    direct_jmp2_count = 0;
2619 e3db7226 bellard
    for(i = 0; i < nb_tbs; i++) {
2620 e3db7226 bellard
        tb = &tbs[i];
2621 e3db7226 bellard
        target_code_size += tb->size;
2622 e3db7226 bellard
        if (tb->size > max_target_code_size)
2623 e3db7226 bellard
            max_target_code_size = tb->size;
2624 e3db7226 bellard
        if (tb->page_addr[1] != -1)
2625 e3db7226 bellard
            cross_page++;
2626 e3db7226 bellard
        if (tb->tb_next_offset[0] != 0xffff) {
2627 e3db7226 bellard
            direct_jmp_count++;
2628 e3db7226 bellard
            if (tb->tb_next_offset[1] != 0xffff) {
2629 e3db7226 bellard
                direct_jmp2_count++;
2630 e3db7226 bellard
            }
2631 e3db7226 bellard
        }
2632 e3db7226 bellard
    }
2633 e3db7226 bellard
    /* XXX: avoid using doubles ? */
2634 e3db7226 bellard
    cpu_fprintf(f, "TB count            %d\n", nb_tbs);
2635 e3db7226 bellard
    cpu_fprintf(f, "TB avg target size  %d max=%d bytes\n", 
2636 e3db7226 bellard
                nb_tbs ? target_code_size / nb_tbs : 0,
2637 e3db7226 bellard
                max_target_code_size);
2638 e3db7226 bellard
    cpu_fprintf(f, "TB avg host size    %d bytes (expansion ratio: %0.1f)\n", 
2639 e3db7226 bellard
                nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
2640 e3db7226 bellard
                target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
2641 e3db7226 bellard
    cpu_fprintf(f, "cross page TB count %d (%d%%)\n", 
2642 e3db7226 bellard
            cross_page, 
2643 e3db7226 bellard
            nb_tbs ? (cross_page * 100) / nb_tbs : 0);
2644 e3db7226 bellard
    cpu_fprintf(f, "direct jump count   %d (%d%%) (2 jumps=%d %d%%)\n",
2645 e3db7226 bellard
                direct_jmp_count, 
2646 e3db7226 bellard
                nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
2647 e3db7226 bellard
                direct_jmp2_count,
2648 e3db7226 bellard
                nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
2649 e3db7226 bellard
    cpu_fprintf(f, "TB flush count      %d\n", tb_flush_count);
2650 e3db7226 bellard
    cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
2651 e3db7226 bellard
    cpu_fprintf(f, "TLB flush count     %d\n", tlb_flush_count);
2652 e3db7226 bellard
}
2653 e3db7226 bellard
2654 61382a50 bellard
#if !defined(CONFIG_USER_ONLY) 
2655 61382a50 bellard
2656 61382a50 bellard
#define MMUSUFFIX _cmmu
2657 61382a50 bellard
#define GETPC() NULL
2658 61382a50 bellard
#define env cpu_single_env
2659 b769d8fe bellard
#define SOFTMMU_CODE_ACCESS
2660 61382a50 bellard
2661 61382a50 bellard
#define SHIFT 0
2662 61382a50 bellard
#include "softmmu_template.h"
2663 61382a50 bellard
2664 61382a50 bellard
#define SHIFT 1
2665 61382a50 bellard
#include "softmmu_template.h"
2666 61382a50 bellard
2667 61382a50 bellard
#define SHIFT 2
2668 61382a50 bellard
#include "softmmu_template.h"
2669 61382a50 bellard
2670 61382a50 bellard
#define SHIFT 3
2671 61382a50 bellard
#include "softmmu_template.h"
2672 61382a50 bellard
2673 61382a50 bellard
#undef env
2674 61382a50 bellard
2675 61382a50 bellard
#endif