|
|
1.1 ! root 1: /* ! 2: * MicroBlaze helper routines. ! 3: * ! 4: * Copyright (c) 2009 Edgar E. Iglesias <[email protected]> ! 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, see <http://www.gnu.org/licenses/>. ! 18: */ ! 19: ! 20: #include <stdio.h> ! 21: #include <string.h> ! 22: #include <assert.h> ! 23: ! 24: #include "config.h" ! 25: #include "cpu.h" ! 26: #include "exec-all.h" ! 27: #include "host-utils.h" ! 28: ! 29: #define D(x) ! 30: #define DMMU(x) ! 31: ! 32: #if defined(CONFIG_USER_ONLY) ! 33: ! 34: void do_interrupt (CPUState *env) ! 35: { ! 36: env->exception_index = -1; ! 37: env->regs[14] = env->sregs[SR_PC]; ! 38: } ! 39: ! 40: int cpu_mb_handle_mmu_fault(CPUState * env, target_ulong address, int rw, ! 41: int mmu_idx, int is_softmmu) ! 42: { ! 43: env->exception_index = 0xaa; ! 44: cpu_dump_state(env, stderr, fprintf, 0); ! 45: return 1; ! 46: } ! 47: ! 48: target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) ! 49: { ! 50: return addr; ! 51: } ! 52: ! 53: #else /* !CONFIG_USER_ONLY */ ! 54: ! 55: int cpu_mb_handle_mmu_fault (CPUState *env, target_ulong address, int rw, ! 56: int mmu_idx, int is_softmmu) ! 57: { ! 58: unsigned int hit; ! 59: unsigned int mmu_available; ! 60: int r = 1; ! 61: int prot; ! 62: ! 63: mmu_available = 0; ! 64: if (env->pvr.regs[0] & PVR0_USE_MMU) { ! 65: mmu_available = 1; ! 66: if ((env->pvr.regs[0] & PVR0_PVR_FULL_MASK) ! 67: && (env->pvr.regs[11] & PVR11_USE_MMU) != PVR11_USE_MMU) { ! 68: mmu_available = 0; ! 69: } ! 70: } ! 71: ! 72: /* Translate if the MMU is available and enabled. */ ! 73: if (mmu_available && (env->sregs[SR_MSR] & MSR_VM)) { ! 74: target_ulong vaddr, paddr; ! 75: struct microblaze_mmu_lookup lu; ! 76: ! 77: hit = mmu_translate(&env->mmu, &lu, address, rw, mmu_idx); ! 78: if (hit) { ! 79: vaddr = address & TARGET_PAGE_MASK; ! 80: paddr = lu.paddr + vaddr - lu.vaddr; ! 81: ! 82: DMMU(qemu_log("MMU map mmu=%d v=%x p=%x prot=%x\n", ! 83: mmu_idx, vaddr, paddr, lu.prot)); ! 84: r = tlb_set_page(env, vaddr, ! 85: paddr, lu.prot, mmu_idx, is_softmmu); ! 86: } else { ! 87: env->sregs[SR_EAR] = address; ! 88: DMMU(qemu_log("mmu=%d miss addr=%x\n", mmu_idx, vaddr)); ! 89: ! 90: switch (lu.err) { ! 91: case ERR_PROT: ! 92: env->sregs[SR_ESR] = rw == 2 ? 17 : 16; ! 93: env->sregs[SR_ESR] |= (rw == 1) << 10; ! 94: break; ! 95: case ERR_MISS: ! 96: env->sregs[SR_ESR] = rw == 2 ? 19 : 18; ! 97: env->sregs[SR_ESR] |= (rw == 1) << 10; ! 98: break; ! 99: default: ! 100: abort(); ! 101: break; ! 102: } ! 103: ! 104: if (env->exception_index == EXCP_MMU) { ! 105: cpu_abort(env, "recursive faults\n"); ! 106: } ! 107: ! 108: /* TLB miss. */ ! 109: env->exception_index = EXCP_MMU; ! 110: } ! 111: } else { ! 112: /* MMU disabled or not available. */ ! 113: address &= TARGET_PAGE_MASK; ! 114: prot = PAGE_BITS; ! 115: r = tlb_set_page(env, address, address, prot, mmu_idx, is_softmmu); ! 116: } ! 117: return r; ! 118: } ! 119: ! 120: void do_interrupt(CPUState *env) ! 121: { ! 122: uint32_t t; ! 123: ! 124: /* IMM flag cannot propagate accross a branch and into the dslot. */ ! 125: assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG))); ! 126: assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG))); ! 127: /* assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions. */ ! 128: switch (env->exception_index) { ! 129: case EXCP_MMU: ! 130: env->regs[17] = env->sregs[SR_PC]; ! 131: ! 132: /* Exception breaks branch + dslot sequence? */ ! 133: if (env->iflags & D_FLAG) { ! 134: D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm)); ! 135: env->sregs[SR_ESR] |= 1 << 12 ; ! 136: env->sregs[SR_BTR] = env->btarget; ! 137: ! 138: /* Reexecute the branch. */ ! 139: env->regs[17] -= 4; ! 140: /* was the branch immprefixed?. */ ! 141: if (env->bimm) { ! 142: qemu_log_mask(CPU_LOG_INT, ! 143: "bimm exception at pc=%x iflags=%x\n", ! 144: env->sregs[SR_PC], env->iflags); ! 145: env->regs[17] -= 4; ! 146: log_cpu_state_mask(CPU_LOG_INT, env, 0); ! 147: } ! 148: } else if (env->iflags & IMM_FLAG) { ! 149: D(qemu_log("IMM_FLAG set at exception\n")); ! 150: env->regs[17] -= 4; ! 151: } ! 152: ! 153: /* Disable the MMU. */ ! 154: t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; ! 155: env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); ! 156: env->sregs[SR_MSR] |= t; ! 157: /* Exception in progress. */ ! 158: env->sregs[SR_MSR] |= MSR_EIP; ! 159: ! 160: qemu_log_mask(CPU_LOG_INT, ! 161: "exception at pc=%x ear=%x iflags=%x\n", ! 162: env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags); ! 163: log_cpu_state_mask(CPU_LOG_INT, env, 0); ! 164: env->iflags &= ~(IMM_FLAG | D_FLAG); ! 165: env->sregs[SR_PC] = 0x20; ! 166: break; ! 167: ! 168: case EXCP_IRQ: ! 169: assert(!(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))); ! 170: assert(env->sregs[SR_MSR] & MSR_IE); ! 171: assert(!(env->iflags & D_FLAG)); ! 172: ! 173: t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; ! 174: ! 175: #if 0 ! 176: #include "disas.h" ! 177: ! 178: /* Useful instrumentation when debugging interrupt issues in either ! 179: the models or in sw. */ ! 180: { ! 181: const char *sym; ! 182: ! 183: sym = lookup_symbol(env->sregs[SR_PC]); ! 184: if (sym ! 185: && (!strcmp("netif_rx", sym) ! 186: || !strcmp("process_backlog", sym))) { ! 187: ! 188: qemu_log( ! 189: "interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n", ! 190: env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags, ! 191: sym); ! 192: ! 193: log_cpu_state(env, 0); ! 194: } ! 195: } ! 196: #endif ! 197: qemu_log_mask(CPU_LOG_INT, ! 198: "interrupt at pc=%x msr=%x %x iflags=%x\n", ! 199: env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags); ! 200: ! 201: env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \ ! 202: | MSR_UM | MSR_IE); ! 203: env->sregs[SR_MSR] |= t; ! 204: ! 205: env->regs[14] = env->sregs[SR_PC]; ! 206: env->sregs[SR_PC] = 0x10; ! 207: //log_cpu_state_mask(CPU_LOG_INT, env, 0); ! 208: break; ! 209: ! 210: case EXCP_BREAK: ! 211: case EXCP_HW_BREAK: ! 212: assert(!(env->iflags & IMM_FLAG)); ! 213: assert(!(env->iflags & D_FLAG)); ! 214: t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; ! 215: qemu_log_mask(CPU_LOG_INT, ! 216: "break at pc=%x msr=%x %x iflags=%x\n", ! 217: env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags); ! 218: log_cpu_state_mask(CPU_LOG_INT, env, 0); ! 219: env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); ! 220: env->sregs[SR_MSR] |= t; ! 221: env->sregs[SR_MSR] |= MSR_BIP; ! 222: if (env->exception_index == EXCP_HW_BREAK) { ! 223: env->regs[16] = env->sregs[SR_PC]; ! 224: env->sregs[SR_MSR] |= MSR_BIP; ! 225: env->sregs[SR_PC] = 0x18; ! 226: } else ! 227: env->sregs[SR_PC] = env->btarget; ! 228: break; ! 229: default: ! 230: cpu_abort(env, "unhandled exception type=%d\n", ! 231: env->exception_index); ! 232: break; ! 233: } ! 234: } ! 235: ! 236: target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) ! 237: { ! 238: target_ulong vaddr, paddr = 0; ! 239: struct microblaze_mmu_lookup lu; ! 240: unsigned int hit; ! 241: ! 242: if (env->sregs[SR_MSR] & MSR_VM) { ! 243: hit = mmu_translate(&env->mmu, &lu, addr, 0, 0); ! 244: if (hit) { ! 245: vaddr = addr & TARGET_PAGE_MASK; ! 246: paddr = lu.paddr + vaddr - lu.vaddr; ! 247: } else ! 248: paddr = 0; /* ???. */ ! 249: } else ! 250: paddr = addr & TARGET_PAGE_MASK; ! 251: ! 252: return paddr; ! 253: } ! 254: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.