Statistics
| Branch: | Revision:

root / target-sparc / helper.c @ 480c1cdb

History | View | Annotate | Download (16 kB)

1 e8af50a3 bellard
/*
2 e8af50a3 bellard
 *  sparc helpers
3 e8af50a3 bellard
 * 
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 9d893301 bellard
#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 6f7e9aec bellard
    *physical = 0xfffff000;
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 e80cfcfc bellard
    *physical = ((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 e80cfcfc bellard
    unsigned long 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 9e61bde5 bellard
        printf("Translate at 0x%lx -> 0x%lx, vaddr 0x%lx\n", (long)address, (long)paddr, (long)vaddr);
224 9e61bde5 bellard
#endif
225 227671c9 bellard
        ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
226 e80cfcfc bellard
        return ret;
227 e80cfcfc bellard
    }
228 e8af50a3 bellard
229 e8af50a3 bellard
    if (env->mmuregs[3]) /* Fault status register */
230 e8af50a3 bellard
        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
231 7483750d bellard
    env->mmuregs[3] |= (access_index << 5) | error_code | 2;
232 e8af50a3 bellard
    env->mmuregs[4] = address; /* Fault address register */
233 e8af50a3 bellard
234 878d3096 bellard
    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
235 6f7e9aec bellard
        // No fault mode: if a mapping is available, just override
236 6f7e9aec bellard
        // permissions. If no mapping is available, redirect accesses to
237 6f7e9aec bellard
        // neverland. Fake/overridden mappings will be flushed when
238 6f7e9aec bellard
        // switching to normal mode.
239 7483750d bellard
        vaddr = address & TARGET_PAGE_MASK;
240 227671c9 bellard
        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
241 227671c9 bellard
        ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
242 7483750d bellard
        return ret;
243 7483750d bellard
    } else {
244 7483750d bellard
        if (rw & 2)
245 7483750d bellard
            env->exception_index = TT_TFAULT;
246 7483750d bellard
        else
247 7483750d bellard
            env->exception_index = TT_DFAULT;
248 7483750d bellard
        return 1;
249 878d3096 bellard
    }
