All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple
@ 2026-08-15 20:37 Richard Henderson
  2026-08-15 20:37 ` [RFC PATCH 01/18] target/arm: Imply probe from allocation_tag_mem_probe Richard Henderson
                   ` (17 more replies)
  0 siblings, 18 replies; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

The driver for this RFC is
https://lore.kernel.org/qemu-devel/ce3a48b5-9847-4cc4-a02f-86db497c91ae@linaro.org/

Based-on: 20260815194549.1377505-1-richard.henderson@linaro.org
("[PATCH 00/23] target/riscv: Reorg vector load/store")

But also merged to master, so for avoidance of doubt:
https://gitlab.com/rth7680/qemu/-/commits/tcg-probe

Convert probe_access_full, probe_access_flags, and the backend tlb_fill
hooks, but not (yet) probe_access itself.  I'm less certain about that,
since its uses are (1) less complicated and (2) there's also a path,
which I can't prove isn't used but neither can I find, which avoids
both watchpoints and notdirty pages.

I've tweaked the riscv pmp check to use the new parameters.
The similar Armv8-M code is a bit more complicated to push through,
and I need to study it a bit more.

Thoughts?


r~


Richard Henderson (18):
  target/arm: Imply probe from allocation_tag_mem_probe
  target/arm: Simplify invalid page test in allocation_tag_mem_internal
  target/arm: Return struct from allocation_tag_mem_internal
  target/arm: Generalize probe argument to allocation_tag_mem_internal
  target/arm: Probe second page earlier in allocation_tag_mem_internal
  accel/tcg: Drop fault_size from user-only probe_access_internal
  accel/tcg: Replace size with first/last in probe_access_full
  accel/tcg: Replace size with first/last in probe_access_flags
  accel/tcg: Allow phost to be NULL in probe_access_flags
  accel/tcg: Replace size with first/last in probe_access_internal
  accel/tcg: Replace size with first/last in tlb_fill_align
  accel/tcg: Replace size with first/last in TCGCPUOps.tlb_fill*
  target/riscv: Move PMP_AMATCH_OFF check in pmp_hart_has_privs
  target/riscv: Return bool from pmp_is_in_range
  target/riscv: Use boolean logic in pmp_hart_has_privs
  target/riscv: Recognize watchpoints with first/last
  target/riscv: Pass first/last to get_physical_address_pmp
  target/riscv: Pass first/last to pmp_hart_has_privs

 include/accel/tcg/cpu-ops.h          |  16 +-
 include/accel/tcg/probe.h            |  27 ++-
 target/alpha/cpu.h                   |   2 +-
 target/arm/internals.h               |   5 +-
 target/arm/tcg/mte_helper.h          |  18 +-
 target/avr/cpu.h                     |   2 +-
 target/hppa/cpu.h                    |   5 +-
 target/i386/tcg/helper-tcg.h         |   2 +-
 target/loongarch/tcg/tcg_loongarch.h |   2 +-
 target/m68k/cpu.h                    |   2 +-
 target/microblaze/cpu.h              |   2 +-
 target/mips/tcg/tcg-internal.h       |   2 +-
 target/or1k/cpu.h                    |   2 +-
 target/ppc/internal.h                |   2 +-
 target/riscv/cpu.h                   |   2 +-
 target/riscv/tcg/pmp.h               |   5 +-
 target/s390x/s390x-internal.h        |   2 +-
 target/sh4/cpu.h                     |   2 +-
 target/sparc/cpu.h                   |   2 +-
 target/tricore/cpu.h                 |   2 +-
 target/xtensa/cpu.h                  |   2 +-
 accel/tcg/cputlb.c                   |  91 +++++----
 accel/tcg/user-exec.c                |  20 +-
 semihosting/uaccess.c                |  10 +-
 target/alpha/helper.c                |   2 +-
 target/arm/gdbstub64.c               |  10 +-
 target/arm/tcg/helper-a64.c          |   5 +-
 target/arm/tcg/mte_helper.c          | 273 +++++++++++++++++----------
 target/arm/tcg/sve_helper.c          |  10 +-
 target/arm/tcg/tlb_helper.c          |   5 +-
 target/avr/helper.c                  |   2 +-
 target/hexagon/cpu.c                 |   8 +-
 target/hppa/mem_helper.c             |   6 +-
 target/i386/tcg/system/excp_helper.c |   2 +-
 target/loongarch/tcg/tlb_helper.c    |   3 +-
 target/m68k/helper.c                 |   3 +-
 target/microblaze/helper.c           |   2 +-
 target/mips/tcg/ldst_helper.c        |   4 +-
 target/mips/tcg/system/tlb_helper.c  |   2 +-
 target/or1k/mmu.c                    |   2 +-
 target/ppc/mmu_helper.c              |   2 +-
 target/riscv/tcg/cpu_helper.c        |  53 +++---
 target/riscv/tcg/op_helper.c         |   5 +-
 target/riscv/tcg/pmp.c               |  66 +++----
 target/riscv/tcg/vector_helper.c     |  21 ++-
 target/rx/cpu.c                      |   2 +-
 target/s390x/tcg/excp_helper.c       |   2 +-
 target/s390x/tcg/mem_helper.c        |   4 +-
 target/sh4/helper.c                  |   2 +-
 target/sparc/mmu_helper.c            |   4 +-
 target/tricore/helper.c              |   2 +-
 target/xtensa/helper.c               |   2 +-
 52 files changed, 412 insertions(+), 319 deletions(-)

-- 
2.43.0



^ permalink raw reply	[flat|nested] 38+ messages in thread

* [RFC PATCH 01/18] target/arm: Imply probe from allocation_tag_mem_probe
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-15 20:37 ` [RFC PATCH 02/18] target/arm: Simplify invalid page test in allocation_tag_mem_internal Richard Henderson
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv, Philippe Mathieu-Daudé

Rename current allocation_tag_mem_probe to
allocation_tag_mem_internal, then create a new
allocation_tag_mem_probe that lacks probe and ra arguments.
Force those to true and 0 when passing off to _internal.

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/tcg/mte_helper.h | 18 +++---------------
 target/arm/gdbstub64.c      | 10 +++++-----
 target/arm/tcg/mte_helper.c | 29 ++++++++++++++++++-----------
 3 files changed, 26 insertions(+), 31 deletions(-)

diff --git a/target/arm/tcg/mte_helper.h b/target/arm/tcg/mte_helper.h
index 1f471fb69b..b23a5de193 100644
--- a/target/arm/tcg/mte_helper.h
+++ b/target/arm/tcg/mte_helper.h
@@ -19,8 +19,6 @@
  * @ptr_access: the access to use for the virtual address
  * @ptr_size: the number of bytes in the normal memory access
  * @tag_access: the access to use for the tag memory
- * @probe: true to merely probe, never taking an exception
- * @ra: the return address for exception handling
  *
  * Our tag memory is formatted as a sequence of little-endian nibbles.
  * That is, the byte at (addr >> (LOG2_TAG_GRANULE + 1)) contains two
@@ -31,22 +29,12 @@
  * a pointer to the corresponding tag byte.
  *
  * If there is no tag storage corresponding to @ptr, return NULL.
- *
- * If the page is inaccessible for @ptr_access, or has a watchpoint, there are
- * three options:
- * (1) probe = true, ra = 0 : pure probe -- we return NULL if the page is not
- *     accessible, and do not take watchpoint traps. The calling code must
- *     handle those cases in the right priority compared to MTE traps.
- * (2) probe = false, ra = 0 : probe, no fault expected -- the caller guarantees
- *     that the page is going to be accessible. We will take watchpoint traps.
- * (3) probe = false, ra != 0 : non-probe -- we will take both memory access
- *     traps and watchpoint traps.
- * (probe = true, ra != 0 is invalid and will assert.)
+ * If the page is inaccessible for @ptr_access, return NULL.
+ * Do not take watcnpoint traps.
  */
 uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
                                   uint64_t ptr, MMUAccessType ptr_access,
-                                  int ptr_size, MMUAccessType tag_access,
-                                  bool probe, uintptr_t ra);
+                                  int ptr_size, MMUAccessType tag_access);
 
 /**
  * load_tag1 - Load 1 tag (nibble) from byte
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
index 0c3e5b30bd..08900f6843 100644
--- a/target/arm/gdbstub64.c
+++ b/target/arm/gdbstub64.c
@@ -725,8 +725,8 @@ static void handle_q_memtag(GArray *params, void *user_ctx)
     /* Find out the current translation regime for probe. */
     mmu_index = cpu_mmu_index(env_cpu(env), false);
     /* Note that tags are packed here (2 tags packed in one byte). */
-    tags = allocation_tag_mem_probe(env, mmu_index, addr, MMU_DATA_LOAD, 1,
-                                    MMU_DATA_LOAD, true, 0);
+    tags = allocation_tag_mem_probe(env, mmu_index, addr, MMU_DATA_LOAD,
+                                    1, MMU_DATA_LOAD);
     if (!tags) {
         /* Address is not in a tagged region. */
         gdb_put_packet("E04");
@@ -753,8 +753,8 @@ static void handle_q_isaddresstagged(GArray *params, void *user_ctx)
 
     /* Find out the current translation regime for probe. */
     mmu_index = cpu_mmu_index(env_cpu(env), false);
-    tags = allocation_tag_mem_probe(env, mmu_index, addr, MMU_DATA_LOAD, 1,
-                                    MMU_DATA_LOAD, true, 0);
+    tags = allocation_tag_mem_probe(env, mmu_index, addr, MMU_DATA_LOAD,
+                                    1, MMU_DATA_LOAD);
     reply = tags ? "01" : "00";
 
     gdb_put_packet(reply);
@@ -800,7 +800,7 @@ static void handle_Q_memtag(GArray *params, void *user_ctx)
     /* Find out the current translation regime for probe. */
     mmu_index = cpu_mmu_index(env_cpu(env), false);
     tags = allocation_tag_mem_probe(env, mmu_index, start_addr, MMU_DATA_STORE,
-                                    1, MMU_DATA_STORE, true, 0);
+                                    1, MMU_DATA_STORE);
     if (!tags) {
         /* Address is not in a tagged region. */
         gdb_put_packet("E04");
diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index ad4ad5b4cc..a1d8618ddb 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -79,10 +79,11 @@ static void mte_perm_check_fail(CPUARMState *env, uint64_t dirty_ptr,
 }
 #endif
 
-uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
-                                  uint64_t ptr, MMUAccessType ptr_access,
-                                  int ptr_size, MMUAccessType tag_access,
-                                  bool probe, uintptr_t ra)
+static uint8_t *
+allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
+                            uint64_t ptr, MMUAccessType ptr_access,
+                            int ptr_size, MMUAccessType tag_access,
+                            bool probe, uintptr_t ra)
 {
 #ifdef CONFIG_USER_ONLY
     const size_t page_data_size = TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1);
@@ -91,8 +92,6 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
     uint8_t *tags;
     uintptr_t index;
 
-    assert(!(probe && ra));
-
     if (!(flags & (ptr_access == MMU_DATA_STORE ? PAGE_WRITE_ORG : PAGE_READ))) {
         if (probe) {
             return NULL;
@@ -249,8 +248,16 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
                                    int ptr_size, MMUAccessType tag_access,
                                    uintptr_t ra)
 {
-    return allocation_tag_mem_probe(env, ptr_mmu_idx, ptr, ptr_access,
-                                    ptr_size, tag_access, false, ra);
+    return allocation_tag_mem_internal(env, ptr_mmu_idx, ptr, ptr_access,
+                                       ptr_size, tag_access, false, ra);
+}
+
+uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
+                                  uint64_t ptr, MMUAccessType ptr_access,
+                                  int ptr_size, MMUAccessType tag_access)
+{
+    return allocation_tag_mem_internal(env, ptr_mmu_idx, ptr, ptr_access,
+                                       ptr_size, tag_access, true, 0);
 }
 
 uint64_t HELPER(irg)(CPUARMState *env, uint64_t rn, uint64_t rm)
@@ -1144,7 +1151,7 @@ uint64_t mte_mops_probe(CPUARMState *env, uint64_t ptr, uint64_t size,
     /* True probe; this will never fault */
     mem = allocation_tag_mem_probe(env, mmu_idx, ptr,
                                    w ? MMU_DATA_STORE : MMU_DATA_LOAD,
-                                   size, MMU_DATA_LOAD, true, 0);
+                                   size, MMU_DATA_LOAD);
     if (!mem) {
         return size;
     }
@@ -1202,7 +1209,7 @@ uint64_t mte_mops_probe_rev(CPUARMState *env, uint64_t ptr, uint64_t size,
      */
     mem = allocation_tag_mem_probe(env, mmu_idx, ptr,
                                    w ? MMU_DATA_STORE : MMU_DATA_LOAD,
-                                   1, MMU_DATA_LOAD, true, 0);
+                                   1, MMU_DATA_LOAD);
     if (!mem) {
         return size;
     }
@@ -1254,7 +1261,7 @@ void mte_mops_set_tags(CPUARMState *env, uint64_t ptr, uint64_t size,
     mmu_idx = FIELD_EX32(desc, MTEDESC, MIDX);
     /* True probe: this will never fault */
     mem = allocation_tag_mem_probe(env, mmu_idx, ptr, MMU_DATA_STORE, size,
-                                   MMU_DATA_STORE, true, 0);
+                                   MMU_DATA_STORE);
     if (!mem) {
         return;
     }
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 02/18] target/arm: Simplify invalid page test in allocation_tag_mem_internal
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
  2026-08-15 20:37 ` [RFC PATCH 01/18] target/arm: Imply probe from allocation_tag_mem_probe Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-15 20:37 ` [RFC PATCH 03/18] target/arm: Return struct from allocation_tag_mem_internal Richard Henderson
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv, Philippe Mathieu-Daudé

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/tcg/mte_helper.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index a1d8618ddb..e3952fcabf 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -132,10 +132,10 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
      */
     flags = probe_access_full(env, ptr, 0, ptr_access, ptr_mmu_idx,
                               ra == 0, &host, &full, ra);
-    if (probe && (flags & TLB_INVALID_MASK)) {
+    if (unlikely(flags & TLB_INVALID_MASK)) {
+        assert(probe);
         return NULL;
     }
-    assert(!(flags & TLB_INVALID_MASK));
 
     switch (full->extra.arm.pte_attrs) {
     case 0xf0: /* Tagged */
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 03/18] target/arm: Return struct from allocation_tag_mem_internal
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
  2026-08-15 20:37 ` [RFC PATCH 01/18] target/arm: Imply probe from allocation_tag_mem_probe Richard Henderson
  2026-08-15 20:37 ` [RFC PATCH 02/18] target/arm: Simplify invalid page test in allocation_tag_mem_internal Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-15 20:37 ` [RFC PATCH 04/18] target/arm: Generalize probe argument to allocation_tag_mem_internal Richard Henderson
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv, Philippe Mathieu-Daudé

Return not just the tag memory, but the data memory, flags,
and attributes.  Make sure probe of NoTagAccess looks like
any other page permission failure.

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/tcg/mte_helper.c | 104 +++++++++++++++++++++---------------
 1 file changed, 62 insertions(+), 42 deletions(-)

diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index e3952fcabf..dd4c10ef4f 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -27,6 +27,7 @@
 #ifdef CONFIG_USER_ONLY
 #include "user/cpu_loop.h"
 #include "user/page-protection.h"
+#include "user/guest-host.h"
 #else
 #include "system/physmem.h"
 #endif
@@ -79,46 +80,55 @@ static void mte_perm_check_fail(CPUARMState *env, uint64_t dirty_ptr,
 }
 #endif
 
-static uint8_t *
+typedef struct AllocationTagMem {
+    uint8_t *tag_mem;
+    void *ptr_mem;
+    int flags;
+    MemTxAttrs attrs;
+} AllocationTagMem;
+
+static AllocationTagMem
 allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
-                            uint64_t ptr, MMUAccessType ptr_access,
+                            vaddr ptr, MMUAccessType ptr_access,
                             int ptr_size, MMUAccessType tag_access,
                             bool probe, uintptr_t ra)
 {
-#ifdef CONFIG_USER_ONLY
-    const size_t page_data_size = TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1);
-    uint64_t clean_ptr = useronly_clean_ptr(ptr);
-    int flags = page_get_flags(clean_ptr);
-    uint8_t *tags;
-    uintptr_t index;
+    AllocationTagMem ret = {
+        .flags = TLB_INVALID_MASK,
+        .attrs = MEMTXATTRS_UNSPECIFIED,
+    };
 
