Statistics
| Branch: | Revision:

root / exec.c @ 2c1794c4

History | View | Annotate | Download (19.6 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 fd6ce8f6 bellard
72 54936004 bellard
unsigned long real_host_page_size;
73 54936004 bellard
unsigned long host_page_bits;
74 54936004 bellard
unsigned long host_page_size;
75 54936004 bellard
unsigned long host_page_mask;
76 54936004 bellard
77 54936004 bellard
static PageDesc *l1_map[L1_SIZE];
78 54936004 bellard
79 b346ff46 bellard
static void page_init(void)
80 54936004 bellard
{
81 54936004 bellard
    /* NOTE: we can always suppose that host_page_size >=
82 54936004 bellard
       TARGET_PAGE_SIZE */
83 54936004 bellard
    real_host_page_size = getpagesize();
84 54936004 bellard
    if (host_page_size == 0)
85 54936004 bellard
        host_page_size = real_host_page_size;
86 54936004 bellard
    if (host_page_size < TARGET_PAGE_SIZE)
87 54936004 bellard
        host_page_size = TARGET_PAGE_SIZE;
88 54936004 bellard
    host_page_bits = 0;
89 54936004 bellard
    while ((1 << host_page_bits) < host_page_size)
90 54936004 bellard
        host_page_bits++;
91 54936004 bellard
    host_page_mask = ~(host_page_size - 1);
92 54936004 bellard
}
93 54936004 bellard
94 54936004 bellard
/* dump memory mappings */
95 54936004 bellard
void page_dump(FILE *f)
96 54936004 bellard
{
97 54936004 bellard
    unsigned long start, end;
98 54936004 bellard
    int i, j, prot, prot1;
99 54936004 bellard
    PageDesc *p;
100 54936004 bellard
101 54936004 bellard
    fprintf(f, "%-8s %-8s %-8s %s\n",
102 54936004 bellard
            "start", "end", "size", "prot");
103 54936004 bellard
    start = -1;
104 54936004 bellard
    end = -1;
105 54936004 bellard
    prot = 0;
106 54936004 bellard
    for(i = 0; i <= L1_SIZE; i++) {
107 54936004 bellard
        if (i < L1_SIZE)
108 54936004 bellard
            p = l1_map[i];
109 54936004 bellard
        else
110 54936004 bellard
            p = NULL;
111 54936004 bellard
        for(j = 0;j < L2_SIZE; j++) {
112 54936004 bellard
            if (!p)
113 54936004 bellard
                prot1 = 0;
114 54936004 bellard
            else
115 54936004 bellard
                prot1 = p[j].flags;
116 54936004 bellard
            if (prot1 != prot) {
117 54936004 bellard
                end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
118 54936004 bellard
                if (start != -1) {
119 54936004 bellard
                    fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
120 54936004 bellard
                            start, end, end - start, 
121 54936004 bellard
                            prot & PAGE_READ ? 'r' : '-',
122 54936004 bellard
                            prot & PAGE_WRITE ? 'w' : '-',
123 54936004 bellard
                            prot & PAGE_EXEC ? 'x' : '-');
124 54936004 bellard
                }
125 54936004 bellard
                if (prot1 != 0)
126 54936004 bellard
                    start = end;
127 54936004 bellard
                else
128 54936004 bellard
                    start = -1;
129 54936004 bellard
                prot = prot1;
130 54936004 bellard
            }
131 54936004 bellard
            if (!p)
132 54936004 bellard
                break;
133 54936004 bellard
        }
134 54936004 bellard
    }
135 54936004 bellard
}
136 54936004 bellard
137 fd6ce8f6 bellard
static inline PageDesc *page_find_alloc(unsigned int index)
138 54936004 bellard
{
139 54936004 bellard
    PageDesc **lp, *p;
140 54936004 bellard
141 54936004 bellard
    lp = &l1_map[index >> L2_BITS];
142 54936004 bellard
    p = *lp;
143 54936004 bellard
    if (!p) {
144 54936004 bellard
        /* allocate if not found */
145 54936004 bellard
        p = malloc(sizeof(PageDesc) * L2_SIZE);
146 fd6ce8f6 bellard
        memset(p, 0, sizeof(PageDesc) * L2_SIZE);
147 54936004 bellard
        *lp = p;
148 54936004 bellard
    }
149 54936004 bellard
    return p + (index & (L2_SIZE - 1));
150 54936004 bellard
}
151 54936004 bellard
152 fd6ce8f6 bellard
static inline PageDesc *page_find(unsigned int index)
153 54936004 bellard
{
154 54936004 bellard
    PageDesc *p;
155 54936004 bellard
156 54936004 bellard
    p = l1_map[index >> L2_BITS];
157 54936004 bellard
    if (!p)
158 54936004 bellard
        return 0;
159 fd6ce8f6 bellard
    return p + (index & (L2_SIZE - 1));
160 fd6ce8f6 bellard
}
161 fd6ce8f6 bellard
162 fd6ce8f6 bellard
int page_get_flags(unsigned long address)
163 fd6ce8f6 bellard
{
164 fd6ce8f6 bellard
    PageDesc *p;
165 fd6ce8f6 bellard
166 fd6ce8f6 bellard
    p = page_find(address >> TARGET_PAGE_BITS);
167 fd6ce8f6 bellard
    if (!p)
168 fd6ce8f6 bellard
        return 0;
169 fd6ce8f6 bellard
    return p->flags;
170 54936004 bellard
}
171 54936004 bellard
172 fd6ce8f6 bellard
/* modify the flags of a page and invalidate the code if
173 fd6ce8f6 bellard
   necessary. The flag PAGE_WRITE_ORG is positionned automatically
174 fd6ce8f6 bellard
   depending on PAGE_WRITE */
