Commit fd6ce8f6604359e60283e6d4dfc935ca57c556e5

Authored by bellard
1 parent 727d01d4

self-modifying code support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@163 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 3 changed files with 400 additions and 123 deletions
cpu-i386.h
... ... @@ -445,16 +445,21 @@ extern unsigned long host_page_mask;
445 445 #define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
446 446  
447 447 /* same as PROT_xxx */
448   -#define PAGE_READ 0x0001
449   -#define PAGE_WRITE 0x0002
450   -#define PAGE_EXEC 0x0004
451   -#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
452   -#define PAGE_VALID 0x0008
  448 +#define PAGE_READ 0x0001
  449 +#define PAGE_WRITE 0x0002
  450 +#define PAGE_EXEC 0x0004
  451 +#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
  452 +#define PAGE_VALID 0x0008
  453 +/* original state of the write flag (used when tracking self-modifying
  454 + code */
  455 +#define PAGE_WRITE_ORG 0x0010
453 456  
454 457 void page_dump(FILE *f);
455 458 int page_get_flags(unsigned long address);
456 459 void page_set_flags(unsigned long start, unsigned long end, int flags);
  460 +void page_unprotect_range(uint8_t *data, unsigned long data_size);
457 461  
  462 +/***************************************************/
458 463 /* internal functions */
459 464  
460 465 #define GEN_FLAG_CODE32_SHIFT 0
... ... @@ -468,8 +473,73 @@ void page_set_flags(unsigned long start, unsigned long end, int flags);
468 473  
469 474 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
470 475 int *gen_code_size_ptr,
471   - uint8_t *pc_start, uint8_t *cs_base, int flags);
  476 + uint8_t *pc_start, uint8_t *cs_base, int flags,
  477 + int *code_size_ptr);
472 478 void cpu_x86_tblocks_init(void);
473 479 void page_init(void);
  480 +int page_unprotect(unsigned long address);
  481 +
  482 +#define CODE_GEN_MAX_SIZE 65536
  483 +#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
  484 +
  485 +#define CODE_GEN_HASH_BITS 15
  486 +#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
  487 +
  488 +/* maximum total translate dcode allocated */
  489 +#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
  490 +//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
  491 +
  492 +typedef struct TranslationBlock {
  493 + unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
  494 + unsigned long cs_base; /* CS base for this block */
  495 + unsigned int flags; /* flags defining in which context the code was generated */
  496 + uint16_t size; /* size of target code for this block (1 <=
  497 + size <= TARGET_PAGE_SIZE) */
  498 + uint8_t *tc_ptr; /* pointer to the translated code */
  499 + struct TranslationBlock *hash_next; /* next matching block */
  500 + struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */
  501 +} TranslationBlock;
  502 +
  503 +static inline unsigned int tb_hash_func(unsigned long pc)
  504 +{
  505 + return pc & (CODE_GEN_HASH_SIZE - 1);
  506 +}
  507 +
  508 +void tb_flush(void);
  509 +TranslationBlock *tb_alloc(unsigned long pc,
  510 + unsigned long size);
  511 +
  512 +extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
  513 +
  514 +extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
  515 +extern uint8_t *code_gen_ptr;
  516 +
  517 +/* find a translation block in the translation cache. If not found,
  518 + return NULL and the pointer to the last element of the list in pptb */
  519 +static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
  520 + unsigned long pc,
  521 + unsigned long cs_base,
  522 + unsigned int flags)
  523 +{
  524 + TranslationBlock **ptb, *tb;
  525 + unsigned int h;
  526 +
  527 + h = tb_hash_func(pc);
  528 + ptb = &tb_hash[h];
  529 + for(;;) {
  530 + tb = *ptb;
  531 + if (!tb)
  532 + break;
  533 + if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
  534 + return tb;
  535 + ptb = &tb->hash_next;
  536 + }
  537 + *pptb = ptb;
  538 + return NULL;
  539 +}
  540 +
  541 +#ifndef offsetof
  542 +#define offsetof(type, field) ((size_t) &((type *)0)->field)
  543 +#endif
