xref: /qemu/target/loongarch/cpu_helper.c (revision 566bf2de87160a8a2fe5a1ba1a2f31f6869f4f80)
127edd504SSong Gao /* SPDX-License-Identifier: GPL-2.0-or-later */
227edd504SSong Gao /*
327edd504SSong Gao  * LoongArch CPU helpers for qemu
427edd504SSong Gao  *
527edd504SSong Gao  * Copyright (c) 2024 Loongson Technology Corporation Limited
627edd504SSong Gao  *
727edd504SSong Gao  */
827edd504SSong Gao 
927edd504SSong Gao #include "qemu/osdep.h"
10a8d1b5bcSBibo Mao #include "system/tcg.h"
1127edd504SSong Gao #include "cpu.h"
1227edd504SSong Gao #include "internals.h"
1327edd504SSong Gao #include "cpu-csr.h"
1427edd504SSong Gao 
156f703a48SBibo Mao #ifdef CONFIG_TCG
1627edd504SSong Gao static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical,
1727edd504SSong Gao                                    int *prot, target_ulong address,
1827edd504SSong Gao                                    int access_type, int index, int mmu_idx)
1927edd504SSong Gao {
2027edd504SSong Gao     LoongArchTLB *tlb = &env->tlb[index];
2127edd504SSong Gao     uint64_t plv = mmu_idx;
2227edd504SSong Gao     uint64_t tlb_entry, tlb_ppn;
2327edd504SSong Gao     uint8_t tlb_ps, n, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv;
2427edd504SSong Gao 
2527edd504SSong Gao     if (index >= LOONGARCH_STLB) {
2627edd504SSong Gao         tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
2727edd504SSong Gao     } else {
2827edd504SSong Gao         tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
2927edd504SSong Gao     }
3027edd504SSong Gao     n = (address >> tlb_ps) & 0x1;/* Odd or even */
3127edd504SSong Gao 
3227edd504SSong Gao     tlb_entry = n ? tlb->tlb_entry1 : tlb->tlb_entry0;
3327edd504SSong Gao     tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V);
3427edd504SSong Gao     tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D);
3527edd504SSong Gao     tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV);
3627edd504SSong Gao     if (is_la64(env)) {
3727edd504SSong Gao         tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_64, PPN);
3827edd504SSong Gao         tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY_64, NX);
3927edd504SSong Gao         tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY_64, NR);
4027edd504SSong Gao         tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY_64, RPLV);
4127edd504SSong Gao     } else {
4227edd504SSong Gao         tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_32, PPN);
4327edd504SSong Gao         tlb_nx = 0;
4427edd504SSong Gao         tlb_nr = 0;
4527edd504SSong Gao         tlb_rplv = 0;
4627edd504SSong Gao     }
4727edd504SSong Gao 
4827edd504SSong Gao     /* Remove sw bit between bit12 -- bit PS*/
4927edd504SSong Gao     tlb_ppn = tlb_ppn & ~(((0x1UL << (tlb_ps - 12)) -1));
5027edd504SSong Gao 
5127edd504SSong Gao     /* Check access rights */
5227edd504SSong Gao     if (!tlb_v) {
5327edd504SSong Gao         return TLBRET_INVALID;
5427edd504SSong Gao     }
5527edd504SSong Gao 
5627edd504SSong Gao     if (access_type == MMU_INST_FETCH && tlb_nx) {
5727edd504SSong Gao         return TLBRET_XI;
5827edd504SSong Gao     }
5927edd504SSong Gao 
6027edd504SSong Gao     if (access_type == MMU_DATA_LOAD && tlb_nr) {
6127edd504SSong Gao         return TLBRET_RI;
6227edd504SSong Gao     }
6327edd504SSong Gao 
6427edd504SSong Gao     if (((tlb_rplv == 0) && (plv > tlb_plv)) ||
6527edd504SSong Gao         ((tlb_rplv == 1) && (plv != tlb_plv))) {
6627edd504SSong Gao         return TLBRET_PE;
6727edd504SSong Gao     }
6827edd504SSong Gao 
6927edd504SSong Gao     if ((access_type == MMU_DATA_STORE) && !tlb_d) {
7027edd504SSong Gao         return TLBRET_DIRTY;
7127edd504SSong Gao     }
7227edd504SSong Gao 
7327edd504SSong Gao     *physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) |
7427edd504SSong Gao                 (address & MAKE_64BIT_MASK(0, tlb_ps));
7527edd504SSong Gao     *prot = PAGE_READ;
7627edd504SSong Gao     if (tlb_d) {
7727edd504SSong Gao         *prot |= PAGE_WRITE;
7827edd504SSong Gao     }
7927edd504SSong Gao     if (!tlb_nx) {
8027edd504SSong Gao         *prot |= PAGE_EXEC;
8127edd504SSong Gao     }
8227edd504SSong Gao     return TLBRET_MATCH;
8327edd504SSong Gao }
8427edd504SSong Gao 
8527edd504SSong Gao /*
8627edd504SSong Gao  * One tlb entry holds an adjacent odd/even pair, the vpn is the
8727edd504SSong Gao  * content of the virtual page number divided by 2. So the
8827edd504SSong Gao  * compare vpn is bit[47:15] for 16KiB page. while the vppn
8927edd504SSong Gao  * field in tlb entry contains bit[47:13], so need adjust.
9027edd504SSong Gao  * virt_vpn = vaddr[47:13]
9127edd504SSong Gao  */
9227edd504SSong Gao bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr,
9327edd504SSong Gao                           int *index)
9427edd504SSong Gao {
9527edd504SSong Gao     LoongArchTLB *tlb;
9627edd504SSong Gao     uint16_t csr_asid, tlb_asid, stlb_idx;
9727edd504SSong Gao     uint8_t tlb_e, tlb_ps, tlb_g, stlb_ps;
9827edd504SSong Gao     int i, compare_shift;
9927edd504SSong Gao     uint64_t vpn, tlb_vppn;
10027edd504SSong Gao 
10127edd504SSong Gao     csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
10227edd504SSong Gao     stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
10327edd504SSong Gao     vpn = (vaddr & TARGET_VIRT_MASK) >> (stlb_ps + 1);
10427edd504SSong Gao     stlb_idx = vpn & 0xff; /* VA[25:15] <==> TLBIDX.index for 16KiB Page */
10527edd504SSong Gao     compare_shift = stlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT;
10627edd504SSong Gao 
10727edd504SSong Gao     /* Search STLB */
10827edd504SSong Gao     for (i = 0; i < 8; ++i) {
10927edd504SSong Gao         tlb = &env->tlb[i * 256 + stlb_idx];
11027edd504SSong Gao         tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E);
11127edd504SSong Gao         if (tlb_e) {
11227edd504SSong Gao             tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
11327edd504SSong Gao             tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
11427edd504SSong Gao             tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
11527edd504SSong Gao 
11627edd504SSong Gao             if ((tlb_g == 1 || tlb_asid == csr_asid) &&
11727edd504SSong Gao                 (vpn == (tlb_vppn >> compare_shift))) {
11827edd504SSong Gao                 *index = i * 256 + stlb_idx;
11927edd504SSong Gao                 return true;
12027edd504SSong Gao             }
12127edd504SSong Gao         }
12227edd504SSong Gao     }
12327edd504SSong Gao 
12427edd504SSong Gao     /* Search MTLB */
12527edd504SSong Gao     for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; ++i) {
12627edd504SSong Gao         tlb = &env->tlb[i];
12727edd504SSong Gao         tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E);
12827edd504SSong Gao         if (tlb_e) {
12927edd504SSong Gao             tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
13027edd504SSong Gao             tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
13127edd504SSong Gao             tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
13227edd504SSong Gao             tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
13327edd504SSong Gao             compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT;
13427edd504SSong Gao             vpn = (vaddr & TARGET_VIRT_MASK) >> (tlb_ps + 1);
13527edd504SSong Gao             if ((tlb_g == 1 || tlb_asid == csr_asid) &&
13627edd504SSong Gao                 (vpn == (tlb_vppn >> compare_shift))) {
13727edd504SSong Gao                 *index = i;
13827edd504SSong Gao                 return true;
13927edd504SSong Gao             }
14027edd504SSong Gao         }
14127edd504SSong Gao     }
14227edd504SSong Gao     return false;
14327edd504SSong Gao }
14427edd504SSong Gao 
145a8d1b5bcSBibo Mao static int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical,
146a8d1b5bcSBibo Mao                                        int *prot, target_ulong address,
147a8d1b5bcSBibo Mao                                        MMUAccessType access_type, int mmu_idx)
148a8d1b5bcSBibo Mao {
149a8d1b5bcSBibo Mao     int index, match;
150a8d1b5bcSBibo Mao 
151a8d1b5bcSBibo Mao     match = loongarch_tlb_search(env, address, &index);
152a8d1b5bcSBibo Mao     if (match) {
153a8d1b5bcSBibo Mao         return loongarch_map_tlb_entry(env, physical, prot,
154a8d1b5bcSBibo Mao                                        address, access_type, index, mmu_idx);
155a8d1b5bcSBibo Mao     }
156a8d1b5bcSBibo Mao 
157a8d1b5bcSBibo Mao     return TLBRET_NOMATCH;
158a8d1b5bcSBibo Mao }
159*566bf2deSBibo Mao #else
160*566bf2deSBibo Mao static int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical,
161*566bf2deSBibo Mao                                        int *prot, target_ulong address,
162*566bf2deSBibo Mao                                        MMUAccessType access_type, int mmu_idx)
163*566bf2deSBibo Mao {
164*566bf2deSBibo Mao     return TLBRET_NOMATCH;
165*566bf2deSBibo Mao }
166*566bf2deSBibo Mao #endif
167a8d1b5bcSBibo Mao 
168*566bf2deSBibo Mao #ifdef CONFIG_TCG
169885398eeSBibo Mao void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
170885398eeSBibo Mao                         uint64_t *dir_width, target_ulong level)
171885398eeSBibo Mao {
172885398eeSBibo Mao     switch (level) {
173885398eeSBibo Mao     case 1:
174885398eeSBibo Mao         *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE);
175885398eeSBibo Mao         *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH);
176885398eeSBibo Mao         break;
177885398eeSBibo Mao     case 2:
178885398eeSBibo Mao         *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE);
179885398eeSBibo Mao         *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH);
180885398eeSBibo Mao         break;
181885398eeSBibo Mao     case 3:
182885398eeSBibo Mao         *dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE);
183885398eeSBibo Mao         *dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH);
184885398eeSBibo Mao         break;
185885398eeSBibo Mao     case 4:
186885398eeSBibo Mao         *dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE);
187885398eeSBibo Mao         *dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH);
188885398eeSBibo Mao         break;
189885398eeSBibo Mao     default:
190885398eeSBibo Mao         /* level may be zero for ldpte */
191885398eeSBibo Mao         *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE);
192885398eeSBibo Mao         *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH);
193885398eeSBibo Mao         break;
194885398eeSBibo Mao     }
195885398eeSBibo Mao }
196885398eeSBibo Mao 
197dd291171SMiao Hao static int loongarch_page_table_walker(CPULoongArchState *env, hwaddr *physical,
198dd291171SMiao Hao                                  int *prot, target_ulong address)
199dd291171SMiao Hao {
200dd291171SMiao Hao     CPUState *cs = env_cpu(env);
201dd291171SMiao Hao     target_ulong index, phys;
202dd291171SMiao Hao     uint64_t dir_base, dir_width;
203dd291171SMiao Hao     uint64_t base;
204dd291171SMiao Hao     int level;
205dd291171SMiao Hao 
206dd291171SMiao Hao     if ((address >> 63) & 0x1) {
207dd291171SMiao Hao         base = env->CSR_PGDH;
208dd291171SMiao Hao     } else {
209dd291171SMiao Hao         base = env->CSR_PGDL;
210dd291171SMiao Hao     }
211dd291171SMiao Hao     base &= TARGET_PHYS_MASK;
212dd291171SMiao Hao 
213dd291171SMiao Hao     for (level = 4; level > 0; level--) {
214dd291171SMiao Hao         get_dir_base_width(env, &dir_base, &dir_width, level);
215dd291171SMiao Hao 
216dd291171SMiao Hao         if (dir_width == 0) {
217dd291171SMiao Hao             continue;
218dd291171SMiao Hao         }
219dd291171SMiao Hao 
220dd291171SMiao Hao         /* get next level page directory */
221dd291171SMiao Hao         index = (address >> dir_base) & ((1 << dir_width) - 1);
222dd291171SMiao Hao         phys = base | index << 3;
223dd291171SMiao Hao         base = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
224dd291171SMiao Hao         if (FIELD_EX64(base, TLBENTRY, HUGE)) {
225dd291171SMiao Hao             /* base is a huge pte */
226dd291171SMiao Hao             break;
227dd291171SMiao Hao         }
228dd291171SMiao Hao     }
229dd291171SMiao Hao 
230dd291171SMiao Hao     /* pte */
231dd291171SMiao Hao     if (FIELD_EX64(base, TLBENTRY, HUGE)) {
232dd291171SMiao Hao         /* Huge Page. base is pte */
233dd291171SMiao Hao         base = FIELD_DP64(base, TLBENTRY, LEVEL, 0);
234dd291171SMiao Hao         base = FIELD_DP64(base, TLBENTRY, HUGE, 0);
235dd291171SMiao Hao         if (FIELD_EX64(base, TLBENTRY, HGLOBAL)) {
236dd291171SMiao Hao             base = FIELD_DP64(base, TLBENTRY, HGLOBAL, 0);
237dd291171SMiao Hao             base = FIELD_DP64(base, TLBENTRY, G, 1);
238dd291171SMiao Hao         }
239dd291171SMiao Hao     } else {
240dd291171SMiao Hao         /* Normal Page. base points to pte */
241dd291171SMiao Hao         get_dir_base_width(env, &dir_base, &dir_width, 0);
242dd291171SMiao Hao         index = (address >> dir_base) & ((1 << dir_width) - 1);
243dd291171SMiao Hao         phys = base | index << 3;
244dd291171SMiao Hao         base = ldq_phys(cs->as, phys);
245dd291171SMiao Hao     }
246dd291171SMiao Hao 
247dd291171SMiao Hao     /* TODO: check plv and other bits? */
248dd291171SMiao Hao 
249dd291171SMiao Hao     /* base is pte, in normal pte format */
250dd291171SMiao Hao     if (!FIELD_EX64(base, TLBENTRY, V)) {
251dd291171SMiao Hao         return TLBRET_NOMATCH;
252dd291171SMiao Hao     }
253dd291171SMiao Hao 
254dd291171SMiao Hao     if (!FIELD_EX64(base, TLBENTRY, D)) {
255dd291171SMiao Hao         *prot = PAGE_READ;
256dd291171SMiao Hao     } else {
257dd291171SMiao Hao         *prot = PAGE_READ | PAGE_WRITE;
258dd291171SMiao Hao     }
259dd291171SMiao Hao 
260dd291171SMiao Hao     /* get TARGET_PAGE_SIZE aligned physical address */
261dd291171SMiao Hao     base += (address & TARGET_PHYS_MASK) & ((1 << dir_base) - 1);
262dd291171SMiao Hao     /* mask RPLV, NX, NR bits */
263dd291171SMiao Hao     base = FIELD_DP64(base, TLBENTRY_64, RPLV, 0);
264dd291171SMiao Hao     base = FIELD_DP64(base, TLBENTRY_64, NX, 0);
265dd291171SMiao Hao     base = FIELD_DP64(base, TLBENTRY_64, NR, 0);
266dd291171SMiao Hao     /* mask other attribute bits */
267dd291171SMiao Hao     *physical = base & TARGET_PAGE_MASK;
268dd291171SMiao Hao 
269dd291171SMiao Hao     return 0;
270dd291171SMiao Hao }
271dd291171SMiao Hao 
27227edd504SSong Gao static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
27327edd504SSong Gao                                  int *prot, target_ulong address,
274dd291171SMiao Hao                                  MMUAccessType access_type, int mmu_idx,
275dd291171SMiao Hao                                  int is_debug)
27627edd504SSong Gao {
277a8d1b5bcSBibo Mao     int ret;
27827edd504SSong Gao 
279a8d1b5bcSBibo Mao     if (tcg_enabled()) {
280a8d1b5bcSBibo Mao         ret = loongarch_get_addr_from_tlb(env, physical, prot, address,
281a8d1b5bcSBibo Mao                                           access_type, mmu_idx);
282a8d1b5bcSBibo Mao         if (ret != TLBRET_NOMATCH) {
283a8d1b5bcSBibo Mao             return ret;
284a8d1b5bcSBibo Mao         }
285a8d1b5bcSBibo Mao     }
286a8d1b5bcSBibo Mao 
287a8d1b5bcSBibo Mao     if (is_debug) {
288dd291171SMiao Hao         /*
289dd291171SMiao Hao          * For debugger memory access, we want to do the map when there is a
290dd291171SMiao Hao          * legal mapping, even if the mapping is not yet in TLB. return 0 if
291dd291171SMiao Hao          * there is a valid map, else none zero.
292dd291171SMiao Hao          */
293dd291171SMiao Hao         return loongarch_page_table_walker(env, physical, prot, address);
29427edd504SSong Gao     }
29527edd504SSong Gao 
29627edd504SSong Gao     return TLBRET_NOMATCH;
29727edd504SSong Gao }
2986f703a48SBibo Mao #else
2996f703a48SBibo Mao static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
3006f703a48SBibo Mao                                  int *prot, target_ulong address,
301dd291171SMiao Hao                                  MMUAccessType access_type, int mmu_idx,
302dd291171SMiao Hao                                  int is_debug)
3036f703a48SBibo Mao {
3046f703a48SBibo Mao     return TLBRET_NOMATCH;
3056f703a48SBibo Mao }
3066f703a48SBibo Mao #endif
30727edd504SSong Gao 
30827edd504SSong Gao static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va,
30927edd504SSong Gao                         target_ulong dmw)
31027edd504SSong Gao {
31127edd504SSong Gao     if (is_la64(env)) {
31227edd504SSong Gao         return va & TARGET_VIRT_MASK;
31327edd504SSong Gao     } else {
31427edd504SSong Gao         uint32_t pseg = FIELD_EX32(dmw, CSR_DMW_32, PSEG);
31527edd504SSong Gao         return (va & MAKE_64BIT_MASK(0, R_CSR_DMW_32_VSEG_SHIFT)) | \
31627edd504SSong Gao             (pseg << R_CSR_DMW_32_VSEG_SHIFT);
31727edd504SSong Gao     }
31827edd504SSong Gao }
31927edd504SSong Gao 
32027edd504SSong Gao int get_physical_address(CPULoongArchState *env, hwaddr *physical,
32127edd504SSong Gao                          int *prot, target_ulong address,
322dd291171SMiao Hao                          MMUAccessType access_type, int mmu_idx, int is_debug)
32327edd504SSong Gao {
3243f262d25SRichard Henderson     int user_mode = mmu_idx == MMU_USER_IDX;
3253f262d25SRichard Henderson     int kernel_mode = mmu_idx == MMU_KERNEL_IDX;
32627edd504SSong Gao     uint32_t plv, base_c, base_v;
32727edd504SSong Gao     int64_t addr_high;
32827edd504SSong Gao     uint8_t da = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, DA);
32927edd504SSong Gao     uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
33027edd504SSong Gao 
33127edd504SSong Gao     /* Check PG and DA */
33227edd504SSong Gao     if (da & !pg) {
33327edd504SSong Gao         *physical = address & TARGET_PHYS_MASK;
33427edd504SSong Gao         *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
33527edd504SSong Gao         return TLBRET_MATCH;
33627edd504SSong Gao     }
33727edd504SSong Gao 
33827edd504SSong Gao     plv = kernel_mode | (user_mode << R_CSR_DMW_PLV3_SHIFT);
33927edd504SSong Gao     if (is_la64(env)) {
34027edd504SSong Gao         base_v = address >> R_CSR_DMW_64_VSEG_SHIFT;
34127edd504SSong Gao     } else {
34227edd504SSong Gao         base_v = address >> R_CSR_DMW_32_VSEG_SHIFT;
34327edd504SSong Gao     }
34427edd504SSong Gao     /* Check direct map window */
34527edd504SSong Gao     for (int i = 0; i < 4; i++) {
34627edd504SSong Gao         if (is_la64(env)) {
34727edd504SSong Gao             base_c = FIELD_EX64(env->CSR_DMW[i], CSR_DMW_64, VSEG);
34827edd504SSong Gao         } else {
34927edd504SSong Gao             base_c = FIELD_EX64(env->CSR_DMW[i], CSR_DMW_32, VSEG);
35027edd504SSong Gao         }
35127edd504SSong Gao         if ((plv & env->CSR_DMW[i]) && (base_c == base_v)) {
35227edd504SSong Gao             *physical = dmw_va2pa(env, address, env->CSR_DMW[i]);
35327edd504SSong Gao             *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
35427edd504SSong Gao             return TLBRET_MATCH;
35527edd504SSong Gao         }
35627edd504SSong Gao     }
35727edd504SSong Gao 
35827edd504SSong Gao     /* Check valid extension */
35927edd504SSong Gao     addr_high = sextract64(address, TARGET_VIRT_ADDR_SPACE_BITS, 16);
36027edd504SSong Gao     if (!(addr_high == 0 || addr_high == -1)) {
36127edd504SSong Gao         return TLBRET_BADADDR;
36227edd504SSong Gao     }
36327edd504SSong Gao 
36427edd504SSong Gao     /* Mapped address */
36527edd504SSong Gao     return loongarch_map_address(env, physical, prot, address,
366dd291171SMiao Hao                                  access_type, mmu_idx, is_debug);
36727edd504SSong Gao }
36827edd504SSong Gao 
36927edd504SSong Gao hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
37027edd504SSong Gao {
371f3b603b9SPhilippe Mathieu-Daudé     CPULoongArchState *env = cpu_env(cs);
37227edd504SSong Gao     hwaddr phys_addr;
37327edd504SSong Gao     int prot;
37427edd504SSong Gao 
37527edd504SSong Gao     if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD,
376dd291171SMiao Hao                              cpu_mmu_index(cs, false), 1) != 0) {
37727edd504SSong Gao         return -1;
37827edd504SSong Gao     }
37927edd504SSong Gao     return phys_addr;
38027edd504SSong Gao }
381