175 54936004 bellard
void page_set_flags(unsigned long start, unsigned long end, int flags)
176 54936004 bellard
{
177 54936004 bellard
    PageDesc *p;
178 54936004 bellard
    unsigned long addr;
179 54936004 bellard
180 54936004 bellard
    start = start & TARGET_PAGE_MASK;
181 54936004 bellard
    end = TARGET_PAGE_ALIGN(end);
182 fd6ce8f6 bellard
    if (flags & PAGE_WRITE)
183 fd6ce8f6 bellard
        flags |= PAGE_WRITE_ORG;
184 eb51d102 bellard
    spin_lock(&tb_lock);
185 54936004 bellard
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
186 fd6ce8f6 bellard
        p = page_find_alloc(addr >> TARGET_PAGE_BITS);
187 fd6ce8f6 bellard
        /* if the write protection is set, then we invalidate the code
188 fd6ce8f6 bellard
           inside */
189 fd6ce8f6 bellard
        if (!(p->flags & PAGE_WRITE) && 
190 fd6ce8f6 bellard
            (flags & PAGE_WRITE) &&
191 fd6ce8f6 bellard
            p->first_tb) {
192 fd6ce8f6 bellard
            tb_invalidate_page(addr);
193 fd6ce8f6 bellard
        }
194 54936004 bellard
        p->flags = flags;
195 54936004 bellard
    }
196 eb51d102 bellard
    spin_unlock(&tb_lock);
197 54936004 bellard
}
198 fd6ce8f6 bellard
199 b346ff46 bellard
void cpu_exec_init(void)
200 fd6ce8f6 bellard
{
201 fd6ce8f6 bellard
    if (!code_gen_ptr) {
202 fd6ce8f6 bellard
        code_gen_ptr = code_gen_buffer;
203 b346ff46 bellard
        page_init();
204 fd6ce8f6 bellard
    }
205 fd6ce8f6 bellard
}
206 fd6ce8f6 bellard
207 fd6ce8f6 bellard
/* set to NULL all the 'first_tb' fields in all PageDescs */
208 fd6ce8f6 bellard
static void page_flush_tb(void)
209 fd6ce8f6 bellard
{
210 fd6ce8f6 bellard
    int i, j;
211 fd6ce8f6 bellard
    PageDesc *p;
212 fd6ce8f6 bellard
213 fd6ce8f6 bellard
    for(i = 0; i < L1_SIZE; i++) {
214 fd6ce8f6 bellard
        p = l1_map[i];
215 fd6ce8f6 bellard
        if (p) {
216 fd6ce8f6 bellard
            for(j = 0; j < L2_SIZE; j++)
217 fd6ce8f6 bellard
                p[j].first_tb = NULL;
218 fd6ce8f6 bellard
        }
219 fd6ce8f6 bellard
    }
220 fd6ce8f6 bellard
}
221 fd6ce8f6 bellard
222 fd6ce8f6 bellard
/* flush all the translation blocks */
223 d4e8164f bellard
/* XXX: tb_flush is currently not thread safe */
224 fd6ce8f6 bellard
void tb_flush(void)
225 fd6ce8f6 bellard
{
226 fd6ce8f6 bellard
    int i;
227 fd6ce8f6 bellard
#ifdef DEBUG_FLUSH
228 fd6ce8f6 bellard
    printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
229 fd6ce8f6 bellard
           code_gen_ptr - code_gen_buffer, 
230 fd6ce8f6 bellard
           nb_tbs, 
231 fd6ce8f6 bellard
           (code_gen_ptr - code_gen_buffer) / nb_tbs);
232 fd6ce8f6 bellard
#endif
233 fd6ce8f6 bellard
    nb_tbs = 0;
234 fd6ce8f6 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
235 fd6ce8f6 bellard
        tb_hash[i] = NULL;
236 fd6ce8f6 bellard
    page_flush_tb();
237 fd6ce8f6 bellard
    code_gen_ptr = code_gen_buffer;
238 d4e8164f bellard
    /* XXX: flush processor icache at this point if cache flush is
239 d4e8164f bellard
       expensive */
