On 6/16/2026 12:33 PM, ZhengXiang Qin wrote:
check_zicbom_access() probes the cache block with MMU_DATA_LOAD and
returns early for any result other than TLB_INVALID_MASK. This treats
TLB_MMIO as a successful load access.
For Zicbom, a TLB_MMIO result does not provide a RAM host pointer for the
cache block operation and should not be treated as a successful access.
Raise a store/AMO access fault instead of silently completing the CBO
instruction.
This fixes sv39_zicbom_exceptions_Smode.S, where cbo.clean/cbo.flush and
cbo.inval access a block mapped to a physical address without PMA
permissions. Before this change, the CBO instruction completed and the
following addi was executed.
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3501
Signed-off-by: ZhengXiang Qin <[email protected]>
---
Thanks for taking care of this one.
Without this patch:
$ ./build/qemu-system-riscv64 -d in_asm,int,mmu,unimp,cpu,fpu,vpu,exec,nochain \
-D sv39_zicbom_access_fault.elf.trace.log -nographic -semihosting
-icount shift=1 \
-machine virt -cpu max,pmu-mask=0xfffffff8 \
-bios ~/Downloads/sv39_zicbom_access_fault.elf
RVCP-SUMMARY: TEST FAILED - Test File "sv39_zicbom_exceptions_Smode.S"
RVCP: DEBUG INFORMATION FOLLOWS
RVCP: Test Info: "Mismatch during cbo.clean in Test Case 1!"
RVCP: Instruction: 0x0017a00f
RVCP: Approximate address (failure may be slightly after this):
0x0000000080000250
RVCP: Register: x12
RVCP: Bad Value: 0x0000000000000814
RVCP: Expected Value: 0x0000000000000810
RVCP: END OF DEBUG INFORMATION
With the patch, same cmd line:
$ ./build/qemu-system-riscv64 (...)
RVCP-SUMMARY: TEST PASSED - Test File "sv39_zicbom_exceptions_Smode.S"
Reviewed-by: Daniel Henrique Barboza <[email protected]>
Tested-by: Daniel Henrique Barboza <[email protected]>
target/riscv/op_helper.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 81873014cb..6c9bd5c102 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -218,6 +218,7 @@ static void check_zicbom_access(CPURISCVState *env,
void *phost;
int ret;
+ target_ulong fault_addr = address;
/* Mask off low-bits to align-down to the cache-block. */
address &= ~(cbomlen - 1);
@@ -235,6 +236,10 @@ static void check_zicbom_access(CPURISCVState *env,
*/
ret = probe_access_flags(env, address, cbomlen, MMU_DATA_LOAD,
mmu_idx, true, &phost, ra);
+ if (ret == TLB_MMIO) {
+ env->badaddr = fault_addr;
+ riscv_raise_exception(env, RISCV_EXCP_STORE_AMO_ACCESS_FAULT, ra);
+ }
if (ret != TLB_INVALID_MASK) {
/* Success: readable */
return;