Statistics
| Branch: | Revision:

root / target-sparc / helper.c @ b769d8fe

History | View | Annotate | Download (9.2 kB)

1 e8af50a3 bellard
/*
2 e8af50a3 bellard
 *  sparc helpers
3 e8af50a3 bellard
 * 
4 e8af50a3 bellard
 *  Copyright (c) 2003 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 e8af50a3 bellard
#include "exec.h"
21 e8af50a3 bellard
22 e8af50a3 bellard
#define DEBUG_PCALL
23 e8af50a3 bellard
24 e8af50a3 bellard
#if 0
25 e8af50a3 bellard
#define raise_exception_err(a, b)\
26 e8af50a3 bellard
do {\
27 e8af50a3 bellard
    fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
28 e8af50a3 bellard
    (raise_exception_err)(a, b);\
29 e8af50a3 bellard
} while (0)
30 e8af50a3 bellard
#endif
31 e8af50a3 bellard
32 e8af50a3 bellard
/* Sparc MMU emulation */
33 e8af50a3 bellard
int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
34 e8af50a3 bellard
                              int is_user, int is_softmmu);
35 e8af50a3 bellard
36 e8af50a3 bellard
37 e8af50a3 bellard
/* thread support */
38 e8af50a3 bellard
39 e8af50a3 bellard
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
40 e8af50a3 bellard
41 e8af50a3 bellard
void cpu_lock(void)
42 e8af50a3 bellard
{
43 e8af50a3 bellard
    spin_lock(&global_cpu_lock);
44 e8af50a3 bellard
}
45 e8af50a3 bellard
46 e8af50a3 bellard
void cpu_unlock(void)
47 e8af50a3 bellard
{
48 e8af50a3 bellard
    spin_unlock(&global_cpu_lock);
49 e8af50a3 bellard
}
50 e8af50a3 bellard
51 e8af50a3 bellard
#if 0
52 e8af50a3 bellard
void cpu_loop_exit(void)
53 e8af50a3 bellard
{
54 e8af50a3 bellard
    /* NOTE: the register at this point must be saved by hand because
55 e8af50a3 bellard
       longjmp restore them */
56 e8af50a3 bellard
    longjmp(env->jmp_env, 1);
57 e8af50a3 bellard
}
58 e8af50a3 bellard
#endif
59 e8af50a3 bellard
60 e8af50a3 bellard
#if !defined(CONFIG_USER_ONLY) 
61 e8af50a3 bellard
62 e8af50a3 bellard
#define MMUSUFFIX _mmu
63 e8af50a3 bellard
#define GETPC() (__builtin_return_address(0))
64 e8af50a3 bellard
65 e8af50a3 bellard
#define SHIFT 0
66 e8af50a3 bellard
#include "softmmu_template.h"
67 e8af50a3 bellard
68 e8af50a3 bellard
#define SHIFT 1
69 e8af50a3 bellard
#include "softmmu_template.h"
70 e8af50a3 bellard
71 e8af50a3 bellard
#define SHIFT 2
72 e8af50a3 bellard
#include "softmmu_template.h"
73 e8af50a3 bellard
74 e8af50a3 bellard
#define SHIFT 3
75 e8af50a3 bellard
#include "softmmu_template.h"
76 e8af50a3 bellard
77 e8af50a3 bellard
78 e8af50a3 bellard
/* try to fill the TLB and return an exception if error. If retaddr is
79 e8af50a3 bellard
   NULL, it means that the function was called in C code (i.e. not
80 e8af50a3 bellard
   from generated code or from helper.c) */
81 e8af50a3 bellard
/* XXX: fix it to restore all registers */
82 e8af50a3 bellard
void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
83 e8af50a3 bellard
{
84 e8af50a3 bellard
    TranslationBlock *tb;
85 e8af50a3 bellard
    int ret;
86 e8af50a3 bellard
    unsigned long pc;
87 e8af50a3 bellard
    CPUState *saved_env;
88 e8af50a3 bellard
89 e8af50a3 bellard
    /* XXX: hack to restore env in all cases, even if not called from
90 e8af50a3 bellard
       generated code */
91 e8af50a3 bellard
    saved_env = env;
92 e8af50a3 bellard
    env = cpu_single_env;
93 e8af50a3 bellard
94 e8af50a3 bellard
    ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1);
