make the TB cache independent of MMU mappings (faster MMU context switches and needed for SMP support)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1632 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									313adae905
								
							
						
					
					
						commit
						8a40a180d3
					
				
							
								
								
									
										298
									
								
								cpu-exec.c
								
								
								
								
							
							
						
						
									
										298
									
								
								cpu-exec.c
								
								
								
								
							|  | @ -73,6 +73,137 @@ void cpu_resume_from_signal(CPUState *env1, void *puc) | ||||||
|     longjmp(env->jmp_env, 1); |     longjmp(env->jmp_env, 1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | static TranslationBlock *tb_find_slow(target_ulong pc, | ||||||
|  |                                       target_ulong cs_base, | ||||||
|  |                                       unsigned int flags) | ||||||
|  | { | ||||||
|  |     TranslationBlock *tb, **ptb1; | ||||||
|  |     int code_gen_size; | ||||||
|  |     unsigned int h; | ||||||
|  |     target_ulong phys_pc, phys_page1, phys_page2, virt_page2; | ||||||
|  |     uint8_t *tc_ptr; | ||||||
|  |      | ||||||
|  |     spin_lock(&tb_lock); | ||||||
|  | 
 | ||||||
|  |     tb_invalidated_flag = 0; | ||||||
|  |      | ||||||
|  |     regs_to_env(); /* XXX: do it just before cpu_gen_code() */ | ||||||
|  |      | ||||||
|  |     /* find translated block using physical mappings */ | ||||||
|  |     phys_pc = get_phys_addr_code(env, pc); | ||||||
|  |     phys_page1 = phys_pc & TARGET_PAGE_MASK; | ||||||
|  |     phys_page2 = -1; | ||||||
|  |     h = tb_phys_hash_func(phys_pc); | ||||||
|  |     ptb1 = &tb_phys_hash[h]; | ||||||
|  |     for(;;) { | ||||||
|  |         tb = *ptb1; | ||||||
|  |         if (!tb) | ||||||
|  |             goto not_found; | ||||||
|  |         if (tb->pc == pc &&  | ||||||
|  |             tb->page_addr[0] == phys_page1 && | ||||||
|  |             tb->cs_base == cs_base &&  | ||||||
|  |             tb->flags == flags) { | ||||||
|  |             /* check next page if needed */ | ||||||
|  |             if (tb->page_addr[1] != -1) { | ||||||
|  |                 virt_page2 = (pc & TARGET_PAGE_MASK) +  | ||||||
|  |                     TARGET_PAGE_SIZE; | ||||||
|  |                 phys_page2 = get_phys_addr_code(env, virt_page2); | ||||||
|  |                 if (tb->page_addr[1] == phys_page2) | ||||||
|  |                     goto found; | ||||||
|  |             } else { | ||||||
|  |                 goto found; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         ptb1 = &tb->phys_hash_next; | ||||||
|  |     } | ||||||
|  |  not_found: | ||||||
|  |     /* if no translated code available, then translate it now */ | ||||||
|  |     tb = tb_alloc(pc); | ||||||
|  |     if (!tb) { | ||||||
|  |         /* flush must be done */ | ||||||
|  |         tb_flush(env); | ||||||
|  |         /* cannot fail at this point */ | ||||||
|  |         tb = tb_alloc(pc); | ||||||
|  |         /* don't forget to invalidate previous TB info */ | ||||||
|  |         T0 = 0; | ||||||
|  |     } | ||||||
|  |     tc_ptr = code_gen_ptr; | ||||||
|  |     tb->tc_ptr = tc_ptr; | ||||||
|  |     tb->cs_base = cs_base; | ||||||
|  |     tb->flags = flags; | ||||||
|  |     cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); | ||||||
|  |     code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); | ||||||
|  |      | ||||||
|  |     /* check next page if needed */ | ||||||
|  |     virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; | ||||||
|  |     phys_page2 = -1; | ||||||
|  |     if ((pc & TARGET_PAGE_MASK) != virt_page2) { | ||||||
|  |         phys_page2 = get_phys_addr_code(env, virt_page2); | ||||||
|  |     } | ||||||
|  |     tb_link_phys(tb, phys_pc, phys_page2); | ||||||
|  |      | ||||||
|  |  found: | ||||||
|  |     if (tb_invalidated_flag) { | ||||||
|  |         /* as some TB could have been invalidated because
 | ||||||
|  |            of memory exceptions while generating the code, we | ||||||
|  |            must recompute the hash index here */ | ||||||
|  |         T0 = 0; | ||||||
|  |     } | ||||||
|  |     /* we add the TB in the virtual pc hash table */ | ||||||
|  |     env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb; | ||||||
|  |     spin_unlock(&tb_lock); | ||||||
|  |     return tb; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline TranslationBlock *tb_find_fast(void) | ||||||
|  | { | ||||||
|  |     TranslationBlock *tb; | ||||||
|  |     target_ulong cs_base, pc; | ||||||
|  |     unsigned int flags; | ||||||
|  | 
 | ||||||
|  |     /* we record a subset of the CPU state. It will
 | ||||||
|  |        always be the same before a given translated block | ||||||
|  |        is executed. */ | ||||||
|  | #if defined(TARGET_I386) | ||||||
|  |     flags = env->hflags; | ||||||
|  |     flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); | ||||||
|  |     cs_base = env->segs[R_CS].base; | ||||||
|  |     pc = cs_base + env->eip; | ||||||
|  | #elif defined(TARGET_ARM) | ||||||
|  |     flags = env->thumb | (env->vfp.vec_len << 1) | ||||||
|  |         | (env->vfp.vec_stride << 4); | ||||||
|  |     cs_base = 0; | ||||||
|  |     pc = env->regs[15]; | ||||||
|  | #elif defined(TARGET_SPARC) | ||||||
|  | #ifdef TARGET_SPARC64 | ||||||
|  |     flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); | ||||||
|  | #else | ||||||
|  |     flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1); | ||||||
|  | #endif | ||||||
|  |     cs_base = env->npc; | ||||||
|  |     pc = env->pc; | ||||||
|  | #elif defined(TARGET_PPC) | ||||||
|  |     flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | | ||||||
|  |         (msr_se << MSR_SE) | (msr_le << MSR_LE); | ||||||
|  |     cs_base = 0; | ||||||
|  |     pc = env->nip; | ||||||
|  | #elif defined(TARGET_MIPS) | ||||||
|  |     flags = env->hflags & MIPS_HFLAGS_TMASK; | ||||||
|  |     cs_base = NULL; | ||||||
|  |     pc = env->PC; | ||||||
|  | #else | ||||||
|  | #error unsupported CPU | ||||||
|  | #endif | ||||||
|  |     tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)]; | ||||||
|  |     if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base || | ||||||
|  |                          tb->flags != flags, 0)) { | ||||||
|  |         tb = tb_find_slow(pc, cs_base, flags); | ||||||
|  |     } | ||||||
|  |     return tb; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /* main execution loop */ | /* main execution loop */ | ||||||
| 
 | 
 | ||||||
