Statistics
| Branch: | Revision:

root / exec.c @ eb51d102

History | View | Annotate | Download (12.4 kB)

1 54936004 bellard
/*
2 fd6ce8f6 bellard
 *  virtual page mapping and translated block handling
3 54936004 bellard
 * 
4 54936004 bellard
 *  Copyright (c) 2003 Fabrice Bellard
5 54936004 bellard
 *
6 54936004 bellard
 * This library is free software; you can redistribute it and/or
7 54936004 bellard
 * modify it under the terms of the GNU Lesser General Public
8 54936004 bellard
 * License as published by the Free Software Foundation; either
9 54936004 bellard
 * version 2 of the License, or (at your option) any later version.
10 54936004 bellard
 *
11 54936004 bellard
 * This library is distributed in the hope that it will be useful,
12 54936004 bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 54936004 bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 54936004 bellard
 * Lesser General Public License for more details.
15 54936004 bellard
 *
16 54936004 bellard
 * You should have received a copy of the GNU Lesser General Public
17 54936004 bellard
 * License along with this library; if not, write to the Free Software
18 54936004 bellard
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 54936004 bellard
 */
20 54936004 bellard
#include <stdlib.h>
21 54936004 bellard
#include <stdio.h>
22 54936004 bellard
#include <stdarg.h>
23 54936004 bellard
#include <string.h>
24 54936004 bellard
#include <errno.h>
25 54936004 bellard
#include <unistd.h>
26 54936004 bellard
#include <inttypes.h>
27 fd6ce8f6 bellard
#include <sys/mman.h>
28 54936004 bellard
29 54936004 bellard
#include "cpu-i386.h"
30 54936004 bellard
31 fd6ce8f6 bellard
//#define DEBUG_TB_INVALIDATE
32 fd6ce8f6 bellard
#define DEBUG_FLUSH
33 fd6ce8f6 bellard
34 fd6ce8f6 bellard
/* make various TB consistency checks */
35 fd6ce8f6 bellard
//#define DEBUG_TB_CHECK 
36 fd6ce8f6 bellard
37 fd6ce8f6 bellard
/* threshold to flush the translated code buffer */
38 fd6ce8f6 bellard
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
39 fd6ce8f6 bellard
40 fd6ce8f6 bellard
#define CODE_GEN_MAX_BLOCKS    (CODE_GEN_BUFFER_SIZE / 64)
41 fd6ce8f6 bellard
42 fd6ce8f6 bellard
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
43 fd6ce8f6 bellard
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
44 fd6ce8f6 bellard
int nb_tbs;
45 eb51d102 bellard
/* any access to the tbs or the page table must use this lock */
46 eb51d102 bellard
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
47 fd6ce8f6 bellard
48 fd6ce8f6 bellard
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
49 fd6ce8f6 bellard
uint8_t *code_gen_ptr;
50 fd6ce8f6 bellard
51 54936004 bellard
/* XXX: pack the flags in the low bits of the pointer ? */
52 54936004 bellard
typedef struct PageDesc {
53 54936004 bellard
    unsigned long flags;
54 fd6ce8f6 bellard
    TranslationBlock *first_tb;
55 54936004 bellard
} PageDesc;
56 54936004 bellard
57 54936004 bellard
#define L2_BITS 10
58 54936004 bellard
#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
59 54936004 bellard
60 54936004 bellard
#define L1_SIZE (1 << L1_BITS)
61 54936004 bellard
#define L2_SIZE (1 << L2_BITS)
62 54936004 bellard
63 fd6ce8f6 bellard
static void tb_invalidate_page(unsigned long address);
64 fd6ce8f6 bellard
65 54936004 bellard
unsigned long real_host_page_size;
66 54936004 bellard
unsigned long host_page_bits;
67 54936004 bellard
unsigned long host_page_size;
68 54936004 bellard
unsigned long host_page_mask;
69 54936004 bellard
70 54936004 bellard
static PageDesc *l1_map[L1_SIZE];
71 54936004 bellard
72 54936004 bellard
void page_init(void)
73 54936004 bellard
{
74 54936004 bellard
    /* NOTE: we can always suppose that host_page_size >=
75 54936004 bellard
       TARGET_PAGE_SIZE */
76 54936004 bellard
    real_host_page_size = getpagesize();
77 54936004 bellard
    if (host_page_size == 0)
78 54936004 bellard
        host_page_size = real_host_page_size;
79 54936004 bellard
    if (host_page_size < TARGET_PAGE_SIZE)
80 54936004 bellard
        host_page_size = TARGET_PAGE_SIZE;
81 54936004 bellard
    host_page_bits = 0;
82 54936004 bellard
    while ((1 << host_page_bits) < host_page_size)
83 54936004 bellard
        host_page_bits++;
84 54936004 bellard
    host_page_mask = ~(host_page_size - 1);
85 54936004 bellard
}
86 54936004 bellard
87 54936004 bellard
/* dump memory mappings */
88 54936004 bellard
void page_dump(FILE *f)
89 54936004 bellard
{
90 54936004 bellard
    unsigned long start, end;
91 54936004 bellard
    int i, j, prot, prot1;
92 54936004 bellard
    PageDesc *p;
93 54936004 bellard
94 54936004 bellard
    fprintf(f, "%-8s %-8s %-8s %s\n",
95 54936004 bellard
            "start", "end", "size", "prot");
96 54936004 bellard
    start = -1;
97 54936004 bellard
    end = -1;
98 54936004 bellard
    prot = 0;
99 54936004 bellard
    for(i = 0; i <= L1_SIZE; i++) {
100 54936004 bellard
        if (i < L1_SIZE)
101 54936004 bellard
            p = l1_map[i];
102 54936004 bellard
        else
103 54936004 bellard
            p = NULL;
104 54936004 bellard
        for(j = 0;j < L2_SIZE; j++) {
105 54936004 bellard
            if (!p)
106 54936004 bellard
                prot1 = 0;
107 54936004 bellard
            else
108 54936004 bellard
                prot1 = p[j].flags;
109 54936004 bellard
            if (prot1 != prot) {
110 54936004 bellard
                end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
111 54936004 bellard
                if (start != -1) {
112 54936004 bellard
                    fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
113 54936004 bellard
                            start, end, end - start, 
114 54936004 bellard
                            prot & PAGE_READ ? 'r' : '-',
115 54936004 bellard
                            prot & PAGE_WRITE ? 'w' : '-',
116 54936004 bellard
                            prot & PAGE_EXEC ? 'x' : '-');
117 54936004 bellard
                }
118 54936004 bellard
                if (prot1 != 0)
119 54936004 bellard
                    start = end;
120 54936004 bellard
                else
121 54936004 bellard
                    start = -1;
122 54936004 bellard
                prot = prot1;
123 54936004 bellard
            }
124 54936004 bellard
            if (!p)
125 54936004 bellard
                break;
126 54936004 bellard
        }
127 54936004 bellard
    }
