[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] another 64/32 mmap() bug
From: |
Vince Weaver |
Subject: |
Re: [Qemu-devel] another 64/32 mmap() bug |
Date: |
Sun, 28 Sep 2008 15:11:20 -0400 (EDT) |
Hello
So I've tracked down this problem. The linux-user mmap() code does not
check to see if an allocation crosses the 2^32 barrier, which is a problem
for emulating 32-bit code on a 64-bit machine.
The attached patch is a hack that fixes this problem, and also the related
mremap() problem. These definitely aren't meant to be committed.
Hoepfully someone who understands the linux-user mmap() code better than I
do can take a look at things.
With the patch though, I can finally run correctly all 48 of Spec2k on
sparc32-linux-user on x86_64, and I can run all but 5 of Spec2k6.
Patch below, hoepfully pine doesn't mess it up this time.
Vince
Index: linux-user/mmap.c
===================================================================
--- linux-user/mmap.c (revision 5321)
+++ linux-user/mmap.c (working copy)
@@ -353,16 +353,27 @@
host_offset = offset & qemu_host_page_mask;
host_len = len + offset - host_offset;
host_len = HOST_PAGE_ALIGN(host_len);
+try_again:
mmap_start = mmap_find_vma(real_start, host_len);
if (mmap_start == (abi_ulong)-1) {
errno = ENOMEM;
goto fail;
}
+
+#if TARGET_ABI_BITS == 32
+ /* vmw */
+ if ( (long)g2h(mmap_start)+host_len > 0xffff0000) {
+ printf("WARNING! Host len too high: 0x%x +
0x%x\n",mmap_start,host_len);
+ goto try_again;
+ }
+#endif
+
/* Note: we prefer to control the mapping address. It is
especially important if qemu_host_page_size >
- qemu_real_host_page_size */
+ qemu_real_host_page_size */
p = mmap(g2h(mmap_start),
host_len, prot, flags | MAP_FIXED, fd, host_offset);
+
if (p == MAP_FAILED)
goto fail;
/* update start so that it points to the file position at 'offset' */
@@ -538,6 +549,25 @@
mmap_lock();
/* XXX: use 5 args syscall */
host_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags);
+#if TARGET_ABI_BITS == 32
+ if (host_addr > 0xffffffff) {
+ void *temp_addr;
+
+ temp_addr = mmap(NULL,new_size,
+
PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_PRIVATE|MAP_32BIT, 0, 0);
+ memcpy(temp_addr,(void *)host_addr,old_size);
+ munmap((void *)host_addr,new_size);
+ host_addr=(long)temp_addr;
+
+
+ if (host_addr > 0xffffffff) {
+
+ printf("ERROR! mremap() returned 64-bit value on 32-bit target!\n\n");
+ exit(-1);
+ }
+ }
+#endif
+
if (host_addr == -1) {
new_addr = -1;
} else {