aboutsummaryrefslogtreecommitdiff
path: root/linux-user/elfload.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/elfload.c')
-rw-r--r--linux-user/elfload.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index ebc663ea0b..475d243f3b 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -2101,6 +2101,50 @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr,
}
}
+/**
+ * pgd_find_hole_fallback: potential mmap address
+ * @guest_size: size of available space
+ * @brk: location of break
+ * @align: memory alignment
+ *
+ * This is a fallback method for finding a hole in the host address
+ * space if we don't have the benefit of being able to access
+ * /proc/self/map. It can potentially take a very long time as we can
+ * only dumbly iterate up the host address space seeing if the
+ * allocation would work.
+ */
+static uintptr_t pgd_find_hole_fallback(uintptr_t guest_size, uintptr_t brk, long align)
+{
+ uintptr_t base;
+
+ /* Start (aligned) at the bottom and work our way up */
+ base = ROUND_UP(mmap_min_addr, align);
+
+ while (true) {
+ uintptr_t align_start, end;
+ align_start = ROUND_UP(base, align);
+ end = align_start + guest_size;
+
+ /* if brk is anywhere in the range give ourselves some room to grow. */
+ if (align_start <= brk && brk < end) {
+ base = brk + (16 * MiB);
+ continue;
+ } else if (align_start + guest_size < align_start) {
+ /* we have run out of space */
+ return -1;
+ } else {
+ int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE | MAP_FIXED;
+ void * mmap_start = mmap((void *) align_start, guest_size,
+ PROT_NONE, flags, -1, 0);
+ if (mmap_start != MAP_FAILED) {
+ munmap((void *) align_start, guest_size);
+ return (uintptr_t) mmap_start;
+ }
+ base += qemu_host_page_size;
+ }
+ }
+}
+
/* Return value for guest_base, or -1 if no hole found. */
static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size,
long align)
@@ -2116,6 +2160,10 @@ static uintptr_t pgb_find_hole(uintptr_t guest_loaddr, uintptr_t guest_size,
/* Read brk after we've read the maps, which will malloc. */
brk = (uintptr_t)sbrk(0);
+ if (!maps) {
+ return pgd_find_hole_fallback(guest_size, brk, align);
+ }
+
/* The first hole is before the first map entry. */
this_start = mmap_min_addr;