Statistics
| Branch: | Revision:

root / exec.c @ facc68be

History | View | Annotate | Download (23.7 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 ea041c0e bellard
#ifdef TARGET_I386
31 54936004 bellard
#include "cpu-i386.h"
32 ea041c0e bellard
#endif
33 ea041c0e bellard
#ifdef TARGET_ARM
34 ea041c0e bellard
#include "cpu-arm.h"
35 ea041c0e bellard
#endif
36 d4e8164f bellard
#include "exec.h"
37 54936004 bellard
38 fd6ce8f6 bellard
//#define DEBUG_TB_INVALIDATE
39 66e85a21 bellard
//#define DEBUG_FLUSH
40 fd6ce8f6 bellard
41 fd6ce8f6 bellard
/* make various TB consistency checks */
42 fd6ce8f6 bellard
//#define DEBUG_TB_CHECK 
43 fd6ce8f6 bellard
44 fd6ce8f6 bellard
/* threshold to flush the translated code buffer */
45 fd6ce8f6 bellard
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
46 fd6ce8f6 bellard
47 fd6ce8f6 bellard
#define CODE_GEN_MAX_BLOCKS    (CODE_GEN_BUFFER_SIZE / 64)
48 fd6ce8f6 bellard
49 fd6ce8f6 bellard
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
50 fd6ce8f6 bellard
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
51 fd6ce8f6 bellard
int nb_tbs;
52 eb51d102 bellard
/* any access to the tbs or the page table must use this lock */
53 eb51d102 bellard
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
54 fd6ce8f6 bellard
55 fd6ce8f6 bellard
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
56 fd6ce8f6 bellard
uint8_t *code_gen_ptr;
57 fd6ce8f6 bellard
58 54936004 bellard
/* XXX: pack the flags in the low bits of the pointer ? */
59 54936004 bellard
typedef struct PageDesc {
60 54936004 bellard
    unsigned long flags;
61 fd6ce8f6 bellard
    TranslationBlock *first_tb;
62 54936004 bellard
} PageDesc;
63 54936004 bellard
64 54936004 bellard
#define L2_BITS 10
65 54936004 bellard
#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
66 54936004 bellard
67 54936004 bellard
#define L1_SIZE (1 << L1_BITS)
68 54936004 bellard
#define L2_SIZE (1 << L2_BITS)
69 54936004 bellard
70 fd6ce8f6 bellard
static void tb_invalidate_page(unsigned long address);
71 33417e70 bellard
static void io_mem_init(void);
72 fd6ce8f6 bellard
73 54936004 bellard
unsigned long real_host_page_size;
74 54936004 bellard
unsigned long host_page_bits;
75 54936004 bellard
unsigned long host_page_size;
76 54936004 bellard
unsigned long host_page_mask;
77 54936004 bellard
78 54936004 bellard
static PageDesc *l1_map[L1_SIZE];
79 54936004 bellard
80 33417e70 bellard
/* io memory support */
81 33417e70 bellard
static unsigned long *l1_physmap[L1_SIZE];
82 33417e70 bellard
CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
83 33417e70 bellard
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
84 33417e70 bellard
static int io_mem_nb;
85 33417e70 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 fd6ce8f6 bellard
        mprotect((void *)host_start, host_page_size, 
448 fd6ce8f6 bellard
                 (prot & PAGE_BITS) & ~PAGE_WRITE);
449 fd6ce8f6 bellard
#ifdef DEBUG_TB_INVALIDATE
450 fd6ce8f6 bellard
        printf("protecting code page: 0x%08lx\n", 
451 fd6ce8f6 bellard
               host_start);
452 fd6ce8f6 bellard
#endif
453 fd6ce8f6 bellard
        p->flags &= ~PAGE_WRITE;
454 fd6ce8f6 bellard
#ifdef DEBUG_TB_CHECK
455 fd6ce8f6 bellard
        tb_page_check();
456 fd6ce8f6 bellard
#endif
457 fd6ce8f6 bellard
    }
458 fd6ce8f6 bellard
}
459 fd6ce8f6 bellard
460 fd6ce8f6 bellard
/* Allocate a new translation block. Flush the translation buffer if
461 fd6ce8f6 bellard
   too many translation blocks or too much generated code. */
