1e8af50a3Sbellard /* 2e8af50a3Sbellard * sparc helpers 3e8af50a3Sbellard * 483469015Sbellard * Copyright (c) 2003-2005 Fabrice Bellard 5e8af50a3Sbellard * 6e8af50a3Sbellard * This library is free software; you can redistribute it and/or 7e8af50a3Sbellard * modify it under the terms of the GNU Lesser General Public 8e8af50a3Sbellard * License as published by the Free Software Foundation; either 9e8af50a3Sbellard * version 2 of the License, or (at your option) any later version. 10e8af50a3Sbellard * 11e8af50a3Sbellard * This library is distributed in the hope that it will be useful, 12e8af50a3Sbellard * but WITHOUT ANY WARRANTY; without even the implied warranty of 13e8af50a3Sbellard * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14e8af50a3Sbellard * Lesser General Public License for more details. 15e8af50a3Sbellard * 16e8af50a3Sbellard * You should have received a copy of the GNU Lesser General Public 178167ee88SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18e8af50a3Sbellard */ 19ee5bbe38Sbellard 20ee5bbe38Sbellard #include "cpu.h" 212336c1f1SBlue Swirl #include "host-utils.h" 222336c1f1SBlue Swirl #include "helper.h" 232336c1f1SBlue Swirl #include "sysemu.h" 24e8af50a3Sbellard 25e80cfcfcSbellard //#define DEBUG_MMU 26e8af50a3Sbellard 27b8e9fc06SIgor V. Kovalenko #ifdef DEBUG_MMU 28b8e9fc06SIgor V. Kovalenko #define DPRINTF_MMU(fmt, ...) \ 29b8e9fc06SIgor V. Kovalenko do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0) 30b8e9fc06SIgor V. Kovalenko #else 31b8e9fc06SIgor V. Kovalenko #define DPRINTF_MMU(fmt, ...) do {} while (0) 32b8e9fc06SIgor V. Kovalenko #endif 33b8e9fc06SIgor V. Kovalenko 34e8af50a3Sbellard /* Sparc MMU emulation */ 35e8af50a3Sbellard 369d893301Sbellard #if defined(CONFIG_USER_ONLY) 379d893301Sbellard 3822548760Sblueswir1 int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw, 3997b348e7SBlue Swirl int mmu_idx) 409d893301Sbellard { 41878d3096Sbellard if (rw & 2) 4222548760Sblueswir1 env1->exception_index = TT_TFAULT; 43878d3096Sbellard else 4422548760Sblueswir1 env1->exception_index = TT_DFAULT; 459d893301Sbellard return 1; 469d893301Sbellard } 479d893301Sbellard 489d893301Sbellard #else 49e8af50a3Sbellard 503475187dSbellard #ifndef TARGET_SPARC64 5183469015Sbellard /* 5283469015Sbellard * Sparc V8 Reference MMU (SRMMU) 5383469015Sbellard */ 54e8af50a3Sbellard static const int access_table[8][8] = { 55a764a566Sblueswir1 { 0, 0, 0, 0, 8, 0, 12, 12 }, 56a764a566Sblueswir1 { 0, 0, 0, 0, 8, 0, 0, 0 }, 57a764a566Sblueswir1 { 8, 8, 0, 0, 0, 8, 12, 12 }, 58a764a566Sblueswir1 { 8, 8, 0, 0, 0, 8, 0, 0 }, 59a764a566Sblueswir1 { 8, 0, 8, 0, 8, 8, 12, 12 }, 60a764a566Sblueswir1 { 8, 0, 8, 0, 8, 0, 8, 0 }, 61a764a566Sblueswir1 { 8, 8, 8, 0, 8, 8, 12, 12 }, 62a764a566Sblueswir1 { 8, 8, 8, 0, 8, 8, 8, 0 } 63e8af50a3Sbellard }; 64e8af50a3Sbellard 65227671c9Sbellard static const int perm_table[2][8] = { 66227671c9Sbellard { 67227671c9Sbellard PAGE_READ, 68227671c9Sbellard PAGE_READ | PAGE_WRITE, 69227671c9Sbellard PAGE_READ | PAGE_EXEC, 70227671c9Sbellard PAGE_READ | PAGE_WRITE | PAGE_EXEC, 71227671c9Sbellard PAGE_EXEC, 72227671c9Sbellard PAGE_READ | PAGE_WRITE, 73227671c9Sbellard PAGE_READ | PAGE_EXEC, 74227671c9Sbellard PAGE_READ | PAGE_WRITE | PAGE_EXEC 75227671c9Sbellard }, 76227671c9Sbellard { 77227671c9Sbellard PAGE_READ, 78227671c9Sbellard PAGE_READ | PAGE_WRITE, 79227671c9Sbellard PAGE_READ | PAGE_EXEC, 80227671c9Sbellard PAGE_READ | PAGE_WRITE | PAGE_EXEC, 81227671c9Sbellard PAGE_EXEC, 82227671c9Sbellard PAGE_READ, 83227671c9Sbellard 0, 84227671c9Sbellard 0, 85227671c9Sbellard } 86e8af50a3Sbellard }; 87e8af50a3Sbellard 88c227f099SAnthony Liguori static int get_physical_address(CPUState *env, target_phys_addr_t *physical, 89c48fcb47Sblueswir1 int *prot, int *access_index, 90d4c430a8SPaul Brook target_ulong address, int rw, int mmu_idx, 91d4c430a8SPaul Brook target_ulong *page_size) 92e8af50a3Sbellard { 93e80cfcfcSbellard int access_perms = 0; 94c227f099SAnthony Liguori target_phys_addr_t pde_ptr; 95af7bf89bSbellard uint32_t pde; 966ebbf390Sj_mayer int error_code = 0, is_dirty, is_user; 97e80cfcfcSbellard unsigned long page_offset; 98e8af50a3Sbellard 996ebbf390Sj_mayer is_user = mmu_idx == MMU_USER_IDX; 10040ce0a9aSblueswir1 101e8af50a3Sbellard if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ 102d4c430a8SPaul Brook *page_size = TARGET_PAGE_SIZE; 10340ce0a9aSblueswir1 // Boot mode: instruction fetches are taken from PROM 1045578ceabSblueswir1 if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) { 10558a770f3Sblueswir1 *physical = env->prom_addr | (address & 0x7ffffULL); 10640ce0a9aSblueswir1 *prot = PAGE_READ | PAGE_EXEC; 10740ce0a9aSblueswir1 return 0; 10840ce0a9aSblueswir1 } 109e80cfcfcSbellard *physical = address; 110227671c9Sbellard *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 111e80cfcfcSbellard return 0; 112e8af50a3Sbellard } 113e8af50a3Sbellard 1147483750dSbellard *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1); 1155dcb6b91Sblueswir1 *physical = 0xffffffffffff0000ULL; 1167483750dSbellard 117e8af50a3Sbellard /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ 118e8af50a3Sbellard /* Context base + context number */ 1193deaeab7Sblueswir1 pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); 12049be8030Sbellard pde = ldl_phys(pde_ptr); 121e8af50a3Sbellard 122e8af50a3Sbellard /* Ctx pde */ 123e8af50a3Sbellard switch (pde & PTE_ENTRYTYPE_MASK) { 124e80cfcfcSbellard default: 125e8af50a3Sbellard case 0: /* Invalid */ 1267483750dSbellard return 1 << 2; 127e80cfcfcSbellard case 2: /* L0 PTE, maybe should not happen? */ 128e8af50a3Sbellard case 3: /* Reserved */ 1297483750dSbellard return 4 << 2; 130e80cfcfcSbellard case 1: /* L0 PDE */ 131e80cfcfcSbellard pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); 13249be8030Sbellard pde = ldl_phys(pde_ptr); 133e80cfcfcSbellard 134e80cfcfcSbellard switch (pde & PTE_ENTRYTYPE_MASK) { 135e80cfcfcSbellard default: 136e80cfcfcSbellard case 0: /* Invalid */ 1377483750dSbellard return (1 << 8) | (1 << 2); 138e80cfcfcSbellard case 3: /* Reserved */ 1397483750dSbellard return (1 << 8) | (4 << 2); 140e8af50a3Sbellard case 1: /* L1 PDE */ 141e80cfcfcSbellard pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); 14249be8030Sbellard pde = ldl_phys(pde_ptr); 143e8af50a3Sbellard 144e8af50a3Sbellard switch (pde & PTE_ENTRYTYPE_MASK) { 145e80cfcfcSbellard default: 146e8af50a3Sbellard case 0: /* Invalid */ 1477483750dSbellard return (2 << 8) | (1 << 2); 148e8af50a3Sbellard case 3: /* Reserved */ 1497483750dSbellard return (2 << 8) | (4 << 2); 150e8af50a3Sbellard case 1: /* L2 PDE */ 151e80cfcfcSbellard pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); 15249be8030Sbellard pde = ldl_phys(pde_ptr); 153e8af50a3Sbellard 154e8af50a3Sbellard switch (pde & PTE_ENTRYTYPE_MASK) { 155e80cfcfcSbellard default: 156e8af50a3Sbellard case 0: /* Invalid */ 1577483750dSbellard return (3 << 8) | (1 << 2); 158e8af50a3Sbellard case 1: /* PDE, should not happen */ 159e8af50a3Sbellard case 3: /* Reserved */ 1607483750dSbellard return (3 << 8) | (4 << 2); 161e8af50a3Sbellard case 2: /* L3 PTE */ 16277f193daSblueswir1 page_offset = (address & TARGET_PAGE_MASK) & 16377f193daSblueswir1 (TARGET_PAGE_SIZE - 1); 164e8af50a3Sbellard } 165d4c430a8SPaul Brook *page_size = TARGET_PAGE_SIZE; 166e8af50a3Sbellard break; 167e8af50a3Sbellard case 2: /* L2 PTE */ 168e8af50a3Sbellard page_offset = address & 0x3ffff; 169d4c430a8SPaul Brook *page_size = 0x40000; 170e8af50a3Sbellard } 171e8af50a3Sbellard break; 172e8af50a3Sbellard case 2: /* L1 PTE */ 173e8af50a3Sbellard page_offset = address & 0xffffff; 174d4c430a8SPaul Brook *page_size = 0x1000000; 175e8af50a3Sbellard } 176e8af50a3Sbellard } 177e8af50a3Sbellard 178698235aaSArtyom Tarasenko /* check access */ 179698235aaSArtyom Tarasenko access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; 180698235aaSArtyom Tarasenko error_code = access_table[*access_index][access_perms]; 181698235aaSArtyom Tarasenko if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) 182698235aaSArtyom Tarasenko return error_code; 183698235aaSArtyom Tarasenko 184e8af50a3Sbellard /* update page modified and dirty bits */ 185b769d8feSbellard is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); 186e8af50a3Sbellard if (!(pde & PG_ACCESSED_MASK) || is_dirty) { 187e8af50a3Sbellard pde |= PG_ACCESSED_MASK; 188e8af50a3Sbellard if (is_dirty) 189e8af50a3Sbellard pde |= PG_MODIFIED_MASK; 19049be8030Sbellard stl_phys_notdirty(pde_ptr, pde); 191e8af50a3Sbellard } 192e8af50a3Sbellard 193e8af50a3Sbellard /* the page can be put in the TLB */ 194227671c9Sbellard *prot = perm_table[is_user][access_perms]; 195227671c9Sbellard if (!(pde & PG_MODIFIED_MASK)) { 196e8af50a3Sbellard /* only set write access if already dirty... otherwise wait 197e8af50a3Sbellard for dirty access */ 198227671c9Sbellard *prot &= ~PAGE_WRITE; 199e8af50a3Sbellard } 200e8af50a3Sbellard 201e8af50a3Sbellard /* Even if large ptes, we map only one 4KB page in the cache to 202e8af50a3Sbellard avoid filling it too fast */ 203c227f099SAnthony Liguori *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset; 2046f7e9aecSbellard return error_code; 205e80cfcfcSbellard } 206e80cfcfcSbellard 207e80cfcfcSbellard /* Perform address translation */ 208af7bf89bSbellard int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, 20997b348e7SBlue Swirl int mmu_idx) 210e80cfcfcSbellard { 211c227f099SAnthony Liguori target_phys_addr_t paddr; 2125dcb6b91Sblueswir1 target_ulong vaddr; 213d4c430a8SPaul Brook target_ulong page_size; 214d4c430a8SPaul Brook int error_code = 0, prot, access_index; 215e80cfcfcSbellard 21677f193daSblueswir1 error_code = get_physical_address(env, &paddr, &prot, &access_index, 217d4c430a8SPaul Brook address, rw, mmu_idx, &page_size); 218e80cfcfcSbellard if (error_code == 0) { 2199e61bde5Sbellard vaddr = address & TARGET_PAGE_MASK; 2209e61bde5Sbellard paddr &= TARGET_PAGE_MASK; 2219e61bde5Sbellard #ifdef DEBUG_MMU 2225dcb6b91Sblueswir1 printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr " 2235dcb6b91Sblueswir1 TARGET_FMT_lx "\n", address, paddr, vaddr); 2249e61bde5Sbellard #endif 225d4c430a8SPaul Brook tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size); 226d4c430a8SPaul Brook return 0; 227e80cfcfcSbellard } 228e8af50a3Sbellard 229e8af50a3Sbellard if (env->mmuregs[3]) /* Fault status register */ 230e8af50a3Sbellard env->mmuregs[3] = 1; /* overflow (not read before another fault) */ 2317483750dSbellard env->mmuregs[3] |= (access_index << 5) | error_code | 2; 232e8af50a3Sbellard env->mmuregs[4] = address; /* Fault address register */ 233e8af50a3Sbellard 234878d3096Sbellard if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) { 2356f7e9aecSbellard // No fault mode: if a mapping is available, just override 2366f7e9aecSbellard // permissions. If no mapping is available, redirect accesses to 2376f7e9aecSbellard // neverland. Fake/overridden mappings will be flushed when 2386f7e9aecSbellard // switching to normal mode. 2397483750dSbellard vaddr = address & TARGET_PAGE_MASK; 240227671c9Sbellard prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 241d4c430a8SPaul Brook tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE); 242d4c430a8SPaul Brook return 0; 2437483750dSbellard } else { 244878d3096Sbellard if (rw & 2) 245878d3096Sbellard env->exception_index = TT_TFAULT; 246878d3096Sbellard else 247878d3096Sbellard env->exception_index = TT_DFAULT; 248878d3096Sbellard return 1; 249e8af50a3Sbellard } 2507483750dSbellard } 25124741ef3Sbellard 25224741ef3Sbellard target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev) 25324741ef3Sbellard { 254c227f099SAnthony Liguori target_phys_addr_t pde_ptr; 25524741ef3Sbellard uint32_t pde; 25624741ef3Sbellard 25724741ef3Sbellard /* Context base + context number */ 258c227f099SAnthony Liguori pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) + 2595dcb6b91Sblueswir1 (env->mmuregs[2] << 2); 26024741ef3Sbellard pde = ldl_phys(pde_ptr); 26124741ef3Sbellard 26224741ef3Sbellard switch (pde & PTE_ENTRYTYPE_MASK) { 26324741ef3Sbellard default: 26424741ef3Sbellard case 0: /* Invalid */ 26524741ef3Sbellard case 2: /* PTE, maybe should not happen? */ 26624741ef3Sbellard case 3: /* Reserved */ 26724741ef3Sbellard return 0; 26824741ef3Sbellard case 1: /* L1 PDE */ 26924741ef3Sbellard if (mmulev == 3) 27024741ef3Sbellard return pde; 27124741ef3Sbellard pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); 27224741ef3Sbellard pde = ldl_phys(pde_ptr); 27324741ef3Sbellard 27424741ef3Sbellard switch (pde & PTE_ENTRYTYPE_MASK) { 27524741ef3Sbellard default: 27624741ef3Sbellard case 0: /* Invalid */ 27724741ef3Sbellard case 3: /* Reserved */ 27824741ef3Sbellard return 0; 27924741ef3Sbellard case 2: /* L1 PTE */ 28024741ef3Sbellard return pde; 28124741ef3Sbellard case 1: /* L2 PDE */ 28224741ef3Sbellard if (mmulev == 2) 28324741ef3Sbellard return pde; 28424741ef3Sbellard pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); 28524741ef3Sbellard pde = ldl_phys(pde_ptr); 28624741ef3Sbellard 28724741ef3Sbellard switch (pde & PTE_ENTRYTYPE_MASK) { 28824741ef3Sbellard default: 28924741ef3Sbellard case 0: /* Invalid */ 29024741ef3Sbellard case 3: /* Reserved */ 29124741ef3Sbellard return 0; 29224741ef3Sbellard case 2: /* L2 PTE */ 29324741ef3Sbellard return pde; 29424741ef3Sbellard case 1: /* L3 PDE */ 29524741ef3Sbellard if (mmulev == 1) 29624741ef3Sbellard return pde; 29724741ef3Sbellard pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); 29824741ef3Sbellard pde = ldl_phys(pde_ptr); 29924741ef3Sbellard 30024741ef3Sbellard switch (pde & PTE_ENTRYTYPE_MASK) { 30124741ef3Sbellard default: 30224741ef3Sbellard case 0: /* Invalid */ 30324741ef3Sbellard case 1: /* PDE, should not happen */ 30424741ef3Sbellard case 3: /* Reserved */ 30524741ef3Sbellard return 0; 30624741ef3Sbellard case 2: /* L3 PTE */ 30724741ef3Sbellard return pde; 30824741ef3Sbellard } 30924741ef3Sbellard } 31024741ef3Sbellard } 31124741ef3Sbellard } 31224741ef3Sbellard return 0; 31324741ef3Sbellard } 31424741ef3Sbellard 315d41160a3SBlue Swirl void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) 31624741ef3Sbellard { 31724741ef3Sbellard target_ulong va, va1, va2; 31824741ef3Sbellard unsigned int n, m, o; 319c227f099SAnthony Liguori target_phys_addr_t pde_ptr, pa; 32024741ef3Sbellard uint32_t pde; 32124741ef3Sbellard 32224741ef3Sbellard pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); 32324741ef3Sbellard pde = ldl_phys(pde_ptr); 324d41160a3SBlue Swirl (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n", 325c227f099SAnthony Liguori (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]); 32624741ef3Sbellard for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { 3275dcb6b91Sblueswir1 pde = mmu_probe(env, va, 2); 3285dcb6b91Sblueswir1 if (pde) { 32924741ef3Sbellard pa = cpu_get_phys_page_debug(env, va); 330d41160a3SBlue Swirl (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx 3315dcb6b91Sblueswir1 " PDE: " TARGET_FMT_lx "\n", va, pa, pde); 33224741ef3Sbellard for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { 3335dcb6b91Sblueswir1 pde = mmu_probe(env, va1, 1); 3345dcb6b91Sblueswir1 if (pde) { 33524741ef3Sbellard pa = cpu_get_phys_page_debug(env, va1); 336d41160a3SBlue Swirl (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " 337d41160a3SBlue Swirl TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n", 338d41160a3SBlue Swirl va1, pa, pde); 33924741ef3Sbellard for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { 3405dcb6b91Sblueswir1 pde = mmu_probe(env, va2, 0); 3415dcb6b91Sblueswir1 if (pde) { 34224741ef3Sbellard pa = cpu_get_phys_page_debug(env, va2); 343d41160a3SBlue Swirl (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " 344d41160a3SBlue Swirl TARGET_FMT_plx " PTE: " 345d41160a3SBlue Swirl TARGET_FMT_lx "\n", 3465dcb6b91Sblueswir1 va2, pa, pde); 34724741ef3Sbellard } 34824741ef3Sbellard } 34924741ef3Sbellard } 35024741ef3Sbellard } 35124741ef3Sbellard } 35224741ef3Sbellard } 35324741ef3Sbellard } 35424741ef3Sbellard 35544520db1SFabien Chouteau /* Gdb expects all registers windows to be flushed in ram. This function handles 35644520db1SFabien Chouteau * reads (and only reads) in stack frames as if windows were flushed. We assume 35744520db1SFabien Chouteau * that the sparc ABI is followed. 35844520db1SFabien Chouteau */ 35944520db1SFabien Chouteau int target_memory_rw_debug(CPUState *env, target_ulong addr, 36044520db1SFabien Chouteau uint8_t *buf, int len, int is_write) 36144520db1SFabien Chouteau { 36244520db1SFabien Chouteau int i; 36344520db1SFabien Chouteau int len1; 36444520db1SFabien Chouteau int cwp = env->cwp; 36544520db1SFabien Chouteau 36644520db1SFabien Chouteau if (!is_write) { 36744520db1SFabien Chouteau for (i = 0; i < env->nwindows; i++) { 36844520db1SFabien Chouteau int off; 36944520db1SFabien Chouteau target_ulong fp = env->regbase[cwp * 16 + 22]; 37044520db1SFabien Chouteau 37144520db1SFabien Chouteau /* Assume fp == 0 means end of frame. */ 37244520db1SFabien Chouteau if (fp == 0) { 37344520db1SFabien Chouteau break; 37444520db1SFabien Chouteau } 37544520db1SFabien Chouteau 37644520db1SFabien Chouteau cwp = cpu_cwp_inc(env, cwp + 1); 37744520db1SFabien Chouteau 37844520db1SFabien Chouteau /* Invalid window ? */ 37944520db1SFabien Chouteau if (env->wim & (1 << cwp)) { 38044520db1SFabien Chouteau break; 38144520db1SFabien Chouteau } 38244520db1SFabien Chouteau 38344520db1SFabien Chouteau /* According to the ABI, the stack is growing downward. */ 38444520db1SFabien Chouteau if (addr + len < fp) { 38544520db1SFabien Chouteau break; 38644520db1SFabien Chouteau } 38744520db1SFabien Chouteau 38844520db1SFabien Chouteau /* Not in this frame. */ 38944520db1SFabien Chouteau if (addr > fp + 64) { 39044520db1SFabien Chouteau continue; 39144520db1SFabien Chouteau } 39244520db1SFabien Chouteau 39344520db1SFabien Chouteau /* Handle access before this window. */ 39444520db1SFabien Chouteau if (addr < fp) { 39544520db1SFabien Chouteau len1 = fp - addr; 39644520db1SFabien Chouteau if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) { 39744520db1SFabien Chouteau return -1; 39844520db1SFabien Chouteau } 39944520db1SFabien Chouteau addr += len1; 40044520db1SFabien Chouteau len -= len1; 40144520db1SFabien Chouteau buf += len1; 40244520db1SFabien Chouteau } 40344520db1SFabien Chouteau 40444520db1SFabien Chouteau /* Access byte per byte to registers. Not very efficient but speed 40544520db1SFabien Chouteau * is not critical. 40644520db1SFabien Chouteau */ 40744520db1SFabien Chouteau off = addr - fp; 40844520db1SFabien Chouteau len1 = 64 - off; 40944520db1SFabien Chouteau 41044520db1SFabien Chouteau if (len1 > len) { 41144520db1SFabien Chouteau len1 = len; 41244520db1SFabien Chouteau } 41344520db1SFabien Chouteau 41444520db1SFabien Chouteau for (; len1; len1--) { 41544520db1SFabien Chouteau int reg = cwp * 16 + 8 + (off >> 2); 41644520db1SFabien Chouteau union { 41744520db1SFabien Chouteau uint32_t v; 41844520db1SFabien Chouteau uint8_t c[4]; 41944520db1SFabien Chouteau } u; 42044520db1SFabien Chouteau u.v = cpu_to_be32(env->regbase[reg]); 42144520db1SFabien Chouteau *buf++ = u.c[off & 3]; 42244520db1SFabien Chouteau addr++; 42344520db1SFabien Chouteau len--; 42444520db1SFabien Chouteau off++; 42544520db1SFabien Chouteau } 42644520db1SFabien Chouteau 42744520db1SFabien Chouteau if (len == 0) { 42844520db1SFabien Chouteau return 0; 42944520db1SFabien Chouteau } 43044520db1SFabien Chouteau } 43144520db1SFabien Chouteau } 43244520db1SFabien Chouteau return cpu_memory_rw_debug(env, addr, buf, len, is_write); 43344520db1SFabien Chouteau } 43444520db1SFabien Chouteau 43524741ef3Sbellard #else /* !TARGET_SPARC64 */ 436e8807b14SIgor Kovalenko 437e8807b14SIgor Kovalenko // 41 bit physical address space 438c227f099SAnthony Liguori static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x) 439e8807b14SIgor Kovalenko { 440e8807b14SIgor Kovalenko return x & 0x1ffffffffffULL; 441e8807b14SIgor Kovalenko } 442e8807b14SIgor Kovalenko 44383469015Sbellard /* 44483469015Sbellard * UltraSparc IIi I/DMMUs 44583469015Sbellard */ 4463475187dSbellard 447536ba015SIgor Kovalenko // Returns true if TTE tag is valid and matches virtual address value in context 448536ba015SIgor Kovalenko // requires virtual address mask value calculated from TTE entry size 4496e8e7d4cSIgor Kovalenko static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, 450536ba015SIgor Kovalenko uint64_t address, uint64_t context, 451299b520cSIgor V. Kovalenko target_phys_addr_t *physical) 452536ba015SIgor Kovalenko { 453536ba015SIgor Kovalenko uint64_t mask; 454536ba015SIgor Kovalenko 45506e12b65STsuneo Saito switch (TTE_PGSIZE(tlb->tte)) { 4563475187dSbellard default: 45783469015Sbellard case 0x0: // 8k 4583475187dSbellard mask = 0xffffffffffffe000ULL; 4593475187dSbellard break; 46083469015Sbellard case 0x1: // 64k 4613475187dSbellard mask = 0xffffffffffff0000ULL; 4623475187dSbellard break; 46383469015Sbellard case 0x2: // 512k 4643475187dSbellard mask = 0xfffffffffff80000ULL; 4653475187dSbellard break; 46683469015Sbellard case 0x3: // 4M 4673475187dSbellard mask = 0xffffffffffc00000ULL; 4683475187dSbellard break; 4693475187dSbellard } 470536ba015SIgor Kovalenko 471536ba015SIgor Kovalenko // valid, context match, virtual address match? 472f707726eSIgor Kovalenko if (TTE_IS_VALID(tlb->tte) && 473299b520cSIgor V. Kovalenko (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context)) 4742a90358fSBlue Swirl && compare_masked(address, tlb->tag, mask)) 475536ba015SIgor Kovalenko { 476536ba015SIgor Kovalenko // decode physical address 4776e8e7d4cSIgor Kovalenko *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL; 478536ba015SIgor Kovalenko return 1; 479536ba015SIgor Kovalenko } 480536ba015SIgor Kovalenko 481536ba015SIgor Kovalenko return 0; 482536ba015SIgor Kovalenko } 483536ba015SIgor Kovalenko 484536ba015SIgor Kovalenko static int get_physical_address_data(CPUState *env, 485c227f099SAnthony Liguori target_phys_addr_t *physical, int *prot, 4862065061eSIgor V. Kovalenko target_ulong address, int rw, int mmu_idx) 487536ba015SIgor Kovalenko { 488536ba015SIgor Kovalenko unsigned int i; 489536ba015SIgor Kovalenko uint64_t context; 490ccc76c24STsuneo Saito uint64_t sfsr = 0; 491536ba015SIgor Kovalenko 4922065061eSIgor V. Kovalenko int is_user = (mmu_idx == MMU_USER_IDX || 4932065061eSIgor V. Kovalenko mmu_idx == MMU_USER_SECONDARY_IDX); 4942065061eSIgor V. Kovalenko 495536ba015SIgor Kovalenko if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */ 496536ba015SIgor Kovalenko *physical = ultrasparc_truncate_physical(address); 497536ba015SIgor Kovalenko *prot = PAGE_READ | PAGE_WRITE; 498536ba015SIgor Kovalenko return 0; 499536ba015SIgor Kovalenko } 500536ba015SIgor Kovalenko 5012065061eSIgor V. Kovalenko switch(mmu_idx) { 5022065061eSIgor V. Kovalenko case MMU_USER_IDX: 5032065061eSIgor V. Kovalenko case MMU_KERNEL_IDX: 5046e8e7d4cSIgor Kovalenko context = env->dmmu.mmu_primary_context & 0x1fff; 505ccc76c24STsuneo Saito sfsr |= SFSR_CT_PRIMARY; 5062065061eSIgor V. Kovalenko break; 5072065061eSIgor V. Kovalenko case MMU_USER_SECONDARY_IDX: 5082065061eSIgor V. Kovalenko case MMU_KERNEL_SECONDARY_IDX: 5092065061eSIgor V. Kovalenko context = env->dmmu.mmu_secondary_context & 0x1fff; 510ccc76c24STsuneo Saito sfsr |= SFSR_CT_SECONDARY; 5112065061eSIgor V. Kovalenko break; 5122065061eSIgor V. Kovalenko case MMU_NUCLEUS_IDX: 513ccc76c24STsuneo Saito sfsr |= SFSR_CT_NUCLEUS; 514ccc76c24STsuneo Saito /* FALLTHRU */ 51544505216SBlue Swirl default: 516299b520cSIgor V. Kovalenko context = 0; 5172065061eSIgor V. Kovalenko break; 518299b520cSIgor V. Kovalenko } 519536ba015SIgor Kovalenko 520ccc76c24STsuneo Saito if (rw == 1) { 521ccc76c24STsuneo Saito sfsr |= SFSR_WRITE_BIT; 522d1afc48bSTsuneo Saito } else if (rw == 4) { 523d1afc48bSTsuneo Saito sfsr |= SFSR_NF_BIT; 524ccc76c24STsuneo Saito } 525ccc76c24STsuneo Saito 526536ba015SIgor Kovalenko for (i = 0; i < 64; i++) { 527afdf8109Sblueswir1 // ctx match, vaddr match, valid? 528b8e9fc06SIgor V. Kovalenko if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) { 529d1afc48bSTsuneo Saito int do_fault = 0; 530b8e9fc06SIgor V. Kovalenko 531b8e9fc06SIgor V. Kovalenko // access ok? 532d1afc48bSTsuneo Saito /* multiple bits in SFSR.FT may be set on TT_DFAULT */ 53306e12b65STsuneo Saito if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) { 534d1afc48bSTsuneo Saito do_fault = 1; 535ccc76c24STsuneo Saito sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */ 536b8e9fc06SIgor V. Kovalenko 537b8e9fc06SIgor V. Kovalenko DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64 538b8e9fc06SIgor V. Kovalenko " mmu_idx=%d tl=%d\n", 539b8e9fc06SIgor V. Kovalenko address, context, mmu_idx, env->tl); 540d1afc48bSTsuneo Saito } 541d1afc48bSTsuneo Saito if (rw == 4) { 542d1afc48bSTsuneo Saito if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) { 543d1afc48bSTsuneo Saito do_fault = 1; 544d1afc48bSTsuneo Saito sfsr |= SFSR_FT_NF_E_BIT; 545d1afc48bSTsuneo Saito } 546d1afc48bSTsuneo Saito } else { 547d1afc48bSTsuneo Saito if (TTE_IS_NFO(env->dtlb[i].tte)) { 548d1afc48bSTsuneo Saito do_fault = 1; 549d1afc48bSTsuneo Saito sfsr |= SFSR_FT_NFO_BIT; 550d1afc48bSTsuneo Saito } 551d1afc48bSTsuneo Saito } 552d1afc48bSTsuneo Saito 553d1afc48bSTsuneo Saito if (do_fault) { 554d1afc48bSTsuneo Saito /* faults above are reported with TT_DFAULT. */ 555d1afc48bSTsuneo Saito env->exception_index = TT_DFAULT; 55606e12b65STsuneo Saito } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) { 557d1afc48bSTsuneo Saito do_fault = 1; 558b8e9fc06SIgor V. Kovalenko env->exception_index = TT_DPROT; 559b8e9fc06SIgor V. Kovalenko 560b8e9fc06SIgor V. Kovalenko DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64 561b8e9fc06SIgor V. Kovalenko " mmu_idx=%d tl=%d\n", 562b8e9fc06SIgor V. Kovalenko address, context, mmu_idx, env->tl); 563d1afc48bSTsuneo Saito } 564d1afc48bSTsuneo Saito 565d1afc48bSTsuneo Saito if (!do_fault) { 566b8e9fc06SIgor V. Kovalenko *prot = PAGE_READ; 56706e12b65STsuneo Saito if (TTE_IS_W_OK(env->dtlb[i].tte)) { 568b8e9fc06SIgor V. Kovalenko *prot |= PAGE_WRITE; 56906e12b65STsuneo Saito } 570b8e9fc06SIgor V. Kovalenko 571b8e9fc06SIgor V. Kovalenko TTE_SET_USED(env->dtlb[i].tte); 572b8e9fc06SIgor V. Kovalenko 573b8e9fc06SIgor V. Kovalenko return 0; 5746e8e7d4cSIgor Kovalenko } 5756e8e7d4cSIgor Kovalenko 576ccc76c24STsuneo Saito if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */ 577ccc76c24STsuneo Saito sfsr |= SFSR_OW_BIT; /* overflow (not read before 57877f193daSblueswir1 another fault) */ 579ccc76c24STsuneo Saito } 5806e8e7d4cSIgor Kovalenko 581ccc76c24STsuneo Saito if (env->pstate & PS_PRIV) { 582ccc76c24STsuneo Saito sfsr |= SFSR_PR_BIT; 583ccc76c24STsuneo Saito } 5846e8e7d4cSIgor Kovalenko 585ccc76c24STsuneo Saito /* FIXME: ASI field in SFSR must be set */ 586ccc76c24STsuneo Saito env->dmmu.sfsr = sfsr | SFSR_VALID_BIT; 5876e8e7d4cSIgor Kovalenko 5886e8e7d4cSIgor Kovalenko env->dmmu.sfar = address; /* Fault address register */ 5899168b3a5SIgor V. Kovalenko 5909168b3a5SIgor V. Kovalenko env->dmmu.tag_access = (address & ~0x1fffULL) | context; 5919168b3a5SIgor V. Kovalenko 5923475187dSbellard return 1; 5933475187dSbellard } 5943475187dSbellard } 595b8e9fc06SIgor V. Kovalenko 596b8e9fc06SIgor V. Kovalenko DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n", 597b8e9fc06SIgor V. Kovalenko address, context); 598b8e9fc06SIgor V. Kovalenko 599ccc76c24STsuneo Saito /* 600ccc76c24STsuneo Saito * On MMU misses: 601ccc76c24STsuneo Saito * - UltraSPARC IIi: SFSR and SFAR unmodified 602ccc76c24STsuneo Saito * - JPS1: SFAR updated and some fields of SFSR updated 603ccc76c24STsuneo Saito */ 6046e8e7d4cSIgor Kovalenko env->dmmu.tag_access = (address & ~0x1fffULL) | context; 60583469015Sbellard env->exception_index = TT_DMISS; 6063475187dSbellard return 1; 6073475187dSbellard } 6083475187dSbellard 60977f193daSblueswir1 static int get_physical_address_code(CPUState *env, 610c227f099SAnthony Liguori target_phys_addr_t *physical, int *prot, 6112065061eSIgor V. Kovalenko target_ulong address, int mmu_idx) 6123475187dSbellard { 6133475187dSbellard unsigned int i; 614536ba015SIgor Kovalenko uint64_t context; 6153475187dSbellard 6162065061eSIgor V. Kovalenko int is_user = (mmu_idx == MMU_USER_IDX || 6172065061eSIgor V. Kovalenko mmu_idx == MMU_USER_SECONDARY_IDX); 6182065061eSIgor V. Kovalenko 619e8807b14SIgor Kovalenko if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) { 620e8807b14SIgor Kovalenko /* IMMU disabled */ 621e8807b14SIgor Kovalenko *physical = ultrasparc_truncate_physical(address); 622227671c9Sbellard *prot = PAGE_EXEC; 6233475187dSbellard return 0; 6243475187dSbellard } 62583469015Sbellard 626299b520cSIgor V. Kovalenko if (env->tl == 0) { 6272065061eSIgor V. Kovalenko /* PRIMARY context */ 6286e8e7d4cSIgor Kovalenko context = env->dmmu.mmu_primary_context & 0x1fff; 629299b520cSIgor V. Kovalenko } else { 6302065061eSIgor V. Kovalenko /* NUCLEUS context */ 631299b520cSIgor V. Kovalenko context = 0; 632299b520cSIgor V. Kovalenko } 633536ba015SIgor Kovalenko 6343475187dSbellard for (i = 0; i < 64; i++) { 635afdf8109Sblueswir1 // ctx match, vaddr match, valid? 6366e8e7d4cSIgor Kovalenko if (ultrasparc_tag_match(&env->itlb[i], 637299b520cSIgor V. Kovalenko address, context, physical)) { 638afdf8109Sblueswir1 // access ok? 63906e12b65STsuneo Saito if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) { 640ccc76c24STsuneo Saito /* Fault status register */ 641ccc76c24STsuneo Saito if (env->immu.sfsr & SFSR_VALID_BIT) { 642ccc76c24STsuneo Saito env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before 64377f193daSblueswir1 another fault) */ 644ccc76c24STsuneo Saito } else { 645ccc76c24STsuneo Saito env->immu.sfsr = 0; 646ccc76c24STsuneo Saito } 647ccc76c24STsuneo Saito if (env->pstate & PS_PRIV) { 648ccc76c24STsuneo Saito env->immu.sfsr |= SFSR_PR_BIT; 649ccc76c24STsuneo Saito } 650ccc76c24STsuneo Saito if (env->tl > 0) { 651ccc76c24STsuneo Saito env->immu.sfsr |= SFSR_CT_NUCLEUS; 652ccc76c24STsuneo Saito } 653ccc76c24STsuneo Saito 654ccc76c24STsuneo Saito /* FIXME: ASI field in SFSR must be set */ 655ccc76c24STsuneo Saito env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT; 6563475187dSbellard env->exception_index = TT_TFAULT; 657b8e9fc06SIgor V. Kovalenko 6589168b3a5SIgor V. Kovalenko env->immu.tag_access = (address & ~0x1fffULL) | context; 6599168b3a5SIgor V. Kovalenko 660b8e9fc06SIgor V. Kovalenko DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n", 661b8e9fc06SIgor V. Kovalenko address, context); 662b8e9fc06SIgor V. Kovalenko 6633475187dSbellard return 1; 6643475187dSbellard } 665227671c9Sbellard *prot = PAGE_EXEC; 666f707726eSIgor Kovalenko TTE_SET_USED(env->itlb[i].tte); 6673475187dSbellard return 0; 6683475187dSbellard } 6693475187dSbellard } 670b8e9fc06SIgor V. Kovalenko 671b8e9fc06SIgor V. Kovalenko DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n", 672b8e9fc06SIgor V. Kovalenko address, context); 673b8e9fc06SIgor V. Kovalenko 6747ab463cbSBlue Swirl /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */ 6756e8e7d4cSIgor Kovalenko env->immu.tag_access = (address & ~0x1fffULL) | context; 67683469015Sbellard env->exception_index = TT_TMISS; 6773475187dSbellard return 1; 6783475187dSbellard } 6793475187dSbellard 680c227f099SAnthony Liguori static int get_physical_address(CPUState *env, target_phys_addr_t *physical, 681c48fcb47Sblueswir1 int *prot, int *access_index, 682d4c430a8SPaul Brook target_ulong address, int rw, int mmu_idx, 683d4c430a8SPaul Brook target_ulong *page_size) 6843475187dSbellard { 685d4c430a8SPaul Brook /* ??? We treat everything as a small page, then explicitly flush 686d4c430a8SPaul Brook everything when an entry is evicted. */ 687d4c430a8SPaul Brook *page_size = TARGET_PAGE_SIZE; 6889fd1ae3aSIgor V. Kovalenko 6899fd1ae3aSIgor V. Kovalenko #if defined (DEBUG_MMU) 6909fd1ae3aSIgor V. Kovalenko /* safety net to catch wrong softmmu index use from dynamic code */ 6919fd1ae3aSIgor V. Kovalenko if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) { 6929fd1ae3aSIgor V. Kovalenko DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d" 6939fd1ae3aSIgor V. Kovalenko " primary context=%" PRIx64 6949fd1ae3aSIgor V. Kovalenko " secondary context=%" PRIx64 6959fd1ae3aSIgor V. Kovalenko " address=%" PRIx64 6969fd1ae3aSIgor V. Kovalenko "\n", 6979fd1ae3aSIgor V. Kovalenko (rw == 2 ? "CODE" : "DATA"), 6989fd1ae3aSIgor V. Kovalenko env->tl, mmu_idx, 6999fd1ae3aSIgor V. Kovalenko env->dmmu.mmu_primary_context, 7009fd1ae3aSIgor V. Kovalenko env->dmmu.mmu_secondary_context, 7019fd1ae3aSIgor V. Kovalenko address); 7029fd1ae3aSIgor V. Kovalenko } 7039fd1ae3aSIgor V. Kovalenko #endif 7049fd1ae3aSIgor V. Kovalenko 7053475187dSbellard if (rw == 2) 70622548760Sblueswir1 return get_physical_address_code(env, physical, prot, address, 7072065061eSIgor V. Kovalenko mmu_idx); 7083475187dSbellard else 70922548760Sblueswir1 return get_physical_address_data(env, physical, prot, address, rw, 7102065061eSIgor V. Kovalenko mmu_idx); 7113475187dSbellard } 7123475187dSbellard 7133475187dSbellard /* Perform address translation */ 7143475187dSbellard int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, 71597b348e7SBlue Swirl int mmu_idx) 7163475187dSbellard { 71783469015Sbellard target_ulong virt_addr, vaddr; 718c227f099SAnthony Liguori target_phys_addr_t paddr; 719d4c430a8SPaul Brook target_ulong page_size; 720d4c430a8SPaul Brook int error_code = 0, prot, access_index; 7213475187dSbellard 72277f193daSblueswir1 error_code = get_physical_address(env, &paddr, &prot, &access_index, 723d4c430a8SPaul Brook address, rw, mmu_idx, &page_size); 7243475187dSbellard if (error_code == 0) { 7253475187dSbellard virt_addr = address & TARGET_PAGE_MASK; 72677f193daSblueswir1 vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & 72777f193daSblueswir1 (TARGET_PAGE_SIZE - 1)); 728b8e9fc06SIgor V. Kovalenko 729b8e9fc06SIgor V. Kovalenko DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 "," 730b8e9fc06SIgor V. Kovalenko " vaddr %" PRIx64 731b8e9fc06SIgor V. Kovalenko " mmu_idx=%d" 732b8e9fc06SIgor V. Kovalenko " tl=%d" 733b8e9fc06SIgor V. Kovalenko " primary context=%" PRIx64 734b8e9fc06SIgor V. Kovalenko " secondary context=%" PRIx64 735b8e9fc06SIgor V. Kovalenko "\n", 736b8e9fc06SIgor V. Kovalenko address, paddr, vaddr, mmu_idx, env->tl, 737b8e9fc06SIgor V. Kovalenko env->dmmu.mmu_primary_context, 738b8e9fc06SIgor V. Kovalenko env->dmmu.mmu_secondary_context); 739b8e9fc06SIgor V. Kovalenko 740d4c430a8SPaul Brook tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size); 741d4c430a8SPaul Brook return 0; 7423475187dSbellard } 7433475187dSbellard // XXX 7443475187dSbellard return 1; 7453475187dSbellard } 7463475187dSbellard 747d41160a3SBlue Swirl void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) 74883469015Sbellard { 74983469015Sbellard unsigned int i; 75083469015Sbellard const char *mask; 75183469015Sbellard 752d41160a3SBlue Swirl (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %" 753d41160a3SBlue Swirl PRId64 "\n", 754d41160a3SBlue Swirl env->dmmu.mmu_primary_context, 755d41160a3SBlue Swirl env->dmmu.mmu_secondary_context); 75683469015Sbellard if ((env->lsu & DMMU_E) == 0) { 757d41160a3SBlue Swirl (*cpu_fprintf)(f, "DMMU disabled\n"); 75883469015Sbellard } else { 759d41160a3SBlue Swirl (*cpu_fprintf)(f, "DMMU dump\n"); 76083469015Sbellard for (i = 0; i < 64; i++) { 76106e12b65STsuneo Saito switch (TTE_PGSIZE(env->dtlb[i].tte)) { 76283469015Sbellard default: 76383469015Sbellard case 0x0: 76483469015Sbellard mask = " 8k"; 76583469015Sbellard break; 76683469015Sbellard case 0x1: 76783469015Sbellard mask = " 64k"; 76883469015Sbellard break; 76983469015Sbellard case 0x2: 77083469015Sbellard mask = "512k"; 77183469015Sbellard break; 77283469015Sbellard case 0x3: 77383469015Sbellard mask = " 4M"; 77483469015Sbellard break; 77583469015Sbellard } 77606e12b65STsuneo Saito if (TTE_IS_VALID(env->dtlb[i].tte)) { 7773b8b030aSStefan Weil (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx" 7782a90358fSBlue Swirl ", %s, %s, %s, %s, ctx %" PRId64 " %s\n", 7796e8e7d4cSIgor Kovalenko i, 78031a68d57SBlue Swirl env->dtlb[i].tag & (uint64_t)~0x1fffULL, 78106e12b65STsuneo Saito TTE_PA(env->dtlb[i].tte), 78283469015Sbellard mask, 78306e12b65STsuneo Saito TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user", 78406e12b65STsuneo Saito TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO", 78506e12b65STsuneo Saito TTE_IS_LOCKED(env->dtlb[i].tte) ? 78606e12b65STsuneo Saito "locked" : "unlocked", 7872a90358fSBlue Swirl env->dtlb[i].tag & (uint64_t)0x1fffULL, 788d41160a3SBlue Swirl TTE_IS_GLOBAL(env->dtlb[i].tte)? 789d41160a3SBlue Swirl "global" : "local"); 79083469015Sbellard } 79183469015Sbellard } 79283469015Sbellard } 79383469015Sbellard if ((env->lsu & IMMU_E) == 0) { 794d41160a3SBlue Swirl (*cpu_fprintf)(f, "IMMU disabled\n"); 79583469015Sbellard } else { 796d41160a3SBlue Swirl (*cpu_fprintf)(f, "IMMU dump\n"); 79783469015Sbellard for (i = 0; i < 64; i++) { 79806e12b65STsuneo Saito switch (TTE_PGSIZE(env->itlb[i].tte)) { 79983469015Sbellard default: 80083469015Sbellard case 0x0: 80183469015Sbellard mask = " 8k"; 80283469015Sbellard break; 80383469015Sbellard case 0x1: 80483469015Sbellard mask = " 64k"; 80583469015Sbellard break; 80683469015Sbellard case 0x2: 80783469015Sbellard mask = "512k"; 80883469015Sbellard break; 80983469015Sbellard case 0x3: 81083469015Sbellard mask = " 4M"; 81183469015Sbellard break; 81283469015Sbellard } 81306e12b65STsuneo Saito if (TTE_IS_VALID(env->itlb[i].tte)) { 8143b8b030aSStefan Weil (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx" 8152a90358fSBlue Swirl ", %s, %s, %s, ctx %" PRId64 " %s\n", 8166e8e7d4cSIgor Kovalenko i, 8176e8e7d4cSIgor Kovalenko env->itlb[i].tag & (uint64_t)~0x1fffULL, 81806e12b65STsuneo Saito TTE_PA(env->itlb[i].tte), 81983469015Sbellard mask, 82006e12b65STsuneo Saito TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user", 82106e12b65STsuneo Saito TTE_IS_LOCKED(env->itlb[i].tte) ? 82206e12b65STsuneo Saito "locked" : "unlocked", 8232a90358fSBlue Swirl env->itlb[i].tag & (uint64_t)0x1fffULL, 824d41160a3SBlue Swirl TTE_IS_GLOBAL(env->itlb[i].tte)? 825d41160a3SBlue Swirl "global" : "local"); 82683469015Sbellard } 82783469015Sbellard } 82883469015Sbellard } 82983469015Sbellard } 83024741ef3Sbellard 83124741ef3Sbellard #endif /* TARGET_SPARC64 */ 83224741ef3Sbellard 833321365abSTsuneo Saito static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys, 834321365abSTsuneo Saito target_ulong addr, int rw, int mmu_idx) 835321365abSTsuneo Saito { 836321365abSTsuneo Saito target_ulong page_size; 837321365abSTsuneo Saito int prot, access_index; 838321365abSTsuneo Saito 839321365abSTsuneo Saito return get_physical_address(env, phys, &prot, &access_index, addr, rw, 840321365abSTsuneo Saito mmu_idx, &page_size); 841321365abSTsuneo Saito } 842321365abSTsuneo Saito 843b64b6436STsuneo Saito #if defined(TARGET_SPARC64) 8442065061eSIgor V. Kovalenko target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr, 8452065061eSIgor V. Kovalenko int mmu_idx) 846c48fcb47Sblueswir1 { 847c227f099SAnthony Liguori target_phys_addr_t phys_addr; 848c48fcb47Sblueswir1 849d1afc48bSTsuneo Saito if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) { 850c48fcb47Sblueswir1 return -1; 851321365abSTsuneo Saito } 852c48fcb47Sblueswir1 return phys_addr; 853c48fcb47Sblueswir1 } 854b64b6436STsuneo Saito #endif 8552065061eSIgor V. Kovalenko 8562065061eSIgor V. Kovalenko target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) 8572065061eSIgor V. Kovalenko { 858b64b6436STsuneo Saito target_phys_addr_t phys_addr; 859b64b6436STsuneo Saito int mmu_idx = cpu_mmu_index(env); 860b64b6436STsuneo Saito 861b64b6436STsuneo Saito if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) { 862b64b6436STsuneo Saito if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) { 863b64b6436STsuneo Saito return -1; 864b64b6436STsuneo Saito } 865b64b6436STsuneo Saito } 866b64b6436STsuneo Saito if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) { 867b64b6436STsuneo Saito return -1; 868b64b6436STsuneo Saito } 869b64b6436STsuneo Saito return phys_addr; 8702065061eSIgor V. Kovalenko } 871c48fcb47Sblueswir1 #endif 8722336c1f1SBlue Swirl 8732336c1f1SBlue Swirl /* misc op helpers */ 8742336c1f1SBlue Swirl void helper_shutdown(void) 8752336c1f1SBlue Swirl { 8762336c1f1SBlue Swirl #if !defined(CONFIG_USER_ONLY) 8772336c1f1SBlue Swirl qemu_system_shutdown_request(); 8782336c1f1SBlue Swirl #endif 8792336c1f1SBlue Swirl } 8802336c1f1SBlue Swirl 8812336c1f1SBlue Swirl #ifdef TARGET_SPARC64 8822336c1f1SBlue Swirl target_ulong helper_popc(target_ulong val) 8832336c1f1SBlue Swirl { 8842336c1f1SBlue Swirl return ctpop64(val); 8852336c1f1SBlue Swirl } 8862336c1f1SBlue Swirl 8872336c1f1SBlue Swirl void helper_tick_set_count(void *opaque, uint64_t count) 8882336c1f1SBlue Swirl { 8892336c1f1SBlue Swirl #if !defined(CONFIG_USER_ONLY) 8902336c1f1SBlue Swirl cpu_tick_set_count(opaque, count); 8912336c1f1SBlue Swirl #endif 8922336c1f1SBlue Swirl } 8932336c1f1SBlue Swirl 8942336c1f1SBlue Swirl uint64_t helper_tick_get_count(void *opaque) 8952336c1f1SBlue Swirl { 8962336c1f1SBlue Swirl #if !defined(CONFIG_USER_ONLY) 8972336c1f1SBlue Swirl return cpu_tick_get_count(opaque); 8982336c1f1SBlue Swirl #else 8992336c1f1SBlue Swirl return 0; 9002336c1f1SBlue Swirl #endif 9012336c1f1SBlue Swirl } 9022336c1f1SBlue Swirl 9032336c1f1SBlue Swirl void helper_tick_set_limit(void *opaque, uint64_t limit) 9042336c1f1SBlue Swirl { 9052336c1f1SBlue Swirl #if !defined(CONFIG_USER_ONLY) 9062336c1f1SBlue Swirl cpu_tick_set_limit(opaque, limit); 9072336c1f1SBlue Swirl #endif 9082336c1f1SBlue Swirl } 9092336c1f1SBlue Swirl #endif 910