240 fd6ce8f6 bellard
}
241 fd6ce8f6 bellard
242 fd6ce8f6 bellard
#ifdef DEBUG_TB_CHECK
243 fd6ce8f6 bellard
244 fd6ce8f6 bellard
static void tb_invalidate_check(unsigned long address)
245 fd6ce8f6 bellard
{
246 fd6ce8f6 bellard
    TranslationBlock *tb;
247 fd6ce8f6 bellard
    int i;
248 fd6ce8f6 bellard
    address &= TARGET_PAGE_MASK;
249 fd6ce8f6 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
250 fd6ce8f6 bellard
        for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
251 fd6ce8f6 bellard
            if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
252 fd6ce8f6 bellard
                  address >= tb->pc + tb->size)) {
253 fd6ce8f6 bellard
                printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
254 fd6ce8f6 bellard
                       address, tb->pc, tb->size);
255 fd6ce8f6 bellard
            }
256 fd6ce8f6 bellard
        }
257 fd6ce8f6 bellard
    }
258 fd6ce8f6 bellard
}
259 fd6ce8f6 bellard
260 fd6ce8f6 bellard
/* verify that all the pages have correct rights for code */
261 fd6ce8f6 bellard
static void tb_page_check(void)
262 fd6ce8f6 bellard
{
263 fd6ce8f6 bellard
    TranslationBlock *tb;
264 fd6ce8f6 bellard
    int i, flags1, flags2;
265 fd6ce8f6 bellard
    
266 fd6ce8f6 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
267 fd6ce8f6 bellard
        for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
268 fd6ce8f6 bellard
            flags1 = page_get_flags(tb->pc);
269 fd6ce8f6 bellard
            flags2 = page_get_flags(tb->pc + tb->size - 1);
270 fd6ce8f6 bellard
            if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
271 fd6ce8f6 bellard
                printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
272 fd6ce8f6 bellard
                       tb->pc, tb->size, flags1, flags2);
273 fd6ce8f6 bellard
            }
274 fd6ce8f6 bellard
        }
275 fd6ce8f6 bellard
    }
276 fd6ce8f6 bellard
}
277 fd6ce8f6 bellard
278 d4e8164f bellard
void tb_jmp_check(TranslationBlock *tb)
279 d4e8164f bellard
{
280 d4e8164f bellard
    TranslationBlock *tb1;
281 d4e8164f bellard
    unsigned int n1;
282 d4e8164f bellard
283 d4e8164f bellard
    /* suppress any remaining jumps to this TB */
284 d4e8164f bellard
    tb1 = tb->jmp_first;
285 d4e8164f bellard
    for(;;) {
286 d4e8164f bellard
        n1 = (long)tb1 & 3;
287 d4e8164f bellard
        tb1 = (TranslationBlock *)((long)tb1 & ~3);
288 d4e8164f bellard
        if (n1 == 2)
289 d4e8164f bellard
            break;
290 d4e8164f bellard
        tb1 = tb1->jmp_next[n1];
291 d4e8164f bellard
    }
292 d4e8164f bellard
    /* check end of list */
293 d4e8164f bellard
    if (tb1 != tb) {
294 d4e8164f bellard
        printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
295 d4e8164f bellard
    }
296 d4e8164f bellard
}
297 d4e8164f bellard
298 fd6ce8f6 bellard
#endif
299 fd6ce8f6 bellard
300 fd6ce8f6 bellard
/* invalidate one TB */
301 fd6ce8f6 bellard
static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
302 fd6ce8f6 bellard
                             int next_offset)
303 fd6ce8f6 bellard
{
304 fd6ce8f6 bellard
    TranslationBlock *tb1;
305 fd6ce8f6 bellard
    for(;;) {
306 fd6ce8f6 bellard
        tb1 = *ptb;
307 fd6ce8f6 bellard
        if (tb1 == tb) {
308 fd6ce8f6 bellard
            *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
309 fd6ce8f6 bellard
            break;
310 fd6ce8f6 bellard
        }
311 fd6ce8f6 bellard
        ptb = (TranslationBlock **)((char *)tb1 + next_offset);
312 fd6ce8f6 bellard
    }
313 fd6ce8f6 bellard
}
314 fd6ce8f6 bellard
315 d4e8164f bellard
static inline void tb_jmp_remove(TranslationBlock *tb, int n)
316 d4e8164f bellard
{
317 d4e8164f bellard
    TranslationBlock *tb1, **ptb;
318 d4e8164f bellard
    unsigned int n1;
319 d4e8164f bellard
320 d4e8164f bellard
    ptb = &tb->jmp_next[n];
321 d4e8164f bellard
    tb1 = *ptb;
322 d4e8164f bellard
    if (tb1) {
323 d4e8164f bellard
        /* find tb(n) in circular list */
324 d4e8164f bellard
        for(;;) {
325 d4e8164f bellard
            tb1 = *ptb;
326 d4e8164f bellard
            n1 = (long)tb1 & 3;
327 d4e8164f bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
328 d4e8164f bellard
            if (n1 == n && tb1 == tb)
329 d4e8164f bellard
                break;
330 d4e8164f bellard
            if (n1 == 2) {
331 d4e8164f bellard
                ptb = &tb1->jmp_first;
332 d4e8164f bellard
            } else {
333 d4e8164f bellard
                ptb = &tb1->jmp_next[n1];
334 d4e8164f bellard
            }
335 d4e8164f bellard
        }
336 d4e8164f bellard
        /* now we can suppress tb(n) from the list */
337 d4e8164f bellard
        *ptb = tb->jmp_next[n];
338 d4e8164f bellard
339 d4e8164f bellard
        tb->jmp_next[n] = NULL;
340 d4e8164f bellard
    }
341 d4e8164f bellard
}
342 d4e8164f bellard
343 d4e8164f bellard
/* reset the jump entry 'n' of a TB so that it is not chained to
344 d4e8164f bellard
   another TB */
