Statistics
| Branch: | Revision:

root / target-sparc / helper.c @ 40ce0a9a

History | View | Annotate | Download (19.1 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 0f8a249a blueswir1
                          int *access_index, target_ulong address, int rw,
103 0f8a249a blueswir1
                          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 40ce0a9a blueswir1
114 e8af50a3 bellard
    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
115 40ce0a9a blueswir1
        // Boot mode: instruction fetches are taken from PROM
116 40ce0a9a blueswir1
        if (rw == 2 && (env->mmuregs[0] & MMU_BM)) {
117 40ce0a9a blueswir1
            *physical = 0xff0000000ULL | (address & 0x3ffffULL);
118 40ce0a9a blueswir1
            *prot = PAGE_READ | PAGE_EXEC;
119 40ce0a9a blueswir1
            return 0;
120 40ce0a9a blueswir1
        }
121 0f8a249a blueswir1
        *physical = address;
122 227671c9 bellard
        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
123 e80cfcfc bellard
        return 0;
124 e8af50a3 bellard
    }
125 e8af50a3 bellard
126 7483750d bellard
    *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
127 5dcb6b91 blueswir1
    *physical = 0xffffffffffff0000ULL;
128 7483750d bellard
129 e8af50a3 bellard
    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
130 e8af50a3 bellard
    /* Context base + context number */
131 b3180cdc bellard
    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
132 49be8030 bellard
    pde = ldl_phys(pde_ptr);
133 e8af50a3 bellard
134 e8af50a3 bellard
    /* Ctx pde */
135 e8af50a3 bellard
    switch (pde & PTE_ENTRYTYPE_MASK) {
136 e80cfcfc bellard
    default:
137 e8af50a3 bellard
    case 0: /* Invalid */
138 0f8a249a blueswir1
        return 1 << 2;
139 e80cfcfc bellard
    case 2: /* L0 PTE, maybe should not happen? */
140 e8af50a3 bellard
    case 3: /* Reserved */
141 7483750d bellard
        return 4 << 2;
142 e80cfcfc bellard
    case 1: /* L0 PDE */
143 0f8a249a blueswir1
        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
144 49be8030 bellard
        pde = ldl_phys(pde_ptr);
145 e8af50a3 bellard
146 0f8a249a blueswir1
        switch (pde & PTE_ENTRYTYPE_MASK) {
147 0f8a249a blueswir1
        default:
148 0f8a249a blueswir1
        case 0: /* Invalid */
149 0f8a249a blueswir1
            return (1 << 8) | (1 << 2);
150 0f8a249a blueswir1
        case 3: /* Reserved */
151 0f8a249a blueswir1
            return (1 << 8) | (4 << 2);
152 0f8a249a blueswir1
        case 1: /* L1 PDE */
153 0f8a249a blueswir1
            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
154 49be8030 bellard
            pde = ldl_phys(pde_ptr);
155 e8af50a3 bellard
156 0f8a249a blueswir1
            switch (pde & PTE_ENTRYTYPE_MASK) {
157 0f8a249a blueswir1
            default:
158 0f8a249a blueswir1
            case 0: /* Invalid */
159 0f8a249a blueswir1
                return (2 << 8) | (1 << 2);
160 0f8a249a blueswir1
            case 3: /* Reserved */
161 0f8a249a blueswir1
                return (2 << 8) | (4 << 2);
162 0f8a249a blueswir1
            case 1: /* L2 PDE */
163 0f8a249a blueswir1
                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
164 49be8030 bellard
                pde = ldl_phys(pde_ptr);
165 e8af50a3 bellard
166 0f8a249a blueswir1
                switch (pde & PTE_ENTRYTYPE_MASK) {
167 0f8a249a blueswir1
                default:
168 0f8a249a blueswir1
                case 0: /* Invalid */
169 0f8a249a blueswir1
                    return (3 << 8) | (1 << 2);
170 0f8a249a blueswir1
                case 1: /* PDE, should not happen */
171 0f8a249a blueswir1
                case 3: /* Reserved */
172 0f8a249a blueswir1
                    return (3 << 8) | (4 << 2);
173 0f8a249a blueswir1
                case 2: /* L3 PTE */
174 0f8a249a blueswir1
                    virt_addr = address & TARGET_PAGE_MASK;
175 0f8a249a blueswir1
                    page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
176 0f8a249a blueswir1
                }
177 0f8a249a blueswir1
                break;
178 0f8a249a blueswir1
            case 2: /* L2 PTE */
179 0f8a249a blueswir1
                virt_addr = address & ~0x3ffff;
180 0f8a249a blueswir1
                page_offset = address & 0x3ffff;
181 0f8a249a blueswir1
            }
182 0f8a249a blueswir1
            break;
183 0f8a249a blueswir1
        case 2: /* L1 PTE */
184 0f8a249a blueswir1
            virt_addr = address & ~0xffffff;
185 0f8a249a blueswir1
            page_offset = address & 0xffffff;
186 0f8a249a blueswir1
        }
187 e8af50a3 bellard
    }
