Statistics
| Branch: | Revision:

root / target-mips / helper.c @ 4f690853

History | View | Annotate | Download (20.6 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 25b91e32 Aurelien Jarno
#if !defined(CONFIG_USER_ONLY)
314 25b91e32 Aurelien Jarno
target_phys_addr_t do_translate_address(CPUState *env, target_ulong address, int rw)
315 25b91e32 Aurelien Jarno
{
316 25b91e32 Aurelien Jarno
    target_phys_addr_t physical;
317 25b91e32 Aurelien Jarno
    int prot;
318 25b91e32 Aurelien Jarno
    int access_type;
319 25b91e32 Aurelien Jarno
    int ret = 0;
320 25b91e32 Aurelien Jarno
321 25b91e32 Aurelien Jarno
    rw &= 1;
322 25b91e32 Aurelien Jarno
323 25b91e32 Aurelien Jarno
    /* data access */
324 25b91e32 Aurelien Jarno
    access_type = ACCESS_INT;
325 25b91e32 Aurelien Jarno
    ret = get_physical_address(env, &physical, &prot,
326 25b91e32 Aurelien Jarno
                               address, rw, access_type);
327 25b91e32 Aurelien Jarno
    if (ret != TLBRET_MATCH) {
328 25b91e32 Aurelien Jarno
        raise_mmu_exception(env, address, rw, ret);
329 25b91e32 Aurelien Jarno
        cpu_loop_exit();
330 25b91e32 Aurelien Jarno
    }
331 25b91e32 Aurelien Jarno
332 25b91e32 Aurelien Jarno
    return physical;
333 25b91e32 Aurelien Jarno
}
334 25b91e32 Aurelien Jarno
#endif
335 25b91e32 Aurelien Jarno
336 9a5d878f ths
static const char * const excp_names[EXCP_LAST + 1] = {
337 9a5d878f ths
    [EXCP_RESET] = "reset",
338 9a5d878f ths
    [EXCP_SRESET] = "soft reset",
339 9a5d878f ths
    [EXCP_DSS] = "debug single step",
340 9a5d878f ths
    [EXCP_DINT] = "debug interrupt",
341 9a5d878f ths
    [EXCP_NMI] = "non-maskable interrupt",
342 9a5d878f ths
    [EXCP_MCHECK] = "machine check",
343 9a5d878f ths
    [EXCP_EXT_INTERRUPT] = "interrupt",
344 9a5d878f ths
    [EXCP_DFWATCH] = "deferred watchpoint",
345 9a5d878f ths
    [EXCP_DIB] = "debug instruction breakpoint",
346 9a5d878f ths
    [EXCP_IWATCH] = "instruction fetch watchpoint",
347 9a5d878f ths
    [EXCP_AdEL] = "address error load",
348 9a5d878f ths
    [EXCP_AdES] = "address error store",
349 9a5d878f ths
    [EXCP_TLBF] = "TLB refill",
350 9a5d878f ths
    [EXCP_IBE] = "instruction bus error",
351 9a5d878f ths
    [EXCP_DBp] = "debug breakpoint",
352 9a5d878f ths
    [EXCP_SYSCALL] = "syscall",
353 9a5d878f ths
    [EXCP_BREAK] = "break",
354 9a5d878f ths
    [EXCP_CpU] = "coprocessor unusable",
355 9a5d878f ths
    [EXCP_RI] = "reserved instruction",
356 9a5d878f ths
    [EXCP_OVERFLOW] = "arithmetic overflow",
357 9a5d878f ths
    [EXCP_TRAP] = "trap",
358 9a5d878f ths
    [EXCP_FPE] = "floating point",
359 9a5d878f ths
    [EXCP_DDBS] = "debug data break store",
360 9a5d878f ths
    [EXCP_DWATCH] = "data watchpoint",
361 9a5d878f ths
    [EXCP_LTLBL] = "TLB modify",
362 9a5d878f ths
    [EXCP_TLBL] = "TLB load",
363 9a5d878f ths
    [EXCP_TLBS] = "TLB store",
364 9a5d878f ths
    [EXCP_DBE] = "data bus error",
365 9a5d878f ths
    [EXCP_DDBL] = "debug data break load",
366 9a5d878f ths
    [EXCP_THREAD] = "thread",
367 9a5d878f ths
    [EXCP_MDMX] = "MDMX",
368 9a5d878f ths
    [EXCP_C2E] = "precise coprocessor 2",
369 9a5d878f ths
    [EXCP_CACHE] = "cache error",
370 14e51cc7 ths
};
371 14e51cc7 ths
372 32188a03 Nathan Froyd
#if !defined(CONFIG_USER_ONLY)
373 32188a03 Nathan Froyd
static target_ulong exception_resume_pc (CPUState *env)
374 32188a03 Nathan Froyd
{
375 32188a03 Nathan Froyd
    target_ulong bad_pc;
376 32188a03 Nathan Froyd
    target_ulong isa_mode;
377 32188a03 Nathan Froyd
378 32188a03 Nathan Froyd
    isa_mode = !!(env->hflags & MIPS_HFLAG_M16);
379 32188a03 Nathan Froyd
    bad_pc = env->active_tc.PC | isa_mode;
380 32188a03 Nathan Froyd
    if (env->hflags & MIPS_HFLAG_BMASK) {
381 32188a03 Nathan Froyd
        /* If the exception was raised from a delay slot, come back to
382 32188a03 Nathan Froyd
           the jump.  */
383 32188a03 Nathan Froyd
        bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
384 32188a03 Nathan Froyd
    }
385 32188a03 Nathan Froyd
386 32188a03 Nathan Froyd
    return bad_pc;
387 32188a03 Nathan Froyd
}
388 32188a03 Nathan Froyd
#endif
389 32188a03 Nathan Froyd
390 6af0bf9c bellard
void do_interrupt (CPUState *env)
391 6af0bf9c bellard
{
392 932e71cd aurel32
#if !defined(CONFIG_USER_ONLY)
393 932e71cd aurel32
    target_ulong offset;
394 932e71cd aurel32
    int cause = -1;
395 932e71cd aurel32
    const char *name;
396 100ce988 ths
397 93fcfe39 aliguori
    if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
398 932e71cd aurel32
        if (env->exception_index < 0 || env->exception_index > EXCP_LAST)
399 932e71cd aurel32
            name = "unknown";
400 932e71cd aurel32
        else
401 932e71cd aurel32
            name = excp_names[env->exception_index];
402 b67bfe8d ths
403 93fcfe39 aliguori
        qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
404 93fcfe39 aliguori
                 __func__, env->active_tc.PC, env->CP0_EPC, name);
405 932e71cd aurel32
    }