95 e8af50a3 bellard
    if (ret) {
96 e8af50a3 bellard
        if (retaddr) {
97 e8af50a3 bellard
            /* now we have a real cpu fault */
98 e8af50a3 bellard
            pc = (unsigned long)retaddr;
99 e8af50a3 bellard
            tb = tb_find_pc(pc);
100 e8af50a3 bellard
            if (tb) {
101 e8af50a3 bellard
                /* the PC is inside the translated code. It means that we have
102 e8af50a3 bellard
                   a virtual CPU fault */
103 e8af50a3 bellard
                cpu_restore_state(tb, env, pc, NULL);
104 e8af50a3 bellard
            }
105 e8af50a3 bellard
        }
106 e8af50a3 bellard
        raise_exception_err(ret, env->error_code);
107 e8af50a3 bellard
    }
108 e8af50a3 bellard
    env = saved_env;
109 e8af50a3 bellard
}
110 e8af50a3 bellard
#endif
111 e8af50a3 bellard
112 e8af50a3 bellard
static const int access_table[8][8] = {
113 e8af50a3 bellard
    { 0, 0, 0, 0, 2, 0, 3, 3 },
114 e8af50a3 bellard
    { 0, 0, 0, 0, 2, 0, 0, 0 },
115 e8af50a3 bellard
    { 2, 2, 0, 0, 0, 2, 3, 3 },
116 e8af50a3 bellard
    { 2, 2, 0, 0, 0, 2, 0, 0 },
117 e8af50a3 bellard
    { 2, 0, 2, 0, 2, 2, 3, 3 },
118 e8af50a3 bellard
    { 2, 0, 2, 0, 2, 0, 2, 0 },
119 e8af50a3 bellard
    { 2, 2, 2, 0, 2, 2, 3, 3 },
120 e8af50a3 bellard
    { 2, 2, 2, 0, 2, 2, 2, 0 }
121 e8af50a3 bellard
};
122 e8af50a3 bellard
123 e8af50a3 bellard
/* 1 = write OK */
124 e8af50a3 bellard
static const int rw_table[2][8] = {
125 e8af50a3 bellard
    { 0, 1, 0, 1, 0, 1, 0, 1 },
126 e8af50a3 bellard
    { 0, 1, 0, 1, 0, 0, 0, 0 }
127 e8af50a3 bellard
};
128 e8af50a3 bellard
129 e8af50a3 bellard
130 e8af50a3 bellard
/* Perform address translation */
131 e8af50a3 bellard
int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
132 e8af50a3 bellard
                              int is_user, int is_softmmu)
133 e8af50a3 bellard
{
134 e8af50a3 bellard
    int exception = 0;
135 b769d8fe bellard
    int access_perms = 0, access_index = 0;
136 e8af50a3 bellard
    uint8_t *pde_ptr;
137 e8af50a3 bellard
    uint32_t pde, virt_addr;
138 e8af50a3 bellard
    int error_code = 0, is_dirty, prot, ret = 0;
139 e8af50a3 bellard
    unsigned long paddr, vaddr, page_offset;
140 e8af50a3 bellard
141 e8af50a3 bellard
    if (env->user_mode_only) {
142 e8af50a3 bellard
        /* user mode only emulation */
143 e8af50a3 bellard
        ret = -2;
144 e8af50a3 bellard
        goto do_fault;
145 e8af50a3 bellard
    }
146 e8af50a3 bellard
147 e8af50a3 bellard
    virt_addr = address & TARGET_PAGE_MASK;
148 e8af50a3 bellard
    if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
149 e8af50a3 bellard
        paddr = address;
150 e8af50a3 bellard
        page_offset = address & (TARGET_PAGE_SIZE - 1);
151 e8af50a3 bellard
        prot = PAGE_READ | PAGE_WRITE;
152 e8af50a3 bellard
        goto do_mapping;
153 e8af50a3 bellard
    }
