Statistics
| Branch: | Revision:

root / exec.c @ 97eb5b14

History | View | Annotate | Download (54.4 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 54936004 bellard
#include <stdlib.h>
21 54936004 bellard
#include <stdio.h>
22 54936004 bellard
#include <stdarg.h>
23 54936004 bellard
#include <string.h>
24 54936004 bellard
#include <errno.h>
25 54936004 bellard
#include <unistd.h>
26 54936004 bellard
#include <inttypes.h>
27 fd6ce8f6 bellard
#include <sys/mman.h>
28 54936004 bellard
29 ea041c0e bellard
#include "config.h"
30 6180a181 bellard
#include "cpu.h"
31 6180a181 bellard
#include "exec-all.h"
32 54936004 bellard
33 fd6ce8f6 bellard
//#define DEBUG_TB_INVALIDATE
34 66e85a21 bellard
//#define DEBUG_FLUSH
35 9fa3e853 bellard
//#define DEBUG_TLB
36 fd6ce8f6 bellard
37 fd6ce8f6 bellard
/* make various TB consistency checks */
38 fd6ce8f6 bellard
//#define DEBUG_TB_CHECK 
39 98857888 bellard
//#define DEBUG_TLB_CHECK 
40 fd6ce8f6 bellard
41 fd6ce8f6 bellard
/* threshold to flush the translated code buffer */
42 fd6ce8f6 bellard
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
43 fd6ce8f6 bellard
44 9fa3e853 bellard
#define SMC_BITMAP_USE_THRESHOLD 10
45 9fa3e853 bellard
46 9fa3e853 bellard
#define MMAP_AREA_START        0x00000000
47 9fa3e853 bellard
#define MMAP_AREA_END          0xa8000000
48 fd6ce8f6 bellard
49 fd6ce8f6 bellard
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
50 fd6ce8f6 bellard
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
51 9fa3e853 bellard
TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
52 fd6ce8f6 bellard
int nb_tbs;
53 eb51d102 bellard
/* any access to the tbs or the page table must use this lock */
54 eb51d102 bellard
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
55 fd6ce8f6 bellard
56 fd6ce8f6 bellard
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
57 fd6ce8f6 bellard
uint8_t *code_gen_ptr;
58 fd6ce8f6 bellard
59 9fa3e853 bellard
int phys_ram_size;
60 9fa3e853 bellard
int phys_ram_fd;
61 9fa3e853 bellard
uint8_t *phys_ram_base;
62 1ccde1cb bellard
uint8_t *phys_ram_dirty;
63 9fa3e853 bellard
64 54936004 bellard
typedef struct PageDesc {
65 9fa3e853 bellard
    /* offset in memory of the page + io_index in the low 12 bits */
66 9fa3e853 bellard
    unsigned long phys_offset;
67 9fa3e853 bellard
    /* list of TBs intersecting this physical page */
68 fd6ce8f6 bellard
    TranslationBlock *first_tb;
69 9fa3e853 bellard
    /* in order to optimize self modifying code, we count the number
70 9fa3e853 bellard
       of lookups we do to a given page to use a bitmap */
71 9fa3e853 bellard
    unsigned int code_write_count;
72 9fa3e853 bellard
    uint8_t *code_bitmap;
73 9fa3e853 bellard
#if defined(CONFIG_USER_ONLY)
74 9fa3e853 bellard
    unsigned long flags;
75 9fa3e853 bellard
#endif
76 54936004 bellard
} PageDesc;
77 54936004 bellard
78 9fa3e853 bellard
typedef struct VirtPageDesc {
79 9fa3e853 bellard
    /* physical address of code page. It is valid only if 'valid_tag'
80 9fa3e853 bellard
       matches 'virt_valid_tag' */ 
81 9fa3e853 bellard
    target_ulong phys_addr; 
82 9fa3e853 bellard
    unsigned int valid_tag;
83 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
84 9fa3e853 bellard
    /* original page access rights. It is valid only if 'valid_tag'
85 9fa3e853 bellard
       matches 'virt_valid_tag' */
86 9fa3e853 bellard
    unsigned int prot;
87 9fa3e853 bellard
#endif
88 9fa3e853 bellard
} VirtPageDesc;
89 9fa3e853 bellard
90 54936004 bellard
#define L2_BITS 10
91 54936004 bellard
#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
92 54936004 bellard
93 54936004 bellard
#define L1_SIZE (1 << L1_BITS)
94 54936004 bellard
#define L2_SIZE (1 << L2_BITS)
95 54936004 bellard
96 33417e70 bellard
static void io_mem_init(void);
97 fd6ce8f6 bellard
98 54936004 bellard
unsigned long real_host_page_size;
99 54936004 bellard
unsigned long host_page_bits;
100 54936004 bellard
unsigned long host_page_size;
101 54936004 bellard
unsigned long host_page_mask;
102 54936004 bellard
103 54936004 bellard
static PageDesc *l1_map[L1_SIZE];
104 54936004 bellard
105 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
106 9fa3e853 bellard
static VirtPageDesc *l1_virt_map[L1_SIZE];
107 9fa3e853 bellard
static unsigned int virt_valid_tag;
108 9fa3e853 bellard
#endif
109 9fa3e853 bellard
110 33417e70 bellard
/* io memory support */
111 33417e70 bellard
CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
112 33417e70 bellard
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
113 33417e70 bellard
static int io_mem_nb;
114 33417e70 bellard
115 34865134 bellard
/* log support */
116 34865134 bellard
char *logfilename = "/tmp/qemu.log";
117 34865134 bellard
FILE *logfile;
118 34865134 bellard
int loglevel;
119 34865134 bellard
120 b346ff46 bellard
static void page_init(void)
121 54936004 bellard
{
122 54936004 bellard
    /* NOTE: we can always suppose that host_page_size >=
123 54936004 bellard
       TARGET_PAGE_SIZE */
124 54936004 bellard
    real_host_page_size = getpagesize();
125 54936004 bellard
    if (host_page_size == 0)
126 54936004 bellard
        host_page_size = real_host_page_size;
127 54936004 bellard
    if (host_page_size < TARGET_PAGE_SIZE)
128 54936004 bellard
        host_page_size = TARGET_PAGE_SIZE;
129 54936004 bellard
    host_page_bits = 0;
130 54936004 bellard
    while ((1 << host_page_bits) < host_page_size)
131 54936004 bellard
        host_page_bits++;
132 54936004 bellard
    host_page_mask = ~(host_page_size - 1);
133 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
134 9fa3e853 bellard
    virt_valid_tag = 1;
135 9fa3e853 bellard
#endif
136 54936004 bellard
}
137 54936004 bellard
138 fd6ce8f6 bellard
static inline PageDesc *page_find_alloc(unsigned int index)
139 54936004 bellard
{
140 54936004 bellard
    PageDesc **lp, *p;
141 54936004 bellard
142 54936004 bellard
    lp = &l1_map[index >> L2_BITS];
143 54936004 bellard
    p = *lp;
144 54936004 bellard
    if (!p) {
145 54936004 bellard
        /* allocate if not found */
146 59817ccb bellard
        p = qemu_malloc(sizeof(PageDesc) * L2_SIZE);
147 fd6ce8f6 bellard
        memset(p, 0, sizeof(PageDesc) * L2_SIZE);
148 54936004 bellard
        *lp = p;
149 54936004 bellard
    }
150 54936004 bellard
    return p + (index & (L2_SIZE - 1));
151 54936004 bellard
}
152 54936004 bellard
153 fd6ce8f6 bellard
static inline PageDesc *page_find(unsigned int index)
154 54936004 bellard
{
155 54936004 bellard
    PageDesc *p;
156 54936004 bellard
157 54936004 bellard
    p = l1_map[index >> L2_BITS];
158 54936004 bellard
    if (!p)
159 54936004 bellard
        return 0;
160 fd6ce8f6 bellard
    return p + (index & (L2_SIZE - 1));
161 fd6ce8f6 bellard
}
162 fd6ce8f6 bellard
163 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
164 9fa3e853 bellard
static void tlb_protect_code(CPUState *env, uint32_t addr);
165 9fa3e853 bellard
static void tlb_unprotect_code(CPUState *env, uint32_t addr);
166 1ccde1cb bellard
static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr, target_ulong vaddr);
167 9fa3e853 bellard
168 9fa3e853 bellard
static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
169 fd6ce8f6 bellard
{
170 9fa3e853 bellard
    VirtPageDesc **lp, *p;
171 fd6ce8f6 bellard
172 9fa3e853 bellard
    lp = &l1_virt_map[index >> L2_BITS];
173 9fa3e853 bellard
    p = *lp;
174 9fa3e853 bellard
    if (!p) {
175 9fa3e853 bellard
        /* allocate if not found */
176 59817ccb bellard
        p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE);
177 9fa3e853 bellard
        memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE);
178 9fa3e853 bellard
        *lp = p;
179 9fa3e853 bellard
    }
180 9fa3e853 bellard
    return p + (index & (L2_SIZE - 1));
181 9fa3e853 bellard
}
182 9fa3e853 bellard
183 9fa3e853 bellard
static inline VirtPageDesc *virt_page_find(unsigned int index)
184 9fa3e853 bellard
{
185 9fa3e853 bellard
    VirtPageDesc *p;
186 9fa3e853 bellard
187 9fa3e853 bellard
    p = l1_virt_map[index >> L2_BITS];
188 fd6ce8f6 bellard
    if (!p)
189 fd6ce8f6 bellard
        return 0;
190 9fa3e853 bellard
    return p + (index & (L2_SIZE - 1));
191 54936004 bellard
}
192 54936004 bellard
193 9fa3e853 bellard
static void virt_page_flush(void)
194 54936004 bellard
{
195 9fa3e853 bellard
    int i, j;
196 9fa3e853 bellard
    VirtPageDesc *p;
197 9fa3e853 bellard
    
198 9fa3e853 bellard
    virt_valid_tag++;
199 9fa3e853 bellard
200 9fa3e853 bellard
    if (virt_valid_tag == 0) {
201 9fa3e853 bellard
        virt_valid_tag = 1;
202 9fa3e853 bellard
        for(i = 0; i < L1_SIZE; i++) {
203 9fa3e853 bellard
            p = l1_virt_map[i];
204 9fa3e853 bellard
            if (p) {
205 9fa3e853 bellard
                for(j = 0; j < L2_SIZE; j++)
206 9fa3e853 bellard
                    p[j].valid_tag = 0;
207 9fa3e853 bellard
            }
208 fd6ce8f6 bellard
        }
209 54936004 bellard
    }
210 54936004 bellard
}
211 9fa3e853 bellard
#else
212 9fa3e853 bellard
static void virt_page_flush(void)
213 9fa3e853 bellard
{
214 9fa3e853 bellard
}
215 9fa3e853 bellard
#endif
216 fd6ce8f6 bellard
217 b346ff46 bellard
void cpu_exec_init(void)
218 fd6ce8f6 bellard
{
219 fd6ce8f6 bellard
    if (!code_gen_ptr) {
220 fd6ce8f6 bellard
        code_gen_ptr = code_gen_buffer;
221 b346ff46 bellard
        page_init();
222 33417e70 bellard
        io_mem_init();
223 fd6ce8f6 bellard
    }
224 fd6ce8f6 bellard
}
225 fd6ce8f6 bellard
226 9fa3e853 bellard
static inline void invalidate_page_bitmap(PageDesc *p)
227 9fa3e853 bellard
{
228 9fa3e853 bellard
    if (p->code_bitmap) {
229 59817ccb bellard
        qemu_free(p->code_bitmap);
230 9fa3e853 bellard
        p->code_bitmap = NULL;
231 9fa3e853 bellard
    }
232 9fa3e853 bellard
    p->code_write_count = 0;
233 9fa3e853 bellard
}
234 9fa3e853 bellard
235 fd6ce8f6 bellard
/* set to NULL all the 'first_tb' fields in all PageDescs */
236 fd6ce8f6 bellard
static void page_flush_tb(void)
237 fd6ce8f6 bellard
{
238 fd6ce8f6 bellard
    int i, j;
239 fd6ce8f6 bellard
    PageDesc *p;
240 fd6ce8f6 bellard
241 fd6ce8f6 bellard
    for(i = 0; i < L1_SIZE; i++) {
242 fd6ce8f6 bellard
        p = l1_map[i];
243 fd6ce8f6 bellard
        if (p) {
244 9fa3e853 bellard
            for(j = 0; j < L2_SIZE; j++) {
245 9fa3e853 bellard
                p->first_tb = NULL;
246 9fa3e853 bellard
                invalidate_page_bitmap(p);
247 9fa3e853 bellard
                p++;
248 9fa3e853 bellard
            }
249 fd6ce8f6 bellard
        }
250 fd6ce8f6 bellard
    }
251 fd6ce8f6 bellard
}
252 fd6ce8f6 bellard
253 fd6ce8f6 bellard
/* flush all the translation blocks */
254 d4e8164f bellard
/* XXX: tb_flush is currently not thread safe */
255 0124311e bellard
void tb_flush(CPUState *env)
256 fd6ce8f6 bellard
{
257 fd6ce8f6 bellard
    int i;
258 0124311e bellard
#if defined(DEBUG_FLUSH)
259 fd6ce8f6 bellard
    printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
260 fd6ce8f6 bellard
           code_gen_ptr - code_gen_buffer, 
261 fd6ce8f6 bellard
           nb_tbs, 
262 0124311e bellard
           nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
263 fd6ce8f6 bellard
#endif
264 fd6ce8f6 bellard
    nb_tbs = 0;
265 fd6ce8f6 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
266 fd6ce8f6 bellard
        tb_hash[i] = NULL;
267 9fa3e853 bellard
    virt_page_flush();
268 9fa3e853 bellard
269 9fa3e853 bellard
    for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++)
