Statistics
| Branch: | Revision:

root / target-mips / helper.c @ fad6cb1a

History | View | Annotate | Download (20.9 kB)

1 6af0bf9c bellard
/*
2 6af0bf9c bellard
 *  MIPS emulation helpers for qemu.
3 5fafdf24 ths
 *
4 6af0bf9c bellard
 *  Copyright (c) 2004-2005 Jocelyn Mayer
5 6af0bf9c bellard
 *
6 6af0bf9c bellard
 * This library is free software; you can redistribute it and/or
7 6af0bf9c bellard
 * modify it under the terms of the GNU Lesser General Public
8 6af0bf9c bellard
 * License as published by the Free Software Foundation; either
9 6af0bf9c bellard
 * version 2 of the License, or (at your option) any later version.
10 6af0bf9c bellard
 *
11 6af0bf9c bellard
 * This library is distributed in the hope that it will be useful,
12 6af0bf9c bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 6af0bf9c bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 6af0bf9c bellard
 * Lesser General Public License for more details.
15 6af0bf9c bellard
 *
16 6af0bf9c bellard
 * You should have received a copy of the GNU Lesser General Public
17 6af0bf9c bellard
 * License along with this library; if not, write to the Free Software
18 fad6cb1a aurel32
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
19 6af0bf9c bellard
 */
20 e37e863f bellard
#include <stdarg.h>
21 e37e863f bellard
#include <stdlib.h>
22 e37e863f bellard
#include <stdio.h>
23 e37e863f bellard
#include <string.h>
24 e37e863f bellard
#include <inttypes.h>
25 e37e863f bellard
#include <signal.h>
26 e37e863f bellard
#include <assert.h>
27 e37e863f bellard
28 e37e863f bellard
#include "cpu.h"
29 e37e863f bellard
#include "exec-all.h"
30 6af0bf9c bellard
31 43057ab1 bellard
enum {
32 43057ab1 bellard
    TLBRET_DIRTY = -4,
33 43057ab1 bellard
    TLBRET_INVALID = -3,
34 43057ab1 bellard
    TLBRET_NOMATCH = -2,
35 43057ab1 bellard
    TLBRET_BADADDR = -1,
36 43057ab1 bellard
    TLBRET_MATCH = 0
37 43057ab1 bellard
};
38 43057ab1 bellard
39 29929e34 ths
/* no MMU emulation */
40 29929e34 ths
int no_mmu_map_address (CPUState *env, target_ulong *physical, int *prot,
41 6af0bf9c bellard
                        target_ulong address, int rw, int access_type)
42 6af0bf9c bellard
{
43 29929e34 ths
    *physical = address;
44 29929e34 ths
    *prot = PAGE_READ | PAGE_WRITE;
45 29929e34 ths
    return TLBRET_MATCH;
46 29929e34 ths
}
47 29929e34 ths
48 29929e34 ths
/* fixed mapping MMU emulation */
49 29929e34 ths
int fixed_mmu_map_address (CPUState *env, target_ulong *physical, int *prot,
50 29929e34 ths
                           target_ulong address, int rw, int access_type)
51 29929e34 ths
{
52 29929e34 ths
    if (address <= (int32_t)0x7FFFFFFFUL) {
53 29929e34 ths
        if (!(env->CP0_Status & (1 << CP0St_ERL)))
54 29929e34 ths
            *physical = address + 0x40000000UL;
55 29929e34 ths
        else
56 29929e34 ths
            *physical = address;
57 29929e34 ths
    } else if (address <= (int32_t)0xBFFFFFFFUL)
58 29929e34 ths
        *physical = address & 0x1FFFFFFF;
59 29929e34 ths
    else
60 29929e34 ths
        *physical = address;
61 29929e34 ths
62 29929e34 ths
    *prot = PAGE_READ | PAGE_WRITE;
63 29929e34 ths
    return TLBRET_MATCH;
64 29929e34 ths
}
65 29929e34 ths
66 29929e34 ths
/* MIPS32/MIPS64 R4000-style MMU emulation */
67 29929e34 ths
int r4k_map_address (CPUState *env, target_ulong *physical, int *prot,
68 29929e34 ths
                     target_ulong address, int rw, int access_type)
