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