Statistics
| Branch: | Revision:

root / target-mips / helper.c @ c227f099

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 c227f099 Anthony Liguori
        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
#endif
199 6af0bf9c bellard
200 6af0bf9c bellard
    return ret;
201 6af0bf9c bellard
}
202 932e71cd aurel32
#endif
203 6af0bf9c bellard
204 c227f099 Anthony Liguori
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
205 6af0bf9c bellard
{
206 932e71cd aurel32
#if defined(CONFIG_USER_ONLY)
207 932e71cd aurel32
    return addr;
208 932e71cd aurel32
#else
209 932e71cd aurel32
    target_ulong phys_addr;
210 932e71cd aurel32
    int prot;
211 6af0bf9c bellard
212 932e71cd aurel32
    if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
213 932e71cd aurel32
        return -1;
214 932e71cd aurel32
    return phys_addr;
215 932e71cd aurel32
#endif
216 6af0bf9c bellard
}
217 6af0bf9c bellard
218 6af0bf9c bellard
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
219 6ebbf390 j_mayer
                               int mmu_idx, int is_softmmu)
220 6af0bf9c bellard
{
221 932e71cd aurel32
#if !defined(CONFIG_USER_ONLY)
222 6af0bf9c bellard
    target_ulong physical;
223 6af0bf9c bellard
    int prot;
224 932e71cd aurel32
#endif
225 6af0bf9c bellard
    int exception = 0, error_code = 0;
226 6af0bf9c bellard
    int access_type;
227 6af0bf9c bellard
    int ret = 0;
228 6af0bf9c bellard
229 4ad40f36 bellard
#if 0
230 93fcfe39 aliguori
    log_cpu_state(env, 0);
231 4ad40f36 bellard
#endif
232 93fcfe39 aliguori
    qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n",
233 93fcfe39 aliguori
              __func__, env->active_tc.PC, address, rw, mmu_idx, is_softmmu);
234 4ad40f36 bellard
235 4ad40f36 bellard
    rw &= 1;
236 4ad40f36 bellard
237 6af0bf9c bellard
    /* data access */
238 6af0bf9c bellard
    /* XXX: put correct access by using cpu_restore_state()
239 6af0bf9c bellard
       correctly */
240 6af0bf9c bellard
    access_type = ACCESS_INT;
241 932e71cd aurel32
#if defined(CONFIG_USER_ONLY)
242 932e71cd aurel32
    ret = TLBRET_NOMATCH;
243 932e71cd aurel32
#else
244 6af0bf9c bellard
    ret = get_physical_address(env, &physical, &prot,
245 6af0bf9c bellard
                               address, rw, access_type);
246 93fcfe39 aliguori
    qemu_log("%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_lx " prot %d\n",
247 93fcfe39 aliguori
              __func__, address, ret, physical, prot);
248 43057ab1 bellard
    if (ret == TLBRET_MATCH) {
249 43057ab1 bellard
       ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
250 43057ab1 bellard
                          physical & TARGET_PAGE_MASK, prot,
251 6ebbf390 j_mayer
                          mmu_idx, is_softmmu);
252 932e71cd aurel32
    } else if (ret < 0)
