Statistics
| Branch: | Revision:

root / target-sparc / helper.c @ 5fafdf24

History | View | Annotate | Download (16.3 kB)

1 e8af50a3 bellard
/*
2 e8af50a3 bellard
 *  sparc helpers
3 5fafdf24 ths
 *
4 83469015 bellard
 *  Copyright (c) 2003-2005 Fabrice Bellard
5 e8af50a3 bellard
 *
6 e8af50a3 bellard
 * This library is free software; you can redistribute it and/or
7 e8af50a3 bellard
 * modify it under the terms of the GNU Lesser General Public
8 e8af50a3 bellard
 * License as published by the Free Software Foundation; either
9 e8af50a3 bellard
 * version 2 of the License, or (at your option) any later version.
10 e8af50a3 bellard
 *
11 e8af50a3 bellard
 * This library is distributed in the hope that it will be useful,
12 e8af50a3 bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 e8af50a3 bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 e8af50a3 bellard
 * Lesser General Public License for more details.
15 e8af50a3 bellard
 *
16 e8af50a3 bellard
 * You should have received a copy of the GNU Lesser General Public
17 e8af50a3 bellard
 * License along with this library; if not, write to the Free Software
18 e8af50a3 bellard
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 e8af50a3 bellard
 */
20 ee5bbe38 bellard
#include <stdarg.h>
21 ee5bbe38 bellard
#include <stdlib.h>
22 ee5bbe38 bellard
#include <stdio.h>
23 ee5bbe38 bellard
#include <string.h>
24 ee5bbe38 bellard
#include <inttypes.h>
25 ee5bbe38 bellard
#include <signal.h>
26 ee5bbe38 bellard
#include <assert.h>
27 ee5bbe38 bellard
28 ee5bbe38 bellard
#include "cpu.h"
29 ee5bbe38 bellard
#include "exec-all.h"
30 e8af50a3 bellard
31 e80cfcfc bellard
//#define DEBUG_MMU
32 e8af50a3 bellard
33 e8af50a3 bellard
/* Sparc MMU emulation */
34 e8af50a3 bellard
35 e8af50a3 bellard
/* thread support */
36 e8af50a3 bellard
37 e8af50a3 bellard
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
38 e8af50a3 bellard
39 e8af50a3 bellard
void cpu_lock(void)
40 e8af50a3 bellard
{
41 e8af50a3 bellard
    spin_lock(&global_cpu_lock);
42 e8af50a3 bellard
}
43 e8af50a3 bellard
44 e8af50a3 bellard
void cpu_unlock(void)
45 e8af50a3 bellard
{
46 e8af50a3 bellard
    spin_unlock(&global_cpu_lock);
47 e8af50a3 bellard
}
48 e8af50a3 bellard
49 5fafdf24 ths
#if defined(CONFIG_USER_ONLY)
50 9d893301 bellard
51 9d893301 bellard
int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
52 9d893301 bellard
                               int is_user, int is_softmmu)
53 9d893301 bellard
{
54 878d3096 bellard
    if (rw & 2)
55 878d3096 bellard
        env->exception_index = TT_TFAULT;
56 878d3096 bellard
    else
57 878d3096 bellard
        env->exception_index = TT_DFAULT;
58 9d893301 bellard
    return 1;
59 9d893301 bellard
}
60 9d893301 bellard
61 9d893301 bellard
#else
62 e8af50a3 bellard
63 3475187d bellard
#ifndef TARGET_SPARC64
64 83469015 bellard
/*
65 83469015 bellard
 * Sparc V8 Reference MMU (SRMMU)
66 83469015 bellard
 */
