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