253 932e71cd aurel32
#endif
254 932e71cd aurel32
    {
255 6af0bf9c bellard
        switch (ret) {
256 6af0bf9c bellard
        default:
257 43057ab1 bellard
        case TLBRET_BADADDR:
258 6af0bf9c bellard
            /* Reference to kernel address from user mode or supervisor mode */
259 6af0bf9c bellard
            /* Reference to supervisor address from user mode */
260 6af0bf9c bellard
            if (rw)
261 6af0bf9c bellard
                exception = EXCP_AdES;
262 6af0bf9c bellard
            else
263 6af0bf9c bellard
                exception = EXCP_AdEL;
264 6af0bf9c bellard
            break;
265 43057ab1 bellard
        case TLBRET_NOMATCH:
266 6af0bf9c bellard
            /* No TLB match for a mapped address */
267 6af0bf9c bellard
            if (rw)
268 6af0bf9c bellard
                exception = EXCP_TLBS;
269 6af0bf9c bellard
            else
270 6af0bf9c bellard
                exception = EXCP_TLBL;
271 6af0bf9c bellard
            error_code = 1;
272 6af0bf9c bellard
            break;
273 43057ab1 bellard
        case TLBRET_INVALID:
274 6af0bf9c bellard
            /* TLB match with no valid bit */
275 6af0bf9c bellard
            if (rw)
276 6af0bf9c bellard
                exception = EXCP_TLBS;
277 6af0bf9c bellard
            else
278 6af0bf9c bellard
                exception = EXCP_TLBL;
279 6af0bf9c bellard
            break;
280 43057ab1 bellard
        case TLBRET_DIRTY:
281 6af0bf9c bellard
            /* TLB match but 'D' bit is cleared */
282 6af0bf9c bellard
            exception = EXCP_LTLBL;
283 6af0bf9c bellard
            break;
284 3b46e624 ths
285 6af0bf9c bellard
        }
286 6af0bf9c bellard
        /* Raise exception */
287 6af0bf9c bellard
        env->CP0_BadVAddr = address;
288 100ce988 ths
        env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
289 6958549d aurel32
                           ((address >> 9) &   0x007ffff0);
290 6af0bf9c bellard
        env->CP0_EntryHi =
291 43057ab1 bellard
            (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
292 d26bc211 ths
#if defined(TARGET_MIPS64)
293 e034e2c3 ths
        env->CP0_EntryHi &= env->SEGMask;
294 e034e2c3 ths
        env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
295 9c67ef0c ths
                            ((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) |
296 e034e2c3 ths
                            ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);
297 100ce988 ths
#endif
298 6af0bf9c bellard
        env->exception_index = exception;
299 6af0bf9c bellard
        env->error_code = error_code;
300 6af0bf9c bellard
        ret = 1;
301 6af0bf9c bellard
    }
302 6af0bf9c bellard
303 6af0bf9c bellard
    return ret;
304 6af0bf9c bellard
}
305 6af0bf9c bellard
306 9a5d878f ths
static const char * const excp_names[EXCP_LAST + 1] = {
307 9a5d878f ths
    [EXCP_RESET] = "reset",
308 9a5d878f ths
    [EXCP_SRESET] = "soft reset",
309 9a5d878f ths
    [EXCP_DSS] = "debug single step",
310 9a5d878f ths
    [EXCP_DINT] = "debug interrupt",
311 9a5d878f ths
    [EXCP_NMI] = "non-maskable interrupt",
312 9a5d878f ths
    [EXCP_MCHECK] = "machine check",
313 9a5d878f ths
    [EXCP_EXT_INTERRUPT] = "interrupt",
314 9a5d878f ths
    [EXCP_DFWATCH] = "deferred watchpoint",
315 9a5d878f ths
    [EXCP_DIB] = "debug instruction breakpoint",
316 9a5d878f ths
    [EXCP_IWATCH] = "instruction fetch watchpoint",
317 9a5d878f ths
    [EXCP_AdEL] = "address error load",
318 9a5d878f ths
    [EXCP_AdES] = "address error store",
319 9a5d878f ths
    [EXCP_TLBF] = "TLB refill",
320 9a5d878f ths
    [EXCP_IBE] = "instruction bus error",
321 9a5d878f ths
    [EXCP_DBp] = "debug breakpoint",
322 9a5d878f ths
    [EXCP_SYSCALL] = "syscall",
323 9a5d878f ths
    [EXCP_BREAK] = "break",
324 9a5d878f ths
    [EXCP_CpU] = "coprocessor unusable",
325 9a5d878f ths
    [EXCP_RI] = "reserved instruction",
326 9a5d878f ths
    [EXCP_OVERFLOW] = "arithmetic overflow",
327 9a5d878f ths
    [EXCP_TRAP] = "trap",
328 9a5d878f ths
    [EXCP_FPE] = "floating point",
329 9a5d878f ths
    [EXCP_DDBS] = "debug data break store",
330 9a5d878f ths
    [EXCP_DWATCH] = "data watchpoint",
331 9a5d878f ths
    [EXCP_LTLBL] = "TLB modify",
332 9a5d878f ths
    [EXCP_TLBL] = "TLB load",
333 9a5d878f ths
    [EXCP_TLBS] = "TLB store",
334 9a5d878f ths
    [EXCP_DBE] = "data bus error",
335 9a5d878f ths
    [EXCP_DDBL] = "debug data break load",
336 9a5d878f ths
    [EXCP_THREAD] = "thread",
337 9a5d878f ths
    [EXCP_MDMX] = "MDMX",
338 9a5d878f ths
    [EXCP_C2E] = "precise coprocessor 2",
339 9a5d878f ths
    [EXCP_CACHE] = "cache error",
340 14e51cc7 ths
};
341 14e51cc7 ths
342 6af0bf9c bellard
void do_interrupt (CPUState *env)
343 6af0bf9c bellard
{
344 932e71cd aurel32
#if !defined(CONFIG_USER_ONLY)
345 932e71cd aurel32
    target_ulong offset;
346 932e71cd aurel32
    int cause = -1;
347 932e71cd aurel32
    const char *name;
348 100ce988 ths
349 93fcfe39 aliguori
    if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
350 932e71cd aurel32
        if (env->exception_index < 0 || env->exception_index > EXCP_LAST)
351 932e71cd aurel32
            name = "unknown";
352 932e71cd aurel32
        else
353 932e71cd aurel32
            name = excp_names[env->exception_index];
354 b67bfe8d ths
355 93fcfe39 aliguori
        qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
356 93fcfe39 aliguori
                 __func__, env->active_tc.PC, env->CP0_EPC, name);