67 e8af50a3 bellard
static const int access_table[8][8] = {
68 e8af50a3 bellard
    { 0, 0, 0, 0, 2, 0, 3, 3 },
69 e8af50a3 bellard
    { 0, 0, 0, 0, 2, 0, 0, 0 },
70 e8af50a3 bellard
    { 2, 2, 0, 0, 0, 2, 3, 3 },
71 e8af50a3 bellard
    { 2, 2, 0, 0, 0, 2, 0, 0 },
72 e8af50a3 bellard
    { 2, 0, 2, 0, 2, 2, 3, 3 },
73 e8af50a3 bellard
    { 2, 0, 2, 0, 2, 0, 2, 0 },
74 e8af50a3 bellard
    { 2, 2, 2, 0, 2, 2, 3, 3 },
75 e8af50a3 bellard
    { 2, 2, 2, 0, 2, 2, 2, 0 }
76 e8af50a3 bellard
};
77 e8af50a3 bellard
78 227671c9 bellard
static const int perm_table[2][8] = {
79 227671c9 bellard
    {
80 227671c9 bellard
        PAGE_READ,
81 227671c9 bellard
        PAGE_READ | PAGE_WRITE,
82 227671c9 bellard
        PAGE_READ | PAGE_EXEC,
83 227671c9 bellard
        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
84 227671c9 bellard
        PAGE_EXEC,
85 227671c9 bellard
        PAGE_READ | PAGE_WRITE,
86 227671c9 bellard
        PAGE_READ | PAGE_EXEC,
87 227671c9 bellard
        PAGE_READ | PAGE_WRITE | PAGE_EXEC
88 227671c9 bellard
    },
89 227671c9 bellard
    {
90 227671c9 bellard
        PAGE_READ,
91 227671c9 bellard
        PAGE_READ | PAGE_WRITE,
92 227671c9 bellard
        PAGE_READ | PAGE_EXEC,
93 227671c9 bellard
        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
94 227671c9 bellard
        PAGE_EXEC,
95 227671c9 bellard
        PAGE_READ,
96 227671c9 bellard
        0,
97 227671c9 bellard
        0,
98 227671c9 bellard
    }
99 e8af50a3 bellard
};
100 e8af50a3 bellard
101 af7bf89b bellard
int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot,
102 af7bf89b bellard
                          int *access_index, target_ulong address, int rw,
103 e80cfcfc bellard
                          int is_user)
104 e8af50a3 bellard
{
105 e80cfcfc bellard
    int access_perms = 0;
106 e80cfcfc bellard
    target_phys_addr_t pde_ptr;
107 af7bf89b bellard
    uint32_t pde;
108 af7bf89b bellard
    target_ulong virt_addr;
109 e80cfcfc bellard
    int error_code = 0, is_dirty;
110 e80cfcfc bellard
    unsigned long page_offset;
111 e8af50a3 bellard
112 e8af50a3 bellard
    virt_addr = address & TARGET_PAGE_MASK;
113 e8af50a3 bellard
    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
114 e80cfcfc bellard
        *physical = address;
115 227671c9 bellard
        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
116 e80cfcfc bellard
        return 0;
117 e8af50a3 bellard
    }
118 e8af50a3 bellard
119 7483750d bellard
    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
120 5dcb6b91 blueswir1
    *physical = 0xffffffffffff0000ULL;
121 7483750d bellard
122 e8af50a3 bellard
    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
123 e8af50a3 bellard
    /* Context base + context number */
124 b3180cdc bellard
    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
125 49be8030 bellard
    pde = ldl_phys(pde_ptr);
126 e8af50a3 bellard
127 e8af50a3 bellard
    /* Ctx pde */
