Patchwork [6/6] Fix last page errors in page_check_range and page_set_flags.

login
register
mail settings
Submitter Richard Henderson
Date March 10, 2010, 11:57 p.m.
Message ID <724d07612e819186ba1e8973df8af1b06c7b259f.1268265556.git.rth@twiddle.net>
Download mbox | patch
Permalink /patch/47290/
State New
Headers show

Comments

Richard Henderson - March 10, 2010, 11:57 p.m.
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>
---
 exec.c |   54 ++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 36 insertions(+), 18 deletions(-)

Patch

diff --git a/exec.c b/exec.c
index 5455a74..245535a 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;