357 932e71cd aurel32
    }
358 932e71cd aurel32
    if (env->exception_index == EXCP_EXT_INTERRUPT &&
359 932e71cd aurel32
        (env->hflags & MIPS_HFLAG_DM))
360 932e71cd aurel32
        env->exception_index = EXCP_DINT;
361 932e71cd aurel32
    offset = 0x180;
362 932e71cd aurel32
    switch (env->exception_index) {
363 932e71cd aurel32
    case EXCP_DSS:
364 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DSS;
365 932e71cd aurel32
        /* Debug single step cannot be raised inside a delay slot and
366 932e71cd aurel32
           resume will always occur on the next instruction
367 932e71cd aurel32
           (but we assume the pc has always been updated during
368 932e71cd aurel32
           code translation). */
369 932e71cd aurel32
        env->CP0_DEPC = env->active_tc.PC;
370 932e71cd aurel32
        goto enter_debug_mode;
371 932e71cd aurel32
    case EXCP_DINT:
372 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DINT;
373 932e71cd aurel32
        goto set_DEPC;
374 932e71cd aurel32
    case EXCP_DIB:
375 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DIB;
376 932e71cd aurel32
        goto set_DEPC;
377 932e71cd aurel32
    case EXCP_DBp:
378 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DBp;
379 932e71cd aurel32
        goto set_DEPC;
380 932e71cd aurel32
    case EXCP_DDBS:
381 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DDBS;
382 932e71cd aurel32
        goto set_DEPC;
383 932e71cd aurel32
    case EXCP_DDBL:
384 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DDBL;
385 932e71cd aurel32
    set_DEPC:
386 932e71cd aurel32
        if (env->hflags & MIPS_HFLAG_BMASK) {
387 932e71cd aurel32
            /* If the exception was raised from a delay slot,
388 932e71cd aurel32
               come back to the jump.  */
389 932e71cd aurel32
            env->CP0_DEPC = env->active_tc.PC - 4;
390 932e71cd aurel32
            env->hflags &= ~MIPS_HFLAG_BMASK;
391 932e71cd aurel32
        } else {
392 0eaef5aa ths
            env->CP0_DEPC = env->active_tc.PC;
393 932e71cd aurel32
        }
394 0eaef5aa ths
 enter_debug_mode:
395 932e71cd aurel32
        env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
396 932e71cd aurel32
        env->hflags &= ~(MIPS_HFLAG_KSU);
397 932e71cd aurel32
        /* EJTAG probe trap enable is not implemented... */
398 932e71cd aurel32
        if (!(env->CP0_Status & (1 << CP0St_EXL)))
399 932e71cd aurel32
            env->CP0_Cause &= ~(1 << CP0Ca_BD);
400 932e71cd aurel32
        env->active_tc.PC = (int32_t)0xBFC00480;
401 932e71cd aurel32
        break;
402 932e71cd aurel32
    case EXCP_RESET:
403 932e71cd aurel32
        cpu_reset(env);
404 932e71cd aurel32
        break;
405 932e71cd aurel32
    case EXCP_SRESET:
406 932e71cd aurel32
        env->CP0_Status |= (1 << CP0St_SR);
407 932e71cd aurel32
        memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo));
