Statistics
| Branch: | Revision:

root / target-mips / helper.c @ 67f0875e

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