Statistics
| Branch: | Revision:

root / target-mips / helper.c @ 1fc7bf6e

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