xref: /qemu/target/ppc/excp_helper.c (revision f8154fd22bf80b1555bac46119747e899c09d0c9)
1ad71ed68SBlue Swirl /*
2ad71ed68SBlue Swirl  *  PowerPC exception emulation helpers for QEMU.
3ad71ed68SBlue Swirl  *
4ad71ed68SBlue Swirl  *  Copyright (c) 2003-2007 Jocelyn Mayer
5ad71ed68SBlue Swirl  *
6ad71ed68SBlue Swirl  * This library is free software; you can redistribute it and/or
7ad71ed68SBlue Swirl  * modify it under the terms of the GNU Lesser General Public
8ad71ed68SBlue Swirl  * License as published by the Free Software Foundation; either
9ad71ed68SBlue Swirl  * version 2 of the License, or (at your option) any later version.
10ad71ed68SBlue Swirl  *
11ad71ed68SBlue Swirl  * This library is distributed in the hope that it will be useful,
12ad71ed68SBlue Swirl  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13ad71ed68SBlue Swirl  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14ad71ed68SBlue Swirl  * Lesser General Public License for more details.
15ad71ed68SBlue Swirl  *
16ad71ed68SBlue Swirl  * You should have received a copy of the GNU Lesser General Public
17ad71ed68SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18ad71ed68SBlue Swirl  */
190d75590dSPeter Maydell #include "qemu/osdep.h"
20f1c29ebcSThomas Huth #include "qemu/main-loop.h"
21ad71ed68SBlue Swirl #include "cpu.h"
222ef6175aSRichard Henderson #include "exec/helper-proto.h"
2363c91552SPaolo Bonzini #include "exec/exec-all.h"
24f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h"
250f3110faSRichard Henderson #include "internal.h"
26ad71ed68SBlue Swirl #include "helper_regs.h"
27ad71ed68SBlue Swirl 
28ad71ed68SBlue Swirl //#define DEBUG_OP
2948880da6SPaolo Bonzini //#define DEBUG_SOFTWARE_TLB
30ad71ed68SBlue Swirl //#define DEBUG_EXCEPTIONS
31ad71ed68SBlue Swirl 
32c79c73f6SBlue Swirl #ifdef DEBUG_EXCEPTIONS
33c79c73f6SBlue Swirl #  define LOG_EXCP(...) qemu_log(__VA_ARGS__)
34c79c73f6SBlue Swirl #else
35c79c73f6SBlue Swirl #  define LOG_EXCP(...) do { } while (0)
36c79c73f6SBlue Swirl #endif
37c79c73f6SBlue Swirl 
38c79c73f6SBlue Swirl /*****************************************************************************/
39c79c73f6SBlue Swirl /* Exception processing */
40c79c73f6SBlue Swirl #if defined(CONFIG_USER_ONLY)
4197a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs)
42c79c73f6SBlue Swirl {
4397a8ea5aSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(cs);
4497a8ea5aSAndreas Färber     CPUPPCState *env = &cpu->env;
4597a8ea5aSAndreas Färber 
4627103424SAndreas Färber     cs->exception_index = POWERPC_EXCP_NONE;
47c79c73f6SBlue Swirl     env->error_code = 0;
48c79c73f6SBlue Swirl }
49c79c73f6SBlue Swirl 
50458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env)
51c79c73f6SBlue Swirl {
5227103424SAndreas Färber     CPUState *cs = CPU(ppc_env_get_cpu(env));
5327103424SAndreas Färber 
5427103424SAndreas Färber     cs->exception_index = POWERPC_EXCP_NONE;
55c79c73f6SBlue Swirl     env->error_code = 0;
56c79c73f6SBlue Swirl }
57c79c73f6SBlue Swirl #else /* defined(CONFIG_USER_ONLY) */
58c79c73f6SBlue Swirl static inline void dump_syscall(CPUPPCState *env)
59c79c73f6SBlue Swirl {
60c79c73f6SBlue Swirl     qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
61c79c73f6SBlue Swirl                   " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
62c79c73f6SBlue Swirl                   " nip=" TARGET_FMT_lx "\n",
63c79c73f6SBlue Swirl                   ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
64c79c73f6SBlue Swirl                   ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
65c79c73f6SBlue Swirl                   ppc_dump_gpr(env, 6), env->nip);
66c79c73f6SBlue Swirl }
67c79c73f6SBlue Swirl 
68dead760bSBenjamin Herrenschmidt static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
69dead760bSBenjamin Herrenschmidt                                 target_ulong *msr)
70dead760bSBenjamin Herrenschmidt {
71dead760bSBenjamin Herrenschmidt     /* We no longer are in a PM state */
721e7fd61dSBenjamin Herrenschmidt     env->resume_as_sreset = false;
73dead760bSBenjamin Herrenschmidt 
74dead760bSBenjamin Herrenschmidt     /* Pretend to be returning from doze always as we don't lose state */
75dead760bSBenjamin Herrenschmidt     *msr |= (0x1ull << (63 - 47));
76dead760bSBenjamin Herrenschmidt 
77dead760bSBenjamin Herrenschmidt     /* Machine checks are sent normally */
78dead760bSBenjamin Herrenschmidt     if (excp == POWERPC_EXCP_MCHECK) {
79dead760bSBenjamin Herrenschmidt         return excp;
80dead760bSBenjamin Herrenschmidt     }
81dead760bSBenjamin Herrenschmidt     switch (excp) {
82dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_RESET:
83dead760bSBenjamin Herrenschmidt         *msr |= 0x4ull << (63 - 45);
84dead760bSBenjamin Herrenschmidt         break;
85dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_EXTERNAL:
86dead760bSBenjamin Herrenschmidt         *msr |= 0x8ull << (63 - 45);
87dead760bSBenjamin Herrenschmidt         break;
88dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_DECR:
89dead760bSBenjamin Herrenschmidt         *msr |= 0x6ull << (63 - 45);
90dead760bSBenjamin Herrenschmidt         break;
91dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_SDOOR:
92dead760bSBenjamin Herrenschmidt         *msr |= 0x5ull << (63 - 45);
93dead760bSBenjamin Herrenschmidt         break;
94dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_SDOOR_HV:
95dead760bSBenjamin Herrenschmidt         *msr |= 0x3ull << (63 - 45);
96dead760bSBenjamin Herrenschmidt         break;
97dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_HV_MAINT:
98dead760bSBenjamin Herrenschmidt         *msr |= 0xaull << (63 - 45);
99dead760bSBenjamin Herrenschmidt         break;
100dead760bSBenjamin Herrenschmidt     default:
101dead760bSBenjamin Herrenschmidt         cpu_abort(cs, "Unsupported exception %d in Power Save mode\n",
102dead760bSBenjamin Herrenschmidt                   excp);
103dead760bSBenjamin Herrenschmidt     }
104dead760bSBenjamin Herrenschmidt     return POWERPC_EXCP_RESET;
105dead760bSBenjamin Herrenschmidt }
106dead760bSBenjamin Herrenschmidt 
107dead760bSBenjamin Herrenschmidt 
108c79c73f6SBlue Swirl /* Note that this function should be greatly optimized
109c79c73f6SBlue Swirl  * when called with a constant excp, from ppc_hw_interrupt
110c79c73f6SBlue Swirl  */
1115c26a5b3SAndreas Färber static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
112c79c73f6SBlue Swirl {
11327103424SAndreas Färber     CPUState *cs = CPU(cpu);
1145c26a5b3SAndreas Färber     CPUPPCState *env = &cpu->env;
115c79c73f6SBlue Swirl     target_ulong msr, new_msr, vector;
1166d49d6d4SBenjamin Herrenschmidt     int srr0, srr1, asrr0, asrr1, lev, ail;
1176d49d6d4SBenjamin Herrenschmidt     bool lpes0;
118c79c73f6SBlue Swirl 
119c79c73f6SBlue Swirl     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
120c79c73f6SBlue Swirl                   " => %08x (%02x)\n", env->nip, excp, env->error_code);
121c79c73f6SBlue Swirl 
122c79c73f6SBlue Swirl     /* new srr1 value excluding must-be-zero bits */
123a1bb7384SScott Wood     if (excp_model == POWERPC_EXCP_BOOKE) {
124a1bb7384SScott Wood         msr = env->msr;
125a1bb7384SScott Wood     } else {
126c79c73f6SBlue Swirl         msr = env->msr & ~0x783f0000ULL;
127a1bb7384SScott Wood     }
128c79c73f6SBlue Swirl 
1296d49d6d4SBenjamin Herrenschmidt     /* new interrupt handler msr preserves existing HV and ME unless
1306d49d6d4SBenjamin Herrenschmidt      * explicitly overriden
1316d49d6d4SBenjamin Herrenschmidt      */
1326d49d6d4SBenjamin Herrenschmidt     new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
133c79c73f6SBlue Swirl 
134c79c73f6SBlue Swirl     /* target registers */
135c79c73f6SBlue Swirl     srr0 = SPR_SRR0;
136c79c73f6SBlue Swirl     srr1 = SPR_SRR1;
137c79c73f6SBlue Swirl     asrr0 = -1;
138c79c73f6SBlue Swirl     asrr1 = -1;
139c79c73f6SBlue Swirl 
14021c0d66aSBenjamin Herrenschmidt     /*
14121c0d66aSBenjamin Herrenschmidt      * check for special resume at 0x100 from doze/nap/sleep/winkle on
14221c0d66aSBenjamin Herrenschmidt      * P7/P8/P9
14321c0d66aSBenjamin Herrenschmidt      */
1441e7fd61dSBenjamin Herrenschmidt     if (env->resume_as_sreset) {
145dead760bSBenjamin Herrenschmidt         excp = powerpc_reset_wakeup(cs, env, excp, &msr);
1467778a575SBenjamin Herrenschmidt     }
1477778a575SBenjamin Herrenschmidt 
1485c94b2a5SCédric Le Goater     /* Exception targetting modifiers
1495c94b2a5SCédric Le Goater      *
150a790e82bSBenjamin Herrenschmidt      * LPES0 is supported on POWER7/8/9
1516d49d6d4SBenjamin Herrenschmidt      * LPES1 is not supported (old iSeries mode)
1526d49d6d4SBenjamin Herrenschmidt      *
1536d49d6d4SBenjamin Herrenschmidt      * On anything else, we behave as if LPES0 is 1
1546d49d6d4SBenjamin Herrenschmidt      * (externals don't alter MSR:HV)
1556d49d6d4SBenjamin Herrenschmidt      *
1565c94b2a5SCédric Le Goater      * AIL is initialized here but can be cleared by
1575c94b2a5SCédric Le Goater      * selected exceptions
1585c94b2a5SCédric Le Goater      */
1595c94b2a5SCédric Le Goater #if defined(TARGET_PPC64)
1605c94b2a5SCédric Le Goater     if (excp_model == POWERPC_EXCP_POWER7 ||
161a790e82bSBenjamin Herrenschmidt         excp_model == POWERPC_EXCP_POWER8 ||
162a790e82bSBenjamin Herrenschmidt         excp_model == POWERPC_EXCP_POWER9) {
1636d49d6d4SBenjamin Herrenschmidt         lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
164a790e82bSBenjamin Herrenschmidt         if (excp_model != POWERPC_EXCP_POWER7) {
1655c94b2a5SCédric Le Goater             ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
1665c94b2a5SCédric Le Goater         } else {
1675c94b2a5SCédric Le Goater             ail = 0;
1685c94b2a5SCédric Le Goater         }
1695c94b2a5SCédric Le Goater     } else
1705c94b2a5SCédric Le Goater #endif /* defined(TARGET_PPC64) */
1715c94b2a5SCédric Le Goater     {
1726d49d6d4SBenjamin Herrenschmidt         lpes0 = true;
1735c94b2a5SCédric Le Goater         ail = 0;
1745c94b2a5SCédric Le Goater     }
1755c94b2a5SCédric Le Goater 
1769b2faddaSBenjamin Herrenschmidt     /* Hypervisor emulation assistance interrupt only exists on server
1779b2faddaSBenjamin Herrenschmidt      * arch 2.05 server or later. We also don't want to generate it if
1789b2faddaSBenjamin Herrenschmidt      * we don't have HVB in msr_mask (PAPR mode).
1799b2faddaSBenjamin Herrenschmidt      */
1809b2faddaSBenjamin Herrenschmidt     if (excp == POWERPC_EXCP_HV_EMU
1819b2faddaSBenjamin Herrenschmidt #if defined(TARGET_PPC64)
1829b2faddaSBenjamin Herrenschmidt         && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB))
1839b2faddaSBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */
1849b2faddaSBenjamin Herrenschmidt 
1859b2faddaSBenjamin Herrenschmidt     ) {
1869b2faddaSBenjamin Herrenschmidt         excp = POWERPC_EXCP_PROGRAM;
1879b2faddaSBenjamin Herrenschmidt     }
1889b2faddaSBenjamin Herrenschmidt 
189c79c73f6SBlue Swirl     switch (excp) {
190c79c73f6SBlue Swirl     case POWERPC_EXCP_NONE:
191c79c73f6SBlue Swirl         /* Should never happen */
192c79c73f6SBlue Swirl         return;
193c79c73f6SBlue Swirl     case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
194c79c73f6SBlue Swirl         switch (excp_model) {
195c79c73f6SBlue Swirl         case POWERPC_EXCP_40x:
196c79c73f6SBlue Swirl             srr0 = SPR_40x_SRR2;
197c79c73f6SBlue Swirl             srr1 = SPR_40x_SRR3;
198c79c73f6SBlue Swirl             break;
199c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
200c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_CSRR0;
201c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_CSRR1;
202c79c73f6SBlue Swirl             break;
203c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
204c79c73f6SBlue Swirl             break;
205c79c73f6SBlue Swirl         default:
206c79c73f6SBlue Swirl             goto excp_invalid;
207c79c73f6SBlue Swirl         }
208bd6fefe7SBenjamin Herrenschmidt         break;
209c79c73f6SBlue Swirl     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
210c79c73f6SBlue Swirl         if (msr_me == 0) {
211c79c73f6SBlue Swirl             /* Machine check exception is not enabled.
212c79c73f6SBlue Swirl              * Enter checkstop state.
213c79c73f6SBlue Swirl              */
214c79c73f6SBlue Swirl             fprintf(stderr, "Machine check while not allowed. "
215c79c73f6SBlue Swirl                     "Entering checkstop state\n");
216013a2942SPaolo Bonzini             if (qemu_log_separate()) {
217013a2942SPaolo Bonzini                 qemu_log("Machine check while not allowed. "
218013a2942SPaolo Bonzini                         "Entering checkstop state\n");
219c79c73f6SBlue Swirl             }
220259186a7SAndreas Färber             cs->halted = 1;
221044897efSRichard Purdie             cpu_interrupt_exittb(cs);
222c79c73f6SBlue Swirl         }
22310c21b5cSNicholas Piggin         if (env->msr_mask & MSR_HVB) {
22410c21b5cSNicholas Piggin             /* ISA specifies HV, but can be delivered to guest with HV clear
22510c21b5cSNicholas Piggin              * (e.g., see FWNMI in PAPR).
22610c21b5cSNicholas Piggin              */
227c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
22810c21b5cSNicholas Piggin         }
2295c94b2a5SCédric Le Goater         ail = 0;
230c79c73f6SBlue Swirl 
231c79c73f6SBlue Swirl         /* machine check exceptions don't have ME set */
232c79c73f6SBlue Swirl         new_msr &= ~((target_ulong)1 << MSR_ME);
233c79c73f6SBlue Swirl 
234c79c73f6SBlue Swirl         /* XXX: should also have something loaded in DAR / DSISR */
235c79c73f6SBlue Swirl         switch (excp_model) {
236c79c73f6SBlue Swirl         case POWERPC_EXCP_40x:
237c79c73f6SBlue Swirl             srr0 = SPR_40x_SRR2;
238c79c73f6SBlue Swirl             srr1 = SPR_40x_SRR3;
239c79c73f6SBlue Swirl             break;
240c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
241a1bb7384SScott Wood             /* FIXME: choose one or the other based on CPU type */
242c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_MCSRR0;
243c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_MCSRR1;
244c79c73f6SBlue Swirl             asrr0 = SPR_BOOKE_CSRR0;
245c79c73f6SBlue Swirl             asrr1 = SPR_BOOKE_CSRR1;
246c79c73f6SBlue Swirl             break;
247c79c73f6SBlue Swirl         default:
248c79c73f6SBlue Swirl             break;
249c79c73f6SBlue Swirl         }
250bd6fefe7SBenjamin Herrenschmidt         break;
251c79c73f6SBlue Swirl     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
252c79c73f6SBlue Swirl         LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
253c79c73f6SBlue Swirl                  "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
254bd6fefe7SBenjamin Herrenschmidt         break;
255c79c73f6SBlue Swirl     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
256c79c73f6SBlue Swirl         LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
257c79c73f6SBlue Swirl                  "\n", msr, env->nip);
258c79c73f6SBlue Swirl         msr |= env->error_code;
259bd6fefe7SBenjamin Herrenschmidt         break;
260c79c73f6SBlue Swirl     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
261fdfba1a2SEdgar E. Iglesias         cs = CPU(cpu);
262fdfba1a2SEdgar E. Iglesias 
2636d49d6d4SBenjamin Herrenschmidt         if (!lpes0) {
264c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
2656d49d6d4SBenjamin Herrenschmidt             new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
2666d49d6d4SBenjamin Herrenschmidt             srr0 = SPR_HSRR0;
2676d49d6d4SBenjamin Herrenschmidt             srr1 = SPR_HSRR1;
268c79c73f6SBlue Swirl         }
26968c2dd70SAlexander Graf         if (env->mpic_proxy) {
27068c2dd70SAlexander Graf             /* IACK the IRQ on delivery */
271fdfba1a2SEdgar E. Iglesias             env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
27268c2dd70SAlexander Graf         }
273bd6fefe7SBenjamin Herrenschmidt         break;
274c79c73f6SBlue Swirl     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
275c79c73f6SBlue Swirl         /* Get rS/rD and rA from faulting opcode */
2763433b732SBenjamin Herrenschmidt         /* Note: the opcode fields will not be set properly for a direct
2773433b732SBenjamin Herrenschmidt          * store load/store, but nobody cares as nobody actually uses
2783433b732SBenjamin Herrenschmidt          * direct store segments.
2793433b732SBenjamin Herrenschmidt          */
2803433b732SBenjamin Herrenschmidt         env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
281bd6fefe7SBenjamin Herrenschmidt         break;
282c79c73f6SBlue Swirl     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
283c79c73f6SBlue Swirl         switch (env->error_code & ~0xF) {
284c79c73f6SBlue Swirl         case POWERPC_EXCP_FP:
285c79c73f6SBlue Swirl             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
286c79c73f6SBlue Swirl                 LOG_EXCP("Ignore floating point exception\n");
28727103424SAndreas Färber                 cs->exception_index = POWERPC_EXCP_NONE;
288c79c73f6SBlue Swirl                 env->error_code = 0;
289c79c73f6SBlue Swirl                 return;
290c79c73f6SBlue Swirl             }
2911b7d17caSBenjamin Herrenschmidt 
2921b7d17caSBenjamin Herrenschmidt             /* FP exceptions always have NIP pointing to the faulting
2931b7d17caSBenjamin Herrenschmidt              * instruction, so always use store_next and claim we are
2941b7d17caSBenjamin Herrenschmidt              * precise in the MSR.
2951b7d17caSBenjamin Herrenschmidt              */
296c79c73f6SBlue Swirl             msr |= 0x00100000;
2970ee604abSAaron Larson             env->spr[SPR_BOOKE_ESR] = ESR_FP;
298bd6fefe7SBenjamin Herrenschmidt             break;
299c79c73f6SBlue Swirl         case POWERPC_EXCP_INVAL:
300c79c73f6SBlue Swirl             LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
301c79c73f6SBlue Swirl             msr |= 0x00080000;
302c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PIL;
303c79c73f6SBlue Swirl             break;
304c79c73f6SBlue Swirl         case POWERPC_EXCP_PRIV:
305c79c73f6SBlue Swirl             msr |= 0x00040000;
306c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PPR;
307c79c73f6SBlue Swirl             break;
308c79c73f6SBlue Swirl         case POWERPC_EXCP_TRAP:
309c79c73f6SBlue Swirl             msr |= 0x00020000;
310c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PTR;
311c79c73f6SBlue Swirl             break;
312c79c73f6SBlue Swirl         default:
313c79c73f6SBlue Swirl             /* Should never occur */
314a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid program exception %d. Aborting\n",
315c79c73f6SBlue Swirl                       env->error_code);
316c79c73f6SBlue Swirl             break;
317c79c73f6SBlue Swirl         }
318bd6fefe7SBenjamin Herrenschmidt         break;
319c79c73f6SBlue Swirl     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
320c79c73f6SBlue Swirl         dump_syscall(env);
321c79c73f6SBlue Swirl         lev = env->error_code;
3226d49d6d4SBenjamin Herrenschmidt 
323bd6fefe7SBenjamin Herrenschmidt         /* We need to correct the NIP which in this case is supposed
324bd6fefe7SBenjamin Herrenschmidt          * to point to the next instruction
325bd6fefe7SBenjamin Herrenschmidt          */
326bd6fefe7SBenjamin Herrenschmidt         env->nip += 4;
327bd6fefe7SBenjamin Herrenschmidt 
3286d49d6d4SBenjamin Herrenschmidt         /* "PAPR mode" built-in hypercall emulation */
3291d1be34dSDavid Gibson         if ((lev == 1) && cpu->vhyp) {
3301d1be34dSDavid Gibson             PPCVirtualHypervisorClass *vhc =
3311d1be34dSDavid Gibson                 PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
3321d1be34dSDavid Gibson             vhc->hypercall(cpu->vhyp, cpu);
333c79c73f6SBlue Swirl             return;
334c79c73f6SBlue Swirl         }
3356d49d6d4SBenjamin Herrenschmidt         if (lev == 1) {
336c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
337c79c73f6SBlue Swirl         }
338bd6fefe7SBenjamin Herrenschmidt         break;
339bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
340c79c73f6SBlue Swirl     case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
341c79c73f6SBlue Swirl     case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
342bd6fefe7SBenjamin Herrenschmidt         break;
343c79c73f6SBlue Swirl     case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
344c79c73f6SBlue Swirl         /* FIT on 4xx */
345c79c73f6SBlue Swirl         LOG_EXCP("FIT exception\n");
346bd6fefe7SBenjamin Herrenschmidt         break;
347c79c73f6SBlue Swirl     case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
348c79c73f6SBlue Swirl         LOG_EXCP("WDT exception\n");
349c79c73f6SBlue Swirl         switch (excp_model) {
350c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
351c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_CSRR0;
352c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_CSRR1;
353c79c73f6SBlue Swirl             break;
354c79c73f6SBlue Swirl         default:
355c79c73f6SBlue Swirl             break;
356c79c73f6SBlue Swirl         }
357bd6fefe7SBenjamin Herrenschmidt         break;
358c79c73f6SBlue Swirl     case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
359c79c73f6SBlue Swirl     case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
360bd6fefe7SBenjamin Herrenschmidt         break;
361c79c73f6SBlue Swirl     case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
3620e3bf489SRoman Kapl         if (env->flags & POWERPC_FLAG_DE) {
363a1bb7384SScott Wood             /* FIXME: choose one or the other based on CPU type */
364c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_DSRR0;
365c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_DSRR1;
366c79c73f6SBlue Swirl             asrr0 = SPR_BOOKE_CSRR0;
367c79c73f6SBlue Swirl             asrr1 = SPR_BOOKE_CSRR1;
3680e3bf489SRoman Kapl             /* DBSR already modified by caller */
3690e3bf489SRoman Kapl         } else {
3700e3bf489SRoman Kapl             cpu_abort(cs, "Debug exception triggered on unsupported model\n");
371c79c73f6SBlue Swirl         }
372bd6fefe7SBenjamin Herrenschmidt         break;
373c79c73f6SBlue Swirl     case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
374c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
375bd6fefe7SBenjamin Herrenschmidt         break;
376c79c73f6SBlue Swirl     case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
377c79c73f6SBlue Swirl         /* XXX: TODO */
378a47dddd7SAndreas Färber         cpu_abort(cs, "Embedded floating point data exception "
379c79c73f6SBlue Swirl                   "is not implemented yet !\n");
380c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
381bd6fefe7SBenjamin Herrenschmidt         break;
382c79c73f6SBlue Swirl     case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
383c79c73f6SBlue Swirl         /* XXX: TODO */
384a47dddd7SAndreas Färber         cpu_abort(cs, "Embedded floating point round exception "
385c79c73f6SBlue Swirl                   "is not implemented yet !\n");
386c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
387bd6fefe7SBenjamin Herrenschmidt         break;
388c79c73f6SBlue Swirl     case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
389c79c73f6SBlue Swirl         /* XXX: TODO */
390a47dddd7SAndreas Färber         cpu_abort(cs,
391c79c73f6SBlue Swirl                   "Performance counter exception is not implemented yet !\n");
392bd6fefe7SBenjamin Herrenschmidt         break;
393c79c73f6SBlue Swirl     case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
394bd6fefe7SBenjamin Herrenschmidt         break;
395c79c73f6SBlue Swirl     case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
396c79c73f6SBlue Swirl         srr0 = SPR_BOOKE_CSRR0;
397c79c73f6SBlue Swirl         srr1 = SPR_BOOKE_CSRR1;
398bd6fefe7SBenjamin Herrenschmidt         break;
399c79c73f6SBlue Swirl     case POWERPC_EXCP_RESET:     /* System reset exception                   */
400f85bcec3SNicholas Piggin         /* A power-saving exception sets ME, otherwise it is unchanged */
401c79c73f6SBlue Swirl         if (msr_pow) {
402c79c73f6SBlue Swirl             /* indicate that we resumed from power save mode */
403c79c73f6SBlue Swirl             msr |= 0x10000;
404f85bcec3SNicholas Piggin             new_msr |= ((target_ulong)1 << MSR_ME);
405c79c73f6SBlue Swirl         }
40610c21b5cSNicholas Piggin         if (env->msr_mask & MSR_HVB) {
40710c21b5cSNicholas Piggin             /* ISA specifies HV, but can be delivered to guest with HV clear
40810c21b5cSNicholas Piggin              * (e.g., see FWNMI in PAPR, NMI injection in QEMU).
40910c21b5cSNicholas Piggin              */
410c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
41110c21b5cSNicholas Piggin         } else {
41210c21b5cSNicholas Piggin             if (msr_pow) {
41310c21b5cSNicholas Piggin                 cpu_abort(cs, "Trying to deliver power-saving system reset "
41410c21b5cSNicholas Piggin                           "exception %d with no HV support\n", excp);
41510c21b5cSNicholas Piggin             }
41610c21b5cSNicholas Piggin         }
4175c94b2a5SCédric Le Goater         ail = 0;
418bd6fefe7SBenjamin Herrenschmidt         break;
419c79c73f6SBlue Swirl     case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
420c79c73f6SBlue Swirl     case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
421c79c73f6SBlue Swirl     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
422bd6fefe7SBenjamin Herrenschmidt         break;
423bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
424c79c73f6SBlue Swirl     case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
425c79c73f6SBlue Swirl     case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
426c79c73f6SBlue Swirl     case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
427c79c73f6SBlue Swirl     case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
4287af1e7b0SCédric Le Goater     case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
429bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_HV_EMU:
430c79c73f6SBlue Swirl         srr0 = SPR_HSRR0;
431c79c73f6SBlue Swirl         srr1 = SPR_HSRR1;
432c79c73f6SBlue Swirl         new_msr |= (target_ulong)MSR_HVB;
433c79c73f6SBlue Swirl         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
434bd6fefe7SBenjamin Herrenschmidt         break;
435c79c73f6SBlue Swirl     case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
4361f29871cSTom Musta     case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
4377019cb3dSAlexey Kardashevskiy     case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
4385310799aSBalbir Singh #ifdef TARGET_PPC64
4395310799aSBalbir Singh         env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
4405310799aSBalbir Singh #endif
441bd6fefe7SBenjamin Herrenschmidt         break;
442c79c73f6SBlue Swirl     case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
443c79c73f6SBlue Swirl         LOG_EXCP("PIT exception\n");
444bd6fefe7SBenjamin Herrenschmidt         break;
445c79c73f6SBlue Swirl     case POWERPC_EXCP_IO:        /* IO error exception                       */
446c79c73f6SBlue Swirl         /* XXX: TODO */
447a47dddd7SAndreas Färber         cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
448bd6fefe7SBenjamin Herrenschmidt         break;
449c79c73f6SBlue Swirl     case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
450c79c73f6SBlue Swirl         /* XXX: TODO */
451a47dddd7SAndreas Färber         cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
452bd6fefe7SBenjamin Herrenschmidt         break;
453c79c73f6SBlue Swirl     case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
454c79c73f6SBlue Swirl         /* XXX: TODO */
455a47dddd7SAndreas Färber         cpu_abort(cs, "602 emulation trap exception "
456c79c73f6SBlue Swirl                   "is not implemented yet !\n");
457bd6fefe7SBenjamin Herrenschmidt         break;
458c79c73f6SBlue Swirl     case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
459c79c73f6SBlue Swirl         switch (excp_model) {
460c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
461c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
462c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
463c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
464c79c73f6SBlue Swirl             goto tlb_miss_tgpr;
465c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
466c79c73f6SBlue Swirl             goto tlb_miss;
467c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
468c79c73f6SBlue Swirl             goto tlb_miss_74xx;
469c79c73f6SBlue Swirl         default:
470a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid instruction TLB miss exception\n");
471c79c73f6SBlue Swirl             break;
472c79c73f6SBlue Swirl         }
473c79c73f6SBlue Swirl         break;
474c79c73f6SBlue Swirl     case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
475c79c73f6SBlue Swirl         switch (excp_model) {
476c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
477c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
478c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
479c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
480c79c73f6SBlue Swirl             goto tlb_miss_tgpr;
481c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
482c79c73f6SBlue Swirl             goto tlb_miss;
483c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
484c79c73f6SBlue Swirl             goto tlb_miss_74xx;
485c79c73f6SBlue Swirl         default:
486a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid data load TLB miss exception\n");
487c79c73f6SBlue Swirl             break;
488c79c73f6SBlue Swirl         }
489c79c73f6SBlue Swirl         break;
490c79c73f6SBlue Swirl     case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
491c79c73f6SBlue Swirl         switch (excp_model) {
492c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
493c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
494c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
495c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
496c79c73f6SBlue Swirl         tlb_miss_tgpr:
497c79c73f6SBlue Swirl             /* Swap temporary saved registers with GPRs */
498c79c73f6SBlue Swirl             if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
499c79c73f6SBlue Swirl                 new_msr |= (target_ulong)1 << MSR_TGPR;
500c79c73f6SBlue Swirl                 hreg_swap_gpr_tgpr(env);
501c79c73f6SBlue Swirl             }
502c79c73f6SBlue Swirl             goto tlb_miss;
503c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
504c79c73f6SBlue Swirl         tlb_miss:
505c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB)
506c79c73f6SBlue Swirl             if (qemu_log_enabled()) {
507c79c73f6SBlue Swirl                 const char *es;
508c79c73f6SBlue Swirl                 target_ulong *miss, *cmp;
509c79c73f6SBlue Swirl                 int en;
510c79c73f6SBlue Swirl 
511c79c73f6SBlue Swirl                 if (excp == POWERPC_EXCP_IFTLB) {
512c79c73f6SBlue Swirl                     es = "I";
513c79c73f6SBlue Swirl                     en = 'I';
514c79c73f6SBlue Swirl                     miss = &env->spr[SPR_IMISS];
515c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_ICMP];
516c79c73f6SBlue Swirl                 } else {
517c79c73f6SBlue Swirl                     if (excp == POWERPC_EXCP_DLTLB) {
518c79c73f6SBlue Swirl                         es = "DL";
519c79c73f6SBlue Swirl                     } else {
520c79c73f6SBlue Swirl                         es = "DS";
521c79c73f6SBlue Swirl                     }
522c79c73f6SBlue Swirl                     en = 'D';
523c79c73f6SBlue Swirl                     miss = &env->spr[SPR_DMISS];
524c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_DCMP];
525c79c73f6SBlue Swirl                 }
526c79c73f6SBlue Swirl                 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
527c79c73f6SBlue Swirl                          TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
528c79c73f6SBlue Swirl                          TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
529c79c73f6SBlue Swirl                          env->spr[SPR_HASH1], env->spr[SPR_HASH2],
530c79c73f6SBlue Swirl                          env->error_code);
531c79c73f6SBlue Swirl             }
532c79c73f6SBlue Swirl #endif
533c79c73f6SBlue Swirl             msr |= env->crf[0] << 28;
534c79c73f6SBlue Swirl             msr |= env->error_code; /* key, D/I, S/L bits */
535c79c73f6SBlue Swirl             /* Set way using a LRU mechanism */
536c79c73f6SBlue Swirl             msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
537c79c73f6SBlue Swirl             break;
538c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
539c79c73f6SBlue Swirl         tlb_miss_74xx:
540c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB)
541c79c73f6SBlue Swirl             if (qemu_log_enabled()) {
542c79c73f6SBlue Swirl                 const char *es;
543c79c73f6SBlue Swirl                 target_ulong *miss, *cmp;
544c79c73f6SBlue Swirl                 int en;
545c79c73f6SBlue Swirl 
546c79c73f6SBlue Swirl                 if (excp == POWERPC_EXCP_IFTLB) {
547c79c73f6SBlue Swirl                     es = "I";
548c79c73f6SBlue Swirl                     en = 'I';
549c79c73f6SBlue Swirl                     miss = &env->spr[SPR_TLBMISS];
550c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_PTEHI];
551c79c73f6SBlue Swirl                 } else {
552c79c73f6SBlue Swirl                     if (excp == POWERPC_EXCP_DLTLB) {
553c79c73f6SBlue Swirl                         es = "DL";
554c79c73f6SBlue Swirl                     } else {
555c79c73f6SBlue Swirl                         es = "DS";
556c79c73f6SBlue Swirl                     }
557c79c73f6SBlue Swirl                     en = 'D';
558c79c73f6SBlue Swirl                     miss = &env->spr[SPR_TLBMISS];
559c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_PTEHI];
560c79c73f6SBlue Swirl                 }
561c79c73f6SBlue Swirl                 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
562c79c73f6SBlue Swirl                          TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
563c79c73f6SBlue Swirl                          env->error_code);
564c79c73f6SBlue Swirl             }
565c79c73f6SBlue Swirl #endif
566c79c73f6SBlue Swirl             msr |= env->error_code; /* key bit */
567c79c73f6SBlue Swirl             break;
568c79c73f6SBlue Swirl         default:
569a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid data store TLB miss exception\n");
570c79c73f6SBlue Swirl             break;
571c79c73f6SBlue Swirl         }
572bd6fefe7SBenjamin Herrenschmidt         break;
573c79c73f6SBlue Swirl     case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
574c79c73f6SBlue Swirl         /* XXX: TODO */
575a47dddd7SAndreas Färber         cpu_abort(cs, "Floating point assist exception "
576c79c73f6SBlue Swirl                   "is not implemented yet !\n");
577bd6fefe7SBenjamin Herrenschmidt         break;
578c79c73f6SBlue Swirl     case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
579c79c73f6SBlue Swirl         /* XXX: TODO */
580a47dddd7SAndreas Färber         cpu_abort(cs, "DABR exception is not implemented yet !\n");
581bd6fefe7SBenjamin Herrenschmidt         break;
582c79c73f6SBlue Swirl     case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
583c79c73f6SBlue Swirl         /* XXX: TODO */
584a47dddd7SAndreas Färber         cpu_abort(cs, "IABR exception is not implemented yet !\n");
585bd6fefe7SBenjamin Herrenschmidt         break;
586c79c73f6SBlue Swirl     case POWERPC_EXCP_SMI:       /* System management interrupt              */
587c79c73f6SBlue Swirl         /* XXX: TODO */
588a47dddd7SAndreas Färber         cpu_abort(cs, "SMI exception is not implemented yet !\n");
589bd6fefe7SBenjamin Herrenschmidt         break;
590c79c73f6SBlue Swirl     case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
591c79c73f6SBlue Swirl         /* XXX: TODO */
592a47dddd7SAndreas Färber         cpu_abort(cs, "Thermal management exception "
593c79c73f6SBlue Swirl                   "is not implemented yet !\n");
594bd6fefe7SBenjamin Herrenschmidt         break;
595c79c73f6SBlue Swirl     case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
596c79c73f6SBlue Swirl         /* XXX: TODO */
597a47dddd7SAndreas Färber         cpu_abort(cs,
598c79c73f6SBlue Swirl                   "Performance counter exception is not implemented yet !\n");
599bd6fefe7SBenjamin Herrenschmidt         break;
600c79c73f6SBlue Swirl     case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
601c79c73f6SBlue Swirl         /* XXX: TODO */
602a47dddd7SAndreas Färber         cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
603bd6fefe7SBenjamin Herrenschmidt         break;
604c79c73f6SBlue Swirl     case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
605c79c73f6SBlue Swirl         /* XXX: TODO */
606a47dddd7SAndreas Färber         cpu_abort(cs,
607c79c73f6SBlue Swirl                   "970 soft-patch exception is not implemented yet !\n");
608bd6fefe7SBenjamin Herrenschmidt         break;
609c79c73f6SBlue Swirl     case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
610c79c73f6SBlue Swirl         /* XXX: TODO */
611a47dddd7SAndreas Färber         cpu_abort(cs,
612c79c73f6SBlue Swirl                   "970 maintenance exception is not implemented yet !\n");
613bd6fefe7SBenjamin Herrenschmidt         break;
614c79c73f6SBlue Swirl     case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
615c79c73f6SBlue Swirl         /* XXX: TODO */
616a47dddd7SAndreas Färber         cpu_abort(cs, "Maskable external exception "
617c79c73f6SBlue Swirl                   "is not implemented yet !\n");
618bd6fefe7SBenjamin Herrenschmidt         break;
619c79c73f6SBlue Swirl     case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
620c79c73f6SBlue Swirl         /* XXX: TODO */
621a47dddd7SAndreas Färber         cpu_abort(cs, "Non maskable external exception "
622c79c73f6SBlue Swirl                   "is not implemented yet !\n");
623bd6fefe7SBenjamin Herrenschmidt         break;
624c79c73f6SBlue Swirl     default:
625c79c73f6SBlue Swirl     excp_invalid:
626a47dddd7SAndreas Färber         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
627c79c73f6SBlue Swirl         break;
628c79c73f6SBlue Swirl     }
629bd6fefe7SBenjamin Herrenschmidt 
630bd6fefe7SBenjamin Herrenschmidt     /* Save PC */
631bd6fefe7SBenjamin Herrenschmidt     env->spr[srr0] = env->nip;
632bd6fefe7SBenjamin Herrenschmidt 
633c79c73f6SBlue Swirl     /* Save MSR */
634c79c73f6SBlue Swirl     env->spr[srr1] = msr;
6356d49d6d4SBenjamin Herrenschmidt 
6366d49d6d4SBenjamin Herrenschmidt     /* Sanity check */
63710c21b5cSNicholas Piggin     if (!(env->msr_mask & MSR_HVB)) {
63810c21b5cSNicholas Piggin         if (new_msr & MSR_HVB) {
63910c21b5cSNicholas Piggin             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
6406d49d6d4SBenjamin Herrenschmidt                       "no HV support\n", excp);
6416d49d6d4SBenjamin Herrenschmidt         }
64210c21b5cSNicholas Piggin         if (srr0 == SPR_HSRR0) {
64310c21b5cSNicholas Piggin             cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
64410c21b5cSNicholas Piggin                       "no HV support\n", excp);
64510c21b5cSNicholas Piggin         }
64610c21b5cSNicholas Piggin     }
6476d49d6d4SBenjamin Herrenschmidt 
648c79c73f6SBlue Swirl     /* If any alternate SRR register are defined, duplicate saved values */
649c79c73f6SBlue Swirl     if (asrr0 != -1) {
650c79c73f6SBlue Swirl         env->spr[asrr0] = env->spr[srr0];
651c79c73f6SBlue Swirl     }
652c79c73f6SBlue Swirl     if (asrr1 != -1) {
653c79c73f6SBlue Swirl         env->spr[asrr1] = env->spr[srr1];
654c79c73f6SBlue Swirl     }
655d5ac4f54SAlexey Kardashevskiy 
6566d49d6d4SBenjamin Herrenschmidt     /* Sort out endianness of interrupt, this differs depending on the
6576d49d6d4SBenjamin Herrenschmidt      * CPU, the HV mode, etc...
6586d49d6d4SBenjamin Herrenschmidt      */
6591e0c7e55SAnton Blanchard #ifdef TARGET_PPC64
6606d49d6d4SBenjamin Herrenschmidt     if (excp_model == POWERPC_EXCP_POWER7) {
6616d49d6d4SBenjamin Herrenschmidt         if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) {
6626d49d6d4SBenjamin Herrenschmidt             new_msr |= (target_ulong)1 << MSR_LE;
6636d49d6d4SBenjamin Herrenschmidt         }
6646d49d6d4SBenjamin Herrenschmidt     } else if (excp_model == POWERPC_EXCP_POWER8) {
6656d49d6d4SBenjamin Herrenschmidt         if (new_msr & MSR_HVB) {
666a790e82bSBenjamin Herrenschmidt             if (env->spr[SPR_HID0] & HID0_HILE) {
667a790e82bSBenjamin Herrenschmidt                 new_msr |= (target_ulong)1 << MSR_LE;
668a790e82bSBenjamin Herrenschmidt             }
669a790e82bSBenjamin Herrenschmidt         } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
670a790e82bSBenjamin Herrenschmidt             new_msr |= (target_ulong)1 << MSR_LE;
671a790e82bSBenjamin Herrenschmidt         }
672a790e82bSBenjamin Herrenschmidt     } else if (excp_model == POWERPC_EXCP_POWER9) {
673a790e82bSBenjamin Herrenschmidt         if (new_msr & MSR_HVB) {
674a790e82bSBenjamin Herrenschmidt             if (env->spr[SPR_HID0] & HID0_POWER9_HILE) {
6756d49d6d4SBenjamin Herrenschmidt                 new_msr |= (target_ulong)1 << MSR_LE;
6766d49d6d4SBenjamin Herrenschmidt             }
6776d49d6d4SBenjamin Herrenschmidt         } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
6781e0c7e55SAnton Blanchard             new_msr |= (target_ulong)1 << MSR_LE;
6791e0c7e55SAnton Blanchard         }
6801e0c7e55SAnton Blanchard     } else if (msr_ile) {
6811e0c7e55SAnton Blanchard         new_msr |= (target_ulong)1 << MSR_LE;
6821e0c7e55SAnton Blanchard     }
6831e0c7e55SAnton Blanchard #else
684c79c73f6SBlue Swirl     if (msr_ile) {
685c79c73f6SBlue Swirl         new_msr |= (target_ulong)1 << MSR_LE;
686c79c73f6SBlue Swirl     }
6871e0c7e55SAnton Blanchard #endif
688c79c73f6SBlue Swirl 
689c79c73f6SBlue Swirl     /* Jump to handler */
690c79c73f6SBlue Swirl     vector = env->excp_vectors[excp];
691c79c73f6SBlue Swirl     if (vector == (target_ulong)-1ULL) {
692a47dddd7SAndreas Färber         cpu_abort(cs, "Raised an exception without defined vector %d\n",
693c79c73f6SBlue Swirl                   excp);
694c79c73f6SBlue Swirl     }
695c79c73f6SBlue Swirl     vector |= env->excp_prefix;
6965c94b2a5SCédric Le Goater 
6975c94b2a5SCédric Le Goater     /* AIL only works if there is no HV transition and we are running with
6985c94b2a5SCédric Le Goater      * translations enabled
6995c94b2a5SCédric Le Goater      */
7006d49d6d4SBenjamin Herrenschmidt     if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) ||
7016d49d6d4SBenjamin Herrenschmidt         ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) {
7025c94b2a5SCédric Le Goater         ail = 0;
7035c94b2a5SCédric Le Goater     }
7045c94b2a5SCédric Le Goater     /* Handle AIL */
7055c94b2a5SCédric Le Goater     if (ail) {
7065c94b2a5SCédric Le Goater         new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
7075c94b2a5SCédric Le Goater         switch(ail) {
7085c94b2a5SCédric Le Goater         case AIL_0001_8000:
7095c94b2a5SCédric Le Goater             vector |= 0x18000;
7105c94b2a5SCédric Le Goater             break;
7115c94b2a5SCédric Le Goater         case AIL_C000_0000_0000_4000:
7125c94b2a5SCédric Le Goater             vector |= 0xc000000000004000ull;
7135c94b2a5SCédric Le Goater             break;
7145c94b2a5SCédric Le Goater         default:
7155c94b2a5SCédric Le Goater             cpu_abort(cs, "Invalid AIL combination %d\n", ail);
7165c94b2a5SCédric Le Goater             break;
7175c94b2a5SCédric Le Goater         }
7185c94b2a5SCédric Le Goater     }
7195c94b2a5SCédric Le Goater 
720c79c73f6SBlue Swirl #if defined(TARGET_PPC64)
721c79c73f6SBlue Swirl     if (excp_model == POWERPC_EXCP_BOOKE) {
722e42a61f1SAlexander Graf         if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
723e42a61f1SAlexander Graf             /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
724c79c73f6SBlue Swirl             new_msr |= (target_ulong)1 << MSR_CM;
725e42a61f1SAlexander Graf         } else {
726e42a61f1SAlexander Graf             vector = (uint32_t)vector;
727c79c73f6SBlue Swirl         }
728c79c73f6SBlue Swirl     } else {
729c79c73f6SBlue Swirl         if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
730c79c73f6SBlue Swirl             vector = (uint32_t)vector;
731c79c73f6SBlue Swirl         } else {
732c79c73f6SBlue Swirl             new_msr |= (target_ulong)1 << MSR_SF;
733c79c73f6SBlue Swirl         }
734c79c73f6SBlue Swirl     }
735c79c73f6SBlue Swirl #endif
7361c953ba5SBenjamin Herrenschmidt     /* We don't use hreg_store_msr here as already have treated
737c79c73f6SBlue Swirl      * any special case that could occur. Just store MSR and update hflags
7381c953ba5SBenjamin Herrenschmidt      *
7391c953ba5SBenjamin Herrenschmidt      * Note: We *MUST* not use hreg_store_msr() as-is anyway because it
7401c953ba5SBenjamin Herrenschmidt      * will prevent setting of the HV bit which some exceptions might need
7411c953ba5SBenjamin Herrenschmidt      * to do.
742c79c73f6SBlue Swirl      */
743c79c73f6SBlue Swirl     env->msr = new_msr & env->msr_mask;
744c79c73f6SBlue Swirl     hreg_compute_hflags(env);
745c79c73f6SBlue Swirl     env->nip = vector;
746c79c73f6SBlue Swirl     /* Reset exception state */
74727103424SAndreas Färber     cs->exception_index = POWERPC_EXCP_NONE;
748c79c73f6SBlue Swirl     env->error_code = 0;
749cd0c6f47SBenjamin Herrenschmidt 
750139d9023SNikunj A Dadhania     /* Reset the reservation */
751139d9023SNikunj A Dadhania     env->reserve_addr = -1;
752139d9023SNikunj A Dadhania 
753cd0c6f47SBenjamin Herrenschmidt     /* Any interrupt is context synchronizing, check if TCG TLB
754cd0c6f47SBenjamin Herrenschmidt      * needs a delayed flush on ppc64
755cd0c6f47SBenjamin Herrenschmidt      */
756e3cffe6fSNikunj A Dadhania     check_tlb_flush(env, false);
757c79c73f6SBlue Swirl }
758c79c73f6SBlue Swirl 
75997a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs)
760c79c73f6SBlue Swirl {
76197a8ea5aSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(cs);
76297a8ea5aSAndreas Färber     CPUPPCState *env = &cpu->env;
7635c26a5b3SAndreas Färber 
76427103424SAndreas Färber     powerpc_excp(cpu, env->excp_model, cs->exception_index);
765c79c73f6SBlue Swirl }
766c79c73f6SBlue Swirl 
767458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env)
768c79c73f6SBlue Swirl {
7695c26a5b3SAndreas Färber     PowerPCCPU *cpu = ppc_env_get_cpu(env);
7703621e2c9SBenjamin Herrenschmidt     bool async_deliver;
771259186a7SAndreas Färber 
772c79c73f6SBlue Swirl     /* External reset */
773c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
774c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
7755c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
776c79c73f6SBlue Swirl         return;
777c79c73f6SBlue Swirl     }
778c79c73f6SBlue Swirl     /* Machine check exception */
779c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
780c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
7815c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
782c79c73f6SBlue Swirl         return;
783c79c73f6SBlue Swirl     }
784c79c73f6SBlue Swirl #if 0 /* TODO */
785c79c73f6SBlue Swirl     /* External debug exception */
786c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
787c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
7885c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
789c79c73f6SBlue Swirl         return;
790c79c73f6SBlue Swirl     }
791c79c73f6SBlue Swirl #endif
7923621e2c9SBenjamin Herrenschmidt 
7933621e2c9SBenjamin Herrenschmidt     /*
7943621e2c9SBenjamin Herrenschmidt      * For interrupts that gate on MSR:EE, we need to do something a
7953621e2c9SBenjamin Herrenschmidt      * bit more subtle, as we need to let them through even when EE is
7963621e2c9SBenjamin Herrenschmidt      * clear when coming out of some power management states (in order
7973621e2c9SBenjamin Herrenschmidt      * for them to become a 0x100).
7983621e2c9SBenjamin Herrenschmidt      */
7991e7fd61dSBenjamin Herrenschmidt     async_deliver = (msr_ee != 0) || env->resume_as_sreset;
8003621e2c9SBenjamin Herrenschmidt 
801c79c73f6SBlue Swirl     /* Hypervisor decrementer exception */
802c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
8034b236b62SBenjamin Herrenschmidt         /* LPCR will be clear when not supported so this will work */
8044b236b62SBenjamin Herrenschmidt         bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
8053621e2c9SBenjamin Herrenschmidt         if ((async_deliver || msr_hv == 0) && hdice) {
8064b236b62SBenjamin Herrenschmidt             /* HDEC clears on delivery */
8074b236b62SBenjamin Herrenschmidt             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
8085c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
809c79c73f6SBlue Swirl             return;
810c79c73f6SBlue Swirl         }
811c79c73f6SBlue Swirl     }
812d1dbe37cSBenjamin Herrenschmidt     /* Extermal interrupt can ignore MSR:EE under some circumstances */
813d1dbe37cSBenjamin Herrenschmidt     if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
814d1dbe37cSBenjamin Herrenschmidt         bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
8153621e2c9SBenjamin Herrenschmidt         if (async_deliver || (env->has_hv_mode && msr_hv == 0 && !lpes0)) {
816d1dbe37cSBenjamin Herrenschmidt             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
817d1dbe37cSBenjamin Herrenschmidt             return;
818d1dbe37cSBenjamin Herrenschmidt         }
819d1dbe37cSBenjamin Herrenschmidt     }
820c79c73f6SBlue Swirl     if (msr_ce != 0) {
821c79c73f6SBlue Swirl         /* External critical interrupt */
822c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
8235c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
824c79c73f6SBlue Swirl             return;
825c79c73f6SBlue Swirl         }
826c79c73f6SBlue Swirl     }
8273621e2c9SBenjamin Herrenschmidt     if (async_deliver != 0) {
828c79c73f6SBlue Swirl         /* Watchdog timer on embedded PowerPC */
829c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
830c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
8315c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
832c79c73f6SBlue Swirl             return;
833c79c73f6SBlue Swirl         }
834c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
835c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
8365c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
837c79c73f6SBlue Swirl             return;
838c79c73f6SBlue Swirl         }
839c79c73f6SBlue Swirl         /* Fixed interval timer on embedded PowerPC */
840c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
841c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
8425c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
843c79c73f6SBlue Swirl             return;
844c79c73f6SBlue Swirl         }
845c79c73f6SBlue Swirl         /* Programmable interval timer on embedded PowerPC */
846c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
847c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
8485c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
849c79c73f6SBlue Swirl             return;
850c79c73f6SBlue Swirl         }
851c79c73f6SBlue Swirl         /* Decrementer exception */
852c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
853e81a982aSAlexander Graf             if (ppc_decr_clear_on_delivery(env)) {
854c79c73f6SBlue Swirl                 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
855e81a982aSAlexander Graf             }
8565c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
857c79c73f6SBlue Swirl             return;
858c79c73f6SBlue Swirl         }
859c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
860c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
8615c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
862c79c73f6SBlue Swirl             return;
863c79c73f6SBlue Swirl         }
8647af1e7b0SCédric Le Goater         if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) {
8657af1e7b0SCédric Le Goater             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
8667af1e7b0SCédric Le Goater             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV);
8677af1e7b0SCédric Le Goater             return;
8687af1e7b0SCédric Le Goater         }
869c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
870c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
8715c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
872c79c73f6SBlue Swirl             return;
873c79c73f6SBlue Swirl         }
874c79c73f6SBlue Swirl         /* Thermal interrupt */
875c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
876c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
8775c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
878c79c73f6SBlue Swirl             return;
879c79c73f6SBlue Swirl         }
880c79c73f6SBlue Swirl     }
881*f8154fd2SBenjamin Herrenschmidt 
882*f8154fd2SBenjamin Herrenschmidt     if (env->resume_as_sreset) {
883*f8154fd2SBenjamin Herrenschmidt         /*
884*f8154fd2SBenjamin Herrenschmidt          * This is a bug ! It means that has_work took us out of halt without
885*f8154fd2SBenjamin Herrenschmidt          * anything to deliver while in a PM state that requires getting
886*f8154fd2SBenjamin Herrenschmidt          * out via a 0x100
887*f8154fd2SBenjamin Herrenschmidt          *
888*f8154fd2SBenjamin Herrenschmidt          * This means we will incorrectly execute past the power management
889*f8154fd2SBenjamin Herrenschmidt          * instruction instead of triggering a reset.
890*f8154fd2SBenjamin Herrenschmidt          *
891*f8154fd2SBenjamin Herrenschmidt          * It generally means a discrepancy between the wakup conditions in the
892*f8154fd2SBenjamin Herrenschmidt          * processor has_work implementation and the logic in this function.
893*f8154fd2SBenjamin Herrenschmidt          */
894*f8154fd2SBenjamin Herrenschmidt         cpu_abort(CPU(ppc_env_get_cpu(env)),
895*f8154fd2SBenjamin Herrenschmidt                   "Wakeup from PM state but interrupt Undelivered");
896*f8154fd2SBenjamin Herrenschmidt     }
897c79c73f6SBlue Swirl }
89834316482SAlexey Kardashevskiy 
89934316482SAlexey Kardashevskiy void ppc_cpu_do_system_reset(CPUState *cs)
90034316482SAlexey Kardashevskiy {
90134316482SAlexey Kardashevskiy     PowerPCCPU *cpu = POWERPC_CPU(cs);
90234316482SAlexey Kardashevskiy     CPUPPCState *env = &cpu->env;
90334316482SAlexey Kardashevskiy 
90434316482SAlexey Kardashevskiy     powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
90534316482SAlexey Kardashevskiy }
906c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */
907c79c73f6SBlue Swirl 
908458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
909458dd766SRichard Henderson {
910458dd766SRichard Henderson     PowerPCCPU *cpu = POWERPC_CPU(cs);
911458dd766SRichard Henderson     CPUPPCState *env = &cpu->env;
912458dd766SRichard Henderson 
913458dd766SRichard Henderson     if (interrupt_request & CPU_INTERRUPT_HARD) {
914458dd766SRichard Henderson         ppc_hw_interrupt(env);
915458dd766SRichard Henderson         if (env->pending_interrupts == 0) {
916458dd766SRichard Henderson             cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
917458dd766SRichard Henderson         }
918458dd766SRichard Henderson         return true;
919458dd766SRichard Henderson     }
920458dd766SRichard Henderson     return false;
921458dd766SRichard Henderson }
922458dd766SRichard Henderson 
923c79c73f6SBlue Swirl #if defined(DEBUG_OP)
924c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
925c79c73f6SBlue Swirl {
926c79c73f6SBlue Swirl     qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
927c79c73f6SBlue Swirl              TARGET_FMT_lx "\n", RA, msr);
928c79c73f6SBlue Swirl }
929c79c73f6SBlue Swirl #endif
930c79c73f6SBlue Swirl 
931ad71ed68SBlue Swirl /*****************************************************************************/
932ad71ed68SBlue Swirl /* Exceptions processing helpers */
933ad71ed68SBlue Swirl 
934db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
935db789c6cSBenjamin Herrenschmidt                             uint32_t error_code, uintptr_t raddr)
936ad71ed68SBlue Swirl {
93727103424SAndreas Färber     CPUState *cs = CPU(ppc_env_get_cpu(env));
93827103424SAndreas Färber 
93927103424SAndreas Färber     cs->exception_index = exception;
940ad71ed68SBlue Swirl     env->error_code = error_code;
941db789c6cSBenjamin Herrenschmidt     cpu_loop_exit_restore(cs, raddr);
942db789c6cSBenjamin Herrenschmidt }
943db789c6cSBenjamin Herrenschmidt 
944db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception,
945db789c6cSBenjamin Herrenschmidt                          uint32_t error_code)
946db789c6cSBenjamin Herrenschmidt {
947db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, error_code, 0);
948db789c6cSBenjamin Herrenschmidt }
949db789c6cSBenjamin Herrenschmidt 
950db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception)
951db789c6cSBenjamin Herrenschmidt {
952db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, 0);
953db789c6cSBenjamin Herrenschmidt }
954db789c6cSBenjamin Herrenschmidt 
955db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception,
956db789c6cSBenjamin Herrenschmidt                         uintptr_t raddr)
957db789c6cSBenjamin Herrenschmidt {
958db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, raddr);
959db789c6cSBenjamin Herrenschmidt }
960db789c6cSBenjamin Herrenschmidt 
961db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
962db789c6cSBenjamin Herrenschmidt                                 uint32_t error_code)
963db789c6cSBenjamin Herrenschmidt {
964db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, error_code, 0);
965ad71ed68SBlue Swirl }
966ad71ed68SBlue Swirl 
967e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception)
968ad71ed68SBlue Swirl {
969db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, 0);
970ad71ed68SBlue Swirl }
971ad71ed68SBlue Swirl 
972ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY)
973e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val)
974ad71ed68SBlue Swirl {
975db789c6cSBenjamin Herrenschmidt     uint32_t excp = hreg_store_msr(env, val, 0);
976259186a7SAndreas Färber 
977db789c6cSBenjamin Herrenschmidt     if (excp != 0) {
978db789c6cSBenjamin Herrenschmidt         CPUState *cs = CPU(ppc_env_get_cpu(env));
979044897efSRichard Purdie         cpu_interrupt_exittb(cs);
980db789c6cSBenjamin Herrenschmidt         raise_exception(env, excp);
981ad71ed68SBlue Swirl     }
982ad71ed68SBlue Swirl }
983ad71ed68SBlue Swirl 
9847778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64)
9857778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
9867778a575SBenjamin Herrenschmidt {
9877778a575SBenjamin Herrenschmidt     CPUState *cs;
9887778a575SBenjamin Herrenschmidt 
9897778a575SBenjamin Herrenschmidt     cs = CPU(ppc_env_get_cpu(env));
9907778a575SBenjamin Herrenschmidt     cs->halted = 1;
9917778a575SBenjamin Herrenschmidt 
9924b236b62SBenjamin Herrenschmidt     /* The architecture specifies that HDEC interrupts are
9934b236b62SBenjamin Herrenschmidt      * discarded in PM states
9944b236b62SBenjamin Herrenschmidt      */
9954b236b62SBenjamin Herrenschmidt     env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
9964b236b62SBenjamin Herrenschmidt 
9973621e2c9SBenjamin Herrenschmidt     /* Condition for waking up at 0x100 */
9981e7fd61dSBenjamin Herrenschmidt     env->resume_as_sreset = (insn != PPC_PM_STOP) ||
99921c0d66aSBenjamin Herrenschmidt         (env->spr[SPR_PSSCR] & PSSCR_EC);
10007778a575SBenjamin Herrenschmidt }
10017778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */
10027778a575SBenjamin Herrenschmidt 
1003a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
1004ad71ed68SBlue Swirl {
1005259186a7SAndreas Färber     CPUState *cs = CPU(ppc_env_get_cpu(env));
1006259186a7SAndreas Färber 
1007a2e71b28SBenjamin Herrenschmidt     /* MSR:POW cannot be set by any form of rfi */
1008a2e71b28SBenjamin Herrenschmidt     msr &= ~(1ULL << MSR_POW);
1009a2e71b28SBenjamin Herrenschmidt 
1010ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1011a2e71b28SBenjamin Herrenschmidt     /* Switching to 32-bit ? Crop the nip */
1012a2e71b28SBenjamin Herrenschmidt     if (!msr_is_64bit(env, msr)) {
1013ad71ed68SBlue Swirl         nip = (uint32_t)nip;
1014ad71ed68SBlue Swirl     }
1015ad71ed68SBlue Swirl #else
1016ad71ed68SBlue Swirl     nip = (uint32_t)nip;
1017ad71ed68SBlue Swirl #endif
1018ad71ed68SBlue Swirl     /* XXX: beware: this is false if VLE is supported */
1019ad71ed68SBlue Swirl     env->nip = nip & ~((target_ulong)0x00000003);
1020ad71ed68SBlue Swirl     hreg_store_msr(env, msr, 1);
1021ad71ed68SBlue Swirl #if defined(DEBUG_OP)
1022ad71ed68SBlue Swirl     cpu_dump_rfi(env->nip, env->msr);
1023ad71ed68SBlue Swirl #endif
1024ad71ed68SBlue Swirl     /* No need to raise an exception here,
1025ad71ed68SBlue Swirl      * as rfi is always the last insn of a TB
1026ad71ed68SBlue Swirl      */
1027044897efSRichard Purdie     cpu_interrupt_exittb(cs);
1028a8b73734SNikunj A Dadhania     /* Reset the reservation */
1029a8b73734SNikunj A Dadhania     env->reserve_addr = -1;
1030a8b73734SNikunj A Dadhania 
1031cd0c6f47SBenjamin Herrenschmidt     /* Context synchronizing: check if TCG TLB needs flush */
1032e3cffe6fSNikunj A Dadhania     check_tlb_flush(env, false);
1033ad71ed68SBlue Swirl }
1034ad71ed68SBlue Swirl 
1035e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env)
1036ad71ed68SBlue Swirl {
1037a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful);
1038a1bb7384SScott Wood }
1039ad71ed68SBlue Swirl 
1040a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK
1041ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1042e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env)
1043ad71ed68SBlue Swirl {
1044a2e71b28SBenjamin Herrenschmidt     /* The architeture defines a number of rules for which bits
1045a2e71b28SBenjamin Herrenschmidt      * can change but in practice, we handle this in hreg_store_msr()
1046a2e71b28SBenjamin Herrenschmidt      * which will be called by do_rfi(), so there is no need to filter
1047a2e71b28SBenjamin Herrenschmidt      * here
1048a2e71b28SBenjamin Herrenschmidt      */
1049a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
1050ad71ed68SBlue Swirl }
1051ad71ed68SBlue Swirl 
1052e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env)
1053ad71ed68SBlue Swirl {
1054a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
1055ad71ed68SBlue Swirl }
1056ad71ed68SBlue Swirl #endif
1057ad71ed68SBlue Swirl 
1058ad71ed68SBlue Swirl /*****************************************************************************/
1059ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */
1060e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env)
1061ad71ed68SBlue Swirl {
1062a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]);
1063ad71ed68SBlue Swirl }
1064ad71ed68SBlue Swirl 
1065e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env)
1066ad71ed68SBlue Swirl {
1067a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]);
1068ad71ed68SBlue Swirl }
1069ad71ed68SBlue Swirl 
1070e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env)
1071ad71ed68SBlue Swirl {
1072a1bb7384SScott Wood     /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
1073a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]);
1074ad71ed68SBlue Swirl }
1075ad71ed68SBlue Swirl 
1076e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env)
1077ad71ed68SBlue Swirl {
1078a1bb7384SScott Wood     /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
1079a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]);
1080ad71ed68SBlue Swirl }
1081ad71ed68SBlue Swirl #endif
1082ad71ed68SBlue Swirl 
1083e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1084e5f17ac6SBlue Swirl                uint32_t flags)
1085ad71ed68SBlue Swirl {
1086ad71ed68SBlue Swirl     if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1087ad71ed68SBlue Swirl                   ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1088ad71ed68SBlue Swirl                   ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1089ad71ed68SBlue Swirl                   ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1090ad71ed68SBlue Swirl                   ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
109172073dccSBenjamin Herrenschmidt         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
109272073dccSBenjamin Herrenschmidt                                POWERPC_EXCP_TRAP, GETPC());
1093ad71ed68SBlue Swirl     }
1094ad71ed68SBlue Swirl }
1095ad71ed68SBlue Swirl 
1096ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1097e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1098e5f17ac6SBlue Swirl                uint32_t flags)
1099ad71ed68SBlue Swirl {
1100ad71ed68SBlue Swirl     if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1101ad71ed68SBlue Swirl                   ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1102ad71ed68SBlue Swirl                   ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1103ad71ed68SBlue Swirl                   ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1104ad71ed68SBlue Swirl                   ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
110572073dccSBenjamin Herrenschmidt         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
110672073dccSBenjamin Herrenschmidt                                POWERPC_EXCP_TRAP, GETPC());
1107ad71ed68SBlue Swirl     }
1108ad71ed68SBlue Swirl }
1109ad71ed68SBlue Swirl #endif
1110ad71ed68SBlue Swirl 
1111ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1112ad71ed68SBlue Swirl /*****************************************************************************/
1113ad71ed68SBlue Swirl /* PowerPC 601 specific instructions (POWER bridge) */
1114ad71ed68SBlue Swirl 
1115e5f17ac6SBlue Swirl void helper_rfsvc(CPUPPCState *env)
1116ad71ed68SBlue Swirl {
1117a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->lr, env->ctr & 0x0000FFFF);
1118ad71ed68SBlue Swirl }
1119ad71ed68SBlue Swirl 
1120ad71ed68SBlue Swirl /* Embedded.Processor Control */
1121ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb)
1122ad71ed68SBlue Swirl {
1123ad71ed68SBlue Swirl     int msg = rb & DBELL_TYPE_MASK;
1124ad71ed68SBlue Swirl     int irq = -1;
1125ad71ed68SBlue Swirl 
1126ad71ed68SBlue Swirl     switch (msg) {
1127ad71ed68SBlue Swirl     case DBELL_TYPE_DBELL:
1128ad71ed68SBlue Swirl         irq = PPC_INTERRUPT_DOORBELL;
1129ad71ed68SBlue Swirl         break;
1130ad71ed68SBlue Swirl     case DBELL_TYPE_DBELL_CRIT:
1131ad71ed68SBlue Swirl         irq = PPC_INTERRUPT_CDOORBELL;
1132ad71ed68SBlue Swirl         break;
1133ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL:
1134ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL_CRIT:
1135ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL_MC:
1136ad71ed68SBlue Swirl         /* XXX implement */
1137ad71ed68SBlue Swirl     default:
1138ad71ed68SBlue Swirl         break;
1139ad71ed68SBlue Swirl     }
1140ad71ed68SBlue Swirl 
1141ad71ed68SBlue Swirl     return irq;
1142ad71ed68SBlue Swirl }
1143ad71ed68SBlue Swirl 
1144e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb)
1145ad71ed68SBlue Swirl {
1146ad71ed68SBlue Swirl     int irq = dbell2irq(rb);
1147ad71ed68SBlue Swirl 
1148ad71ed68SBlue Swirl     if (irq < 0) {
1149ad71ed68SBlue Swirl         return;
1150ad71ed68SBlue Swirl     }
1151ad71ed68SBlue Swirl 
1152ad71ed68SBlue Swirl     env->pending_interrupts &= ~(1 << irq);
1153ad71ed68SBlue Swirl }
1154ad71ed68SBlue Swirl 
1155ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb)
1156ad71ed68SBlue Swirl {
1157ad71ed68SBlue Swirl     int irq = dbell2irq(rb);
1158ad71ed68SBlue Swirl     int pir = rb & DBELL_PIRTAG_MASK;
1159182735efSAndreas Färber     CPUState *cs;
1160ad71ed68SBlue Swirl 
1161ad71ed68SBlue Swirl     if (irq < 0) {
1162ad71ed68SBlue Swirl         return;
1163ad71ed68SBlue Swirl     }
1164ad71ed68SBlue Swirl 
1165f1c29ebcSThomas Huth     qemu_mutex_lock_iothread();
1166bdc44640SAndreas Färber     CPU_FOREACH(cs) {
1167182735efSAndreas Färber         PowerPCCPU *cpu = POWERPC_CPU(cs);
1168182735efSAndreas Färber         CPUPPCState *cenv = &cpu->env;
1169182735efSAndreas Färber 
1170ad71ed68SBlue Swirl         if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
1171ad71ed68SBlue Swirl             cenv->pending_interrupts |= 1 << irq;
1172182735efSAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
1173ad71ed68SBlue Swirl         }
1174ad71ed68SBlue Swirl     }
1175f1c29ebcSThomas Huth     qemu_mutex_unlock_iothread();
1176ad71ed68SBlue Swirl }
11777af1e7b0SCédric Le Goater 
11787af1e7b0SCédric Le Goater /* Server Processor Control */
11797af1e7b0SCédric Le Goater static int book3s_dbell2irq(target_ulong rb)
11807af1e7b0SCédric Le Goater {
11817af1e7b0SCédric Le Goater     int msg = rb & DBELL_TYPE_MASK;
11827af1e7b0SCédric Le Goater 
11837af1e7b0SCédric Le Goater     /* A Directed Hypervisor Doorbell message is sent only if the
11847af1e7b0SCédric Le Goater      * message type is 5. All other types are reserved and the
11857af1e7b0SCédric Le Goater      * instruction is a no-op */
11867af1e7b0SCédric Le Goater     return msg == DBELL_TYPE_DBELL_SERVER ? PPC_INTERRUPT_HDOORBELL : -1;
11877af1e7b0SCédric Le Goater }
11887af1e7b0SCédric Le Goater 
11897af1e7b0SCédric Le Goater void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
11907af1e7b0SCédric Le Goater {
11917af1e7b0SCédric Le Goater     int irq = book3s_dbell2irq(rb);
11927af1e7b0SCédric Le Goater 
11937af1e7b0SCédric Le Goater     if (irq < 0) {
11947af1e7b0SCédric Le Goater         return;
11957af1e7b0SCédric Le Goater     }
11967af1e7b0SCédric Le Goater 
11977af1e7b0SCédric Le Goater     env->pending_interrupts &= ~(1 << irq);
11987af1e7b0SCédric Le Goater }
11997af1e7b0SCédric Le Goater 
12007af1e7b0SCédric Le Goater void helper_book3s_msgsnd(target_ulong rb)
12017af1e7b0SCédric Le Goater {
12027af1e7b0SCédric Le Goater     int irq = book3s_dbell2irq(rb);
12037af1e7b0SCédric Le Goater     int pir = rb & DBELL_PROCIDTAG_MASK;
12047af1e7b0SCédric Le Goater     CPUState *cs;
12057af1e7b0SCédric Le Goater 
12067af1e7b0SCédric Le Goater     if (irq < 0) {
12077af1e7b0SCédric Le Goater         return;
12087af1e7b0SCédric Le Goater     }
12097af1e7b0SCédric Le Goater 
12107af1e7b0SCédric Le Goater     qemu_mutex_lock_iothread();
12117af1e7b0SCédric Le Goater     CPU_FOREACH(cs) {
12127af1e7b0SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
12137af1e7b0SCédric Le Goater         CPUPPCState *cenv = &cpu->env;
12147af1e7b0SCédric Le Goater 
12157af1e7b0SCédric Le Goater         /* TODO: broadcast message to all threads of the same  processor */
12167af1e7b0SCédric Le Goater         if (cenv->spr_cb[SPR_PIR].default_value == pir) {
12177af1e7b0SCédric Le Goater             cenv->pending_interrupts |= 1 << irq;
12187af1e7b0SCédric Le Goater             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
12197af1e7b0SCédric Le Goater         }
12207af1e7b0SCédric Le Goater     }
12217af1e7b0SCédric Le Goater     qemu_mutex_unlock_iothread();
12227af1e7b0SCédric Le Goater }
1223ad71ed68SBlue Swirl #endif
12240f3110faSRichard Henderson 
12250f3110faSRichard Henderson void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
12260f3110faSRichard Henderson                                  MMUAccessType access_type,
12270f3110faSRichard Henderson                                  int mmu_idx, uintptr_t retaddr)
12280f3110faSRichard Henderson {
12290f3110faSRichard Henderson     CPUPPCState *env = cs->env_ptr;
12300f3110faSRichard Henderson     uint32_t insn;
12310f3110faSRichard Henderson 
12320f3110faSRichard Henderson     /* Restore state and reload the insn we executed, for filling in DSISR.  */
12330f3110faSRichard Henderson     cpu_restore_state(cs, retaddr, true);
12340f3110faSRichard Henderson     insn = cpu_ldl_code(env, env->nip);
12350f3110faSRichard Henderson 
12360f3110faSRichard Henderson     cs->exception_index = POWERPC_EXCP_ALIGN;
12370f3110faSRichard Henderson     env->error_code = insn & 0x03FF0000;
12380f3110faSRichard Henderson     cpu_loop_exit(cs);
12390f3110faSRichard Henderson }
1240