xref: /qemu/target/microblaze/helper.c (revision 3072961b6edc99abfbd87caac3de29bb58a52ccf)
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