154 e8af50a3 bellard
155 e8af50a3 bellard
    /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
156 e8af50a3 bellard
    /* Context base + context number */
157 e8af50a3 bellard
    pde_ptr = phys_ram_base + (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
158 e8af50a3 bellard
    pde = ldl_raw(pde_ptr);
159 e8af50a3 bellard
160 e8af50a3 bellard
    /* Ctx pde */
161 e8af50a3 bellard
    switch (pde & PTE_ENTRYTYPE_MASK) {
162 e8af50a3 bellard
    case 0: /* Invalid */
163 e8af50a3 bellard
        error_code = 1;
164 e8af50a3 bellard
        goto do_fault;
165 e8af50a3 bellard
    case 2: /* PTE, maybe should not happen? */
166 e8af50a3 bellard
    case 3: /* Reserved */
167 e8af50a3 bellard
        error_code = 4;
168 e8af50a3 bellard
        goto do_fault;
169 e8af50a3 bellard
    case 1: /* L1 PDE */
170 e8af50a3 bellard
        pde_ptr = phys_ram_base + ((address >> 22) & ~3) + ((pde & ~3) << 4);
171 e8af50a3 bellard
        pde = ldl_raw(pde_ptr);
172 e8af50a3 bellard
173 e8af50a3 bellard
        switch (pde & PTE_ENTRYTYPE_MASK) {
174 e8af50a3 bellard
        case 0: /* Invalid */
175 e8af50a3 bellard
            error_code = 1;
176 e8af50a3 bellard
            goto do_fault;
177 e8af50a3 bellard
        case 3: /* Reserved */
178 e8af50a3 bellard
            error_code = 4;
179 e8af50a3 bellard
            goto do_fault;
180 e8af50a3 bellard
        case 1: /* L2 PDE */
181 e8af50a3 bellard
            pde_ptr = phys_ram_base + ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
182 e8af50a3 bellard
            pde = ldl_raw(pde_ptr);
183 e8af50a3 bellard
184 e8af50a3 bellard
            switch (pde & PTE_ENTRYTYPE_MASK) {
185 e8af50a3 bellard
            case 0: /* Invalid */
186 e8af50a3 bellard
                error_code = 1;
187 e8af50a3 bellard
                goto do_fault;
188 e8af50a3 bellard
            case 3: /* Reserved */
189 e8af50a3 bellard
                error_code = 4;
190 e8af50a3 bellard
                goto do_fault;
191 e8af50a3 bellard
            case 1: /* L3 PDE */
192 e8af50a3 bellard
                pde_ptr = phys_ram_base + ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
193 e8af50a3 bellard
                pde = ldl_raw(pde_ptr);
194 e8af50a3 bellard
195 e8af50a3 bellard
                switch (pde & PTE_ENTRYTYPE_MASK) {
196 e8af50a3 bellard
                case 0: /* Invalid */
197 e8af50a3 bellard
                    error_code = 1;
198 e8af50a3 bellard
                    goto do_fault;
199 e8af50a3 bellard
                case 1: /* PDE, should not happen */
200 e8af50a3 bellard
                case 3: /* Reserved */
201 e8af50a3 bellard
                    error_code = 4;
202 e8af50a3 bellard
                    goto do_fault;
203 e8af50a3 bellard
                case 2: /* L3 PTE */
204 e8af50a3 bellard
                    virt_addr = address & TARGET_PAGE_MASK;
205 e8af50a3 bellard
                    page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
206 e8af50a3 bellard
                }
207 e8af50a3 bellard
                break;
208 e8af50a3 bellard
            case 2: /* L2 PTE */
209 e8af50a3 bellard
                virt_addr = address & ~0x3ffff;
210 e8af50a3 bellard
                page_offset = address & 0x3ffff;
211 e8af50a3 bellard
            }
212 e8af50a3 bellard
            break;
213 e8af50a3 bellard
        case 2: /* L1 PTE */
214 e8af50a3 bellard
            virt_addr = address & ~0xffffff;
215 e8af50a3 bellard
            page_offset = address & 0xffffff;
216 e8af50a3 bellard
        }
217 e8af50a3 bellard
    }
218 e8af50a3 bellard
219 e8af50a3 bellard
    /* update page modified and dirty bits */
220 b769d8fe bellard
    is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
221 e8af50a3 bellard
    if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
222 e8af50a3 bellard
        pde |= PG_ACCESSED_MASK;
223 e8af50a3 bellard
        if (is_dirty)
224 e8af50a3 bellard
            pde |= PG_MODIFIED_MASK;
225 e8af50a3 bellard
        stl_raw(pde_ptr, pde);
226 e8af50a3 bellard
    }