128 54936004 bellard
}
129 54936004 bellard
130 fd6ce8f6 bellard
static inline PageDesc *page_find_alloc(unsigned int index)
131 54936004 bellard
{
132 54936004 bellard
    PageDesc **lp, *p;
133 54936004 bellard
134 54936004 bellard
    lp = &l1_map[index >> L2_BITS];
135 54936004 bellard
    p = *lp;
136 54936004 bellard
    if (!p) {
137 54936004 bellard
        /* allocate if not found */
138 54936004 bellard
        p = malloc(sizeof(PageDesc) * L2_SIZE);
139 fd6ce8f6 bellard
        memset(p, 0, sizeof(PageDesc) * L2_SIZE);
140 54936004 bellard
        *lp = p;
141 54936004 bellard
    }
142 54936004 bellard
    return p + (index & (L2_SIZE - 1));
143 54936004 bellard
}
144 54936004 bellard
145 fd6ce8f6 bellard
static inline PageDesc *page_find(unsigned int index)
146 54936004 bellard
{
147 54936004 bellard
    PageDesc *p;
148 54936004 bellard
149 54936004 bellard
    p = l1_map[index >> L2_BITS];
150 54936004 bellard
    if (!p)
151 54936004 bellard
        return 0;
152 fd6ce8f6 bellard
    return p + (index & (L2_SIZE - 1));
153 fd6ce8f6 bellard
}
154 fd6ce8f6 bellard
155 fd6ce8f6 bellard
int page_get_flags(unsigned long address)
156 fd6ce8f6 bellard
{
157 fd6ce8f6 bellard
    PageDesc *p;
158 fd6ce8f6 bellard
159 fd6ce8f6 bellard
    p = page_find(address >> TARGET_PAGE_BITS);
160 fd6ce8f6 bellard
    if (!p)
161 fd6ce8f6 bellard
        return 0;
162 fd6ce8f6 bellard
    return p->flags;
163 54936004 bellard
}
164 54936004 bellard
165 fd6ce8f6 bellard
/* modify the flags of a page and invalidate the code if
166 fd6ce8f6 bellard
   necessary. The flag PAGE_WRITE_ORG is positionned automatically
167 fd6ce8f6 bellard
   depending on PAGE_WRITE */
