Statistics
| Branch: | Revision:

root / exec.c @ 925fb139

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