270 9fa3e853 bellard
        tb_phys_hash[i] = NULL;
271 fd6ce8f6 bellard
    page_flush_tb();
272 9fa3e853 bellard
273 fd6ce8f6 bellard
    code_gen_ptr = code_gen_buffer;
274 d4e8164f bellard
    /* XXX: flush processor icache at this point if cache flush is
275 d4e8164f bellard
       expensive */
276 fd6ce8f6 bellard
}
277 fd6ce8f6 bellard
278 fd6ce8f6 bellard
#ifdef DEBUG_TB_CHECK
279 fd6ce8f6 bellard
280 fd6ce8f6 bellard
static void tb_invalidate_check(unsigned long address)
281 fd6ce8f6 bellard
{
282 fd6ce8f6 bellard
    TranslationBlock *tb;
283 fd6ce8f6 bellard
    int i;
284 fd6ce8f6 bellard
    address &= TARGET_PAGE_MASK;
285 fd6ce8f6 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
286 fd6ce8f6 bellard
        for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
287 fd6ce8f6 bellard
            if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
288 fd6ce8f6 bellard
                  address >= tb->pc + tb->size)) {
289 fd6ce8f6 bellard
                printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
290 fd6ce8f6 bellard
                       address, tb->pc, tb->size);
291 fd6ce8f6 bellard
            }
292 fd6ce8f6 bellard
        }
293 fd6ce8f6 bellard
    }
294 fd6ce8f6 bellard
}
295 fd6ce8f6 bellard
296 fd6ce8f6 bellard
/* verify that all the pages have correct rights for code */
297 fd6ce8f6 bellard
static void tb_page_check(void)
298 fd6ce8f6 bellard
{
299 fd6ce8f6 bellard
    TranslationBlock *tb;
300 fd6ce8f6 bellard
    int i, flags1, flags2;
301 fd6ce8f6 bellard
    
302 fd6ce8f6 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
303 fd6ce8f6 bellard
        for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
304 fd6ce8f6 bellard
            flags1 = page_get_flags(tb->pc);
305 fd6ce8f6 bellard
            flags2 = page_get_flags(tb->pc + tb->size - 1);
306 fd6ce8f6 bellard
            if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
307 fd6ce8f6 bellard
                printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
308 fd6ce8f6 bellard
                       tb->pc, tb->size, flags1, flags2);
309 fd6ce8f6 bellard
            }
310 fd6ce8f6 bellard
        }
311 fd6ce8f6 bellard
    }
312 fd6ce8f6 bellard
}
313 fd6ce8f6 bellard
314 d4e8164f bellard
void tb_jmp_check(TranslationBlock *tb)
315 d4e8164f bellard
{
316 d4e8164f bellard
    TranslationBlock *tb1;
317 d4e8164f bellard
    unsigned int n1;
318 d4e8164f bellard
319 d4e8164f bellard
    /* suppress any remaining jumps to this TB */
320 d4e8164f bellard
    tb1 = tb->jmp_first;
321 d4e8164f bellard
    for(;;) {
322 d4e8164f bellard
        n1 = (long)tb1 & 3;
323 d4e8164f bellard
        tb1 = (TranslationBlock *)((long)tb1 & ~3);
324 d4e8164f bellard
        if (n1 == 2)
325 d4e8164f bellard
            break;
326 d4e8164f bellard
        tb1 = tb1->jmp_next[n1];
327 d4e8164f bellard
    }
328 d4e8164f bellard
    /* check end of list */
329 d4e8164f bellard
    if (tb1 != tb) {
330 d4e8164f bellard
        printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
331 d4e8164f bellard
    }
332 d4e8164f bellard
}
333 d4e8164f bellard
334 fd6ce8f6 bellard
#endif
335 fd6ce8f6 bellard
336 fd6ce8f6 bellard
/* invalidate one TB */
337 fd6ce8f6 bellard
static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
338 fd6ce8f6 bellard
                             int next_offset)
339 fd6ce8f6 bellard
{
340 fd6ce8f6 bellard
    TranslationBlock *tb1;
341 fd6ce8f6 bellard
    for(;;) {
342 fd6ce8f6 bellard
        tb1 = *ptb;
343 fd6ce8f6 bellard
        if (tb1 == tb) {
344 fd6ce8f6 bellard
            *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
345 fd6ce8f6 bellard
            break;
346 fd6ce8f6 bellard
        }
347 fd6ce8f6 bellard
        ptb = (TranslationBlock **)((char *)tb1 + next_offset);
348 fd6ce8f6 bellard
    }
349 fd6ce8f6 bellard
}
350 fd6ce8f6 bellard
351 9fa3e853 bellard
static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
352 9fa3e853 bellard
{
353 9fa3e853 bellard
    TranslationBlock *tb1;
354 9fa3e853 bellard
    unsigned int n1;
355 9fa3e853 bellard
356 9fa3e853 bellard
    for(;;) {
357 9fa3e853 bellard
        tb1 = *ptb;
358 9fa3e853 bellard
        n1 = (long)tb1 & 3;
359 9fa3e853 bellard
        tb1 = (TranslationBlock *)((long)tb1 & ~3);
360 9fa3e853 bellard
        if (tb1 == tb) {
361 9fa3e853 bellard
            *ptb = tb1->page_next[n1];
362 9fa3e853 bellard
            break;
363 9fa3e853 bellard
        }
364 9fa3e853 bellard
        ptb = &tb1->page_next[n1];
365 9fa3e853 bellard
    }
366 9fa3e853 bellard
}
367 9fa3e853 bellard
368 d4e8164f bellard
static inline void tb_jmp_remove(TranslationBlock *tb, int n)
369 d4e8164f bellard
{
370 d4e8164f bellard
    TranslationBlock *tb1, **ptb;
371 d4e8164f bellard
    unsigned int n1;
372 d4e8164f bellard
373 d4e8164f bellard
    ptb = &tb->jmp_next[n];
374 d4e8164f bellard
    tb1 = *ptb;
375 d4e8164f bellard
    if (tb1) {
376 d4e8164f bellard
        /* find tb(n) in circular list */
377 d4e8164f bellard
        for(;;) {
378 d4e8164f bellard
            tb1 = *ptb;
379 d4e8164f bellard
            n1 = (long)tb1 & 3;
380 d4e8164f bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
381 d4e8164f bellard
            if (n1 == n && tb1 == tb)
382 d4e8164f bellard
                break;
383 d4e8164f bellard
            if (n1 == 2) {
384 d4e8164f bellard
                ptb = &tb1->jmp_first;
385 d4e8164f bellard
            } else {
386 d4e8164f bellard
                ptb = &tb1->jmp_next[n1];
387 d4e8164f bellard
            }
388 d4e8164f bellard
        }
389 d4e8164f bellard
        /* now we can suppress tb(n) from the list */
390 d4e8164f bellard
        *ptb = tb->jmp_next[n];
391 d4e8164f bellard
392 d4e8164f bellard
        tb->jmp_next[n] = NULL;
393 d4e8164f bellard
    }
394 d4e8164f bellard
}
395 d4e8164f bellard
396 d4e8164f bellard
/* reset the jump entry 'n' of a TB so that it is not chained to
397 d4e8164f bellard
   another TB */
398 d4e8164f bellard
static inline void tb_reset_jump(TranslationBlock *tb, int n)
399 d4e8164f bellard
{
400 d4e8164f bellard
    tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
401 d4e8164f bellard
}
402 d4e8164f bellard
403 9fa3e853 bellard
static inline void tb_invalidate(TranslationBlock *tb)
404 fd6ce8f6 bellard
{
405 d4e8164f bellard
    unsigned int h, n1;
406 9fa3e853 bellard
    TranslationBlock *tb1, *tb2, **ptb;
407 d4e8164f bellard
    
408 36bdbe54 bellard
    tb_invalidated_flag = 1;
409 59817ccb bellard
410 fd6ce8f6 bellard
    /* remove the TB from the hash list */
411 fd6ce8f6 bellard
    h = tb_hash_func(tb->pc);
412 9fa3e853 bellard
    ptb = &tb_hash[h];
413 9fa3e853 bellard
    for(;;) {
414 9fa3e853 bellard
        tb1 = *ptb;
415 9fa3e853 bellard
        /* NOTE: the TB is not necessarily linked in the hash. It
416 9fa3e853 bellard
           indicates that it is not currently used */
417 9fa3e853 bellard
        if (tb1 == NULL)
418 9fa3e853 bellard
            return;
419 9fa3e853 bellard
        if (tb1 == tb) {
420 9fa3e853 bellard
            *ptb = tb1->hash_next;
421 9fa3e853 bellard
            break;
422 9fa3e853 bellard
        }
423 9fa3e853 bellard
        ptb = &tb1->hash_next;
424 fd6ce8f6 bellard
    }
425 d4e8164f bellard
426 d4e8164f bellard
    /* suppress this TB from the two jump lists */
427 d4e8164f bellard
    tb_jmp_remove(tb, 0);
428 d4e8164f bellard
    tb_jmp_remove(tb, 1);
429 d4e8164f bellard
430 d4e8164f bellard
    /* suppress any remaining jumps to this TB */
431 d4e8164f bellard
    tb1 = tb->jmp_first;
432 d4e8164f bellard
    for(;;) {
433 d4e8164f bellard
        n1 = (long)tb1 & 3;
434 d4e8164f bellard
        if (n1 == 2)
435 d4e8164f bellard
            break;
436 d4e8164f bellard
        tb1 = (TranslationBlock *)((long)tb1 & ~3);
437 d4e8164f bellard
        tb2 = tb1->jmp_next[n1];
438 d4e8164f bellard
        tb_reset_jump(tb1, n1);
439 d4e8164f bellard
        tb1->jmp_next[n1] = NULL;
440 d4e8164f bellard
        tb1 = tb2;
441 d4e8164f bellard
    }
442 d4e8164f bellard
    tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
443 fd6ce8f6 bellard
}
444 fd6ce8f6 bellard
445 9fa3e853 bellard
static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
446 fd6ce8f6 bellard
{
447 fd6ce8f6 bellard
    PageDesc *p;
448 9fa3e853 bellard
    unsigned int h;
449 9fa3e853 bellard
    target_ulong phys_pc;
450 9fa3e853 bellard
    
451 9fa3e853 bellard
    /* remove the TB from the hash list */
452 9fa3e853 bellard
    phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
453 9fa3e853 bellard
    h = tb_phys_hash_func(phys_pc);
454 9fa3e853 bellard
    tb_remove(&tb_phys_hash[h], tb, 
455 9fa3e853 bellard
              offsetof(TranslationBlock, phys_hash_next));
456 9fa3e853 bellard
457 9fa3e853 bellard
    /* remove the TB from the page list */
458 9fa3e853 bellard
    if (tb->page_addr[0] != page_addr) {
459 9fa3e853 bellard
        p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
460 9fa3e853 bellard
        tb_page_remove(&p->first_tb, tb);
461 9fa3e853 bellard
        invalidate_page_bitmap(p);
462 9fa3e853 bellard
    }
463 9fa3e853 bellard
    if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
464 9fa3e853 bellard
        p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
465 9fa3e853 bellard
        tb_page_remove(&p->first_tb, tb);
466 9fa3e853 bellard
        invalidate_page_bitmap(p);
467 9fa3e853 bellard
    }
468 9fa3e853 bellard
469 9fa3e853 bellard
    tb_invalidate(tb);
470 9fa3e853 bellard
}
471 9fa3e853 bellard
472 9fa3e853 bellard
static inline void set_bits(uint8_t *tab, int start, int len)
473 9fa3e853 bellard
{
474 9fa3e853 bellard
    int end, mask, end1;
475 9fa3e853 bellard
476 9fa3e853 bellard
    end = start + len;
477 9fa3e853 bellard
    tab += start >> 3;
478 9fa3e853 bellard
    mask = 0xff << (start & 7);
479 9fa3e853 bellard
    if ((start & ~7) == (end & ~7)) {
480 9fa3e853 bellard
        if (start < end) {
481 9fa3e853 bellard
            mask &= ~(0xff << (end & 7));
482 9fa3e853 bellard
            *tab |= mask;
483 9fa3e853 bellard
        }
484 9fa3e853 bellard
    } else {
485 9fa3e853 bellard
        *tab++ |= mask;
486 9fa3e853 bellard
        start = (start + 8) & ~7;
487 9fa3e853 bellard
        end1 = end & ~7;
488 9fa3e853 bellard
        while (start < end1) {
489 9fa3e853 bellard
            *tab++ = 0xff;
490 9fa3e853 bellard
            start += 8;
491 9fa3e853 bellard
        }
492 9fa3e853 bellard
        if (start < end) {
493 9fa3e853 bellard
            mask = ~(0xff << (end & 7));
494 9fa3e853 bellard
            *tab |= mask;
495 9fa3e853 bellard
        }
496 9fa3e853 bellard
    }
497 9fa3e853 bellard
}
498 9fa3e853 bellard
499 9fa3e853 bellard
static void build_page_bitmap(PageDesc *p)
500 9fa3e853 bellard
{
501 9fa3e853 bellard
    int n, tb_start, tb_end;
502 9fa3e853 bellard
    TranslationBlock *tb;
503 9fa3e853 bellard
    
504 59817ccb bellard
    p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
505 9fa3e853 bellard
    if (!p->code_bitmap)
506 9fa3e853 bellard
        return;
507 9fa3e853 bellard
    memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
508 9fa3e853 bellard
509 9fa3e853 bellard
    tb = p->first_tb;
510 9fa3e853 bellard
    while (tb != NULL) {
511 9fa3e853 bellard
        n = (long)tb & 3;
512 9fa3e853 bellard
        tb = (TranslationBlock *)((long)tb & ~3);
513 9fa3e853 bellard
        /* NOTE: this is subtle as a TB may span two physical pages */
514 9fa3e853 bellard
        if (n == 0) {
515 9fa3e853 bellard
            /* NOTE: tb_end may be after the end of the page, but
516 9fa3e853 bellard
               it is not a problem */
517 9fa3e853 bellard
            tb_start = tb->pc & ~TARGET_PAGE_MASK;
518 9fa3e853 bellard
            tb_end = tb_start + tb->size;
519 9fa3e853 bellard
            if (tb_end > TARGET_PAGE_SIZE)
520 9fa3e853 bellard
                tb_end = TARGET_PAGE_SIZE;
521 9fa3e853 bellard
        } else {
522 9fa3e853 bellard
            tb_start = 0;
523 9fa3e853 bellard
            tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
524 9fa3e853 bellard
        }
525 9fa3e853 bellard
        set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
526 9fa3e853 bellard
        tb = tb->page_next[n];
527 9fa3e853 bellard
    }
528 9fa3e853 bellard
}
529 9fa3e853 bellard
530 9fa3e853 bellard
/* invalidate all TBs which intersect with the target physical page
531 9fa3e853 bellard
   starting in range [start;end[. NOTE: start and end must refer to
532 1ccde1cb bellard
   the same physical page. 'vaddr' is a virtual address referencing
533 1ccde1cb bellard
   the physical page of code. It is only used an a hint if there is no
534 1ccde1cb bellard
   code left. */
