On Thu, 2026-08-20 at 21:03 -0700, Richard Henderson wrote:
> 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]>

Reviewed-by: Alistair Francis <[email protected]>

Alistair

> ---
>  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 63a51f2b48..18840336cb 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)
> @@ -433,16 +436,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) {
>              vext_continuous_ldst_host(env, ldst_host, vd, evl, env-
> >vstart,
>                                        host, esz, is_load);
> @@ -462,6 +456,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,
> @@ -474,16 +482,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);
> @@ -495,7 +508,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;
> @@ -725,7 +737,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;
> @@ -823,6 +855,7 @@ ProbeSuccess:
>          }
>      }
>  
> + tail:
>      env->vstart = 0;
>      vext_set_tail_elems_1s(env->vl, vd, desc, 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;

Reply via email to