diff options
Diffstat (limited to 'linux-user/mmap.c')
| -rw-r--r-- | linux-user/mmap.c | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 6a828e8418..28f3bc85ed 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -22,6 +22,7 @@ #include "qemu.h" #include "user-internals.h" #include "user-mmap.h" +#include "target_mman.h" static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER; static __thread int mmap_lock_count; @@ -105,6 +106,8 @@ static int validate_prot_to_pageflags(int *host_prot, int prot) page_flags |= PAGE_MTE; } } +#elif defined(TARGET_HPPA) + valid |= PROT_GROWSDOWN | PROT_GROWSUP; #endif return prot & ~valid ? 0 : page_flags; @@ -253,8 +256,12 @@ static int mmap_frag(abi_ulong real_start, # define TASK_UNMAPPED_BASE (1ul << 38) #endif #else +#ifdef TARGET_HPPA +# define TASK_UNMAPPED_BASE 0xfa000000 +#else # define TASK_UNMAPPED_BASE 0x40000000 #endif +#endif abi_ulong mmap_next_start = TASK_UNMAPPED_BASE; unsigned long last_brk; @@ -426,7 +433,8 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align) abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, int flags, int fd, abi_ulong offset) { - abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; + abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len, + passthrough_start = -1, passthrough_end = -1; int page_flags, host_prot; mmap_lock(); @@ -539,6 +547,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, host_start += offset - host_offset; } start = h2g(host_start); + passthrough_start = start; + passthrough_end = start + len; } else { if (start & ~TARGET_PAGE_MASK) { errno = EINVAL; @@ -621,6 +631,8 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, host_prot, flags, fd, offset1); if (p == MAP_FAILED) goto fail; + passthrough_start = real_start; + passthrough_end = real_end; } } the_end1: @@ -628,7 +640,18 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, page_flags |= PAGE_ANON; } page_flags |= PAGE_RESET; - page_set_flags(start, start + len, page_flags); + if (passthrough_start == passthrough_end) { + page_set_flags(start, start + len, page_flags); + } else { + if (start < passthrough_start) { + page_set_flags(start, passthrough_start, page_flags); + } + page_set_flags(passthrough_start, passthrough_end, + page_flags | PAGE_PASSTHROUGH); + if (passthrough_end < start + len) { + page_set_flags(passthrough_end, start + len, page_flags); + } + } the_end: trace_target_mmap_complete(start); if (qemu_loglevel_mask(CPU_LOG_PAGE)) { @@ -847,7 +870,7 @@ static bool can_passthrough_madv_dontneed(abi_ulong start, abi_ulong end) } for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) { - if (!(page_get_flags(addr) & PAGE_ANON)) { + if (!(page_get_flags(addr) & PAGE_PASSTHROUGH)) { return false; } } @@ -889,11 +912,12 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) * This is a hint, so ignoring and returning success is ok. * * This breaks MADV_DONTNEED, completely implementing which is quite - * complicated. However, there is one low-hanging fruit: host-page-aligned - * anonymous mappings. In this case passthrough is safe, so do it. + * complicated. However, there is one low-hanging fruit: mappings that are + * known to have the same semantics in the host and the guest. In this case + * passthrough is safe, so do it. */ mmap_lock(); - if (advice == MADV_DONTNEED && + if (advice == TARGET_MADV_DONTNEED && can_passthrough_madv_dontneed(start, end)) { ret = get_errno(madvise(g2h_untagged(start), len, MADV_DONTNEED)); if (ret == 0) { |