535 1ccde1cb bellard
static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, 
536 1ccde1cb bellard
                                          target_ulong vaddr)
537 9fa3e853 bellard
{
538 9fa3e853 bellard
    int n;
539 9fa3e853 bellard
    PageDesc *p;
540 9fa3e853 bellard
    TranslationBlock *tb, *tb_next;
541 9fa3e853 bellard
    target_ulong tb_start, tb_end;
542 9fa3e853 bellard
543 9fa3e853 bellard
    p = page_find(start >> TARGET_PAGE_BITS);
544 9fa3e853 bellard
    if (!p) 
545 9fa3e853 bellard
        return;
546 9fa3e853 bellard
    if (!p->code_bitmap && 
547 9fa3e853 bellard
        ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD) {
548 9fa3e853 bellard
        /* build code bitmap */
549 9fa3e853 bellard
        build_page_bitmap(p);
550 9fa3e853 bellard
    }
551 9fa3e853 bellard
552 9fa3e853 bellard
    /* we remove all the TBs in the range [start, end[ */
553 9fa3e853 bellard
    /* XXX: see if in some cases it could be faster to invalidate all the code */
554 9fa3e853 bellard
    tb = p->first_tb;
555 9fa3e853 bellard
    while (tb != NULL) {
556 9fa3e853 bellard
        n = (long)tb & 3;
557 9fa3e853 bellard
        tb = (TranslationBlock *)((long)tb & ~3);
558 9fa3e853 bellard
        tb_next = tb->page_next[n];
559 9fa3e853 bellard
        /* NOTE: this is subtle as a TB may span two physical pages */
560 9fa3e853 bellard
        if (n == 0) {
561 9fa3e853 bellard
            /* NOTE: tb_end may be after the end of the page, but
562 9fa3e853 bellard
               it is not a problem */
563 9fa3e853 bellard
            tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
564 9fa3e853 bellard
            tb_end = tb_start + tb->size;
565 9fa3e853 bellard
        } else {
566 9fa3e853 bellard
            tb_start = tb->page_addr[1];
567 9fa3e853 bellard
            tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
568 9fa3e853 bellard
        }
569 9fa3e853 bellard
        if (!(tb_end <= start || tb_start >= end)) {
570 9fa3e853 bellard
            tb_phys_invalidate(tb, -1);
571 9fa3e853 bellard
        }
572 9fa3e853 bellard
        tb = tb_next;
573 9fa3e853 bellard
    }
574 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
575 9fa3e853 bellard
    /* if no code remaining, no need to continue to use slow writes */
576 9fa3e853 bellard
    if (!p->first_tb) {
577 9fa3e853 bellard
        invalidate_page_bitmap(p);
578 1ccde1cb bellard
        tlb_unprotect_code_phys(cpu_single_env, start, vaddr);
579 9fa3e853 bellard
    }
580 fd6ce8f6 bellard
#endif
581 9fa3e853 bellard
}
582 fd6ce8f6 bellard
583 9fa3e853 bellard
/* len must be <= 8 and start must be a multiple of len */
584 1ccde1cb bellard
static inline void tb_invalidate_phys_page_fast(target_ulong start, int len, target_ulong vaddr)
585 9fa3e853 bellard
{
586 9fa3e853 bellard
    PageDesc *p;
587 9fa3e853 bellard
    int offset, b;
588 59817ccb bellard
#if 0
589 59817ccb bellard
    if (cpu_single_env->cr[0] & CR0_PE_MASK) {
590 59817ccb bellard
        printf("modifying code at 0x%x size=%d EIP=%x\n", 
591 59817ccb bellard
               (vaddr & TARGET_PAGE_MASK) | (start & ~TARGET_PAGE_MASK), len, 
592 59817ccb bellard
               cpu_single_env->eip);
593 59817ccb bellard
    }
594 59817ccb bellard
#endif
595 9fa3e853 bellard
    p = page_find(start >> TARGET_PAGE_BITS);
596 9fa3e853 bellard
    if (!p) 
597 9fa3e853 bellard
        return;
598 9fa3e853 bellard
    if (p->code_bitmap) {
599 9fa3e853 bellard
        offset = start & ~TARGET_PAGE_MASK;
600 9fa3e853 bellard
        b = p->code_bitmap[offset >> 3] >> (offset & 7);
601 9fa3e853 bellard
        if (b & ((1 << len) - 1))
602 9fa3e853 bellard
            goto do_invalidate;
603 9fa3e853 bellard
    } else {
604 9fa3e853 bellard
    do_invalidate:
605 1ccde1cb bellard
        tb_invalidate_phys_page_range(start, start + len, vaddr);
606 9fa3e853 bellard
    }
607 9fa3e853 bellard
}
608 9fa3e853 bellard
609 9fa3e853 bellard
/* invalidate all TBs which intersect with the target virtual page
610 9fa3e853 bellard
   starting in range [start;end[. This function is usually used when
611 9fa3e853 bellard
   the target processor flushes its I-cache. NOTE: start and end must
612 9fa3e853 bellard
   refer to the same physical page */
613 9fa3e853 bellard
void tb_invalidate_page_range(target_ulong start, target_ulong end)
614 9fa3e853 bellard
{
615 9fa3e853 bellard
    int n;
616 9fa3e853 bellard
    PageDesc *p;
617 9fa3e853 bellard
    TranslationBlock *tb, *tb_next;
618 9fa3e853 bellard
    target_ulong pc;
619 9fa3e853 bellard
    target_ulong phys_start;
620 9fa3e853 bellard
621 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
622 9fa3e853 bellard
    {
623 9fa3e853 bellard
        VirtPageDesc *vp;
624 9fa3e853 bellard
        vp = virt_page_find(start >> TARGET_PAGE_BITS);
625 9fa3e853 bellard
        if (!vp)
626 9fa3e853 bellard
            return;
627 9fa3e853 bellard
        if (vp->valid_tag != virt_valid_tag)
628 9fa3e853 bellard
            return;
629 9fa3e853 bellard
        phys_start = vp->phys_addr + (start & ~TARGET_PAGE_MASK);
630 9fa3e853 bellard
    }
631 9fa3e853 bellard
#else
632 9fa3e853 bellard
    phys_start = start;
633 9fa3e853 bellard
#endif    
634 9fa3e853 bellard
    p = page_find(phys_start >> TARGET_PAGE_BITS);
635 9fa3e853 bellard
    if (!p) 
636 fd6ce8f6 bellard
        return;
637 9fa3e853 bellard
    /* we remove all the TBs in the range [start, end[ */
638 9fa3e853 bellard
    /* XXX: see if in some cases it could be faster to invalidate all the code */
639 fd6ce8f6 bellard
    tb = p->first_tb;
640 fd6ce8f6 bellard
    while (tb != NULL) {
641 9fa3e853 bellard
        n = (long)tb & 3;
642 9fa3e853 bellard
        tb = (TranslationBlock *)((long)tb & ~3);
643 9fa3e853 bellard
        tb_next = tb->page_next[n];
644 9fa3e853 bellard
        pc = tb->pc;
645 9fa3e853 bellard
        if (!((pc + tb->size) <= start || pc >= end)) {
646 9fa3e853 bellard
            tb_phys_invalidate(tb, -1);
647 9fa3e853 bellard
        }
648 fd6ce8f6 bellard
        tb = tb_next;
649 fd6ce8f6 bellard
    }
650 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
651 9fa3e853 bellard
    /* if no code remaining, no need to continue to use slow writes */
652 9fa3e853 bellard
    if (!p->first_tb)
653 9fa3e853 bellard
        tlb_unprotect_code(cpu_single_env, start);
654 9fa3e853 bellard
#endif
655 9fa3e853 bellard
}
656 9fa3e853 bellard
657 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
658 9fa3e853 bellard
static void tb_invalidate_phys_page(target_ulong addr)
659 9fa3e853 bellard
{
660 9fa3e853 bellard
    int n;
661 9fa3e853 bellard
    PageDesc *p;
662 9fa3e853 bellard
    TranslationBlock *tb;
663 9fa3e853 bellard
664 9fa3e853 bellard
    addr &= TARGET_PAGE_MASK;
665 9fa3e853 bellard
    p = page_find(addr >> TARGET_PAGE_BITS);
666 9fa3e853 bellard
    if (!p) 
667 9fa3e853 bellard
        return;
668 9fa3e853 bellard
    tb = p->first_tb;
669 9fa3e853 bellard
    while (tb != NULL) {
670 9fa3e853 bellard
        n = (long)tb & 3;
671 9fa3e853 bellard
        tb = (TranslationBlock *)((long)tb & ~3);
672 9fa3e853 bellard
        tb_phys_invalidate(tb, addr);
673 9fa3e853 bellard
        tb = tb->page_next[n];
674 9fa3e853 bellard
    }
675 fd6ce8f6 bellard
    p->first_tb = NULL;
676 fd6ce8f6 bellard
}
677 9fa3e853 bellard
#endif
678 fd6ce8f6 bellard
679 fd6ce8f6 bellard
/* add the tb in the target page and protect it if necessary */
680 9fa3e853 bellard
static inline void tb_alloc_page(TranslationBlock *tb, 
681 9fa3e853 bellard
                                 unsigned int n, unsigned int page_addr)
682 fd6ce8f6 bellard
{
683 fd6ce8f6 bellard
    PageDesc *p;
684 9fa3e853 bellard
    TranslationBlock *last_first_tb;
685 9fa3e853 bellard
686 9fa3e853 bellard
    tb->page_addr[n] = page_addr;
687 9fa3e853 bellard
    p = page_find(page_addr >> TARGET_PAGE_BITS);
688 9fa3e853 bellard
    tb->page_next[n] = p->first_tb;
689 9fa3e853 bellard
    last_first_tb = p->first_tb;
690 9fa3e853 bellard
    p->first_tb = (TranslationBlock *)((long)tb | n);
691 9fa3e853 bellard
    invalidate_page_bitmap(p);
692 fd6ce8f6 bellard
693 9fa3e853 bellard
#if defined(CONFIG_USER_ONLY)
694 fd6ce8f6 bellard
    if (p->flags & PAGE_WRITE) {
695 9fa3e853 bellard
        unsigned long host_start, host_end, addr;
696 9fa3e853 bellard
        int prot;
697 9fa3e853 bellard
698 fd6ce8f6 bellard
        /* force the host page as non writable (writes will have a
699 fd6ce8f6 bellard
           page fault + mprotect overhead) */
700 fd6ce8f6 bellard
        host_start = page_addr & host_page_mask;
701 fd6ce8f6 bellard
        host_end = host_start + host_page_size;
702 fd6ce8f6 bellard
        prot = 0;
703 fd6ce8f6 bellard
        for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
704 fd6ce8f6 bellard
            prot |= page_get_flags(addr);
705 fd6ce8f6 bellard
        mprotect((void *)host_start, host_page_size, 
706 fd6ce8f6 bellard
                 (prot & PAGE_BITS) & ~PAGE_WRITE);
707 fd6ce8f6 bellard
#ifdef DEBUG_TB_INVALIDATE
708 fd6ce8f6 bellard
        printf("protecting code page: 0x%08lx\n", 
709 fd6ce8f6 bellard
               host_start);
710 fd6ce8f6 bellard
#endif
711 fd6ce8f6 bellard
        p->flags &= ~PAGE_WRITE;
712 fd6ce8f6 bellard
    }
713 9fa3e853 bellard
#else
714 9fa3e853 bellard
    /* if some code is already present, then the pages are already
715 9fa3e853 bellard
       protected. So we handle the case where only the first TB is
716 9fa3e853 bellard
       allocated in a physical page */
717 9fa3e853 bellard
    if (!last_first_tb) {
718 9fa3e853 bellard
        target_ulong virt_addr;
719 9fa3e853 bellard
720 9fa3e853 bellard
        virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS);
721 9fa3e853 bellard
        tlb_protect_code(cpu_single_env, virt_addr);        
722 9fa3e853 bellard
    }
