X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=bsd-user%2Fmmap.c;h=8e148a2ea3e24f4290ad109b3f48dcebea12af6a;hb=b55e4b9c0525560577384adfc6d30eb0daa8d7be;hp=b40ab9045fe404db95f1ceb0658172d8ba9c52c4;hpb=eae587e8e3694b1aceab23239493fb4c7e1a80f5;p=mirror_qemu.git diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c index b40ab9045f..8e148a2ea3 100644 --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -19,9 +19,6 @@ #include "qemu/osdep.h" #include "qemu.h" -#include "qemu-common.h" - -//#define DEBUG_MMAP static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER; static __thread int mmap_lock_count; @@ -35,6 +32,7 @@ void mmap_lock(void) void mmap_unlock(void) { + assert(mmap_lock_count > 0); if (--mmap_lock_count == 0) { pthread_mutex_unlock(&mmap_mutex); } @@ -67,14 +65,11 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot) abi_ulong end, host_start, host_end, addr; int prot1, ret; -#ifdef DEBUG_MMAP - printf("mprotect: start=0x" TARGET_ABI_FMT_lx - "len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c\n", start, len, - prot & PROT_READ ? 'r' : '-', - prot & PROT_WRITE ? 'w' : '-', - prot & PROT_EXEC ? 'x' : '-'); -#endif - + qemu_log_mask(CPU_LOG_PAGE, "mprotect: start=0x" TARGET_ABI_FMT_lx + " len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c\n", start, len, + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-'); if ((start & ~TARGET_PAGE_MASK) != 0) return -EINVAL; len = TARGET_PAGE_ALIGN(len); @@ -124,7 +119,7 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot) if (ret != 0) goto error; } - page_set_flags(start, start + len, prot | PAGE_VALID); + page_set_flags(start, start + len - 1, prot | PAGE_VALID); mmap_unlock(); return 0; error: @@ -132,7 +127,27 @@ error: return ret; } -/* map an incomplete host page */ +/* + * map an incomplete host page + * + * mmap_frag can be called with a valid fd, if flags doesn't contain one of + * MAP_ANON, MAP_STACK, MAP_GUARD. If we need to map a page in those cases, we + * pass fd == -1. However, if flags contains MAP_GUARD then MAP_ANON cannot be + * added. + * + * * If fd is valid (not -1) we want to map the pages with MAP_ANON. + * * If flags contains MAP_GUARD we don't want to add MAP_ANON because it + * will be rejected. See kern_mmap's enforcing of constraints for MAP_GUARD + * in sys/vm/vm_mmap.c. + * * If flags contains MAP_ANON it doesn't matter if we add it or not. + * * If flags contains MAP_STACK, mmap adds MAP_ANON when called so doesn't + * matter if we add it or not either. See enforcing of constraints for + * MAP_STACK in kern_mmap. + * + * Don't add MAP_ANON for the flags that use fd == -1 without specifying the + * flags directly, with the assumption that future flags that require fd == -1 + * will also not require MAP_ANON. + */ static int mmap_frag(abi_ulong real_start, abi_ulong start, abi_ulong end, int prot, int flags, int fd, abi_ulong offset) @@ -152,9 +167,9 @@ static int mmap_frag(abi_ulong real_start, } if (prot1 == 0) { - /* no page was there, so we allocate one */ + /* no page was there, so we allocate one. See also above. */ void *p = mmap(host_start, qemu_host_page_size, prot, - flags | MAP_ANON, -1, 0); + flags | ((fd != -1) ? MAP_ANON : 0), -1, 0); if (p == MAP_FAILED) return -1; prot1 = prot; @@ -162,7 +177,7 @@ static int mmap_frag(abi_ulong real_start, prot1 &= PAGE_BITS; prot_new = prot | prot1; - if (!(flags & MAP_ANON)) { + if (fd != -1) { /* msync() won't work here, so we return an error if write is possible while it is a shared mapping */ if ((flags & TARGET_BSD_MAP_FLAGMASK) == MAP_SHARED && @@ -174,16 +189,20 @@ static int mmap_frag(abi_ulong real_start, mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE); /* read the corresponding file data */ - pread(fd, g2h_untagged(start), end - start, offset); + if (pread(fd, g2h_untagged(start), end - start, offset) == -1) { + return -1; + } /* put final protection */ if (prot_new != (prot1 | PROT_WRITE)) mprotect(host_start, qemu_host_page_size, prot_new); } else { - /* just update the protection */ if (prot_new != prot1) { mprotect(host_start, qemu_host_page_size, prot_new); } + if (prot_new & PROT_WRITE) { + memset(g2h_untagged(start), 0, end - start); + } } return 0; } @@ -195,8 +214,6 @@ static int mmap_frag(abi_ulong real_start, #endif abi_ulong mmap_next_start = TASK_UNMAPPED_BASE; -unsigned long last_brk; - /* * Subroutine of mmap_find_vma, used when we have pre-allocated a chunk of guest * address space. @@ -204,50 +221,16 @@ unsigned long last_brk; static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size, abi_ulong alignment) { - abi_ulong addr; - abi_ulong end_addr; - int prot; - int looped = 0; - - if (size > reserved_va) { - return (abi_ulong)-1; - } + abi_ulong ret; - size = HOST_PAGE_ALIGN(size) + alignment; - end_addr = start + size; - if (end_addr > reserved_va) { - end_addr = reserved_va; + ret = page_find_range_empty(start, reserved_va, size, alignment); + if (ret == -1 && start > TARGET_PAGE_SIZE) { + /* Restart at the beginning of the address space. */ + ret = page_find_range_empty(TARGET_PAGE_SIZE, start - 1, + size, alignment); } - addr = end_addr - qemu_host_page_size; - while (1) { - if (addr > end_addr) { - if (looped) { - return (abi_ulong)-1; - } - end_addr = reserved_va; - addr = end_addr - qemu_host_page_size; - looped = 1; - continue; - } - prot = page_get_flags(addr); - if (prot) { - end_addr = addr; - } - if (end_addr - addr >= size) { - break; - } - addr -= qemu_host_page_size; - } - - if (start == mmap_next_start) { - mmap_next_start = addr; - } - /* addr is sufficiently low to align it up */ - if (alignment != 0) { - addr = (addr + alignment) & ~(alignment - 1); - } - return addr; + return ret; } /* @@ -275,20 +258,17 @@ static abi_ulong mmap_find_vma_aligned(abi_ulong start, abi_ulong size, if (reserved_va) { return mmap_find_vma_reserved(start, size, - (alignment != 0 ? 1 << alignment : 0)); + (alignment != 0 ? 1 << alignment : + MAX(qemu_host_page_size, TARGET_PAGE_SIZE))); } addr = start; wrapped = repeat = 0; prev = 0; - flags = MAP_ANONYMOUS | MAP_PRIVATE; -#ifdef MAP_ALIGNED + flags = MAP_ANON | MAP_PRIVATE; if (alignment != 0) { flags |= MAP_ALIGNED(alignment); } -#else - /* XXX TODO */ -#endif for (;; prev = ptr) { /* @@ -391,57 +371,48 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; mmap_lock(); -#ifdef DEBUG_MMAP - { - printf("mmap: start=0x" TARGET_ABI_FMT_lx - " len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c flags=", - start, len, - prot & PROT_READ ? 'r' : '-', - prot & PROT_WRITE ? 'w' : '-', - prot & PROT_EXEC ? 'x' : '-'); + if (qemu_loglevel_mask(CPU_LOG_PAGE)) { + qemu_log("mmap: start=0x" TARGET_ABI_FMT_lx + " len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c flags=", + start, len, + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-'); if (flags & MAP_ALIGNMENT_MASK) { - printf("MAP_ALIGNED(%u) ", (flags & MAP_ALIGNMENT_MASK) - >> MAP_ALIGNMENT_SHIFT); + qemu_log("MAP_ALIGNED(%u) ", + (flags & MAP_ALIGNMENT_MASK) >> MAP_ALIGNMENT_SHIFT); } -#if MAP_GUARD if (flags & MAP_GUARD) { - printf("MAP_GUARD "); + qemu_log("MAP_GUARD "); } -#endif if (flags & MAP_FIXED) { - printf("MAP_FIXED "); + qemu_log("MAP_FIXED "); } - if (flags & MAP_ANONYMOUS) { - printf("MAP_ANON "); + if (flags & MAP_ANON) { + qemu_log("MAP_ANON "); } -#ifdef MAP_EXCL if (flags & MAP_EXCL) { - printf("MAP_EXCL "); + qemu_log("MAP_EXCL "); } -#endif if (flags & MAP_PRIVATE) { - printf("MAP_PRIVATE "); + qemu_log("MAP_PRIVATE "); } if (flags & MAP_SHARED) { - printf("MAP_SHARED "); + qemu_log("MAP_SHARED "); } if (flags & MAP_NOCORE) { - printf("MAP_NOCORE "); + qemu_log("MAP_NOCORE "); } -#ifdef MAP_STACK if (flags & MAP_STACK) { - printf("MAP_STACK "); + qemu_log("MAP_STACK "); } -#endif - printf("fd=%d offset=0x%llx\n", fd, offset); + qemu_log("fd=%d offset=0x%lx\n", fd, offset); } -#endif - if ((flags & MAP_ANONYMOUS) && fd != -1) { + if ((flags & MAP_ANON) && fd != -1) { errno = EINVAL; goto fail; } -#ifdef MAP_STACK if (flags & MAP_STACK) { if ((fd != -1) || ((prot & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE))) { @@ -449,8 +420,6 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, goto fail; } } -#endif /* MAP_STACK */ -#ifdef MAP_GUARD if ((flags & MAP_GUARD) && (prot != PROT_NONE || fd != -1 || offset != 0 || (flags & (MAP_SHARED | MAP_PRIVATE | /* MAP_PREFAULT | */ /* MAP_PREFAULT not in mman.h */ @@ -458,18 +427,24 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, errno = EINVAL; goto fail; } -#endif if (offset & ~TARGET_PAGE_MASK) { errno = EINVAL; goto fail; } - len = TARGET_PAGE_ALIGN(len); if (len == 0) { errno = EINVAL; goto fail; } + + /* Check for overflows */ + len = TARGET_PAGE_ALIGN(len); + if (len == 0) { + errno = ENOMEM; + goto fail; + } + real_start = start & qemu_host_page_mask; host_offset = offset & qemu_host_page_mask; @@ -505,7 +480,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, * up to the targets page boundary. */ - if ((qemu_real_host_page_size < qemu_host_page_size) && fd != -1) { + if ((qemu_real_host_page_size() < qemu_host_page_size) && fd != -1) { struct stat sb; if (fstat(fd, &sb) == -1) { @@ -536,7 +511,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, * qemu_real_host_page_size */ p = mmap(g2h_untagged(start), host_len, prot, - flags | MAP_FIXED | ((fd != -1) ? MAP_ANONYMOUS : 0), -1, 0); + flags | MAP_FIXED | ((fd != -1) ? MAP_ANON : 0), -1, 0); if (p == MAP_FAILED) goto fail; /* update start so that it points to the file position at 'offset' */ @@ -564,18 +539,16 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, * It can fail only on 64-bit host with 32-bit target. * On any other target/host host mmap() handles this error correctly. */ -#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64 - if ((unsigned long)start + len - 1 > (abi_ulong) -1) { + if (!guest_range_valid_untagged(start, len)) { errno = EINVAL; goto fail; } -#endif /* * worst case: we cannot map the file because the offset is not * aligned, so we read it */ - if (!(flags & MAP_ANON) && + if (fd != -1 && (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { /* * msync() won't work here, so we return an error if write is @@ -591,17 +564,22 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, -1, 0); if (retaddr == -1) goto fail; - pread(fd, g2h_untagged(start), len, offset); + if (pread(fd, g2h_untagged(start), len, offset) == -1) { + goto fail; + } if (!(prot & PROT_WRITE)) { ret = target_mprotect(start, len, prot); - if (ret != 0) { - start = ret; - goto the_end; - } + assert(ret == 0); } goto the_end; } + /* Reject the mapping if any page within the range is mapped */ + if ((flags & MAP_EXCL) && !page_check_range_empty(start, end - 1)) { + errno = EINVAL; + goto fail; + } + /* handle the start of the mapping */ if (start > real_start) { if (real_end == real_start + qemu_host_page_size) { @@ -644,14 +622,13 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, } } the_end1: - page_set_flags(start, start + len, prot | PAGE_VALID); + page_set_flags(start, start + len - 1, prot | PAGE_VALID); the_end: #ifdef DEBUG_MMAP printf("ret=0x" TARGET_ABI_FMT_lx "\n", start); page_dump(stdout); printf("\n"); #endif - tb_invalidate_phys_range(start, start + len); mmap_unlock(); return start; fail: @@ -697,8 +674,7 @@ static void mmap_reserve(abi_ulong start, abi_ulong size) } if (real_start != real_end) { mmap(g2h_untagged(real_start), real_end - real_start, PROT_NONE, - MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, - -1, 0); + MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); } } @@ -757,8 +733,7 @@ int target_munmap(abi_ulong start, abi_ulong len) } if (ret == 0) { - page_set_flags(start, start + len, 0); - tb_invalidate_phys_range(start, start + len); + page_set_flags(start, start + len - 1, 0); } mmap_unlock(); return ret;