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 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;
-- 
2.43.0


Reply via email to