Hello,

I have cleaned up the mmap patch that corrects the alignment for un-fixed 
mappings when the target page-size is larger than the hosts.

The error was found and the patch tested with the CRIS target port (not yet 
contributed) on a x86 host running GCC's c-torture tests for CRIS. Without the 
patch, randomly every other test case fails to load.

I tried the sparc64-linux-user target but it fails to run any of my programs 
both with and without the change. Similarly, the m68k-linux-user target also 
fails but it at least manages to load and start executing before hitting an 
illegal insn. For the m68k I could verify that it also randomly fails to load 
programs. With the patch, it always manages to load the elf files at least. 
Additionally I tested the mips target after changing the page size to 8K, it 
also randomly fails to load programs but works fine with the patch (thanks for 
suggesting this test Thiemo).

If you see any issues with the change or if you feel I need to test something 
else, I'll be happy to fix or do that. Otherwise, I'd appreciate it if this 
went in.

Thanks
-- 
Edgar E. Iglesias
Axis Communications AB

Index: mmap.c
===================================================================
RCS file: /sources/qemu/qemu/linux-user/mmap.c,v
retrieving revision 1.15
diff -u -p -r1.15 mmap.c
--- mmap.c      27 Sep 2007 04:10:43 -0000      1.15
+++ mmap.c      30 Sep 2007 01:06:46 -0000
@@ -209,30 +209,45 @@ long target_mmap(target_ulong start, tar
             last_start += HOST_PAGE_ALIGN(len);
         }
 #endif
-        if (0 && qemu_host_page_size != qemu_real_host_page_size) {
-            /* NOTE: this code is only for debugging with '-p' option */
-            /* ??? Can also occur when TARGET_PAGE_SIZE > host page size.  */
-            /* reserve a memory area */
-            /* ??? This needs fixing for remapping.  */
-abort();
-            host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - 
TARGET_PAGE_SIZE;
-            real_start = (long)mmap(g2h(real_start), host_len, PROT_NONE,
-                                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-            if (real_start == -1)
-                return real_start;
-            real_end = real_start + host_len;
-            start = HOST_PAGE_ALIGN(real_start);
-            end = start + HOST_PAGE_ALIGN(len);
-            if (start > real_start)
-                munmap((void *)g2h(real_start), start - real_start);
-            if (end < real_end)
-                munmap((void *)g2h(end), real_end - end);
-            /* use it as a fixed mapping */
-            flags |= MAP_FIXED;
+        host_offset = offset & qemu_host_page_mask;
+        host_len = len + offset - host_offset;
+
+        if (qemu_host_page_size > qemu_real_host_page_size) {
+           /*
+            * The guest expects to see mmapped areas aligned to it's pagesize.
+            * If the hosts real page size is smaller than the guests, we need 
+            * to fixup the maps. It is done by allocating a larger area, 
+            * displacing the map (if needed) and finally choping off the spare
+            * room at the edges.
+            */
+
+           /* 
+            * We assume qemu_host_page_size is always the same as 
+            * TARGET_PAGE_SIZE, see exec.c. qemu_real_host_page_size is the
+            * hosts real page size. 
+            */
+            target_ulong host_end;
+
+            host_len = HOST_PAGE_ALIGN(host_len + qemu_host_page_size
+                                       - qemu_real_host_page_size); 
+            host_start = (long)mmap(real_start ? g2h(real_start) : NULL,
+                                    host_len, prot, flags, fd, host_offset);
+            if (host_start == -1)
+                return host_start;
+            host_end = host_start + host_len;
+
+            /* Find start and end, aligned to the targets pagesize with-in the
+               large mmaped area.  */
+            start = TARGET_PAGE_ALIGN(host_start);
+            end = start + TARGET_PAGE_ALIGN(len);
+            /* Chop off the leftovers, if any.  */
+            if (start > host_start)
+                munmap((void *)g2h(host_start), start - host_start);
+            if (end < host_end)
+                munmap((void *)g2h(end), host_end - end);
+           goto the_end1;
         } else {
             /* if not fixed, no need to do anything */
-            host_offset = offset & qemu_host_page_mask;
-            host_len = len + offset - host_offset;
             host_start = (long)mmap(real_start ? g2h(real_start) : NULL,
                                     host_len, prot, flags, fd, host_offset);
             if (host_start == -1)


Reply via email to