406 932e71cd aurel32
    if (env->exception_index == EXCP_EXT_INTERRUPT &&
407 932e71cd aurel32
        (env->hflags & MIPS_HFLAG_DM))
408 932e71cd aurel32
        env->exception_index = EXCP_DINT;
409 932e71cd aurel32
    offset = 0x180;
410 932e71cd aurel32
    switch (env->exception_index) {
411 932e71cd aurel32
    case EXCP_DSS:
412 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DSS;
413 932e71cd aurel32
        /* Debug single step cannot be raised inside a delay slot and
414 932e71cd aurel32
           resume will always occur on the next instruction
415 932e71cd aurel32
           (but we assume the pc has always been updated during
416 932e71cd aurel32
           code translation). */
417 32188a03 Nathan Froyd
        env->CP0_DEPC = env->active_tc.PC | !!(env->hflags & MIPS_HFLAG_M16);
418 932e71cd aurel32
        goto enter_debug_mode;
419 932e71cd aurel32
    case EXCP_DINT:
420 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DINT;
421 932e71cd aurel32
        goto set_DEPC;
422 932e71cd aurel32
    case EXCP_DIB:
423 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DIB;
424 932e71cd aurel32
        goto set_DEPC;
425 932e71cd aurel32
    case EXCP_DBp:
426 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DBp;
427 932e71cd aurel32
        goto set_DEPC;
428 932e71cd aurel32
    case EXCP_DDBS:
429 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DDBS;
430 932e71cd aurel32
        goto set_DEPC;
431 932e71cd aurel32
    case EXCP_DDBL:
432 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DDBL;
433 932e71cd aurel32
    set_DEPC:
434 32188a03 Nathan Froyd
        env->CP0_DEPC = exception_resume_pc(env);
435 32188a03 Nathan Froyd
        env->hflags &= ~MIPS_HFLAG_BMASK;
436 0eaef5aa ths
 enter_debug_mode:
437 932e71cd aurel32
        env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
438 932e71cd aurel32
        env->hflags &= ~(MIPS_HFLAG_KSU);
439 932e71cd aurel32
        /* EJTAG probe trap enable is not implemented... */
440 932e71cd aurel32
        if (!(env->CP0_Status & (1 << CP0St_EXL)))
441 932e71cd aurel32
            env->CP0_Cause &= ~(1 << CP0Ca_BD);
442 932e71cd aurel32
        env->active_tc.PC = (int32_t)0xBFC00480;
443 32188a03 Nathan Froyd
        /* Exception handlers are entered in 32-bit mode.  */
444 32188a03 Nathan Froyd
        env->hflags &= ~(MIPS_HFLAG_M16);
445 932e71cd aurel32
        break;
446 932e71cd aurel32
    case EXCP_RESET:
447 932e71cd aurel32
        cpu_reset(env);
448 932e71cd aurel32
        break;
449 932e71cd aurel32
    case EXCP_SRESET:
450 932e71cd aurel32
        env->CP0_Status |= (1 << CP0St_SR);
451 932e71cd aurel32
        memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo));
