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