168 54936004 bellard
void page_set_flags(unsigned long start, unsigned long end, int flags)
169 54936004 bellard
{
170 54936004 bellard
    PageDesc *p;
171 54936004 bellard
    unsigned long addr;
172 54936004 bellard
173 54936004 bellard
    start = start & TARGET_PAGE_MASK;
174 54936004 bellard
    end = TARGET_PAGE_ALIGN(end);
175 fd6ce8f6 bellard
    if (flags & PAGE_WRITE)
176 fd6ce8f6 bellard
        flags |= PAGE_WRITE_ORG;
177 eb51d102 bellard
    spin_lock(&tb_lock);
178 54936004 bellard
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
179 fd6ce8f6 bellard
        p = page_find_alloc(addr >> TARGET_PAGE_BITS);
180 fd6ce8f6 bellard
        /* if the write protection is set, then we invalidate the code
181 fd6ce8f6 bellard
           inside */
182 fd6ce8f6 bellard
        if (!(p->flags & PAGE_WRITE) && 
183 fd6ce8f6 bellard
            (flags & PAGE_WRITE) &&
184 fd6ce8f6 bellard
            p->first_tb) {
185 fd6ce8f6 bellard
            tb_invalidate_page(addr);
186 fd6ce8f6 bellard
        }
187 54936004 bellard
        p->flags = flags;
188 54936004 bellard
    }
189 eb51d102 bellard
    spin_unlock(&tb_lock);
