Commit 54c5a2ae54aa02a3e7a1f708c20b6bffe81b330b
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,6 +24,8 @@ | ||
| 24 | #include <string.h> | 24 | #include <string.h> |
| 25 | #include <unistd.h> | 25 | #include <unistd.h> |
| 26 | #include <errno.h> | 26 | #include <errno.h> |
| 27 | +#include <sys/types.h> | ||
| 28 | +#include <sys/stat.h> | ||
| 27 | #include <sys/mman.h> | 29 | #include <sys/mman.h> |
| 28 | #include <linux/mman.h> | 30 | #include <linux/mman.h> |
| 29 | #include <linux/unistd.h> | 31 | #include <linux/unistd.h> |
| @@ -366,6 +368,36 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, | @@ -366,6 +368,36 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, | ||
| 366 | goto the_end; | 368 | goto the_end; |
| 367 | real_start = start & qemu_host_page_mask; | 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 | if (!(flags & MAP_FIXED)) { | 401 | if (!(flags & MAP_FIXED)) { |
| 370 | abi_ulong mmap_start; | 402 | abi_ulong mmap_start; |
| 371 | void *p; | 403 | void *p; |
| @@ -381,13 +413,16 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, | @@ -381,13 +413,16 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, | ||
| 381 | especially important if qemu_host_page_size > | 413 | especially important if qemu_host_page_size > |
| 382 | qemu_real_host_page_size */ | 414 | qemu_real_host_page_size */ |
| 383 | p = mmap(g2h(mmap_start), | 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 | if (p == MAP_FAILED) | 417 | if (p == MAP_FAILED) |
| 386 | goto fail; | 418 | goto fail; |
| 387 | /* update start so that it points to the file position at 'offset' */ | 419 | /* update start so that it points to the file position at 'offset' */ |
| 388 | host_start = (unsigned long)p; | 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 | host_start += offset - host_offset; | 424 | host_start += offset - host_offset; |
| 425 | + } | ||
| 391 | start = h2g(host_start); | 426 | start = h2g(host_start); |
| 392 | } else { | 427 | } else { |
| 393 | int flg; | 428 | int flg; |