Statistics
| Branch: | Revision:

root / exec.c @ 61382a50

History | View | Annotate | Download (25.5 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 fd6ce8f6 bellard
36 fd6ce8f6 bellard
/* make various TB consistency checks */
37 fd6ce8f6 bellard
//#define DEBUG_TB_CHECK 
38 fd6ce8f6 bellard
39 fd6ce8f6 bellard
/* threshold to flush the translated code buffer */
40 fd6ce8f6 bellard
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
41 fd6ce8f6 bellard
42 fd6ce8f6 bellard
#define CODE_GEN_MAX_BLOCKS    (CODE_GEN_BUFFER_SIZE / 64)
43 fd6ce8f6 bellard
44 fd6ce8f6 bellard
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
45 fd6ce8f6 bellard
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
46 fd6ce8f6 bellard
int nb_tbs;
47 eb51d102 bellard
/* any access to the tbs or the page table must use this lock */
48 eb51d102 bellard
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
49 fd6ce8f6 bellard
50 fd6ce8f6 bellard
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
51 fd6ce8f6 bellard
uint8_t *code_gen_ptr;
52 fd6ce8f6 bellard
53 54936004 bellard
/* XXX: pack the flags in the low bits of the pointer ? */
54 54936004 bellard
typedef struct PageDesc {
55 54936004 bellard
    unsigned long flags;
56 fd6ce8f6 bellard
    TranslationBlock *first_tb;
57 54936004 bellard
} PageDesc;
58 54936004 bellard
59 54936004 bellard
#define L2_BITS 10
60 54936004 bellard
#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
61 54936004 bellard
62 54936004 bellard
#define L1_SIZE (1 << L1_BITS)
63 54936004 bellard
#define L2_SIZE (1 << L2_BITS)
64 54936004 bellard
65 fd6ce8f6 bellard
static void tb_invalidate_page(unsigned long address);
66 33417e70 bellard
static void io_mem_init(void);
67 fd6ce8f6 bellard
68 54936004 bellard
unsigned long real_host_page_size;
69 54936004 bellard
unsigned long host_page_bits;
70 54936004 bellard
unsigned long host_page_size;
71 54936004 bellard
unsigned long host_page_mask;
72 54936004 bellard
73 54936004 bellard
static PageDesc *l1_map[L1_SIZE];
74 54936004 bellard
75 33417e70 bellard
/* io memory support */
76 33417e70 bellard
static unsigned long *l1_physmap[L1_SIZE];
77 33417e70 bellard
CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
78 33417e70 bellard
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
79 33417e70 bellard
static int io_mem_nb;
80 33417e70 bellard
81 34865134 bellard
/* log support */
82 34865134 bellard
char *logfilename = "/tmp/qemu.log";
83 34865134 bellard
FILE *logfile;
84 34865134 bellard
int loglevel;
85 34865134 bellard
86 b346ff46 bellard
static void page_init(void)
87 54936004 bellard
{
88 54936004 bellard
    /* NOTE: we can always suppose that host_page_size >=
89 54936004 bellard
       TARGET_PAGE_SIZE */
90 54936004 bellard
    real_host_page_size = getpagesize();
91 54936004 bellard
    if (host_page_size == 0)
92 54936004 bellard
        host_page_size = real_host_page_size;
93 54936004 bellard
    if (host_page_size < TARGET_PAGE_SIZE)
94 54936004 bellard
        host_page_size = TARGET_PAGE_SIZE;
95 54936004 bellard
    host_page_bits = 0;
96 54936004 bellard
    while ((1 << host_page_bits) < host_page_size)
97 54936004 bellard
        host_page_bits++;
98 54936004 bellard
    host_page_mask = ~(host_page_size - 1);
99 54936004 bellard
}
100 54936004 bellard
101 54936004 bellard
/* dump memory mappings */
102 54936004 bellard
void page_dump(FILE *f)
103 54936004 bellard
{
104 54936004 bellard
    unsigned long start, end;
105 54936004 bellard
    int i, j, prot, prot1;
106 54936004 bellard
    PageDesc *p;
107 54936004 bellard
108 54936004 bellard
    fprintf(f, "%-8s %-8s %-8s %s\n",
109 54936004 bellard
            "start", "end", "size", "prot");
110 54936004 bellard
    start = -1;
111 54936004 bellard
    end = -1;
112 54936004 bellard
    prot = 0;
113 54936004 bellard
    for(i = 0; i <= L1_SIZE; i++) {
114 54936004 bellard
        if (i < L1_SIZE)
115 54936004 bellard
            p = l1_map[i];
116 54936004 bellard
        else
117 54936004 bellard
            p = NULL;
118 54936004 bellard
        for(j = 0;j < L2_SIZE; j++) {
119 54936004 bellard
            if (!p)
120 54936004 bellard
                prot1 = 0;
121 54936004 bellard
            else
122 54936004 bellard
                prot1 = p[j].flags;
123 54936004 bellard
            if (prot1 != prot) {
124 54936004 bellard
                end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
125 54936004 bellard
                if (start != -1) {
126 54936004 bellard
                    fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
127 54936004 bellard
                            start, end, end - start, 
128 54936004 bellard
                            prot & PAGE_READ ? 'r' : '-',
129 54936004 bellard
                            prot & PAGE_WRITE ? 'w' : '-',
130 54936004 bellard
                            prot & PAGE_EXEC ? 'x' : '-');
131 54936004 bellard
                }
132 54936004 bellard
                if (prot1 != 0)
133 54936004 bellard
                    start = end;
134 54936004 bellard
                else
135 54936004 bellard
                    start = -1;
136 54936004 bellard
                prot = prot1;
137 54936004 bellard
            }
138 54936004 bellard
            if (!p)
139 54936004 bellard
                break;
140 54936004 bellard
        }
141 54936004 bellard
    }
142 54936004 bellard
}
143 54936004 bellard
144 fd6ce8f6 bellard
static inline PageDesc *page_find_alloc(unsigned int index)
145 54936004 bellard
{
146 54936004 bellard
    PageDesc **lp, *p;
147 54936004 bellard
148 54936004 bellard
    lp = &l1_map[index >> L2_BITS];
149 54936004 bellard
    p = *lp;
150 54936004 bellard
    if (!p) {
151 54936004 bellard
        /* allocate if not found */
152 54936004 bellard
        p = malloc(sizeof(PageDesc) * L2_SIZE);
153 fd6ce8f6 bellard
        memset(p, 0, sizeof(PageDesc) * L2_SIZE);
154 54936004 bellard
        *lp = p;
155 54936004 bellard
    }
156 54936004 bellard
    return p + (index & (L2_SIZE - 1));
157 54936004 bellard
}
158 54936004 bellard
159 fd6ce8f6 bellard
static inline PageDesc *page_find(unsigned int index)
160 54936004 bellard
{
161 54936004 bellard
    PageDesc *p;
162 54936004 bellard
163 54936004 bellard
    p = l1_map[index >> L2_BITS];
164 54936004 bellard
    if (!p)
165 54936004 bellard
        return 0;
166 fd6ce8f6 bellard
    return p + (index & (L2_SIZE - 1));
167 fd6ce8f6 bellard
}
168 fd6ce8f6 bellard
169 fd6ce8f6 bellard
int page_get_flags(unsigned long address)
170 fd6ce8f6 bellard
{
171 fd6ce8f6 bellard
    PageDesc *p;
172 fd6ce8f6 bellard
173 fd6ce8f6 bellard
    p = page_find(address >> TARGET_PAGE_BITS);
174 fd6ce8f6 bellard
    if (!p)
175 fd6ce8f6 bellard
        return 0;
176 fd6ce8f6 bellard
    return p->flags;
177 54936004 bellard
}
178 54936004 bellard
179 fd6ce8f6 bellard
/* modify the flags of a page and invalidate the code if
180 fd6ce8f6 bellard
   necessary. The flag PAGE_WRITE_ORG is positionned automatically
181 fd6ce8f6 bellard
   depending on PAGE_WRITE */