474 544  
475 545 #endif /* CPU_I386_H */
... ...
exec-i386.c
... ... @@ -21,39 +21,10 @@
21 21 #include "disas.h"
22 22  
23 23 //#define DEBUG_EXEC
24   -#define DEBUG_FLUSH
25 24 //#define DEBUG_SIGNAL
26 25  
27 26 /* main execution loop */
28 27  
29   -/* maximum total translate dcode allocated */
30   -#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
31   -//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
32   -#define CODE_GEN_MAX_SIZE 65536
33   -#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
34   -
35   -/* threshold to flush the translated code buffer */
36   -#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
37   -
38   -#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64)
39   -#define CODE_GEN_HASH_BITS 15
40   -#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
41   -
42   -typedef struct TranslationBlock {
43   - unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
44   - unsigned long cs_base; /* CS base for this block */
45   - unsigned int flags; /* flags defining in which context the code was generated */
46   - uint8_t *tc_ptr; /* pointer to the translated code */
47   - struct TranslationBlock *hash_next; /* next matching block */
48   -} TranslationBlock;
49   -
50   -TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
51   -TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
52   -int nb_tbs;
53   -
54   -uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
55   -uint8_t *code_gen_ptr;
56   -
57 28 /* thread support */
58 29  
59 30 #ifdef __powerpc__
... ... @@ -195,70 +166,6 @@ void raise_exception(int exception_index)
195 166 raise_exception_err(exception_index, 0);
196 167 }
197 168  
198   -void cpu_x86_tblocks_init(void)
199   -{
200   - if (!code_gen_ptr) {
201   - code_gen_ptr = code_gen_buffer;
202   - }
203   -}
204   -
205   -/* flush all the translation blocks */
206   -static void tb_flush(void)
207   -{
208   - int i;
209   -#ifdef DEBUG_FLUSH
210   - printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
211   - code_gen_ptr - code_gen_buffer,
212   - nb_tbs,
213   - (code_gen_ptr - code_gen_buffer) / nb_tbs);
214   -#endif
215   - nb_tbs = 0;
216   - for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
217   - tb_hash[i] = NULL;
218   - code_gen_ptr = code_gen_buffer;
219   - /* XXX: flush processor icache at this point */
220   -}
221   -
222   -/* find a translation block in the translation cache. If not found,
223   - return NULL and the pointer to the last element of the list in pptb */
224   -static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
225   - unsigned long pc,
226   - unsigned long cs_base,
227   - unsigned int flags)
228   -{
229   - TranslationBlock **ptb, *tb;
230   - unsigned int h;
231   -
232   - h = pc & (CODE_GEN_HASH_SIZE - 1);
233   - ptb = &tb_hash[h];
234   -#if 0
235   - /* XXX: hack to handle 16 bit modyfing code */
236   - if (flags & (1 << GEN_FLAG_CODE32_SHIFT))
237   -#endif
238   - for(;;) {
239   - tb = *ptb;
240   - if (!tb)
241   - break;
242   - if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
243   - return tb;
244   - ptb = &tb->hash_next;
245   - }
246   - *pptb = ptb;
247   - return NULL;
248   -}
249   -
250   -/* allocate a new translation block. flush the translation buffer if
251   - too many translation blocks or too much generated code */
252   -static inline TranslationBlock *tb_alloc(void)
253   -{
254   - TranslationBlock *tb;
255   - if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
256   - (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
257   - tb_flush();
258   - tb = &tbs[nb_tbs++];
259   - return tb;
260   -}
261   -
262 169 int cpu_x86_exec(CPUX86State *env1)
263 170 {
264 171 int saved_T0, saved_T1, saved_A0;
... ... @@ -287,7 +194,7 @@ int cpu_x86_exec(CPUX86State *env1)
287 194 #ifdef reg_EDI
288 195 int saved_EDI;
289 196 #endif
290   - int code_gen_size, ret;
  197 + int code_gen_size, ret, code_size;
291 198 void (*gen_func)(void);
292 199 TranslationBlock *tb, **ptb;
293 200 uint8_t *tc_ptr, *cs_base, *pc;
... ... @@ -390,15 +297,15 @@ int cpu_x86_exec(CPUX86State *env1)
390 297 cpu_lock();
391 298 tc_ptr = code_gen_ptr;
392 299 ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
393   - &code_gen_size, pc, cs_base, flags);
  300 + &code_gen_size, pc, cs_base, flags,
  301 + &code_size);