345 d4e8164f bellard
static inline void tb_reset_jump(TranslationBlock *tb, int n)
346 d4e8164f bellard
{
347 d4e8164f bellard
    tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
348 d4e8164f bellard
}
349 d4e8164f bellard
350 fd6ce8f6 bellard
static inline void tb_invalidate(TranslationBlock *tb, int parity)
351 fd6ce8f6 bellard
{
352 fd6ce8f6 bellard
    PageDesc *p;
353 fd6ce8f6 bellard
    unsigned int page_index1, page_index2;
354 d4e8164f bellard
    unsigned int h, n1;
355 d4e8164f bellard
    TranslationBlock *tb1, *tb2;
356 d4e8164f bellard
    
357 fd6ce8f6 bellard
    /* remove the TB from the hash list */
358 fd6ce8f6 bellard
    h = tb_hash_func(tb->pc);
359 fd6ce8f6 bellard
    tb_remove(&tb_hash[h], tb, 
360 fd6ce8f6 bellard
              offsetof(TranslationBlock, hash_next));
361 fd6ce8f6 bellard
    /* remove the TB from the page list */
362 fd6ce8f6 bellard
    page_index1 = tb->pc >> TARGET_PAGE_BITS;
363 fd6ce8f6 bellard
    if ((page_index1 & 1) == parity) {
364 fd6ce8f6 bellard
        p = page_find(page_index1);
365 fd6ce8f6 bellard
        tb_remove(&p->first_tb, tb, 
366 fd6ce8f6 bellard
                  offsetof(TranslationBlock, page_next[page_index1 & 1]));
367 fd6ce8f6 bellard
    }
368 fd6ce8f6 bellard
    page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
369 fd6ce8f6 bellard
    if ((page_index2 & 1) == parity) {
370 fd6ce8f6 bellard
        p = page_find(page_index2);
371 fd6ce8f6 bellard
        tb_remove(&p->first_tb, tb, 
372 fd6ce8f6 bellard
                  offsetof(TranslationBlock, page_next[page_index2 & 1]));
373 fd6ce8f6 bellard
    }
374 d4e8164f bellard
375 d4e8164f bellard
    /* suppress this TB from the two jump lists */
376 d4e8164f bellard
    tb_jmp_remove(tb, 0);
377 d4e8164f bellard
    tb_jmp_remove(tb, 1);
378 d4e8164f bellard
379 d4e8164f bellard
    /* suppress any remaining jumps to this TB */
380 d4e8164f bellard
    tb1 = tb->jmp_first;
381 d4e8164f bellard
    for(;;) {
382 d4e8164f bellard
        n1 = (long)tb1 & 3;
383 d4e8164f bellard
        if (n1 == 2)
384 d4e8164f bellard
            break;
385 d4e8164f bellard
        tb1 = (TranslationBlock *)((long)tb1 & ~3);
386 d4e8164f bellard
        tb2 = tb1->jmp_next[n1];
387 d4e8164f bellard
        tb_reset_jump(tb1, n1);
388 d4e8164f bellard
        tb1->jmp_next[n1] = NULL;
389 d4e8164f bellard
        tb1 = tb2;
390 d4e8164f bellard
    }
391 d4e8164f bellard
    tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
392 fd6ce8f6 bellard
}
393 fd6ce8f6 bellard
394 fd6ce8f6 bellard
/* invalidate all TBs which intersect with the target page starting at addr */
395 fd6ce8f6 bellard
static void tb_invalidate_page(unsigned long address)
396 fd6ce8f6 bellard
{
397 fd6ce8f6 bellard
    TranslationBlock *tb_next, *tb;
398 fd6ce8f6 bellard
    unsigned int page_index;
399 fd6ce8f6 bellard
    int parity1, parity2;
400 fd6ce8f6 bellard
    PageDesc *p;
401 fd6ce8f6 bellard
#ifdef DEBUG_TB_INVALIDATE
402 fd6ce8f6 bellard
    printf("tb_invalidate_page: %lx\n", address);
403 fd6ce8f6 bellard
#endif
404 fd6ce8f6 bellard
405 fd6ce8f6 bellard
    page_index = address >> TARGET_PAGE_BITS;
406 fd6ce8f6 bellard
    p = page_find(page_index);
407 fd6ce8f6 bellard
    if (!p)
408 fd6ce8f6 bellard
        return;
409 fd6ce8f6 bellard
    tb = p->first_tb;
410 fd6ce8f6 bellard
    parity1 = page_index & 1;
411 fd6ce8f6 bellard
    parity2 = parity1 ^ 1;
412 fd6ce8f6 bellard
    while (tb != NULL) {
413 fd6ce8f6 bellard
        tb_next = tb->page_next[parity1];
414 fd6ce8f6 bellard
        tb_invalidate(tb, parity2);
415 fd6ce8f6 bellard
        tb = tb_next;
416 fd6ce8f6 bellard
    }
417 fd6ce8f6 bellard
    p->first_tb = NULL;
418 fd6ce8f6 bellard
}
419 fd6ce8f6 bellard
420 fd6ce8f6 bellard
/* add the tb in the target page and protect it if necessary */
421 fd6ce8f6 bellard
static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
422 fd6ce8f6 bellard
{
423 fd6ce8f6 bellard
    PageDesc *p;
424 fd6ce8f6 bellard
    unsigned long host_start, host_end, addr, page_addr;
425 fd6ce8f6 bellard
    int prot;
426 fd6ce8f6 bellard
427 fd6ce8f6 bellard
    p = page_find_alloc(page_index);
428 fd6ce8f6 bellard
    tb->page_next[page_index & 1] = p->first_tb;
429 fd6ce8f6 bellard
    p->first_tb = tb;
430 fd6ce8f6 bellard
    if (p->flags & PAGE_WRITE) {
431 fd6ce8f6 bellard
        /* force the host page as non writable (writes will have a
432 fd6ce8f6 bellard
           page fault + mprotect overhead) */
433 fd6ce8f6 bellard
        page_addr = (page_index << TARGET_PAGE_BITS);
434 fd6ce8f6 bellard
        host_start = page_addr & host_page_mask;
435 fd6ce8f6 bellard
        host_end = host_start + host_page_size;
436 fd6ce8f6 bellard
        prot = 0;
437 fd6ce8f6 bellard
        for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
438 fd6ce8f6 bellard
            prot |= page_get_flags(addr);
439 fd6ce8f6 bellard
        mprotect((void *)host_start, host_page_size, 
440 fd6ce8f6 bellard
                 (prot & PAGE_BITS) & ~PAGE_WRITE);
441 fd6ce8f6 bellard
#ifdef DEBUG_TB_INVALIDATE
442 fd6ce8f6 bellard
        printf("protecting code page: 0x%08lx\n", 
443 fd6ce8f6 bellard
               host_start);
444 fd6ce8f6 bellard
#endif
445 fd6ce8f6 bellard
        p->flags &= ~PAGE_WRITE;
446 fd6ce8f6 bellard
#ifdef DEBUG_TB_CHECK
447 fd6ce8f6 bellard
        tb_page_check();
448 fd6ce8f6 bellard
#endif
449 fd6ce8f6 bellard
    }
450 fd6ce8f6 bellard
}
451 fd6ce8f6 bellard
452 fd6ce8f6 bellard
/* Allocate a new translation block. Flush the translation buffer if
453 fd6ce8f6 bellard
   too many translation blocks or too much generated code. */
