From: imaginos <imaginos32@gmail.com>
To: Palmer Dabbelt <palmer@dabbelt.com>,
Alistair Francis <alistair.francis@wdc.com>
Cc: Weiwei Li <liwei1518@gmail.com>,
Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>,
Liu Zhiwei <zhiwei_liu@linux.alibaba.com>,
Chao Liu <chao.liu.zevorn@gmail.com>,
qemu-riscv@nongnu.org, qemu-devel@nongnu.org,
imaginos <imaginos32@gmail.com>
Subject: [PATCH v2] target/riscv: check G-stage write permission for VS-stage A/D updates
Date: Sun, 5 Jul 2026 16:02:10 +0200 [thread overview]
Message-ID: <20260705140508.17692-1-imaginos32@gmail.com> (raw)
In-Reply-To: <v1-Message-ID>
During a two-stage (VS-stage + G-stage) page-table walk with hardware
A/D updating enabled (Svadu / menvcfg.ADUE), a store that reaches a
VS-stage leaf PTE whose accessed or dirty bit is clear triggers a
hardware write-back of those bits into the PTE. That write-back is an
implicit store to the PTE's guest-physical address, so it must be
permitted by G-stage.
Fix this by re-running the G-stage translation of the guest PTE's
address with store semantics. get_physical_address() then also checks
that G-stage permits the guest PTE to be written, and raises a
guest-page store fault when it does not.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3426
Signed-off-by: imaginos <imaginos32@gmail.com>
---
target/riscv/cpu_helper.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
v2:
Reword an incomplete sentence in the code comment.
Verified against Spike, with this patch QEMU's
reported values match Spike.
Spike (reference): QEMU, before this patch:
mcause 0x17 mcause 0x17
mtval 0x80000000 mtval 0x80000000
mtval2 0x20001004 mtval2 0x20000000
mtinst 0x3020 mtinst 0x6a704073
If I've misread any of the A/D-update semantics here, I'd appreciate the
correction.
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 2db07f5dfb..eb34ba19e1 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1370,6 +1370,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
int ptshift;
target_ulong pte;
hwaddr pte_addr;
+ hwaddr pte_gpa = 0;
const hwaddr base_root = base;
const bool be = mo_endian_env(env) == MO_BE;
int i;
@@ -1407,6 +1408,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
}
pte_addr = vbase + idx * ptesize;
+ pte_gpa = base + idx * ptesize;
} else {
pte_addr = base + idx * ptesize;
}
@@ -1661,6 +1663,28 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
return TRANSLATE_FAIL;
}
+ /*
+ * The implicit store that writes updated A/D bits back to a VS-stage
+ * (first-stage) PTE must itself be permitted by G-stage. Re-run the
+ * second-stage translation of the PTE's guest-physical address with
+ * store semantics. If G-stage denies write, raise G-stage store fault
+ * against the PTE address.
+ */
+ if (two_stage && first_stage) {
+ int gpa_prot;
+ hwaddr gpa_paddr;
+ int gpa_ret = get_physical_address(env, &gpa_paddr, &gpa_prot,
+ pte_gpa, NULL, MMU_DATA_STORE,
+ MMUIdx_U, false, true,
+ is_debug, false);
+ if (gpa_ret != TRANSLATE_SUCCESS) {
+ if (fault_pte_addr) {
+ *fault_pte_addr = pte_gpa >> 2;
+ }
+ return TRANSLATE_G_STAGE_FAIL;
+ }
+ }
+
pmp_ret = get_physical_address_pmp(env, &pmp_prot, pte_addr,
sxlen_bytes, MMU_DATA_STORE, PRV_S);
if (pmp_ret != TRANSLATE_SUCCESS) {
@@ -2345,6 +2369,10 @@ void riscv_cpu_do_interrupt(CPUState *cs)
* doing VS-stage page table walk.
*/
tinst = (riscv_cpu_xlen(env) == 32) ? 0x00002000 : 0x00003000;
+
+ if (cause == RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT) {
+ tinst |= 0x20;
+ }
} else {
/*
* The "Addr. Offset" field in transformed instruction is
--
2.43.0
next parent reply other threads:[~2026-07-05 14:06 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <v1-Message-ID>
2026-07-05 14:02 ` imaginos [this message]
2026-07-10 2:23 ` [PATCH v2] target/riscv: check G-stage write permission for VS-stage A/D updates Alistair Francis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260705140508.17692-1-imaginos32@gmail.com \
--to=imaginos32@gmail.com \
--cc=alistair.francis@wdc.com \
--cc=chao.liu.zevorn@gmail.com \
--cc=daniel.barboza@oss.qualcomm.com \
--cc=liwei1518@gmail.com \
--cc=palmer@dabbelt.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
--cc=zhiwei_liu@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.