14acb54baSEdgar E. Iglesias /* 24acb54baSEdgar E. Iglesias * MicroBlaze helper routines. 34acb54baSEdgar E. Iglesias * 44acb54baSEdgar E. Iglesias * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com> 5dadc1064SPeter A. G. Crosthwaite * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd. 64acb54baSEdgar E. Iglesias * 74acb54baSEdgar E. Iglesias * This library is free software; you can redistribute it and/or 84acb54baSEdgar E. Iglesias * modify it under the terms of the GNU Lesser General Public 94acb54baSEdgar E. Iglesias * License as published by the Free Software Foundation; either 104acb54baSEdgar E. Iglesias * version 2 of the License, or (at your option) any later version. 114acb54baSEdgar E. Iglesias * 124acb54baSEdgar E. Iglesias * This library is distributed in the hope that it will be useful, 134acb54baSEdgar E. Iglesias * but WITHOUT ANY WARRANTY; without even the implied warranty of 144acb54baSEdgar E. Iglesias * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 154acb54baSEdgar E. Iglesias * Lesser General Public License for more details. 164acb54baSEdgar E. Iglesias * 174acb54baSEdgar E. Iglesias * You should have received a copy of the GNU Lesser General Public 188167ee88SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 194acb54baSEdgar E. Iglesias */ 204acb54baSEdgar E. Iglesias 214acb54baSEdgar E. Iglesias #include "cpu.h" 221de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 234acb54baSEdgar E. Iglesias 244acb54baSEdgar E. Iglesias #define D(x) 254acb54baSEdgar E. Iglesias #define DMMU(x) 264acb54baSEdgar E. Iglesias 274acb54baSEdgar E. Iglesias #if defined(CONFIG_USER_ONLY) 284acb54baSEdgar E. Iglesias 2997a8ea5aSAndreas Färber void mb_cpu_do_interrupt(CPUState *cs) 304acb54baSEdgar E. Iglesias { 3197a8ea5aSAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 3297a8ea5aSAndreas Färber CPUMBState *env = &cpu->env; 3397a8ea5aSAndreas Färber 344acb54baSEdgar E. Iglesias env->exception_index = -1; 358cc9b43fSPeter A. G. Crosthwaite env->res_addr = RES_ADDR_NONE; 364acb54baSEdgar E. Iglesias env->regs[14] = env->sregs[SR_PC]; 374acb54baSEdgar E. Iglesias } 384acb54baSEdgar E. Iglesias 3968cee38aSAndreas Färber int cpu_mb_handle_mmu_fault(CPUMBState * env, target_ulong address, int rw, 4097b348e7SBlue Swirl int mmu_idx) 414acb54baSEdgar E. Iglesias { 42878096eeSAndreas Färber MicroBlazeCPU *cpu = mb_env_get_cpu(env); 43878096eeSAndreas Färber 444acb54baSEdgar E. Iglesias env->exception_index = 0xaa; 45878096eeSAndreas Färber cpu_dump_state(CPU(cpu), stderr, fprintf, 0); 464acb54baSEdgar E. Iglesias return 1; 474acb54baSEdgar E. Iglesias } 484acb54baSEdgar E. Iglesias 494acb54baSEdgar E. Iglesias #else /* !CONFIG_USER_ONLY */ 504acb54baSEdgar E. Iglesias 5168cee38aSAndreas Färber int cpu_mb_handle_mmu_fault (CPUMBState *env, target_ulong address, int rw, 5297b348e7SBlue Swirl int mmu_idx) 534acb54baSEdgar E. Iglesias { 544acb54baSEdgar E. Iglesias unsigned int hit; 554acb54baSEdgar E. Iglesias unsigned int mmu_available; 564acb54baSEdgar E. Iglesias int r = 1; 574acb54baSEdgar E. Iglesias int prot; 584acb54baSEdgar E. Iglesias 594acb54baSEdgar E. Iglesias mmu_available = 0; 604acb54baSEdgar E. Iglesias if (env->pvr.regs[0] & PVR0_USE_MMU) { 614acb54baSEdgar E. Iglesias mmu_available = 1; 624acb54baSEdgar E. Iglesias if ((env->pvr.regs[0] & PVR0_PVR_FULL_MASK) 634acb54baSEdgar E. Iglesias && (env->pvr.regs[11] & PVR11_USE_MMU) != PVR11_USE_MMU) { 644acb54baSEdgar E. Iglesias mmu_available = 0; 654acb54baSEdgar E. Iglesias } 664acb54baSEdgar E. Iglesias } 674acb54baSEdgar E. Iglesias 684acb54baSEdgar E. Iglesias /* Translate if the MMU is available and enabled. */ 694acb54baSEdgar E. Iglesias if (mmu_available && (env->sregs[SR_MSR] & MSR_VM)) { 704acb54baSEdgar E. Iglesias target_ulong vaddr, paddr; 714acb54baSEdgar E. Iglesias struct microblaze_mmu_lookup lu; 724acb54baSEdgar E. Iglesias 734acb54baSEdgar E. Iglesias hit = mmu_translate(&env->mmu, &lu, address, rw, mmu_idx); 744acb54baSEdgar E. Iglesias if (hit) { 754acb54baSEdgar E. Iglesias vaddr = address & TARGET_PAGE_MASK; 764acb54baSEdgar E. Iglesias paddr = lu.paddr + vaddr - lu.vaddr; 774acb54baSEdgar E. Iglesias 784acb54baSEdgar E. Iglesias DMMU(qemu_log("MMU map mmu=%d v=%x p=%x prot=%x\n", 794acb54baSEdgar E. Iglesias mmu_idx, vaddr, paddr, lu.prot)); 80d4c430a8SPaul Brook tlb_set_page(env, vaddr, paddr, lu.prot, mmu_idx, TARGET_PAGE_SIZE); 81d4c430a8SPaul Brook r = 0; 824acb54baSEdgar E. Iglesias } else { 834acb54baSEdgar E. Iglesias env->sregs[SR_EAR] = address; 8421d20636SEdgar E. Iglesias DMMU(qemu_log("mmu=%d miss v=%x\n", mmu_idx, address)); 854acb54baSEdgar E. Iglesias 864acb54baSEdgar E. Iglesias switch (lu.err) { 874acb54baSEdgar E. Iglesias case ERR_PROT: 884acb54baSEdgar E. Iglesias env->sregs[SR_ESR] = rw == 2 ? 17 : 16; 894acb54baSEdgar E. Iglesias env->sregs[SR_ESR] |= (rw == 1) << 10; 904acb54baSEdgar E. Iglesias break; 914acb54baSEdgar E. Iglesias case ERR_MISS: 924acb54baSEdgar E. Iglesias env->sregs[SR_ESR] = rw == 2 ? 19 : 18; 934acb54baSEdgar E. Iglesias env->sregs[SR_ESR] |= (rw == 1) << 10; 944acb54baSEdgar E. Iglesias break; 954acb54baSEdgar E. Iglesias default: 964acb54baSEdgar E. Iglesias abort(); 974acb54baSEdgar E. Iglesias break; 984acb54baSEdgar E. Iglesias } 994acb54baSEdgar E. Iglesias 1004acb54baSEdgar E. Iglesias if (env->exception_index == EXCP_MMU) { 1014acb54baSEdgar E. Iglesias cpu_abort(env, "recursive faults\n"); 1024acb54baSEdgar E. Iglesias } 1034acb54baSEdgar E. Iglesias 1044acb54baSEdgar E. Iglesias /* TLB miss. */ 1054acb54baSEdgar E. Iglesias env->exception_index = EXCP_MMU; 1064acb54baSEdgar E. Iglesias } 1074acb54baSEdgar E. Iglesias } else { 1084acb54baSEdgar E. Iglesias /* MMU disabled or not available. */ 1094acb54baSEdgar E. Iglesias address &= TARGET_PAGE_MASK; 1104acb54baSEdgar E. Iglesias prot = PAGE_BITS; 111d4c430a8SPaul Brook tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE); 112d4c430a8SPaul Brook r = 0; 1134acb54baSEdgar E. Iglesias } 1144acb54baSEdgar E. Iglesias return r; 1154acb54baSEdgar E. Iglesias } 1164acb54baSEdgar E. Iglesias 11797a8ea5aSAndreas Färber void mb_cpu_do_interrupt(CPUState *cs) 1184acb54baSEdgar E. Iglesias { 11997a8ea5aSAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 12097a8ea5aSAndreas Färber CPUMBState *env = &cpu->env; 1214acb54baSEdgar E. Iglesias uint32_t t; 1224acb54baSEdgar E. Iglesias 1235225d669SStefan Weil /* IMM flag cannot propagate across a branch and into the dslot. */ 1244acb54baSEdgar E. Iglesias assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG))); 1254acb54baSEdgar E. Iglesias assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG))); 1264acb54baSEdgar E. Iglesias /* assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions. */ 1278cc9b43fSPeter A. G. Crosthwaite env->res_addr = RES_ADDR_NONE; 1284acb54baSEdgar E. Iglesias switch (env->exception_index) { 129cedb936bSEdgar E. Iglesias case EXCP_HW_EXCP: 130cedb936bSEdgar E. Iglesias if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) { 131cedb936bSEdgar E. Iglesias qemu_log("Exception raised on system without exceptions!\n"); 132cedb936bSEdgar E. Iglesias return; 133cedb936bSEdgar E. Iglesias } 134cedb936bSEdgar E. Iglesias 135cedb936bSEdgar E. Iglesias env->regs[17] = env->sregs[SR_PC] + 4; 136cedb936bSEdgar E. Iglesias env->sregs[SR_ESR] &= ~(1 << 12); 137cedb936bSEdgar E. Iglesias 138cedb936bSEdgar E. Iglesias /* Exception breaks branch + dslot sequence? */ 139cedb936bSEdgar E. Iglesias if (env->iflags & D_FLAG) { 140cedb936bSEdgar E. Iglesias env->sregs[SR_ESR] |= 1 << 12 ; 141cedb936bSEdgar E. Iglesias env->sregs[SR_BTR] = env->btarget; 142cedb936bSEdgar E. Iglesias } 143cedb936bSEdgar E. Iglesias 144cedb936bSEdgar E. Iglesias /* Disable the MMU. */ 145cedb936bSEdgar E. Iglesias t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; 146cedb936bSEdgar E. Iglesias env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); 147cedb936bSEdgar E. Iglesias env->sregs[SR_MSR] |= t; 148cedb936bSEdgar E. Iglesias /* Exception in progress. */ 149cedb936bSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_EIP; 150cedb936bSEdgar E. Iglesias 151cedb936bSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 152cedb936bSEdgar E. Iglesias "hw exception at pc=%x ear=%x esr=%x iflags=%x\n", 153cedb936bSEdgar E. Iglesias env->sregs[SR_PC], env->sregs[SR_EAR], 154cedb936bSEdgar E. Iglesias env->sregs[SR_ESR], env->iflags); 155a0762859SAndreas Färber log_cpu_state_mask(CPU_LOG_INT, cs, 0); 156cedb936bSEdgar E. Iglesias env->iflags &= ~(IMM_FLAG | D_FLAG); 157a1bff71cSEdgar E. Iglesias env->sregs[SR_PC] = cpu->base_vectors + 0x20; 158cedb936bSEdgar E. Iglesias break; 159cedb936bSEdgar E. Iglesias 1604acb54baSEdgar E. Iglesias case EXCP_MMU: 1614acb54baSEdgar E. Iglesias env->regs[17] = env->sregs[SR_PC]; 1624acb54baSEdgar E. Iglesias 163a75cf0c5SEdgar E. Iglesias env->sregs[SR_ESR] &= ~(1 << 12); 1644acb54baSEdgar E. Iglesias /* Exception breaks branch + dslot sequence? */ 1654acb54baSEdgar E. Iglesias if (env->iflags & D_FLAG) { 1664acb54baSEdgar E. Iglesias D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm)); 1674acb54baSEdgar E. Iglesias env->sregs[SR_ESR] |= 1 << 12 ; 1684acb54baSEdgar E. Iglesias env->sregs[SR_BTR] = env->btarget; 1694acb54baSEdgar E. Iglesias 1704acb54baSEdgar E. Iglesias /* Reexecute the branch. */ 1714acb54baSEdgar E. Iglesias env->regs[17] -= 4; 1724acb54baSEdgar E. Iglesias /* was the branch immprefixed?. */ 1734acb54baSEdgar E. Iglesias if (env->bimm) { 1744acb54baSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 1754acb54baSEdgar E. Iglesias "bimm exception at pc=%x iflags=%x\n", 1764acb54baSEdgar E. Iglesias env->sregs[SR_PC], env->iflags); 1774acb54baSEdgar E. Iglesias env->regs[17] -= 4; 178a0762859SAndreas Färber log_cpu_state_mask(CPU_LOG_INT, cs, 0); 1794acb54baSEdgar E. Iglesias } 1804acb54baSEdgar E. Iglesias } else if (env->iflags & IMM_FLAG) { 1814acb54baSEdgar E. Iglesias D(qemu_log("IMM_FLAG set at exception\n")); 1824acb54baSEdgar E. Iglesias env->regs[17] -= 4; 1834acb54baSEdgar E. Iglesias } 1844acb54baSEdgar E. Iglesias 1854acb54baSEdgar E. Iglesias /* Disable the MMU. */ 1864acb54baSEdgar E. Iglesias t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; 1874acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); 1884acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= t; 1894acb54baSEdgar E. Iglesias /* Exception in progress. */ 1904acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_EIP; 1914acb54baSEdgar E. Iglesias 1924acb54baSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 1934acb54baSEdgar E. Iglesias "exception at pc=%x ear=%x iflags=%x\n", 1944acb54baSEdgar E. Iglesias env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags); 195a0762859SAndreas Färber log_cpu_state_mask(CPU_LOG_INT, cs, 0); 1964acb54baSEdgar E. Iglesias env->iflags &= ~(IMM_FLAG | D_FLAG); 197a1bff71cSEdgar E. Iglesias env->sregs[SR_PC] = cpu->base_vectors + 0x20; 1984acb54baSEdgar E. Iglesias break; 1994acb54baSEdgar E. Iglesias 2004acb54baSEdgar E. Iglesias case EXCP_IRQ: 2014acb54baSEdgar E. Iglesias assert(!(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))); 2024acb54baSEdgar E. Iglesias assert(env->sregs[SR_MSR] & MSR_IE); 2034acb54baSEdgar E. Iglesias assert(!(env->iflags & D_FLAG)); 2044acb54baSEdgar E. Iglesias 2054acb54baSEdgar E. Iglesias t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; 2064acb54baSEdgar E. Iglesias 2074acb54baSEdgar E. Iglesias #if 0 20876cad711SPaolo Bonzini #include "disas/disas.h" 2094acb54baSEdgar E. Iglesias 2104acb54baSEdgar E. Iglesias /* Useful instrumentation when debugging interrupt issues in either 2114acb54baSEdgar E. Iglesias the models or in sw. */ 2124acb54baSEdgar E. Iglesias { 2134acb54baSEdgar E. Iglesias const char *sym; 2144acb54baSEdgar E. Iglesias 2154acb54baSEdgar E. Iglesias sym = lookup_symbol(env->sregs[SR_PC]); 2164acb54baSEdgar E. Iglesias if (sym 2174acb54baSEdgar E. Iglesias && (!strcmp("netif_rx", sym) 2184acb54baSEdgar E. Iglesias || !strcmp("process_backlog", sym))) { 2194acb54baSEdgar E. Iglesias 2204acb54baSEdgar E. Iglesias qemu_log( 2214acb54baSEdgar E. Iglesias "interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n", 2224acb54baSEdgar E. Iglesias env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags, 2234acb54baSEdgar E. Iglesias sym); 2244acb54baSEdgar E. Iglesias 225a0762859SAndreas Färber log_cpu_state(cs, 0); 2264acb54baSEdgar E. Iglesias } 2274acb54baSEdgar E. Iglesias } 2284acb54baSEdgar E. Iglesias #endif 2294acb54baSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 2304acb54baSEdgar E. Iglesias "interrupt at pc=%x msr=%x %x iflags=%x\n", 2314acb54baSEdgar E. Iglesias env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags); 2324acb54baSEdgar E. Iglesias 2334acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \ 2344acb54baSEdgar E. Iglesias | MSR_UM | MSR_IE); 2354acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= t; 2364acb54baSEdgar E. Iglesias 2374acb54baSEdgar E. Iglesias env->regs[14] = env->sregs[SR_PC]; 238a1bff71cSEdgar E. Iglesias env->sregs[SR_PC] = cpu->base_vectors + 0x10; 239a0762859SAndreas Färber //log_cpu_state_mask(CPU_LOG_INT, cs, 0); 2404acb54baSEdgar E. Iglesias break; 2414acb54baSEdgar E. Iglesias 2424acb54baSEdgar E. Iglesias case EXCP_BREAK: 2434acb54baSEdgar E. Iglesias case EXCP_HW_BREAK: 2444acb54baSEdgar E. Iglesias assert(!(env->iflags & IMM_FLAG)); 2454acb54baSEdgar E. Iglesias assert(!(env->iflags & D_FLAG)); 2464acb54baSEdgar E. Iglesias t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; 2474acb54baSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 2484acb54baSEdgar E. Iglesias "break at pc=%x msr=%x %x iflags=%x\n", 2494acb54baSEdgar E. Iglesias env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags); 250a0762859SAndreas Färber log_cpu_state_mask(CPU_LOG_INT, cs, 0); 2514acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); 2524acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= t; 2534acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_BIP; 2544acb54baSEdgar E. Iglesias if (env->exception_index == EXCP_HW_BREAK) { 2554acb54baSEdgar E. Iglesias env->regs[16] = env->sregs[SR_PC]; 2564acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_BIP; 257a1bff71cSEdgar E. Iglesias env->sregs[SR_PC] = cpu->base_vectors + 0x18; 2584acb54baSEdgar E. Iglesias } else 2594acb54baSEdgar E. Iglesias env->sregs[SR_PC] = env->btarget; 2604acb54baSEdgar E. Iglesias break; 2614acb54baSEdgar E. Iglesias default: 2624acb54baSEdgar E. Iglesias cpu_abort(env, "unhandled exception type=%d\n", 2634acb54baSEdgar E. Iglesias env->exception_index); 2644acb54baSEdgar E. Iglesias break; 2654acb54baSEdgar E. Iglesias } 2664acb54baSEdgar E. Iglesias } 2674acb54baSEdgar E. Iglesias 268a8170e5eSAvi Kivity hwaddr cpu_get_phys_page_debug(CPUMBState * env, target_ulong addr) 2694acb54baSEdgar E. Iglesias { 2704acb54baSEdgar E. Iglesias target_ulong vaddr, paddr = 0; 2714acb54baSEdgar E. Iglesias struct microblaze_mmu_lookup lu; 2724acb54baSEdgar E. Iglesias unsigned int hit; 2734acb54baSEdgar E. Iglesias 2744acb54baSEdgar E. Iglesias if (env->sregs[SR_MSR] & MSR_VM) { 2754acb54baSEdgar E. Iglesias hit = mmu_translate(&env->mmu, &lu, addr, 0, 0); 2764acb54baSEdgar E. Iglesias if (hit) { 2774acb54baSEdgar E. Iglesias vaddr = addr & TARGET_PAGE_MASK; 2784acb54baSEdgar E. Iglesias paddr = lu.paddr + vaddr - lu.vaddr; 2794acb54baSEdgar E. Iglesias } else 2804acb54baSEdgar E. Iglesias paddr = 0; /* ???. */ 2814acb54baSEdgar E. Iglesias } else 2824acb54baSEdgar E. Iglesias paddr = addr & TARGET_PAGE_MASK; 2834acb54baSEdgar E. Iglesias 2844acb54baSEdgar E. Iglesias return paddr; 2854acb54baSEdgar E. Iglesias } 2864acb54baSEdgar E. Iglesias #endif 287