@samitouri / QOSamiQemu / commits / 9affb4decd

common-user: Move probe_guest_base from linux-user

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. Reviewed-by: Warner Losh <imp@bsdimp.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Richard Henderson committed May 30, 2026 at 10:28 UTC 9affb4decdd3777172c32f1820ae62f2e511cad8
6 files changed +392 -338
common-user/meson.build
+1
@@ -6,6 +6,7 @@ common_user_inc += include_directories('host/' / host_arch)
6
7 user_ss.add(files(
8 'mmap-min-addr.c',
9 + 'probe-guest-base.c',
10 'safe-syscall.S',
11 'safe-syscall-error.c',
12 'selfmap.c',
common-user/probe-guest-base.c new
+343
@@ -0,0 +1,343 @@
1 +/* SPDX-License-Identifier: GPL-2.0-or-later */
2 +
3 +#include "qemu/osdep.h"
4 +#include "qemu/error-report.h"
5 +#include "qemu/units.h"
6 +#include "qemu/target-info.h"
7 +#include "qemu/log.h"
8 +#include "user/guest-base.h"
9 +#include "user/mmap-min-addr.h"
10 +#include "user/guest-host.h"
11 +#include "user/probe-guest-base.h"
12 +#include "user/selfmap.h"
13 +#include "exec/target_page.h"
14 +#include <sys/shm.h>
15 +
16 +/* Linux and FreeBSD use different flags to express NOREPLACE. */
17 +#ifdef __FreeBSD__
18 +#define MAP_FIXED_NOREPLACE (MAP_FIXED | MAP_EXCL)
19 +#endif
20 +
21 +/**
22 + * pgb_try_mmap:
23 + * @addr: host start address
24 + * @addr_last: host last address
25 + * @keep: do not unmap the probe region
26 + *
27 + * Return 1 if [@addr, @addr_last] is not mapped in the host,
28 + * return 0 if it is not available to map, and -1 on mmap error.
29 + * If @keep, the region is left mapped on success, otherwise unmapped.
30 + */
31 +static int pgb_try_mmap(uintptr_t addr, uintptr_t addr_last, bool keep)
32 +{
33 + size_t size = addr_last - addr + 1;
34 + void *p = mmap((void *)addr, size, PROT_NONE,
35 + MAP_ANONYMOUS | MAP_PRIVATE |
36 + MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0);
37 + int ret;
38 +
39 + if (p == MAP_FAILED) {
40 + return errno == EEXIST ? 0 : -1;
41 + }
42 + ret = p == (void *)addr;
43 + if (!keep || !ret) {
44 + munmap(p, size);
45 + }
46 + return ret;
47 +}
48 +
49 +/**
50 + * pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t size, uintptr_t brk)
51 + * @addr: host address
52 + * @addr_last: host last address
53 + * @brk: host brk
54 + *
55 + * Like pgb_try_mmap, but additionally reserve some memory following brk.
56 + */
57 +static int pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t addr_last,
58 + uintptr_t brk, bool keep)
59 +{
60 + uintptr_t brk_last = brk + 16 * MiB - 1;
61 +
62 + /* Do not map anything close to the host brk. */
63 + if (addr <= brk_last && brk <= addr_last) {
64 + return 0;
65 + }
66 + return pgb_try_mmap(addr, addr_last, keep);
67 +}
68 +
69 +/**
70 + * pgb_try_mmap_set:
71 + * @ga: set of guest addrs
72 + * @base: guest_base
73 + * @brk: host brk
74 + *
75 + * Return true if all @ga can be mapped by the host at @base.
76 + * On success, retain the mapping at index 0 for reserved_va.
77 + */
78 +
79 +typedef struct PGBAddrs {
80 + PGBRange bounds[3];
81 + int nbounds;
82 +} PGBAddrs;
83 +
84 +static bool pgb_try_mmap_set(const PGBAddrs *ga, uintptr_t base, uintptr_t brk)
85 +{
86 + for (int i = ga->nbounds - 1; i >= 0; --i) {
87 + if (pgb_try_mmap_skip_brk(ga->bounds[i].lo + base,
88 + ga->bounds[i].hi + base,
89 + brk, i == 0 && reserved_va) <= 0) {
90 + return false;
91 + }
92 + }
93 + return true;
94 +}
95 +
96 +/**
97 + * pgb_addr_set:
98 + * @ga: output set of guest addrs
99 + * @image_range: fixed guest image addresses
100 + * @identity: create for identity mapping
101 + *
102 + * Fill in @ga with the image, COMMPAGE and NULL page.
103 + */
104 +static bool pgb_addr_set(PGBAddrs *ga, const PGBRange *image_range,
105 + const PGBRange *commpage_range, bool try_identity)
106 +{
107 + int n;
108 +
109 + /*
110 + * With a low commpage, or a guest mapped very low,
111 + * we may not be able to use the identity map.
112 + */
113 + if (try_identity) {
114 + if (commpage_range && commpage_range->lo < mmap_min_addr) {
115 + return false;
116 + }
117 + if (image_range && image_range->lo < mmap_min_addr) {
118 + return false;
119 + }
120 + }
121 +
122 + memset(ga, 0, sizeof(*ga));
123 + n = 0;
124 +
125 + if (reserved_va) {
126 + ga->bounds[n].lo = try_identity ? mmap_min_addr : 0;
127 + ga->bounds[n].hi = reserved_va;
128 + n++;
129 + /* Low COMMPAGE and NULL handled by reserving from 0. */
130 + } else {
131 + /* Add any low COMMPAGE or NULL page. */
132 + if (!try_identity || (commpage_range && commpage_range->lo == 0)) {
133 + ga->bounds[n].lo = 0;
134 + ga->bounds[n].hi = TARGET_PAGE_SIZE - 1;
135 + n++;
136 + }
137 +
138 + /* Add the guest image for ET_EXEC. */
139 + if (image_range) {
140 + ga->bounds[n++] = *image_range;
141 + }
142 + }
143 +
144 + /* Add any high COMMPAGE not covered by reserved_va. */
145 + if (commpage_range && reserved_va < commpage_range->hi) {
146 + ga->bounds[n].lo = commpage_range->lo & qemu_real_host_page_mask();
147 + ga->bounds[n].hi = commpage_range->hi;
148 + n++;
149 + }
150 +
151 + ga->nbounds = n;
152 + return true;
153 +}
154 +
155 +static void pgb_fail_in_use(const char *image_name)
156 +{
157 + error_report("%s: requires virtual address space that is in use "
158 + "(omit the -B option or choose a different value)",
159 + image_name);
160 + exit(EXIT_FAILURE);
161 +}
162 +
163 +static void pgb_fixed(const char *image_name, const PGBRange *image_range,
164 + const PGBRange *commpage_range, uintptr_t align)
165 +{
166 + PGBAddrs ga;
167 + uintptr_t brk = (uintptr_t)sbrk(0);
168 +
169 + if (!QEMU_IS_ALIGNED(guest_base, align)) {
170 + fprintf(stderr, "Requested guest base %p does not satisfy "
171 + "host minimum alignment (0x%" PRIxPTR ")\n",
172 + (void *)guest_base, align);
173 + exit(EXIT_FAILURE);
174 + }
175 +
176 + if (!pgb_addr_set(&ga, image_range, commpage_range, !guest_base)
177 + || !pgb_try_mmap_set(&ga, guest_base, brk)) {
178 + pgb_fail_in_use(image_name);
179 + }
180 +}
181 +
182 +/**
183 + * pgb_find_fallback:
184 + *
185 + * This is a fallback method for finding holes in the host address space
186 + * if we don't have the benefit of being able to access /proc/self/map.
187 + * It can potentially take a very long time as we can only dumbly iterate
188 + * up the host address space seeing if the allocation would work.
189 + */
190 +static uintptr_t pgb_find_fallback(const PGBAddrs *ga, uintptr_t align,
191 + uintptr_t brk)
192 +{
193 + /* TODO: come up with a better estimate of how much to skip. */
194 + uintptr_t skip = sizeof(uintptr_t) == 4 ? MiB : GiB;
195 +
196 + for (uintptr_t base = skip; ; base += skip) {
197 + base = ROUND_UP(base, align);
198 + if (pgb_try_mmap_set(ga, base, brk)) {
199 + return base;
200 + }
201 + if (base >= -skip) {
202 + return -1;
203 + }
204 + }
205 +}
206 +
207 +static uintptr_t pgb_try_itree(const PGBAddrs *ga, uintptr_t base,
208 + IntervalTreeRoot *root)
209 +{
210 + for (int i = ga->nbounds - 1; i >= 0; --i) {
211 + uintptr_t s = base + ga->bounds[i].lo;
212 + uintptr_t l = base + ga->bounds[i].hi;
213 + IntervalTreeNode *n;
214 +
215 + if (l < s) {
216 + /* Wraparound. Skip to advance S to mmap_min_addr. */
217 + return mmap_min_addr - s;
218 + }
219 +
220 + n = interval_tree_iter_first(root, s, l);
221 + if (n != NULL) {
222 + /* Conflict. Skip to advance S to LAST + 1. */
223 + return n->last - s + 1;
224 + }
225 + }
226 + return 0; /* success */
227 +}
228 +
229 +static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root,
230 + uintptr_t align, uintptr_t brk)
231 +{
232 + uintptr_t last = sizeof(uintptr_t) == 4 ? MiB : GiB;
233 + uintptr_t base, skip;
234 +
235 + while (true) {
236 + base = ROUND_UP(last, align);
237 + if (base < last) {
238 + return -1;
239 + }
240 +
241 + skip = pgb_try_itree(ga, base, root);
242 + if (skip == 0) {
243 + break;
244 + }
245 +
246 + last = base + skip;
247 + if (last < base) {
248 + return -1;
249 + }
250 + }
251 +
252 + /*
253 + * We've chosen 'base' based on holes in the interval tree,
254 + * but we don't yet know if it is a valid host address.
255 + * Because it is the first matching hole, if the host addresses
256 + * are invalid we know there are no further matches.
257 + */
258 + return pgb_try_mmap_set(ga, base, brk) ? base : -1;
259 +}
260 +
261 +static void pgb_dynamic(const char *image_name, const PGBRange *image_range,
262 + const PGBRange *commpage_range, uintptr_t align)
263 +{
264 + IntervalTreeRoot *root;
265 + uintptr_t brk, ret;
266 + PGBAddrs ga;
267 +
268 + /* Try the identity map first. */
269 + if (pgb_addr_set(&ga, image_range, commpage_range, true)) {
270 + brk = (uintptr_t)sbrk(0);
271 + if (pgb_try_mmap_set(&ga, 0, brk)) {
272 + guest_base = 0;
273 + return;
274 + }
275 + }
276 +
277 + /*
278 + * Rebuild the address set for non-identity map.
279 + * This differs in the mapping of the guest NULL page.
280 + */
281 + pgb_addr_set(&ga, image_range, commpage_range, false);
282 +
283 + root = read_self_maps();
284 +
285 + /* Read brk after we've read the maps, which will malloc. */
286 + brk = (uintptr_t)sbrk(0);
287 +
288 + if (!root) {
289 + ret = pgb_find_fallback(&ga, align, brk);
290 + } else {
291 + /*
292 + * Reserve the area close to the host brk.
293 + * This will be freed with the rest of the tree.
294 + */
295 + IntervalTreeNode *b = g_new0(IntervalTreeNode, 1);
296 + b->start = brk;
297 + b->last = brk + 16 * MiB - 1;
298 + interval_tree_insert(b, root);
299 +
300 + ret = pgb_find_itree(&ga, root, align, brk);
301 + free_self_maps(root);
302 + }
303 +
304 + if (ret == -1) {
305 + int w = target_long_bits() / 4;
306 +
307 + error_report("%s: Unable to find a guest_base to satisfy all "
308 + "guest address mapping requirements", image_name);
309 +
310 + for (int i = 0; i < ga.nbounds; ++i) {
311 + error_printf(" %0*" VADDR_PRIx "-%0*" VADDR_PRIx "\n",
312 + w, ga.bounds[i].lo,
313 + w, ga.bounds[i].hi);
314 + }
315 + exit(EXIT_FAILURE);
316 + }
317 + guest_base = ret;
318 +}
319 +
320 +void probe_guest_base(const char *image_name, const PGBRange *image_range,
321 + const PGBRange *commpage_range)
322 +{
323 + /* In order to use host shmat, we must be able to honor SHMLBA. */
324 + uintptr_t align = MAX(SHMLBA, TARGET_PAGE_SIZE);
325 +
326 + /* Sanity check the guest binary. */
327 + if (reserved_va && image_range && image_range->hi > reserved_va) {
328 + error_report("%s: requires more than reserved virtual "
329 + "address space (0x%" VADDR_PRIx " > 0x%lx)",
330 + image_name, image_range->hi, reserved_va);
331 + exit(EXIT_FAILURE);
332 + }
333 +
334 + if (have_guest_base) {
335 + pgb_fixed(image_name, image_range, commpage_range, align);
336 + } else {
337 + pgb_dynamic(image_name, image_range, commpage_range, align);
338 + }
339 +
340 + assert(QEMU_IS_ALIGNED(guest_base, align));
341 + qemu_log_mask(CPU_LOG_PAGE, "Locating guest address space "
342 + "@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
343 +}
include/user/probe-guest-base.h new
+37
@@ -0,0 +1,37 @@
1 +/* SPDX-License-Identifier: GPL-2.0-or-later */
2 +
3 +#ifndef USER_PROBE_GUEST_BASE_H
4 +#define USER_PROBE_GUEST_BASE_H
5 +
6 +#ifndef CONFIG_USER_ONLY
7 +#error Cannot include this header from system emulation
8 +#endif
9 +
10 +#include "exec/vaddr.h"
11 +
12 +typedef struct PGBRange {
13 + vaddr lo;
14 + vaddr hi;
15 +} PGBRange;
16 +
17 +/**
18 + * probe_guest_base:
19 + * @image_name: the executable being loaded
20 + * @image_range: the fixed addresses within the executable
21 + *
22 + * Creates the initial guest address space in the host memory space.
23 + *
24 + * If @image_range is NULL, then no address in the executable is fixed,
25 + * i.e. it is fully relocatable.
26 + *
27 + * This function will not return if a valid value for guest_base
28 + * cannot be chosen. On return, the executable loader can expect
29 + *
30 + * target_mmap(i->lo, i->hi - i->lo + 1, ...)
31 + *
32 + * to succeed.
33 + */
34 +void probe_guest_base(const char *image_name, const PGBRange *image_range,
35 + const PGBRange *commpage_range);
36 +
37 +#endif
linux-user/elfload.c
+7 -330
@@ -4,7 +4,6 @@
4
5 #include <sys/prctl.h>
6 #include <sys/resource.h>
7 -#include <sys/shm.h>
7
8 #include "qemu.h"
9 #include "user/tswap-target.h"
@@ -13,8 +12,6 @@
12 #include "exec/mmap-lock.h"
13 #include "exec/translation-block.h"
14 #include "exec/tswap.h"
16 -#include "user/guest-base.h"
17 -#include "user/mmap-min-addr.h"
15 #include "user-internals.h"
16 #include "signal-common.h"
17 #include "loader.h"
@@ -25,7 +22,6 @@
22 #include "qemu/queue.h"
23 #include "qemu/guest-random.h"
24 #include "qemu/units.h"
28 -#include "user/selfmap.h"
25 #include "qemu/lockable.h"
26 #include "qapi/error.h"
27 #include "qemu/error-report.h"
@@ -758,310 +754,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
754 return sp;
755 }
756
761 -#if !defined(COMMPAGE) && !defined(HAVE_GUEST_COMMPAGE)
762 -bool init_guest_commpage(void) { return true; }
763 -#endif
764 -
765 -/**
766 - * pgb_try_mmap:
767 - * @addr: host start address
768 - * @addr_last: host last address
769 - * @keep: do not unmap the probe region
770 - *
771 - * Return 1 if [@addr, @addr_last] is not mapped in the host,
772 - * return 0 if it is not available to map, and -1 on mmap error.
773 - * If @keep, the region is left mapped on success, otherwise unmapped.
774 - */
775 -static int pgb_try_mmap(uintptr_t addr, uintptr_t addr_last, bool keep)
776 -{
777 - size_t size = addr_last - addr + 1;
778 - void *p = mmap((void *)addr, size, PROT_NONE,
779 - MAP_ANONYMOUS | MAP_PRIVATE |
780 - MAP_NORESERVE | MAP_FIXED_NOREPLACE, -1, 0);
781 - int ret;
782 -
783 - if (p == MAP_FAILED) {
784 - return errno == EEXIST ? 0 : -1;
785 - }
786 - ret = p == (void *)addr;
787 - if (!keep || !ret) {
788 - munmap(p, size);
789 - }
790 - return ret;
791 -}
792 -
793 -/**
794 - * pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t size, uintptr_t brk)
795 - * @addr: host address
796 - * @addr_last: host last address
797 - * @brk: host brk
798 - *
799 - * Like pgb_try_mmap, but additionally reserve some memory following brk.
800 - */
801 -static int pgb_try_mmap_skip_brk(uintptr_t addr, uintptr_t addr_last,
802 - uintptr_t brk, bool keep)
803 -{
804 - uintptr_t brk_last = brk + 16 * MiB - 1;
805 -
806 - /* Do not map anything close to the host brk. */
807 - if (addr <= brk_last && brk <= addr_last) {
808 - return 0;
809 - }
810 - return pgb_try_mmap(addr, addr_last, keep);
811 -}
812 -
813 -/**
814 - * pgb_try_mmap_set:
815 - * @ga: set of guest addrs
816 - * @base: guest_base
817 - * @brk: host brk
818 - *
819 - * Return true if all @ga can be mapped by the host at @base.
820 - * On success, retain the mapping at index 0 for reserved_va.
821 - */
822 -
823 -typedef struct PGBAddrs {
824 - PGBRange bounds[3];
825 - int nbounds;
826 -} PGBAddrs;
827 -
828 -static bool pgb_try_mmap_set(const PGBAddrs *ga, uintptr_t base, uintptr_t brk)
829 -{
830 - for (int i = ga->nbounds - 1; i >= 0; --i) {
831 - if (pgb_try_mmap_skip_brk(ga->bounds[i].lo + base,
832 - ga->bounds[i].hi + base,
833 - brk, i == 0 && reserved_va) <= 0) {
834 - return false;
835 - }
836 - }
837 - return true;
838 -}
839 -
840 -/**
841 - * pgb_addr_set:
842 - * @ga: output set of guest addrs
843 - * @image_range: fixed guest image addresses
844 - * @identity: create for identity mapping
845 - *
846 - * Fill in @ga with the image, COMMPAGE and NULL page.
847 - */
848 -static bool pgb_addr_set(PGBAddrs *ga, const PGBRange *image_range,
849 - const PGBRange *commpage_range, bool try_identity)
850 -{
851 - int n;
852 -
853 - /*
854 - * With a low commpage, or a guest mapped very low,
855 - * we may not be able to use the identity map.
856 - */
857 - if (try_identity) {
858 - if (commpage_range && commpage_range->lo < mmap_min_addr) {
859 - return false;
860 - }
861 - if (image_range && image_range->lo < mmap_min_addr) {
862 - return false;
863 - }
864 - }
865 -
866 - memset(ga, 0, sizeof(*ga));
867 - n = 0;
868 -
869 - if (reserved_va) {
870 - ga->bounds[n].lo = try_identity ? mmap_min_addr : 0;
871 - ga->bounds[n].hi = reserved_va;
872 - n++;
873 - /* Low COMMPAGE and NULL handled by reserving from 0. */
874 - } else {
875 - /* Add any low COMMPAGE or NULL page. */
876 - if (!try_identity || (commpage_range && commpage_range->lo == 0)) {
877 - ga->bounds[n].lo = 0;
878 - ga->bounds[n].hi = TARGET_PAGE_SIZE - 1;
879 - n++;
880 - }
881 -
882 - /* Add the guest image for ET_EXEC. */
883 - if (image_range) {
884 - ga->bounds[n++] = *image_range;
885 - }
886 - }
887 -
888 - /* Add any high COMMPAGE not covered by reserved_va. */
889 - if (commpage_range && reserved_va < commpage_range->hi) {
890 - ga->bounds[n].lo = commpage_range->lo & qemu_real_host_page_mask();
891 - ga->bounds[n].hi = commpage_range->hi;
892 - n++;
893 - }
894 -
895 - ga->nbounds = n;
896 - return true;
897 -}
898 -
899 -static void pgb_fail_in_use(const char *image_name)
900 -{
901 - error_report("%s: requires virtual address space that is in use "
902 - "(omit the -B option or choose a different value)",
903 - image_name);
904 - exit(EXIT_FAILURE);
905 -}
906 -
907 -static void pgb_fixed(const char *image_name, const PGBRange *image_range,
908 - const PGBRange *commpage_range, uintptr_t align)
909 -{
910 - PGBAddrs ga;
911 - uintptr_t brk = (uintptr_t)sbrk(0);
912 -
913 - if (!QEMU_IS_ALIGNED(guest_base, align)) {
914 - fprintf(stderr, "Requested guest base %p does not satisfy "
915 - "host minimum alignment (0x%" PRIxPTR ")\n",
916 - (void *)guest_base, align);
917 - exit(EXIT_FAILURE);
918 - }
919 -
920 - if (!pgb_addr_set(&ga, image_range, commpage_range, !guest_base)
921 - || !pgb_try_mmap_set(&ga, guest_base, brk)) {
922 - pgb_fail_in_use(image_name);
923 - }
924 -}
925 -
926 -/**
927 - * pgb_find_fallback:
928 - *
929 - * This is a fallback method for finding holes in the host address space
930 - * if we don't have the benefit of being able to access /proc/self/map.
931 - * It can potentially take a very long time as we can only dumbly iterate
932 - * up the host address space seeing if the allocation would work.
933 - */
934 -static uintptr_t pgb_find_fallback(const PGBAddrs *ga, uintptr_t align,
935 - uintptr_t brk)
936 -{
937 - /* TODO: come up with a better estimate of how much to skip. */
938 - uintptr_t skip = sizeof(uintptr_t) == 4 ? MiB : GiB;
939 -
940 - for (uintptr_t base = skip; ; base += skip) {
941 - base = ROUND_UP(base, align);
942 - if (pgb_try_mmap_set(ga, base, brk)) {
943 - return base;
944 - }
945 - if (base >= -skip) {
946 - return -1;
947 - }
948 - }
949 -}
950 -
951 -static uintptr_t pgb_try_itree(const PGBAddrs *ga, uintptr_t base,
952 - IntervalTreeRoot *root)
953 -{
954 - for (int i = ga->nbounds - 1; i >= 0; --i) {
955 - uintptr_t s = base + ga->bounds[i].lo;
956 - uintptr_t l = base + ga->bounds[i].hi;
957 - IntervalTreeNode *n;
958 -
959 - if (l < s) {
960 - /* Wraparound. Skip to advance S to mmap_min_addr. */
961 - return mmap_min_addr - s;
962 - }
963 -
964 - n = interval_tree_iter_first(root, s, l);
965 - if (n != NULL) {
966 - /* Conflict. Skip to advance S to LAST + 1. */
967 - return n->last - s + 1;
968 - }
969 - }
970 - return 0; /* success */
971 -}
972 -
973 -static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root,
974 - uintptr_t align, uintptr_t brk)
975 -{
976 - uintptr_t last = sizeof(uintptr_t) == 4 ? MiB : GiB;
977 - uintptr_t base, skip;
978 -
979 - while (true) {
980 - base = ROUND_UP(last, align);
981 - if (base < last) {
982 - return -1;
983 - }
984 -
985 - skip = pgb_try_itree(ga, base, root);
986 - if (skip == 0) {
987 - break;
988 - }
989 -
990 - last = base + skip;
991 - if (last < base) {
992 - return -1;
993 - }
994 - }
995 -
996 - /*
997 - * We've chosen 'base' based on holes in the interval tree,
998 - * but we don't yet know if it is a valid host address.
999 - * Because it is the first matching hole, if the host addresses
1000 - * are invalid we know there are no further matches.
1001 - */
1002 - return pgb_try_mmap_set(ga, base, brk) ? base : -1;
1003 -}
1004 -
1005 -static void pgb_dynamic(const char *image_name, const PGBRange *image_range,
1006 - const PGBRange *commpage_range, uintptr_t align)
1007 -{
1008 - IntervalTreeRoot *root;
1009 - uintptr_t brk, ret;
1010 - PGBAddrs ga;
1011 -
1012 - /* Try the identity map first. */
1013 - if (pgb_addr_set(&ga, image_range, commpage_range, true)) {
1014 - brk = (uintptr_t)sbrk(0);
1015 - if (pgb_try_mmap_set(&ga, 0, brk)) {
1016 - guest_base = 0;
1017 - return;
1018 - }
1019 - }
1020 -
1021 - /*
1022 - * Rebuild the address set for non-identity map.
1023 - * This differs in the mapping of the guest NULL page.
1024 - */
1025 - pgb_addr_set(&ga, image_range, commpage_range, false);
1026 -
1027 - root = read_self_maps();
1028 -
1029 - /* Read brk after we've read the maps, which will malloc. */
1030 - brk = (uintptr_t)sbrk(0);
1031 -
1032 - if (!root) {
1033 - ret = pgb_find_fallback(&ga, align, brk);
1034 - } else {
1035 - /*
1036 - * Reserve the area close to the host brk.
1037 - * This will be freed with the rest of the tree.
1038 - */
1039 - IntervalTreeNode *b = g_new0(IntervalTreeNode, 1);
1040 - b->start = brk;
1041 - b->last = brk + 16 * MiB - 1;
1042 - interval_tree_insert(b, root);
1043 -
1044 - ret = pgb_find_itree(&ga, root, align, brk);
1045 - free_self_maps(root);
1046 - }
1047 -
1048 - if (ret == -1) {
1049 - int w = TARGET_LONG_BITS / 4;
1050 -
1051 - error_report("%s: Unable to find a guest_base to satisfy all "
1052 - "guest address mapping requirements", image_name);
1053 -
1054 - for (int i = 0; i < ga.nbounds; ++i) {
1055 - error_printf(" %0*" VADDR_PRIx "-%0*" VADDR_PRIx "\n",
1056 - w, ga.bounds[i].lo,
1057 - w, ga.bounds[i].hi);
1058 - }
1059 - exit(EXIT_FAILURE);
1060 - }
1061 - guest_base = ret;
1062 -}
1063 -
1064 -void probe_guest_base(const char *image_name, const PGBRange *image_range)
757 +void linux_probe_guest_base(const char *image_name,
758 + const PGBRange *image_range)
759 {
760 #ifdef COMMPAGE
761 const PGBRange * const commpage_range = &(PGBRange){
@@ -1071,32 +765,15 @@ void probe_guest_base(const char *image_name, const PGBRange *image_range)
765 const PGBRange * const commpage_range = NULL;
766 #endif
767
1074 - /* In order to use host shmat, we must be able to honor SHMLBA. */
1075 - uintptr_t align = MAX(SHMLBA, TARGET_PAGE_SIZE);
1076 -
1077 - /* Sanity check the guest binary. */
1078 - if (reserved_va && image_range && image_range->hi > reserved_va) {
1079 - error_report("%s: requires more than reserved virtual "
1080 - "address space (0x%" VADDR_PRIx " > 0x%lx)",
1081 - image_name, image_range->hi, reserved_va);
1082 - exit(EXIT_FAILURE);
1083 - }
1084 -
1085 - if (have_guest_base) {
1086 - pgb_fixed(image_name, image_range, commpage_range, align);
1087 - } else {
1088 - pgb_dynamic(image_name, image_range, commpage_range, align);
1089 - }
768 + probe_guest_base(image_name, image_range, commpage_range);
769
770 /* Reserve and initialize the commpage. */
771 +#if defined(COMMPAGE) || defined(HAVE_GUEST_COMMPAGE)
772 if (!init_guest_commpage()) {
773 /* We have already probed for the commpage being free. */
774 g_assert_not_reached();
775 }
1096 -
1097 - assert(QEMU_IS_ALIGNED(guest_base, align));
1098 - qemu_log_mask(CPU_LOG_PAGE, "Locating guest address space "
1099 - "@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
776 +#endif
777 }
778
779 enum {
@@ -1345,10 +1022,10 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
1022 * Make sure that the low address does not conflict with
1023 * MMAP_MIN_ADDR or the QEMU application itself.
1024 */
1348 - probe_guest_base(image_name, &range);
1025 + linux_probe_guest_base(image_name, &range);
1026 } else {
1027 /* The binary is dynamic; we still need to select guest_base. */
1351 - probe_guest_base(image_name, NULL);
1028 + linux_probe_guest_base(image_name, NULL);
1029
1030 /*
1031 * Avoid collision with the loader by providing a different
linux-user/flatload.c
+1 -1
@@ -261,7 +261,7 @@ static int load_flat_file(struct linux_binprm * bprm,
261 /*
262 * Allocate the address space.
263 */
264 - probe_guest_base(bprm->filename, NULL);
264 + linux_probe_guest_base(bprm->filename, NULL);
265
266 /*
267 * there are a couple of cases here, the separate code/data
linux-user/user-internals.h
+3 -7
@@ -22,6 +22,7 @@
22 #include "qemu/log.h"
23 #include "exec/tb-flush.h"
24 #include "exec/translation-block.h"
25 +#include "user/probe-guest-base.h"
26
27 extern char *exec_path;
28 extern char real_exec_path[PATH_MAX];
@@ -74,13 +75,8 @@ void clone_fork_end(bool child);
75 void fork_start(void);
76 void fork_end(pid_t pid);
77
77 -typedef struct PGBRange {
78 - vaddr lo;
79 - vaddr hi;
80 -} PGBRange;
81 -
78 /**
83 - * probe_guest_base:
79 + * linux_probe_guest_base:
80 * @image_name: the executable being loaded
81 * @image_range: the fixed addresses within the executable
82 *
@@ -96,7 +92,7 @@ typedef struct PGBRange {
92 *
93 * to succeed.
94 */
99 -void probe_guest_base(const char *image_name, const PGBRange *image_range);
95 +void linux_probe_guest_base(const char *image_name, const PGBRange *image_range);
96
97 /* syscall.c */
98 int host_to_target_waitstatus(int status);