454 d4e8164f bellard
TranslationBlock *tb_alloc(unsigned long pc)
455 fd6ce8f6 bellard
{
456 fd6ce8f6 bellard
    TranslationBlock *tb;
457 fd6ce8f6 bellard
458 fd6ce8f6 bellard
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
459 fd6ce8f6 bellard
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
460 d4e8164f bellard
        return NULL;
461 fd6ce8f6 bellard
    tb = &tbs[nb_tbs++];
462 fd6ce8f6 bellard
    tb->pc = pc;
463 d4e8164f bellard
    return tb;
464 d4e8164f bellard
}
465 d4e8164f bellard
466 d4e8164f bellard
/* link the tb with the other TBs */
467 d4e8164f bellard
void tb_link(TranslationBlock *tb)
468 d4e8164f bellard
{
469 d4e8164f bellard
    unsigned int page_index1, page_index2;
470 fd6ce8f6 bellard
471 fd6ce8f6 bellard
    /* add in the page list */
472 d4e8164f bellard
    page_index1 = tb->pc >> TARGET_PAGE_BITS;
473 fd6ce8f6 bellard
    tb_alloc_page(tb, page_index1);
474 d4e8164f bellard
    page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
475 fd6ce8f6 bellard
    if (page_index2 != page_index1) {
476 fd6ce8f6 bellard
        tb_alloc_page(tb, page_index2);
477 fd6ce8f6 bellard
    }
478 d4e8164f bellard
    tb->jmp_first = (TranslationBlock *)((long)tb | 2);
479 d4e8164f bellard
    tb->jmp_next[0] = NULL;
480 d4e8164f bellard
    tb->jmp_next[1] = NULL;
481 d4e8164f bellard
482 d4e8164f bellard
    /* init original jump addresses */
483 d4e8164f bellard
    if (tb->tb_next_offset[0] != 0xffff)
484 d4e8164f bellard
        tb_reset_jump(tb, 0);
485 d4e8164f bellard
    if (tb->tb_next_offset[1] != 0xffff)
486 d4e8164f bellard
        tb_reset_jump(tb, 1);
487 fd6ce8f6 bellard
}
488 fd6ce8f6 bellard
489 fd6ce8f6 bellard
/* called from signal handler: invalidate the code and unprotect the
490 fd6ce8f6 bellard
   page. Return TRUE if the fault was succesfully handled. */