394 302 /* if invalid instruction, signal it */
395 303 if (ret != 0) {
396 304 cpu_unlock();
397 305 raise_exception(EXCP06_ILLOP);
398 306 }
399   - tb = tb_alloc();
  307 + tb = tb_alloc((unsigned long)pc, code_size);
400 308 *ptb = tb;
401   - tb->pc = (unsigned long)pc;
402 309 tb->cs_base = (unsigned long)cs_base;
403 310 tb->flags = flags;
404 311 tb->tc_ptr = tc_ptr;
... ... @@ -493,15 +400,22 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
493 400 #include <sys/ucontext.h>
494 401  
495 402 /* 'pc' is the host PC at which the exception was raised. 'address' is
496   - the effective address of the memory exception */
  403 + the effective address of the memory exception. 'is_write' is 1 if a
  404 + write caused the exception and otherwise 0'. 'old_set' is the
  405 + signal set which should be restored */
497 406 static inline int handle_cpu_signal(unsigned long pc,
498 407 unsigned long address,
  408 + int is_write,
499 409 sigset_t *old_set)
500 410 {
501   -#ifdef DEBUG_SIGNAL
502   - printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
503   - pc, *(unsigned long *)old_set);
  411 +#if defined(DEBUG_SIGNAL)
  412 + printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n",
  413 + pc, address, is_write, *(unsigned long *)old_set);
504 414 #endif
  415 + if (is_write && page_unprotect(address)) {
  416 + sigprocmask(SIG_SETMASK, old_set, NULL);
  417 + return 1;
  418 + }
