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 20163fa5caSBlue Swirl #include "cpu.h" 21163fa5caSBlue Swirl 22163fa5caSBlue Swirl //#define DEBUG_MMU 23163fa5caSBlue Swirl 24163fa5caSBlue Swirl #ifdef DEBUG_MMU 25163fa5caSBlue Swirl #define DPRINTF_MMU(fmt, ...) \ 26163fa5caSBlue Swirl do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0) 27163fa5caSBlue Swirl #else 28163fa5caSBlue Swirl #define DPRINTF_MMU(fmt, ...) do {} while (0) 29163fa5caSBlue Swirl #endif 30163fa5caSBlue Swirl 31163fa5caSBlue Swirl /* Sparc MMU emulation */ 32163fa5caSBlue Swirl 33163fa5caSBlue Swirl #if defined(CONFIG_USER_ONLY) 34163fa5caSBlue Swirl 35163fa5caSBlue Swirl int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw, 36163fa5caSBlue Swirl int mmu_idx) 37163fa5caSBlue Swirl { 38163fa5caSBlue Swirl if (rw & 2) { 39163fa5caSBlue Swirl env1->exception_index = TT_TFAULT; 40163fa5caSBlue Swirl } else { 41163fa5caSBlue Swirl env1->exception_index = TT_DFAULT; 42163fa5caSBlue Swirl } 43163fa5caSBlue Swirl return 1; 44163fa5caSBlue Swirl } 45163fa5caSBlue Swirl 46163fa5caSBlue Swirl #else 47163fa5caSBlue Swirl 48163fa5caSBlue Swirl #ifndef TARGET_SPARC64 49163fa5caSBlue Swirl /* 50163fa5caSBlue Swirl * Sparc V8 Reference MMU (SRMMU) 51163fa5caSBlue Swirl */ 52163fa5caSBlue Swirl static const int access_table[8][8] = { 53163fa5caSBlue Swirl { 0, 0, 0, 0, 8, 0, 12, 12 }, 54163fa5caSBlue Swirl { 0, 0, 0, 0, 8, 0, 0, 0 }, 55163fa5caSBlue Swirl { 8, 8, 0, 0, 0, 8, 12, 12 }, 56163fa5caSBlue Swirl { 8, 8, 0, 0, 0, 8, 0, 0 }, 57163fa5caSBlue Swirl { 8, 0, 8, 0, 8, 8, 12, 12 }, 58163fa5caSBlue Swirl { 8, 0, 8, 0, 8, 0, 8, 0 }, 59163fa5caSBlue Swirl { 8, 8, 8, 0, 8, 8, 12, 12 }, 60163fa5caSBlue Swirl { 8, 8, 8, 0, 8, 8, 8, 0 } 61163fa5caSBlue Swirl }; 62163fa5caSBlue Swirl 63163fa5caSBlue Swirl static const int perm_table[2][8] = { 64163fa5caSBlue Swirl { 65163fa5caSBlue Swirl PAGE_READ, 66163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE, 67163fa5caSBlue Swirl PAGE_READ | PAGE_EXEC, 68163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE | PAGE_EXEC, 69163fa5caSBlue Swirl PAGE_EXEC, 70163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE, 71163fa5caSBlue Swirl PAGE_READ | PAGE_EXEC, 72163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE | PAGE_EXEC 73163fa5caSBlue Swirl }, 74163fa5caSBlue Swirl { 75163fa5caSBlue Swirl PAGE_READ, 76163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE, 77163fa5caSBlue Swirl PAGE_READ | PAGE_EXEC, 78163fa5caSBlue Swirl PAGE_READ | PAGE_WRITE | PAGE_EXEC, 79163fa5caSBlue Swirl PAGE_EXEC, 80163fa5caSBlue Swirl PAGE_READ, 81163fa5caSBlue Swirl 0, 82163fa5caSBlue Swirl 0, 83163fa5caSBlue Swirl } 84163fa5caSBlue Swirl }; 85163fa5caSBlue Swirl 86163fa5caSBlue Swirl static int get_physical_address(CPUState *env, target_phys_addr_t *physical, 87163fa5caSBlue Swirl int *prot, int *access_index, 88163fa5caSBlue Swirl target_ulong address, int rw, int mmu_idx, 89163fa5caSBlue Swirl target_ulong *page_size) 90163fa5caSBlue Swirl { 91163fa5caSBlue Swirl int access_perms = 0; 92163fa5caSBlue Swirl target_phys_addr_t pde_ptr; 93163fa5caSBlue Swirl uint32_t pde; 94163fa5caSBlue Swirl int error_code = 0, is_dirty, is_user; 95163fa5caSBlue Swirl unsigned long page_offset; 96163fa5caSBlue Swirl 97163fa5caSBlue Swirl is_user = mmu_idx == MMU_USER_IDX; 98163fa5caSBlue Swirl 99163fa5caSBlue Swirl if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ 100163fa5caSBlue Swirl *page_size = TARGET_PAGE_SIZE; 101163fa5caSBlue Swirl /* Boot mode: instruction fetches are taken from PROM */ 102163fa5caSBlue Swirl if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) { 103163fa5caSBlue Swirl *physical = env->prom_addr | (address & 0x7ffffULL); 104163fa5caSBlue Swirl *prot = PAGE_READ | PAGE_EXEC; 105163fa5caSBlue Swirl return 0; 106163fa5caSBlue Swirl } 107163fa5caSBlue Swirl *physical = address; 108163fa5caSBlue Swirl *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 109163fa5caSBlue Swirl return 0; 110163fa5caSBlue Swirl } 111163fa5caSBlue Swirl 112163fa5caSBlue Swirl *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1); 113163fa5caSBlue Swirl *physical = 0xffffffffffff0000ULL; 114163fa5caSBlue Swirl 115163fa5caSBlue Swirl /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ 116163fa5caSBlue Swirl /* Context base + context number */ 117163fa5caSBlue Swirl pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); 118163fa5caSBlue Swirl pde = ldl_phys(pde_ptr); 119163fa5caSBlue Swirl 120163fa5caSBlue Swirl /* Ctx pde */ 121163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 122163fa5caSBlue Swirl default: 123163fa5caSBlue Swirl case 0: /* Invalid */ 124163fa5caSBlue Swirl return 1 << 2; 125163fa5caSBlue Swirl case 2: /* L0 PTE, maybe should not happen? */ 126163fa5caSBlue Swirl case 3: /* Reserved */ 127163fa5caSBlue Swirl return 4 << 2; 128163fa5caSBlue Swirl case 1: /* L0 PDE */ 129163fa5caSBlue Swirl pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); 130163fa5caSBlue Swirl pde = ldl_phys(pde_ptr); 131163fa5caSBlue Swirl 132163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 133163fa5caSBlue Swirl default: 134163fa5caSBlue Swirl case 0: /* Invalid */ 135163fa5caSBlue Swirl return (1 << 8) | (1 << 2); 136163fa5caSBlue Swirl case 3: /* Reserved */ 137163fa5caSBlue Swirl return (1 << 8) | (4 << 2); 138163fa5caSBlue Swirl case 1: /* L1 PDE */ 139163fa5caSBlue Swirl pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); 140163fa5caSBlue Swirl pde = ldl_phys(pde_ptr); 141163fa5caSBlue Swirl 142163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 143163fa5caSBlue Swirl default: 144163fa5caSBlue Swirl case 0: /* Invalid */ 145163fa5caSBlue Swirl return (2 << 8) | (1 << 2); 146163fa5caSBlue Swirl case 3: /* Reserved */ 147163fa5caSBlue Swirl return (2 << 8) | (4 << 2); 148163fa5caSBlue Swirl case 1: /* L2 PDE */ 149163fa5caSBlue Swirl pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); 150163fa5caSBlue Swirl pde = ldl_phys(pde_ptr); 151163fa5caSBlue Swirl 152163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 153163fa5caSBlue Swirl default: 154163fa5caSBlue Swirl case 0: /* Invalid */ 155163fa5caSBlue Swirl return (3 << 8) | (1 << 2); 156163fa5caSBlue Swirl case 1: /* PDE, should not happen */ 157163fa5caSBlue Swirl case 3: /* Reserved */ 158163fa5caSBlue Swirl return (3 << 8) | (4 << 2); 159163fa5caSBlue Swirl case 2: /* L3 PTE */ 160163fa5caSBlue Swirl page_offset = (address & TARGET_PAGE_MASK) & 161163fa5caSBlue Swirl (TARGET_PAGE_SIZE - 1); 162163fa5caSBlue Swirl } 163163fa5caSBlue Swirl *page_size = TARGET_PAGE_SIZE; 164163fa5caSBlue Swirl break; 165163fa5caSBlue Swirl case 2: /* L2 PTE */ 166163fa5caSBlue Swirl page_offset = address & 0x3ffff; 167163fa5caSBlue Swirl *page_size = 0x40000; 168163fa5caSBlue Swirl } 169163fa5caSBlue Swirl break; 170163fa5caSBlue Swirl case 2: /* L1 PTE */ 171163fa5caSBlue Swirl page_offset = address & 0xffffff; 172163fa5caSBlue Swirl *page_size = 0x1000000; 173163fa5caSBlue Swirl } 174163fa5caSBlue Swirl } 175163fa5caSBlue Swirl 176163fa5caSBlue Swirl /* check access */ 177163fa5caSBlue Swirl access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; 178163fa5caSBlue Swirl error_code = access_table[*access_index][access_perms]; 179163fa5caSBlue Swirl if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) { 180163fa5caSBlue Swirl return error_code; 181163fa5caSBlue Swirl } 182163fa5caSBlue Swirl 183163fa5caSBlue Swirl /* update page modified and dirty bits */ 184163fa5caSBlue Swirl is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); 185163fa5caSBlue Swirl if (!(pde & PG_ACCESSED_MASK) || is_dirty) { 186163fa5caSBlue Swirl pde |= PG_ACCESSED_MASK; 187163fa5caSBlue Swirl if (is_dirty) { 188163fa5caSBlue Swirl pde |= PG_MODIFIED_MASK; 189163fa5caSBlue Swirl } 190163fa5caSBlue Swirl stl_phys_notdirty(pde_ptr, pde); 191163fa5caSBlue Swirl } 192163fa5caSBlue Swirl 193163fa5caSBlue Swirl /* the page can be put in the TLB */ 194163fa5caSBlue Swirl *prot = perm_table[is_user][access_perms]; 195163fa5caSBlue Swirl if (!(pde & PG_MODIFIED_MASK)) { 196163fa5caSBlue Swirl /* only set write access if already dirty... otherwise wait 197163fa5caSBlue Swirl for dirty access */ 198163fa5caSBlue Swirl *prot &= ~PAGE_WRITE; 199163fa5caSBlue Swirl } 200163fa5caSBlue Swirl 201163fa5caSBlue Swirl /* Even if large ptes, we map only one 4KB page in the cache to 202163fa5caSBlue Swirl avoid filling it too fast */ 203163fa5caSBlue Swirl *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset; 204163fa5caSBlue Swirl return error_code; 205163fa5caSBlue Swirl } 206163fa5caSBlue Swirl 207163fa5caSBlue Swirl /* Perform address translation */ 208163fa5caSBlue Swirl int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, 209163fa5caSBlue Swirl int mmu_idx) 210163fa5caSBlue Swirl { 211163fa5caSBlue Swirl target_phys_addr_t paddr; 212163fa5caSBlue Swirl target_ulong vaddr; 213163fa5caSBlue Swirl target_ulong page_size; 214163fa5caSBlue Swirl int error_code = 0, prot, access_index; 215163fa5caSBlue Swirl 216163fa5caSBlue Swirl error_code = get_physical_address(env, &paddr, &prot, &access_index, 217163fa5caSBlue Swirl address, rw, mmu_idx, &page_size); 218163fa5caSBlue Swirl if (error_code == 0) { 219163fa5caSBlue Swirl vaddr = address & TARGET_PAGE_MASK; 220163fa5caSBlue Swirl paddr &= TARGET_PAGE_MASK; 221163fa5caSBlue Swirl #ifdef DEBUG_MMU 222163fa5caSBlue Swirl printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr " 223163fa5caSBlue Swirl TARGET_FMT_lx "\n", address, paddr, vaddr); 224163fa5caSBlue Swirl #endif 225163fa5caSBlue Swirl tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size); 226163fa5caSBlue Swirl return 0; 227163fa5caSBlue Swirl } 228163fa5caSBlue Swirl 229163fa5caSBlue Swirl if (env->mmuregs[3]) { /* Fault status register */ 230163fa5caSBlue Swirl env->mmuregs[3] = 1; /* overflow (not read before another fault) */ 231163fa5caSBlue Swirl } 232163fa5caSBlue Swirl env->mmuregs[3] |= (access_index << 5) | error_code | 2; 233163fa5caSBlue Swirl env->mmuregs[4] = address; /* Fault address register */ 234163fa5caSBlue Swirl 235163fa5caSBlue Swirl if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) { 236163fa5caSBlue Swirl /* No fault mode: if a mapping is available, just override 237163fa5caSBlue Swirl permissions. If no mapping is available, redirect accesses to 238163fa5caSBlue Swirl neverland. Fake/overridden mappings will be flushed when 239163fa5caSBlue Swirl switching to normal mode. */ 240163fa5caSBlue Swirl vaddr = address & TARGET_PAGE_MASK; 241163fa5caSBlue Swirl prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 242163fa5caSBlue Swirl tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE); 243163fa5caSBlue Swirl return 0; 244163fa5caSBlue Swirl } else { 245163fa5caSBlue Swirl if (rw & 2) { 246163fa5caSBlue Swirl env->exception_index = TT_TFAULT; 247163fa5caSBlue Swirl } else { 248163fa5caSBlue Swirl env->exception_index = TT_DFAULT; 249163fa5caSBlue Swirl } 250163fa5caSBlue Swirl return 1; 251163fa5caSBlue Swirl } 252163fa5caSBlue Swirl } 253163fa5caSBlue Swirl 254163fa5caSBlue Swirl target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev) 255163fa5caSBlue Swirl { 256163fa5caSBlue Swirl target_phys_addr_t pde_ptr; 257163fa5caSBlue Swirl uint32_t pde; 258163fa5caSBlue Swirl 259163fa5caSBlue Swirl /* Context base + context number */ 260163fa5caSBlue Swirl pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) + 261163fa5caSBlue Swirl (env->mmuregs[2] << 2); 262163fa5caSBlue Swirl pde = ldl_phys(pde_ptr); 263163fa5caSBlue Swirl 264163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 265163fa5caSBlue Swirl default: 266163fa5caSBlue Swirl case 0: /* Invalid */ 267163fa5caSBlue Swirl case 2: /* PTE, maybe should not happen? */ 268163fa5caSBlue Swirl case 3: /* Reserved */ 269163fa5caSBlue Swirl return 0; 270163fa5caSBlue Swirl case 1: /* L1 PDE */ 271163fa5caSBlue Swirl if (mmulev == 3) { 272163fa5caSBlue Swirl return pde; 273163fa5caSBlue Swirl } 274163fa5caSBlue Swirl pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); 275163fa5caSBlue Swirl pde = ldl_phys(pde_ptr); 276163fa5caSBlue Swirl 277163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 278163fa5caSBlue Swirl default: 279163fa5caSBlue Swirl case 0: /* Invalid */ 280163fa5caSBlue Swirl case 3: /* Reserved */ 281163fa5caSBlue Swirl return 0; 282163fa5caSBlue Swirl case 2: /* L1 PTE */ 283163fa5caSBlue Swirl return pde; 284163fa5caSBlue Swirl case 1: /* L2 PDE */ 285163fa5caSBlue Swirl if (mmulev == 2) { 286163fa5caSBlue Swirl return pde; 287163fa5caSBlue Swirl } 288163fa5caSBlue Swirl pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); 289163fa5caSBlue Swirl pde = ldl_phys(pde_ptr); 290163fa5caSBlue Swirl 291163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 292163fa5caSBlue Swirl default: 293163fa5caSBlue Swirl case 0: /* Invalid */ 294163fa5caSBlue Swirl case 3: /* Reserved */ 295163fa5caSBlue Swirl return 0; 296163fa5caSBlue Swirl case 2: /* L2 PTE */ 297163fa5caSBlue Swirl return pde; 298163fa5caSBlue Swirl case 1: /* L3 PDE */ 299163fa5caSBlue Swirl if (mmulev == 1) { 300163fa5caSBlue Swirl return pde; 301163fa5caSBlue Swirl } 302163fa5caSBlue Swirl pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); 303163fa5caSBlue Swirl pde = ldl_phys(pde_ptr); 304163fa5caSBlue Swirl 305163fa5caSBlue Swirl switch (pde & PTE_ENTRYTYPE_MASK) { 306163fa5caSBlue Swirl default: 307163fa5caSBlue Swirl case 0: /* Invalid */ 308163fa5caSBlue Swirl case 1: /* PDE, should not happen */ 309163fa5caSBlue Swirl case 3: /* Reserved */ 310163fa5caSBlue Swirl return 0; 311163fa5caSBlue Swirl case 2: /* L3 PTE */ 312163fa5caSBlue Swirl return pde; 313163fa5caSBlue Swirl } 314163fa5caSBlue Swirl } 315163fa5caSBlue Swirl } 316163fa5caSBlue Swirl } 317163fa5caSBlue Swirl return 0; 318163fa5caSBlue Swirl } 319163fa5caSBlue Swirl 320163fa5caSBlue Swirl void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) 321163fa5caSBlue Swirl { 322163fa5caSBlue Swirl target_ulong va, va1, va2; 323163fa5caSBlue Swirl unsigned int n, m, o; 324163fa5caSBlue Swirl target_phys_addr_t pde_ptr, pa; 325163fa5caSBlue Swirl uint32_t pde; 326163fa5caSBlue Swirl 327163fa5caSBlue Swirl pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); 328163fa5caSBlue Swirl pde = ldl_phys(pde_ptr); 329163fa5caSBlue Swirl (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n", 330163fa5caSBlue Swirl (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]); 331163fa5caSBlue Swirl for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { 332163fa5caSBlue Swirl pde = mmu_probe(env, va, 2); 333163fa5caSBlue Swirl if (pde) { 334163fa5caSBlue Swirl pa = cpu_get_phys_page_debug(env, va); 335163fa5caSBlue Swirl (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx 336163fa5caSBlue Swirl " PDE: " TARGET_FMT_lx "\n", va, pa, pde); 337163fa5caSBlue Swirl for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { 338163fa5caSBlue Swirl pde = mmu_probe(env, va1, 1); 339163fa5caSBlue Swirl if (pde) { 340163fa5caSBlue Swirl pa = cpu_get_phys_page_debug(env, va1); 341163fa5caSBlue Swirl (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " 342163fa5caSBlue Swirl TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n", 343163fa5caSBlue Swirl va1, pa, pde); 344163fa5caSBlue Swirl for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { 345163fa5caSBlue Swirl pde = mmu_probe(env, va2, 0); 346163fa5caSBlue Swirl if (pde) { 347163fa5caSBlue Swirl pa = cpu_get_phys_page_debug(env, va2); 348163fa5caSBlue Swirl (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " 349163fa5caSBlue Swirl TARGET_FMT_plx " PTE: " 350163fa5caSBlue Swirl TARGET_FMT_lx "\n", 351163fa5caSBlue Swirl va2, pa, pde); 352163fa5caSBlue Swirl } 353163fa5caSBlue Swirl } 354163fa5caSBlue Swirl } 355163fa5caSBlue Swirl } 356163fa5caSBlue Swirl } 357163fa5caSBlue Swirl } 358163fa5caSBlue Swirl } 359163fa5caSBlue Swirl 360163fa5caSBlue Swirl /* Gdb expects all registers windows to be flushed in ram. This function handles 361163fa5caSBlue Swirl * reads (and only reads) in stack frames as if windows were flushed. We assume 362163fa5caSBlue Swirl * that the sparc ABI is followed. 363163fa5caSBlue Swirl */ 364163fa5caSBlue Swirl int target_memory_rw_debug(CPUState *env, target_ulong addr, 365163fa5caSBlue Swirl uint8_t *buf, int len, int is_write) 366163fa5caSBlue Swirl { 367163fa5caSBlue Swirl int i; 368163fa5caSBlue Swirl int len1; 369163fa5caSBlue Swirl int cwp = env->cwp; 370163fa5caSBlue Swirl 371163fa5caSBlue Swirl if (!is_write) { 372163fa5caSBlue Swirl for (i = 0; i < env->nwindows; i++) { 373163fa5caSBlue Swirl int off; 374163fa5caSBlue Swirl target_ulong fp = env->regbase[cwp * 16 + 22]; 375163fa5caSBlue Swirl 376163fa5caSBlue Swirl /* Assume fp == 0 means end of frame. */ 377163fa5caSBlue Swirl if (fp == 0) { 378163fa5caSBlue Swirl break; 379163fa5caSBlue Swirl } 380163fa5caSBlue Swirl 381163fa5caSBlue Swirl cwp = cpu_cwp_inc(env, cwp + 1); 382163fa5caSBlue Swirl 383163fa5caSBlue Swirl /* Invalid window ? */ 384163fa5caSBlue Swirl if (env->wim & (1 << cwp)) { 385163fa5caSBlue Swirl break; 386163fa5caSBlue Swirl } 387163fa5caSBlue Swirl 388163fa5caSBlue Swirl /* According to the ABI, the stack is growing downward. */ 389163fa5caSBlue Swirl if (addr + len < fp) { 390163fa5caSBlue Swirl break; 391163fa5caSBlue Swirl } 392163fa5caSBlue Swirl 393163fa5caSBlue Swirl /* Not in this frame. */ 394163fa5caSBlue Swirl if (addr > fp + 64) { 395163fa5caSBlue Swirl continue; 396163fa5caSBlue Swirl } 397163fa5caSBlue Swirl 398163fa5caSBlue Swirl /* Handle access before this window. */ 399163fa5caSBlue Swirl if (addr < fp) { 400163fa5caSBlue Swirl len1 = fp - addr; 401163fa5caSBlue Swirl if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) { 402163fa5caSBlue Swirl return -1; 403163fa5caSBlue Swirl } 404163fa5caSBlue Swirl addr += len1; 405163fa5caSBlue Swirl len -= len1; 406163fa5caSBlue Swirl buf += len1; 407163fa5caSBlue Swirl } 408163fa5caSBlue Swirl 409163fa5caSBlue Swirl /* Access byte per byte to registers. Not very efficient but speed 410163fa5caSBlue Swirl * is not critical. 411163fa5caSBlue Swirl */ 412163fa5caSBlue Swirl off = addr - fp; 413163fa5caSBlue Swirl len1 = 64 - off; 414163fa5caSBlue Swirl 415163fa5caSBlue Swirl if (len1 > len) { 416163fa5caSBlue Swirl len1 = len; 417163fa5caSBlue Swirl } 418163fa5caSBlue Swirl 419163fa5caSBlue Swirl for (; len1; len1--) { 420163fa5caSBlue Swirl int reg = cwp * 16 + 8 + (off >> 2); 421163fa5caSBlue Swirl union { 422163fa5caSBlue Swirl uint32_t v; 423163fa5caSBlue Swirl uint8_t c[4]; 424163fa5caSBlue Swirl } u; 425163fa5caSBlue Swirl u.v = cpu_to_be32(env->regbase[reg]); 426163fa5caSBlue Swirl *buf++ = u.c[off & 3]; 427163fa5caSBlue Swirl addr++; 428163fa5caSBlue Swirl len--; 429163fa5caSBlue Swirl off++; 430163fa5caSBlue Swirl } 431163fa5caSBlue Swirl 432163fa5caSBlue Swirl if (len == 0) { 433163fa5caSBlue Swirl return 0; 434163fa5caSBlue Swirl } 435163fa5caSBlue Swirl } 436163fa5caSBlue Swirl } 437163fa5caSBlue Swirl return cpu_memory_rw_debug(env, addr, buf, len, is_write); 438163fa5caSBlue Swirl } 439163fa5caSBlue Swirl 440163fa5caSBlue Swirl #else /* !TARGET_SPARC64 */ 441163fa5caSBlue Swirl 442163fa5caSBlue Swirl /* 41 bit physical address space */ 443163fa5caSBlue Swirl static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x) 444163fa5caSBlue Swirl { 445163fa5caSBlue Swirl return x & 0x1ffffffffffULL; 446163fa5caSBlue Swirl } 447163fa5caSBlue Swirl 448163fa5caSBlue Swirl /* 449163fa5caSBlue Swirl * UltraSparc IIi I/DMMUs 450163fa5caSBlue Swirl */ 451163fa5caSBlue Swirl 452163fa5caSBlue Swirl /* Returns true if TTE tag is valid and matches virtual address value 453163fa5caSBlue Swirl in context requires virtual address mask value calculated from TTE 454163fa5caSBlue Swirl entry size */ 455163fa5caSBlue Swirl static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, 456163fa5caSBlue Swirl uint64_t address, uint64_t context, 457163fa5caSBlue Swirl target_phys_addr_t *physical) 458163fa5caSBlue Swirl { 459163fa5caSBlue Swirl uint64_t mask; 460163fa5caSBlue Swirl 461163fa5caSBlue Swirl switch (TTE_PGSIZE(tlb->tte)) { 462163fa5caSBlue Swirl default: 463163fa5caSBlue Swirl case 0x0: /* 8k */ 464163fa5caSBlue Swirl mask = 0xffffffffffffe000ULL; 465163fa5caSBlue Swirl break; 466163fa5caSBlue Swirl case 0x1: /* 64k */ 467163fa5caSBlue Swirl mask = 0xffffffffffff0000ULL; 468163fa5caSBlue Swirl break; 469163fa5caSBlue Swirl case 0x2: /* 512k */ 470163fa5caSBlue Swirl mask = 0xfffffffffff80000ULL; 471163fa5caSBlue Swirl break; 472163fa5caSBlue Swirl case 0x3: /* 4M */ 473163fa5caSBlue Swirl mask = 0xffffffffffc00000ULL; 474163fa5caSBlue Swirl break; 475163fa5caSBlue Swirl } 476163fa5caSBlue Swirl 477163fa5caSBlue Swirl /* valid, context match, virtual address match? */ 478163fa5caSBlue Swirl if (TTE_IS_VALID(tlb->tte) && 479163fa5caSBlue Swirl (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context)) 480163fa5caSBlue Swirl && compare_masked(address, tlb->tag, mask)) { 481163fa5caSBlue Swirl /* decode physical address */ 482163fa5caSBlue Swirl *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL; 483163fa5caSBlue Swirl return 1; 484163fa5caSBlue Swirl } 485163fa5caSBlue Swirl 486163fa5caSBlue Swirl return 0; 487163fa5caSBlue Swirl } 488163fa5caSBlue Swirl 489163fa5caSBlue Swirl static int get_physical_address_data(CPUState *env, 490163fa5caSBlue Swirl target_phys_addr_t *physical, int *prot, 491163fa5caSBlue Swirl target_ulong address, int rw, int mmu_idx) 492163fa5caSBlue Swirl { 493163fa5caSBlue Swirl unsigned int i; 494163fa5caSBlue Swirl uint64_t context; 495163fa5caSBlue Swirl uint64_t sfsr = 0; 496163fa5caSBlue Swirl 497163fa5caSBlue Swirl int is_user = (mmu_idx == MMU_USER_IDX || 498163fa5caSBlue Swirl mmu_idx == MMU_USER_SECONDARY_IDX); 499163fa5caSBlue Swirl 500163fa5caSBlue Swirl if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */ 501163fa5caSBlue Swirl *physical = ultrasparc_truncate_physical(address); 502163fa5caSBlue Swirl *prot = PAGE_READ | PAGE_WRITE; 503163fa5caSBlue Swirl return 0; 504163fa5caSBlue Swirl } 505163fa5caSBlue Swirl 506163fa5caSBlue Swirl switch (mmu_idx) { 507163fa5caSBlue Swirl case MMU_USER_IDX: 508163fa5caSBlue Swirl case MMU_KERNEL_IDX: 509163fa5caSBlue Swirl context = env->dmmu.mmu_primary_context & 0x1fff; 510163fa5caSBlue Swirl sfsr |= SFSR_CT_PRIMARY; 511163fa5caSBlue Swirl break; 512163fa5caSBlue Swirl case MMU_USER_SECONDARY_IDX: 513163fa5caSBlue Swirl case MMU_KERNEL_SECONDARY_IDX: 514163fa5caSBlue Swirl context = env->dmmu.mmu_secondary_context & 0x1fff; 515163fa5caSBlue Swirl sfsr |= SFSR_CT_SECONDARY; 516163fa5caSBlue Swirl break; 517163fa5caSBlue Swirl case MMU_NUCLEUS_IDX: 518163fa5caSBlue Swirl sfsr |= SFSR_CT_NUCLEUS; 519163fa5caSBlue Swirl /* FALLTHRU */ 520163fa5caSBlue Swirl default: 521163fa5caSBlue Swirl context = 0; 522163fa5caSBlue Swirl break; 523163fa5caSBlue Swirl } 524163fa5caSBlue Swirl 525163fa5caSBlue Swirl if (rw == 1) { 526163fa5caSBlue Swirl sfsr |= SFSR_WRITE_BIT; 527163fa5caSBlue Swirl } else if (rw == 4) { 528163fa5caSBlue Swirl sfsr |= SFSR_NF_BIT; 529163fa5caSBlue Swirl } 530163fa5caSBlue Swirl 531163fa5caSBlue Swirl for (i = 0; i < 64; i++) { 532163fa5caSBlue Swirl /* ctx match, vaddr match, valid? */ 533163fa5caSBlue Swirl if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) { 534163fa5caSBlue Swirl int do_fault = 0; 535163fa5caSBlue Swirl 536163fa5caSBlue Swirl /* access ok? */ 537163fa5caSBlue Swirl /* multiple bits in SFSR.FT may be set on TT_DFAULT */ 538163fa5caSBlue Swirl if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) { 539163fa5caSBlue Swirl do_fault = 1; 540163fa5caSBlue Swirl sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */ 541163fa5caSBlue Swirl 542163fa5caSBlue Swirl DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64 543163fa5caSBlue Swirl " mmu_idx=%d tl=%d\n", 544163fa5caSBlue Swirl address, context, mmu_idx, env->tl); 545163fa5caSBlue Swirl } 546163fa5caSBlue Swirl if (rw == 4) { 547163fa5caSBlue Swirl if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) { 548163fa5caSBlue Swirl do_fault = 1; 549163fa5caSBlue Swirl sfsr |= SFSR_FT_NF_E_BIT; 550163fa5caSBlue Swirl } 551163fa5caSBlue Swirl } else { 552163fa5caSBlue Swirl if (TTE_IS_NFO(env->dtlb[i].tte)) { 553163fa5caSBlue Swirl do_fault = 1; 554163fa5caSBlue Swirl sfsr |= SFSR_FT_NFO_BIT; 555163fa5caSBlue Swirl } 556163fa5caSBlue Swirl } 557163fa5caSBlue Swirl 558163fa5caSBlue Swirl if (do_fault) { 559163fa5caSBlue Swirl /* faults above are reported with TT_DFAULT. */ 560163fa5caSBlue Swirl env->exception_index = TT_DFAULT; 561163fa5caSBlue Swirl } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) { 562163fa5caSBlue Swirl do_fault = 1; 563163fa5caSBlue Swirl env->exception_index = TT_DPROT; 564163fa5caSBlue Swirl 565163fa5caSBlue Swirl DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64 566163fa5caSBlue Swirl " mmu_idx=%d tl=%d\n", 567163fa5caSBlue Swirl address, context, mmu_idx, env->tl); 568163fa5caSBlue Swirl } 569163fa5caSBlue Swirl 570163fa5caSBlue Swirl if (!do_fault) { 571163fa5caSBlue Swirl *prot = PAGE_READ; 572163fa5caSBlue Swirl if (TTE_IS_W_OK(env->dtlb[i].tte)) { 573163fa5caSBlue Swirl *prot |= PAGE_WRITE; 574163fa5caSBlue Swirl } 575163fa5caSBlue Swirl 576163fa5caSBlue Swirl TTE_SET_USED(env->dtlb[i].tte); 577163fa5caSBlue Swirl 578163fa5caSBlue Swirl return 0; 579163fa5caSBlue Swirl } 580163fa5caSBlue Swirl 581163fa5caSBlue Swirl if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */ 582163fa5caSBlue Swirl sfsr |= SFSR_OW_BIT; /* overflow (not read before 583163fa5caSBlue Swirl another fault) */ 584163fa5caSBlue Swirl } 585163fa5caSBlue Swirl 586163fa5caSBlue Swirl if (env->pstate & PS_PRIV) { 587163fa5caSBlue Swirl sfsr |= SFSR_PR_BIT; 588163fa5caSBlue Swirl } 589163fa5caSBlue Swirl 590163fa5caSBlue Swirl /* FIXME: ASI field in SFSR must be set */ 591163fa5caSBlue Swirl env->dmmu.sfsr = sfsr | SFSR_VALID_BIT; 592163fa5caSBlue Swirl 593163fa5caSBlue Swirl env->dmmu.sfar = address; /* Fault address register */ 594163fa5caSBlue Swirl 595163fa5caSBlue Swirl env->dmmu.tag_access = (address & ~0x1fffULL) | context; 596163fa5caSBlue Swirl 597163fa5caSBlue Swirl return 1; 598163fa5caSBlue Swirl } 599163fa5caSBlue Swirl } 600163fa5caSBlue Swirl 601163fa5caSBlue Swirl DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n", 602163fa5caSBlue Swirl address, context); 603163fa5caSBlue Swirl 604163fa5caSBlue Swirl /* 605163fa5caSBlue Swirl * On MMU misses: 606163fa5caSBlue Swirl * - UltraSPARC IIi: SFSR and SFAR unmodified 607163fa5caSBlue Swirl * - JPS1: SFAR updated and some fields of SFSR updated 608163fa5caSBlue Swirl */ 609163fa5caSBlue Swirl env->dmmu.tag_access = (address & ~0x1fffULL) | context; 610163fa5caSBlue Swirl env->exception_index = TT_DMISS; 611163fa5caSBlue Swirl return 1; 612163fa5caSBlue Swirl } 613163fa5caSBlue Swirl 614163fa5caSBlue Swirl static int get_physical_address_code(CPUState *env, 615163fa5caSBlue Swirl target_phys_addr_t *physical, int *prot, 616163fa5caSBlue Swirl target_ulong address, int mmu_idx) 617163fa5caSBlue Swirl { 618163fa5caSBlue Swirl unsigned int i; 619163fa5caSBlue Swirl uint64_t context; 620163fa5caSBlue Swirl 621163fa5caSBlue Swirl int is_user = (mmu_idx == MMU_USER_IDX || 622163fa5caSBlue Swirl mmu_idx == MMU_USER_SECONDARY_IDX); 623163fa5caSBlue Swirl 624163fa5caSBlue Swirl if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) { 625163fa5caSBlue Swirl /* IMMU disabled */ 626163fa5caSBlue Swirl *physical = ultrasparc_truncate_physical(address); 627163fa5caSBlue Swirl *prot = PAGE_EXEC; 628163fa5caSBlue Swirl return 0; 629163fa5caSBlue Swirl } 630163fa5caSBlue Swirl 631163fa5caSBlue Swirl if (env->tl == 0) { 632163fa5caSBlue Swirl /* PRIMARY context */ 633163fa5caSBlue Swirl context = env->dmmu.mmu_primary_context & 0x1fff; 634163fa5caSBlue Swirl } else { 635163fa5caSBlue Swirl /* NUCLEUS context */ 636163fa5caSBlue Swirl context = 0; 637163fa5caSBlue Swirl } 638163fa5caSBlue Swirl 639163fa5caSBlue Swirl for (i = 0; i < 64; i++) { 640163fa5caSBlue Swirl /* ctx match, vaddr match, valid? */ 641163fa5caSBlue Swirl if (ultrasparc_tag_match(&env->itlb[i], 642163fa5caSBlue Swirl address, context, physical)) { 643163fa5caSBlue Swirl /* access ok? */ 644163fa5caSBlue Swirl if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) { 645163fa5caSBlue Swirl /* Fault status register */ 646163fa5caSBlue Swirl if (env->immu.sfsr & SFSR_VALID_BIT) { 647163fa5caSBlue Swirl env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before 648163fa5caSBlue Swirl another fault) */ 649163fa5caSBlue Swirl } else { 650163fa5caSBlue Swirl env->immu.sfsr = 0; 651163fa5caSBlue Swirl } 652163fa5caSBlue Swirl if (env->pstate & PS_PRIV) { 653163fa5caSBlue Swirl env->immu.sfsr |= SFSR_PR_BIT; 654163fa5caSBlue Swirl } 655163fa5caSBlue Swirl if (env->tl > 0) { 656163fa5caSBlue Swirl env->immu.sfsr |= SFSR_CT_NUCLEUS; 657163fa5caSBlue Swirl } 658163fa5caSBlue Swirl 659163fa5caSBlue Swirl /* FIXME: ASI field in SFSR must be set */ 660163fa5caSBlue Swirl env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT; 661163fa5caSBlue Swirl env->exception_index = TT_TFAULT; 662163fa5caSBlue Swirl 663163fa5caSBlue Swirl env->immu.tag_access = (address & ~0x1fffULL) | context; 664163fa5caSBlue Swirl 665163fa5caSBlue Swirl DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n", 666163fa5caSBlue Swirl address, context); 667163fa5caSBlue Swirl 668163fa5caSBlue Swirl return 1; 669163fa5caSBlue Swirl } 670163fa5caSBlue Swirl *prot = PAGE_EXEC; 671163fa5caSBlue Swirl TTE_SET_USED(env->itlb[i].tte); 672163fa5caSBlue Swirl return 0; 673163fa5caSBlue Swirl } 674163fa5caSBlue Swirl } 675163fa5caSBlue Swirl 676163fa5caSBlue Swirl DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n", 677163fa5caSBlue Swirl address, context); 678163fa5caSBlue Swirl 679163fa5caSBlue Swirl /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */ 680163fa5caSBlue Swirl env->immu.tag_access = (address & ~0x1fffULL) | context; 681163fa5caSBlue Swirl env->exception_index = TT_TMISS; 682163fa5caSBlue Swirl return 1; 683163fa5caSBlue Swirl } 684163fa5caSBlue Swirl 685163fa5caSBlue Swirl static int get_physical_address(CPUState *env, target_phys_addr_t *physical, 686163fa5caSBlue Swirl int *prot, int *access_index, 687163fa5caSBlue Swirl target_ulong address, int rw, int mmu_idx, 688163fa5caSBlue Swirl target_ulong *page_size) 689163fa5caSBlue Swirl { 690163fa5caSBlue Swirl /* ??? We treat everything as a small page, then explicitly flush 691163fa5caSBlue Swirl everything when an entry is evicted. */ 692163fa5caSBlue Swirl *page_size = TARGET_PAGE_SIZE; 693163fa5caSBlue Swirl 694163fa5caSBlue Swirl #if defined(DEBUG_MMU) 695163fa5caSBlue Swirl /* safety net to catch wrong softmmu index use from dynamic code */ 696163fa5caSBlue Swirl if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) { 697163fa5caSBlue Swirl DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d" 698163fa5caSBlue Swirl " primary context=%" PRIx64 699163fa5caSBlue Swirl " secondary context=%" PRIx64 700163fa5caSBlue Swirl " address=%" PRIx64 701163fa5caSBlue Swirl "\n", 702163fa5caSBlue Swirl (rw == 2 ? "CODE" : "DATA"), 703163fa5caSBlue Swirl env->tl, mmu_idx, 704163fa5caSBlue Swirl env->dmmu.mmu_primary_context, 705163fa5caSBlue Swirl env->dmmu.mmu_secondary_context, 706163fa5caSBlue Swirl address); 707163fa5caSBlue Swirl } 708163fa5caSBlue Swirl #endif 709163fa5caSBlue Swirl 710163fa5caSBlue Swirl if (rw == 2) { 711163fa5caSBlue Swirl return get_physical_address_code(env, physical, prot, address, 712163fa5caSBlue Swirl mmu_idx); 713163fa5caSBlue Swirl } else { 714163fa5caSBlue Swirl return get_physical_address_data(env, physical, prot, address, rw, 715163fa5caSBlue Swirl mmu_idx); 716163fa5caSBlue Swirl } 717163fa5caSBlue Swirl } 718163fa5caSBlue Swirl 719163fa5caSBlue Swirl /* Perform address translation */ 720163fa5caSBlue Swirl int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, 721163fa5caSBlue Swirl int mmu_idx) 722163fa5caSBlue Swirl { 723163fa5caSBlue Swirl target_ulong virt_addr, vaddr; 724163fa5caSBlue Swirl target_phys_addr_t paddr; 725163fa5caSBlue Swirl target_ulong page_size; 726163fa5caSBlue Swirl int error_code = 0, prot, access_index; 727163fa5caSBlue Swirl 728163fa5caSBlue Swirl error_code = get_physical_address(env, &paddr, &prot, &access_index, 729163fa5caSBlue Swirl address, rw, mmu_idx, &page_size); 730163fa5caSBlue Swirl if (error_code == 0) { 731163fa5caSBlue Swirl virt_addr = address & TARGET_PAGE_MASK; 732163fa5caSBlue Swirl vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & 733163fa5caSBlue Swirl (TARGET_PAGE_SIZE - 1)); 734163fa5caSBlue Swirl 735163fa5caSBlue Swirl DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 "," 736163fa5caSBlue Swirl " vaddr %" PRIx64 737163fa5caSBlue Swirl " mmu_idx=%d" 738163fa5caSBlue Swirl " tl=%d" 739163fa5caSBlue Swirl " primary context=%" PRIx64 740163fa5caSBlue Swirl " secondary context=%" PRIx64 741163fa5caSBlue Swirl "\n", 742163fa5caSBlue Swirl address, paddr, vaddr, mmu_idx, env->tl, 743163fa5caSBlue Swirl env->dmmu.mmu_primary_context, 744163fa5caSBlue Swirl env->dmmu.mmu_secondary_context); 745163fa5caSBlue Swirl 746163fa5caSBlue Swirl tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size); 747163fa5caSBlue Swirl return 0; 748163fa5caSBlue Swirl } 749163fa5caSBlue Swirl /* XXX */ 750163fa5caSBlue Swirl return 1; 751163fa5caSBlue Swirl } 752163fa5caSBlue Swirl 753163fa5caSBlue Swirl void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) 754163fa5caSBlue Swirl { 755163fa5caSBlue Swirl unsigned int i; 756163fa5caSBlue Swirl const char *mask; 757163fa5caSBlue Swirl 758163fa5caSBlue Swirl (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %" 759163fa5caSBlue Swirl PRId64 "\n", 760163fa5caSBlue Swirl env->dmmu.mmu_primary_context, 761163fa5caSBlue Swirl env->dmmu.mmu_secondary_context); 762163fa5caSBlue Swirl if ((env->lsu & DMMU_E) == 0) { 763163fa5caSBlue Swirl (*cpu_fprintf)(f, "DMMU disabled\n"); 764163fa5caSBlue Swirl } else { 765163fa5caSBlue Swirl (*cpu_fprintf)(f, "DMMU dump\n"); 766163fa5caSBlue Swirl for (i = 0; i < 64; i++) { 767163fa5caSBlue Swirl switch (TTE_PGSIZE(env->dtlb[i].tte)) { 768163fa5caSBlue Swirl default: 769163fa5caSBlue Swirl case 0x0: 770163fa5caSBlue Swirl mask = " 8k"; 771163fa5caSBlue Swirl break; 772163fa5caSBlue Swirl case 0x1: 773163fa5caSBlue Swirl mask = " 64k"; 774163fa5caSBlue Swirl break; 775163fa5caSBlue Swirl case 0x2: 776163fa5caSBlue Swirl mask = "512k"; 777163fa5caSBlue Swirl break; 778163fa5caSBlue Swirl case 0x3: 779163fa5caSBlue Swirl mask = " 4M"; 780163fa5caSBlue Swirl break; 781163fa5caSBlue Swirl } 782163fa5caSBlue Swirl if (TTE_IS_VALID(env->dtlb[i].tte)) { 783163fa5caSBlue Swirl (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx" 784163fa5caSBlue Swirl ", %s, %s, %s, %s, ctx %" PRId64 " %s\n", 785163fa5caSBlue Swirl i, 786163fa5caSBlue Swirl env->dtlb[i].tag & (uint64_t)~0x1fffULL, 787163fa5caSBlue Swirl TTE_PA(env->dtlb[i].tte), 788163fa5caSBlue Swirl mask, 789163fa5caSBlue Swirl TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user", 790163fa5caSBlue Swirl TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO", 791163fa5caSBlue Swirl TTE_IS_LOCKED(env->dtlb[i].tte) ? 792163fa5caSBlue Swirl "locked" : "unlocked", 793163fa5caSBlue Swirl env->dtlb[i].tag & (uint64_t)0x1fffULL, 794163fa5caSBlue Swirl TTE_IS_GLOBAL(env->dtlb[i].tte) ? 795163fa5caSBlue Swirl "global" : "local"); 796163fa5caSBlue Swirl } 797163fa5caSBlue Swirl } 798163fa5caSBlue Swirl } 799163fa5caSBlue Swirl if ((env->lsu & IMMU_E) == 0) { 800163fa5caSBlue Swirl (*cpu_fprintf)(f, "IMMU disabled\n"); 801163fa5caSBlue Swirl } else { 802163fa5caSBlue Swirl (*cpu_fprintf)(f, "IMMU dump\n"); 803163fa5caSBlue Swirl for (i = 0; i < 64; i++) { 804163fa5caSBlue Swirl switch (TTE_PGSIZE(env->itlb[i].tte)) { 805163fa5caSBlue Swirl default: 806163fa5caSBlue Swirl case 0x0: 807163fa5caSBlue Swirl mask = " 8k"; 808163fa5caSBlue Swirl break; 809163fa5caSBlue Swirl case 0x1: 810163fa5caSBlue Swirl mask = " 64k"; 811163fa5caSBlue Swirl break; 812163fa5caSBlue Swirl case 0x2: 813163fa5caSBlue Swirl mask = "512k"; 814163fa5caSBlue Swirl break; 815163fa5caSBlue Swirl case 0x3: 816163fa5caSBlue Swirl mask = " 4M"; 817163fa5caSBlue Swirl break; 818163fa5caSBlue Swirl } 819163fa5caSBlue Swirl if (TTE_IS_VALID(env->itlb[i].tte)) { 820163fa5caSBlue Swirl (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx" 821163fa5caSBlue Swirl ", %s, %s, %s, ctx %" PRId64 " %s\n", 822163fa5caSBlue Swirl i, 823163fa5caSBlue Swirl env->itlb[i].tag & (uint64_t)~0x1fffULL, 824163fa5caSBlue Swirl TTE_PA(env->itlb[i].tte), 825163fa5caSBlue Swirl mask, 826163fa5caSBlue Swirl TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user", 827163fa5caSBlue Swirl TTE_IS_LOCKED(env->itlb[i].tte) ? 828163fa5caSBlue Swirl "locked" : "unlocked", 829163fa5caSBlue Swirl env->itlb[i].tag & (uint64_t)0x1fffULL, 830163fa5caSBlue Swirl TTE_IS_GLOBAL(env->itlb[i].tte) ? 831163fa5caSBlue Swirl "global" : "local"); 832163fa5caSBlue Swirl } 833163fa5caSBlue Swirl } 834163fa5caSBlue Swirl } 835163fa5caSBlue Swirl } 836163fa5caSBlue Swirl 837163fa5caSBlue Swirl #endif /* TARGET_SPARC64 */ 838163fa5caSBlue Swirl 839163fa5caSBlue Swirl static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys, 840163fa5caSBlue Swirl target_ulong addr, int rw, int mmu_idx) 841163fa5caSBlue Swirl { 842163fa5caSBlue Swirl target_ulong page_size; 843163fa5caSBlue Swirl int prot, access_index; 844163fa5caSBlue Swirl 845163fa5caSBlue Swirl return get_physical_address(env, phys, &prot, &access_index, addr, rw, 846163fa5caSBlue Swirl mmu_idx, &page_size); 847163fa5caSBlue Swirl } 848163fa5caSBlue Swirl 849163fa5caSBlue Swirl #if defined(TARGET_SPARC64) 850163fa5caSBlue Swirl target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr, 851163fa5caSBlue Swirl int mmu_idx) 852163fa5caSBlue Swirl { 853163fa5caSBlue Swirl target_phys_addr_t phys_addr; 854163fa5caSBlue Swirl 855163fa5caSBlue Swirl if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) { 856163fa5caSBlue Swirl return -1; 857163fa5caSBlue Swirl } 858163fa5caSBlue Swirl return phys_addr; 859163fa5caSBlue Swirl } 860163fa5caSBlue Swirl #endif 861163fa5caSBlue Swirl 862163fa5caSBlue Swirl target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) 863163fa5caSBlue Swirl { 864163fa5caSBlue Swirl target_phys_addr_t phys_addr; 865163fa5caSBlue Swirl int mmu_idx = cpu_mmu_index(env); 866163fa5caSBlue Swirl 867163fa5caSBlue Swirl if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) { 868163fa5caSBlue Swirl if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) { 869163fa5caSBlue Swirl return -1; 870163fa5caSBlue Swirl } 871163fa5caSBlue Swirl } 872163fa5caSBlue Swirl if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) { 873163fa5caSBlue Swirl return -1; 874163fa5caSBlue Swirl } 875163fa5caSBlue Swirl return phys_addr; 876163fa5caSBlue Swirl } 877163fa5caSBlue Swirl #endif 878