Statistics
| Branch: | Revision:

root / target-mips / helper.c @ 353ebb7a

History | View | Annotate | Download (22.1 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 3c7b48b7 Paul Brook
#if !defined(CONFIG_USER_ONLY)
38 3c7b48b7 Paul Brook
39 29929e34 ths
/* no MMU emulation */
40 60c9af07 Aurelien Jarno
int no_mmu_map_address (CPUState *env, target_phys_addr_t *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 60c9af07 Aurelien Jarno
int fixed_mmu_map_address (CPUState *env, target_phys_addr_t *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 60c9af07 Aurelien Jarno
int r4k_map_address (CPUState *env, target_phys_addr_t *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 c227f099 Anthony Liguori
        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 60c9af07 Aurelien Jarno
static int get_physical_address (CPUState *env, target_phys_addr_t *physical,
104 43057ab1 bellard
                                int *prot, target_ulong address,
105 43057ab1 bellard
                                int rw, int access_type)
106 6af0bf9c bellard
{
107 b4ab4b4e ths
    /* User mode can only access useg/xuseg */
108 43057ab1 bellard
    int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
109 671880e6 ths
    int supervisor_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_SM;
110 671880e6 ths
    int kernel_mode = !user_mode && !supervisor_mode;
111 d26bc211 ths
#if defined(TARGET_MIPS64)
112 b4ab4b4e ths
    int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
113 b4ab4b4e ths
    int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
114 b4ab4b4e ths
    int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
115 b4ab4b4e ths
#endif
116 43057ab1 bellard
    int ret = TLBRET_MATCH;
117 43057ab1 bellard
118 6af0bf9c bellard
#if 0
119 93fcfe39 aliguori
    qemu_log("user mode %d h %08x\n", user_mode, env->hflags);
120 6af0bf9c bellard
#endif
121 b4ab4b4e ths
122 b4ab4b4e ths
    if (address <= (int32_t)0x7FFFFFFFUL) {
123 b4ab4b4e ths
        /* useg */
124 996ba2cc ths
        if (env->CP0_Status & (1 << CP0St_ERL)) {
125 29929e34 ths
            *physical = address & 0xFFFFFFFF;
126 6af0bf9c bellard
            *prot = PAGE_READ | PAGE_WRITE;
127 996ba2cc ths
        } else {
128 ead9360e ths
            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
129 6af0bf9c bellard
        }
130 d26bc211 ths
#if defined(TARGET_MIPS64)
131 89fc88da ths
    } else if (address < 0x4000000000000000ULL) {
132 b4ab4b4e ths
        /* xuseg */
133 6958549d aurel32
        if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) {
134 ead9360e ths
            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
135 6958549d aurel32
        } else {
136 6958549d aurel32
            ret = TLBRET_BADADDR;
137 b4ab4b4e ths
        }
138 89fc88da ths
    } else if (address < 0x8000000000000000ULL) {
139 b4ab4b4e ths
        /* xsseg */
140 6958549d aurel32
        if ((supervisor_mode || kernel_mode) &&
141 6958549d aurel32
            SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) {
142 ead9360e ths
            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
143 6958549d aurel32
        } else {
144 6958549d aurel32
            ret = TLBRET_BADADDR;
145 b4ab4b4e ths
        }
146 89fc88da ths
    } else if (address < 0xC000000000000000ULL) {
147 b4ab4b4e ths
        /* xkphys */
148 671880e6 ths
        if (kernel_mode && KX &&
149 6d35524c ths
            (address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) {
150 6d35524c ths
            *physical = address & env->PAMask;
151 b4ab4b4e ths
            *prot = PAGE_READ | PAGE_WRITE;
152 6958549d aurel32
        } else {
153 6958549d aurel32
            ret = TLBRET_BADADDR;
154 6958549d aurel32
        }
155 89fc88da ths
    } else if (address < 0xFFFFFFFF80000000ULL) {
156 b4ab4b4e ths
        /* xkseg */
157 6958549d aurel32
        if (kernel_mode && KX &&
158 6958549d aurel32
            address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) {
159 ead9360e ths
            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
160 6958549d aurel32
        } else {
161 6958549d aurel32
            ret = TLBRET_BADADDR;
162 6958549d aurel32
        }
163 b4ab4b4e ths
#endif
164 5dc4b744 ths
    } else if (address < (int32_t)0xA0000000UL) {
165 6af0bf9c bellard
        /* kseg0 */
166 671880e6 ths
        if (kernel_mode) {
167 671880e6 ths
            *physical = address - (int32_t)0x80000000UL;
168 671880e6 ths
            *prot = PAGE_READ | PAGE_WRITE;
169 671880e6 ths
        } else {
170 671880e6 ths
            ret = TLBRET_BADADDR;
171 671880e6 ths
        }
172 5dc4b744 ths
    } else if (address < (int32_t)0xC0000000UL) {
173 6af0bf9c bellard
        /* kseg1 */
174 671880e6 ths
        if (kernel_mode) {
175 671880e6 ths
            *physical = address - (int32_t)0xA0000000UL;
176 671880e6 ths
            *prot = PAGE_READ | PAGE_WRITE;
177 671880e6 ths
        } else {
178 671880e6 ths
            ret = TLBRET_BADADDR;
179 671880e6 ths
        }
180 5dc4b744 ths
    } else if (address < (int32_t)0xE0000000UL) {
181 89fc88da ths
        /* sseg (kseg2) */
182 671880e6 ths
        if (supervisor_mode || kernel_mode) {
183 671880e6 ths
            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
184 671880e6 ths
        } else {
185 671880e6 ths
            ret = TLBRET_BADADDR;
186 671880e6 ths
        }
187 6af0bf9c bellard
    } else {
188 6af0bf9c bellard
        /* kseg3 */
189 6af0bf9c bellard
        /* XXX: debug segment is not emulated */
190 671880e6 ths
        if (kernel_mode) {
191 671880e6 ths
            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
192 671880e6 ths
        } else {
193 671880e6 ths
            ret = TLBRET_BADADDR;
194 671880e6 ths
        }
195 6af0bf9c bellard
    }
196 6af0bf9c bellard
#if 0
197 93fcfe39 aliguori
    qemu_log(TARGET_FMT_lx " %d %d => " TARGET_FMT_lx " %d (%d)\n",
198 93fcfe39 aliguori
            address, rw, access_type, *physical, *prot, ret);
199 6af0bf9c bellard
#endif
200 6af0bf9c bellard
201 6af0bf9c bellard
    return ret;
202 6af0bf9c bellard
}
203 932e71cd aurel32
#endif
204 6af0bf9c bellard
205 1147e189 Aurelien Jarno
static void raise_mmu_exception(CPUState *env, target_ulong address,
206 1147e189 Aurelien Jarno
                                int rw, int tlb_error)
207 1147e189 Aurelien Jarno
{
208 1147e189 Aurelien Jarno
    int exception = 0, error_code = 0;
209 1147e189 Aurelien Jarno
210 1147e189 Aurelien Jarno
    switch (tlb_error) {
211 1147e189 Aurelien Jarno
    default:
212 1147e189 Aurelien Jarno
    case TLBRET_BADADDR:
213 1147e189 Aurelien Jarno
        /* Reference to kernel address from user mode or supervisor mode */
214 1147e189 Aurelien Jarno
        /* Reference to supervisor address from user mode */
215 1147e189 Aurelien Jarno
        if (rw)
216 1147e189 Aurelien Jarno
            exception = EXCP_AdES;
217 1147e189 Aurelien Jarno
        else
218 1147e189 Aurelien Jarno
            exception = EXCP_AdEL;
219 1147e189 Aurelien Jarno
        break;
220 1147e189 Aurelien Jarno
    case TLBRET_NOMATCH:
221 1147e189 Aurelien Jarno
        /* No TLB match for a mapped address */
222 1147e189 Aurelien Jarno
        if (rw)
223 1147e189 Aurelien Jarno
            exception = EXCP_TLBS;
224 1147e189 Aurelien Jarno
        else
225 1147e189 Aurelien Jarno
            exception = EXCP_TLBL;
226 1147e189 Aurelien Jarno
        error_code = 1;
227 1147e189 Aurelien Jarno
        break;
228 1147e189 Aurelien Jarno
    case TLBRET_INVALID:
229 1147e189 Aurelien Jarno
        /* TLB match with no valid bit */
230 1147e189 Aurelien Jarno
        if (rw)
231 1147e189 Aurelien Jarno
            exception = EXCP_TLBS;
232 1147e189 Aurelien Jarno
        else
233 1147e189 Aurelien Jarno
            exception = EXCP_TLBL;
234 1147e189 Aurelien Jarno
        break;
235 1147e189 Aurelien Jarno
    case TLBRET_DIRTY:
236 1147e189 Aurelien Jarno
        /* TLB match but 'D' bit is cleared */
237 1147e189 Aurelien Jarno
        exception = EXCP_LTLBL;
238 1147e189 Aurelien Jarno
        break;
239 1147e189 Aurelien Jarno
240 1147e189 Aurelien Jarno
    }
241 1147e189 Aurelien Jarno
    /* Raise exception */
242 1147e189 Aurelien Jarno
    env->CP0_BadVAddr = address;
243 1147e189 Aurelien Jarno
    env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
244 1147e189 Aurelien Jarno
                       ((address >> 9) & 0x007ffff0);
245 1147e189 Aurelien Jarno
    env->CP0_EntryHi =
246 1147e189 Aurelien Jarno
        (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
247 1147e189 Aurelien Jarno
#if defined(TARGET_MIPS64)
248 1147e189 Aurelien Jarno
    env->CP0_EntryHi &= env->SEGMask;
249 1147e189 Aurelien Jarno
    env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
250 1147e189 Aurelien Jarno
                        ((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) |
251 1147e189 Aurelien Jarno
                        ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);
252 1147e189 Aurelien Jarno
#endif
253 1147e189 Aurelien Jarno
    env->exception_index = exception;
254 1147e189 Aurelien Jarno
    env->error_code = error_code;
255 1147e189 Aurelien Jarno
}
256 1147e189 Aurelien Jarno
257 4fcc562b Paul Brook
#if !defined(CONFIG_USER_ONLY)
258 c227f099 Anthony Liguori
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
259 6af0bf9c bellard
{
260 60c9af07 Aurelien Jarno
    target_phys_addr_t phys_addr;
261 932e71cd aurel32
    int prot;
262 6af0bf9c bellard
263 932e71cd aurel32
    if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
264 932e71cd aurel32
        return -1;
265 932e71cd aurel32
    return phys_addr;
266 6af0bf9c bellard
}
267 4fcc562b Paul Brook
#endif
268 6af0bf9c bellard
269 6af0bf9c bellard
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
270 6ebbf390 j_mayer
                               int mmu_idx, int is_softmmu)
271 6af0bf9c bellard
{
272 932e71cd aurel32
#if !defined(CONFIG_USER_ONLY)
273 60c9af07 Aurelien Jarno
    target_phys_addr_t physical;
274 6af0bf9c bellard
    int prot;
275 932e71cd aurel32
#endif
276 6af0bf9c bellard
    int access_type;
277 6af0bf9c bellard
    int ret = 0;
278 6af0bf9c bellard
279 4ad40f36 bellard
#if 0
280 93fcfe39 aliguori
    log_cpu_state(env, 0);
281 4ad40f36 bellard
#endif
282 93fcfe39 aliguori
    qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n",
283 93fcfe39 aliguori
              __func__, env->active_tc.PC, address, rw, mmu_idx, is_softmmu);
284 4ad40f36 bellard
285 4ad40f36 bellard
    rw &= 1;
286 4ad40f36 bellard
287 6af0bf9c bellard
    /* data access */
288 6af0bf9c bellard
    /* XXX: put correct access by using cpu_restore_state()
289 6af0bf9c bellard
       correctly */
290 6af0bf9c bellard
    access_type = ACCESS_INT;
291 932e71cd aurel32
#if defined(CONFIG_USER_ONLY)
292 932e71cd aurel32
    ret = TLBRET_NOMATCH;
293 932e71cd aurel32
#else
294 6af0bf9c bellard
    ret = get_physical_address(env, &physical, &prot,
295 6af0bf9c bellard
                               address, rw, access_type);
296 60c9af07 Aurelien Jarno
    qemu_log("%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_plx " prot %d\n",
297 93fcfe39 aliguori
              __func__, address, ret, physical, prot);
298 43057ab1 bellard
    if (ret == TLBRET_MATCH) {
299 d4c430a8 Paul Brook
       tlb_set_page(env, address & TARGET_PAGE_MASK,
300 d4c430a8 Paul Brook
                    physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
301 d4c430a8 Paul Brook
                    mmu_idx, TARGET_PAGE_SIZE);
302 d4c430a8 Paul Brook
       ret = 0;
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 c36bbb28 Aurelien Jarno
target_phys_addr_t cpu_mips_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 c36bbb28 Aurelien Jarno
        return -1LL;
330 c36bbb28 Aurelien Jarno
    } else {
331 c36bbb28 Aurelien Jarno
        return physical;
332 25b91e32 Aurelien Jarno
    }
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 bbfa8f72 Nathan Froyd
389 bbfa8f72 Nathan Froyd
static void set_hflags_for_handler (CPUState *env)
390 bbfa8f72 Nathan Froyd
{
391 bbfa8f72 Nathan Froyd
    /* Exception handlers are entered in 32-bit mode.  */
392 bbfa8f72 Nathan Froyd
    env->hflags &= ~(MIPS_HFLAG_M16);
393 bbfa8f72 Nathan Froyd
    /* ...except that microMIPS lets you choose.  */
394 bbfa8f72 Nathan Froyd
    if (env->insn_flags & ASE_MICROMIPS) {
395 bbfa8f72 Nathan Froyd
        env->hflags |= (!!(env->CP0_Config3
396 bbfa8f72 Nathan Froyd
                           & (1 << CP0C3_ISA_ON_EXC))
397 bbfa8f72 Nathan Froyd
                        << MIPS_HFLAG_M16_SHIFT);
398 bbfa8f72 Nathan Froyd
    }
399 bbfa8f72 Nathan Froyd
}
400 32188a03 Nathan Froyd
#endif
401 32188a03 Nathan Froyd
402 6af0bf9c bellard
void do_interrupt (CPUState *env)
403 6af0bf9c bellard
{
404 932e71cd aurel32
#if !defined(CONFIG_USER_ONLY)
405 932e71cd aurel32
    target_ulong offset;
406 932e71cd aurel32
    int cause = -1;
407 932e71cd aurel32
    const char *name;
408 100ce988 ths
409 93fcfe39 aliguori
    if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
410 932e71cd aurel32
        if (env->exception_index < 0 || env->exception_index > EXCP_LAST)
411 932e71cd aurel32
            name = "unknown";
412 932e71cd aurel32
        else
413 932e71cd aurel32
            name = excp_names[env->exception_index];
414 b67bfe8d ths
415 93fcfe39 aliguori
        qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
416 93fcfe39 aliguori
                 __func__, env->active_tc.PC, env->CP0_EPC, name);
417 932e71cd aurel32
    }
418 932e71cd aurel32
    if (env->exception_index == EXCP_EXT_INTERRUPT &&
419 932e71cd aurel32
        (env->hflags & MIPS_HFLAG_DM))
420 932e71cd aurel32
        env->exception_index = EXCP_DINT;
421 932e71cd aurel32
    offset = 0x180;
422 932e71cd aurel32
    switch (env->exception_index) {
423 932e71cd aurel32
    case EXCP_DSS:
424 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DSS;
425 932e71cd aurel32
        /* Debug single step cannot be raised inside a delay slot and
426 932e71cd aurel32
           resume will always occur on the next instruction
427 932e71cd aurel32
           (but we assume the pc has always been updated during
428 932e71cd aurel32
           code translation). */
429 32188a03 Nathan Froyd
        env->CP0_DEPC = env->active_tc.PC | !!(env->hflags & MIPS_HFLAG_M16);
430 932e71cd aurel32
        goto enter_debug_mode;
431 932e71cd aurel32
    case EXCP_DINT:
432 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DINT;
433 932e71cd aurel32
        goto set_DEPC;
434 932e71cd aurel32
    case EXCP_DIB:
435 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DIB;
436 932e71cd aurel32
        goto set_DEPC;
437 932e71cd aurel32
    case EXCP_DBp:
438 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DBp;
439 932e71cd aurel32
        goto set_DEPC;
440 932e71cd aurel32
    case EXCP_DDBS:
441 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DDBS;
442 932e71cd aurel32
        goto set_DEPC;
443 932e71cd aurel32
    case EXCP_DDBL:
444 932e71cd aurel32
        env->CP0_Debug |= 1 << CP0DB_DDBL;
445 932e71cd aurel32
    set_DEPC:
446 32188a03 Nathan Froyd
        env->CP0_DEPC = exception_resume_pc(env);
447 32188a03 Nathan Froyd
        env->hflags &= ~MIPS_HFLAG_BMASK;
448 0eaef5aa ths
 enter_debug_mode:
449 932e71cd aurel32
        env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
450 932e71cd aurel32
        env->hflags &= ~(MIPS_HFLAG_KSU);
451 932e71cd aurel32
        /* EJTAG probe trap enable is not implemented... */
452 932e71cd aurel32
        if (!(env->CP0_Status & (1 << CP0St_EXL)))
453 932e71cd aurel32
            env->CP0_Cause &= ~(1 << CP0Ca_BD);
454 932e71cd aurel32
        env->active_tc.PC = (int32_t)0xBFC00480;
455 bbfa8f72 Nathan Froyd
        set_hflags_for_handler(env);
456 932e71cd aurel32
        break;
457 932e71cd aurel32
    case EXCP_RESET:
458 932e71cd aurel32
        cpu_reset(env);
459 932e71cd aurel32
        break;
460 932e71cd aurel32
    case EXCP_SRESET:
461 932e71cd aurel32
        env->CP0_Status |= (1 << CP0St_SR);
462 932e71cd aurel32
        memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo));
463 932e71cd aurel32
        goto set_error_EPC;
464 932e71cd aurel32
    case EXCP_NMI:
465 932e71cd aurel32
        env->CP0_Status |= (1 << CP0St_NMI);
466 0eaef5aa ths
 set_error_EPC:
467 32188a03 Nathan Froyd
        env->CP0_ErrorEPC = exception_resume_pc(env);
468 32188a03 Nathan Froyd
        env->hflags &= ~MIPS_HFLAG_BMASK;
469 932e71cd aurel32
        env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
470 932e71cd aurel32
        env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
471 932e71cd aurel32
        env->hflags &= ~(MIPS_HFLAG_KSU);
472 932e71cd aurel32
        if (!(env->CP0_Status & (1 << CP0St_EXL)))
473 932e71cd aurel32
            env->CP0_Cause &= ~(1 << CP0Ca_BD);
474 932e71cd aurel32
        env->active_tc.PC = (int32_t)0xBFC00000;
475 bbfa8f72 Nathan Froyd
        set_hflags_for_handler(env);
476 932e71cd aurel32
        break;
477 932e71cd aurel32
    case EXCP_EXT_INTERRUPT:
478 932e71cd aurel32
        cause = 0;
479 932e71cd aurel32
        if (env->CP0_Cause & (1 << CP0Ca_IV))
480 932e71cd aurel32
            offset = 0x200;
481 138afb02 Edgar E. Iglesias
482 138afb02 Edgar E. Iglesias
        if (env->CP0_Config3 & ((1 << CP0C3_VInt) | (1 << CP0C3_VEIC))) {
483 138afb02 Edgar E. Iglesias
            /* Vectored Interrupts.  */
484 138afb02 Edgar E. Iglesias
            unsigned int spacing;
485 138afb02 Edgar E. Iglesias
            unsigned int vector;
486 138afb02 Edgar E. Iglesias
            unsigned int pending = (env->CP0_Cause & CP0Ca_IP_mask) >> 8;
487 138afb02 Edgar E. Iglesias
488 138afb02 Edgar E. Iglesias
            /* Compute the Vector Spacing.  */
489 138afb02 Edgar E. Iglesias
            spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & ((1 << 6) - 1);
490 138afb02 Edgar E. Iglesias
            spacing <<= 5;
491 138afb02 Edgar E. Iglesias
492 138afb02 Edgar E. Iglesias
            if (env->CP0_Config3 & (1 << CP0C3_VInt)) {
493 138afb02 Edgar E. Iglesias
                /* For VInt mode, the MIPS computes the vector internally.  */
494 138afb02 Edgar E. Iglesias
                for (vector = 0; vector < 8; vector++) {
495 138afb02 Edgar E. Iglesias
                    if (pending & 1) {
496 138afb02 Edgar E. Iglesias
                        /* Found it.  */
497 138afb02 Edgar E. Iglesias
                        break;
498 138afb02 Edgar E. Iglesias
                    }
499 138afb02 Edgar E. Iglesias
                    pending >>= 1;
500 138afb02 Edgar E. Iglesias
                }
501 138afb02 Edgar E. Iglesias
            } else {
502 138afb02 Edgar E. Iglesias
                /* For VEIC mode, the external interrupt controller feeds the
503 138afb02 Edgar E. Iglesias
                   vector throught the CP0Cause IP lines.  */
504 138afb02 Edgar E. Iglesias
                vector = pending;
505 138afb02 Edgar E. Iglesias
            }
506 138afb02 Edgar E. Iglesias
            offset = 0x200 + vector * spacing;
507 138afb02 Edgar E. Iglesias
        }
508 932e71cd aurel32
        goto set_EPC;
509 932e71cd aurel32
    case EXCP_LTLBL:
510 932e71cd aurel32
        cause = 1;
511 932e71cd aurel32
        goto set_EPC;
512 932e71cd aurel32
    case EXCP_TLBL:
513 932e71cd aurel32
        cause = 2;
514 932e71cd aurel32
        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
515 0eaef5aa ths
#if defined(TARGET_MIPS64)
516 932e71cd aurel32
            int R = env->CP0_BadVAddr >> 62;
517 932e71cd aurel32
            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
518 932e71cd aurel32
            int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
519 932e71cd aurel32
            int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
520 0eaef5aa ths
521 3fc00a7b Aurelien Jarno
            if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
522 3fc00a7b Aurelien Jarno
                (!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
523 932e71cd aurel32
                offset = 0x080;
524 932e71cd aurel32
            else
525 0eaef5aa ths
#endif
526 932e71cd aurel32
                offset = 0x000;
527 932e71cd aurel32
        }
528 932e71cd aurel32
        goto set_EPC;
529 932e71cd aurel32
    case EXCP_TLBS:
530 932e71cd aurel32
        cause = 3;
531 932e71cd aurel32
        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
532 0eaef5aa ths
#if defined(TARGET_MIPS64)
533 932e71cd aurel32
            int R = env->CP0_BadVAddr >> 62;
534 932e71cd aurel32
            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
535 932e71cd aurel32
            int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
536 932e71cd aurel32
            int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
537 0eaef5aa ths
538 3fc00a7b Aurelien Jarno
            if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
539 3fc00a7b Aurelien Jarno
                (!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
540 932e71cd aurel32
                offset = 0x080;
541 932e71cd aurel32
            else
542 0eaef5aa ths
#endif
543 932e71cd aurel32
                offset = 0x000;
544 932e71cd aurel32
        }
545 932e71cd aurel32
        goto set_EPC;
546 932e71cd aurel32
    case EXCP_AdEL:
547 932e71cd aurel32
        cause = 4;
548 932e71cd aurel32
        goto set_EPC;
549 932e71cd aurel32
    case EXCP_AdES:
550 932e71cd aurel32
        cause = 5;
551 932e71cd aurel32
        goto set_EPC;
552 932e71cd aurel32
    case EXCP_IBE:
553 932e71cd aurel32
        cause = 6;
554 932e71cd aurel32
        goto set_EPC;
555 932e71cd aurel32
    case EXCP_DBE:
556 932e71cd aurel32
        cause = 7;
557 932e71cd aurel32
        goto set_EPC;
558 932e71cd aurel32
    case EXCP_SYSCALL:
559 932e71cd aurel32
        cause = 8;
560 932e71cd aurel32
        goto set_EPC;
561 932e71cd aurel32
    case EXCP_BREAK:
562 932e71cd aurel32
        cause = 9;
563 932e71cd aurel32
        goto set_EPC;
564 932e71cd aurel32
    case EXCP_RI:
565 932e71cd aurel32
        cause = 10;
566 932e71cd aurel32
        goto set_EPC;
567 932e71cd aurel32
    case EXCP_CpU:
568 932e71cd aurel32
        cause = 11;
569 932e71cd aurel32
        env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) |
570 932e71cd aurel32
                         (env->error_code << CP0Ca_CE);
571 932e71cd aurel32
        goto set_EPC;
572 932e71cd aurel32
    case EXCP_OVERFLOW:
573 932e71cd aurel32
        cause = 12;
574 932e71cd aurel32
        goto set_EPC;
575 932e71cd aurel32
    case EXCP_TRAP:
576 932e71cd aurel32
        cause = 13;
577 932e71cd aurel32
        goto set_EPC;
578 932e71cd aurel32
    case EXCP_FPE:
579 932e71cd aurel32
        cause = 15;
580 932e71cd aurel32
        goto set_EPC;
581 932e71cd aurel32
    case EXCP_C2E:
582 932e71cd aurel32
        cause = 18;
583 932e71cd aurel32
        goto set_EPC;
584 932e71cd aurel32
    case EXCP_MDMX:
585 932e71cd aurel32
        cause = 22;
586 932e71cd aurel32
        goto set_EPC;
587 932e71cd aurel32
    case EXCP_DWATCH:
588 932e71cd aurel32
        cause = 23;
589 932e71cd aurel32
        /* XXX: TODO: manage defered watch exceptions */
590 932e71cd aurel32
        goto set_EPC;
591 932e71cd aurel32
    case EXCP_MCHECK:
592 932e71cd aurel32
        cause = 24;
593 932e71cd aurel32
        goto set_EPC;
594 932e71cd aurel32
    case EXCP_THREAD:
595 932e71cd aurel32
        cause = 25;
596 932e71cd aurel32
        goto set_EPC;
597 932e71cd aurel32
    case EXCP_CACHE:
598 932e71cd aurel32
        cause = 30;
599 932e71cd aurel32
        if (env->CP0_Status & (1 << CP0St_BEV)) {
600 932e71cd aurel32
            offset = 0x100;
601 932e71cd aurel32
        } else {
602 932e71cd aurel32
            offset = 0x20000100;
603 932e71cd aurel32
        }
604 0eaef5aa ths
 set_EPC:
605 932e71cd aurel32
        if (!(env->CP0_Status & (1 << CP0St_EXL))) {
606 32188a03 Nathan Froyd
            env->CP0_EPC = exception_resume_pc(env);
607 932e71cd aurel32
            if (env->hflags & MIPS_HFLAG_BMASK) {
608 932e71cd aurel32
                env->CP0_Cause |= (1 << CP0Ca_BD);
609 0eaef5aa ths
            } else {
610 932e71cd aurel32
                env->CP0_Cause &= ~(1 << CP0Ca_BD);
611 0eaef5aa ths
            }
612 932e71cd aurel32
            env->CP0_Status |= (1 << CP0St_EXL);
613 932e71cd aurel32
            env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
614 932e71cd aurel32
            env->hflags &= ~(MIPS_HFLAG_KSU);
615 6af0bf9c bellard
        }
616 932e71cd aurel32
        env->hflags &= ~MIPS_HFLAG_BMASK;
617 932e71cd aurel32
        if (env->CP0_Status & (1 << CP0St_BEV)) {
618 932e71cd aurel32
            env->active_tc.PC = (int32_t)0xBFC00200;
619 932e71cd aurel32
        } else {
620 932e71cd aurel32
            env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
621 6af0bf9c bellard
        }
622 932e71cd aurel32
        env->active_tc.PC += offset;
623 bbfa8f72 Nathan Froyd
        set_hflags_for_handler(env);
624 932e71cd aurel32
        env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
625 932e71cd aurel32
        break;
626 932e71cd aurel32
    default:
627 93fcfe39 aliguori
        qemu_log("Invalid MIPS exception %d. Exiting\n", env->exception_index);
628 932e71cd aurel32
        printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
629 932e71cd aurel32
        exit(1);
630 932e71cd aurel32
    }