462 d4e8164f bellard
TranslationBlock *tb_alloc(unsigned long pc)
463 fd6ce8f6 bellard
{
464 fd6ce8f6 bellard
    TranslationBlock *tb;
465 fd6ce8f6 bellard
466 fd6ce8f6 bellard
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
467 fd6ce8f6 bellard
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
468 d4e8164f bellard
        return NULL;
469 fd6ce8f6 bellard
    tb = &tbs[nb_tbs++];
470 fd6ce8f6 bellard
    tb->pc = pc;
471 d4e8164f bellard
    return tb;
472 d4e8164f bellard
}
473 d4e8164f bellard
474 d4e8164f bellard
/* link the tb with the other TBs */
475 d4e8164f bellard
void tb_link(TranslationBlock *tb)
476 d4e8164f bellard
{
477 d4e8164f bellard
    unsigned int page_index1, page_index2;
478 fd6ce8f6 bellard
479 fd6ce8f6 bellard
    /* add in the page list */
480 d4e8164f bellard
    page_index1 = tb->pc >> TARGET_PAGE_BITS;
481 fd6ce8f6 bellard
    tb_alloc_page(tb, page_index1);
482 d4e8164f bellard
    page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
483 fd6ce8f6 bellard
    if (page_index2 != page_index1) {
484 fd6ce8f6 bellard
        tb_alloc_page(tb, page_index2);
485 fd6ce8f6 bellard
    }
486 d4e8164f bellard
    tb->jmp_first = (TranslationBlock *)((long)tb | 2);
487 d4e8164f bellard
    tb->jmp_next[0] = NULL;
488 d4e8164f bellard
    tb->jmp_next[1] = NULL;
489 d4e8164f bellard
490 d4e8164f bellard
    /* init original jump addresses */
491 d4e8164f bellard
    if (tb->tb_next_offset[0] != 0xffff)
492 d4e8164f bellard
        tb_reset_jump(tb, 0);
493 d4e8164f bellard
    if (tb->tb_next_offset[1] != 0xffff)
494 d4e8164f bellard
        tb_reset_jump(tb, 1);
495 fd6ce8f6 bellard
}
496 fd6ce8f6 bellard
497 fd6ce8f6 bellard
/* called from signal handler: invalidate the code and unprotect the
498 fd6ce8f6 bellard
   page. Return TRUE if the fault was succesfully handled. */
499 fd6ce8f6 bellard
int page_unprotect(unsigned long address)
500 fd6ce8f6 bellard
{
501 1565b7bc bellard
    unsigned int page_index, prot, pindex;
502 1565b7bc bellard
    PageDesc *p, *p1;
503 fd6ce8f6 bellard
    unsigned long host_start, host_end, addr;
504 fd6ce8f6 bellard
505 1565b7bc bellard
    host_start = address & host_page_mask;
506 1565b7bc bellard
    page_index = host_start >> TARGET_PAGE_BITS;
507 1565b7bc bellard
    p1 = page_find(page_index);
508 1565b7bc bellard
    if (!p1)
509 fd6ce8f6 bellard
        return 0;
510 1565b7bc bellard
    host_end = host_start + host_page_size;
511 1565b7bc bellard
    p = p1;
512 1565b7bc bellard
    prot = 0;
513 1565b7bc bellard
    for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
514 1565b7bc bellard
        prot |= p->flags;
515 1565b7bc bellard
        p++;
516 1565b7bc bellard
    }
517 1565b7bc bellard
    /* if the page was really writable, then we change its
518 1565b7bc bellard
       protection back to writable */