188 e8af50a3 bellard
189 e8af50a3 bellard
    /* update page modified and dirty bits */
190 b769d8fe bellard
    is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
191 e8af50a3 bellard
    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
192 0f8a249a blueswir1
        pde |= PG_ACCESSED_MASK;
193 0f8a249a blueswir1
        if (is_dirty)
194 0f8a249a blueswir1
            pde |= PG_MODIFIED_MASK;
195 49be8030 bellard
        stl_phys_notdirty(pde_ptr, pde);
196 e8af50a3 bellard
    }
197 e8af50a3 bellard
    /* check access */
198 e8af50a3 bellard
    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
199 e80cfcfc bellard
    error_code = access_table[*access_index][access_perms];
200 d8e3326c bellard
    if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
201 0f8a249a blueswir1
        return error_code;
202 e8af50a3 bellard
203 e8af50a3 bellard
    /* the page can be put in the TLB */
204 227671c9 bellard
    *prot = perm_table[is_user][access_perms];
205 227671c9 bellard
    if (!(pde & PG_MODIFIED_MASK)) {
206 e8af50a3 bellard
        /* only set write access if already dirty... otherwise wait
207 e8af50a3 bellard
           for dirty access */
208 227671c9 bellard
        *prot &= ~PAGE_WRITE;
209 e8af50a3 bellard
    }
210 e8af50a3 bellard
211 e8af50a3 bellard
    /* Even if large ptes, we map only one 4KB page in the cache to
212 e8af50a3 bellard
       avoid filling it too fast */
213 5dcb6b91 blueswir1
    *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
214 6f7e9aec bellard
    return error_code;
215 e80cfcfc bellard
}
216 e80cfcfc bellard
217 e80cfcfc bellard
/* Perform address translation */
218 af7bf89b bellard
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
219 e80cfcfc bellard
                              int is_user, int is_softmmu)
220 e80cfcfc bellard
{
221 af7bf89b bellard
    target_phys_addr_t paddr;
222 5dcb6b91 blueswir1
    target_ulong vaddr;
223 e80cfcfc bellard
    int error_code = 0, prot, ret = 0, access_index;
224 e8af50a3 bellard
225 e80cfcfc bellard
    error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
226 e80cfcfc bellard
    if (error_code == 0) {
227 0f8a249a blueswir1
        vaddr = address & TARGET_PAGE_MASK;
228 0f8a249a blueswir1
        paddr &= TARGET_PAGE_MASK;
229 9e61bde5 bellard
#ifdef DEBUG_MMU
230 0f8a249a blueswir1
        printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
231 5dcb6b91 blueswir1
               TARGET_FMT_lx "\n", address, paddr, vaddr);
232 9e61bde5 bellard
#endif
233 0f8a249a blueswir1
        ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
234 0f8a249a blueswir1
        return ret;
235 e80cfcfc bellard
    }
236 e8af50a3 bellard
237 e8af50a3 bellard
    if (env->mmuregs[3]) /* Fault status register */
238 0f8a249a blueswir1
        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
239 7483750d bellard
    env->mmuregs[3] |= (access_index << 5) | error_code | 2;
240 e8af50a3 bellard
    env->mmuregs[4] = address; /* Fault address register */
241 e8af50a3 bellard
242 878d3096 bellard
    if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
243 6f7e9aec bellard
        // No fault mode: if a mapping is available, just override
244 6f7e9aec bellard
        // permissions. If no mapping is available, redirect accesses to
