[PATCH 08/23] target/riscv: Move misalignment check out of vext_page_ldst_us
Richard Henderson <[email protected]>
| Newsgroups | org.nongnu.qemu-riscv,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Alignment faults generally have precedence over page faults, therefore we need to test for that before probing pages. Signed-off-by: Richard Henderson <[email protected]> --- target/riscv/tcg/vector_helper.c | 62 +++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/target/riscv/tcg/vector_helper.c b/target/riscv/tcg/vector_helper.c index 79c1d77a14..12ef020840 100644 --- a/target/riscv/tcg/vector_helper.c +++ b/target/riscv/tcg/vector_helper.c @@ -31,6 +31,9 @@ #include "tcg/tcg-gvec-desc.h" #include "internals.h" #include "vector_internals.h" +#ifdef CONFIG_USER_ONLY +#include "user/cpu_loop.h" +#endif #include <math.h> static target_ulong vtype_reserved(CPURISCVState *env, target_ulong vtype) @@ -425,16 +428,7 @@ vext_page_ldst_us(CPURISCVState *env, void *vd, target_ulong addr, probe_pages(env, addr, size, ra, access_type, mmu_index, &host, &flags, true); - bool misaligned = addr & (esz - 1); - - /* - * Allow the host fast-pash when: - * 1. Page permission/pmp/watchpoint are checked and we have a contigous - * host mapping. - * 2. Zicclsm is enabled or load/store is not a misaligned access. - * Otherwise, we will fall back to the slow TLB-path. - */ - if (flags == 0 && (riscv_cpu_cfg(env)->ext_zicclsm || !misaligned)) { + if (flags == 0) { if (nf == 1) { ldst_host(vd, host, env->vstart, evl); } else { @@ -453,6 +447,20 @@ vext_page_ldst_us(CPURISCVState *env, void *vd, target_ulong addr, } } +static void vext_test_alignment(CPURISCVState *env, vaddr addr, uint32_t esz, + MMUAccessType access_type, int mmu_index, + uintptr_t ra) +{ + if (!riscv_cpu_cfg(env)->ext_zicclsm && (addr & (esz - 1)) != 0) { +#ifdef CONFIG_USER_ONLY + cpu_loop_exit_sigbus(env_cpu(env), addr, access_type, ra); +#else + riscv_cpu_do_unaligned_access(env_cpu(env), addr, access_type, + mmu_index, ra); +#endif + } +} + static inline QEMU_ALWAYS_INLINE void vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, vext_ldst_elem_fn_tlb *ldst_tlb, @@ -466,16 +474,21 @@ vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, uint32_t esz = 1 << log2_esz; uint32_t msize = nf * esz; int mmu_index = riscv_env_mmu_index(env, false); + MMUAccessType access_type = is_load ? MMU_DATA_LOAD : MMU_DATA_STORE; VSTART_CHECK_EARLY_EXIT(env, evl); + addr = base + env->vstart * msize; + + /* Recognize alignment fault before memory protection fault. */ + vext_test_alignment(env, addr, esz, access_type, mmu_index, ra); + #if defined(CONFIG_USER_ONLY) /* * For data sizes <= 6 bytes we get better performance * by simply calling ldst_tlb. */ if (nf == 1 && (evl << log2_esz) <= 6) { - addr = base + (env->vstart << log2_esz); for (uint32_t i = env->vstart; i < evl; env->vstart = ++i, addr += esz) { ldst_tlb(env, adjust_addr(env, addr), i, vd, ra); @@ -489,7 +502,6 @@ vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, #endif /* Calculate the page range of first page */ - addr = base + ((env->vstart * nf) << log2_esz); page_split = -(addr | TARGET_PAGE_MASK); /* Get number of elements */ elems = page_split / msize; @@ -723,7 +735,27 @@ vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env, VSTART_CHECK_EARLY_EXIT(env, env->vl); + /* Search for the first active element. */ + if (!vm) { + for (i = env->vstart; i < env->vl; ++i) { + if (vext_elem_mask(v0, i)) { + break; + } + if (vma) { + vext_set_nf_elems_1s(vd, i, nf, esz, max_elems); + } + } + if (i == env->vl) { + goto tail; + } + env->vstart = i; + } + addr = base + ((env->vstart * nf) << log2_esz); + + /* Recognize alignment fault before memory protection fault. */ + vext_test_alignment(env, addr, esz, MMU_DATA_LOAD, mmu_index, ra); + page_split = -(addr | TARGET_PAGE_MASK); /* Get number of elements */ elems = page_split / msize; @@ -821,6 +853,7 @@ ProbeSuccess: } } + tail: env->vstart = 0; if (vma) { vext_set_tail_elems_1s(env->vl, vd, nf, esz, max_elems); @@ -866,9 +899,14 @@ vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, uint32_t evl = nf * max_elems; uint32_t esz = 1 << log2_esz; int mmu_index = riscv_env_mmu_index(env, false); + MMUAccessType access_type = is_load ? MMU_DATA_LOAD : MMU_DATA_STORE; /* Calculate the page range of first page */ addr = base + (env->vstart << log2_esz); + + /* Recognize alignment fault before memory protection fault. */ + vext_test_alignment(env, addr, esz, access_type, mmu_index, ra); + page_split = -(addr | TARGET_PAGE_MASK); /* Get number of elements */ elems = page_split / esz; -- 2.43.0