ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 1 | /* |
| 2 | * CRIS helper routines. |
| 3 | * |
| 4 | * Copyright (c) 2007 AXIS Communications AB |
| 5 | * Written by Edgar E. Iglesias. |
| 6 | * |
| 7 | * This library is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU Lesser General Public |
| 9 | * License as published by the Free Software Foundation; either |
| 10 | * version 2 of the License, or (at your option) any later version. |
| 11 | * |
| 12 | * This library is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | * Lesser General Public License for more details. |
| 16 | * |
| 17 | * You should have received a copy of the GNU Lesser General Public |
Blue Swirl | 8167ee8 | 2009-07-16 20:47:01 +0000 | [diff] [blame] | 18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 19 | */ |
| 20 | |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 21 | #include "cpu.h" |
| 22 | #include "mmu.h" |
Paolo Bonzini | 1de7afc | 2012-12-17 18:20:00 +0100 | [diff] [blame] | 23 | #include "qemu/host-utils.h" |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 24 | |
aliguori | d12d51d | 2009-01-15 21:48:06 +0000 | [diff] [blame] | 25 | |
| 26 | //#define CRIS_HELPER_DEBUG |
| 27 | |
| 28 | |
| 29 | #ifdef CRIS_HELPER_DEBUG |
| 30 | #define D(x) x |
Andreas Färber | 3f668b6 | 2013-01-24 10:51:47 +0100 | [diff] [blame] | 31 | #define D_LOG(...) qemu_log(__VA_ARGS__) |
aliguori | d12d51d | 2009-01-15 21:48:06 +0000 | [diff] [blame] | 32 | #else |
edgar_igl | e62b5b1 | 2008-03-14 01:04:24 +0000 | [diff] [blame] | 33 | #define D(x) |
aliguori | d12d51d | 2009-01-15 21:48:06 +0000 | [diff] [blame] | 34 | #define D_LOG(...) do { } while (0) |
| 35 | #endif |
edgar_igl | e62b5b1 | 2008-03-14 01:04:24 +0000 | [diff] [blame] | 36 | |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 37 | #if defined(CONFIG_USER_ONLY) |
| 38 | |
Andreas Färber | 97a8ea5 | 2013-02-02 10:57:51 +0100 | [diff] [blame] | 39 | void cris_cpu_do_interrupt(CPUState *cs) |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 40 | { |
Andreas Färber | 97a8ea5 | 2013-02-02 10:57:51 +0100 | [diff] [blame] | 41 | CRISCPU *cpu = CRIS_CPU(cs); |
| 42 | CPUCRISState *env = &cpu->env; |
| 43 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 44 | env->exception_index = -1; |
| 45 | env->pregs[PR_ERP] = env->pc; |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 46 | } |
| 47 | |
Andreas Färber | b21bfee | 2013-02-18 19:59:39 +0100 | [diff] [blame] | 48 | void crisv10_cpu_do_interrupt(CPUState *cs) |
| 49 | { |
| 50 | cris_cpu_do_interrupt(cs); |
| 51 | } |
| 52 | |
Andreas Färber | a1170bf | 2012-03-14 01:38:21 +0100 | [diff] [blame] | 53 | int cpu_cris_handle_mmu_fault(CPUCRISState * env, target_ulong address, int rw, |
Blue Swirl | 97b348e | 2011-08-01 16:12:17 +0000 | [diff] [blame] | 54 | int mmu_idx) |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 55 | { |
Andreas Färber | 878096e | 2013-05-27 01:33:50 +0200 | [diff] [blame] | 56 | CRISCPU *cpu = cris_env_get_cpu(env); |
| 57 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 58 | env->exception_index = 0xaa; |
| 59 | env->pregs[PR_EDA] = address; |
Andreas Färber | 878096e | 2013-05-27 01:33:50 +0200 | [diff] [blame] | 60 | cpu_dump_state(CPU(cpu), stderr, fprintf, 0); |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 61 | return 1; |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 62 | } |
| 63 | |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 64 | #else /* !CONFIG_USER_ONLY */ |
| 65 | |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 66 | |
Andreas Färber | a1170bf | 2012-03-14 01:38:21 +0100 | [diff] [blame] | 67 | static void cris_shift_ccs(CPUCRISState *env) |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 68 | { |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 69 | uint32_t ccs; |
| 70 | /* Apply the ccs shift. */ |
| 71 | ccs = env->pregs[PR_CCS]; |
| 72 | ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff; |
| 73 | env->pregs[PR_CCS] = ccs; |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 74 | } |
| 75 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 76 | int cpu_cris_handle_mmu_fault(CPUCRISState *env, target_ulong address, int rw, |
| 77 | int mmu_idx) |
edgar_igl | e62b5b1 | 2008-03-14 01:04:24 +0000 | [diff] [blame] | 78 | { |
Andreas Färber | 259186a | 2013-01-17 18:51:17 +0100 | [diff] [blame] | 79 | D(CPUState *cpu = CPU(cris_env_get_cpu(env))); |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 80 | struct cris_mmu_result res; |
| 81 | int prot, miss; |
| 82 | int r = -1; |
| 83 | target_ulong phy; |
edgar_igl | e62b5b1 | 2008-03-14 01:04:24 +0000 | [diff] [blame] | 84 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 85 | D(printf("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw)); |
| 86 | miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK, |
| 87 | rw, mmu_idx, 0); |
| 88 | if (miss) { |
| 89 | if (env->exception_index == EXCP_BUSFAULT) { |
| 90 | cpu_abort(env, |
| 91 | "CRIS: Illegal recursive bus fault." |
| 92 | "addr=%x rw=%d\n", |
| 93 | address, rw); |
| 94 | } |
edgar_igl | ef29a70 | 2008-05-06 08:04:40 +0000 | [diff] [blame] | 95 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 96 | env->pregs[PR_EDA] = address; |
| 97 | env->exception_index = EXCP_BUSFAULT; |
| 98 | env->fault_vector = res.bf_vec; |
| 99 | r = 1; |
| 100 | } else { |
| 101 | /* |
| 102 | * Mask off the cache selection bit. The ETRAX busses do not |
| 103 | * see the top bit. |
| 104 | */ |
| 105 | phy = res.phy & ~0x80000000; |
| 106 | prot = res.prot; |
| 107 | tlb_set_page(env, address & TARGET_PAGE_MASK, phy, |
| 108 | prot, mmu_idx, TARGET_PAGE_SIZE); |
| 109 | r = 0; |
| 110 | } |
| 111 | if (r > 0) { |
| 112 | D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n", |
Andreas Färber | 259186a | 2013-01-17 18:51:17 +0100 | [diff] [blame] | 113 | __func__, r, cpu->interrupt_request, address, res.phy, |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 114 | res.bf_vec, env->pc); |
| 115 | } |
| 116 | return r; |
edgar_igl | e62b5b1 | 2008-03-14 01:04:24 +0000 | [diff] [blame] | 117 | } |
| 118 | |
Andreas Färber | b21bfee | 2013-02-18 19:59:39 +0100 | [diff] [blame] | 119 | void crisv10_cpu_do_interrupt(CPUState *cs) |
Edgar E. Iglesias | 7a97735 | 2010-02-15 11:47:34 +0100 | [diff] [blame] | 120 | { |
Andreas Färber | b21bfee | 2013-02-18 19:59:39 +0100 | [diff] [blame] | 121 | CRISCPU *cpu = CRIS_CPU(cs); |
| 122 | CPUCRISState *env = &cpu->env; |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 123 | int ex_vec = -1; |
Edgar E. Iglesias | 7a97735 | 2010-02-15 11:47:34 +0100 | [diff] [blame] | 124 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 125 | D_LOG("exception index=%d interrupt_req=%d\n", |
| 126 | env->exception_index, |
Andreas Färber | 259186a | 2013-01-17 18:51:17 +0100 | [diff] [blame] | 127 | cs->interrupt_request); |
Edgar E. Iglesias | 7a97735 | 2010-02-15 11:47:34 +0100 | [diff] [blame] | 128 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 129 | assert(!(env->pregs[PR_CCS] & PFIX_FLAG)); |
| 130 | switch (env->exception_index) { |
| 131 | case EXCP_BREAK: |
| 132 | /* These exceptions are genereated by the core itself. |
| 133 | ERP should point to the insn following the brk. */ |
| 134 | ex_vec = env->trap_vector; |
| 135 | env->pregs[PRV10_BRP] = env->pc; |
| 136 | break; |
Edgar E. Iglesias | 7a97735 | 2010-02-15 11:47:34 +0100 | [diff] [blame] | 137 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 138 | case EXCP_NMI: |
| 139 | /* NMI is hardwired to vector zero. */ |
| 140 | ex_vec = 0; |
| 141 | env->pregs[PR_CCS] &= ~M_FLAG_V10; |
| 142 | env->pregs[PRV10_BRP] = env->pc; |
| 143 | break; |
Edgar E. Iglesias | 7a97735 | 2010-02-15 11:47:34 +0100 | [diff] [blame] | 144 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 145 | case EXCP_BUSFAULT: |
| 146 | cpu_abort(env, "Unhandled busfault"); |
| 147 | break; |
Edgar E. Iglesias | 7a97735 | 2010-02-15 11:47:34 +0100 | [diff] [blame] | 148 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 149 | default: |
| 150 | /* The interrupt controller gives us the vector. */ |
| 151 | ex_vec = env->interrupt_vector; |
| 152 | /* Normal interrupts are taken between |
| 153 | TB's. env->pc is valid here. */ |
| 154 | env->pregs[PR_ERP] = env->pc; |
| 155 | break; |
| 156 | } |
Edgar E. Iglesias | 7a97735 | 2010-02-15 11:47:34 +0100 | [diff] [blame] | 157 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 158 | if (env->pregs[PR_CCS] & U_FLAG) { |
| 159 | /* Swap stack pointers. */ |
| 160 | env->pregs[PR_USP] = env->regs[R_SP]; |
| 161 | env->regs[R_SP] = env->ksp; |
| 162 | } |
Edgar E. Iglesias | 7a97735 | 2010-02-15 11:47:34 +0100 | [diff] [blame] | 163 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 164 | /* Now that we are in kernel mode, load the handlers address. */ |
| 165 | env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); |
| 166 | env->locked_irq = 1; |
| 167 | env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */ |
Edgar E. Iglesias | 7a97735 | 2010-02-15 11:47:34 +0100 | [diff] [blame] | 168 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 169 | qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", |
| 170 | __func__, env->pc, ex_vec, |
| 171 | env->pregs[PR_CCS], |
| 172 | env->pregs[PR_PID], |
| 173 | env->pregs[PR_ERP]); |
Edgar E. Iglesias | 7a97735 | 2010-02-15 11:47:34 +0100 | [diff] [blame] | 174 | } |
| 175 | |
Andreas Färber | 97a8ea5 | 2013-02-02 10:57:51 +0100 | [diff] [blame] | 176 | void cris_cpu_do_interrupt(CPUState *cs) |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 177 | { |
Andreas Färber | 97a8ea5 | 2013-02-02 10:57:51 +0100 | [diff] [blame] | 178 | CRISCPU *cpu = CRIS_CPU(cs); |
| 179 | CPUCRISState *env = &cpu->env; |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 180 | int ex_vec = -1; |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 181 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 182 | D_LOG("exception index=%d interrupt_req=%d\n", |
| 183 | env->exception_index, |
Andreas Färber | 259186a | 2013-01-17 18:51:17 +0100 | [diff] [blame] | 184 | cs->interrupt_request); |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 185 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 186 | switch (env->exception_index) { |
| 187 | case EXCP_BREAK: |
| 188 | /* These exceptions are genereated by the core itself. |
| 189 | ERP should point to the insn following the brk. */ |
| 190 | ex_vec = env->trap_vector; |
| 191 | env->pregs[PR_ERP] = env->pc; |
| 192 | break; |
edgar_igl | e62b5b1 | 2008-03-14 01:04:24 +0000 | [diff] [blame] | 193 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 194 | case EXCP_NMI: |
| 195 | /* NMI is hardwired to vector zero. */ |
| 196 | ex_vec = 0; |
| 197 | env->pregs[PR_CCS] &= ~M_FLAG_V32; |
| 198 | env->pregs[PR_NRP] = env->pc; |
| 199 | break; |
edgar_igl | 1b1a38b | 2008-06-09 23:18:06 +0000 | [diff] [blame] | 200 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 201 | case EXCP_BUSFAULT: |
| 202 | ex_vec = env->fault_vector; |
| 203 | env->pregs[PR_ERP] = env->pc; |
| 204 | break; |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 205 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 206 | default: |
| 207 | /* The interrupt controller gives us the vector. */ |
| 208 | ex_vec = env->interrupt_vector; |
| 209 | /* Normal interrupts are taken between |
| 210 | TB's. env->pc is valid here. */ |
| 211 | env->pregs[PR_ERP] = env->pc; |
| 212 | break; |
| 213 | } |
edgar_igl | b41f7df | 2008-05-02 22:16:17 +0000 | [diff] [blame] | 214 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 215 | /* Fill in the IDX field. */ |
| 216 | env->pregs[PR_EXS] = (ex_vec & 0xff) << 8; |
edgar_igl | cddffe3 | 2008-10-08 14:22:17 +0000 | [diff] [blame] | 217 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 218 | if (env->dslot) { |
| 219 | D_LOG("excp isr=%x PC=%x ds=%d SP=%x" |
| 220 | " ERP=%x pid=%x ccs=%x cc=%d %x\n", |
| 221 | ex_vec, env->pc, env->dslot, |
| 222 | env->regs[R_SP], |
| 223 | env->pregs[PR_ERP], env->pregs[PR_PID], |
| 224 | env->pregs[PR_CCS], |
| 225 | env->cc_op, env->cc_mask); |
| 226 | /* We loose the btarget, btaken state here so rexec the |
| 227 | branch. */ |
| 228 | env->pregs[PR_ERP] -= env->dslot; |
| 229 | /* Exception starts with dslot cleared. */ |
| 230 | env->dslot = 0; |
| 231 | } |
edgar_igl | b41f7df | 2008-05-02 22:16:17 +0000 | [diff] [blame] | 232 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 233 | if (env->pregs[PR_CCS] & U_FLAG) { |
| 234 | /* Swap stack pointers. */ |
| 235 | env->pregs[PR_USP] = env->regs[R_SP]; |
| 236 | env->regs[R_SP] = env->ksp; |
| 237 | } |
edgar_igl | b41f7df | 2008-05-02 22:16:17 +0000 | [diff] [blame] | 238 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 239 | /* Apply the CRIS CCS shift. Clears U if set. */ |
| 240 | cris_shift_ccs(env); |
Edgar E. Iglesias | 218951e | 2009-10-10 17:34:27 +0200 | [diff] [blame] | 241 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 242 | /* Now that we are in kernel mode, load the handlers address. |
| 243 | This load may not fault, real hw leaves that behaviour as |
| 244 | undefined. */ |
| 245 | env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); |
Edgar E. Iglesias | 218951e | 2009-10-10 17:34:27 +0200 | [diff] [blame] | 246 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 247 | /* Clear the excption_index to avoid spurios hw_aborts for recursive |
| 248 | bus faults. */ |
| 249 | env->exception_index = -1; |
Edgar E. Iglesias | abdfd95 | 2010-09-16 15:40:27 +0200 | [diff] [blame] | 250 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 251 | D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", |
| 252 | __func__, env->pc, ex_vec, |
| 253 | env->pregs[PR_CCS], |
| 254 | env->pregs[PR_PID], |
| 255 | env->pregs[PR_ERP]); |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 256 | } |
| 257 | |
Andreas Färber | 00b941e | 2013-06-29 18:55:54 +0200 | [diff] [blame] | 258 | hwaddr cris_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 259 | { |
Andreas Färber | 00b941e | 2013-06-29 18:55:54 +0200 | [diff] [blame] | 260 | CRISCPU *cpu = CRIS_CPU(cs); |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 261 | uint32_t phy = addr; |
| 262 | struct cris_mmu_result res; |
| 263 | int miss; |
Edgar E. Iglesias | 3c4fe42 | 2010-07-05 10:24:56 +0200 | [diff] [blame] | 264 | |
Andreas Färber | 00b941e | 2013-06-29 18:55:54 +0200 | [diff] [blame] | 265 | miss = cris_mmu_translate(&res, &cpu->env, addr, 0, 0, 1); |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 266 | /* If D TLB misses, try I TLB. */ |
| 267 | if (miss) { |
Andreas Färber | 00b941e | 2013-06-29 18:55:54 +0200 | [diff] [blame] | 268 | miss = cris_mmu_translate(&res, &cpu->env, addr, 2, 0, 1); |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 269 | } |
Edgar E. Iglesias | 3c4fe42 | 2010-07-05 10:24:56 +0200 | [diff] [blame] | 270 | |
Andreas Färber | 21317bc | 2013-01-25 17:37:28 +0100 | [diff] [blame] | 271 | if (!miss) { |
| 272 | phy = res.phy; |
| 273 | } |
| 274 | D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy)); |
| 275 | return phy; |
ths | 81fdc5f | 2007-10-08 13:04:02 +0000 | [diff] [blame] | 276 | } |
| 277 | #endif |