Fix last page errors in page_check_range and page_set_flags.
The addr < end comparison prevents iterating over the last page in the guest address space; an iteration based on length avoids this problem. At the same time, assert that the given address is in the guest address space. Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
5cd2c5b6ad
commit
376a790970
54
exec.c
54
exec.c
|
@ -2315,27 +2315,35 @@ int page_get_flags(target_ulong address)
|
||||||
return p->flags;
|
return p->flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* modify the flags of a page and invalidate the code if
|
/* Modify the flags of a page and invalidate the code if necessary.
|
||||||
necessary. The flag PAGE_WRITE_ORG is positioned automatically
|
The flag PAGE_WRITE_ORG is positioned automatically depending
|
||||||
depending on PAGE_WRITE */
|
on PAGE_WRITE. The mmap_lock should already be held. */
|
||||||
void page_set_flags(target_ulong start, target_ulong end, int flags)
|
void page_set_flags(target_ulong start, target_ulong end, int flags)
|
||||||
{
|
{
|
||||||
PageDesc *p;
|
target_ulong addr, len;
|
||||||
target_ulong addr;
|
|
||||||
|
/* This function should never be called with addresses outside the
|
||||||
|
guest address space. If this assert fires, it probably indicates
|
||||||
|
a missing call to h2g_valid. */
|
||||||
|
#if HOST_LONG_BITS > L1_MAP_ADDR_SPACE_BITS
|
||||||
|
assert(end < (1ul << L1_MAP_ADDR_SPACE_BITS));
|
||||||
|
#endif
|
||||||
|
assert(start < end);
|
||||||
|
|
||||||
/* mmap_lock should already be held. */
|
|
||||||
start = start & TARGET_PAGE_MASK;
|
start = start & TARGET_PAGE_MASK;
|
||||||
end = TARGET_PAGE_ALIGN(end);
|
end = TARGET_PAGE_ALIGN(end);
|
||||||
if (flags & PAGE_WRITE)
|
|
||||||
|
if (flags & PAGE_WRITE) {
|
||||||
flags |= PAGE_WRITE_ORG;
|
flags |= PAGE_WRITE_ORG;
|
||||||
for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
|
}
|
||||||
p = page_find_alloc(addr >> TARGET_PAGE_BITS);
|
|
||||||
/* We may be called for host regions that are outside guest
|
for (addr = start, len = end - start;
|
||||||
address space. */
|
len != 0;
|
||||||
if (!p)
|
len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
|
||||||
return;
|
PageDesc *p = page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
|
||||||
/* if the write protection is set, then we invalidate the code
|
|
||||||
inside */
|
/* If the write protection bit is set, then we invalidate
|
||||||
|
the code inside. */
|
||||||
if (!(p->flags & PAGE_WRITE) &&
|
if (!(p->flags & PAGE_WRITE) &&
|
||||||
(flags & PAGE_WRITE) &&
|
(flags & PAGE_WRITE) &&
|
||||||
p->first_tb) {
|
p->first_tb) {
|
||||||
|
@ -2351,14 +2359,24 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
|
||||||
target_ulong end;
|
target_ulong end;
|
||||||
target_ulong addr;
|
target_ulong addr;
|
||||||
|
|
||||||
if (start + len < start)
|
/* This function should never be called with addresses outside the
|
||||||
/* we've wrapped around */
|
guest address space. If this assert fires, it probably indicates
|
||||||
|
a missing call to h2g_valid. */
|
||||||
|
#if HOST_LONG_BITS > L1_MAP_ADDR_SPACE_BITS
|
||||||
|
assert(start < (1ul << L1_MAP_ADDR_SPACE_BITS));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (start + len - 1 < start) {
|
||||||
|
/* We've wrapped around. */
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
|
end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
|
||||||
start = start & TARGET_PAGE_MASK;
|
start = start & TARGET_PAGE_MASK;
|
||||||
|
|
||||||
for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
|
for (addr = start, len = end - start;
|
||||||
|
len != 0;
|
||||||
|
len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
|
||||||
p = page_find(addr >> TARGET_PAGE_BITS);
|
p = page_find(addr >> TARGET_PAGE_BITS);
|
||||||
if( !p )
|
if( !p )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
Loading…
Reference in a new issue