[RFC PATCH 08/18] accel/tcg: Replace size with first/last in probe_access_flags

Richard Henderson <[email protected]>
Newsgroups org.nongnu.qemu-riscv,org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <[email protected]>
Signed-off-by: Richard Henderson <[email protected]>
---
 include/accel/tcg/probe.h        | 24 +++++++++++++++++-------
 accel/tcg/cputlb.c               | 15 ++++++++-------
 accel/tcg/user-exec.c            |  7 +++++--
 semihosting/uaccess.c            | 10 ++++------
 target/arm/tcg/sve_helper.c      |  5 ++++-
 target/riscv/tcg/op_helper.c     |  4 ++--
 target/riscv/tcg/vector_helper.c | 21 ++++++++++++---------
 target/s390x/tcg/mem_helper.c    |  4 ++--
 8 files changed, 54 insertions(+), 36 deletions(-)

diff --git a/include/accel/tcg/probe.h b/include/accel/tcg/probe.h
index e3068a79de..06faf1269d 100644
--- a/include/accel/tcg/probe.h
+++ b/include/accel/tcg/probe.h
@@ -49,23 +49,33 @@ static inline void *probe_read(CPUArchState *env, vaddr addr, int size,
 /**
  * probe_access_flags:
  * @env: CPUArchState
- * @addr: guest virtual address to look up
- * @size: size of the access
+ * @addr: virtual address
+ * @first: beginning of virtual address range
+ * @last: end of virtual address range
  * @access_type: read, write or execute permission
  * @mmu_idx: MMU index to use for lookup
  * @nonfault: suppress the fault
  * @phost: return value for host address
  * @retaddr: return address for unwinding
  *
- * Similar to probe_access, loosely returning the TLB_FLAGS_MASK for
- * the page, and storing the host address for RAM in @phost.
+ * Probe an access for [@first, @last], where @addr is somewhere
+ * in that range.  Normally @addr == @first, but some targets have
+ * accesses which are forcibly aligned after an initial fault for an
+ * inaccessible page (e.g. Arm DC_ZVA, where [@first, @last] will be
+ * the bounds of the cacheline containing @addr).
+ *
+ * If the access does not satisfy @access_type:
+ *   - if @nonfault is false, raise an exception at @addr
+ *   - otherwise return TLB_INVALID_MASK.
+ *
+ * Otherwise, return the TLB_FLAGS_MASK for the page, and set @phost:
+ *   - host address for @addr, if direct host accesses are allowed,
+ *   - otherwise NULL.
  *
- * If @nonfault is set, do not raise an exception but return TLB_INVALID_MASK.
  * Do not handle watchpoints, but include TLB_WATCHPOINT in the returned flags.
  * Do handle clean pages, so exclude TLB_NOTDIRY from the returned flags.
- * For simplicity, all "mmio-like" flags are folded to TLB_MMIO.
  */
-int probe_access_flags(CPUArchState *env, vaddr addr, int size,
+int probe_access_flags(CPUArchState *env, vaddr addr, vaddr first, vaddr last,
                        MMUAccessType access_type, int mmu_idx,
                        bool nonfault, void **phost, uintptr_t retaddr);
 
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 6299cc73a4..a192c50e90 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1460,23 +1460,24 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size,
     return flags;
 }
 
-int probe_access_flags(CPUArchState *env, vaddr addr, int size,
+int probe_access_flags(CPUArchState *env, vaddr addr, vaddr first, vaddr last,
                        MMUAccessType access_type, int mmu_idx,
                        bool nonfault, void **phost, uintptr_t retaddr)
 {
     CPUTLBEntryFull *full;
     int flags;
 
-    g_assert(-(addr | TARGET_PAGE_MASK) >= size);
+    assert(first <= addr);
+    assert(addr <= last);
+    assert(((first ^ last) & TARGET_PAGE_MASK) == 0);
 
-    flags = probe_access_internal(env_cpu(env), addr, size, access_type,
-                                  mmu_idx, nonfault, phost, &full, retaddr,
-                                  true);
+    flags = probe_access_internal(env_cpu(env), addr, last - addr + 1,
+                                  access_type, mmu_idx, nonfault,
+                                  phost, &full, retaddr, true);
 
     /* Handle clean RAM pages. */
     if (unlikely(flags & TLB_NOTDIRTY)) {
-        int dirtysize = size == 0 ? 1 : size;
-        notdirty_write(env_cpu(env), addr, dirtysize, full, retaddr);
+        notdirty_write(env_cpu(env), first, last - first + 1, full, retaddr);
         flags &= ~TLB_NOTDIRTY;
     }
 
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index 3724e5d98e..44e9f7fa1a 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -790,13 +790,16 @@ static int probe_access_internal(CPUArchState *env, vaddr addr,
     cpu_loop_exit_sigsegv(env_cpu(env), addr, access_type, maperr, ra);
 }
 
-int probe_access_flags(CPUArchState *env, vaddr addr, int size,
+int probe_access_flags(CPUArchState *env, vaddr addr, vaddr first, vaddr last,
                        MMUAccessType access_type, int mmu_idx,
                        bool nonfault, void **phost, uintptr_t ra)
 {
     int flags;
 
-    g_assert(-(addr | TARGET_PAGE_MASK) >= size);
+    assert(first <= addr);
+    assert(addr <= first);
+    assert(((first ^ last) & TARGET_PAGE_MASK) == 0);
+
     flags = probe_access_internal(env, addr, access_type, nonfault, ra);
     *phost = (flags & TLB_INVALID_MASK) ? NULL : g2h_vaddr(env_cpu(env), addr);
     return flags;
diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c
index ff944d8c2f..1efe8464d7 100644
--- a/semihosting/uaccess.c
+++ b/semihosting/uaccess.c
@@ -33,15 +33,13 @@ ssize_t uaccess_strlen_user(CPUArchState *env, vaddr addr)
     size_t len = 0;
 
     while (1) {
-        size_t left_in_page;
+        vaddr last_in_page = addr | ~TARGET_PAGE_MASK;
+        size_t left_in_page = last_in_page - addr + 1;
         int flags;
         void *h;
 
-        /* Find the number of bytes remaining in the page. */
-        left_in_page = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK);
-
-        flags = probe_access_flags(env, addr, 0, MMU_DATA_LOAD,
-                                   mmu_idx, true, &h, 0);
+        flags = probe_access_flags(env, addr, addr, last_in_page,
+                                   MMU_DATA_LOAD, mmu_idx, true, &h, 0);
         if (flags & TLB_INVALID_MASK) {
             return -1;
         }
diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c
index 4e77a824dd..b824933694 100644
--- a/target/arm/tcg/sve_helper.c
+++ b/target/arm/tcg/sve_helper.c
@@ -6036,7 +6036,10 @@ bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env,
     addr = useronly_clean_ptr(addr);
 
 #ifdef CONFIG_USER_ONLY
-    flags = probe_access_flags(env, addr, 0, access_type, mmu_idx, nofault,
+    flags = probe_access_flags(env, addr,
+                               addr & TARGET_PAGE_MASK,
+                               addr | ~TARGET_PAGE_MASK,
+                               access_type, mmu_idx, nofault,
                                &info->host, retaddr);
 #else
     CPUTLBEntryFull *full;
diff --git a/target/riscv/tcg/op_helper.c b/target/riscv/tcg/op_helper.c
index a7bd42d2c6..b18bf683f4 100644
--- a/target/riscv/tcg/op_helper.c
+++ b/target/riscv/tcg/op_helper.c
@@ -250,8 +250,8 @@ static void check_zicbom_access(CPURISCVState *env,
      * addresses, whether a cache-block management instruction is
      * permitted to access the cache block is UNSPECIFIED."
      */
-    ret = probe_access_flags(env, address, cbomlen, MMU_DATA_LOAD,
-                             mmu_idx, true, &phost, ra);
+    ret = probe_access_flags(env, address, address, address + cbomlen - 1,
+                             MMU_DATA_LOAD, mmu_idx, true, &phost, ra);
     if (ret != TLB_INVALID_MASK) {
         /* Success: readable */
         return;
diff --git a/target/riscv/tcg/vector_helper.c b/target/riscv/tcg/vector_helper.c
index b7b3805a6d..87f2196bc7 100644
--- a/target/riscv/tcg/vector_helper.c
+++ b/target/riscv/tcg/vector_helper.c
@@ -704,7 +704,7 @@ vext_ldff(void *vd, target_ulong base, CPURISCVState *env,
     uint32_t esz = 1 << log2_esz;
     uint32_t msize = nf * esz;
     uint32_t vma = vext_vma(desc);
-    target_ulong addr, last, last_in_page, page_split, elems;
+    target_ulong addr, last, last_in_page, page_split, elems, adj, adj_last;
     MemOpIdx oi = vext_oi(desc, log2_esz);
     int mmu_index = get_mmuidx(oi);
     bool first_active;
@@ -759,10 +759,10 @@ vext_ldff(void *vd, target_ulong base, CPURISCVState *env,
      * Test whether the first page is accessible.
      * If the first element is active, it must succeed.
      */
-    flags = probe_access_flags(env, adjust_addr(env, addr),
-                               MIN(last, last_in_page) - addr + 1,
-                               MMU_DATA_LOAD, mmu_index, !first_active,
-                               &host, ra);
+    adj = adjust_addr(env, addr);
+    adj_last = MIN(last, last_in_page) - (addr - adj);
+    flags = probe_access_flags(env, adj, adj, adj_last, MMU_DATA_LOAD,
+                               mmu_index, !first_active, &host, ra);
 
     /* Get number of complete elements in the first page. */
     elems = MIN(page_split / msize, vl - i);
@@ -853,8 +853,10 @@ vext_ldff(void *vd, target_ulong base, CPURISCVState *env,
          * We have not yet advanced addr to the next page.
          */
         target_ulong next_page = addr + page_split;
-        flags |= probe_access_flags(env, adjust_addr(env, next_page),
-                                    last - next_page + 1, MMU_DATA_LOAD,
+
+        adj = adjust_addr(env, next_page);
+        adj_last = last - (next_page - adj);
+        flags |= probe_access_flags(env, adj, adj, adj_last, MMU_DATA_LOAD,
                                     mmu_index, true, &host, ra);
 
         /* Stop if invalid (unmapped) or mmio (transaction may fail). */
@@ -873,8 +875,9 @@ vext_ldff(void *vd, target_ulong base, CPURISCVState *env,
             host += addr - next_page;
         }
     } else {
-        flags = probe_access_flags(env, adjust_addr(env, addr),
-                                   last - addr + 1, MMU_DATA_LOAD,
+        adj = adjust_addr(env, addr);
+        adj_last = last - (addr - adj);
+        flags = probe_access_flags(env, adj, adj, adj_last, MMU_DATA_LOAD,
                                    mmu_index, true, &host, ra);
 
         /* Stop if invalid (unmapped) or mmio (transaction may fail). */
diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c
index 414e6838c8..d490434806 100644
--- a/target/s390x/tcg/mem_helper.c
+++ b/target/s390x/tcg/mem_helper.c
@@ -155,8 +155,8 @@ static inline int s390_probe_access(CPUArchState *env, vaddr addr,
                                     int mmu_idx, bool nonfault,
                                     void **phost, uintptr_t ra)
 {
-    int flags = probe_access_flags(env, addr, size, access_type, mmu_idx,
-                                   nonfault, phost, ra);
+    int flags = probe_access_flags(env, addr, addr, addr + size - 1,
+                                   access_type, mmu_idx, nonfault, phost, ra);
 
     if (unlikely(flags & TLB_INVALID_MASK)) {
 #ifdef CONFIG_USER_ONLY
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.