128 e8af50a3 bellard
    switch (pde & PTE_ENTRYTYPE_MASK) {
129 e80cfcfc bellard
    default:
130 e8af50a3 bellard
    case 0: /* Invalid */
131 7483750d bellard
        return 1 << 2;
132 e80cfcfc bellard
    case 2: /* L0 PTE, maybe should not happen? */
133 e8af50a3 bellard
    case 3: /* Reserved */
134 7483750d bellard
        return 4 << 2;
135 e80cfcfc bellard
    case 1: /* L0 PDE */
136 e80cfcfc bellard
        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
137 49be8030 bellard
        pde = ldl_phys(pde_ptr);
138 e8af50a3 bellard
139 e8af50a3 bellard
        switch (pde & PTE_ENTRYTYPE_MASK) {
140 e80cfcfc bellard
        default:
141 e8af50a3 bellard
        case 0: /* Invalid */
142 7483750d bellard
            return (1 << 8) | (1 << 2);
143 e8af50a3 bellard
        case 3: /* Reserved */
144 7483750d bellard
            return (1 << 8) | (4 << 2);
145 e80cfcfc bellard
        case 1: /* L1 PDE */
146 e80cfcfc bellard
            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
147 49be8030 bellard
            pde = ldl_phys(pde_ptr);
148 e8af50a3 bellard
149 e8af50a3 bellard
            switch (pde & PTE_ENTRYTYPE_MASK) {
150 e80cfcfc bellard
            default:
151 e8af50a3 bellard
            case 0: /* Invalid */
152 7483750d bellard
                return (2 << 8) | (1 << 2);
153 e8af50a3 bellard
            case 3: /* Reserved */
154 7483750d bellard
                return (2 << 8) | (4 << 2);
155 e80cfcfc bellard
            case 1: /* L2 PDE */
156 e80cfcfc bellard
                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
157 49be8030 bellard
                pde = ldl_phys(pde_ptr);
158 e8af50a3 bellard
159 e8af50a3 bellard
                switch (pde & PTE_ENTRYTYPE_MASK) {
160 e80cfcfc bellard
                default:
161 e8af50a3 bellard
                case 0: /* Invalid */
162 7483750d bellard
                    return (3 << 8) | (1 << 2);
163 e8af50a3 bellard
                case 1: /* PDE, should not happen */
164 e8af50a3 bellard
                case 3: /* Reserved */
165 7483750d bellard
                    return (3 << 8) | (4 << 2);
166 e8af50a3 bellard
                case 2: /* L3 PTE */
167 e8af50a3 bellard
                    virt_addr = address & TARGET_PAGE_MASK;
168 e8af50a3 bellard
                    page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
169 e8af50a3 bellard
                }
170 e8af50a3 bellard
                break;
171 e8af50a3 bellard
            case 2: /* L2 PTE */
172 e8af50a3 bellard
                virt_addr = address & ~0x3ffff;
173 e8af50a3 bellard
                page_offset = address & 0x3ffff;
174 e8af50a3 bellard
            }
175 e8af50a3 bellard
            break;
176 e8af50a3 bellard
        case 2: /* L1 PTE */
177 e8af50a3 bellard
            virt_addr = address & ~0xffffff;
178 e8af50a3 bellard
            page_offset = address & 0xffffff;
179 e8af50a3 bellard
        }
180 e8af50a3 bellard
    }
181 e8af50a3 bellard
182 e8af50a3 bellard
    /* update page modified and dirty bits */
183 b769d8fe bellard
    is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
184 e8af50a3 bellard
    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
185 e8af50a3 bellard
        pde |= PG_ACCESSED_MASK;
186 e8af50a3 bellard
        if (is_dirty)
187 e8af50a3 bellard
            pde |= PG_MODIFIED_MASK;
188 49be8030 bellard
        stl_phys_notdirty(pde_ptr, pde);
189 e8af50a3 bellard
    }
190 e8af50a3 bellard
    /* check access */
191 e8af50a3 bellard
    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
192 e80cfcfc bellard
    error_code = access_table[*access_index][access_perms];
193 d8e3326c bellard
    if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
194 e80cfcfc bellard
        return error_code;
195 e8af50a3 bellard
196 e8af50a3 bellard
    /* the page can be put in the TLB */
197 227671c9 bellard
    *prot = perm_table[is_user][access_perms];
198 227671c9 bellard
    if (!(pde & PG_MODIFIED_MASK)) {
199 e8af50a3 bellard
        /* only set write access if already dirty... otherwise wait
200 e8af50a3 bellard
           for dirty access */
201 227671c9 bellard
        *prot &= ~PAGE_WRITE;
202 e8af50a3 bellard
    }
203 e8af50a3 bellard
204 e8af50a3 bellard
    /* Even if large ptes, we map only one 4KB page in the cache to
205 e8af50a3 bellard
       avoid filling it too fast */
206 5dcb6b91 blueswir1
    *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
207 6f7e9aec bellard
    return error_code;
208 e80cfcfc bellard
}
209 e80cfcfc bellard
210 e80cfcfc bellard
/* Perform address translation */
211 af7bf89b bellard
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
212 e80cfcfc bellard
                              int is_user, int is_softmmu)