245 6f7e9aec bellard
        // neverland. Fake/overridden mappings will be flushed when
246 6f7e9aec bellard
        // switching to normal mode.
247 0f8a249a blueswir1
        vaddr = address & TARGET_PAGE_MASK;
248 227671c9 bellard
        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
249 227671c9 bellard
        ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
250 0f8a249a blueswir1
        return ret;
251 7483750d bellard
    } else {
252 7483750d bellard
        if (rw & 2)
253 7483750d bellard
            env->exception_index = TT_TFAULT;
254 7483750d bellard
        else
255 7483750d bellard
            env->exception_index = TT_DFAULT;
256 7483750d bellard
        return 1;
257 878d3096 bellard
    }
258 e8af50a3 bellard
}
259 24741ef3 bellard
260 24741ef3 bellard
target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
261 24741ef3 bellard
{
262 24741ef3 bellard
    target_phys_addr_t pde_ptr;
263 24741ef3 bellard
    uint32_t pde;
264 24741ef3 bellard
265 24741ef3 bellard
    /* Context base + context number */
266 5dcb6b91 blueswir1
    pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
267 5dcb6b91 blueswir1
        (env->mmuregs[2] << 2);
268 24741ef3 bellard
    pde = ldl_phys(pde_ptr);
269 24741ef3 bellard
270 24741ef3 bellard
    switch (pde & PTE_ENTRYTYPE_MASK) {
271 24741ef3 bellard
    default:
272 24741ef3 bellard
    case 0: /* Invalid */
273 24741ef3 bellard
    case 2: /* PTE, maybe should not happen? */
274 24741ef3 bellard
    case 3: /* Reserved */
275 0f8a249a blueswir1
        return 0;
276 24741ef3 bellard
    case 1: /* L1 PDE */
277 0f8a249a blueswir1
        if (mmulev == 3)
278 0f8a249a blueswir1
            return pde;
279 0f8a249a blueswir1
        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
280 24741ef3 bellard
        pde = ldl_phys(pde_ptr);
281 24741ef3 bellard
282 0f8a249a blueswir1
        switch (pde & PTE_ENTRYTYPE_MASK) {
283 0f8a249a blueswir1
        default:
284 0f8a249a blueswir1
        case 0: /* Invalid */
285 0f8a249a blueswir1
        case 3: /* Reserved */
286 0f8a249a blueswir1
            return 0;
287 0f8a249a blueswir1
        case 2: /* L1 PTE */
288 0f8a249a blueswir1
            return pde;
289 0f8a249a blueswir1
        case 1: /* L2 PDE */
290 0f8a249a blueswir1
            if (mmulev == 2)
291 0f8a249a blueswir1
                return pde;
292 0f8a249a blueswir1
            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
293 24741ef3 bellard
            pde = ldl_phys(pde_ptr);
294 24741ef3 bellard
295 0f8a249a blueswir1
            switch (pde & PTE_ENTRYTYPE_MASK) {
296 0f8a249a blueswir1
            default:
297 0f8a249a blueswir1
            case 0: /* Invalid */
298 0f8a249a blueswir1
            case 3: /* Reserved */
299 0f8a249a blueswir1
                return 0;
300 0f8a249a blueswir1
            case 2: /* L2 PTE */
301 0f8a249a blueswir1
                return pde;
302 0f8a249a blueswir1
            case 1: /* L3 PDE */
303 0f8a249a blueswir1
                if (mmulev == 1)
304 0f8a249a blueswir1
                    return pde;
305 0f8a249a blueswir1
                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
306 24741ef3 bellard
                pde = ldl_phys(pde_ptr);
307 24741ef3 bellard
308 0f8a249a blueswir1
                switch (pde & PTE_ENTRYTYPE_MASK) {
309 0f8a249a blueswir1
                default:
310 0f8a249a blueswir1
                case 0: /* Invalid */
311 0f8a249a blueswir1
                case 1: /* PDE, should not happen */
312 0f8a249a blueswir1
                case 3: /* Reserved */
313 0f8a249a blueswir1
                    return 0;
314 0f8a249a blueswir1
                case 2: /* L3 PTE */
315 0f8a249a blueswir1
                    return pde;
316 0f8a249a blueswir1
                }
317 0f8a249a blueswir1
            }
318 0f8a249a blueswir1
        }
319 24741ef3 bellard
    }
320 24741ef3 bellard
    return 0;
321 24741ef3 bellard
}
322 24741ef3 bellard
323 24741ef3 bellard
#ifdef DEBUG_MMU
324 24741ef3 bellard
void dump_mmu(CPUState *env)
325 24741ef3 bellard
{
326 5dcb6b91 blueswir1
    target_ulong va, va1, va2;
327 5dcb6b91 blueswir1
    unsigned int n, m, o;
328 5dcb6b91 blueswir1
    target_phys_addr_t pde_ptr, pa;
329 24741ef3 bellard
    uint32_t pde;
330 24741ef3 bellard
331 24741ef3 bellard
    printf("MMU dump:\n");
332 24741ef3 bellard
    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
333 24741ef3 bellard
    pde = ldl_phys(pde_ptr);
334 5dcb6b91 blueswir1
    printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
335 5dcb6b91 blueswir1
           (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
336 24741ef3 bellard
    for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
337 0f8a249a blueswir1
        pde = mmu_probe(env, va, 2);
338 0f8a249a blueswir1
        if (pde) {
339 0f8a249a blueswir1
            pa = cpu_get_phys_page_debug(env, va);
340 0f8a249a blueswir1
            printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
341 5dcb6b91 blueswir1
                   " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
342 0f8a249a blueswir1
            for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
343 0f8a249a blueswir1
                pde = mmu_probe(env, va1, 1);
344 0f8a249a blueswir1
                if (pde) {
345 0f8a249a blueswir1
                    pa = cpu_get_phys_page_debug(env, va1);
346 0f8a249a blueswir1
                    printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
347 5dcb6b91 blueswir1
                           " PDE: " TARGET_FMT_lx "\n", va1, pa, pde);
348 0f8a249a blueswir1
                    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
349 0f8a249a blueswir1
                        pde = mmu_probe(env, va2, 0);
350 0f8a249a blueswir1
                        if (pde) {
351 0f8a249a blueswir1
                            pa = cpu_get_phys_page_debug(env, va2);
352 0f8a249a blueswir1
                            printf("  VA: " TARGET_FMT_lx ", PA: "
353 5dcb6b91 blueswir1
                                   TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n",
354 5dcb6b91 blueswir1
                                   va2, pa, pde);
355 0f8a249a blueswir1
                        }
356 0f8a249a blueswir1
                    }
357 0f8a249a blueswir1
                }
358 0f8a249a blueswir1
            }
