aboutsummaryrefslogtreecommitdiff
path: root/bsd-user/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsd-user/main.c')
-rw-r--r--bsd-user/main.c43
1 files changed, 42 insertions, 1 deletions
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 6df4f4f011..48643eeabc 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -52,10 +52,47 @@
#include "target_arch_cpu.h"
int singlestep;
-unsigned long mmap_min_addr;
uintptr_t guest_base;
bool have_guest_base;
+/*
+ * When running 32-on-64 we should make sure we can fit all of the possible
+ * guest address space into a contiguous chunk of virtual host memory.
+ *
+ * This way we will never overlap with our own libraries or binaries or stack
+ * or anything else that QEMU maps.
+ *
+ * Many cpus reserve the high bit (or more than one for some 64-bit cpus)
+ * of the address for the kernel. Some cpus rely on this and user space
+ * uses the high bit(s) for pointer tagging and the like. For them, we
+ * must preserve the expected address space.
+ */
+#ifndef MAX_RESERVED_VA
+# if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
+# if TARGET_VIRT_ADDR_SPACE_BITS == 32 && \
+ (TARGET_LONG_BITS == 32 || defined(TARGET_ABI32))
+/*
+ * There are a number of places where we assign reserved_va to a variable
+ * of type abi_ulong and expect it to fit. Avoid the last page.
+ */
+# define MAX_RESERVED_VA (0xfffffffful & TARGET_PAGE_MASK)
+# else
+# define MAX_RESERVED_VA (1ul << TARGET_VIRT_ADDR_SPACE_BITS)
+# endif
+# else
+# define MAX_RESERVED_VA 0
+# endif
+#endif
+
+/*
+ * That said, reserving *too* much vm space via mmap can run into problems
+ * with rlimits, oom due to page table creation, etc. We will still try it,
+ * if directed by the command-line option, but not by default.
+ */
+#if HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32
+unsigned long reserved_va = MAX_RESERVED_VA;
+#else
unsigned long reserved_va;
+#endif
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release;
@@ -439,6 +476,10 @@ int main(int argc, char **argv)
target_environ = envlist_to_environ(envlist, NULL);
envlist_free(envlist);
+ if (reserved_va) {
+ mmap_next_start = reserved_va;
+ }
+
{
Error *err = NULL;
if (seed_optarg != NULL) {