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
mb_unaligned_access_internal(CPUState * cs,uint64_t addr,uintptr_t retaddr)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
mb_cpu_do_unaligned_access(CPUState * cs,vaddr addr,MMUAccessType access_type,int mmu_idx,uintptr_t retaddr)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
HELPER(unaligned_access)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
mb_cpu_access_is_secure(MicroBlazeCPU * cpu,MMUAccessType access_type)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
mb_cpu_tlb_fill(CPUState * cs,vaddr address,int size,MMUAccessType access_type,int mmu_idx,bool probe,uintptr_t retaddr)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
mb_cpu_do_interrupt(CPUState * cs)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
mb_cpu_get_phys_page_attrs_debug(CPUState * cs,vaddr addr,MemTxAttrs * attrs)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
mb_cpu_exec_interrupt(CPUState * cs,int interrupt_request)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