182 54936004 bellard
void page_set_flags(unsigned long start, unsigned long end, int flags)
183 54936004 bellard
{
184 54936004 bellard
    PageDesc *p;
185 54936004 bellard
    unsigned long addr;
186 54936004 bellard
187 54936004 bellard
    start = start & TARGET_PAGE_MASK;
188 54936004 bellard
    end = TARGET_PAGE_ALIGN(end);
189 fd6ce8f6 bellard
    if (flags & PAGE_WRITE)
190 fd6ce8f6 bellard
        flags |= PAGE_WRITE_ORG;
191 eb51d102 bellard
    spin_lock(&tb_lock);
192 54936004 bellard
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
193 fd6ce8f6 bellard
        p = page_find_alloc(addr >> TARGET_PAGE_BITS);
194 fd6ce8f6 bellard
        /* if the write protection is set, then we invalidate the code
195 fd6ce8f6 bellard
           inside */
196 fd6ce8f6 bellard
        if (!(p->flags & PAGE_WRITE) && 
197 fd6ce8f6 bellard
            (flags & PAGE_WRITE) &&
198 fd6ce8f6 bellard
            p->first_tb) {
199 fd6ce8f6 bellard
            tb_invalidate_page(addr);
200 fd6ce8f6 bellard
        }
201 54936004 bellard
        p->flags = flags;
202 54936004 bellard
    }
203 eb51d102 bellard
    spin_unlock(&tb_lock);
204 54936004 bellard
}
205 fd6ce8f6 bellard
206 b346ff46 bellard
void cpu_exec_init(void)
207 fd6ce8f6 bellard
{
208 fd6ce8f6 bellard
    if (!code_gen_ptr) {
209 fd6ce8f6 bellard
        code_gen_ptr = code_gen_buffer;
210 b346ff46 bellard
        page_init();
211 33417e70 bellard
        io_mem_init();
212 fd6ce8f6 bellard
    }
213 fd6ce8f6 bellard
}
214 fd6ce8f6 bellard
215 fd6ce8f6 bellard
/* set to NULL all the 'first_tb' fields in all PageDescs */
216 fd6ce8f6 bellard
static void page_flush_tb(void)
217 fd6ce8f6 bellard
{
218 fd6ce8f6 bellard
    int i, j;
219 fd6ce8f6 bellard
    PageDesc *p;
220 fd6ce8f6 bellard
221 fd6ce8f6 bellard
    for(i = 0; i < L1_SIZE; i++) {
222 fd6ce8f6 bellard
        p = l1_map[i];
223 fd6ce8f6 bellard
        if (p) {
224 fd6ce8f6 bellard
            for(j = 0; j < L2_SIZE; j++)
225 fd6ce8f6 bellard
                p[j].first_tb = NULL;
226 fd6ce8f6 bellard
        }
227 fd6ce8f6 bellard
    }
228 fd6ce8f6 bellard
}
229 fd6ce8f6 bellard
230 fd6ce8f6 bellard
/* flush all the translation blocks */
231 d4e8164f bellard
/* XXX: tb_flush is currently not thread safe */
232 fd6ce8f6 bellard
void tb_flush(void)
233 fd6ce8f6 bellard
{
234 fd6ce8f6 bellard
    int i;
235 fd6ce8f6 bellard
#ifdef DEBUG_FLUSH
236 fd6ce8f6 bellard
    printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
237 fd6ce8f6 bellard
           code_gen_ptr - code_gen_buffer, 
238 fd6ce8f6 bellard
           nb_tbs, 
239 fd6ce8f6 bellard
           (code_gen_ptr - code_gen_buffer) / nb_tbs);
240 fd6ce8f6 bellard
#endif
241 fd6ce8f6 bellard
    nb_tbs = 0;
242 fd6ce8f6 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
243 fd6ce8f6 bellard
        tb_hash[i] = NULL;
244 fd6ce8f6 bellard
    page_flush_tb();
245 fd6ce8f6 bellard
    code_gen_ptr = code_gen_buffer;
246 d4e8164f bellard
    /* XXX: flush processor icache at this point if cache flush is
247 d4e8164f bellard
       expensive */
248 fd6ce8f6 bellard
}
249 fd6ce8f6 bellard
250 fd6ce8f6 bellard
#ifdef DEBUG_TB_CHECK
251 fd6ce8f6 bellard
252 fd6ce8f6 bellard
static void tb_invalidate_check(unsigned long address)
253 fd6ce8f6 bellard
{
254 fd6ce8f6 bellard
    TranslationBlock *tb;
255 fd6ce8f6 bellard
    int i;
256 fd6ce8f6 bellard
    address &= TARGET_PAGE_MASK;
257 fd6ce8f6 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
258 fd6ce8f6 bellard
        for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
259 fd6ce8f6 bellard
            if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
260 fd6ce8f6 bellard
                  address >= tb->pc + tb->size)) {
261 fd6ce8f6 bellard
                printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
262 fd6ce8f6 bellard
                       address, tb->pc, tb->size);
263 fd6ce8f6 bellard
            }
264 fd6ce8f6 bellard
        }
265 fd6ce8f6 bellard
    }
