[PATCH] target/loongarch: Preserve PTW dirty tracking on read fills

Bibo Mao posted 1 patch 1 week, 1 day ago
target/loongarch/tcg/tlb_helper.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
[PATCH] target/loongarch: Preserve PTW dirty tracking on read fills
Posted by Bibo Mao 1 week, 1 day ago
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