723 9fa3e853 bellard
#endif
724 fd6ce8f6 bellard
}
725 fd6ce8f6 bellard
726 fd6ce8f6 bellard
/* Allocate a new translation block. Flush the translation buffer if
727 fd6ce8f6 bellard
   too many translation blocks or too much generated code. */
728 d4e8164f bellard
TranslationBlock *tb_alloc(unsigned long pc)
729 fd6ce8f6 bellard
{
730 fd6ce8f6 bellard
    TranslationBlock *tb;
731 fd6ce8f6 bellard
732 fd6ce8f6 bellard
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
733 fd6ce8f6 bellard
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
734 d4e8164f bellard
        return NULL;
735 fd6ce8f6 bellard
    tb = &tbs[nb_tbs++];
736 fd6ce8f6 bellard
    tb->pc = pc;
737 d4e8164f bellard
    return tb;
738 d4e8164f bellard
}
739 d4e8164f bellard
740 9fa3e853 bellard
/* add a new TB and link it to the physical page tables. phys_page2 is
741 9fa3e853 bellard
   (-1) to indicate that only one page contains the TB. */
742 9fa3e853 bellard
void tb_link_phys(TranslationBlock *tb, 
743 9fa3e853 bellard
                  target_ulong phys_pc, target_ulong phys_page2)
744 d4e8164f bellard
{
745 9fa3e853 bellard
    unsigned int h;
746 9fa3e853 bellard
    TranslationBlock **ptb;
747 9fa3e853 bellard
748 9fa3e853 bellard
    /* add in the physical hash table */
749 9fa3e853 bellard
    h = tb_phys_hash_func(phys_pc);
750 9fa3e853 bellard
    ptb = &tb_phys_hash[h];
751 9fa3e853 bellard
    tb->phys_hash_next = *ptb;
752 9fa3e853 bellard
    *ptb = tb;
753 fd6ce8f6 bellard
754 fd6ce8f6 bellard
    /* add in the page list */
755 9fa3e853 bellard
    tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
756 9fa3e853 bellard
    if (phys_page2 != -1)
757 9fa3e853 bellard
        tb_alloc_page(tb, 1, phys_page2);
758 9fa3e853 bellard
    else
759 9fa3e853 bellard
        tb->page_addr[1] = -1;
760 61382a50 bellard
#ifdef DEBUG_TB_CHECK
761 61382a50 bellard
    tb_page_check();
762 61382a50 bellard
#endif
763 9fa3e853 bellard
}
764 9fa3e853 bellard
765 9fa3e853 bellard
/* link the tb with the other TBs */
766 9fa3e853 bellard
void tb_link(TranslationBlock *tb)
767 9fa3e853 bellard
{
768 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
769 9fa3e853 bellard
    {
770 9fa3e853 bellard
        VirtPageDesc *vp;
771 9fa3e853 bellard
        target_ulong addr;
772 9fa3e853 bellard
        
773 9fa3e853 bellard
        /* save the code memory mappings (needed to invalidate the code) */
774 9fa3e853 bellard
        addr = tb->pc & TARGET_PAGE_MASK;
775 9fa3e853 bellard
        vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
776 98857888 bellard
#ifdef DEBUG_TLB_CHECK 
777 98857888 bellard
        if (vp->valid_tag == virt_valid_tag &&
778 98857888 bellard
            vp->phys_addr != tb->page_addr[0]) {
779 98857888 bellard
            printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
780 98857888 bellard
                   addr, tb->page_addr[0], vp->phys_addr);
781 98857888 bellard
        }
782 98857888 bellard
#endif
783 9fa3e853 bellard
        vp->phys_addr = tb->page_addr[0];
784 59817ccb bellard
        if (vp->valid_tag != virt_valid_tag) {
785 59817ccb bellard
            vp->valid_tag = virt_valid_tag;
786 59817ccb bellard
#if !defined(CONFIG_SOFTMMU)
787 59817ccb bellard
            vp->prot = 0;
788 59817ccb bellard
#endif
789 59817ccb bellard
        }
790 9fa3e853 bellard
        
791 9fa3e853 bellard
        if (tb->page_addr[1] != -1) {
792 9fa3e853 bellard
            addr += TARGET_PAGE_SIZE;
793 9fa3e853 bellard
            vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS);
794 98857888 bellard
#ifdef DEBUG_TLB_CHECK 
795 98857888 bellard
            if (vp->valid_tag == virt_valid_tag &&
796 98857888 bellard
                vp->phys_addr != tb->page_addr[1]) { 
797 98857888 bellard
                printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
798 98857888 bellard
                       addr, tb->page_addr[1], vp->phys_addr);
799 98857888 bellard
            }
800 98857888 bellard
#endif
801 9fa3e853 bellard
            vp->phys_addr = tb->page_addr[1];
802 59817ccb bellard
            if (vp->valid_tag != virt_valid_tag) {
803 59817ccb bellard
                vp->valid_tag = virt_valid_tag;
804 59817ccb bellard
#if !defined(CONFIG_SOFTMMU)
805 59817ccb bellard
                vp->prot = 0;
806 59817ccb bellard
#endif
807 59817ccb bellard
            }
808 9fa3e853 bellard
        }
809 9fa3e853 bellard
    }
810 9fa3e853 bellard
#endif
811 9fa3e853 bellard
812 d4e8164f bellard
    tb->jmp_first = (TranslationBlock *)((long)tb | 2);
813 d4e8164f bellard
    tb->jmp_next[0] = NULL;
814 d4e8164f bellard
    tb->jmp_next[1] = NULL;
815 d4e8164f bellard
816 d4e8164f bellard
    /* init original jump addresses */
817 d4e8164f bellard
    if (tb->tb_next_offset[0] != 0xffff)
818 d4e8164f bellard
        tb_reset_jump(tb, 0);
819 d4e8164f bellard
    if (tb->tb_next_offset[1] != 0xffff)
820 d4e8164f bellard
        tb_reset_jump(tb, 1);
821 fd6ce8f6 bellard
}
822 fd6ce8f6 bellard
823 9fa3e853 bellard
/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
824 9fa3e853 bellard
   tb[1].tc_ptr. Return NULL if not found */
825 9fa3e853 bellard
TranslationBlock *tb_find_pc(unsigned long tc_ptr)
826 fd6ce8f6 bellard
{
827 9fa3e853 bellard
    int m_min, m_max, m;
828 9fa3e853 bellard
    unsigned long v;
829 9fa3e853 bellard
    TranslationBlock *tb;
830 a513fe19 bellard
831 a513fe19 bellard
    if (nb_tbs <= 0)
832 a513fe19 bellard
        return NULL;
833 a513fe19 bellard
    if (tc_ptr < (unsigned long)code_gen_buffer ||
834 a513fe19 bellard
        tc_ptr >= (unsigned long)code_gen_ptr)
835 a513fe19 bellard
        return NULL;
836 a513fe19 bellard
    /* binary search (cf Knuth) */
837 a513fe19 bellard
    m_min = 0;
838 a513fe19 bellard
    m_max = nb_tbs - 1;
839 a513fe19 bellard
    while (m_min <= m_max) {
840 a513fe19 bellard
        m = (m_min + m_max) >> 1;
841 a513fe19 bellard
        tb = &tbs[m];
842 a513fe19 bellard
        v = (unsigned long)tb->tc_ptr;
843 a513fe19 bellard
        if (v == tc_ptr)
844 a513fe19 bellard
            return tb;
845 a513fe19 bellard
        else if (tc_ptr < v) {
846 a513fe19 bellard
            m_max = m - 1;
847 a513fe19 bellard
        } else {
848 a513fe19 bellard
            m_min = m + 1;
849 a513fe19 bellard
        }
850 a513fe19 bellard
    } 
851 a513fe19 bellard
    return &tbs[m_max];
852 a513fe19 bellard
}
853 7501267e bellard
854 ea041c0e bellard
static void tb_reset_jump_recursive(TranslationBlock *tb);
855 ea041c0e bellard
856 ea041c0e bellard
static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
857 ea041c0e bellard
{
858 ea041c0e bellard
    TranslationBlock *tb1, *tb_next, **ptb;
859 ea041c0e bellard
    unsigned int n1;
860 ea041c0e bellard
861 ea041c0e bellard
    tb1 = tb->jmp_next[n];
862 ea041c0e bellard
    if (tb1 != NULL) {
863 ea041c0e bellard
        /* find head of list */
864 ea041c0e bellard
        for(;;) {
865 ea041c0e bellard
            n1 = (long)tb1 & 3;
866 ea041c0e bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
867 ea041c0e bellard
            if (n1 == 2)
868 ea041c0e bellard
                break;
869 ea041c0e bellard
            tb1 = tb1->jmp_next[n1];
870 ea041c0e bellard
        }
871 ea041c0e bellard
        /* we are now sure now that tb jumps to tb1 */
872 ea041c0e bellard
        tb_next = tb1;
873 ea041c0e bellard
874 ea041c0e bellard
        /* remove tb from the jmp_first list */
875 ea041c0e bellard
        ptb = &tb_next->jmp_first;
876 ea041c0e bellard
        for(;;) {
877 ea041c0e bellard
            tb1 = *ptb;
878 ea041c0e bellard
            n1 = (long)tb1 & 3;
879 ea041c0e bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
880 ea041c0e bellard
            if (n1 == n && tb1 == tb)
881 ea041c0e bellard
                break;
882 ea041c0e bellard
            ptb = &tb1->jmp_next[n1];
883 ea041c0e bellard
        }
884 ea041c0e bellard
        *ptb = tb->jmp_next[n];
885 ea041c0e bellard
        tb->jmp_next[n] = NULL;
886 ea041c0e bellard
        
887 ea041c0e bellard
        /* suppress the jump to next tb in generated code */
888 ea041c0e bellard
        tb_reset_jump(tb, n);
889 ea041c0e bellard
890 0124311e bellard
        /* suppress jumps in the tb on which we could have jumped */
891 ea041c0e bellard
        tb_reset_jump_recursive(tb_next);
892 ea041c0e bellard
    }
893 ea041c0e bellard
}
894 ea041c0e bellard
895 ea041c0e bellard
static void tb_reset_jump_recursive(TranslationBlock *tb)
896 ea041c0e bellard
{
897 ea041c0e bellard
    tb_reset_jump_recursive2(tb, 0);
898 ea041c0e bellard
    tb_reset_jump_recursive2(tb, 1);
899 ea041c0e bellard
}
900 ea041c0e bellard
901 c33a346e bellard
/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
902 c33a346e bellard
   breakpoint is reached */