266 fd6ce8f6 bellard
}
267 fd6ce8f6 bellard
268 fd6ce8f6 bellard
/* verify that all the pages have correct rights for code */
269 fd6ce8f6 bellard
static void tb_page_check(void)
270 fd6ce8f6 bellard
{
271 fd6ce8f6 bellard
    TranslationBlock *tb;
272 fd6ce8f6 bellard
    int i, flags1, flags2;
273 fd6ce8f6 bellard
    
274 fd6ce8f6 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
275 fd6ce8f6 bellard
        for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
276 fd6ce8f6 bellard
            flags1 = page_get_flags(tb->pc);
277 fd6ce8f6 bellard
            flags2 = page_get_flags(tb->pc + tb->size - 1);
278 fd6ce8f6 bellard
            if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
279 fd6ce8f6 bellard
                printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
280 fd6ce8f6 bellard
                       tb->pc, tb->size, flags1, flags2);
281 fd6ce8f6 bellard
            }
282 fd6ce8f6 bellard
        }
283 fd6ce8f6 bellard
    }
284 fd6ce8f6 bellard
}
285 fd6ce8f6 bellard
286 d4e8164f bellard
void tb_jmp_check(TranslationBlock *tb)
287 d4e8164f bellard
{
288 d4e8164f bellard
    TranslationBlock *tb1;
289 d4e8164f bellard
    unsigned int n1;
290 d4e8164f bellard
291 d4e8164f bellard
    /* suppress any remaining jumps to this TB */
292 d4e8164f bellard
    tb1 = tb->jmp_first;
293 d4e8164f bellard
    for(;;) {
294 d4e8164f bellard
        n1 = (long)tb1 & 3;
295 d4e8164f bellard
        tb1 = (TranslationBlock *)((long)tb1 & ~3);
296 d4e8164f bellard
        if (n1 == 2)
297 d4e8164f bellard
            break;
298 d4e8164f bellard
        tb1 = tb1->jmp_next[n1];
299 d4e8164f bellard
    }
300 d4e8164f bellard
    /* check end of list */
301 d4e8164f bellard
    if (tb1 != tb) {
302 d4e8164f bellard
        printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
303 d4e8164f bellard
    }
304 d4e8164f bellard
}
305 d4e8164f bellard
306 fd6ce8f6 bellard
#endif
307 fd6ce8f6 bellard
308 fd6ce8f6 bellard
/* invalidate one TB */
309 fd6ce8f6 bellard
static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
310 fd6ce8f6 bellard
                             int next_offset)
311 fd6ce8f6 bellard
{
312 fd6ce8f6 bellard
    TranslationBlock *tb1;
313 fd6ce8f6 bellard
    for(;;) {
314 fd6ce8f6 bellard
        tb1 = *ptb;
315 fd6ce8f6 bellard
        if (tb1 == tb) {
316 fd6ce8f6 bellard
            *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
317 fd6ce8f6 bellard
            break;
318 fd6ce8f6 bellard
        }
319 fd6ce8f6 bellard
        ptb = (TranslationBlock **)((char *)tb1 + next_offset);
320 fd6ce8f6 bellard
    }
321 fd6ce8f6 bellard
}
322 fd6ce8f6 bellard
323 d4e8164f bellard
static inline void tb_jmp_remove(TranslationBlock *tb, int n)
324 d4e8164f bellard
{
325 d4e8164f bellard
    TranslationBlock *tb1, **ptb;
326 d4e8164f bellard
    unsigned int n1;
327 d4e8164f bellard
328 d4e8164f bellard
    ptb = &tb->jmp_next[n];
329 d4e8164f bellard
    tb1 = *ptb;
330 d4e8164f bellard
    if (tb1) {
331 d4e8164f bellard
        /* find tb(n) in circular list */
332 d4e8164f bellard
        for(;;) {
333 d4e8164f bellard
            tb1 = *ptb;
334 d4e8164f bellard
            n1 = (long)tb1 & 3;
335 d4e8164f bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
336 d4e8164f bellard
            if (n1 == n && tb1 == tb)
337 d4e8164f bellard
                break;
338 d4e8164f bellard
            if (n1 == 2) {
339 d4e8164f bellard
                ptb = &tb1->jmp_first;
340 d4e8164f bellard
            } else {
341 d4e8164f bellard
                ptb = &tb1->jmp_next[n1];
342 d4e8164f bellard
            }
343 d4e8164f bellard
        }
344 d4e8164f bellard
        /* now we can suppress tb(n) from the list */
345 d4e8164f bellard
        *ptb = tb->jmp_next[n];
346 d4e8164f bellard
347 d4e8164f bellard
        tb->jmp_next[n] = NULL;
348 d4e8164f bellard
    }
349 d4e8164f bellard
}
350 d4e8164f bellard
351 d4e8164f bellard
/* reset the jump entry 'n' of a TB so that it is not chained to
352 d4e8164f bellard
   another TB */
