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:
Alexander Graf 2012-05-10 22:40:10 +00:00 committed by Blue Swirl
parent 4636b9d146
commit 77a8f1a512
3 changed files with 24 additions and 1 deletions

View File

@ -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
View File

@ -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

View File

@ -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;
}