[PATCH 4/7] linux-user/riscv: preserve rs1 address for cbo.zero fault reporting

"wangyang" <[email protected]>
Newsgroups org.nongnu.qemu-riscv,org.nongnu.qemu-devel
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.