69 29929e34 ths
{
70 925fd0f2 ths
    uint8_t ASID = env->CP0_EntryHi & 0xFF;
71 3b1c8be4 ths
    int i;
72 6af0bf9c bellard
73 ead9360e ths
    for (i = 0; i < env->tlb->tlb_in_use; i++) {
74 ead9360e ths
        r4k_tlb_t *tlb = &env->tlb->mmu.r4k.tlb[i];
75 3b1c8be4 ths
        /* 1k pages are not supported. */
76 f2e9ebef ths
        target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
77 3b1c8be4 ths
        target_ulong tag = address & ~mask;
78 f2e9ebef ths
        target_ulong VPN = tlb->VPN & ~mask;
79 d26bc211 ths
#if defined(TARGET_MIPS64)
80 e034e2c3 ths
        tag &= env->SEGMask;
81 100ce988 ths
#endif
82 3b1c8be4 ths
83 6af0bf9c bellard
        /* Check ASID, virtual page number & size */
84 f2e9ebef ths
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
85 6af0bf9c bellard
            /* TLB match */
86 f2e9ebef ths
            int n = !!(address & mask & ~(mask >> 1));
87 6af0bf9c bellard
            /* Check access rights */
88 f2e9ebef ths
            if (!(n ? tlb->V1 : tlb->V0))
89 43057ab1 bellard
                return TLBRET_INVALID;
90 f2e9ebef ths
            if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
91 3b1c8be4 ths
                *physical = tlb->PFN[n] | (address & (mask >> 1));
92 9fb63ac2 bellard
                *prot = PAGE_READ;
93 98c1b82b pbrook
                if (n ? tlb->D1 : tlb->D0)
94 9fb63ac2 bellard
                    *prot |= PAGE_WRITE;
95 43057ab1 bellard
                return TLBRET_MATCH;
96 6af0bf9c bellard
            }
97 43057ab1 bellard
            return TLBRET_DIRTY;
98 6af0bf9c bellard
        }
99 6af0bf9c bellard
    }
100 43057ab1 bellard
    return TLBRET_NOMATCH;
101 6af0bf9c bellard
}
102 6af0bf9c bellard
103 43057ab1 bellard
static int get_physical_address (CPUState *env, target_ulong *physical,
104 43057ab1 bellard
                                int *prot, target_ulong address,
105 43057ab1 bellard
                                int rw, int access_type)