190 54936004 bellard
}
191 fd6ce8f6 bellard
192 fd6ce8f6 bellard
void cpu_x86_tblocks_init(void)
193 fd6ce8f6 bellard
{
194 fd6ce8f6 bellard
    if (!code_gen_ptr) {
195 fd6ce8f6 bellard
        code_gen_ptr = code_gen_buffer;
196 fd6ce8f6 bellard
    }
197 fd6ce8f6 bellard
}
198 fd6ce8f6 bellard
199 fd6ce8f6 bellard
/* set to NULL all the 'first_tb' fields in all PageDescs */
200 fd6ce8f6 bellard
static void page_flush_tb(void)
201 fd6ce8f6 bellard
{
202 fd6ce8f6 bellard
    int i, j;
203 fd6ce8f6 bellard
    PageDesc *p;
204 fd6ce8f6 bellard
205 fd6ce8f6 bellard
    for(i = 0; i < L1_SIZE; i++) {
206 fd6ce8f6 bellard
        p = l1_map[i];
207 fd6ce8f6 bellard
        if (p) {
208 fd6ce8f6 bellard
            for(j = 0; j < L2_SIZE; j++)
209 fd6ce8f6 bellard
                p[j].first_tb = NULL;
210 fd6ce8f6 bellard
        }
211 fd6ce8f6 bellard
    }
212 fd6ce8f6 bellard
}
213 fd6ce8f6 bellard
214 fd6ce8f6 bellard
/* flush all the translation blocks */
215 fd6ce8f6 bellard
void tb_flush(void)
216 fd6ce8f6 bellard
{
217 fd6ce8f6 bellard
    int i;
218 fd6ce8f6 bellard
#ifdef DEBUG_FLUSH
219 fd6ce8f6 bellard
    printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
220 fd6ce8f6 bellard
           code_gen_ptr - code_gen_buffer, 
221 fd6ce8f6 bellard
           nb_tbs, 
222 fd6ce8f6 bellard
           (code_gen_ptr - code_gen_buffer) / nb_tbs);
223 fd6ce8f6 bellard
#endif
224 fd6ce8f6 bellard
    nb_tbs = 0;
225 fd6ce8f6 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
226 fd6ce8f6 bellard
        tb_hash[i] = NULL;
227 fd6ce8f6 bellard
    page_flush_tb();
228 fd6ce8f6 bellard
    code_gen_ptr = code_gen_buffer;
229 fd6ce8f6 bellard
    /* XXX: flush processor icache at this point */
230 fd6ce8f6 bellard
}
231 fd6ce8f6 bellard
232 fd6ce8f6 bellard
#ifdef DEBUG_TB_CHECK
233 fd6ce8f6 bellard
234 fd6ce8f6 bellard
static void tb_invalidate_check(unsigned long address)
235 fd6ce8f6 bellard
{
236 fd6ce8f6 bellard
    TranslationBlock *tb;
237 fd6ce8f6 bellard
    int i;
238 fd6ce8f6 bellard
    address &= TARGET_PAGE_MASK;
239 fd6ce8f6 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
240 fd6ce8f6 bellard
        for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
241 fd6ce8f6 bellard
            if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
242 fd6ce8f6 bellard
                  address >= tb->pc + tb->size)) {
243 fd6ce8f6 bellard
                printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
244 fd6ce8f6 bellard
                       address, tb->pc, tb->size);
245 fd6ce8f6 bellard
            }
246 fd6ce8f6 bellard
        }
247 fd6ce8f6 bellard
    }
248 fd6ce8f6 bellard
}
249 fd6ce8f6 bellard
250 fd6ce8f6 bellard
/* verify that all the pages have correct rights for code */
251 fd6ce8f6 bellard
static void tb_page_check(void)
252 fd6ce8f6 bellard
{
253 fd6ce8f6 bellard
    TranslationBlock *tb;
254 fd6ce8f6 bellard
    int i, flags1, flags2;
255 fd6ce8f6 bellard
    
256 fd6ce8f6 bellard
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
257 fd6ce8f6 bellard
        for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
258 fd6ce8f6 bellard
            flags1 = page_get_flags(tb->pc);
259 fd6ce8f6 bellard
            flags2 = page_get_flags(tb->pc + tb->size - 1);
260 fd6ce8f6 bellard
            if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
261 fd6ce8f6 bellard
                printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
262 fd6ce8f6 bellard
                       tb->pc, tb->size, flags1, flags2);
263 fd6ce8f6 bellard
            }
264 fd6ce8f6 bellard
        }
265 fd6ce8f6 bellard
    }
266 fd6ce8f6 bellard
}
267 fd6ce8f6 bellard
268 fd6ce8f6 bellard
#endif
269 fd6ce8f6 bellard
270 fd6ce8f6 bellard
/* invalidate one TB */
271 fd6ce8f6 bellard
static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
272 fd6ce8f6 bellard
                             int next_offset)