213 e80cfcfc bellard
{
214 af7bf89b bellard
    target_phys_addr_t paddr;
215 5dcb6b91 blueswir1
    target_ulong vaddr;
216 e80cfcfc bellard
    int error_code = 0, prot, ret = 0, access_index;
217 e8af50a3 bellard
218 e80cfcfc bellard
    error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
219 e80cfcfc bellard
    if (error_code == 0) {
220 9e61bde5 bellard
        vaddr = address & TARGET_PAGE_MASK;
221 9e61bde5 bellard
        paddr &= TARGET_PAGE_MASK;
222 9e61bde5 bellard
#ifdef DEBUG_MMU
223 5dcb6b91 blueswir1
        printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
224 5dcb6b91 blueswir1
               TARGET_FMT_lx "\n", address, paddr, vaddr);
225 9e61bde5 bellard
#endif
226 227671c9 bellard
        ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
227 e80cfcfc bellard
        return ret;
228 e80cfcfc bellard
    }
229 e8af50a3 bellard
230 e8af50a3 bellard
    if (env->mmuregs[3]) /* Fault status register */
231 e8af50a3 bellard
        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
232 7483750d bellard
    env->mmuregs[3] |= (access_index << 5) | error_code | 2;
233 e8af50a3 bellard
    env->mmuregs[4] = address; /* Fault address register */
234 e8af50a3 bellard
235 878d3096 bellard
    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
236 6f7e9aec bellard
        // No fault mode: if a mapping is available, just override
237 6f7e9aec bellard
        // permissions. If no mapping is available, redirect accesses to
238 6f7e9aec bellard
        // neverland. Fake/overridden mappings will be flushed when
239 6f7e9aec bellard
        // switching to normal mode.
240 7483750d bellard
        vaddr = address & TARGET_PAGE_MASK;
241 227671c9 bellard
        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
242 227671c9 bellard
        ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
243 7483750d bellard
        return ret;
244 7483750d bellard
    } else {
245 7483750d bellard
        if (rw & 2)
246 7483750d bellard
            env->exception_index = TT_TFAULT;
247 7483750d bellard
        else
248 7483750d bellard
            env->exception_index = TT_DFAULT;
249 7483750d bellard
        return 1;
250 878d3096 bellard
    }