491 fd6ce8f6 bellard
int page_unprotect(unsigned long address)
492 fd6ce8f6 bellard
{
493 1565b7bc bellard
    unsigned int page_index, prot, pindex;
494 1565b7bc bellard
    PageDesc *p, *p1;
495 fd6ce8f6 bellard
    unsigned long host_start, host_end, addr;
496 fd6ce8f6 bellard
497 1565b7bc bellard
    host_start = address & host_page_mask;
498 1565b7bc bellard
    page_index = host_start >> TARGET_PAGE_BITS;
499 1565b7bc bellard
    p1 = page_find(page_index);
500 1565b7bc bellard
    if (!p1)
501 fd6ce8f6 bellard
        return 0;
502 1565b7bc bellard
    host_end = host_start + host_page_size;
503 1565b7bc bellard
    p = p1;
504 1565b7bc bellard
    prot = 0;
505 1565b7bc bellard
    for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
506 1565b7bc bellard
        prot |= p->flags;
507 1565b7bc bellard
        p++;
508 1565b7bc bellard
    }
509 1565b7bc bellard
    /* if the page was really writable, then we change its
510 1565b7bc bellard
       protection back to writable */
511 1565b7bc bellard
    if (prot & PAGE_WRITE_ORG) {
512 fd6ce8f6 bellard
        mprotect((void *)host_start, host_page_size, 
513 fd6ce8f6 bellard
                 (prot & PAGE_BITS) | PAGE_WRITE);
514 1565b7bc bellard
        pindex = (address - host_start) >> TARGET_PAGE_BITS;
515 1565b7bc bellard
        p1[pindex].flags |= PAGE_WRITE;
516 fd6ce8f6 bellard
        /* and since the content will be modified, we must invalidate
517 fd6ce8f6 bellard
           the corresponding translated code. */
518 fd6ce8f6 bellard
        tb_invalidate_page(address);
519 fd6ce8f6 bellard
#ifdef DEBUG_TB_CHECK
520 fd6ce8f6 bellard
        tb_invalidate_check(address);
521 fd6ce8f6 bellard
#endif
522 fd6ce8f6 bellard
        return 1;
523 fd6ce8f6 bellard
    } else {
524 fd6ce8f6 bellard
        return 0;
525 fd6ce8f6 bellard
    }
526 fd6ce8f6 bellard
}
527 fd6ce8f6 bellard
528 fd6ce8f6 bellard
/* call this function when system calls directly modify a memory area */
529 fd6ce8f6 bellard
void page_unprotect_range(uint8_t *data, unsigned long data_size)
530 fd6ce8f6 bellard
{
531 fd6ce8f6 bellard
    unsigned long start, end, addr;
532 fd6ce8f6 bellard
533 fd6ce8f6 bellard
    start = (unsigned long)data;
534 fd6ce8f6 bellard
    end = start + data_size;
535 fd6ce8f6 bellard
    start &= TARGET_PAGE_MASK;
536 fd6ce8f6 bellard
    end = TARGET_PAGE_ALIGN(end);
537 fd6ce8f6 bellard
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
538 fd6ce8f6 bellard
        page_unprotect(addr);
539 fd6ce8f6 bellard
    }
540 fd6ce8f6 bellard
}
541 a513fe19 bellard
542 a513fe19 bellard
/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
543 a513fe19 bellard
   tb[1].tc_ptr. Return NULL if not found */