519 1565b7bc bellard
    if (prot & PAGE_WRITE_ORG) {
520 fd6ce8f6 bellard
        mprotect((void *)host_start, host_page_size, 
521 fd6ce8f6 bellard
                 (prot & PAGE_BITS) | PAGE_WRITE);
522 1565b7bc bellard
        pindex = (address - host_start) >> TARGET_PAGE_BITS;
523 1565b7bc bellard
        p1[pindex].flags |= PAGE_WRITE;
524 fd6ce8f6 bellard
        /* and since the content will be modified, we must invalidate
525 fd6ce8f6 bellard
           the corresponding translated code. */
526 fd6ce8f6 bellard
        tb_invalidate_page(address);
527 fd6ce8f6 bellard
#ifdef DEBUG_TB_CHECK
528 fd6ce8f6 bellard
        tb_invalidate_check(address);
529 fd6ce8f6 bellard
#endif
530 fd6ce8f6 bellard
        return 1;
531 fd6ce8f6 bellard
    } else {
532 fd6ce8f6 bellard
        return 0;
533 fd6ce8f6 bellard
    }
534 fd6ce8f6 bellard
}
535 fd6ce8f6 bellard
536 fd6ce8f6 bellard
/* call this function when system calls directly modify a memory area */
537 fd6ce8f6 bellard
void page_unprotect_range(uint8_t *data, unsigned long data_size)
538 fd6ce8f6 bellard
{
539 fd6ce8f6 bellard
    unsigned long start, end, addr;
540 fd6ce8f6 bellard
541 fd6ce8f6 bellard
    start = (unsigned long)data;
542 fd6ce8f6 bellard
    end = start + data_size;
543 fd6ce8f6 bellard
    start &= TARGET_PAGE_MASK;
544 fd6ce8f6 bellard
    end = TARGET_PAGE_ALIGN(end);
545 fd6ce8f6 bellard
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
546 fd6ce8f6 bellard
        page_unprotect(addr);
547 fd6ce8f6 bellard
    }
548 fd6ce8f6 bellard
}
549 a513fe19 bellard
550 a513fe19 bellard
/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
551 a513fe19 bellard
   tb[1].tc_ptr. Return NULL if not found */
552 a513fe19 bellard
TranslationBlock *tb_find_pc(unsigned long tc_ptr)
553 a513fe19 bellard
{
554 a513fe19 bellard
    int m_min, m_max, m;
555 a513fe19 bellard
    unsigned long v;
556 a513fe19 bellard
    TranslationBlock *tb;
557 a513fe19 bellard
558 a513fe19 bellard
    if (nb_tbs <= 0)
559 a513fe19 bellard
        return NULL;
560 a513fe19 bellard
    if (tc_ptr < (unsigned long)code_gen_buffer ||
561 a513fe19 bellard
        tc_ptr >= (unsigned long)code_gen_ptr)
562 a513fe19 bellard
        return NULL;
563 a513fe19 bellard
    /* binary search (cf Knuth) */
564 a513fe19 bellard
    m_min = 0;
565 a513fe19 bellard
    m_max = nb_tbs - 1;
566 a513fe19 bellard
    while (m_min <= m_max) {
567 a513fe19 bellard
        m = (m_min + m_max) >> 1;
568 a513fe19 bellard
        tb = &tbs[m];
569 a513fe19 bellard
        v = (unsigned long)tb->tc_ptr;
570 a513fe19 bellard
        if (v == tc_ptr)
571 a513fe19 bellard
            return tb;
572 a513fe19 bellard
        else if (tc_ptr < v) {
573 a513fe19 bellard
            m_max = m - 1;
574 a513fe19 bellard
        } else {
575 a513fe19 bellard
            m_min = m + 1;
576 a513fe19 bellard
        }
577 a513fe19 bellard
    } 
578 a513fe19 bellard
    return &tbs[m_max];
579 a513fe19 bellard
}
580 7501267e bellard
581 ea041c0e bellard
static void tb_reset_jump_recursive(TranslationBlock *tb);
582 ea041c0e bellard
583 ea041c0e bellard
static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
584 ea041c0e bellard
{
585 ea041c0e bellard
    TranslationBlock *tb1, *tb_next, **ptb;
586 ea041c0e bellard
    unsigned int n1;
587 ea041c0e bellard
588 ea041c0e bellard
    tb1 = tb->jmp_next[n];
589 ea041c0e bellard
    if (tb1 != NULL) {
590 ea041c0e bellard
        /* find head of list */
591 ea041c0e bellard
        for(;;) {
592 ea041c0e bellard
            n1 = (long)tb1 & 3;
593 ea041c0e bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
594 ea041c0e bellard
            if (n1 == 2)
595 ea041c0e bellard
                break;
596 ea041c0e bellard
            tb1 = tb1->jmp_next[n1];
597 ea041c0e bellard
        }
598 ea041c0e bellard
        /* we are now sure now that tb jumps to tb1 */
599 ea041c0e bellard
        tb_next = tb1;
600 ea041c0e bellard
601 ea041c0e bellard
        /* remove tb from the jmp_first list */
602 ea041c0e bellard
        ptb = &tb_next->jmp_first;
603 ea041c0e bellard
        for(;;) {
604 ea041c0e bellard
            tb1 = *ptb;
605 ea041c0e bellard
            n1 = (long)tb1 & 3;
606 ea041c0e bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
607 ea041c0e bellard
            if (n1 == n && tb1 == tb)
608 ea041c0e bellard
                break;
609 ea041c0e bellard
            ptb = &tb1->jmp_next[n1];
610 ea041c0e bellard
        }
611 ea041c0e bellard
        *ptb = tb->jmp_next[n];
612 ea041c0e bellard
        tb->jmp_next[n] = NULL;
613 ea041c0e bellard
        
614 ea041c0e bellard
        /* suppress the jump to next tb in generated code */
615 ea041c0e bellard
        tb_reset_jump(tb, n);
616 ea041c0e bellard
617 ea041c0e bellard
        /* suppress jumps in the tb on which we could have jump */
618 ea041c0e bellard
        tb_reset_jump_recursive(tb_next);
619 ea041c0e bellard
    }
620 ea041c0e bellard
}
621 ea041c0e bellard
622 ea041c0e bellard
static void tb_reset_jump_recursive(TranslationBlock *tb)
623 ea041c0e bellard
{
624 ea041c0e bellard
    tb_reset_jump_recursive2(tb, 0);
625 ea041c0e bellard
    tb_reset_jump_recursive2(tb, 1);
626 ea041c0e bellard
}
627 ea041c0e bellard
628 c33a346e bellard
/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
629 c33a346e bellard
   breakpoint is reached */
