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);