qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Warner Losh <imp@bsdimp.com>
To: qemu-devel@nongnu.org
Cc: Warner Losh <imp@bsdimp.com>, Kyle Evans <kevans@freebsd.org>,
	Jessica Clarke <jrtc27@jrtc27.com>
Subject: [PATCH 17/17] bsd-user: copy linux-user target_mprotect impl
Date: Fri,  2 Aug 2024 17:56:17 -0600	[thread overview]
Message-ID: <20240802235617.7971-18-imp@bsdimp.com> (raw)
In-Reply-To: <20240802235617.7971-1-imp@bsdimp.com>

Now that we're closer to the linux-user target_mprotect code, go ahead
and grab the rest of the implementation. This moves from a stard, end
impl to a start, last which will allow last page mapping, etc. This also
moves to a more general algorithm. We're close enough that this jump
isn't so large, and doing it incrementally further has become too
much work for too little gain.

Signed-off-by: Warner Losh <imp@bsdimp.com>
---
 bsd-user/mmap.c | 138 +++++++++++++++++++++++++++++++-----------------
 1 file changed, 90 insertions(+), 48 deletions(-)

diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index 3c48a188e88..a4de7674bec 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -60,6 +60,17 @@ void mmap_fork_end(int child)
         pthread_mutex_unlock(&mmap_mutex);
 }
 
+/*
+ * Map target protection mask to host. Identity on FreeBSD.
+ */
+static abi_ulong target_to_host_prot(abi_ulong prot)
+{
+    return (prot);
+}
+
+/* Helpful temporary #define to reduce diffs with linux-user mmap.c */
+#define trace_target_mprotect(start, len, target_prot)
+
 /*
  * Validate target prot bitmask.
  * Return the prot bitmask for the host in *HOST_PROT.
@@ -78,72 +89,103 @@ static int validate_prot_to_pageflags(int prot)
 int target_mprotect(abi_ulong start, abi_ulong len, int target_prot)
 {
     int host_page_size = qemu_real_host_page_size();
-    abi_ulong end, host_start, host_end, addr;
-    int prot1, ret, page_flags;
-
-    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,
-                  target_prot & PROT_READ ? 'r' : '-',
-                  target_prot & PROT_WRITE ? 'w' : '-',
-                  target_prot & PROT_EXEC ? 'x' : '-');
-    if ((start & ~TARGET_PAGE_MASK) != 0)
-        return -EINVAL;
+    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);
+
+    if ((start & ~TARGET_PAGE_MASK) != 0) {
+        return -TARGET_EINVAL;
+    }
     page_flags = validate_prot_to_pageflags(target_prot);
     if (!page_flags) {
         return -TARGET_EINVAL;
     }
-    len = TARGET_PAGE_ALIGN(len);
-    if (len == 0)
+    if (len == 0) {
         return 0;
+    }
+    len = TARGET_PAGE_ALIGN(len);
     if (!guest_range_valid_untagged(start, len)) {
-        return -ENOMEM;
+        return -TARGET_ENOMEM;
     }
-    target_prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
-    end = start + len;
 
-    mmap_lock();
+    last = start + len - 1;
     host_start = start & -host_page_size;
-    host_end = HOST_PAGE_ALIGN(end);
-    if (start > host_start) {
-        /* handle host page containing start */
+    host_last = ROUND_UP(last, host_page_size) - 1;
+    nranges = 0;
+
+    mmap_lock();
+
+    if (host_last - host_start < 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);
+        }
+        for (abi_ulong a = last; a < host_last; a += TARGET_PAGE_SIZE) {
+            prot1 |= page_get_flags(a + 1);
         }
-        if (host_end == host_start + host_page_size) {
-            for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
-                prot1 |= page_get_flags(addr);
+        starts[nranges] = host_start;
+        lens[nranges] = 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] = host_page_size;
+                prots[nranges] = prot1;
+                nranges++;
+                host_start += host_page_size;
             }
-            end = host_end;
         }
-        ret = mprotect(g2h_untagged(host_start),
-                       host_page_size, prot1 & PAGE_RWX);
-        if (ret != 0)
-            goto error;
-        host_start += 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);
+
+        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 -= host_page_size;
+                starts[nranges] = host_last + 1;
+                lens[nranges] = host_page_size;
+                prots[nranges] = prot1;
+                nranges++;
+            }
+        }
+
+        /* 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 - host_page_size),
-                       host_page_size, prot1 & PAGE_RWX);
-        if (ret != 0)
-            goto error;
-        host_end -= 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_prot);
-        if (ret != 0)
+    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);
-    mmap_unlock();
-    return 0;
-error:
+
+    page_set_flags(start, last, page_flags);
+    ret = 0;
+
+ error:
     mmap_unlock();
     return ret;
 }
-- 
2.45.1



  parent reply	other threads:[~2024-08-02 23:59 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-02 23:56 [PATCH 00/17] For 9.2: A bunch of cleanups and work towards variable pagesize support Warner Losh
2024-08-02 23:56 ` [PATCH 01/17] bsd-user: Delete TaskState next member Warner Losh
2024-08-04  7:07   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 02/17] bsd-user: Make init_task_state global Warner Losh
2024-08-04  7:08   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 03/17] bsd-user: Make cpu_model and cpu_type file scope Warner Losh
2024-08-04  7:22   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 04/17] bsd-user: Implement cpu_copy() Warner Losh
2024-08-04  7:24   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 05/17] bsd-user: Eliminate unused regs arg in load_elf_binary Warner Losh
2024-08-04  7:26   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 06/17] bsd-user: Remove load_flt_binary prototype Warner Losh
2024-08-04  7:26   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 07/17] bsd-user: Remove deprecated -p argument Warner Losh
2024-08-04  7:26   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 08/17] bsd-user: Eliminate unused qemu_uname_release Warner Losh
2024-08-04  7:27   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 09/17] bsd-user: target_msync unused, remove it Warner Losh
2024-08-04  7:28   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 10/17] bsd-user: Pass image name down the stack Warner Losh
2024-08-04  7:29   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 11/17] bsd-user: Replace set_brk and padzero with zerobss from linux-user Warner Losh
2024-08-04 11:38   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 12/17] bsd-user: Use guest_range_valid_untagged to validate range Warner Losh
2024-08-04 21:30   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 13/17] bsd-user: target_mprotect: rename prot to target_prot Warner Losh
2024-08-04 21:31   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 14/17] bsd-user: target_mmap*: change " Warner Losh
2024-08-04 21:32   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 15/17] bsd-user: target_mprotect: use helper host_page_size local Warner Losh
2024-08-04 21:33   ` Richard Henderson
2024-08-02 23:56 ` [PATCH 16/17] bsd-user: Define validate_prot_to_pageflags and use in mprotect Warner Losh
2024-08-04 21:44   ` Richard Henderson
2024-08-02 23:56 ` Warner Losh [this message]
2024-08-04 21:47   ` [PATCH 17/17] bsd-user: copy linux-user target_mprotect impl 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=20240802235617.7971-18-imp@bsdimp.com \
    --to=imp@bsdimp.com \
    --cc=jrtc27@jrtc27.com \
    --cc=kevans@freebsd.org \
    --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).