qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Richard Henderson <richard.henderson@linaro.org>
To: qemu-devel@nongnu.org
Cc: laurent@vivier.eu, mjt@tls.msk.ru
Subject: [PATCH v2 12/24] linux-user: Rewrite target_mprotect
Date: Fri,  7 Jul 2023 21:40:42 +0100	[thread overview]
Message-ID: <20230707204054.8792-15-richard.henderson@linaro.org> (raw)
In-Reply-To: <20230707204054.8792-1-richard.henderson@linaro.org>

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>
---
 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 bba01804b3..c03b0b4e43 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -119,8 +119,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);
 
@@ -131,63 +134,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



  parent reply	other threads:[~2023-07-07 20:43 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-07 20:40 [PATCH v2 00/24] linux-user: mmap range fixes Richard Henderson
2023-07-07 20:40 ` [PATCH v2 1/2] accel/tcg: Split out cpu_exec_longjmp_cleanup Richard Henderson
2023-07-08 13:07   ` Alex Bennée
2023-07-07 20:40 ` [PATCH v2 01/24] linux-user: Use assert in mmap_fork_start Richard Henderson
2023-07-07 20:40 ` [PATCH v2 2/2] accel/tcg: Always lock pages before translation Richard Henderson
2023-07-07 21:34   ` Richard W.M. Jones
2023-07-07 20:40 ` [PATCH v2 02/24] linux-user: Fix formatting of mmap.c Richard Henderson
2023-07-07 20:40 ` [PATCH v2 03/24] linux-user/strace: Expand struct flags to hold a mask Richard Henderson
2023-07-07 20:40 ` [PATCH v2 04/24] linux-user: Split TARGET_MAP_* out of syscall_defs.h Richard Henderson
2023-07-07 20:40 ` [PATCH v2 05/24] linux-user: Split TARGET_PROT_* " Richard Henderson
2023-07-07 20:40 ` [PATCH v2 06/24] linux-user: Populate more bits in mmap_flags_tbl Richard Henderson
2023-07-07 20:40 ` [PATCH v2 07/24] accel/tcg: Introduce page_check_range_empty Richard Henderson
2023-07-07 20:40 ` [PATCH v2 08/24] bsd-user: Use page_check_range_empty for MAP_EXCL Richard Henderson
2023-07-07 22:06   ` Warner Losh
2023-07-07 20:40 ` [PATCH v2 09/24] linux-user: Implement MAP_FIXED_NOREPLACE Richard Henderson
2023-07-07 20:40 ` [PATCH v2 10/24] linux-user: Split out target_to_host_prot Richard Henderson
2023-07-07 20:40 ` [PATCH v2 11/24] linux-user: Widen target_mmap offset argument to off_t Richard Henderson
2023-07-07 20:40 ` Richard Henderson [this message]
2023-07-07 20:40 ` [PATCH v2 13/24] linux-user: Rewrite mmap_frag Richard Henderson
2023-07-07 20:40 ` [PATCH v2 14/24] accel/tcg: Introduce page_find_range_empty Richard Henderson
2023-07-07 20:40 ` [PATCH v2 15/24] bsd-user: Use page_find_range_empty for mmap_find_vma_reserved Richard Henderson
2023-07-07 22:09   ` Warner Losh
2023-07-07 20:40 ` [PATCH v2 16/24] linux-user: " Richard Henderson
2023-07-07 20:40 ` [PATCH v2 17/24] linux-user: Use 'last' instead of 'end' in target_mmap Richard Henderson
2023-07-08 17:42   ` Philippe Mathieu-Daudé
2023-07-07 20:40 ` [PATCH v2 18/24] linux-user: Rewrite mmap_reserve Richard Henderson
2023-07-07 20:40 ` [PATCH v2 19/24] linux-user: Rename mmap_reserve to mmap_reserve_or_unmap Richard Henderson
2023-07-07 20:40 ` [PATCH v2 20/24] linux-user: Simplify target_munmap Richard Henderson
2023-07-07 20:40 ` [PATCH v2 21/24] accel/tcg: Accept more page flags in page_check_range Richard Henderson
2023-07-08 17:40   ` Philippe Mathieu-Daudé
2023-07-07 20:40 ` [PATCH v2 22/24] accel/tcg: Return bool from page_check_range Richard Henderson
2023-07-07 20:40 ` [PATCH v2 23/24] linux-user: Remove can_passthrough_madvise Richard Henderson
2023-07-07 20:40 ` [PATCH v2 24/24] linux-user: Simplify target_madvise Richard Henderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230707204054.8792-15-richard.henderson@linaro.org \
    --to=richard.henderson@linaro.org \
    --cc=laurent@vivier.eu \
    --cc=mjt@tls.msk.ru \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).