Commit 54c5a2ae54aa02a3e7a1f708c20b6bffe81b330b

Authored by edgar_igl
1 parent d6755878

Partialy fix mmap at EOF for large pagesize targets in user-mode.

Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6510 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 37 additions and 2 deletions
linux-user/mmap.c
... ... @@ -24,6 +24,8 @@
24 24 #include <string.h>
25 25 #include <unistd.h>
26 26 #include <errno.h>
  27 +#include <sys/types.h>
  28 +#include <sys/stat.h>
27 29 #include <sys/mman.h>
28 30 #include <linux/mman.h>
29 31 #include <linux/unistd.h>
... ... @@ -366,6 +368,36 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
366 368 goto the_end;
367 369 real_start = start & qemu_host_page_mask;
368 370  
  371 + /* When mapping files into a memory area larger than the file, accesses
  372 + to pages beyond the file size will cause a SIGBUS.
  373 +
  374 + For example, if mmaping a file of 100 bytes on a host with 4K pages
  375 + emulating a target with 8K pages, the target expects to be able to
  376 + access the first 8K. But the host will trap us on any access beyond
  377 + 4K.
  378 +
  379 + When emulating a target with a larger page-size than the hosts, we
  380 + may need to truncate file maps at EOF and add extra anonymous pages
  381 + up to the targets page boundary. */
  382 +
  383 + if ((qemu_real_host_page_size < TARGET_PAGE_SIZE)
  384 + && !(flags & MAP_ANONYMOUS)) {
  385 + struct stat sb;
  386 +
  387 + if (fstat (fd, &sb) == -1)
  388 + goto fail;
  389 +
  390 + /* Are we trying to create a map beyond EOF?. */
  391 + if (offset + len > sb.st_size) {
  392 + /* If so, truncate the file map at eof aligned with
  393 + the hosts real pagesize. Additional anonymous maps
  394 + will be created beyond EOF. */
  395 + len = (sb.st_size - offset);
  396 + len += qemu_real_host_page_size - 1;
  397 + len &= ~(qemu_real_host_page_size - 1);
  398 + }
  399 + }
  400 +
369 401 if (!(flags & MAP_FIXED)) {
370 402 abi_ulong mmap_start;
371 403 void *p;
... ... @@ -381,13 +413,16 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
381 413 especially important if qemu_host_page_size >
382 414 qemu_real_host_page_size */
383 415 p = mmap(g2h(mmap_start),
384   - host_len, prot, flags | MAP_FIXED, fd, host_offset);
  416 + host_len, prot, flags | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
385 417 if (p == MAP_FAILED)
386 418 goto fail;
387 419 /* update start so that it points to the file position at 'offset' */
388 420 host_start = (unsigned long)p;
389   - if (!(flags & MAP_ANONYMOUS))
  421 + if (!(flags & MAP_ANONYMOUS)) {
  422 + p = mmap(g2h(mmap_start), len, prot,
  423 + flags | MAP_FIXED, fd, host_offset);
390 424 host_start += offset - host_offset;
  425 + }
391 426 start = h2g(host_start);
392 427 } else {
393 428 int flg;
... ...