diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2024-01-02 12:57:56 +1100 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2024-02-29 11:35:37 -1000 |
commit | 68098de90e653adbb8bfc30f85aab9d12f111b80 (patch) | |
tree | b9f0b46ff55c728cacdc6df850e90b2586ef3b84 /linux-user/mmap.c | |
parent | 3bfa271e46b506b2ceff41e3b258ad2ddeb25bc3 (diff) |
linux-user: Split out mmap_h_eq_g
Move the MAX_FIXED_NOREPLACE check for reserved_va earlier.
Move the computation of host_prot earlier.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Acked-by: Helge Deller <deller@gmx.de>
Message-Id: <20240102015808.132373-22-richard.henderson@linaro.org>
Diffstat (limited to 'linux-user/mmap.c')
-rw-r--r-- | linux-user/mmap.c | 68 |
1 files changed, 55 insertions, 13 deletions
diff --git a/linux-user/mmap.c b/linux-user/mmap.c index cbcd31e941..d3556bcc14 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -542,6 +542,33 @@ static abi_long mmap_end(abi_ulong start, abi_ulong last, return start; } +/* + * Special case host page size == target page size, + * where there are no edge conditions. + */ +static abi_long mmap_h_eq_g(abi_ulong start, abi_ulong len, + int host_prot, int flags, int page_flags, + int fd, off_t offset) +{ + void *p, *want_p = g2h_untagged(start); + abi_ulong last; + + p = mmap(want_p, len, host_prot, flags, fd, offset); + if (p == MAP_FAILED) { + return -1; + } + /* If the host kernel does not support MAP_FIXED_NOREPLACE, emulate. */ + if ((flags & MAP_FIXED_NOREPLACE) && p != want_p) { + do_munmap(p, len); + errno = EEXIST; + return -1; + } + + start = h2g(p); + last = start + len - 1; + return mmap_end(start, last, start, last, flags, page_flags); +} + static abi_long target_mmap__locked(abi_ulong start, abi_ulong len, int target_prot, int flags, int page_flags, int fd, off_t offset) @@ -550,6 +577,7 @@ static abi_long target_mmap__locked(abi_ulong start, abi_ulong len, abi_ulong ret, last, real_start, real_last, retaddr, host_len; abi_ulong passthrough_start = -1, passthrough_last = 0; off_t host_offset; + int host_prot; real_start = start & -host_page_size; host_offset = offset & -host_page_size; @@ -558,16 +586,33 @@ static abi_long target_mmap__locked(abi_ulong start, abi_ulong len, * For reserved_va, we are in full control of the allocation. * Find a suitable hole and convert to MAP_FIXED. */ - if (reserved_va && !(flags & (MAP_FIXED | MAP_FIXED_NOREPLACE))) { - host_len = len + offset - host_offset; - start = mmap_find_vma(real_start, host_len, - MAX(host_page_size, TARGET_PAGE_SIZE)); - if (start == (abi_ulong)-1) { - errno = ENOMEM; - return -1; + if (reserved_va) { + if (flags & MAP_FIXED_NOREPLACE) { + /* Validate that the chosen range is empty. */ + if (!page_check_range_empty(start, start + len - 1)) { + errno = EEXIST; + return -1; + } + flags = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED; + } else if (!(flags & MAP_FIXED)) { + size_t real_len = len + offset - host_offset; + abi_ulong align = MAX(host_page_size, TARGET_PAGE_SIZE); + + start = mmap_find_vma(real_start, real_len, align); + if (start == (abi_ulong)-1) { + errno = ENOMEM; + return -1; + } + start += offset - host_offset; + flags |= MAP_FIXED; } - start += offset - host_offset; - flags |= MAP_FIXED; + } + + host_prot = target_to_host_prot(target_prot); + + if (host_page_size == TARGET_PAGE_SIZE) { + return mmap_h_eq_g(start, len, host_prot, flags, + page_flags, fd, offset); } /* @@ -603,12 +648,10 @@ static abi_long target_mmap__locked(abi_ulong start, abi_ulong len, if (!(flags & (MAP_FIXED | MAP_FIXED_NOREPLACE))) { uintptr_t host_start; - int host_prot; void *p; host_len = len + offset - host_offset; host_len = ROUND_UP(host_len, host_page_size); - host_prot = target_to_host_prot(target_prot); /* Note: we prefer to control the mapping address. */ p = mmap(g2h_untagged(start), host_len, host_prot, @@ -731,8 +774,7 @@ static abi_long target_mmap__locked(abi_ulong start, abi_ulong len, len1 = real_last - real_start + 1; want_p = g2h_untagged(real_start); - p = mmap(want_p, len1, target_to_host_prot(target_prot), - flags, fd, offset1); + p = mmap(want_p, len1, host_prot, flags, fd, offset1); if (p != want_p) { if (p != MAP_FAILED) { do_munmap(p, len1); |