227 e8af50a3 bellard
228 e8af50a3 bellard
    /* check access */
229 b769d8fe bellard
    access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
230 e8af50a3 bellard
    access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
231 e8af50a3 bellard
    error_code = access_table[access_index][access_perms];
232 e8af50a3 bellard
    if (error_code)
233 e8af50a3 bellard
        goto do_fault;
234 e8af50a3 bellard
235 e8af50a3 bellard
    /* the page can be put in the TLB */
236 e8af50a3 bellard
    prot = PAGE_READ;
237 e8af50a3 bellard
    if (pde & PG_MODIFIED_MASK) {
238 e8af50a3 bellard
        /* only set write access if already dirty... otherwise wait
239 e8af50a3 bellard
           for dirty access */
240 e8af50a3 bellard
        if (rw_table[is_user][access_perms])
241 e8af50a3 bellard
                prot |= PAGE_WRITE;
242 e8af50a3 bellard
    }
243 e8af50a3 bellard
244 e8af50a3 bellard
    /* Even if large ptes, we map only one 4KB page in the cache to
245 e8af50a3 bellard
       avoid filling it too fast */
246 e8af50a3 bellard
    virt_addr = address & TARGET_PAGE_MASK;
247 e8af50a3 bellard
    paddr = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
248 e8af50a3 bellard
249 e8af50a3 bellard
 do_mapping:
250 e8af50a3 bellard
    vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
251 e8af50a3 bellard
252 e8af50a3 bellard
    ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
253 e8af50a3 bellard
    return ret;
254 e8af50a3 bellard
255 e8af50a3 bellard
 do_fault:
256 e8af50a3 bellard
    if (env->mmuregs[3]) /* Fault status register */
257 e8af50a3 bellard
        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
258 e8af50a3 bellard
    env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2;
259 e8af50a3 bellard
    env->mmuregs[4] = address; /* Fault address register */
260 e8af50a3 bellard
261 e8af50a3 bellard
    if (env->mmuregs[0] & MMU_NF) // No fault
262 e8af50a3 bellard
        return 0;
263 e8af50a3 bellard
264 e8af50a3 bellard
    env->exception_index = exception;
265 e8af50a3 bellard
    env->error_code = error_code;
266 e8af50a3 bellard
    return error_code;
