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);