630 4c3a88a2 bellard
int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
631 4c3a88a2 bellard
{
632 4c3a88a2 bellard
#if defined(TARGET_I386)
633 4c3a88a2 bellard
    int i;
634 4c3a88a2 bellard
635 4c3a88a2 bellard
    for(i = 0; i < env->nb_breakpoints; i++) {
636 4c3a88a2 bellard
        if (env->breakpoints[i] == pc)
637 4c3a88a2 bellard
            return 0;
638 4c3a88a2 bellard
    }
639 4c3a88a2 bellard
640 4c3a88a2 bellard
    if (env->nb_breakpoints >= MAX_BREAKPOINTS)
641 4c3a88a2 bellard
        return -1;
642 4c3a88a2 bellard
    env->breakpoints[env->nb_breakpoints++] = pc;
643 4c3a88a2 bellard
    tb_invalidate_page(pc);
644 4c3a88a2 bellard
    return 0;
645 4c3a88a2 bellard
#else
646 4c3a88a2 bellard
    return -1;
647 4c3a88a2 bellard
#endif
648 4c3a88a2 bellard
}
649 4c3a88a2 bellard
650 4c3a88a2 bellard
/* remove a breakpoint */
651 4c3a88a2 bellard
int cpu_breakpoint_remove(CPUState *env, uint32_t pc)
652 4c3a88a2 bellard
{
653 4c3a88a2 bellard
#if defined(TARGET_I386)
654 4c3a88a2 bellard
    int i;
655 4c3a88a2 bellard
    for(i = 0; i < env->nb_breakpoints; i++) {
656 4c3a88a2 bellard
        if (env->breakpoints[i] == pc)
657 4c3a88a2 bellard
            goto found;
658 4c3a88a2 bellard
    }
659 4c3a88a2 bellard
    return -1;
660 4c3a88a2 bellard
 found:
661 4c3a88a2 bellard
    memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
662 4c3a88a2 bellard
            (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
663 4c3a88a2 bellard
    env->nb_breakpoints--;
664 4c3a88a2 bellard
    tb_invalidate_page(pc);
665 4c3a88a2 bellard
    return 0;
666 4c3a88a2 bellard
#else
667 4c3a88a2 bellard
    return -1;
668 4c3a88a2 bellard
#endif
669 4c3a88a2 bellard
}
670 4c3a88a2 bellard
671 c33a346e bellard
/* enable or disable single step mode. EXCP_DEBUG is returned by the
672 c33a346e bellard
   CPU loop after each instruction */
673 c33a346e bellard
void cpu_single_step(CPUState *env, int enabled)
674 c33a346e bellard
{
675 c33a346e bellard
#if defined(TARGET_I386)
676 c33a346e bellard
    if (env->singlestep_enabled != enabled) {
677 c33a346e bellard
        env->singlestep_enabled = enabled;
678 c33a346e bellard
        /* must flush all the translated code to avoid inconsistancies */
679 c33a346e bellard
        tb_flush();
680 c33a346e bellard
    }
681 c33a346e bellard
#endif
682 c33a346e bellard
}
683 c33a346e bellard
684 c33a346e bellard
685 68a79315 bellard
/* mask must never be zero */
686 68a79315 bellard
void cpu_interrupt(CPUState *env, int mask)
687 ea041c0e bellard
{
688 ea041c0e bellard
    TranslationBlock *tb;
689 68a79315 bellard
    
690 68a79315 bellard
    env->interrupt_request |= mask;
691 ea041c0e bellard
    /* if the cpu is currently executing code, we must unlink it and
692 ea041c0e bellard
       all the potentially executing TB */
693 ea041c0e bellard
    tb = env->current_tb;
694 ea041c0e bellard
    if (tb) {
695 ea041c0e bellard
        tb_reset_jump_recursive(tb);
696 ea041c0e bellard
    }
697 ea041c0e bellard
}
698 ea041c0e bellard
699 ea041c0e bellard
700 7501267e bellard
void cpu_abort(CPUState *env, const char *fmt, ...)
701 7501267e bellard
{
702 7501267e bellard
    va_list ap;
703 7501267e bellard
704 7501267e bellard
    va_start(ap, fmt);
705 7501267e bellard
    fprintf(stderr, "qemu: fatal: ");
706 7501267e bellard
    vfprintf(stderr, fmt, ap);
707 7501267e bellard
    fprintf(stderr, "\n");
708 7501267e bellard
#ifdef TARGET_I386
709 7501267e bellard
    cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
710 7501267e bellard
#endif
711 7501267e bellard
    va_end(ap);
712 7501267e bellard
    abort();
713 7501267e bellard
}
714 7501267e bellard
715 66e85a21 bellard
#ifdef TARGET_I386
716 66e85a21 bellard
/* unmap all maped pages and flush all associated code */
717 66e85a21 bellard
void page_unmap(void)
718 66e85a21 bellard
{
719 66e85a21 bellard
    PageDesc *p, *pmap;
720 66e85a21 bellard
    unsigned long addr;
721 7c2d6a78 bellard
    int i, j, ret, j1;
722 66e85a21 bellard
723 66e85a21 bellard
    for(i = 0; i < L1_SIZE; i++) {
724 66e85a21 bellard
        pmap = l1_map[i];
725 66e85a21 bellard
        if (pmap) {
726 66e85a21 bellard
            p = pmap;
727 7c2d6a78 bellard
            for(j = 0;j < L2_SIZE;) {
728 66e85a21 bellard
                if (p->flags & PAGE_VALID) {
729 66e85a21 bellard
                    addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
730 7c2d6a78 bellard
                    /* we try to find a range to make less syscalls */
731 7c2d6a78 bellard
                    j1 = j;
732 7c2d6a78 bellard
                    p++;
733 7c2d6a78 bellard
                    j++;
734 7c2d6a78 bellard
                    while (j < L2_SIZE && (p->flags & PAGE_VALID)) {
735 7c2d6a78 bellard
                        p++;
736 7c2d6a78 bellard
                        j++;
737 7c2d6a78 bellard
                    }
738 7c2d6a78 bellard
                    ret = munmap((void *)addr, (j - j1) << TARGET_PAGE_BITS);
739 66e85a21 bellard
                    if (ret != 0) {
740 66e85a21 bellard
                        fprintf(stderr, "Could not unmap page 0x%08lx\n", addr);
741 66e85a21 bellard
                        exit(1);
742 66e85a21 bellard
                    }
743 7c2d6a78 bellard
                } else {
744 7c2d6a78 bellard
                    p++;
745 7c2d6a78 bellard
                    j++;
746 66e85a21 bellard
                }
747 66e85a21 bellard
            }
748 66e85a21 bellard
            free(pmap);
749 66e85a21 bellard
            l1_map[i] = NULL;
750 66e85a21 bellard
        }
751 66e85a21 bellard
    }
752 66e85a21 bellard
    tb_flush();
753 66e85a21 bellard
}
754 66e85a21 bellard
#endif
755 33417e70 bellard
756 33417e70 bellard
void tlb_flush(CPUState *env)
757 33417e70 bellard
{
758 33417e70 bellard
#if defined(TARGET_I386)
759 33417e70 bellard
    int i;
760 33417e70 bellard
    for(i = 0; i < CPU_TLB_SIZE; i++) {
761 33417e70 bellard
        env->tlb_read[0][i].address = -1;
762 33417e70 bellard
        env->tlb_write[0][i].address = -1;
763 33417e70 bellard
        env->tlb_read[1][i].address = -1;
764 33417e70 bellard
        env->tlb_write[1][i].address = -1;
765 33417e70 bellard
    }
766 33417e70 bellard
#endif
767 33417e70 bellard
}
768 33417e70 bellard
769 33417e70 bellard
void tlb_flush_page(CPUState *env, uint32_t addr)
770 33417e70 bellard
{
771 33417e70 bellard
#if defined(TARGET_I386)
772 33417e70 bellard
    int i;
773 33417e70 bellard
774 33417e70 bellard
    i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
775 33417e70 bellard
    env->tlb_read[0][i].address = -1;
776 33417e70 bellard
    env->tlb_write[0][i].address = -1;
777 33417e70 bellard
    env->tlb_read[1][i].address = -1;
778 33417e70 bellard
    env->tlb_write[1][i].address = -1;
779 33417e70 bellard
#endif
780 33417e70 bellard
}
781 33417e70 bellard
782 33417e70 bellard
static inline unsigned long *physpage_find_alloc(unsigned int page)
783 33417e70 bellard
{
784 33417e70 bellard
    unsigned long **lp, *p;
785 33417e70 bellard
    unsigned int index, i;
786 33417e70 bellard
787 33417e70 bellard
    index = page >> TARGET_PAGE_BITS;
788 33417e70 bellard
    lp = &l1_physmap[index >> L2_BITS];
789 33417e70 bellard
    p = *lp;
790 33417e70 bellard
    if (!p) {
791 33417e70 bellard
        /* allocate if not found */
792 33417e70 bellard
        p = malloc(sizeof(unsigned long) * L2_SIZE);
793 33417e70 bellard
        for(i = 0; i < L2_SIZE; i++)
794 33417e70 bellard
            p[i] = IO_MEM_UNASSIGNED;
795 33417e70 bellard
        *lp = p;
796 33417e70 bellard
    }
797 33417e70 bellard
    return p + (index & (L2_SIZE - 1));
798 33417e70 bellard
}
799 33417e70 bellard
800 33417e70 bellard
/* return NULL if no page defined (unused memory) */
801 33417e70 bellard
unsigned long physpage_find(unsigned long page)
802 33417e70 bellard
{
803 33417e70 bellard
    unsigned long *p;
804 33417e70 bellard
    unsigned int index;
805 33417e70 bellard
    index = page >> TARGET_PAGE_BITS;
806 33417e70 bellard
    p = l1_physmap[index >> L2_BITS];
807 33417e70 bellard
    if (!p)
808 33417e70 bellard
        return IO_MEM_UNASSIGNED;
809 33417e70 bellard
    return p[index & (L2_SIZE - 1)];
810 33417e70 bellard
}
811 33417e70 bellard
812 33417e70 bellard
/* register physical memory. 'size' must be a multiple of the target
813 33417e70 bellard
   page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
814 33417e70 bellard
   io memory page */
815 33417e70 bellard
void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
816 33417e70 bellard
                                  long phys_offset)
