Statistics
| Branch: | Revision:

root / target-sparc / helper.c @ ff07ec83

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