631 93fcfe39 aliguori
    if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
632 93fcfe39 aliguori
        qemu_log("%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
633 932e71cd aurel32
                "    S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
634 932e71cd aurel32
                __func__, env->active_tc.PC, env->CP0_EPC, cause,
635 932e71cd aurel32
                env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
636 932e71cd aurel32
                env->CP0_DEPC);
637 6af0bf9c bellard
    }
638 932e71cd aurel32
#endif
639 6af0bf9c bellard
    env->exception_index = EXCP_NONE;
640 6af0bf9c bellard
}
641 2ee4aed8 bellard
642 3c7b48b7 Paul Brook
#if !defined(CONFIG_USER_ONLY)
643 29929e34 ths
void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
644 2ee4aed8 bellard
{
645 c227f099 Anthony Liguori
    r4k_tlb_t *tlb;
646 3b1c8be4 ths
    target_ulong addr;
647 3b1c8be4 ths
    target_ulong end;
648 3b1c8be4 ths
    uint8_t ASID = env->CP0_EntryHi & 0xFF;
649 3b1c8be4 ths
    target_ulong mask;
650 2ee4aed8 bellard
651 ead9360e ths
    tlb = &env->tlb->mmu.r4k.tlb[idx];
652 f2e9ebef ths
    /* The qemu TLB is flushed when the ASID changes, so no need to
653 2ee4aed8 bellard
       flush these entries again.  */
654 2ee4aed8 bellard
    if (tlb->G == 0 && tlb->ASID != ASID) {
655 2ee4aed8 bellard
        return;
656 2ee4aed8 bellard
    }
657 2ee4aed8 bellard
658 ead9360e ths
    if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) {
659 2ee4aed8 bellard
        /* For tlbwr, we can shadow the discarded entry into
660 6958549d aurel32
           a new (fake) TLB entry, as long as the guest can not
661 6958549d aurel32
           tell that it's there.  */
662 ead9360e ths
        env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb;
663 ead9360e ths
        env->tlb->tlb_in_use++;
664 2ee4aed8 bellard
        return;
665 2ee4aed8 bellard
    }