452 932e71cd aurel32
        goto set_error_EPC;
453 932e71cd aurel32
    case EXCP_NMI:
454 932e71cd aurel32
        env->CP0_Status |= (1 << CP0St_NMI);
455 0eaef5aa ths
 set_error_EPC:
456 32188a03 Nathan Froyd
        env->CP0_ErrorEPC = exception_resume_pc(env);
457 32188a03 Nathan Froyd
        env->hflags &= ~MIPS_HFLAG_BMASK;
458 932e71cd aurel32
        env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
459 932e71cd aurel32
        env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
460 932e71cd aurel32
        env->hflags &= ~(MIPS_HFLAG_KSU);
461 932e71cd aurel32
        if (!(env->CP0_Status & (1 << CP0St_EXL)))
462 932e71cd aurel32
            env->CP0_Cause &= ~(1 << CP0Ca_BD);
463 932e71cd aurel32
        env->active_tc.PC = (int32_t)0xBFC00000;
464 32188a03 Nathan Froyd
        /* Exception handlers are entered in 32-bit mode.  */
465 32188a03 Nathan Froyd
        env->hflags &= ~(MIPS_HFLAG_M16);
466 932e71cd aurel32
        break;
467 932e71cd aurel32
    case EXCP_EXT_INTERRUPT:
468 932e71cd aurel32
        cause = 0;
469 932e71cd aurel32
        if (env->CP0_Cause & (1 << CP0Ca_IV))
470 932e71cd aurel32
            offset = 0x200;
471 932e71cd aurel32
        goto set_EPC;
472 932e71cd aurel32
    case EXCP_LTLBL:
473 932e71cd aurel32
        cause = 1;
474 932e71cd aurel32
        goto set_EPC;
475 932e71cd aurel32
    case EXCP_TLBL:
476 932e71cd aurel32
        cause = 2;
477 932e71cd aurel32
        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
478 0eaef5aa ths
#if defined(TARGET_MIPS64)
479 932e71cd aurel32
            int R = env->CP0_BadVAddr >> 62;
480 932e71cd aurel32
            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
481 932e71cd aurel32
            int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
482 932e71cd aurel32
            int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
483 0eaef5aa ths
484 932e71cd aurel32
            if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
485 932e71cd aurel32
                offset = 0x080;
486 932e71cd aurel32
            else
487 0eaef5aa ths
#endif
488 932e71cd aurel32
                offset = 0x000;
489 932e71cd aurel32
        }
490 932e71cd aurel32
        goto set_EPC;
491 932e71cd aurel32
    case EXCP_TLBS:
492 932e71cd aurel32
        cause = 3;
493 932e71cd aurel32
        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
494 0eaef5aa ths
#if defined(TARGET_MIPS64)
495 932e71cd aurel32
            int R = env->CP0_BadVAddr >> 62;
496 932e71cd aurel32
            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
497 932e71cd aurel32
            int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
498 932e71cd aurel32
            int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
499 0eaef5aa ths
500 932e71cd aurel32
            if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
501 932e71cd aurel32
                offset = 0x080;
502 932e71cd aurel32
            else
503 0eaef5aa ths
#endif
504 932e71cd aurel32
                offset = 0x000;
505 932e71cd aurel32
        }
506 932e71cd aurel32
        goto set_EPC;
507 932e71cd aurel32
    case EXCP_AdEL:
508 932e71cd aurel32
        cause = 4;
509 932e71cd aurel32
        goto set_EPC;