267 e8af50a3 bellard
}
268 e8af50a3 bellard
269 e8af50a3 bellard
void memcpy32(uint32_t *dst, const uint32_t *src)
270 e8af50a3 bellard
{
271 e8af50a3 bellard
    dst[0] = src[0];
272 e8af50a3 bellard
    dst[1] = src[1];
273 e8af50a3 bellard
    dst[2] = src[2];
274 e8af50a3 bellard
    dst[3] = src[3];
275 e8af50a3 bellard
    dst[4] = src[4];
276 e8af50a3 bellard
    dst[5] = src[5];
277 e8af50a3 bellard
    dst[6] = src[6];
278 e8af50a3 bellard
    dst[7] = src[7];
279 e8af50a3 bellard
}
280 e8af50a3 bellard
281 e8af50a3 bellard
void set_cwp(int new_cwp)
282 e8af50a3 bellard
{
283 e8af50a3 bellard
    /* put the modified wrap registers at their proper location */
284 e8af50a3 bellard
    if (env->cwp == (NWINDOWS - 1))
285 e8af50a3 bellard
        memcpy32(env->regbase, env->regbase + NWINDOWS * 16);
286 e8af50a3 bellard
    env->cwp = new_cwp;
287 e8af50a3 bellard
    /* put the wrap registers at their temporary location */
288 e8af50a3 bellard
    if (new_cwp == (NWINDOWS - 1))
289 e8af50a3 bellard
        memcpy32(env->regbase + NWINDOWS * 16, env->regbase);
290 e8af50a3 bellard
    env->regwptr = env->regbase + (new_cwp * 16);
291 e8af50a3 bellard
}
292 e8af50a3 bellard
293 e8af50a3 bellard
/*
294 e8af50a3 bellard
 * Begin execution of an interruption. is_int is TRUE if coming from
295 e8af50a3 bellard
 * the int instruction. next_eip is the EIP value AFTER the interrupt
296 e8af50a3 bellard
 * instruction. It is only relevant if is_int is TRUE.  
297 e8af50a3 bellard
 */
298 e8af50a3 bellard
void do_interrupt(int intno, int is_int, int error_code, 
299 e8af50a3 bellard
                  unsigned int next_eip, int is_hw)
300 e8af50a3 bellard
{
301 e8af50a3 bellard
    int cwp;
302 e8af50a3 bellard
303 e8af50a3 bellard
#ifdef DEBUG_PCALL
304 e8af50a3 bellard
    if (loglevel & CPU_LOG_INT) {
305 e8af50a3 bellard
        static int count;
306 e8af50a3 bellard
        fprintf(logfile, "%6d: v=%02x e=%04x i=%d pc=%08x npc=%08x SP=%08x\n",
307 e8af50a3 bellard
                    count, intno, error_code, is_int,
308 e8af50a3 bellard
                    env->pc,
309 e8af50a3 bellard
                    env->npc, env->gregs[7]);
310 e8af50a3 bellard
#if 0
311 e8af50a3 bellard
        cpu_sparc_dump_state(env, logfile, 0);
312 e8af50a3 bellard
        {
313 e8af50a3 bellard
            int i;
314 e8af50a3 bellard
            uint8_t *ptr;
315 e8af50a3 bellard
            fprintf(logfile, "       code=");
316 e8af50a3 bellard
            ptr = env->pc;
317 e8af50a3 bellard
            for(i = 0; i < 16; i++) {
318 e8af50a3 bellard
                fprintf(logfile, " %02x", ldub(ptr + i));
319 e8af50a3 bellard
            }
320 e8af50a3 bellard
            fprintf(logfile, "\n");
321 e8af50a3 bellard
        }
322 e8af50a3 bellard
#endif
323 e8af50a3 bellard
        count++;
324 e8af50a3 bellard
    }
325 e8af50a3 bellard
#endif
326 e8af50a3 bellard
    env->psret = 0;
327 e8af50a3 bellard
    cwp = (env->cwp - 1) & (NWINDOWS - 1); 
328 e8af50a3 bellard
    set_cwp(cwp);
329 e8af50a3 bellard
    env->regwptr[9] = env->pc;
330 e8af50a3 bellard
    env->regwptr[10] = env->npc;
331 e8af50a3 bellard
    env->psrps = env->psrs;
332 e8af50a3 bellard
    env->psrs = 1;
333 e8af50a3 bellard
    env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
334 e8af50a3 bellard
    env->pc = env->tbr;
335 e8af50a3 bellard
    env->npc = env->pc + 4;
336 e8af50a3 bellard
    env->exception_index = 0;
337 e8af50a3 bellard
}
338 e8af50a3 bellard
339 e8af50a3 bellard
void raise_exception_err(int exception_index, int error_code)
340 e8af50a3 bellard
{
341 e8af50a3 bellard
    raise_exception(exception_index);
342 e8af50a3 bellard
}