71c71b82ae
- 0.14 -> 0.15: http://wiki.qemu.org/ChangeLog/0.15 - 0.15 -> 1.0: http://wiki.qemu.org/ChangeLog/1.0 - the binary "qemu" is now called qemu-system-i386 OBS-URL: https://build.opensuse.org/package/show/Virtualization/qemu?expand=0&rev=29
125 lines
5.0 KiB
Diff
125 lines
5.0 KiB
Diff
From 52a4e3af8ca37d895bcff2ede1073ebb2cb2dd29 Mon Sep 17 00:00:00 2001
|
|
From: Alexander Graf <agraf@suse.de>
|
|
Date: Sat, 19 Nov 2011 22:57:55 +0100
|
|
Subject: [PATCH 12/32] linux-user: Fix 32-on-64 mmap for x86_64
|
|
|
|
When running a 32 bit guest on a 64 bit host, we can run into trouble while
|
|
calling the host's mmap() because it could potentially give us a 64 bit
|
|
return value which the guest can't interpret.
|
|
|
|
There are 2 ways of dealing with this:
|
|
|
|
1) Only do MAP_FIXED mmap calls and implement our own vm management in QEMU
|
|
2) Tell the kernel that we only want mappings in the lower 32 bits
|
|
|
|
Way 1 is very involved and hard to do. It's been advocated forever now but
|
|
nobody sat down to actually implement it.
|
|
|
|
Way 2 is easy. It's what this patch does. However, it only works on x86_64
|
|
because that's the only platform implementing the MAP_32BIT flag. Since most
|
|
people are on x86_64 though, I think it's a good enough compromise for now
|
|
though
|
|
|
|
Signed-off-by: Alexander Graf <agraf@suse.de>
|
|
---
|
|
linux-user/mmap.c | 35 ++++++++++++++++++++++++++---------
|
|
1 files changed, 26 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
|
|
index 994c02b..7d846f3 100644
|
|
--- a/linux-user/mmap.c
|
|
+++ b/linux-user/mmap.c
|
|
@@ -33,6 +33,22 @@
|
|
|
|
//#define DEBUG_MMAP
|
|
|
|
+/*
|
|
+ * On x86_64 we can tell mmap that we only want to map within the first 32
|
|
+ * bits to not get pointers that potentially exceed the return size. Without
|
|
+ * this flag set mmap will eventually break for users when running 32-on-64.
|
|
+ *
|
|
+ * However, Linux doesn't implement this for non-x86_64 systems. So we have
|
|
+ * to safeguard the bit with an empty flag which will be ignore on other
|
|
+ * architectures. At least we fixed the "common case" this way :).
|
|
+ *
|
|
+ * - agraf
|
|
+ */
|
|
+#if !defined(MAP_32BIT) || !defined(__x86_64__) || (TARGET_LONG_BITS != 32)
|
|
+#undef MAP_32BIT
|
|
+#define MAP_32BIT 0
|
|
+#endif
|
|
+
|
|
#if defined(CONFIG_USE_NPTL)
|
|
static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
static __thread int mmap_lock_count;
|
|
@@ -169,7 +185,7 @@ static int mmap_frag(abi_ulong real_start,
|
|
if (prot1 == 0) {
|
|
/* no page was there, so we allocate one */
|
|
void *p = mmap(host_start, qemu_host_page_size, prot,
|
|
- flags | MAP_ANONYMOUS, -1, 0);
|
|
+ flags | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
|
|
if (p == MAP_FAILED)
|
|
return -1;
|
|
prot1 = prot;
|
|
@@ -292,7 +308,7 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
|
|
* - shmat() with SHM_REMAP flag
|
|
*/
|
|
ptr = mmap(g2h(addr), size, PROT_NONE,
|
|
- MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
|
|
+ MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE|MAP_32BIT, -1, 0);
|
|
|
|
/* ENOMEM, if host address space has no memory */
|
|
if (ptr == MAP_FAILED) {
|
|
@@ -454,14 +470,15 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
|
|
especially important if qemu_host_page_size >
|
|
qemu_real_host_page_size */
|
|
p = mmap(g2h(mmap_start),
|
|
- host_len, prot, flags | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
|
+ host_len, prot, flags | MAP_FIXED | MAP_ANONYMOUS | MAP_32BIT,
|
|
+ -1, 0);
|
|
if (p == MAP_FAILED)
|
|
goto fail;
|
|
/* update start so that it points to the file position at 'offset' */
|
|
host_start = (unsigned long)p;
|
|
if (!(flags & MAP_ANONYMOUS)) {
|
|
p = mmap(g2h(mmap_start), len, prot,
|
|
- flags | MAP_FIXED, fd, host_offset);
|
|
+ flags | MAP_FIXED | MAP_32BIT, fd, host_offset);
|
|
host_start += offset - host_offset;
|
|
}
|
|
start = h2g(host_start);
|
|
@@ -495,8 +512,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
|
|
goto fail;
|
|
}
|
|
retaddr = target_mmap(start, len, prot | PROT_WRITE,
|
|
- MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
|
|
- -1, 0);
|
|
+ MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS |
|
|
+ MAP_32BIT, -1, 0);
|
|
if (retaddr == -1)
|
|
goto fail;
|
|
if (pread(fd, g2h(start), len, offset) == -1)
|
|
@@ -547,7 +564,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
|
|
else
|
|
offset1 = offset + real_start - start;
|
|
p = mmap(g2h(real_start), real_end - real_start,
|
|
- prot, flags, fd, offset1);
|
|
+ prot, flags | MAP_32BIT, fd, offset1);
|
|
if (p == MAP_FAILED)
|
|
goto fail;
|
|
}
|
|
@@ -603,8 +620,8 @@ static void mmap_reserve(abi_ulong start, abi_ulong size)
|
|
}
|
|
if (real_start != real_end) {
|
|
mmap(g2h(real_start), real_end - real_start, PROT_NONE,
|
|
- MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
|
|
- -1, 0);
|
|
+ MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE |
|
|
+ MAP_32BIT, -1, 0);
|
|
}
|
|
}
|
|
|
|
--
|
|
1.6.0.2
|
|
|