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