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