linux-user: Fix stale tbs after mmap
If we execute linux-user code that does the following: * A = mmap() * execute code in A * munmap(A) * B = mmap(), but mmap returns the same address as A * execute code in B we end up executing a stale cached tb that contains translated code from A, while we want new code from B. This patch adds a TB flush for mmap'ed regions, before we return them, avoiding the whole issue. It also adds a flush for munmap, so that we don't execute stale TBs instead of getting a segfault. Reported-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Alexander Graf <agraf@suse.de> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Acked-by: Riku Voipio <riku.voipio@linaro.org> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
This commit is contained in:
parent
4636b9d146
commit
77a8f1a512
@ -96,6 +96,8 @@ void QEMU_NORETURN cpu_loop_exit(CPUArchState *env1);
|
||||
int page_unprotect(target_ulong address, uintptr_t pc, void *puc);
|
||||
void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
|
||||
int is_cpu_write_access);
|
||||
void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end,
|
||||
int is_cpu_write_access);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* cputlb.c */
|
||||
void tlb_flush_page(CPUArchState *env, target_ulong addr);
|
||||
|
17
exec.c
17
exec.c
@ -1075,6 +1075,23 @@ TranslationBlock *tb_gen_code(CPUArchState *env,
|
||||
return tb;
|
||||
}
|
||||
|
||||
/*
|
||||
* invalidate all TBs which intersect with the target physical pages
|
||||
* starting in range [start;end[. NOTE: start and end may refer to
|
||||
* different physical pages. 'is_cpu_write_access' should be true if called
|
||||
* from a real cpu write access: the virtual CPU will exit the current
|
||||
* TB if code is modified inside this TB.
|
||||
*/
|
||||
void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end,
|
||||
int is_cpu_write_access)
|
||||
{
|
||||
while (start < end) {
|
||||
tb_invalidate_phys_page_range(start, end, is_cpu_write_access);
|
||||
start &= TARGET_PAGE_MASK;
|
||||
start += TARGET_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* invalidate all TBs which intersect with the target physical page
|
||||
starting in range [start;end[. NOTE: start and end must refer to
|
||||
the same physical page. 'is_cpu_write_access' should be true if called
|
||||
|
@ -573,6 +573,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
|
||||
page_dump(stdout);
|
||||
printf("\n");
|
||||
#endif
|
||||
tb_invalidate_phys_range(start, start + len, 0);
|
||||
mmap_unlock();
|
||||
return start;
|
||||
fail:
|
||||
@ -675,8 +676,10 @@ int target_munmap(abi_ulong start, abi_ulong len)
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
if (ret == 0) {
|
||||
page_set_flags(start, start + len, 0);
|
||||
tb_invalidate_phys_range(start, start + len, 0);
|
||||
}
|
||||
mmap_unlock();
|
||||
return ret;
|
||||
}
|
||||
@ -754,6 +757,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
|
||||
page_set_flags(old_addr, old_addr + old_size, 0);
|
||||
page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
|
||||
}
|
||||
tb_invalidate_phys_range(new_addr, new_addr + new_size, 0);
|
||||
mmap_unlock();
|
||||
return new_addr;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user