target/loongarch/tcg/tlb_helper.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
helper_lddir and helper_ldpte used TARGET_PHYS_MASK (bits 0-47) when
extracting the base address from a directory entry. This retained flag
bits (V, D, PLV, MAT, etc.) at positions 0-11, which were then OR'd
with the next-level index, producing a wrong physical address whenever
the directory entry carried non-zero flags.
Fix both helpers to extract only the PPN field (bits 12-47) before
computing the address of the next-level page table entry.
Signed-off-by: numpy1314 <xzj13@mail.ustc.edu.cn>
---
target/loongarch/tcg/tlb_helper.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index 40cc076424..f63cac0392 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -750,7 +750,13 @@ target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
}
badvaddr = sys->CSR_TLBRBADV;
- base = base & palen_mask;
+ /*
+ * Extract only the PPN field (bits 12-47) from the directory entry.
+ * Flag bits (V, D, PLV, MAT, etc.) at positions 0-11 must not
+ * participate in the next-level address calculation.
+ */
+ base = (target_ulong)FIELD_EX64(base, TLBENTRY_64, PPN)
+ << TARGET_PAGE_BITS;
get_dir_base_width(env, &dir_base, &dir_width, level);
index = (badvaddr >> dir_base) & ((1 << dir_width) - 1);
phys = base | index << 3;
@@ -769,11 +775,9 @@ void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
uint64_t badv;
uint64_t ptbase = FIELD_EX64(sys->CSR_PWCL, CSR_PWCL, PTBASE);
uint64_t ptwidth = FIELD_EX64(sys->CSR_PWCL, CSR_PWCL, PTWIDTH);
- uint64_t palen_mask = loongarch_palen_mask(env);
uint64_t dir_base, dir_width;
uint8_t ps;
-
/*
* The parameter "base" has only two types,
* one is the page table base address,
@@ -815,9 +819,9 @@ void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
}
} else {
badv = sys->CSR_TLBRBADV;
-
- base = base & palen_mask;
-
+ /* Strip flag bits (0-11) from base before address calculation. */
+ base = (target_ulong)FIELD_EX64(base, TLBENTRY_64, PPN)
+ << TARGET_PAGE_BITS;
ptindex = (badv >> ptbase) & ((1 << ptwidth) - 1);
ptindex = ptindex & ~0x1; /* clear bit 0 */
ptoffset0 = ptindex << 3;
--
2.55.0
On 9/16/26 18:08, SignKirigami wrote:
> - base = base & palen_mask;
> -
> + /* Strip flag bits (0-11) from base before address calculation. */
> + base = (target_ulong)FIELD_EX64(base, TLBENTRY_64, PPN)
> + << TARGET_PAGE_BITS;
This drops the masking due to PALEN.
I think you want
/* Strip flag bits (0-11) from base before address calculation. */
base = base & palen_mask & ~MAKE_64BIT_MASK(0, 12);
r~
© 2016 - 2026 Red Hat, Inc.