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 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "qemu/osdep.h" 22 #include "cpu.h" 23 #include "mmu.h" 24 #include "qemu/host-utils.h" 25 #include "exec/exec-all.h" 26 #include "exec/cpu_ldst.h" 27 28 29 //#define CRIS_HELPER_DEBUG 30 31 32 #ifdef CRIS_HELPER_DEBUG 33 #define D(x) x 34 #define D_LOG(...) qemu_log(__VA_ARGS__) 35 #else 36 #define D(x) 37 #define D_LOG(...) do { } while (0) 38 #endif 39 40 #if defined(CONFIG_USER_ONLY) 41 42 void cris_cpu_do_interrupt(CPUState *cs) 43 { 44 CRISCPU *cpu = CRIS_CPU(cs); 45 CPUCRISState *env = &cpu->env; 46 47 cs->exception_index = -1; 48 env->pregs[PR_ERP] = env->pc; 49 } 50 51 void crisv10_cpu_do_interrupt(CPUState *cs) 52 { 53 cris_cpu_do_interrupt(cs); 54 } 55 56 int cris_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, 57 int mmu_idx) 58 { 59 CRISCPU *cpu = CRIS_CPU(cs); 60 61 cs->exception_index = 0xaa; 62 cpu->env.pregs[PR_EDA] = address; 63 cpu_dump_state(cs, stderr, fprintf, 0); 64 return 1; 65 } 66 67 #else /* !CONFIG_USER_ONLY */ 68 69 70 static void cris_shift_ccs(CPUCRISState *env) 71 { 72 uint32_t ccs; 73 /* Apply the ccs shift. */ 74 ccs = env->pregs[PR_CCS]; 75 ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff; 76 env->pregs[PR_CCS] = ccs; 77 } 78 79 int cris_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, 80 int mmu_idx) 81 { 82 CRISCPU *cpu = CRIS_CPU(cs); 83 CPUCRISState *env = &cpu->env; 84 struct cris_mmu_result res; 85 int prot, miss; 86 int r = -1; 87 target_ulong phy; 88 89 qemu_log_mask(CPU_LOG_MMU, "%s addr=%" VADDR_PRIx " pc=%x rw=%x\n", 90 __func__, address, env->pc, rw); 91 miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK, 92 rw, mmu_idx, 0); 93 if (miss) { 94 if (cs->exception_index == EXCP_BUSFAULT) { 95 cpu_abort(cs, 96 "CRIS: Illegal recursive bus fault." 97 "addr=%" VADDR_PRIx " rw=%d\n", 98 address, rw); 99 } 100 101 env->pregs[PR_EDA] = address; 102 cs->exception_index = EXCP_BUSFAULT; 103 env->fault_vector = res.bf_vec; 104 r = 1; 105 } else { 106 /* 107 * Mask off the cache selection bit. The ETRAX busses do not 108 * see the top bit. 109 */ 110 phy = res.phy & ~0x80000000; 111 prot = res.prot; 112 tlb_set_page(cs, address & TARGET_PAGE_MASK, phy, 113 prot, mmu_idx, TARGET_PAGE_SIZE); 114 r = 0; 115 } 116 if (r > 0) { 117 qemu_log_mask(CPU_LOG_MMU, 118 "%s returns %d irqreq=%x addr=%" VADDR_PRIx " phy=%x vec=%x" 119 " pc=%x\n", __func__, r, cs->interrupt_request, address, 120 res.phy, res.bf_vec, env->pc); 121 } 122 return r; 123 } 124 125 void crisv10_cpu_do_interrupt(CPUState *cs) 126 { 127 CRISCPU *cpu = CRIS_CPU(cs); 128 CPUCRISState *env = &cpu->env; 129 int ex_vec = -1; 130 131 D_LOG("exception index=%d interrupt_req=%d\n", 132 cs->exception_index, 133 cs->interrupt_request); 134 135 if (env->dslot) { 136 /* CRISv10 never takes interrupts while in a delay-slot. */ 137 cpu_abort(cs, "CRIS: Interrupt on delay-slot\n"); 138 } 139 140 assert(!(env->pregs[PR_CCS] & PFIX_FLAG)); 141 switch (cs->exception_index) { 142 case EXCP_BREAK: 143 /* These exceptions are genereated by the core itself. 144 ERP should point to the insn following the brk. */ 145 ex_vec = env->trap_vector; 146 env->pregs[PRV10_BRP] = env->pc; 147 break; 148 149 case EXCP_NMI: 150 /* NMI is hardwired to vector zero. */ 151 ex_vec = 0; 152 env->pregs[PR_CCS] &= ~M_FLAG_V10; 153 env->pregs[PRV10_BRP] = env->pc; 154 break; 155 156 case EXCP_BUSFAULT: 157 cpu_abort(cs, "Unhandled busfault"); 158 break; 159 160 default: 161 /* The interrupt controller gives us the vector. */ 162 ex_vec = env->interrupt_vector; 163 /* Normal interrupts are taken between 164 TB's. env->pc is valid here. */ 165 env->pregs[PR_ERP] = env->pc; 166 break; 167 } 168 169 if (env->pregs[PR_CCS] & U_FLAG) { 170 /* Swap stack pointers. */ 171 env->pregs[PR_USP] = env->regs[R_SP]; 172 env->regs[R_SP] = env->ksp; 173 } 174 175 /* Now that we are in kernel mode, load the handlers address. */ 176 env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); 177 env->locked_irq = 1; 178 env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */ 179 180 qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", 181 __func__, env->pc, ex_vec, 182 env->pregs[PR_CCS], 183 env->pregs[PR_PID], 184 env->pregs[PR_ERP]); 185 } 186 187 void cris_cpu_do_interrupt(CPUState *cs) 188 { 189 CRISCPU *cpu = CRIS_CPU(cs); 190 CPUCRISState *env = &cpu->env; 191 int ex_vec = -1; 192 193 D_LOG("exception index=%d interrupt_req=%d\n", 194 cs->exception_index, 195 cs->interrupt_request); 196 197 switch (cs->exception_index) { 198 case EXCP_BREAK: 199 /* These exceptions are genereated by the core itself. 200 ERP should point to the insn following the brk. */ 201 ex_vec = env->trap_vector; 202 env->pregs[PR_ERP] = env->pc; 203 break; 204 205 case EXCP_NMI: 206 /* NMI is hardwired to vector zero. */ 207 ex_vec = 0; 208 env->pregs[PR_CCS] &= ~M_FLAG_V32; 209 env->pregs[PR_NRP] = env->pc; 210 break; 211 212 case EXCP_BUSFAULT: 213 ex_vec = env->fault_vector; 214 env->pregs[PR_ERP] = env->pc; 215 break; 216 217 default: 218 /* The interrupt controller gives us the vector. */ 219 ex_vec = env->interrupt_vector; 220 /* Normal interrupts are taken between 221 TB's. env->pc is valid here. */ 222 env->pregs[PR_ERP] = env->pc; 223 break; 224 } 225 226 /* Fill in the IDX field. */ 227 env->pregs[PR_EXS] = (ex_vec & 0xff) << 8; 228 229 if (env->dslot) { 230 D_LOG("excp isr=%x PC=%x ds=%d SP=%x" 231 " ERP=%x pid=%x ccs=%x cc=%d %x\n", 232 ex_vec, env->pc, env->dslot, 233 env->regs[R_SP], 234 env->pregs[PR_ERP], env->pregs[PR_PID], 235 env->pregs[PR_CCS], 236 env->cc_op, env->cc_mask); 237 /* We loose the btarget, btaken state here so rexec the 238 branch. */ 239 env->pregs[PR_ERP] -= env->dslot; 240 /* Exception starts with dslot cleared. */ 241 env->dslot = 0; 242 } 243 244 if (env->pregs[PR_CCS] & U_FLAG) { 245 /* Swap stack pointers. */ 246 env->pregs[PR_USP] = env->regs[R_SP]; 247 env->regs[R_SP] = env->ksp; 248 } 249 250 /* Apply the CRIS CCS shift. Clears U if set. */ 251 cris_shift_ccs(env); 252 253 /* Now that we are in kernel mode, load the handlers address. 254 This load may not fault, real hw leaves that behaviour as 255 undefined. */ 256 env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); 257 258 /* Clear the excption_index to avoid spurios hw_aborts for recursive 259 bus faults. */ 260 cs->exception_index = -1; 261 262 D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", 263 __func__, env->pc, ex_vec, 264 env->pregs[PR_CCS], 265 env->pregs[PR_PID], 266 env->pregs[PR_ERP]); 267 } 268 269 hwaddr cris_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 270 { 271 CRISCPU *cpu = CRIS_CPU(cs); 272 uint32_t phy = addr; 273 struct cris_mmu_result res; 274 int miss; 275 276 miss = cris_mmu_translate(&res, &cpu->env, addr, 0, 0, 1); 277 /* If D TLB misses, try I TLB. */ 278 if (miss) { 279 miss = cris_mmu_translate(&res, &cpu->env, addr, 2, 0, 1); 280 } 281 282 if (!miss) { 283 phy = res.phy; 284 } 285 D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy)); 286 return phy; 287 } 288 #endif 289 290 bool cris_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 291 { 292 CPUClass *cc = CPU_GET_CLASS(cs); 293 CRISCPU *cpu = CRIS_CPU(cs); 294 CPUCRISState *env = &cpu->env; 295 bool ret = false; 296 297 if (interrupt_request & CPU_INTERRUPT_HARD 298 && (env->pregs[PR_CCS] & I_FLAG) 299 && !env->locked_irq) { 300 cs->exception_index = EXCP_IRQ; 301 cc->do_interrupt(cs); 302 ret = true; 303 } 304 if (interrupt_request & CPU_INTERRUPT_NMI) { 305 unsigned int m_flag_archval; 306 if (env->pregs[PR_VR] < 32) { 307 m_flag_archval = M_FLAG_V10; 308 } else { 309 m_flag_archval = M_FLAG_V32; 310 } 311 if ((env->pregs[PR_CCS] & m_flag_archval)) { 312 cs->exception_index = EXCP_NMI; 313 cc->do_interrupt(cs); 314 ret = true; 315 } 316 } 317 318 return ret; 319 } 320