xref: /qemu/target/ppc/excp_helper.c (revision ad77c6ca0c63e39eb6ded9c1a761eaa16b21b7f9)
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 
2847733729SDavid Gibson /* #define DEBUG_OP */
2947733729SDavid Gibson /* #define DEBUG_SOFTWARE_TLB */
3047733729SDavid Gibson /* #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 {
52db70b311SRichard Henderson     CPUState *cs = env_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;
100d8ce5fd6SBenjamin Herrenschmidt     case POWERPC_EXCP_HVIRT:
101d8ce5fd6SBenjamin Herrenschmidt         *msr |= 0x9ull << (63 - 45);
102d8ce5fd6SBenjamin Herrenschmidt         break;
103dead760bSBenjamin Herrenschmidt     default:
104dead760bSBenjamin Herrenschmidt         cpu_abort(cs, "Unsupported exception %d in Power Save mode\n",
105dead760bSBenjamin Herrenschmidt                   excp);
106dead760bSBenjamin Herrenschmidt     }
107dead760bSBenjamin Herrenschmidt     return POWERPC_EXCP_RESET;
108dead760bSBenjamin Herrenschmidt }
109dead760bSBenjamin Herrenschmidt 
1102586a4d7SFabiano Rosas static uint64_t ppc_excp_vector_offset(CPUState *cs, int ail)
1112586a4d7SFabiano Rosas {
1122586a4d7SFabiano Rosas     uint64_t offset = 0;
1132586a4d7SFabiano Rosas 
1142586a4d7SFabiano Rosas     switch (ail) {
115bc5fdfc0SFabiano Rosas     case AIL_NONE:
116bc5fdfc0SFabiano Rosas         break;
1172586a4d7SFabiano Rosas     case AIL_0001_8000:
1182586a4d7SFabiano Rosas         offset = 0x18000;
1192586a4d7SFabiano Rosas         break;
1202586a4d7SFabiano Rosas     case AIL_C000_0000_0000_4000:
1212586a4d7SFabiano Rosas         offset = 0xc000000000004000ull;
1222586a4d7SFabiano Rosas         break;
1232586a4d7SFabiano Rosas     default:
1242586a4d7SFabiano Rosas         cpu_abort(cs, "Invalid AIL combination %d\n", ail);
1252586a4d7SFabiano Rosas         break;
1262586a4d7SFabiano Rosas     }
1272586a4d7SFabiano Rosas 
1282586a4d7SFabiano Rosas     return offset;
1292586a4d7SFabiano Rosas }
130dead760bSBenjamin Herrenschmidt 
131*ad77c6caSNicholas Piggin static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
132*ad77c6caSNicholas Piggin                                           target_ulong vector, target_ulong msr)
133*ad77c6caSNicholas Piggin {
134*ad77c6caSNicholas Piggin     CPUState *cs = CPU(cpu);
135*ad77c6caSNicholas Piggin     CPUPPCState *env = &cpu->env;
136*ad77c6caSNicholas Piggin 
137*ad77c6caSNicholas Piggin     /*
138*ad77c6caSNicholas Piggin      * We don't use hreg_store_msr here as already have treated any
139*ad77c6caSNicholas Piggin      * special case that could occur. Just store MSR and update hflags
140*ad77c6caSNicholas Piggin      *
141*ad77c6caSNicholas Piggin      * Note: We *MUST* not use hreg_store_msr() as-is anyway because it
142*ad77c6caSNicholas Piggin      * will prevent setting of the HV bit which some exceptions might need
143*ad77c6caSNicholas Piggin      * to do.
144*ad77c6caSNicholas Piggin      */
145*ad77c6caSNicholas Piggin     env->msr = msr & env->msr_mask;
146*ad77c6caSNicholas Piggin     hreg_compute_hflags(env);
147*ad77c6caSNicholas Piggin     env->nip = vector;
148*ad77c6caSNicholas Piggin     /* Reset exception state */
149*ad77c6caSNicholas Piggin     cs->exception_index = POWERPC_EXCP_NONE;
150*ad77c6caSNicholas Piggin     env->error_code = 0;
151*ad77c6caSNicholas Piggin 
152*ad77c6caSNicholas Piggin     /* Reset the reservation */
153*ad77c6caSNicholas Piggin     env->reserve_addr = -1;
154*ad77c6caSNicholas Piggin 
155*ad77c6caSNicholas Piggin     /*
156*ad77c6caSNicholas Piggin      * Any interrupt is context synchronizing, check if TCG TLB needs
157*ad77c6caSNicholas Piggin      * a delayed flush on ppc64
158*ad77c6caSNicholas Piggin      */
159*ad77c6caSNicholas Piggin     check_tlb_flush(env, false);
160*ad77c6caSNicholas Piggin }
161*ad77c6caSNicholas Piggin 
16247733729SDavid Gibson /*
16347733729SDavid Gibson  * Note that this function should be greatly optimized when called
16447733729SDavid Gibson  * with a constant excp, from ppc_hw_interrupt
165c79c73f6SBlue Swirl  */
1665c26a5b3SAndreas Färber static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
167c79c73f6SBlue Swirl {
16827103424SAndreas Färber     CPUState *cs = CPU(cpu);
1695c26a5b3SAndreas Färber     CPUPPCState *env = &cpu->env;
170c79c73f6SBlue Swirl     target_ulong msr, new_msr, vector;
1716d49d6d4SBenjamin Herrenschmidt     int srr0, srr1, asrr0, asrr1, lev, ail;
1726d49d6d4SBenjamin Herrenschmidt     bool lpes0;
173c79c73f6SBlue Swirl 
174c79c73f6SBlue Swirl     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
175c79c73f6SBlue Swirl                   " => %08x (%02x)\n", env->nip, excp, env->error_code);
176c79c73f6SBlue Swirl 
177c79c73f6SBlue Swirl     /* new srr1 value excluding must-be-zero bits */
178a1bb7384SScott Wood     if (excp_model == POWERPC_EXCP_BOOKE) {
179a1bb7384SScott Wood         msr = env->msr;
180a1bb7384SScott Wood     } else {
181c79c73f6SBlue Swirl         msr = env->msr & ~0x783f0000ULL;
182a1bb7384SScott Wood     }
183c79c73f6SBlue Swirl 
18447733729SDavid Gibson     /*
18547733729SDavid Gibson      * new interrupt handler msr preserves existing HV and ME unless
1866d49d6d4SBenjamin Herrenschmidt      * explicitly overriden
1876d49d6d4SBenjamin Herrenschmidt      */
1886d49d6d4SBenjamin Herrenschmidt     new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
189c79c73f6SBlue Swirl 
190c79c73f6SBlue Swirl     /* target registers */
191c79c73f6SBlue Swirl     srr0 = SPR_SRR0;
192c79c73f6SBlue Swirl     srr1 = SPR_SRR1;
193c79c73f6SBlue Swirl     asrr0 = -1;
194c79c73f6SBlue Swirl     asrr1 = -1;
195c79c73f6SBlue Swirl 
19621c0d66aSBenjamin Herrenschmidt     /*
19721c0d66aSBenjamin Herrenschmidt      * check for special resume at 0x100 from doze/nap/sleep/winkle on
19821c0d66aSBenjamin Herrenschmidt      * P7/P8/P9
19921c0d66aSBenjamin Herrenschmidt      */
2001e7fd61dSBenjamin Herrenschmidt     if (env->resume_as_sreset) {
201dead760bSBenjamin Herrenschmidt         excp = powerpc_reset_wakeup(cs, env, excp, &msr);
2027778a575SBenjamin Herrenschmidt     }
2037778a575SBenjamin Herrenschmidt 
20447733729SDavid Gibson     /*
20547733729SDavid Gibson      * Exception targetting modifiers
2065c94b2a5SCédric Le Goater      *
207a790e82bSBenjamin Herrenschmidt      * LPES0 is supported on POWER7/8/9
2086d49d6d4SBenjamin Herrenschmidt      * LPES1 is not supported (old iSeries mode)
2096d49d6d4SBenjamin Herrenschmidt      *
2106d49d6d4SBenjamin Herrenschmidt      * On anything else, we behave as if LPES0 is 1
2116d49d6d4SBenjamin Herrenschmidt      * (externals don't alter MSR:HV)
2126d49d6d4SBenjamin Herrenschmidt      *
2135c94b2a5SCédric Le Goater      * AIL is initialized here but can be cleared by
2145c94b2a5SCédric Le Goater      * selected exceptions
2155c94b2a5SCédric Le Goater      */
2165c94b2a5SCédric Le Goater #if defined(TARGET_PPC64)
2175c94b2a5SCédric Le Goater     if (excp_model == POWERPC_EXCP_POWER7 ||
218a790e82bSBenjamin Herrenschmidt         excp_model == POWERPC_EXCP_POWER8 ||
219a790e82bSBenjamin Herrenschmidt         excp_model == POWERPC_EXCP_POWER9) {
2206d49d6d4SBenjamin Herrenschmidt         lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
221a790e82bSBenjamin Herrenschmidt         if (excp_model != POWERPC_EXCP_POWER7) {
2225c94b2a5SCédric Le Goater             ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
2235c94b2a5SCédric Le Goater         } else {
2245c94b2a5SCédric Le Goater             ail = 0;
2255c94b2a5SCédric Le Goater         }
2265c94b2a5SCédric Le Goater     } else
2275c94b2a5SCédric Le Goater #endif /* defined(TARGET_PPC64) */
2285c94b2a5SCédric Le Goater     {
2296d49d6d4SBenjamin Herrenschmidt         lpes0 = true;
2305c94b2a5SCédric Le Goater         ail = 0;
2315c94b2a5SCédric Le Goater     }
2325c94b2a5SCédric Le Goater 
23347733729SDavid Gibson     /*
23447733729SDavid Gibson      * Hypervisor emulation assistance interrupt only exists on server
2359b2faddaSBenjamin Herrenschmidt      * arch 2.05 server or later. We also don't want to generate it if
2369b2faddaSBenjamin Herrenschmidt      * we don't have HVB in msr_mask (PAPR mode).
2379b2faddaSBenjamin Herrenschmidt      */
2389b2faddaSBenjamin Herrenschmidt     if (excp == POWERPC_EXCP_HV_EMU
2399b2faddaSBenjamin Herrenschmidt #if defined(TARGET_PPC64)
2409b2faddaSBenjamin Herrenschmidt         && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB))
2419b2faddaSBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */
2429b2faddaSBenjamin Herrenschmidt 
2439b2faddaSBenjamin Herrenschmidt     ) {
2449b2faddaSBenjamin Herrenschmidt         excp = POWERPC_EXCP_PROGRAM;
2459b2faddaSBenjamin Herrenschmidt     }
2469b2faddaSBenjamin Herrenschmidt 
247c79c73f6SBlue Swirl     switch (excp) {
248c79c73f6SBlue Swirl     case POWERPC_EXCP_NONE:
249c79c73f6SBlue Swirl         /* Should never happen */
250c79c73f6SBlue Swirl         return;
251c79c73f6SBlue Swirl     case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
252c79c73f6SBlue Swirl         switch (excp_model) {
253c79c73f6SBlue Swirl         case POWERPC_EXCP_40x:
254c79c73f6SBlue Swirl             srr0 = SPR_40x_SRR2;
255c79c73f6SBlue Swirl             srr1 = SPR_40x_SRR3;
256c79c73f6SBlue Swirl             break;
257c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
258c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_CSRR0;
259c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_CSRR1;
260c79c73f6SBlue Swirl             break;
261c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
262c79c73f6SBlue Swirl             break;
263c79c73f6SBlue Swirl         default:
264c79c73f6SBlue Swirl             goto excp_invalid;
265c79c73f6SBlue Swirl         }
266bd6fefe7SBenjamin Herrenschmidt         break;
267c79c73f6SBlue Swirl     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
268c79c73f6SBlue Swirl         if (msr_me == 0) {
26947733729SDavid Gibson             /*
27047733729SDavid Gibson              * Machine check exception is not enabled.  Enter
27147733729SDavid Gibson              * checkstop state.
272c79c73f6SBlue Swirl              */
273c79c73f6SBlue Swirl             fprintf(stderr, "Machine check while not allowed. "
274c79c73f6SBlue Swirl                     "Entering checkstop state\n");
275013a2942SPaolo Bonzini             if (qemu_log_separate()) {
276013a2942SPaolo Bonzini                 qemu_log("Machine check while not allowed. "
277013a2942SPaolo Bonzini                         "Entering checkstop state\n");
278c79c73f6SBlue Swirl             }
279259186a7SAndreas Färber             cs->halted = 1;
280044897efSRichard Purdie             cpu_interrupt_exittb(cs);
281c79c73f6SBlue Swirl         }
28210c21b5cSNicholas Piggin         if (env->msr_mask & MSR_HVB) {
28347733729SDavid Gibson             /*
28447733729SDavid Gibson              * ISA specifies HV, but can be delivered to guest with HV
28547733729SDavid Gibson              * clear (e.g., see FWNMI in PAPR).
28610c21b5cSNicholas Piggin              */
287c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
28810c21b5cSNicholas Piggin         }
2895c94b2a5SCédric Le Goater         ail = 0;
290c79c73f6SBlue Swirl 
291c79c73f6SBlue Swirl         /* machine check exceptions don't have ME set */
292c79c73f6SBlue Swirl         new_msr &= ~((target_ulong)1 << MSR_ME);
293c79c73f6SBlue Swirl 
294c79c73f6SBlue Swirl         /* XXX: should also have something loaded in DAR / DSISR */
295c79c73f6SBlue Swirl         switch (excp_model) {
296c79c73f6SBlue Swirl         case POWERPC_EXCP_40x:
297c79c73f6SBlue Swirl             srr0 = SPR_40x_SRR2;
298c79c73f6SBlue Swirl             srr1 = SPR_40x_SRR3;
299c79c73f6SBlue Swirl             break;
300c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
301a1bb7384SScott Wood             /* FIXME: choose one or the other based on CPU type */
302c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_MCSRR0;
303c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_MCSRR1;
304c79c73f6SBlue Swirl             asrr0 = SPR_BOOKE_CSRR0;
305c79c73f6SBlue Swirl             asrr1 = SPR_BOOKE_CSRR1;
306c79c73f6SBlue Swirl             break;
307c79c73f6SBlue Swirl         default:
308c79c73f6SBlue Swirl             break;
309c79c73f6SBlue Swirl         }
310bd6fefe7SBenjamin Herrenschmidt         break;
311c79c73f6SBlue Swirl     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
312c79c73f6SBlue Swirl         LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
313c79c73f6SBlue Swirl                  "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
314bd6fefe7SBenjamin Herrenschmidt         break;
315c79c73f6SBlue Swirl     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
316c79c73f6SBlue Swirl         LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
317c79c73f6SBlue Swirl                  "\n", msr, env->nip);
318c79c73f6SBlue Swirl         msr |= env->error_code;
319bd6fefe7SBenjamin Herrenschmidt         break;
320c79c73f6SBlue Swirl     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
321fdfba1a2SEdgar E. Iglesias         cs = CPU(cpu);
322fdfba1a2SEdgar E. Iglesias 
3236d49d6d4SBenjamin Herrenschmidt         if (!lpes0) {
324c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
3256d49d6d4SBenjamin Herrenschmidt             new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
3266d49d6d4SBenjamin Herrenschmidt             srr0 = SPR_HSRR0;
3276d49d6d4SBenjamin Herrenschmidt             srr1 = SPR_HSRR1;
328c79c73f6SBlue Swirl         }
32968c2dd70SAlexander Graf         if (env->mpic_proxy) {
33068c2dd70SAlexander Graf             /* IACK the IRQ on delivery */
331fdfba1a2SEdgar E. Iglesias             env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
33268c2dd70SAlexander Graf         }
333bd6fefe7SBenjamin Herrenschmidt         break;
334c79c73f6SBlue Swirl     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
335c79c73f6SBlue Swirl         /* Get rS/rD and rA from faulting opcode */
33647733729SDavid Gibson         /*
33747733729SDavid Gibson          * Note: the opcode fields will not be set properly for a
33847733729SDavid Gibson          * direct store load/store, but nobody cares as nobody
33947733729SDavid Gibson          * actually uses direct store segments.
3403433b732SBenjamin Herrenschmidt          */
3413433b732SBenjamin Herrenschmidt         env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
342bd6fefe7SBenjamin Herrenschmidt         break;
343c79c73f6SBlue Swirl     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
344c79c73f6SBlue Swirl         switch (env->error_code & ~0xF) {
345c79c73f6SBlue Swirl         case POWERPC_EXCP_FP:
346c79c73f6SBlue Swirl             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
347c79c73f6SBlue Swirl                 LOG_EXCP("Ignore floating point exception\n");
34827103424SAndreas Färber                 cs->exception_index = POWERPC_EXCP_NONE;
349c79c73f6SBlue Swirl                 env->error_code = 0;
350c79c73f6SBlue Swirl                 return;
351c79c73f6SBlue Swirl             }
3521b7d17caSBenjamin Herrenschmidt 
35347733729SDavid Gibson             /*
35447733729SDavid Gibson              * FP exceptions always have NIP pointing to the faulting
3551b7d17caSBenjamin Herrenschmidt              * instruction, so always use store_next and claim we are
3561b7d17caSBenjamin Herrenschmidt              * precise in the MSR.
3571b7d17caSBenjamin Herrenschmidt              */
358c79c73f6SBlue Swirl             msr |= 0x00100000;
3590ee604abSAaron Larson             env->spr[SPR_BOOKE_ESR] = ESR_FP;
360bd6fefe7SBenjamin Herrenschmidt             break;
361c79c73f6SBlue Swirl         case POWERPC_EXCP_INVAL:
362c79c73f6SBlue Swirl             LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
363c79c73f6SBlue Swirl             msr |= 0x00080000;
364c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PIL;
365c79c73f6SBlue Swirl             break;
366c79c73f6SBlue Swirl         case POWERPC_EXCP_PRIV:
367c79c73f6SBlue Swirl             msr |= 0x00040000;
368c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PPR;
369c79c73f6SBlue Swirl             break;
370c79c73f6SBlue Swirl         case POWERPC_EXCP_TRAP:
371c79c73f6SBlue Swirl             msr |= 0x00020000;
372c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PTR;
373c79c73f6SBlue Swirl             break;
374c79c73f6SBlue Swirl         default:
375c79c73f6SBlue Swirl             /* Should never occur */
376a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid program exception %d. Aborting\n",
377c79c73f6SBlue Swirl                       env->error_code);
378c79c73f6SBlue Swirl             break;
379c79c73f6SBlue Swirl         }
380bd6fefe7SBenjamin Herrenschmidt         break;
381c79c73f6SBlue Swirl     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
382c79c73f6SBlue Swirl         dump_syscall(env);
383c79c73f6SBlue Swirl         lev = env->error_code;
3846d49d6d4SBenjamin Herrenschmidt 
38547733729SDavid Gibson         /*
38647733729SDavid Gibson          * We need to correct the NIP which in this case is supposed
387bd6fefe7SBenjamin Herrenschmidt          * to point to the next instruction
388bd6fefe7SBenjamin Herrenschmidt          */
389bd6fefe7SBenjamin Herrenschmidt         env->nip += 4;
390bd6fefe7SBenjamin Herrenschmidt 
3916d49d6d4SBenjamin Herrenschmidt         /* "PAPR mode" built-in hypercall emulation */
3921d1be34dSDavid Gibson         if ((lev == 1) && cpu->vhyp) {
3931d1be34dSDavid Gibson             PPCVirtualHypervisorClass *vhc =
3941d1be34dSDavid Gibson                 PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
3951d1be34dSDavid Gibson             vhc->hypercall(cpu->vhyp, cpu);
396c79c73f6SBlue Swirl             return;
397c79c73f6SBlue Swirl         }
3986d49d6d4SBenjamin Herrenschmidt         if (lev == 1) {
399c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
400c79c73f6SBlue Swirl         }
401bd6fefe7SBenjamin Herrenschmidt         break;
402bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
403c79c73f6SBlue Swirl     case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
404c79c73f6SBlue Swirl     case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
405bd6fefe7SBenjamin Herrenschmidt         break;
406c79c73f6SBlue Swirl     case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
407c79c73f6SBlue Swirl         /* FIT on 4xx */
408c79c73f6SBlue Swirl         LOG_EXCP("FIT exception\n");
409bd6fefe7SBenjamin Herrenschmidt         break;
410c79c73f6SBlue Swirl     case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
411c79c73f6SBlue Swirl         LOG_EXCP("WDT exception\n");
412c79c73f6SBlue Swirl         switch (excp_model) {
413c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
414c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_CSRR0;
415c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_CSRR1;
416c79c73f6SBlue Swirl             break;
417c79c73f6SBlue Swirl         default:
418c79c73f6SBlue Swirl             break;
419c79c73f6SBlue Swirl         }
420bd6fefe7SBenjamin Herrenschmidt         break;
421c79c73f6SBlue Swirl     case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
422c79c73f6SBlue Swirl     case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
423bd6fefe7SBenjamin Herrenschmidt         break;
424c79c73f6SBlue Swirl     case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
4250e3bf489SRoman Kapl         if (env->flags & POWERPC_FLAG_DE) {
426a1bb7384SScott Wood             /* FIXME: choose one or the other based on CPU type */
427c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_DSRR0;
428c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_DSRR1;
429c79c73f6SBlue Swirl             asrr0 = SPR_BOOKE_CSRR0;
430c79c73f6SBlue Swirl             asrr1 = SPR_BOOKE_CSRR1;
4310e3bf489SRoman Kapl             /* DBSR already modified by caller */
4320e3bf489SRoman Kapl         } else {
4330e3bf489SRoman Kapl             cpu_abort(cs, "Debug exception triggered on unsupported model\n");
434c79c73f6SBlue Swirl         }
435bd6fefe7SBenjamin Herrenschmidt         break;
436c79c73f6SBlue Swirl     case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
437c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
438bd6fefe7SBenjamin Herrenschmidt         break;
439c79c73f6SBlue Swirl     case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
440c79c73f6SBlue Swirl         /* XXX: TODO */
441a47dddd7SAndreas Färber         cpu_abort(cs, "Embedded floating point data exception "
442c79c73f6SBlue Swirl                   "is not implemented yet !\n");
443c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
444bd6fefe7SBenjamin Herrenschmidt         break;
445c79c73f6SBlue Swirl     case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
446c79c73f6SBlue Swirl         /* XXX: TODO */
447a47dddd7SAndreas Färber         cpu_abort(cs, "Embedded floating point round exception "
448c79c73f6SBlue Swirl                   "is not implemented yet !\n");
449c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
450bd6fefe7SBenjamin Herrenschmidt         break;
451c79c73f6SBlue Swirl     case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
452c79c73f6SBlue Swirl         /* XXX: TODO */
453a47dddd7SAndreas Färber         cpu_abort(cs,
454c79c73f6SBlue Swirl                   "Performance counter exception is not implemented yet !\n");
455bd6fefe7SBenjamin Herrenschmidt         break;
456c79c73f6SBlue Swirl     case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
457bd6fefe7SBenjamin Herrenschmidt         break;
458c79c73f6SBlue Swirl     case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
459c79c73f6SBlue Swirl         srr0 = SPR_BOOKE_CSRR0;
460c79c73f6SBlue Swirl         srr1 = SPR_BOOKE_CSRR1;
461bd6fefe7SBenjamin Herrenschmidt         break;
462c79c73f6SBlue Swirl     case POWERPC_EXCP_RESET:     /* System reset exception                   */
463f85bcec3SNicholas Piggin         /* A power-saving exception sets ME, otherwise it is unchanged */
464c79c73f6SBlue Swirl         if (msr_pow) {
465c79c73f6SBlue Swirl             /* indicate that we resumed from power save mode */
466c79c73f6SBlue Swirl             msr |= 0x10000;
467f85bcec3SNicholas Piggin             new_msr |= ((target_ulong)1 << MSR_ME);
468c79c73f6SBlue Swirl         }
46910c21b5cSNicholas Piggin         if (env->msr_mask & MSR_HVB) {
47047733729SDavid Gibson             /*
47147733729SDavid Gibson              * ISA specifies HV, but can be delivered to guest with HV
47247733729SDavid Gibson              * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
47310c21b5cSNicholas Piggin              */
474c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
47510c21b5cSNicholas Piggin         } else {
47610c21b5cSNicholas Piggin             if (msr_pow) {
47710c21b5cSNicholas Piggin                 cpu_abort(cs, "Trying to deliver power-saving system reset "
47810c21b5cSNicholas Piggin                           "exception %d with no HV support\n", excp);
47910c21b5cSNicholas Piggin             }
48010c21b5cSNicholas Piggin         }
4815c94b2a5SCédric Le Goater         ail = 0;
482bd6fefe7SBenjamin Herrenschmidt         break;
483c79c73f6SBlue Swirl     case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
484c79c73f6SBlue Swirl     case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
485c79c73f6SBlue Swirl     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
486bd6fefe7SBenjamin Herrenschmidt         break;
487bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
488c79c73f6SBlue Swirl     case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
489c79c73f6SBlue Swirl     case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
490c79c73f6SBlue Swirl     case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
491c79c73f6SBlue Swirl     case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
4927af1e7b0SCédric Le Goater     case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
493bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_HV_EMU:
494d8ce5fd6SBenjamin Herrenschmidt     case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
495c79c73f6SBlue Swirl         srr0 = SPR_HSRR0;
496c79c73f6SBlue Swirl         srr1 = SPR_HSRR1;
497c79c73f6SBlue Swirl         new_msr |= (target_ulong)MSR_HVB;
498c79c73f6SBlue Swirl         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
499bd6fefe7SBenjamin Herrenschmidt         break;
500c79c73f6SBlue Swirl     case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
5011f29871cSTom Musta     case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
5027019cb3dSAlexey Kardashevskiy     case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
5035310799aSBalbir Singh #ifdef TARGET_PPC64
5045310799aSBalbir Singh         env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
5055310799aSBalbir Singh #endif
506bd6fefe7SBenjamin Herrenschmidt         break;
507493028d8SCédric Le Goater     case POWERPC_EXCP_HV_FU:     /* Hypervisor Facility Unavailable Exception */
508493028d8SCédric Le Goater #ifdef TARGET_PPC64
509493028d8SCédric Le Goater         env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
510493028d8SCédric Le Goater         srr0 = SPR_HSRR0;
511493028d8SCédric Le Goater         srr1 = SPR_HSRR1;
512493028d8SCédric Le Goater         new_msr |= (target_ulong)MSR_HVB;
513493028d8SCédric Le Goater         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
514493028d8SCédric Le Goater #endif
515493028d8SCédric Le Goater         break;
516c79c73f6SBlue Swirl     case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
517c79c73f6SBlue Swirl         LOG_EXCP("PIT exception\n");
518bd6fefe7SBenjamin Herrenschmidt         break;
519c79c73f6SBlue Swirl     case POWERPC_EXCP_IO:        /* IO error exception                       */
520c79c73f6SBlue Swirl         /* XXX: TODO */
521a47dddd7SAndreas Färber         cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
522bd6fefe7SBenjamin Herrenschmidt         break;
523c79c73f6SBlue Swirl     case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
524c79c73f6SBlue Swirl         /* XXX: TODO */
525a47dddd7SAndreas Färber         cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
526bd6fefe7SBenjamin Herrenschmidt         break;
527c79c73f6SBlue Swirl     case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
528c79c73f6SBlue Swirl         /* XXX: TODO */
529a47dddd7SAndreas Färber         cpu_abort(cs, "602 emulation trap exception "
530c79c73f6SBlue Swirl                   "is not implemented yet !\n");
531bd6fefe7SBenjamin Herrenschmidt         break;
532c79c73f6SBlue Swirl     case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
533c79c73f6SBlue Swirl         switch (excp_model) {
534c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
535c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
536c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
537c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
538c79c73f6SBlue Swirl             goto tlb_miss_tgpr;
539c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
540c79c73f6SBlue Swirl             goto tlb_miss;
541c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
542c79c73f6SBlue Swirl             goto tlb_miss_74xx;
543c79c73f6SBlue Swirl         default:
544a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid instruction TLB miss exception\n");
545c79c73f6SBlue Swirl             break;
546c79c73f6SBlue Swirl         }
547c79c73f6SBlue Swirl         break;
548c79c73f6SBlue Swirl     case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
549c79c73f6SBlue Swirl         switch (excp_model) {
550c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
551c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
552c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
553c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
554c79c73f6SBlue Swirl             goto tlb_miss_tgpr;
555c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
556c79c73f6SBlue Swirl             goto tlb_miss;
557c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
558c79c73f6SBlue Swirl             goto tlb_miss_74xx;
559c79c73f6SBlue Swirl         default:
560a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid data load TLB miss exception\n");
561c79c73f6SBlue Swirl             break;
562c79c73f6SBlue Swirl         }
563c79c73f6SBlue Swirl         break;
564c79c73f6SBlue Swirl     case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
565c79c73f6SBlue Swirl         switch (excp_model) {
566c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
567c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
568c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
569c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
570c79c73f6SBlue Swirl         tlb_miss_tgpr:
571c79c73f6SBlue Swirl             /* Swap temporary saved registers with GPRs */
572c79c73f6SBlue Swirl             if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
573c79c73f6SBlue Swirl                 new_msr |= (target_ulong)1 << MSR_TGPR;
574c79c73f6SBlue Swirl                 hreg_swap_gpr_tgpr(env);
575c79c73f6SBlue Swirl             }
576c79c73f6SBlue Swirl             goto tlb_miss;
577c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
578c79c73f6SBlue Swirl         tlb_miss:
579c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB)
580c79c73f6SBlue Swirl             if (qemu_log_enabled()) {
581c79c73f6SBlue Swirl                 const char *es;
582c79c73f6SBlue Swirl                 target_ulong *miss, *cmp;
583c79c73f6SBlue Swirl                 int en;
584c79c73f6SBlue Swirl 
585c79c73f6SBlue Swirl                 if (excp == POWERPC_EXCP_IFTLB) {
586c79c73f6SBlue Swirl                     es = "I";
587c79c73f6SBlue Swirl                     en = 'I';
588c79c73f6SBlue Swirl                     miss = &env->spr[SPR_IMISS];
589c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_ICMP];
590c79c73f6SBlue Swirl                 } else {
591c79c73f6SBlue Swirl                     if (excp == POWERPC_EXCP_DLTLB) {
592c79c73f6SBlue Swirl                         es = "DL";
593c79c73f6SBlue Swirl                     } else {
594c79c73f6SBlue Swirl                         es = "DS";
595c79c73f6SBlue Swirl                     }
596c79c73f6SBlue Swirl                     en = 'D';
597c79c73f6SBlue Swirl                     miss = &env->spr[SPR_DMISS];
598c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_DCMP];
599c79c73f6SBlue Swirl                 }
600c79c73f6SBlue Swirl                 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
601c79c73f6SBlue Swirl                          TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
602c79c73f6SBlue Swirl                          TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
603c79c73f6SBlue Swirl                          env->spr[SPR_HASH1], env->spr[SPR_HASH2],
604c79c73f6SBlue Swirl                          env->error_code);
605c79c73f6SBlue Swirl             }
606c79c73f6SBlue Swirl #endif
607c79c73f6SBlue Swirl             msr |= env->crf[0] << 28;
608c79c73f6SBlue Swirl             msr |= env->error_code; /* key, D/I, S/L bits */
609c79c73f6SBlue Swirl             /* Set way using a LRU mechanism */
610c79c73f6SBlue Swirl             msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
611c79c73f6SBlue Swirl             break;
612c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
613c79c73f6SBlue Swirl         tlb_miss_74xx:
614c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB)
615c79c73f6SBlue Swirl             if (qemu_log_enabled()) {
616c79c73f6SBlue Swirl                 const char *es;
617c79c73f6SBlue Swirl                 target_ulong *miss, *cmp;
618c79c73f6SBlue Swirl                 int en;
619c79c73f6SBlue Swirl 
620c79c73f6SBlue Swirl                 if (excp == POWERPC_EXCP_IFTLB) {
621c79c73f6SBlue Swirl                     es = "I";
622c79c73f6SBlue Swirl                     en = 'I';
623c79c73f6SBlue Swirl                     miss = &env->spr[SPR_TLBMISS];
624c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_PTEHI];
625c79c73f6SBlue Swirl                 } else {
626c79c73f6SBlue Swirl                     if (excp == POWERPC_EXCP_DLTLB) {
627c79c73f6SBlue Swirl                         es = "DL";
628c79c73f6SBlue Swirl                     } else {
629c79c73f6SBlue Swirl                         es = "DS";
630c79c73f6SBlue Swirl                     }
631c79c73f6SBlue Swirl                     en = 'D';
632c79c73f6SBlue Swirl                     miss = &env->spr[SPR_TLBMISS];
633c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_PTEHI];
634c79c73f6SBlue Swirl                 }
635c79c73f6SBlue Swirl                 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
636c79c73f6SBlue Swirl                          TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
637c79c73f6SBlue Swirl                          env->error_code);
638c79c73f6SBlue Swirl             }
639c79c73f6SBlue Swirl #endif
640c79c73f6SBlue Swirl             msr |= env->error_code; /* key bit */
641c79c73f6SBlue Swirl             break;
642c79c73f6SBlue Swirl         default:
643a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid data store TLB miss exception\n");
644c79c73f6SBlue Swirl             break;
645c79c73f6SBlue Swirl         }
646bd6fefe7SBenjamin Herrenschmidt         break;
647c79c73f6SBlue Swirl     case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
648c79c73f6SBlue Swirl         /* XXX: TODO */
649a47dddd7SAndreas Färber         cpu_abort(cs, "Floating point assist exception "
650c79c73f6SBlue Swirl                   "is not implemented yet !\n");
651bd6fefe7SBenjamin Herrenschmidt         break;
652c79c73f6SBlue Swirl     case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
653c79c73f6SBlue Swirl         /* XXX: TODO */
654a47dddd7SAndreas Färber         cpu_abort(cs, "DABR exception is not implemented yet !\n");
655bd6fefe7SBenjamin Herrenschmidt         break;
656c79c73f6SBlue Swirl     case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
657c79c73f6SBlue Swirl         /* XXX: TODO */
658a47dddd7SAndreas Färber         cpu_abort(cs, "IABR exception is not implemented yet !\n");
659bd6fefe7SBenjamin Herrenschmidt         break;
660c79c73f6SBlue Swirl     case POWERPC_EXCP_SMI:       /* System management interrupt              */
661c79c73f6SBlue Swirl         /* XXX: TODO */
662a47dddd7SAndreas Färber         cpu_abort(cs, "SMI exception is not implemented yet !\n");
663bd6fefe7SBenjamin Herrenschmidt         break;
664c79c73f6SBlue Swirl     case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
665c79c73f6SBlue Swirl         /* XXX: TODO */
666a47dddd7SAndreas Färber         cpu_abort(cs, "Thermal management exception "
667c79c73f6SBlue Swirl                   "is not implemented yet !\n");
668bd6fefe7SBenjamin Herrenschmidt         break;
669c79c73f6SBlue Swirl     case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
670c79c73f6SBlue Swirl         /* XXX: TODO */
671a47dddd7SAndreas Färber         cpu_abort(cs,
672c79c73f6SBlue Swirl                   "Performance counter exception is not implemented yet !\n");
673bd6fefe7SBenjamin Herrenschmidt         break;
674c79c73f6SBlue Swirl     case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
675c79c73f6SBlue Swirl         /* XXX: TODO */
676a47dddd7SAndreas Färber         cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
677bd6fefe7SBenjamin Herrenschmidt         break;
678c79c73f6SBlue Swirl     case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
679c79c73f6SBlue Swirl         /* XXX: TODO */
680a47dddd7SAndreas Färber         cpu_abort(cs,
681c79c73f6SBlue Swirl                   "970 soft-patch exception is not implemented yet !\n");
682bd6fefe7SBenjamin Herrenschmidt         break;
683c79c73f6SBlue Swirl     case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
684c79c73f6SBlue Swirl         /* XXX: TODO */
685a47dddd7SAndreas Färber         cpu_abort(cs,
686c79c73f6SBlue Swirl                   "970 maintenance exception is not implemented yet !\n");
687bd6fefe7SBenjamin Herrenschmidt         break;
688c79c73f6SBlue Swirl     case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
689c79c73f6SBlue Swirl         /* XXX: TODO */
690a47dddd7SAndreas Färber         cpu_abort(cs, "Maskable external exception "
691c79c73f6SBlue Swirl                   "is not implemented yet !\n");
692bd6fefe7SBenjamin Herrenschmidt         break;
693c79c73f6SBlue Swirl     case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
694c79c73f6SBlue Swirl         /* XXX: TODO */
695a47dddd7SAndreas Färber         cpu_abort(cs, "Non maskable external exception "
696c79c73f6SBlue Swirl                   "is not implemented yet !\n");
697bd6fefe7SBenjamin Herrenschmidt         break;
698c79c73f6SBlue Swirl     default:
699c79c73f6SBlue Swirl     excp_invalid:
700a47dddd7SAndreas Färber         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
701c79c73f6SBlue Swirl         break;
702c79c73f6SBlue Swirl     }
703bd6fefe7SBenjamin Herrenschmidt 
704bd6fefe7SBenjamin Herrenschmidt     /* Save PC */
705bd6fefe7SBenjamin Herrenschmidt     env->spr[srr0] = env->nip;
706bd6fefe7SBenjamin Herrenschmidt 
707c79c73f6SBlue Swirl     /* Save MSR */
708c79c73f6SBlue Swirl     env->spr[srr1] = msr;
7096d49d6d4SBenjamin Herrenschmidt 
7106d49d6d4SBenjamin Herrenschmidt     /* Sanity check */
71110c21b5cSNicholas Piggin     if (!(env->msr_mask & MSR_HVB)) {
71210c21b5cSNicholas Piggin         if (new_msr & MSR_HVB) {
71310c21b5cSNicholas Piggin             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
7146d49d6d4SBenjamin Herrenschmidt                       "no HV support\n", excp);
7156d49d6d4SBenjamin Herrenschmidt         }
71610c21b5cSNicholas Piggin         if (srr0 == SPR_HSRR0) {
71710c21b5cSNicholas Piggin             cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
71810c21b5cSNicholas Piggin                       "no HV support\n", excp);
71910c21b5cSNicholas Piggin         }
72010c21b5cSNicholas Piggin     }
7216d49d6d4SBenjamin Herrenschmidt 
722c79c73f6SBlue Swirl     /* If any alternate SRR register are defined, duplicate saved values */
723c79c73f6SBlue Swirl     if (asrr0 != -1) {
724c79c73f6SBlue Swirl         env->spr[asrr0] = env->spr[srr0];
725c79c73f6SBlue Swirl     }
726c79c73f6SBlue Swirl     if (asrr1 != -1) {
727c79c73f6SBlue Swirl         env->spr[asrr1] = env->spr[srr1];
728c79c73f6SBlue Swirl     }
729d5ac4f54SAlexey Kardashevskiy 
73047733729SDavid Gibson     /*
73147733729SDavid Gibson      * Sort out endianness of interrupt, this differs depending on the
7326d49d6d4SBenjamin Herrenschmidt      * CPU, the HV mode, etc...
7336d49d6d4SBenjamin Herrenschmidt      */
7341e0c7e55SAnton Blanchard #ifdef TARGET_PPC64
7356d49d6d4SBenjamin Herrenschmidt     if (excp_model == POWERPC_EXCP_POWER7) {
7366d49d6d4SBenjamin Herrenschmidt         if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) {
7376d49d6d4SBenjamin Herrenschmidt             new_msr |= (target_ulong)1 << MSR_LE;
7386d49d6d4SBenjamin Herrenschmidt         }
7396d49d6d4SBenjamin Herrenschmidt     } else if (excp_model == POWERPC_EXCP_POWER8) {
7406d49d6d4SBenjamin Herrenschmidt         if (new_msr & MSR_HVB) {
741a790e82bSBenjamin Herrenschmidt             if (env->spr[SPR_HID0] & HID0_HILE) {
742a790e82bSBenjamin Herrenschmidt                 new_msr |= (target_ulong)1 << MSR_LE;
743a790e82bSBenjamin Herrenschmidt             }
744a790e82bSBenjamin Herrenschmidt         } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
745a790e82bSBenjamin Herrenschmidt             new_msr |= (target_ulong)1 << MSR_LE;
746a790e82bSBenjamin Herrenschmidt         }
747a790e82bSBenjamin Herrenschmidt     } else if (excp_model == POWERPC_EXCP_POWER9) {
748a790e82bSBenjamin Herrenschmidt         if (new_msr & MSR_HVB) {
749a790e82bSBenjamin Herrenschmidt             if (env->spr[SPR_HID0] & HID0_POWER9_HILE) {
7506d49d6d4SBenjamin Herrenschmidt                 new_msr |= (target_ulong)1 << MSR_LE;
7516d49d6d4SBenjamin Herrenschmidt             }
7526d49d6d4SBenjamin Herrenschmidt         } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
7531e0c7e55SAnton Blanchard             new_msr |= (target_ulong)1 << MSR_LE;
7541e0c7e55SAnton Blanchard         }
7551e0c7e55SAnton Blanchard     } else if (msr_ile) {
7561e0c7e55SAnton Blanchard         new_msr |= (target_ulong)1 << MSR_LE;
7571e0c7e55SAnton Blanchard     }
7581e0c7e55SAnton Blanchard #else
759c79c73f6SBlue Swirl     if (msr_ile) {
760c79c73f6SBlue Swirl         new_msr |= (target_ulong)1 << MSR_LE;
761c79c73f6SBlue Swirl     }
7621e0c7e55SAnton Blanchard #endif
763c79c73f6SBlue Swirl 
764c79c73f6SBlue Swirl     /* Jump to handler */
765c79c73f6SBlue Swirl     vector = env->excp_vectors[excp];
766c79c73f6SBlue Swirl     if (vector == (target_ulong)-1ULL) {
767a47dddd7SAndreas Färber         cpu_abort(cs, "Raised an exception without defined vector %d\n",
768c79c73f6SBlue Swirl                   excp);
769c79c73f6SBlue Swirl     }
770c79c73f6SBlue Swirl     vector |= env->excp_prefix;
7715c94b2a5SCédric Le Goater 
77247733729SDavid Gibson     /*
77347733729SDavid Gibson      * AIL only works if there is no HV transition and we are running
77447733729SDavid Gibson      * with translations enabled
7755c94b2a5SCédric Le Goater      */
7766d49d6d4SBenjamin Herrenschmidt     if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) ||
7776d49d6d4SBenjamin Herrenschmidt         ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) {
7785c94b2a5SCédric Le Goater         ail = 0;
7795c94b2a5SCédric Le Goater     }
7805c94b2a5SCédric Le Goater     /* Handle AIL */
7815c94b2a5SCédric Le Goater     if (ail) {
7825c94b2a5SCédric Le Goater         new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
7832586a4d7SFabiano Rosas         vector |= ppc_excp_vector_offset(cs, ail);
7845c94b2a5SCédric Le Goater     }
7855c94b2a5SCédric Le Goater 
786c79c73f6SBlue Swirl #if defined(TARGET_PPC64)
787c79c73f6SBlue Swirl     if (excp_model == POWERPC_EXCP_BOOKE) {
788e42a61f1SAlexander Graf         if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
789e42a61f1SAlexander Graf             /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
790c79c73f6SBlue Swirl             new_msr |= (target_ulong)1 << MSR_CM;
791e42a61f1SAlexander Graf         } else {
792e42a61f1SAlexander Graf             vector = (uint32_t)vector;
793c79c73f6SBlue Swirl         }
794c79c73f6SBlue Swirl     } else {
795c79c73f6SBlue Swirl         if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
796c79c73f6SBlue Swirl             vector = (uint32_t)vector;
797c79c73f6SBlue Swirl         } else {
798c79c73f6SBlue Swirl             new_msr |= (target_ulong)1 << MSR_SF;
799c79c73f6SBlue Swirl         }
800c79c73f6SBlue Swirl     }
801c79c73f6SBlue Swirl #endif
802cd0c6f47SBenjamin Herrenschmidt 
803*ad77c6caSNicholas Piggin     powerpc_set_excp_state(cpu, vector, new_msr);
804c79c73f6SBlue Swirl }
805c79c73f6SBlue Swirl 
80697a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs)
807c79c73f6SBlue Swirl {
80897a8ea5aSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(cs);
80997a8ea5aSAndreas Färber     CPUPPCState *env = &cpu->env;
8105c26a5b3SAndreas Färber 
81127103424SAndreas Färber     powerpc_excp(cpu, env->excp_model, cs->exception_index);
812c79c73f6SBlue Swirl }
813c79c73f6SBlue Swirl 
814458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env)
815c79c73f6SBlue Swirl {
816db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
8173621e2c9SBenjamin Herrenschmidt     bool async_deliver;
818259186a7SAndreas Färber 
819c79c73f6SBlue Swirl     /* External reset */
820c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
821c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
8225c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
823c79c73f6SBlue Swirl         return;
824c79c73f6SBlue Swirl     }
825c79c73f6SBlue Swirl     /* Machine check exception */
826c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
827c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
8285c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
829c79c73f6SBlue Swirl         return;
830c79c73f6SBlue Swirl     }
831c79c73f6SBlue Swirl #if 0 /* TODO */
832c79c73f6SBlue Swirl     /* External debug exception */
833c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
834c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
8355c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
836c79c73f6SBlue Swirl         return;
837c79c73f6SBlue Swirl     }
838c79c73f6SBlue Swirl #endif
8393621e2c9SBenjamin Herrenschmidt 
8403621e2c9SBenjamin Herrenschmidt     /*
8413621e2c9SBenjamin Herrenschmidt      * For interrupts that gate on MSR:EE, we need to do something a
8423621e2c9SBenjamin Herrenschmidt      * bit more subtle, as we need to let them through even when EE is
8433621e2c9SBenjamin Herrenschmidt      * clear when coming out of some power management states (in order
8443621e2c9SBenjamin Herrenschmidt      * for them to become a 0x100).
8453621e2c9SBenjamin Herrenschmidt      */
8461e7fd61dSBenjamin Herrenschmidt     async_deliver = (msr_ee != 0) || env->resume_as_sreset;
8473621e2c9SBenjamin Herrenschmidt 
848c79c73f6SBlue Swirl     /* Hypervisor decrementer exception */
849c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
8504b236b62SBenjamin Herrenschmidt         /* LPCR will be clear when not supported so this will work */
8514b236b62SBenjamin Herrenschmidt         bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
8523621e2c9SBenjamin Herrenschmidt         if ((async_deliver || msr_hv == 0) && hdice) {
8534b236b62SBenjamin Herrenschmidt             /* HDEC clears on delivery */
8544b236b62SBenjamin Herrenschmidt             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
8555c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
856c79c73f6SBlue Swirl             return;
857c79c73f6SBlue Swirl         }
858c79c73f6SBlue Swirl     }
859d8ce5fd6SBenjamin Herrenschmidt 
860d8ce5fd6SBenjamin Herrenschmidt     /* Hypervisor virtualization interrupt */
861d8ce5fd6SBenjamin Herrenschmidt     if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) {
862d8ce5fd6SBenjamin Herrenschmidt         /* LPCR will be clear when not supported so this will work */
863d8ce5fd6SBenjamin Herrenschmidt         bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
864d8ce5fd6SBenjamin Herrenschmidt         if ((async_deliver || msr_hv == 0) && hvice) {
865d8ce5fd6SBenjamin Herrenschmidt             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT);
866d8ce5fd6SBenjamin Herrenschmidt             return;
867d8ce5fd6SBenjamin Herrenschmidt         }
868d8ce5fd6SBenjamin Herrenschmidt     }
869d8ce5fd6SBenjamin Herrenschmidt 
870d8ce5fd6SBenjamin Herrenschmidt     /* External interrupt can ignore MSR:EE under some circumstances */
871d1dbe37cSBenjamin Herrenschmidt     if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
872d1dbe37cSBenjamin Herrenschmidt         bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
8736eebe6dcSBenjamin Herrenschmidt         bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
8746eebe6dcSBenjamin Herrenschmidt         /* HEIC blocks delivery to the hypervisor */
8756eebe6dcSBenjamin Herrenschmidt         if ((async_deliver && !(heic && msr_hv && !msr_pr)) ||
8766eebe6dcSBenjamin Herrenschmidt             (env->has_hv_mode && msr_hv == 0 && !lpes0)) {
877d1dbe37cSBenjamin Herrenschmidt             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
878d1dbe37cSBenjamin Herrenschmidt             return;
879d1dbe37cSBenjamin Herrenschmidt         }
880d1dbe37cSBenjamin Herrenschmidt     }
881c79c73f6SBlue Swirl     if (msr_ce != 0) {
882c79c73f6SBlue Swirl         /* External critical interrupt */
883c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
8845c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
885c79c73f6SBlue Swirl             return;
886c79c73f6SBlue Swirl         }
887c79c73f6SBlue Swirl     }
8883621e2c9SBenjamin Herrenschmidt     if (async_deliver != 0) {
889c79c73f6SBlue Swirl         /* Watchdog timer on embedded PowerPC */
890c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
891c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
8925c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
893c79c73f6SBlue Swirl             return;
894c79c73f6SBlue Swirl         }
895c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
896c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
8975c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
898c79c73f6SBlue Swirl             return;
899c79c73f6SBlue Swirl         }
900c79c73f6SBlue Swirl         /* Fixed interval timer on embedded PowerPC */
901c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
902c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
9035c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
904c79c73f6SBlue Swirl             return;
905c79c73f6SBlue Swirl         }
906c79c73f6SBlue Swirl         /* Programmable interval timer on embedded PowerPC */
907c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
908c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
9095c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
910c79c73f6SBlue Swirl             return;
911c79c73f6SBlue Swirl         }
912c79c73f6SBlue Swirl         /* Decrementer exception */
913c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
914e81a982aSAlexander Graf             if (ppc_decr_clear_on_delivery(env)) {
915c79c73f6SBlue Swirl                 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
916e81a982aSAlexander Graf             }
9175c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
918c79c73f6SBlue Swirl             return;
919c79c73f6SBlue Swirl         }
920c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
921c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
9225ba7ba1dSCédric Le Goater             if (is_book3s_arch2x(env)) {
9235ba7ba1dSCédric Le Goater                 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR);
9245ba7ba1dSCédric Le Goater             } else {
9255c26a5b3SAndreas Färber                 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
9265ba7ba1dSCédric Le Goater             }
927c79c73f6SBlue Swirl             return;
928c79c73f6SBlue Swirl         }
9297af1e7b0SCédric Le Goater         if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) {
9307af1e7b0SCédric Le Goater             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
9317af1e7b0SCédric Le Goater             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV);
9327af1e7b0SCédric Le Goater             return;
9337af1e7b0SCédric Le Goater         }
934c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
935c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
9365c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
937c79c73f6SBlue Swirl             return;
938c79c73f6SBlue Swirl         }
939c79c73f6SBlue Swirl         /* Thermal interrupt */
940c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
941c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
9425c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
943c79c73f6SBlue Swirl             return;
944c79c73f6SBlue Swirl         }
945c79c73f6SBlue Swirl     }
946f8154fd2SBenjamin Herrenschmidt 
947f8154fd2SBenjamin Herrenschmidt     if (env->resume_as_sreset) {
948f8154fd2SBenjamin Herrenschmidt         /*
949f8154fd2SBenjamin Herrenschmidt          * This is a bug ! It means that has_work took us out of halt without
950f8154fd2SBenjamin Herrenschmidt          * anything to deliver while in a PM state that requires getting
951f8154fd2SBenjamin Herrenschmidt          * out via a 0x100
952f8154fd2SBenjamin Herrenschmidt          *
953f8154fd2SBenjamin Herrenschmidt          * This means we will incorrectly execute past the power management
954f8154fd2SBenjamin Herrenschmidt          * instruction instead of triggering a reset.
955f8154fd2SBenjamin Herrenschmidt          *
956f8154fd2SBenjamin Herrenschmidt          * It generally means a discrepancy between the wakup conditions in the
957f8154fd2SBenjamin Herrenschmidt          * processor has_work implementation and the logic in this function.
958f8154fd2SBenjamin Herrenschmidt          */
959db70b311SRichard Henderson         cpu_abort(env_cpu(env),
960f8154fd2SBenjamin Herrenschmidt                   "Wakeup from PM state but interrupt Undelivered");
961f8154fd2SBenjamin Herrenschmidt     }
962c79c73f6SBlue Swirl }
96334316482SAlexey Kardashevskiy 
96434316482SAlexey Kardashevskiy void ppc_cpu_do_system_reset(CPUState *cs)
96534316482SAlexey Kardashevskiy {
96634316482SAlexey Kardashevskiy     PowerPCCPU *cpu = POWERPC_CPU(cs);
96734316482SAlexey Kardashevskiy     CPUPPCState *env = &cpu->env;
96834316482SAlexey Kardashevskiy 
96934316482SAlexey Kardashevskiy     powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
97034316482SAlexey Kardashevskiy }
971*ad77c6caSNicholas Piggin 
972*ad77c6caSNicholas Piggin void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
973*ad77c6caSNicholas Piggin {
974*ad77c6caSNicholas Piggin     PowerPCCPU *cpu = POWERPC_CPU(cs);
975*ad77c6caSNicholas Piggin     CPUPPCState *env = &cpu->env;
976*ad77c6caSNicholas Piggin     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
977*ad77c6caSNicholas Piggin     target_ulong msr = 0;
978*ad77c6caSNicholas Piggin 
979*ad77c6caSNicholas Piggin     /*
980*ad77c6caSNicholas Piggin      * Set MSR and NIP for the handler, SRR0/1, DAR and DSISR have already
981*ad77c6caSNicholas Piggin      * been set by KVM.
982*ad77c6caSNicholas Piggin      */
983*ad77c6caSNicholas Piggin     msr = (1ULL << MSR_ME);
984*ad77c6caSNicholas Piggin     msr |= env->msr & (1ULL << MSR_SF);
985*ad77c6caSNicholas Piggin     if (!(*pcc->interrupts_big_endian)(cpu)) {
986*ad77c6caSNicholas Piggin         msr |= (1ULL << MSR_LE);
987*ad77c6caSNicholas Piggin     }
988*ad77c6caSNicholas Piggin 
989*ad77c6caSNicholas Piggin     powerpc_set_excp_state(cpu, vector, msr);
990*ad77c6caSNicholas Piggin }
991c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */
992c79c73f6SBlue Swirl 
993458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
994458dd766SRichard Henderson {
995458dd766SRichard Henderson     PowerPCCPU *cpu = POWERPC_CPU(cs);
996458dd766SRichard Henderson     CPUPPCState *env = &cpu->env;
997458dd766SRichard Henderson 
998458dd766SRichard Henderson     if (interrupt_request & CPU_INTERRUPT_HARD) {
999458dd766SRichard Henderson         ppc_hw_interrupt(env);
1000458dd766SRichard Henderson         if (env->pending_interrupts == 0) {
1001458dd766SRichard Henderson             cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
1002458dd766SRichard Henderson         }
1003458dd766SRichard Henderson         return true;
1004458dd766SRichard Henderson     }
1005458dd766SRichard Henderson     return false;
1006458dd766SRichard Henderson }
1007458dd766SRichard Henderson 
1008c79c73f6SBlue Swirl #if defined(DEBUG_OP)
1009c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
1010c79c73f6SBlue Swirl {
1011c79c73f6SBlue Swirl     qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
1012c79c73f6SBlue Swirl              TARGET_FMT_lx "\n", RA, msr);
1013c79c73f6SBlue Swirl }
1014c79c73f6SBlue Swirl #endif
1015c79c73f6SBlue Swirl 
1016ad71ed68SBlue Swirl /*****************************************************************************/
1017ad71ed68SBlue Swirl /* Exceptions processing helpers */
1018ad71ed68SBlue Swirl 
1019db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
1020db789c6cSBenjamin Herrenschmidt                             uint32_t error_code, uintptr_t raddr)
1021ad71ed68SBlue Swirl {
1022db70b311SRichard Henderson     CPUState *cs = env_cpu(env);
102327103424SAndreas Färber 
102427103424SAndreas Färber     cs->exception_index = exception;
1025ad71ed68SBlue Swirl     env->error_code = error_code;
1026db789c6cSBenjamin Herrenschmidt     cpu_loop_exit_restore(cs, raddr);
1027db789c6cSBenjamin Herrenschmidt }
1028db789c6cSBenjamin Herrenschmidt 
1029db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception,
1030db789c6cSBenjamin Herrenschmidt                          uint32_t error_code)
1031db789c6cSBenjamin Herrenschmidt {
1032db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, error_code, 0);
1033db789c6cSBenjamin Herrenschmidt }
1034db789c6cSBenjamin Herrenschmidt 
1035db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception)
1036db789c6cSBenjamin Herrenschmidt {
1037db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, 0);
1038db789c6cSBenjamin Herrenschmidt }
1039db789c6cSBenjamin Herrenschmidt 
1040db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception,
1041db789c6cSBenjamin Herrenschmidt                         uintptr_t raddr)
1042db789c6cSBenjamin Herrenschmidt {
1043db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, raddr);
1044db789c6cSBenjamin Herrenschmidt }
1045db789c6cSBenjamin Herrenschmidt 
1046db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
1047db789c6cSBenjamin Herrenschmidt                                 uint32_t error_code)
1048db789c6cSBenjamin Herrenschmidt {
1049db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, error_code, 0);
1050ad71ed68SBlue Swirl }
1051ad71ed68SBlue Swirl 
1052e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception)
1053ad71ed68SBlue Swirl {
1054db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, 0);
1055ad71ed68SBlue Swirl }
1056ad71ed68SBlue Swirl 
1057ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1058e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val)
1059ad71ed68SBlue Swirl {
1060db789c6cSBenjamin Herrenschmidt     uint32_t excp = hreg_store_msr(env, val, 0);
1061259186a7SAndreas Färber 
1062db789c6cSBenjamin Herrenschmidt     if (excp != 0) {
1063db70b311SRichard Henderson         CPUState *cs = env_cpu(env);
1064044897efSRichard Purdie         cpu_interrupt_exittb(cs);
1065db789c6cSBenjamin Herrenschmidt         raise_exception(env, excp);
1066ad71ed68SBlue Swirl     }
1067ad71ed68SBlue Swirl }
1068ad71ed68SBlue Swirl 
10697778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64)
10707778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
10717778a575SBenjamin Herrenschmidt {
10727778a575SBenjamin Herrenschmidt     CPUState *cs;
10737778a575SBenjamin Herrenschmidt 
1074db70b311SRichard Henderson     cs = env_cpu(env);
10757778a575SBenjamin Herrenschmidt     cs->halted = 1;
10767778a575SBenjamin Herrenschmidt 
107747733729SDavid Gibson     /*
107847733729SDavid Gibson      * The architecture specifies that HDEC interrupts are discarded
107947733729SDavid Gibson      * in PM states
10804b236b62SBenjamin Herrenschmidt      */
10814b236b62SBenjamin Herrenschmidt     env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
10824b236b62SBenjamin Herrenschmidt 
10833621e2c9SBenjamin Herrenschmidt     /* Condition for waking up at 0x100 */
10841e7fd61dSBenjamin Herrenschmidt     env->resume_as_sreset = (insn != PPC_PM_STOP) ||
108521c0d66aSBenjamin Herrenschmidt         (env->spr[SPR_PSSCR] & PSSCR_EC);
10867778a575SBenjamin Herrenschmidt }
10877778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */
10887778a575SBenjamin Herrenschmidt 
1089a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
1090ad71ed68SBlue Swirl {
1091db70b311SRichard Henderson     CPUState *cs = env_cpu(env);
1092259186a7SAndreas Färber 
1093a2e71b28SBenjamin Herrenschmidt     /* MSR:POW cannot be set by any form of rfi */
1094a2e71b28SBenjamin Herrenschmidt     msr &= ~(1ULL << MSR_POW);
1095a2e71b28SBenjamin Herrenschmidt 
1096ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1097a2e71b28SBenjamin Herrenschmidt     /* Switching to 32-bit ? Crop the nip */
1098a2e71b28SBenjamin Herrenschmidt     if (!msr_is_64bit(env, msr)) {
1099ad71ed68SBlue Swirl         nip = (uint32_t)nip;
1100ad71ed68SBlue Swirl     }
1101ad71ed68SBlue Swirl #else
1102ad71ed68SBlue Swirl     nip = (uint32_t)nip;
1103ad71ed68SBlue Swirl #endif
1104ad71ed68SBlue Swirl     /* XXX: beware: this is false if VLE is supported */
1105ad71ed68SBlue Swirl     env->nip = nip & ~((target_ulong)0x00000003);
1106ad71ed68SBlue Swirl     hreg_store_msr(env, msr, 1);
1107ad71ed68SBlue Swirl #if defined(DEBUG_OP)
1108ad71ed68SBlue Swirl     cpu_dump_rfi(env->nip, env->msr);
1109ad71ed68SBlue Swirl #endif
111047733729SDavid Gibson     /*
111147733729SDavid Gibson      * No need to raise an exception here, as rfi is always the last
111247733729SDavid Gibson      * insn of a TB
1113ad71ed68SBlue Swirl      */
1114044897efSRichard Purdie     cpu_interrupt_exittb(cs);
1115a8b73734SNikunj A Dadhania     /* Reset the reservation */
1116a8b73734SNikunj A Dadhania     env->reserve_addr = -1;
1117a8b73734SNikunj A Dadhania 
1118cd0c6f47SBenjamin Herrenschmidt     /* Context synchronizing: check if TCG TLB needs flush */
1119e3cffe6fSNikunj A Dadhania     check_tlb_flush(env, false);
1120ad71ed68SBlue Swirl }
1121ad71ed68SBlue Swirl 
1122e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env)
1123ad71ed68SBlue Swirl {
1124a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful);
1125a1bb7384SScott Wood }
1126ad71ed68SBlue Swirl 
1127a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK
1128ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1129e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env)
1130ad71ed68SBlue Swirl {
113147733729SDavid Gibson     /*
113247733729SDavid Gibson      * The architeture defines a number of rules for which bits can
113347733729SDavid Gibson      * change but in practice, we handle this in hreg_store_msr()
1134a2e71b28SBenjamin Herrenschmidt      * which will be called by do_rfi(), so there is no need to filter
1135a2e71b28SBenjamin Herrenschmidt      * here
1136a2e71b28SBenjamin Herrenschmidt      */
1137a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
1138ad71ed68SBlue Swirl }
1139ad71ed68SBlue Swirl 
1140e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env)
1141ad71ed68SBlue Swirl {
1142a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
1143ad71ed68SBlue Swirl }
1144ad71ed68SBlue Swirl #endif
1145ad71ed68SBlue Swirl 
1146ad71ed68SBlue Swirl /*****************************************************************************/
1147ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */
1148e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env)
1149ad71ed68SBlue Swirl {
1150a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]);
1151ad71ed68SBlue Swirl }
1152ad71ed68SBlue Swirl 
1153e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env)
1154ad71ed68SBlue Swirl {
1155a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]);
1156ad71ed68SBlue Swirl }
1157ad71ed68SBlue Swirl 
1158e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env)
1159ad71ed68SBlue Swirl {
1160a1bb7384SScott Wood     /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
1161a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]);
1162ad71ed68SBlue Swirl }
1163ad71ed68SBlue Swirl 
1164e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env)
1165ad71ed68SBlue Swirl {
1166a1bb7384SScott Wood     /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
1167a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]);
1168ad71ed68SBlue Swirl }
1169ad71ed68SBlue Swirl #endif
1170ad71ed68SBlue Swirl 
1171e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1172e5f17ac6SBlue Swirl                uint32_t flags)
1173ad71ed68SBlue Swirl {
1174ad71ed68SBlue Swirl     if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1175ad71ed68SBlue Swirl                   ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1176ad71ed68SBlue Swirl                   ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1177ad71ed68SBlue Swirl                   ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1178ad71ed68SBlue Swirl                   ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
117972073dccSBenjamin Herrenschmidt         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
118072073dccSBenjamin Herrenschmidt                                POWERPC_EXCP_TRAP, GETPC());
1181ad71ed68SBlue Swirl     }
1182ad71ed68SBlue Swirl }
1183ad71ed68SBlue Swirl 
1184ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1185e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1186e5f17ac6SBlue Swirl                uint32_t flags)
1187ad71ed68SBlue Swirl {
1188ad71ed68SBlue Swirl     if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1189ad71ed68SBlue Swirl                   ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1190ad71ed68SBlue Swirl                   ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1191ad71ed68SBlue Swirl                   ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1192ad71ed68SBlue Swirl                   ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
119372073dccSBenjamin Herrenschmidt         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
119472073dccSBenjamin Herrenschmidt                                POWERPC_EXCP_TRAP, GETPC());
1195ad71ed68SBlue Swirl     }
1196ad71ed68SBlue Swirl }
1197ad71ed68SBlue Swirl #endif
1198ad71ed68SBlue Swirl 
1199ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1200ad71ed68SBlue Swirl /*****************************************************************************/
1201ad71ed68SBlue Swirl /* PowerPC 601 specific instructions (POWER bridge) */
1202ad71ed68SBlue Swirl 
1203e5f17ac6SBlue Swirl void helper_rfsvc(CPUPPCState *env)
1204ad71ed68SBlue Swirl {
1205a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->lr, env->ctr & 0x0000FFFF);
1206ad71ed68SBlue Swirl }
1207ad71ed68SBlue Swirl 
1208ad71ed68SBlue Swirl /* Embedded.Processor Control */
1209ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb)
1210ad71ed68SBlue Swirl {
1211ad71ed68SBlue Swirl     int msg = rb & DBELL_TYPE_MASK;
1212ad71ed68SBlue Swirl     int irq = -1;
1213ad71ed68SBlue Swirl 
1214ad71ed68SBlue Swirl     switch (msg) {
1215ad71ed68SBlue Swirl     case DBELL_TYPE_DBELL:
1216ad71ed68SBlue Swirl         irq = PPC_INTERRUPT_DOORBELL;
1217ad71ed68SBlue Swirl         break;
1218ad71ed68SBlue Swirl     case DBELL_TYPE_DBELL_CRIT:
1219ad71ed68SBlue Swirl         irq = PPC_INTERRUPT_CDOORBELL;
1220ad71ed68SBlue Swirl         break;
1221ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL:
1222ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL_CRIT:
1223ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL_MC:
1224ad71ed68SBlue Swirl         /* XXX implement */
1225ad71ed68SBlue Swirl     default:
1226ad71ed68SBlue Swirl         break;
1227ad71ed68SBlue Swirl     }
1228ad71ed68SBlue Swirl 
1229ad71ed68SBlue Swirl     return irq;
1230ad71ed68SBlue Swirl }
1231ad71ed68SBlue Swirl 
1232e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb)
1233ad71ed68SBlue Swirl {
1234ad71ed68SBlue Swirl     int irq = dbell2irq(rb);
1235ad71ed68SBlue Swirl 
1236ad71ed68SBlue Swirl     if (irq < 0) {
1237ad71ed68SBlue Swirl         return;
1238ad71ed68SBlue Swirl     }
1239ad71ed68SBlue Swirl 
1240ad71ed68SBlue Swirl     env->pending_interrupts &= ~(1 << irq);
1241ad71ed68SBlue Swirl }
1242ad71ed68SBlue Swirl 
1243ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb)
1244ad71ed68SBlue Swirl {
1245ad71ed68SBlue Swirl     int irq = dbell2irq(rb);
1246ad71ed68SBlue Swirl     int pir = rb & DBELL_PIRTAG_MASK;
1247182735efSAndreas Färber     CPUState *cs;
1248ad71ed68SBlue Swirl 
1249ad71ed68SBlue Swirl     if (irq < 0) {
1250ad71ed68SBlue Swirl         return;
1251ad71ed68SBlue Swirl     }
1252ad71ed68SBlue Swirl 
1253f1c29ebcSThomas Huth     qemu_mutex_lock_iothread();
1254bdc44640SAndreas Färber     CPU_FOREACH(cs) {
1255182735efSAndreas Färber         PowerPCCPU *cpu = POWERPC_CPU(cs);
1256182735efSAndreas Färber         CPUPPCState *cenv = &cpu->env;
1257182735efSAndreas Färber 
1258ad71ed68SBlue Swirl         if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
1259ad71ed68SBlue Swirl             cenv->pending_interrupts |= 1 << irq;
1260182735efSAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
1261ad71ed68SBlue Swirl         }
1262ad71ed68SBlue Swirl     }
1263f1c29ebcSThomas Huth     qemu_mutex_unlock_iothread();
1264ad71ed68SBlue Swirl }
12657af1e7b0SCédric Le Goater 
12667af1e7b0SCédric Le Goater /* Server Processor Control */
12677af1e7b0SCédric Le Goater 
12685ba7ba1dSCédric Le Goater static bool dbell_type_server(target_ulong rb)
12695ba7ba1dSCédric Le Goater {
127047733729SDavid Gibson     /*
127147733729SDavid Gibson      * A Directed Hypervisor Doorbell message is sent only if the
12727af1e7b0SCédric Le Goater      * message type is 5. All other types are reserved and the
127347733729SDavid Gibson      * instruction is a no-op
127447733729SDavid Gibson      */
12755ba7ba1dSCédric Le Goater     return (rb & DBELL_TYPE_MASK) == DBELL_TYPE_DBELL_SERVER;
12767af1e7b0SCédric Le Goater }
12777af1e7b0SCédric Le Goater 
12787af1e7b0SCédric Le Goater void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
12797af1e7b0SCédric Le Goater {
12805ba7ba1dSCédric Le Goater     if (!dbell_type_server(rb)) {
12817af1e7b0SCédric Le Goater         return;
12827af1e7b0SCédric Le Goater     }
12837af1e7b0SCédric Le Goater 
12845ba7ba1dSCédric Le Goater     env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
12857af1e7b0SCédric Le Goater }
12867af1e7b0SCédric Le Goater 
12875ba7ba1dSCédric Le Goater static void book3s_msgsnd_common(int pir, int irq)
12887af1e7b0SCédric Le Goater {
12897af1e7b0SCédric Le Goater     CPUState *cs;
12907af1e7b0SCédric Le Goater 
12917af1e7b0SCédric Le Goater     qemu_mutex_lock_iothread();
12927af1e7b0SCédric Le Goater     CPU_FOREACH(cs) {
12937af1e7b0SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
12947af1e7b0SCédric Le Goater         CPUPPCState *cenv = &cpu->env;
12957af1e7b0SCédric Le Goater 
12967af1e7b0SCédric Le Goater         /* TODO: broadcast message to all threads of the same  processor */
12977af1e7b0SCédric Le Goater         if (cenv->spr_cb[SPR_PIR].default_value == pir) {
12987af1e7b0SCédric Le Goater             cenv->pending_interrupts |= 1 << irq;
12997af1e7b0SCédric Le Goater             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
13007af1e7b0SCédric Le Goater         }
13017af1e7b0SCédric Le Goater     }
13027af1e7b0SCédric Le Goater     qemu_mutex_unlock_iothread();
13037af1e7b0SCédric Le Goater }
13045ba7ba1dSCédric Le Goater 
13055ba7ba1dSCédric Le Goater void helper_book3s_msgsnd(target_ulong rb)
13065ba7ba1dSCédric Le Goater {
13075ba7ba1dSCédric Le Goater     int pir = rb & DBELL_PROCIDTAG_MASK;
13085ba7ba1dSCédric Le Goater 
13095ba7ba1dSCédric Le Goater     if (!dbell_type_server(rb)) {
13105ba7ba1dSCédric Le Goater         return;
13115ba7ba1dSCédric Le Goater     }
13125ba7ba1dSCédric Le Goater 
13135ba7ba1dSCédric Le Goater     book3s_msgsnd_common(pir, PPC_INTERRUPT_HDOORBELL);
13145ba7ba1dSCédric Le Goater }
13155ba7ba1dSCédric Le Goater 
13165ba7ba1dSCédric Le Goater #if defined(TARGET_PPC64)
13175ba7ba1dSCédric Le Goater void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb)
13185ba7ba1dSCédric Le Goater {
1319493028d8SCédric Le Goater     helper_hfscr_facility_check(env, HFSCR_MSGP, "msgclrp", HFSCR_IC_MSGP);
1320493028d8SCédric Le Goater 
13215ba7ba1dSCédric Le Goater     if (!dbell_type_server(rb)) {
13225ba7ba1dSCédric Le Goater         return;
13235ba7ba1dSCédric Le Goater     }
13245ba7ba1dSCédric Le Goater 
13255ba7ba1dSCédric Le Goater     env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
13265ba7ba1dSCédric Le Goater }
13275ba7ba1dSCédric Le Goater 
13285ba7ba1dSCédric Le Goater /*
13295ba7ba1dSCédric Le Goater  * sends a message to other threads that are on the same
13305ba7ba1dSCédric Le Goater  * multi-threaded processor
13315ba7ba1dSCédric Le Goater  */
13325ba7ba1dSCédric Le Goater void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb)
13335ba7ba1dSCédric Le Goater {
13345ba7ba1dSCédric Le Goater     int pir = env->spr_cb[SPR_PIR].default_value;
13355ba7ba1dSCédric Le Goater 
1336493028d8SCédric Le Goater     helper_hfscr_facility_check(env, HFSCR_MSGP, "msgsndp", HFSCR_IC_MSGP);
1337493028d8SCédric Le Goater 
13385ba7ba1dSCédric Le Goater     if (!dbell_type_server(rb)) {
13395ba7ba1dSCédric Le Goater         return;
13405ba7ba1dSCédric Le Goater     }
13415ba7ba1dSCédric Le Goater 
13425ba7ba1dSCédric Le Goater     /* TODO: TCG supports only one thread */
13435ba7ba1dSCédric Le Goater 
13445ba7ba1dSCédric Le Goater     book3s_msgsnd_common(pir, PPC_INTERRUPT_DOORBELL);
13455ba7ba1dSCédric Le Goater }
13465ba7ba1dSCédric Le Goater #endif
1347ad71ed68SBlue Swirl #endif
13480f3110faSRichard Henderson 
13490f3110faSRichard Henderson void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
13500f3110faSRichard Henderson                                  MMUAccessType access_type,
13510f3110faSRichard Henderson                                  int mmu_idx, uintptr_t retaddr)
13520f3110faSRichard Henderson {
13530f3110faSRichard Henderson     CPUPPCState *env = cs->env_ptr;
13540f3110faSRichard Henderson     uint32_t insn;
13550f3110faSRichard Henderson 
13560f3110faSRichard Henderson     /* Restore state and reload the insn we executed, for filling in DSISR.  */
13570f3110faSRichard Henderson     cpu_restore_state(cs, retaddr, true);
13580f3110faSRichard Henderson     insn = cpu_ldl_code(env, env->nip);
13590f3110faSRichard Henderson 
13600f3110faSRichard Henderson     cs->exception_index = POWERPC_EXCP_ALIGN;
13610f3110faSRichard Henderson     env->error_code = insn & 0x03FF0000;
13620f3110faSRichard Henderson     cpu_loop_exit(cs);
13630f3110faSRichard Henderson }
1364