Common function loongarch_check_pte() is to check tlb entry, return the physical address and access priviledge. Also it can be used with page table entry, which is used in page table walker.
Signed-off-by: Bibo Mao <maob...@loongson.cn> --- target/loongarch/cpu-mmu.h | 9 +++++ target/loongarch/cpu_helper.c | 63 +++++++++++++++++++++++++++++++ target/loongarch/tcg/tlb_helper.c | 61 ++++-------------------------- 3 files changed, 80 insertions(+), 53 deletions(-) diff --git a/target/loongarch/cpu-mmu.h b/target/loongarch/cpu-mmu.h index 4c5cbd7425..6ca77b8501 100644 --- a/target/loongarch/cpu-mmu.h +++ b/target/loongarch/cpu-mmu.h @@ -19,7 +19,15 @@ enum { TLBRET_PE = 7, }; +typedef struct pte_context { + target_ulong vaddr; + uint64_t pte; + int page_shift; +} pte_context; + bool check_ps(CPULoongArchState *ent, uint8_t ps); +int loongarch_check_pte(CPULoongArchState *env, hwaddr *physical, int *prot, + pte_context *context, int access_type, int mmu_idx); int get_physical_address(CPULoongArchState *env, hwaddr *physical, int *prot, target_ulong address, MMUAccessType access_type, int mmu_idx, int is_debug); @@ -27,4 +35,5 @@ void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base, uint64_t *dir_width, target_ulong level); hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); + #endif /* LOONGARCH_CPU_MMU_H */ diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c index 2e8d3d7cfb..ed72ca1640 100644 --- a/target/loongarch/cpu_helper.c +++ b/target/loongarch/cpu_helper.c @@ -44,6 +44,69 @@ void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base, } } +int loongarch_check_pte(CPULoongArchState *env, hwaddr *physical, int *prot, + pte_context *context, int access_type, int mmu_idx) + +{ + uint64_t plv = mmu_idx; + uint64_t tlb_entry, tlb_ppn; + uint8_t tlb_ps, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv; + + tlb_entry = context->pte; + tlb_ps = context->page_shift; + + tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V); + tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D); + tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV); + if (is_la64(env)) { + tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_64, PPN); + tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY_64, NX); + tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY_64, NR); + tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY_64, RPLV); + } else { + tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_32, PPN); + tlb_nx = 0; + tlb_nr = 0; + tlb_rplv = 0; + } + + /* Check access rights */ + if (!tlb_v) { + return TLBRET_INVALID; + } + + if (access_type == MMU_INST_FETCH && tlb_nx) { + return TLBRET_XI; + } + + if (access_type == MMU_DATA_LOAD && tlb_nr) { + return TLBRET_RI; + } + + if (((tlb_rplv == 0) && (plv > tlb_plv)) || + ((tlb_rplv == 1) && (plv != tlb_plv))) { + return TLBRET_PE; + } + + if ((access_type == MMU_DATA_STORE) && !tlb_d) { + return TLBRET_DIRTY; + } + + /* Remove sw bit between bit12 -- bit PS*/ + tlb_ppn = tlb_ppn & ~(((0x1UL << (tlb_ps - 12)) - 1)); + *physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) | + (context->vaddr & MAKE_64BIT_MASK(0, tlb_ps)); + *prot = PAGE_READ; + if (tlb_d) { + *prot |= PAGE_WRITE; + } + if (!tlb_nx) { + *prot |= PAGE_EXEC; + } + + return TLBRET_MATCH; +} + static int loongarch_page_table_walker(CPULoongArchState *env, hwaddr *physical, int *prot, target_ulong address) { diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c index a2855209e2..ccd2e52258 100644 --- a/target/loongarch/tcg/tlb_helper.c +++ b/target/loongarch/tcg/tlb_helper.c @@ -660,64 +660,19 @@ static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, int access_type, int index, int mmu_idx) { LoongArchTLB *tlb = &env->tlb[index]; - uint64_t plv = mmu_idx; - uint64_t tlb_entry, tlb_ppn; - uint8_t tlb_ps, n, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv; + uint64_t tlb_entry; + uint8_t tlb_ps, n; + pte_context context; tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); n = (address >> tlb_ps) & 0x1;/* Odd or even */ tlb_entry = n ? tlb->tlb_entry1 : tlb->tlb_entry0; - tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V); - tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D); - tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV); - if (is_la64(env)) { - tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_64, PPN); - tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY_64, NX); - tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY_64, NR); - tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY_64, RPLV); - } else { - tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_32, PPN); - tlb_nx = 0; - tlb_nr = 0; - tlb_rplv = 0; - } - - /* Remove sw bit between bit12 -- bit PS*/ - tlb_ppn = tlb_ppn & ~(((0x1UL << (tlb_ps - 12)) - 1)); - - /* Check access rights */ - if (!tlb_v) { - return TLBRET_INVALID; - } - - if (access_type == MMU_INST_FETCH && tlb_nx) { - return TLBRET_XI; - } - - if (access_type == MMU_DATA_LOAD && tlb_nr) { - return TLBRET_RI; - } - - if (((tlb_rplv == 0) && (plv > tlb_plv)) || - ((tlb_rplv == 1) && (plv != tlb_plv))) { - return TLBRET_PE; - } - - if ((access_type == MMU_DATA_STORE) && !tlb_d) { - return TLBRET_DIRTY; - } - - *physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) | - (address & MAKE_64BIT_MASK(0, tlb_ps)); - *prot = PAGE_READ; - if (tlb_d) { - *prot |= PAGE_WRITE; - } - if (!tlb_nx) { - *prot |= PAGE_EXEC; - } - return TLBRET_MATCH; + context.vaddr = address; + context.page_shift = tlb_ps; + context.pte = tlb_entry; + return loongarch_check_pte(env, physical, prot, &context, access_type, + mmu_idx); } int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, -- 2.39.3