106 6af0bf9c bellard
{
107 b4ab4b4e ths
    /* User mode can only access useg/xuseg */
108 43057ab1 bellard
    int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
109 671880e6 ths
    int supervisor_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_SM;
110 671880e6 ths
    int kernel_mode = !user_mode && !supervisor_mode;
111 d26bc211 ths
#if defined(TARGET_MIPS64)
112 b4ab4b4e ths
    int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
113 b4ab4b4e ths
    int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
114 b4ab4b4e ths
    int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
115 b4ab4b4e ths
#endif
116 43057ab1 bellard
    int ret = TLBRET_MATCH;
117 43057ab1 bellard
118 6af0bf9c bellard
#if 0
119 6af0bf9c bellard
    if (logfile) {
120 6af0bf9c bellard
        fprintf(logfile, "user mode %d h %08x\n",
121 6af0bf9c bellard
                user_mode, env->hflags);
122 6af0bf9c bellard
    }
123 6af0bf9c bellard
#endif
124 b4ab4b4e ths
125 b4ab4b4e ths
    if (address <= (int32_t)0x7FFFFFFFUL) {
126 b4ab4b4e ths
        /* useg */
127 996ba2cc ths
        if (env->CP0_Status & (1 << CP0St_ERL)) {
128 29929e34 ths
            *physical = address & 0xFFFFFFFF;
129 6af0bf9c bellard
            *prot = PAGE_READ | PAGE_WRITE;
130 996ba2cc ths
        } else {
131 ead9360e ths
            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
132 6af0bf9c bellard
        }
133 d26bc211 ths
#if defined(TARGET_MIPS64)
134 89fc88da ths
    } else if (address < 0x4000000000000000ULL) {
135 b4ab4b4e ths
        /* xuseg */
136 67d6abff ths
        if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) {
137 ead9360e ths
            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
138 b4ab4b4e ths
        } else {
139 b4ab4b4e ths
            ret = TLBRET_BADADDR;
140 b4ab4b4e ths
        }
141 89fc88da ths
    } else if (address < 0x8000000000000000ULL) {
142 b4ab4b4e ths
        /* xsseg */
143 671880e6 ths
        if ((supervisor_mode || kernel_mode) &&
144 67d6abff ths
            SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) {
145 ead9360e ths
            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
146 b4ab4b4e ths
        } else {
147 b4ab4b4e ths
            ret = TLBRET_BADADDR;
148 b4ab4b4e ths
        }
149 89fc88da ths
    } else if (address < 0xC000000000000000ULL) {
150 b4ab4b4e ths
        /* xkphys */
151 671880e6 ths
        if (kernel_mode && KX &&
152 6d35524c ths
            (address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) {
153 6d35524c ths
            *physical = address & env->PAMask;
154 b4ab4b4e ths
            *prot = PAGE_READ | PAGE_WRITE;
155 b4ab4b4e ths
        } else {
156 b4ab4b4e ths
            ret = TLBRET_BADADDR;
157 b4ab4b4e ths
        }
158 89fc88da ths
    } else if (address < 0xFFFFFFFF80000000ULL) {
159 b4ab4b4e ths
        /* xkseg */
160 671880e6 ths
        if (kernel_mode && KX &&
161 67d6abff ths
            address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) {
162 ead9360e ths
            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
163 b4ab4b4e ths
        } else {
164 b4ab4b4e ths
            ret = TLBRET_BADADDR;
165 b4ab4b4e ths
        }
166 b4ab4b4e ths
#endif
167 5dc4b744 ths
    } else if (address < (int32_t)0xA0000000UL) {
168 6af0bf9c bellard
        /* kseg0 */
169 671880e6 ths
        if (kernel_mode) {
170 671880e6 ths
            *physical = address - (int32_t)0x80000000UL;
171 671880e6 ths
            *prot = PAGE_READ | PAGE_WRITE;
172 671880e6 ths
        } else {
173 671880e6 ths
            ret = TLBRET_BADADDR;
174 671880e6 ths
        }
175 5dc4b744 ths
    } else if (address < (int32_t)0xC0000000UL) {
176 6af0bf9c bellard
        /* kseg1 */
177 671880e6 ths
        if (kernel_mode) {
178 671880e6 ths
            *physical = address - (int32_t)0xA0000000UL;
179 671880e6 ths
            *prot = PAGE_READ | PAGE_WRITE;
180 671880e6 ths
        } else {
181 671880e6 ths
            ret = TLBRET_BADADDR;
182 671880e6 ths
        }
183 5dc4b744 ths
    } else if (address < (int32_t)0xE0000000UL) {
184 89fc88da ths
        /* sseg (kseg2) */
185 671880e6 ths
        if (supervisor_mode || kernel_mode) {
186 671880e6 ths
            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
187 671880e6 ths
        } else {
188 671880e6 ths
            ret = TLBRET_BADADDR;
189 671880e6 ths
        }
190 6af0bf9c bellard
    } else {
191 6af0bf9c bellard
        /* kseg3 */
192 6af0bf9c bellard
        /* XXX: debug segment is not emulated */
193 671880e6 ths
        if (kernel_mode) {
194 671880e6 ths
            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
195 671880e6 ths
        } else {
196 671880e6 ths
            ret = TLBRET_BADADDR;
197 671880e6 ths
        }
198 6af0bf9c bellard
    }
199 6af0bf9c bellard
#if 0
200 6af0bf9c bellard
    if (logfile) {
201 3594c774 ths
        fprintf(logfile, TARGET_FMT_lx " %d %d => " TARGET_FMT_lx " %d (%d)\n",
202 c570fd16 ths
                address, rw, access_type, *physical, *prot, ret);
203 6af0bf9c bellard
    }
204 6af0bf9c bellard
#endif
205 6af0bf9c bellard
206 6af0bf9c bellard
    return ret;
207 6af0bf9c bellard
}
208 6af0bf9c bellard
209 9b3c35e0 j_mayer
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
210 6af0bf9c bellard
{
211 0eaef5aa ths
    if (env->user_mode_only)
212 0eaef5aa ths
        return addr;
213 0eaef5aa ths
    else {
214 0eaef5aa ths
        target_ulong phys_addr;
215 0eaef5aa ths
        int prot;
216 6af0bf9c bellard
217 0eaef5aa ths
        if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
218 0eaef5aa ths
            return -1;
219 0eaef5aa ths
        return phys_addr;
220 0eaef5aa ths
    }
221 6af0bf9c bellard
}
222 6af0bf9c bellard
223 6af0bf9c bellard
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
224 6ebbf390 j_mayer
                               int mmu_idx, int is_softmmu)
