Re: [PATCH 1/3] target/riscv: Fix RCsc ordering of Zalasr store-release
Daniel Henrique Barboza <[email protected]>
| Newsgroups | org.nongnu.qemu-riscv,org.nongnu.qemu-arm,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
On 8/21/2026 3:40 AM, LIU Zhiwei wrote:
> The Zalasr load-acquire instructions carry an acquire-RCsc annotation
> and the store-release instructions carry a release-RCsc annotation;
> the extension has no RCpc variant (Zalasr specification, chapter 2).
>
> Per Rule 7 of the RVWMO preserved program order rules ("a and b both
> have RCsc annotations"), a Zalasr store-release must precede any
> subsequent RCsc memory operation of the same hart in the global
> memory order. In particular "sw.rl X=1; lw.aq r1=Y" must be ordered,
> which is what forbids the [0,0] outcome of a Store Buffering litmus
> test that runs this pair on two harts.
>
> gen_store_release() only emits a barrier before the store, which
> orders the memory operations preceding the store before the store
> itself (Rule 6, release semantics). Nothing prevents the store from
> being reordered with the memory operations that follow it, so under
> MTTCG the host CPU may execute the load-acquire that immediately
> follows a store-release before the store has left its store buffer:
>
> * on an x86 host (TSO), store-load is the only reordering the
> hardware may perform, and it is exactly the ordering that is
> missing here;
>
> * on an aarch64 host, no dmb follows the store either.
>
> The defect is easily observed with a bare-metal Store Buffering
> litmus test on a 4 vCPU guest: "sw.rl X=1; lw.aq r1=Y" on hart 0 and
> "sw.rl Y=1; lw.aq r2=X" on hart 1 produce the architecturally
> forbidden [0,0] result in 89881 out of 100000 iterations.
>
> Fix this by emitting a full barrier after the store as well, which
> mirrors the FENCE translation. The TCG_MO_ST_LD bit included in
> TCG_MO_ALL makes the x86 backend emit a serializing lock-prefixed
> instruction after the store, draining the store buffer before any
> subsequent load executes, and the aarch64 backend emit dmb ish; the
> store therefore becomes globally visible before any subsequent memory
> operation of the same vCPU, and Rule 7 is satisfied. This is
> stronger than Rule 7 strictly requires, since the barrier also orders
> the store with respect to subsequent non-RCsc operations, but this
> matches how QEMU already implements FENCE and keeps the fix simple.
>
> The load-acquire side needs no change: the barrier emitted after the
> load already orders it with all subsequent memory operations, which
> covers Rule 5 and the remaining Rule 7 combinations (load-load and
> load-store).
>
> Signed-off-by: LIU Zhiwei <[email protected]>
> Co-authored-by: TANG TianCheng <[email protected]>
> Signed-off-by: TANG TianCheng <[email protected]>
> ---
Reviewed-by: Daniel Henrique Barboza <[email protected]>
> target/riscv/tcg/insn_trans/trans_rvzalasr.c.inc | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/target/riscv/tcg/insn_trans/trans_rvzalasr.c.inc b/target/riscv/tcg/insn_trans/trans_rvzalasr.c.inc
> index 79b0b2c63b..28d9b13c55 100644
> --- a/target/riscv/tcg/insn_trans/trans_rvzalasr.c.inc
> +++ b/target/riscv/tcg/insn_trans/trans_rvzalasr.c.inc
> @@ -86,6 +86,14 @@ static bool gen_store_release(DisasContext *ctx, arg_sb_aqrl *a, MemOp memop)
> tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL | bar);
>
> tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
> +
> + /*
> + * Zalasr annotations are always RCsc: per RVWMO Rule 7, the store
> + * must also be ordered before any subsequent memory operation,
> + * e.g. a load-acquire in a Store Buffering litmus test. The
> + * barrier above only orders previous memory ops before the store.
> + */
> + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
> return true;
> }
>