273 fd6ce8f6 bellard
{
274 fd6ce8f6 bellard
    TranslationBlock *tb1;
275 fd6ce8f6 bellard
    for(;;) {
276 fd6ce8f6 bellard
        tb1 = *ptb;
277 fd6ce8f6 bellard
        if (tb1 == tb) {
278 fd6ce8f6 bellard
            *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
279 fd6ce8f6 bellard
            break;
280 fd6ce8f6 bellard
        }
281 fd6ce8f6 bellard
        ptb = (TranslationBlock **)((char *)tb1 + next_offset);
282 fd6ce8f6 bellard
    }
283 fd6ce8f6 bellard
}
284 fd6ce8f6 bellard
285 fd6ce8f6 bellard
static inline void tb_invalidate(TranslationBlock *tb, int parity)
286 fd6ce8f6 bellard
{
287 fd6ce8f6 bellard
    PageDesc *p;
288 fd6ce8f6 bellard
    unsigned int page_index1, page_index2;
289 fd6ce8f6 bellard
    unsigned int h;
290 fd6ce8f6 bellard
291 fd6ce8f6 bellard
    /* remove the TB from the hash list */
292 fd6ce8f6 bellard
    h = tb_hash_func(tb->pc);
293 fd6ce8f6 bellard
    tb_remove(&tb_hash[h], tb, 
294 fd6ce8f6 bellard
              offsetof(TranslationBlock, hash_next));
295 fd6ce8f6 bellard
    /* remove the TB from the page list */
296 fd6ce8f6 bellard
    page_index1 = tb->pc >> TARGET_PAGE_BITS;
297 fd6ce8f6 bellard
    if ((page_index1 & 1) == parity) {
298 fd6ce8f6 bellard
        p = page_find(page_index1);
299 fd6ce8f6 bellard
        tb_remove(&p->first_tb, tb, 
300 fd6ce8f6 bellard
                  offsetof(TranslationBlock, page_next[page_index1 & 1]));
301 fd6ce8f6 bellard
    }
302 fd6ce8f6 bellard
    page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
303 fd6ce8f6 bellard
    if ((page_index2 & 1) == parity) {
304 fd6ce8f6 bellard
        p = page_find(page_index2);
305 fd6ce8f6 bellard
        tb_remove(&p->first_tb, tb, 
306 fd6ce8f6 bellard
                  offsetof(TranslationBlock, page_next[page_index2 & 1]));
307 fd6ce8f6 bellard
    }
308 fd6ce8f6 bellard
}
309 fd6ce8f6 bellard
310 fd6ce8f6 bellard
/* invalidate all TBs which intersect with the target page starting at addr */
311 fd6ce8f6 bellard
static void tb_invalidate_page(unsigned long address)
312 fd6ce8f6 bellard
{
313 fd6ce8f6 bellard
    TranslationBlock *tb_next, *tb;
314 fd6ce8f6 bellard
    unsigned int page_index;
315 fd6ce8f6 bellard
    int parity1, parity2;
316 fd6ce8f6 bellard
    PageDesc *p;
317 fd6ce8f6 bellard
#ifdef DEBUG_TB_INVALIDATE
318 fd6ce8f6 bellard
    printf("tb_invalidate_page: %lx\n", address);
319 fd6ce8f6 bellard
#endif
320 fd6ce8f6 bellard
321 fd6ce8f6 bellard
    page_index = address >> TARGET_PAGE_BITS;
322 fd6ce8f6 bellard
    p = page_find(page_index);
323 fd6ce8f6 bellard
    if (!p)
324 fd6ce8f6 bellard
        return;
325 fd6ce8f6 bellard
    tb = p->first_tb;
326 fd6ce8f6 bellard
    parity1 = page_index & 1;
327 fd6ce8f6 bellard
    parity2 = parity1 ^ 1;
328 fd6ce8f6 bellard
    while (tb != NULL) {
329 fd6ce8f6 bellard
        tb_next = tb->page_next[parity1];
330 fd6ce8f6 bellard
        tb_invalidate(tb, parity2);
331 fd6ce8f6 bellard
        tb = tb_next;
332 fd6ce8f6 bellard
    }
333 fd6ce8f6 bellard
    p->first_tb = NULL;
334 fd6ce8f6 bellard
}
335 fd6ce8f6 bellard
336 fd6ce8f6 bellard
/* add the tb in the target page and protect it if necessary */
337 fd6ce8f6 bellard
static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
338 fd6ce8f6 bellard
{
339 fd6ce8f6 bellard
    PageDesc *p;
340 fd6ce8f6 bellard
    unsigned long host_start, host_end, addr, page_addr;
341 fd6ce8f6 bellard
    int prot;
342 fd6ce8f6 bellard
343 fd6ce8f6 bellard
    p = page_find_alloc(page_index);
344 fd6ce8f6 bellard
    tb->page_next[page_index & 1] = p->first_tb;
345 fd6ce8f6 bellard
    p->first_tb = tb;
346 fd6ce8f6 bellard
    if (p->flags & PAGE_WRITE) {
347 fd6ce8f6 bellard
        /* force the host page as non writable (writes will have a
348 fd6ce8f6 bellard
           page fault + mprotect overhead) */
349 fd6ce8f6 bellard
        page_addr = (page_index << TARGET_PAGE_BITS);
350 fd6ce8f6 bellard
        host_start = page_addr & host_page_mask;
351 fd6ce8f6 bellard
        host_end = host_start + host_page_size;
352 fd6ce8f6 bellard
        prot = 0;
353 fd6ce8f6 bellard
        for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
354 fd6ce8f6 bellard
            prot |= page_get_flags(addr);
355 fd6ce8f6 bellard
        mprotect((void *)host_start, host_page_size, 
356 fd6ce8f6 bellard
                 (prot & PAGE_BITS) & ~PAGE_WRITE);
357 fd6ce8f6 bellard
#ifdef DEBUG_TB_INVALIDATE
358 fd6ce8f6 bellard
        printf("protecting code page: 0x%08lx\n", 
359 fd6ce8f6 bellard
               host_start);
360 fd6ce8f6 bellard
#endif
361 fd6ce8f6 bellard
        p->flags &= ~PAGE_WRITE;
362 fd6ce8f6 bellard
#ifdef DEBUG_TB_CHECK
363 fd6ce8f6 bellard
        tb_page_check();
364 fd6ce8f6 bellard
#endif
365 fd6ce8f6 bellard
    }
366 fd6ce8f6 bellard
}
367 fd6ce8f6 bellard
368 fd6ce8f6 bellard
/* Allocate a new translation block. Flush the translation buffer if
369 fd6ce8f6 bellard
   too many translation blocks or too much generated code. */