359 0f8a249a blueswir1
        }
360 24741ef3 bellard
    }
361 24741ef3 bellard
    printf("MMU dump ends\n");
362 24741ef3 bellard
}
363 24741ef3 bellard
#endif /* DEBUG_MMU */
364 24741ef3 bellard
365 24741ef3 bellard
#else /* !TARGET_SPARC64 */
366 83469015 bellard
/*
367 83469015 bellard
 * UltraSparc IIi I/DMMUs
368 83469015 bellard
 */
369 3475187d bellard
static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot,
370 0f8a249a blueswir1
                          int *access_index, target_ulong address, int rw,
371 0f8a249a blueswir1
                          int is_user)
372 3475187d bellard
{
373 3475187d bellard
    target_ulong mask;
374 3475187d bellard
    unsigned int i;
375 3475187d bellard
376 3475187d bellard
    if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
377 0f8a249a blueswir1
        *physical = address;
378 0f8a249a blueswir1
        *prot = PAGE_READ | PAGE_WRITE;
379 3475187d bellard
        return 0;
380 3475187d bellard
    }
381 3475187d bellard
382 3475187d bellard
    for (i = 0; i < 64; i++) {
383 0f8a249a blueswir1
        switch ((env->dtlb_tte[i] >> 61) & 3) {
384 0f8a249a blueswir1
        default:
385 0f8a249a blueswir1
        case 0x0: // 8k
386 0f8a249a blueswir1
            mask = 0xffffffffffffe000ULL;
387 0f8a249a blueswir1
            break;
388 0f8a249a blueswir1
        case 0x1: // 64k
389 0f8a249a blueswir1
            mask = 0xffffffffffff0000ULL;
390 0f8a249a blueswir1
            break;
391 0f8a249a blueswir1
        case 0x2: // 512k
392 0f8a249a blueswir1
            mask = 0xfffffffffff80000ULL;
393 0f8a249a blueswir1
            break;
394 0f8a249a blueswir1
        case 0x3: // 4M
395 0f8a249a blueswir1
            mask = 0xffffffffffc00000ULL;
396 0f8a249a blueswir1
            break;
397 0f8a249a blueswir1
        }
398 0f8a249a blueswir1
        // ctx match, vaddr match?
399 0f8a249a blueswir1
        if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
400 0f8a249a blueswir1
            (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
401 0f8a249a blueswir1
            // valid, access ok?
402 0f8a249a blueswir1
            if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 ||
403 0f8a249a blueswir1
                ((env->dtlb_tte[i] & 0x4) && is_user) ||
404 0f8a249a blueswir1
                (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
405 0f8a249a blueswir1
                if (env->dmmuregs[3]) /* Fault status register */
406 0f8a249a blueswir1
                    env->dmmuregs[3] = 2; /* overflow (not read before another fault) */
407 0f8a249a blueswir1
                env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1;
408 0f8a249a blueswir1
                env->dmmuregs[4] = address; /* Fault address register */
409 0f8a249a blueswir1
                env->exception_index = TT_DFAULT;
410 83469015 bellard
#ifdef DEBUG_MMU
411 0f8a249a blueswir1
                printf("DFAULT at 0x%" PRIx64 "\n", address);
412 83469015 bellard
#endif
413 0f8a249a blueswir1
                return 1;
414 0f8a249a blueswir1
            }
415 0f8a249a blueswir1
            *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
416 0f8a249a blueswir1
            *prot = PAGE_READ;
417 0f8a249a blueswir1
            if (env->dtlb_tte[i] & 0x2)
418 0f8a249a blueswir1
                *prot |= PAGE_WRITE;
419 0f8a249a blueswir1
            return 0;
420 0f8a249a blueswir1
        }
421 3475187d bellard
    }