666 2ee4aed8 bellard
667 3b1c8be4 ths
    /* 1k pages are not supported. */
668 f2e9ebef ths
    mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
669 3b1c8be4 ths
    if (tlb->V0) {
670 f2e9ebef ths
        addr = tlb->VPN & ~mask;
671 d26bc211 ths
#if defined(TARGET_MIPS64)
672 e034e2c3 ths
        if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
673 100ce988 ths
            addr |= 0x3FFFFF0000000000ULL;
674 100ce988 ths
        }
675 100ce988 ths
#endif
676 3b1c8be4 ths
        end = addr | (mask >> 1);
677 3b1c8be4 ths
        while (addr < end) {
678 3b1c8be4 ths
            tlb_flush_page (env, addr);
679 3b1c8be4 ths
            addr += TARGET_PAGE_SIZE;
680 3b1c8be4 ths
        }
681 3b1c8be4 ths
    }
682 3b1c8be4 ths
    if (tlb->V1) {
683 f2e9ebef ths
        addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
684 d26bc211 ths
#if defined(TARGET_MIPS64)
685 e034e2c3 ths
        if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
686 100ce988 ths
            addr |= 0x3FFFFF0000000000ULL;
687 100ce988 ths
        }
688 100ce988 ths
#endif
689 3b1c8be4 ths
        end = addr | mask;
690 53715e48 ths
        while (addr - 1 < end) {
691 3b1c8be4 ths
            tlb_flush_page (env, addr);
692 3b1c8be4 ths
            addr += TARGET_PAGE_SIZE;
693 3b1c8be4 ths
        }
694 3b1c8be4 ths
    }
695 2ee4aed8 bellard
}
696 3c7b48b7 Paul Brook
#endif