- /* Note: we prefer to control the mapping address. It is
- especially important if qemu_host_page_size >
- qemu_real_host_page_size */
- p = mmap(g2h_untagged(mmap_start),
- host_len, prot, flags | MAP_FIXED, fd, host_offset);
+ }
+
+ /*
+ * 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 file maps at EOF and add extra anonymous pages
+ * up to the targets page boundary.
+ */
+
+ if ((qemu_real_host_page_size < qemu_host_page_size) && fd != -1) {
+ struct stat sb;
+
+ if (fstat(fd, &sb) == -1) {
+ goto fail;
+ }
+
+ /* Are we trying to create a map beyond 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 = REAL_HOST_PAGE_ALIGN(sb.st_size - offset);
+ }
+ }
+
+ if (!(flags & MAP_FIXED)) {
+ unsigned long host_start;
+ void *p;
+
+ host_len = len + offset - host_offset;
+ host_len = HOST_PAGE_ALIGN(host_len);
+
+ /*
+ * Note: we prefer to control the mapping address. It is
+ * especially important if qemu_host_page_size >
+ * qemu_real_host_page_size
+ */
+ p = mmap(g2h_untagged(start), host_len, prot,
+ flags | MAP_FIXED | ((fd != -1) ? MAP_ANONYMOUS : 0), -1, 0);