422 83469015 bellard
#ifdef DEBUG_MMU
423 26a76461 bellard
    printf("DMISS at 0x%" PRIx64 "\n", address);
424 83469015 bellard
#endif
425 83469015 bellard
    env->exception_index = TT_DMISS;
426 3475187d bellard
    return 1;
427 3475187d bellard
}
428 3475187d bellard
429 3475187d bellard
static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot,
430 0f8a249a blueswir1
                          int *access_index, target_ulong address, int rw,
431 0f8a249a blueswir1
                          int is_user)
432 3475187d bellard
{
433 3475187d bellard
    target_ulong mask;
434 3475187d bellard
    unsigned int i;
435 3475187d bellard
436 3475187d bellard
    if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */
437 0f8a249a blueswir1
        *physical = address;
438 0f8a249a blueswir1
        *prot = PAGE_EXEC;
439 3475187d bellard
        return 0;
440 3475187d bellard
    }
441 83469015 bellard
442 3475187d bellard
    for (i = 0; i < 64; i++) {
443 0f8a249a blueswir1
        switch ((env->itlb_tte[i] >> 61) & 3) {
444 0f8a249a blueswir1
        default:
445 0f8a249a blueswir1
        case 0x0: // 8k
446 0f8a249a blueswir1
            mask = 0xffffffffffffe000ULL;
447 0f8a249a blueswir1
            break;
448 0f8a249a blueswir1
        case 0x1: // 64k
449 0f8a249a blueswir1
            mask = 0xffffffffffff0000ULL;
450 0f8a249a blueswir1
            break;
451 0f8a249a blueswir1
        case 0x2: // 512k
452 0f8a249a blueswir1
            mask = 0xfffffffffff80000ULL;
453 0f8a249a blueswir1
            break;
454 0f8a249a blueswir1
        case 0x3: // 4M
455 0f8a249a blueswir1
            mask = 0xffffffffffc00000ULL;
456 0f8a249a blueswir1
                break;
457 0f8a249a blueswir1
        }
458 0f8a249a blueswir1
        // ctx match, vaddr match?
459 0f8a249a blueswir1
        if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
460 0f8a249a blueswir1
            (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
461 0f8a249a blueswir1
            // valid, access ok?
462 0f8a249a blueswir1
            if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 ||
463 0f8a249a blueswir1
                ((env->itlb_tte[i] & 0x4) && is_user)) {
464 0f8a249a blueswir1
                if (env->immuregs[3]) /* Fault status register */
465 0f8a249a blueswir1
                    env->immuregs[3] = 2; /* overflow (not read before another fault) */
466 0f8a249a blueswir1
                env->immuregs[3] |= (is_user << 3) | 1;
467 0f8a249a blueswir1
                env->exception_index = TT_TFAULT;
468 83469015 bellard
#ifdef DEBUG_MMU
469 0f8a249a blueswir1
                printf("TFAULT at 0x%" PRIx64 "\n", address);
470 83469015 bellard
#endif
471 0f8a249a blueswir1
                return 1;
472 0f8a249a blueswir1
            }
473 0f8a249a blueswir1
            *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
474 0f8a249a blueswir1
            *prot = PAGE_EXEC;
475 0f8a249a blueswir1
            return 0;
476 0f8a249a blueswir1
        }
