1163fa5caSBlue Swirl /* 2163fa5caSBlue Swirl * Sparc MMU helpers 3163fa5caSBlue Swirl * 4163fa5caSBlue Swirl * Copyright (c) 2003-2005 Fabrice Bellard 5163fa5caSBlue Swirl * 6163fa5caSBlue Swirl * This library is free software; you can redistribute it and/or 7163fa5caSBlue Swirl * modify it under the terms of the GNU Lesser General Public 8163fa5caSBlue Swirl * License as published by the Free Software Foundation; either 95650b549SChetan Pant * version 2.1 of the License, or (at your option) any later version. 10163fa5caSBlue Swirl * 11163fa5caSBlue Swirl * This library is distributed in the hope that it will be useful, 12163fa5caSBlue Swirl * but WITHOUT ANY WARRANTY; without even the implied warranty of 13163fa5caSBlue Swirl * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14163fa5caSBlue Swirl * Lesser General Public License for more details. 15163fa5caSBlue Swirl * 16163fa5caSBlue Swirl * You should have received a copy of the GNU Lesser General Public 17163fa5caSBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18163fa5caSBlue Swirl */ 19163fa5caSBlue Swirl 20db5ebe5fSPeter Maydell #include "qemu/osdep.h" 21cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h" 22163fa5caSBlue Swirl #include "cpu.h" 23a9f5ab92SPhilippe Mathieu-Daudé #include "exec/cputlb.h" 24efe25c26SRichard Henderson #include "accel/tcg/cpu-mmu-index.h" 2574781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h" 26*9c2ff9cdSPierrick Bouvier #include "exec/target_page.h" 274d43552aSPierrick Bouvier #include "exec/tlb-flags.h" 28342e313dSPierrick Bouvier #include "system/memory.h" 29fad866daSMarkus Armbruster #include "qemu/qemu-print.h" 30ec0ceb17SBlue Swirl #include "trace.h" 31163fa5caSBlue Swirl 32163fa5caSBlue Swirl /* Sparc MMU emulation */ 33163fa5caSBlue Swirl 34163fa5caSBlue Swirl #ifndef TARGET_SPARC64 35163fa5caSBlue Swirl /* 36163fa5caSBlue Swirl * Sparc V8 Reference MMU (SRMMU) 37163fa5caSBlue Swirl */ 38163fa5caSBlue Swirl static const int access_table[8][8] = { 39163fa5caSBlue Swirl { 0, 0, 0, 0, 8, 0, 12, 12 }, 40163fa5caSBlue Swirl { 0, 0, 0, 0, 8, 0, 0, 0 }, 41163fa5caSBlue Swirl { 8, 8, 0, 0, 0, 8, 12, 12 }, 42163fa5caSBlue Swirl { 8, 8, 0, 0, 0, 8, 0, 0 }, 43163fa5caSBlue Swirl { 8, 0, 8, 0, 8, 8, 12, 12 }, 44163fa5caSBlue Swirl { 8, 0, 8, 0, 8, 0, 8, 0 }, 45163fa5caSBlue Swirl { 8, 8, 8, 0, 8, 8, 12, 12 }, 46163fa5caSBlue Swirl { 8, 8, 8, 0, 8, 8, 8, 0 } 47163fa5caSBlue Swirl }; 48163fa5caSBlue Swirl 49163fa5caSBlue Swirl static const int perm_table[2][8] = { 50163fa5caSBlue Swirl { 51163fa5caSBlue Swirl PAGE_READ, 52163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE, 53163fa5caSBlue Swirl PAGE_READ | PAGE_EXEC, 54163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE | PAGE_EXEC, 55163fa5caSBlue Swirl PAGE_EXEC, 56163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE, 57163fa5caSBlue Swirl PAGE_READ | PAGE_EXEC, 58163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE | PAGE_EXEC 59163fa5caSBlue Swirl }, 60163fa5caSBlue Swirl { 61163fa5caSBlue Swirl PAGE_READ, 62163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE, 63163fa5caSBlue Swirl PAGE_READ | PAGE_EXEC, 64163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE | PAGE_EXEC, 65163fa5caSBlue Swirl PAGE_EXEC, 66163fa5caSBlue Swirl PAGE_READ, 67163fa5caSBlue Swirl 0, 68163fa5caSBlue Swirl 0, 69163fa5caSBlue Swirl } 70163fa5caSBlue Swirl }; 71163fa5caSBlue Swirl 7271b7794bSRichard Henderson static int get_physical_address(CPUSPARCState *env, CPUTLBEntryFull *full, 7371b7794bSRichard Henderson int *access_index, target_ulong address, 7471b7794bSRichard Henderson int rw, int mmu_idx) 75163fa5caSBlue Swirl { 76163fa5caSBlue Swirl int access_perms = 0; 77a8170e5eSAvi Kivity hwaddr pde_ptr; 78163fa5caSBlue Swirl uint32_t pde; 79163fa5caSBlue Swirl int error_code = 0, is_dirty, is_user; 80163fa5caSBlue Swirl unsigned long page_offset; 815a59fbceSRichard Henderson CPUState *cs = env_cpu(env); 823c818dfcSPeter Maydell MemTxResult result; 83163fa5caSBlue Swirl 84163fa5caSBlue Swirl is_user = mmu_idx == MMU_USER_IDX; 85163fa5caSBlue Swirl 86af7a06baSRichard Henderson if (mmu_idx == MMU_PHYS_IDX) { 8771b7794bSRichard Henderson full->lg_page_size = TARGET_PAGE_BITS; 88163fa5caSBlue Swirl /* Boot mode: instruction fetches are taken from PROM */ 89576e1c4cSIgor Mammedov if (rw == 2 && (env->mmuregs[0] & env->def.mmu_bm)) { 9071b7794bSRichard Henderson full->phys_addr = env->prom_addr | (address & 0x7ffffULL); 9171b7794bSRichard Henderson full->prot = PAGE_READ | PAGE_EXEC; 92163fa5caSBlue Swirl return 0; 93163fa5caSBlue Swirl } 9471b7794bSRichard Henderson full->phys_addr = address; 9571b7794bSRichard Henderson full->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 96163fa5caSBlue Swirl return 0; 97163fa5caSBlue Swirl } 98163fa5caSBlue Swirl 99163fa5caSBlue Swirl *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1); 10071b7794bSRichard Henderson full->phys_addr = 0xffffffffffff0000ULL; 101163fa5caSBlue Swirl 102163fa5caSBlue Swirl /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ 103163fa5caSBlue Swirl /* Context base + context number */ 104163fa5caSBlue Swirl pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); 1053c818dfcSPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result); 1063c818dfcSPeter Maydell if (result != MEMTX_OK) { 1073c818dfcSPeter Maydell return 4 << 2; /* Translation fault, L = 0 */ 1083c818dfcSPeter Maydell } 109163fa5caSBlue Swirl 110163fa5caSBlue Swirl /* Ctx pde */ 111163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 112163fa5caSBlue Swirl default: 113163fa5caSBlue Swirl case 0: /* Invalid */ 114163fa5caSBlue Swirl return 1 << 2; 115163fa5caSBlue Swirl case 2: /* L0 PTE, maybe should not happen? */ 116163fa5caSBlue Swirl case 3: /* Reserved */ 117163fa5caSBlue Swirl return 4 << 2; 118163fa5caSBlue Swirl case 1: /* L0 PDE */ 119163fa5caSBlue Swirl pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); 1203c818dfcSPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, 1213c818dfcSPeter Maydell MEMTXATTRS_UNSPECIFIED, &result); 1223c818dfcSPeter Maydell if (result != MEMTX_OK) { 1233c818dfcSPeter Maydell return (1 << 8) | (4 << 2); /* Translation fault, L = 1 */ 1243c818dfcSPeter Maydell } 125163fa5caSBlue Swirl 126163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 127163fa5caSBlue Swirl default: 128163fa5caSBlue Swirl case 0: /* Invalid */ 129163fa5caSBlue Swirl return (1 << 8) | (1 << 2); 130163fa5caSBlue Swirl case 3: /* Reserved */ 131163fa5caSBlue Swirl return (1 << 8) | (4 << 2); 132163fa5caSBlue Swirl case 1: /* L1 PDE */ 133163fa5caSBlue Swirl pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); 1343c818dfcSPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, 1353c818dfcSPeter Maydell MEMTXATTRS_UNSPECIFIED, &result); 1363c818dfcSPeter Maydell if (result != MEMTX_OK) { 1373c818dfcSPeter Maydell return (2 << 8) | (4 << 2); /* Translation fault, L = 2 */ 1383c818dfcSPeter Maydell } 139163fa5caSBlue Swirl 140163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 141163fa5caSBlue Swirl default: 142163fa5caSBlue Swirl case 0: /* Invalid */ 143163fa5caSBlue Swirl return (2 << 8) | (1 << 2); 144163fa5caSBlue Swirl case 3: /* Reserved */ 145163fa5caSBlue Swirl return (2 << 8) | (4 << 2); 146163fa5caSBlue Swirl case 1: /* L2 PDE */ 147163fa5caSBlue Swirl pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); 1483c818dfcSPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, 1493c818dfcSPeter Maydell MEMTXATTRS_UNSPECIFIED, &result); 1503c818dfcSPeter Maydell if (result != MEMTX_OK) { 1513c818dfcSPeter Maydell return (3 << 8) | (4 << 2); /* Translation fault, L = 3 */ 1523c818dfcSPeter Maydell } 153163fa5caSBlue Swirl 154163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 155163fa5caSBlue Swirl default: 156163fa5caSBlue Swirl case 0: /* Invalid */ 157163fa5caSBlue Swirl return (3 << 8) | (1 << 2); 158163fa5caSBlue Swirl case 1: /* PDE, should not happen */ 159163fa5caSBlue Swirl case 3: /* Reserved */ 160163fa5caSBlue Swirl return (3 << 8) | (4 << 2); 161163fa5caSBlue Swirl case 2: /* L3 PTE */ 1621658dd32SBlue Swirl page_offset = 0; 163163fa5caSBlue Swirl } 16471b7794bSRichard Henderson full->lg_page_size = TARGET_PAGE_BITS; 165163fa5caSBlue Swirl break; 166163fa5caSBlue Swirl case 2: /* L2 PTE */ 1671658dd32SBlue Swirl page_offset = address & 0x3f000; 16871b7794bSRichard Henderson full->lg_page_size = 18; 169163fa5caSBlue Swirl } 170163fa5caSBlue Swirl break; 171163fa5caSBlue Swirl case 2: /* L1 PTE */ 1721658dd32SBlue Swirl page_offset = address & 0xfff000; 17371b7794bSRichard Henderson full->lg_page_size = 24; 17471b7794bSRichard Henderson break; 175163fa5caSBlue Swirl } 176163fa5caSBlue Swirl } 177163fa5caSBlue Swirl 178163fa5caSBlue Swirl /* check access */ 179163fa5caSBlue Swirl access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; 180163fa5caSBlue Swirl error_code = access_table[*access_index][access_perms]; 181163fa5caSBlue Swirl if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) { 182163fa5caSBlue Swirl return error_code; 183163fa5caSBlue Swirl } 184163fa5caSBlue Swirl 185163fa5caSBlue Swirl /* update page modified and dirty bits */ 186163fa5caSBlue Swirl is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); 187163fa5caSBlue Swirl if (!(pde & PG_ACCESSED_MASK) || is_dirty) { 188163fa5caSBlue Swirl pde |= PG_ACCESSED_MASK; 189163fa5caSBlue Swirl if (is_dirty) { 190163fa5caSBlue Swirl pde |= PG_MODIFIED_MASK; 191163fa5caSBlue Swirl } 1922198a121SEdgar E. Iglesias stl_phys_notdirty(cs->as, pde_ptr, pde); 193163fa5caSBlue Swirl } 194163fa5caSBlue Swirl 195163fa5caSBlue Swirl /* the page can be put in the TLB */ 19671b7794bSRichard Henderson full->prot = perm_table[is_user][access_perms]; 197163fa5caSBlue Swirl if (!(pde & PG_MODIFIED_MASK)) { 198163fa5caSBlue Swirl /* only set write access if already dirty... otherwise wait 199163fa5caSBlue Swirl for dirty access */ 20071b7794bSRichard Henderson full->prot &= ~PAGE_WRITE; 201163fa5caSBlue Swirl } 202163fa5caSBlue Swirl 203163fa5caSBlue Swirl /* Even if large ptes, we map only one 4KB page in the cache to 204163fa5caSBlue Swirl avoid filling it too fast */ 20571b7794bSRichard Henderson full->phys_addr = ((hwaddr)(pde & PTE_ADDR_MASK) << 4) + page_offset; 206163fa5caSBlue Swirl return error_code; 207163fa5caSBlue Swirl } 208163fa5caSBlue Swirl 209163fa5caSBlue Swirl /* Perform address translation */ 210e84942f2SRichard Henderson bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 211e84942f2SRichard Henderson MMUAccessType access_type, int mmu_idx, 212e84942f2SRichard Henderson bool probe, uintptr_t retaddr) 213163fa5caSBlue Swirl { 21477976769SPhilippe Mathieu-Daudé CPUSPARCState *env = cpu_env(cs); 21571b7794bSRichard Henderson CPUTLBEntryFull full = {}; 216163fa5caSBlue Swirl target_ulong vaddr; 21771b7794bSRichard Henderson int error_code = 0, access_index; 218163fa5caSBlue Swirl 219e84942f2SRichard Henderson /* 220e84942f2SRichard Henderson * TODO: If we ever need tlb_vaddr_to_host for this target, 221e84942f2SRichard Henderson * then we must figure out how to manipulate FSR and FAR 222e84942f2SRichard Henderson * when both MMU_NF and probe are set. In the meantime, 223e84942f2SRichard Henderson * do not support this use case. 224e84942f2SRichard Henderson */ 225e84942f2SRichard Henderson assert(!probe); 226e84942f2SRichard Henderson 2271658dd32SBlue Swirl address &= TARGET_PAGE_MASK; 22871b7794bSRichard Henderson error_code = get_physical_address(env, &full, &access_index, 22971b7794bSRichard Henderson address, access_type, mmu_idx); 2301658dd32SBlue Swirl vaddr = address; 231e84942f2SRichard Henderson if (likely(error_code == 0)) { 232339aaf5bSAntony Pavlov qemu_log_mask(CPU_LOG_MMU, 233e84942f2SRichard Henderson "Translate at %" VADDR_PRIx " -> " 234883f2c59SPhilippe Mathieu-Daudé HWADDR_FMT_plx ", vaddr " TARGET_FMT_lx "\n", 23571b7794bSRichard Henderson address, full.phys_addr, vaddr); 23671b7794bSRichard Henderson tlb_set_page_full(cs, mmu_idx, vaddr, &full); 237e84942f2SRichard Henderson return true; 238163fa5caSBlue Swirl } 239163fa5caSBlue Swirl 240163fa5caSBlue Swirl if (env->mmuregs[3]) { /* Fault status register */ 241163fa5caSBlue Swirl env->mmuregs[3] = 1; /* overflow (not read before another fault) */ 242163fa5caSBlue Swirl } 243163fa5caSBlue Swirl env->mmuregs[3] |= (access_index << 5) | error_code | 2; 244163fa5caSBlue Swirl env->mmuregs[4] = address; /* Fault address register */ 245163fa5caSBlue Swirl 246163fa5caSBlue Swirl if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) { 247163fa5caSBlue Swirl /* No fault mode: if a mapping is available, just override 248163fa5caSBlue Swirl permissions. If no mapping is available, redirect accesses to 249163fa5caSBlue Swirl neverland. Fake/overridden mappings will be flushed when 250163fa5caSBlue Swirl switching to normal mode. */ 25171b7794bSRichard Henderson full.prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 25271b7794bSRichard Henderson tlb_set_page_full(cs, mmu_idx, vaddr, &full); 253e84942f2SRichard Henderson return true; 254163fa5caSBlue Swirl } else { 255e84942f2SRichard Henderson if (access_type == MMU_INST_FETCH) { 25627103424SAndreas Färber cs->exception_index = TT_TFAULT; 257163fa5caSBlue Swirl } else { 25827103424SAndreas Färber cs->exception_index = TT_DFAULT; 259163fa5caSBlue Swirl } 260e84942f2SRichard Henderson cpu_loop_exit_restore(cs, retaddr); 261163fa5caSBlue Swirl } 262163fa5caSBlue Swirl } 263163fa5caSBlue Swirl 264c5f9864eSAndreas Färber target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev) 265163fa5caSBlue Swirl { 2665a59fbceSRichard Henderson CPUState *cs = env_cpu(env); 267a8170e5eSAvi Kivity hwaddr pde_ptr; 268163fa5caSBlue Swirl uint32_t pde; 269d86a9ad3SPeter Maydell MemTxResult result; 270d86a9ad3SPeter Maydell 271d86a9ad3SPeter Maydell /* 272d86a9ad3SPeter Maydell * TODO: MMU probe operations are supposed to set the fault 273d86a9ad3SPeter Maydell * status registers, but we don't do this. 274d86a9ad3SPeter Maydell */ 275163fa5caSBlue Swirl 276163fa5caSBlue Swirl /* Context base + context number */ 277a8170e5eSAvi Kivity pde_ptr = (hwaddr)(env->mmuregs[1] << 4) + 278163fa5caSBlue Swirl (env->mmuregs[2] << 2); 279d86a9ad3SPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result); 280d86a9ad3SPeter Maydell if (result != MEMTX_OK) { 281d86a9ad3SPeter Maydell return 0; 282d86a9ad3SPeter Maydell } 283163fa5caSBlue Swirl 284163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 285163fa5caSBlue Swirl default: 286163fa5caSBlue Swirl case 0: /* Invalid */ 287163fa5caSBlue Swirl case 2: /* PTE, maybe should not happen? */ 288163fa5caSBlue Swirl case 3: /* Reserved */ 289163fa5caSBlue Swirl return 0; 290163fa5caSBlue Swirl case 1: /* L1 PDE */ 291163fa5caSBlue Swirl if (mmulev == 3) { 292163fa5caSBlue Swirl return pde; 293163fa5caSBlue Swirl } 294163fa5caSBlue Swirl pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); 295d86a9ad3SPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, 296d86a9ad3SPeter Maydell MEMTXATTRS_UNSPECIFIED, &result); 297d86a9ad3SPeter Maydell if (result != MEMTX_OK) { 298d86a9ad3SPeter Maydell return 0; 299d86a9ad3SPeter Maydell } 300163fa5caSBlue Swirl 301163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 302163fa5caSBlue Swirl default: 303163fa5caSBlue Swirl case 0: /* Invalid */ 304163fa5caSBlue Swirl case 3: /* Reserved */ 305163fa5caSBlue Swirl return 0; 306163fa5caSBlue Swirl case 2: /* L1 PTE */ 307163fa5caSBlue Swirl return pde; 308163fa5caSBlue Swirl case 1: /* L2 PDE */ 309163fa5caSBlue Swirl if (mmulev == 2) { 310163fa5caSBlue Swirl return pde; 311163fa5caSBlue Swirl } 312163fa5caSBlue Swirl pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); 313d86a9ad3SPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, 314d86a9ad3SPeter Maydell MEMTXATTRS_UNSPECIFIED, &result); 315d86a9ad3SPeter Maydell if (result != MEMTX_OK) { 316d86a9ad3SPeter Maydell return 0; 317d86a9ad3SPeter Maydell } 318163fa5caSBlue Swirl 319163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 320163fa5caSBlue Swirl default: 321163fa5caSBlue Swirl case 0: /* Invalid */ 322163fa5caSBlue Swirl case 3: /* Reserved */ 323163fa5caSBlue Swirl return 0; 324163fa5caSBlue Swirl case 2: /* L2 PTE */ 325163fa5caSBlue Swirl return pde; 326163fa5caSBlue Swirl case 1: /* L3 PDE */ 327163fa5caSBlue Swirl if (mmulev == 1) { 328163fa5caSBlue Swirl return pde; 329163fa5caSBlue Swirl } 330163fa5caSBlue Swirl pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); 331d86a9ad3SPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, 332d86a9ad3SPeter Maydell MEMTXATTRS_UNSPECIFIED, &result); 333d86a9ad3SPeter Maydell if (result != MEMTX_OK) { 334d86a9ad3SPeter Maydell return 0; 335d86a9ad3SPeter Maydell } 336163fa5caSBlue Swirl 337163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 338163fa5caSBlue Swirl default: 339163fa5caSBlue Swirl case 0: /* Invalid */ 340163fa5caSBlue Swirl case 1: /* PDE, should not happen */ 341163fa5caSBlue Swirl case 3: /* Reserved */ 342163fa5caSBlue Swirl return 0; 343163fa5caSBlue Swirl case 2: /* L3 PTE */ 344163fa5caSBlue Swirl return pde; 345163fa5caSBlue Swirl } 346163fa5caSBlue Swirl } 347163fa5caSBlue Swirl } 348163fa5caSBlue Swirl } 349163fa5caSBlue Swirl return 0; 350163fa5caSBlue Swirl } 351163fa5caSBlue Swirl 352fad866daSMarkus Armbruster void dump_mmu(CPUSPARCState *env) 353163fa5caSBlue Swirl { 3545a59fbceSRichard Henderson CPUState *cs = env_cpu(env); 355163fa5caSBlue Swirl target_ulong va, va1, va2; 356163fa5caSBlue Swirl unsigned int n, m, o; 3579dffeec2SPeter Maydell hwaddr pa; 358163fa5caSBlue Swirl uint32_t pde; 359163fa5caSBlue Swirl 360883f2c59SPhilippe Mathieu-Daudé qemu_printf("Root ptr: " HWADDR_FMT_plx ", ctx: %d\n", 361a8170e5eSAvi Kivity (hwaddr)env->mmuregs[1] << 4, env->mmuregs[2]); 362163fa5caSBlue Swirl for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { 363163fa5caSBlue Swirl pde = mmu_probe(env, va, 2); 364163fa5caSBlue Swirl if (pde) { 36500b941e5SAndreas Färber pa = cpu_get_phys_page_debug(cs, va); 366883f2c59SPhilippe Mathieu-Daudé qemu_printf("VA: " TARGET_FMT_lx ", PA: " HWADDR_FMT_plx 367163fa5caSBlue Swirl " PDE: " TARGET_FMT_lx "\n", va, pa, pde); 368163fa5caSBlue Swirl for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { 369163fa5caSBlue Swirl pde = mmu_probe(env, va1, 1); 370163fa5caSBlue Swirl if (pde) { 37100b941e5SAndreas Färber pa = cpu_get_phys_page_debug(cs, va1); 372fad866daSMarkus Armbruster qemu_printf(" VA: " TARGET_FMT_lx ", PA: " 373883f2c59SPhilippe Mathieu-Daudé HWADDR_FMT_plx " PDE: " TARGET_FMT_lx "\n", 374163fa5caSBlue Swirl va1, pa, pde); 375163fa5caSBlue Swirl for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { 376163fa5caSBlue Swirl pde = mmu_probe(env, va2, 0); 377163fa5caSBlue Swirl if (pde) { 37800b941e5SAndreas Färber pa = cpu_get_phys_page_debug(cs, va2); 379fad866daSMarkus Armbruster qemu_printf(" VA: " TARGET_FMT_lx ", PA: " 380883f2c59SPhilippe Mathieu-Daudé HWADDR_FMT_plx " PTE: " 381163fa5caSBlue Swirl TARGET_FMT_lx "\n", 382163fa5caSBlue Swirl va2, pa, pde); 383163fa5caSBlue Swirl } 384163fa5caSBlue Swirl } 385163fa5caSBlue Swirl } 386163fa5caSBlue Swirl } 387163fa5caSBlue Swirl } 388163fa5caSBlue Swirl } 389163fa5caSBlue Swirl } 390163fa5caSBlue Swirl 391163fa5caSBlue Swirl /* Gdb expects all registers windows to be flushed in ram. This function handles 392163fa5caSBlue Swirl * reads (and only reads) in stack frames as if windows were flushed. We assume 393163fa5caSBlue Swirl * that the sparc ABI is followed. 394163fa5caSBlue Swirl */ 395f3659eeeSAndreas Färber int sparc_cpu_memory_rw_debug(CPUState *cs, vaddr address, 396581ca582SRichard Henderson uint8_t *buf, size_t len, bool is_write) 397163fa5caSBlue Swirl { 39877976769SPhilippe Mathieu-Daudé CPUSPARCState *env = cpu_env(cs); 399f3659eeeSAndreas Färber target_ulong addr = address; 400163fa5caSBlue Swirl int i; 401163fa5caSBlue Swirl int len1; 402163fa5caSBlue Swirl int cwp = env->cwp; 403163fa5caSBlue Swirl 404163fa5caSBlue Swirl if (!is_write) { 405163fa5caSBlue Swirl for (i = 0; i < env->nwindows; i++) { 406163fa5caSBlue Swirl int off; 407163fa5caSBlue Swirl target_ulong fp = env->regbase[cwp * 16 + 22]; 408163fa5caSBlue Swirl 409163fa5caSBlue Swirl /* Assume fp == 0 means end of frame. */ 410163fa5caSBlue Swirl if (fp == 0) { 411163fa5caSBlue Swirl break; 412163fa5caSBlue Swirl } 413163fa5caSBlue Swirl 414163fa5caSBlue Swirl cwp = cpu_cwp_inc(env, cwp + 1); 415163fa5caSBlue Swirl 416163fa5caSBlue Swirl /* Invalid window ? */ 417163fa5caSBlue Swirl if (env->wim & (1 << cwp)) { 418163fa5caSBlue Swirl break; 419163fa5caSBlue Swirl } 420163fa5caSBlue Swirl 421163fa5caSBlue Swirl /* According to the ABI, the stack is growing downward. */ 422163fa5caSBlue Swirl if (addr + len < fp) { 423163fa5caSBlue Swirl break; 424163fa5caSBlue Swirl } 425163fa5caSBlue Swirl 426163fa5caSBlue Swirl /* Not in this frame. */ 427163fa5caSBlue Swirl if (addr > fp + 64) { 428163fa5caSBlue Swirl continue; 429163fa5caSBlue Swirl } 430163fa5caSBlue Swirl 431163fa5caSBlue Swirl /* Handle access before this window. */ 432163fa5caSBlue Swirl if (addr < fp) { 433163fa5caSBlue Swirl len1 = fp - addr; 434f17ec444SAndreas Färber if (cpu_memory_rw_debug(cs, addr, buf, len1, is_write) != 0) { 435163fa5caSBlue Swirl return -1; 436163fa5caSBlue Swirl } 437163fa5caSBlue Swirl addr += len1; 438163fa5caSBlue Swirl len -= len1; 439163fa5caSBlue Swirl buf += len1; 440163fa5caSBlue Swirl } 441163fa5caSBlue Swirl 442163fa5caSBlue Swirl /* Access byte per byte to registers. Not very efficient but speed 443163fa5caSBlue Swirl * is not critical. 444163fa5caSBlue Swirl */ 445163fa5caSBlue Swirl off = addr - fp; 446163fa5caSBlue Swirl len1 = 64 - off; 447163fa5caSBlue Swirl 448163fa5caSBlue Swirl if (len1 > len) { 449163fa5caSBlue Swirl len1 = len; 450163fa5caSBlue Swirl } 451163fa5caSBlue Swirl 452163fa5caSBlue Swirl for (; len1; len1--) { 453163fa5caSBlue Swirl int reg = cwp * 16 + 8 + (off >> 2); 454163fa5caSBlue Swirl union { 455163fa5caSBlue Swirl uint32_t v; 456163fa5caSBlue Swirl uint8_t c[4]; 457163fa5caSBlue Swirl } u; 458163fa5caSBlue Swirl u.v = cpu_to_be32(env->regbase[reg]); 459163fa5caSBlue Swirl *buf++ = u.c[off & 3]; 460163fa5caSBlue Swirl addr++; 461163fa5caSBlue Swirl len--; 462163fa5caSBlue Swirl off++; 463163fa5caSBlue Swirl } 464163fa5caSBlue Swirl 465163fa5caSBlue Swirl if (len == 0) { 466163fa5caSBlue Swirl return 0; 467163fa5caSBlue Swirl } 468163fa5caSBlue Swirl } 469163fa5caSBlue Swirl } 470f17ec444SAndreas Färber return cpu_memory_rw_debug(cs, addr, buf, len, is_write); 471163fa5caSBlue Swirl } 472163fa5caSBlue Swirl 473163fa5caSBlue Swirl #else /* !TARGET_SPARC64 */ 474163fa5caSBlue Swirl 475163fa5caSBlue Swirl /* 41 bit physical address space */ 476a8170e5eSAvi Kivity static inline hwaddr ultrasparc_truncate_physical(uint64_t x) 477163fa5caSBlue Swirl { 478163fa5caSBlue Swirl return x & 0x1ffffffffffULL; 479163fa5caSBlue Swirl } 480163fa5caSBlue Swirl 481163fa5caSBlue Swirl /* 482163fa5caSBlue Swirl * UltraSparc IIi I/DMMUs 483163fa5caSBlue Swirl */ 484163fa5caSBlue Swirl 485163fa5caSBlue Swirl /* Returns true if TTE tag is valid and matches virtual address value 486163fa5caSBlue Swirl in context requires virtual address mask value calculated from TTE 487163fa5caSBlue Swirl entry size */ 488163fa5caSBlue Swirl static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, 489163fa5caSBlue Swirl uint64_t address, uint64_t context, 490a8170e5eSAvi Kivity hwaddr *physical) 491163fa5caSBlue Swirl { 492913b5f28SArtyom Tarasenko uint64_t mask = -(8192ULL << 3 * TTE_PGSIZE(tlb->tte)); 493163fa5caSBlue Swirl 494163fa5caSBlue Swirl /* valid, context match, virtual address match? */ 495163fa5caSBlue Swirl if (TTE_IS_VALID(tlb->tte) && 496163fa5caSBlue Swirl (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context)) 497163fa5caSBlue Swirl && compare_masked(address, tlb->tag, mask)) { 498163fa5caSBlue Swirl /* decode physical address */ 499163fa5caSBlue Swirl *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL; 500163fa5caSBlue Swirl return 1; 501163fa5caSBlue Swirl } 502163fa5caSBlue Swirl 503163fa5caSBlue Swirl return 0; 504163fa5caSBlue Swirl } 505163fa5caSBlue Swirl 506c0e0c6feSRichard Henderson static uint64_t build_sfsr(CPUSPARCState *env, int mmu_idx, int rw) 507c0e0c6feSRichard Henderson { 508c0e0c6feSRichard Henderson uint64_t sfsr = SFSR_VALID_BIT; 509c0e0c6feSRichard Henderson 510c0e0c6feSRichard Henderson switch (mmu_idx) { 511c0e0c6feSRichard Henderson case MMU_PHYS_IDX: 512c0e0c6feSRichard Henderson sfsr |= SFSR_CT_NOTRANS; 513c0e0c6feSRichard Henderson break; 514c0e0c6feSRichard Henderson case MMU_USER_IDX: 515c0e0c6feSRichard Henderson case MMU_KERNEL_IDX: 516c0e0c6feSRichard Henderson sfsr |= SFSR_CT_PRIMARY; 517c0e0c6feSRichard Henderson break; 518c0e0c6feSRichard Henderson case MMU_USER_SECONDARY_IDX: 519c0e0c6feSRichard Henderson case MMU_KERNEL_SECONDARY_IDX: 520c0e0c6feSRichard Henderson sfsr |= SFSR_CT_SECONDARY; 521c0e0c6feSRichard Henderson break; 522c0e0c6feSRichard Henderson case MMU_NUCLEUS_IDX: 523c0e0c6feSRichard Henderson sfsr |= SFSR_CT_NUCLEUS; 524c0e0c6feSRichard Henderson break; 525c0e0c6feSRichard Henderson default: 526c0e0c6feSRichard Henderson g_assert_not_reached(); 527c0e0c6feSRichard Henderson } 528c0e0c6feSRichard Henderson 529c0e0c6feSRichard Henderson if (rw == 1) { 530c0e0c6feSRichard Henderson sfsr |= SFSR_WRITE_BIT; 531c0e0c6feSRichard Henderson } else if (rw == 4) { 532c0e0c6feSRichard Henderson sfsr |= SFSR_NF_BIT; 533c0e0c6feSRichard Henderson } 534c0e0c6feSRichard Henderson 535c0e0c6feSRichard Henderson if (env->pstate & PS_PRIV) { 536c0e0c6feSRichard Henderson sfsr |= SFSR_PR_BIT; 537c0e0c6feSRichard Henderson } 538c0e0c6feSRichard Henderson 539c0e0c6feSRichard Henderson if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */ 540c0e0c6feSRichard Henderson sfsr |= SFSR_OW_BIT; /* overflow (not read before another fault) */ 541c0e0c6feSRichard Henderson } 542c0e0c6feSRichard Henderson 543c0e0c6feSRichard Henderson /* FIXME: ASI field in SFSR must be set */ 544c0e0c6feSRichard Henderson 545c0e0c6feSRichard Henderson return sfsr; 546c0e0c6feSRichard Henderson } 547c0e0c6feSRichard Henderson 54871b7794bSRichard Henderson static int get_physical_address_data(CPUSPARCState *env, CPUTLBEntryFull *full, 549163fa5caSBlue Swirl target_ulong address, int rw, int mmu_idx) 550163fa5caSBlue Swirl { 5515a59fbceSRichard Henderson CPUState *cs = env_cpu(env); 552163fa5caSBlue Swirl unsigned int i; 553c0e0c6feSRichard Henderson uint64_t sfsr; 554163fa5caSBlue Swirl uint64_t context; 555af7a06baSRichard Henderson bool is_user = false; 556163fa5caSBlue Swirl 557c0e0c6feSRichard Henderson sfsr = build_sfsr(env, mmu_idx, rw); 558c0e0c6feSRichard Henderson 559163fa5caSBlue Swirl switch (mmu_idx) { 560af7a06baSRichard Henderson case MMU_PHYS_IDX: 561af7a06baSRichard Henderson g_assert_not_reached(); 562163fa5caSBlue Swirl case MMU_USER_IDX: 563af7a06baSRichard Henderson is_user = true; 564af7a06baSRichard Henderson /* fallthru */ 565163fa5caSBlue Swirl case MMU_KERNEL_IDX: 566163fa5caSBlue Swirl context = env->dmmu.mmu_primary_context & 0x1fff; 567163fa5caSBlue Swirl break; 568163fa5caSBlue Swirl case MMU_USER_SECONDARY_IDX: 569af7a06baSRichard Henderson is_user = true; 570af7a06baSRichard Henderson /* fallthru */ 571163fa5caSBlue Swirl case MMU_KERNEL_SECONDARY_IDX: 572163fa5caSBlue Swirl context = env->dmmu.mmu_secondary_context & 0x1fff; 573163fa5caSBlue Swirl break; 574163fa5caSBlue Swirl default: 575163fa5caSBlue Swirl context = 0; 576163fa5caSBlue Swirl break; 577163fa5caSBlue Swirl } 578163fa5caSBlue Swirl 579163fa5caSBlue Swirl for (i = 0; i < 64; i++) { 580163fa5caSBlue Swirl /* ctx match, vaddr match, valid? */ 58171b7794bSRichard Henderson if (ultrasparc_tag_match(&env->dtlb[i], address, context, 58271b7794bSRichard Henderson &full->phys_addr)) { 583163fa5caSBlue Swirl int do_fault = 0; 584163fa5caSBlue Swirl 585ccdb4c55STony Nguyen if (TTE_IS_IE(env->dtlb[i].tte)) { 586a0ff4a87SRichard Henderson full->tlb_fill_flags |= TLB_BSWAP; 587ccdb4c55STony Nguyen } 588ccdb4c55STony Nguyen 589163fa5caSBlue Swirl /* access ok? */ 590163fa5caSBlue Swirl /* multiple bits in SFSR.FT may be set on TT_DFAULT */ 591163fa5caSBlue Swirl if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) { 592163fa5caSBlue Swirl do_fault = 1; 593163fa5caSBlue Swirl sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */ 594ec0ceb17SBlue Swirl trace_mmu_helper_dfault(address, context, mmu_idx, env->tl); 595163fa5caSBlue Swirl } 596163fa5caSBlue Swirl if (rw == 4) { 597163fa5caSBlue Swirl if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) { 598163fa5caSBlue Swirl do_fault = 1; 599163fa5caSBlue Swirl sfsr |= SFSR_FT_NF_E_BIT; 600163fa5caSBlue Swirl } 601163fa5caSBlue Swirl } else { 602163fa5caSBlue Swirl if (TTE_IS_NFO(env->dtlb[i].tte)) { 603163fa5caSBlue Swirl do_fault = 1; 604163fa5caSBlue Swirl sfsr |= SFSR_FT_NFO_BIT; 605163fa5caSBlue Swirl } 606163fa5caSBlue Swirl } 607163fa5caSBlue Swirl 608163fa5caSBlue Swirl if (do_fault) { 609163fa5caSBlue Swirl /* faults above are reported with TT_DFAULT. */ 61027103424SAndreas Färber cs->exception_index = TT_DFAULT; 611163fa5caSBlue Swirl } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) { 612163fa5caSBlue Swirl do_fault = 1; 61327103424SAndreas Färber cs->exception_index = TT_DPROT; 614163fa5caSBlue Swirl 615ec0ceb17SBlue Swirl trace_mmu_helper_dprot(address, context, mmu_idx, env->tl); 616163fa5caSBlue Swirl } 617163fa5caSBlue Swirl 618163fa5caSBlue Swirl if (!do_fault) { 61971b7794bSRichard Henderson full->prot = PAGE_READ; 620163fa5caSBlue Swirl if (TTE_IS_W_OK(env->dtlb[i].tte)) { 62171b7794bSRichard Henderson full->prot |= PAGE_WRITE; 622163fa5caSBlue Swirl } 623163fa5caSBlue Swirl 624163fa5caSBlue Swirl TTE_SET_USED(env->dtlb[i].tte); 625163fa5caSBlue Swirl 626163fa5caSBlue Swirl return 0; 627163fa5caSBlue Swirl } 628163fa5caSBlue Swirl 629c0e0c6feSRichard Henderson env->dmmu.sfsr = sfsr; 630163fa5caSBlue Swirl env->dmmu.sfar = address; /* Fault address register */ 631163fa5caSBlue Swirl env->dmmu.tag_access = (address & ~0x1fffULL) | context; 632163fa5caSBlue Swirl return 1; 633163fa5caSBlue Swirl } 634163fa5caSBlue Swirl } 635163fa5caSBlue Swirl 636ec0ceb17SBlue Swirl trace_mmu_helper_dmiss(address, context); 637163fa5caSBlue Swirl 638163fa5caSBlue Swirl /* 639163fa5caSBlue Swirl * On MMU misses: 640163fa5caSBlue Swirl * - UltraSPARC IIi: SFSR and SFAR unmodified 641163fa5caSBlue Swirl * - JPS1: SFAR updated and some fields of SFSR updated 642163fa5caSBlue Swirl */ 643163fa5caSBlue Swirl env->dmmu.tag_access = (address & ~0x1fffULL) | context; 64427103424SAndreas Färber cs->exception_index = TT_DMISS; 645163fa5caSBlue Swirl return 1; 646163fa5caSBlue Swirl } 647163fa5caSBlue Swirl 64871b7794bSRichard Henderson static int get_physical_address_code(CPUSPARCState *env, CPUTLBEntryFull *full, 649163fa5caSBlue Swirl target_ulong address, int mmu_idx) 650163fa5caSBlue Swirl { 6515a59fbceSRichard Henderson CPUState *cs = env_cpu(env); 652163fa5caSBlue Swirl unsigned int i; 653163fa5caSBlue Swirl uint64_t context; 654af7a06baSRichard Henderson bool is_user = false; 655163fa5caSBlue Swirl 656af7a06baSRichard Henderson switch (mmu_idx) { 657af7a06baSRichard Henderson case MMU_PHYS_IDX: 658af7a06baSRichard Henderson case MMU_USER_SECONDARY_IDX: 659af7a06baSRichard Henderson case MMU_KERNEL_SECONDARY_IDX: 660af7a06baSRichard Henderson g_assert_not_reached(); 661af7a06baSRichard Henderson case MMU_USER_IDX: 662af7a06baSRichard Henderson is_user = true; 663af7a06baSRichard Henderson /* fallthru */ 664af7a06baSRichard Henderson case MMU_KERNEL_IDX: 665af7a06baSRichard Henderson context = env->dmmu.mmu_primary_context & 0x1fff; 666af7a06baSRichard Henderson break; 667af7a06baSRichard Henderson default: 668af7a06baSRichard Henderson context = 0; 669af7a06baSRichard Henderson break; 670163fa5caSBlue Swirl } 671163fa5caSBlue Swirl 672163fa5caSBlue Swirl if (env->tl == 0) { 673163fa5caSBlue Swirl /* PRIMARY context */ 674163fa5caSBlue Swirl context = env->dmmu.mmu_primary_context & 0x1fff; 675163fa5caSBlue Swirl } else { 676163fa5caSBlue Swirl /* NUCLEUS context */ 677163fa5caSBlue Swirl context = 0; 678163fa5caSBlue Swirl } 679163fa5caSBlue Swirl 680163fa5caSBlue Swirl for (i = 0; i < 64; i++) { 681163fa5caSBlue Swirl /* ctx match, vaddr match, valid? */ 682163fa5caSBlue Swirl if (ultrasparc_tag_match(&env->itlb[i], 68371b7794bSRichard Henderson address, context, &full->phys_addr)) { 684163fa5caSBlue Swirl /* access ok? */ 685163fa5caSBlue Swirl if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) { 686163fa5caSBlue Swirl /* Fault status register */ 687163fa5caSBlue Swirl if (env->immu.sfsr & SFSR_VALID_BIT) { 688163fa5caSBlue Swirl env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before 689163fa5caSBlue Swirl another fault) */ 690163fa5caSBlue Swirl } else { 691163fa5caSBlue Swirl env->immu.sfsr = 0; 692163fa5caSBlue Swirl } 693163fa5caSBlue Swirl if (env->pstate & PS_PRIV) { 694163fa5caSBlue Swirl env->immu.sfsr |= SFSR_PR_BIT; 695163fa5caSBlue Swirl } 696163fa5caSBlue Swirl if (env->tl > 0) { 697163fa5caSBlue Swirl env->immu.sfsr |= SFSR_CT_NUCLEUS; 698163fa5caSBlue Swirl } 699163fa5caSBlue Swirl 700163fa5caSBlue Swirl /* FIXME: ASI field in SFSR must be set */ 701163fa5caSBlue Swirl env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT; 70227103424SAndreas Färber cs->exception_index = TT_TFAULT; 703163fa5caSBlue Swirl 704163fa5caSBlue Swirl env->immu.tag_access = (address & ~0x1fffULL) | context; 705163fa5caSBlue Swirl 706ec0ceb17SBlue Swirl trace_mmu_helper_tfault(address, context); 707163fa5caSBlue Swirl 708163fa5caSBlue Swirl return 1; 709163fa5caSBlue Swirl } 71071b7794bSRichard Henderson full->prot = PAGE_EXEC; 711163fa5caSBlue Swirl TTE_SET_USED(env->itlb[i].tte); 712163fa5caSBlue Swirl return 0; 713163fa5caSBlue Swirl } 714163fa5caSBlue Swirl } 715163fa5caSBlue Swirl 716ec0ceb17SBlue Swirl trace_mmu_helper_tmiss(address, context); 717163fa5caSBlue Swirl 718163fa5caSBlue Swirl /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */ 719163fa5caSBlue Swirl env->immu.tag_access = (address & ~0x1fffULL) | context; 72027103424SAndreas Färber cs->exception_index = TT_TMISS; 721163fa5caSBlue Swirl return 1; 722163fa5caSBlue Swirl } 723163fa5caSBlue Swirl 72471b7794bSRichard Henderson static int get_physical_address(CPUSPARCState *env, CPUTLBEntryFull *full, 72571b7794bSRichard Henderson int *access_index, target_ulong address, 72671b7794bSRichard Henderson int rw, int mmu_idx) 727163fa5caSBlue Swirl { 728163fa5caSBlue Swirl /* ??? We treat everything as a small page, then explicitly flush 729163fa5caSBlue Swirl everything when an entry is evicted. */ 73071b7794bSRichard Henderson full->lg_page_size = TARGET_PAGE_BITS; 731163fa5caSBlue Swirl 732163fa5caSBlue Swirl /* safety net to catch wrong softmmu index use from dynamic code */ 733163fa5caSBlue Swirl if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) { 734ec0ceb17SBlue Swirl if (rw == 2) { 735ec0ceb17SBlue Swirl trace_mmu_helper_get_phys_addr_code(env->tl, mmu_idx, 736ec0ceb17SBlue Swirl env->dmmu.mmu_primary_context, 737ec0ceb17SBlue Swirl env->dmmu.mmu_secondary_context, 738ec0ceb17SBlue Swirl address); 739ec0ceb17SBlue Swirl } else { 740ec0ceb17SBlue Swirl trace_mmu_helper_get_phys_addr_data(env->tl, mmu_idx, 741163fa5caSBlue Swirl env->dmmu.mmu_primary_context, 742163fa5caSBlue Swirl env->dmmu.mmu_secondary_context, 743163fa5caSBlue Swirl address); 744163fa5caSBlue Swirl } 745ec0ceb17SBlue Swirl } 746163fa5caSBlue Swirl 747af7a06baSRichard Henderson if (mmu_idx == MMU_PHYS_IDX) { 74871b7794bSRichard Henderson full->phys_addr = ultrasparc_truncate_physical(address); 74971b7794bSRichard Henderson full->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 750af7a06baSRichard Henderson return 0; 751af7a06baSRichard Henderson } 752af7a06baSRichard Henderson 753163fa5caSBlue Swirl if (rw == 2) { 75471b7794bSRichard Henderson return get_physical_address_code(env, full, address, mmu_idx); 755163fa5caSBlue Swirl } else { 75671b7794bSRichard Henderson return get_physical_address_data(env, full, address, rw, mmu_idx); 757163fa5caSBlue Swirl } 758163fa5caSBlue Swirl } 759163fa5caSBlue Swirl 760163fa5caSBlue Swirl /* Perform address translation */ 761e84942f2SRichard Henderson bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 762e84942f2SRichard Henderson MMUAccessType access_type, int mmu_idx, 763e84942f2SRichard Henderson bool probe, uintptr_t retaddr) 764163fa5caSBlue Swirl { 76577976769SPhilippe Mathieu-Daudé CPUSPARCState *env = cpu_env(cs); 76671b7794bSRichard Henderson CPUTLBEntryFull full = {}; 76771b7794bSRichard Henderson int error_code = 0, access_index; 768163fa5caSBlue Swirl 7691658dd32SBlue Swirl address &= TARGET_PAGE_MASK; 77071b7794bSRichard Henderson error_code = get_physical_address(env, &full, &access_index, 77171b7794bSRichard Henderson address, access_type, mmu_idx); 772e84942f2SRichard Henderson if (likely(error_code == 0)) { 77371b7794bSRichard Henderson trace_mmu_helper_mmu_fault(address, full.phys_addr, mmu_idx, env->tl, 774163fa5caSBlue Swirl env->dmmu.mmu_primary_context, 775163fa5caSBlue Swirl env->dmmu.mmu_secondary_context); 77671b7794bSRichard Henderson tlb_set_page_full(cs, mmu_idx, address, &full); 777e84942f2SRichard Henderson return true; 778163fa5caSBlue Swirl } 779e84942f2SRichard Henderson if (probe) { 780e84942f2SRichard Henderson return false; 781e84942f2SRichard Henderson } 782e84942f2SRichard Henderson cpu_loop_exit_restore(cs, retaddr); 783163fa5caSBlue Swirl } 784163fa5caSBlue Swirl 785fad866daSMarkus Armbruster void dump_mmu(CPUSPARCState *env) 786163fa5caSBlue Swirl { 787163fa5caSBlue Swirl unsigned int i; 788163fa5caSBlue Swirl const char *mask; 789163fa5caSBlue Swirl 790fad866daSMarkus Armbruster qemu_printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" 791163fa5caSBlue Swirl PRId64 "\n", 792163fa5caSBlue Swirl env->dmmu.mmu_primary_context, 793163fa5caSBlue Swirl env->dmmu.mmu_secondary_context); 794fad866daSMarkus Armbruster qemu_printf("DMMU Tag Access: %" PRIx64 ", TSB Tag Target: %" PRIx64 795d00a2334SArtyom Tarasenko "\n", env->dmmu.tag_access, env->dmmu.tsb_tag_target); 796163fa5caSBlue Swirl if ((env->lsu & DMMU_E) == 0) { 797fad866daSMarkus Armbruster qemu_printf("DMMU disabled\n"); 798163fa5caSBlue Swirl } else { 799fad866daSMarkus Armbruster qemu_printf("DMMU dump\n"); 800163fa5caSBlue Swirl for (i = 0; i < 64; i++) { 801163fa5caSBlue Swirl switch (TTE_PGSIZE(env->dtlb[i].tte)) { 802163fa5caSBlue Swirl default: 803163fa5caSBlue Swirl case 0x0: 804163fa5caSBlue Swirl mask = " 8k"; 805163fa5caSBlue Swirl break; 806163fa5caSBlue Swirl case 0x1: 807163fa5caSBlue Swirl mask = " 64k"; 808163fa5caSBlue Swirl break; 809163fa5caSBlue Swirl case 0x2: 810163fa5caSBlue Swirl mask = "512k"; 811163fa5caSBlue Swirl break; 812163fa5caSBlue Swirl case 0x3: 813163fa5caSBlue Swirl mask = " 4M"; 814163fa5caSBlue Swirl break; 815163fa5caSBlue Swirl } 816163fa5caSBlue Swirl if (TTE_IS_VALID(env->dtlb[i].tte)) { 817fad866daSMarkus Armbruster qemu_printf("[%02u] VA: %" PRIx64 ", PA: %llx" 818ccdb4c55STony Nguyen ", %s, %s, %s, %s, ie %s, ctx %" PRId64 " %s\n", 819163fa5caSBlue Swirl i, 820163fa5caSBlue Swirl env->dtlb[i].tag & (uint64_t)~0x1fffULL, 821163fa5caSBlue Swirl TTE_PA(env->dtlb[i].tte), 822163fa5caSBlue Swirl mask, 823163fa5caSBlue Swirl TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user", 824163fa5caSBlue Swirl TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO", 825163fa5caSBlue Swirl TTE_IS_LOCKED(env->dtlb[i].tte) ? 826163fa5caSBlue Swirl "locked" : "unlocked", 827ccdb4c55STony Nguyen TTE_IS_IE(env->dtlb[i].tte) ? 828ccdb4c55STony Nguyen "yes" : "no", 829163fa5caSBlue Swirl env->dtlb[i].tag & (uint64_t)0x1fffULL, 830163fa5caSBlue Swirl TTE_IS_GLOBAL(env->dtlb[i].tte) ? 831163fa5caSBlue Swirl "global" : "local"); 832163fa5caSBlue Swirl } 833163fa5caSBlue Swirl } 834163fa5caSBlue Swirl } 835163fa5caSBlue Swirl if ((env->lsu & IMMU_E) == 0) { 836fad866daSMarkus Armbruster qemu_printf("IMMU disabled\n"); 837163fa5caSBlue Swirl } else { 838fad866daSMarkus Armbruster qemu_printf("IMMU dump\n"); 839163fa5caSBlue Swirl for (i = 0; i < 64; i++) { 840163fa5caSBlue Swirl switch (TTE_PGSIZE(env->itlb[i].tte)) { 841163fa5caSBlue Swirl default: 842163fa5caSBlue Swirl case 0x0: 843163fa5caSBlue Swirl mask = " 8k"; 844163fa5caSBlue Swirl break; 845163fa5caSBlue Swirl case 0x1: 846163fa5caSBlue Swirl mask = " 64k"; 847163fa5caSBlue Swirl break; 848163fa5caSBlue Swirl case 0x2: 849163fa5caSBlue Swirl mask = "512k"; 850163fa5caSBlue Swirl break; 851163fa5caSBlue Swirl case 0x3: 852163fa5caSBlue Swirl mask = " 4M"; 853163fa5caSBlue Swirl break; 854163fa5caSBlue Swirl } 855163fa5caSBlue Swirl if (TTE_IS_VALID(env->itlb[i].tte)) { 856fad866daSMarkus Armbruster qemu_printf("[%02u] VA: %" PRIx64 ", PA: %llx" 857163fa5caSBlue Swirl ", %s, %s, %s, ctx %" PRId64 " %s\n", 858163fa5caSBlue Swirl i, 859163fa5caSBlue Swirl env->itlb[i].tag & (uint64_t)~0x1fffULL, 860163fa5caSBlue Swirl TTE_PA(env->itlb[i].tte), 861163fa5caSBlue Swirl mask, 862163fa5caSBlue Swirl TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user", 863163fa5caSBlue Swirl TTE_IS_LOCKED(env->itlb[i].tte) ? 864163fa5caSBlue Swirl "locked" : "unlocked", 865163fa5caSBlue Swirl env->itlb[i].tag & (uint64_t)0x1fffULL, 866163fa5caSBlue Swirl TTE_IS_GLOBAL(env->itlb[i].tte) ? 867163fa5caSBlue Swirl "global" : "local"); 868163fa5caSBlue Swirl } 869163fa5caSBlue Swirl } 870163fa5caSBlue Swirl } 871163fa5caSBlue Swirl } 872163fa5caSBlue Swirl 873163fa5caSBlue Swirl #endif /* TARGET_SPARC64 */ 874163fa5caSBlue Swirl 875a8170e5eSAvi Kivity static int cpu_sparc_get_phys_page(CPUSPARCState *env, hwaddr *phys, 876163fa5caSBlue Swirl target_ulong addr, int rw, int mmu_idx) 877163fa5caSBlue Swirl { 87871b7794bSRichard Henderson CPUTLBEntryFull full = {}; 87971b7794bSRichard Henderson int access_index, ret; 880163fa5caSBlue Swirl 88171b7794bSRichard Henderson ret = get_physical_address(env, &full, &access_index, addr, rw, mmu_idx); 88271b7794bSRichard Henderson if (ret == 0) { 88371b7794bSRichard Henderson *phys = full.phys_addr; 88471b7794bSRichard Henderson } 88571b7794bSRichard Henderson return ret; 886163fa5caSBlue Swirl } 887163fa5caSBlue Swirl 888163fa5caSBlue Swirl #if defined(TARGET_SPARC64) 889a8170e5eSAvi Kivity hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr, 890163fa5caSBlue Swirl int mmu_idx) 891163fa5caSBlue Swirl { 892a8170e5eSAvi Kivity hwaddr phys_addr; 893163fa5caSBlue Swirl 894163fa5caSBlue Swirl if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) { 895163fa5caSBlue Swirl return -1; 896163fa5caSBlue Swirl } 897163fa5caSBlue Swirl return phys_addr; 898163fa5caSBlue Swirl } 899163fa5caSBlue Swirl #endif 900163fa5caSBlue Swirl 90100b941e5SAndreas Färber hwaddr sparc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 902163fa5caSBlue Swirl { 90377976769SPhilippe Mathieu-Daudé CPUSPARCState *env = cpu_env(cs); 904a8170e5eSAvi Kivity hwaddr phys_addr; 9053b916140SRichard Henderson int mmu_idx = cpu_mmu_index(cs, false); 906163fa5caSBlue Swirl 907163fa5caSBlue Swirl if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) { 908163fa5caSBlue Swirl if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) { 909163fa5caSBlue Swirl return -1; 910163fa5caSBlue Swirl } 911163fa5caSBlue Swirl } 912163fa5caSBlue Swirl return phys_addr; 913163fa5caSBlue Swirl } 914aebe5153SRichard Henderson 9158905770bSMarc-André Lureau G_NORETURN void sparc_cpu_do_unaligned_access(CPUState *cs, vaddr addr, 916aebe5153SRichard Henderson MMUAccessType access_type, 917aebe5153SRichard Henderson int mmu_idx, 918aebe5153SRichard Henderson uintptr_t retaddr) 919aebe5153SRichard Henderson { 92077976769SPhilippe Mathieu-Daudé CPUSPARCState *env = cpu_env(cs); 921aebe5153SRichard Henderson 922aebe5153SRichard Henderson #ifdef TARGET_SPARC64 923aebe5153SRichard Henderson env->dmmu.sfsr = build_sfsr(env, mmu_idx, access_type); 924aebe5153SRichard Henderson env->dmmu.sfar = addr; 925aebe5153SRichard Henderson #else 926aebe5153SRichard Henderson env->mmuregs[4] = addr; 927aebe5153SRichard Henderson #endif 928aebe5153SRichard Henderson 929aebe5153SRichard Henderson cpu_raise_exception_ra(env, TT_UNALIGNED, retaddr); 930aebe5153SRichard Henderson } 931