225 6af0bf9c bellard
{
226 6af0bf9c bellard
    target_ulong physical;
227 6af0bf9c bellard
    int prot;
228 6af0bf9c bellard
    int exception = 0, error_code = 0;
229 6af0bf9c bellard
    int access_type;
230 6af0bf9c bellard
    int ret = 0;
231 6af0bf9c bellard
232 6af0bf9c bellard
    if (logfile) {
233 4ad40f36 bellard
#if 0
234 6af0bf9c bellard
        cpu_dump_state(env, logfile, fprintf, 0);
235 4ad40f36 bellard
#endif
236 6ebbf390 j_mayer
        fprintf(logfile, "%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n",
237 b5dc7732 ths
                __func__, env->active_tc.PC, address, rw, mmu_idx, is_softmmu);
238 6af0bf9c bellard
    }
239 4ad40f36 bellard
240 4ad40f36 bellard
    rw &= 1;
241 4ad40f36 bellard
242 6af0bf9c bellard
    /* data access */
243 6af0bf9c bellard
    /* XXX: put correct access by using cpu_restore_state()
244 6af0bf9c bellard
       correctly */
245 6af0bf9c bellard
    access_type = ACCESS_INT;
246 6af0bf9c bellard
    if (env->user_mode_only) {
247 6af0bf9c bellard
        /* user mode only emulation */
248 43057ab1 bellard
        ret = TLBRET_NOMATCH;
249 6af0bf9c bellard
        goto do_fault;
250 6af0bf9c bellard
    }
251 6af0bf9c bellard
    ret = get_physical_address(env, &physical, &prot,
252 6af0bf9c bellard
                               address, rw, access_type);
253 6af0bf9c bellard
    if (logfile) {
254 3594c774 ths
        fprintf(logfile, "%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_lx " prot %d\n",
255 6af0bf9c bellard
                __func__, address, ret, physical, prot);
256 6af0bf9c bellard
    }
257 43057ab1 bellard
    if (ret == TLBRET_MATCH) {
258 43057ab1 bellard
       ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
259 43057ab1 bellard
                          physical & TARGET_PAGE_MASK, prot,
260 6ebbf390 j_mayer
                          mmu_idx, is_softmmu);
261 6af0bf9c bellard
    } else if (ret < 0) {
262 6af0bf9c bellard
    do_fault:
263 6af0bf9c bellard
        switch (ret) {
264 6af0bf9c bellard
        default:
265 43057ab1 bellard
        case TLBRET_BADADDR:
266 6af0bf9c bellard
            /* Reference to kernel address from user mode or supervisor mode */
267 6af0bf9c bellard
            /* Reference to supervisor address from user mode */
268 6af0bf9c bellard
            if (rw)
269 6af0bf9c bellard
                exception = EXCP_AdES;
270 6af0bf9c bellard
            else
271 6af0bf9c bellard
                exception = EXCP_AdEL;
272 6af0bf9c bellard
            break;
273 43057ab1 bellard
        case TLBRET_NOMATCH:
274 6af0bf9c bellard
            /* No TLB match for a mapped address */
275 6af0bf9c bellard
            if (rw)
276 6af0bf9c bellard
                exception = EXCP_TLBS;
277 6af0bf9c bellard
            else
278 6af0bf9c bellard
                exception = EXCP_TLBL;
279 6af0bf9c bellard
            error_code = 1;
280 6af0bf9c bellard
            break;
281 43057ab1 bellard
        case TLBRET_INVALID:
282 6af0bf9c bellard
            /* TLB match with no valid bit */
283 6af0bf9c bellard
            if (rw)
284 6af0bf9c bellard
                exception = EXCP_TLBS;
285 6af0bf9c bellard
            else
286 6af0bf9c bellard
                exception = EXCP_TLBL;
287 6af0bf9c bellard
            break;
288 43057ab1 bellard
        case TLBRET_DIRTY:
289 6af0bf9c bellard
            /* TLB match but 'D' bit is cleared */
290 6af0bf9c bellard
            exception = EXCP_LTLBL;
291 6af0bf9c bellard
            break;
292 3b46e624 ths
293 6af0bf9c bellard
        }
294 6af0bf9c bellard
        /* Raise exception */
295 6af0bf9c bellard
        env->CP0_BadVAddr = address;
296 100ce988 ths
        env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
297 4ad40f36 bellard
                           ((address >> 9) &   0x007ffff0);
298 6af0bf9c bellard
        env->CP0_EntryHi =
299 43057ab1 bellard
            (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
300 d26bc211 ths
#if defined(TARGET_MIPS64)
301 e034e2c3 ths
        env->CP0_EntryHi &= env->SEGMask;
302 e034e2c3 ths
        env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
303 9c67ef0c ths
                            ((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) |
304 e034e2c3 ths
                            ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);
305 100ce988 ths
#endif
306 6af0bf9c bellard
        env->exception_index = exception;
307 6af0bf9c bellard
        env->error_code = error_code;
308 6af0bf9c bellard
        ret = 1;
309 6af0bf9c bellard
    }
310 6af0bf9c bellard
311 6af0bf9c bellard
    return ret;
312 6af0bf9c bellard
}
313 6af0bf9c bellard
314 9a5d878f ths
static const char * const excp_names[EXCP_LAST + 1] = {
315 9a5d878f ths
    [EXCP_RESET] = "reset",
316 9a5d878f ths
    [EXCP_SRESET] = "soft reset",
317 9a5d878f ths
    [EXCP_DSS] = "debug single step",
318 9a5d878f ths
    [EXCP_DINT] = "debug interrupt",
319 9a5d878f ths
    [EXCP_NMI] = "non-maskable interrupt",
320 9a5d878f ths
    [EXCP_MCHECK] = "machine check",
321 9a5d878f ths
    [EXCP_EXT_INTERRUPT] = "interrupt",
322 9a5d878f ths
    [EXCP_DFWATCH] = "deferred watchpoint",
323 9a5d878f ths
    [EXCP_DIB] = "debug instruction breakpoint",
324 9a5d878f ths
    [EXCP_IWATCH] = "instruction fetch watchpoint",
325 9a5d878f ths
    [EXCP_AdEL] = "address error load",
326 9a5d878f ths
    [EXCP_AdES] = "address error store",
327 9a5d878f ths
    [EXCP_TLBF] = "TLB refill",
328 9a5d878f ths
    [EXCP_IBE] = "instruction bus error",
329 9a5d878f ths
    [EXCP_DBp] = "debug breakpoint",
330 9a5d878f ths
    [EXCP_SYSCALL] = "syscall",
331 9a5d878f ths
    [EXCP_BREAK] = "break",
332 9a5d878f ths
    [EXCP_CpU] = "coprocessor unusable",
333 9a5d878f ths
    [EXCP_RI] = "reserved instruction",
334 9a5d878f ths
    [EXCP_OVERFLOW] = "arithmetic overflow",
335 9a5d878f ths
    [EXCP_TRAP] = "trap",
336 9a5d878f ths
    [EXCP_FPE] = "floating point",
337 9a5d878f ths
    [EXCP_DDBS] = "debug data break store",
338 9a5d878f ths
    [EXCP_DWATCH] = "data watchpoint",
339 9a5d878f ths
    [EXCP_LTLBL] = "TLB modify",
340 9a5d878f ths
    [EXCP_TLBL] = "TLB load",
341 9a5d878f ths
    [EXCP_TLBS] = "TLB store",
342 9a5d878f ths
    [EXCP_DBE] = "data bus error",
343 9a5d878f ths
    [EXCP_DDBL] = "debug data break load",
344 9a5d878f ths
    [EXCP_THREAD] = "thread",
345 9a5d878f ths
    [EXCP_MDMX] = "MDMX",
346 9a5d878f ths
    [EXCP_C2E] = "precise coprocessor 2",
347 9a5d878f ths
    [EXCP_CACHE] = "cache error",
348 14e51cc7 ths
};
349 14e51cc7 ths
350 6af0bf9c bellard
void do_interrupt (CPUState *env)
351 6af0bf9c bellard
{
352 0eaef5aa ths
    if (!env->user_mode_only) {
353 0eaef5aa ths
        target_ulong offset;
354 0eaef5aa ths
        int cause = -1;
355 0eaef5aa ths
        const char *name;
356 100ce988 ths
357 0eaef5aa ths
        if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
358 0eaef5aa ths
            if (env->exception_index < 0 || env->exception_index > EXCP_LAST)
359 0eaef5aa ths
                name = "unknown";
360 100ce988 ths
            else
361 0eaef5aa ths
                name = excp_names[env->exception_index];
362 b67bfe8d ths
363 0eaef5aa ths
            fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
364 0eaef5aa ths
                    __func__, env->active_tc.PC, env->CP0_EPC, name);
365 b67bfe8d ths
        }
