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:
Richard Henderson 2010-03-10 15:57:04 -08:00 committed by Paul Brook
parent 5cd2c5b6ad
commit 376a790970

54
exec.c
View file

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