251 e8af50a3 bellard
}
252 24741ef3 bellard
253 24741ef3 bellard
target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
254 24741ef3 bellard
{
255 24741ef3 bellard
    target_phys_addr_t pde_ptr;
256 24741ef3 bellard
    uint32_t pde;
257 24741ef3 bellard
258 24741ef3 bellard
    /* Context base + context number */
259 5dcb6b91 blueswir1
    pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
260 5dcb6b91 blueswir1
        (env->mmuregs[2] << 2);
261 24741ef3 bellard
    pde = ldl_phys(pde_ptr);
262 24741ef3 bellard
263 24741ef3 bellard
    switch (pde & PTE_ENTRYTYPE_MASK) {
264 24741ef3 bellard
    default:
265 24741ef3 bellard
    case 0: /* Invalid */
266 24741ef3 bellard
    case 2: /* PTE, maybe should not happen? */
267 24741ef3 bellard
    case 3: /* Reserved */
268 24741ef3 bellard
        return 0;
269 24741ef3 bellard
    case 1: /* L1 PDE */
270 24741ef3 bellard
        if (mmulev == 3)
271 24741ef3 bellard
            return pde;
272 24741ef3 bellard
        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
273 24741ef3 bellard
        pde = ldl_phys(pde_ptr);
274 24741ef3 bellard
275 24741ef3 bellard
        switch (pde & PTE_ENTRYTYPE_MASK) {
276 24741ef3 bellard
        default:
277 24741ef3 bellard
        case 0: /* Invalid */
278 24741ef3 bellard
        case 3: /* Reserved */
279 24741ef3 bellard
            return 0;
280 24741ef3 bellard
        case 2: /* L1 PTE */
281 24741ef3 bellard
            return pde;
282 24741ef3 bellard
        case 1: /* L2 PDE */
283 24741ef3 bellard
            if (mmulev == 2)
284 24741ef3 bellard
                return pde;
285 24741ef3 bellard
            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
286 24741ef3 bellard
            pde = ldl_phys(pde_ptr);
287 24741ef3 bellard
288 24741ef3 bellard
            switch (pde & PTE_ENTRYTYPE_MASK) {
289 24741ef3 bellard
            default:
290 24741ef3 bellard
            case 0: /* Invalid */
291 24741ef3 bellard
            case 3: /* Reserved */
292 24741ef3 bellard
                return 0;
293 24741ef3 bellard
            case 2: /* L2 PTE */
294 24741ef3 bellard
                return pde;
295 24741ef3 bellard
            case 1: /* L3 PDE */
296 24741ef3 bellard
                if (mmulev == 1)
297 24741ef3 bellard
                    return pde;
298 24741ef3 bellard
                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
299 24741ef3 bellard
                pde = ldl_phys(pde_ptr);
300 24741ef3 bellard
301 24741ef3 bellard
                switch (pde & PTE_ENTRYTYPE_MASK) {
302 24741ef3 bellard
                default:
303 24741ef3 bellard
                case 0: /* Invalid */
304 24741ef3 bellard
                case 1: /* PDE, should not happen */
305 24741ef3 bellard
                case 3: /* Reserved */
306 24741ef3 bellard
                    return 0;
307 24741ef3 bellard
                case 2: /* L3 PTE */
308 24741ef3 bellard
                    return pde;
309 24741ef3 bellard
                }
310 24741ef3 bellard
            }
311 24741ef3 bellard
        }
312 24741ef3 bellard
    }
313 24741ef3 bellard
    return 0;
314 24741ef3 bellard
}
315 24741ef3 bellard
316 24741ef3 bellard
#ifdef DEBUG_MMU
317 24741ef3 bellard
void dump_mmu(CPUState *env)
318 24741ef3 bellard
{
319 5dcb6b91 blueswir1
    target_ulong va, va1, va2;
320 5dcb6b91 blueswir1
    unsigned int n, m, o;
321 5dcb6b91 blueswir1
    target_phys_addr_t pde_ptr, pa;
322 24741ef3 bellard
    uint32_t pde;
323 24741ef3 bellard
324 24741ef3 bellard
    printf("MMU dump:\n");
325 24741ef3 bellard
    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
326 24741ef3 bellard
    pde = ldl_phys(pde_ptr);
327 5dcb6b91 blueswir1
    printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
328 5dcb6b91 blueswir1
           (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
329 24741ef3 bellard
    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
330 5dcb6b91 blueswir1
        pde = mmu_probe(env, va, 2);
331 5dcb6b91 blueswir1
        if (pde) {
332 24741ef3 bellard
            pa = cpu_get_phys_page_debug(env, va);
333 5dcb6b91 blueswir1
             printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
334 5dcb6b91 blueswir1
                   " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
335 24741ef3 bellard
            for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
336 5dcb6b91 blueswir1
                pde = mmu_probe(env, va1, 1);
337 5dcb6b91 blueswir1
                if (pde) {
338 24741ef3 bellard
                    pa = cpu_get_phys_page_debug(env, va1);
339 5dcb6b91 blueswir1
                     printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
340 5dcb6b91 blueswir1
                           " PDE: " TARGET_FMT_lx "\n", va1, pa, pde);
341 24741ef3 bellard
                    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
342 5dcb6b91 blueswir1
                        pde = mmu_probe(env, va2, 0);
343 5dcb6b91 blueswir1
                        if (pde) {
344 24741ef3 bellard
                            pa = cpu_get_phys_page_debug(env, va2);
345 5dcb6b91 blueswir1
                             printf("  VA: " TARGET_FMT_lx ", PA: "
346 5dcb6b91 blueswir1
                                   TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n",
347 5dcb6b91 blueswir1
                                   va2, pa, pde);
348 24741ef3 bellard
                        }
349 24741ef3 bellard
                    }
350 24741ef3 bellard
                }
351 24741ef3 bellard
            }
352 24741ef3 bellard
        }
353 24741ef3 bellard
    }
354 24741ef3 bellard
    printf("MMU dump ends\n");
355 24741ef3 bellard
}
356 24741ef3 bellard
#endif /* DEBUG_MMU */
357 24741ef3 bellard
358 24741ef3 bellard
#else /* !TARGET_SPARC64 */
359 83469015 bellard
/*
360 83469015 bellard
 * UltraSparc IIi I/DMMUs
361 83469015 bellard
 */
