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


Reply via email to