510 932e71cd aurel32
    case EXCP_AdES:
511 932e71cd aurel32
        cause = 5;
512 932e71cd aurel32
        goto set_EPC;
513 932e71cd aurel32
    case EXCP_IBE:
514 932e71cd aurel32
        cause = 6;
515 932e71cd aurel32
        goto set_EPC;
516 932e71cd aurel32
    case EXCP_DBE:
517 932e71cd aurel32
        cause = 7;
518 932e71cd aurel32
        goto set_EPC;
519 932e71cd aurel32
    case EXCP_SYSCALL:
520 932e71cd aurel32
        cause = 8;
521 932e71cd aurel32
        goto set_EPC;
522 932e71cd aurel32
    case EXCP_BREAK:
523 932e71cd aurel32
        cause = 9;
524 932e71cd aurel32
        goto set_EPC;
525 932e71cd aurel32
    case EXCP_RI:
526 932e71cd aurel32
        cause = 10;
527 932e71cd aurel32
        goto set_EPC;
528 932e71cd aurel32
    case EXCP_CpU:
529 932e71cd aurel32
        cause = 11;
530 932e71cd aurel32
        env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) |
531 932e71cd aurel32
                         (env->error_code << CP0Ca_CE);
532 932e71cd aurel32
        goto set_EPC;
533 932e71cd aurel32
    case EXCP_OVERFLOW:
534 932e71cd aurel32
        cause = 12;
535 932e71cd aurel32
        goto set_EPC;
536 932e71cd aurel32
    case EXCP_TRAP:
537 932e71cd aurel32
        cause = 13;
538 932e71cd aurel32
        goto set_EPC;
539 932e71cd aurel32
    case EXCP_FPE:
540 932e71cd aurel32
        cause = 15;
541 932e71cd aurel32
        goto set_EPC;
542 932e71cd aurel32
    case EXCP_C2E:
543 932e71cd aurel32
        cause = 18;
544 932e71cd aurel32
        goto set_EPC;
545 932e71cd aurel32
    case EXCP_MDMX:
546 932e71cd aurel32
        cause = 22;
547 932e71cd aurel32
        goto set_EPC;
548 932e71cd aurel32
    case EXCP_DWATCH:
549 932e71cd aurel32
        cause = 23;
550 932e71cd aurel32
        /* XXX: TODO: manage defered watch exceptions */
551 932e71cd aurel32
        goto set_EPC;
552 932e71cd aurel32
    case EXCP_MCHECK:
553 932e71cd aurel32
        cause = 24;
554 932e71cd aurel32
        goto set_EPC;
555 932e71cd aurel32
    case EXCP_THREAD:
556 932e71cd aurel32
        cause = 25;
557 932e71cd aurel32
        goto set_EPC;
558 932e71cd aurel32
    case EXCP_CACHE:
559 932e71cd aurel32
        cause = 30;
560 932e71cd aurel32
        if (env->CP0_Status & (1 << CP0St_BEV)) {
561 932e71cd aurel32
            offset = 0x100;
562 932e71cd aurel32
        } else {
563 932e71cd aurel32
            offset = 0x20000100;
564 932e71cd aurel32
        }
565 0eaef5aa ths
 set_EPC:
566 932e71cd aurel32
        if (!(env->CP0_Status & (1 << CP0St_EXL))) {
567 32188a03 Nathan Froyd
            env->CP0_EPC = exception_resume_pc(env);
568 932e71cd aurel32
            if (env->hflags & MIPS_HFLAG_BMASK) {
569 932e71cd aurel32
                env->CP0_Cause |= (1 << CP0Ca_BD);
570 0eaef5aa ths
            } else {
571 932e71cd aurel32
                env->CP0_Cause &= ~(1 << CP0Ca_BD);
572 0eaef5aa ths
            }
573 932e71cd aurel32
            env->CP0_Status |= (1 << CP0St_EXL);
574 932e71cd aurel32
            env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
575 932e71cd aurel32
            env->hflags &= ~(MIPS_HFLAG_KSU);
576 6af0bf9c bellard
        }
577 932e71cd aurel32
        env->hflags &= ~MIPS_HFLAG_BMASK;
578 932e71cd aurel32
        if (env->CP0_Status & (1 << CP0St_BEV)) {
579 932e71cd aurel32
            env->active_tc.PC = (int32_t)0xBFC00200;
580 932e71cd aurel32
        } else {
581 932e71cd aurel32
            env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
582 6af0bf9c bellard
        }
