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