On 2025/2/17 上午8:54, Song Gao wrote:
For LoongArch th min tlb_ps is 12(4KB), for TLB code,
the tlb_ps may be 0,this may case UndefinedBehavior
Add a check-tlb_ps fuction to check tlb_ps, when use
csrwr insn to write CRMD PG=1, check the tlb_ps, and when
use csrwr insn to write STLBPS, check the tlb_ps value.

Signed-off-by: Song Gao <gaos...@loongson.cn>
---
  target/loongarch/helper.h                     |  2 +
  target/loongarch/internals.h                  |  1 +
  target/loongarch/tcg/csr_helper.c             | 52 +++++++++++++++++++
  .../tcg/insn_trans/trans_privileged.c.inc     |  2 +
  target/loongarch/tcg/tlb_helper.c             |  4 ++
  5 files changed, 61 insertions(+)

diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 943517b5f2..4f1490a465 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -100,6 +100,8 @@ DEF_HELPER_1(rdtime_d, i64, env)
  DEF_HELPER_1(csrrd_pgd, i64, env)
  DEF_HELPER_1(csrrd_cpuid, i64, env)
  DEF_HELPER_1(csrrd_tval, i64, env)
+DEF_HELPER_2(csrwr_crmd, i64, env,tl)
+DEF_HELPER_2(csrwr_stlbps, i64, env, tl)
  DEF_HELPER_2(csrwr_estat, i64, env, tl)
  DEF_HELPER_2(csrwr_asid, i64, env, tl)
  DEF_HELPER_2(csrwr_tcfg, i64, env, tl)
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index 7b254c5f49..bb1644f0a0 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -43,6 +43,7 @@ enum {
      TLBRET_PE = 7,
  };
+void check_tlb_ps(CPULoongArchState *env);
  extern const VMStateDescription vmstate_loongarch_cpu;
void loongarch_cpu_set_irq(void *opaque, int irq, int level);
diff --git a/target/loongarch/tcg/csr_helper.c 
b/target/loongarch/tcg/csr_helper.c
index 6c95be9910..32c9716f42 100644
--- a/target/loongarch/tcg/csr_helper.c
+++ b/target/loongarch/tcg/csr_helper.c
@@ -97,6 +97,58 @@ target_ulong helper_csrwr_ticlr(CPULoongArchState *env, 
target_ulong val)
      return old_v;
  }
+void check_tlb_ps(CPULoongArchState *env)
+{
+    for (int i=0; i<LOONGARCH_TLB_MAX; i++)
+    {
+        LoongArchTLB*tlb =&env->tlb[i];
+        uint8_t tlb_ps;
+        if(i >= LOONGARCH_STLB) {
+            tlb_ps = FIELD_EX64(tlb->tlb_misc,TLB_MISC,PS);
It is strange why tlb entries is check here? If I am understanding right, TLB page size should comes from these two areas:
   FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE); or
   FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS,PS);

If page size of CSR_PWCL is equal to CSR_STLBPS, it is put to STLB, else it is put to MTLB. If so, it will be ok if these CSR registers are checked.
   FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE)
   FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS,PS)

And when system is set with Page-mode by writing CRMD register, TLB entry should be empty in theory.

+           if (tlb_ps < 12) {
+                tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, PS, 12);
+            }
+        } else {
+            tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS,PS);
+            if (tlb_ps < 12) {
+               env->CSR_STLBPS= FIELD_DP64(env->CSR_STLBPS, CSR_STLBPS, PS, 
12);
+           }
+       }
+    }
+}
+
+target_ulong helper_csrwr_crmd(CPULoongArchState *env, target_ulong val)
+{
+    uint8_t pg;
+    int64_t old_v = env->CSR_CRMD;
+
+    pg = FIELD_EX64(val, CSR_CRMD, PG);
Do you mean that it is the first time that Page-mode is set. If so, it had better be:
       old = FIELD_EX64(old_v, CSR_CRMD, PG);
       if (pg && !old) {

Regards
Bibo Mao
+    if (pg) {
+        check_tlb_ps(env);
+    }
+    env->CSR_CRMD = val;
+    return old_v;
+}
+
+target_ulong helper_csrwr_stlbps(CPULoongArchState *env, target_ulong val)
+{
+    uint8_t tlb_ps;
+    int64_t old_v = env->CSR_STLBPS;
+
+    /*
+     * The real hardware only supports the min tlb_ps is 12
+     * tlb_ps=0 may cause undefined-behavior.
+     */
+    tlb_ps = FIELD_EX64(val, CSR_STLBPS, PS);
+    if (tlb_ps  < 12) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Attempted set ps %d\n",tlb_ps);
+        val = FIELD_DP64(val, CSR_STLBPS, PS, 12);
+    }
+    env->CSR_STLBPS = val;
+    return old_v;
+}
+
  target_ulong helper_csrwr_pwcl(CPULoongArchState *env, target_ulong val)
  {
      int shift;
diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc 
b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
index 3afa23af79..d6b1f8319f 100644
--- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
@@ -74,6 +74,8 @@ static bool set_csr_trans_func(unsigned int csr_num, 
GenCSRRead readfn,
void loongarch_csr_translate_init(void)
  {
+    SET_CSR_FUNC(CRMD, NULL,gen_helper_csrwr_crmd);
+    SET_CSR_FUNC(STLBPS, NULL,gen_helper_csrwr_stlbps);
      SET_CSR_FUNC(ESTAT, NULL, gen_helper_csrwr_estat);
      SET_CSR_FUNC(ASID,  NULL, gen_helper_csrwr_asid);
      SET_CSR_FUNC(PGD,   gen_helper_csrrd_pgd, NULL);
diff --git a/target/loongarch/tcg/tlb_helper.c 
b/target/loongarch/tcg/tlb_helper.c
index a323606e5a..fc9c7823e7 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -449,7 +449,11 @@ void helper_invtlb_page_asid_or_g(CPULoongArchState *env,
                                    target_ulong info, target_ulong addr)
  {
      uint16_t asid = info & 0x3ff;
+    uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
+ if (!pg) {
+        return;
+    }
      for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
          LoongArchTLB *tlb = &env->tlb[i];
          uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);



Reply via email to