366 0eaef5aa ths
        if (env->exception_index == EXCP_EXT_INTERRUPT &&
367 0eaef5aa ths
            (env->hflags & MIPS_HFLAG_DM))
368 0eaef5aa ths
            env->exception_index = EXCP_DINT;
369 0eaef5aa ths
        offset = 0x180;
370 0eaef5aa ths
        switch (env->exception_index) {
371 0eaef5aa ths
        case EXCP_DSS:
372 0eaef5aa ths
            env->CP0_Debug |= 1 << CP0DB_DSS;
373 0eaef5aa ths
            /* Debug single step cannot be raised inside a delay slot and
374 0eaef5aa ths
               resume will always occur on the next instruction
375 0eaef5aa ths
               (but we assume the pc has always been updated during
376 0eaef5aa ths
               code translation). */
377 0eaef5aa ths
            env->CP0_DEPC = env->active_tc.PC;
378 0eaef5aa ths
            goto enter_debug_mode;
379 0eaef5aa ths
        case EXCP_DINT:
380 0eaef5aa ths
            env->CP0_Debug |= 1 << CP0DB_DINT;
381 0eaef5aa ths
            goto set_DEPC;
382 0eaef5aa ths
        case EXCP_DIB:
383 0eaef5aa ths
            env->CP0_Debug |= 1 << CP0DB_DIB;
384 0eaef5aa ths
            goto set_DEPC;
385 0eaef5aa ths
        case EXCP_DBp:
386 0eaef5aa ths
            env->CP0_Debug |= 1 << CP0DB_DBp;
387 0eaef5aa ths
            goto set_DEPC;
388 0eaef5aa ths
        case EXCP_DDBS:
389 0eaef5aa ths
            env->CP0_Debug |= 1 << CP0DB_DDBS;
390 0eaef5aa ths
            goto set_DEPC;
391 0eaef5aa ths
        case EXCP_DDBL:
392 0eaef5aa ths
            env->CP0_Debug |= 1 << CP0DB_DDBL;
393 0eaef5aa ths
        set_DEPC:
394 24c7b0e3 ths
            if (env->hflags & MIPS_HFLAG_BMASK) {
395 24c7b0e3 ths
                /* If the exception was raised from a delay slot,
396 24c7b0e3 ths
                   come back to the jump.  */
397 0eaef5aa ths
                env->CP0_DEPC = env->active_tc.PC - 4;
398 0eaef5aa ths
                env->hflags &= ~MIPS_HFLAG_BMASK;
399 24c7b0e3 ths
            } else {
400 0eaef5aa ths
                env->CP0_DEPC = env->active_tc.PC;
401 0eaef5aa ths
            }
402 0eaef5aa ths
 enter_debug_mode:
403 0eaef5aa ths
            env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
404 0eaef5aa ths
            env->hflags &= ~(MIPS_HFLAG_KSU);
405 0eaef5aa ths
            /* EJTAG probe trap enable is not implemented... */
406 0eaef5aa ths
            if (!(env->CP0_Status & (1 << CP0St_EXL)))
407 24c7b0e3 ths
                env->CP0_Cause &= ~(1 << CP0Ca_BD);
408 0eaef5aa ths
            env->active_tc.PC = (int32_t)0xBFC00480;
409 0eaef5aa ths
            break;
410 0eaef5aa ths
        case EXCP_RESET:
411 0eaef5aa ths
            cpu_reset(env);
412 0eaef5aa ths
            break;
413 0eaef5aa ths
        case EXCP_SRESET:
414 0eaef5aa ths
            env->CP0_Status |= (1 << CP0St_SR);
415 0eaef5aa ths
            memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo));
