helper_cbo_zero() aligns the address down to the cache-block size before
probe_write(), and accel/tcg/user-exec.c:probe_access_internal() reports
that aligned address to cpu_loop_exit_sigsegv(), so a store fault from a
legal cbo.zero (e.g. on a read-only page) reports the aligned block base
as si_addr instead of the rs1 value supplied by the program.  Native
RISC-V Linux reports the exact rs1 address.  Keep the original address
and use it when the fault is reported.

Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4151
Signed-off-by: wangyang <[email protected]>
---
 accel/tcg/user-exec.c         |  7 ++++++-
 include/hw/core/cpu.h         |  2 ++
 target/riscv/tcg/cpu_helper.c | 21 ++++++++++++++++++---
 target/riscv/tcg/op_helper.c  |  5 +++++
 4 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index a35aca78893..13c38458111 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -787,7 +787,12 @@ static int probe_access_internal(CPUArchState *env, vaddr 
addr,
         return TLB_INVALID_MASK;
     }
 
-    cpu_loop_exit_sigsegv(env_cpu(env), addr, access_type, maperr, ra);
+    CPUState *cpu = env_cpu(env);
+    if (cpu->exception_addr_valid) {
+        addr = cpu->exception_addr;
+        cpu->exception_addr_valid = false;
+    }
+    cpu_loop_exit_sigsegv(cpu, addr, access_type, maperr, ra);
 }
 
 int probe_access_flags(CPUArchState *env, vaddr addr, int size,
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index b54035fb13b..2799d3d6701 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -560,6 +560,8 @@ struct CPUState {
     uint32_t tcg_cflags;
     uint32_t halted;
     int32_t exception_index;
+    vaddr exception_addr;
+    bool exception_addr_valid;
 
     bool vcpu_dirty;
     AccelCPUState *accel;
diff --git a/target/riscv/tcg/cpu_helper.c b/target/riscv/tcg/cpu_helper.c
index 07d92226527..73db04545e1 100644
--- a/target/riscv/tcg/cpu_helper.c
+++ b/target/riscv/tcg/cpu_helper.c
@@ -1537,7 +1537,12 @@ static void raise_mmu_exception(CPURISCVState *env, 
target_ulong address,
     default:
         g_assert_not_reached();
     }
-    env->badaddr = address;
+    if (cs->exception_addr_valid) {
+        env->badaddr = cs->exception_addr;
+        cs->exception_addr_valid = false;
+    } else {
+        env->badaddr = address;
+    }
     env->two_stage_lookup = two_stage;
     env->two_stage_indirect_lookup = two_stage_indirect;
 }
@@ -1588,7 +1593,12 @@ void riscv_cpu_do_transaction_failed(CPUState *cs, 
hwaddr physaddr,
         cs->exception_index = RISCV_EXCP_INST_ACCESS_FAULT;
     }
 
-    env->badaddr = addr;
+    if (cs->exception_addr_valid) {
+        env->badaddr = cs->exception_addr;
+        cs->exception_addr_valid = false;
+    } else {
+        env->badaddr = addr;
+    }
     env->two_stage_lookup = mmuidx_2stage(mmu_idx);
     env->two_stage_indirect_lookup = false;
     cpu_loop_exit_restore(cs, retaddr);
@@ -1621,7 +1631,12 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr 
addr,
     default:
         g_assert_not_reached();
     }
-    env->badaddr = addr;
+    if (cs->exception_addr_valid) {
+        env->badaddr = cs->exception_addr;
+        cs->exception_addr_valid = false;
+    } else {
+        env->badaddr = addr;
+    }
     env->two_stage_lookup = mmuidx_2stage(mmu_idx);
     env->two_stage_indirect_lookup = false;
     cpu_loop_exit_restore(cs, retaddr);
diff --git a/target/riscv/tcg/op_helper.c b/target/riscv/tcg/op_helper.c
index 11cac77e3fe..7f1107905f5 100644
--- a/target/riscv/tcg/op_helper.c
+++ b/target/riscv/tcg/op_helper.c
@@ -171,9 +171,13 @@ void helper_cbo_zero(CPURISCVState *env, target_ulong 
address)
     int mmu_idx = riscv_env_mmu_index(env, false);
     uintptr_t ra = GETPC();
     void *mem;
+    CPUState *cs = env_cpu(env);
 
     check_zicbo_envcfg(env, MENVCFG_CBZE, ra);
 
+    cs->exception_addr = address;
+    cs->exception_addr_valid = true;
+
     /* Mask off low-bits to align-down to the cache-block. */
     address &= ~(cbozlen - 1);
 
@@ -201,6 +205,7 @@ void helper_cbo_zero(CPURISCVState *env, target_ulong 
address)
             cpu_stb_mmuidx_ra(env, address + i, 0, mmu_idx, ra);
         }
     }
+    cs->exception_addr_valid = false;
 }
 
 /*
-- 
2.43.0

Reply via email to