250 e8af50a3 bellard
}
251 24741ef3 bellard
252 24741ef3 bellard
target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
253 24741ef3 bellard
{
254 24741ef3 bellard
    target_phys_addr_t pde_ptr;
255 24741ef3 bellard
    uint32_t pde;
256 24741ef3 bellard
257 24741ef3 bellard
    /* Context base + context number */
258 24741ef3 bellard
    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
259 24741ef3 bellard
    pde = ldl_phys(pde_ptr);
260 24741ef3 bellard
261 24741ef3 bellard
    switch (pde & PTE_ENTRYTYPE_MASK) {
262 24741ef3 bellard
    default:
263 24741ef3 bellard
    case 0: /* Invalid */
264 24741ef3 bellard
    case 2: /* PTE, maybe should not happen? */
265 24741ef3 bellard
    case 3: /* Reserved */
266 24741ef3 bellard
        return 0;
267 24741ef3 bellard
    case 1: /* L1 PDE */
268 24741ef3 bellard
        if (mmulev == 3)
269 24741ef3 bellard
            return pde;
270 24741ef3 bellard
        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
271 24741ef3 bellard
        pde = ldl_phys(pde_ptr);
272 24741ef3 bellard
273 24741ef3 bellard
        switch (pde & PTE_ENTRYTYPE_MASK) {
274 24741ef3 bellard
        default:
275 24741ef3 bellard
        case 0: /* Invalid */
276 24741ef3 bellard
        case 3: /* Reserved */
277 24741ef3 bellard
            return 0;
278 24741ef3 bellard
        case 2: /* L1 PTE */
279 24741ef3 bellard
            return pde;
280 24741ef3 bellard
        case 1: /* L2 PDE */
281 24741ef3 bellard
            if (mmulev == 2)
282 24741ef3 bellard
                return pde;
283 24741ef3 bellard
            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
284 24741ef3 bellard
            pde = ldl_phys(pde_ptr);
285 24741ef3 bellard
286 24741ef3 bellard
            switch (pde & PTE_ENTRYTYPE_MASK) {
287 24741ef3 bellard
            default:
288 24741ef3 bellard
            case 0: /* Invalid */
289 24741ef3 bellard
            case 3: /* Reserved */
290 24741ef3 bellard
                return 0;
291 24741ef3 bellard
            case 2: /* L2 PTE */
292 24741ef3 bellard
                return pde;
293 24741ef3 bellard
            case 1: /* L3 PDE */
294 24741ef3 bellard
                if (mmulev == 1)
295 24741ef3 bellard
                    return pde;
296 24741ef3 bellard
                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
297 24741ef3 bellard
                pde = ldl_phys(pde_ptr);
298 24741ef3 bellard
299 24741ef3 bellard
                switch (pde & PTE_ENTRYTYPE_MASK) {
300 24741ef3 bellard
                default:
301 24741ef3 bellard
                case 0: /* Invalid */
302 24741ef3 bellard
                case 1: /* PDE, should not happen */
303 24741ef3 bellard
                case 3: /* Reserved */
304 24741ef3 bellard
                    return 0;
305 24741ef3 bellard
                case 2: /* L3 PTE */
306 24741ef3 bellard
                    return pde;
307 24741ef3 bellard
                }
308 24741ef3 bellard
            }
309 24741ef3 bellard
        }
310 24741ef3 bellard
    }
311 24741ef3 bellard
    return 0;
312 24741ef3 bellard
}
313 24741ef3 bellard
314 24741ef3 bellard
#ifdef DEBUG_MMU
315 24741ef3 bellard
void dump_mmu(CPUState *env)
316 24741ef3 bellard
{
317 24741ef3 bellard
     target_ulong va, va1, va2;
318 24741ef3 bellard
     unsigned int n, m, o;
319 24741ef3 bellard
     target_phys_addr_t pde_ptr, pa;
320 24741ef3 bellard
    uint32_t pde;
321 24741ef3 bellard
322 24741ef3 bellard
    printf("MMU dump:\n");
323 24741ef3 bellard
    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
324 24741ef3 bellard
    pde = ldl_phys(pde_ptr);
325 24741ef3 bellard
    printf("Root ptr: " TARGET_FMT_lx ", ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]);
326 24741ef3 bellard
    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
327 24741ef3 bellard
        pde_ptr = mmu_probe(env, va, 2);
328 24741ef3 bellard
        if (pde_ptr) {
329 24741ef3 bellard
            pa = cpu_get_phys_page_debug(env, va);
330 24741ef3 bellard
             printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va, pa, pde_ptr);
331 24741ef3 bellard
            for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
332 24741ef3 bellard
                pde_ptr = mmu_probe(env, va1, 1);
333 24741ef3 bellard
                if (pde_ptr) {
334 24741ef3 bellard
                    pa = cpu_get_phys_page_debug(env, va1);
335 24741ef3 bellard
                     printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde_ptr);
336 24741ef3 bellard
                    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
337 24741ef3 bellard
                        pde_ptr = mmu_probe(env, va2, 0);
338 24741ef3 bellard
                        if (pde_ptr) {
339 24741ef3 bellard
                            pa = cpu_get_phys_page_debug(env, va2);
340 24741ef3 bellard
                             printf("  VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde_ptr);
341 24741ef3 bellard
                        }
342 24741ef3 bellard
                    }
343 24741ef3 bellard
                }
344 24741ef3 bellard
            }
345 24741ef3 bellard
        }
346 24741ef3 bellard
    }
347 24741ef3 bellard
    printf("MMU dump ends\n");
348 24741ef3 bellard
}
349 24741ef3 bellard
#endif /* DEBUG_MMU */
350 24741ef3 bellard
351 24741ef3 bellard
#else /* !TARGET_SPARC64 */
352 83469015 bellard
/*
353 83469015 bellard
 * UltraSparc IIi I/DMMUs
354 83469015 bellard
 */
355 3475187d bellard
static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot,
356 3475187d bellard
                          int *access_index, target_ulong address, int rw,
357 3475187d bellard
                          int is_user)