408 932e71cd aurel32
        goto set_error_EPC;
409 932e71cd aurel32
    case EXCP_NMI:
410 932e71cd aurel32
        env->CP0_Status |= (1 << CP0St_NMI);
411 0eaef5aa ths
 set_error_EPC:
412 932e71cd aurel32
        if (env->hflags & MIPS_HFLAG_BMASK) {
413 932e71cd aurel32
            /* If the exception was raised from a delay slot,
414 932e71cd aurel32
               come back to the jump.  */
415 932e71cd aurel32
            env->CP0_ErrorEPC = env->active_tc.PC - 4;
416 932e71cd aurel32
            env->hflags &= ~MIPS_HFLAG_BMASK;
417 932e71cd aurel32
        } else {
418 932e71cd aurel32
            env->CP0_ErrorEPC = env->active_tc.PC;
419 932e71cd aurel32
        }
420 932e71cd aurel32
        env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
421 932e71cd aurel32
        env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
422 932e71cd aurel32
        env->hflags &= ~(MIPS_HFLAG_KSU);
423 932e71cd aurel32
        if (!(env->CP0_Status & (1 << CP0St_EXL)))
424 932e71cd aurel32
            env->CP0_Cause &= ~(1 << CP0Ca_BD);
425 932e71cd aurel32
        env->active_tc.PC = (int32_t)0xBFC00000;
426 932e71cd aurel32
        break;
427 932e71cd aurel32
    case EXCP_EXT_INTERRUPT:
428 932e71cd aurel32
        cause = 0;
429 932e71cd aurel32
        if (env->CP0_Cause & (1 << CP0Ca_IV))
430 932e71cd aurel32
            offset = 0x200;
431 932e71cd aurel32
        goto set_EPC;
432 932e71cd aurel32
    case EXCP_LTLBL:
433 932e71cd aurel32
        cause = 1;
434 932e71cd aurel32
        goto set_EPC;
435 932e71cd aurel32
    case EXCP_TLBL:
436 932e71cd aurel32
        cause = 2;
437 932e71cd aurel32
        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
438 0eaef5aa ths
#if defined(TARGET_MIPS64)
439 932e71cd aurel32
            int R = env->CP0_BadVAddr >> 62;
440 932e71cd aurel32
            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
441 932e71cd aurel32
            int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
442 932e71cd aurel32
            int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
443 0eaef5aa ths
444 932e71cd aurel32
            if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
445 932e71cd aurel32
                offset = 0x080;
446 932e71cd aurel32
            else
447 0eaef5aa ths
#endif
448 932e71cd aurel32
                offset = 0x000;
449 932e71cd aurel32
        }
450 932e71cd aurel32
        goto set_EPC;
451 932e71cd aurel32
    case EXCP_TLBS:
452 932e71cd aurel32
        cause = 3;
453 932e71cd aurel32
        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
454 0eaef5aa ths
#if defined(TARGET_MIPS64)
455 932e71cd aurel32
            int R = env->CP0_BadVAddr >> 62;
456 932e71cd aurel32
            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
457 932e71cd aurel32
            int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
458 932e71cd aurel32
            int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
459 0eaef5aa ths
460 932e71cd aurel32
            if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
461 932e71cd aurel32
                offset = 0x080;
462 932e71cd aurel32
            else
463 0eaef5aa ths
#endif
464 932e71cd aurel32
                offset = 0x000;
465 932e71cd aurel32
        }
466 932e71cd aurel32
        goto set_EPC;
467 932e71cd aurel32
    case EXCP_AdEL:
468 932e71cd aurel32
        cause = 4;
469 932e71cd aurel32
        goto set_EPC;
470 932e71cd aurel32
    case EXCP_AdES:
471 932e71cd aurel32
        cause = 5;
472 932e71cd aurel32
        goto set_EPC;
473 932e71cd aurel32
    case EXCP_IBE:
474 932e71cd aurel32
        cause = 6;
475 932e71cd aurel32
        goto set_EPC;
