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 218fd9deceSPeter Maydell #include "qemu/osdep.h" 224acb54baSEdgar E. Iglesias #include "cpu.h" 2363c91552SPaolo Bonzini #include "exec/exec-all.h" 241de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 25508127e2SPaolo Bonzini #include "exec/log.h" 264acb54baSEdgar E. Iglesias 274acb54baSEdgar E. Iglesias #define D(x) 284acb54baSEdgar E. Iglesias 294acb54baSEdgar E. Iglesias #if defined(CONFIG_USER_ONLY) 304acb54baSEdgar E. Iglesias 3197a8ea5aSAndreas Färber void mb_cpu_do_interrupt(CPUState *cs) 324acb54baSEdgar E. Iglesias { 3397a8ea5aSAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 3497a8ea5aSAndreas Färber CPUMBState *env = &cpu->env; 3597a8ea5aSAndreas Färber 3627103424SAndreas Färber cs->exception_index = -1; 378cc9b43fSPeter A. G. Crosthwaite env->res_addr = RES_ADDR_NONE; 38*76e8187dSRichard Henderson env->regs[14] = env->pc; 394acb54baSEdgar E. Iglesias } 404acb54baSEdgar E. Iglesias 41f429d607SRichard Henderson bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 42f429d607SRichard Henderson MMUAccessType access_type, int mmu_idx, 43f429d607SRichard Henderson bool probe, uintptr_t retaddr) 444acb54baSEdgar E. Iglesias { 4527103424SAndreas Färber cs->exception_index = 0xaa; 46f429d607SRichard Henderson cpu_loop_exit_restore(cs, retaddr); 474acb54baSEdgar E. Iglesias } 484acb54baSEdgar E. Iglesias 494acb54baSEdgar E. Iglesias #else /* !CONFIG_USER_ONLY */ 504acb54baSEdgar E. Iglesias 51f429d607SRichard Henderson bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 52f429d607SRichard Henderson MMUAccessType access_type, int mmu_idx, 53f429d607SRichard Henderson bool probe, uintptr_t retaddr) 544acb54baSEdgar E. Iglesias { 557510454eSAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 567510454eSAndreas Färber CPUMBState *env = &cpu->env; 57f429d607SRichard Henderson struct microblaze_mmu_lookup lu; 584acb54baSEdgar E. Iglesias unsigned int hit; 594acb54baSEdgar E. Iglesias int prot; 604acb54baSEdgar E. Iglesias 61f429d607SRichard Henderson if (mmu_idx == MMU_NOMMU_IDX) { 62f429d607SRichard Henderson /* MMU disabled or not available. */ 63f429d607SRichard Henderson address &= TARGET_PAGE_MASK; 64f429d607SRichard Henderson prot = PAGE_BITS; 65f429d607SRichard Henderson tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE); 66f429d607SRichard Henderson return true; 67f429d607SRichard Henderson } 684acb54baSEdgar E. Iglesias 69f429d607SRichard Henderson hit = mmu_translate(&env->mmu, &lu, address, access_type, mmu_idx); 70f429d607SRichard Henderson if (likely(hit)) { 71f429d607SRichard Henderson uint32_t vaddr = address & TARGET_PAGE_MASK; 72f429d607SRichard Henderson uint32_t paddr = lu.paddr + vaddr - lu.vaddr; 734acb54baSEdgar E. Iglesias 74339aaf5bSAntony Pavlov qemu_log_mask(CPU_LOG_MMU, "MMU map mmu=%d v=%x p=%x prot=%x\n", 75339aaf5bSAntony Pavlov mmu_idx, vaddr, paddr, lu.prot); 760c591eb0SAndreas Färber tlb_set_page(cs, vaddr, paddr, lu.prot, mmu_idx, TARGET_PAGE_SIZE); 77f429d607SRichard Henderson return true; 78f429d607SRichard Henderson } 79f429d607SRichard Henderson 80f429d607SRichard Henderson /* TLB miss. */ 81f429d607SRichard Henderson if (probe) { 82f429d607SRichard Henderson return false; 83f429d607SRichard Henderson } 84f429d607SRichard Henderson 85339aaf5bSAntony Pavlov qemu_log_mask(CPU_LOG_MMU, "mmu=%d miss v=%" VADDR_PRIx "\n", 86339aaf5bSAntony Pavlov mmu_idx, address); 874acb54baSEdgar E. Iglesias 88f429d607SRichard Henderson env->sregs[SR_EAR] = address; 894acb54baSEdgar E. Iglesias switch (lu.err) { 904acb54baSEdgar E. Iglesias case ERR_PROT: 91f429d607SRichard Henderson env->sregs[SR_ESR] = access_type == MMU_INST_FETCH ? 17 : 16; 92f429d607SRichard Henderson env->sregs[SR_ESR] |= (access_type == MMU_DATA_STORE) << 10; 934acb54baSEdgar E. Iglesias break; 944acb54baSEdgar E. Iglesias case ERR_MISS: 95f429d607SRichard Henderson env->sregs[SR_ESR] = access_type == MMU_INST_FETCH ? 19 : 18; 96f429d607SRichard Henderson env->sregs[SR_ESR] |= (access_type == MMU_DATA_STORE) << 10; 974acb54baSEdgar E. Iglesias break; 984acb54baSEdgar E. Iglesias default: 994acb54baSEdgar E. Iglesias abort(); 1004acb54baSEdgar E. Iglesias } 1014acb54baSEdgar E. Iglesias 10227103424SAndreas Färber if (cs->exception_index == EXCP_MMU) { 103a47dddd7SAndreas Färber cpu_abort(cs, "recursive faults\n"); 1044acb54baSEdgar E. Iglesias } 1054acb54baSEdgar E. Iglesias 1064acb54baSEdgar E. Iglesias /* TLB miss. */ 10727103424SAndreas Färber cs->exception_index = EXCP_MMU; 108f429d607SRichard Henderson cpu_loop_exit_restore(cs, retaddr); 1094acb54baSEdgar E. Iglesias } 110f429d607SRichard Henderson 11197a8ea5aSAndreas Färber void mb_cpu_do_interrupt(CPUState *cs) 1124acb54baSEdgar E. Iglesias { 11397a8ea5aSAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 11497a8ea5aSAndreas Färber CPUMBState *env = &cpu->env; 1154acb54baSEdgar E. Iglesias uint32_t t; 1164acb54baSEdgar E. Iglesias 1175225d669SStefan Weil /* IMM flag cannot propagate across a branch and into the dslot. */ 1184acb54baSEdgar E. Iglesias assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG))); 1194acb54baSEdgar E. Iglesias assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG))); 1204acb54baSEdgar E. Iglesias /* assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions. */ 1218cc9b43fSPeter A. G. Crosthwaite env->res_addr = RES_ADDR_NONE; 12227103424SAndreas Färber switch (cs->exception_index) { 123cedb936bSEdgar E. Iglesias case EXCP_HW_EXCP: 124cedb936bSEdgar E. Iglesias if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) { 1251d512a65SPaolo Bonzini qemu_log_mask(LOG_GUEST_ERROR, "Exception raised on system without exceptions!\n"); 126cedb936bSEdgar E. Iglesias return; 127cedb936bSEdgar E. Iglesias } 128cedb936bSEdgar E. Iglesias 129*76e8187dSRichard Henderson env->regs[17] = env->pc + 4; 130cedb936bSEdgar E. Iglesias env->sregs[SR_ESR] &= ~(1 << 12); 131cedb936bSEdgar E. Iglesias 132cedb936bSEdgar E. Iglesias /* Exception breaks branch + dslot sequence? */ 133cedb936bSEdgar E. Iglesias if (env->iflags & D_FLAG) { 134cedb936bSEdgar E. Iglesias env->sregs[SR_ESR] |= 1 << 12 ; 135cedb936bSEdgar E. Iglesias env->sregs[SR_BTR] = env->btarget; 136cedb936bSEdgar E. Iglesias } 137cedb936bSEdgar E. Iglesias 138cedb936bSEdgar E. Iglesias /* Disable the MMU. */ 139cedb936bSEdgar E. Iglesias t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; 140cedb936bSEdgar E. Iglesias env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); 141cedb936bSEdgar E. Iglesias env->sregs[SR_MSR] |= t; 142cedb936bSEdgar E. Iglesias /* Exception in progress. */ 143cedb936bSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_EIP; 144cedb936bSEdgar E. Iglesias 145cedb936bSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 1460a22f8cfSEdgar E. Iglesias "hw exception at pc=%" PRIx64 " ear=%" PRIx64 " " 1470a22f8cfSEdgar E. Iglesias "esr=%" PRIx64 " iflags=%x\n", 148*76e8187dSRichard Henderson env->pc, env->sregs[SR_EAR], 149cedb936bSEdgar E. Iglesias env->sregs[SR_ESR], env->iflags); 150a0762859SAndreas Färber log_cpu_state_mask(CPU_LOG_INT, cs, 0); 151cedb936bSEdgar E. Iglesias env->iflags &= ~(IMM_FLAG | D_FLAG); 152*76e8187dSRichard Henderson env->pc = cpu->cfg.base_vectors + 0x20; 153cedb936bSEdgar E. Iglesias break; 154cedb936bSEdgar E. Iglesias 1554acb54baSEdgar E. Iglesias case EXCP_MMU: 156*76e8187dSRichard Henderson env->regs[17] = env->pc; 1574acb54baSEdgar E. Iglesias 158a75cf0c5SEdgar E. Iglesias env->sregs[SR_ESR] &= ~(1 << 12); 1594acb54baSEdgar E. Iglesias /* Exception breaks branch + dslot sequence? */ 1604acb54baSEdgar E. Iglesias if (env->iflags & D_FLAG) { 1614acb54baSEdgar E. Iglesias D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm)); 1624acb54baSEdgar E. Iglesias env->sregs[SR_ESR] |= 1 << 12 ; 1634acb54baSEdgar E. Iglesias env->sregs[SR_BTR] = env->btarget; 1644acb54baSEdgar E. Iglesias 1654acb54baSEdgar E. Iglesias /* Reexecute the branch. */ 1664acb54baSEdgar E. Iglesias env->regs[17] -= 4; 1674acb54baSEdgar E. Iglesias /* was the branch immprefixed?. */ 1684acb54baSEdgar E. Iglesias if (env->bimm) { 1694acb54baSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 1700a22f8cfSEdgar E. Iglesias "bimm exception at pc=%" PRIx64 " " 1710a22f8cfSEdgar E. Iglesias "iflags=%x\n", 172*76e8187dSRichard Henderson env->pc, env->iflags); 1734acb54baSEdgar E. Iglesias env->regs[17] -= 4; 174a0762859SAndreas Färber log_cpu_state_mask(CPU_LOG_INT, cs, 0); 1754acb54baSEdgar E. Iglesias } 1764acb54baSEdgar E. Iglesias } else if (env->iflags & IMM_FLAG) { 1774acb54baSEdgar E. Iglesias D(qemu_log("IMM_FLAG set at exception\n")); 1784acb54baSEdgar E. Iglesias env->regs[17] -= 4; 1794acb54baSEdgar E. Iglesias } 1804acb54baSEdgar E. Iglesias 1814acb54baSEdgar E. Iglesias /* Disable the MMU. */ 1824acb54baSEdgar E. Iglesias t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; 1834acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); 1844acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= t; 1854acb54baSEdgar E. Iglesias /* Exception in progress. */ 1864acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_EIP; 1874acb54baSEdgar E. Iglesias 1884acb54baSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 1890a22f8cfSEdgar E. Iglesias "exception at pc=%" PRIx64 " ear=%" PRIx64 " " 1900a22f8cfSEdgar E. Iglesias "iflags=%x\n", 191*76e8187dSRichard Henderson env->pc, env->sregs[SR_EAR], env->iflags); 192a0762859SAndreas Färber log_cpu_state_mask(CPU_LOG_INT, cs, 0); 1934acb54baSEdgar E. Iglesias env->iflags &= ~(IMM_FLAG | D_FLAG); 194*76e8187dSRichard Henderson env->pc = cpu->cfg.base_vectors + 0x20; 1954acb54baSEdgar E. Iglesias break; 1964acb54baSEdgar E. Iglesias 1974acb54baSEdgar E. Iglesias case EXCP_IRQ: 1984acb54baSEdgar E. Iglesias assert(!(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))); 1994acb54baSEdgar E. Iglesias assert(env->sregs[SR_MSR] & MSR_IE); 2004acb54baSEdgar E. Iglesias assert(!(env->iflags & D_FLAG)); 2014acb54baSEdgar E. Iglesias 2024acb54baSEdgar E. Iglesias t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; 2034acb54baSEdgar E. Iglesias 2044acb54baSEdgar E. Iglesias #if 0 20576cad711SPaolo Bonzini #include "disas/disas.h" 2064acb54baSEdgar E. Iglesias 2074acb54baSEdgar E. Iglesias /* Useful instrumentation when debugging interrupt issues in either 2084acb54baSEdgar E. Iglesias the models or in sw. */ 2094acb54baSEdgar E. Iglesias { 2104acb54baSEdgar E. Iglesias const char *sym; 2114acb54baSEdgar E. Iglesias 212*76e8187dSRichard Henderson sym = lookup_symbol(env->pc); 2134acb54baSEdgar E. Iglesias if (sym 2144acb54baSEdgar E. Iglesias && (!strcmp("netif_rx", sym) 2154acb54baSEdgar E. Iglesias || !strcmp("process_backlog", sym))) { 2164acb54baSEdgar E. Iglesias 2174acb54baSEdgar E. Iglesias qemu_log( 2184acb54baSEdgar E. Iglesias "interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n", 219*76e8187dSRichard Henderson env->pc, env->sregs[SR_MSR], t, env->iflags, 2204acb54baSEdgar E. Iglesias sym); 2214acb54baSEdgar E. Iglesias 222a0762859SAndreas Färber log_cpu_state(cs, 0); 2234acb54baSEdgar E. Iglesias } 2244acb54baSEdgar E. Iglesias } 2254acb54baSEdgar E. Iglesias #endif 2264acb54baSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 2270a22f8cfSEdgar E. Iglesias "interrupt at pc=%" PRIx64 " msr=%" PRIx64 " %x " 2280a22f8cfSEdgar E. Iglesias "iflags=%x\n", 229*76e8187dSRichard Henderson env->pc, env->sregs[SR_MSR], t, env->iflags); 2304acb54baSEdgar E. Iglesias 2314acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \ 2324acb54baSEdgar E. Iglesias | MSR_UM | MSR_IE); 2334acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= t; 2344acb54baSEdgar E. Iglesias 235*76e8187dSRichard Henderson env->regs[14] = env->pc; 236*76e8187dSRichard Henderson env->pc = cpu->cfg.base_vectors + 0x10; 237a0762859SAndreas Färber //log_cpu_state_mask(CPU_LOG_INT, cs, 0); 2384acb54baSEdgar E. Iglesias break; 2394acb54baSEdgar E. Iglesias 2404acb54baSEdgar E. Iglesias case EXCP_BREAK: 2414acb54baSEdgar E. Iglesias case EXCP_HW_BREAK: 2424acb54baSEdgar E. Iglesias assert(!(env->iflags & IMM_FLAG)); 2434acb54baSEdgar E. Iglesias assert(!(env->iflags & D_FLAG)); 2444acb54baSEdgar E. Iglesias t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; 2454acb54baSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 2460a22f8cfSEdgar E. Iglesias "break at pc=%" PRIx64 " msr=%" PRIx64 " %x " 2470a22f8cfSEdgar E. Iglesias "iflags=%x\n", 248*76e8187dSRichard Henderson env->pc, env->sregs[SR_MSR], t, env->iflags); 249a0762859SAndreas Färber log_cpu_state_mask(CPU_LOG_INT, cs, 0); 2504acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); 2514acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= t; 2524acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_BIP; 25327103424SAndreas Färber if (cs->exception_index == EXCP_HW_BREAK) { 254*76e8187dSRichard Henderson env->regs[16] = env->pc; 2554acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_BIP; 256*76e8187dSRichard Henderson env->pc = cpu->cfg.base_vectors + 0x18; 2574acb54baSEdgar E. Iglesias } else 258*76e8187dSRichard Henderson env->pc = env->btarget; 2594acb54baSEdgar E. Iglesias break; 2604acb54baSEdgar E. Iglesias default: 261a47dddd7SAndreas Färber cpu_abort(cs, "unhandled exception type=%d\n", 26227103424SAndreas Färber cs->exception_index); 2634acb54baSEdgar E. Iglesias break; 2644acb54baSEdgar E. Iglesias } 2654acb54baSEdgar E. Iglesias } 2664acb54baSEdgar E. Iglesias 26700b941e5SAndreas Färber hwaddr mb_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 2684acb54baSEdgar E. Iglesias { 26900b941e5SAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 27000b941e5SAndreas Färber CPUMBState *env = &cpu->env; 2714acb54baSEdgar E. Iglesias target_ulong vaddr, paddr = 0; 2724acb54baSEdgar E. Iglesias struct microblaze_mmu_lookup lu; 273d10367e0SEdgar E. Iglesias int mmu_idx = cpu_mmu_index(env, false); 2744acb54baSEdgar E. Iglesias unsigned int hit; 2754acb54baSEdgar E. Iglesias 276d10367e0SEdgar E. Iglesias if (mmu_idx != MMU_NOMMU_IDX) { 2774acb54baSEdgar E. Iglesias hit = mmu_translate(&env->mmu, &lu, addr, 0, 0); 2784acb54baSEdgar E. Iglesias if (hit) { 2794acb54baSEdgar E. Iglesias vaddr = addr & TARGET_PAGE_MASK; 2804acb54baSEdgar E. Iglesias paddr = lu.paddr + vaddr - lu.vaddr; 2814acb54baSEdgar E. Iglesias } else 2824acb54baSEdgar E. Iglesias paddr = 0; /* ???. */ 2834acb54baSEdgar E. Iglesias } else 2844acb54baSEdgar E. Iglesias paddr = addr & TARGET_PAGE_MASK; 2854acb54baSEdgar E. Iglesias 2864acb54baSEdgar E. Iglesias return paddr; 2874acb54baSEdgar E. Iglesias } 2884acb54baSEdgar E. Iglesias #endif 28929cd33d3SRichard Henderson 29029cd33d3SRichard Henderson bool mb_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 29129cd33d3SRichard Henderson { 29229cd33d3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 29329cd33d3SRichard Henderson CPUMBState *env = &cpu->env; 29429cd33d3SRichard Henderson 29529cd33d3SRichard Henderson if ((interrupt_request & CPU_INTERRUPT_HARD) 29629cd33d3SRichard Henderson && (env->sregs[SR_MSR] & MSR_IE) 29729cd33d3SRichard Henderson && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)) 29829cd33d3SRichard Henderson && !(env->iflags & (D_FLAG | IMM_FLAG))) { 29929cd33d3SRichard Henderson cs->exception_index = EXCP_IRQ; 30029cd33d3SRichard Henderson mb_cpu_do_interrupt(cs); 30129cd33d3SRichard Henderson return true; 30229cd33d3SRichard Henderson } 30329cd33d3SRichard Henderson return false; 30429cd33d3SRichard Henderson } 305