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