summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--linux-user/main.c1
-rw-r--r--linux-user/mmap.c35
-rw-r--r--linux-user/qemu.h1
3 files changed, 26 insertions, 11 deletions
diff --git a/linux-user/main.c b/linux-user/main.c
index 25701403e4..aa95db3a6d 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3420,6 +3420,7 @@ int main(int argc, char **argv, char **envp)
             guest_base = HOST_PAGE_ALIGN((unsigned long)p);
         }
         qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
+        mmap_next_start = reserved_va;
     }
 
     if (reserved_va || have_guest_base) {
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 994c02bb77..7125d1cd4b 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -212,7 +212,7 @@ static int mmap_frag(abi_ulong real_start,
 #else
 # define TASK_UNMAPPED_BASE  0x40000000
 #endif
-static abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
+abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
 
 unsigned long last_brk;
 
@@ -222,7 +222,7 @@ unsigned long last_brk;
 static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
 {
     abi_ulong addr;
-    abi_ulong last_addr;
+    abi_ulong end_addr;
     int prot;
     int looped = 0;
 
@@ -230,25 +230,38 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
         return (abi_ulong)-1;
     }
 
-    last_addr = start;
-    for (addr = start; last_addr + size != addr; addr += qemu_host_page_size) {
-        if (last_addr + size >= RESERVED_VA
-            || (abi_ulong)(last_addr + size) < last_addr) {
+    size = HOST_PAGE_ALIGN(size);
+    end_addr = start + size;
+    if (end_addr > RESERVED_VA) {
+        end_addr = RESERVED_VA;
+    }
+    addr = end_addr - qemu_host_page_size;
+
+    while (1) {
+        if (addr > end_addr) {
             if (looped) {
                 return (abi_ulong)-1;
             }
-            last_addr = qemu_host_page_size;
-            addr = 0;
+            end_addr = RESERVED_VA;
+            addr = end_addr - qemu_host_page_size;
             looped = 1;
             continue;
         }
         prot = page_get_flags(addr);
         if (prot) {
-            last_addr = addr + qemu_host_page_size;
+            end_addr = addr;
+        }
+        if (addr + size == end_addr) {
+            break;
         }
+        addr -= qemu_host_page_size;
+    }
+
+    if (start == mmap_next_start) {
+        mmap_next_start = addr;
     }
-    mmap_next_start = addr;
-    return last_addr;
+
+    return addr;
 }
 #endif
 
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 68895671ed..dd74cc0510 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -251,6 +251,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
                        abi_ulong new_addr);
 int target_msync(abi_ulong start, abi_ulong len, int flags);
 extern unsigned long last_brk;
+extern abi_ulong mmap_next_start;
 void mmap_lock(void);
 void mmap_unlock(void);
 abi_ulong mmap_find_vma(abi_ulong, abi_ulong);