target/loongarch/tcg/tlb_helper.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
with LoongArch hardware page table walking (PTW) enabled, a PTE
can be writable (W=1) but still clean (D=0). A load or instruction fetch
can install PAGE_WRITE in QEMU's software TLB based on W alone. A later
store then bypasses loongarch_cpu_tlb_fill() and PTW, dirty bit of PTE
will not be set with the later store operation.
Here remove PAGE_WRITE for clean PTEs on read/fetch fills at the common
software TLB fill point. The next store must re-enter PTW to set D before
using a writable cached translation.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
target/loongarch/tcg/tlb_helper.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index 40cc076424..dae04854ad 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -652,15 +652,6 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
need_update = false;
} else if (access_type != MMU_DATA_STORE && pte_access(context.pte)) {
need_update = false;
-
- /*
- * FIXME: should context.prot be set without PAGE_WRITE with
- * pte_write(context.pte) && !pte_dirty(context.pte)??
- *
- * Otherwise there will be no loongarch_cpu_tlb_fill() function call
- * for MMU_DATA_STORE access_type in future since QEMU TLB with
- * prot PAGE_WRITE is added already
- */
}
if (need_update) {
@@ -684,6 +675,19 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
if (ret == TLBRET_MATCH) {
physical = context.physical;
prot = context.prot;
+
+ /*
+ * Loads or instruction fetches must not cache write access to a
+ * clean PTE. The first store must enter PTW to set D, whether this
+ * translation came from the LoongArch TLB or a page table walk.
+ * Store walks have already handled D, but context.pte may still
+ * contain its old value. Direct mappings have no PTE to check.
+ */
+ if (cpu_has_ptw(env) && context.mmu_index != MMU_DA_IDX &&
+ access_type != MMU_DATA_STORE && !pte_dirty(context.pte)) {
+ prot &= ~PAGE_WRITE;
+ }
+
tlb_set_page(cs, address & TARGET_PAGE_MASK,
physical & TARGET_PAGE_MASK, prot,
mmu_idx, TARGET_PAGE_SIZE);
base-commit: c66824ffb01931be0ddfe49a1642a78570abf44b
--
2.54.0
© 2016 - 2026 Red Hat, Inc.