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