353 d4e8164f bellard
static inline void tb_reset_jump(TranslationBlock *tb, int n)
354 d4e8164f bellard
{
355 d4e8164f bellard
    tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
356 d4e8164f bellard
}
357 d4e8164f bellard
358 fd6ce8f6 bellard
static inline void tb_invalidate(TranslationBlock *tb, int parity)
359 fd6ce8f6 bellard
{
360 fd6ce8f6 bellard
    PageDesc *p;
361 fd6ce8f6 bellard
    unsigned int page_index1, page_index2;
362 d4e8164f bellard
    unsigned int h, n1;
363 d4e8164f bellard
    TranslationBlock *tb1, *tb2;
364 d4e8164f bellard
    
365 fd6ce8f6 bellard
    /* remove the TB from the hash list */
366 fd6ce8f6 bellard
    h = tb_hash_func(tb->pc);
367 fd6ce8f6 bellard
    tb_remove(&tb_hash[h], tb, 
368 fd6ce8f6 bellard
              offsetof(TranslationBlock, hash_next));
369 fd6ce8f6 bellard
    /* remove the TB from the page list */
370 fd6ce8f6 bellard
    page_index1 = tb->pc >> TARGET_PAGE_BITS;
371 fd6ce8f6 bellard
    if ((page_index1 & 1) == parity) {
372 fd6ce8f6 bellard
        p = page_find(page_index1);
373 fd6ce8f6 bellard
        tb_remove(&p->first_tb, tb, 
374 fd6ce8f6 bellard
                  offsetof(TranslationBlock, page_next[page_index1 & 1]));
375 fd6ce8f6 bellard
    }
376 fd6ce8f6 bellard
    page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
377 fd6ce8f6 bellard
    if ((page_index2 & 1) == parity) {
378 fd6ce8f6 bellard
        p = page_find(page_index2);
379 fd6ce8f6 bellard
        tb_remove(&p->first_tb, tb, 
380 fd6ce8f6 bellard
                  offsetof(TranslationBlock, page_next[page_index2 & 1]));
381 fd6ce8f6 bellard
    }
382 d4e8164f bellard
383 d4e8164f bellard
    /* suppress this TB from the two jump lists */
384 d4e8164f bellard
    tb_jmp_remove(tb, 0);
385 d4e8164f bellard
    tb_jmp_remove(tb, 1);
386 d4e8164f bellard
387 d4e8164f bellard
    /* suppress any remaining jumps to this TB */
388 d4e8164f bellard
    tb1 = tb->jmp_first;
389 d4e8164f bellard
    for(;;) {
390 d4e8164f bellard
        n1 = (long)tb1 & 3;
391 d4e8164f bellard
        if (n1 == 2)
392 d4e8164f bellard
            break;
393 d4e8164f bellard
        tb1 = (TranslationBlock *)((long)tb1 & ~3);
394 d4e8164f bellard
        tb2 = tb1->jmp_next[n1];
395 d4e8164f bellard
        tb_reset_jump(tb1, n1);
396 d4e8164f bellard
        tb1->jmp_next[n1] = NULL;
397 d4e8164f bellard
        tb1 = tb2;
398 d4e8164f bellard
    }
399 d4e8164f bellard
    tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
400 fd6ce8f6 bellard
}
401 fd6ce8f6 bellard
402 fd6ce8f6 bellard
/* invalidate all TBs which intersect with the target page starting at addr */
403 fd6ce8f6 bellard
static void tb_invalidate_page(unsigned long address)
404 fd6ce8f6 bellard
{
405 fd6ce8f6 bellard
    TranslationBlock *tb_next, *tb;
406 fd6ce8f6 bellard
    unsigned int page_index;
407 fd6ce8f6 bellard
    int parity1, parity2;
408 fd6ce8f6 bellard
    PageDesc *p;
409 fd6ce8f6 bellard
#ifdef DEBUG_TB_INVALIDATE
410 fd6ce8f6 bellard
    printf("tb_invalidate_page: %lx\n", address);
411 fd6ce8f6 bellard
#endif
412 fd6ce8f6 bellard
413 fd6ce8f6 bellard
    page_index = address >> TARGET_PAGE_BITS;
414 fd6ce8f6 bellard
    p = page_find(page_index);
415 fd6ce8f6 bellard
    if (!p)
416 fd6ce8f6 bellard
        return;
417 fd6ce8f6 bellard
    tb = p->first_tb;
418 fd6ce8f6 bellard
    parity1 = page_index & 1;
419 fd6ce8f6 bellard
    parity2 = parity1 ^ 1;
420 fd6ce8f6 bellard
    while (tb != NULL) {
421 fd6ce8f6 bellard
        tb_next = tb->page_next[parity1];
422 fd6ce8f6 bellard
        tb_invalidate(tb, parity2);
423 fd6ce8f6 bellard
        tb = tb_next;
424 fd6ce8f6 bellard
    }
425 fd6ce8f6 bellard
    p->first_tb = NULL;
426 fd6ce8f6 bellard
}
427 fd6ce8f6 bellard
428 fd6ce8f6 bellard
/* add the tb in the target page and protect it if necessary */
429 fd6ce8f6 bellard
static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
430 fd6ce8f6 bellard
{
431 fd6ce8f6 bellard
    PageDesc *p;
432 fd6ce8f6 bellard
    unsigned long host_start, host_end, addr, page_addr;
433 fd6ce8f6 bellard
    int prot;
434 fd6ce8f6 bellard
435 fd6ce8f6 bellard
    p = page_find_alloc(page_index);
436 fd6ce8f6 bellard
    tb->page_next[page_index & 1] = p->first_tb;
437 fd6ce8f6 bellard
    p->first_tb = tb;
438 fd6ce8f6 bellard
    if (p->flags & PAGE_WRITE) {
439 fd6ce8f6 bellard
        /* force the host page as non writable (writes will have a
440 fd6ce8f6 bellard
           page fault + mprotect overhead) */
441 fd6ce8f6 bellard
        page_addr = (page_index << TARGET_PAGE_BITS);
442 fd6ce8f6 bellard
        host_start = page_addr & host_page_mask;
443 fd6ce8f6 bellard
        host_end = host_start + host_page_size;
444 fd6ce8f6 bellard
        prot = 0;
445 fd6ce8f6 bellard
        for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
446 fd6ce8f6 bellard
            prot |= page_get_flags(addr);
447 61382a50 bellard
#if !defined(CONFIG_SOFTMMU)
448 fd6ce8f6 bellard
        mprotect((void *)host_start, host_page_size, 
449 fd6ce8f6 bellard
                 (prot & PAGE_BITS) & ~PAGE_WRITE);
450 61382a50 bellard
#endif
451 61382a50 bellard
#if !defined(CONFIG_USER_ONLY)
452 61382a50 bellard
        /* suppress soft TLB */
453 61382a50 bellard
        /* XXX: must flush on all processor with same address space */
454 61382a50 bellard
        tlb_flush_page_write(cpu_single_env, host_start);
455 61382a50 bellard
#endif
456 fd6ce8f6 bellard
#ifdef DEBUG_TB_INVALIDATE
457 fd6ce8f6 bellard
        printf("protecting code page: 0x%08lx\n", 
458 fd6ce8f6 bellard
               host_start);
459 fd6ce8f6 bellard
#endif
460 fd6ce8f6 bellard
        p->flags &= ~PAGE_WRITE;
461 fd6ce8f6 bellard
    }
462 fd6ce8f6 bellard
}
463 fd6ce8f6 bellard
464 fd6ce8f6 bellard
/* Allocate a new translation block. Flush the translation buffer if
465 fd6ce8f6 bellard
   too many translation blocks or too much generated code. */
