qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] mmap and pagesizes


From: Edgar E. Iglesias
Subject: [Qemu-devel] mmap and pagesizes
Date: Tue, 8 Jan 2008 14:17:44 +0100
User-agent: Mutt/1.5.16 (2007-06-09)

Hello,

I've been puzzled again by a problem related to different page-sizes between 
the host and the target. This time it's with fixed file mmaps.

Apparently, when mapping files into a memory area larger than the file, 
accesses to pages beyond the file size will cause a SIGBUS.

For example, if mmap-ing a file of 100 bytes on a host with 4K pages emulating 
a target with 8K pages, the target expects to be able to access the first 8K. 
But the host OS will trap us on any access beyond 4K.

In my particular test-case, the problem trigged when the dynamic linker was 
setting up the .bss which happened to share a targets worth of page with the 
.data section. On the host, two pages were needed, one of them beyond the file 
size.

When emulating a target with a larger page-size than the hosts, we may need to 
truncate fixed file maps at EOF and add extra anonymous pages up to the targets 
page boundary to compensate. Luckily AFAICS, most of the code was already there 
to handle this case. I believe the hack in elfload.c is safe to remove now, but 
I'd appreciate it some one (the author) can verify that.

Best regards,
-- 
Edgar E. Iglesias
Axis Communications AB

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index cde3c49..753d87d 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -714,23 +714,6 @@ static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
        if (elf_bss >= last_bss)
                return;
 
-        /* XXX: this is really a hack : if the real host page size is
-           smaller than the target page size, some pages after the end
-           of the file may not be mapped. A better fix would be to
-           patch target_mmap(), but it is more complicated as the file
-           size must be known */
-        if (qemu_real_host_page_size < qemu_host_page_size) {
-            abi_ulong end_addr, end_addr1;
-            end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
-                ~(qemu_real_host_page_size - 1);
-            end_addr = HOST_PAGE_ALIGN(elf_bss);
-            if (end_addr1 < end_addr) {
-                mmap((void *)g2h(end_addr1), end_addr - end_addr1,
-                     PROT_READ|PROT_WRITE|PROT_EXEC,
-                     MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
-            }
-        }
-
         nbyte = elf_bss & (qemu_host_page_size-1);
         if (nbyte) {
            nbyte = qemu_host_page_size - nbyte;
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 6292826..c352ebc 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -24,6 +24,8 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include "qemu.h"
 
@@ -264,6 +266,36 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int 
prot,
             errno = EINVAL;
             return -1;
         }
+
+       /* When mapping files into a memory area larger than the file, accesses
+          to pages beyond the file size will cause a SIGBUS. 
+
+          For example, if mmaping a file of 100 bytes on a host with 4K pages
+          emulating a target with 8K pages, the target expects to be able to
+          access the first 8K. But the host will trap us on any access beyond
+          4K.  
+
+          When emulating a target with a larger page-size than the hosts, we
+          may need to truncate fixed file maps at EOF and add extra anonymous 
+          pages up to the targets page boundary.  */
+       if (!(flags & MAP_ANONYMOUS)) {
+               struct stat sb;
+               
+               if (fstat (fd, &sb) == -1)
+                       return -1;
+               
+               /* Are trying to create a map beyond the EOF?.  */
+               if (offset + len > sb.st_size)
+               {
+                       /* If so, truncate the file map at eof aligned with 
+                          the hosts real pagesize. Additional anonymous maps
+                          will be created beyond EOF.  */
+                       len = (sb.st_size - offset);
+                       len += qemu_real_host_page_size - 1;
+                       len &= ~(qemu_real_host_page_size - 1);
+               }
+       }
+
         end = start + len;
         real_end = HOST_PAGE_ALIGN(end);
         
@@ -337,7 +369,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int 
prot,
     page_set_flags(start, start + len, prot | PAGE_VALID);
  the_end:
 #ifdef DEBUG_MMAP
-    printf("ret=0x%llx\n", start);
+    printf("ret=0x" TARGET_FMT_lx "\n", start);
     page_dump(stdout);
     printf("\n");
 #endif




reply via email to

[Prev in Thread] Current Thread [Next in Thread]