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" 232809e2d6SPhilippe Mathieu-Daudé #include "exec/cputlb.h" 24efe25c26SRichard Henderson #include "accel/tcg/cpu-mmu-index.h" 2574781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h" 269c2ff9cdSPierrick Bouvier #include "exec/target_page.h" 271de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 28508127e2SPaolo Bonzini #include "exec/log.h" 29*3f8d6b43SRichard Henderson #include "exec/helper-proto.h" 304acb54baSEdgar E. Iglesias 3167f2d507SRichard Henderson 3267f2d507SRichard Henderson G_NORETURN 3367f2d507SRichard Henderson static void mb_unaligned_access_internal(CPUState *cs, uint64_t addr, 3467f2d507SRichard Henderson uintptr_t retaddr) 3567f2d507SRichard Henderson { 3667f2d507SRichard Henderson CPUMBState *env = cpu_env(cs); 3767f2d507SRichard Henderson uint32_t esr, iflags; 3867f2d507SRichard Henderson 3967f2d507SRichard Henderson /* Recover the pc and iflags from the corresponding insn_start. */ 4067f2d507SRichard Henderson cpu_restore_state(cs, retaddr); 4167f2d507SRichard Henderson iflags = env->iflags; 4267f2d507SRichard Henderson 4367f2d507SRichard Henderson qemu_log_mask(CPU_LOG_INT, 4467f2d507SRichard Henderson "Unaligned access addr=0x%" PRIx64 " pc=%x iflags=%x\n", 4567f2d507SRichard Henderson addr, env->pc, iflags); 4667f2d507SRichard Henderson 4767f2d507SRichard Henderson esr = ESR_EC_UNALIGNED_DATA; 4867f2d507SRichard Henderson if (likely(iflags & ESR_ESS_FLAG)) { 4967f2d507SRichard Henderson esr |= iflags & ESR_ESS_MASK; 5067f2d507SRichard Henderson } else { 5167f2d507SRichard Henderson qemu_log_mask(LOG_UNIMP, "Unaligned access without ESR_ESS_FLAG\n"); 5267f2d507SRichard Henderson } 5367f2d507SRichard Henderson 5467f2d507SRichard Henderson env->ear = addr; 5567f2d507SRichard Henderson env->esr = esr; 5667f2d507SRichard Henderson cs->exception_index = EXCP_HW_EXCP; 5767f2d507SRichard Henderson cpu_loop_exit(cs); 5867f2d507SRichard Henderson } 5967f2d507SRichard Henderson 6067f2d507SRichard Henderson void mb_cpu_do_unaligned_access(CPUState *cs, vaddr addr, 6167f2d507SRichard Henderson MMUAccessType access_type, 6267f2d507SRichard Henderson int mmu_idx, uintptr_t retaddr) 6367f2d507SRichard Henderson { 6467f2d507SRichard Henderson mb_unaligned_access_internal(cs, addr, retaddr); 6567f2d507SRichard Henderson } 6667f2d507SRichard Henderson 67fd297732SRichard Henderson #ifndef CONFIG_USER_ONLY 68*3f8d6b43SRichard Henderson 69*3f8d6b43SRichard Henderson void HELPER(unaligned_access)(CPUMBState *env, uint64_t addr) 70*3f8d6b43SRichard Henderson { 71*3f8d6b43SRichard Henderson mb_unaligned_access_internal(env_cpu(env), addr, GETPC()); 72*3f8d6b43SRichard Henderson } 73*3f8d6b43SRichard Henderson 7443a9ede1SJoe Komlodi static bool mb_cpu_access_is_secure(MicroBlazeCPU *cpu, 7543a9ede1SJoe Komlodi MMUAccessType access_type) 7643a9ede1SJoe Komlodi { 7743a9ede1SJoe Komlodi if (access_type == MMU_INST_FETCH) { 7843a9ede1SJoe Komlodi return !cpu->ns_axi_ip; 7943a9ede1SJoe Komlodi } else { 8043a9ede1SJoe Komlodi return !cpu->ns_axi_dp; 8143a9ede1SJoe Komlodi } 8243a9ede1SJoe Komlodi } 8343a9ede1SJoe Komlodi 84f429d607SRichard Henderson bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 85f429d607SRichard Henderson MMUAccessType access_type, int mmu_idx, 86f429d607SRichard Henderson bool probe, uintptr_t retaddr) 874acb54baSEdgar E. Iglesias { 887510454eSAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 897510454eSAndreas Färber CPUMBState *env = &cpu->env; 908ce97bc1SRichard Henderson MicroBlazeMMULookup lu; 914acb54baSEdgar E. Iglesias unsigned int hit; 924acb54baSEdgar E. Iglesias int prot; 9343a9ede1SJoe Komlodi MemTxAttrs attrs = {}; 9443a9ede1SJoe Komlodi 9543a9ede1SJoe Komlodi attrs.secure = mb_cpu_access_is_secure(cpu, access_type); 964acb54baSEdgar E. Iglesias 97f429d607SRichard Henderson if (mmu_idx == MMU_NOMMU_IDX) { 98f429d607SRichard Henderson /* MMU disabled or not available. */ 99f429d607SRichard Henderson address &= TARGET_PAGE_MASK; 10086b7c551SBALATON Zoltan prot = PAGE_RWX; 10143a9ede1SJoe Komlodi tlb_set_page_with_attrs(cs, address, address, attrs, prot, mmu_idx, 10243a9ede1SJoe Komlodi TARGET_PAGE_SIZE); 103f429d607SRichard Henderson return true; 104f429d607SRichard Henderson } 1054acb54baSEdgar E. Iglesias 106de73ee1aSRichard Henderson hit = mmu_translate(cpu, &lu, address, access_type, mmu_idx); 107f429d607SRichard Henderson if (likely(hit)) { 108f429d607SRichard Henderson uint32_t vaddr = address & TARGET_PAGE_MASK; 109f429d607SRichard Henderson uint32_t paddr = lu.paddr + vaddr - lu.vaddr; 1104acb54baSEdgar E. Iglesias 111339aaf5bSAntony Pavlov qemu_log_mask(CPU_LOG_MMU, "MMU map mmu=%d v=%x p=%x prot=%x\n", 112339aaf5bSAntony Pavlov mmu_idx, vaddr, paddr, lu.prot); 11343a9ede1SJoe Komlodi tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, lu.prot, mmu_idx, 11443a9ede1SJoe Komlodi TARGET_PAGE_SIZE); 115f429d607SRichard Henderson return true; 116f429d607SRichard Henderson } 117f429d607SRichard Henderson 118f429d607SRichard Henderson /* TLB miss. */ 119f429d607SRichard Henderson if (probe) { 120f429d607SRichard Henderson return false; 121f429d607SRichard Henderson } 122f429d607SRichard Henderson 123339aaf5bSAntony Pavlov qemu_log_mask(CPU_LOG_MMU, "mmu=%d miss v=%" VADDR_PRIx "\n", 124339aaf5bSAntony Pavlov mmu_idx, address); 1254acb54baSEdgar E. Iglesias 126b2e80a3cSRichard Henderson env->ear = address; 1274acb54baSEdgar E. Iglesias switch (lu.err) { 1284acb54baSEdgar E. Iglesias case ERR_PROT: 12978e9caf2SRichard Henderson env->esr = access_type == MMU_INST_FETCH ? 17 : 16; 13078e9caf2SRichard Henderson env->esr |= (access_type == MMU_DATA_STORE) << 10; 1314acb54baSEdgar E. Iglesias break; 1324acb54baSEdgar E. Iglesias case ERR_MISS: 13378e9caf2SRichard Henderson env->esr = access_type == MMU_INST_FETCH ? 19 : 18; 13478e9caf2SRichard Henderson env->esr |= (access_type == MMU_DATA_STORE) << 10; 1354acb54baSEdgar E. Iglesias break; 1364acb54baSEdgar E. Iglesias default: 1374acb54baSEdgar E. Iglesias abort(); 1384acb54baSEdgar E. Iglesias } 1394acb54baSEdgar E. Iglesias 14027103424SAndreas Färber if (cs->exception_index == EXCP_MMU) { 141a47dddd7SAndreas Färber cpu_abort(cs, "recursive faults\n"); 1424acb54baSEdgar E. Iglesias } 1434acb54baSEdgar E. Iglesias 1444acb54baSEdgar E. Iglesias /* TLB miss. */ 14527103424SAndreas Färber cs->exception_index = EXCP_MMU; 146f429d607SRichard Henderson cpu_loop_exit_restore(cs, retaddr); 1474acb54baSEdgar E. Iglesias } 148f429d607SRichard Henderson 14997a8ea5aSAndreas Färber void mb_cpu_do_interrupt(CPUState *cs) 1504acb54baSEdgar E. Iglesias { 15197a8ea5aSAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 15297a8ea5aSAndreas Färber CPUMBState *env = &cpu->env; 1531074c0fbSRichard Henderson uint32_t t, msr = mb_cpu_read_msr(env); 154a9f61458SRichard Henderson bool set_esr; 1554acb54baSEdgar E. Iglesias 1565225d669SStefan Weil /* IMM flag cannot propagate across a branch and into the dslot. */ 15788e74b61SRichard Henderson assert((env->iflags & (D_FLAG | IMM_FLAG)) != (D_FLAG | IMM_FLAG)); 15888e74b61SRichard Henderson /* BIMM flag cannot be set without D_FLAG. */ 15988e74b61SRichard Henderson assert((env->iflags & (D_FLAG | BIMM_FLAG)) != BIMM_FLAG); 16088e74b61SRichard Henderson /* RTI flags are private to translate. */ 1614acb54baSEdgar E. Iglesias assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG))); 162a9f61458SRichard Henderson 16327103424SAndreas Färber switch (cs->exception_index) { 164cedb936bSEdgar E. Iglesias case EXCP_HW_EXCP: 165a4bcfc33SRichard Henderson if (!(cpu->cfg.pvr_regs[0] & PVR0_USE_EXC_MASK)) { 166a9f61458SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 167a9f61458SRichard Henderson "Exception raised on system without exceptions!\n"); 168cedb936bSEdgar E. Iglesias return; 169cedb936bSEdgar E. Iglesias } 170cedb936bSEdgar E. Iglesias 171a9f61458SRichard Henderson qemu_log_mask(CPU_LOG_INT, 172a9f61458SRichard Henderson "INT: HWE at pc=%08x msr=%08x iflags=%x\n", 173a9f61458SRichard Henderson env->pc, msr, env->iflags); 174cedb936bSEdgar E. Iglesias 175cedb936bSEdgar E. Iglesias /* Exception breaks branch + dslot sequence? */ 176a9f61458SRichard Henderson set_esr = true; 177a9f61458SRichard Henderson env->esr &= ~D_FLAG; 178cedb936bSEdgar E. Iglesias if (env->iflags & D_FLAG) { 179a9f61458SRichard Henderson env->esr |= D_FLAG; 1806fbf78f2SRichard Henderson env->btr = env->btarget; 181cedb936bSEdgar E. Iglesias } 182cedb936bSEdgar E. Iglesias 183cedb936bSEdgar E. Iglesias /* Exception in progress. */ 1841074c0fbSRichard Henderson msr |= MSR_EIP; 185a9f61458SRichard Henderson env->regs[17] = env->pc + 4; 18676e8187dSRichard Henderson env->pc = cpu->cfg.base_vectors + 0x20; 187cedb936bSEdgar E. Iglesias break; 188cedb936bSEdgar E. Iglesias 1894acb54baSEdgar E. Iglesias case EXCP_MMU: 190e3f8d192SRichard Henderson qemu_log_mask(CPU_LOG_INT, 191a9f61458SRichard Henderson "INT: MMU at pc=%08x msr=%08x " 192a9f61458SRichard Henderson "ear=%" PRIx64 " iflags=%x\n", 193a9f61458SRichard Henderson env->pc, msr, env->ear, env->iflags); 194e3f8d192SRichard Henderson 1954acb54baSEdgar E. Iglesias /* Exception breaks branch + dslot sequence? */ 196a9f61458SRichard Henderson set_esr = true; 197a9f61458SRichard Henderson env->esr &= ~D_FLAG; 1984acb54baSEdgar E. Iglesias if (env->iflags & D_FLAG) { 199a9f61458SRichard Henderson env->esr |= D_FLAG; 2006fbf78f2SRichard Henderson env->btr = env->btarget; 2014acb54baSEdgar E. Iglesias /* Reexecute the branch. */ 202a9f61458SRichard Henderson env->regs[17] = env->pc - (env->iflags & BIMM_FLAG ? 8 : 4); 2034acb54baSEdgar E. Iglesias } else if (env->iflags & IMM_FLAG) { 204a9f61458SRichard Henderson /* Reexecute the imm. */ 205a9f61458SRichard Henderson env->regs[17] = env->pc - 4; 206a9f61458SRichard Henderson } else { 207a9f61458SRichard Henderson env->regs[17] = env->pc; 2084acb54baSEdgar E. Iglesias } 2094acb54baSEdgar E. Iglesias 2104acb54baSEdgar E. Iglesias /* Exception in progress. */ 2111074c0fbSRichard Henderson msr |= MSR_EIP; 21276e8187dSRichard Henderson env->pc = cpu->cfg.base_vectors + 0x20; 2134acb54baSEdgar E. Iglesias break; 2144acb54baSEdgar E. Iglesias 2154acb54baSEdgar E. Iglesias case EXCP_IRQ: 2161074c0fbSRichard Henderson assert(!(msr & (MSR_EIP | MSR_BIP))); 2171074c0fbSRichard Henderson assert(msr & MSR_IE); 21888e74b61SRichard Henderson assert(!(env->iflags & (D_FLAG | IMM_FLAG))); 2194acb54baSEdgar E. Iglesias 2204acb54baSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 221a9f61458SRichard Henderson "INT: DEV at pc=%08x msr=%08x iflags=%x\n", 222a9f61458SRichard Henderson env->pc, msr, env->iflags); 223a9f61458SRichard Henderson set_esr = false; 2244acb54baSEdgar E. Iglesias 225a9f61458SRichard Henderson /* Disable interrupts. */ 226a9f61458SRichard Henderson msr &= ~MSR_IE; 22776e8187dSRichard Henderson env->regs[14] = env->pc; 22876e8187dSRichard Henderson env->pc = cpu->cfg.base_vectors + 0x10; 2294acb54baSEdgar E. Iglesias break; 2304acb54baSEdgar E. Iglesias 2314acb54baSEdgar E. Iglesias case EXCP_HW_BREAK: 23288e74b61SRichard Henderson assert(!(env->iflags & (D_FLAG | IMM_FLAG))); 23388e74b61SRichard Henderson 2344acb54baSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 235a9f61458SRichard Henderson "INT: BRK at pc=%08x msr=%08x iflags=%x\n", 236a9f61458SRichard Henderson env->pc, msr, env->iflags); 237a9f61458SRichard Henderson set_esr = false; 238a9f61458SRichard Henderson 239a9f61458SRichard Henderson /* Break in progress. */ 2401074c0fbSRichard Henderson msr |= MSR_BIP; 24176e8187dSRichard Henderson env->regs[16] = env->pc; 24276e8187dSRichard Henderson env->pc = cpu->cfg.base_vectors + 0x18; 2434acb54baSEdgar E. Iglesias break; 244a9f61458SRichard Henderson 2454acb54baSEdgar E. Iglesias default: 246a9f61458SRichard Henderson cpu_abort(cs, "unhandled exception type=%d\n", cs->exception_index); 247a9f61458SRichard Henderson /* not reached */ 248a9f61458SRichard Henderson } 249a9f61458SRichard Henderson 250a9f61458SRichard Henderson /* Save previous mode, disable mmu, disable user-mode. */ 251a9f61458SRichard Henderson t = (msr & (MSR_VM | MSR_UM)) << 1; 252a9f61458SRichard Henderson msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); 253a9f61458SRichard Henderson msr |= t; 254a9f61458SRichard Henderson mb_cpu_write_msr(env, msr); 255a9f61458SRichard Henderson 256a9f61458SRichard Henderson env->res_addr = RES_ADDR_NONE; 257a9f61458SRichard Henderson env->iflags = 0; 258a9f61458SRichard Henderson 259a9f61458SRichard Henderson if (!set_esr) { 260a9f61458SRichard Henderson qemu_log_mask(CPU_LOG_INT, 261a9f61458SRichard Henderson " to pc=%08x msr=%08x\n", env->pc, msr); 262a9f61458SRichard Henderson } else if (env->esr & D_FLAG) { 263a9f61458SRichard Henderson qemu_log_mask(CPU_LOG_INT, 264a9f61458SRichard Henderson " to pc=%08x msr=%08x esr=%04x btr=%08x\n", 265a9f61458SRichard Henderson env->pc, msr, env->esr, env->btr); 266a9f61458SRichard Henderson } else { 267a9f61458SRichard Henderson qemu_log_mask(CPU_LOG_INT, 268a9f61458SRichard Henderson " to pc=%08x msr=%08x esr=%04x\n", 269a9f61458SRichard Henderson env->pc, msr, env->esr); 2704acb54baSEdgar E. Iglesias } 2714acb54baSEdgar E. Iglesias } 2724acb54baSEdgar E. Iglesias 27343a9ede1SJoe Komlodi hwaddr mb_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, 27443a9ede1SJoe Komlodi MemTxAttrs *attrs) 2754acb54baSEdgar E. Iglesias { 27600b941e5SAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 2774acb54baSEdgar E. Iglesias target_ulong vaddr, paddr = 0; 2788ce97bc1SRichard Henderson MicroBlazeMMULookup lu; 2793b916140SRichard Henderson int mmu_idx = cpu_mmu_index(cs, false); 2804acb54baSEdgar E. Iglesias unsigned int hit; 2814acb54baSEdgar E. Iglesias 28243a9ede1SJoe Komlodi /* Caller doesn't initialize */ 28343a9ede1SJoe Komlodi *attrs = (MemTxAttrs) {}; 28443a9ede1SJoe Komlodi attrs->secure = mb_cpu_access_is_secure(cpu, MMU_DATA_LOAD); 28543a9ede1SJoe Komlodi 286d10367e0SEdgar E. Iglesias if (mmu_idx != MMU_NOMMU_IDX) { 287de73ee1aSRichard Henderson hit = mmu_translate(cpu, &lu, addr, 0, 0); 2884acb54baSEdgar E. Iglesias if (hit) { 2894acb54baSEdgar E. Iglesias vaddr = addr & TARGET_PAGE_MASK; 2904acb54baSEdgar E. Iglesias paddr = lu.paddr + vaddr - lu.vaddr; 2914acb54baSEdgar E. Iglesias } else 2924acb54baSEdgar E. Iglesias paddr = 0; /* ???. */ 2934acb54baSEdgar E. Iglesias } else 2944acb54baSEdgar E. Iglesias paddr = addr & TARGET_PAGE_MASK; 2954acb54baSEdgar E. Iglesias 2964acb54baSEdgar E. Iglesias return paddr; 2974acb54baSEdgar E. Iglesias } 29829cd33d3SRichard Henderson 29929cd33d3SRichard Henderson bool mb_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 30029cd33d3SRichard Henderson { 301da953643SPhilippe Mathieu-Daudé CPUMBState *env = cpu_env(cs); 30229cd33d3SRichard Henderson 30329cd33d3SRichard Henderson if ((interrupt_request & CPU_INTERRUPT_HARD) 3042e5282caSRichard Henderson && (env->msr & MSR_IE) 3052e5282caSRichard Henderson && !(env->msr & (MSR_EIP | MSR_BIP)) 30629cd33d3SRichard Henderson && !(env->iflags & (D_FLAG | IMM_FLAG))) { 30729cd33d3SRichard Henderson cs->exception_index = EXCP_IRQ; 30829cd33d3SRichard Henderson mb_cpu_do_interrupt(cs); 30929cd33d3SRichard Henderson return true; 31029cd33d3SRichard Henderson } 31129cd33d3SRichard Henderson return false; 31229cd33d3SRichard Henderson } 313ab0c8d0fSRichard Henderson 314eb3ef313SPhilippe Mathieu-Daudé #endif /* !CONFIG_USER_ONLY */ 315