903 4c3a88a2 bellard
int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
904 4c3a88a2 bellard
{
905 4c3a88a2 bellard
#if defined(TARGET_I386)
906 4c3a88a2 bellard
    int i;
907 4c3a88a2 bellard
908 4c3a88a2 bellard
    for(i = 0; i < env->nb_breakpoints; i++) {
909 4c3a88a2 bellard
        if (env->breakpoints[i] == pc)
910 4c3a88a2 bellard
            return 0;
911 4c3a88a2 bellard
    }
912 4c3a88a2 bellard
913 4c3a88a2 bellard
    if (env->nb_breakpoints >= MAX_BREAKPOINTS)
914 4c3a88a2 bellard
        return -1;
915 4c3a88a2 bellard
    env->breakpoints[env->nb_breakpoints++] = pc;
916 9fa3e853 bellard
    tb_invalidate_page_range(pc, pc + 1);
917 4c3a88a2 bellard
    return 0;
918 4c3a88a2 bellard
#else
919 4c3a88a2 bellard
    return -1;
920 4c3a88a2 bellard
#endif
921 4c3a88a2 bellard
}
922 4c3a88a2 bellard
923 4c3a88a2 bellard
/* remove a breakpoint */
924 4c3a88a2 bellard
int cpu_breakpoint_remove(CPUState *env, uint32_t pc)
925 4c3a88a2 bellard
{
926 4c3a88a2 bellard
#if defined(TARGET_I386)
927 4c3a88a2 bellard
    int i;
928 4c3a88a2 bellard
    for(i = 0; i < env->nb_breakpoints; i++) {
929 4c3a88a2 bellard
        if (env->breakpoints[i] == pc)
930 4c3a88a2 bellard
            goto found;
931 4c3a88a2 bellard
    }
932 4c3a88a2 bellard
    return -1;
933 4c3a88a2 bellard
 found:
934 4c3a88a2 bellard
    memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
935 4c3a88a2 bellard
            (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
936 4c3a88a2 bellard
    env->nb_breakpoints--;
937 9fa3e853 bellard
    tb_invalidate_page_range(pc, pc + 1);
938 4c3a88a2 bellard
    return 0;
939 4c3a88a2 bellard
#else
940 4c3a88a2 bellard
    return -1;
941 4c3a88a2 bellard
#endif
942 4c3a88a2 bellard
}
943 4c3a88a2 bellard
944 c33a346e bellard
/* enable or disable single step mode. EXCP_DEBUG is returned by the
945 c33a346e bellard
   CPU loop after each instruction */
946 c33a346e bellard
void cpu_single_step(CPUState *env, int enabled)
947 c33a346e bellard
{
948 c33a346e bellard
#if defined(TARGET_I386)
949 c33a346e bellard
    if (env->singlestep_enabled != enabled) {
950 c33a346e bellard
        env->singlestep_enabled = enabled;
951 c33a346e bellard
        /* must flush all the translated code to avoid inconsistancies */
952 9fa3e853 bellard
        /* XXX: only flush what is necessary */
953 0124311e bellard
        tb_flush(env);
954 c33a346e bellard
    }
955 c33a346e bellard
#endif
956 c33a346e bellard
}
957 c33a346e bellard
958 34865134 bellard
/* enable or disable low levels log */
959 34865134 bellard
void cpu_set_log(int log_flags)
960 34865134 bellard
{
961 34865134 bellard
    loglevel = log_flags;
962 34865134 bellard
    if (loglevel && !logfile) {
963 34865134 bellard
        logfile = fopen(logfilename, "w");
964 34865134 bellard
        if (!logfile) {
965 34865134 bellard
            perror(logfilename);
966 34865134 bellard
            _exit(1);
967 34865134 bellard
        }
968 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
969 9fa3e853 bellard
        /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
970 9fa3e853 bellard
        {
971 9fa3e853 bellard
            static uint8_t logfile_buf[4096];
972 9fa3e853 bellard
            setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
973 9fa3e853 bellard
        }
974 9fa3e853 bellard
#else
975 34865134 bellard
        setvbuf(logfile, NULL, _IOLBF, 0);
976 9fa3e853 bellard
#endif
977 34865134 bellard
    }
978 34865134 bellard
}
979 34865134 bellard
980 34865134 bellard
void cpu_set_log_filename(const char *filename)
981 34865134 bellard
{
982 34865134 bellard
    logfilename = strdup(filename);
983 34865134 bellard
}
984 c33a346e bellard
985 0124311e bellard
/* mask must never be zero, except for A20 change call */
986 68a79315 bellard
void cpu_interrupt(CPUState *env, int mask)
987 ea041c0e bellard
{
988 ea041c0e bellard
    TranslationBlock *tb;
989 ee8b7021 bellard
    static int interrupt_lock;
990 59817ccb bellard
991 68a79315 bellard
    env->interrupt_request |= mask;
992 ea041c0e bellard
    /* if the cpu is currently executing code, we must unlink it and
993 ea041c0e bellard
       all the potentially executing TB */
994 ea041c0e bellard
    tb = env->current_tb;
995 ee8b7021 bellard
    if (tb && !testandset(&interrupt_lock)) {
996 ee8b7021 bellard
        env->current_tb = NULL;
997 ea041c0e bellard
        tb_reset_jump_recursive(tb);
998 ee8b7021 bellard
        interrupt_lock = 0;
999 ea041c0e bellard
    }
1000 ea041c0e bellard
}
1001 ea041c0e bellard
1002 ea041c0e bellard
1003 7501267e bellard
void cpu_abort(CPUState *env, const char *fmt, ...)
1004 7501267e bellard
{
1005 7501267e bellard
    va_list ap;
1006 7501267e bellard
1007 7501267e bellard
    va_start(ap, fmt);
1008 7501267e bellard
    fprintf(stderr, "qemu: fatal: ");
1009 7501267e bellard
    vfprintf(stderr, fmt, ap);
1010 7501267e bellard
    fprintf(stderr, "\n");
1011 7501267e bellard
#ifdef TARGET_I386
1012 7501267e bellard
    cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
1013 7501267e bellard
#endif
1014 7501267e bellard
    va_end(ap);
1015 7501267e bellard
    abort();
1016 7501267e bellard
}
1017 7501267e bellard
1018 0124311e bellard
#if !defined(CONFIG_USER_ONLY)
1019 0124311e bellard
1020 ee8b7021 bellard
/* NOTE: if flush_global is true, also flush global entries (not
1021 ee8b7021 bellard
   implemented yet) */
1022 ee8b7021 bellard
void tlb_flush(CPUState *env, int flush_global)
1023 33417e70 bellard
{
1024 33417e70 bellard
    int i;
1025 0124311e bellard
1026 9fa3e853 bellard
#if defined(DEBUG_TLB)
1027 9fa3e853 bellard
    printf("tlb_flush:\n");
1028 9fa3e853 bellard
#endif
1029 0124311e bellard
    /* must reset current TB so that interrupts cannot modify the
1030 0124311e bellard
       links while we are modifying them */
1031 0124311e bellard
    env->current_tb = NULL;
1032 0124311e bellard
1033 33417e70 bellard
    for(i = 0; i < CPU_TLB_SIZE; i++) {
1034 33417e70 bellard
        env->tlb_read[0][i].address = -1;
1035 33417e70 bellard
        env->tlb_write[0][i].address = -1;
1036 33417e70 bellard
        env->tlb_read[1][i].address = -1;
1037 33417e70 bellard
        env->tlb_write[1][i].address = -1;
1038 33417e70 bellard
    }
1039 9fa3e853 bellard
1040 9fa3e853 bellard
    virt_page_flush();
1041 9fa3e853 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
1042 9fa3e853 bellard
        tb_hash[i] = NULL;
1043 9fa3e853 bellard
1044 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
1045 9fa3e853 bellard
    munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
1046 9fa3e853 bellard
#endif
1047 33417e70 bellard
}
1048 33417e70 bellard
1049 61382a50 bellard
static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr)
1050 61382a50 bellard
{
1051 61382a50 bellard
    if (addr == (tlb_entry->address & 
1052 61382a50 bellard
                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
1053 61382a50 bellard
        tlb_entry->address = -1;
1054 61382a50 bellard
}
1055 61382a50 bellard
1056 33417e70 bellard
void tlb_flush_page(CPUState *env, uint32_t addr)
1057 33417e70 bellard
{
1058 9fa3e853 bellard
    int i, n;
1059 9fa3e853 bellard
    VirtPageDesc *vp;
1060 9fa3e853 bellard
    PageDesc *p;
1061 9fa3e853 bellard
    TranslationBlock *tb;
1062 0124311e bellard
1063 9fa3e853 bellard
#if defined(DEBUG_TLB)
1064 9fa3e853 bellard
    printf("tlb_flush_page: 0x%08x\n", addr);
1065 9fa3e853 bellard
#endif
1066 0124311e bellard
    /* must reset current TB so that interrupts cannot modify the
1067 0124311e bellard
       links while we are modifying them */
1068 0124311e bellard
    env->current_tb = NULL;
1069 61382a50 bellard
1070 61382a50 bellard
    addr &= TARGET_PAGE_MASK;
1071 61382a50 bellard
    i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1072 61382a50 bellard
    tlb_flush_entry(&env->tlb_read[0][i], addr);
1073 61382a50 bellard
    tlb_flush_entry(&env->tlb_write[0][i], addr);
1074 61382a50 bellard
    tlb_flush_entry(&env->tlb_read[1][i], addr);
1075 61382a50 bellard
    tlb_flush_entry(&env->tlb_write[1][i], addr);
1076 0124311e bellard
1077 9fa3e853 bellard
    /* remove from the virtual pc hash table all the TB at this
1078 9fa3e853 bellard
       virtual address */
1079 9fa3e853 bellard
    
1080 9fa3e853 bellard
    vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1081 9fa3e853 bellard
    if (vp && vp->valid_tag == virt_valid_tag) {
1082 9fa3e853 bellard
        p = page_find(vp->phys_addr >> TARGET_PAGE_BITS);
1083 9fa3e853 bellard
        if (p) {
1084 9fa3e853 bellard
            /* we remove all the links to the TBs in this virtual page */
1085 9fa3e853 bellard
            tb = p->first_tb;
1086 9fa3e853 bellard
            while (tb != NULL) {
1087 9fa3e853 bellard
                n = (long)tb & 3;
1088 9fa3e853 bellard
                tb = (TranslationBlock *)((long)tb & ~3);
1089 9fa3e853 bellard
                if ((tb->pc & TARGET_PAGE_MASK) == addr ||
1090 9fa3e853 bellard
                    ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) {
1091 9fa3e853 bellard
                    tb_invalidate(tb);
1092 9fa3e853 bellard
                }
1093 9fa3e853 bellard
                tb = tb->page_next[n];
1094 9fa3e853 bellard
            }
1095 9fa3e853 bellard
        }
1096 98857888 bellard
        vp->valid_tag = 0;
1097 9fa3e853 bellard
    }
1098 9fa3e853 bellard
1099 0124311e bellard
#if !defined(CONFIG_SOFTMMU)
1100 9fa3e853 bellard
    if (addr < MMAP_AREA_END)
1101 0124311e bellard
        munmap((void *)addr, TARGET_PAGE_SIZE);
1102 61382a50 bellard
#endif
1103 9fa3e853 bellard
}
1104 9fa3e853 bellard
1105 9fa3e853 bellard
static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, uint32_t addr)
1106 9fa3e853 bellard
{
1107 9fa3e853 bellard
    if (addr == (tlb_entry->address & 
1108 9fa3e853 bellard
                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
1109 98857888 bellard
        (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE &&
1110 98857888 bellard
        (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) {
1111 1ccde1cb bellard
        tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_CODE;
1112 9fa3e853 bellard
    }
1113 9fa3e853 bellard
}
1114 9fa3e853 bellard
1115 9fa3e853 bellard
/* update the TLBs so that writes to code in the virtual page 'addr'
1116 9fa3e853 bellard
   can be detected */
1117 9fa3e853 bellard
static void tlb_protect_code(CPUState *env, uint32_t addr)
1118 9fa3e853 bellard
{
1119 9fa3e853 bellard
    int i;
1120 9fa3e853 bellard
1121 9fa3e853 bellard
    addr &= TARGET_PAGE_MASK;
1122 9fa3e853 bellard
    i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1123 9fa3e853 bellard
    tlb_protect_code1(&env->tlb_write[0][i], addr);
1124 9fa3e853 bellard
    tlb_protect_code1(&env->tlb_write[1][i], addr);
1125 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
1126 9fa3e853 bellard
    /* NOTE: as we generated the code for this page, it is already at
1127 9fa3e853 bellard
       least readable */
1128 9fa3e853 bellard
    if (addr < MMAP_AREA_END)
1129 9fa3e853 bellard
        mprotect((void *)addr, TARGET_PAGE_SIZE, PROT_READ);
1130 9fa3e853 bellard
#endif
1131 9fa3e853 bellard
}
1132 9fa3e853 bellard
1133 9fa3e853 bellard
static inline void tlb_unprotect_code1(CPUTLBEntry *tlb_entry, uint32_t addr)
1134 9fa3e853 bellard
{
1135 9fa3e853 bellard
    if (addr == (tlb_entry->address & 
1136 9fa3e853 bellard
                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
1137 9fa3e853 bellard
        (tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE) {
1138 1ccde1cb bellard
        tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1139 0124311e bellard
    }
1140 61382a50 bellard
}
1141 61382a50 bellard
1142 9fa3e853 bellard
/* update the TLB so that writes in virtual page 'addr' are no longer
1143 9fa3e853 bellard
   tested self modifying code */
1144 9fa3e853 bellard
static void tlb_unprotect_code(CPUState *env, uint32_t addr)
1145 61382a50 bellard
{
1146 33417e70 bellard
    int i;
1147 33417e70 bellard
1148 61382a50 bellard
    addr &= TARGET_PAGE_MASK;
1149 33417e70 bellard
    i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1150 9fa3e853 bellard
    tlb_unprotect_code1(&env->tlb_write[0][i], addr);
1151 9fa3e853 bellard
    tlb_unprotect_code1(&env->tlb_write[1][i], addr);
1152 9fa3e853 bellard
}
1153 9fa3e853 bellard
1154 9fa3e853 bellard
static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry, 
1155 9fa3e853 bellard
                                       uint32_t phys_addr)
1156 9fa3e853 bellard
{
1157 9fa3e853 bellard
    if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE &&
1158 9fa3e853 bellard
        ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) {
1159 1ccde1cb bellard
        tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1160 9fa3e853 bellard
    }
1161 9fa3e853 bellard
}
1162 9fa3e853 bellard
1163 9fa3e853 bellard
/* update the TLB so that writes in physical page 'phys_addr' are no longer
1164 9fa3e853 bellard
   tested self modifying code */
1165 1ccde1cb bellard
static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr, target_ulong vaddr)
1166 9fa3e853 bellard
{
1167 9fa3e853 bellard
    int i;
1168 9fa3e853 bellard
1169 9fa3e853 bellard
    phys_addr &= TARGET_PAGE_MASK;
1170 1ccde1cb bellard
    phys_addr += (long)phys_ram_base;
1171 1ccde1cb bellard
    i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1172 1ccde1cb bellard
    tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr);
1173 1ccde1cb bellard
    tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr);
1174 1ccde1cb bellard
}
1175 1ccde1cb bellard
1176 1ccde1cb bellard
static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, 
1177 1ccde1cb bellard
                                         unsigned long start, unsigned long length)
1178 1ccde1cb bellard
{
1179 1ccde1cb bellard
    unsigned long addr;
1180 1ccde1cb bellard
    if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
1181 1ccde1cb bellard
        addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1182 1ccde1cb bellard
        if ((addr - start) < length) {
1183 1ccde1cb bellard
            tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1184 1ccde1cb bellard
        }
1185 1ccde1cb bellard
    }