476 932e71cd aurel32
    case EXCP_DBE:
477 932e71cd aurel32
        cause = 7;
478 932e71cd aurel32
        goto set_EPC;
479 932e71cd aurel32
    case EXCP_SYSCALL:
480 932e71cd aurel32
        cause = 8;
481 932e71cd aurel32
        goto set_EPC;
482 932e71cd aurel32
    case EXCP_BREAK:
483 932e71cd aurel32
        cause = 9;
484 932e71cd aurel32
        goto set_EPC;
485 932e71cd aurel32
    case EXCP_RI:
486 932e71cd aurel32
        cause = 10;
487 932e71cd aurel32
        goto set_EPC;
488 932e71cd aurel32
    case EXCP_CpU:
489 932e71cd aurel32
        cause = 11;
490 932e71cd aurel32
        env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) |
491 932e71cd aurel32
                         (env->error_code << CP0Ca_CE);
492 932e71cd aurel32
        goto set_EPC;
493 932e71cd aurel32
    case EXCP_OVERFLOW:
494 932e71cd aurel32
        cause = 12;
495 932e71cd aurel32
        goto set_EPC;
496 932e71cd aurel32
    case EXCP_TRAP:
497 932e71cd aurel32
        cause = 13;
498 932e71cd aurel32
        goto set_EPC;
499 932e71cd aurel32
    case EXCP_FPE:
500 932e71cd aurel32
        cause = 15;
501 932e71cd aurel32
        goto set_EPC;
502 932e71cd aurel32
    case EXCP_C2E:
503 932e71cd aurel32
        cause = 18;
504 932e71cd aurel32
        goto set_EPC;
505 932e71cd aurel32
    case EXCP_MDMX:
506 932e71cd aurel32
        cause = 22;
507 932e71cd aurel32
        goto set_EPC;
508 932e71cd aurel32
    case EXCP_DWATCH:
509 932e71cd aurel32
        cause = 23;
510 932e71cd aurel32
        /* XXX: TODO: manage defered watch exceptions */
511 932e71cd aurel32
        goto set_EPC;
512 932e71cd aurel32
    case EXCP_MCHECK:
513 932e71cd aurel32
        cause = 24;
514 932e71cd aurel32
        goto set_EPC;
515 932e71cd aurel32
    case EXCP_THREAD:
516 932e71cd aurel32
        cause = 25;
517 932e71cd aurel32
        goto set_EPC;
518 932e71cd aurel32
    case EXCP_CACHE:
519 932e71cd aurel32
        cause = 30;
520 932e71cd aurel32
        if (env->CP0_Status & (1 << CP0St_BEV)) {
521 932e71cd aurel32
            offset = 0x100;
522 932e71cd aurel32
        } else {
523 932e71cd aurel32
            offset = 0x20000100;
524 932e71cd aurel32
        }
525 0eaef5aa ths
 set_EPC:
526 932e71cd aurel32
        if (!(env->CP0_Status & (1 << CP0St_EXL))) {
527 932e71cd aurel32
            if (env->hflags & MIPS_HFLAG_BMASK) {
528 932e71cd aurel32
                /* If the exception was raised from a delay slot,
529 932e71cd aurel32
                   come back to the jump.  */
530 932e71cd aurel32
                env->CP0_EPC = env->active_tc.PC - 4;
531 932e71cd aurel32
                env->CP0_Cause |= (1 << CP0Ca_BD);
532 0eaef5aa ths
            } else {
533 932e71cd aurel32
                env->CP0_EPC = env->active_tc.PC;
534 932e71cd aurel32
                env->CP0_Cause &= ~(1 << CP0Ca_BD);
535 0eaef5aa ths
            }
536 932e71cd aurel32
            env->CP0_Status |= (1 << CP0St_EXL);
537 932e71cd aurel32
            env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
538 932e71cd aurel32
            env->hflags &= ~(MIPS_HFLAG_KSU);
539 6af0bf9c bellard
        }
540 932e71cd aurel32
        env->hflags &= ~MIPS_HFLAG_BMASK;
541 932e71cd aurel32
        if (env->CP0_Status & (1 << CP0St_BEV)) {
542 932e71cd aurel32
            env->active_tc.PC = (int32_t)0xBFC00200;
543 932e71cd aurel32
        } else {
544 932e71cd aurel32
            env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
545 6af0bf9c bellard
        }
