summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2010-03-10 15:57:04 -0800
committerPaul Brook <paul@codesourcery.com>2010-03-12 16:31:32 +0000
commit376a790970de7e84170ee9360b6ff53ecfa4a1be (patch)
treeb0e0a267364b3026c48fe5ba809f008a7a68c8cb
parent5cd2c5b6ad75c46d40118ac67c0c09d4e7930a65 (diff)
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>
-rw-r--r--exec.c54
1 files changed, 36 insertions, 18 deletions
diff --git a/exec.c b/exec.c
index 3a1fcd7bf..246e9701f 100644
--- a/exec.c
+++ b/exec.c
@@ -2315,27 +2315,35 @@ int page_get_flags(target_ulong address)
return p->flags;
}
-/* modify the flags of a page and invalidate the code if
- necessary. The flag PAGE_WRITE_ORG is positioned automatically
- depending on PAGE_WRITE */
+/* Modify the flags of a page and invalidate the code if necessary.
+ The flag PAGE_WRITE_ORG is positioned automatically depending
+ on PAGE_WRITE. The mmap_lock should already be held. */
void page_set_flags(target_ulong start, target_ulong end, int flags)
{
- PageDesc *p;
- target_ulong addr;
+ target_ulong addr, len;
+
+ /* 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;
end = TARGET_PAGE_ALIGN(end);
- if (flags & PAGE_WRITE)
+
+ if (flags & PAGE_WRITE) {
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
- address space. */
- if (!p)
- return;
- /* if the write protection is set, then we invalidate the code
- inside */
+ }
+
+ for (addr = start, len = end - start;
+ len != 0;
+ len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
+ PageDesc *p = page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
+
+ /* If the write protection bit is set, then we invalidate
+ the code inside. */
if (!(p->flags & PAGE_WRITE) &&
(flags & PAGE_WRITE) &&
p->first_tb) {
@@ -2351,14 +2359,24 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
target_ulong end;
target_ulong addr;
- if (start + len < start)
- /* we've wrapped around */
+ /* 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(start < (1ul << L1_MAP_ADDR_SPACE_BITS));
+#endif
+
+ if (start + len - 1 < start) {
+ /* We've wrapped around. */
return -1;
+ }
end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
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);
if( !p )
return -1;