1186 1ccde1cb bellard
}
1187 1ccde1cb bellard
1188 1ccde1cb bellard
void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end)
1189 1ccde1cb bellard
{
1190 1ccde1cb bellard
    CPUState *env;
1191 59817ccb bellard
    target_ulong length, start1;
1192 1ccde1cb bellard
    int i;
1193 1ccde1cb bellard
1194 1ccde1cb bellard
    start &= TARGET_PAGE_MASK;
1195 1ccde1cb bellard
    end = TARGET_PAGE_ALIGN(end);
1196 1ccde1cb bellard
1197 1ccde1cb bellard
    length = end - start;
1198 1ccde1cb bellard
    if (length == 0)
1199 1ccde1cb bellard
        return;
1200 1ccde1cb bellard
    memset(phys_ram_dirty + (start >> TARGET_PAGE_BITS), 0, length >> TARGET_PAGE_BITS);
1201 1ccde1cb bellard
1202 1ccde1cb bellard
    env = cpu_single_env;
1203 1ccde1cb bellard
    /* we modify the TLB cache so that the dirty bit will be set again
1204 1ccde1cb bellard
       when accessing the range */
1205 59817ccb bellard
    start1 = start + (unsigned long)phys_ram_base;
1206 9fa3e853 bellard
    for(i = 0; i < CPU_TLB_SIZE; i++)
1207 59817ccb bellard
        tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
1208 9fa3e853 bellard
    for(i = 0; i < CPU_TLB_SIZE; i++)
1209 59817ccb bellard
        tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
1210 59817ccb bellard
1211 59817ccb bellard
#if !defined(CONFIG_SOFTMMU)
1212 59817ccb bellard
    /* XXX: this is expensive */
1213 59817ccb bellard
    {
1214 59817ccb bellard
        VirtPageDesc *p;
1215 59817ccb bellard
        int j;
1216 59817ccb bellard
        target_ulong addr;
1217 59817ccb bellard
1218 59817ccb bellard
        for(i = 0; i < L1_SIZE; i++) {
1219 59817ccb bellard
            p = l1_virt_map[i];
1220 59817ccb bellard
            if (p) {
1221 59817ccb bellard
                addr = i << (TARGET_PAGE_BITS + L2_BITS);
1222 59817ccb bellard
                for(j = 0; j < L2_SIZE; j++) {
1223 59817ccb bellard
                    if (p->valid_tag == virt_valid_tag &&
1224 59817ccb bellard
                        p->phys_addr >= start && p->phys_addr < end &&
1225 59817ccb bellard
                        (p->prot & PROT_WRITE)) {
1226 59817ccb bellard
                        if (addr < MMAP_AREA_END) {
1227 59817ccb bellard
                            mprotect((void *)addr, TARGET_PAGE_SIZE, 
1228 59817ccb bellard
                                     p->prot & ~PROT_WRITE);
1229 59817ccb bellard
                        }
1230 59817ccb bellard
                    }
1231 59817ccb bellard
                    addr += TARGET_PAGE_SIZE;
1232 59817ccb bellard
                    p++;
1233 59817ccb bellard
                }
1234 59817ccb bellard
            }
1235 59817ccb bellard
        }
1236 59817ccb bellard
    }
1237 59817ccb bellard
#endif
1238 1ccde1cb bellard
}
1239 1ccde1cb bellard
1240 1ccde1cb bellard
static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, 
1241 1ccde1cb bellard
                                    unsigned long start)
1242 1ccde1cb bellard
{
1243 1ccde1cb bellard
    unsigned long addr;
1244 1ccde1cb bellard
    if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
1245 1ccde1cb bellard
        addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
1246 1ccde1cb bellard
        if (addr == start) {
1247 1ccde1cb bellard
            tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
1248 1ccde1cb bellard
        }
1249 1ccde1cb bellard
    }
1250 1ccde1cb bellard
}
1251 1ccde1cb bellard
1252 1ccde1cb bellard
/* update the TLB corresponding to virtual page vaddr and phys addr
1253 1ccde1cb bellard
   addr so that it is no longer dirty */
1254 1ccde1cb bellard
static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1255 1ccde1cb bellard
{
1256 1ccde1cb bellard
    CPUState *env = cpu_single_env;
1257 1ccde1cb bellard
    int i;
1258 1ccde1cb bellard
1259 1ccde1cb bellard
    phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 1;
1260 1ccde1cb bellard
1261 1ccde1cb bellard
    addr &= TARGET_PAGE_MASK;
1262 1ccde1cb bellard
    i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1263 1ccde1cb bellard
    tlb_set_dirty1(&env->tlb_write[0][i], addr);
1264 1ccde1cb bellard
    tlb_set_dirty1(&env->tlb_write[1][i], addr);
1265 9fa3e853 bellard
}
1266 9fa3e853 bellard
1267 59817ccb bellard
/* add a new TLB entry. At most one entry for a given virtual address
1268 59817ccb bellard
   is permitted. Return 0 if OK or 2 if the page could not be mapped
1269 59817ccb bellard
   (can only happen in non SOFTMMU mode for I/O pages or pages
1270 59817ccb bellard
   conflicting with the host address space). */
1271 9fa3e853 bellard
int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, 
1272 9fa3e853 bellard
                 int is_user, int is_softmmu)
1273 9fa3e853 bellard
{
1274 9fa3e853 bellard
    PageDesc *p;
1275 9fa3e853 bellard
    target_ulong pd;
1276 9fa3e853 bellard
    TranslationBlock *first_tb;
1277 9fa3e853 bellard
    unsigned int index;
1278 9fa3e853 bellard
    target_ulong address, addend;
1279 9fa3e853 bellard
    int ret;
1280 9fa3e853 bellard
1281 9fa3e853 bellard
    p = page_find(paddr >> TARGET_PAGE_BITS);
1282 9fa3e853 bellard
    if (!p) {
1283 9fa3e853 bellard
        pd = IO_MEM_UNASSIGNED;
1284 9fa3e853 bellard
        first_tb = NULL;
1285 9fa3e853 bellard
    } else {
1286 9fa3e853 bellard
        pd = p->phys_offset;
1287 9fa3e853 bellard
        first_tb = p->first_tb;
1288 9fa3e853 bellard
    }
1289 9fa3e853 bellard
#if defined(DEBUG_TLB)
1290 9fa3e853 bellard
    printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
1291 9fa3e853 bellard
           vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd);
1292 9fa3e853 bellard
#endif
1293 9fa3e853 bellard
1294 9fa3e853 bellard
    ret = 0;
1295 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
1296 9fa3e853 bellard
    if (is_softmmu) 
1297 9fa3e853 bellard
#endif
1298 9fa3e853 bellard
    {
1299 9fa3e853 bellard
        if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1300 9fa3e853 bellard
            /* IO memory case */
1301 9fa3e853 bellard
            address = vaddr | pd;
1302 9fa3e853 bellard
            addend = paddr;
1303 9fa3e853 bellard
        } else {
1304 9fa3e853 bellard
            /* standard memory */
1305 9fa3e853 bellard
            address = vaddr;
1306 9fa3e853 bellard
            addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
1307 9fa3e853 bellard
        }
1308 9fa3e853 bellard
        
1309 9fa3e853 bellard
        index = (vaddr >> 12) & (CPU_TLB_SIZE - 1);
1310 9fa3e853 bellard
        addend -= vaddr;
1311 9fa3e853 bellard
        if (prot & PROT_READ) {
1312 9fa3e853 bellard
            env->tlb_read[is_user][index].address = address;
1313 9fa3e853 bellard
            env->tlb_read[is_user][index].addend = addend;
1314 9fa3e853 bellard
        } else {
1315 9fa3e853 bellard
            env->tlb_read[is_user][index].address = -1;
1316 9fa3e853 bellard
            env->tlb_read[is_user][index].addend = -1;
1317 9fa3e853 bellard
        }
1318 9fa3e853 bellard
        if (prot & PROT_WRITE) {
1319 9fa3e853 bellard
            if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
1320 9fa3e853 bellard
                /* ROM: access is ignored (same as unassigned) */
1321 9fa3e853 bellard
                env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
1322 1ccde1cb bellard
                env->tlb_write[is_user][index].addend = addend;
1323 9fa3e853 bellard
            } else if (first_tb) {
1324 9fa3e853 bellard
                /* if code is present, we use a specific memory
1325 9fa3e853 bellard
                   handler. It works only for physical memory access */
1326 9fa3e853 bellard
                env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE;
1327 1ccde1cb bellard
                env->tlb_write[is_user][index].addend = addend;
1328 1ccde1cb bellard
            } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && 
1329 1ccde1cb bellard
                       !cpu_physical_memory_is_dirty(pd)) {
1330 1ccde1cb bellard
                env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
1331 1ccde1cb bellard
                env->tlb_write[is_user][index].addend = addend;
1332 9fa3e853 bellard
            } else {
1333 9fa3e853 bellard
                env->tlb_write[is_user][index].address = address;
1334 9fa3e853 bellard
                env->tlb_write[is_user][index].addend = addend;
1335 9fa3e853 bellard
            }
1336 9fa3e853 bellard
        } else {
1337 9fa3e853 bellard
            env->tlb_write[is_user][index].address = -1;
1338 9fa3e853 bellard
            env->tlb_write[is_user][index].addend = -1;
1339 9fa3e853 bellard
        }
1340 9fa3e853 bellard
    }
1341 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
1342 9fa3e853 bellard
    else {
1343 9fa3e853 bellard
        if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
1344 9fa3e853 bellard
            /* IO access: no mapping is done as it will be handled by the
1345 9fa3e853 bellard
               soft MMU */
1346 9fa3e853 bellard
            if (!(env->hflags & HF_SOFTMMU_MASK))
1347 9fa3e853 bellard
                ret = 2;
1348 9fa3e853 bellard
        } else {
1349 9fa3e853 bellard
            void *map_addr;
1350 59817ccb bellard
1351 59817ccb bellard
            if (vaddr >= MMAP_AREA_END) {
1352 59817ccb bellard
                ret = 2;
1353 59817ccb bellard
            } else {
1354 59817ccb bellard
                if (prot & PROT_WRITE) {
1355 59817ccb bellard
                    if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || 
1356 59817ccb bellard
                        first_tb ||
1357 59817ccb bellard
                        ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && 
1358 59817ccb bellard
                         !cpu_physical_memory_is_dirty(pd))) {
1359 59817ccb bellard
                        /* ROM: we do as if code was inside */
1360 59817ccb bellard
                        /* if code is present, we only map as read only and save the
1361 59817ccb bellard
                           original mapping */
1362 59817ccb bellard
                        VirtPageDesc *vp;
1363 59817ccb bellard
                        
1364 59817ccb bellard
                        vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS);
1365 59817ccb bellard
                        vp->phys_addr = pd;
1366 59817ccb bellard
                        vp->prot = prot;
1367 59817ccb bellard
                        vp->valid_tag = virt_valid_tag;
1368 59817ccb bellard
                        prot &= ~PAGE_WRITE;
1369 59817ccb bellard
                    }
1370 59817ccb bellard
                }
1371 59817ccb bellard
                map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot, 
1372 59817ccb bellard
                                MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
1373 59817ccb bellard
                if (map_addr == MAP_FAILED) {
1374 59817ccb bellard
                    cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
1375 59817ccb bellard
                              paddr, vaddr);
1376 9fa3e853 bellard
                }
1377 9fa3e853 bellard
            }
1378 9fa3e853 bellard
        }
1379 9fa3e853 bellard
    }
1380 9fa3e853 bellard
#endif
1381 9fa3e853 bellard
    return ret;
1382 9fa3e853 bellard
}
1383 9fa3e853 bellard
1384 9fa3e853 bellard
/* called from signal handler: invalidate the code and unprotect the
1385 9fa3e853 bellard
   page. Return TRUE if the fault was succesfully handled. */
1386 9fa3e853 bellard
int page_unprotect(unsigned long addr)
1387 9fa3e853 bellard
{
1388 9fa3e853 bellard
#if !defined(CONFIG_SOFTMMU)
1389 9fa3e853 bellard
    VirtPageDesc *vp;
1390 9fa3e853 bellard
1391 9fa3e853 bellard
#if defined(DEBUG_TLB)
1392 9fa3e853 bellard
    printf("page_unprotect: addr=0x%08x\n", addr);
1393 9fa3e853 bellard
#endif
1394 9fa3e853 bellard
    addr &= TARGET_PAGE_MASK;
1395 59817ccb bellard
1396 59817ccb bellard
    /* if it is not mapped, no need to worry here */
1397 59817ccb bellard
    if (addr >= MMAP_AREA_END)
1398 59817ccb bellard
        return 0;
1399 9fa3e853 bellard
    vp = virt_page_find(addr >> TARGET_PAGE_BITS);
1400 9fa3e853 bellard
    if (!vp)
1401 9fa3e853 bellard
        return 0;
1402 9fa3e853 bellard
    /* NOTE: in this case, validate_tag is _not_ tested as it
1403 9fa3e853 bellard
       validates only the code TLB */
1404 9fa3e853 bellard
    if (vp->valid_tag != virt_valid_tag)
1405 9fa3e853 bellard
        return 0;
1406 9fa3e853 bellard
    if (!(vp->prot & PAGE_WRITE))
1407 9fa3e853 bellard
        return 0;
1408 9fa3e853 bellard
#if defined(DEBUG_TLB)
1409 9fa3e853 bellard
    printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n", 
1410 9fa3e853 bellard
           addr, vp->phys_addr, vp->prot);
1411 9fa3e853 bellard
#endif
1412 59817ccb bellard
    /* set the dirty bit */
1413 59817ccb bellard
    phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1;
1414 59817ccb bellard
    /* flush the code inside */
1415 9fa3e853 bellard
    tb_invalidate_phys_page(vp->phys_addr);
1416 59817ccb bellard
    if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1417 59817ccb bellard
        cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1418 59817ccb bellard
                  (unsigned long)addr, vp->prot);
1419 9fa3e853 bellard
    return 1;
1420 9fa3e853 bellard
#else
1421 9fa3e853 bellard
    return 0;
1422 9fa3e853 bellard
#endif
1423 33417e70 bellard
}
1424 33417e70 bellard
1425 0124311e bellard
#else
1426 0124311e bellard
1427 ee8b7021 bellard
void tlb_flush(CPUState *env, int flush_global)
1428 0124311e bellard
{
1429 0124311e bellard
}
1430 0124311e bellard
1431 0124311e bellard
void tlb_flush_page(CPUState *env, uint32_t addr)
1432 0124311e bellard
{
1433 0124311e bellard
}
1434 0124311e bellard
1435 0124311e bellard
void tlb_flush_page_write(CPUState *env, uint32_t addr)
1436 0124311e bellard
{
1437 0124311e bellard
}
1438 0124311e bellard
1439 9fa3e853 bellard
int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, 
1440 9fa3e853 bellard
                 int is_user, int is_softmmu)
