Prepare to share probe_guest_base with bsd-user.

Create a linux_probe_guest_base wrapper with the portions
of probe_guest_base that are linux specific: managing the
commpage for various targets.

Signed-off-by: Richard Henderson <[email protected]>
---
 include/user/probe-guest-base.h |  37 ++++
 linux-user/user-internals.h     |  10 +-
 common-user/probe-guest-base.c  | 343 ++++++++++++++++++++++++++++++++
 linux-user/elfload.c            | 337 +------------------------------
 linux-user/flatload.c           |   2 +-
 common-user/meson.build         |   1 +
 6 files changed, 392 insertions(+), 338 deletions(-)
 create mode 100644 include/user/probe-guest-base.h
 create mode 100644 common-user/probe-guest-base.c

diff --git a/include/user/probe-guest-base.h b/include/user/probe-guest-base.h
new file mode 100644
index 0000000000..d7492ef46c
--- /dev/null
+++ b/include/user/probe-guest-base.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef USER_PROBE_GUEST_BASE_H
+#define USER_PROBE_GUEST_BASE_H
+
+#ifndef CONFIG_USER_ONLY
+#error Cannot include this header from system emulation
+#endif
+
+#include "exec/vaddr.h"
+
+typedef struct PGBRange {
+    vaddr lo;
+    vaddr hi;
+} PGBRange;
+
+/**
+ * probe_guest_base:
+ * @image_name: the executable being loaded
+ * @image_range: the fixed addresses within the executable
+ *
+ * Creates the initial guest address space in the host memory space.
+ *
+ * If @image_range is NULL, then no address in the executable is fixed,
+ * i.e. it is fully relocatable.
+ *
+ * This function will not return if a valid value for guest_base
+ * cannot be chosen.  On return, the executable loader can expect
+ *
+ *    target_mmap(i->lo, i->hi - i->lo + 1, ...)
+ *
+ * to succeed.
+ */
+void probe_guest_base(const char *image_name, const PGBRange *image_range,
+                      const PGBRange *commpage_range);
+
+#endif
diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h
index bc6b9f44e6..71f72002b6 100644
--- a/linux-user/user-internals.h
+++ b/linux-user/user-internals.h
@@ -22,6 +22,7 @@
 #include "qemu/log.h"
 #include "exec/tb-flush.h"
 #include "exec/translation-block.h"
+#include "user/probe-guest-base.h"
 
 extern char *exec_path;
 extern char real_exec_path[PATH_MAX];
@@ -74,13 +75,8 @@ void clone_fork_end(bool child);
 void fork_start(void);
 void fork_end(pid_t pid);
 
-typedef struct PGBRange {
-    vaddr lo;
-    vaddr hi;
-} PGBRange;
-
 /**
- * probe_guest_base:
+ * linux_probe_guest_base:
  * @image_name: the executable being loaded
  * @image_range: the fixed addresses within the executable
  *
@@ -96,7 +92,7 @@ typedef struct PGBRange {
  *
  * to succeed.
  */
-void probe_guest_base(const char *image_name, const PGBRange *image_range);
+void linux_probe_guest_base(const char *image_name, const PGBRange 
*image_range);
 
 /* syscall.c */
 int host_to_target_waitstatus(int status);