-    if (!(flags & (ptr_access == MMU_DATA_STORE ? PAGE_WRITE_ORG : PAGE_READ))) {
+#ifdef CONFIG_USER_ONLY
+    vaddr clean_ptr = useronly_clean_ptr(ptr);
+    int flags = page_get_flags(clean_ptr);
+    int req_flags = ptr_access == MMU_DATA_STORE ? PAGE_WRITE_ORG : PAGE_READ;
+
+    if (unlikely(!(flags & req_flags))) {
         if (probe) {
-            return NULL;
+            goto fini;
         }
         cpu_loop_exit_sigsegv(env_cpu(env), ptr, ptr_access,
                               !(flags & PAGE_VALID), ra);
     }
 
     /* Require both MAP_ANON and PROT_MTE for the page. */
-    if (!(flags & PAGE_ANON) || !(flags & PAGE_MTE)) {
-        return NULL;
+    if ((flags & PAGE_ANON) && (flags & PAGE_MTE)) {
+        size_t page_data_size = TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1);
+        uint8_t *tags = page_get_target_data(clean_ptr, page_data_size);
+        uintptr_t index = extract64(ptr, LOG2_TAG_GRANULE + 1,
+                                    TARGET_PAGE_BITS - LOG2_TAG_GRANULE - 1);
+        ret.tag_mem = tags + index;
     }
 
-    tags = page_get_target_data(clean_ptr, page_data_size);
-
-    index = extract32(ptr, LOG2_TAG_GRANULE + 1,
-                      TARGET_PAGE_BITS - LOG2_TAG_GRANULE - 1);
-    return tags + index;
+    ret.ptr_mem = g2h_untagged_vaddr(clean_ptr);
+    ret.flags = 0;
 #else
     CPUTLBEntryFull *full;
-    MemTxAttrs attrs;
-    int in_page, flags;
+    int in_page;
     hwaddr ptr_paddr, tag_paddr, xlat;
     MemoryRegion *mr;
     ARMASIdx tag_asi;
     AddressSpace *tag_as;
-    void *host;
 
     /*
      * Probe the first byte of the virtual address.  This raises an
@@ -130,12 +140,13 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
      * for the pure probe, or assert that we received a valid page for the
      * no-fault-expected probe.
      */
-    flags = probe_access_full(env, ptr, 0, ptr_access, ptr_mmu_idx,
-                              ra == 0, &host, &full, ra);
-    if (unlikely(flags & TLB_INVALID_MASK)) {
+    ret.flags = probe_access_full(env, ptr, 0, ptr_access, ptr_mmu_idx,
+                                  ra == 0, &ret.ptr_mem, &full, ra);
+    if (unlikely(ret.flags & TLB_INVALID_MASK)) {
         assert(probe);
-        return NULL;
+        goto fini;
     }
+    ret.attrs = full->attrs;
 
     switch (full->extra.arm.pte_attrs) {
     case 0xf0: /* Tagged */
@@ -144,7 +155,9 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
     case 0xe0: /* NoTagAccess */
         if (cpu_isar_feature(aa64_mteperm, env_archcpu(env))) {
             if (probe) {
-                return NULL;
+                ret.ptr_mem = NULL;
+                ret.flags = TLB_INVALID_MASK;
+                goto fini;
             }
             assert(ra);
             mte_perm_check_fail(env, ptr, ra, tag_access == MMU_DATA_STORE);
@@ -152,27 +165,25 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
         /* fall through */
 
     default: /* Not Tagged */
-        return NULL;
+        goto fini;
     }
 
     /*
      * If not backed by host ram, there is no tag storage: access unchecked.
      * This is probably a guest os bug though, so log it.
      */
-    if (unlikely(flags & TLB_MMIO)) {
+    if (unlikely(ret.flags & TLB_MMIO)) {
         qemu_log_mask(LOG_GUEST_ERROR,
                       "Page @ 0x%" PRIx64 " indicates Tagged Normal memory "
                       "but is not backed by host ram\n", ptr);
-        return NULL;
+        goto fini;
     }
 
     /*
-     * Remember these values across the second lookup below,
+     * Remember this across the second lookup below,
      * which may invalidate this pointer via tlb resize.
      */
     ptr_paddr = full->phys_addr | (ptr & ~TARGET_PAGE_MASK);
-    attrs = full->attrs;
-    full = NULL;
 
     /*
      * The Normal memory access can extend to the next page.  E.g. a single
@@ -182,26 +193,30 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
      */
     in_page = -(ptr | TARGET_PAGE_MASK);
     if (unlikely(ptr_size > in_page)) {
-        flags |= probe_access_full(env, ptr + in_page, 0, ptr_access,
-                                   ptr_mmu_idx, ra == 0, &host, &full, ra);
-        assert(!(flags & TLB_INVALID_MASK));
+        void *discard_mem;
+        int flags2 = probe_access_full(env, ptr + in_page, 0, ptr_access,
+                                       ptr_mmu_idx, ra == 0,
+                                       &discard_mem, &full, ra);
+
+        assert(!(flags2 & TLB_INVALID_MASK));
+        ret.flags |= flags2;
     }
 
     /* Any debug exception has priority over a tag check exception. */
-    if (!probe && unlikely(flags & TLB_WATCHPOINT)) {
+    if (!probe && unlikely(ret.flags & TLB_WATCHPOINT)) {
         int wp = ptr_access == MMU_DATA_LOAD ? BP_MEM_READ : BP_MEM_WRITE;
         assert(ra != 0);
-        cpu_check_watchpoint(env_cpu(env), ptr, ptr_size, attrs, wp, ra);
+        cpu_check_watchpoint(env_cpu(env), ptr, ptr_size, ret.attrs, wp, ra);
     }
 
     /* Convert to the physical address in tag space.  */
     tag_paddr = ptr_paddr >> (LOG2_TAG_GRANULE + 1);
 
     /* Look up the address in tag space. */
-    tag_asi = attrs.secure ? ARMASIdx_TagS : ARMASIdx_TagNS;
+    tag_asi = ret.attrs.secure ? ARMASIdx_TagS : ARMASIdx_TagNS;
     tag_as = cpu_get_address_space(env_cpu(env), tag_asi);
     mr = address_space_translate(tag_as, tag_paddr, &xlat, NULL,
-                                 tag_access == MMU_DATA_STORE, attrs);
+                                 tag_access == MMU_DATA_STORE, ret.attrs);
 
     /*
      * Note that @mr will never be NULL.  If there is nothing in the address
@@ -214,7 +229,7 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
                       "Tag Memory @ 0x%" HWADDR_PRIx " not found for "
                       "Normal Memory @ 0x%" HWADDR_PRIx "\n",
                       tag_paddr, ptr_paddr);
-        return NULL;
+        goto fini;
     }
 
     /*
@@ -226,8 +241,11 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
         physical_memory_set_dirty_flag(tag_ra, DIRTY_MEMORY_MIGRATION);
     }
 
-    return memory_region_get_ram_ptr(mr) + xlat;
+    ret.tag_mem = memory_region_get_ram_ptr(mr) + xlat;
 #endif
+
+ fini:
+    return ret;
 }
 
 static G_NORETURN void canonical_tag_write_fail(CPUARMState *env,
@@ -249,7 +267,8 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
                                    uintptr_t ra)
 {
     return allocation_tag_mem_internal(env, ptr_mmu_idx, ptr, ptr_access,
-                                       ptr_size, tag_access, false, ra);
+                                       ptr_size, tag_access, false, ra)
+           .tag_mem;
 }
 
 uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
@@ -257,7 +276,8 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
                                   int ptr_size, MMUAccessType tag_access)
 {
     return allocation_tag_mem_internal(env, ptr_mmu_idx, ptr, ptr_access,
-                                       ptr_size, tag_access, true, 0);
+                                       ptr_size, tag_access, true, 0)
+           .tag_mem;
 }
 
 uint64_t HELPER(irg)(CPUARMState *env, uint64_t rn, uint64_t rm)
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 04/18] target/arm: Generalize probe argument to allocation_tag_mem_internal
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (2 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 03/18] target/arm: Return struct from allocation_tag_mem_internal Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-15 20:37 ` [RFC PATCH 05/18] target/arm: Probe second page earlier in allocation_tag_mem_internal Richard Henderson
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

We had a confusing relationship between 'probe' and 'ra == 0'.
Make this explicit via an enumeration.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/tcg/mte_helper.c | 130 ++++++++++++++++++++++--------------
 1 file changed, 80 insertions(+), 50 deletions(-)

diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index dd4c10ef4f..31bf58c937 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -87,28 +87,48 @@ typedef struct AllocationTagMem {
     MemTxAttrs attrs;
 } AllocationTagMem;
 
+typedef enum {
+    /* Trap on missing pages, invalid tag access, or watchpoints. */
+    ATM_NORMAL,
+    /* Gracefully return no tag memory for invalid pages. */
+    ATM_PROBE_PAGES,
+    /*
+     * Basic page access has already been checked,
+     * so a missing tlb entry is some sort of bug.
+     * Assert the tlb entry is present, but gracefully fail if tag
+     * access is not permitted to the page.
+     */
+    ATM_ASSERT_PAGES,
+} AllocationTagMemKind;
+
 static AllocationTagMem
 allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
                             vaddr ptr, MMUAccessType ptr_access,
                             int ptr_size, MMUAccessType tag_access,
-                            bool probe, uintptr_t ra)
+                            uintptr_t ra, AllocationTagMemKind atm_kind)
 {
     AllocationTagMem ret = {
         .flags = TLB_INVALID_MASK,
         .attrs = MEMTXATTRS_UNSPECIFIED,
     };
 
+    assert((atm_kind >= ATM_PROBE_PAGES) == (ra == 0));
+
 #ifdef CONFIG_USER_ONLY
     vaddr clean_ptr = useronly_clean_ptr(ptr);
     int flags = page_get_flags(clean_ptr);
     int req_flags = ptr_access == MMU_DATA_STORE ? PAGE_WRITE_ORG : PAGE_READ;
 
     if (unlikely(!(flags & req_flags))) {
-        if (probe) {
+        switch (atm_kind) {
+        case ATM_PROBE_PAGES:
             goto fini;
+        case ATM_NORMAL:
+            cpu_loop_exit_sigsegv(env_cpu(env), ptr, ptr_access,
+                                  !(flags & PAGE_VALID), ra);
+        default:
+            g_assert_not_reached();
         }
-        cpu_loop_exit_sigsegv(env_cpu(env), ptr, ptr_access,
-                              !(flags & PAGE_VALID), ra);
     }
 
     /* Require both MAP_ANON and PROT_MTE for the page. */
@@ -124,7 +144,6 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
     ret.flags = 0;
 #else
     CPUTLBEntryFull *full;
-    int in_page;
     hwaddr ptr_paddr, tag_paddr, xlat;
     MemoryRegion *mr;
     ARMASIdx tag_asi;
@@ -134,16 +153,12 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
      * Probe the first byte of the virtual address.  This raises an
      * exception for inaccessible pages, and resolves the virtual address
      * into the softmmu tlb.
-     *
-     * When RA == 0, this is either a pure probe or a no-fault-expected probe.
-     * Indicate to probe_access_flags no-fault, then either return NULL
-     * for the pure probe, or assert that we received a valid page for the
-     * no-fault-expected probe.
      */
     ret.flags = probe_access_full(env, ptr, 0, ptr_access, ptr_mmu_idx,
-                                  ra == 0, &ret.ptr_mem, &full, ra);
+                                  atm_kind >= ATM_PROBE_PAGES,
+                                  &ret.ptr_mem, &full, ra);
     if (unlikely(ret.flags & TLB_INVALID_MASK)) {
-        assert(probe);
+        assert(atm_kind == ATM_PROBE_PAGES);
         goto fini;
     }
     ret.attrs = full->attrs;
@@ -154,12 +169,11 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
 
     case 0xe0: /* NoTagAccess */
         if (cpu_isar_feature(aa64_mteperm, env_archcpu(env))) {
-            if (probe) {
+            if (atm_kind >= ATM_PROBE_PAGES) {
                 ret.ptr_mem = NULL;
                 ret.flags = TLB_INVALID_MASK;
                 goto fini;
             }
-            assert(ra);
             mte_perm_check_fail(env, ptr, ra, tag_access == MMU_DATA_STORE);
         }
         /* fall through */
@@ -191,22 +205,21 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
      * tag on the first page.
      * Any page access exception has priority over tag check exception.
      */
-    in_page = -(ptr | TARGET_PAGE_MASK);
-    if (unlikely(ptr_size > in_page)) {
-        void *discard_mem;
-        int flags2 = probe_access_full(env, ptr + in_page, 0, ptr_access,
-                                       ptr_mmu_idx, ra == 0,
-                                       &discard_mem, &full, ra);
+    if (atm_kind == ATM_NORMAL) {
+        int in_page = -(ptr | TARGET_PAGE_MASK);
+        if (unlikely(ptr_size > in_page)) {
+            void *discard_mem;
+            ret.flags |= probe_access_full(env, ptr + in_page, 0, ptr_access,
+                                           ptr_mmu_idx, false,
+                                           &discard_mem, &full, ra);
+        }
 
-        assert(!(flags2 & TLB_INVALID_MASK));
-        ret.flags |= flags2;
-    }
-
-    /* Any debug exception has priority over a tag check exception. */
-    if (!probe && unlikely(ret.flags & TLB_WATCHPOINT)) {
-        int wp = ptr_access == MMU_DATA_LOAD ? BP_MEM_READ : BP_MEM_WRITE;
-        assert(ra != 0);
-        cpu_check_watchpoint(env_cpu(env), ptr, ptr_size, ret.attrs, wp, ra);
+        /* Any debug exception has priority over a tag check exception. */
+        if (unlikely(ret.flags & TLB_WATCHPOINT)) {
+            int wp = ptr_access == MMU_DATA_LOAD ? BP_MEM_READ : BP_MEM_WRITE;
+            cpu_check_watchpoint(env_cpu(env), ptr, ptr_size,
+                                 ret.attrs, wp, ra);
+        }
     }
 
     /* Convert to the physical address in tag space.  */
@@ -267,8 +280,8 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
                                    uintptr_t ra)
 {
     return allocation_tag_mem_internal(env, ptr_mmu_idx, ptr, ptr_access,
-                                       ptr_size, tag_access, false, ra)
-           .tag_mem;
+                                       ptr_size, tag_access,
+                                       ra, ATM_NORMAL).tag_mem;
 }
 
 uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
@@ -276,8 +289,8 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx,
                                   int ptr_size, MMUAccessType tag_access)
 {
     return allocation_tag_mem_internal(env, ptr_mmu_idx, ptr, ptr_access,
-                                       ptr_size, tag_access, true, 0)
-           .tag_mem;
+                                       ptr_size, tag_access,
+                                       0, ATM_PROBE_PAGES).tag_mem;
 }
 
 uint64_t HELPER(irg)(CPUARMState *env, uint64_t rn, uint64_t rm)
@@ -881,6 +894,7 @@ static int checkNrev(uint8_t *mem, int odd, int cmp, int count)
  * @desc: MTEDESC descriptor
  * @ptr: virtual address of the base of the access
  * @fault: return virtual address of the first check failure
+ * @kind: per allocation_tag_mem_internal
  *
  * Internal routine for both mte_probe and mte_check.
  * Return zero on failure, filling in *fault.
@@ -888,13 +902,14 @@ static int checkNrev(uint8_t *mem, int odd, int cmp, int count)
  * Return positive on success with tbi enabled.
  */
 static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