| int cpu_exec(CPUState *env1) | int cpu_exec(CPUState *env1) | ||||||
|  | @ -115,12 +246,10 @@ int cpu_exec(CPUState *env1) | ||||||
| #ifdef __sparc__ | #ifdef __sparc__ | ||||||
|     int saved_i7, tmp_T0; |     int saved_i7, tmp_T0; | ||||||
| #endif | #endif | ||||||
|     int code_gen_size, ret, interrupt_request; |     int ret, interrupt_request; | ||||||
|     void (*gen_func)(void); |     void (*gen_func)(void); | ||||||
|     TranslationBlock *tb, **ptb; |     TranslationBlock *tb; | ||||||
|     target_ulong cs_base, pc; |  | ||||||
|     uint8_t *tc_ptr; |     uint8_t *tc_ptr; | ||||||
|     unsigned int flags; |  | ||||||
| 
 | 
 | ||||||
|     /* first we save global registers */ |     /* first we save global registers */ | ||||||
|     saved_env = env; |     saved_env = env; | ||||||
|  | @ -290,19 +419,29 @@ int cpu_exec(CPUState *env1) | ||||||
|                     } |                     } | ||||||
| #endif | #endif | ||||||
|                     if (msr_ee != 0) { |                     if (msr_ee != 0) { | ||||||
|                     if ((interrupt_request & CPU_INTERRUPT_HARD)) { |                         if ((interrupt_request & CPU_INTERRUPT_HARD)) { | ||||||
| 			    /* Raise it */ | 			    /* Raise it */ | ||||||
| 			    env->exception_index = EXCP_EXTERNAL; | 			    env->exception_index = EXCP_EXTERNAL; | ||||||
| 			    env->error_code = 0; | 			    env->error_code = 0; | ||||||
|                             do_interrupt(env); |                             do_interrupt(env); | ||||||
|                         env->interrupt_request &= ~CPU_INTERRUPT_HARD; |                             env->interrupt_request &= ~CPU_INTERRUPT_HARD; | ||||||
| 			} else if ((interrupt_request & CPU_INTERRUPT_TIMER)) { | #ifdef __sparc__ | ||||||
| 			    /* Raise it */ |                             tmp_T0 = 0; | ||||||
| 			    env->exception_index = EXCP_DECR; | #else | ||||||
| 			    env->error_code = 0; |                             T0 = 0; | ||||||
| 			    do_interrupt(env); | #endif | ||||||
|  |                         } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) { | ||||||
|  |                             /* Raise it */ | ||||||
|  |                             env->exception_index = EXCP_DECR; | ||||||
|  |                             env->error_code = 0; | ||||||
|  |                             do_interrupt(env); | ||||||
|                             env->interrupt_request &= ~CPU_INTERRUPT_TIMER; |                             env->interrupt_request &= ~CPU_INTERRUPT_TIMER; | ||||||
| 			} | #ifdef __sparc__ | ||||||
|  |                             tmp_T0 = 0; | ||||||
|  | #else | ||||||
|  |                             T0 = 0; | ||||||
|  | #endif | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
| #elif defined(TARGET_MIPS) | #elif defined(TARGET_MIPS) | ||||||
|                     if ((interrupt_request & CPU_INTERRUPT_HARD) && |                     if ((interrupt_request & CPU_INTERRUPT_HARD) && | ||||||
|  | @ -316,6 +455,11 @@ int cpu_exec(CPUState *env1) | ||||||
|                         env->error_code = 0; |                         env->error_code = 0; | ||||||
|                         do_interrupt(env); |                         do_interrupt(env); | ||||||
|                         env->interrupt_request &= ~CPU_INTERRUPT_HARD; |                         env->interrupt_request &= ~CPU_INTERRUPT_HARD; | ||||||
|  | #ifdef __sparc__ | ||||||
|  |                         tmp_T0 = 0; | ||||||
|  | #else | ||||||
|  |                         T0 = 0; | ||||||
|  | #endif | ||||||
|                     } |                     } | ||||||
| #elif defined(TARGET_SPARC) | #elif defined(TARGET_SPARC) | ||||||
|                     if ((interrupt_request & CPU_INTERRUPT_HARD) && |                     if ((interrupt_request & CPU_INTERRUPT_HARD) && | ||||||
|  | @ -329,6 +473,11 @@ int cpu_exec(CPUState *env1) | ||||||
| 			    env->interrupt_request &= ~CPU_INTERRUPT_HARD; | 			    env->interrupt_request &= ~CPU_INTERRUPT_HARD; | ||||||
| 			    do_interrupt(env->interrupt_index); | 			    do_interrupt(env->interrupt_index); | ||||||
| 			    env->interrupt_index = 0; | 			    env->interrupt_index = 0; | ||||||
|  | #ifdef __sparc__ | ||||||
|  |                             tmp_T0 = 0; | ||||||
|  | #else | ||||||
|  |                             T0 = 0; | ||||||
|  | #endif | ||||||
| 			} | 			} | ||||||
| 		    } else if (interrupt_request & CPU_INTERRUPT_TIMER) { | 		    } else if (interrupt_request & CPU_INTERRUPT_TIMER) { | ||||||
| 			//do_interrupt(0, 0, 0, 0, 0);
 | 			//do_interrupt(0, 0, 0, 0, 0);
 | ||||||
|  | @ -399,123 +548,7 @@ int cpu_exec(CPUState *env1) | ||||||
| #endif | #endif | ||||||
|                 } |                 } | ||||||
| #endif | #endif | ||||||
|                 /* we record a subset of the CPU state. It will
 |                 tb = tb_find_fast(); | ||||||
|                    always be the same before a given translated block |  | ||||||
|                    is executed. */ |  | ||||||
| #if defined(TARGET_I386) |  | ||||||
|                 flags = env->hflags; |  | ||||||
|                 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); |  | ||||||
|                 cs_base = env->segs[R_CS].base; |  | ||||||
|                 pc = cs_base + env->eip; |  | ||||||
| #elif defined(TARGET_ARM) |  | ||||||
|                 flags = env->thumb | (env->vfp.vec_len << 1) |  | ||||||
|                         | (env->vfp.vec_stride << 4); |  | ||||||
|                 cs_base = 0; |  | ||||||
|                 pc = env->regs[15]; |  | ||||||
| #elif defined(TARGET_SPARC) |  | ||||||
| #ifdef TARGET_SPARC64 |  | ||||||
|                 flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2); |  | ||||||
| #else |  | ||||||
|                 flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1); |  | ||||||
| #endif |  | ||||||
|                 cs_base = env->npc; |  | ||||||
|                 pc = env->pc; |  | ||||||
| #elif defined(TARGET_PPC) |  | ||||||
|                 flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | |  | ||||||
|                     (msr_se << MSR_SE) | (msr_le << MSR_LE); |  | ||||||
|                 cs_base = 0; |  | ||||||
|                 pc = env->nip; |  | ||||||
| #elif defined(TARGET_MIPS) |  | ||||||
|                 flags = env->hflags & MIPS_HFLAGS_TMASK; |  | ||||||
|                 cs_base = NULL; |  | ||||||
|                 pc = env->PC; |  | ||||||
| #else |  | ||||||
| #error unsupported CPU |  | ||||||
| #endif |  | ||||||
|                 tb = tb_find(&ptb, pc, cs_base,  |  | ||||||
|                              flags); |  | ||||||
|                 if (!tb) { |  | ||||||
|                     TranslationBlock **ptb1; |  | ||||||
|                     unsigned int h; |  | ||||||
|                     target_ulong phys_pc, phys_page1, phys_page2, virt_page2; |  | ||||||
|                      |  | ||||||
|                      |  | ||||||
|                     spin_lock(&tb_lock); |  | ||||||
| 
 |  | ||||||
|                     tb_invalidated_flag = 0; |  | ||||||
|                      |  | ||||||
|                     regs_to_env(); /* XXX: do it just before cpu_gen_code() */ |  | ||||||
| 
 |  | ||||||
|                     /* find translated block using physical mappings */ |  | ||||||
|                     phys_pc = get_phys_addr_code(env, pc); |  | ||||||
|                     phys_page1 = phys_pc & TARGET_PAGE_MASK; |  | ||||||
|                     phys_page2 = -1; |  | ||||||
|                     h = tb_phys_hash_func(phys_pc); |  | ||||||
|                     ptb1 = &tb_phys_hash[h]; |  | ||||||
|                     for(;;) { |  | ||||||
|                         tb = *ptb1; |  | ||||||
|                         if (!tb) |  | ||||||
|                             goto not_found; |  | ||||||
|                         if (tb->pc == pc &&  |  | ||||||
|                             tb->page_addr[0] == phys_page1 && |  | ||||||
|                             tb->cs_base == cs_base &&  |  | ||||||
|                             tb->flags == flags) { |  | ||||||
|                             /* check next page if needed */ |  | ||||||
|                             if (tb->page_addr[1] != -1) { |  | ||||||
|                                 virt_page2 = (pc & TARGET_PAGE_MASK) +  |  | ||||||
|                                     TARGET_PAGE_SIZE; |  | ||||||
|                                 phys_page2 = get_phys_addr_code(env, virt_page2); |  | ||||||
|                                 if (tb->page_addr[1] == phys_page2) |  | ||||||
|                                     goto found; |  | ||||||
|                             } else { |  | ||||||
|                                 goto found; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         ptb1 = &tb->phys_hash_next; |  | ||||||
|                     } |  | ||||||
|                 not_found: |  | ||||||
|                     /* if no translated code available, then translate it now */ |  | ||||||
|                     tb = tb_alloc(pc); |  | ||||||
|                     if (!tb) { |  | ||||||
|                         /* flush must be done */ |  | ||||||
|                         tb_flush(env); |  | ||||||
|                         /* cannot fail at this point */ |  | ||||||
|                         tb = tb_alloc(pc); |  | ||||||
|                         /* don't forget to invalidate previous TB info */ |  | ||||||
|                         ptb = &tb_hash[tb_hash_func(pc)]; |  | ||||||
|                         T0 = 0; |  | ||||||
|                     } |  | ||||||
|                     tc_ptr = code_gen_ptr; |  | ||||||
|                     tb->tc_ptr = tc_ptr; |  | ||||||
|                     tb->cs_base = cs_base; |  | ||||||
|                     tb->flags = flags; |  | ||||||
|                     cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); |  | ||||||
|                     code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); |  | ||||||
|                      |  | ||||||
|                     /* check next page if needed */ |  | ||||||
|                     virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; |  | ||||||
|                     phys_page2 = -1; |  | ||||||
|                     if ((pc & TARGET_PAGE_MASK) != virt_page2) { |  | ||||||
|                         phys_page2 = get_phys_addr_code(env, virt_page2); |  | ||||||
|                     } |  | ||||||
|                     tb_link_phys(tb, phys_pc, phys_page2); |  | ||||||
| 
 |  | ||||||
|                 found: |  | ||||||
|                     if (tb_invalidated_flag) { |  | ||||||
|                         /* as some TB could have been invalidated because
 |  | ||||||
|                            of memory exceptions while generating the code, we |  | ||||||
|                            must recompute the hash index here */ |  | ||||||
|                         ptb = &tb_hash[tb_hash_func(pc)]; |  | ||||||
|                         while (*ptb != NULL) |  | ||||||
|                             ptb = &(*ptb)->hash_next; |  | ||||||
|                         T0 = 0; |  | ||||||
|                     } |  | ||||||
|                     /* we add the TB in the virtual pc hash table */ |  | ||||||
|                     *ptb = tb; |  | ||||||
|                     tb->hash_next = NULL; |  | ||||||
|                     tb_link(tb); |  | ||||||
|                     spin_unlock(&tb_lock); |  | ||||||
|                 } |  | ||||||
| #ifdef DEBUG_EXEC | #ifdef DEBUG_EXEC | ||||||
|                 if ((loglevel & CPU_LOG_EXEC)) { |                 if ((loglevel & CPU_LOG_EXEC)) { | ||||||
|                     fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", |                     fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n", | ||||||
|  | @ -526,9 +559,12 @@ int cpu_exec(CPUState *env1) | ||||||
| #ifdef __sparc__ | #ifdef __sparc__ | ||||||
|                 T0 = tmp_T0; |                 T0 = tmp_T0; | ||||||
| #endif	     | #endif	     | ||||||
|                 /* see if we can patch the calling TB. */ |                 /* see if we can patch the calling TB. When the TB
 | ||||||
|  |                    spans two pages, we cannot safely do a direct | ||||||
|  |                    jump. */ | ||||||
|                 { |                 { | ||||||
|                     if (T0 != 0 |                     if (T0 != 0 && | ||||||
|  |                         tb->page_addr[1] == -1 | ||||||
| #if defined(TARGET_I386) && defined(USE_CODE_COPY) | #if defined(TARGET_I386) && defined(USE_CODE_COPY) | ||||||
|                     && (tb->cflags & CF_CODE_COPY) ==  |                     && (tb->cflags & CF_CODE_COPY) ==  | ||||||
|                     (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY) |                     (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY) | ||||||
|  |  | ||||||
							
								
								
									
										35
									
								
								exec-all.h
								
								
								
								
							
							
						
						
									
										35
									
								
								exec-all.h
								
								
								
								
							|  | @ -105,9 +105,6 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, | ||||||
| #define CODE_GEN_MAX_SIZE        65536 | #define CODE_GEN_MAX_SIZE        65536 | ||||||
| #define CODE_GEN_ALIGN           16 /* must be >= of the size of a icache line */ | #define CODE_GEN_ALIGN           16 /* must be >= of the size of a icache line */ | ||||||
| 
 | 
 | ||||||
| #define CODE_GEN_HASH_BITS     15 |  | ||||||
| #define CODE_GEN_HASH_SIZE     (1 << CODE_GEN_HASH_BITS) |  | ||||||
| 
 |  | ||||||
| #define CODE_GEN_PHYS_HASH_BITS     15 | #define CODE_GEN_PHYS_HASH_BITS     15 | ||||||
| #define CODE_GEN_PHYS_HASH_SIZE     (1 << CODE_GEN_PHYS_HASH_BITS) | #define CODE_GEN_PHYS_HASH_SIZE     (1 << CODE_GEN_PHYS_HASH_BITS) | ||||||
| 
 | 
 | ||||||
|  | @ -167,7 +164,6 @@ typedef struct TranslationBlock { | ||||||
| #define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */ | #define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */ | ||||||
| 
 | 
 | ||||||
|     uint8_t *tc_ptr;    /* pointer to the translated code */ |     uint8_t *tc_ptr;    /* pointer to the translated code */ | ||||||
|     struct TranslationBlock *hash_next; /* next matching tb for virtual address */ |  | ||||||
|     /* next matching tb for physical address. */ |     /* next matching tb for physical address. */ | ||||||
|     struct TranslationBlock *phys_hash_next;  |     struct TranslationBlock *phys_hash_next;  | ||||||
|     /* first and second physical page containing code. The lower bit
 |     /* first and second physical page containing code. The lower bit
 | ||||||
|  | @ -191,9 +187,9 @@ typedef struct TranslationBlock { | ||||||
|     struct TranslationBlock *jmp_first; |     struct TranslationBlock *jmp_first; | ||||||
| } TranslationBlock; | } TranslationBlock; | ||||||
| 
 | 
 | ||||||
| static inline unsigned int tb_hash_func(target_ulong pc) | static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) | ||||||
| { | { | ||||||
|     return pc & (CODE_GEN_HASH_SIZE - 1); |     return (pc ^ (pc >> TB_JMP_CACHE_BITS)) & (TB_JMP_CACHE_SIZE - 1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline unsigned int tb_phys_hash_func(unsigned long pc) | static inline unsigned int tb_phys_hash_func(unsigned long pc) | ||||||
|  | @ -203,41 +199,14 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc) | ||||||
| 
 | 
 | ||||||
| TranslationBlock *tb_alloc(target_ulong pc); | TranslationBlock *tb_alloc(target_ulong pc); | ||||||
| void tb_flush(CPUState *env); | void tb_flush(CPUState *env); | ||||||
| void tb_link(TranslationBlock *tb); |  | ||||||
| void tb_link_phys(TranslationBlock *tb,  | void tb_link_phys(TranslationBlock *tb,  | ||||||
|                   target_ulong phys_pc, target_ulong phys_page2); |                   target_ulong phys_pc, target_ulong phys_page2); | ||||||
| 
 | 
 | ||||||
| extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; |  | ||||||
| extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; | extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; | ||||||
| 
 | 
 | ||||||
| extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; | extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; | ||||||
| extern uint8_t *code_gen_ptr; | extern uint8_t *code_gen_ptr; | ||||||
| 
 | 
 | ||||||
| /* find a translation block in the translation cache. If not found,
 |  | ||||||
|    return NULL and the pointer to the last element of the list in pptb */ |  | ||||||
| static inline TranslationBlock *tb_find(TranslationBlock ***pptb, |  | ||||||
|                                         target_ulong pc,  |  | ||||||
|                                         target_ulong cs_base, |  | ||||||
|                                         unsigned int flags) |  | ||||||
| { |  | ||||||
|     TranslationBlock **ptb, *tb; |  | ||||||
|     unsigned int h; |  | ||||||
|   |  | ||||||
|     h = tb_hash_func(pc); |  | ||||||
|     ptb = &tb_hash[h]; |  | ||||||
|     for(;;) { |  | ||||||
|         tb = *ptb; |  | ||||||
|         if (!tb) |  | ||||||
|             break; |  | ||||||
|         if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) |  | ||||||
|             return tb; |  | ||||||
|         ptb = &tb->hash_next; |  | ||||||
|     } |  | ||||||
|     *pptb = ptb; |  | ||||||
|     return NULL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| #if defined(USE_DIRECT_JUMP) | #if defined(USE_DIRECT_JUMP) | ||||||
| 
 | 
 | ||||||
| #if defined(__powerpc__) | #if defined(__powerpc__) | ||||||
|  |  | ||||||
							
								
								
									
										303
									
								
								exec.c
								
								
								
								
							
							
						
						
									
										303
									
								
								exec.c
								
								
								
								
							|  | @ -61,7 +61,6 @@ | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; | TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; | ||||||
| TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; |  | ||||||
| TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; | TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; | ||||||
| int nb_tbs; | int nb_tbs; | ||||||
| /* any access to the tbs or the page table must use this lock */ | /* any access to the tbs or the page table must use this lock */ | ||||||
|  | @ -92,20 +91,6 @@ typedef struct PhysPageDesc { | ||||||
|     uint32_t phys_offset; |     uint32_t phys_offset; | ||||||
| } PhysPageDesc; | } PhysPageDesc; | ||||||
| 
 | 
 | ||||||
| /* Note: the VirtPage handling is absolete and will be suppressed
 |  | ||||||
|    ASAP */ |  | ||||||
| typedef struct VirtPageDesc { |  | ||||||
|     /* physical address of code page. It is valid only if 'valid_tag'
 |  | ||||||
|        matches 'virt_valid_tag' */  |  | ||||||
|     target_ulong phys_addr;  |  | ||||||
|     unsigned int valid_tag; |  | ||||||
| #if !defined(CONFIG_SOFTMMU) |  | ||||||
|     /* original page access rights. It is valid only if 'valid_tag'
 |  | ||||||
|        matches 'virt_valid_tag' */ |  | ||||||
|     unsigned int prot; |  | ||||||
| #endif |  | ||||||
| } VirtPageDesc; |  | ||||||
| 
 |  | ||||||
| #define L2_BITS 10 | #define L2_BITS 10 | ||||||
| #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS) | #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS) | ||||||
| 
 | 
 | ||||||
|  | @ -123,17 +108,6 @@ unsigned long qemu_host_page_mask; | ||||||
| static PageDesc *l1_map[L1_SIZE]; | static PageDesc *l1_map[L1_SIZE]; | ||||||
| PhysPageDesc **l1_phys_map; | PhysPageDesc **l1_phys_map; | ||||||
| 
 | 
 | ||||||
| #if !defined(CONFIG_USER_ONLY) |  | ||||||
| #if TARGET_LONG_BITS > 32 |  | ||||||
| #define VIRT_L_BITS 9 |  | ||||||
| #define VIRT_L_SIZE (1 << VIRT_L_BITS) |  | ||||||
| static void *l1_virt_map[VIRT_L_SIZE]; |  | ||||||
| #else |  | ||||||
| static VirtPageDesc *l1_virt_map[L1_SIZE]; |  | ||||||
| #endif |  | ||||||
| static unsigned int virt_valid_tag; |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /* io memory support */ | /* io memory support */ | ||||||
| CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; | CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; | ||||||
| CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; | CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; | ||||||
|  | @ -190,9 +164,6 @@ static void page_init(void) | ||||||
|     while ((1 << qemu_host_page_bits) < qemu_host_page_size) |     while ((1 << qemu_host_page_bits) < qemu_host_page_size) | ||||||
|         qemu_host_page_bits++; |         qemu_host_page_bits++; | ||||||
|     qemu_host_page_mask = ~(qemu_host_page_size - 1); |     qemu_host_page_mask = ~(qemu_host_page_size - 1); | ||||||
| #if !defined(CONFIG_USER_ONLY) |  | ||||||
|     virt_valid_tag = 1; |  | ||||||
| #endif |  | ||||||
|     l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *)); |     l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *)); | ||||||
|     memset(l1_phys_map, 0, L1_SIZE * sizeof(void *)); |     memset(l1_phys_map, 0, L1_SIZE * sizeof(void *)); | ||||||
| } | } | ||||||
|  | @ -266,120 +237,6 @@ static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr, | ||||||
|                              target_ulong vaddr); |                              target_ulong vaddr); | ||||||
| static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,  | static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,  | ||||||
|                                     target_ulong vaddr); |                                     target_ulong vaddr); | ||||||
| 
 |  | ||||||