diff --git a/common-user/probe-guest-base.c b/common-user/probe-guest-base.c
new file mode 100644
index 0000000000..77722fe63f
--- /dev/null
+++ b/common-user/probe-guest-base.c
@@ -0,0 +1,343 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/units.h"
+#include "qemu/target-info.h"
+#include "qemu/log.h"
+#include "user/guest-base.h"
+#include "user/mmap-min-addr.h"
+#include "user/guest-host.h"
+#include "user/probe-guest-base.h"
+#include "user/selfmap.h"
+#include "exec/target_page.h"
+#include <sys/shm.h>
+
+/* Linux and FreeBSD use different flags to express NOREPLACE. */
+#ifdef __FreeBSD__
+#define MAP_FIXED_NOREPLACE  (MAP_FIXED | MAP_EXCL)
+#endif
+
+/**
+ * pgb_try_mmap:
+ * @addr: host start address
+ * @addr_last: host last address
+ * @keep: do not unmap the probe region
+ *
+ * Return 1 if [@addr, @addr_last] is not mapped in the host,
+ * return 0 if it is not available to map, and -1 on mmap error.
+ * If @keep, the region is left mapped on success, otherwise unmapped.
+ */
+static int pgb_try_mmap(uintptr_t addr, uintptr_t addr_last, bool keep)
+{
+    size_t size = addr_last - addr + 1;
+    void *p = mmap((void *)addr, size, PROT_NONE,
+                   MAP_ANONYMOUS | MAP_PRIVATE |
+                   MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0);
+    int ret;
+
+    if (p == MAP_FAILED) {
+        return errno == EEXIST ? 0 : -1;
+    }
+    ret = p == (void *)addr;
+    if (!keep || !ret) {
+        munmap(p, size);
+    }
+    return ret;
+}
+
+/**
+ * pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t size, uintptr_t brk)
+ * @addr: host address
+ * @addr_last: host last address
+ * @brk: host brk
+ *
+ * Like pgb_try_mmap, but additionally reserve some memory following brk.
+ */
+static int pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t addr_last,
+                                 uintptr_t brk, bool keep)
+{
+    uintptr_t brk_last = brk + 16 * MiB - 1;
+
+    /* Do not map anything close to the host brk. */
+    if (addr <= brk_last && brk <= addr_last) {
+        return 0;
+    }
+    return pgb_try_mmap(addr, addr_last, keep);
+}
+
+/**
+ * pgb_try_mmap_set:
+ * @ga: set of guest addrs
+ * @base: guest_base
+ * @brk: host brk
+ *
+ * Return true if all @ga can be mapped by the host at @base.
+ * On success, retain the mapping at index 0 for reserved_va.
+ */
+
+typedef struct PGBAddrs {
+    PGBRange bounds[3];
+    int nbounds;
+} PGBAddrs;
+
+static bool pgb_try_mmap_set(const PGBAddrs *ga, uintptr_t base, uintptr_t brk)
+{
+    for (int i = ga->nbounds - 1; i >= 0; --i) {
+        if (pgb_try_mmap_skip_brk(ga->bounds[i].lo + base,
+                                  ga->bounds[i].hi + base,
+                                  brk, i == 0 && reserved_va) <= 0) {
+            return false;
+        }
+    }
+    return true;
+}
+
+/**
+ * pgb_addr_set:
+ * @ga: output set of guest addrs
+ * @image_range: fixed guest image addresses
+ * @identity: create for identity mapping
+ *
+ * Fill in @ga with the image, COMMPAGE and NULL page.
+ */
+static bool pgb_addr_set(PGBAddrs *ga, const PGBRange *image_range,
+                         const PGBRange *commpage_range, bool try_identity)
+{
+    int n;
+
+    /*
+     * With a low commpage, or a guest mapped very low,
+     * we may not be able to use the identity map.
+     */
+    if (try_identity) {
+        if (commpage_range && commpage_range->lo < mmap_min_addr) {
+            return false;
+        }
+        if (image_range && image_range->lo < mmap_min_addr) {
+            return false;
+        }
+    }
+
+    memset(ga, 0, sizeof(*ga));
+    n = 0;
+
+    if (reserved_va) {
+        ga->bounds[n].lo = try_identity ? mmap_min_addr : 0;
+        ga->bounds[n].hi = reserved_va;
+        n++;
+        /* Low COMMPAGE and NULL handled by reserving from 0. */
+    } else {
+        /* Add any low COMMPAGE or NULL page. */
+        if (!try_identity || (commpage_range && commpage_range->lo == 0)) {
+            ga->bounds[n].lo = 0;
+            ga->bounds[n].hi = TARGET_PAGE_SIZE - 1;
+            n++;
+        }
+
+        /* Add the guest image for ET_EXEC. */
+        if (image_range) {
+            ga->bounds[n++] = *image_range;
+        }
+    }
+
+    /* Add any high COMMPAGE not covered by reserved_va. */
+    if (commpage_range && reserved_va < commpage_range->hi) {
+        ga->bounds[n].lo = commpage_range->lo & qemu_real_host_page_mask();
+        ga->bounds[n].hi = commpage_range->hi;
+        n++;
+    }
+
+    ga->nbounds = n;
+    return true;
+}
+
+static void pgb_fail_in_use(const char *image_name)
+{
+    error_report("%s: requires virtual address space that is in use "
+                 "(omit the -B option or choose a different value)",
+                 image_name);
+    exit(EXIT_FAILURE);
+}
+
+static void pgb_fixed(const char *image_name, const PGBRange *image_range,
+                      const PGBRange *commpage_range, uintptr_t align)
+{
+    PGBAddrs ga;
+    uintptr_t brk = (uintptr_t)sbrk(0);
+
+    if (!QEMU_IS_ALIGNED(guest_base, align)) {
+        fprintf(stderr, "Requested guest base %p does not satisfy "
+                "host minimum alignment (0x%" PRIxPTR ")\n",
+                (void *)guest_base, align);
+        exit(EXIT_FAILURE);
+    }
+
+    if (!pgb_addr_set(&ga, image_range, commpage_range, !guest_base)
+        || !pgb_try_mmap_set(&ga, guest_base, brk)) {
+        pgb_fail_in_use(image_name);
+    }
+}
+
+/**
+ * pgb_find_fallback:
+ *
+ * This is a fallback method for finding holes 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 pgb_find_fallback(const PGBAddrs *ga, uintptr_t align,
+                                   uintptr_t brk)
+{
+    /* TODO: come up with a better estimate of how much to skip. */
+    uintptr_t skip = sizeof(uintptr_t) == 4 ? MiB : GiB;
+
+    for (uintptr_t base = skip; ; base += skip) {
+        base = ROUND_UP(base, align);
+        if (pgb_try_mmap_set(ga, base, brk)) {
+            return base;
+        }
+        if (base >= -skip) {
+            return -1;
+        }
+    }
+}
+
+static uintptr_t pgb_try_itree(const PGBAddrs *ga, uintptr_t base,
+                               IntervalTreeRoot *root)
+{
+    for (int i = ga->nbounds - 1; i >= 0; --i) {
+        uintptr_t s = base + ga->bounds[i].lo;
+        uintptr_t l = base + ga->bounds[i].hi;
+        IntervalTreeNode *n;
+
+        if (l < s) {
+            /* Wraparound. Skip to advance S to mmap_min_addr. */
+            return mmap_min_addr - s;
+        }
+
+        n = interval_tree_iter_first(root, s, l);
+        if (n != NULL) {
+            /* Conflict.  Skip to advance S to LAST + 1. */
+            return n->last - s + 1;
+        }
+    }
+    return 0;  /* success */
+}
+
+static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root,
+                                uintptr_t align, uintptr_t brk)
+{
+    uintptr_t last = sizeof(uintptr_t) == 4 ? MiB : GiB;
+    uintptr_t base, skip;
+
+    while (true) {
+        base = ROUND_UP(last, align);
+        if (base < last) {
+            return -1;
+        }
+
+        skip = pgb_try_itree(ga, base, root);
+        if (skip == 0) {
+            break;
+        }
+
+        last = base + skip;
+        if (last < base) {
+            return -1;
+        }
+    }
+
+    /*
+     * We've chosen 'base' based on holes in the interval tree,
+     * but we don't yet know if it is a valid host address.
+     * Because it is the first matching hole, if the host addresses
+     * are invalid we know there are no further matches.
+     */
+    return pgb_try_mmap_set(ga, base, brk) ? base : -1;
+}
+
+static void pgb_dynamic(const char *image_name, const PGBRange *image_range,
+                        const PGBRange *commpage_range, uintptr_t align)
+{
+    IntervalTreeRoot *root;
+    uintptr_t brk, ret;
+    PGBAddrs ga;
+
+    /* Try the identity map first. */
+    if (pgb_addr_set(&ga, image_range, commpage_range, true)) {
+        brk = (uintptr_t)sbrk(0);
+        if (pgb_try_mmap_set(&ga, 0, brk)) {
+            guest_base = 0;
+            return;
+        }
+    }
+
+    /*
+     * Rebuild the address set for non-identity map.
+     * This differs in the mapping of the guest NULL page.
+     */
+    pgb_addr_set(&ga, image_range, commpage_range, false);
+
+    root = read_self_maps();
+
+    /* Read brk after we've read the maps, which will malloc. */
+    brk = (uintptr_t)sbrk(0);
+
+    if (!root) {
+        ret = pgb_find_fallback(&ga, align, brk);
+    } else {
+        /*
+         * Reserve the area close to the host brk.
+         * This will be freed with the rest of the tree.
+         */
+        IntervalTreeNode *b = g_new0(IntervalTreeNode, 1);
+        b->start = brk;
+        b->last = brk + 16 * MiB - 1;
+        interval_tree_insert(b, root);
+
+        ret = pgb_find_itree(&ga, root, align, brk);
+        free_self_maps(root);
+    }
+
+    if (ret == -1) {
+        int w = target_long_bits() / 4;
+
+        error_report("%s: Unable to find a guest_base to satisfy all "
+                     "guest address mapping requirements", image_name);
+
+        for (int i = 0; i < ga.nbounds; ++i) {
+            error_printf("  %0*" VADDR_PRIx "-%0*" VADDR_PRIx "\n",
+                         w, ga.bounds[i].lo,
+                         w, ga.bounds[i].hi);
+        }
+        exit(EXIT_FAILURE);
+    }
+    guest_base = ret;
+}
+
+void probe_guest_base(const char *image_name, const PGBRange *image_range,
+                      const PGBRange *commpage_range)
+{
+    /* In order to use host shmat, we must be able to honor SHMLBA.  */
+    uintptr_t align = MAX(SHMLBA, TARGET_PAGE_SIZE);
+
+    /* Sanity check the guest binary. */
+    if (reserved_va && image_range && image_range->hi > reserved_va) {
+        error_report("%s: requires more than reserved virtual "
+                     "address space (0x%" VADDR_PRIx " > 0x%lx)",
+                     image_name, image_range->hi, reserved_va);
+        exit(EXIT_FAILURE);
+    }
+
+    if (have_guest_base) {
+        pgb_fixed(image_name, image_range, commpage_range, align);
+    } else {
+        pgb_dynamic(image_name, image_range, commpage_range, align);
+    }
+
+    assert(QEMU_IS_ALIGNED(guest_base, align));
+    qemu_log_mask(CPU_LOG_PAGE, "Locating guest address space "
+                  "@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
+}
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 0450aa13d8..4ab1a7b78c 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -4,7 +4,6 @@
 
 #include <sys/prctl.h>
 #include <sys/resource.h>
-#include <sys/shm.h>
 
 #include "qemu.h"
 #include "user/tswap-target.h"
@@ -13,8 +12,6 @@
 #include "exec/mmap-lock.h"
 #include "exec/translation-block.h"
 #include "exec/tswap.h"
-#include "user/guest-base.h"
-#include "user/mmap-min-addr.h"
 #include "user-internals.h"
 #include "signal-common.h"
 #include "loader.h"
@@ -25,7 +22,6 @@
 #include "qemu/queue.h"
 #include "qemu/guest-random.h"
 #include "qemu/units.h"
-#include "user/selfmap.h"
 #include "qemu/lockable.h"
 #include "qapi/error.h"
 #include "qemu/error-report.h"
@@ -758,310 +754,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, 
int envc,
     return sp;
 }
 