466 d4e8164f bellard
TranslationBlock *tb_alloc(unsigned long pc)
467 fd6ce8f6 bellard
{
468 fd6ce8f6 bellard
    TranslationBlock *tb;
469 fd6ce8f6 bellard
470 fd6ce8f6 bellard
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
471 fd6ce8f6 bellard
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
472 d4e8164f bellard
        return NULL;
473 fd6ce8f6 bellard
    tb = &tbs[nb_tbs++];
474 fd6ce8f6 bellard
    tb->pc = pc;
475 d4e8164f bellard
    return tb;
476 d4e8164f bellard
}
477 d4e8164f bellard
478 d4e8164f bellard
/* link the tb with the other TBs */
479 d4e8164f bellard
void tb_link(TranslationBlock *tb)
480 d4e8164f bellard
{
481 d4e8164f bellard
    unsigned int page_index1, page_index2;
482 fd6ce8f6 bellard
483 fd6ce8f6 bellard
    /* add in the page list */
484 d4e8164f bellard
    page_index1 = tb->pc >> TARGET_PAGE_BITS;
485 fd6ce8f6 bellard
    tb_alloc_page(tb, page_index1);
486 d4e8164f bellard
    page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
487 fd6ce8f6 bellard
    if (page_index2 != page_index1) {
488 fd6ce8f6 bellard
        tb_alloc_page(tb, page_index2);
489 fd6ce8f6 bellard
    }
490 61382a50 bellard
#ifdef DEBUG_TB_CHECK
491 61382a50 bellard
    tb_page_check();
492 61382a50 bellard
#endif
493 d4e8164f bellard
    tb->jmp_first = (TranslationBlock *)((long)tb | 2);
494 d4e8164f bellard
    tb->jmp_next[0] = NULL;
495 d4e8164f bellard
    tb->jmp_next[1] = NULL;
496 d4e8164f bellard
497 d4e8164f bellard
    /* init original jump addresses */
498 d4e8164f bellard
    if (tb->tb_next_offset[0] != 0xffff)
499 d4e8164f bellard
        tb_reset_jump(tb, 0);
500 d4e8164f bellard
    if (tb->tb_next_offset[1] != 0xffff)
501 d4e8164f bellard
        tb_reset_jump(tb, 1);
502 fd6ce8f6 bellard
}
503 fd6ce8f6 bellard
504 fd6ce8f6 bellard
/* called from signal handler: invalidate the code and unprotect the
505 fd6ce8f6 bellard
   page. Return TRUE if the fault was succesfully handled. */
506 fd6ce8f6 bellard
int page_unprotect(unsigned long address)
507 fd6ce8f6 bellard
{
508 1565b7bc bellard
    unsigned int page_index, prot, pindex;
509 1565b7bc bellard
    PageDesc *p, *p1;
510 fd6ce8f6 bellard
    unsigned long host_start, host_end, addr;
511 fd6ce8f6 bellard
512 1565b7bc bellard
    host_start = address & host_page_mask;
513 1565b7bc bellard
    page_index = host_start >> TARGET_PAGE_BITS;
514 1565b7bc bellard
    p1 = page_find(page_index);
515 1565b7bc bellard
    if (!p1)
516 fd6ce8f6 bellard
        return 0;
517 1565b7bc bellard
    host_end = host_start + host_page_size;
518 1565b7bc bellard
    p = p1;
519 1565b7bc bellard
    prot = 0;
520 1565b7bc bellard
    for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
521 1565b7bc bellard
        prot |= p->flags;
522 1565b7bc bellard
        p++;
523 1565b7bc bellard
    }
524 1565b7bc bellard
    /* if the page was really writable, then we change its
525 1565b7bc bellard
       protection back to writable */
526 1565b7bc bellard
    if (prot & PAGE_WRITE_ORG) {
527 1565b7bc bellard
        pindex = (address - host_start) >> TARGET_PAGE_BITS;
528 61382a50 bellard
        if (!(p1[pindex].flags & PAGE_WRITE)) {
529 61382a50 bellard
#if !defined(CONFIG_SOFTMMU)
530 61382a50 bellard
            mprotect((void *)host_start, host_page_size, 
531 61382a50 bellard
                     (prot & PAGE_BITS) | PAGE_WRITE);
532 61382a50 bellard
#endif
533 61382a50 bellard
            p1[pindex].flags |= PAGE_WRITE;
534 61382a50 bellard
            /* and since the content will be modified, we must invalidate
535 61382a50 bellard
               the corresponding translated code. */
536 61382a50 bellard
            tb_invalidate_page(address);
537 fd6ce8f6 bellard
#ifdef DEBUG_TB_CHECK
538 61382a50 bellard
            tb_invalidate_check(address);
539 fd6ce8f6 bellard
#endif
540 61382a50 bellard
            return 1;
541 61382a50 bellard
        }
542 fd6ce8f6 bellard
    }
543 61382a50 bellard
    return 0;
544 fd6ce8f6 bellard
}
545 fd6ce8f6 bellard
546 fd6ce8f6 bellard
/* call this function when system calls directly modify a memory area */
547 fd6ce8f6 bellard
void page_unprotect_range(uint8_t *data, unsigned long data_size)
548 fd6ce8f6 bellard
{
549 fd6ce8f6 bellard
    unsigned long start, end, addr;
550 fd6ce8f6 bellard
551 fd6ce8f6 bellard
    start = (unsigned long)data;
552 fd6ce8f6 bellard
    end = start + data_size;
553 fd6ce8f6 bellard
    start &= TARGET_PAGE_MASK;
554 fd6ce8f6 bellard
    end = TARGET_PAGE_ALIGN(end);
555 fd6ce8f6 bellard
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
556 fd6ce8f6 bellard
        page_unprotect(addr);
557 fd6ce8f6 bellard
    }
558 fd6ce8f6 bellard
}
559 a513fe19 bellard
560 a513fe19 bellard
/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
561 a513fe19 bellard
   tb[1].tc_ptr. Return NULL if not found */
