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