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