| static VirtPageDesc *virt_page_find_alloc(target_ulong index, int alloc) |  | ||||||
| { |  | ||||||
| #if TARGET_LONG_BITS > 32 |  | ||||||
|     void **p, **lp; |  | ||||||
| 
 |  | ||||||
|     p = l1_virt_map; |  | ||||||
|     lp = p + ((index >> (5 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); |  | ||||||
|     p = *lp; |  | ||||||
|     if (!p) { |  | ||||||
|         if (!alloc) |  | ||||||
|             return NULL; |  | ||||||
|         p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE); |  | ||||||
|         *lp = p; |  | ||||||
|     } |  | ||||||
|     lp = p + ((index >> (4 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); |  | ||||||
|     p = *lp; |  | ||||||
|     if (!p) { |  | ||||||
|         if (!alloc) |  | ||||||
|             return NULL; |  | ||||||
|         p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE); |  | ||||||
|         *lp = p; |  | ||||||
|     } |  | ||||||
|     lp = p + ((index >> (3 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); |  | ||||||
|     p = *lp; |  | ||||||
|     if (!p) { |  | ||||||
|         if (!alloc) |  | ||||||
|             return NULL; |  | ||||||
|         p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE); |  | ||||||
|         *lp = p; |  | ||||||
|     } |  | ||||||
|     lp = p + ((index >> (2 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); |  | ||||||
|     p = *lp; |  | ||||||
|     if (!p) { |  | ||||||
|         if (!alloc) |  | ||||||
|             return NULL; |  | ||||||
|         p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE); |  | ||||||
|         *lp = p; |  | ||||||
|     } |  | ||||||
|     lp = p + ((index >> (1 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1)); |  | ||||||
|     p = *lp; |  | ||||||
|     if (!p) { |  | ||||||
|         if (!alloc) |  | ||||||
|             return NULL; |  | ||||||
|         p = qemu_mallocz(sizeof(VirtPageDesc) * VIRT_L_SIZE); |  | ||||||
|         *lp = p; |  | ||||||
|     } |  | ||||||
|     return ((VirtPageDesc *)p) + (index & (VIRT_L_SIZE - 1)); |  | ||||||
| #else |  | ||||||
|     VirtPageDesc *p, **lp; |  | ||||||
| 
 |  | ||||||
|     lp = &l1_virt_map[index >> L2_BITS]; |  | ||||||
|     p = *lp; |  | ||||||
|     if (!p) { |  | ||||||
|         /* allocate if not found */ |  | ||||||
|         if (!alloc) |  | ||||||
|             return NULL; |  | ||||||
|         p = qemu_mallocz(sizeof(VirtPageDesc) * L2_SIZE); |  | ||||||
|         *lp = p; |  | ||||||
|     } |  | ||||||
|     return p + (index & (L2_SIZE - 1)); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline VirtPageDesc *virt_page_find(target_ulong index) |  | ||||||
| { |  | ||||||
|     return virt_page_find_alloc(index, 0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #if TARGET_LONG_BITS > 32 |  | ||||||
| static void virt_page_flush_internal(void **p, int level) |  | ||||||
| { |  | ||||||
|     int i;  |  | ||||||
|     if (level == 0) { |  | ||||||
|         VirtPageDesc *q = (VirtPageDesc *)p; |  | ||||||
|         for(i = 0; i < VIRT_L_SIZE; i++) |  | ||||||
|             q[i].valid_tag = 0; |  | ||||||
|     } else { |  | ||||||
|         level--; |  | ||||||
|         for(i = 0; i < VIRT_L_SIZE; i++) { |  | ||||||
|             if (p[i]) |  | ||||||
|                 virt_page_flush_internal(p[i], level); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| static void virt_page_flush(void) |  | ||||||
| { |  | ||||||
|     virt_valid_tag++; |  | ||||||
| 
 |  | ||||||
|     if (virt_valid_tag == 0) { |  | ||||||
|         virt_valid_tag = 1; |  | ||||||
| #if TARGET_LONG_BITS > 32 |  | ||||||
|         virt_page_flush_internal(l1_virt_map, 5); |  | ||||||
| #else |  | ||||||
|         { |  | ||||||
|             int i, j; |  | ||||||
|             VirtPageDesc *p; |  | ||||||
|             for(i = 0; i < L1_SIZE; i++) { |  | ||||||
|                 p = l1_virt_map[i]; |  | ||||||
|                 if (p) { |  | ||||||
|                     for(j = 0; j < L2_SIZE; j++) |  | ||||||
|                         p[j].valid_tag = 0; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| #endif |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| #else |  | ||||||
| static void virt_page_flush(void) |  | ||||||
| { |  | ||||||
| } |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| void cpu_exec_init(void) | void cpu_exec_init(void) | ||||||
|  | @ -429,8 +286,7 @@ void tb_flush(CPUState *env) | ||||||
|            nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); |            nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); | ||||||
| #endif | #endif | ||||||
|     nb_tbs = 0; |     nb_tbs = 0; | ||||||
|     memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *)); |     memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); | ||||||
|     virt_page_flush(); |  | ||||||
| 
 | 
 | ||||||
|     memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *)); |     memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *)); | ||||||
|     page_flush_tb(); |     page_flush_tb(); | ||||||
|  | @ -566,53 +422,12 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n) | ||||||
|     tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); |     tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline void tb_invalidate(TranslationBlock *tb) |  | ||||||
| { |  | ||||||
|     unsigned int h, n1; |  | ||||||
|     TranslationBlock *tb1, *tb2, **ptb; |  | ||||||
|      |  | ||||||
|     tb_invalidated_flag = 1; |  | ||||||
| 
 |  | ||||||
|     /* remove the TB from the hash list */ |  | ||||||
|     h = tb_hash_func(tb->pc); |  | ||||||
|     ptb = &tb_hash[h]; |  | ||||||
|     for(;;) { |  | ||||||
|         tb1 = *ptb; |  | ||||||
|         /* NOTE: the TB is not necessarily linked in the hash. It
 |  | ||||||
|            indicates that it is not currently used */ |  | ||||||
|         if (tb1 == NULL) |  | ||||||
|             return; |  | ||||||
|         if (tb1 == tb) { |  | ||||||
|             *ptb = tb1->hash_next; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         ptb = &tb1->hash_next; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* suppress this TB from the two jump lists */ |  | ||||||
|     tb_jmp_remove(tb, 0); |  | ||||||
|     tb_jmp_remove(tb, 1); |  | ||||||
| 
 |  | ||||||
|     /* suppress any remaining jumps to this TB */ |  | ||||||
|     tb1 = tb->jmp_first; |  | ||||||
|     for(;;) { |  | ||||||
|         n1 = (long)tb1 & 3; |  | ||||||
|         if (n1 == 2) |  | ||||||
|             break; |  | ||||||
|         tb1 = (TranslationBlock *)((long)tb1 & ~3); |  | ||||||
|         tb2 = tb1->jmp_next[n1]; |  | ||||||
|         tb_reset_jump(tb1, n1); |  | ||||||
|         tb1->jmp_next[n1] = NULL; |  | ||||||
|         tb1 = tb2; |  | ||||||
|     } |  | ||||||
|     tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr) | static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr) | ||||||
| { | { | ||||||
|     PageDesc *p; |     PageDesc *p; | ||||||
|     unsigned int h; |     unsigned int h, n1; | ||||||
|     target_ulong phys_pc; |     target_ulong phys_pc; | ||||||
|  |     TranslationBlock *tb1, *tb2; | ||||||
|      |      | ||||||
|     /* remove the TB from the hash list */ |     /* remove the TB from the hash list */ | ||||||
|     phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); |     phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); | ||||||
|  | @ -632,7 +447,30 @@ static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_ad | ||||||
|         invalidate_page_bitmap(p); |         invalidate_page_bitmap(p); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     tb_invalidate(tb); |     tb_invalidated_flag = 1; | ||||||
|  | 
 | ||||||
|  |     /* remove the TB from the hash list */ | ||||||
|  |     h = tb_jmp_cache_hash_func(tb->pc); | ||||||
|  |     cpu_single_env->tb_jmp_cache[h] = NULL; | ||||||
|  | 
 | ||||||
|  |     /* suppress this TB from the two jump lists */ | ||||||
|  |     tb_jmp_remove(tb, 0); | ||||||
|  |     tb_jmp_remove(tb, 1); | ||||||
|  | 
 | ||||||
|  |     /* suppress any remaining jumps to this TB */ | ||||||
|  |     tb1 = tb->jmp_first; | ||||||
|  |     for(;;) { | ||||||
|  |         n1 = (long)tb1 & 3; | ||||||
|  |         if (n1 == 2) | ||||||
|  |             break; | ||||||
|  |         tb1 = (TranslationBlock *)((long)tb1 & ~3); | ||||||
|  |         tb2 = tb1->jmp_next[n1]; | ||||||
|  |         tb_reset_jump(tb1, n1); | ||||||
|  |         tb1->jmp_next[n1] = NULL; | ||||||
|  |         tb1 = tb2; | ||||||
|  |     } | ||||||
|  |     tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */ | ||||||
|  | 
 | ||||||
|     tb_phys_invalidate_count++; |     tb_phys_invalidate_count++; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1025,57 +863,6 @@ void tb_link_phys(TranslationBlock *tb, | ||||||
|         tb_alloc_page(tb, 1, phys_page2); |         tb_alloc_page(tb, 1, phys_page2); | ||||||
|     else |     else | ||||||
|         tb->page_addr[1] = -1; |         tb->page_addr[1] = -1; | ||||||
| #ifdef DEBUG_TB_CHECK |  | ||||||
|     tb_page_check(); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* link the tb with the other TBs */ |  | ||||||
| void tb_link(TranslationBlock *tb) |  | ||||||
| { |  | ||||||
| #if !defined(CONFIG_USER_ONLY) |  | ||||||
|     { |  | ||||||
|         VirtPageDesc *vp; |  | ||||||
|         target_ulong addr; |  | ||||||
|          |  | ||||||
|         /* save the code memory mappings (needed to invalidate the code) */ |  | ||||||
|         addr = tb->pc & TARGET_PAGE_MASK; |  | ||||||
|         vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); |  | ||||||
| #ifdef DEBUG_TLB_CHECK  |  | ||||||
|         if (vp->valid_tag == virt_valid_tag && |  | ||||||
|             vp->phys_addr != tb->page_addr[0]) { |  | ||||||
|             printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n", |  | ||||||
|                    addr, tb->page_addr[0], vp->phys_addr); |  | ||||||
|         } |  | ||||||
| #endif |  | ||||||
|         vp->phys_addr = tb->page_addr[0]; |  | ||||||
|         if (vp->valid_tag != virt_valid_tag) { |  | ||||||
|             vp->valid_tag = virt_valid_tag; |  | ||||||
| #if !defined(CONFIG_SOFTMMU) |  | ||||||
|             vp->prot = 0; |  | ||||||
| #endif |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         if (tb->page_addr[1] != -1) { |  | ||||||
|             addr += TARGET_PAGE_SIZE; |  | ||||||
|             vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); |  | ||||||
| #ifdef DEBUG_TLB_CHECK  |  | ||||||
|             if (vp->valid_tag == virt_valid_tag && |  | ||||||
|                 vp->phys_addr != tb->page_addr[1]) {  |  | ||||||
|                 printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n", |  | ||||||
|                        addr, tb->page_addr[1], vp->phys_addr); |  | ||||||
|             } |  | ||||||
| #endif |  | ||||||
|             vp->phys_addr = tb->page_addr[1]; |  | ||||||
|             if (vp->valid_tag != virt_valid_tag) { |  | ||||||
|                 vp->valid_tag = virt_valid_tag; |  | ||||||
| #if !defined(CONFIG_SOFTMMU) |  | ||||||
|                 vp->prot = 0; |  | ||||||
| #endif |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
|     tb->jmp_first = (TranslationBlock *)((long)tb | 2); |     tb->jmp_first = (TranslationBlock *)((long)tb | 2); | ||||||
|     tb->jmp_next[0] = NULL; |     tb->jmp_next[0] = NULL; | ||||||
|  | @ -1091,6 +878,10 @@ void tb_link(TranslationBlock *tb) | ||||||
|         tb_reset_jump(tb, 0); |         tb_reset_jump(tb, 0); | ||||||
|     if (tb->tb_next_offset[1] != 0xffff) |     if (tb->tb_next_offset[1] != 0xffff) | ||||||
|         tb_reset_jump(tb, 1); |         tb_reset_jump(tb, 1); | ||||||
|  | 
 | ||||||
|  | #ifdef DEBUG_TB_CHECK | ||||||
|  |     tb_page_check(); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
 | /* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
 | ||||||
|  | @ -1396,8 +1187,7 @@ void tlb_flush(CPUState *env, int flush_global) | ||||||
|         env->tlb_write[1][i].address = -1; |         env->tlb_write[1][i].address = -1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     virt_page_flush(); |     memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); | ||||||
|     memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *)); |  | ||||||
| 
 | 
 | ||||||
| #if !defined(CONFIG_SOFTMMU) | #if !defined(CONFIG_SOFTMMU) | ||||||
|     munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START); |     munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START); | ||||||
|  | @ -1419,9 +1209,7 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) | ||||||
| 
 | 
 | ||||||
| void tlb_flush_page(CPUState *env, target_ulong addr) | void tlb_flush_page(CPUState *env, target_ulong addr) | ||||||
| { | { | ||||||
|     int i, n; |     int i; | ||||||
|     VirtPageDesc *vp; |  | ||||||
|     PageDesc *p; |  | ||||||
|     TranslationBlock *tb; |     TranslationBlock *tb; | ||||||
| 
 | 
 | ||||||
| #if defined(DEBUG_TLB) | #if defined(DEBUG_TLB) | ||||||
|  | @ -1438,26 +1226,13 @@ void tlb_flush_page(CPUState *env, target_ulong addr) | ||||||
|     tlb_flush_entry(&env->tlb_read[1][i], addr); |     tlb_flush_entry(&env->tlb_read[1][i], addr); | ||||||
|     tlb_flush_entry(&env->tlb_write[1][i], addr); |     tlb_flush_entry(&env->tlb_write[1][i], addr); | ||||||
| 
 | 
 | ||||||
|     /* remove from the virtual pc hash table all the TB at this
 |     for(i = 0; i < TB_JMP_CACHE_SIZE; i++) { | ||||||
|        virtual address */ |         tb = env->tb_jmp_cache[i]; | ||||||
|      |         if (tb &&  | ||||||
|     vp = virt_page_find(addr >> TARGET_PAGE_BITS); |             ((tb->pc & TARGET_PAGE_MASK) == addr || | ||||||
|     if (vp && vp->valid_tag == virt_valid_tag) { |              ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr)) { | ||||||
|         p = page_find(vp->phys_addr >> TARGET_PAGE_BITS); |             env->tb_jmp_cache[i] = NULL; | ||||||
|         if (p) { |  | ||||||
|             /* we remove all the links to the TBs in this virtual page */ |  | ||||||
|             tb = p->first_tb; |  | ||||||
|             while (tb != NULL) { |  | ||||||
|                 n = (long)tb & 3; |  | ||||||
|                 tb = (TranslationBlock *)((long)tb & ~3); |  | ||||||
|                 if ((tb->pc & TARGET_PAGE_MASK) == addr || |  | ||||||
|                     ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) { |  | ||||||
|                     tb_invalidate(tb); |  | ||||||
|                 } |  | ||||||
|                 tb = tb->page_next[n]; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|         vp->valid_tag = 0; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| #if !defined(CONFIG_SOFTMMU) | #if !defined(CONFIG_SOFTMMU) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 bellard
						bellard