477 3475187d bellard
    }
478 83469015 bellard
#ifdef DEBUG_MMU
479 26a76461 bellard
    printf("TMISS at 0x%" PRIx64 "\n", address);
480 83469015 bellard
#endif
481 83469015 bellard
    env->exception_index = TT_TMISS;
482 3475187d bellard
    return 1;
483 3475187d bellard
}
484 3475187d bellard
485 3475187d bellard
int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot,
486 0f8a249a blueswir1
                          int *access_index, target_ulong address, int rw,
487 0f8a249a blueswir1
                          int is_user)
488 3475187d bellard
{
489 3475187d bellard
    if (rw == 2)
490 0f8a249a blueswir1
        return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user);
491 3475187d bellard
    else
492 0f8a249a blueswir1
        return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user);
493 3475187d bellard
}
494 3475187d bellard
495 3475187d bellard
/* Perform address translation */
496 3475187d bellard
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
497 3475187d bellard
                              int is_user, int is_softmmu)
498 3475187d bellard
{
499 83469015 bellard
    target_ulong virt_addr, vaddr;
500 3475187d bellard
    target_phys_addr_t paddr;
501 3475187d bellard
    int error_code = 0, prot, ret = 0, access_index;
502 3475187d bellard
503 3475187d bellard
    error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
504 3475187d bellard
    if (error_code == 0) {
505 0f8a249a blueswir1
        virt_addr = address & TARGET_PAGE_MASK;
506 0f8a249a blueswir1
        vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
507 83469015 bellard
#ifdef DEBUG_MMU
508 0f8a249a blueswir1
        printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 "\n", address, paddr, vaddr);
509 83469015 bellard
#endif
510 0f8a249a blueswir1
        ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
511 0f8a249a blueswir1
        return ret;
512 3475187d bellard
    }
513 3475187d bellard
    // XXX
514 3475187d bellard
    return 1;
515 3475187d bellard
}
516 3475187d bellard
517 83469015 bellard
#ifdef DEBUG_MMU
518 83469015 bellard
void dump_mmu(CPUState *env)
519 83469015 bellard
{
520 83469015 bellard
    unsigned int i;
521 83469015 bellard
    const char *mask;
522 83469015 bellard
523 26a76461 bellard
    printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n", env->dmmuregs[1], env->dmmuregs[2]);
524 83469015 bellard
    if ((env->lsu & DMMU_E) == 0) {
525 0f8a249a blueswir1
        printf("DMMU disabled\n");
526 83469015 bellard
    } else {
527 0f8a249a blueswir1
        printf("DMMU dump:\n");
528 0f8a249a blueswir1
        for (i = 0; i < 64; i++) {
529 0f8a249a blueswir1
            switch ((env->dtlb_tte[i] >> 61) & 3) {
530 0f8a249a blueswir1
            default:
531 0f8a249a blueswir1
            case 0x0:
532 0f8a249a blueswir1
                mask = "  8k";
533 0f8a249a blueswir1
                break;
534 0f8a249a blueswir1
            case 0x1:
535 0f8a249a blueswir1
                mask = " 64k";
536 0f8a249a blueswir1
                break;
537 0f8a249a blueswir1
            case 0x2:
538 0f8a249a blueswir1
                mask = "512k";
539 0f8a249a blueswir1
                break;
540 0f8a249a blueswir1
            case 0x3:
541 0f8a249a blueswir1
                mask = "  4M";
542 0f8a249a blueswir1
                break;
543 0f8a249a blueswir1
            }
544 0f8a249a blueswir1
            if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
545 0f8a249a blueswir1
                printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %" PRId64 "\n",
546 0f8a249a blueswir1
                       env->dtlb_tag[i] & ~0x1fffULL,
547 0f8a249a blueswir1
                       env->dtlb_tte[i] & 0x1ffffffe000ULL,
548 0f8a249a blueswir1
                       mask,
549 0f8a249a blueswir1
                       env->dtlb_tte[i] & 0x4? "priv": "user",
550 0f8a249a blueswir1
                       env->dtlb_tte[i] & 0x2? "RW": "RO",
551 0f8a249a blueswir1
                       env->dtlb_tte[i] & 0x40? "locked": "unlocked",
552 0f8a249a blueswir1
                       env->dtlb_tag[i] & 0x1fffULL);
553 0f8a249a blueswir1
            }
554 0f8a249a blueswir1
        }