416 0eaef5aa ths
            goto set_error_EPC;
417 0eaef5aa ths
        case EXCP_NMI:
418 0eaef5aa ths
            env->CP0_Status |= (1 << CP0St_NMI);
419 0eaef5aa ths
 set_error_EPC:
420 0eaef5aa ths
            if (env->hflags & MIPS_HFLAG_BMASK) {
421 0eaef5aa ths
                /* If the exception was raised from a delay slot,
422 0eaef5aa ths
                   come back to the jump.  */
423 0eaef5aa ths
                env->CP0_ErrorEPC = env->active_tc.PC - 4;
424 0eaef5aa ths
                env->hflags &= ~MIPS_HFLAG_BMASK;
425 0eaef5aa ths
            } else {
426 0eaef5aa ths
                env->CP0_ErrorEPC = env->active_tc.PC;
427 24c7b0e3 ths
            }
428 0eaef5aa ths
            env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
429 08fa4bab ths
            env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
430 623a930e ths
            env->hflags &= ~(MIPS_HFLAG_KSU);
431 0eaef5aa ths
            if (!(env->CP0_Status & (1 << CP0St_EXL)))
432 0eaef5aa ths
                env->CP0_Cause &= ~(1 << CP0Ca_BD);
433 0eaef5aa ths
            env->active_tc.PC = (int32_t)0xBFC00000;
434 0eaef5aa ths
            break;
435 0eaef5aa ths
        case EXCP_EXT_INTERRUPT:
436 0eaef5aa ths
            cause = 0;
437 0eaef5aa ths
            if (env->CP0_Cause & (1 << CP0Ca_IV))
438 0eaef5aa ths
                offset = 0x200;
439 0eaef5aa ths
            goto set_EPC;
440 0eaef5aa ths
        case EXCP_LTLBL:
441 0eaef5aa ths
            cause = 1;
442 0eaef5aa ths
            goto set_EPC;
443 0eaef5aa ths
        case EXCP_TLBL:
444 0eaef5aa ths
            cause = 2;
445 0eaef5aa ths
            if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
446 0eaef5aa ths
#if defined(TARGET_MIPS64)
447 0eaef5aa ths
                int R = env->CP0_BadVAddr >> 62;
448 0eaef5aa ths
                int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
449 0eaef5aa ths
                int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
450 0eaef5aa ths
                int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
451 0eaef5aa ths
452 0eaef5aa ths
                if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
453 0eaef5aa ths
                    offset = 0x080;
454 0eaef5aa ths
                else
455 0eaef5aa ths
#endif
456 0eaef5aa ths
                    offset = 0x000;
457 0eaef5aa ths
            }
458 0eaef5aa ths
            goto set_EPC;
459 0eaef5aa ths
        case EXCP_TLBS:
460 0eaef5aa ths
            cause = 3;
461 0eaef5aa ths
            if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
462 0eaef5aa ths
#if defined(TARGET_MIPS64)
463 0eaef5aa ths
                int R = env->CP0_BadVAddr >> 62;