362 3475187d bellard
static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot,
363 3475187d bellard
                          int *access_index, target_ulong address, int rw,
364 3475187d bellard
                          int is_user)
365 3475187d bellard
{
366 3475187d bellard
    target_ulong mask;
367 3475187d bellard
    unsigned int i;
368 3475187d bellard
369 3475187d bellard
    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
370 83469015 bellard
        *physical = address;
371 3475187d bellard
        *prot = PAGE_READ | PAGE_WRITE;
372 3475187d bellard
        return 0;
373 3475187d bellard
    }
374 3475187d bellard
375 3475187d bellard
    for (i = 0; i < 64; i++) {
376 83469015 bellard
        switch ((env->dtlb_tte[i] >> 61) & 3) {
377 83469015 bellard
        default:
378 83469015 bellard
        case 0x0: // 8k
379 83469015 bellard
            mask = 0xffffffffffffe000ULL;
380 83469015 bellard
            break;
381 83469015 bellard
        case 0x1: // 64k
382 83469015 bellard
            mask = 0xffffffffffff0000ULL;
383 83469015 bellard
            break;
384 83469015 bellard
        case 0x2: // 512k
385 83469015 bellard
            mask = 0xfffffffffff80000ULL;
386 83469015 bellard
            break;
387 83469015 bellard
        case 0x3: // 4M
388 83469015 bellard
            mask = 0xffffffffffc00000ULL;
389 83469015 bellard
            break;
390 83469015 bellard
        }
391 83469015 bellard
        // ctx match, vaddr match?
392 83469015 bellard
        if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
393 83469015 bellard
            (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
394 83469015 bellard
            // valid, access ok?
395 83469015 bellard
            if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 ||
396 83469015 bellard
                ((env->dtlb_tte[i] & 0x4) && is_user) ||
397 83469015 bellard
                (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
398 83469015 bellard
                if (env->dmmuregs[3]) /* Fault status register */
399 83469015 bellard
                    env->dmmuregs[3] = 2; /* overflow (not read before another fault) */
400 83469015 bellard
                env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1;
401 83469015 bellard
                env->dmmuregs[4] = address; /* Fault address register */
402 83469015 bellard
                env->exception_index = TT_DFAULT;
403 83469015 bellard
#ifdef DEBUG_MMU
404 26a76461 bellard
                printf("DFAULT at 0x%" PRIx64 "\n", address);
405 83469015 bellard
#endif
406 83469015 bellard
                return 1;
407 3475187d bellard
            }
408 83469015 bellard
            *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
409 83469015 bellard
            *prot = PAGE_READ;
410 83469015 bellard
            if (env->dtlb_tte[i] & 0x2)
411 83469015 bellard
                *prot |= PAGE_WRITE;
412 83469015 bellard
            return 0;
413 3475187d bellard
        }
414 3475187d bellard
    }
415 83469015 bellard
#ifdef DEBUG_MMU
416 26a76461 bellard
    printf("DMISS at 0x%" PRIx64 "\n", address);
417 83469015 bellard
#endif
418 83469015 bellard
    env->exception_index = TT_DMISS;
419 3475187d bellard
    return 1;
420 3475187d bellard
}
421 3475187d bellard
422 3475187d bellard
static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot,
423 3475187d bellard
                          int *access_index, target_ulong address, int rw,
424 3475187d bellard
                          int is_user)
425 3475187d bellard
{
426 3475187d bellard
    target_ulong mask;
427 3475187d bellard
    unsigned int i;
428 3475187d bellard
429 3475187d bellard
    if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */
430 83469015 bellard
        *physical = address;
431 227671c9 bellard
        *prot = PAGE_EXEC;
432 3475187d bellard
        return 0;
433 3475187d bellard
    }