358 3475187d bellard
{
359 3475187d bellard
    target_ulong mask;
360 3475187d bellard
    unsigned int i;
361 3475187d bellard
362 3475187d bellard
    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
363 83469015 bellard
        *physical = address;
364 3475187d bellard
        *prot = PAGE_READ | PAGE_WRITE;
365 3475187d bellard
        return 0;
366 3475187d bellard
    }
367 3475187d bellard
368 3475187d bellard
    for (i = 0; i < 64; i++) {
369 83469015 bellard
        switch ((env->dtlb_tte[i] >> 61) & 3) {
370 83469015 bellard
        default:
371 83469015 bellard
        case 0x0: // 8k
372 83469015 bellard
            mask = 0xffffffffffffe000ULL;
373 83469015 bellard
            break;
374 83469015 bellard
        case 0x1: // 64k
375 83469015 bellard
            mask = 0xffffffffffff0000ULL;
376 83469015 bellard
            break;
377 83469015 bellard
        case 0x2: // 512k
378 83469015 bellard
            mask = 0xfffffffffff80000ULL;
379 83469015 bellard
            break;
380 83469015 bellard
        case 0x3: // 4M
381 83469015 bellard
            mask = 0xffffffffffc00000ULL;
382 83469015 bellard
            break;
383 83469015 bellard
        }
384 83469015 bellard
        // ctx match, vaddr match?
385 83469015 bellard
        if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
386 83469015 bellard
            (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
387 83469015 bellard
            // valid, access ok?
388 83469015 bellard
            if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 ||
389 83469015 bellard
                ((env->dtlb_tte[i] & 0x4) && is_user) ||
390 83469015 bellard
                (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
391 83469015 bellard
                if (env->dmmuregs[3]) /* Fault status register */
392 83469015 bellard
                    env->dmmuregs[3] = 2; /* overflow (not read before another fault) */
393 83469015 bellard
                env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1;
394 83469015 bellard
                env->dmmuregs[4] = address; /* Fault address register */
395 83469015 bellard
                env->exception_index = TT_DFAULT;
396 83469015 bellard
#ifdef DEBUG_MMU
397 83469015 bellard
                printf("DFAULT at 0x%llx\n", address);
398 83469015 bellard
#endif
399 83469015 bellard
                return 1;
400 3475187d bellard
            }
401 83469015 bellard
            *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
402 83469015 bellard
            *prot = PAGE_READ;
403 83469015 bellard
            if (env->dtlb_tte[i] & 0x2)
404 83469015 bellard
                *prot |= PAGE_WRITE;
405 83469015 bellard
            return 0;
406 3475187d bellard
        }
407 3475187d bellard
    }
408 83469015 bellard
#ifdef DEBUG_MMU
409 83469015 bellard
    printf("DMISS at 0x%llx\n", address);
410 83469015 bellard
#endif
411 83469015 bellard
    env->exception_index = TT_DMISS;
412 3475187d bellard
    return 1;
413 3475187d bellard
}
414 3475187d bellard
415 3475187d bellard
static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot,
416 3475187d bellard
                          int *access_index, target_ulong address, int rw,
417 3475187d bellard
                          int is_user)
418 3475187d bellard
{
419 3475187d bellard
    target_ulong mask;
420 3475187d bellard
    unsigned int i;
421 3475187d bellard
422 3475187d bellard
    if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */
423 83469015 bellard
        *physical = address;
424 227671c9 bellard
        *prot = PAGE_EXEC;
425 3475187d bellard
        return 0;
426 3475187d bellard
    }
