cpu: move exec-all.h inclusion out of cpu.h
[qemu/cris-port.git] / target-ppc / excp_helper.c
blob288903ee1d35739927336cc87c3c3bc57c212368
1 /*
2 * PowerPC exception emulation helpers for QEMU.
4 * Copyright (c) 2003-2007 Jocelyn Mayer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #include "qemu/osdep.h"
20 #include "cpu.h"
21 #include "exec/helper-proto.h"
22 #include "exec/exec-all.h"
23 #include "exec/cpu_ldst.h"
25 #include "helper_regs.h"
27 //#define DEBUG_OP
28 //#define DEBUG_SOFTWARE_TLB
29 //#define DEBUG_EXCEPTIONS
31 #ifdef DEBUG_EXCEPTIONS
32 # define LOG_EXCP(...) qemu_log(__VA_ARGS__)
33 #else
34 # define LOG_EXCP(...) do { } while (0)
35 #endif
37 /*****************************************************************************/
38 /* PowerPC Hypercall emulation */
40 void (*cpu_ppc_hypercall)(PowerPCCPU *);
42 /*****************************************************************************/
43 /* Exception processing */
44 #if defined(CONFIG_USER_ONLY)
45 void ppc_cpu_do_interrupt(CPUState *cs)
47 PowerPCCPU *cpu = POWERPC_CPU(cs);
48 CPUPPCState *env = &cpu->env;
50 cs->exception_index = POWERPC_EXCP_NONE;
51 env->error_code = 0;
54 static void ppc_hw_interrupt(CPUPPCState *env)
56 CPUState *cs = CPU(ppc_env_get_cpu(env));
58 cs->exception_index = POWERPC_EXCP_NONE;
59 env->error_code = 0;
61 #else /* defined(CONFIG_USER_ONLY) */
62 static inline void dump_syscall(CPUPPCState *env)
64 qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
65 " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
66 " nip=" TARGET_FMT_lx "\n",
67 ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
68 ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
69 ppc_dump_gpr(env, 6), env->nip);
72 /* Note that this function should be greatly optimized
73 * when called with a constant excp, from ppc_hw_interrupt
75 static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
77 CPUState *cs = CPU(cpu);
78 CPUPPCState *env = &cpu->env;
79 target_ulong msr, new_msr, vector;
80 int srr0, srr1, asrr0, asrr1;
81 int lpes0, lpes1, lev, ail;
83 if (0) {
84 /* XXX: find a suitable condition to enable the hypervisor mode */
85 lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
86 lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
87 } else {
88 /* Those values ensure we won't enter the hypervisor mode */
89 lpes0 = 0;
90 lpes1 = 1;
93 qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
94 " => %08x (%02x)\n", env->nip, excp, env->error_code);
96 /* new srr1 value excluding must-be-zero bits */
97 if (excp_model == POWERPC_EXCP_BOOKE) {
98 msr = env->msr;
99 } else {
100 msr = env->msr & ~0x783f0000ULL;
103 /* new interrupt handler msr */
104 new_msr = env->msr & ((target_ulong)1 << MSR_ME);
106 /* target registers */
107 srr0 = SPR_SRR0;
108 srr1 = SPR_SRR1;
109 asrr0 = -1;
110 asrr1 = -1;
112 /* Exception targetting modifiers
114 * AIL is initialized here but can be cleared by
115 * selected exceptions
117 #if defined(TARGET_PPC64)
118 if (excp_model == POWERPC_EXCP_POWER7 ||
119 excp_model == POWERPC_EXCP_POWER8) {
120 if (excp_model == POWERPC_EXCP_POWER8) {
121 ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
122 } else {
123 ail = 0;
125 } else
126 #endif /* defined(TARGET_PPC64) */
128 ail = 0;
131 switch (excp) {
132 case POWERPC_EXCP_NONE:
133 /* Should never happen */
134 return;
135 case POWERPC_EXCP_CRITICAL: /* Critical input */
136 switch (excp_model) {
137 case POWERPC_EXCP_40x:
138 srr0 = SPR_40x_SRR2;
139 srr1 = SPR_40x_SRR3;
140 break;
141 case POWERPC_EXCP_BOOKE:
142 srr0 = SPR_BOOKE_CSRR0;
143 srr1 = SPR_BOOKE_CSRR1;
144 break;
145 case POWERPC_EXCP_G2:
146 break;
147 default:
148 goto excp_invalid;
150 goto store_next;
151 case POWERPC_EXCP_MCHECK: /* Machine check exception */
152 if (msr_me == 0) {
153 /* Machine check exception is not enabled.
154 * Enter checkstop state.
156 fprintf(stderr, "Machine check while not allowed. "
157 "Entering checkstop state\n");
158 if (qemu_log_separate()) {
159 qemu_log("Machine check while not allowed. "
160 "Entering checkstop state\n");
162 cs->halted = 1;
163 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
165 if (0) {
166 /* XXX: find a suitable condition to enable the hypervisor mode */
167 new_msr |= (target_ulong)MSR_HVB;
169 ail = 0;
171 /* machine check exceptions don't have ME set */
172 new_msr &= ~((target_ulong)1 << MSR_ME);
174 /* XXX: should also have something loaded in DAR / DSISR */
175 switch (excp_model) {
176 case POWERPC_EXCP_40x:
177 srr0 = SPR_40x_SRR2;
178 srr1 = SPR_40x_SRR3;
179 break;
180 case POWERPC_EXCP_BOOKE:
181 /* FIXME: choose one or the other based on CPU type */
182 srr0 = SPR_BOOKE_MCSRR0;
183 srr1 = SPR_BOOKE_MCSRR1;
184 asrr0 = SPR_BOOKE_CSRR0;
185 asrr1 = SPR_BOOKE_CSRR1;
186 break;
187 default:
188 break;
190 goto store_next;
191 case POWERPC_EXCP_DSI: /* Data storage exception */
192 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
193 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
194 if (lpes1 == 0) {
195 new_msr |= (target_ulong)MSR_HVB;
197 goto store_next;
198 case POWERPC_EXCP_ISI: /* Instruction storage exception */
199 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
200 "\n", msr, env->nip);
201 if (lpes1 == 0) {
202 new_msr |= (target_ulong)MSR_HVB;
204 msr |= env->error_code;
205 goto store_next;
206 case POWERPC_EXCP_EXTERNAL: /* External input */
207 cs = CPU(cpu);
209 if (lpes0 == 1) {
210 new_msr |= (target_ulong)MSR_HVB;
212 if (env->mpic_proxy) {
213 /* IACK the IRQ on delivery */
214 env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
216 goto store_next;
217 case POWERPC_EXCP_ALIGN: /* Alignment exception */
218 if (lpes1 == 0) {
219 new_msr |= (target_ulong)MSR_HVB;
221 /* XXX: this is false */
222 /* Get rS/rD and rA from faulting opcode */
223 env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
224 & 0x03FF0000) >> 16;
225 goto store_next;
226 case POWERPC_EXCP_PROGRAM: /* Program exception */
227 switch (env->error_code & ~0xF) {
228 case POWERPC_EXCP_FP:
229 if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
230 LOG_EXCP("Ignore floating point exception\n");
231 cs->exception_index = POWERPC_EXCP_NONE;
232 env->error_code = 0;
233 return;
235 if (lpes1 == 0) {
236 new_msr |= (target_ulong)MSR_HVB;
238 msr |= 0x00100000;
239 if (msr_fe0 == msr_fe1) {
240 goto store_next;
242 msr |= 0x00010000;
243 break;
244 case POWERPC_EXCP_INVAL:
245 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
246 if (lpes1 == 0) {
247 new_msr |= (target_ulong)MSR_HVB;
249 msr |= 0x00080000;
250 env->spr[SPR_BOOKE_ESR] = ESR_PIL;
251 break;
252 case POWERPC_EXCP_PRIV:
253 if (lpes1 == 0) {
254 new_msr |= (target_ulong)MSR_HVB;
256 msr |= 0x00040000;
257 env->spr[SPR_BOOKE_ESR] = ESR_PPR;
258 break;
259 case POWERPC_EXCP_TRAP:
260 if (lpes1 == 0) {
261 new_msr |= (target_ulong)MSR_HVB;
263 msr |= 0x00020000;
264 env->spr[SPR_BOOKE_ESR] = ESR_PTR;
265 break;
266 default:
267 /* Should never occur */
268 cpu_abort(cs, "Invalid program exception %d. Aborting\n",
269 env->error_code);
270 break;
272 goto store_current;
273 case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
274 if (lpes1 == 0) {
275 new_msr |= (target_ulong)MSR_HVB;
277 goto store_current;
278 case POWERPC_EXCP_SYSCALL: /* System call exception */
279 dump_syscall(env);
280 lev = env->error_code;
281 if ((lev == 1) && cpu_ppc_hypercall) {
282 cpu_ppc_hypercall(cpu);
283 return;
285 if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
286 new_msr |= (target_ulong)MSR_HVB;
288 goto store_next;
289 case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
290 goto store_current;
291 case POWERPC_EXCP_DECR: /* Decrementer exception */
292 if (lpes1 == 0) {
293 new_msr |= (target_ulong)MSR_HVB;
295 goto store_next;
296 case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
297 /* FIT on 4xx */
298 LOG_EXCP("FIT exception\n");
299 goto store_next;
300 case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
301 LOG_EXCP("WDT exception\n");
302 switch (excp_model) {
303 case POWERPC_EXCP_BOOKE:
304 srr0 = SPR_BOOKE_CSRR0;
305 srr1 = SPR_BOOKE_CSRR1;
306 break;
307 default:
308 break;
310 goto store_next;
311 case POWERPC_EXCP_DTLB: /* Data TLB error */
312 goto store_next;
313 case POWERPC_EXCP_ITLB: /* Instruction TLB error */
314 goto store_next;
315 case POWERPC_EXCP_DEBUG: /* Debug interrupt */
316 switch (excp_model) {
317 case POWERPC_EXCP_BOOKE:
318 /* FIXME: choose one or the other based on CPU type */
319 srr0 = SPR_BOOKE_DSRR0;
320 srr1 = SPR_BOOKE_DSRR1;
321 asrr0 = SPR_BOOKE_CSRR0;
322 asrr1 = SPR_BOOKE_CSRR1;
323 break;
324 default:
325 break;
327 /* XXX: TODO */
328 cpu_abort(cs, "Debug exception is not implemented yet !\n");
329 goto store_next;
330 case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
331 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
332 goto store_current;
333 case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
334 /* XXX: TODO */
335 cpu_abort(cs, "Embedded floating point data exception "
336 "is not implemented yet !\n");
337 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
338 goto store_next;
339 case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
340 /* XXX: TODO */
341 cpu_abort(cs, "Embedded floating point round exception "
342 "is not implemented yet !\n");
343 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
344 goto store_next;
345 case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
346 /* XXX: TODO */
347 cpu_abort(cs,
348 "Performance counter exception is not implemented yet !\n");
349 goto store_next;
350 case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
351 goto store_next;
352 case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
353 srr0 = SPR_BOOKE_CSRR0;
354 srr1 = SPR_BOOKE_CSRR1;
355 goto store_next;
356 case POWERPC_EXCP_RESET: /* System reset exception */
357 if (msr_pow) {
358 /* indicate that we resumed from power save mode */
359 msr |= 0x10000;
360 } else {
361 new_msr &= ~((target_ulong)1 << MSR_ME);
364 if (0) {
365 /* XXX: find a suitable condition to enable the hypervisor mode */
366 new_msr |= (target_ulong)MSR_HVB;
368 ail = 0;
369 goto store_next;
370 case POWERPC_EXCP_DSEG: /* Data segment exception */
371 if (lpes1 == 0) {
372 new_msr |= (target_ulong)MSR_HVB;
374 goto store_next;
375 case POWERPC_EXCP_ISEG: /* Instruction segment exception */
376 if (lpes1 == 0) {
377 new_msr |= (target_ulong)MSR_HVB;
379 goto store_next;
380 case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
381 srr0 = SPR_HSRR0;
382 srr1 = SPR_HSRR1;
383 new_msr |= (target_ulong)MSR_HVB;
384 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
385 goto store_next;
386 case POWERPC_EXCP_TRACE: /* Trace exception */
387 if (lpes1 == 0) {
388 new_msr |= (target_ulong)MSR_HVB;
390 goto store_next;
391 case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
392 srr0 = SPR_HSRR0;
393 srr1 = SPR_HSRR1;
394 new_msr |= (target_ulong)MSR_HVB;
395 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
396 goto store_next;
397 case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
398 srr0 = SPR_HSRR0;
399 srr1 = SPR_HSRR1;
400 new_msr |= (target_ulong)MSR_HVB;
401 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
402 goto store_next;
403 case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
404 srr0 = SPR_HSRR0;
405 srr1 = SPR_HSRR1;
406 new_msr |= (target_ulong)MSR_HVB;
407 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
408 goto store_next;
409 case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
410 srr0 = SPR_HSRR0;
411 srr1 = SPR_HSRR1;
412 new_msr |= (target_ulong)MSR_HVB;
413 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
414 goto store_next;
415 case POWERPC_EXCP_VPU: /* Vector unavailable exception */
416 if (lpes1 == 0) {
417 new_msr |= (target_ulong)MSR_HVB;
419 goto store_current;
420 case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
421 if (lpes1 == 0) {
422 new_msr |= (target_ulong)MSR_HVB;
424 goto store_current;
425 case POWERPC_EXCP_FU: /* Facility unavailable exception */
426 if (lpes1 == 0) {
427 new_msr |= (target_ulong)MSR_HVB;
429 goto store_current;
430 case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
431 LOG_EXCP("PIT exception\n");
432 goto store_next;
433 case POWERPC_EXCP_IO: /* IO error exception */
434 /* XXX: TODO */
435 cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
436 goto store_next;
437 case POWERPC_EXCP_RUNM: /* Run mode exception */
438 /* XXX: TODO */
439 cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
440 goto store_next;
441 case POWERPC_EXCP_EMUL: /* Emulation trap exception */
442 /* XXX: TODO */
443 cpu_abort(cs, "602 emulation trap exception "
444 "is not implemented yet !\n");
445 goto store_next;
446 case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
447 if (lpes1 == 0) { /* XXX: check this */
448 new_msr |= (target_ulong)MSR_HVB;
450 switch (excp_model) {
451 case POWERPC_EXCP_602:
452 case POWERPC_EXCP_603:
453 case POWERPC_EXCP_603E:
454 case POWERPC_EXCP_G2:
455 goto tlb_miss_tgpr;
456 case POWERPC_EXCP_7x5:
457 goto tlb_miss;
458 case POWERPC_EXCP_74xx:
459 goto tlb_miss_74xx;
460 default:
461 cpu_abort(cs, "Invalid instruction TLB miss exception\n");
462 break;
464 break;
465 case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
466 if (lpes1 == 0) { /* XXX: check this */
467 new_msr |= (target_ulong)MSR_HVB;
469 switch (excp_model) {
470 case POWERPC_EXCP_602:
471 case POWERPC_EXCP_603:
472 case POWERPC_EXCP_603E:
473 case POWERPC_EXCP_G2:
474 goto tlb_miss_tgpr;
475 case POWERPC_EXCP_7x5:
476 goto tlb_miss;
477 case POWERPC_EXCP_74xx:
478 goto tlb_miss_74xx;
479 default:
480 cpu_abort(cs, "Invalid data load TLB miss exception\n");
481 break;
483 break;
484 case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
485 if (lpes1 == 0) { /* XXX: check this */
486 new_msr |= (target_ulong)MSR_HVB;
488 switch (excp_model) {
489 case POWERPC_EXCP_602:
490 case POWERPC_EXCP_603:
491 case POWERPC_EXCP_603E:
492 case POWERPC_EXCP_G2:
493 tlb_miss_tgpr:
494 /* Swap temporary saved registers with GPRs */
495 if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
496 new_msr |= (target_ulong)1 << MSR_TGPR;
497 hreg_swap_gpr_tgpr(env);
499 goto tlb_miss;
500 case POWERPC_EXCP_7x5:
501 tlb_miss:
502 #if defined(DEBUG_SOFTWARE_TLB)
503 if (qemu_log_enabled()) {
504 const char *es;
505 target_ulong *miss, *cmp;
506 int en;
508 if (excp == POWERPC_EXCP_IFTLB) {
509 es = "I";
510 en = 'I';
511 miss = &env->spr[SPR_IMISS];
512 cmp = &env->spr[SPR_ICMP];
513 } else {
514 if (excp == POWERPC_EXCP_DLTLB) {
515 es = "DL";
516 } else {
517 es = "DS";
519 en = 'D';
520 miss = &env->spr[SPR_DMISS];
521 cmp = &env->spr[SPR_DCMP];
523 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
524 TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
525 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
526 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
527 env->error_code);
529 #endif
530 msr |= env->crf[0] << 28;
531 msr |= env->error_code; /* key, D/I, S/L bits */
532 /* Set way using a LRU mechanism */
533 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
534 break;
535 case POWERPC_EXCP_74xx:
536 tlb_miss_74xx:
537 #if defined(DEBUG_SOFTWARE_TLB)
538 if (qemu_log_enabled()) {
539 const char *es;
540 target_ulong *miss, *cmp;
541 int en;
543 if (excp == POWERPC_EXCP_IFTLB) {
544 es = "I";
545 en = 'I';
546 miss = &env->spr[SPR_TLBMISS];
547 cmp = &env->spr[SPR_PTEHI];
548 } else {
549 if (excp == POWERPC_EXCP_DLTLB) {
550 es = "DL";
551 } else {
552 es = "DS";
554 en = 'D';
555 miss = &env->spr[SPR_TLBMISS];
556 cmp = &env->spr[SPR_PTEHI];
558 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
559 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
560 env->error_code);
562 #endif
563 msr |= env->error_code; /* key bit */
564 break;
565 default:
566 cpu_abort(cs, "Invalid data store TLB miss exception\n");
567 break;
569 goto store_next;
570 case POWERPC_EXCP_FPA: /* Floating-point assist exception */
571 /* XXX: TODO */
572 cpu_abort(cs, "Floating point assist exception "
573 "is not implemented yet !\n");
574 goto store_next;
575 case POWERPC_EXCP_DABR: /* Data address breakpoint */
576 /* XXX: TODO */
577 cpu_abort(cs, "DABR exception is not implemented yet !\n");
578 goto store_next;
579 case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
580 /* XXX: TODO */
581 cpu_abort(cs, "IABR exception is not implemented yet !\n");
582 goto store_next;
583 case POWERPC_EXCP_SMI: /* System management interrupt */
584 /* XXX: TODO */
585 cpu_abort(cs, "SMI exception is not implemented yet !\n");
586 goto store_next;
587 case POWERPC_EXCP_THERM: /* Thermal interrupt */
588 /* XXX: TODO */
589 cpu_abort(cs, "Thermal management exception "
590 "is not implemented yet !\n");
591 goto store_next;
592 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
593 if (lpes1 == 0) {
594 new_msr |= (target_ulong)MSR_HVB;
596 /* XXX: TODO */
597 cpu_abort(cs,
598 "Performance counter exception is not implemented yet !\n");
599 goto store_next;
600 case POWERPC_EXCP_VPUA: /* Vector assist exception */
601 /* XXX: TODO */
602 cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
603 goto store_next;
604 case POWERPC_EXCP_SOFTP: /* Soft patch exception */
605 /* XXX: TODO */
606 cpu_abort(cs,
607 "970 soft-patch exception is not implemented yet !\n");
608 goto store_next;
609 case POWERPC_EXCP_MAINT: /* Maintenance exception */
610 /* XXX: TODO */
611 cpu_abort(cs,
612 "970 maintenance exception is not implemented yet !\n");
613 goto store_next;
614 case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
615 /* XXX: TODO */
616 cpu_abort(cs, "Maskable external exception "
617 "is not implemented yet !\n");
618 goto store_next;
619 case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
620 /* XXX: TODO */
621 cpu_abort(cs, "Non maskable external exception "
622 "is not implemented yet !\n");
623 goto store_next;
624 default:
625 excp_invalid:
626 cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
627 break;
628 store_current:
629 /* save current instruction location */
630 env->spr[srr0] = env->nip - 4;
631 break;
632 store_next:
633 /* save next instruction location */
634 env->spr[srr0] = env->nip;
635 break;
637 /* Save MSR */
638 env->spr[srr1] = msr;
639 /* If any alternate SRR register are defined, duplicate saved values */
640 if (asrr0 != -1) {
641 env->spr[asrr0] = env->spr[srr0];
643 if (asrr1 != -1) {
644 env->spr[asrr1] = env->spr[srr1];
647 if (env->spr[SPR_LPCR] & LPCR_AIL) {
648 new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
649 } else if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
650 /* If we disactivated any translation, flush TLBs */
651 tlb_flush(cs, 1);
654 #ifdef TARGET_PPC64
655 if (excp_model == POWERPC_EXCP_POWER7 ||
656 excp_model == POWERPC_EXCP_POWER8) {
657 if (env->spr[SPR_LPCR] & LPCR_ILE) {
658 new_msr |= (target_ulong)1 << MSR_LE;
660 } else if (msr_ile) {
661 new_msr |= (target_ulong)1 << MSR_LE;
663 #else
664 if (msr_ile) {
665 new_msr |= (target_ulong)1 << MSR_LE;
667 #endif
669 /* Jump to handler */
670 vector = env->excp_vectors[excp];
671 if (vector == (target_ulong)-1ULL) {
672 cpu_abort(cs, "Raised an exception without defined vector %d\n",
673 excp);
675 vector |= env->excp_prefix;
677 /* AIL only works if there is no HV transition and we are running with
678 * translations enabled
680 if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1)) {
681 ail = 0;
683 /* Handle AIL */
684 if (ail) {
685 new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
686 switch(ail) {
687 case AIL_0001_8000:
688 vector |= 0x18000;
689 break;
690 case AIL_C000_0000_0000_4000:
691 vector |= 0xc000000000004000ull;
692 break;
693 default:
694 cpu_abort(cs, "Invalid AIL combination %d\n", ail);
695 break;
699 #if defined(TARGET_PPC64)
700 if (excp_model == POWERPC_EXCP_BOOKE) {
701 if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
702 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
703 new_msr |= (target_ulong)1 << MSR_CM;
704 } else {
705 vector = (uint32_t)vector;
707 } else {
708 if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
709 vector = (uint32_t)vector;
710 } else {
711 new_msr |= (target_ulong)1 << MSR_SF;
714 #endif
715 /* XXX: we don't use hreg_store_msr here as already have treated
716 * any special case that could occur. Just store MSR and update hflags
718 env->msr = new_msr & env->msr_mask;
719 hreg_compute_hflags(env);
720 env->nip = vector;
721 /* Reset exception state */
722 cs->exception_index = POWERPC_EXCP_NONE;
723 env->error_code = 0;
725 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
726 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
727 /* XXX: The BookE changes address space when switching modes,
728 we should probably implement that as different MMU indexes,
729 but for the moment we do it the slow way and flush all. */
730 tlb_flush(cs, 1);
734 void ppc_cpu_do_interrupt(CPUState *cs)
736 PowerPCCPU *cpu = POWERPC_CPU(cs);
737 CPUPPCState *env = &cpu->env;
739 powerpc_excp(cpu, env->excp_model, cs->exception_index);
742 static void ppc_hw_interrupt(CPUPPCState *env)
744 PowerPCCPU *cpu = ppc_env_get_cpu(env);
745 int hdice;
746 #if 0
747 CPUState *cs = CPU(cpu);
749 qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
750 __func__, env, env->pending_interrupts,
751 cs->interrupt_request, (int)msr_me, (int)msr_ee);
752 #endif
753 /* External reset */
754 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
755 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
756 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
757 return;
759 /* Machine check exception */
760 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
761 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
762 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
763 return;
765 #if 0 /* TODO */
766 /* External debug exception */
767 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
768 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
769 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
770 return;
772 #endif
773 if (0) {
774 /* XXX: find a suitable condition to enable the hypervisor mode */
775 hdice = env->spr[SPR_LPCR] & 1;
776 } else {
777 hdice = 0;
779 if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
780 /* Hypervisor decrementer exception */
781 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
782 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
783 return;
786 if (msr_ce != 0) {
787 /* External critical interrupt */
788 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
789 /* Taking a critical external interrupt does not clear the external
790 * critical interrupt status
792 #if 0
793 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
794 #endif
795 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
796 return;
799 if (msr_ee != 0) {
800 /* Watchdog timer on embedded PowerPC */
801 if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
802 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
803 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
804 return;
806 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
807 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
808 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
809 return;
811 /* Fixed interval timer on embedded PowerPC */
812 if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
813 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
814 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
815 return;
817 /* Programmable interval timer on embedded PowerPC */
818 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
819 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
820 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
821 return;
823 /* Decrementer exception */
824 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
825 if (ppc_decr_clear_on_delivery(env)) {
826 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
828 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
829 return;
831 /* External interrupt */
832 if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
833 /* Taking an external interrupt does not clear the external
834 * interrupt status
836 #if 0
837 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
838 #endif
839 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
840 return;
842 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
843 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
844 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
845 return;
847 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
848 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
849 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
850 return;
852 /* Thermal interrupt */
853 if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
854 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
855 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
856 return;
861 void ppc_cpu_do_system_reset(CPUState *cs)
863 PowerPCCPU *cpu = POWERPC_CPU(cs);
864 CPUPPCState *env = &cpu->env;
866 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
868 #endif /* !CONFIG_USER_ONLY */
870 bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
872 PowerPCCPU *cpu = POWERPC_CPU(cs);
873 CPUPPCState *env = &cpu->env;
875 if (interrupt_request & CPU_INTERRUPT_HARD) {
876 ppc_hw_interrupt(env);
877 if (env->pending_interrupts == 0) {
878 cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
880 return true;
882 return false;
885 #if defined(DEBUG_OP)
886 static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
888 qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
889 TARGET_FMT_lx "\n", RA, msr);
891 #endif
893 /*****************************************************************************/
894 /* Exceptions processing helpers */
896 void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
897 uint32_t error_code)
899 CPUState *cs = CPU(ppc_env_get_cpu(env));
901 #if 0
902 printf("Raise exception %3x code : %d\n", exception, error_code);
903 #endif
904 cs->exception_index = exception;
905 env->error_code = error_code;
906 cpu_loop_exit(cs);
909 void helper_raise_exception(CPUPPCState *env, uint32_t exception)
911 helper_raise_exception_err(env, exception, 0);
914 #if !defined(CONFIG_USER_ONLY)
915 void helper_store_msr(CPUPPCState *env, target_ulong val)
917 CPUState *cs;
919 val = hreg_store_msr(env, val, 0);
920 if (val != 0) {
921 cs = CPU(ppc_env_get_cpu(env));
922 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
923 helper_raise_exception(env, val);
927 static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
928 target_ulong msrm, int keep_msrh)
930 CPUState *cs = CPU(ppc_env_get_cpu(env));
932 #if defined(TARGET_PPC64)
933 if (msr_is_64bit(env, msr)) {
934 nip = (uint64_t)nip;
935 msr &= (uint64_t)msrm;
936 } else {
937 nip = (uint32_t)nip;
938 msr = (uint32_t)(msr & msrm);
939 if (keep_msrh) {
940 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
943 #else
944 nip = (uint32_t)nip;
945 msr &= (uint32_t)msrm;
946 #endif
947 /* XXX: beware: this is false if VLE is supported */
948 env->nip = nip & ~((target_ulong)0x00000003);
949 hreg_store_msr(env, msr, 1);
950 #if defined(DEBUG_OP)
951 cpu_dump_rfi(env->nip, env->msr);
952 #endif
953 /* No need to raise an exception here,
954 * as rfi is always the last insn of a TB
956 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
959 void helper_rfi(CPUPPCState *env)
961 if (env->excp_model == POWERPC_EXCP_BOOKE) {
962 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
963 ~((target_ulong)0), 0);
964 } else {
965 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
966 ~((target_ulong)0x783F0000), 1);
970 #if defined(TARGET_PPC64)
971 void helper_rfid(CPUPPCState *env)
973 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
974 ~((target_ulong)0x783F0000), 0);
977 void helper_hrfid(CPUPPCState *env)
979 do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
980 ~((target_ulong)0x783F0000), 0);
982 #endif
984 /*****************************************************************************/
985 /* Embedded PowerPC specific helpers */
986 void helper_40x_rfci(CPUPPCState *env)
988 do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
989 ~((target_ulong)0xFFFF0000), 0);
992 void helper_rfci(CPUPPCState *env)
994 do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
995 ~((target_ulong)0), 0);
998 void helper_rfdi(CPUPPCState *env)
1000 /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
1001 do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1],
1002 ~((target_ulong)0), 0);
1005 void helper_rfmci(CPUPPCState *env)
1007 /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
1008 do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1],
1009 ~((target_ulong)0), 0);
1011 #endif
1013 void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1014 uint32_t flags)
1016 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1017 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1018 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1019 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1020 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
1021 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1022 POWERPC_EXCP_TRAP);
1026 #if defined(TARGET_PPC64)
1027 void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1028 uint32_t flags)
1030 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1031 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1032 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1033 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1034 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
1035 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1036 POWERPC_EXCP_TRAP);
1039 #endif
1041 #if !defined(CONFIG_USER_ONLY)
1042 /*****************************************************************************/
1043 /* PowerPC 601 specific instructions (POWER bridge) */
1045 void helper_rfsvc(CPUPPCState *env)
1047 do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
1050 /* Embedded.Processor Control */
1051 static int dbell2irq(target_ulong rb)
1053 int msg = rb & DBELL_TYPE_MASK;
1054 int irq = -1;
1056 switch (msg) {
1057 case DBELL_TYPE_DBELL:
1058 irq = PPC_INTERRUPT_DOORBELL;
1059 break;
1060 case DBELL_TYPE_DBELL_CRIT:
1061 irq = PPC_INTERRUPT_CDOORBELL;
1062 break;
1063 case DBELL_TYPE_G_DBELL:
1064 case DBELL_TYPE_G_DBELL_CRIT:
1065 case DBELL_TYPE_G_DBELL_MC:
1066 /* XXX implement */
1067 default:
1068 break;
1071 return irq;
1074 void helper_msgclr(CPUPPCState *env, target_ulong rb)
1076 int irq = dbell2irq(rb);
1078 if (irq < 0) {
1079 return;
1082 env->pending_interrupts &= ~(1 << irq);
1085 void helper_msgsnd(target_ulong rb)
1087 int irq = dbell2irq(rb);
1088 int pir = rb & DBELL_PIRTAG_MASK;
1089 CPUState *cs;
1091 if (irq < 0) {
1092 return;
1095 CPU_FOREACH(cs) {
1096 PowerPCCPU *cpu = POWERPC_CPU(cs);
1097 CPUPPCState *cenv = &cpu->env;
1099 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
1100 cenv->pending_interrupts |= 1 << irq;
1101 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
1105 #endif