555 83469015 bellard
    }
556 83469015 bellard
    if ((env->lsu & IMMU_E) == 0) {
557 0f8a249a blueswir1
        printf("IMMU disabled\n");
558 83469015 bellard
    } else {
559 0f8a249a blueswir1
        printf("IMMU dump:\n");
560 0f8a249a blueswir1
        for (i = 0; i < 64; i++) {
561 0f8a249a blueswir1
            switch ((env->itlb_tte[i] >> 61) & 3) {
562 0f8a249a blueswir1
            default:
563 0f8a249a blueswir1
            case 0x0:
564 0f8a249a blueswir1
                mask = "  8k";
565 0f8a249a blueswir1
                break;
566 0f8a249a blueswir1
            case 0x1:
567 0f8a249a blueswir1
                mask = " 64k";
568 0f8a249a blueswir1
                break;
569 0f8a249a blueswir1
            case 0x2:
570 0f8a249a blueswir1
                mask = "512k";
571 0f8a249a blueswir1
                break;
572 0f8a249a blueswir1
            case 0x3:
573 0f8a249a blueswir1
                mask = "  4M";
574 0f8a249a blueswir1
                break;
575 0f8a249a blueswir1
            }
576 0f8a249a blueswir1
            if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
577 0f8a249a blueswir1
                printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %" PRId64 "\n",
578 0f8a249a blueswir1
                       env->itlb_tag[i] & ~0x1fffULL,
579 0f8a249a blueswir1
                       env->itlb_tte[i] & 0x1ffffffe000ULL,
580 0f8a249a blueswir1
                       mask,
581 0f8a249a blueswir1
                       env->itlb_tte[i] & 0x4? "priv": "user",
582 0f8a249a blueswir1
                       env->itlb_tte[i] & 0x40? "locked": "unlocked",
583 0f8a249a blueswir1
                       env->itlb_tag[i] & 0x1fffULL);
584 0f8a249a blueswir1
            }
585 0f8a249a blueswir1
        }
586 83469015 bellard
    }
587 83469015 bellard
}
588 24741ef3 bellard
#endif /* DEBUG_MMU */
589 24741ef3 bellard
590 24741ef3 bellard
#endif /* TARGET_SPARC64 */
591 24741ef3 bellard
#endif /* !CONFIG_USER_ONLY */
592 24741ef3 bellard
593 24741ef3 bellard
void memcpy32(target_ulong *dst, const target_ulong *src)
594 24741ef3 bellard
{
595 24741ef3 bellard
    dst[0] = src[0];
596 24741ef3 bellard
    dst[1] = src[1];
597 24741ef3 bellard
    dst[2] = src[2];
598 24741ef3 bellard
    dst[3] = src[3];
599 24741ef3 bellard
    dst[4] = src[4];
600 24741ef3 bellard
    dst[5] = src[5];
601 24741ef3 bellard
    dst[6] = src[6];
602 24741ef3 bellard
    dst[7] = src[7];
603 24741ef3 bellard
}