817 33417e70 bellard
{
818 33417e70 bellard
    unsigned long addr, end_addr;
819 33417e70 bellard
    unsigned long *p;
820 33417e70 bellard
821 33417e70 bellard
    end_addr = start_addr + size;
822 33417e70 bellard
    for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) {
823 33417e70 bellard
        p = physpage_find_alloc(addr);
824 33417e70 bellard
        *p = phys_offset;
825 33417e70 bellard
        if ((phys_offset & ~TARGET_PAGE_MASK) == 0)
826 33417e70 bellard
            phys_offset += TARGET_PAGE_SIZE;
827 33417e70 bellard
    }
828 33417e70 bellard
}
829 33417e70 bellard
830 33417e70 bellard
static uint32_t unassigned_mem_readb(uint32_t addr)
831 33417e70 bellard
{
832 33417e70 bellard
    return 0;
833 33417e70 bellard
}
834 33417e70 bellard
835 33417e70 bellard
static void unassigned_mem_writeb(uint32_t addr, uint32_t val)
836 33417e70 bellard
{
837 33417e70 bellard
}
838 33417e70 bellard
839 33417e70 bellard
static CPUReadMemoryFunc *unassigned_mem_read[3] = {
840 33417e70 bellard
    unassigned_mem_readb,
841 33417e70 bellard
    unassigned_mem_readb,
842 33417e70 bellard
    unassigned_mem_readb,
843 33417e70 bellard
};
844 33417e70 bellard
845 33417e70 bellard
static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
846 33417e70 bellard
    unassigned_mem_writeb,