505 419 if (pc >= (unsigned long)code_gen_buffer &&
506 420 pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
507 421 /* the PC is inside the translated code. It means that we have
... ... @@ -512,8 +426,7 @@ static inline int handle_cpu_signal(unsigned long pc,
512 426 /* XXX: need to compute virtual pc position by retranslating
513 427 code. The rest of the CPU state should be correct. */
514 428 env->cr2 = address;
515   - /* XXX: more precise exception code */
516   - raise_exception_err(EXCP0E_PAGE, 4);
  429 + raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
517 430 /* never comes here */
518 431 return 1;
519 432 } else {
... ... @@ -531,11 +444,16 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
531 444  
532 445 #ifndef REG_EIP
533 446 /* for glibc 2.1 */
534   -#define REG_EIP EIP
  447 +#define REG_EIP EIP
  448 +#define REG_ERR ERR
  449 +#define REG_TRAPNO TRAPNO
535 450 #endif
536 451 pc = uc->uc_mcontext.gregs[REG_EIP];
537 452 pold_set = &uc->uc_sigmask;
538   - return handle_cpu_signal(pc, (unsigned long)info->si_addr, pold_set);
  453 + return handle_cpu_signal(pc, (unsigned long)info->si_addr,
  454 + uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
  455 + (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
  456 + pold_set);
539 457 #else
540 458 #warning No CPU specific signal handler: cannot handle target SIGSEGV events
541 459 return 0;
... ...
1 1 /*
2   - * virtual page mapping
  2 + * virtual page mapping and translated block handling
3 3 *
4 4 * Copyright (c) 2003 Fabrice Bellard
5 5 *
... ... @@ -24,13 +24,32 @@
24 24 #include <errno.h>
25 25 #include <unistd.h>
26 26 #include <inttypes.h>
  27 +#include <sys/mman.h>
27 28  
28 29 #include "cpu-i386.h"
29 30  
  31 +//#define DEBUG_TB_INVALIDATE
  32 +#define DEBUG_FLUSH
  33 +
  34 +/* make various TB consistency checks */
  35 +//#define DEBUG_TB_CHECK
  36 +
  37 +/* threshold to flush the translated code buffer */
  38 +#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
  39 +
  40 +#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64)
  41 +
  42 +TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
  43 +TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
  44 +int nb_tbs;
  45 +
  46 +uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
  47 +uint8_t *code_gen_ptr;
  48 +
30 49 /* XXX: pack the flags in the low bits of the pointer ? */
31 50 typedef struct PageDesc {
32   - struct TranslationBlock *first_tb;
33 51 unsigned long flags;
  52 + TranslationBlock *first_tb;
34 53 } PageDesc;
35 54  
36 55 #define L2_BITS 10
... ... @@ -39,6 +58,8 @@ typedef struct PageDesc {
39 58 #define L1_SIZE (1 << L1_BITS)
40 59 #define L2_SIZE (1 << L2_BITS)
41 60  
  61 +static void tb_invalidate_page(unsigned long address);
  62 +
42 63 unsigned long real_host_page_size;
43 64 unsigned long host_page_bits;
44 65 unsigned long host_page_size;
... ... @@ -104,36 +125,44 @@ void page_dump(FILE *f)
104 125 }
105 126 }
106 127  
107   -
108   -static inline PageDesc *page_find_alloc(unsigned long address)
  128 +static inline PageDesc *page_find_alloc(unsigned int index)
109 129 {
110   - unsigned int index;
111 130 PageDesc **lp, *p;
112 131  
113   - index = address >> TARGET_PAGE_BITS;
114 132 lp = &l1_map[index >> L2_BITS];
115 133 p = *lp;
116 134 if (!p) {
117 135 /* allocate if not found */
118 136 p = malloc(sizeof(PageDesc) * L2_SIZE);
119   - memset(p, 0, sizeof(sizeof(PageDesc) * L2_SIZE));
  137 + memset(p, 0, sizeof(PageDesc) * L2_SIZE);
120 138 *lp = p;
121 139 }
122 140 return p + (index & (L2_SIZE - 1));
123 141 }
124 142  
125   -int page_get_flags(unsigned long address)
  143 +static inline PageDesc *page_find(unsigned int index)
126 144 {
127   - unsigned int index;
128 145 PageDesc *p;
129 146  
130   - index = address >> TARGET_PAGE_BITS;
131 147 p = l1_map[index >> L2_BITS];
132 148 if (!p)
133 149 return 0;
134   - return p[index & (L2_SIZE - 1)].flags;
  150 + return p + (index & (L2_SIZE - 1));
  151 +}
  152 +
  153 +int page_get_flags(unsigned long address)
  154 +{
  155 + PageDesc *p;
  156 +
  157 + p = page_find(address >> TARGET_PAGE_BITS);
  158 + if (!p)
  159 + return 0;
  160 + return p->flags;
135 161 }
136 162  
  163 +/* modify the flags of a page and invalidate the code if
  164 + necessary. The flag PAGE_WRITE_ORG is positionned automatically
  165 + depending on PAGE_WRITE */
137 166 void page_set_flags(unsigned long start, unsigned long end, int flags)
138 167 {
139 168 PageDesc *p;
... ... @@ -141,8 +170,268 @@ void page_set_flags(unsigned long start, unsigned long end, int flags)
141 170  
142 171 start = start & TARGET_PAGE_MASK;
143 172 end = TARGET_PAGE_ALIGN(end);
  173 + if (flags & PAGE_WRITE)
  174 + flags |= PAGE_WRITE_ORG;
144 175 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
145   - p = page_find_alloc(addr);
  176 + p = page_find_alloc(addr >> TARGET_PAGE_BITS);
  177 + /* if the write protection is set, then we invalidate the code
  178 + inside */
  179 + if (!(p->flags & PAGE_WRITE) &&
  180 + (flags & PAGE_WRITE) &&
  181 + p->first_tb) {
  182 + tb_invalidate_page(addr);
  183 + }
146 184 p->flags = flags;
147 185 }
148 186 }
  187 +
  188 +void cpu_x86_tblocks_init(void)
  189 +{
  190 + if (!code_gen_ptr) {
  191 + code_gen_ptr = code_gen_buffer;
  192 + }
  193 +}
  194 +
  195 +/* set to NULL all the 'first_tb' fields in all PageDescs */
  196 +static void page_flush_tb(void)
  197 +{
  198 + int i, j;
  199 + PageDesc *p;
  200 +
  201 + for(i = 0; i < L1_SIZE; i++) {
  202 + p = l1_map[i];
  203 + if (p) {
  204 + for(j = 0; j < L2_SIZE; j++)
  205 + p[j].first_tb = NULL;
  206 + }
  207 + }
  208 +}
  209 +
  210 +/* flush all the translation blocks */
  211 +void tb_flush(void)
  212 +{
  213 + int i;
  214 +#ifdef DEBUG_FLUSH
  215 + printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
  216 + code_gen_ptr - code_gen_buffer,
  217 + nb_tbs,
  218 + (code_gen_ptr - code_gen_buffer) / nb_tbs);
  219 +#endif
  220 + nb_tbs = 0;
  221 + for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
  222 + tb_hash[i] = NULL;
  223 + page_flush_tb();
  224 + code_gen_ptr = code_gen_buffer;
  225 + /* XXX: flush processor icache at this point */
  226 +}
  227 +
  228 +#ifdef DEBUG_TB_CHECK
  229 +
  230 +static void tb_invalidate_check(unsigned long address)
  231 +{
  232 + TranslationBlock *tb;
  233 + int i;
  234 + address &= TARGET_PAGE_MASK;
  235 + for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
  236 + for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
  237 + if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
  238 + address >= tb->pc + tb->size)) {
  239 + printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
  240 + address, tb->pc, tb->size);
  241 + }
  242 + }
  243 + }
  244 +}
  245 +
  246 +/* verify that all the pages have correct rights for code */
  247 +static void tb_page_check(void)
  248 +{
  249 + TranslationBlock *tb;
  250 + int i, flags1, flags2;
  251 +
  252 + for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
  253 + for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
  254 + flags1 = page_get_flags(tb->pc);
  255 + flags2 = page_get_flags(tb->pc + tb->size - 1);
  256 + if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
  257 + printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
  258 + tb->pc, tb->size, flags1, flags2);
  259 + }
  260 + }
  261 + }
  262 +}
  263 +
  264 +#endif
  265 +
  266 +/* invalidate one TB */
  267 +static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
  268 + int next_offset)
  269 +{
  270 + TranslationBlock *tb1;
  271 + for(;;) {
  272 + tb1 = *ptb;
  273 + if (tb1 == tb) {
  274 + *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
  275 + break;
  276 + }
  277 + ptb = (TranslationBlock **)((char *)tb1 + next_offset);
  278 + }
  279 +}
  280 +
  281 +static inline void tb_invalidate(TranslationBlock *tb, int parity)
  282 +{
  283 + PageDesc *p;
  284 + unsigned int page_index1, page_index2;
  285 + unsigned int h;
  286 +
  287 + /* remove the TB from the hash list */
  288 + h = tb_hash_func(tb->pc);
  289 + tb_remove(&tb_hash[h], tb,
  290 + offsetof(TranslationBlock, hash_next));
  291 + /* remove the TB from the page list */
  292 + page_index1 = tb->pc >> TARGET_PAGE_BITS;
  293 + if ((page_index1 & 1) == parity) {
  294 + p = page_find(page_index1);
  295 + tb_remove(&p->first_tb, tb,
  296 + offsetof(TranslationBlock, page_next[page_index1 & 1]));
  297 + }
  298 + page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
  299 + if ((page_index2 & 1) == parity) {
  300 + p = page_find(page_index2);
  301 + tb_remove(&p->first_tb, tb,
  302 + offsetof(TranslationBlock, page_next[page_index2 & 1]));
  303 + }
  304 +}
  305 +
  306 +/* invalidate all TBs which intersect with the target page starting at addr */
  307 +static void tb_invalidate_page(unsigned long address)
  308 +{
  309 + TranslationBlock *tb_next, *tb;
  310 + unsigned int page_index;
  311 + int parity1, parity2;
  312 + PageDesc *p;
  313 +#ifdef DEBUG_TB_INVALIDATE
  314 + printf("tb_invalidate_page: %lx\n", address);
  315 +#endif
  316 +
  317 + page_index = address >> TARGET_PAGE_BITS;
  318 + p = page_find(page_index);
  319 + if (!p)
  320 + return;
  321 + tb = p->first_tb;
  322 + parity1 = page_index & 1;
  323 + parity2 = parity1 ^ 1;
  324 + while (tb != NULL) {
  325 + tb_next = tb->page_next[parity1];
  326 + tb_invalidate(tb, parity2);
  327 + tb = tb_next;
  328 + }
  329 + p->first_tb = NULL;
  330 +}
  331 +
  332 +/* add the tb in the target page and protect it if necessary */
  333 +static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
  334 +{
  335 + PageDesc *p;
  336 + unsigned long host_start, host_end, addr, page_addr;
  337 + int prot;
  338 +
  339 + p = page_find_alloc(page_index);
  340 + tb->page_next[page_index & 1] = p->first_tb;
  341 + p->first_tb = tb;
  342 + if (p->flags & PAGE_WRITE) {
  343 + /* force the host page as non writable (writes will have a
  344 + page fault + mprotect overhead) */
  345 + page_addr = (page_index << TARGET_PAGE_BITS);
  346 + host_start = page_addr & host_page_mask;
  347 + host_end = host_start + host_page_size;
  348 + prot = 0;
  349 + for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
  350 + prot |= page_get_flags(addr);
  351 + mprotect((void *)host_start, host_page_size,
  352 + (prot & PAGE_BITS) & ~PAGE_WRITE);
  353 +#ifdef DEBUG_TB_INVALIDATE
  354 + printf("protecting code page: 0x%08lx\n",
  355 + host_start);
  356 +#endif
  357 + p->flags &= ~PAGE_WRITE;
  358 +#ifdef DEBUG_TB_CHECK
  359 + tb_page_check();
  360 +#endif
  361 + }
  362 +}
  363 +
  364 +/* Allocate a new translation block. Flush the translation buffer if
  365 + too many translation blocks or too much generated code. */
  366 +TranslationBlock *tb_alloc(unsigned long pc,
  367 + unsigned long size)
  368 +{
  369 + TranslationBlock *tb;
  370 + unsigned int page_index1, page_index2;
  371 +
  372 + if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
  373 + (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
  374 + tb_flush();
  375 + tb = &tbs[nb_tbs++];
  376 + tb->pc = pc;
  377 + tb->size = size;
  378 +
  379 + /* add in the page list */
  380 + page_index1 = pc >> TARGET_PAGE_BITS;
  381 + tb_alloc_page(tb, page_index1);
  382 + page_index2 = (pc + size - 1) >> TARGET_PAGE_BITS;
  383 + if (page_index2 != page_index1) {
  384 + tb_alloc_page(tb, page_index2);
  385 + }
  386 + return tb;
  387 +}
  388 +
  389 +/* called from signal handler: invalidate the code and unprotect the
  390 + page. Return TRUE if the fault was succesfully handled. */
  391 +int page_unprotect(unsigned long address)
  392 +{
  393 + unsigned int page_index, prot;
  394 + PageDesc *p;
  395 + unsigned long host_start, host_end, addr;
  396 +
  397 + page_index = address >> TARGET_PAGE_BITS;
  398 + p = page_find(page_index);
  399 + if (!p)
  400 + return 0;
  401 + if ((p->flags & (PAGE_WRITE_ORG | PAGE_WRITE)) == PAGE_WRITE_ORG) {
  402 + /* if the page was really writable, then we change its
  403 + protection back to writable */
  404 + host_start = address & host_page_mask;
  405 + host_end = host_start + host_page_size;
  406 + prot = 0;
  407 + for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
  408 + prot |= page_get_flags(addr);
  409 + mprotect((void *)host_start, host_page_size,
  410 + (prot & PAGE_BITS) | PAGE_WRITE);
  411 + p->flags |= PAGE_WRITE;
  412 +
  413 + /* and since the content will be modified, we must invalidate
  414 + the corresponding translated code. */
  415 + tb_invalidate_page(address);
  416 +#ifdef DEBUG_TB_CHECK
  417 + tb_invalidate_check(address);
  418 +#endif
  419 + return 1;
  420 + } else {
  421 + return 0;
  422 + }
  423 +}
  424 +
  425 +/* call this function when system calls directly modify a memory area */
  426 +void page_unprotect_range(uint8_t *data, unsigned long data_size)
  427 +{
  428 + unsigned long start, end, addr;
  429 +
  430 + start = (unsigned long)data;
  431 + end = start + data_size;
  432 + start &= TARGET_PAGE_MASK;
  433 + end = TARGET_PAGE_ALIGN(end);
  434 + for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
  435 + page_unprotect(addr);
  436 + }
  437 +}
... ...