370 fd6ce8f6 bellard
TranslationBlock *tb_alloc(unsigned long pc, 
371 fd6ce8f6 bellard
                           unsigned long size)
372 fd6ce8f6 bellard
{
373 fd6ce8f6 bellard
    TranslationBlock *tb;
374 fd6ce8f6 bellard
    unsigned int page_index1, page_index2;
375 fd6ce8f6 bellard
376 fd6ce8f6 bellard
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
377 fd6ce8f6 bellard
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
378 fd6ce8f6 bellard
        tb_flush();
379 fd6ce8f6 bellard
    tb = &tbs[nb_tbs++];
380 fd6ce8f6 bellard
    tb->pc = pc;
381 fd6ce8f6 bellard
    tb->size = size;
382 fd6ce8f6 bellard
383 fd6ce8f6 bellard
    /* add in the page list */
384 fd6ce8f6 bellard
    page_index1 = pc >> TARGET_PAGE_BITS;
385 fd6ce8f6 bellard
    tb_alloc_page(tb, page_index1);
386 fd6ce8f6 bellard
    page_index2 = (pc + size - 1) >> TARGET_PAGE_BITS;
387 fd6ce8f6 bellard
    if (page_index2 != page_index1) {
388 fd6ce8f6 bellard
        tb_alloc_page(tb, page_index2);
389 fd6ce8f6 bellard
    }
390 fd6ce8f6 bellard
    return tb;
391 fd6ce8f6 bellard
}
392 fd6ce8f6 bellard
393 fd6ce8f6 bellard
/* called from signal handler: invalidate the code and unprotect the
394 fd6ce8f6 bellard
   page. Return TRUE if the fault was succesfully handled. */
