[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 31/47] linux-user: Rewrite target_mprotect
From: |
Richard Henderson |
Subject: |
[PULL 31/47] linux-user: Rewrite target_mprotect |
Date: |
Sat, 15 Jul 2023 14:53:01 +0100 |
Use 'last' variables instead of 'end' variables.
When host page size > guest page size, detect when
adjacent host pages have the same protection and
merge that expanded host range into fewer syscalls.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20230707204054.8792-15-richard.henderson@linaro.org>
---
linux-user/mmap.c | 106 +++++++++++++++++++++++++++++-----------------
1 file changed, 67 insertions(+), 39 deletions(-)
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index b2c2d85857..d02d74d279 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -120,8 +120,11 @@ static int target_to_host_prot(int prot)
/* NOTE: all the constants are the HOST ones, but addresses are target. */
int target_mprotect(abi_ulong start, abi_ulong len, int target_prot)
{
- abi_ulong end, host_start, host_end, addr;
- int prot1, ret, page_flags;
+ abi_ulong starts[3];
+ abi_ulong lens[3];
+ int prots[3];
+ abi_ulong host_start, host_last, last;
+ int prot1, ret, page_flags, nranges;
trace_target_mprotect(start, len, target_prot);
@@ -132,63 +135,88 @@ int target_mprotect(abi_ulong start, abi_ulong len, int
target_prot)
if (!page_flags) {
return -TARGET_EINVAL;
}
- len = TARGET_PAGE_ALIGN(len);
- end = start + len;
- if (!guest_range_valid_untagged(start, len)) {
- return -TARGET_ENOMEM;
- }
if (len == 0) {
return 0;
}
+ len = TARGET_PAGE_ALIGN(len);
+ if (!guest_range_valid_untagged(start, len)) {
+ return -TARGET_ENOMEM;
+ }
+
+ last = start + len - 1;
+ host_start = start & qemu_host_page_mask;
+ host_last = HOST_PAGE_ALIGN(last) - 1;
+ nranges = 0;
mmap_lock();
- host_start = start & qemu_host_page_mask;
- host_end = HOST_PAGE_ALIGN(end);
- if (start > host_start) {
- /* handle host page containing start */
+
+ if (host_last - host_start < qemu_host_page_size) {
+ /* Single host page contains all guest pages: sum the prot. */
prot1 = target_prot;
- for (addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
- prot1 |= page_get_flags(addr);
+ for (abi_ulong a = host_start; a < start; a += TARGET_PAGE_SIZE) {
+ prot1 |= page_get_flags(a);
}
- if (host_end == host_start + qemu_host_page_size) {
- for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
- prot1 |= page_get_flags(addr);
+ for (abi_ulong a = last; a < host_last; a += TARGET_PAGE_SIZE) {
+ prot1 |= page_get_flags(a + 1);
+ }
+ starts[nranges] = host_start;
+ lens[nranges] = qemu_host_page_size;
+ prots[nranges] = prot1;
+ nranges++;
+ } else {
+ if (host_start < start) {
+ /* Host page contains more than one guest page: sum the prot. */
+ prot1 = target_prot;
+ for (abi_ulong a = host_start; a < start; a += TARGET_PAGE_SIZE) {
+ prot1 |= page_get_flags(a);
+ }
+ /* If the resulting sum differs, create a new range. */
+ if (prot1 != target_prot) {
+ starts[nranges] = host_start;
+ lens[nranges] = qemu_host_page_size;
+ prots[nranges] = prot1;
+ nranges++;
+ host_start += qemu_host_page_size;
}
- end = host_end;
}
- ret = mprotect(g2h_untagged(host_start), qemu_host_page_size,
- target_to_host_prot(prot1));
- if (ret != 0) {
- goto error;
+
+ if (last < host_last) {
+ /* Host page contains more than one guest page: sum the prot. */
+ prot1 = target_prot;
+ for (abi_ulong a = last; a < host_last; a += TARGET_PAGE_SIZE) {
+ prot1 |= page_get_flags(a + 1);
+ }
+ /* If the resulting sum differs, create a new range. */
+ if (prot1 != target_prot) {
+ host_last -= qemu_host_page_size;
+ starts[nranges] = host_last + 1;
+ lens[nranges] = qemu_host_page_size;
+ prots[nranges] = prot1;
+ nranges++;
+ }
}
- host_start += qemu_host_page_size;
- }
- if (end < host_end) {
- prot1 = target_prot;
- for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
- prot1 |= page_get_flags(addr);
+
+ /* Create a range for the middle, if any remains. */
+ if (host_start < host_last) {
+ starts[nranges] = host_start;
+ lens[nranges] = host_last - host_start + 1;
+ prots[nranges] = target_prot;
+ nranges++;
}
- ret = mprotect(g2h_untagged(host_end - qemu_host_page_size),
- qemu_host_page_size, target_to_host_prot(prot1));
- if (ret != 0) {
- goto error;
- }
- host_end -= qemu_host_page_size;
}
- /* handle the pages in the middle */
- if (host_start < host_end) {
- ret = mprotect(g2h_untagged(host_start), host_end - host_start,
- target_to_host_prot(target_prot));
+ for (int i = 0; i < nranges; ++i) {
+ ret = mprotect(g2h_untagged(starts[i]), lens[i],
+ target_to_host_prot(prots[i]));
if (ret != 0) {
goto error;
}
}
- page_set_flags(start, start + len - 1, page_flags);
+ page_set_flags(start, last, page_flags);
ret = 0;
-error:
+ error:
mmap_unlock();
return ret;
}
--
2.34.1
- [PULL 39/47] linux-user: Simplify target_munmap, (continued)
- [PULL 39/47] linux-user: Simplify target_munmap, Richard Henderson, 2023/07/15
- [PULL 01/47] linux-user: Reformat syscall_defs.h, Richard Henderson, 2023/07/15
- [PULL 03/47] linux-user: Use abi_uint not uint32_t in syscall_defs.h, Richard Henderson, 2023/07/15
- [PULL 07/47] linux-user: Use abi_uint not unsigned int in syscall_defs.h, Richard Henderson, 2023/07/15
- [PULL 11/47] linux-user: Use abi_ushort not unsigned short in syscall_defs.h, Richard Henderson, 2023/07/15
- [PULL 22/47] linux-user/strace: Expand struct flags to hold a mask, Richard Henderson, 2023/07/15
- [PULL 12/47] linux-user: Use abi_short not short in syscall_defs.h, Richard Henderson, 2023/07/15
- [PULL 29/47] linux-user: Split out target_to_host_prot, Richard Henderson, 2023/07/15
- [PULL 35/47] linux-user: Use page_find_range_empty for mmap_find_vma_reserved, Richard Henderson, 2023/07/15
- [PULL 31/47] linux-user: Rewrite target_mprotect,
Richard Henderson <=
- [PULL 34/47] bsd-user: Use page_find_range_empty for mmap_find_vma_reserved, Richard Henderson, 2023/07/15
- [PULL 08/47] linux-user: Use abi_ullong not unsigned long long in syscall_defs.h, Richard Henderson, 2023/07/15
- [PULL 18/47] accel/tcg: Split out cpu_exec_longjmp_cleanup, Richard Henderson, 2023/07/15
- [PULL 32/47] linux-user: Rewrite mmap_frag, Richard Henderson, 2023/07/15
- [PULL 23/47] linux-user: Split TARGET_MAP_* out of syscall_defs.h, Richard Henderson, 2023/07/15
- [PULL 33/47] accel/tcg: Introduce page_find_range_empty, Richard Henderson, 2023/07/15
- [PULL 28/47] linux-user: Implement MAP_FIXED_NOREPLACE, Richard Henderson, 2023/07/15
- [PULL 24/47] linux-user: Split TARGET_PROT_* out of syscall_defs.h, Richard Henderson, 2023/07/15
- [PULL 21/47] linux-user: Fix formatting of mmap.c, Richard Henderson, 2023/07/15
- [PULL 38/47] linux-user: Rename mmap_reserve to mmap_reserve_or_unmap, Richard Henderson, 2023/07/15