-                         uintptr_t ra, uint64_t *fault)
+                         uintptr_t ra, uint64_t *fault,
+                         AllocationTagMemKind atm_kind)
 {
     int mmu_idx, ptr_tag, bit55;
     uint64_t ptr_last, prev_page, next_page;
     uint64_t tag_first, tag_last;
     uint32_t sizem1, tag_count, n, c;
-    uint8_t *mem1, *mem2;
+    AllocationTagMem r1, r2;
     MMUAccessType type;
 
     bit55 = extract64(ptr, 55, 1);
@@ -932,9 +947,14 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
 
     if (likely(tag_last - prev_page < TARGET_PAGE_SIZE)) {
         /* Memory access stays on one page. */
-        mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, sizem1 + 1,
-                                  MMU_DATA_LOAD, ra);
-        if (!mem1) {
+        r1 = allocation_tag_mem_internal(env, mmu_idx, ptr, type, sizem1 + 1,
+                                           MMU_DATA_LOAD, ra, atm_kind);
+        if (unlikely(r1.flags & TLB_INVALID_MASK)) {
+            /* Tag access disabled on an otherwise accessible page. */
+            assert(atm_kind == ATM_ASSERT_PAGES);
+            return 0;
+        }
+        if (r1.tag_mem == NULL) {
             /*
              * If mtx is enabled, then the access is MemTag_CanonicallyTagged,
              * otherwise it is Untagged. See AArch64.S1DecodeMemAttrs and
@@ -946,15 +966,22 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
             return 1;
         }
         /* Perform all of the comparisons. */
-        n = checkN(mem1, ptr & TAG_GRANULE, ptr_tag, tag_count);
+        n = checkN(r1.tag_mem, ptr & TAG_GRANULE, ptr_tag, tag_count);
     } else {
         /* Memory access crosses to next page. */
-        mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, next_page - ptr,
-                                  MMU_DATA_LOAD, ra);
+        r1 = allocation_tag_mem_internal(env, mmu_idx, ptr, type,
+                                         next_page - ptr, MMU_DATA_LOAD,
+                                         ra, atm_kind);
 
-        mem2 = allocation_tag_mem(env, mmu_idx, next_page, type,
-                                  ptr_last - next_page + 1,
-                                  MMU_DATA_LOAD, ra);
+        if (r1.flags & TLB_INVALID_MASK) {
+            /* Tag access disabled on an otherwise accessible page. */
+            assert(atm_kind == ATM_ASSERT_PAGES);
+            return 0;
+        }
+
+        r2 = allocation_tag_mem_internal(env, mmu_idx, next_page, type,
+                                         ptr_last - next_page + 1,
+                                         MMU_DATA_LOAD, ra, atm_kind);
 
         /*
          * Perform all of the comparisons.
@@ -963,15 +990,18 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
          * happen with or without mtx (canonical tagging) enabled.
          */
         n = c = (next_page - tag_first) / TAG_GRANULE;
-        if (mem1) {
-            n = checkN(mem1, ptr & TAG_GRANULE, ptr_tag, c);
+        if (r1.tag_mem) {
+            n = checkN(r1.tag_mem, ptr & TAG_GRANULE, ptr_tag, c);
         } else if (mtx_check(desc, bit55) &&
                    !tag_is_canonical(ptr_tag, bit55)) {
             return 0;
         }
         if (n == c) {
-            if (mem2) {
-                n += checkN(mem2, 0, ptr_tag, tag_count - c);
+            if (r2.flags & TLB_INVALID_MASK) {
+                /* Tag access disabled on an otherwise accessible page. */
+                assert(atm_kind == ATM_ASSERT_PAGES);
+            } else if (r2.tag_mem) {
+                n += checkN(r2.tag_mem, 0, ptr_tag, tag_count - c);
             } else if (!mtx_check(desc, bit55) ||
                        tag_is_canonical(ptr_tag, bit55)) {
                 return 1;
@@ -997,7 +1027,7 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr,
 uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra)
 {
     uint64_t fault;
-    int ret = mte_probe_int(env, desc, ptr, ra, &fault);
+    int ret = mte_probe_int(env, desc, ptr, ra, &fault, ATM_NORMAL);
 
     if (unlikely(ret == 0)) {
         mte_check_fail(env, desc, fault, ra);
@@ -1039,7 +1069,7 @@ uint64_t HELPER(mte_check)(CPUARMState *env, uint32_t desc, uint64_t ptr)
 bool mte_probe(CPUARMState *env, uint32_t desc, uint64_t ptr)
 {
     uint64_t fault;
-    int ret = mte_probe_int(env, desc, ptr, 0, &fault);
+    int ret = mte_probe_int(env, desc, ptr, 0, &fault, ATM_ASSERT_PAGES);
 
     return ret != 0;
 }
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 05/18] target/arm: Probe second page earlier in allocation_tag_mem_internal
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (3 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 04/18] target/arm: Generalize probe argument to allocation_tag_mem_internal Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-15 20:37 ` [RFC PATCH 06/18] accel/tcg: Drop fault_size from user-only probe_access_internal Richard Henderson
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

Translation faults have priority over everything else in
this function.  We were failing to trap for the second page
entirely in the user-only case, and when tag access is disabled
on the first page for the system case.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/tcg/mte_helper.c | 55 ++++++++++++++++++++++---------------
 1 file changed, 33 insertions(+), 22 deletions(-)

diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index 31bf58c937..399bca30c9 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -130,6 +130,13 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
             g_assert_not_reached();
         }
     }
+    if (atm_kind == ATM_NORMAL) {
+        int in_page = -(ptr | TARGET_PAGE_MASK);
+        if (unlikely(ptr_size > in_page)) {
+            probe_access(env, ptr + in_page, ptr_size - in_page,
+                         ptr_access, MMU_USER_IDX, ra);
+        }
+    }
 
     /* Require both MAP_ANON and PROT_MTE for the page. */
     if ((flags & PAGE_ANON) && (flags & PAGE_MTE)) {
@@ -148,6 +155,7 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
     MemoryRegion *mr;
     ARMASIdx tag_asi;
     AddressSpace *tag_as;
+    uint8_t pte_attrs;
 
     /*
      * Probe the first byte of the virtual address.  This raises an
@@ -161,9 +169,32 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
         assert(atm_kind == ATM_PROBE_PAGES);
         goto fini;
     }
+
+    /*
+     * Remember these across the second lookup below,
+     * which may invalidate this pointer via tlb resize.
+     */
+    ptr_paddr = full->phys_addr | (ptr & ~TARGET_PAGE_MASK);
+    pte_attrs = full->extra.arm.pte_attrs;
     ret.attrs = full->attrs;
 
-    switch (full->extra.arm.pte_attrs) {
+    /*
+     * The Normal memory access can extend to the next page.  E.g. a single
+     * 8-byte access to the last byte of a page will check only the last
+     * tag on the first page.
+     * Any page access exception has priority over tag check exception.
+     */
+    if (atm_kind == ATM_NORMAL) {
+        int in_page = -(ptr | TARGET_PAGE_MASK);
+        if (unlikely(ptr_size > in_page)) {
+            void *discard_mem;
+            ret.flags |= probe_access_full(env, ptr + in_page, 0, ptr_access,
+                                           ptr_mmu_idx, false,
+                                           &discard_mem, &full, ra);
+        }
+    }
+
+    switch (pte_attrs) {
     case 0xf0: /* Tagged */
         break;
 
@@ -193,28 +224,8 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
         goto fini;
     }
 
-    /*
-     * Remember this across the second lookup below,
-     * which may invalidate this pointer via tlb resize.
-     */
-    ptr_paddr = full->phys_addr | (ptr & ~TARGET_PAGE_MASK);
-
-    /*
-     * The Normal memory access can extend to the next page.  E.g. a single
-     * 8-byte access to the last byte of a page will check only the last
-     * tag on the first page.
-     * Any page access exception has priority over tag check exception.
-     */
+    /* Any debug exception has priority over a tag check exception. */
     if (atm_kind == ATM_NORMAL) {
-        int in_page = -(ptr | TARGET_PAGE_MASK);
-        if (unlikely(ptr_size > in_page)) {
-            void *discard_mem;
-            ret.flags |= probe_access_full(env, ptr + in_page, 0, ptr_access,
-                                           ptr_mmu_idx, false,
-                                           &discard_mem, &full, ra);
-        }
-
-        /* Any debug exception has priority over a tag check exception. */
         if (unlikely(ret.flags & TLB_WATCHPOINT)) {
             int wp = ptr_access == MMU_DATA_LOAD ? BP_MEM_READ : BP_MEM_WRITE;
             cpu_check_watchpoint(env_cpu(env), ptr, ptr_size,
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 06/18] accel/tcg: Drop fault_size from user-only probe_access_internal
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (4 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 05/18] target/arm: Probe second page earlier in allocation_tag_mem_internal Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-16  9:05   ` Philippe Mathieu-Daudé
  2026-08-15 20:37 ` [RFC PATCH 07/18] accel/tcg: Replace size with first/last in probe_access_full Richard Henderson
                   ` (11 subsequent siblings)
  17 siblings, 1 reply; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

This argument is unused.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/tcg/user-exec.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index a35aca7889..3724e5d98e 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -749,7 +749,7 @@ int page_unprotect(CPUState *cpu, tb_page_addr_t address, uintptr_t pc)
 }
 
 static int probe_access_internal(CPUArchState *env, vaddr addr,
-                                 int fault_size, MMUAccessType access_type,
+                                 MMUAccessType access_type,
                                  bool nonfault, uintptr_t ra)
 {
     int acc_flag;
@@ -797,7 +797,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size,
     int flags;
 
     g_assert(-(addr | TARGET_PAGE_MASK) >= size);
-    flags = probe_access_internal(env, addr, size, access_type, nonfault, ra);
+    flags = probe_access_internal(env, addr, access_type, nonfault, ra);
     *phost = (flags & TLB_INVALID_MASK) ? NULL : g2h_vaddr(env_cpu(env), addr);
     return flags;
 }
@@ -808,7 +808,7 @@ void *probe_access(CPUArchState *env, vaddr addr, int size,
     int flags;
 
     g_assert(-(addr | TARGET_PAGE_MASK) >= size);
-    flags = probe_access_internal(env, addr, size, access_type, false, ra);
+    flags = probe_access_internal(env, addr, access_type, false, ra);
     g_assert((flags & ~TLB_FORCE_SLOW) == 0);
 
     return size ? g2h_vaddr(env_cpu(env), addr) : NULL;
@@ -825,7 +825,7 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr,
 {
     int flags;
 
-    flags = probe_access_internal(env, addr, 1, MMU_INST_FETCH, false, 0);
+    flags = probe_access_internal(env, addr, MMU_INST_FETCH, false, 0);
     g_assert(flags == 0);
 
     *hostp = g2h_untagged_vaddr(addr);
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 07/18] accel/tcg: Replace size with first/last in probe_access_full
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (5 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 06/18] accel/tcg: Drop fault_size from user-only probe_access_internal Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-16  9:09   ` Philippe Mathieu-Daudé
  2026-08-15 20:37 ` [RFC PATCH 08/18] accel/tcg: Replace size with first/last in probe_access_flags Richard Henderson
                   ` (10 subsequent siblings)
  17 siblings, 1 reply; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/accel/tcg/probe.h     |  2 +-
 accel/tcg/cputlb.c            | 17 +++++++++++------
 target/arm/tcg/helper-a64.c   |  5 ++++-
 target/arm/tcg/mte_helper.c   | 21 ++++++++++++---------
 target/arm/tcg/sve_helper.c   |  5 ++++-
 target/mips/tcg/ldst_helper.c |  4 ++--
 6 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/include/accel/tcg/probe.h b/include/accel/tcg/probe.h
index 0b788901ba..e3068a79de 100644
--- a/include/accel/tcg/probe.h
+++ b/include/accel/tcg/probe.h
@@ -86,7 +86,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size,
  * This function will return TLB_MMIO in order to force the access
  * to be handled out-of-line if plugins wish to instrument the access.
  */
-int probe_access_full(CPUArchState *env, vaddr addr, int size,
+int probe_access_full(CPUArchState *env, vaddr addr, vaddr first, vaddr last,
                       MMUAccessType access_type, int mmu_idx,
                       bool nonfault, void **phost,
                       CPUTLBEntryFull **pfull, uintptr_t retaddr);
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 7f7c208ba1..6299cc73a4 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1412,19 +1412,24 @@ static int probe_access_internal(CPUState *cpu, vaddr addr,
     return flags;
 }
 
-int probe_access_full(CPUArchState *env, vaddr addr, int size,
+int probe_access_full(CPUArchState *env, vaddr addr, vaddr first, vaddr last,
                       MMUAccessType access_type, int mmu_idx,
                       bool nonfault, void **phost, CPUTLBEntryFull **pfull,
                       uintptr_t retaddr)
 {
-    int flags = probe_access_internal(env_cpu(env), addr, size, access_type,
-                                      mmu_idx, nonfault, phost, pfull, retaddr,
-                                      true);
+    int flags;
+
+    assert(first <= addr);
+    assert(addr <= last);
+    assert(((first ^ last) & TARGET_PAGE_MASK) == 0);
+
+    flags = probe_access_internal(env_cpu(env), addr, last - addr + 1,
+                                  access_type, mmu_idx, nonfault,
+                                  phost, pfull, retaddr, true);
 
     /* Handle clean RAM pages.  */
     if (unlikely(flags & TLB_NOTDIRTY)) {
-        int dirtysize = size == 0 ? 1 : size;
-        notdirty_write(env_cpu(env), addr, dirtysize, *pfull, retaddr);
+        notdirty_write(env_cpu(env), first, last - first + 1, *pfull, retaddr);
         flags &= ~TLB_NOTDIRTY;
     }
 
diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c
index 05ab9ab6d3..2e0e7cd756 100644
--- a/target/arm/tcg/helper-a64.c
+++ b/target/arm/tcg/helper-a64.c
@@ -1745,7 +1745,10 @@ static bool is_guarded_page(CPUARMState *env, vaddr addr, uintptr_t ra)
     CPUTLBEntryFull *full;
     void *host;
     int mmu_idx = cpu_mmu_index(env_cpu(env), true);
-    int flags = probe_access_full(env, addr, 0, MMU_INST_FETCH, mmu_idx,
+    int flags = probe_access_full(env, addr,
+                                  addr & TARGET_PAGE_MASK,
+                                  addr | ~TARGET_PAGE_MASK,
+                                  MMU_INST_FETCH, mmu_idx,
                                   false, &host, &full, ra);
 
     assert(!(flags & TLB_INVALID_MASK));
diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
index 399bca30c9..f36286d596 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -151,6 +151,7 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
     ret.flags = 0;
 #else
     CPUTLBEntryFull *full;
+    vaddr ptr_last, ptr_page_last;
     hwaddr ptr_paddr, tag_paddr, xlat;
     MemoryRegion *mr;
     ARMASIdx tag_asi;
@@ -162,7 +163,11 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
      * exception for inaccessible pages, and resolves the virtual address
      * into the softmmu tlb.
      */
-    ret.flags = probe_access_full(env, ptr, 0, ptr_access, ptr_mmu_idx,
+    ptr_last = ptr + ptr_size - 1;
+    ptr_page_last = ptr | ~TARGET_PAGE_MASK;
+
+    ret.flags = probe_access_full(env, ptr, ptr, MIN(ptr_last, ptr_page_last),
+                                  ptr_access, ptr_mmu_idx,
                                   atm_kind >= ATM_PROBE_PAGES,
                                   &ret.ptr_mem, &full, ra);
     if (unlikely(ret.flags & TLB_INVALID_MASK)) {
@@ -184,14 +189,12 @@ allocation_tag_mem_internal(CPUARMState *env, int ptr_mmu_idx,
      * tag on the first page.
      * Any page access exception has priority over tag check exception.
      */
-    if (atm_kind == ATM_NORMAL) {
-        int in_page = -(ptr | TARGET_PAGE_MASK);
-        if (unlikely(ptr_size > in_page)) {
-            void *discard_mem;
-            ret.flags |= probe_access_full(env, ptr + in_page, 0, ptr_access,
-                                           ptr_mmu_idx, false,
-                                           &discard_mem, &full, ra);
-        }
+    if (atm_kind == ATM_NORMAL && unlikely(ptr_page_last < ptr_last)) {
+        void *discard_mem;
+        ret.flags |= probe_access_full(env, ptr_page_last + 1,
+                                       ptr_page_last + 1, ptr_last,
+                                       ptr_access, ptr_mmu_idx, false,
+                                       &discard_mem, &full, ra);
     }
 
     switch (pte_attrs) {
diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c
index ac96b18784..4e77a824dd 100644
--- a/target/arm/tcg/sve_helper.c
+++ b/target/arm/tcg/sve_helper.c
@@ -6040,7 +6040,10 @@ bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env,
                                &info->host, retaddr);
 #else
     CPUTLBEntryFull *full;
-    flags = probe_access_full(env, addr, 0, access_type, mmu_idx, nofault,
+    flags = probe_access_full(env, addr,
+                              addr & TARGET_PAGE_MASK,
+                              addr | ~TARGET_PAGE_MASK,
+                              access_type, mmu_idx, nofault,
                               &info->host, &full, retaddr);
 #endif
     info->flags = flags;
diff --git a/target/mips/tcg/ldst_helper.c b/target/mips/tcg/ldst_helper.c
index 1b25466b49..065570a8f1 100644
--- a/target/mips/tcg/ldst_helper.c
+++ b/target/mips/tcg/ldst_helper.c
@@ -44,8 +44,8 @@ target_ulong helper_##name(CPUMIPSState *env, target_ulong arg,               \
     int flags;                                                                \
                                                                               \
     env->llval = do_cast cpu_##insn##_mmu(env, arg, oi, ra);                  \
-    flags = probe_access_full(env, arg, size, MMU_DATA_LOAD, mem_idx,         \
-                              true, &host_unused, &full, ra);                 \
+    flags = probe_access_full(env, arg, arg, arg + size - 1, MMU_DATA_LOAD,   \
+                              mem_idx, true, &host_unused, &full, ra);        \
     assert(!(flags & TLB_INVALID_MASK));                                      \
     env->CP0_LLAddr = full->phys_addr;                                        \
     env->lladdr = arg;                                                        \
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 08/18] accel/tcg: Replace size with first/last in probe_access_flags
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (6 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 07/18] accel/tcg: Replace size with first/last in probe_access_full Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-16  9:18   ` Philippe Mathieu-Daudé
  2026-08-15 20:37 ` [RFC PATCH 09/18] accel/tcg: Allow phost to be NULL " Richard Henderson
                   ` (9 subsequent siblings)
  17 siblings, 1 reply; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 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



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 09/18] accel/tcg: Allow phost to be NULL in probe_access_flags
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (7 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 08/18] accel/tcg: Replace size with first/last in probe_access_flags Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-16  9:18   ` Philippe Mathieu-Daudé
  2026-08-15 20:37 ` [RFC PATCH 10/18] accel/tcg: Replace size with first/last in probe_access_internal Richard Henderson
                   ` (8 subsequent siblings)
  17 siblings, 1 reply; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

Do not require the caller to create a dummy variable.
The one instance so far is riscv check_zicbom_access.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/accel/tcg/probe.h    | 3 ++-
 accel/tcg/cputlb.c           | 4 +++-
 accel/tcg/user-exec.c        | 5 ++++-
 target/riscv/tcg/op_helper.c | 3 +--
 4 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/include/accel/tcg/probe.h b/include/accel/tcg/probe.h
index 06faf1269d..477320c88d 100644
--- a/include/accel/tcg/probe.h
+++ b/include/accel/tcg/probe.h
@@ -68,7 +68,8 @@ static inline void *probe_read(CPUArchState *env, vaddr addr, int size,
  *   - 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:
+ * Otherwise, return the TLB_FLAGS_MASK for the page,
+ * and, if @phost is not NULL, set @phost:
  *   - host address for @addr, if direct host accesses are allowed,
  *   - otherwise NULL.
  *
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index a192c50e90..c2ea31a397 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1465,6 +1465,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, vaddr first, vaddr last,
                        bool nonfault, void **phost, uintptr_t retaddr)
 {
     CPUTLBEntryFull *full;
+    void *discard_host;
     int flags;
 
     assert(first <= addr);
@@ -1473,7 +1474,8 @@ int probe_access_flags(CPUArchState *env, vaddr addr, vaddr first, vaddr last,
 
     flags = probe_access_internal(env_cpu(env), addr, last - addr + 1,
                                   access_type, mmu_idx, nonfault,
-                                  phost, &full, retaddr, true);
+                                  phost ? phost : &discard_host,
+                                  &full, retaddr, true);
 
     /* Handle clean RAM pages. */
     if (unlikely(flags & TLB_NOTDIRTY)) {
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index 44e9f7fa1a..3578282a3d 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -801,7 +801,10 @@ int probe_access_flags(CPUArchState *env, vaddr addr, vaddr first, vaddr last,
     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);
+    if (phost) {
+        *phost = (flags & TLB_INVALID_MASK ? NULL
+                  : g2h_vaddr(env_cpu(env), addr));
+    }
     return flags;
 }
 
diff --git a/target/riscv/tcg/op_helper.c b/target/riscv/tcg/op_helper.c
index b18bf683f4..9c0cfd35fc 100644
--- a/target/riscv/tcg/op_helper.c
+++ b/target/riscv/tcg/op_helper.c
@@ -232,7 +232,6 @@ static void check_zicbom_access(CPURISCVState *env,
     RISCVCPU *cpu = env_archcpu(env);
     int mmu_idx = riscv_env_mmu_index(env, false);
     uint16_t cbomlen = cpu->cfg.cbom_blocksize;
-    void *phost;
     int ret;
 
     /* Mask off low-bits to align-down to the cache-block. */
@@ -251,7 +250,7 @@ static void check_zicbom_access(CPURISCVState *env,
      * permitted to access the cache block is UNSPECIFIED."
      */
     ret = probe_access_flags(env, address, address, address + cbomlen - 1,
-                             MMU_DATA_LOAD, mmu_idx, true, &phost, ra);
+                             MMU_DATA_LOAD, mmu_idx, true, NULL, ra);
     if (ret != TLB_INVALID_MASK) {
         /* Success: readable */
         return;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 10/18] accel/tcg: Replace size with first/last in probe_access_internal
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (8 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 09/18] accel/tcg: Allow phost to be NULL " Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-16  9:19   ` Philippe Mathieu-Daudé
  2026-08-15 20:37 ` [RFC PATCH 11/18] accel/tcg: Replace size with first/last in tlb_fill_align Richard Henderson
                   ` (7 subsequent siblings)
  17 siblings, 1 reply; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

Propagate the API change down one step further within cputlb.c.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/tcg/cputlb.c | 37 ++++++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index c2ea31a397..b8c23b2948 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1358,8 +1358,8 @@ static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size,
     }
 }
 
-static int probe_access_internal(CPUState *cpu, vaddr addr,
-                                 int fault_size, MMUAccessType access_type,
+static int probe_access_internal(CPUState *cpu, vaddr addr, vaddr first,
+                                 vaddr last, MMUAccessType access_type,
                                  int mmu_idx, bool nonfault,
                                  void **phost, CPUTLBEntryFull **pfull,
                                  uintptr_t retaddr, bool check_mem_cbs)
@@ -1375,7 +1375,7 @@ static int probe_access_internal(CPUState *cpu, vaddr addr,
     if (!tlb_hit_page(tlb_addr, page_addr)) {
         if (!victim_tlb_hit(cpu, mmu_idx, index, access_type, page_addr)) {
             if (!tlb_fill_align(cpu, addr, access_type, mmu_idx,
-                                0, fault_size, nonfault, retaddr)) {
+                                0, last - addr + 1, nonfault, retaddr)) {
                 /* Non-faulting page table read failed.  */
                 *phost = NULL;
                 *pfull = NULL;
@@ -1423,7 +1423,7 @@ int probe_access_full(CPUArchState *env, vaddr addr, vaddr first, vaddr last,
     assert(addr <= last);
     assert(((first ^ last) & TARGET_PAGE_MASK) == 0);
 
-    flags = probe_access_internal(env_cpu(env), addr, last - addr + 1,
+    flags = probe_access_internal(env_cpu(env), addr, first, last,
                                   access_type, mmu_idx, nonfault,
                                   phost, pfull, retaddr, true);
 
@@ -1440,6 +1440,7 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size,
                           MMUAccessType access_type, int mmu_idx,
                           void **phost, CPUTLBEntryFull **pfull)
 {
+    vaddr last = size ? addr + size - 1 : addr;
     void *discard_phost;
     CPUTLBEntryFull *discard_tlb;
 
@@ -1447,13 +1448,13 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size,
     phost = phost ? phost : &discard_phost;
     pfull = pfull ? pfull : &discard_tlb;
 
-    int flags = probe_access_internal(env_cpu(env), addr, size, access_type,
-                                      mmu_idx, true, phost, pfull, 0, false);
+    int flags = probe_access_internal(env_cpu(env), addr, addr, last,
+                                      access_type, mmu_idx, true, phost,
+                                      pfull, 0, false);
 
     /* Handle clean RAM pages.  */
     if (unlikely(flags & TLB_NOTDIRTY)) {
-        int dirtysize = size == 0 ? 1 : size;
-        notdirty_write(env_cpu(env), addr, dirtysize, *pfull, 0);
+        notdirty_write(env_cpu(env), addr, last - addr + 1, *pfull, 0);
         flags &= ~TLB_NOTDIRTY;
     }
 
@@ -1472,7 +1473,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, vaddr first, vaddr last,
     assert(addr <= last);
     assert(((first ^ last) & TARGET_PAGE_MASK) == 0);
 
-    flags = probe_access_internal(env_cpu(env), addr, last - addr + 1,
+    flags = probe_access_internal(env_cpu(env), addr, first, last,
                                   access_type, mmu_idx, nonfault,
                                   phost ? phost : &discard_host,
                                   &full, retaddr, true);
@@ -1489,15 +1490,16 @@ int probe_access_flags(CPUArchState *env, vaddr addr, vaddr first, vaddr last,
 void *probe_access(CPUArchState *env, vaddr addr, int size,
                    MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
 {
+    vaddr last = size ? addr + size - 1 : addr;
     CPUTLBEntryFull *full;
     void *host;
     int flags;
 
-    g_assert(-(addr | TARGET_PAGE_MASK) >= size);
+    assert(((addr ^ last) & TARGET_PAGE_MASK) == 0);
 
-    flags = probe_access_internal(env_cpu(env), addr, size, access_type,
-                                  mmu_idx, false, &host, &full, retaddr,
-                                  true);
+    flags = probe_access_internal(env_cpu(env), addr, addr, last,
+                                  access_type, mmu_idx, false,
+                                  &host, &full, retaddr, true);
 
     /* Per the interface, size == 0 merely faults the access. */
     if (size == 0) {
@@ -1529,7 +1531,7 @@ void *tlb_vaddr_to_host(CPUArchState *env, vaddr addr,
     void *host;
     int flags;
 
-    flags = probe_access_internal(env_cpu(env), addr, 0, access_type,
+    flags = probe_access_internal(env_cpu(env), addr, addr, addr, access_type,
                                   mmu_idx, true, &host, &full, 0, false);
 
     /* No combination of flags are expected by the caller. */
@@ -1552,9 +1554,10 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr,
     CPUTLBEntryFull *full;
     void *p;
 
-    (void)probe_access_internal(env_cpu(env), addr, 1, MMU_INST_FETCH,
-                                cpu_mmu_index(env_cpu(env), true), false,
-                                hostp, &full, 0, false);
+    (void)probe_access_internal(env_cpu(env), addr, addr, addr,
+                                MMU_INST_FETCH,
+                                cpu_mmu_index(env_cpu(env), true),
+                                false, hostp, &full, 0, false);
 
     p = *hostp;
     if (p == NULL) {
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 11/18] accel/tcg: Replace size with first/last in tlb_fill_align
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (9 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 10/18] accel/tcg: Replace size with first/last in probe_access_internal Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-16  9:20   ` Philippe Mathieu-Daudé
  2026-08-15 20:37 ` [RFC PATCH 12/18] accel/tcg: Replace size with first/last in TCGCPUOps.tlb_fill* Richard Henderson
                   ` (6 subsequent siblings)
  17 siblings, 1 reply; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

Propagate the API change down one step further within cputlb.c.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/tcg/cputlb.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index b8c23b2948..95db2c22e2 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1236,11 +1236,12 @@ static inline bool tlb_hit(uint64_t tlb_addr, vaddr addr)
  * (e.g. CPUTLBEntry pointers) must be discarded and looked up again
  * (e.g. via tlb_entry()).
  */
-static bool tlb_fill_align(CPUState *cpu, vaddr addr, MMUAccessType type,
-                           int mmu_idx, MemOp memop, int size,
+static bool tlb_fill_align(CPUState *cpu, vaddr addr, vaddr first, vaddr last,
+                           MMUAccessType type, int mmu_idx, MemOp memop,
                            bool probe, uintptr_t ra)
 {
     const TCGCPUOps *ops = cpu->cc->tcg_ops;
+    int size = last - addr + 1;
     CPUTLBEntryFull full;
 
     if (ops->tlb_fill_align) {
@@ -1374,8 +1375,8 @@ static int probe_access_internal(CPUState *cpu, vaddr addr, vaddr first,
 
     if (!tlb_hit_page(tlb_addr, page_addr)) {
         if (!victim_tlb_hit(cpu, mmu_idx, index, access_type, page_addr)) {
-            if (!tlb_fill_align(cpu, addr, access_type, mmu_idx,
-                                0, last - addr + 1, nonfault, retaddr)) {
+            if (!tlb_fill_align(cpu, addr, first, last, access_type,
+                                mmu_idx, MO_UNALN, nonfault, retaddr)) {
                 /* Non-faulting page table read failed.  */
                 *phost = NULL;
                 *pfull = NULL;
@@ -1664,8 +1665,8 @@ static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data, MemOp memop,
     if (!tlb_hit(tlb_addr, addr)) {
         if (!victim_tlb_hit(cpu, mmu_idx, index, access_type,
                             addr & TARGET_PAGE_MASK)) {
-            tlb_fill_align(cpu, addr, access_type, mmu_idx,
-                           memop, data->size, false, ra);
+            tlb_fill_align(cpu, addr, addr, addr + data->size - 1,
+                           access_type, mmu_idx, memop, false, ra);
             maybe_resized = true;
             index = tlb_index(cpu, mmu_idx, addr);
             entry = tlb_entry(cpu, mmu_idx, addr);
@@ -1833,8 +1834,8 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
     if (!tlb_hit(tlb_addr, addr)) {
         if (!victim_tlb_hit(cpu, mmu_idx, index, MMU_DATA_STORE,
                             addr & TARGET_PAGE_MASK)) {
-            tlb_fill_align(cpu, addr, MMU_DATA_STORE, mmu_idx,
-                           mop, size, false, retaddr);
+            tlb_fill_align(cpu, addr, addr, addr + size - 1,
+                           MMU_DATA_STORE, mmu_idx, mop, false, retaddr);
             did_tlb_fill = true;
             index = tlb_index(cpu, mmu_idx, addr);
             tlbe = tlb_entry(cpu, mmu_idx, addr);
@@ -1849,8 +1850,8 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
      * but addr_read will only be -1 if PAGE_READ was unset.
      */
     if (unlikely(tlbe->addr_read == -1)) {
-        tlb_fill_align(cpu, addr, MMU_DATA_LOAD, mmu_idx,
-                       0, size, false, retaddr);
+        tlb_fill_align(cpu, addr, addr, addr + size - 1,
+                       MMU_DATA_LOAD, mmu_idx, 0, false, retaddr);
         /*
          * Since we don't support reads and writes to different
          * addresses, and we do have the proper page loaded for
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 12/18] accel/tcg: Replace size with first/last in TCGCPUOps.tlb_fill*
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (10 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 11/18] accel/tcg: Replace size with first/last in tlb_fill_align Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-16 15:17   ` Philippe Mathieu-Daudé
  2026-08-15 20:37 ` [RFC PATCH 13/18] target/riscv: Move PMP_AMATCH_OFF check in pmp_hart_has_privs Richard Henderson
                   ` (5 subsequent siblings)
  17 siblings, 1 reply; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

Expand the interfaces to allow an address within a range to be tested.
Additionally, where was an edge case of size == 0 which was ambiguous,
and is now eliminated.

Only change the functional interface.  Where required by the callee,
rebuild "size = last - addr + 1" locally.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 include/accel/tcg/cpu-ops.h          | 16 ++++++++++++----
 target/alpha/cpu.h                   |  2 +-
 target/arm/internals.h               |  5 +++--
 target/avr/cpu.h                     |  2 +-
 target/hppa/cpu.h                    |  5 +++--
 target/i386/tcg/helper-tcg.h         |  2 +-
 target/loongarch/tcg/tcg_loongarch.h |  2 +-
 target/m68k/cpu.h                    |  2 +-
 target/microblaze/cpu.h              |  2 +-
 target/mips/tcg/tcg-internal.h       |  2 +-
 target/or1k/cpu.h                    |  2 +-
 target/ppc/internal.h                |  2 +-
 target/riscv/cpu.h                   |  2 +-
 target/s390x/s390x-internal.h        |  2 +-
 target/sh4/cpu.h                     |  2 +-
 target/sparc/cpu.h                   |  2 +-
 target/tricore/cpu.h                 |  2 +-
 target/xtensa/cpu.h                  |  2 +-
 accel/tcg/cputlb.c                   |  7 +++----
 target/alpha/helper.c                |  2 +-
 target/arm/tcg/tlb_helper.c          |  5 +++--
 target/avr/helper.c                  |  2 +-
 target/hexagon/cpu.c                 |  8 +++++---
 target/hppa/mem_helper.c             |  6 ++++--
 target/i386/tcg/system/excp_helper.c |  2 +-
 target/loongarch/tcg/tlb_helper.c    |  3 ++-
 target/m68k/helper.c                 |  3 ++-
 target/microblaze/helper.c           |  2 +-
 target/mips/tcg/system/tlb_helper.c  |  2 +-
 target/or1k/mmu.c                    |  2 +-
 target/ppc/mmu_helper.c              |  2 +-
 target/riscv/tcg/cpu_helper.c        |  3 ++-
 target/rx/cpu.c                      |  2 +-
 target/s390x/tcg/excp_helper.c       |  2 +-
 target/sh4/helper.c                  |  2 +-
 target/sparc/mmu_helper.c            |  4 ++--
 target/tricore/helper.c              |  2 +-
 target/xtensa/helper.c               |  2 +-
 38 files changed, 68 insertions(+), 51 deletions(-)

diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h
index 3ff6e6810e..4f162ae5b0 100644
--- a/include/accel/tcg/cpu-ops.h
+++ b/include/accel/tcg/cpu-ops.h
@@ -196,13 +196,20 @@ struct TCGCPUOps {
      * @cpu: cpu context
      * @out: output page properties
      * @addr: virtual address
+     * @first: beginning of virtual address range
+     * @last: end of virtual address range
      * @access_type: read, write or execute
      * @mmu_idx: mmu context
      * @memop: memory operation for the access
-     * @size: memory access size, or 0 for whole page
      * @probe: test only, no fault
      * @ra: host return address for exception unwind
      *
+     * The access in progress is [@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 is valid, fill in @out and return true.
      * Otherwise if probe is true, return false.
      * Otherwise raise an exception and do not return.
@@ -213,9 +220,10 @@ struct TCGCPUOps {
      * Zero may be passed for @memop to skip any alignment check
      * for non-memory-access operations such as probing.
      */
-    bool (*tlb_fill_align)(CPUState *cpu, CPUTLBEntryFull *out, vaddr addr,
+    bool (*tlb_fill_align)(CPUState *cpu, CPUTLBEntryFull *out,
+                           vaddr addr, vaddr first, vaddr last,
                            MMUAccessType access_type, int mmu_idx,
-                           MemOp memop, int size, bool probe, uintptr_t ra);
+                           MemOp memop, bool probe, uintptr_t ra);
     /**
      * @tlb_fill: Handle a softmmu tlb miss
      *
@@ -223,7 +231,7 @@ struct TCGCPUOps {
      * if the access is invalid and probe is true, return false;
      * otherwise raise an exception and do not return.
      */
-    bool (*tlb_fill)(CPUState *cpu, vaddr address, int size,
+    bool (*tlb_fill)(CPUState *cpu, vaddr addr, vaddr first, vaddr last,
                      MMUAccessType access_type, int mmu_idx,
                      bool probe, uintptr_t retaddr);
     /**
diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h
index 378bd96d94..1ee3a6855e 100644
--- a/target/alpha/cpu.h
+++ b/target/alpha/cpu.h
@@ -450,7 +450,7 @@ void alpha_cpu_record_sigsegv(CPUState *cs, vaddr address,
 void alpha_cpu_record_sigbus(CPUState *cs, vaddr address,
                              MMUAccessType access_type, uintptr_t retaddr);
 #else
-bool alpha_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool alpha_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                         MMUAccessType access_type, int mmu_idx,
                         bool probe, uintptr_t retaddr);
 G_NORETURN void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 4026f67579..6457fa06ee 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1011,9 +1011,10 @@ void arm_cpu_record_sigsegv(CPUState *cpu, vaddr addr,
 void arm_cpu_record_sigbus(CPUState *cpu, vaddr addr,
                            MMUAccessType access_type, uintptr_t ra);
 #else
-bool arm_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out, vaddr addr,
+bool arm_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out,
+                            vaddr addr, vaddr first, vaddr last,
                             MMUAccessType access_type, int mmu_idx,
-                            MemOp memop, int size, bool probe, uintptr_t ra);
+                            MemOp memop, bool probe, uintptr_t ra);
 #endif
 
 static inline int arm_to_core_mmu_idx(ARMMMUIdx mmu_idx)
diff --git a/target/avr/cpu.h b/target/avr/cpu.h
index a818db753b..e40367b832 100644
--- a/target/avr/cpu.h
+++ b/target/avr/cpu.h
@@ -233,7 +233,7 @@ static inline void cpu_set_sreg(CPUAVRState *env, uint8_t sreg)
     env->sregI = (sreg >> 7) & 0x01;
 }
 
-bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool avr_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                       MMUAccessType access_type, int mmu_idx,
                       bool probe, uintptr_t retaddr);
 
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index f453444d7f..bbf44ea220 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -391,9 +391,10 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, int);
 void hppa_ptlbe(CPUHPPAState *env);
 hwaddr hppa_cpu_get_phys_addr_debug(CPUState *cs, vaddr addr);
 void hppa_set_ior_and_isr(CPUHPPAState *env, vaddr addr, bool mmu_disabled);
-bool hppa_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out, vaddr addr,
+bool hppa_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out,
+                             vaddr addr, vaddr first, vaddr last,
                              MMUAccessType access_type, int mmu_idx,
-                             MemOp memop, int size, bool probe, uintptr_t ra);
+                             MemOp memop, bool probe, uintptr_t ra);
 void hppa_cpu_do_interrupt(CPUState *cpu);
 bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
 int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h
index f4b2ff740d..ba0a4da322 100644
--- a/target/i386/tcg/helper-tcg.h
+++ b/target/i386/tcg/helper-tcg.h
@@ -78,7 +78,7 @@ void x86_cpu_record_sigsegv(CPUState *cs, vaddr addr,
 void x86_cpu_record_sigbus(CPUState *cs, vaddr addr,
                            MMUAccessType access_type, uintptr_t ra);
 #else
-bool x86_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                       MMUAccessType access_type, int mmu_idx,
                       bool probe, uintptr_t retaddr);
 G_NORETURN void x86_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
diff --git a/target/loongarch/tcg/tcg_loongarch.h b/target/loongarch/tcg/tcg_loongarch.h
index 7fb627f2d6..1d43dbc751 100644
--- a/target/loongarch/tcg/tcg_loongarch.h
+++ b/target/loongarch/tcg/tcg_loongarch.h
@@ -12,7 +12,7 @@
 extern const TCGCPUOps loongarch_tcg_ops;
 void loongarch_csr_translate_init(void);
 
-bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                             MMUAccessType access_type, int mmu_idx,
                             bool probe, uintptr_t retaddr);
 
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 7cf3791108..08bdf27c7e 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -585,7 +585,7 @@ enum {
 #define MMU_KERNEL_IDX 0
 #define MMU_USER_IDX 1
 
-bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool m68k_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                        MMUAccessType access_type, int mmu_idx,
                        bool probe, uintptr_t retaddr);
 #ifndef CONFIG_USER_ONLY
diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h
index b9602f72b9..08d2a8f843 100644
--- a/target/microblaze/cpu.h
+++ b/target/microblaze/cpu.h
@@ -413,7 +413,7 @@ void mb_translate_code(CPUState *cs, TranslationBlock *tb,
 QEMU_BUILD_BUG_ON(MSR_TB_MASK & IFLAGS_TB_MASK);
 
 #if !defined(CONFIG_USER_ONLY)
-bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool mb_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                      MMUAccessType access_type, int mmu_idx,
                      bool probe, uintptr_t retaddr);
 
diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h
index 950e6afc3f..de179d0d5f 100644
--- a/target/mips/tcg/tcg-internal.h
+++ b/target/mips/tcg/tcg-internal.h
@@ -63,7 +63,7 @@ void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
                                     MemTxResult response, uintptr_t retaddr);
 void cpu_mips_tlb_flush(CPUMIPSState *env);
 
-bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool mips_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                        MMUAccessType access_type, int mmu_idx,
                        bool probe, uintptr_t retaddr);
 
diff --git a/target/or1k/cpu.h b/target/or1k/cpu.h
index fc4387ce7a..8a6293c030 100644
--- a/target/or1k/cpu.h
+++ b/target/or1k/cpu.h
@@ -298,7 +298,7 @@ int print_insn_or1k(bfd_vma addr, disassemble_info *info);
 #ifndef CONFIG_USER_ONLY
 hwaddr openrisc_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
 
-bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                            MMUAccessType access_type, int mmu_idx,
                            bool probe, uintptr_t retaddr);
 
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index a3bb12afd9..3a80719a16 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -292,7 +292,7 @@ void ppc_cpu_record_sigsegv(CPUState *cs, vaddr addr,
                             MMUAccessType access_type,
                             bool maperr, uintptr_t ra);
 #else
-bool ppc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool ppc_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                       MMUAccessType access_type, int mmu_idx,
                       bool probe, uintptr_t retaddr);
 G_NORETURN void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index e980b5964d..ed712761d5 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -659,7 +659,7 @@ bool riscv_env_smode_dbltrp_enabled(CPURISCVState *env, bool virt);
 G_NORETURN void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
                                                MMUAccessType access_type,
                                                int mmu_idx, uintptr_t retaddr);
-bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool riscv_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                         MMUAccessType access_type, int mmu_idx,
                         bool probe, uintptr_t retaddr);
 char *riscv_isa_string(RISCVCPU *cpu);
diff --git a/target/s390x/s390x-internal.h b/target/s390x/s390x-internal.h
index 35d1e34ef4..559a8d9201 100644
--- a/target/s390x/s390x-internal.h
+++ b/target/s390x/s390x-internal.h
@@ -271,7 +271,7 @@ void s390_cpu_record_sigsegv(CPUState *cs, vaddr address,
 void s390_cpu_record_sigbus(CPUState *cs, vaddr address,
                             MMUAccessType access_type, uintptr_t retaddr);
 #else
-bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool s390_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                        MMUAccessType access_type, int mmu_idx,
                        bool probe, uintptr_t retaddr);
 G_NORETURN void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h
index 3302702376..be377d4178 100644
--- a/target/sh4/cpu.h
+++ b/target/sh4/cpu.h
@@ -252,7 +252,7 @@ void sh4_translate_code(CPUState *cs, TranslationBlock *tb,
 
 #if !defined(CONFIG_USER_ONLY)
 hwaddr superh_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
-bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool superh_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                          MMUAccessType access_type, int mmu_idx,
                          bool probe, uintptr_t retaddr);
 void superh_cpu_do_interrupt(CPUState *cpu);
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 5f583ed9de..13ec3f4a3a 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -596,7 +596,7 @@ G_NORETURN void cpu_raise_exception_ra(CPUSPARCState *, int, uintptr_t);
 /* cpu_init.c */
 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu);
 /* mmu_helper.c */
-bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool sparc_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                         MMUAccessType access_type, int mmu_idx,
                         bool probe, uintptr_t retaddr);
 target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h
index 12e497d2a7..880c5e0067 100644
--- a/target/tricore/cpu.h
+++ b/target/tricore/cpu.h
@@ -260,7 +260,7 @@ void tricore_translate_code(CPUState *cs, TranslationBlock *tb,
 #define CPU_RESOLVING_TYPE TYPE_TRICORE_CPU
 
 /* helpers.c */
-bool tricore_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool tricore_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                           MMUAccessType access_type, int mmu_idx,
                           bool probe, uintptr_t retaddr);
 
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index 442e98bd1b..46660a7dad 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -581,7 +581,7 @@ struct XtensaCPUClass {
 };
 
 #ifndef CONFIG_USER_ONLY
-bool xtensa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool xtensa_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                          MMUAccessType access_type, int mmu_idx,
                          bool probe, uintptr_t retaddr);
 void xtensa_cpu_do_interrupt(CPUState *cpu);
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 95db2c22e2..d559ce1ef6 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1241,12 +1241,11 @@ static bool tlb_fill_align(CPUState *cpu, vaddr addr, vaddr first, vaddr last,
                            bool probe, uintptr_t ra)
 {
     const TCGCPUOps *ops = cpu->cc->tcg_ops;
-    int size = last - addr + 1;
     CPUTLBEntryFull full;
 
     if (ops->tlb_fill_align) {
-        if (ops->tlb_fill_align(cpu, &full, addr, type, mmu_idx,
-                                memop, size, probe, ra)) {
+        if (ops->tlb_fill_align(cpu, &full, addr, first, last, type, mmu_idx,
+                                memop, probe, ra)) {
             tlb_set_page_full(cpu, mmu_idx, addr, &full);
             return true;
         }
@@ -1255,7 +1254,7 @@ static bool tlb_fill_align(CPUState *cpu, vaddr addr, vaddr first, vaddr last,
         if (addr & ((1u << memop_alignment_bits(memop)) - 1)) {
             ops->do_unaligned_access(cpu, addr, type, mmu_idx, ra);
         }
-        if (ops->tlb_fill(cpu, addr, size, type, mmu_idx, probe, ra)) {
+        if (ops->tlb_fill(cpu, addr, first, last, type, mmu_idx, probe, ra)) {
             return true;
         }
     }
diff --git a/target/alpha/helper.c b/target/alpha/helper.c
index c3614ecafd..d24b206388 100644
--- a/target/alpha/helper.c
+++ b/target/alpha/helper.c
@@ -307,7 +307,7 @@ hwaddr alpha_cpu_get_phys_addr_debug(CPUState *cs, vaddr addr)
     return (fail >= 0 ? -1 : phys);
 }
 
-bool alpha_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
+bool alpha_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                         MMUAccessType access_type, int mmu_idx,
                         bool probe, uintptr_t retaddr)
 {
diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c
index 4c3f16dc2a..826daf6772 100644
--- a/target/arm/tcg/tlb_helper.c
+++ b/target/arm/tcg/tlb_helper.c
@@ -353,9 +353,10 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
     arm_deliver_fault(cpu, addr, access_type, mmu_idx, &fi);
 }
 
-bool arm_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out, vaddr address,
+bool arm_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out,
+                            vaddr address, vaddr first, vaddr last,
                             MMUAccessType access_type, int mmu_idx,
-                            MemOp memop, int size, bool probe, uintptr_t ra)
+                            MemOp memop, bool probe, uintptr_t ra)
 {
     ARMCPU *cpu = ARM_CPU(cs);
     GetPhysAddrResult res = {};
diff --git a/target/avr/helper.c b/target/avr/helper.c
index f452c9d904..b5cbdc7b2c 100644
--- a/target/avr/helper.c
+++ b/target/avr/helper.c
@@ -113,7 +113,7 @@ hwaddr avr_cpu_get_phys_addr_debug(CPUState *cs, vaddr addr)
     return addr; /* I assume 1:1 address correspondence */
 }
 
-bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
                       MMUAccessType access_type, int mmu_idx,
                       bool probe, uintptr_t retaddr)
 {
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 0ddd898e6e..bfcd9b6159 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -666,11 +666,13 @@ static const char *access_type_names[] = { "MMU_DATA_LOAD ", "MMU_DATA_STORE",
 static const char *mmu_idx_names[] = { "MMU_USER_IDX", "MMU_GUEST_IDX",
                                        "MMU_KERNEL_IDX" };
 
-static bool hexagon_tlb_fill(CPUState *cs, vaddr address, int size,
-                             MMUAccessType access_type, int mmu_idx, bool probe,
-                             uintptr_t retaddr)
+static bool hexagon_tlb_fill(CPUState *cs, vaddr address,
+                             vaddr first, vaddr last,
+                             MMUAccessType access_type, int mmu_idx,
+                             bool probe, uintptr_t retaddr)
 {
     CPUHexagonState *env = cpu_env(cs);
+    int size = last - address + 1;
     int slot = 0;
     hwaddr phys;
     int prot = 0;
diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c
index 01e6149c81..0427fd0917 100644
--- a/target/hppa/mem_helper.c
+++ b/target/hppa/mem_helper.c
@@ -435,11 +435,13 @@ void hppa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
     }
 }
 
-bool hppa_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out, vaddr addr,
+bool hppa_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out,
+                             vaddr addr, vaddr first, vaddr last,
                              MMUAccessType type, int mmu_idx,
-                             MemOp memop, int size, bool probe, uintptr_t ra)
+                             MemOp memop, bool probe, uintptr_t ra)
 {
     CPUHPPAState *env = cpu_env(cs);
+    int size = last - addr + 1;
     int prot, excp, a_prot;
     hwaddr phys;
 
diff --git a/target/i386/tcg/system/excp_helper.c b/target/i386/tcg/system/excp_helper.c
index d7ea77c855..fd21287a8b 100644
--- a/target/i386/tcg/system/excp_helper.c
+++ b/target/i386/tcg/system/excp_helper.c
@@ -610,7 +610,7 @@ static bool get_physical_address(CPUX86State *env, vaddr addr,
     return true;
 }
 
-bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
+bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                       MMUAccessType access_type, int mmu_idx,
                       bool probe, uintptr_t retaddr)
 {
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index a4b90beca6..08c992d774 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -630,7 +630,8 @@ static void ptw_update_tlb(CPULoongArchState *env, MMUContext *context)
     update_tlb_index(env, context, index);
 }
 
-bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address,
+                            vaddr first, vaddr last,
                             MMUAccessType access_type, int mmu_idx,
                             bool probe, uintptr_t retaddr)
 {
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 5f91d206f5..c15fb1bc05 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -954,11 +954,12 @@ void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
     }
 }
 
-bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
                        MMUAccessType qemu_access_type, int mmu_idx,
                        bool probe, uintptr_t retaddr)
 {
     CPUM68KState *env = cpu_env(cs);
+    int size = last - address + 1;
     hwaddr physical;
     int prot;
     int access_type;
diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c
index 05a90f5ecb..65c73951ca 100644
--- a/target/microblaze/helper.c
+++ b/target/microblaze/helper.c
@@ -85,7 +85,7 @@ static bool mb_cpu_access_is_secure(MicroBlazeCPU *cpu,
     }
 }
 
-bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
                      MMUAccessType access_type, int mmu_idx,
                      bool probe, uintptr_t retaddr)
 {
diff --git a/target/mips/tcg/system/tlb_helper.c b/target/mips/tcg/system/tlb_helper.c
index 4398c6f80b..a54a98dd08 100644
--- a/target/mips/tcg/system/tlb_helper.c
+++ b/target/mips/tcg/system/tlb_helper.c
@@ -906,7 +906,7 @@ refill:
 }
 #endif
 
-bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
                        MMUAccessType access_type, int mmu_idx,
                        bool probe, uintptr_t retaddr)
 {
diff --git a/target/or1k/mmu.c b/target/or1k/mmu.c
index 3fc56e1b77..a3c0fd7089 100644
--- a/target/or1k/mmu.c
+++ b/target/or1k/mmu.c
@@ -104,7 +104,7 @@ static void raise_mmu_exception(OpenRISCCPU *cpu, vaddr address,
     cpu->env.lock_addr = -1;
 }
 
-bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
+bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                            MMUAccessType access_type, int mmu_idx,
                            bool probe, uintptr_t retaddr)
 {
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index ac60705402..0edaeab045 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -1358,7 +1358,7 @@ void helper_check_tlb_flush_global(CPUPPCState *env)
 }
 
 
-bool ppc_cpu_tlb_fill(CPUState *cs, vaddr eaddr, int size,
+bool ppc_cpu_tlb_fill(CPUState *cs, vaddr eaddr, vaddr first, vaddr last,
                       MMUAccessType access_type, int mmu_idx,
                       bool probe, uintptr_t retaddr)
 {
diff --git a/target/riscv/tcg/cpu_helper.c b/target/riscv/tcg/cpu_helper.c
index 07d9222652..11f2654da1 100644
--- a/target/riscv/tcg/cpu_helper.c
+++ b/target/riscv/tcg/cpu_helper.c
@@ -1649,12 +1649,13 @@ static void pmu_tlb_fill_incr_ctr(RISCVCPU *cpu, MMUAccessType access_type)
     riscv_pmu_incr_ctr(cpu, pmu_event_type);
 }
 
-bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
                         MMUAccessType access_type, int mmu_idx,
                         bool probe, uintptr_t retaddr)
 {
     RISCVCPU *cpu = RISCV_CPU(cs);
     CPURISCVState *env = &cpu->env;
+    int size = last - address + 1;
     vaddr im_address;
     hwaddr pa = 0;
     int prot, prot2, prot_pmp;
diff --git a/target/rx/cpu.c b/target/rx/cpu.c
index 20b188c24c..5d955c3763 100644
--- a/target/rx/cpu.c
+++ b/target/rx/cpu.c
@@ -185,7 +185,7 @@ static void rx_cpu_disas_set_info(const CPUState *cpu, disassemble_info *info)
     info->print_insn = print_insn_rx;
 }
 
-static bool rx_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
+static bool rx_cpu_tlb_fill(CPUState *cs, vaddr addr, vaddr first, vaddr last,
                             MMUAccessType access_type, int mmu_idx,
                             bool probe, uintptr_t retaddr)
 {
diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c
index d952bb20cf..d9f68e1afc 100644
--- a/target/s390x/tcg/excp_helper.c
+++ b/target/s390x/tcg/excp_helper.c
@@ -145,7 +145,7 @@ static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx)
     }
 }
 
-bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
                        MMUAccessType access_type, int mmu_idx,
                        bool probe, uintptr_t retaddr)
 {
diff --git a/target/sh4/helper.c b/target/sh4/helper.c
index b6b057f104..1fe1fe0275 100644
--- a/target/sh4/helper.c
+++ b/target/sh4/helper.c
@@ -798,7 +798,7 @@ bool superh_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
     return false;
 }
 
-bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
                          MMUAccessType access_type, int mmu_idx,
                          bool probe, uintptr_t retaddr)
 {
diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c
index 07ba25dfce..cab476006a 100644
--- a/target/sparc/mmu_helper.c
+++ b/target/sparc/mmu_helper.c
@@ -211,7 +211,7 @@ static int get_physical_address(CPUSPARCState *env, CPUTLBEntryFull *full,
 }
 
 /* Perform address translation */
-bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
                         MMUAccessType access_type, int mmu_idx,
                         bool probe, uintptr_t retaddr)
 {
@@ -776,7 +776,7 @@ static int get_physical_address(CPUSPARCState *env, CPUTLBEntryFull *full,
 }
 
 /* Perform address translation */
-bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
                         MMUAccessType access_type, int mmu_idx,
                         bool probe, uintptr_t retaddr)
 {
diff --git a/target/tricore/helper.c b/target/tricore/helper.c
index 273713a147..5a6fb6c6c9 100644
--- a/target/tricore/helper.c
+++ b/target/tricore/helper.c
@@ -67,7 +67,7 @@ static void raise_mmu_exception(CPUTriCoreState *env, vaddr address,
 {
 }
 
-bool tricore_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool tricore_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
                           MMUAccessType rw, int mmu_idx,
                           bool probe, uintptr_t retaddr)
 {
diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c
index 5a0e865514..a99956614b 100644
--- a/target/xtensa/helper.c
+++ b/target/xtensa/helper.c
@@ -264,7 +264,7 @@ void xtensa_cpu_do_unaligned_access(CPUState *cs,
                                   addr);
 }
 
-bool xtensa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+bool xtensa_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
                          MMUAccessType access_type, int mmu_idx,
                          bool probe, uintptr_t retaddr)
 {
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 13/18] target/riscv: Move PMP_AMATCH_OFF check in pmp_hart_has_privs
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (11 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 12/18] accel/tcg: Replace size with first/last in TCGCPUOps.tlb_fill* Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-16  9:21   ` Philippe Mathieu-Daudé
  2026-08-18  3:30   ` Alistair
  2026-08-15 20:37 ` [RFC PATCH 14/18] target/riscv: Return bool from pmp_is_in_range Richard Henderson
                   ` (4 subsequent siblings)
  17 siblings, 2 replies; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

Check for region disabled before checking the region range.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/riscv/tcg/pmp.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/target/riscv/tcg/pmp.c b/target/riscv/tcg/pmp.c
index 41b55519a8..5bccc60527 100644
--- a/target/riscv/tcg/pmp.c
+++ b/target/riscv/tcg/pmp.c
@@ -415,6 +415,10 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
      * from low to high
      */
     for (i = 0; i < pmp_regions; i++) {
+        if (pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg) == PMP_AMATCH_OFF) {
+            continue;
+        }
+
         s = pmp_is_in_range(env, i, addr);
         e = pmp_is_in_range(env, i, addr + pmp_size - 1);
 
@@ -427,10 +431,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
         }
 
         /* fully inside */
-        const uint8_t a_field =
-            pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
-
-        if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
+        if (s + e == 2) {
             /*
              * If the PMP entry is not off and the address is in range,
              * do the priv check
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 14/18] target/riscv: Return bool from pmp_is_in_range
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (12 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 13/18] target/riscv: Move PMP_AMATCH_OFF check in pmp_hart_has_privs Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-16 15:09   ` Philippe Mathieu-Daudé
  2026-08-18  3:31   ` Alistair
  2026-08-15 20:37 ` [RFC PATCH 15/18] target/riscv: Use boolean logic in pmp_hart_has_privs Richard Henderson
                   ` (3 subsequent siblings)
  17 siblings, 2 replies; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/riscv/tcg/pmp.c | 21 ++++++---------------
 1 file changed, 6 insertions(+), 15 deletions(-)

diff --git a/target/riscv/tcg/pmp.c b/target/riscv/tcg/pmp.c
index 5bccc60527..5ea0e5b6c3 100644
--- a/target/riscv/tcg/pmp.c
+++ b/target/riscv/tcg/pmp.c
@@ -299,18 +299,10 @@ void pmp_update_rule_nums(CPURISCVState *env)
     }
 }
 
-static int pmp_is_in_range(CPURISCVState *env, int pmp_index, hwaddr addr)
+static bool pmp_is_in_range(CPURISCVState *env, int pmp_index, hwaddr addr)
 {
-    int result = 0;
-
-    if ((addr >= env->pmp_state.addr[pmp_index].sa) &&
-        (addr <= env->pmp_state.addr[pmp_index].ea)) {
-        result = 1;
-    } else {
-        result = 0;
-    }
-
-    return result;
+    return (addr >= env->pmp_state.addr[pmp_index].sa &&
+            addr <= env->pmp_state.addr[pmp_index].ea);
 }
 
 /*
@@ -385,10 +377,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
                         pmp_priv_t *allowed_privs,
                         privilege_mode_t mode)
 {
-    int i = 0;
     int pmp_size = 0;
-    hwaddr s = 0;
-    hwaddr e = 0;
     uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
 
     /* Short cut if no rules */
@@ -414,7 +403,9 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
      * 1.10 draft priv spec states there is an implicit order
      * from low to high
      */
-    for (i = 0; i < pmp_regions; i++) {
+    for (int i = 0; i < pmp_regions; i++) {
+        bool s, e;
+
         if (pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg) == PMP_AMATCH_OFF) {
             continue;
         }
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 15/18] target/riscv: Use boolean logic in pmp_hart_has_privs
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (13 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 14/18] target/riscv: Return bool from pmp_is_in_range Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-18  3:32   ` Alistair
  2026-08-15 20:37 ` [RFC PATCH 16/18] target/riscv: Recognize watchpoints with first/last Richard Henderson
                   ` (2 subsequent siblings)
  17 siblings, 1 reply; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

While addition with bool variables isn't wrong, as they promote
to int, it's odd.  Use normal boolean operators instead.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/riscv/tcg/pmp.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/target/riscv/tcg/pmp.c b/target/riscv/tcg/pmp.c
index 5ea0e5b6c3..fc035c95cf 100644
--- a/target/riscv/tcg/pmp.c
+++ b/target/riscv/tcg/pmp.c
@@ -413,16 +413,8 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
         s = pmp_is_in_range(env, i, addr);
         e = pmp_is_in_range(env, i, addr + pmp_size - 1);
 
-        /* partially inside */
-        if ((s + e) == 1) {
-            qemu_log_mask(LOG_GUEST_ERROR,
-                          "pmp violation - access is partially inside\n");
-            *allowed_privs = 0;
-            return false;
-        }
-
         /* fully inside */
-        if (s + e == 2) {
+        if (s && e) {
             /*
              * If the PMP entry is not off and the address is in range,
              * do the priv check
@@ -517,6 +509,14 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
              */
             return (privs & *allowed_privs) == privs;
         }
+
+        /* partially inside */
+        if (s || e) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "pmp violation - access is partially inside\n");
+            *allowed_privs = 0;
+            return false;
+        }
     }
 
     /* No rule matched */
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 16/18] target/riscv: Recognize watchpoints with first/last
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (14 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 15/18] target/riscv: Use boolean logic in pmp_hart_has_privs Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-18  5:43   ` Philippe Mathieu-Daudé
  2026-08-15 20:37 ` [RFC PATCH 17/18] target/riscv: Pass first/last to get_physical_address_pmp Richard Henderson
  2026-08-15 20:37 ` [RFC PATCH 18/18] target/riscv: Pass first/last to pmp_hart_has_privs Richard Henderson
  17 siblings, 1 reply; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/riscv/tcg/cpu_helper.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/riscv/tcg/cpu_helper.c b/target/riscv/tcg/cpu_helper.c
index 11f2654da1..3318e82ea7 100644
--- a/target/riscv/tcg/cpu_helper.c
+++ b/target/riscv/tcg/cpu_helper.c
@@ -1784,8 +1784,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
          * Otherwise we'll throw a debug exception and execution
          * will continue elsewhere.
          */
-        cpu_check_watchpoint(cs, address, size, MEMTXATTRS_UNSPECIFIED,
-                             wp_access, retaddr);
+        cpu_check_watchpoint(cs, first, last - first + 1,
+                             MEMTXATTRS_UNSPECIFIED, wp_access, retaddr);
 
         raise_mmu_exception(env, address, access_type, pmp_pma_violation,
                             first_stage_error, two_stage_lookup,
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 17/18] target/riscv: Pass first/last to get_physical_address_pmp
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (15 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 16/18] target/riscv: Recognize watchpoints with first/last Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-18  3:35   ` Alistair
  2026-08-18  5:35   ` Philippe Mathieu-Daudé
  2026-08-15 20:37 ` [RFC PATCH 18/18] target/riscv: Pass first/last to pmp_hart_has_privs Richard Henderson
  17 siblings, 2 replies; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/riscv/tcg/cpu_helper.c | 48 +++++++++++++++++++----------------
 1 file changed, 26 insertions(+), 22 deletions(-)

diff --git a/target/riscv/tcg/cpu_helper.c b/target/riscv/tcg/cpu_helper.c
index 3318e82ea7..fb1250a4b8 100644
--- a/target/riscv/tcg/cpu_helper.c
+++ b/target/riscv/tcg/cpu_helper.c
@@ -899,12 +899,13 @@ void riscv_cpu_set_mode(CPURISCVState *env, privilege_mode_t newpriv,
  *
  * @env: CPURISCVState
  * @prot: The returned protection attributes
- * @addr: The physical address to be checked permission
+ * @first, @last: The physical address range to be permission checked
  * @access_type: The type of MMU access
  * @mode: Indicates current privilege level.
  */
-static int get_physical_address_pmp(CPURISCVState *env, int *prot, hwaddr addr,
-                                    int size, MMUAccessType access_type,
+static int get_physical_address_pmp(CPURISCVState *env, int *prot,
+                                    hwaddr first, hwaddr last,
+                                    MMUAccessType access_type,
                                     privilege_mode_t mode)
 {
     pmp_priv_t pmp_priv;
@@ -915,8 +916,8 @@ static int get_physical_address_pmp(CPURISCVState *env, int *prot, hwaddr addr,
         return TRANSLATE_SUCCESS;
     }
 
-    pmp_has_privs = pmp_hart_has_privs(env, addr, size, 1 << access_type,
-                                       &pmp_priv, mode);
+    pmp_has_privs = pmp_hart_has_privs(env, first, last - first + 1,
+                                       1 << access_type, &pmp_priv, mode);
     if (!pmp_has_privs) {
         *prot = 0;
         return TRANSLATE_PMP_FAIL;
@@ -1142,6 +1143,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
     base = base_root;
     for (i = 0; i < levels; i++, ptshift -= ptidxbits) {
         target_ulong idx;
+        int pmp_prot, pmp_ret;
+
         if (i == 0) {
             idx = (addr >> (PGSHIFT + ptshift)) &
                            ((1 << (ptidxbits + widened)) - 1);
@@ -1174,10 +1177,9 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
             pte_addr = base + idx * ptesize;
         }
 
-        int pmp_prot;
-        int pmp_ret = get_physical_address_pmp(env, &pmp_prot, pte_addr,
-                                               sxlen_bytes,
-                                               MMU_DATA_LOAD, PRV_S);
+        pmp_ret = get_physical_address_pmp(env, &pmp_prot, pte_addr,
+                                           pte_addr + sxlen_bytes - 1,
+                                           MMU_DATA_LOAD, PRV_S);
         if (pmp_ret != TRANSLATE_SUCCESS) {
             return TRANSLATE_PMP_FAIL;
         }
@@ -1425,7 +1427,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
         }
 
         pmp_ret = get_physical_address_pmp(env, &pmp_prot, pte_addr,
-                                           sxlen_bytes, MMU_DATA_STORE, PRV_S);
+                                           pte_addr + sxlen_bytes - 1,
+                                           MMU_DATA_STORE, PRV_S);
         if (pmp_ret != TRANSLATE_SUCCESS) {
             return TRANSLATE_PMP_FAIL;
         }
@@ -1655,8 +1658,6 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
 {
     RISCVCPU *cpu = RISCV_CPU(cs);
     CPURISCVState *env = &cpu->env;
-    int size = last - address + 1;
-    vaddr im_address;
     hwaddr pa = 0;
     int prot, prot2, prot_pmp;
     bool pmp_pma_violation = false;
@@ -1676,7 +1677,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
     pmu_tlb_fill_incr_ctr(cpu, access_type);
     if (two_stage_lookup) {
         /* Two stage lookup */
-        ret = get_physical_address(env, &pa, &prot, address,
+        ret = get_physical_address(env, &pa, &prot, first,
                                    &env->guest_phys_fault_addr, access_type,
                                    mmu_idx, true, true, false, probe);
         /*
@@ -1692,11 +1693,11 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
         qemu_log_mask(CPU_LOG_MMU,
                       "%s 1st-stage address=%" VADDR_PRIx " ret %d physical "
                       HWADDR_FMT_plx " prot %d\n",
-                      __func__, address, ret, pa, prot);
+                      __func__, first, ret, pa, prot);
 
         if (ret == TRANSLATE_SUCCESS) {
             /* Second stage lookup */
-            im_address = pa;
+            vaddr im_address = pa;
 
             ret = get_physical_address(env, &pa, &prot2, im_address, NULL,
                                        access_type, MMUIdx_U, false, true,
@@ -1711,8 +1712,9 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
             prot &= prot2;
 
             if (ret == TRANSLATE_SUCCESS) {
-                ret = get_physical_address_pmp(env, &prot_pmp, pa,
-                                               size, access_type, mode);
+                ret = get_physical_address_pmp(env, &prot_pmp,
+                                               pa, pa + (last - first),
+                                               access_type, mode);
                 tlb_size = pmp_get_tlb_size(env, pa);
 
                 qemu_log_mask(CPU_LOG_MMU,
@@ -1736,18 +1738,19 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
         }
     } else {
         /* Single stage lookup */
-        ret = get_physical_address(env, &pa, &prot, address, NULL,
+        ret = get_physical_address(env, &pa, &prot, first, NULL,
                                    access_type, mmu_idx, true, false, false,
                                    probe);
 
         qemu_log_mask(CPU_LOG_MMU,
                       "%s address=%" VADDR_PRIx " ret %d physical "
                       HWADDR_FMT_plx " prot %d\n",
-                      __func__, address, ret, pa, prot);
+                      __func__, first, ret, pa, prot);
 
         if (ret == TRANSLATE_SUCCESS) {
-            ret = get_physical_address_pmp(env, &prot_pmp, pa,
-                                           size, access_type, mode);
+            ret = get_physical_address_pmp(env, &prot_pmp,
+                                           pa, pa + (last - first),
+                                           access_type, mode);
             tlb_size = pmp_get_tlb_size(env, pa);
 
             qemu_log_mask(CPU_LOG_MMU,
@@ -1764,7 +1767,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
     }
 
     if (ret == TRANSLATE_SUCCESS) {
-        tlb_set_page(cs, address & ~(tlb_size - 1), pa & ~(tlb_size - 1),
+        tlb_set_page(cs, address & ~(tlb_size - 1),
+                     (pa + (address - first)) & ~(tlb_size - 1),
                      prot, mmu_idx, tlb_size);
         return true;
     } else if (probe) {
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [RFC PATCH 18/18] target/riscv: Pass first/last to pmp_hart_has_privs
  2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
                   ` (16 preceding siblings ...)
  2026-08-15 20:37 ` [RFC PATCH 17/18] target/riscv: Pass first/last to get_physical_address_pmp Richard Henderson
@ 2026-08-15 20:37 ` Richard Henderson
  2026-08-18  3:36   ` Alistair
  17 siblings, 1 reply; 38+ messages in thread
From: Richard Henderson @ 2026-08-15 20:37 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-arm, qemu-riscv

This eliminates an ambiguity with size == 0 and also
aligns with the underlying hw representation.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/riscv/tcg/pmp.h        |  5 ++---
 target/riscv/tcg/cpu_helper.c |  2 +-
 target/riscv/tcg/pmp.c        | 24 ++++--------------------
 3 files changed, 7 insertions(+), 24 deletions(-)

diff --git a/target/riscv/tcg/pmp.h b/target/riscv/tcg/pmp.h
index 4c95c2767a..eacb5b5349 100644
--- a/target/riscv/tcg/pmp.h
+++ b/target/riscv/tcg/pmp.h
@@ -70,9 +70,8 @@ typedef struct {
 
 typedef struct CPUArchState CPURISCVState;
 
-bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
-                        int size, pmp_priv_t privs,
-                        pmp_priv_t *allowed_privs,
+bool pmp_hart_has_privs(CPURISCVState *env, hwaddr first, hwaddr last,
+                        pmp_priv_t privs, pmp_priv_t *allowed_privs,
                         privilege_mode_t mode);
 uint64_t pmp_get_tlb_size(CPURISCVState *env, hwaddr addr);
 void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index);
diff --git a/target/riscv/tcg/cpu_helper.c b/target/riscv/tcg/cpu_helper.c
index fb1250a4b8..7ef5ab5277 100644
--- a/target/riscv/tcg/cpu_helper.c
+++ b/target/riscv/tcg/cpu_helper.c
@@ -916,7 +916,7 @@ static int get_physical_address_pmp(CPURISCVState *env, int *prot,
         return TRANSLATE_SUCCESS;
     }
 
-    pmp_has_privs = pmp_hart_has_privs(env, first, last - first + 1,
+    pmp_has_privs = pmp_hart_has_privs(env, first, last,
                                        1 << access_type, &pmp_priv, mode);
     if (!pmp_has_privs) {
         *prot = 0;
diff --git a/target/riscv/tcg/pmp.c b/target/riscv/tcg/pmp.c
index fc035c95cf..d3cbb2cb2e 100644
--- a/target/riscv/tcg/pmp.c
+++ b/target/riscv/tcg/pmp.c
@@ -372,12 +372,10 @@ static bool pmp_hart_has_privs_default(CPURISCVState *env, pmp_priv_t privs,
  * pmpcfg but is not acted upon during access checks. Cache attributes
  * have no functional impact in QEMU emulation.
  */
-bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
-                        int size, pmp_priv_t privs,
-                        pmp_priv_t *allowed_privs,
+bool pmp_hart_has_privs(CPURISCVState *env, hwaddr first, hwaddr last,
+                        pmp_priv_t privs, pmp_priv_t *allowed_privs,
                         privilege_mode_t mode)
 {
-    int pmp_size = 0;
     uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
 
     /* Short cut if no rules */
@@ -385,20 +383,6 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
         return pmp_hart_has_privs_default(env, privs, allowed_privs, mode);
     }
 
-    if (size == 0) {
-        if (riscv_cpu_cfg(env)->mmu) {
-            /*
-             * If size is unknown (0), assume that all bytes
-             * from addr to the end of the page will be accessed.
-             */
-            pmp_size = -(addr | TARGET_PAGE_MASK);
-        } else {
-            pmp_size = 2 << riscv_cpu_mxl(env);
-        }
-    } else {
-        pmp_size = size;
-    }
-
     /*
      * 1.10 draft priv spec states there is an implicit order
      * from low to high
@@ -410,8 +394,8 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
             continue;
         }
 
-        s = pmp_is_in_range(env, i, addr);
-        e = pmp_is_in_range(env, i, addr + pmp_size - 1);
+        s = pmp_is_in_range(env, i, first);
+        e = pmp_is_in_range(env, i, last);
 
         /* fully inside */
         if (s && e) {
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 06/18] accel/tcg: Drop fault_size from user-only probe_access_internal
  2026-08-15 20:37 ` [RFC PATCH 06/18] accel/tcg: Drop fault_size from user-only probe_access_internal Richard Henderson
@ 2026-08-16  9:05   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-16  9:05 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 15/8/26 22:37, Richard Henderson wrote:
> This argument is unused.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   accel/tcg/user-exec.c | 8 ++++----
>   1 file changed, 4 insertions(+), 4 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 07/18] accel/tcg: Replace size with first/last in probe_access_full
  2026-08-15 20:37 ` [RFC PATCH 07/18] accel/tcg: Replace size with first/last in probe_access_full Richard Henderson
@ 2026-08-16  9:09   ` Philippe Mathieu-Daudé
  2026-08-16  9:11     ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-16  9:09 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 15/8/26 22:37, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/accel/tcg/probe.h     |  2 +-
>   accel/tcg/cputlb.c            | 17 +++++++++++------
>   target/arm/tcg/helper-a64.c   |  5 ++++-
>   target/arm/tcg/mte_helper.c   | 21 ++++++++++++---------
>   target/arm/tcg/sve_helper.c   |  5 ++++-
>   target/mips/tcg/ldst_helper.c |  4 ++--
>   6 files changed, 34 insertions(+), 20 deletions(-)
> 
> diff --git a/include/accel/tcg/probe.h b/include/accel/tcg/probe.h
> index 0b788901ba..e3068a79de 100644
> --- a/include/accel/tcg/probe.h
> +++ b/include/accel/tcg/probe.h
> @@ -86,7 +86,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size,
>    * This function will return TLB_MMIO in order to force the access
>    * to be handled out-of-line if plugins wish to instrument the access.
>    */
> -int probe_access_full(CPUArchState *env, vaddr addr, int size,
> +int probe_access_full(CPUArchState *env, vaddr addr, vaddr first, vaddr last,

I prefer this clearer first/last range API, it feels safer.

Missing updating the docstring, otherwise:
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

>                         MMUAccessType access_type, int mmu_idx,
>                         bool nonfault, void **phost,
>                         CPUTLBEntryFull **pfull, uintptr_t retaddr);


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 07/18] accel/tcg: Replace size with first/last in probe_access_full
  2026-08-16  9:09   ` Philippe Mathieu-Daudé
@ 2026-08-16  9:11     ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-16  9:11 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 16/8/26 11:09, Philippe Mathieu-Daudé wrote:
> On 15/8/26 22:37, Richard Henderson wrote:
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>>   include/accel/tcg/probe.h     |  2 +-
>>   accel/tcg/cputlb.c            | 17 +++++++++++------
>>   target/arm/tcg/helper-a64.c   |  5 ++++-
>>   target/arm/tcg/mte_helper.c   | 21 ++++++++++++---------
>>   target/arm/tcg/sve_helper.c   |  5 ++++-
>>   target/mips/tcg/ldst_helper.c |  4 ++--
>>   6 files changed, 34 insertions(+), 20 deletions(-)
>>
>> diff --git a/include/accel/tcg/probe.h b/include/accel/tcg/probe.h
>> index 0b788901ba..e3068a79de 100644
>> --- a/include/accel/tcg/probe.h
>> +++ b/include/accel/tcg/probe.h
>> @@ -86,7 +86,7 @@ int probe_access_flags(CPUArchState *env, vaddr 
>> addr, int size,
>>    * This function will return TLB_MMIO in order to force the access
>>    * to be handled out-of-line if plugins wish to instrument the access.
>>    */
>> -int probe_access_full(CPUArchState *env, vaddr addr, int size,
>> +int probe_access_full(CPUArchState *env, vaddr addr, vaddr first, 
>> vaddr last,
> 
> I prefer this clearer first/last range API, it feels safer.
> 
> Missing updating the docstring, otherwise:

I now see this is done in the following patch. Maybe amend

"the probe_access_full() docstring will be updated in the next commit"?
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> 
>>                         MMUAccessType access_type, int mmu_idx,
>>                         bool nonfault, void **phost,
>>                         CPUTLBEntryFull **pfull, uintptr_t retaddr);
> 



^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 08/18] accel/tcg: Replace size with first/last in probe_access_flags
  2026-08-15 20:37 ` [RFC PATCH 08/18] accel/tcg: Replace size with first/last in probe_access_flags Richard Henderson
@ 2026-08-16  9:18   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-16  9:18 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 15/8/26 22:37, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   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.

This If/Otherwise block sounds like implementation detail leaking into
documentation API contract, but I don't mind.

>    *
> - * 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/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);

Something in this function (on the pre-existing code) bugged me,
confirmed by your cover letter (I haven't looked at the RISCV
preliminary series).

>       /* 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);

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>



^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 09/18] accel/tcg: Allow phost to be NULL in probe_access_flags
  2026-08-15 20:37 ` [RFC PATCH 09/18] accel/tcg: Allow phost to be NULL " Richard Henderson
@ 2026-08-16  9:18   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-16  9:18 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 15/8/26 22:37, Richard Henderson wrote:
> Do not require the caller to create a dummy variable.
> The one instance so far is riscv check_zicbom_access.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/accel/tcg/probe.h    | 3 ++-
>   accel/tcg/cputlb.c           | 4 +++-
>   accel/tcg/user-exec.c        | 5 ++++-
>   target/riscv/tcg/op_helper.c | 3 +--
>   4 files changed, 10 insertions(+), 5 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 10/18] accel/tcg: Replace size with first/last in probe_access_internal
  2026-08-15 20:37 ` [RFC PATCH 10/18] accel/tcg: Replace size with first/last in probe_access_internal Richard Henderson
@ 2026-08-16  9:19   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-16  9:19 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 15/8/26 22:37, Richard Henderson wrote:
> Propagate the API change down one step further within cputlb.c.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   accel/tcg/cputlb.c | 37 ++++++++++++++++++++-----------------
>   1 file changed, 20 insertions(+), 17 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 11/18] accel/tcg: Replace size with first/last in tlb_fill_align
  2026-08-15 20:37 ` [RFC PATCH 11/18] accel/tcg: Replace size with first/last in tlb_fill_align Richard Henderson
@ 2026-08-16  9:20   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-16  9:20 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 15/8/26 22:37, Richard Henderson wrote:
> Propagate the API change down one step further within cputlb.c.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   accel/tcg/cputlb.c | 21 +++++++++++----------
>   1 file changed, 11 insertions(+), 10 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 13/18] target/riscv: Move PMP_AMATCH_OFF check in pmp_hart_has_privs
  2026-08-15 20:37 ` [RFC PATCH 13/18] target/riscv: Move PMP_AMATCH_OFF check in pmp_hart_has_privs Richard Henderson
@ 2026-08-16  9:21   ` Philippe Mathieu-Daudé
  2026-08-18  3:30   ` Alistair
  1 sibling, 0 replies; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-16  9:21 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 15/8/26 22:37, Richard Henderson wrote:
> Check for region disabled before checking the region range.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/riscv/tcg/pmp.c | 9 +++++----
>   1 file changed, 5 insertions(+), 4 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 14/18] target/riscv: Return bool from pmp_is_in_range
  2026-08-15 20:37 ` [RFC PATCH 14/18] target/riscv: Return bool from pmp_is_in_range Richard Henderson
@ 2026-08-16 15:09   ` Philippe Mathieu-Daudé
  2026-08-18  3:31   ` Alistair
  1 sibling, 0 replies; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-16 15:09 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 15/8/26 22:37, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/riscv/tcg/pmp.c | 21 ++++++---------------
>   1 file changed, 6 insertions(+), 15 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 12/18] accel/tcg: Replace size with first/last in TCGCPUOps.tlb_fill*
  2026-08-15 20:37 ` [RFC PATCH 12/18] accel/tcg: Replace size with first/last in TCGCPUOps.tlb_fill* Richard Henderson
@ 2026-08-16 15:17   ` Philippe Mathieu-Daudé
  2026-08-21 21:07     ` Richard Henderson
  0 siblings, 1 reply; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-16 15:17 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 15/8/26 22:37, Richard Henderson wrote:
> Expand the interfaces to allow an address within a range to be tested.
> Additionally, where was an edge case of size == 0 which was ambiguous,
> and is now eliminated.
> 
> Only change the functional interface.  Where required by the callee,
> rebuild "size = last - addr + 1" locally.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   include/accel/tcg/cpu-ops.h          | 16 ++++++++++++----
>   target/alpha/cpu.h                   |  2 +-
>   target/arm/internals.h               |  5 +++--
>   target/avr/cpu.h                     |  2 +-
>   target/hppa/cpu.h                    |  5 +++--
>   target/i386/tcg/helper-tcg.h         |  2 +-
>   target/loongarch/tcg/tcg_loongarch.h |  2 +-
>   target/m68k/cpu.h                    |  2 +-
>   target/microblaze/cpu.h              |  2 +-
>   target/mips/tcg/tcg-internal.h       |  2 +-
>   target/or1k/cpu.h                    |  2 +-
>   target/ppc/internal.h                |  2 +-
>   target/riscv/cpu.h                   |  2 +-
>   target/s390x/s390x-internal.h        |  2 +-
>   target/sh4/cpu.h                     |  2 +-
>   target/sparc/cpu.h                   |  2 +-
>   target/tricore/cpu.h                 |  2 +-
>   target/xtensa/cpu.h                  |  2 +-
>   accel/tcg/cputlb.c                   |  7 +++----
>   target/alpha/helper.c                |  2 +-
>   target/arm/tcg/tlb_helper.c          |  5 +++--
>   target/avr/helper.c                  |  2 +-
>   target/hexagon/cpu.c                 |  8 +++++---
>   target/hppa/mem_helper.c             |  6 ++++--
>   target/i386/tcg/system/excp_helper.c |  2 +-
>   target/loongarch/tcg/tlb_helper.c    |  3 ++-
>   target/m68k/helper.c                 |  3 ++-
>   target/microblaze/helper.c           |  2 +-
>   target/mips/tcg/system/tlb_helper.c  |  2 +-
>   target/or1k/mmu.c                    |  2 +-
>   target/ppc/mmu_helper.c              |  2 +-
>   target/riscv/tcg/cpu_helper.c        |  3 ++-
>   target/rx/cpu.c                      |  2 +-
>   target/s390x/tcg/excp_helper.c       |  2 +-
>   target/sh4/helper.c                  |  2 +-
>   target/sparc/mmu_helper.c            |  4 ++--
>   target/tricore/helper.c              |  2 +-
>   target/xtensa/helper.c               |  2 +-
>   38 files changed, 68 insertions(+), 51 deletions(-)


> diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
> index 0ddd898e6e..bfcd9b6159 100644
> --- a/target/hexagon/cpu.c
> +++ b/target/hexagon/cpu.c
> @@ -666,11 +666,13 @@ static const char *access_type_names[] = { "MMU_DATA_LOAD ", "MMU_DATA_STORE",
>   static const char *mmu_idx_names[] = { "MMU_USER_IDX", "MMU_GUEST_IDX",
>                                          "MMU_KERNEL_IDX" };
>   
> -static bool hexagon_tlb_fill(CPUState *cs, vaddr address, int size,
> -                             MMUAccessType access_type, int mmu_idx, bool probe,
> -                             uintptr_t retaddr)
> +static bool hexagon_tlb_fill(CPUState *cs, vaddr address,
> +                             vaddr first, vaddr last,
> +                             MMUAccessType access_type, int mmu_idx,
> +                             bool probe, uintptr_t retaddr)
>   {
>       CPUHexagonState *env = cpu_env(cs);
> +    int size = last - address + 1;

Nitpicking, since we know last >= first, could we use size_t instead?
Otherwise:
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

>       int slot = 0;
>       hwaddr phys;
>       int prot = 0;


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 13/18] target/riscv: Move PMP_AMATCH_OFF check in pmp_hart_has_privs
  2026-08-15 20:37 ` [RFC PATCH 13/18] target/riscv: Move PMP_AMATCH_OFF check in pmp_hart_has_privs Richard Henderson
  2026-08-16  9:21   ` Philippe Mathieu-Daudé
@ 2026-08-18  3:30   ` Alistair
  1 sibling, 0 replies; 38+ messages in thread
From: Alistair @ 2026-08-18  3:30 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On Sat, 2026-08-15 at 13:37 -0700, Richard Henderson wrote:
> Check for region disabled before checking the region range.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/tcg/pmp.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/target/riscv/tcg/pmp.c b/target/riscv/tcg/pmp.c
> index 41b55519a8..5bccc60527 100644
> --- a/target/riscv/tcg/pmp.c
> +++ b/target/riscv/tcg/pmp.c
> @@ -415,6 +415,10 @@ bool pmp_hart_has_privs(CPURISCVState *env,
> hwaddr addr,
>       * from low to high
>       */
>      for (i = 0; i < pmp_regions; i++) {
> +        if (pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg) ==
> PMP_AMATCH_OFF) {
> +            continue;
> +        }
> +
>          s = pmp_is_in_range(env, i, addr);
>          e = pmp_is_in_range(env, i, addr + pmp_size - 1);
>  
> @@ -427,10 +431,7 @@ bool pmp_hart_has_privs(CPURISCVState *env,
> hwaddr addr,
>          }
>  
>          /* fully inside */
> -        const uint8_t a_field =
> -            pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
> -
> -        if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
> +        if (s + e == 2) {
>              /*
>               * If the PMP entry is not off and the address is in
> range,
>               * do the priv check

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 14/18] target/riscv: Return bool from pmp_is_in_range
  2026-08-15 20:37 ` [RFC PATCH 14/18] target/riscv: Return bool from pmp_is_in_range Richard Henderson
  2026-08-16 15:09   ` Philippe Mathieu-Daudé
@ 2026-08-18  3:31   ` Alistair
  1 sibling, 0 replies; 38+ messages in thread
From: Alistair @ 2026-08-18  3:31 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On Sat, 2026-08-15 at 13:37 -0700, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/tcg/pmp.c | 21 ++++++---------------
>  1 file changed, 6 insertions(+), 15 deletions(-)
> 
> diff --git a/target/riscv/tcg/pmp.c b/target/riscv/tcg/pmp.c
> index 5bccc60527..5ea0e5b6c3 100644
> --- a/target/riscv/tcg/pmp.c
> +++ b/target/riscv/tcg/pmp.c
> @@ -299,18 +299,10 @@ void pmp_update_rule_nums(CPURISCVState *env)
>      }
>  }
>  
> -static int pmp_is_in_range(CPURISCVState *env, int pmp_index, hwaddr
> addr)
> +static bool pmp_is_in_range(CPURISCVState *env, int pmp_index,
> hwaddr addr)
>  {
> -    int result = 0;
> -
> -    if ((addr >= env->pmp_state.addr[pmp_index].sa) &&
> -        (addr <= env->pmp_state.addr[pmp_index].ea)) {
> -        result = 1;
> -    } else {
> -        result = 0;
> -    }
> -
> -    return result;
> +    return (addr >= env->pmp_state.addr[pmp_index].sa &&
> +            addr <= env->pmp_state.addr[pmp_index].ea);
>  }
>  
>  /*
> @@ -385,10 +377,7 @@ bool pmp_hart_has_privs(CPURISCVState *env,
> hwaddr addr,
>                          pmp_priv_t *allowed_privs,
>                          privilege_mode_t mode)
>  {
> -    int i = 0;
>      int pmp_size = 0;
> -    hwaddr s = 0;
> -    hwaddr e = 0;
>      uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
>  
>      /* Short cut if no rules */
> @@ -414,7 +403,9 @@ bool pmp_hart_has_privs(CPURISCVState *env,
> hwaddr addr,
>       * 1.10 draft priv spec states there is an implicit order
>       * from low to high
>       */
> -    for (i = 0; i < pmp_regions; i++) {
> +    for (int i = 0; i < pmp_regions; i++) {
> +        bool s, e;
> +
>          if (pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg) ==
> PMP_AMATCH_OFF) {
>              continue;
>          }

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 15/18] target/riscv: Use boolean logic in pmp_hart_has_privs
  2026-08-15 20:37 ` [RFC PATCH 15/18] target/riscv: Use boolean logic in pmp_hart_has_privs Richard Henderson
@ 2026-08-18  3:32   ` Alistair
  0 siblings, 0 replies; 38+ messages in thread
From: Alistair @ 2026-08-18  3:32 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On Sat, 2026-08-15 at 13:37 -0700, Richard Henderson wrote:
> While addition with bool variables isn't wrong, as they promote
> to int, it's odd.  Use normal boolean operators instead.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/tcg/pmp.c | 18 +++++++++---------
>  1 file changed, 9 insertions(+), 9 deletions(-)
> 
> diff --git a/target/riscv/tcg/pmp.c b/target/riscv/tcg/pmp.c
> index 5ea0e5b6c3..fc035c95cf 100644
> --- a/target/riscv/tcg/pmp.c
> +++ b/target/riscv/tcg/pmp.c
> @@ -413,16 +413,8 @@ bool pmp_hart_has_privs(CPURISCVState *env,
> hwaddr addr,
>          s = pmp_is_in_range(env, i, addr);
>          e = pmp_is_in_range(env, i, addr + pmp_size - 1);
>  
> -        /* partially inside */
> -        if ((s + e) == 1) {
> -            qemu_log_mask(LOG_GUEST_ERROR,
> -                          "pmp violation - access is partially
> inside\n");
> -            *allowed_privs = 0;
> -            return false;
> -        }
> -
>          /* fully inside */
> -        if (s + e == 2) {
> +        if (s && e) {
>              /*
>               * If the PMP entry is not off and the address is in
> range,
>               * do the priv check
> @@ -517,6 +509,14 @@ bool pmp_hart_has_privs(CPURISCVState *env,
> hwaddr addr,
>               */
>              return (privs & *allowed_privs) == privs;
>          }
> +
> +        /* partially inside */
> +        if (s || e) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "pmp violation - access is partially
> inside\n");
> +            *allowed_privs = 0;
> +            return false;
> +        }
>      }
>  
>      /* No rule matched */

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 17/18] target/riscv: Pass first/last to get_physical_address_pmp
  2026-08-15 20:37 ` [RFC PATCH 17/18] target/riscv: Pass first/last to get_physical_address_pmp Richard Henderson
@ 2026-08-18  3:35   ` Alistair
  2026-08-18  5:35   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 38+ messages in thread
From: Alistair @ 2026-08-18  3:35 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On Sat, 2026-08-15 at 13:37 -0700, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/tcg/cpu_helper.c | 48 +++++++++++++++++++--------------
> --
>  1 file changed, 26 insertions(+), 22 deletions(-)
> 
> diff --git a/target/riscv/tcg/cpu_helper.c
> b/target/riscv/tcg/cpu_helper.c
> index 3318e82ea7..fb1250a4b8 100644
> --- a/target/riscv/tcg/cpu_helper.c
> +++ b/target/riscv/tcg/cpu_helper.c
> @@ -899,12 +899,13 @@ void riscv_cpu_set_mode(CPURISCVState *env,
> privilege_mode_t newpriv,
>   *
>   * @env: CPURISCVState
>   * @prot: The returned protection attributes
> - * @addr: The physical address to be checked permission
> + * @first, @last: The physical address range to be permission
> checked
>   * @access_type: The type of MMU access
>   * @mode: Indicates current privilege level.
>   */
> -static int get_physical_address_pmp(CPURISCVState *env, int *prot,
> hwaddr addr,
> -                                    int size, MMUAccessType
> access_type,
> +static int get_physical_address_pmp(CPURISCVState *env, int *prot,
> +                                    hwaddr first, hwaddr last,
> +                                    MMUAccessType access_type,
>                                      privilege_mode_t mode)
>  {
>      pmp_priv_t pmp_priv;
> @@ -915,8 +916,8 @@ static int get_physical_address_pmp(CPURISCVState
> *env, int *prot, hwaddr addr,
>          return TRANSLATE_SUCCESS;
>      }
>  
> -    pmp_has_privs = pmp_hart_has_privs(env, addr, size, 1 <<
> access_type,
> -                                       &pmp_priv, mode);
> +    pmp_has_privs = pmp_hart_has_privs(env, first, last - first + 1,
> +                                       1 << access_type, &pmp_priv,
> mode);
>      if (!pmp_has_privs) {
>          *prot = 0;
>          return TRANSLATE_PMP_FAIL;
> @@ -1142,6 +1143,8 @@ static int get_physical_address(CPURISCVState
> *env, hwaddr *physical,
>      base = base_root;
>      for (i = 0; i < levels; i++, ptshift -= ptidxbits) {
>          target_ulong idx;
> +        int pmp_prot, pmp_ret;
> +
>          if (i == 0) {
>              idx = (addr >> (PGSHIFT + ptshift)) &
>                             ((1 << (ptidxbits + widened)) - 1);
> @@ -1174,10 +1177,9 @@ static int get_physical_address(CPURISCVState
> *env, hwaddr *physical,
>              pte_addr = base + idx * ptesize;
>          }
>  
> -        int pmp_prot;
> -        int pmp_ret = get_physical_address_pmp(env, &pmp_prot,
> pte_addr,
> -                                               sxlen_bytes,
> -                                               MMU_DATA_LOAD,
> PRV_S);
> +        pmp_ret = get_physical_address_pmp(env, &pmp_prot, pte_addr,
> +                                           pte_addr + sxlen_bytes -
> 1,
> +                                           MMU_DATA_LOAD, PRV_S);
>          if (pmp_ret != TRANSLATE_SUCCESS) {
>              return TRANSLATE_PMP_FAIL;
>          }
> @@ -1425,7 +1427,8 @@ static int get_physical_address(CPURISCVState
> *env, hwaddr *physical,
>          }
>  
>          pmp_ret = get_physical_address_pmp(env, &pmp_prot, pte_addr,
> -                                           sxlen_bytes,
> MMU_DATA_STORE, PRV_S);
> +                                           pte_addr + sxlen_bytes -
> 1,
> +                                           MMU_DATA_STORE, PRV_S);
>          if (pmp_ret != TRANSLATE_SUCCESS) {
>              return TRANSLATE_PMP_FAIL;
>          }
> @@ -1655,8 +1658,6 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr
> address, vaddr first, vaddr last,
>  {
>      RISCVCPU *cpu = RISCV_CPU(cs);
>      CPURISCVState *env = &cpu->env;
> -    int size = last - address + 1;
> -    vaddr im_address;
>      hwaddr pa = 0;
>      int prot, prot2, prot_pmp;
>      bool pmp_pma_violation = false;
> @@ -1676,7 +1677,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr
> address, vaddr first, vaddr last,
>      pmu_tlb_fill_incr_ctr(cpu, access_type);
>      if (two_stage_lookup) {
>          /* Two stage lookup */
> -        ret = get_physical_address(env, &pa, &prot, address,
> +        ret = get_physical_address(env, &pa, &prot, first,
>                                     &env->guest_phys_fault_addr,
> access_type,
>                                     mmu_idx, true, true, false,
> probe);
>          /*
> @@ -1692,11 +1693,11 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr
> address, vaddr first, vaddr last,
>          qemu_log_mask(CPU_LOG_MMU,
>                        "%s 1st-stage address=%" VADDR_PRIx " ret %d
> physical "
>                        HWADDR_FMT_plx " prot %d\n",
> -                      __func__, address, ret, pa, prot);
> +                      __func__, first, ret, pa, prot);
>  
>          if (ret == TRANSLATE_SUCCESS) {
>              /* Second stage lookup */
> -            im_address = pa;
> +            vaddr im_address = pa;
>  
>              ret = get_physical_address(env, &pa, &prot2, im_address,
> NULL,
>                                         access_type, MMUIdx_U, false,
> true,
> @@ -1711,8 +1712,9 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr
> address, vaddr first, vaddr last,
>              prot &= prot2;
>  
>              if (ret == TRANSLATE_SUCCESS) {
> -                ret = get_physical_address_pmp(env, &prot_pmp, pa,
> -                                               size, access_type,
> mode);
> +                ret = get_physical_address_pmp(env, &prot_pmp,
> +                                               pa, pa + (last -
> first),
> +                                               access_type, mode);
>                  tlb_size = pmp_get_tlb_size(env, pa);
>  
>                  qemu_log_mask(CPU_LOG_MMU,
> @@ -1736,18 +1738,19 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr
> address, vaddr first, vaddr last,
>          }
>      } else {
>          /* Single stage lookup */
> -        ret = get_physical_address(env, &pa, &prot, address, NULL,
> +        ret = get_physical_address(env, &pa, &prot, first, NULL,
>                                     access_type, mmu_idx, true,
> false, false,
>                                     probe);
>  
>          qemu_log_mask(CPU_LOG_MMU,
>                        "%s address=%" VADDR_PRIx " ret %d physical "
>                        HWADDR_FMT_plx " prot %d\n",
> -                      __func__, address, ret, pa, prot);
> +                      __func__, first, ret, pa, prot);
>  
>          if (ret == TRANSLATE_SUCCESS) {
> -            ret = get_physical_address_pmp(env, &prot_pmp, pa,
> -                                           size, access_type, mode);
> +            ret = get_physical_address_pmp(env, &prot_pmp,
> +                                           pa, pa + (last - first),
> +                                           access_type, mode);
>              tlb_size = pmp_get_tlb_size(env, pa);
>  
>              qemu_log_mask(CPU_LOG_MMU,
> @@ -1764,7 +1767,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr
> address, vaddr first, vaddr last,
>      }
>  
>      if (ret == TRANSLATE_SUCCESS) {
> -        tlb_set_page(cs, address & ~(tlb_size - 1), pa & ~(tlb_size
> - 1),
> +        tlb_set_page(cs, address & ~(tlb_size - 1),
> +                     (pa + (address - first)) & ~(tlb_size - 1),
>                       prot, mmu_idx, tlb_size);
>          return true;
>      } else if (probe) {

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 18/18] target/riscv: Pass first/last to pmp_hart_has_privs
  2026-08-15 20:37 ` [RFC PATCH 18/18] target/riscv: Pass first/last to pmp_hart_has_privs Richard Henderson
@ 2026-08-18  3:36   ` Alistair
  0 siblings, 0 replies; 38+ messages in thread
From: Alistair @ 2026-08-18  3:36 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On Sat, 2026-08-15 at 13:37 -0700, Richard Henderson wrote:
> This eliminates an ambiguity with size == 0 and also
> aligns with the underlying hw representation.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/tcg/pmp.h        |  5 ++---
>  target/riscv/tcg/cpu_helper.c |  2 +-
>  target/riscv/tcg/pmp.c        | 24 ++++--------------------
>  3 files changed, 7 insertions(+), 24 deletions(-)
> 
> diff --git a/target/riscv/tcg/pmp.h b/target/riscv/tcg/pmp.h
> index 4c95c2767a..eacb5b5349 100644
> --- a/target/riscv/tcg/pmp.h
> +++ b/target/riscv/tcg/pmp.h
> @@ -70,9 +70,8 @@ typedef struct {
>  
>  typedef struct CPUArchState CPURISCVState;
>  
> -bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
> -                        int size, pmp_priv_t privs,
> -                        pmp_priv_t *allowed_privs,
> +bool pmp_hart_has_privs(CPURISCVState *env, hwaddr first, hwaddr
> last,
> +                        pmp_priv_t privs, pmp_priv_t *allowed_privs,
>                          privilege_mode_t mode);
>  uint64_t pmp_get_tlb_size(CPURISCVState *env, hwaddr addr);
>  void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index);
> diff --git a/target/riscv/tcg/cpu_helper.c
> b/target/riscv/tcg/cpu_helper.c
> index fb1250a4b8..7ef5ab5277 100644
> --- a/target/riscv/tcg/cpu_helper.c
> +++ b/target/riscv/tcg/cpu_helper.c
> @@ -916,7 +916,7 @@ static int get_physical_address_pmp(CPURISCVState
> *env, int *prot,
>          return TRANSLATE_SUCCESS;
>      }
>  
> -    pmp_has_privs = pmp_hart_has_privs(env, first, last - first + 1,
> +    pmp_has_privs = pmp_hart_has_privs(env, first, last,
>                                         1 << access_type, &pmp_priv,
> mode);
>      if (!pmp_has_privs) {
>          *prot = 0;
> diff --git a/target/riscv/tcg/pmp.c b/target/riscv/tcg/pmp.c
> index fc035c95cf..d3cbb2cb2e 100644
> --- a/target/riscv/tcg/pmp.c
> +++ b/target/riscv/tcg/pmp.c
> @@ -372,12 +372,10 @@ static bool
> pmp_hart_has_privs_default(CPURISCVState *env, pmp_priv_t privs,
>   * pmpcfg but is not acted upon during access checks. Cache
> attributes
>   * have no functional impact in QEMU emulation.
>   */
> -bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
> -                        int size, pmp_priv_t privs,
> -                        pmp_priv_t *allowed_privs,
> +bool pmp_hart_has_privs(CPURISCVState *env, hwaddr first, hwaddr
> last,
> +                        pmp_priv_t privs, pmp_priv_t *allowed_privs,
>                          privilege_mode_t mode)
>  {
> -    int pmp_size = 0;
>      uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
>  
>      /* Short cut if no rules */
> @@ -385,20 +383,6 @@ bool pmp_hart_has_privs(CPURISCVState *env,
> hwaddr addr,
>          return pmp_hart_has_privs_default(env, privs, allowed_privs,
> mode);
>      }
>  
> -    if (size == 0) {
> -        if (riscv_cpu_cfg(env)->mmu) {
> -            /*
> -             * If size is unknown (0), assume that all bytes
> -             * from addr to the end of the page will be accessed.
> -             */
> -            pmp_size = -(addr | TARGET_PAGE_MASK);
> -        } else {
> -            pmp_size = 2 << riscv_cpu_mxl(env);
> -        }
> -    } else {
> -        pmp_size = size;
> -    }
> -
>      /*
>       * 1.10 draft priv spec states there is an implicit order
>       * from low to high
> @@ -410,8 +394,8 @@ bool pmp_hart_has_privs(CPURISCVState *env,
> hwaddr addr,
>              continue;
>          }
>  
> -        s = pmp_is_in_range(env, i, addr);
> -        e = pmp_is_in_range(env, i, addr + pmp_size - 1);
> +        s = pmp_is_in_range(env, i, first);
> +        e = pmp_is_in_range(env, i, last);
>  
>          /* fully inside */
>          if (s && e) {

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 17/18] target/riscv: Pass first/last to get_physical_address_pmp
  2026-08-15 20:37 ` [RFC PATCH 17/18] target/riscv: Pass first/last to get_physical_address_pmp Richard Henderson
  2026-08-18  3:35   ` Alistair
@ 2026-08-18  5:35   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-18  5:35 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel
  Cc: qemu-arm, qemu-riscv, Daniel Henrique Barboza

On 15/8/26 22:37, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/riscv/tcg/cpu_helper.c | 48 +++++++++++++++++++----------------
>   1 file changed, 26 insertions(+), 22 deletions(-)
> 
> diff --git a/target/riscv/tcg/cpu_helper.c b/target/riscv/tcg/cpu_helper.c
> index 3318e82ea7..fb1250a4b8 100644
> --- a/target/riscv/tcg/cpu_helper.c
> +++ b/target/riscv/tcg/cpu_helper.c
> @@ -899,12 +899,13 @@ void riscv_cpu_set_mode(CPURISCVState *env, privilege_mode_t newpriv,
>    *
>    * @env: CPURISCVState
>    * @prot: The returned protection attributes
> - * @addr: The physical address to be checked permission
> + * @first, @last: The physical address range to be permission checked
>    * @access_type: The type of MMU access
>    * @mode: Indicates current privilege level.
>    */
> -static int get_physical_address_pmp(CPURISCVState *env, int *prot, hwaddr addr,
> -                                    int size, MMUAccessType access_type,
> +static int get_physical_address_pmp(CPURISCVState *env, int *prot,
> +                                    hwaddr first, hwaddr last,
> +                                    MMUAccessType access_type,
>                                       privilege_mode_t mode)

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

Orthogonal, it would be clearer if get_physical_address_pmp & co
were returning an enum.



^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 16/18] target/riscv: Recognize watchpoints with first/last
  2026-08-15 20:37 ` [RFC PATCH 16/18] target/riscv: Recognize watchpoints with first/last Richard Henderson
@ 2026-08-18  5:43   ` Philippe Mathieu-Daudé
  2026-08-18 23:47     ` Richard Henderson
  0 siblings, 1 reply; 38+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-18  5:43 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 15/8/26 22:37, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   target/riscv/tcg/cpu_helper.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/target/riscv/tcg/cpu_helper.c b/target/riscv/tcg/cpu_helper.c
> index 11f2654da1..3318e82ea7 100644
> --- a/target/riscv/tcg/cpu_helper.c
> +++ b/target/riscv/tcg/cpu_helper.c
> @@ -1784,8 +1784,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, vaddr last,
>            * Otherwise we'll throw a debug exception and execution
>            * will continue elsewhere.
>            */
> -        cpu_check_watchpoint(cs, address, size, MEMTXATTRS_UNSPECIFIED,
> -                             wp_access, retaddr);
> +        cpu_check_watchpoint(cs, first, last - first + 1,
> +                             MEMTXATTRS_UNSPECIFIED, wp_access, retaddr);

Maybe squash in "accel/tcg: Replace size with first/last in 
TCGCPUOps.tlb_fill" or re-order just after?
I'm confused by this single WP change in midle of PMP API ones.
Anyway,
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>



^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 16/18] target/riscv: Recognize watchpoints with first/last
  2026-08-18  5:43   ` Philippe Mathieu-Daudé
@ 2026-08-18 23:47     ` Richard Henderson
  0 siblings, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2026-08-18 23:47 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 8/17/26 22:43, Philippe Mathieu-Daudé wrote:
> On 15/8/26 22:37, Richard Henderson wrote:
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>>   target/riscv/tcg/cpu_helper.c | 4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/target/riscv/tcg/cpu_helper.c b/target/riscv/tcg/cpu_helper.c
>> index 11f2654da1..3318e82ea7 100644
>> --- a/target/riscv/tcg/cpu_helper.c
>> +++ b/target/riscv/tcg/cpu_helper.c
>> @@ -1784,8 +1784,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, vaddr first, 
>> vaddr last,
>>            * Otherwise we'll throw a debug exception and execution
>>            * will continue elsewhere.
>>            */
>> -        cpu_check_watchpoint(cs, address, size, MEMTXATTRS_UNSPECIFIED,
>> -                             wp_access, retaddr);
>> +        cpu_check_watchpoint(cs, first, last - first + 1,
>> +                             MEMTXATTRS_UNSPECIFIED, wp_access, retaddr);
> 
> Maybe squash in "accel/tcg: Replace size with first/last in TCGCPUOps.tlb_fill"

No, because that one explicitly makes no other code changes.


> or re-order just after?

Ok.

> I'm confused by this single WP change in middle of PMP API ones.
It's just before the last use of size is removed.  :-/


r~


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFC PATCH 12/18] accel/tcg: Replace size with first/last in TCGCPUOps.tlb_fill*
  2026-08-16 15:17   ` Philippe Mathieu-Daudé
@ 2026-08-21 21:07     ` Richard Henderson
  0 siblings, 0 replies; 38+ messages in thread
From: Richard Henderson @ 2026-08-21 21:07 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel; +Cc: qemu-arm, qemu-riscv

On 8/16/26 08:17, Philippe Mathieu-Daudé wrote:
>> diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
>> index 0ddd898e6e..bfcd9b6159 100644
>> --- a/target/hexagon/cpu.c
>> +++ b/target/hexagon/cpu.c
>> @@ -666,11 +666,13 @@ static const char *access_type_names[] = { "MMU_DATA_LOAD ", 
>> "MMU_DATA_STORE",
>>   static const char *mmu_idx_names[] = { "MMU_USER_IDX", "MMU_GUEST_IDX",
>>                                          "MMU_KERNEL_IDX" };
>> -static bool hexagon_tlb_fill(CPUState *cs, vaddr address, int size,
>> -                             MMUAccessType access_type, int mmu_idx, bool probe,
>> -                             uintptr_t retaddr)
>> +static bool hexagon_tlb_fill(CPUState *cs, vaddr address,
>> +                             vaddr first, vaddr last,
>> +                             MMUAccessType access_type, int mmu_idx,
>> +                             bool probe, uintptr_t retaddr)
>>   {
>>       CPUHexagonState *env = cpu_env(cs);
>> +    int size = last - address + 1;
> 
> Nitpicking, since we know last >= first, could we use size_t instead?
> Otherwise:
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

Certainly I won't change the type in this patch.

It's only used by logging/tracing, so I don't really care, but you may, after the fact.


r~


^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2026-08-21 21:07 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-15 20:37 [RFC PATCH 00/18] accel/tcg: Change tlb_fill/probe_access to (addr, first, last) tuple Richard Henderson
2026-08-15 20:37 ` [RFC PATCH 01/18] target/arm: Imply probe from allocation_tag_mem_probe Richard Henderson
2026-08-15 20:37 ` [RFC PATCH 02/18] target/arm: Simplify invalid page test in allocation_tag_mem_internal Richard Henderson
2026-08-15 20:37 ` [RFC PATCH 03/18] target/arm: Return struct from allocation_tag_mem_internal Richard Henderson
2026-08-15 20:37 ` [RFC PATCH 04/18] target/arm: Generalize probe argument to allocation_tag_mem_internal Richard Henderson
2026-08-15 20:37 ` [RFC PATCH 05/18] target/arm: Probe second page earlier in allocation_tag_mem_internal Richard Henderson
2026-08-15 20:37 ` [RFC PATCH 06/18] accel/tcg: Drop fault_size from user-only probe_access_internal Richard Henderson
2026-08-16  9:05   ` Philippe Mathieu-Daudé
2026-08-15 20:37 ` [RFC PATCH 07/18] accel/tcg: Replace size with first/last in probe_access_full Richard Henderson
2026-08-16  9:09   ` Philippe Mathieu-Daudé
2026-08-16  9:11     ` Philippe Mathieu-Daudé
2026-08-15 20:37 ` [RFC PATCH 08/18] accel/tcg: Replace size with first/last in probe_access_flags Richard Henderson
2026-08-16  9:18   ` Philippe Mathieu-Daudé
2026-08-15 20:37 ` [RFC PATCH 09/18] accel/tcg: Allow phost to be NULL " Richard Henderson
2026-08-16  9:18   ` Philippe Mathieu-Daudé
2026-08-15 20:37 ` [RFC PATCH 10/18] accel/tcg: Replace size with first/last in probe_access_internal Richard Henderson
2026-08-16  9:19   ` Philippe Mathieu-Daudé
2026-08-15 20:37 ` [RFC PATCH 11/18] accel/tcg: Replace size with first/last in tlb_fill_align Richard Henderson
2026-08-16  9:20   ` Philippe Mathieu-Daudé
2026-08-15 20:37 ` [RFC PATCH 12/18] accel/tcg: Replace size with first/last in TCGCPUOps.tlb_fill* Richard Henderson
2026-08-16 15:17   ` Philippe Mathieu-Daudé
2026-08-21 21:07     ` Richard Henderson
2026-08-15 20:37 ` [RFC PATCH 13/18] target/riscv: Move PMP_AMATCH_OFF check in pmp_hart_has_privs Richard Henderson
2026-08-16  9:21   ` Philippe Mathieu-Daudé
2026-08-18  3:30   ` Alistair
2026-08-15 20:37 ` [RFC PATCH 14/18] target/riscv: Return bool from pmp_is_in_range Richard Henderson
2026-08-16 15:09   ` Philippe Mathieu-Daudé
2026-08-18  3:31   ` Alistair
2026-08-15 20:37 ` [RFC PATCH 15/18] target/riscv: Use boolean logic in pmp_hart_has_privs Richard Henderson
2026-08-18  3:32   ` Alistair
2026-08-15 20:37 ` [RFC PATCH 16/18] target/riscv: Recognize watchpoints with first/last Richard Henderson
2026-08-18  5:43   ` Philippe Mathieu-Daudé
2026-08-18 23:47     ` Richard Henderson
2026-08-15 20:37 ` [RFC PATCH 17/18] target/riscv: Pass first/last to get_physical_address_pmp Richard Henderson
2026-08-18  3:35   ` Alistair
2026-08-18  5:35   ` Philippe Mathieu-Daudé
2026-08-15 20:37 ` [RFC PATCH 18/18] target/riscv: Pass first/last to pmp_hart_has_privs Richard Henderson
2026-08-18  3:36   ` Alistair

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.