xref: /qemu/target/sparc/helper.c (revision 2336c1f1970a5c5cfd34a1785af646c960b6f43f)
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