1441 9fa3e853 bellard
{
1442 9fa3e853 bellard
    return 0;
1443 9fa3e853 bellard
}
1444 0124311e bellard
1445 9fa3e853 bellard
/* dump memory mappings */
1446 9fa3e853 bellard
void page_dump(FILE *f)
1447 33417e70 bellard
{
1448 9fa3e853 bellard
    unsigned long start, end;
1449 9fa3e853 bellard
    int i, j, prot, prot1;
1450 9fa3e853 bellard
    PageDesc *p;
1451 33417e70 bellard
1452 9fa3e853 bellard
    fprintf(f, "%-8s %-8s %-8s %s\n",
1453 9fa3e853 bellard
            "start", "end", "size", "prot");
1454 9fa3e853 bellard
    start = -1;
1455 9fa3e853 bellard
    end = -1;
1456 9fa3e853 bellard
    prot = 0;
1457 9fa3e853 bellard
    for(i = 0; i <= L1_SIZE; i++) {
1458 9fa3e853 bellard
        if (i < L1_SIZE)
1459 9fa3e853 bellard
            p = l1_map[i];
1460 9fa3e853 bellard
        else
1461 9fa3e853 bellard
            p = NULL;
1462 9fa3e853 bellard
        for(j = 0;j < L2_SIZE; j++) {
1463 9fa3e853 bellard
            if (!p)
1464 9fa3e853 bellard
                prot1 = 0;
1465 9fa3e853 bellard
            else
1466 9fa3e853 bellard
                prot1 = p[j].flags;
1467 9fa3e853 bellard
            if (prot1 != prot) {
1468 9fa3e853 bellard
                end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
1469 9fa3e853 bellard
                if (start != -1) {
1470 9fa3e853 bellard
                    fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
1471 9fa3e853 bellard
                            start, end, end - start, 
1472 9fa3e853 bellard
                            prot & PAGE_READ ? 'r' : '-',
1473 9fa3e853 bellard
                            prot & PAGE_WRITE ? 'w' : '-',
1474 9fa3e853 bellard
                            prot & PAGE_EXEC ? 'x' : '-');
1475 9fa3e853 bellard
                }
1476 9fa3e853 bellard
                if (prot1 != 0)
1477 9fa3e853 bellard
                    start = end;
1478 9fa3e853 bellard
                else
1479 9fa3e853 bellard
                    start = -1;
1480 9fa3e853 bellard
                prot = prot1;
1481 9fa3e853 bellard
            }
1482 9fa3e853 bellard
            if (!p)
1483 9fa3e853 bellard
                break;
1484 9fa3e853 bellard
        }
1485 33417e70 bellard
    }
1486 33417e70 bellard
}
1487 33417e70 bellard
1488 9fa3e853 bellard
int page_get_flags(unsigned long address)
1489 33417e70 bellard
{
1490 9fa3e853 bellard
    PageDesc *p;
1491 9fa3e853 bellard
1492 9fa3e853 bellard
    p = page_find(address >> TARGET_PAGE_BITS);
1493 33417e70 bellard
    if (!p)
1494 9fa3e853 bellard
        return 0;
1495 9fa3e853 bellard
    return p->flags;
1496 9fa3e853 bellard
}
1497 9fa3e853 bellard
1498 9fa3e853 bellard
/* modify the flags of a page and invalidate the code if
1499 9fa3e853 bellard
   necessary. The flag PAGE_WRITE_ORG is positionned automatically
1500 9fa3e853 bellard
   depending on PAGE_WRITE */
1501 9fa3e853 bellard
void page_set_flags(unsigned long start, unsigned long end, int flags)
1502 9fa3e853 bellard
{
1503 9fa3e853 bellard
    PageDesc *p;
1504 9fa3e853 bellard
    unsigned long addr;
1505 9fa3e853 bellard
1506 9fa3e853 bellard
    start = start & TARGET_PAGE_MASK;
1507 9fa3e853 bellard
    end = TARGET_PAGE_ALIGN(end);
1508 9fa3e853 bellard
    if (flags & PAGE_WRITE)
1509 9fa3e853 bellard
        flags |= PAGE_WRITE_ORG;
1510 9fa3e853 bellard
    spin_lock(&tb_lock);
1511 9fa3e853 bellard
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1512 9fa3e853 bellard
        p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1513 9fa3e853 bellard
        /* if the write protection is set, then we invalidate the code
1514 9fa3e853 bellard
           inside */
1515 9fa3e853 bellard
        if (!(p->flags & PAGE_WRITE) && 
1516 9fa3e853 bellard
            (flags & PAGE_WRITE) &&
1517 9fa3e853 bellard
            p->first_tb) {
1518 9fa3e853 bellard
            tb_invalidate_phys_page(addr);
1519 9fa3e853 bellard
        }
1520 9fa3e853 bellard
        p->flags = flags;
1521 9fa3e853 bellard
    }
1522 9fa3e853 bellard
    spin_unlock(&tb_lock);
1523 33417e70 bellard
}
1524 33417e70 bellard
1525 9fa3e853 bellard
/* called from signal handler: invalidate the code and unprotect the
1526 9fa3e853 bellard
   page. Return TRUE if the fault was succesfully handled. */
1527 9fa3e853 bellard
int page_unprotect(unsigned long address)
1528 9fa3e853 bellard
{
1529 9fa3e853 bellard
    unsigned int page_index, prot, pindex;
1530 9fa3e853 bellard
    PageDesc *p, *p1;
1531 9fa3e853 bellard
    unsigned long host_start, host_end, addr;
1532 9fa3e853 bellard
1533 9fa3e853 bellard
    host_start = address & host_page_mask;
1534 9fa3e853 bellard
    page_index = host_start >> TARGET_PAGE_BITS;
1535 9fa3e853 bellard
    p1 = page_find(page_index);
1536 9fa3e853 bellard
    if (!p1)
1537 9fa3e853 bellard
        return 0;
1538 9fa3e853 bellard
    host_end = host_start + host_page_size;
1539 9fa3e853 bellard
    p = p1;
1540 9fa3e853 bellard
    prot = 0;
1541 9fa3e853 bellard
    for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
1542 9fa3e853 bellard
        prot |= p->flags;
1543 9fa3e853 bellard
        p++;
1544 9fa3e853 bellard
    }
1545 9fa3e853 bellard
    /* if the page was really writable, then we change its
1546 9fa3e853 bellard
       protection back to writable */
1547 9fa3e853 bellard
    if (prot & PAGE_WRITE_ORG) {
1548 9fa3e853 bellard
        pindex = (address - host_start) >> TARGET_PAGE_BITS;
1549 9fa3e853 bellard
        if (!(p1[pindex].flags & PAGE_WRITE)) {
1550 9fa3e853 bellard
            mprotect((void *)host_start, host_page_size, 
1551 9fa3e853 bellard
                     (prot & PAGE_BITS) | PAGE_WRITE);
1552 9fa3e853 bellard
            p1[pindex].flags |= PAGE_WRITE;
1553 9fa3e853 bellard
            /* and since the content will be modified, we must invalidate
1554 9fa3e853 bellard
               the corresponding translated code. */
1555 9fa3e853 bellard
            tb_invalidate_phys_page(address);
1556 9fa3e853 bellard
#ifdef DEBUG_TB_CHECK
1557 9fa3e853 bellard
            tb_invalidate_check(address);
1558 9fa3e853 bellard
#endif
1559 9fa3e853 bellard
            return 1;
1560 9fa3e853 bellard
        }
1561 9fa3e853 bellard
    }
1562 9fa3e853 bellard
    return 0;
1563 9fa3e853 bellard
}
1564 9fa3e853 bellard
1565 9fa3e853 bellard
/* call this function when system calls directly modify a memory area */
1566 9fa3e853 bellard
void page_unprotect_range(uint8_t *data, unsigned long data_size)
1567 9fa3e853 bellard
{
1568 9fa3e853 bellard
    unsigned long start, end, addr;
1569 9fa3e853 bellard
1570 9fa3e853 bellard
    start = (unsigned long)data;
1571 9fa3e853 bellard
    end = start + data_size;
1572 9fa3e853 bellard
    start &= TARGET_PAGE_MASK;
1573 9fa3e853 bellard
    end = TARGET_PAGE_ALIGN(end);
1574 9fa3e853 bellard
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1575 9fa3e853 bellard
        page_unprotect(addr);
1576 9fa3e853 bellard
    }
1577 9fa3e853 bellard
}
1578 9fa3e853 bellard
1579 1ccde1cb bellard
static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1580 1ccde1cb bellard
{
1581 1ccde1cb bellard
}
1582 1ccde1cb bellard
1583 9fa3e853 bellard
#endif /* defined(CONFIG_USER_ONLY) */
1584 9fa3e853 bellard
1585 33417e70 bellard
/* register physical memory. 'size' must be a multiple of the target
1586 33417e70 bellard
   page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
1587 33417e70 bellard
   io memory page */
1588 33417e70 bellard
void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
1589 33417e70 bellard
                                  long phys_offset)
1590 33417e70 bellard
{
1591 33417e70 bellard
    unsigned long addr, end_addr;
1592 9fa3e853 bellard
    PageDesc *p;
1593 33417e70 bellard
1594 33417e70 bellard
    end_addr = start_addr + size;
1595 33417e70 bellard
    for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) {
1596 9fa3e853 bellard
        p = page_find_alloc(addr >> TARGET_PAGE_BITS);
1597 9fa3e853 bellard
        p->phys_offset = phys_offset;
1598 9fa3e853 bellard
        if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
1599 33417e70 bellard
            phys_offset += TARGET_PAGE_SIZE;
1600 33417e70 bellard
    }
1601 33417e70 bellard
}
1602 33417e70 bellard
1603 33417e70 bellard
static uint32_t unassigned_mem_readb(uint32_t addr)
1604 33417e70 bellard
{
1605 33417e70 bellard
    return 0;
1606 33417e70 bellard
}
1607 33417e70 bellard
1608 1ccde1cb bellard
static void unassigned_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
1609 33417e70 bellard
{
1610 33417e70 bellard
}
1611 33417e70 bellard
1612 33417e70 bellard
static CPUReadMemoryFunc *unassigned_mem_read[3] = {
1613 33417e70 bellard
    unassigned_mem_readb,
1614 33417e70 bellard
    unassigned_mem_readb,
1615 33417e70 bellard
    unassigned_mem_readb,
1616 33417e70 bellard
};
1617 33417e70 bellard
1618 33417e70 bellard
static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1619 33417e70 bellard
    unassigned_mem_writeb,
1620 33417e70 bellard
    unassigned_mem_writeb,
1621 33417e70 bellard
    unassigned_mem_writeb,
1622 33417e70 bellard
};
1623 33417e70 bellard
1624 9fa3e853 bellard
/* self modifying code support in soft mmu mode : writing to a page
1625 9fa3e853 bellard
   containing code comes to these functions */
1626 9fa3e853 bellard
1627 1ccde1cb bellard
static void code_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
1628 9fa3e853 bellard
{
1629 1ccde1cb bellard
    unsigned long phys_addr;
1630 1ccde1cb bellard
1631 1ccde1cb bellard
    phys_addr = addr - (long)phys_ram_base;
1632 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
1633 1ccde1cb bellard
    tb_invalidate_phys_page_fast(phys_addr, 1, vaddr);
1634 9fa3e853 bellard
#endif
1635 1ccde1cb bellard
    stb_raw((uint8_t *)addr, val);
1636 1ccde1cb bellard
    phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
1637 9fa3e853 bellard
}
1638 9fa3e853 bellard
1639 1ccde1cb bellard
static void code_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr)
1640 9fa3e853 bellard
{
1641 1ccde1cb bellard
    unsigned long phys_addr;
1642 1ccde1cb bellard
1643 1ccde1cb bellard
    phys_addr = addr - (long)phys_ram_base;
1644 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
1645 1ccde1cb bellard
    tb_invalidate_phys_page_fast(phys_addr, 2, vaddr);
1646 9fa3e853 bellard
#endif
1647 1ccde1cb bellard
    stw_raw((uint8_t *)addr, val);
1648 1ccde1cb bellard
    phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
1649 9fa3e853 bellard
}
1650 9fa3e853 bellard
1651 1ccde1cb bellard
static void code_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr)
1652 9fa3e853 bellard
{
1653 1ccde1cb bellard
    unsigned long phys_addr;
1654 1ccde1cb bellard
1655 1ccde1cb bellard
    phys_addr = addr - (long)phys_ram_base;
1656 9fa3e853 bellard
#if !defined(CONFIG_USER_ONLY)
1657 1ccde1cb bellard
    tb_invalidate_phys_page_fast(phys_addr, 4, vaddr);
1658 9fa3e853 bellard
#endif
1659 1ccde1cb bellard
    stl_raw((uint8_t *)addr, val);
1660 1ccde1cb bellard
    phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
1661 9fa3e853 bellard
}
1662 9fa3e853 bellard
1663 9fa3e853 bellard
static CPUReadMemoryFunc *code_mem_read[3] = {
1664 9fa3e853 bellard
    NULL, /* never used */
1665 9fa3e853 bellard
    NULL, /* never used */
1666 9fa3e853 bellard
    NULL, /* never used */
1667 9fa3e853 bellard
};
1668 9fa3e853 bellard
1669 9fa3e853 bellard
static CPUWriteMemoryFunc *code_mem_write[3] = {
1670 9fa3e853 bellard
    code_mem_writeb,
1671 9fa3e853 bellard
    code_mem_writew,
1672 9fa3e853 bellard
    code_mem_writel,
1673 9fa3e853 bellard
};
1674 33417e70 bellard
1675 1ccde1cb bellard
static void notdirty_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
1676 1ccde1cb bellard
{
1677 1ccde1cb bellard
    stb_raw((uint8_t *)addr, val);
1678 1ccde1cb bellard
    tlb_set_dirty(addr, vaddr);
1679 1ccde1cb bellard
}
1680 1ccde1cb bellard
1681 1ccde1cb bellard
static void notdirty_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr)
1682 1ccde1cb bellard
{
1683 1ccde1cb bellard
    stw_raw((uint8_t *)addr, val);
1684 1ccde1cb bellard
    tlb_set_dirty(addr, vaddr);
1685 1ccde1cb bellard
}
1686 1ccde1cb bellard
1687 1ccde1cb bellard
static void notdirty_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr)
1688 1ccde1cb bellard
{
1689 1ccde1cb bellard
    stl_raw((uint8_t *)addr, val);
1690 1ccde1cb bellard
    tlb_set_dirty(addr, vaddr);
1691 1ccde1cb bellard
}
1692 1ccde1cb bellard
1693 1ccde1cb bellard
static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
1694 1ccde1cb bellard
    notdirty_mem_writeb,