583 932e71cd aurel32
        env->active_tc.PC += offset;
584 32188a03 Nathan Froyd
        /* Exception handlers are entered in 32-bit mode.  */
585 32188a03 Nathan Froyd
        env->hflags &= ~(MIPS_HFLAG_M16);
586 932e71cd aurel32
        env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
587 932e71cd aurel32
        break;
588 932e71cd aurel32
    default:
589 93fcfe39 aliguori
        qemu_log("Invalid MIPS exception %d. Exiting\n", env->exception_index);
590 932e71cd aurel32
        printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
591 932e71cd aurel32
        exit(1);
592 932e71cd aurel32
    }
593 93fcfe39 aliguori
    if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
594 93fcfe39 aliguori
        qemu_log("%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
595 932e71cd aurel32
                "    S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
596 932e71cd aurel32
                __func__, env->active_tc.PC, env->CP0_EPC, cause,
597 932e71cd aurel32
                env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
598 932e71cd aurel32
                env->CP0_DEPC);
599 6af0bf9c bellard
    }
600 932e71cd aurel32
#endif
601 6af0bf9c bellard
    env->exception_index = EXCP_NONE;
602 6af0bf9c bellard
}
603 2ee4aed8 bellard
604 29929e34 ths
void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
605 2ee4aed8 bellard
{
606 c227f099 Anthony Liguori
    r4k_tlb_t *tlb;
607 3b1c8be4 ths
    target_ulong addr;
608 3b1c8be4 ths
    target_ulong end;
609 3b1c8be4 ths
    uint8_t ASID = env->CP0_EntryHi & 0xFF;
610 3b1c8be4 ths
    target_ulong mask;
611 2ee4aed8 bellard
612 ead9360e ths
    tlb = &env->tlb->mmu.r4k.tlb[idx];
613 f2e9ebef ths
    /* The qemu TLB is flushed when the ASID changes, so no need to
614 2ee4aed8 bellard
       flush these entries again.  */
615 2ee4aed8 bellard
    if (tlb->G == 0 && tlb->ASID != ASID) {
616 2ee4aed8 bellard
        return;
617 2ee4aed8 bellard
    }
618 2ee4aed8 bellard
619 ead9360e ths
    if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) {
620 2ee4aed8 bellard
        /* For tlbwr, we can shadow the discarded entry into
621 6958549d aurel32
           a new (fake) TLB entry, as long as the guest can not
622 6958549d aurel32
           tell that it's there.  */
623 ead9360e ths
        env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb;
624 ead9360e ths
        env->tlb->tlb_in_use++;
625 2ee4aed8 bellard
        return;
626 2ee4aed8 bellard
    }
627 2ee4aed8 bellard
628 3b1c8be4 ths
    /* 1k pages are not supported. */
629 f2e9ebef ths
    mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
630 3b1c8be4 ths
    if (tlb->V0) {
631 f2e9ebef ths
        addr = tlb->VPN & ~mask;
632 d26bc211 ths
#if defined(TARGET_MIPS64)
633 e034e2c3 ths
        if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
634 100ce988 ths
            addr |= 0x3FFFFF0000000000ULL;
635 100ce988 ths
        }
636 100ce988 ths
#endif
637 3b1c8be4 ths
        end = addr | (mask >> 1);
638 3b1c8be4 ths
        while (addr < end) {
639 3b1c8be4 ths
            tlb_flush_page (env, addr);
640 3b1c8be4 ths
            addr += TARGET_PAGE_SIZE;
641 3b1c8be4 ths
        }
642 3b1c8be4 ths
    }
643 3b1c8be4 ths
    if (tlb->V1) {
644 f2e9ebef ths
        addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
645 d26bc211 ths
#if defined(TARGET_MIPS64)
646 e034e2c3 ths
        if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
647 100ce988 ths
            addr |= 0x3FFFFF0000000000ULL;
648 100ce988 ths
        }
649 100ce988 ths
#endif
650 3b1c8be4 ths
        end = addr | mask;
651 53715e48 ths
        while (addr - 1 < end) {
652 3b1c8be4 ths
            tlb_flush_page (env, addr);
653 3b1c8be4 ths
            addr += TARGET_PAGE_SIZE;
654 3b1c8be4 ths
        }
655 3b1c8be4 ths
    }
656 2ee4aed8 bellard
}