Statistics
| Branch: | Revision:

root / target-mips / helper.c @ 6c0d7ee8

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