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