562 a513fe19 bellard
TranslationBlock *tb_find_pc(unsigned long tc_ptr)
563 a513fe19 bellard
{
564 a513fe19 bellard
    int m_min, m_max, m;
565 a513fe19 bellard
    unsigned long v;
566 a513fe19 bellard
    TranslationBlock *tb;
567 a513fe19 bellard
568 a513fe19 bellard
    if (nb_tbs <= 0)
569 a513fe19 bellard
        return NULL;
570 a513fe19 bellard
    if (tc_ptr < (unsigned long)code_gen_buffer ||
571 a513fe19 bellard
        tc_ptr >= (unsigned long)code_gen_ptr)
572 a513fe19 bellard
        return NULL;
573 a513fe19 bellard
    /* binary search (cf Knuth) */
574 a513fe19 bellard
    m_min = 0;
575 a513fe19 bellard
    m_max = nb_tbs - 1;
576 a513fe19 bellard
    while (m_min <= m_max) {
577 a513fe19 bellard
        m = (m_min + m_max) >> 1;
578 a513fe19 bellard
        tb = &tbs[m];
579 a513fe19 bellard
        v = (unsigned long)tb->tc_ptr;
580 a513fe19 bellard
        if (v == tc_ptr)
581 a513fe19 bellard
            return tb;
582 a513fe19 bellard
        else if (tc_ptr < v) {
583 a513fe19 bellard
            m_max = m - 1;
584 a513fe19 bellard
        } else {
585 a513fe19 bellard
            m_min = m + 1;
586 a513fe19 bellard
        }
587 a513fe19 bellard
    } 
588 a513fe19 bellard
    return &tbs[m_max];
589 a513fe19 bellard
}
590 7501267e bellard
591 ea041c0e bellard
static void tb_reset_jump_recursive(TranslationBlock *tb);
592 ea041c0e bellard
593 ea041c0e bellard
static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
594 ea041c0e bellard
{
595 ea041c0e bellard
    TranslationBlock *tb1, *tb_next, **ptb;
596 ea041c0e bellard
    unsigned int n1;
597 ea041c0e bellard
598 ea041c0e bellard
    tb1 = tb->jmp_next[n];
599 ea041c0e bellard
    if (tb1 != NULL) {
600 ea041c0e bellard
        /* find head of list */
601 ea041c0e bellard
        for(;;) {
602 ea041c0e bellard
            n1 = (long)tb1 & 3;
603 ea041c0e bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
604 ea041c0e bellard
            if (n1 == 2)
605 ea041c0e bellard
                break;
606 ea041c0e bellard
            tb1 = tb1->jmp_next[n1];
607 ea041c0e bellard
        }
608 ea041c0e bellard
        /* we are now sure now that tb jumps to tb1 */
609 ea041c0e bellard
        tb_next = tb1;
610 ea041c0e bellard
611 ea041c0e bellard
        /* remove tb from the jmp_first list */
612 ea041c0e bellard
        ptb = &tb_next->jmp_first;
613 ea041c0e bellard
        for(;;) {
614 ea041c0e bellard
            tb1 = *ptb;
615 ea041c0e bellard
            n1 = (long)tb1 & 3;
616 ea041c0e bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
617 ea041c0e bellard
            if (n1 == n && tb1 == tb)
618 ea041c0e bellard
                break;
619 ea041c0e bellard
            ptb = &tb1->jmp_next[n1];
620 ea041c0e bellard
        }
621 ea041c0e bellard
        *ptb = tb->jmp_next[n];
622 ea041c0e bellard
        tb->jmp_next[n] = NULL;
623 ea041c0e bellard
        
624 ea041c0e bellard
        /* suppress the jump to next tb in generated code */
625 ea041c0e bellard
        tb_reset_jump(tb, n);
626 ea041c0e bellard
627 ea041c0e bellard
        /* suppress jumps in the tb on which we could have jump */
628 ea041c0e bellard
        tb_reset_jump_recursive(tb_next);
629 ea041c0e bellard
    }
630 ea041c0e bellard
}
631 ea041c0e bellard
632 ea041c0e bellard
static void tb_reset_jump_recursive(TranslationBlock *tb)
633 ea041c0e bellard
{
634 ea041c0e bellard
    tb_reset_jump_recursive2(tb, 0);
635 ea041c0e bellard
    tb_reset_jump_recursive2(tb, 1);
636 ea041c0e bellard
}
637 ea041c0e bellard
638 c33a346e bellard
/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
639 c33a346e bellard
   breakpoint is reached */