427 83469015 bellard
428 3475187d bellard
    for (i = 0; i < 64; i++) {
429 83469015 bellard
        switch ((env->itlb_tte[i] >> 61) & 3) {
430 83469015 bellard
        default:
431 83469015 bellard
        case 0x0: // 8k
432 83469015 bellard
            mask = 0xffffffffffffe000ULL;
433 83469015 bellard
            break;
434 83469015 bellard
        case 0x1: // 64k
435 83469015 bellard
            mask = 0xffffffffffff0000ULL;
436 83469015 bellard
            break;
437 83469015 bellard
        case 0x2: // 512k
438 83469015 bellard
            mask = 0xfffffffffff80000ULL;
439 83469015 bellard
            break;
440 83469015 bellard
        case 0x3: // 4M
441 83469015 bellard
            mask = 0xffffffffffc00000ULL;
442 3475187d bellard
                break;
443 83469015 bellard
        }
444 83469015 bellard
        // ctx match, vaddr match?
445 83469015 bellard
        if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
446 83469015 bellard
            (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
447 83469015 bellard
            // valid, access ok?
448 83469015 bellard
            if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 ||
449 83469015 bellard
                ((env->itlb_tte[i] & 0x4) && is_user)) {
450 83469015 bellard
                if (env->immuregs[3]) /* Fault status register */
451 83469015 bellard
                    env->immuregs[3] = 2; /* overflow (not read before another fault) */
452 83469015 bellard
                env->immuregs[3] |= (is_user << 3) | 1;
453 83469015 bellard
                env->exception_index = TT_TFAULT;
454 83469015 bellard
#ifdef DEBUG_MMU
455 83469015 bellard
                printf("TFAULT at 0x%llx\n", address);
456 83469015 bellard
#endif
457 83469015 bellard
                return 1;
458 3475187d bellard
            }
459 83469015 bellard
            *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
460 227671c9 bellard
            *prot = PAGE_EXEC;
461 83469015 bellard
            return 0;
462 3475187d bellard
        }
463 3475187d bellard
    }
464 83469015 bellard
#ifdef DEBUG_MMU
465 83469015 bellard
    printf("TMISS at 0x%llx\n", address);
466 83469015 bellard
#endif
467 83469015 bellard
    env->exception_index = TT_TMISS;
468 3475187d bellard
    return 1;
469 3475187d bellard
}
470 3475187d bellard
471 3475187d bellard
int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot,
472 3475187d bellard
                          int *access_index, target_ulong address, int rw,
473 3475187d bellard
                          int is_user)
474 3475187d bellard
{
475 3475187d bellard
    if (rw == 2)
476 3475187d bellard
        return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user);
477 3475187d bellard
    else
478 3475187d bellard
        return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user);
479 3475187d bellard
}
480 3475187d bellard
481 3475187d bellard
/* Perform address translation */
482 3475187d bellard
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
483 3475187d bellard
                              int is_user, int is_softmmu)
484 3475187d bellard
{
485 83469015 bellard
    target_ulong virt_addr, vaddr;
486 3475187d bellard
    target_phys_addr_t paddr;
487 3475187d bellard
    int error_code = 0, prot, ret = 0, access_index;
488 3475187d bellard
489 3475187d bellard
    error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
490 3475187d bellard
    if (error_code == 0) {
491 3475187d bellard
        virt_addr = address & TARGET_PAGE_MASK;
492 3475187d bellard
        vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
493 83469015 bellard
#ifdef DEBUG_MMU
494 83469015 bellard
        printf("Translate at 0x%llx -> 0x%llx, vaddr 0x%llx\n", address, paddr, vaddr);
495 83469015 bellard
#endif
496 227671c9 bellard
        ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
497 3475187d bellard
        return ret;
498 3475187d bellard
    }
499 3475187d bellard
    // XXX
500 3475187d bellard
    return 1;
501 3475187d bellard
}
502 3475187d bellard
503 83469015 bellard
#ifdef DEBUG_MMU
504 83469015 bellard
void dump_mmu(CPUState *env)
505 83469015 bellard
{
506 83469015 bellard
    unsigned int i;
507 83469015 bellard
    const char *mask;
508 83469015 bellard
509 83469015 bellard
    printf("MMU contexts: Primary: %lld, Secondary: %lld\n", env->dmmuregs[1], env->dmmuregs[2]);
510 83469015 bellard
    if ((env->lsu & DMMU_E) == 0) {
511 83469015 bellard
        printf("DMMU disabled\n");
512 83469015 bellard
    } else {
513 83469015 bellard
        printf("DMMU dump:\n");
514 83469015 bellard
        for (i = 0; i < 64; i++) {
515 83469015 bellard
            switch ((env->dtlb_tte[i] >> 61) & 3) {
516 83469015 bellard
            default:
517 83469015 bellard
            case 0x0:
518 83469015 bellard
                mask = "  8k";
519 83469015 bellard
                break;
520 83469015 bellard
            case 0x1:
521 83469015 bellard
                mask = " 64k";
522 83469015 bellard
                break;
523 83469015 bellard
            case 0x2:
524 83469015 bellard
                mask = "512k";
525 83469015 bellard
                break;
526 83469015 bellard
            case 0x3:
527 83469015 bellard
                mask = "  4M";
528 83469015 bellard
                break;
529 83469015 bellard
            }
530 83469015 bellard
            if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
531 83469015 bellard
                printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %lld\n",
532 83469015 bellard
                       env->dtlb_tag[i] & ~0x1fffULL,
533 83469015 bellard
                       env->dtlb_tte[i] & 0x1ffffffe000ULL,
534 83469015 bellard
                       mask,
535 83469015 bellard
                       env->dtlb_tte[i] & 0x4? "priv": "user",
536 83469015 bellard
                       env->dtlb_tte[i] & 0x2? "RW": "RO",
537 83469015 bellard
                       env->dtlb_tte[i] & 0x40? "locked": "unlocked",
538 83469015 bellard
                       env->dtlb_tag[i] & 0x1fffULL);
539 83469015 bellard
            }
540 83469015 bellard
        }