434 83469015 bellard
435 3475187d bellard
    for (i = 0; i < 64; i++) {
436 83469015 bellard
        switch ((env->itlb_tte[i] >> 61) & 3) {
437 83469015 bellard
        default:
438 83469015 bellard
        case 0x0: // 8k
439 83469015 bellard
            mask = 0xffffffffffffe000ULL;
440 83469015 bellard
            break;
441 83469015 bellard
        case 0x1: // 64k
442 83469015 bellard
            mask = 0xffffffffffff0000ULL;
443 83469015 bellard
            break;
444 83469015 bellard
        case 0x2: // 512k
445 83469015 bellard
            mask = 0xfffffffffff80000ULL;
446 83469015 bellard
            break;
447 83469015 bellard
        case 0x3: // 4M
448 83469015 bellard
            mask = 0xffffffffffc00000ULL;
449 3475187d bellard
                break;
450 83469015 bellard
        }
451 83469015 bellard
        // ctx match, vaddr match?
452 83469015 bellard
        if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
453 83469015 bellard
            (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
454 83469015 bellard
            // valid, access ok?
455 83469015 bellard
            if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 ||
456 83469015 bellard
                ((env->itlb_tte[i] & 0x4) && is_user)) {
457 83469015 bellard
                if (env->immuregs[3]) /* Fault status register */
458 83469015 bellard
                    env->immuregs[3] = 2; /* overflow (not read before another fault) */
459 83469015 bellard
                env->immuregs[3] |= (is_user << 3) | 1;
460 83469015 bellard
                env->exception_index = TT_TFAULT;
461 83469015 bellard
#ifdef DEBUG_MMU
462 26a76461 bellard
                printf("TFAULT at 0x%" PRIx64 "\n", address);
463 83469015 bellard
#endif
464 83469015 bellard
                return 1;
465 3475187d bellard
            }
466 83469015 bellard
            *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
467 227671c9 bellard
            *prot = PAGE_EXEC;
468 83469015 bellard
            return 0;
469 3475187d bellard
        }
470 3475187d bellard
    }
471 83469015 bellard
#ifdef DEBUG_MMU
472 26a76461 bellard
    printf("TMISS at 0x%" PRIx64 "\n", address);
473 83469015 bellard
#endif
474 83469015 bellard
    env->exception_index = TT_TMISS;
475 3475187d bellard
    return 1;
476 3475187d bellard
}
477 3475187d bellard
478 3475187d bellard
int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot,
479 3475187d bellard
                          int *access_index, target_ulong address, int rw,
480 3475187d bellard
                          int is_user)
481 3475187d bellard
{
482 3475187d bellard
    if (rw == 2)
483 3475187d bellard
        return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user);
484 3475187d bellard
    else
485 3475187d bellard
        return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user);
486 3475187d bellard
}
487 3475187d bellard
488 3475187d bellard
/* Perform address translation */
489 3475187d bellard
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
490 3475187d bellard
                              int is_user, int is_softmmu)
491 3475187d bellard
{
492 83469015 bellard
    target_ulong virt_addr, vaddr;
493 3475187d bellard
    target_phys_addr_t paddr;
494 3475187d bellard
    int error_code = 0, prot, ret = 0, access_index;
495 3475187d bellard
496 3475187d bellard
    error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
497 3475187d bellard
    if (error_code == 0) {
498 3475187d bellard
        virt_addr = address & TARGET_PAGE_MASK;
499 3475187d bellard
        vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
500 83469015 bellard
#ifdef DEBUG_MMU
501 26a76461 bellard
        printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 "\n", address, paddr, vaddr);
502 83469015 bellard
#endif
503 227671c9 bellard
        ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
504 3475187d bellard
        return ret;
505 3475187d bellard
    }
506 3475187d bellard
    // XXX
507 3475187d bellard
    return 1;