464 0eaef5aa ths
                int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
465 0eaef5aa ths
                int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
466 0eaef5aa ths
                int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
467 0eaef5aa ths
468 0eaef5aa ths
                if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
469 0eaef5aa ths
                    offset = 0x080;
470 0eaef5aa ths
                else
471 0eaef5aa ths
#endif
472 0eaef5aa ths
                    offset = 0x000;
473 0eaef5aa ths
            }
474 0eaef5aa ths
            goto set_EPC;
475 0eaef5aa ths
        case EXCP_AdEL:
476 0eaef5aa ths
            cause = 4;
477 0eaef5aa ths
            goto set_EPC;
478 0eaef5aa ths
        case EXCP_AdES:
479 0eaef5aa ths
            cause = 5;
480 0eaef5aa ths
            goto set_EPC;
481 0eaef5aa ths
        case EXCP_IBE:
482 0eaef5aa ths
            cause = 6;
483 0eaef5aa ths
            goto set_EPC;
484 0eaef5aa ths
        case EXCP_DBE:
485 0eaef5aa ths
            cause = 7;
486 0eaef5aa ths
            goto set_EPC;
487 0eaef5aa ths
        case EXCP_SYSCALL:
488 0eaef5aa ths
            cause = 8;
489 0eaef5aa ths
            goto set_EPC;
490 0eaef5aa ths
        case EXCP_BREAK:
491 0eaef5aa ths
            cause = 9;
492 0eaef5aa ths
            goto set_EPC;
493 0eaef5aa ths
        case EXCP_RI:
494 0eaef5aa ths
            cause = 10;
495 0eaef5aa ths
            goto set_EPC;
496 0eaef5aa ths
        case EXCP_CpU:
497 0eaef5aa ths
            cause = 11;
498 0eaef5aa ths
            env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) |
499 0eaef5aa ths
                             (env->error_code << CP0Ca_CE);
500 0eaef5aa ths
            goto set_EPC;
501 0eaef5aa ths
        case EXCP_OVERFLOW:
502 0eaef5aa ths
            cause = 12;
503 0eaef5aa ths
            goto set_EPC;
504 0eaef5aa ths
        case EXCP_TRAP:
505 0eaef5aa ths
            cause = 13;
506 0eaef5aa ths
            goto set_EPC;
507 0eaef5aa ths
        case EXCP_FPE:
508 0eaef5aa ths
            cause = 15;
509 0eaef5aa ths
            goto set_EPC;
510 0eaef5aa ths
        case EXCP_C2E:
511 0eaef5aa ths
            cause = 18;
512 0eaef5aa ths
            goto set_EPC;
513 0eaef5aa ths
        case EXCP_MDMX:
514 0eaef5aa ths
            cause = 22;
515 0eaef5aa ths
            goto set_EPC;
516 0eaef5aa ths
        case EXCP_DWATCH:
517 0eaef5aa ths
            cause = 23;
518 0eaef5aa ths
            /* XXX: TODO: manage defered watch exceptions */
519 0eaef5aa ths
            goto set_EPC;
520 0eaef5aa ths
        case EXCP_MCHECK:
521 0eaef5aa ths
            cause = 24;
522 0eaef5aa ths
            goto set_EPC;
523 0eaef5aa ths
        case EXCP_THREAD:
524 0eaef5aa ths
            cause = 25;
525 0eaef5aa ths
            goto set_EPC;
526 0eaef5aa ths
        case EXCP_CACHE:
527 0eaef5aa ths
            cause = 30;
528 0eaef5aa ths
            if (env->CP0_Status & (1 << CP0St_BEV)) {
529 0eaef5aa ths
                offset = 0x100;
530 0eaef5aa ths
            } else {
531 0eaef5aa ths
                offset = 0x20000100;
532 0eaef5aa ths
            }
533 0eaef5aa ths
 set_EPC:
534 0eaef5aa ths
            if (!(env->CP0_Status & (1 << CP0St_EXL))) {
535 0eaef5aa ths
                if (env->hflags & MIPS_HFLAG_BMASK) {
536 0eaef5aa ths
                    /* If the exception was raised from a delay slot,
537 0eaef5aa ths
                       come back to the jump.  */
538 0eaef5aa ths
                    env->CP0_EPC = env->active_tc.PC - 4;
539 0eaef5aa ths
                    env->CP0_Cause |= (1 << CP0Ca_BD);
540 0eaef5aa ths
                } else {
541 0eaef5aa ths
                    env->CP0_EPC = env->active_tc.PC;
542 0eaef5aa ths
                    env->CP0_Cause &= ~(1 << CP0Ca_BD);
543 0eaef5aa ths
                }
544 0eaef5aa ths
                env->CP0_Status |= (1 << CP0St_EXL);
545 0eaef5aa ths
                env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
546 0eaef5aa ths
                env->hflags &= ~(MIPS_HFLAG_KSU);
547 0eaef5aa ths
            }