847 33417e70 bellard
    unassigned_mem_writeb,
848 33417e70 bellard
    unassigned_mem_writeb,
849 33417e70 bellard
};
850 33417e70 bellard
851 33417e70 bellard
852 33417e70 bellard
static void io_mem_init(void)
853 33417e70 bellard
{
854 33417e70 bellard
    io_mem_nb = 1;
855 33417e70 bellard
    cpu_register_io_memory(0, unassigned_mem_read, unassigned_mem_write);
856 33417e70 bellard
}
857 33417e70 bellard
858 33417e70 bellard
/* mem_read and mem_write are arrays of functions containing the
859 33417e70 bellard
   function to access byte (index 0), word (index 1) and dword (index
860 33417e70 bellard
   2). All functions must be supplied. If io_index is non zero, the
861 33417e70 bellard
   corresponding io zone is modified. If it is zero, a new io zone is
862 33417e70 bellard
   allocated. The return value can be used with
863 33417e70 bellard
   cpu_register_physical_memory(). (-1) is returned if error. */
864 33417e70 bellard
int cpu_register_io_memory(int io_index,
865 33417e70 bellard
                           CPUReadMemoryFunc **mem_read,
866 33417e70 bellard
                           CPUWriteMemoryFunc **mem_write)
867 33417e70 bellard
{
868 33417e70 bellard
    int i;
869 33417e70 bellard
870 33417e70 bellard
    if (io_index <= 0) {
871 33417e70 bellard
        if (io_index >= IO_MEM_NB_ENTRIES)
872 33417e70 bellard
            return -1;
873 33417e70 bellard
        io_index = io_mem_nb++;
874 33417e70 bellard
    } else {
875 33417e70 bellard
        if (io_index >= IO_MEM_NB_ENTRIES)
876 33417e70 bellard
            return -1;
877 33417e70 bellard
    }
878 33417e70 bellard
    
879 33417e70 bellard
    for(i = 0;i < 3; i++) {
880 33417e70 bellard
        io_mem_read[io_index][i] = mem_read[i];
881 33417e70 bellard
        io_mem_write[io_index][i] = mem_write[i];
882 33417e70 bellard
    }
883 33417e70 bellard
    return io_index << IO_MEM_SHIFT;
884 33417e70 bellard
}