]> Git Repo - qemu.git/blob - target-ppc/excp_helper.c
ppc: Use split I/D mmu modes to avoid flushes on interrupts
[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     /* XXX: 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     env->msr = new_msr & env->msr_mask;
716     hreg_compute_hflags(env);
717     env->nip = vector;
718     /* Reset exception state */
719     cs->exception_index = POWERPC_EXCP_NONE;
720     env->error_code = 0;
721 }
722
723 void ppc_cpu_do_interrupt(CPUState *cs)
724 {
725     PowerPCCPU *cpu = POWERPC_CPU(cs);
726     CPUPPCState *env = &cpu->env;
727
728     powerpc_excp(cpu, env->excp_model, cs->exception_index);
729 }
730
731 static void ppc_hw_interrupt(CPUPPCState *env)
732 {
733     PowerPCCPU *cpu = ppc_env_get_cpu(env);
734     int hdice;
735 #if 0
736     CPUState *cs = CPU(cpu);
737
738     qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
739                   __func__, env, env->pending_interrupts,
740                   cs->interrupt_request, (int)msr_me, (int)msr_ee);
741 #endif
742     /* External reset */
743     if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
744         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
745         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
746         return;
747     }
748     /* Machine check exception */
749     if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
750         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
751         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
752         return;
753     }
754 #if 0 /* TODO */
755     /* External debug exception */
756     if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
757         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
758         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
759         return;
760     }
761 #endif
762     if (0) {
763         /* XXX: find a suitable condition to enable the hypervisor mode */
764         hdice = env->spr[SPR_LPCR] & 1;
765     } else {
766         hdice = 0;
767     }
768     if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
769         /* Hypervisor decrementer exception */
770         if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
771             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
772             return;
773         }
774     }
775     if (msr_ce != 0) {
776         /* External critical interrupt */
777         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
778             /* Taking a critical external interrupt does not clear the external
779              * critical interrupt status
780              */
781 #if 0
782             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
783 #endif
784             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
785             return;
786         }
787     }
788     if (msr_ee != 0) {
789         /* Watchdog timer on embedded PowerPC */
790         if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
791             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
792             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
793             return;
794         }
795         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
796             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
797             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
798             return;
799         }
800         /* Fixed interval timer on embedded PowerPC */
801         if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
802             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
803             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
804             return;
805         }
806         /* Programmable interval timer on embedded PowerPC */
807         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
808             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
809             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
810             return;
811         }
812         /* Decrementer exception */
813         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
814             if (ppc_decr_clear_on_delivery(env)) {
815                 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
816             }
817             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
818             return;
819         }
820         /* External interrupt */
821         if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
822             /* Taking an external interrupt does not clear the external
823              * interrupt status
824              */
825 #if 0
826             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
827 #endif
828             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
829             return;
830         }
831         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
832             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
833             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
834             return;
835         }
836         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
837             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
838             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
839             return;
840         }
841         /* Thermal interrupt */
842         if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
843             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
844             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
845             return;
846         }
847     }
848 }
849
850 void ppc_cpu_do_system_reset(CPUState *cs)
851 {
852     PowerPCCPU *cpu = POWERPC_CPU(cs);
853     CPUPPCState *env = &cpu->env;
854
855     powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
856 }
857 #endif /* !CONFIG_USER_ONLY */
858
859 bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
860 {
861     PowerPCCPU *cpu = POWERPC_CPU(cs);
862     CPUPPCState *env = &cpu->env;
863
864     if (interrupt_request & CPU_INTERRUPT_HARD) {
865         ppc_hw_interrupt(env);
866         if (env->pending_interrupts == 0) {
867             cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
868         }
869         return true;
870     }
871     return false;
872 }
873
874 #if defined(DEBUG_OP)
875 static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
876 {
877     qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
878              TARGET_FMT_lx "\n", RA, msr);
879 }
880 #endif
881
882 /*****************************************************************************/
883 /* Exceptions processing helpers */
884
885 void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
886                                 uint32_t error_code)
887 {
888     CPUState *cs = CPU(ppc_env_get_cpu(env));
889
890 #if 0
891     printf("Raise exception %3x code : %d\n", exception, error_code);
892 #endif
893     cs->exception_index = exception;
894     env->error_code = error_code;
895     cpu_loop_exit(cs);
896 }
897
898 void helper_raise_exception(CPUPPCState *env, uint32_t exception)
899 {
900     helper_raise_exception_err(env, exception, 0);
901 }
902
903 #if !defined(CONFIG_USER_ONLY)
904 void helper_store_msr(CPUPPCState *env, target_ulong val)
905 {
906     CPUState *cs;
907
908     val = hreg_store_msr(env, val, 0);
909     if (val != 0) {
910         cs = CPU(ppc_env_get_cpu(env));
911         cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
912         helper_raise_exception(env, val);
913     }
914 }
915
916 static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
917                           target_ulong msrm, int keep_msrh)
918 {
919     CPUState *cs = CPU(ppc_env_get_cpu(env));
920
921 #if defined(TARGET_PPC64)
922     if (msr_is_64bit(env, msr)) {
923         nip = (uint64_t)nip;
924         msr &= (uint64_t)msrm;
925     } else {
926         nip = (uint32_t)nip;
927         msr = (uint32_t)(msr & msrm);
928         if (keep_msrh) {
929             msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
930         }
931     }
932 #else
933     nip = (uint32_t)nip;
934     msr &= (uint32_t)msrm;
935 #endif
936     /* XXX: beware: this is false if VLE is supported */
937     env->nip = nip & ~((target_ulong)0x00000003);
938     hreg_store_msr(env, msr, 1);
939 #if defined(DEBUG_OP)
940     cpu_dump_rfi(env->nip, env->msr);
941 #endif
942     /* No need to raise an exception here,
943      * as rfi is always the last insn of a TB
944      */
945     cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
946 }
947
948 void helper_rfi(CPUPPCState *env)
949 {
950     if (env->excp_model == POWERPC_EXCP_BOOKE) {
951         do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
952                ~((target_ulong)0), 0);
953     } else {
954         do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
955                ~((target_ulong)0x783F0000), 1);
956     }
957 }
958
959 #if defined(TARGET_PPC64)
960 void helper_rfid(CPUPPCState *env)
961 {
962     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
963            ~((target_ulong)0x783F0000), 0);
964 }
965
966 void helper_hrfid(CPUPPCState *env)
967 {
968     do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
969            ~((target_ulong)0x783F0000), 0);
970 }
971 #endif
972
973 /*****************************************************************************/
974 /* Embedded PowerPC specific helpers */
975 void helper_40x_rfci(CPUPPCState *env)
976 {
977     do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
978            ~((target_ulong)0xFFFF0000), 0);
979 }
980
981 void helper_rfci(CPUPPCState *env)
982 {
983     do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
984            ~((target_ulong)0), 0);
985 }
986
987 void helper_rfdi(CPUPPCState *env)
988 {
989     /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
990     do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1],
991            ~((target_ulong)0), 0);
992 }
993
994 void helper_rfmci(CPUPPCState *env)
995 {
996     /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
997     do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1],
998            ~((target_ulong)0), 0);
999 }
1000 #endif
1001
1002 void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1003                uint32_t flags)
1004 {
1005     if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1006                   ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1007                   ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1008                   ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1009                   ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
1010         helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1011                                    POWERPC_EXCP_TRAP);
1012     }
1013 }
1014
1015 #if defined(TARGET_PPC64)
1016 void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1017                uint32_t flags)
1018 {
1019     if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1020                   ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1021                   ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1022                   ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1023                   ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
1024         helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1025                                    POWERPC_EXCP_TRAP);
1026     }
1027 }
1028 #endif
1029
1030 #if !defined(CONFIG_USER_ONLY)
1031 /*****************************************************************************/
1032 /* PowerPC 601 specific instructions (POWER bridge) */
1033
1034 void helper_rfsvc(CPUPPCState *env)
1035 {
1036     do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
1037 }
1038
1039 /* Embedded.Processor Control */
1040 static int dbell2irq(target_ulong rb)
1041 {
1042     int msg = rb & DBELL_TYPE_MASK;
1043     int irq = -1;
1044
1045     switch (msg) {
1046     case DBELL_TYPE_DBELL:
1047         irq = PPC_INTERRUPT_DOORBELL;
1048         break;
1049     case DBELL_TYPE_DBELL_CRIT:
1050         irq = PPC_INTERRUPT_CDOORBELL;
1051         break;
1052     case DBELL_TYPE_G_DBELL:
1053     case DBELL_TYPE_G_DBELL_CRIT:
1054     case DBELL_TYPE_G_DBELL_MC:
1055         /* XXX implement */
1056     default:
1057         break;
1058     }
1059
1060     return irq;
1061 }
1062
1063 void helper_msgclr(CPUPPCState *env, target_ulong rb)
1064 {
1065     int irq = dbell2irq(rb);
1066
1067     if (irq < 0) {
1068         return;
1069     }
1070
1071     env->pending_interrupts &= ~(1 << irq);
1072 }
1073
1074 void helper_msgsnd(target_ulong rb)
1075 {
1076     int irq = dbell2irq(rb);
1077     int pir = rb & DBELL_PIRTAG_MASK;
1078     CPUState *cs;
1079
1080     if (irq < 0) {
1081         return;
1082     }
1083
1084     CPU_FOREACH(cs) {
1085         PowerPCCPU *cpu = POWERPC_CPU(cs);
1086         CPUPPCState *cenv = &cpu->env;
1087
1088         if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
1089             cenv->pending_interrupts |= 1 << irq;
1090             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
1091         }
1092     }
1093 }
1094 #endif
This page took 0.085916 seconds and 4 git commands to generate.