508 3475187d bellard
}
509 3475187d bellard
510 83469015 bellard
#ifdef DEBUG_MMU
511 83469015 bellard
void dump_mmu(CPUState *env)
512 83469015 bellard
{
513 83469015 bellard
    unsigned int i;
514 83469015 bellard
    const char *mask;
515 83469015 bellard
516 26a76461 bellard
    printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n", env->dmmuregs[1], env->dmmuregs[2]);
517 83469015 bellard
    if ((env->lsu & DMMU_E) == 0) {
518 83469015 bellard
        printf("DMMU disabled\n");
519 83469015 bellard
    } else {
520 83469015 bellard
        printf("DMMU dump:\n");
521 83469015 bellard
        for (i = 0; i < 64; i++) {
522 83469015 bellard
            switch ((env->dtlb_tte[i] >> 61) & 3) {
523 83469015 bellard
            default:
524 83469015 bellard
            case 0x0:
525 83469015 bellard
                mask = "  8k";
526 83469015 bellard
                break;
527 83469015 bellard
            case 0x1:
528 83469015 bellard
                mask = " 64k";
529 83469015 bellard
                break;
530 83469015 bellard
            case 0x2:
531 83469015 bellard
                mask = "512k";
532 83469015 bellard
                break;
533 83469015 bellard
            case 0x3:
534 83469015 bellard
                mask = "  4M";
535 83469015 bellard
                break;
536 83469015 bellard
            }
537 83469015 bellard
            if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
538 26a76461 bellard
                printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %" PRId64 "\n",
539 83469015 bellard
                       env->dtlb_tag[i] & ~0x1fffULL,
540 83469015 bellard
                       env->dtlb_tte[i] & 0x1ffffffe000ULL,
541 83469015 bellard
                       mask,
542 83469015 bellard
                       env->dtlb_tte[i] & 0x4? "priv": "user",
543 83469015 bellard
                       env->dtlb_tte[i] & 0x2? "RW": "RO",
544 83469015 bellard
                       env->dtlb_tte[i] & 0x40? "locked": "unlocked",
545 83469015 bellard
                       env->dtlb_tag[i] & 0x1fffULL);
546 83469015 bellard
            }
547 83469015 bellard
        }
548 83469015 bellard
    }
549 83469015 bellard
    if ((env->lsu & IMMU_E) == 0) {
550 83469015 bellard
        printf("IMMU disabled\n");
551 83469015 bellard
    } else {
552 83469015 bellard
        printf("IMMU dump:\n");
553 83469015 bellard
        for (i = 0; i < 64; i++) {
554 83469015 bellard
            switch ((env->itlb_tte[i] >> 61) & 3) {
555 83469015 bellard
            default:
556 83469015 bellard
            case 0x0:
557 83469015 bellard
                mask = "  8k";
558 83469015 bellard
                break;
559 83469015 bellard
            case 0x1:
560 83469015 bellard
                mask = " 64k";
561 83469015 bellard
                break;
562 83469015 bellard
            case 0x2:
563 83469015 bellard
                mask = "512k";
564 83469015 bellard
                break;
565 83469015 bellard
            case 0x3:
566 83469015 bellard
                mask = "  4M";
567 83469015 bellard
                break;
568 83469015 bellard
            }
569 83469015 bellard
            if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
570 26a76461 bellard
                printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %" PRId64 "\n",
571 83469015 bellard
                       env->itlb_tag[i] & ~0x1fffULL,
572 83469015 bellard
                       env->itlb_tte[i] & 0x1ffffffe000ULL,
573 83469015 bellard
                       mask,
574 83469015 bellard
                       env->itlb_tte[i] & 0x4? "priv": "user",
575 83469015 bellard
                       env->itlb_tte[i] & 0x40? "locked": "unlocked",
576 83469015 bellard
                       env->itlb_tag[i] & 0x1fffULL);
577 83469015 bellard
            }
578 83469015 bellard
        }
579 83469015 bellard
    }
580 83469015 bellard
}
581 24741ef3 bellard
#endif /* DEBUG_MMU */
582 24741ef3 bellard
583 24741ef3 bellard
#endif /* TARGET_SPARC64 */
584 24741ef3 bellard
#endif /* !CONFIG_USER_ONLY */
585 24741ef3 bellard
586 24741ef3 bellard
void memcpy32(target_ulong *dst, const target_ulong *src)
587 24741ef3 bellard
{
588 24741ef3 bellard
    dst[0] = src[0];
589 24741ef3 bellard
    dst[1] = src[1];
590 24741ef3 bellard
    dst[2] = src[2];
591 24741ef3 bellard
    dst[3] = src[3];
592 24741ef3 bellard
    dst[4] = src[4];
593 24741ef3 bellard
    dst[5] = src[5];
594 24741ef3 bellard
    dst[6] = src[6];
595 24741ef3 bellard
    dst[7] = src[7];
596 24741ef3 bellard
}