546 932e71cd aurel32
        env->active_tc.PC += offset;
547 932e71cd aurel32
        env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
548 932e71cd aurel32
        break;
549 932e71cd aurel32
    default:
550 93fcfe39 aliguori
        qemu_log("Invalid MIPS exception %d. Exiting\n", env->exception_index);
551 932e71cd aurel32
        printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
552 932e71cd aurel32
        exit(1);
553 932e71cd aurel32
    }
554 93fcfe39 aliguori
    if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
555 93fcfe39 aliguori
        qemu_log("%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
556 932e71cd aurel32
                "    S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
557 932e71cd aurel32
                __func__, env->active_tc.PC, env->CP0_EPC, cause,
558 932e71cd aurel32
                env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
559 932e71cd aurel32
                env->CP0_DEPC);
560 6af0bf9c bellard
    }
561 932e71cd aurel32
#endif
562 6af0bf9c bellard
    env->exception_index = EXCP_NONE;
563 6af0bf9c bellard
}
564 2ee4aed8 bellard
565 29929e34 ths
void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
566 2ee4aed8 bellard
{
567 c227f099 Anthony Liguori
    r4k_tlb_t *tlb;
568 3b1c8be4 ths
    target_ulong addr;
569 3b1c8be4 ths
    target_ulong end;
570 3b1c8be4 ths
    uint8_t ASID = env->CP0_EntryHi & 0xFF;
571 3b1c8be4 ths
    target_ulong mask;
572 2ee4aed8 bellard
573 ead9360e ths
    tlb = &env->tlb->mmu.r4k.tlb[idx];
574 f2e9ebef ths
    /* The qemu TLB is flushed when the ASID changes, so no need to
575 2ee4aed8 bellard
       flush these entries again.  */
576 2ee4aed8 bellard
    if (tlb->G == 0 && tlb->ASID != ASID) {
577 2ee4aed8 bellard
        return;
578 2ee4aed8 bellard
    }
579 2ee4aed8 bellard
580 ead9360e ths
    if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) {
581 2ee4aed8 bellard
        /* For tlbwr, we can shadow the discarded entry into
582 6958549d aurel32
           a new (fake) TLB entry, as long as the guest can not
583 6958549d aurel32
           tell that it's there.  */
584 ead9360e ths
        env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb;
585 ead9360e ths
        env->tlb->tlb_in_use++;
586 2ee4aed8 bellard
        return;
587 2ee4aed8 bellard
    }
588 2ee4aed8 bellard
589 3b1c8be4 ths
    /* 1k pages are not supported. */
590 f2e9ebef ths
    mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
591 3b1c8be4 ths
    if (tlb->V0) {
592 f2e9ebef ths
        addr = tlb->VPN & ~mask;
593 d26bc211 ths
#if defined(TARGET_MIPS64)
594 e034e2c3 ths
        if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
595 100ce988 ths
            addr |= 0x3FFFFF0000000000ULL;
596 100ce988 ths
        }
597 100ce988 ths
#endif
598 3b1c8be4 ths
        end = addr | (mask >> 1);
599 3b1c8be4 ths
        while (addr < end) {
600 3b1c8be4 ths
            tlb_flush_page (env, addr);
601 3b1c8be4 ths
            addr += TARGET_PAGE_SIZE;
602 3b1c8be4 ths
        }
603 3b1c8be4 ths
    }
604 3b1c8be4 ths
    if (tlb->V1) {
605 f2e9ebef ths
        addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
606 d26bc211 ths
#if defined(TARGET_MIPS64)
607 e034e2c3 ths
        if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
608 100ce988 ths
            addr |= 0x3FFFFF0000000000ULL;
609 100ce988 ths
        }
610 100ce988 ths
#endif
611 3b1c8be4 ths
        end = addr | mask;
612 53715e48 ths
        while (addr - 1 < end) {
613 3b1c8be4 ths
            tlb_flush_page (env, addr);
614 3b1c8be4 ths
            addr += TARGET_PAGE_SIZE;
615 3b1c8be4 ths
        }
616 3b1c8be4 ths
    }
617 2ee4aed8 bellard
}