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 9163fa5caSBlue Swirl * version 2 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" 21163fa5caSBlue Swirl #include "cpu.h" 2263c91552SPaolo Bonzini #include "exec/exec-all.h" 23fad866daSMarkus Armbruster #include "qemu/qemu-print.h" 24ec0ceb17SBlue Swirl #include "trace.h" 25163fa5caSBlue Swirl 26163fa5caSBlue Swirl /* Sparc MMU emulation */ 27163fa5caSBlue Swirl 28163fa5caSBlue Swirl #if defined(CONFIG_USER_ONLY) 29163fa5caSBlue Swirl 30e84942f2SRichard Henderson bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 31e84942f2SRichard Henderson MMUAccessType access_type, int mmu_idx, 32e84942f2SRichard Henderson bool probe, uintptr_t retaddr) 33163fa5caSBlue Swirl { 348d8cb956SPeter Maydell SPARCCPU *cpu = SPARC_CPU(cs); 358d8cb956SPeter Maydell CPUSPARCState *env = &cpu->env; 368d8cb956SPeter Maydell 37e84942f2SRichard Henderson if (access_type == MMU_INST_FETCH) { 3827103424SAndreas Färber cs->exception_index = TT_TFAULT; 39163fa5caSBlue Swirl } else { 4027103424SAndreas Färber cs->exception_index = TT_DFAULT; 418d8cb956SPeter Maydell #ifdef TARGET_SPARC64 428d8cb956SPeter Maydell env->dmmu.mmuregs[4] = address; 438d8cb956SPeter Maydell #else 448d8cb956SPeter Maydell env->mmuregs[4] = address; 458d8cb956SPeter Maydell #endif 46163fa5caSBlue Swirl } 47e84942f2SRichard Henderson cpu_loop_exit_restore(cs, retaddr); 48163fa5caSBlue Swirl } 49163fa5caSBlue Swirl 50163fa5caSBlue Swirl #else 51163fa5caSBlue Swirl 52163fa5caSBlue Swirl #ifndef TARGET_SPARC64 53163fa5caSBlue Swirl /* 54163fa5caSBlue Swirl * Sparc V8 Reference MMU (SRMMU) 55163fa5caSBlue Swirl */ 56163fa5caSBlue Swirl static const int access_table[8][8] = { 57163fa5caSBlue Swirl { 0, 0, 0, 0, 8, 0, 12, 12 }, 58163fa5caSBlue Swirl { 0, 0, 0, 0, 8, 0, 0, 0 }, 59163fa5caSBlue Swirl { 8, 8, 0, 0, 0, 8, 12, 12 }, 60163fa5caSBlue Swirl { 8, 8, 0, 0, 0, 8, 0, 0 }, 61163fa5caSBlue Swirl { 8, 0, 8, 0, 8, 8, 12, 12 }, 62163fa5caSBlue Swirl { 8, 0, 8, 0, 8, 0, 8, 0 }, 63163fa5caSBlue Swirl { 8, 8, 8, 0, 8, 8, 12, 12 }, 64163fa5caSBlue Swirl { 8, 8, 8, 0, 8, 8, 8, 0 } 65163fa5caSBlue Swirl }; 66163fa5caSBlue Swirl 67163fa5caSBlue Swirl static const int perm_table[2][8] = { 68163fa5caSBlue Swirl { 69163fa5caSBlue Swirl PAGE_READ, 70163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE, 71163fa5caSBlue Swirl PAGE_READ | PAGE_EXEC, 72163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE | PAGE_EXEC, 73163fa5caSBlue Swirl PAGE_EXEC, 74163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE, 75163fa5caSBlue Swirl PAGE_READ | PAGE_EXEC, 76163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE | PAGE_EXEC 77163fa5caSBlue Swirl }, 78163fa5caSBlue Swirl { 79163fa5caSBlue Swirl PAGE_READ, 80163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE, 81163fa5caSBlue Swirl PAGE_READ | PAGE_EXEC, 82163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE | PAGE_EXEC, 83163fa5caSBlue Swirl PAGE_EXEC, 84163fa5caSBlue Swirl PAGE_READ, 85163fa5caSBlue Swirl 0, 86163fa5caSBlue Swirl 0, 87163fa5caSBlue Swirl } 88163fa5caSBlue Swirl }; 89163fa5caSBlue Swirl 90a8170e5eSAvi Kivity static int get_physical_address(CPUSPARCState *env, hwaddr *physical, 919bed46e6STony Nguyen int *prot, int *access_index, MemTxAttrs *attrs, 92163fa5caSBlue Swirl target_ulong address, int rw, int mmu_idx, 93163fa5caSBlue Swirl target_ulong *page_size) 94163fa5caSBlue Swirl { 95163fa5caSBlue Swirl int access_perms = 0; 96a8170e5eSAvi Kivity hwaddr pde_ptr; 97163fa5caSBlue Swirl uint32_t pde; 98163fa5caSBlue Swirl int error_code = 0, is_dirty, is_user; 99163fa5caSBlue Swirl unsigned long page_offset; 1005a59fbceSRichard Henderson CPUState *cs = env_cpu(env); 1013c818dfcSPeter Maydell MemTxResult result; 102163fa5caSBlue Swirl 103163fa5caSBlue Swirl is_user = mmu_idx == MMU_USER_IDX; 104163fa5caSBlue Swirl 105af7a06baSRichard Henderson if (mmu_idx == MMU_PHYS_IDX) { 106163fa5caSBlue Swirl *page_size = TARGET_PAGE_SIZE; 107163fa5caSBlue Swirl /* Boot mode: instruction fetches are taken from PROM */ 108576e1c4cSIgor Mammedov if (rw == 2 && (env->mmuregs[0] & env->def.mmu_bm)) { 109163fa5caSBlue Swirl *physical = env->prom_addr | (address & 0x7ffffULL); 110163fa5caSBlue Swirl *prot = PAGE_READ | PAGE_EXEC; 111163fa5caSBlue Swirl return 0; 112163fa5caSBlue Swirl } 113163fa5caSBlue Swirl *physical = address; 114163fa5caSBlue Swirl *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 115163fa5caSBlue Swirl return 0; 116163fa5caSBlue Swirl } 117163fa5caSBlue Swirl 118163fa5caSBlue Swirl *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1); 119163fa5caSBlue Swirl *physical = 0xffffffffffff0000ULL; 120163fa5caSBlue Swirl 121163fa5caSBlue Swirl /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ 122163fa5caSBlue Swirl /* Context base + context number */ 123163fa5caSBlue Swirl pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); 1243c818dfcSPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result); 1253c818dfcSPeter Maydell if (result != MEMTX_OK) { 1263c818dfcSPeter Maydell return 4 << 2; /* Translation fault, L = 0 */ 1273c818dfcSPeter Maydell } 128163fa5caSBlue Swirl 129163fa5caSBlue Swirl /* Ctx pde */ 130163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 131163fa5caSBlue Swirl default: 132163fa5caSBlue Swirl case 0: /* Invalid */ 133163fa5caSBlue Swirl return 1 << 2; 134163fa5caSBlue Swirl case 2: /* L0 PTE, maybe should not happen? */ 135163fa5caSBlue Swirl case 3: /* Reserved */ 136163fa5caSBlue Swirl return 4 << 2; 137163fa5caSBlue Swirl case 1: /* L0 PDE */ 138163fa5caSBlue Swirl pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); 1393c818dfcSPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, 1403c818dfcSPeter Maydell MEMTXATTRS_UNSPECIFIED, &result); 1413c818dfcSPeter Maydell if (result != MEMTX_OK) { 1423c818dfcSPeter Maydell return (1 << 8) | (4 << 2); /* Translation fault, L = 1 */ 1433c818dfcSPeter Maydell } 144163fa5caSBlue Swirl 145163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 146163fa5caSBlue Swirl default: 147163fa5caSBlue Swirl case 0: /* Invalid */ 148163fa5caSBlue Swirl return (1 << 8) | (1 << 2); 149163fa5caSBlue Swirl case 3: /* Reserved */ 150163fa5caSBlue Swirl return (1 << 8) | (4 << 2); 151163fa5caSBlue Swirl case 1: /* L1 PDE */ 152163fa5caSBlue Swirl pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); 1533c818dfcSPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, 1543c818dfcSPeter Maydell MEMTXATTRS_UNSPECIFIED, &result); 1553c818dfcSPeter Maydell if (result != MEMTX_OK) { 1563c818dfcSPeter Maydell return (2 << 8) | (4 << 2); /* Translation fault, L = 2 */ 1573c818dfcSPeter Maydell } 158163fa5caSBlue Swirl 159163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 160163fa5caSBlue Swirl default: 161163fa5caSBlue Swirl case 0: /* Invalid */ 162163fa5caSBlue Swirl return (2 << 8) | (1 << 2); 163163fa5caSBlue Swirl case 3: /* Reserved */ 164163fa5caSBlue Swirl return (2 << 8) | (4 << 2); 165163fa5caSBlue Swirl case 1: /* L2 PDE */ 166163fa5caSBlue Swirl pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); 1673c818dfcSPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, 1683c818dfcSPeter Maydell MEMTXATTRS_UNSPECIFIED, &result); 1693c818dfcSPeter Maydell if (result != MEMTX_OK) { 1703c818dfcSPeter Maydell return (3 << 8) | (4 << 2); /* Translation fault, L = 3 */ 1713c818dfcSPeter Maydell } 172163fa5caSBlue Swirl 173163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 174163fa5caSBlue Swirl default: 175163fa5caSBlue Swirl case 0: /* Invalid */ 176163fa5caSBlue Swirl return (3 << 8) | (1 << 2); 177163fa5caSBlue Swirl case 1: /* PDE, should not happen */ 178163fa5caSBlue Swirl case 3: /* Reserved */ 179163fa5caSBlue Swirl return (3 << 8) | (4 << 2); 180163fa5caSBlue Swirl case 2: /* L3 PTE */ 1811658dd32SBlue Swirl page_offset = 0; 182163fa5caSBlue Swirl } 183163fa5caSBlue Swirl *page_size = TARGET_PAGE_SIZE; 184163fa5caSBlue Swirl break; 185163fa5caSBlue Swirl case 2: /* L2 PTE */ 1861658dd32SBlue Swirl page_offset = address & 0x3f000; 187163fa5caSBlue Swirl *page_size = 0x40000; 188163fa5caSBlue Swirl } 189163fa5caSBlue Swirl break; 190163fa5caSBlue Swirl case 2: /* L1 PTE */ 1911658dd32SBlue Swirl page_offset = address & 0xfff000; 192163fa5caSBlue Swirl *page_size = 0x1000000; 193163fa5caSBlue Swirl } 194163fa5caSBlue Swirl } 195163fa5caSBlue Swirl 196163fa5caSBlue Swirl /* check access */ 197163fa5caSBlue Swirl access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; 198163fa5caSBlue Swirl error_code = access_table[*access_index][access_perms]; 199163fa5caSBlue Swirl if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) { 200163fa5caSBlue Swirl return error_code; 201163fa5caSBlue Swirl } 202163fa5caSBlue Swirl 203163fa5caSBlue Swirl /* update page modified and dirty bits */ 204163fa5caSBlue Swirl is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); 205163fa5caSBlue Swirl if (!(pde & PG_ACCESSED_MASK) || is_dirty) { 206163fa5caSBlue Swirl pde |= PG_ACCESSED_MASK; 207163fa5caSBlue Swirl if (is_dirty) { 208163fa5caSBlue Swirl pde |= PG_MODIFIED_MASK; 209163fa5caSBlue Swirl } 2102198a121SEdgar E. Iglesias stl_phys_notdirty(cs->as, pde_ptr, pde); 211163fa5caSBlue Swirl } 212163fa5caSBlue Swirl 213163fa5caSBlue Swirl /* the page can be put in the TLB */ 214163fa5caSBlue Swirl *prot = perm_table[is_user][access_perms]; 215163fa5caSBlue Swirl if (!(pde & PG_MODIFIED_MASK)) { 216163fa5caSBlue Swirl /* only set write access if already dirty... otherwise wait 217163fa5caSBlue Swirl for dirty access */ 218163fa5caSBlue Swirl *prot &= ~PAGE_WRITE; 219163fa5caSBlue Swirl } 220163fa5caSBlue Swirl 221163fa5caSBlue Swirl /* Even if large ptes, we map only one 4KB page in the cache to 222163fa5caSBlue Swirl avoid filling it too fast */ 223a8170e5eSAvi Kivity *physical = ((hwaddr)(pde & PTE_ADDR_MASK) << 4) + page_offset; 224163fa5caSBlue Swirl return error_code; 225163fa5caSBlue Swirl } 226163fa5caSBlue Swirl 227163fa5caSBlue Swirl /* Perform address translation */ 228e84942f2SRichard Henderson bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 229e84942f2SRichard Henderson MMUAccessType access_type, int mmu_idx, 230e84942f2SRichard Henderson bool probe, uintptr_t retaddr) 231163fa5caSBlue Swirl { 2327510454eSAndreas Färber SPARCCPU *cpu = SPARC_CPU(cs); 2337510454eSAndreas Färber CPUSPARCState *env = &cpu->env; 234a8170e5eSAvi Kivity hwaddr paddr; 235163fa5caSBlue Swirl target_ulong vaddr; 236163fa5caSBlue Swirl target_ulong page_size; 237163fa5caSBlue Swirl int error_code = 0, prot, access_index; 2389bed46e6STony Nguyen MemTxAttrs attrs = {}; 239163fa5caSBlue Swirl 240e84942f2SRichard Henderson /* 241e84942f2SRichard Henderson * TODO: If we ever need tlb_vaddr_to_host for this target, 242e84942f2SRichard Henderson * then we must figure out how to manipulate FSR and FAR 243e84942f2SRichard Henderson * when both MMU_NF and probe are set. In the meantime, 244e84942f2SRichard Henderson * do not support this use case. 245e84942f2SRichard Henderson */ 246e84942f2SRichard Henderson assert(!probe); 247e84942f2SRichard Henderson 2481658dd32SBlue Swirl address &= TARGET_PAGE_MASK; 2499bed46e6STony Nguyen error_code = get_physical_address(env, &paddr, &prot, &access_index, &attrs, 250e84942f2SRichard Henderson address, access_type, 251e84942f2SRichard Henderson mmu_idx, &page_size); 2521658dd32SBlue Swirl vaddr = address; 253e84942f2SRichard Henderson if (likely(error_code == 0)) { 254339aaf5bSAntony Pavlov qemu_log_mask(CPU_LOG_MMU, 255e84942f2SRichard Henderson "Translate at %" VADDR_PRIx " -> " 256e84942f2SRichard Henderson TARGET_FMT_plx ", vaddr " TARGET_FMT_lx "\n", 257e84942f2SRichard Henderson address, paddr, vaddr); 2580c591eb0SAndreas Färber tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size); 259e84942f2SRichard Henderson return true; 260163fa5caSBlue Swirl } 261163fa5caSBlue Swirl 262163fa5caSBlue Swirl if (env->mmuregs[3]) { /* Fault status register */ 263163fa5caSBlue Swirl env->mmuregs[3] = 1; /* overflow (not read before another fault) */ 264163fa5caSBlue Swirl } 265163fa5caSBlue Swirl env->mmuregs[3] |= (access_index << 5) | error_code | 2; 266163fa5caSBlue Swirl env->mmuregs[4] = address; /* Fault address register */ 267163fa5caSBlue Swirl 268163fa5caSBlue Swirl if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) { 269163fa5caSBlue Swirl /* No fault mode: if a mapping is available, just override 270163fa5caSBlue Swirl permissions. If no mapping is available, redirect accesses to 271163fa5caSBlue Swirl neverland. Fake/overridden mappings will be flushed when 272163fa5caSBlue Swirl switching to normal mode. */ 273163fa5caSBlue Swirl prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 2740c591eb0SAndreas Färber tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE); 275e84942f2SRichard Henderson return true; 276163fa5caSBlue Swirl } else { 277e84942f2SRichard Henderson if (access_type == MMU_INST_FETCH) { 27827103424SAndreas Färber cs->exception_index = TT_TFAULT; 279163fa5caSBlue Swirl } else { 28027103424SAndreas Färber cs->exception_index = TT_DFAULT; 281163fa5caSBlue Swirl } 282e84942f2SRichard Henderson cpu_loop_exit_restore(cs, retaddr); 283163fa5caSBlue Swirl } 284163fa5caSBlue Swirl } 285163fa5caSBlue Swirl 286c5f9864eSAndreas Färber target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev) 287163fa5caSBlue Swirl { 2885a59fbceSRichard Henderson CPUState *cs = env_cpu(env); 289a8170e5eSAvi Kivity hwaddr pde_ptr; 290163fa5caSBlue Swirl uint32_t pde; 291d86a9ad3SPeter Maydell MemTxResult result; 292d86a9ad3SPeter Maydell 293d86a9ad3SPeter Maydell /* 294d86a9ad3SPeter Maydell * TODO: MMU probe operations are supposed to set the fault 295d86a9ad3SPeter Maydell * status registers, but we don't do this. 296d86a9ad3SPeter Maydell */ 297163fa5caSBlue Swirl 298163fa5caSBlue Swirl /* Context base + context number */ 299a8170e5eSAvi Kivity pde_ptr = (hwaddr)(env->mmuregs[1] << 4) + 300163fa5caSBlue Swirl (env->mmuregs[2] << 2); 301d86a9ad3SPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result); 302d86a9ad3SPeter Maydell if (result != MEMTX_OK) { 303d86a9ad3SPeter Maydell return 0; 304d86a9ad3SPeter Maydell } 305163fa5caSBlue Swirl 306163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 307163fa5caSBlue Swirl default: 308163fa5caSBlue Swirl case 0: /* Invalid */ 309163fa5caSBlue Swirl case 2: /* PTE, maybe should not happen? */ 310163fa5caSBlue Swirl case 3: /* Reserved */ 311163fa5caSBlue Swirl return 0; 312163fa5caSBlue Swirl case 1: /* L1 PDE */ 313163fa5caSBlue Swirl if (mmulev == 3) { 314163fa5caSBlue Swirl return pde; 315163fa5caSBlue Swirl } 316163fa5caSBlue Swirl pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); 317d86a9ad3SPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, 318d86a9ad3SPeter Maydell MEMTXATTRS_UNSPECIFIED, &result); 319d86a9ad3SPeter Maydell if (result != MEMTX_OK) { 320d86a9ad3SPeter Maydell return 0; 321d86a9ad3SPeter Maydell } 322163fa5caSBlue Swirl 323163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 324163fa5caSBlue Swirl default: 325163fa5caSBlue Swirl case 0: /* Invalid */ 326163fa5caSBlue Swirl case 3: /* Reserved */ 327163fa5caSBlue Swirl return 0; 328163fa5caSBlue Swirl case 2: /* L1 PTE */ 329163fa5caSBlue Swirl return pde; 330163fa5caSBlue Swirl case 1: /* L2 PDE */ 331163fa5caSBlue Swirl if (mmulev == 2) { 332163fa5caSBlue Swirl return pde; 333163fa5caSBlue Swirl } 334163fa5caSBlue Swirl pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); 335d86a9ad3SPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, 336d86a9ad3SPeter Maydell MEMTXATTRS_UNSPECIFIED, &result); 337d86a9ad3SPeter Maydell if (result != MEMTX_OK) { 338d86a9ad3SPeter Maydell return 0; 339d86a9ad3SPeter Maydell } 340163fa5caSBlue Swirl 341163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 342163fa5caSBlue Swirl default: 343163fa5caSBlue Swirl case 0: /* Invalid */ 344163fa5caSBlue Swirl case 3: /* Reserved */ 345163fa5caSBlue Swirl return 0; 346163fa5caSBlue Swirl case 2: /* L2 PTE */ 347163fa5caSBlue Swirl return pde; 348163fa5caSBlue Swirl case 1: /* L3 PDE */ 349163fa5caSBlue Swirl if (mmulev == 1) { 350163fa5caSBlue Swirl return pde; 351163fa5caSBlue Swirl } 352163fa5caSBlue Swirl pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); 353d86a9ad3SPeter Maydell pde = address_space_ldl(cs->as, pde_ptr, 354d86a9ad3SPeter Maydell MEMTXATTRS_UNSPECIFIED, &result); 355d86a9ad3SPeter Maydell if (result != MEMTX_OK) { 356d86a9ad3SPeter Maydell return 0; 357d86a9ad3SPeter Maydell } 358163fa5caSBlue Swirl 359163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 360163fa5caSBlue Swirl default: 361163fa5caSBlue Swirl case 0: /* Invalid */ 362163fa5caSBlue Swirl case 1: /* PDE, should not happen */ 363163fa5caSBlue Swirl case 3: /* Reserved */ 364163fa5caSBlue Swirl return 0; 365163fa5caSBlue Swirl case 2: /* L3 PTE */ 366163fa5caSBlue Swirl return pde; 367163fa5caSBlue Swirl } 368163fa5caSBlue Swirl } 369163fa5caSBlue Swirl } 370163fa5caSBlue Swirl } 371163fa5caSBlue Swirl return 0; 372163fa5caSBlue Swirl } 373163fa5caSBlue Swirl 374fad866daSMarkus Armbruster void dump_mmu(CPUSPARCState *env) 375163fa5caSBlue Swirl { 3765a59fbceSRichard Henderson CPUState *cs = env_cpu(env); 377163fa5caSBlue Swirl target_ulong va, va1, va2; 378163fa5caSBlue Swirl unsigned int n, m, o; 379*9dffeec2SPeter Maydell hwaddr pa; 380163fa5caSBlue Swirl uint32_t pde; 381163fa5caSBlue Swirl 382fad866daSMarkus Armbruster qemu_printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n", 383a8170e5eSAvi Kivity (hwaddr)env->mmuregs[1] << 4, env->mmuregs[2]); 384163fa5caSBlue Swirl for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { 385163fa5caSBlue Swirl pde = mmu_probe(env, va, 2); 386163fa5caSBlue Swirl if (pde) { 38700b941e5SAndreas Färber pa = cpu_get_phys_page_debug(cs, va); 388fad866daSMarkus Armbruster qemu_printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx 389163fa5caSBlue Swirl " PDE: " TARGET_FMT_lx "\n", va, pa, pde); 390163fa5caSBlue Swirl for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { 391163fa5caSBlue Swirl pde = mmu_probe(env, va1, 1); 392163fa5caSBlue Swirl if (pde) { 39300b941e5SAndreas Färber pa = cpu_get_phys_page_debug(cs, va1); 394fad866daSMarkus Armbruster qemu_printf(" VA: " TARGET_FMT_lx ", PA: " 395163fa5caSBlue Swirl TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n", 396163fa5caSBlue Swirl va1, pa, pde); 397163fa5caSBlue Swirl for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { 398163fa5caSBlue Swirl pde = mmu_probe(env, va2, 0); 399163fa5caSBlue Swirl if (pde) { 40000b941e5SAndreas Färber pa = cpu_get_phys_page_debug(cs, va2); 401fad866daSMarkus Armbruster qemu_printf(" VA: " TARGET_FMT_lx ", PA: " 402163fa5caSBlue Swirl TARGET_FMT_plx " PTE: " 403163fa5caSBlue Swirl TARGET_FMT_lx "\n", 404163fa5caSBlue Swirl va2, pa, pde); 405163fa5caSBlue Swirl } 406163fa5caSBlue Swirl } 407163fa5caSBlue Swirl } 408163fa5caSBlue Swirl } 409163fa5caSBlue Swirl } 410163fa5caSBlue Swirl } 411163fa5caSBlue Swirl } 412163fa5caSBlue Swirl 413163fa5caSBlue Swirl /* Gdb expects all registers windows to be flushed in ram. This function handles 414163fa5caSBlue Swirl * reads (and only reads) in stack frames as if windows were flushed. We assume 415163fa5caSBlue Swirl * that the sparc ABI is followed. 416163fa5caSBlue Swirl */ 417f3659eeeSAndreas Färber int sparc_cpu_memory_rw_debug(CPUState *cs, vaddr address, 418f3659eeeSAndreas Färber uint8_t *buf, int len, bool is_write) 419163fa5caSBlue Swirl { 420f3659eeeSAndreas Färber SPARCCPU *cpu = SPARC_CPU(cs); 421f3659eeeSAndreas Färber CPUSPARCState *env = &cpu->env; 422f3659eeeSAndreas Färber target_ulong addr = address; 423163fa5caSBlue Swirl int i; 424163fa5caSBlue Swirl int len1; 425163fa5caSBlue Swirl int cwp = env->cwp; 426163fa5caSBlue Swirl 427163fa5caSBlue Swirl if (!is_write) { 428163fa5caSBlue Swirl for (i = 0; i < env->nwindows; i++) { 429163fa5caSBlue Swirl int off; 430163fa5caSBlue Swirl target_ulong fp = env->regbase[cwp * 16 + 22]; 431163fa5caSBlue Swirl 432163fa5caSBlue Swirl /* Assume fp == 0 means end of frame. */ 433163fa5caSBlue Swirl if (fp == 0) { 434163fa5caSBlue Swirl break; 435163fa5caSBlue Swirl } 436163fa5caSBlue Swirl 437163fa5caSBlue Swirl cwp = cpu_cwp_inc(env, cwp + 1); 438163fa5caSBlue Swirl 439163fa5caSBlue Swirl /* Invalid window ? */ 440163fa5caSBlue Swirl if (env->wim & (1 << cwp)) { 441163fa5caSBlue Swirl break; 442163fa5caSBlue Swirl } 443163fa5caSBlue Swirl 444163fa5caSBlue Swirl /* According to the ABI, the stack is growing downward. */ 445163fa5caSBlue Swirl if (addr + len < fp) { 446163fa5caSBlue Swirl break; 447163fa5caSBlue Swirl } 448163fa5caSBlue Swirl 449163fa5caSBlue Swirl /* Not in this frame. */ 450163fa5caSBlue Swirl if (addr > fp + 64) { 451163fa5caSBlue Swirl continue; 452163fa5caSBlue Swirl } 453163fa5caSBlue Swirl 454163fa5caSBlue Swirl /* Handle access before this window. */ 455163fa5caSBlue Swirl if (addr < fp) { 456163fa5caSBlue Swirl len1 = fp - addr; 457f17ec444SAndreas Färber if (cpu_memory_rw_debug(cs, addr, buf, len1, is_write) != 0) { 458163fa5caSBlue Swirl return -1; 459163fa5caSBlue Swirl } 460163fa5caSBlue Swirl addr += len1; 461163fa5caSBlue Swirl len -= len1; 462163fa5caSBlue Swirl buf += len1; 463163fa5caSBlue Swirl } 464163fa5caSBlue Swirl 465163fa5caSBlue Swirl /* Access byte per byte to registers. Not very efficient but speed 466163fa5caSBlue Swirl * is not critical. 467163fa5caSBlue Swirl */ 468163fa5caSBlue Swirl off = addr - fp; 469163fa5caSBlue Swirl len1 = 64 - off; 470163fa5caSBlue Swirl 471163fa5caSBlue Swirl if (len1 > len) { 472163fa5caSBlue Swirl len1 = len; 473163fa5caSBlue Swirl } 474163fa5caSBlue Swirl 475163fa5caSBlue Swirl for (; len1; len1--) { 476163fa5caSBlue Swirl int reg = cwp * 16 + 8 + (off >> 2); 477163fa5caSBlue Swirl union { 478163fa5caSBlue Swirl uint32_t v; 479163fa5caSBlue Swirl uint8_t c[4]; 480163fa5caSBlue Swirl } u; 481163fa5caSBlue Swirl u.v = cpu_to_be32(env->regbase[reg]); 482163fa5caSBlue Swirl *buf++ = u.c[off & 3]; 483163fa5caSBlue Swirl addr++; 484163fa5caSBlue Swirl len--; 485163fa5caSBlue Swirl off++; 486163fa5caSBlue Swirl } 487163fa5caSBlue Swirl 488163fa5caSBlue Swirl if (len == 0) { 489163fa5caSBlue Swirl return 0; 490163fa5caSBlue Swirl } 491163fa5caSBlue Swirl } 492163fa5caSBlue Swirl } 493f17ec444SAndreas Färber return cpu_memory_rw_debug(cs, addr, buf, len, is_write); 494163fa5caSBlue Swirl } 495163fa5caSBlue Swirl 496163fa5caSBlue Swirl #else /* !TARGET_SPARC64 */ 497163fa5caSBlue Swirl 498163fa5caSBlue Swirl /* 41 bit physical address space */ 499a8170e5eSAvi Kivity static inline hwaddr ultrasparc_truncate_physical(uint64_t x) 500163fa5caSBlue Swirl { 501163fa5caSBlue Swirl return x & 0x1ffffffffffULL; 502163fa5caSBlue Swirl } 503163fa5caSBlue Swirl 504163fa5caSBlue Swirl /* 505163fa5caSBlue Swirl * UltraSparc IIi I/DMMUs 506163fa5caSBlue Swirl */ 507163fa5caSBlue Swirl 508163fa5caSBlue Swirl /* Returns true if TTE tag is valid and matches virtual address value 509163fa5caSBlue Swirl in context requires virtual address mask value calculated from TTE 510163fa5caSBlue Swirl entry size */ 511163fa5caSBlue Swirl static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, 512163fa5caSBlue Swirl uint64_t address, uint64_t context, 513a8170e5eSAvi Kivity hwaddr *physical) 514163fa5caSBlue Swirl { 515913b5f28SArtyom Tarasenko uint64_t mask = -(8192ULL << 3 * TTE_PGSIZE(tlb->tte)); 516163fa5caSBlue Swirl 517163fa5caSBlue Swirl /* valid, context match, virtual address match? */ 518163fa5caSBlue Swirl if (TTE_IS_VALID(tlb->tte) && 519163fa5caSBlue Swirl (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context)) 520163fa5caSBlue Swirl && compare_masked(address, tlb->tag, mask)) { 521163fa5caSBlue Swirl /* decode physical address */ 522163fa5caSBlue Swirl *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL; 523163fa5caSBlue Swirl return 1; 524163fa5caSBlue Swirl } 525163fa5caSBlue Swirl 526163fa5caSBlue Swirl return 0; 527163fa5caSBlue Swirl } 528163fa5caSBlue Swirl 5299bed46e6STony Nguyen static int get_physical_address_data(CPUSPARCState *env, hwaddr *physical, 5309bed46e6STony Nguyen int *prot, MemTxAttrs *attrs, 531163fa5caSBlue Swirl target_ulong address, int rw, int mmu_idx) 532163fa5caSBlue Swirl { 5335a59fbceSRichard Henderson CPUState *cs = env_cpu(env); 534163fa5caSBlue Swirl unsigned int i; 535163fa5caSBlue Swirl uint64_t context; 536163fa5caSBlue Swirl uint64_t sfsr = 0; 537af7a06baSRichard Henderson bool is_user = false; 538163fa5caSBlue Swirl 539163fa5caSBlue Swirl switch (mmu_idx) { 540af7a06baSRichard Henderson case MMU_PHYS_IDX: 541af7a06baSRichard Henderson g_assert_not_reached(); 542163fa5caSBlue Swirl case MMU_USER_IDX: 543af7a06baSRichard Henderson is_user = true; 544af7a06baSRichard Henderson /* fallthru */ 545163fa5caSBlue Swirl case MMU_KERNEL_IDX: 546163fa5caSBlue Swirl context = env->dmmu.mmu_primary_context & 0x1fff; 547163fa5caSBlue Swirl sfsr |= SFSR_CT_PRIMARY; 548163fa5caSBlue Swirl break; 549163fa5caSBlue Swirl case MMU_USER_SECONDARY_IDX: 550af7a06baSRichard Henderson is_user = true; 551af7a06baSRichard Henderson /* fallthru */ 552163fa5caSBlue Swirl case MMU_KERNEL_SECONDARY_IDX: 553163fa5caSBlue Swirl context = env->dmmu.mmu_secondary_context & 0x1fff; 554163fa5caSBlue Swirl sfsr |= SFSR_CT_SECONDARY; 555163fa5caSBlue Swirl break; 556163fa5caSBlue Swirl case MMU_NUCLEUS_IDX: 557163fa5caSBlue Swirl sfsr |= SFSR_CT_NUCLEUS; 558163fa5caSBlue Swirl /* FALLTHRU */ 559163fa5caSBlue Swirl default: 560163fa5caSBlue Swirl context = 0; 561163fa5caSBlue Swirl break; 562163fa5caSBlue Swirl } 563163fa5caSBlue Swirl 564163fa5caSBlue Swirl if (rw == 1) { 565163fa5caSBlue Swirl sfsr |= SFSR_WRITE_BIT; 566163fa5caSBlue Swirl } else if (rw == 4) { 567163fa5caSBlue Swirl sfsr |= SFSR_NF_BIT; 568163fa5caSBlue Swirl } 569163fa5caSBlue Swirl 570163fa5caSBlue Swirl for (i = 0; i < 64; i++) { 571163fa5caSBlue Swirl /* ctx match, vaddr match, valid? */ 572163fa5caSBlue Swirl if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) { 573163fa5caSBlue Swirl int do_fault = 0; 574163fa5caSBlue Swirl 575ccdb4c55STony Nguyen if (TTE_IS_IE(env->dtlb[i].tte)) { 576ccdb4c55STony Nguyen attrs->byte_swap = true; 577ccdb4c55STony Nguyen } 578ccdb4c55STony Nguyen 579163fa5caSBlue Swirl /* access ok? */ 580163fa5caSBlue Swirl /* multiple bits in SFSR.FT may be set on TT_DFAULT */ 581163fa5caSBlue Swirl if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) { 582163fa5caSBlue Swirl do_fault = 1; 583163fa5caSBlue Swirl sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */ 584ec0ceb17SBlue Swirl trace_mmu_helper_dfault(address, context, mmu_idx, env->tl); 585163fa5caSBlue Swirl } 586163fa5caSBlue Swirl if (rw == 4) { 587163fa5caSBlue Swirl if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) { 588163fa5caSBlue Swirl do_fault = 1; 589163fa5caSBlue Swirl sfsr |= SFSR_FT_NF_E_BIT; 590163fa5caSBlue Swirl } 591163fa5caSBlue Swirl } else { 592163fa5caSBlue Swirl if (TTE_IS_NFO(env->dtlb[i].tte)) { 593163fa5caSBlue Swirl do_fault = 1; 594163fa5caSBlue Swirl sfsr |= SFSR_FT_NFO_BIT; 595163fa5caSBlue Swirl } 596163fa5caSBlue Swirl } 597163fa5caSBlue Swirl 598163fa5caSBlue Swirl if (do_fault) { 599163fa5caSBlue Swirl /* faults above are reported with TT_DFAULT. */ 60027103424SAndreas Färber cs->exception_index = TT_DFAULT; 601163fa5caSBlue Swirl } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) { 602163fa5caSBlue Swirl do_fault = 1; 60327103424SAndreas Färber cs->exception_index = TT_DPROT; 604163fa5caSBlue Swirl 605ec0ceb17SBlue Swirl trace_mmu_helper_dprot(address, context, mmu_idx, env->tl); 606163fa5caSBlue Swirl } 607163fa5caSBlue Swirl 608163fa5caSBlue Swirl if (!do_fault) { 609163fa5caSBlue Swirl *prot = PAGE_READ; 610163fa5caSBlue Swirl if (TTE_IS_W_OK(env->dtlb[i].tte)) { 611163fa5caSBlue Swirl *prot |= PAGE_WRITE; 612163fa5caSBlue Swirl } 613163fa5caSBlue Swirl 614163fa5caSBlue Swirl TTE_SET_USED(env->dtlb[i].tte); 615163fa5caSBlue Swirl 616163fa5caSBlue Swirl return 0; 617163fa5caSBlue Swirl } 618163fa5caSBlue Swirl 619163fa5caSBlue Swirl if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */ 620163fa5caSBlue Swirl sfsr |= SFSR_OW_BIT; /* overflow (not read before 621163fa5caSBlue Swirl another fault) */ 622163fa5caSBlue Swirl } 623163fa5caSBlue Swirl 624163fa5caSBlue Swirl if (env->pstate & PS_PRIV) { 625163fa5caSBlue Swirl sfsr |= SFSR_PR_BIT; 626163fa5caSBlue Swirl } 627163fa5caSBlue Swirl 628163fa5caSBlue Swirl /* FIXME: ASI field in SFSR must be set */ 629163fa5caSBlue Swirl env->dmmu.sfsr = sfsr | SFSR_VALID_BIT; 630163fa5caSBlue Swirl 631163fa5caSBlue Swirl env->dmmu.sfar = address; /* Fault address register */ 632163fa5caSBlue Swirl 633163fa5caSBlue Swirl env->dmmu.tag_access = (address & ~0x1fffULL) | context; 634163fa5caSBlue Swirl 635163fa5caSBlue Swirl return 1; 636163fa5caSBlue Swirl } 637163fa5caSBlue Swirl } 638163fa5caSBlue Swirl 639ec0ceb17SBlue Swirl trace_mmu_helper_dmiss(address, context); 640163fa5caSBlue Swirl 641163fa5caSBlue Swirl /* 642163fa5caSBlue Swirl * On MMU misses: 643163fa5caSBlue Swirl * - UltraSPARC IIi: SFSR and SFAR unmodified 644163fa5caSBlue Swirl * - JPS1: SFAR updated and some fields of SFSR updated 645163fa5caSBlue Swirl */ 646163fa5caSBlue Swirl env->dmmu.tag_access = (address & ~0x1fffULL) | context; 64727103424SAndreas Färber cs->exception_index = TT_DMISS; 648163fa5caSBlue Swirl return 1; 649163fa5caSBlue Swirl } 650163fa5caSBlue Swirl 6519bed46e6STony Nguyen static int get_physical_address_code(CPUSPARCState *env, hwaddr *physical, 6529bed46e6STony Nguyen int *prot, MemTxAttrs *attrs, 653163fa5caSBlue Swirl target_ulong address, int mmu_idx) 654163fa5caSBlue Swirl { 6555a59fbceSRichard Henderson CPUState *cs = env_cpu(env); 656163fa5caSBlue Swirl unsigned int i; 657163fa5caSBlue Swirl uint64_t context; 658af7a06baSRichard Henderson bool is_user = false; 659163fa5caSBlue Swirl 660af7a06baSRichard Henderson switch (mmu_idx) { 661af7a06baSRichard Henderson case MMU_PHYS_IDX: 662af7a06baSRichard Henderson case MMU_USER_SECONDARY_IDX: 663af7a06baSRichard Henderson case MMU_KERNEL_SECONDARY_IDX: 664af7a06baSRichard Henderson g_assert_not_reached(); 665af7a06baSRichard Henderson case MMU_USER_IDX: 666af7a06baSRichard Henderson is_user = true; 667af7a06baSRichard Henderson /* fallthru */ 668af7a06baSRichard Henderson case MMU_KERNEL_IDX: 669af7a06baSRichard Henderson context = env->dmmu.mmu_primary_context & 0x1fff; 670af7a06baSRichard Henderson break; 671af7a06baSRichard Henderson default: 672af7a06baSRichard Henderson context = 0; 673af7a06baSRichard Henderson break; 674163fa5caSBlue Swirl } 675163fa5caSBlue Swirl 676163fa5caSBlue Swirl if (env->tl == 0) { 677163fa5caSBlue Swirl /* PRIMARY context */ 678163fa5caSBlue Swirl context = env->dmmu.mmu_primary_context & 0x1fff; 679163fa5caSBlue Swirl } else { 680163fa5caSBlue Swirl /* NUCLEUS context */ 681163fa5caSBlue Swirl context = 0; 682163fa5caSBlue Swirl } 683163fa5caSBlue Swirl 684163fa5caSBlue Swirl for (i = 0; i < 64; i++) { 685163fa5caSBlue Swirl /* ctx match, vaddr match, valid? */ 686163fa5caSBlue Swirl if (ultrasparc_tag_match(&env->itlb[i], 687163fa5caSBlue Swirl address, context, physical)) { 688163fa5caSBlue Swirl /* access ok? */ 689163fa5caSBlue Swirl if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) { 690163fa5caSBlue Swirl /* Fault status register */ 691163fa5caSBlue Swirl if (env->immu.sfsr & SFSR_VALID_BIT) { 692163fa5caSBlue Swirl env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before 693163fa5caSBlue Swirl another fault) */ 694163fa5caSBlue Swirl } else { 695163fa5caSBlue Swirl env->immu.sfsr = 0; 696163fa5caSBlue Swirl } 697163fa5caSBlue Swirl if (env->pstate & PS_PRIV) { 698163fa5caSBlue Swirl env->immu.sfsr |= SFSR_PR_BIT; 699163fa5caSBlue Swirl } 700163fa5caSBlue Swirl if (env->tl > 0) { 701163fa5caSBlue Swirl env->immu.sfsr |= SFSR_CT_NUCLEUS; 702163fa5caSBlue Swirl } 703163fa5caSBlue Swirl 704163fa5caSBlue Swirl /* FIXME: ASI field in SFSR must be set */ 705163fa5caSBlue Swirl env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT; 70627103424SAndreas Färber cs->exception_index = TT_TFAULT; 707163fa5caSBlue Swirl 708163fa5caSBlue Swirl env->immu.tag_access = (address & ~0x1fffULL) | context; 709163fa5caSBlue Swirl 710ec0ceb17SBlue Swirl trace_mmu_helper_tfault(address, context); 711163fa5caSBlue Swirl 712163fa5caSBlue Swirl return 1; 713163fa5caSBlue Swirl } 714163fa5caSBlue Swirl *prot = PAGE_EXEC; 715163fa5caSBlue Swirl TTE_SET_USED(env->itlb[i].tte); 716163fa5caSBlue Swirl return 0; 717163fa5caSBlue Swirl } 718163fa5caSBlue Swirl } 719163fa5caSBlue Swirl 720ec0ceb17SBlue Swirl trace_mmu_helper_tmiss(address, context); 721163fa5caSBlue Swirl 722163fa5caSBlue Swirl /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */ 723163fa5caSBlue Swirl env->immu.tag_access = (address & ~0x1fffULL) | context; 72427103424SAndreas Färber cs->exception_index = TT_TMISS; 725163fa5caSBlue Swirl return 1; 726163fa5caSBlue Swirl } 727163fa5caSBlue Swirl 728a8170e5eSAvi Kivity static int get_physical_address(CPUSPARCState *env, hwaddr *physical, 7299bed46e6STony Nguyen int *prot, int *access_index, MemTxAttrs *attrs, 730163fa5caSBlue Swirl target_ulong address, int rw, int mmu_idx, 731163fa5caSBlue Swirl target_ulong *page_size) 732163fa5caSBlue Swirl { 733163fa5caSBlue Swirl /* ??? We treat everything as a small page, then explicitly flush 734163fa5caSBlue Swirl everything when an entry is evicted. */ 735163fa5caSBlue Swirl *page_size = TARGET_PAGE_SIZE; 736163fa5caSBlue Swirl 737163fa5caSBlue Swirl /* safety net to catch wrong softmmu index use from dynamic code */ 738163fa5caSBlue Swirl if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) { 739ec0ceb17SBlue Swirl if (rw == 2) { 740ec0ceb17SBlue Swirl trace_mmu_helper_get_phys_addr_code(env->tl, mmu_idx, 741ec0ceb17SBlue Swirl env->dmmu.mmu_primary_context, 742ec0ceb17SBlue Swirl env->dmmu.mmu_secondary_context, 743ec0ceb17SBlue Swirl address); 744ec0ceb17SBlue Swirl } else { 745ec0ceb17SBlue Swirl trace_mmu_helper_get_phys_addr_data(env->tl, mmu_idx, 746163fa5caSBlue Swirl env->dmmu.mmu_primary_context, 747163fa5caSBlue Swirl env->dmmu.mmu_secondary_context, 748163fa5caSBlue Swirl address); 749163fa5caSBlue Swirl } 750ec0ceb17SBlue Swirl } 751163fa5caSBlue Swirl 752af7a06baSRichard Henderson if (mmu_idx == MMU_PHYS_IDX) { 753af7a06baSRichard Henderson *physical = ultrasparc_truncate_physical(address); 754af7a06baSRichard Henderson *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 755af7a06baSRichard Henderson return 0; 756af7a06baSRichard Henderson } 757af7a06baSRichard Henderson 758163fa5caSBlue Swirl if (rw == 2) { 7599bed46e6STony Nguyen return get_physical_address_code(env, physical, prot, attrs, address, 760163fa5caSBlue Swirl mmu_idx); 761163fa5caSBlue Swirl } else { 7629bed46e6STony Nguyen return get_physical_address_data(env, physical, prot, attrs, address, 7639bed46e6STony Nguyen rw, mmu_idx); 764163fa5caSBlue Swirl } 765163fa5caSBlue Swirl } 766163fa5caSBlue Swirl 767163fa5caSBlue Swirl /* Perform address translation */ 768e84942f2SRichard Henderson bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 769e84942f2SRichard Henderson MMUAccessType access_type, int mmu_idx, 770e84942f2SRichard Henderson bool probe, uintptr_t retaddr) 771163fa5caSBlue Swirl { 7727510454eSAndreas Färber SPARCCPU *cpu = SPARC_CPU(cs); 7737510454eSAndreas Färber CPUSPARCState *env = &cpu->env; 7741658dd32SBlue Swirl target_ulong vaddr; 775a8170e5eSAvi Kivity hwaddr paddr; 776163fa5caSBlue Swirl target_ulong page_size; 7779bed46e6STony Nguyen MemTxAttrs attrs = {}; 778163fa5caSBlue Swirl int error_code = 0, prot, access_index; 779163fa5caSBlue Swirl 7801658dd32SBlue Swirl address &= TARGET_PAGE_MASK; 7819bed46e6STony Nguyen error_code = get_physical_address(env, &paddr, &prot, &access_index, &attrs, 782e84942f2SRichard Henderson address, access_type, 783e84942f2SRichard Henderson mmu_idx, &page_size); 784e84942f2SRichard Henderson if (likely(error_code == 0)) { 7851658dd32SBlue Swirl vaddr = address; 786163fa5caSBlue Swirl 787ec0ceb17SBlue Swirl trace_mmu_helper_mmu_fault(address, paddr, mmu_idx, env->tl, 788163fa5caSBlue Swirl env->dmmu.mmu_primary_context, 789163fa5caSBlue Swirl env->dmmu.mmu_secondary_context); 790163fa5caSBlue Swirl 7919bed46e6STony Nguyen tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, 7929bed46e6STony Nguyen page_size); 793e84942f2SRichard Henderson return true; 794163fa5caSBlue Swirl } 795e84942f2SRichard Henderson if (probe) { 796e84942f2SRichard Henderson return false; 797e84942f2SRichard Henderson } 798e84942f2SRichard Henderson cpu_loop_exit_restore(cs, retaddr); 799163fa5caSBlue Swirl } 800163fa5caSBlue Swirl 801fad866daSMarkus Armbruster void dump_mmu(CPUSPARCState *env) 802163fa5caSBlue Swirl { 803163fa5caSBlue Swirl unsigned int i; 804163fa5caSBlue Swirl const char *mask; 805163fa5caSBlue Swirl 806fad866daSMarkus Armbruster qemu_printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" 807163fa5caSBlue Swirl PRId64 "\n", 808163fa5caSBlue Swirl env->dmmu.mmu_primary_context, 809163fa5caSBlue Swirl env->dmmu.mmu_secondary_context); 810fad866daSMarkus Armbruster qemu_printf("DMMU Tag Access: %" PRIx64 ", TSB Tag Target: %" PRIx64 811d00a2334SArtyom Tarasenko "\n", env->dmmu.tag_access, env->dmmu.tsb_tag_target); 812163fa5caSBlue Swirl if ((env->lsu & DMMU_E) == 0) { 813fad866daSMarkus Armbruster qemu_printf("DMMU disabled\n"); 814163fa5caSBlue Swirl } else { 815fad866daSMarkus Armbruster qemu_printf("DMMU dump\n"); 816163fa5caSBlue Swirl for (i = 0; i < 64; i++) { 817163fa5caSBlue Swirl switch (TTE_PGSIZE(env->dtlb[i].tte)) { 818163fa5caSBlue Swirl default: 819163fa5caSBlue Swirl case 0x0: 820163fa5caSBlue Swirl mask = " 8k"; 821163fa5caSBlue Swirl break; 822163fa5caSBlue Swirl case 0x1: 823163fa5caSBlue Swirl mask = " 64k"; 824163fa5caSBlue Swirl break; 825163fa5caSBlue Swirl case 0x2: 826163fa5caSBlue Swirl mask = "512k"; 827163fa5caSBlue Swirl break; 828163fa5caSBlue Swirl case 0x3: 829163fa5caSBlue Swirl mask = " 4M"; 830163fa5caSBlue Swirl break; 831163fa5caSBlue Swirl } 832163fa5caSBlue Swirl if (TTE_IS_VALID(env->dtlb[i].tte)) { 833fad866daSMarkus Armbruster qemu_printf("[%02u] VA: %" PRIx64 ", PA: %llx" 834ccdb4c55STony Nguyen ", %s, %s, %s, %s, ie %s, ctx %" PRId64 " %s\n", 835163fa5caSBlue Swirl i, 836163fa5caSBlue Swirl env->dtlb[i].tag & (uint64_t)~0x1fffULL, 837163fa5caSBlue Swirl TTE_PA(env->dtlb[i].tte), 838163fa5caSBlue Swirl mask, 839163fa5caSBlue Swirl TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user", 840163fa5caSBlue Swirl TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO", 841163fa5caSBlue Swirl TTE_IS_LOCKED(env->dtlb[i].tte) ? 842163fa5caSBlue Swirl "locked" : "unlocked", 843ccdb4c55STony Nguyen TTE_IS_IE(env->dtlb[i].tte) ? 844ccdb4c55STony Nguyen "yes" : "no", 845163fa5caSBlue Swirl env->dtlb[i].tag & (uint64_t)0x1fffULL, 846163fa5caSBlue Swirl TTE_IS_GLOBAL(env->dtlb[i].tte) ? 847163fa5caSBlue Swirl "global" : "local"); 848163fa5caSBlue Swirl } 849163fa5caSBlue Swirl } 850163fa5caSBlue Swirl } 851163fa5caSBlue Swirl if ((env->lsu & IMMU_E) == 0) { 852fad866daSMarkus Armbruster qemu_printf("IMMU disabled\n"); 853163fa5caSBlue Swirl } else { 854fad866daSMarkus Armbruster qemu_printf("IMMU dump\n"); 855163fa5caSBlue Swirl for (i = 0; i < 64; i++) { 856163fa5caSBlue Swirl switch (TTE_PGSIZE(env->itlb[i].tte)) { 857163fa5caSBlue Swirl default: 858163fa5caSBlue Swirl case 0x0: 859163fa5caSBlue Swirl mask = " 8k"; 860163fa5caSBlue Swirl break; 861163fa5caSBlue Swirl case 0x1: 862163fa5caSBlue Swirl mask = " 64k"; 863163fa5caSBlue Swirl break; 864163fa5caSBlue Swirl case 0x2: 865163fa5caSBlue Swirl mask = "512k"; 866163fa5caSBlue Swirl break; 867163fa5caSBlue Swirl case 0x3: 868163fa5caSBlue Swirl mask = " 4M"; 869163fa5caSBlue Swirl break; 870163fa5caSBlue Swirl } 871163fa5caSBlue Swirl if (TTE_IS_VALID(env->itlb[i].tte)) { 872fad866daSMarkus Armbruster qemu_printf("[%02u] VA: %" PRIx64 ", PA: %llx" 873163fa5caSBlue Swirl ", %s, %s, %s, ctx %" PRId64 " %s\n", 874163fa5caSBlue Swirl i, 875163fa5caSBlue Swirl env->itlb[i].tag & (uint64_t)~0x1fffULL, 876163fa5caSBlue Swirl TTE_PA(env->itlb[i].tte), 877163fa5caSBlue Swirl mask, 878163fa5caSBlue Swirl TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user", 879163fa5caSBlue Swirl TTE_IS_LOCKED(env->itlb[i].tte) ? 880163fa5caSBlue Swirl "locked" : "unlocked", 881163fa5caSBlue Swirl env->itlb[i].tag & (uint64_t)0x1fffULL, 882163fa5caSBlue Swirl TTE_IS_GLOBAL(env->itlb[i].tte) ? 883163fa5caSBlue Swirl "global" : "local"); 884163fa5caSBlue Swirl } 885163fa5caSBlue Swirl } 886163fa5caSBlue Swirl } 887163fa5caSBlue Swirl } 888163fa5caSBlue Swirl 889163fa5caSBlue Swirl #endif /* TARGET_SPARC64 */ 890163fa5caSBlue Swirl 891a8170e5eSAvi Kivity static int cpu_sparc_get_phys_page(CPUSPARCState *env, hwaddr *phys, 892163fa5caSBlue Swirl target_ulong addr, int rw, int mmu_idx) 893163fa5caSBlue Swirl { 894163fa5caSBlue Swirl target_ulong page_size; 895163fa5caSBlue Swirl int prot, access_index; 8969bed46e6STony Nguyen MemTxAttrs attrs = {}; 897163fa5caSBlue Swirl 8989bed46e6STony Nguyen return get_physical_address(env, phys, &prot, &access_index, &attrs, addr, 8999bed46e6STony Nguyen rw, mmu_idx, &page_size); 900163fa5caSBlue Swirl } 901163fa5caSBlue Swirl 902163fa5caSBlue Swirl #if defined(TARGET_SPARC64) 903a8170e5eSAvi Kivity hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr, 904163fa5caSBlue Swirl int mmu_idx) 905163fa5caSBlue Swirl { 906a8170e5eSAvi Kivity hwaddr phys_addr; 907163fa5caSBlue Swirl 908163fa5caSBlue Swirl if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) { 909163fa5caSBlue Swirl return -1; 910163fa5caSBlue Swirl } 911163fa5caSBlue Swirl return phys_addr; 912163fa5caSBlue Swirl } 913163fa5caSBlue Swirl #endif 914163fa5caSBlue Swirl 91500b941e5SAndreas Färber hwaddr sparc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 916163fa5caSBlue Swirl { 91700b941e5SAndreas Färber SPARCCPU *cpu = SPARC_CPU(cs); 91800b941e5SAndreas Färber CPUSPARCState *env = &cpu->env; 919a8170e5eSAvi Kivity hwaddr phys_addr; 92097ed5ccdSBenjamin Herrenschmidt int mmu_idx = cpu_mmu_index(env, false); 921163fa5caSBlue Swirl 922163fa5caSBlue Swirl if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) { 923163fa5caSBlue Swirl if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) { 924163fa5caSBlue Swirl return -1; 925163fa5caSBlue Swirl } 926163fa5caSBlue Swirl } 927163fa5caSBlue Swirl return phys_addr; 928163fa5caSBlue Swirl } 929163fa5caSBlue Swirl #endif 930