cpu-exec: fix lock hierarchy for user-mode emulation
tb_lock has to be taken inside the mmap_lock (example: tb_invalidate_phys_range is called by target_mmap), but tb_link_page is taking the mmap_lock and it is called with the tb_lock held. To fix this, take the mmap_lock in tb_find_slow, not in tb_link_page. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									8fd19e6cfd
								
							
						
					
					
						commit
						9fd1a94888
					
				
							
								
								
									
										71
									
								
								cpu-exec.c
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								cpu-exec.c
									
									
									
									
									
								
							| @ -249,10 +249,10 @@ static void cpu_exec_nocache(CPUState *cpu, int max_cycles, | ||||
|     tb_free(tb); | ||||
| } | ||||
| 
 | ||||
| static TranslationBlock *tb_find_slow(CPUState *cpu, | ||||
|                                       target_ulong pc, | ||||
|                                       target_ulong cs_base, | ||||
|                                       uint64_t flags) | ||||
| static TranslationBlock *tb_find_physical(CPUState *cpu, | ||||
|                                           target_ulong pc, | ||||
|                                           target_ulong cs_base, | ||||
|                                           uint64_t flags) | ||||
| { | ||||
|     CPUArchState *env = (CPUArchState *)cpu->env_ptr; | ||||
|     TranslationBlock *tb, **ptb1; | ||||
| @ -269,8 +269,9 @@ static TranslationBlock *tb_find_slow(CPUState *cpu, | ||||
|     ptb1 = &tcg_ctx.tb_ctx.tb_phys_hash[h]; | ||||
|     for(;;) { | ||||
|         tb = *ptb1; | ||||
|         if (!tb) | ||||
|             goto not_found; | ||||
|         if (!tb) { | ||||
|             return NULL; | ||||
|         } | ||||
|         if (tb->pc == pc && | ||||
|             tb->page_addr[0] == phys_page1 && | ||||
|             tb->cs_base == cs_base && | ||||
| @ -282,25 +283,59 @@ static TranslationBlock *tb_find_slow(CPUState *cpu, | ||||
|                 virt_page2 = (pc & TARGET_PAGE_MASK) + | ||||
|                     TARGET_PAGE_SIZE; | ||||
|                 phys_page2 = get_page_addr_code(env, virt_page2); | ||||
|                 if (tb->page_addr[1] == phys_page2) | ||||
|                     goto found; | ||||
|                 if (tb->page_addr[1] == phys_page2) { | ||||
|                     break; | ||||
|                 } | ||||
|             } else { | ||||
|                 goto found; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         ptb1 = &tb->phys_hash_next; | ||||
|     } | ||||
|  not_found: | ||||
|    /* if no translated code available, then translate it now */ | ||||
| 
 | ||||
|     /* Move the TB to the head of the list */ | ||||
|     *ptb1 = tb->phys_hash_next; | ||||
|     tb->phys_hash_next = tcg_ctx.tb_ctx.tb_phys_hash[h]; | ||||
|     tcg_ctx.tb_ctx.tb_phys_hash[h] = tb; | ||||
|     return tb; | ||||
| } | ||||
| 
 | ||||
| static TranslationBlock *tb_find_slow(CPUState *cpu, | ||||
|                                       target_ulong pc, | ||||
|                                       target_ulong cs_base, | ||||
|                                       uint64_t flags) | ||||
| { | ||||
|     TranslationBlock *tb; | ||||
| 
 | ||||
|     tb = tb_find_physical(cpu, pc, cs_base, flags); | ||||
|     if (tb) { | ||||
|         goto found; | ||||
|     } | ||||
| 
 | ||||
| #ifdef CONFIG_USER_ONLY | ||||
|     /* mmap_lock is needed by tb_gen_code, and mmap_lock must be
 | ||||
|      * taken outside tb_lock.  Since we're momentarily dropping | ||||
|      * tb_lock, there's a chance that our desired tb has been | ||||
|      * translated. | ||||
|      */ | ||||
|     tb_unlock(); | ||||
|     mmap_lock(); | ||||
|     tb_lock(); | ||||
|     tb = tb_find_physical(cpu, pc, cs_base, flags); | ||||
|     if (tb) { | ||||
|         mmap_unlock(); | ||||
|         goto found; | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|     /* if no translated code available, then translate it now */ | ||||
|     tb = tb_gen_code(cpu, pc, cs_base, flags, 0); | ||||
| 
 | ||||
|  found: | ||||
|     /* Move the last found TB to the head of the list */ | ||||
|     if (likely(*ptb1)) { | ||||
|         *ptb1 = tb->phys_hash_next; | ||||
|         tb->phys_hash_next = tcg_ctx.tb_ctx.tb_phys_hash[h]; | ||||
|         tcg_ctx.tb_ctx.tb_phys_hash[h] = tb; | ||||
|     } | ||||
| #ifdef CONFIG_USER_ONLY | ||||
|     mmap_unlock(); | ||||
| #endif | ||||
| 
 | ||||
| found: | ||||
|     /* we add the TB in the virtual pc hash table */ | ||||
|     cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb; | ||||
|     return tb; | ||||
|  | ||||
| @ -1375,6 +1375,8 @@ static inline void tb_alloc_page(TranslationBlock *tb, | ||||
| 
 | ||||
| /* add a new TB and link it to the physical page tables. phys_page2 is
 | ||||
|  * (-1) to indicate that only one page contains the TB. | ||||
|  * | ||||
|  * Called with mmap_lock held for user-mode emulation. | ||||
|  */ | ||||
| static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, | ||||
|                          tb_page_addr_t phys_page2) | ||||
| @ -1382,9 +1384,6 @@ static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, | ||||
|     unsigned int h; | ||||
|     TranslationBlock **ptb; | ||||
| 
 | ||||
|     /* Grab the mmap lock to stop another thread invalidating this TB
 | ||||
|        before we are done.  */ | ||||
|     mmap_lock(); | ||||
|     /* add in the physical hash table */ | ||||
|     h = tb_phys_hash_func(phys_pc); | ||||
|     ptb = &tcg_ctx.tb_ctx.tb_phys_hash[h]; | ||||
| @ -1414,7 +1413,6 @@ static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, | ||||
| #ifdef DEBUG_TB_CHECK | ||||
|     tb_page_check(); | ||||
| #endif | ||||
|     mmap_unlock(); | ||||
| } | ||||
| 
 | ||||
| /* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Paolo Bonzini
						Paolo Bonzini