640 4c3a88a2 bellard
int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
641 4c3a88a2 bellard
{
642 4c3a88a2 bellard
#if defined(TARGET_I386)
643 4c3a88a2 bellard
    int i;
644 4c3a88a2 bellard
645 4c3a88a2 bellard
    for(i = 0; i < env->nb_breakpoints; i++) {
646 4c3a88a2 bellard
        if (env->breakpoints[i] == pc)
647 4c3a88a2 bellard
            return 0;
648 4c3a88a2 bellard
    }
649 4c3a88a2 bellard
650 4c3a88a2 bellard
    if (env->nb_breakpoints >= MAX_BREAKPOINTS)
651 4c3a88a2 bellard
        return -1;
652 4c3a88a2 bellard
    env->breakpoints[env->nb_breakpoints++] = pc;
653 4c3a88a2 bellard
    tb_invalidate_page(pc);
654 4c3a88a2 bellard
    return 0;
655 4c3a88a2 bellard
#else
656 4c3a88a2 bellard
    return -1;
657 4c3a88a2 bellard
#endif
658 4c3a88a2 bellard
}
659 4c3a88a2 bellard
660 4c3a88a2 bellard
/* remove a breakpoint */
661 4c3a88a2 bellard
int cpu_breakpoint_remove(CPUState *env, uint32_t pc)
662 4c3a88a2 bellard
{
663 4c3a88a2 bellard
#if defined(TARGET_I386)
664 4c3a88a2 bellard
    int i;
665 4c3a88a2 bellard
    for(i = 0; i < env->nb_breakpoints; i++) {
666 4c3a88a2 bellard
        if (env->breakpoints[i] == pc)
667 4c3a88a2 bellard
            goto found;
668 4c3a88a2 bellard
    }
669 4c3a88a2 bellard
    return -1;
670 4c3a88a2 bellard
 found:
671 4c3a88a2 bellard
    memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
672 4c3a88a2 bellard
            (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
673 4c3a88a2 bellard
    env->nb_breakpoints--;
674 4c3a88a2 bellard
    tb_invalidate_page(pc);
675 4c3a88a2 bellard
    return 0;
676 4c3a88a2 bellard
#else
677 4c3a88a2 bellard
    return -1;
678 4c3a88a2 bellard
#endif
679 4c3a88a2 bellard
}
680 4c3a88a2 bellard
681 c33a346e bellard
/* enable or disable single step mode. EXCP_DEBUG is returned by the
682 c33a346e bellard
   CPU loop after each instruction */
683 c33a346e bellard
void cpu_single_step(CPUState *env, int enabled)
684 c33a346e bellard
{
685 c33a346e bellard
#if defined(TARGET_I386)
686 c33a346e bellard
    if (env->singlestep_enabled != enabled) {
687 c33a346e bellard
        env->singlestep_enabled = enabled;
688 c33a346e bellard
        /* must flush all the translated code to avoid inconsistancies */
689 c33a346e bellard
        tb_flush();
690 c33a346e bellard
    }
691 c33a346e bellard
#endif
692 c33a346e bellard
}
693 c33a346e bellard
694 34865134 bellard
/* enable or disable low levels log */
695 34865134 bellard
void cpu_set_log(int log_flags)
696 34865134 bellard
{
697 34865134 bellard
    loglevel = log_flags;
698 34865134 bellard
    if (loglevel && !logfile) {
699 34865134 bellard
        logfile = fopen(logfilename, "w");
700 34865134 bellard
        if (!logfile) {
701 34865134 bellard
            perror(logfilename);
702 34865134 bellard
            _exit(1);
703 34865134 bellard
        }
704 34865134 bellard
        setvbuf(logfile, NULL, _IOLBF, 0);
705 34865134 bellard
    }
706 34865134 bellard
}
707 34865134 bellard
708 34865134 bellard
void cpu_set_log_filename(const char *filename)
709 34865134 bellard
{
710 34865134 bellard
    logfilename = strdup(filename);
711 34865134 bellard
}
712 c33a346e bellard
713 68a79315 bellard
/* mask must never be zero */
714 68a79315 bellard
void cpu_interrupt(CPUState *env, int mask)
715 ea041c0e bellard
{
716 ea041c0e bellard
    TranslationBlock *tb;
717 68a79315 bellard
    
718 68a79315 bellard
    env->interrupt_request |= mask;
719 ea041c0e bellard
    /* if the cpu is currently executing code, we must unlink it and
720 ea041c0e bellard
       all the potentially executing TB */
721 ea041c0e bellard
    tb = env->current_tb;
722 ea041c0e bellard
    if (tb) {
723 ea041c0e bellard
        tb_reset_jump_recursive(tb);
724 ea041c0e bellard
    }
725 ea041c0e bellard
}
726 ea041c0e bellard
727 ea041c0e bellard
728 7501267e bellard
void cpu_abort(CPUState *env, const char *fmt, ...)
729 7501267e bellard
{
730 7501267e bellard
    va_list ap;
731 7501267e bellard
732 7501267e bellard
    va_start(ap, fmt);
733 7501267e bellard
    fprintf(stderr, "qemu: fatal: ");
734 7501267e bellard
    vfprintf(stderr, fmt, ap);
735 7501267e bellard
    fprintf(stderr, "\n");
736 7501267e bellard
#ifdef TARGET_I386
737 7501267e bellard
    cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
738 7501267e bellard
#endif
739 7501267e bellard
    va_end(ap);
740 7501267e bellard
    abort();
741 7501267e bellard
}
742 7501267e bellard
743 66e85a21 bellard
#ifdef TARGET_I386
744 66e85a21 bellard
/* unmap all maped pages and flush all associated code */
745 66e85a21 bellard
void page_unmap(void)
746 66e85a21 bellard
{
747 61382a50 bellard
    PageDesc *pmap;
748 61382a50 bellard
    int i;
749 66e85a21 bellard
750 66e85a21 bellard
    for(i = 0; i < L1_SIZE; i++) {
751 66e85a21 bellard
        pmap = l1_map[i];
752 66e85a21 bellard
        if (pmap) {
753 61382a50 bellard
#if !defined(CONFIG_SOFTMMU)
754 61382a50 bellard
            PageDesc *p;
755 61382a50 bellard
            unsigned long addr;
756 61382a50 bellard
            int j, ret, j1;
757 61382a50 bellard
            
758 66e85a21 bellard
            p = pmap;
759 7c2d6a78 bellard
            for(j = 0;j < L2_SIZE;) {
760 66e85a21 bellard
                if (p->flags & PAGE_VALID) {
761 66e85a21 bellard
                    addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
762 7c2d6a78 bellard
                    /* we try to find a range to make less syscalls */
763 7c2d6a78 bellard
                    j1 = j;
764 7c2d6a78 bellard
                    p++;
765 7c2d6a78 bellard
                    j++;
766 7c2d6a78 bellard
                    while (j < L2_SIZE && (p->flags & PAGE_VALID)) {
767 7c2d6a78 bellard
                        p++;
768 7c2d6a78 bellard
                        j++;
769 7c2d6a78 bellard
                    }
770 7c2d6a78 bellard
                    ret = munmap((void *)addr, (j - j1) << TARGET_PAGE_BITS);
771 66e85a21 bellard
                    if (ret != 0) {
772 66e85a21 bellard
                        fprintf(stderr, "Could not unmap page 0x%08lx\n", addr);
773 66e85a21 bellard
                        exit(1);
774 66e85a21 bellard
                    }
775 7c2d6a78 bellard
                } else {
776 7c2d6a78 bellard
                    p++;
777 7c2d6a78 bellard
                    j++;
778 66e85a21 bellard
                }
779 66e85a21 bellard
            }
780 61382a50 bellard
#endif
781 66e85a21 bellard
            free(pmap);
782 66e85a21 bellard
            l1_map[i] = NULL;
783 66e85a21 bellard
        }
784 66e85a21 bellard
    }
785 66e85a21 bellard
    tb_flush();
786 66e85a21 bellard
}
787 66e85a21 bellard
#endif
788 33417e70 bellard
789 33417e70 bellard
void tlb_flush(CPUState *env)
790 33417e70 bellard
{
791 61382a50 bellard
#if !defined(CONFIG_USER_ONLY)
792 33417e70 bellard
    int i;
793 33417e70 bellard
    for(i = 0; i < CPU_TLB_SIZE; i++) {
794 33417e70 bellard
        env->tlb_read[0][i].address = -1;
795 33417e70 bellard
        env->tlb_write[0][i].address = -1;
796 33417e70 bellard
        env->tlb_read[1][i].address = -1;
797 33417e70 bellard
        env->tlb_write[1][i].address = -1;
798 33417e70 bellard
    }
799 33417e70 bellard
#endif
800 33417e70 bellard
}
801 33417e70 bellard
802 61382a50 bellard
static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr)
803 61382a50 bellard
{
804 61382a50 bellard
    if (addr == (tlb_entry->address & 
805 61382a50 bellard
                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
806 61382a50 bellard
        tlb_entry->address = -1;
807 61382a50 bellard
}
808 61382a50 bellard
809 33417e70 bellard
void tlb_flush_page(CPUState *env, uint32_t addr)
810 33417e70 bellard
{
811 61382a50 bellard
#if !defined(CONFIG_USER_ONLY)
812 61382a50 bellard
    int i;
813 61382a50 bellard
814 61382a50 bellard
    addr &= TARGET_PAGE_MASK;
815 61382a50 bellard
    i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
816 61382a50 bellard
    tlb_flush_entry(&env->tlb_read[0][i], addr);
817 61382a50 bellard
    tlb_flush_entry(&env->tlb_write[0][i], addr);
818 61382a50 bellard
    tlb_flush_entry(&env->tlb_read[1][i], addr);
819 61382a50 bellard
    tlb_flush_entry(&env->tlb_write[1][i], addr);
820 61382a50 bellard
#endif
821 61382a50 bellard
}
822 61382a50 bellard
823 61382a50 bellard
/* make all write to page 'addr' trigger a TLB exception to detect
824 61382a50 bellard
   self modifying code */
825 61382a50 bellard
void tlb_flush_page_write(CPUState *env, uint32_t addr)
826 61382a50 bellard
{
827 61382a50 bellard
#if !defined(CONFIG_USER_ONLY)
828 33417e70 bellard
    int i;
829 33417e70 bellard
830 61382a50 bellard
    addr &= TARGET_PAGE_MASK;
831 33417e70 bellard
    i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
832 61382a50 bellard
    tlb_flush_entry(&env->tlb_write[0][i], addr);
833 61382a50 bellard
    tlb_flush_entry(&env->tlb_write[1][i], addr);
834 33417e70 bellard
#endif
835 33417e70 bellard
}
836 33417e70 bellard
837 33417e70 bellard
static inline unsigned long *physpage_find_alloc(unsigned int page)
838 33417e70 bellard
{
839 33417e70 bellard
    unsigned long **lp, *p;
840 33417e70 bellard
    unsigned int index, i;
841 33417e70 bellard
842 33417e70 bellard
    index = page >> TARGET_PAGE_BITS;
843 33417e70 bellard
    lp = &l1_physmap[index >> L2_BITS];
844 33417e70 bellard
    p = *lp;
845 33417e70 bellard
    if (!p) {
846 33417e70 bellard
        /* allocate if not found */
847 33417e70 bellard
        p = malloc(sizeof(unsigned long) * L2_SIZE);
848 33417e70 bellard
        for(i = 0; i < L2_SIZE; i++)
849 33417e70 bellard
            p[i] = IO_MEM_UNASSIGNED;
850 33417e70 bellard
        *lp = p;
851 33417e70 bellard
    }
852 33417e70 bellard
    return p + (index & (L2_SIZE - 1));
853 33417e70 bellard
}
854 33417e70 bellard
855 33417e70 bellard
/* return NULL if no page defined (unused memory) */
856 33417e70 bellard
unsigned long physpage_find(unsigned long page)
857 33417e70 bellard
{
858 33417e70 bellard
    unsigned long *p;
859 33417e70 bellard
    unsigned int index;
860 33417e70 bellard
    index = page >> TARGET_PAGE_BITS;
861 33417e70 bellard
    p = l1_physmap[index >> L2_BITS];
862 33417e70 bellard
    if (!p)
863 33417e70 bellard
        return IO_MEM_UNASSIGNED;
864 33417e70 bellard
    return p[index & (L2_SIZE - 1)];
865 33417e70 bellard
}
866 33417e70 bellard
867 33417e70 bellard
/* register physical memory. 'size' must be a multiple of the target
868 33417e70 bellard
   page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
869 33417e70 bellard
   io memory page */
870 33417e70 bellard
void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
871 33417e70 bellard
                                  long phys_offset)
872 33417e70 bellard
{
873 33417e70 bellard
    unsigned long addr, end_addr;
874 33417e70 bellard
    unsigned long *p;
875 33417e70 bellard
876 33417e70 bellard
    end_addr = start_addr + size;
877 33417e70 bellard
    for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) {
878 33417e70 bellard
        p = physpage_find_alloc(addr);
879 33417e70 bellard
        *p = phys_offset;
880 33417e70 bellard
        if ((phys_offset & ~TARGET_PAGE_MASK) == 0)
881 33417e70 bellard
            phys_offset += TARGET_PAGE_SIZE;
882 33417e70 bellard
    }
883 33417e70 bellard
}
884 33417e70 bellard
885 33417e70 bellard
static uint32_t unassigned_mem_readb(uint32_t addr)
886 33417e70 bellard
{
887 33417e70 bellard
    return 0;
888 33417e70 bellard
}
889 33417e70 bellard
890 33417e70 bellard
static void unassigned_mem_writeb(uint32_t addr, uint32_t val)
891 33417e70 bellard
{
892 33417e70 bellard
}
893 33417e70 bellard
894 33417e70 bellard
static CPUReadMemoryFunc *unassigned_mem_read[3] = {
895 33417e70 bellard
    unassigned_mem_readb,
896 33417e70 bellard
    unassigned_mem_readb,
897 33417e70 bellard
    unassigned_mem_readb,
898 33417e70 bellard
};
899 33417e70 bellard
900 33417e70 bellard
static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
901 33417e70 bellard
    unassigned_mem_writeb,