541 83469015 bellard
    }
542 83469015 bellard
    if ((env->lsu & IMMU_E) == 0) {
543 83469015 bellard
        printf("IMMU disabled\n");
544 83469015 bellard
    } else {
545 83469015 bellard
        printf("IMMU dump:\n");
546 83469015 bellard
        for (i = 0; i < 64; i++) {
547 83469015 bellard
            switch ((env->itlb_tte[i] >> 61) & 3) {
548 83469015 bellard
            default:
549 83469015 bellard
            case 0x0:
550 83469015 bellard
                mask = "  8k";
551 83469015 bellard
                break;
552 83469015 bellard
            case 0x1:
553 83469015 bellard
                mask = " 64k";
554 83469015 bellard
                break;
555 83469015 bellard
            case 0x2:
556 83469015 bellard
                mask = "512k";
557 83469015 bellard
                break;
558 83469015 bellard
            case 0x3:
559 83469015 bellard
                mask = "  4M";
560 83469015 bellard
                break;
561 83469015 bellard
            }
562 83469015 bellard
            if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
563 83469015 bellard
                printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %lld\n",
564 83469015 bellard
                       env->itlb_tag[i] & ~0x1fffULL,
565 83469015 bellard
                       env->itlb_tte[i] & 0x1ffffffe000ULL,
566 83469015 bellard
                       mask,
567 83469015 bellard
                       env->itlb_tte[i] & 0x4? "priv": "user",
568 83469015 bellard
                       env->itlb_tte[i] & 0x40? "locked": "unlocked",
569 83469015 bellard
                       env->itlb_tag[i] & 0x1fffULL);
570 83469015 bellard
            }
571 83469015 bellard
        }
572 83469015 bellard
    }
573 83469015 bellard
}
574 24741ef3 bellard
#endif /* DEBUG_MMU */
575 24741ef3 bellard
576 24741ef3 bellard
#endif /* TARGET_SPARC64 */
577 24741ef3 bellard
#endif /* !CONFIG_USER_ONLY */
578 24741ef3 bellard
579 24741ef3 bellard
void memcpy32(target_ulong *dst, const target_ulong *src)
580 24741ef3 bellard
{
581 24741ef3 bellard
    dst[0] = src[0];
582 24741ef3 bellard
    dst[1] = src[1];
583 24741ef3 bellard
    dst[2] = src[2];
584 24741ef3 bellard
    dst[3] = src[3];
585 24741ef3 bellard
    dst[4] = src[4];
586 24741ef3 bellard
    dst[5] = src[5];
587 24741ef3 bellard
    dst[6] = src[6];
588 24741ef3 bellard
    dst[7] = src[7];
589 24741ef3 bellard
}