-#if !defined(COMMPAGE) && !defined(HAVE_GUEST_COMMPAGE)
-bool init_guest_commpage(void) { return true; }
-#endif
-
-/**
- * pgb_try_mmap:
- * @addr: host start address
- * @addr_last: host last address
- * @keep: do not unmap the probe region
- *
- * Return 1 if [@addr, @addr_last] is not mapped in the host,
- * return 0 if it is not available to map, and -1 on mmap error.
- * If @keep, the region is left mapped on success, otherwise unmapped.
- */
-static int pgb_try_mmap(uintptr_t addr, uintptr_t addr_last, bool keep)
-{
-    size_t size = addr_last - addr + 1;
-    void *p = mmap((void *)addr, size, PROT_NONE,
-                   MAP_ANONYMOUS | MAP_PRIVATE |
-                   MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0);
-    int ret;
-
-    if (p == MAP_FAILED) {
-        return errno == EEXIST ? 0 : -1;
-    }
-    ret = p == (void *)addr;
-    if (!keep || !ret) {
-        munmap(p, size);
-    }
-    return ret;
-}
-
-/**
- * pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t size, uintptr_t brk)
- * @addr: host address
- * @addr_last: host last address
- * @brk: host brk
- *
- * Like pgb_try_mmap, but additionally reserve some memory following brk.
- */
-static int pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t addr_last,
-                                 uintptr_t brk, bool keep)
-{
-    uintptr_t brk_last = brk + 16 * MiB - 1;
-
-    /* Do not map anything close to the host brk. */
-    if (addr <= brk_last && brk <= addr_last) {
-        return 0;
-    }
-    return pgb_try_mmap(addr, addr_last, keep);
-}
-
-/**
- * pgb_try_mmap_set:
- * @ga: set of guest addrs
- * @base: guest_base
- * @brk: host brk
- *
- * Return true if all @ga can be mapped by the host at @base.
- * On success, retain the mapping at index 0 for reserved_va.
- */
-
-typedef struct PGBAddrs {
-    PGBRange bounds[3];
-    int nbounds;
-} PGBAddrs;
-
-static bool pgb_try_mmap_set(const PGBAddrs *ga, uintptr_t base, uintptr_t brk)
-{
-    for (int i = ga->nbounds - 1; i >= 0; --i) {
-        if (pgb_try_mmap_skip_brk(ga->bounds[i].lo + base,
-                                  ga->bounds[i].hi + base,
-                                  brk, i == 0 && reserved_va) <= 0) {
-            return false;
-        }
-    }
-    return true;
-}
-
-/**
- * pgb_addr_set:
- * @ga: output set of guest addrs
- * @image_range: fixed guest image addresses
- * @identity: create for identity mapping
- *
- * Fill in @ga with the image, COMMPAGE and NULL page.
- */
-static bool pgb_addr_set(PGBAddrs *ga, const PGBRange *image_range,
-                         const PGBRange *commpage_range, bool try_identity)
-{
-    int n;
-
-    /*
-     * With a low commpage, or a guest mapped very low,
-     * we may not be able to use the identity map.
-     */
-    if (try_identity) {
-        if (commpage_range && commpage_range->lo < mmap_min_addr) {
-            return false;
-        }
-        if (image_range && image_range->lo < mmap_min_addr) {
-            return false;
-        }
-    }
-
-    memset(ga, 0, sizeof(*ga));
-    n = 0;
-
-    if (reserved_va) {
-        ga->bounds[n].lo = try_identity ? mmap_min_addr : 0;
-        ga->bounds[n].hi = reserved_va;
-        n++;
-        /* Low COMMPAGE and NULL handled by reserving from 0. */
-    } else {
-        /* Add any low COMMPAGE or NULL page. */
-        if (!try_identity || (commpage_range && commpage_range->lo == 0)) {
-            ga->bounds[n].lo = 0;
-            ga->bounds[n].hi = TARGET_PAGE_SIZE - 1;
-            n++;
-        }
-
-        /* Add the guest image for ET_EXEC. */
-        if (image_range) {
-            ga->bounds[n++] = *image_range;
-        }
-    }
-
-    /* Add any high COMMPAGE not covered by reserved_va. */
-    if (commpage_range && reserved_va < commpage_range->hi) {
-        ga->bounds[n].lo = commpage_range->lo & qemu_real_host_page_mask();
-        ga->bounds[n].hi = commpage_range->hi;
-        n++;
-    }
-
-    ga->nbounds = n;
-    return true;
-}
-
-static void pgb_fail_in_use(const char *image_name)
-{
-    error_report("%s: requires virtual address space that is in use "
-                 "(omit the -B option or choose a different value)",
-                 image_name);
-    exit(EXIT_FAILURE);
-}
-
-static void pgb_fixed(const char *image_name, const PGBRange *image_range,
-                      const PGBRange *commpage_range, uintptr_t align)
-{
-    PGBAddrs ga;
-    uintptr_t brk = (uintptr_t)sbrk(0);
-
-    if (!QEMU_IS_ALIGNED(guest_base, align)) {
-        fprintf(stderr, "Requested guest base %p does not satisfy "
-                "host minimum alignment (0x%" PRIxPTR ")\n",
-                (void *)guest_base, align);
-        exit(EXIT_FAILURE);
-    }
-
-    if (!pgb_addr_set(&ga, image_range, commpage_range, !guest_base)
-        || !pgb_try_mmap_set(&ga, guest_base, brk)) {
-        pgb_fail_in_use(image_name);
-    }
-}
-
-/**
- * pgb_find_fallback:
- *
- * This is a fallback method for finding holes 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 pgb_find_fallback(const PGBAddrs *ga, uintptr_t align,
-                                   uintptr_t brk)
-{
-    /* TODO: come up with a better estimate of how much to skip. */
-    uintptr_t skip = sizeof(uintptr_t) == 4 ? MiB : GiB;
-
-    for (uintptr_t base = skip; ; base += skip) {
-        base = ROUND_UP(base, align);
-        if (pgb_try_mmap_set(ga, base, brk)) {
-            return base;
-        }
-        if (base >= -skip) {
-            return -1;
-        }
-    }
-}
-
-static uintptr_t pgb_try_itree(const PGBAddrs *ga, uintptr_t base,
-                               IntervalTreeRoot *root)
-{
-    for (int i = ga->nbounds - 1; i >= 0; --i) {
-        uintptr_t s = base + ga->bounds[i].lo;
-        uintptr_t l = base + ga->bounds[i].hi;
-        IntervalTreeNode *n;
-
-        if (l < s) {
-            /* Wraparound. Skip to advance S to mmap_min_addr. */
-            return mmap_min_addr - s;
-        }
-
-        n = interval_tree_iter_first(root, s, l);
-        if (n != NULL) {
-            /* Conflict.  Skip to advance S to LAST + 1. */
-            return n->last - s + 1;
-        }
-    }
-    return 0;  /* success */
-}
-
-static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root,
-                                uintptr_t align, uintptr_t brk)
-{
-    uintptr_t last = sizeof(uintptr_t) == 4 ? MiB : GiB;
-    uintptr_t base, skip;
-
-    while (true) {
-        base = ROUND_UP(last, align);
-        if (base < last) {
-            return -1;
-        }
-
-        skip = pgb_try_itree(ga, base, root);
-        if (skip == 0) {
-            break;
-        }
-
-        last = base + skip;
-        if (last < base) {
-            return -1;
-        }
-    }
-
-    /*
-     * We've chosen 'base' based on holes in the interval tree,
-     * but we don't yet know if it is a valid host address.
-     * Because it is the first matching hole, if the host addresses
-     * are invalid we know there are no further matches.
-     */
-    return pgb_try_mmap_set(ga, base, brk) ? base : -1;
-}
-
-static void pgb_dynamic(const char *image_name, const PGBRange *image_range,
-                        const PGBRange *commpage_range, uintptr_t align)
-{
-    IntervalTreeRoot *root;
-    uintptr_t brk, ret;
-    PGBAddrs ga;
-
-    /* Try the identity map first. */
-    if (pgb_addr_set(&ga, image_range, commpage_range, true)) {
-        brk = (uintptr_t)sbrk(0);
-        if (pgb_try_mmap_set(&ga, 0, brk)) {
-            guest_base = 0;
-            return;
-        }
-    }
-
-    /*
-     * Rebuild the address set for non-identity map.
-     * This differs in the mapping of the guest NULL page.
-     */
-    pgb_addr_set(&ga, image_range, commpage_range, false);
-
-    root = read_self_maps();
-
-    /* Read brk after we've read the maps, which will malloc. */
-    brk = (uintptr_t)sbrk(0);
-
-    if (!root) {
-        ret = pgb_find_fallback(&ga, align, brk);
-    } else {
-        /*
-         * Reserve the area close to the host brk.
-         * This will be freed with the rest of the tree.
-         */
-        IntervalTreeNode *b = g_new0(IntervalTreeNode, 1);
-        b->start = brk;
-        b->last = brk + 16 * MiB - 1;
-        interval_tree_insert(b, root);
-
-        ret = pgb_find_itree(&ga, root, align, brk);
-        free_self_maps(root);
-    }
-
-    if (ret == -1) {
-        int w = TARGET_LONG_BITS / 4;
-
-        error_report("%s: Unable to find a guest_base to satisfy all "
-                     "guest address mapping requirements", image_name);
-
-        for (int i = 0; i < ga.nbounds; ++i) {
-            error_printf("  %0*" VADDR_PRIx "-%0*" VADDR_PRIx "\n",
-                         w, ga.bounds[i].lo,
-                         w, ga.bounds[i].hi);
-        }
-        exit(EXIT_FAILURE);
-    }
-    guest_base = ret;
-}
-
-void probe_guest_base(const char *image_name, const PGBRange *image_range)
+void linux_probe_guest_base(const char *image_name,
+                            const PGBRange *image_range)
 {
 #ifdef COMMPAGE
     const PGBRange * const commpage_range = &(PGBRange){
@@ -1071,32 +765,15 @@ void probe_guest_base(const char *image_name, const 
PGBRange *image_range)
     const PGBRange * const commpage_range = NULL;
 #endif
 
-    /* In order to use host shmat, we must be able to honor SHMLBA.  */
-    uintptr_t align = MAX(SHMLBA, TARGET_PAGE_SIZE);
-
-    /* Sanity check the guest binary. */
-    if (reserved_va && image_range && image_range->hi > reserved_va) {
-        error_report("%s: requires more than reserved virtual "
-                     "address space (0x%" VADDR_PRIx " > 0x%lx)",
-                     image_name, image_range->hi, reserved_va);
-        exit(EXIT_FAILURE);
-    }
-
-    if (have_guest_base) {
-        pgb_fixed(image_name, image_range, commpage_range, align);
-    } else {
-        pgb_dynamic(image_name, image_range, commpage_range, align);
-    }
+    probe_guest_base(image_name, image_range, commpage_range);
 
     /* Reserve and initialize the commpage. */
+#if defined(COMMPAGE) || defined(HAVE_GUEST_COMMPAGE)
     if (!init_guest_commpage()) {
         /* We have already probed for the commpage being free. */
         g_assert_not_reached();
     }
-
-    assert(QEMU_IS_ALIGNED(guest_base, align));
-    qemu_log_mask(CPU_LOG_PAGE, "Locating guest address space "
-                  "@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
+#endif
 }
 
 enum {
@@ -1345,10 +1022,10 @@ static void load_elf_image(const char *image_name, 
const ImageSource *src,
              * Make sure that the low address does not conflict with
              * MMAP_MIN_ADDR or the QEMU application itself.
              */
-            probe_guest_base(image_name, &range);
+            linux_probe_guest_base(image_name, &range);
         } else {
             /* The binary is dynamic; we still need to select guest_base. */
-            probe_guest_base(image_name, NULL);
+            linux_probe_guest_base(image_name, NULL);
 
             /*
              * Avoid collision with the loader by providing a different
diff --git a/linux-user/flatload.c b/linux-user/flatload.c
index 45d69040c6..a551f083a4 100644
--- a/linux-user/flatload.c
+++ b/linux-user/flatload.c
@@ -261,7 +261,7 @@ static int load_flat_file(struct linux_binprm * bprm,
     /*
      * Allocate the address space.
      */
-    probe_guest_base(bprm->filename, NULL);
+    linux_probe_guest_base(bprm->filename, NULL);
 
     /*
      * there are a couple of cases here,  the separate code/data
diff --git a/common-user/meson.build b/common-user/meson.build
index 5e041de55e..2d4ffe07d3 100644
--- a/common-user/meson.build
+++ b/common-user/meson.build
@@ -6,6 +6,7 @@ common_user_inc += include_directories('host/' / host_arch)
 
 user_ss.add(files(
   'mmap-min-addr.c',
+  'probe-guest-base.c',
   'safe-syscall.S',
   'safe-syscall-error.c',
   'selfmap.c',
-- 
2.43.0


Reply via email to