544 a513fe19 bellard
TranslationBlock *tb_find_pc(unsigned long tc_ptr)
545 a513fe19 bellard
{
546 a513fe19 bellard
    int m_min, m_max, m;
547 a513fe19 bellard
    unsigned long v;
548 a513fe19 bellard
    TranslationBlock *tb;
549 a513fe19 bellard
550 a513fe19 bellard
    if (nb_tbs <= 0)
551 a513fe19 bellard
        return NULL;
552 a513fe19 bellard
    if (tc_ptr < (unsigned long)code_gen_buffer ||
553 a513fe19 bellard
        tc_ptr >= (unsigned long)code_gen_ptr)
554 a513fe19 bellard
        return NULL;
555 a513fe19 bellard
    /* binary search (cf Knuth) */
556 a513fe19 bellard
    m_min = 0;
557 a513fe19 bellard
    m_max = nb_tbs - 1;
558 a513fe19 bellard
    while (m_min <= m_max) {
559 a513fe19 bellard
        m = (m_min + m_max) >> 1;
560 a513fe19 bellard
        tb = &tbs[m];
561 a513fe19 bellard
        v = (unsigned long)tb->tc_ptr;
562 a513fe19 bellard
        if (v == tc_ptr)
563 a513fe19 bellard
            return tb;
564 a513fe19 bellard
        else if (tc_ptr < v) {
565 a513fe19 bellard
            m_max = m - 1;
566 a513fe19 bellard
        } else {
567 a513fe19 bellard
            m_min = m + 1;
568 a513fe19 bellard
        }
569 a513fe19 bellard
    } 
570 a513fe19 bellard
    return &tbs[m_max];
571 a513fe19 bellard
}
572 7501267e bellard
573 ea041c0e bellard
static void tb_reset_jump_recursive(TranslationBlock *tb);
574 ea041c0e bellard
575 ea041c0e bellard
static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
576 ea041c0e bellard
{
577 ea041c0e bellard
    TranslationBlock *tb1, *tb_next, **ptb;
578 ea041c0e bellard
    unsigned int n1;
579 ea041c0e bellard
580 ea041c0e bellard
    tb1 = tb->jmp_next[n];
581 ea041c0e bellard
    if (tb1 != NULL) {
582 ea041c0e bellard
        /* find head of list */
583 ea041c0e bellard
        for(;;) {
584 ea041c0e bellard
            n1 = (long)tb1 & 3;
585 ea041c0e bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
586 ea041c0e bellard
            if (n1 == 2)
587 ea041c0e bellard
                break;
588 ea041c0e bellard
            tb1 = tb1->jmp_next[n1];
589 ea041c0e bellard
        }
590 ea041c0e bellard
        /* we are now sure now that tb jumps to tb1 */
591 ea041c0e bellard
        tb_next = tb1;
592 ea041c0e bellard
593 ea041c0e bellard
        /* remove tb from the jmp_first list */
594 ea041c0e bellard
        ptb = &tb_next->jmp_first;
595 ea041c0e bellard
        for(;;) {
596 ea041c0e bellard
            tb1 = *ptb;
597 ea041c0e bellard
            n1 = (long)tb1 & 3;
598 ea041c0e bellard
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
599 ea041c0e bellard
            if (n1 == n && tb1 == tb)
600 ea041c0e bellard
                break;
601 ea041c0e bellard
            ptb = &tb1->jmp_next[n1];
602 ea041c0e bellard
        }
603 ea041c0e bellard
        *ptb = tb->jmp_next[n];
604 ea041c0e bellard
        tb->jmp_next[n] = NULL;
605 ea041c0e bellard
        
606 ea041c0e bellard
        /* suppress the jump to next tb in generated code */
607 ea041c0e bellard
        tb_reset_jump(tb, n);
608 ea041c0e bellard
609 ea041c0e bellard
        /* suppress jumps in the tb on which we could have jump */
610 ea041c0e bellard
        tb_reset_jump_recursive(tb_next);
611 ea041c0e bellard
    }
612 ea041c0e bellard
}
613 ea041c0e bellard
614 ea041c0e bellard
static void tb_reset_jump_recursive(TranslationBlock *tb)
615 ea041c0e bellard
{
616 ea041c0e bellard
    tb_reset_jump_recursive2(tb, 0);
617 ea041c0e bellard
    tb_reset_jump_recursive2(tb, 1);
618 ea041c0e bellard
}
619 ea041c0e bellard
620 4c3a88a2 bellard
/* add a breakpoint */
621 4c3a88a2 bellard
int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
622 4c3a88a2 bellard
{
623 4c3a88a2 bellard
#if defined(TARGET_I386)
624 4c3a88a2 bellard
    int i;
625 4c3a88a2 bellard
626 4c3a88a2 bellard
    for(i = 0; i < env->nb_breakpoints; i++) {
627 4c3a88a2 bellard
        if (env->breakpoints[i] == pc)
628 4c3a88a2 bellard
            return 0;
629 4c3a88a2 bellard
    }
630 4c3a88a2 bellard
631 4c3a88a2 bellard
    if (env->nb_breakpoints >= MAX_BREAKPOINTS)
632 4c3a88a2 bellard
        return -1;
633 4c3a88a2 bellard
    env->breakpoints[env->nb_breakpoints++] = pc;
634 4c3a88a2 bellard
    tb_invalidate_page(pc);
635 4c3a88a2 bellard
    return 0;
636 4c3a88a2 bellard
#else
637 4c3a88a2 bellard
    return -1;
638 4c3a88a2 bellard
#endif
639 4c3a88a2 bellard
}
640 4c3a88a2 bellard
641 4c3a88a2 bellard
/* remove a breakpoint */
642 4c3a88a2 bellard
int cpu_breakpoint_remove(CPUState *env, uint32_t pc)
643 4c3a88a2 bellard
{
644 4c3a88a2 bellard
#if defined(TARGET_I386)
645 4c3a88a2 bellard
    int i;
646 4c3a88a2 bellard
    for(i = 0; i < env->nb_breakpoints; i++) {
647 4c3a88a2 bellard
        if (env->breakpoints[i] == pc)
648 4c3a88a2 bellard
            goto found;
649 4c3a88a2 bellard
    }
650 4c3a88a2 bellard
    return -1;
651 4c3a88a2 bellard
 found:
652 4c3a88a2 bellard
    memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
653 4c3a88a2 bellard
            (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
654 4c3a88a2 bellard
    env->nb_breakpoints--;
655 4c3a88a2 bellard
    tb_invalidate_page(pc);
656 4c3a88a2 bellard
    return 0;
657 4c3a88a2 bellard
#else
658 4c3a88a2 bellard
    return -1;
659 4c3a88a2 bellard
#endif
660 4c3a88a2 bellard
}
661 4c3a88a2 bellard
662 68a79315 bellard
/* mask must never be zero */
663 68a79315 bellard
void cpu_interrupt(CPUState *env, int mask)
664 ea041c0e bellard
{
665 ea041c0e bellard
    TranslationBlock *tb;
666 68a79315 bellard
    
667 68a79315 bellard
    env->interrupt_request |= mask;
668 ea041c0e bellard
    /* if the cpu is currently executing code, we must unlink it and
669 ea041c0e bellard
       all the potentially executing TB */
670 ea041c0e bellard
    tb = env->current_tb;
671 ea041c0e bellard
    if (tb) {
672 ea041c0e bellard
        tb_reset_jump_recursive(tb);
673 ea041c0e bellard
    }
674 ea041c0e bellard
}
675 ea041c0e bellard
676 ea041c0e bellard
677 7501267e bellard
void cpu_abort(CPUState *env, const char *fmt, ...)
678 7501267e bellard
{
679 7501267e bellard
    va_list ap;
680 7501267e bellard
681 7501267e bellard
    va_start(ap, fmt);
682 7501267e bellard
    fprintf(stderr, "qemu: fatal: ");
683 7501267e bellard
    vfprintf(stderr, fmt, ap);
684 7501267e bellard
    fprintf(stderr, "\n");
685 7501267e bellard
#ifdef TARGET_I386
686 7501267e bellard
    cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
687 7501267e bellard
#endif
688 7501267e bellard
    va_end(ap);
689 7501267e bellard
    abort();
690 7501267e bellard
}
691 7501267e bellard
692 66e85a21 bellard
#ifdef TARGET_I386
693 66e85a21 bellard
/* unmap all maped pages and flush all associated code */
694 66e85a21 bellard
void page_unmap(void)
695 66e85a21 bellard
{
696 66e85a21 bellard
    PageDesc *p, *pmap;
697 66e85a21 bellard
    unsigned long addr;
698 7c2d6a78 bellard
    int i, j, ret, j1;
699 66e85a21 bellard
700 66e85a21 bellard
    for(i = 0; i < L1_SIZE; i++) {
701 66e85a21 bellard
        pmap = l1_map[i];
702 66e85a21 bellard
        if (pmap) {
703 66e85a21 bellard
            p = pmap;
704 7c2d6a78 bellard
            for(j = 0;j < L2_SIZE;) {
705 66e85a21 bellard
                if (p->flags & PAGE_VALID) {
706 66e85a21 bellard
                    addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
707 7c2d6a78 bellard
                    /* we try to find a range to make less syscalls */
708 7c2d6a78 bellard
                    j1 = j;
709 7c2d6a78 bellard
                    p++;
710 7c2d6a78 bellard
                    j++;
711 7c2d6a78 bellard
                    while (j < L2_SIZE && (p->flags & PAGE_VALID)) {
712 7c2d6a78 bellard
                        p++;
713 7c2d6a78 bellard
                        j++;
714 7c2d6a78 bellard
                    }
715 7c2d6a78 bellard
                    ret = munmap((void *)addr, (j - j1) << TARGET_PAGE_BITS);
716 66e85a21 bellard
                    if (ret != 0) {
717 66e85a21 bellard
                        fprintf(stderr, "Could not unmap page 0x%08lx\n", addr);
718 66e85a21 bellard
                        exit(1);
719 66e85a21 bellard
                    }
720 7c2d6a78 bellard
                } else {
721 7c2d6a78 bellard
                    p++;
722 7c2d6a78 bellard
                    j++;
723 66e85a21 bellard
                }
724 66e85a21 bellard
            }
725 66e85a21 bellard
            free(pmap);
726 66e85a21 bellard
            l1_map[i] = NULL;
727 66e85a21 bellard
        }
728 66e85a21 bellard
    }
729 66e85a21 bellard
    tb_flush();
730 66e85a21 bellard
}
731 66e85a21 bellard
#endif