395 fd6ce8f6 bellard
int page_unprotect(unsigned long address)
396 fd6ce8f6 bellard
{
397 fd6ce8f6 bellard
    unsigned int page_index, prot;
398 fd6ce8f6 bellard
    PageDesc *p;
399 fd6ce8f6 bellard
    unsigned long host_start, host_end, addr;
400 fd6ce8f6 bellard
401 fd6ce8f6 bellard
    page_index = address >> TARGET_PAGE_BITS;
402 fd6ce8f6 bellard
    p = page_find(page_index);
403 fd6ce8f6 bellard
    if (!p)
404 fd6ce8f6 bellard
        return 0;
405 fd6ce8f6 bellard
    if ((p->flags & (PAGE_WRITE_ORG | PAGE_WRITE)) == PAGE_WRITE_ORG) {
406 fd6ce8f6 bellard
        /* if the page was really writable, then we change its
407 fd6ce8f6 bellard
           protection back to writable */
408 fd6ce8f6 bellard
        host_start = address & host_page_mask;
409 fd6ce8f6 bellard
        host_end = host_start + host_page_size;
410 fd6ce8f6 bellard
        prot = 0;
411 fd6ce8f6 bellard
        for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
412 fd6ce8f6 bellard
            prot |= page_get_flags(addr);
413 fd6ce8f6 bellard
        mprotect((void *)host_start, host_page_size, 
414 fd6ce8f6 bellard
                 (prot & PAGE_BITS) | PAGE_WRITE);
415 fd6ce8f6 bellard
        p->flags |= PAGE_WRITE;
416 fd6ce8f6 bellard
417 fd6ce8f6 bellard
        /* and since the content will be modified, we must invalidate
418 fd6ce8f6 bellard
           the corresponding translated code. */
419 fd6ce8f6 bellard
        tb_invalidate_page(address);
420 fd6ce8f6 bellard
#ifdef DEBUG_TB_CHECK
421 fd6ce8f6 bellard
        tb_invalidate_check(address);
422 fd6ce8f6 bellard
#endif
423 fd6ce8f6 bellard
        return 1;
424 fd6ce8f6 bellard
    } else {
425 fd6ce8f6 bellard
        return 0;
426 fd6ce8f6 bellard
    }
427 fd6ce8f6 bellard
}
428 fd6ce8f6 bellard
429 fd6ce8f6 bellard
/* call this function when system calls directly modify a memory area */
430 fd6ce8f6 bellard
void page_unprotect_range(uint8_t *data, unsigned long data_size)
431 fd6ce8f6 bellard
{
432 fd6ce8f6 bellard
    unsigned long start, end, addr;
433 fd6ce8f6 bellard
434 fd6ce8f6 bellard
    start = (unsigned long)data;
435 fd6ce8f6 bellard
    end = start + data_size;
436 fd6ce8f6 bellard
    start &= TARGET_PAGE_MASK;
437 fd6ce8f6 bellard
    end = TARGET_PAGE_ALIGN(end);
438 fd6ce8f6 bellard
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
439 fd6ce8f6 bellard
        page_unprotect(addr);
440 fd6ce8f6 bellard
    }
441 fd6ce8f6 bellard
}