902 33417e70 bellard
    unassigned_mem_writeb,
903 33417e70 bellard
    unassigned_mem_writeb,
904 33417e70 bellard
};
905 33417e70 bellard
906 33417e70 bellard
907 33417e70 bellard
static void io_mem_init(void)
908 33417e70 bellard
{
909 33417e70 bellard
    io_mem_nb = 1;
910 33417e70 bellard
    cpu_register_io_memory(0, unassigned_mem_read, unassigned_mem_write);
911 33417e70 bellard
}
912 33417e70 bellard
913 33417e70 bellard
/* mem_read and mem_write are arrays of functions containing the
914 33417e70 bellard
   function to access byte (index 0), word (index 1) and dword (index
915 33417e70 bellard
   2). All functions must be supplied. If io_index is non zero, the
916 33417e70 bellard
   corresponding io zone is modified. If it is zero, a new io zone is
917 33417e70 bellard
   allocated. The return value can be used with
918 33417e70 bellard
   cpu_register_physical_memory(). (-1) is returned if error. */
919 33417e70 bellard
int cpu_register_io_memory(int io_index,
920 33417e70 bellard
                           CPUReadMemoryFunc **mem_read,
921 33417e70 bellard
                           CPUWriteMemoryFunc **mem_write)
922 33417e70 bellard
{
923 33417e70 bellard
    int i;
924 33417e70 bellard
925 33417e70 bellard
    if (io_index <= 0) {
926 33417e70 bellard
        if (io_index >= IO_MEM_NB_ENTRIES)
927 33417e70 bellard
            return -1;
928 33417e70 bellard
        io_index = io_mem_nb++;
929 33417e70 bellard
    } else {
930 33417e70 bellard
        if (io_index >= IO_MEM_NB_ENTRIES)
931 33417e70 bellard
            return -1;
932 33417e70 bellard
    }
933 33417e70 bellard
    
934 33417e70 bellard
    for(i = 0;i < 3; i++) {
935 33417e70 bellard
        io_mem_read[io_index][i] = mem_read[i];
936 33417e70 bellard
        io_mem_write[io_index][i] = mem_write[i];
937 33417e70 bellard
    }
938 33417e70 bellard
    return io_index << IO_MEM_SHIFT;
939 33417e70 bellard
}
940 61382a50 bellard
941 61382a50 bellard
#if !defined(CONFIG_USER_ONLY) 
942 61382a50 bellard
943 61382a50 bellard
#define MMUSUFFIX _cmmu
944 61382a50 bellard
#define GETPC() NULL
945 61382a50 bellard
#define env cpu_single_env
946 61382a50 bellard
947 61382a50 bellard
#define SHIFT 0
948 61382a50 bellard
#include "softmmu_template.h"
949 61382a50 bellard
950 61382a50 bellard
#define SHIFT 1
951 61382a50 bellard
#include "softmmu_template.h"
952 61382a50 bellard
953 61382a50 bellard
#define SHIFT 2
954 61382a50 bellard
#include "softmmu_template.h"
955 61382a50 bellard
956 61382a50 bellard
#define SHIFT 3
957 61382a50 bellard
#include "softmmu_template.h"
958 61382a50 bellard
959 61382a50 bellard
#undef env
960 61382a50 bellard
961 61382a50 bellard
#endif