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 10ee452036SChetan Pant * version 2.1 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 #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 3427103424SAndreas Färber cs->exception_index = -1; 358cc9b43fSPeter A. G. Crosthwaite env->res_addr = RES_ADDR_NONE; 3676e8187dSRichard Henderson env->regs[14] = env->pc; 374acb54baSEdgar E. Iglesias } 384acb54baSEdgar E. Iglesias 39f429d607SRichard Henderson bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 40f429d607SRichard Henderson MMUAccessType access_type, int mmu_idx, 41f429d607SRichard Henderson bool probe, uintptr_t retaddr) 424acb54baSEdgar E. Iglesias { 4327103424SAndreas Färber cs->exception_index = 0xaa; 44f429d607SRichard Henderson cpu_loop_exit_restore(cs, retaddr); 454acb54baSEdgar E. Iglesias } 464acb54baSEdgar E. Iglesias 474acb54baSEdgar E. Iglesias #else /* !CONFIG_USER_ONLY */ 484acb54baSEdgar E. Iglesias 49*43a9ede1SJoe Komlodi static bool mb_cpu_access_is_secure(MicroBlazeCPU *cpu, 50*43a9ede1SJoe Komlodi MMUAccessType access_type) 51*43a9ede1SJoe Komlodi { 52*43a9ede1SJoe Komlodi if (access_type == MMU_INST_FETCH) { 53*43a9ede1SJoe Komlodi return !cpu->ns_axi_ip; 54*43a9ede1SJoe Komlodi } else { 55*43a9ede1SJoe Komlodi return !cpu->ns_axi_dp; 56*43a9ede1SJoe Komlodi } 57*43a9ede1SJoe Komlodi } 58*43a9ede1SJoe Komlodi 59f429d607SRichard Henderson bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 60f429d607SRichard Henderson MMUAccessType access_type, int mmu_idx, 61f429d607SRichard Henderson bool probe, uintptr_t retaddr) 624acb54baSEdgar E. Iglesias { 637510454eSAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 647510454eSAndreas Färber CPUMBState *env = &cpu->env; 658ce97bc1SRichard Henderson MicroBlazeMMULookup lu; 664acb54baSEdgar E. Iglesias unsigned int hit; 674acb54baSEdgar E. Iglesias int prot; 68*43a9ede1SJoe Komlodi MemTxAttrs attrs = {}; 69*43a9ede1SJoe Komlodi 70*43a9ede1SJoe Komlodi attrs.secure = mb_cpu_access_is_secure(cpu, access_type); 714acb54baSEdgar E. Iglesias 72f429d607SRichard Henderson if (mmu_idx == MMU_NOMMU_IDX) { 73f429d607SRichard Henderson /* MMU disabled or not available. */ 74f429d607SRichard Henderson address &= TARGET_PAGE_MASK; 75f429d607SRichard Henderson prot = PAGE_BITS; 76*43a9ede1SJoe Komlodi tlb_set_page_with_attrs(cs, address, address, attrs, prot, mmu_idx, 77*43a9ede1SJoe Komlodi TARGET_PAGE_SIZE); 78f429d607SRichard Henderson return true; 79f429d607SRichard Henderson } 804acb54baSEdgar E. Iglesias 81de73ee1aSRichard Henderson hit = mmu_translate(cpu, &lu, address, access_type, mmu_idx); 82f429d607SRichard Henderson if (likely(hit)) { 83f429d607SRichard Henderson uint32_t vaddr = address & TARGET_PAGE_MASK; 84f429d607SRichard Henderson uint32_t paddr = lu.paddr + vaddr - lu.vaddr; 854acb54baSEdgar E. Iglesias 86339aaf5bSAntony Pavlov qemu_log_mask(CPU_LOG_MMU, "MMU map mmu=%d v=%x p=%x prot=%x\n", 87339aaf5bSAntony Pavlov mmu_idx, vaddr, paddr, lu.prot); 88*43a9ede1SJoe Komlodi tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, lu.prot, mmu_idx, 89*43a9ede1SJoe Komlodi TARGET_PAGE_SIZE); 90f429d607SRichard Henderson return true; 91f429d607SRichard Henderson } 92f429d607SRichard Henderson 93f429d607SRichard Henderson /* TLB miss. */ 94f429d607SRichard Henderson if (probe) { 95f429d607SRichard Henderson return false; 96f429d607SRichard Henderson } 97f429d607SRichard Henderson 98339aaf5bSAntony Pavlov qemu_log_mask(CPU_LOG_MMU, "mmu=%d miss v=%" VADDR_PRIx "\n", 99339aaf5bSAntony Pavlov mmu_idx, address); 1004acb54baSEdgar E. Iglesias 101b2e80a3cSRichard Henderson env->ear = address; 1024acb54baSEdgar E. Iglesias switch (lu.err) { 1034acb54baSEdgar E. Iglesias case ERR_PROT: 10478e9caf2SRichard Henderson env->esr = access_type == MMU_INST_FETCH ? 17 : 16; 10578e9caf2SRichard Henderson env->esr |= (access_type == MMU_DATA_STORE) << 10; 1064acb54baSEdgar E. Iglesias break; 1074acb54baSEdgar E. Iglesias case ERR_MISS: 10878e9caf2SRichard Henderson env->esr = access_type == MMU_INST_FETCH ? 19 : 18; 10978e9caf2SRichard Henderson env->esr |= (access_type == MMU_DATA_STORE) << 10; 1104acb54baSEdgar E. Iglesias break; 1114acb54baSEdgar E. Iglesias default: 1124acb54baSEdgar E. Iglesias abort(); 1134acb54baSEdgar E. Iglesias } 1144acb54baSEdgar E. Iglesias 11527103424SAndreas Färber if (cs->exception_index == EXCP_MMU) { 116a47dddd7SAndreas Färber cpu_abort(cs, "recursive faults\n"); 1174acb54baSEdgar E. Iglesias } 1184acb54baSEdgar E. Iglesias 1194acb54baSEdgar E. Iglesias /* TLB miss. */ 12027103424SAndreas Färber cs->exception_index = EXCP_MMU; 121f429d607SRichard Henderson cpu_loop_exit_restore(cs, retaddr); 1224acb54baSEdgar E. Iglesias } 123f429d607SRichard Henderson 12497a8ea5aSAndreas Färber void mb_cpu_do_interrupt(CPUState *cs) 1254acb54baSEdgar E. Iglesias { 12697a8ea5aSAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 12797a8ea5aSAndreas Färber CPUMBState *env = &cpu->env; 1281074c0fbSRichard Henderson uint32_t t, msr = mb_cpu_read_msr(env); 129a9f61458SRichard Henderson bool set_esr; 1304acb54baSEdgar E. Iglesias 1315225d669SStefan Weil /* IMM flag cannot propagate across a branch and into the dslot. */ 13288e74b61SRichard Henderson assert((env->iflags & (D_FLAG | IMM_FLAG)) != (D_FLAG | IMM_FLAG)); 13388e74b61SRichard Henderson /* BIMM flag cannot be set without D_FLAG. */ 13488e74b61SRichard Henderson assert((env->iflags & (D_FLAG | BIMM_FLAG)) != BIMM_FLAG); 13588e74b61SRichard Henderson /* RTI flags are private to translate. */ 1364acb54baSEdgar E. Iglesias assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG))); 137a9f61458SRichard Henderson 13827103424SAndreas Färber switch (cs->exception_index) { 139cedb936bSEdgar E. Iglesias case EXCP_HW_EXCP: 140a4bcfc33SRichard Henderson if (!(cpu->cfg.pvr_regs[0] & PVR0_USE_EXC_MASK)) { 141a9f61458SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 142a9f61458SRichard Henderson "Exception raised on system without exceptions!\n"); 143cedb936bSEdgar E. Iglesias return; 144cedb936bSEdgar E. Iglesias } 145cedb936bSEdgar E. Iglesias 146a9f61458SRichard Henderson qemu_log_mask(CPU_LOG_INT, 147a9f61458SRichard Henderson "INT: HWE at pc=%08x msr=%08x iflags=%x\n", 148a9f61458SRichard Henderson env->pc, msr, env->iflags); 149cedb936bSEdgar E. Iglesias 150cedb936bSEdgar E. Iglesias /* Exception breaks branch + dslot sequence? */ 151a9f61458SRichard Henderson set_esr = true; 152a9f61458SRichard Henderson env->esr &= ~D_FLAG; 153cedb936bSEdgar E. Iglesias if (env->iflags & D_FLAG) { 154a9f61458SRichard Henderson env->esr |= D_FLAG; 1556fbf78f2SRichard Henderson env->btr = env->btarget; 156cedb936bSEdgar E. Iglesias } 157cedb936bSEdgar E. Iglesias 158cedb936bSEdgar E. Iglesias /* Exception in progress. */ 1591074c0fbSRichard Henderson msr |= MSR_EIP; 160a9f61458SRichard Henderson env->regs[17] = env->pc + 4; 16176e8187dSRichard Henderson env->pc = cpu->cfg.base_vectors + 0x20; 162cedb936bSEdgar E. Iglesias break; 163cedb936bSEdgar E. Iglesias 1644acb54baSEdgar E. Iglesias case EXCP_MMU: 165e3f8d192SRichard Henderson qemu_log_mask(CPU_LOG_INT, 166a9f61458SRichard Henderson "INT: MMU at pc=%08x msr=%08x " 167a9f61458SRichard Henderson "ear=%" PRIx64 " iflags=%x\n", 168a9f61458SRichard Henderson env->pc, msr, env->ear, env->iflags); 169e3f8d192SRichard Henderson 1704acb54baSEdgar E. Iglesias /* Exception breaks branch + dslot sequence? */ 171a9f61458SRichard Henderson set_esr = true; 172a9f61458SRichard Henderson env->esr &= ~D_FLAG; 1734acb54baSEdgar E. Iglesias if (env->iflags & D_FLAG) { 174a9f61458SRichard Henderson env->esr |= D_FLAG; 1756fbf78f2SRichard Henderson env->btr = env->btarget; 1764acb54baSEdgar E. Iglesias /* Reexecute the branch. */ 177a9f61458SRichard Henderson env->regs[17] = env->pc - (env->iflags & BIMM_FLAG ? 8 : 4); 1784acb54baSEdgar E. Iglesias } else if (env->iflags & IMM_FLAG) { 179a9f61458SRichard Henderson /* Reexecute the imm. */ 180a9f61458SRichard Henderson env->regs[17] = env->pc - 4; 181a9f61458SRichard Henderson } else { 182a9f61458SRichard Henderson env->regs[17] = env->pc; 1834acb54baSEdgar E. Iglesias } 1844acb54baSEdgar E. Iglesias 1854acb54baSEdgar E. Iglesias /* Exception in progress. */ 1861074c0fbSRichard Henderson msr |= MSR_EIP; 18776e8187dSRichard Henderson env->pc = cpu->cfg.base_vectors + 0x20; 1884acb54baSEdgar E. Iglesias break; 1894acb54baSEdgar E. Iglesias 1904acb54baSEdgar E. Iglesias case EXCP_IRQ: 1911074c0fbSRichard Henderson assert(!(msr & (MSR_EIP | MSR_BIP))); 1921074c0fbSRichard Henderson assert(msr & MSR_IE); 19388e74b61SRichard Henderson assert(!(env->iflags & (D_FLAG | IMM_FLAG))); 1944acb54baSEdgar E. Iglesias 1954acb54baSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 196a9f61458SRichard Henderson "INT: DEV at pc=%08x msr=%08x iflags=%x\n", 197a9f61458SRichard Henderson env->pc, msr, env->iflags); 198a9f61458SRichard Henderson set_esr = false; 1994acb54baSEdgar E. Iglesias 200a9f61458SRichard Henderson /* Disable interrupts. */ 201a9f61458SRichard Henderson msr &= ~MSR_IE; 20276e8187dSRichard Henderson env->regs[14] = env->pc; 20376e8187dSRichard Henderson env->pc = cpu->cfg.base_vectors + 0x10; 2044acb54baSEdgar E. Iglesias break; 2054acb54baSEdgar E. Iglesias 2064acb54baSEdgar E. Iglesias case EXCP_HW_BREAK: 20788e74b61SRichard Henderson assert(!(env->iflags & (D_FLAG | IMM_FLAG))); 20888e74b61SRichard Henderson 2094acb54baSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 210a9f61458SRichard Henderson "INT: BRK at pc=%08x msr=%08x iflags=%x\n", 211a9f61458SRichard Henderson env->pc, msr, env->iflags); 212a9f61458SRichard Henderson set_esr = false; 213a9f61458SRichard Henderson 214a9f61458SRichard Henderson /* Break in progress. */ 2151074c0fbSRichard Henderson msr |= MSR_BIP; 21676e8187dSRichard Henderson env->regs[16] = env->pc; 21776e8187dSRichard Henderson env->pc = cpu->cfg.base_vectors + 0x18; 2184acb54baSEdgar E. Iglesias break; 219a9f61458SRichard Henderson 2204acb54baSEdgar E. Iglesias default: 221a9f61458SRichard Henderson cpu_abort(cs, "unhandled exception type=%d\n", cs->exception_index); 222a9f61458SRichard Henderson /* not reached */ 223a9f61458SRichard Henderson } 224a9f61458SRichard Henderson 225a9f61458SRichard Henderson /* Save previous mode, disable mmu, disable user-mode. */ 226a9f61458SRichard Henderson t = (msr & (MSR_VM | MSR_UM)) << 1; 227a9f61458SRichard Henderson msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); 228a9f61458SRichard Henderson msr |= t; 229a9f61458SRichard Henderson mb_cpu_write_msr(env, msr); 230a9f61458SRichard Henderson 231a9f61458SRichard Henderson env->res_addr = RES_ADDR_NONE; 232a9f61458SRichard Henderson env->iflags = 0; 233a9f61458SRichard Henderson 234a9f61458SRichard Henderson if (!set_esr) { 235a9f61458SRichard Henderson qemu_log_mask(CPU_LOG_INT, 236a9f61458SRichard Henderson " to pc=%08x msr=%08x\n", env->pc, msr); 237a9f61458SRichard Henderson } else if (env->esr & D_FLAG) { 238a9f61458SRichard Henderson qemu_log_mask(CPU_LOG_INT, 239a9f61458SRichard Henderson " to pc=%08x msr=%08x esr=%04x btr=%08x\n", 240a9f61458SRichard Henderson env->pc, msr, env->esr, env->btr); 241a9f61458SRichard Henderson } else { 242a9f61458SRichard Henderson qemu_log_mask(CPU_LOG_INT, 243a9f61458SRichard Henderson " to pc=%08x msr=%08x esr=%04x\n", 244a9f61458SRichard Henderson env->pc, msr, env->esr); 2454acb54baSEdgar E. Iglesias } 2464acb54baSEdgar E. Iglesias } 2474acb54baSEdgar E. Iglesias 248*43a9ede1SJoe Komlodi hwaddr mb_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, 249*43a9ede1SJoe Komlodi MemTxAttrs *attrs) 2504acb54baSEdgar E. Iglesias { 25100b941e5SAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 25200b941e5SAndreas Färber CPUMBState *env = &cpu->env; 2534acb54baSEdgar E. Iglesias target_ulong vaddr, paddr = 0; 2548ce97bc1SRichard Henderson MicroBlazeMMULookup lu; 255d10367e0SEdgar E. Iglesias int mmu_idx = cpu_mmu_index(env, false); 2564acb54baSEdgar E. Iglesias unsigned int hit; 2574acb54baSEdgar E. Iglesias 258*43a9ede1SJoe Komlodi /* Caller doesn't initialize */ 259*43a9ede1SJoe Komlodi *attrs = (MemTxAttrs) {}; 260*43a9ede1SJoe Komlodi attrs->secure = mb_cpu_access_is_secure(cpu, MMU_DATA_LOAD); 261*43a9ede1SJoe Komlodi 262d10367e0SEdgar E. Iglesias if (mmu_idx != MMU_NOMMU_IDX) { 263de73ee1aSRichard Henderson hit = mmu_translate(cpu, &lu, addr, 0, 0); 2644acb54baSEdgar E. Iglesias if (hit) { 2654acb54baSEdgar E. Iglesias vaddr = addr & TARGET_PAGE_MASK; 2664acb54baSEdgar E. Iglesias paddr = lu.paddr + vaddr - lu.vaddr; 2674acb54baSEdgar E. Iglesias } else 2684acb54baSEdgar E. Iglesias paddr = 0; /* ???. */ 2694acb54baSEdgar E. Iglesias } else 2704acb54baSEdgar E. Iglesias paddr = addr & TARGET_PAGE_MASK; 2714acb54baSEdgar E. Iglesias 2724acb54baSEdgar E. Iglesias return paddr; 2734acb54baSEdgar E. Iglesias } 2744acb54baSEdgar E. Iglesias #endif 27529cd33d3SRichard Henderson 27629cd33d3SRichard Henderson bool mb_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 27729cd33d3SRichard Henderson { 27829cd33d3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 27929cd33d3SRichard Henderson CPUMBState *env = &cpu->env; 28029cd33d3SRichard Henderson 28129cd33d3SRichard Henderson if ((interrupt_request & CPU_INTERRUPT_HARD) 2822e5282caSRichard Henderson && (env->msr & MSR_IE) 2832e5282caSRichard Henderson && !(env->msr & (MSR_EIP | MSR_BIP)) 28429cd33d3SRichard Henderson && !(env->iflags & (D_FLAG | IMM_FLAG))) { 28529cd33d3SRichard Henderson cs->exception_index = EXCP_IRQ; 28629cd33d3SRichard Henderson mb_cpu_do_interrupt(cs); 28729cd33d3SRichard Henderson return true; 28829cd33d3SRichard Henderson } 28929cd33d3SRichard Henderson return false; 29029cd33d3SRichard Henderson } 291ab0c8d0fSRichard Henderson 292ab0c8d0fSRichard Henderson void mb_cpu_do_unaligned_access(CPUState *cs, vaddr addr, 293ab0c8d0fSRichard Henderson MMUAccessType access_type, 294ab0c8d0fSRichard Henderson int mmu_idx, uintptr_t retaddr) 295ab0c8d0fSRichard Henderson { 296ab0c8d0fSRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 297ab0c8d0fSRichard Henderson uint32_t esr, iflags; 298ab0c8d0fSRichard Henderson 299ab0c8d0fSRichard Henderson /* Recover the pc and iflags from the corresponding insn_start. */ 300ab0c8d0fSRichard Henderson cpu_restore_state(cs, retaddr, true); 301ab0c8d0fSRichard Henderson iflags = cpu->env.iflags; 302ab0c8d0fSRichard Henderson 303ab0c8d0fSRichard Henderson qemu_log_mask(CPU_LOG_INT, 30419f27b6cSRichard Henderson "Unaligned access addr=" TARGET_FMT_lx " pc=%x iflags=%x\n", 30519f27b6cSRichard Henderson (target_ulong)addr, cpu->env.pc, iflags); 306ab0c8d0fSRichard Henderson 307ab0c8d0fSRichard Henderson esr = ESR_EC_UNALIGNED_DATA; 308ab0c8d0fSRichard Henderson if (likely(iflags & ESR_ESS_FLAG)) { 309ab0c8d0fSRichard Henderson esr |= iflags & ESR_ESS_MASK; 310ab0c8d0fSRichard Henderson } else { 311ab0c8d0fSRichard Henderson qemu_log_mask(LOG_UNIMP, "Unaligned access without ESR_ESS_FLAG\n"); 312ab0c8d0fSRichard Henderson } 313ab0c8d0fSRichard Henderson 314ab0c8d0fSRichard Henderson cpu->env.ear = addr; 315ab0c8d0fSRichard Henderson cpu->env.esr = esr; 316ab0c8d0fSRichard Henderson cs->exception_index = EXCP_HW_EXCP; 317ab0c8d0fSRichard Henderson cpu_loop_exit(cs); 318ab0c8d0fSRichard Henderson } 319