Statistics
| Branch: | Revision:

root / target-mips / helper.c @ 1147e189

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