* [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.