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,16 +445,21 @@ extern unsigned long host_page_mask;
445 #define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask) 445 #define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
446 446
447 /* same as PROT_xxx */ 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 void page_dump(FILE *f); 457 void page_dump(FILE *f);
455 int page_get_flags(unsigned long address); 458 int page_get_flags(unsigned long address);
456 void page_set_flags(unsigned long start, unsigned long end, int flags); 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 /* internal functions */ 463 /* internal functions */
459 464
460 #define GEN_FLAG_CODE32_SHIFT 0 465 #define GEN_FLAG_CODE32_SHIFT 0
@@ -468,8 +473,73 @@ void page_set_flags(unsigned long start, unsigned long end, int flags); @@ -468,8 +473,73 @@ void page_set_flags(unsigned long start, unsigned long end, int flags);
468 473
469 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 474 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
470 int *gen_code_size_ptr, 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 void cpu_x86_tblocks_init(void); 478 void cpu_x86_tblocks_init(void);
473 void page_init(void); 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 #endif /* CPU_I386_H */ 545 #endif /* CPU_I386_H */
exec-i386.c
@@ -21,39 +21,10 @@ @@ -21,39 +21,10 @@
21 #include "disas.h" 21 #include "disas.h"
22 22
23 //#define DEBUG_EXEC 23 //#define DEBUG_EXEC
24 -#define DEBUG_FLUSH  
25 //#define DEBUG_SIGNAL 24 //#define DEBUG_SIGNAL
26 25
27 /* main execution loop */ 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 /* thread support */ 28 /* thread support */
58 29
59 #ifdef __powerpc__ 30 #ifdef __powerpc__
@@ -195,70 +166,6 @@ void raise_exception(int exception_index) @@ -195,70 +166,6 @@ void raise_exception(int exception_index)
195 raise_exception_err(exception_index, 0); 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 int cpu_x86_exec(CPUX86State *env1) 169 int cpu_x86_exec(CPUX86State *env1)
263 { 170 {
264 int saved_T0, saved_T1, saved_A0; 171 int saved_T0, saved_T1, saved_A0;
@@ -287,7 +194,7 @@ int cpu_x86_exec(CPUX86State *env1) @@ -287,7 +194,7 @@ int cpu_x86_exec(CPUX86State *env1)
287 #ifdef reg_EDI 194 #ifdef reg_EDI
288 int saved_EDI; 195 int saved_EDI;
289 #endif 196 #endif
290 - int code_gen_size, ret; 197 + int code_gen_size, ret, code_size;
291 void (*gen_func)(void); 198 void (*gen_func)(void);
292 TranslationBlock *tb, **ptb; 199 TranslationBlock *tb, **ptb;
293 uint8_t *tc_ptr, *cs_base, *pc; 200 uint8_t *tc_ptr, *cs_base, *pc;
@@ -390,15 +297,15 @@ int cpu_x86_exec(CPUX86State *env1) @@ -390,15 +297,15 @@ int cpu_x86_exec(CPUX86State *env1)
390 cpu_lock(); 297 cpu_lock();
391 tc_ptr = code_gen_ptr; 298 tc_ptr = code_gen_ptr;
392 ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 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 /* if invalid instruction, signal it */ 302 /* if invalid instruction, signal it */
395 if (ret != 0) { 303 if (ret != 0) {
396 cpu_unlock(); 304 cpu_unlock();
397 raise_exception(EXCP06_ILLOP); 305 raise_exception(EXCP06_ILLOP);
398 } 306 }
399 - tb = tb_alloc(); 307 + tb = tb_alloc((unsigned long)pc, code_size);
400 *ptb = tb; 308 *ptb = tb;
401 - tb->pc = (unsigned long)pc;  
402 tb->cs_base = (unsigned long)cs_base; 309 tb->cs_base = (unsigned long)cs_base;
403 tb->flags = flags; 310 tb->flags = flags;
404 tb->tc_ptr = tc_ptr; 311 tb->tc_ptr = tc_ptr;
@@ -493,15 +400,22 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) @@ -493,15 +400,22 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
493 #include <sys/ucontext.h> 400 #include <sys/ucontext.h>
494 401
495 /* 'pc' is the host PC at which the exception was raised. 'address' is 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 static inline int handle_cpu_signal(unsigned long pc, 406 static inline int handle_cpu_signal(unsigned long pc,
498 unsigned long address, 407 unsigned long address,
  408 + int is_write,
499 sigset_t *old_set) 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 #endif 414 #endif
  415 + if (is_write && page_unprotect(address)) {
  416 + sigprocmask(SIG_SETMASK, old_set, NULL);
  417 + return 1;
  418 + }
505 if (pc >= (unsigned long)code_gen_buffer && 419 if (pc >= (unsigned long)code_gen_buffer &&
506 pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) { 420 pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
507 /* the PC is inside the translated code. It means that we have 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,8 +426,7 @@ static inline int handle_cpu_signal(unsigned long pc,
512 /* XXX: need to compute virtual pc position by retranslating 426 /* XXX: need to compute virtual pc position by retranslating
513 code. The rest of the CPU state should be correct. */ 427 code. The rest of the CPU state should be correct. */
514 env->cr2 = address; 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 /* never comes here */ 430 /* never comes here */
518 return 1; 431 return 1;
519 } else { 432 } else {
@@ -531,11 +444,16 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, @@ -531,11 +444,16 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
531 444
532 #ifndef REG_EIP 445 #ifndef REG_EIP
533 /* for glibc 2.1 */ 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 #endif 450 #endif
536 pc = uc->uc_mcontext.gregs[REG_EIP]; 451 pc = uc->uc_mcontext.gregs[REG_EIP];
537 pold_set = &uc->uc_sigmask; 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 #else 457 #else
540 #warning No CPU specific signal handler: cannot handle target SIGSEGV events 458 #warning No CPU specific signal handler: cannot handle target SIGSEGV events
541 return 0; 459 return 0;
1 /* 1 /*
2 - * virtual page mapping 2 + * virtual page mapping and translated block handling
3 * 3 *
4 * Copyright (c) 2003 Fabrice Bellard 4 * Copyright (c) 2003 Fabrice Bellard
5 * 5 *
@@ -24,13 +24,32 @@ @@ -24,13 +24,32 @@
24 #include <errno.h> 24 #include <errno.h>
25 #include <unistd.h> 25 #include <unistd.h>
26 #include <inttypes.h> 26 #include <inttypes.h>
  27 +#include <sys/mman.h>
27 28
28 #include "cpu-i386.h" 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 /* XXX: pack the flags in the low bits of the pointer ? */ 49 /* XXX: pack the flags in the low bits of the pointer ? */
31 typedef struct PageDesc { 50 typedef struct PageDesc {
32 - struct TranslationBlock *first_tb;  
33 unsigned long flags; 51 unsigned long flags;
  52 + TranslationBlock *first_tb;
34 } PageDesc; 53 } PageDesc;
35 54
36 #define L2_BITS 10 55 #define L2_BITS 10
@@ -39,6 +58,8 @@ typedef struct PageDesc { @@ -39,6 +58,8 @@ typedef struct PageDesc {
39 #define L1_SIZE (1 << L1_BITS) 58 #define L1_SIZE (1 << L1_BITS)
40 #define L2_SIZE (1 << L2_BITS) 59 #define L2_SIZE (1 << L2_BITS)
41 60
  61 +static void tb_invalidate_page(unsigned long address);
  62 +
42 unsigned long real_host_page_size; 63 unsigned long real_host_page_size;
43 unsigned long host_page_bits; 64 unsigned long host_page_bits;
44 unsigned long host_page_size; 65 unsigned long host_page_size;
@@ -104,36 +125,44 @@ void page_dump(FILE *f) @@ -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 PageDesc **lp, *p; 130 PageDesc **lp, *p;
112 131
113 - index = address >> TARGET_PAGE_BITS;  
114 lp = &l1_map[index >> L2_BITS]; 132 lp = &l1_map[index >> L2_BITS];
115 p = *lp; 133 p = *lp;
116 if (!p) { 134 if (!p) {
117 /* allocate if not found */ 135 /* allocate if not found */
118 p = malloc(sizeof(PageDesc) * L2_SIZE); 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 *lp = p; 138 *lp = p;
121 } 139 }
122 return p + (index & (L2_SIZE - 1)); 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 PageDesc *p; 145 PageDesc *p;
129 146
130 - index = address >> TARGET_PAGE_BITS;  
131 p = l1_map[index >> L2_BITS]; 147 p = l1_map[index >> L2_BITS];
132 if (!p) 148 if (!p)
133 return 0; 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 void page_set_flags(unsigned long start, unsigned long end, int flags) 166 void page_set_flags(unsigned long start, unsigned long end, int flags)
138 { 167 {
139 PageDesc *p; 168 PageDesc *p;
@@ -141,8 +170,268 @@ void page_set_flags(unsigned long start, unsigned long end, int flags) @@ -141,8 +170,268 @@ void page_set_flags(unsigned long start, unsigned long end, int flags)
141 170
142 start = start & TARGET_PAGE_MASK; 171 start = start & TARGET_PAGE_MASK;
143 end = TARGET_PAGE_ALIGN(end); 172 end = TARGET_PAGE_ALIGN(end);
  173 + if (flags & PAGE_WRITE)
  174 + flags |= PAGE_WRITE_ORG;
144 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { 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 p->flags = flags; 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 +}