548 0eaef5aa ths
            env->hflags &= ~MIPS_HFLAG_BMASK;
549 0eaef5aa ths
            if (env->CP0_Status & (1 << CP0St_BEV)) {
550 0eaef5aa ths
                env->active_tc.PC = (int32_t)0xBFC00200;
551 0eaef5aa ths
            } else {
552 0eaef5aa ths
                env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
553 0eaef5aa ths
            }
554 0eaef5aa ths
            env->active_tc.PC += offset;
555 0eaef5aa ths
            env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
556 0eaef5aa ths
            break;
557 0eaef5aa ths
        default:
558 0eaef5aa ths
            if (logfile) {
559 0eaef5aa ths
                fprintf(logfile, "Invalid MIPS exception %d. Exiting\n",
560 0eaef5aa ths
                        env->exception_index);
561 0eaef5aa ths
            }
562 0eaef5aa ths
            printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
563 0eaef5aa ths
            exit(1);
564 6af0bf9c bellard
        }
565 0eaef5aa ths
        if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
566 0eaef5aa ths
            fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
567 0eaef5aa ths
                    "    S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
568 0eaef5aa ths
                    __func__, env->active_tc.PC, env->CP0_EPC, cause,
569 0eaef5aa ths
                    env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
570 0eaef5aa ths
                    env->CP0_DEPC);
571 6af0bf9c bellard
        }
572 6af0bf9c bellard
    }
573 6af0bf9c bellard
    env->exception_index = EXCP_NONE;
574 6af0bf9c bellard
}
575 2ee4aed8 bellard
576 29929e34 ths
void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
577 2ee4aed8 bellard
{
578 29929e34 ths
    r4k_tlb_t *tlb;
579 3b1c8be4 ths
    target_ulong addr;
580 3b1c8be4 ths
    target_ulong end;
581 3b1c8be4 ths
    uint8_t ASID = env->CP0_EntryHi & 0xFF;
582 3b1c8be4 ths
    target_ulong mask;
583 2ee4aed8 bellard
584 ead9360e ths
    tlb = &env->tlb->mmu.r4k.tlb[idx];
585 f2e9ebef ths
    /* The qemu TLB is flushed when the ASID changes, so no need to
586 2ee4aed8 bellard
       flush these entries again.  */
587 2ee4aed8 bellard
    if (tlb->G == 0 && tlb->ASID != ASID) {
588 2ee4aed8 bellard
        return;
589 2ee4aed8 bellard
    }
590 2ee4aed8 bellard
591 ead9360e ths
    if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) {
592 2ee4aed8 bellard
        /* For tlbwr, we can shadow the discarded entry into
593 2ee4aed8 bellard
           a new (fake) TLB entry, as long as the guest can not
594 2ee4aed8 bellard
           tell that it's there.  */
595 ead9360e ths
        env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb;
596 ead9360e ths
        env->tlb->tlb_in_use++;
597 2ee4aed8 bellard
        return;
598 2ee4aed8 bellard
    }
599 2ee4aed8 bellard
600 3b1c8be4 ths
    /* 1k pages are not supported. */
601 f2e9ebef ths
    mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
602 3b1c8be4 ths
    if (tlb->V0) {
603 f2e9ebef ths
        addr = tlb->VPN & ~mask;
604 d26bc211 ths
#if defined(TARGET_MIPS64)
605 e034e2c3 ths
        if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
606 100ce988 ths
            addr |= 0x3FFFFF0000000000ULL;
607 100ce988 ths
        }
608 100ce988 ths
#endif
609 3b1c8be4 ths
        end = addr | (mask >> 1);
610 3b1c8be4 ths
        while (addr < end) {
611 3b1c8be4 ths
            tlb_flush_page (env, addr);
612 3b1c8be4 ths
            addr += TARGET_PAGE_SIZE;
613 3b1c8be4 ths
        }
614 3b1c8be4 ths
    }
615 3b1c8be4 ths
    if (tlb->V1) {
616 f2e9ebef ths
        addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
617 d26bc211 ths
#if defined(TARGET_MIPS64)
618 e034e2c3 ths
        if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
619 100ce988 ths
            addr |= 0x3FFFFF0000000000ULL;
620 100ce988 ths
        }
621 100ce988 ths
#endif
622 3b1c8be4 ths
        end = addr | mask;
623 53715e48 ths
        while (addr - 1 < end) {
624 3b1c8be4 ths
            tlb_flush_page (env, addr);
625 3b1c8be4 ths
            addr += TARGET_PAGE_SIZE;
626 3b1c8be4 ths
        }
627 3b1c8be4 ths
    }
628 2ee4aed8 bellard
}