1695 1ccde1cb bellard
    notdirty_mem_writew,
1696 1ccde1cb bellard
    notdirty_mem_writel,
1697 1ccde1cb bellard
};
1698 1ccde1cb bellard
1699 33417e70 bellard
static void io_mem_init(void)
1700 33417e70 bellard
{
1701 9fa3e853 bellard
    cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write);
1702 9fa3e853 bellard
    cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write);
1703 9fa3e853 bellard
    cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write);
1704 1ccde1cb bellard
    cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write);
1705 1ccde1cb bellard
    io_mem_nb = 5;
1706 1ccde1cb bellard
1707 1ccde1cb bellard
    /* alloc dirty bits array */
1708 59817ccb bellard
    phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS);
1709 33417e70 bellard
}
1710 33417e70 bellard
1711 33417e70 bellard
/* mem_read and mem_write are arrays of functions containing the
1712 33417e70 bellard
   function to access byte (index 0), word (index 1) and dword (index
1713 33417e70 bellard
   2). All functions must be supplied. If io_index is non zero, the
1714 33417e70 bellard
   corresponding io zone is modified. If it is zero, a new io zone is
1715 33417e70 bellard
   allocated. The return value can be used with
1716 33417e70 bellard
   cpu_register_physical_memory(). (-1) is returned if error. */
1717 33417e70 bellard
int cpu_register_io_memory(int io_index,
1718 33417e70 bellard
                           CPUReadMemoryFunc **mem_read,
1719 33417e70 bellard
                           CPUWriteMemoryFunc **mem_write)
1720 33417e70 bellard
{
1721 33417e70 bellard
    int i;
1722 33417e70 bellard
1723 33417e70 bellard
    if (io_index <= 0) {
1724 33417e70 bellard
        if (io_index >= IO_MEM_NB_ENTRIES)
1725 33417e70 bellard
            return -1;
1726 33417e70 bellard
        io_index = io_mem_nb++;
1727 33417e70 bellard
    } else {
1728 33417e70 bellard
        if (io_index >= IO_MEM_NB_ENTRIES)
1729 33417e70 bellard
            return -1;
1730 33417e70 bellard
    }
1731 33417e70 bellard
    
1732 33417e70 bellard
    for(i = 0;i < 3; i++) {
1733 33417e70 bellard
        io_mem_read[io_index][i] = mem_read[i];
1734 33417e70 bellard
        io_mem_write[io_index][i] = mem_write[i];
1735 33417e70 bellard
    }
1736 33417e70 bellard
    return io_index << IO_MEM_SHIFT;
1737 33417e70 bellard
}
1738 61382a50 bellard
1739 13eb76e0 bellard
/* physical memory access (slow version, mainly for debug) */
1740 13eb76e0 bellard
#if defined(CONFIG_USER_ONLY)
1741 13eb76e0 bellard
void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, 
1742 13eb76e0 bellard
                            int len, int is_write)
1743 13eb76e0 bellard
{
1744 13eb76e0 bellard
    int l, flags;
1745 13eb76e0 bellard
    target_ulong page;
1746 13eb76e0 bellard
1747 13eb76e0 bellard
    while (len > 0) {
1748 13eb76e0 bellard
        page = addr & TARGET_PAGE_MASK;
1749 13eb76e0 bellard
        l = (page + TARGET_PAGE_SIZE) - addr;
1750 13eb76e0 bellard
        if (l > len)
1751 13eb76e0 bellard
            l = len;
1752 13eb76e0 bellard
        flags = page_get_flags(page);
1753 13eb76e0 bellard
        if (!(flags & PAGE_VALID))
1754 13eb76e0 bellard
            return;
1755 13eb76e0 bellard
        if (is_write) {
1756 13eb76e0 bellard
            if (!(flags & PAGE_WRITE))
1757 13eb76e0 bellard
                return;
1758 13eb76e0 bellard
            memcpy((uint8_t *)addr, buf, len);
1759 13eb76e0 bellard
        } else {
1760 13eb76e0 bellard
            if (!(flags & PAGE_READ))
1761 13eb76e0 bellard
                return;
1762 13eb76e0 bellard
            memcpy(buf, (uint8_t *)addr, len);
1763 13eb76e0 bellard
        }
1764 13eb76e0 bellard
        len -= l;
1765 13eb76e0 bellard
        buf += l;
1766 13eb76e0 bellard
        addr += l;
1767 13eb76e0 bellard
    }
1768 13eb76e0 bellard
}
1769 13eb76e0 bellard
#else
1770 13eb76e0 bellard
void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr, 
1771 13eb76e0 bellard
                            int len, int is_write)
1772 13eb76e0 bellard
{
1773 13eb76e0 bellard
    int l, io_index;
1774 13eb76e0 bellard
    uint8_t *ptr;
1775 13eb76e0 bellard
    uint32_t val;
1776 13eb76e0 bellard
    target_ulong page, pd;
1777 13eb76e0 bellard
    PageDesc *p;
1778 13eb76e0 bellard
    
1779 13eb76e0 bellard
    while (len > 0) {
1780 13eb76e0 bellard
        page = addr & TARGET_PAGE_MASK;
1781 13eb76e0 bellard
        l = (page + TARGET_PAGE_SIZE) - addr;
1782 13eb76e0 bellard
        if (l > len)
1783 13eb76e0 bellard
            l = len;
1784 13eb76e0 bellard
        p = page_find(page >> TARGET_PAGE_BITS);
1785 13eb76e0 bellard
        if (!p) {
1786 13eb76e0 bellard
            pd = IO_MEM_UNASSIGNED;
1787 13eb76e0 bellard
        } else {
1788 13eb76e0 bellard
            pd = p->phys_offset;
1789 13eb76e0 bellard
        }
1790 13eb76e0 bellard
        
1791 13eb76e0 bellard
        if (is_write) {
1792 13eb76e0 bellard
            if ((pd & ~TARGET_PAGE_MASK) != 0) {
1793 13eb76e0 bellard
                io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
1794 13eb76e0 bellard
                if (l >= 4 && ((addr & 3) == 0)) {
1795 13eb76e0 bellard
                    /* 32 bit read access */
1796 13eb76e0 bellard
                    val = ldl_raw(buf);
1797 1ccde1cb bellard
                    io_mem_write[io_index][2](addr, val, 0);
1798 13eb76e0 bellard
                    l = 4;
1799 13eb76e0 bellard
                } else if (l >= 2 && ((addr & 1) == 0)) {
1800 13eb76e0 bellard
                    /* 16 bit read access */
1801 13eb76e0 bellard
                    val = lduw_raw(buf);
1802 1ccde1cb bellard
                    io_mem_write[io_index][1](addr, val, 0);
1803 13eb76e0 bellard
                    l = 2;
1804 13eb76e0 bellard
                } else {
1805 13eb76e0 bellard
                    /* 8 bit access */
1806 13eb76e0 bellard
                    val = ldub_raw(buf);
1807 1ccde1cb bellard
                    io_mem_write[io_index][0](addr, val, 0);
1808 13eb76e0 bellard
                    l = 1;
1809 13eb76e0 bellard
                }
1810 13eb76e0 bellard
            } else {
1811 13eb76e0 bellard
                /* RAM case */
1812 13eb76e0 bellard
                ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
1813 13eb76e0 bellard
                    (addr & ~TARGET_PAGE_MASK);
1814 13eb76e0 bellard
                memcpy(ptr, buf, l);
1815 13eb76e0 bellard
            }
1816 13eb76e0 bellard
        } else {
1817 13eb76e0 bellard
            if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
1818 13eb76e0 bellard
                (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
1819 13eb76e0 bellard
                /* I/O case */
1820 13eb76e0 bellard
                io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
1821 13eb76e0 bellard
                if (l >= 4 && ((addr & 3) == 0)) {
1822 13eb76e0 bellard
                    /* 32 bit read access */
1823 13eb76e0 bellard
                    val = io_mem_read[io_index][2](addr);
1824 13eb76e0 bellard
                    stl_raw(buf, val);
1825 13eb76e0 bellard
                    l = 4;
1826 13eb76e0 bellard
                } else if (l >= 2 && ((addr & 1) == 0)) {
1827 13eb76e0 bellard
                    /* 16 bit read access */
1828 13eb76e0 bellard
                    val = io_mem_read[io_index][1](addr);
1829 13eb76e0 bellard
                    stw_raw(buf, val);
1830 13eb76e0 bellard
                    l = 2;
1831 13eb76e0 bellard
                } else {
1832 13eb76e0 bellard
                    /* 8 bit access */
1833 13eb76e0 bellard
                    val = io_mem_read[io_index][0](addr);
1834 13eb76e0 bellard
                    stb_raw(buf, val);
1835 13eb76e0 bellard
                    l = 1;
1836 13eb76e0 bellard
                }
1837 13eb76e0 bellard
            } else {
1838 13eb76e0 bellard
                /* RAM case */
1839 13eb76e0 bellard
                ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
1840 13eb76e0 bellard
                    (addr & ~TARGET_PAGE_MASK);
1841 13eb76e0 bellard
                memcpy(buf, ptr, l);
1842 13eb76e0 bellard
            }
1843 13eb76e0 bellard
        }
1844 13eb76e0 bellard
        len -= l;
1845 13eb76e0 bellard
        buf += l;
1846 13eb76e0 bellard
        addr += l;
1847 13eb76e0 bellard
    }
1848 13eb76e0 bellard
}
1849 13eb76e0 bellard
#endif
1850 13eb76e0 bellard
1851 13eb76e0 bellard
/* virtual memory access for debug */
1852 13eb76e0 bellard
int cpu_memory_rw_debug(CPUState *env, 
1853 13eb76e0 bellard
                        uint8_t *buf, target_ulong addr, int len, int is_write)
1854 13eb76e0 bellard
{
1855 13eb76e0 bellard
    int l;
1856 13eb76e0 bellard
    target_ulong page, phys_addr;
1857 13eb76e0 bellard
1858 13eb76e0 bellard
    while (len > 0) {
1859 13eb76e0 bellard
        page = addr & TARGET_PAGE_MASK;
1860 13eb76e0 bellard
        phys_addr = cpu_get_phys_page_debug(env, page);
1861 13eb76e0 bellard
        /* if no physical page mapped, return an error */
1862 13eb76e0 bellard
        if (phys_addr == -1)
1863 13eb76e0 bellard
            return -1;
1864 13eb76e0 bellard
        l = (page + TARGET_PAGE_SIZE) - addr;
1865 13eb76e0 bellard
        if (l > len)
1866 13eb76e0 bellard
            l = len;
1867 13eb76e0 bellard
        cpu_physical_memory_rw(env, buf, 
1868 13eb76e0 bellard
                               phys_addr + (addr & ~TARGET_PAGE_MASK), l, 
1869 13eb76e0 bellard
                               is_write);
1870 13eb76e0 bellard
        len -= l;
1871 13eb76e0 bellard
        buf += l;
1872 13eb76e0 bellard
        addr += l;
1873 13eb76e0 bellard
    }
1874 13eb76e0 bellard
    return 0;
1875 13eb76e0 bellard
}
1876 13eb76e0 bellard
1877 61382a50 bellard
#if !defined(CONFIG_USER_ONLY) 
1878 61382a50 bellard
1879 61382a50 bellard
#define MMUSUFFIX _cmmu
1880 61382a50 bellard
#define GETPC() NULL
1881 61382a50 bellard
#define env cpu_single_env
1882 61382a50 bellard
1883 61382a50 bellard
#define SHIFT 0
1884 61382a50 bellard
#include "softmmu_template.h"
1885 61382a50 bellard
1886 61382a50 bellard
#define SHIFT 1
1887 61382a50 bellard
#include "softmmu_template.h"
1888 61382a50 bellard
1889 61382a50 bellard
#define SHIFT 2
1890 61382a50 bellard
#include "softmmu_template.h"
1891 61382a50 bellard
1892 61382a50 bellard
#define SHIFT 3
1893 61382a50 bellard
#include "softmmu_template.h"
1894 61382a50 bellard
1895 61382a50 bellard
#undef env
1896 61382a50 bellard
1897 61382a50 bellard
#endif