linux-user: fix page_unprotect when host page size > target page size
When the host page size is bigger that the target one, unprotecting a page should: - mark all the target pages corresponding to the host page as writable - invalidate all tb corresponding to the host page (and not the target page) Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
parent
60e99246d6
commit
45d679d643
43
exec.c
43
exec.c
|
@ -2498,8 +2498,8 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
|
||||||
page. Return TRUE if the fault was successfully handled. */
|
page. Return TRUE if the fault was successfully handled. */
|
||||||
int page_unprotect(target_ulong address, unsigned long pc, void *puc)
|
int page_unprotect(target_ulong address, unsigned long pc, void *puc)
|
||||||
{
|
{
|
||||||
unsigned int page_index, prot, pindex;
|
unsigned int prot;
|
||||||
PageDesc *p, *p1;
|
PageDesc *p;
|
||||||
target_ulong host_start, host_end, addr;
|
target_ulong host_start, host_end, addr;
|
||||||
|
|
||||||
/* Technically this isn't safe inside a signal handler. However we
|
/* Technically this isn't safe inside a signal handler. However we
|
||||||
|
@ -2507,38 +2507,37 @@ int page_unprotect(target_ulong address, unsigned long pc, void *puc)
|
||||||
practice it seems to be ok. */
|
practice it seems to be ok. */
|
||||||
mmap_lock();
|
mmap_lock();
|
||||||
|
|
||||||
host_start = address & qemu_host_page_mask;
|
p = page_find(address >> TARGET_PAGE_BITS);
|
||||||
page_index = host_start >> TARGET_PAGE_BITS;
|
if (!p) {
|
||||||
p1 = page_find(page_index);
|
|
||||||
if (!p1) {
|
|
||||||
mmap_unlock();
|
mmap_unlock();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
host_end = host_start + qemu_host_page_size;
|
|
||||||
p = p1;
|
|
||||||
prot = 0;
|
|
||||||
for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
|
|
||||||
prot |= p->flags;
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
/* if the page was really writable, then we change its
|
/* if the page was really writable, then we change its
|
||||||
protection back to writable */
|
protection back to writable */
|
||||||
if (prot & PAGE_WRITE_ORG) {
|
if ((p->flags & PAGE_WRITE_ORG) && !(p->flags & PAGE_WRITE)) {
|
||||||
pindex = (address - host_start) >> TARGET_PAGE_BITS;
|
host_start = address & qemu_host_page_mask;
|
||||||
if (!(p1[pindex].flags & PAGE_WRITE)) {
|
host_end = host_start + qemu_host_page_size;
|
||||||
mprotect((void *)g2h(host_start), qemu_host_page_size,
|
|
||||||
(prot & PAGE_BITS) | PAGE_WRITE);
|
prot = 0;
|
||||||
p1[pindex].flags |= PAGE_WRITE;
|
for (addr = host_start ; addr < host_end ; addr += TARGET_PAGE_SIZE) {
|
||||||
|
p = page_find(addr >> TARGET_PAGE_BITS);
|
||||||
|
p->flags |= PAGE_WRITE;
|
||||||
|
prot |= p->flags;
|
||||||
|
|
||||||
/* and since the content will be modified, we must invalidate
|
/* and since the content will be modified, we must invalidate
|
||||||
the corresponding translated code. */
|
the corresponding translated code. */
|
||||||
tb_invalidate_phys_page(address, pc, puc);
|
tb_invalidate_phys_page(addr, pc, puc);
|
||||||
#ifdef DEBUG_TB_CHECK
|
#ifdef DEBUG_TB_CHECK
|
||||||
tb_invalidate_check(address);
|
tb_invalidate_check(addr);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
mprotect((void *)g2h(host_start), qemu_host_page_size,
|
||||||
|
prot & PAGE_BITS);
|
||||||
|
|
||||||
mmap_unlock();
|
mmap_unlock();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mmap_unlock();
|
mmap_unlock();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue