xref: /qemu/target/ppc/excp_helper.c (revision db70b31144d28a40838f8916a7c02adcdf5d8dcd)
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 {
52*db70b311SRichard 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) {
1152586a4d7SFabiano Rosas     case AIL_0001_8000:
1162586a4d7SFabiano Rosas         offset = 0x18000;
1172586a4d7SFabiano Rosas         break;
1182586a4d7SFabiano Rosas     case AIL_C000_0000_0000_4000:
1192586a4d7SFabiano Rosas         offset = 0xc000000000004000ull;
1202586a4d7SFabiano Rosas         break;
1212586a4d7SFabiano Rosas     default:
1222586a4d7SFabiano Rosas         cpu_abort(cs, "Invalid AIL combination %d\n", ail);
1232586a4d7SFabiano Rosas         break;
1242586a4d7SFabiano Rosas     }
1252586a4d7SFabiano Rosas 
1262586a4d7SFabiano Rosas     return offset;
1272586a4d7SFabiano Rosas }
128dead760bSBenjamin Herrenschmidt 
12947733729SDavid Gibson /*
13047733729SDavid Gibson  * Note that this function should be greatly optimized when called
13147733729SDavid Gibson  * with a constant excp, from ppc_hw_interrupt
132c79c73f6SBlue Swirl  */
1335c26a5b3SAndreas Färber static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
134c79c73f6SBlue Swirl {
13527103424SAndreas Färber     CPUState *cs = CPU(cpu);
1365c26a5b3SAndreas Färber     CPUPPCState *env = &cpu->env;
137c79c73f6SBlue Swirl     target_ulong msr, new_msr, vector;
1386d49d6d4SBenjamin Herrenschmidt     int srr0, srr1, asrr0, asrr1, lev, ail;
1396d49d6d4SBenjamin Herrenschmidt     bool lpes0;
140c79c73f6SBlue Swirl 
141c79c73f6SBlue Swirl     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
142c79c73f6SBlue Swirl                   " => %08x (%02x)\n", env->nip, excp, env->error_code);
143c79c73f6SBlue Swirl 
144c79c73f6SBlue Swirl     /* new srr1 value excluding must-be-zero bits */
145a1bb7384SScott Wood     if (excp_model == POWERPC_EXCP_BOOKE) {
146a1bb7384SScott Wood         msr = env->msr;
147a1bb7384SScott Wood     } else {
148c79c73f6SBlue Swirl         msr = env->msr & ~0x783f0000ULL;
149a1bb7384SScott Wood     }
150c79c73f6SBlue Swirl 
15147733729SDavid Gibson     /*
15247733729SDavid Gibson      * new interrupt handler msr preserves existing HV and ME unless
1536d49d6d4SBenjamin Herrenschmidt      * explicitly overriden
1546d49d6d4SBenjamin Herrenschmidt      */
1556d49d6d4SBenjamin Herrenschmidt     new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
156c79c73f6SBlue Swirl 
157c79c73f6SBlue Swirl     /* target registers */
158c79c73f6SBlue Swirl     srr0 = SPR_SRR0;
159c79c73f6SBlue Swirl     srr1 = SPR_SRR1;
160c79c73f6SBlue Swirl     asrr0 = -1;
161c79c73f6SBlue Swirl     asrr1 = -1;
162c79c73f6SBlue Swirl 
16321c0d66aSBenjamin Herrenschmidt     /*
16421c0d66aSBenjamin Herrenschmidt      * check for special resume at 0x100 from doze/nap/sleep/winkle on
16521c0d66aSBenjamin Herrenschmidt      * P7/P8/P9
16621c0d66aSBenjamin Herrenschmidt      */
1671e7fd61dSBenjamin Herrenschmidt     if (env->resume_as_sreset) {
168dead760bSBenjamin Herrenschmidt         excp = powerpc_reset_wakeup(cs, env, excp, &msr);
1697778a575SBenjamin Herrenschmidt     }
1707778a575SBenjamin Herrenschmidt 
17147733729SDavid Gibson     /*
17247733729SDavid Gibson      * Exception targetting modifiers
1735c94b2a5SCédric Le Goater      *
174a790e82bSBenjamin Herrenschmidt      * LPES0 is supported on POWER7/8/9
1756d49d6d4SBenjamin Herrenschmidt      * LPES1 is not supported (old iSeries mode)
1766d49d6d4SBenjamin Herrenschmidt      *
1776d49d6d4SBenjamin Herrenschmidt      * On anything else, we behave as if LPES0 is 1
1786d49d6d4SBenjamin Herrenschmidt      * (externals don't alter MSR:HV)
1796d49d6d4SBenjamin Herrenschmidt      *
1805c94b2a5SCédric Le Goater      * AIL is initialized here but can be cleared by
1815c94b2a5SCédric Le Goater      * selected exceptions
1825c94b2a5SCédric Le Goater      */
1835c94b2a5SCédric Le Goater #if defined(TARGET_PPC64)
1845c94b2a5SCédric Le Goater     if (excp_model == POWERPC_EXCP_POWER7 ||
185a790e82bSBenjamin Herrenschmidt         excp_model == POWERPC_EXCP_POWER8 ||
186a790e82bSBenjamin Herrenschmidt         excp_model == POWERPC_EXCP_POWER9) {
1876d49d6d4SBenjamin Herrenschmidt         lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
188a790e82bSBenjamin Herrenschmidt         if (excp_model != POWERPC_EXCP_POWER7) {
1895c94b2a5SCédric Le Goater             ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
1905c94b2a5SCédric Le Goater         } else {
1915c94b2a5SCédric Le Goater             ail = 0;
1925c94b2a5SCédric Le Goater         }
1935c94b2a5SCédric Le Goater     } else
1945c94b2a5SCédric Le Goater #endif /* defined(TARGET_PPC64) */
1955c94b2a5SCédric Le Goater     {
1966d49d6d4SBenjamin Herrenschmidt         lpes0 = true;
1975c94b2a5SCédric Le Goater         ail = 0;
1985c94b2a5SCédric Le Goater     }
1995c94b2a5SCédric Le Goater 
20047733729SDavid Gibson     /*
20147733729SDavid Gibson      * Hypervisor emulation assistance interrupt only exists on server
2029b2faddaSBenjamin Herrenschmidt      * arch 2.05 server or later. We also don't want to generate it if
2039b2faddaSBenjamin Herrenschmidt      * we don't have HVB in msr_mask (PAPR mode).
2049b2faddaSBenjamin Herrenschmidt      */
2059b2faddaSBenjamin Herrenschmidt     if (excp == POWERPC_EXCP_HV_EMU
2069b2faddaSBenjamin Herrenschmidt #if defined(TARGET_PPC64)
2079b2faddaSBenjamin Herrenschmidt         && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB))
2089b2faddaSBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */
2099b2faddaSBenjamin Herrenschmidt 
2109b2faddaSBenjamin Herrenschmidt     ) {
2119b2faddaSBenjamin Herrenschmidt         excp = POWERPC_EXCP_PROGRAM;
2129b2faddaSBenjamin Herrenschmidt     }
2139b2faddaSBenjamin Herrenschmidt 
214c79c73f6SBlue Swirl     switch (excp) {
215c79c73f6SBlue Swirl     case POWERPC_EXCP_NONE:
216c79c73f6SBlue Swirl         /* Should never happen */
217c79c73f6SBlue Swirl         return;
218c79c73f6SBlue Swirl     case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
219c79c73f6SBlue Swirl         switch (excp_model) {
220c79c73f6SBlue Swirl         case POWERPC_EXCP_40x:
221c79c73f6SBlue Swirl             srr0 = SPR_40x_SRR2;
222c79c73f6SBlue Swirl             srr1 = SPR_40x_SRR3;
223c79c73f6SBlue Swirl             break;
224c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
225c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_CSRR0;
226c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_CSRR1;
227c79c73f6SBlue Swirl             break;
228c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
229c79c73f6SBlue Swirl             break;
230c79c73f6SBlue Swirl         default:
231c79c73f6SBlue Swirl             goto excp_invalid;
232c79c73f6SBlue Swirl         }
233bd6fefe7SBenjamin Herrenschmidt         break;
234c79c73f6SBlue Swirl     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
235c79c73f6SBlue Swirl         if (msr_me == 0) {
23647733729SDavid Gibson             /*
23747733729SDavid Gibson              * Machine check exception is not enabled.  Enter
23847733729SDavid Gibson              * checkstop state.
239c79c73f6SBlue Swirl              */
240c79c73f6SBlue Swirl             fprintf(stderr, "Machine check while not allowed. "
241c79c73f6SBlue Swirl                     "Entering checkstop state\n");
242013a2942SPaolo Bonzini             if (qemu_log_separate()) {
243013a2942SPaolo Bonzini                 qemu_log("Machine check while not allowed. "
244013a2942SPaolo Bonzini                         "Entering checkstop state\n");
245c79c73f6SBlue Swirl             }
246259186a7SAndreas Färber             cs->halted = 1;
247044897efSRichard Purdie             cpu_interrupt_exittb(cs);
248c79c73f6SBlue Swirl         }
24910c21b5cSNicholas Piggin         if (env->msr_mask & MSR_HVB) {
25047733729SDavid Gibson             /*
25147733729SDavid Gibson              * ISA specifies HV, but can be delivered to guest with HV
25247733729SDavid Gibson              * clear (e.g., see FWNMI in PAPR).
25310c21b5cSNicholas Piggin              */
254c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
25510c21b5cSNicholas Piggin         }
2565c94b2a5SCédric Le Goater         ail = 0;
257c79c73f6SBlue Swirl 
258c79c73f6SBlue Swirl         /* machine check exceptions don't have ME set */
259c79c73f6SBlue Swirl         new_msr &= ~((target_ulong)1 << MSR_ME);
260c79c73f6SBlue Swirl 
261c79c73f6SBlue Swirl         /* XXX: should also have something loaded in DAR / DSISR */
262c79c73f6SBlue Swirl         switch (excp_model) {
263c79c73f6SBlue Swirl         case POWERPC_EXCP_40x:
264c79c73f6SBlue Swirl             srr0 = SPR_40x_SRR2;
265c79c73f6SBlue Swirl             srr1 = SPR_40x_SRR3;
266c79c73f6SBlue Swirl             break;
267c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
268a1bb7384SScott Wood             /* FIXME: choose one or the other based on CPU type */
269c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_MCSRR0;
270c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_MCSRR1;
271c79c73f6SBlue Swirl             asrr0 = SPR_BOOKE_CSRR0;
272c79c73f6SBlue Swirl             asrr1 = SPR_BOOKE_CSRR1;
273c79c73f6SBlue Swirl             break;
274c79c73f6SBlue Swirl         default:
275c79c73f6SBlue Swirl             break;
276c79c73f6SBlue Swirl         }
277bd6fefe7SBenjamin Herrenschmidt         break;
278c79c73f6SBlue Swirl     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
279c79c73f6SBlue Swirl         LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
280c79c73f6SBlue Swirl                  "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
281bd6fefe7SBenjamin Herrenschmidt         break;
282c79c73f6SBlue Swirl     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
283c79c73f6SBlue Swirl         LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
284c79c73f6SBlue Swirl                  "\n", msr, env->nip);
285c79c73f6SBlue Swirl         msr |= env->error_code;
286bd6fefe7SBenjamin Herrenschmidt         break;
287c79c73f6SBlue Swirl     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
288fdfba1a2SEdgar E. Iglesias         cs = CPU(cpu);
289fdfba1a2SEdgar E. Iglesias 
2906d49d6d4SBenjamin Herrenschmidt         if (!lpes0) {
291c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
2926d49d6d4SBenjamin Herrenschmidt             new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
2936d49d6d4SBenjamin Herrenschmidt             srr0 = SPR_HSRR0;
2946d49d6d4SBenjamin Herrenschmidt             srr1 = SPR_HSRR1;
295c79c73f6SBlue Swirl         }
29668c2dd70SAlexander Graf         if (env->mpic_proxy) {
29768c2dd70SAlexander Graf             /* IACK the IRQ on delivery */
298fdfba1a2SEdgar E. Iglesias             env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
29968c2dd70SAlexander Graf         }
300bd6fefe7SBenjamin Herrenschmidt         break;
301c79c73f6SBlue Swirl     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
302c79c73f6SBlue Swirl         /* Get rS/rD and rA from faulting opcode */
30347733729SDavid Gibson         /*
30447733729SDavid Gibson          * Note: the opcode fields will not be set properly for a
30547733729SDavid Gibson          * direct store load/store, but nobody cares as nobody
30647733729SDavid Gibson          * actually uses direct store segments.
3073433b732SBenjamin Herrenschmidt          */
3083433b732SBenjamin Herrenschmidt         env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
309bd6fefe7SBenjamin Herrenschmidt         break;
310c79c73f6SBlue Swirl     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
311c79c73f6SBlue Swirl         switch (env->error_code & ~0xF) {
312c79c73f6SBlue Swirl         case POWERPC_EXCP_FP:
313c79c73f6SBlue Swirl             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
314c79c73f6SBlue Swirl                 LOG_EXCP("Ignore floating point exception\n");
31527103424SAndreas Färber                 cs->exception_index = POWERPC_EXCP_NONE;
316c79c73f6SBlue Swirl                 env->error_code = 0;
317c79c73f6SBlue Swirl                 return;
318c79c73f6SBlue Swirl             }
3191b7d17caSBenjamin Herrenschmidt 
32047733729SDavid Gibson             /*
32147733729SDavid Gibson              * FP exceptions always have NIP pointing to the faulting
3221b7d17caSBenjamin Herrenschmidt              * instruction, so always use store_next and claim we are
3231b7d17caSBenjamin Herrenschmidt              * precise in the MSR.
3241b7d17caSBenjamin Herrenschmidt              */
325c79c73f6SBlue Swirl             msr |= 0x00100000;
3260ee604abSAaron Larson             env->spr[SPR_BOOKE_ESR] = ESR_FP;
327bd6fefe7SBenjamin Herrenschmidt             break;
328c79c73f6SBlue Swirl         case POWERPC_EXCP_INVAL:
329c79c73f6SBlue Swirl             LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
330c79c73f6SBlue Swirl             msr |= 0x00080000;
331c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PIL;
332c79c73f6SBlue Swirl             break;
333c79c73f6SBlue Swirl         case POWERPC_EXCP_PRIV:
334c79c73f6SBlue Swirl             msr |= 0x00040000;
335c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PPR;
336c79c73f6SBlue Swirl             break;
337c79c73f6SBlue Swirl         case POWERPC_EXCP_TRAP:
338c79c73f6SBlue Swirl             msr |= 0x00020000;
339c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PTR;
340c79c73f6SBlue Swirl             break;
341c79c73f6SBlue Swirl         default:
342c79c73f6SBlue Swirl             /* Should never occur */
343a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid program exception %d. Aborting\n",
344c79c73f6SBlue Swirl                       env->error_code);
345c79c73f6SBlue Swirl             break;
346c79c73f6SBlue Swirl         }
347bd6fefe7SBenjamin Herrenschmidt         break;
348c79c73f6SBlue Swirl     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
349c79c73f6SBlue Swirl         dump_syscall(env);
350c79c73f6SBlue Swirl         lev = env->error_code;
3516d49d6d4SBenjamin Herrenschmidt 
35247733729SDavid Gibson         /*
35347733729SDavid Gibson          * We need to correct the NIP which in this case is supposed
354bd6fefe7SBenjamin Herrenschmidt          * to point to the next instruction
355bd6fefe7SBenjamin Herrenschmidt          */
356bd6fefe7SBenjamin Herrenschmidt         env->nip += 4;
357bd6fefe7SBenjamin Herrenschmidt 
3586d49d6d4SBenjamin Herrenschmidt         /* "PAPR mode" built-in hypercall emulation */
3591d1be34dSDavid Gibson         if ((lev == 1) && cpu->vhyp) {
3601d1be34dSDavid Gibson             PPCVirtualHypervisorClass *vhc =
3611d1be34dSDavid Gibson                 PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
3621d1be34dSDavid Gibson             vhc->hypercall(cpu->vhyp, cpu);
363c79c73f6SBlue Swirl             return;
364c79c73f6SBlue Swirl         }
3656d49d6d4SBenjamin Herrenschmidt         if (lev == 1) {
366c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
367c79c73f6SBlue Swirl         }
368bd6fefe7SBenjamin Herrenschmidt         break;
369bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
370c79c73f6SBlue Swirl     case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
371c79c73f6SBlue Swirl     case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
372bd6fefe7SBenjamin Herrenschmidt         break;
373c79c73f6SBlue Swirl     case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
374c79c73f6SBlue Swirl         /* FIT on 4xx */
375c79c73f6SBlue Swirl         LOG_EXCP("FIT exception\n");
376bd6fefe7SBenjamin Herrenschmidt         break;
377c79c73f6SBlue Swirl     case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
378c79c73f6SBlue Swirl         LOG_EXCP("WDT exception\n");
379c79c73f6SBlue Swirl         switch (excp_model) {
380c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
381c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_CSRR0;
382c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_CSRR1;
383c79c73f6SBlue Swirl             break;
384c79c73f6SBlue Swirl         default:
385c79c73f6SBlue Swirl             break;
386c79c73f6SBlue Swirl         }
387bd6fefe7SBenjamin Herrenschmidt         break;
388c79c73f6SBlue Swirl     case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
389c79c73f6SBlue Swirl     case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
390bd6fefe7SBenjamin Herrenschmidt         break;
391c79c73f6SBlue Swirl     case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
3920e3bf489SRoman Kapl         if (env->flags & POWERPC_FLAG_DE) {
393a1bb7384SScott Wood             /* FIXME: choose one or the other based on CPU type */
394c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_DSRR0;
395c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_DSRR1;
396c79c73f6SBlue Swirl             asrr0 = SPR_BOOKE_CSRR0;
397c79c73f6SBlue Swirl             asrr1 = SPR_BOOKE_CSRR1;
3980e3bf489SRoman Kapl             /* DBSR already modified by caller */
3990e3bf489SRoman Kapl         } else {
4000e3bf489SRoman Kapl             cpu_abort(cs, "Debug exception triggered on unsupported model\n");
401c79c73f6SBlue Swirl         }
402bd6fefe7SBenjamin Herrenschmidt         break;
403c79c73f6SBlue Swirl     case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
404c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
405bd6fefe7SBenjamin Herrenschmidt         break;
406c79c73f6SBlue Swirl     case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
407c79c73f6SBlue Swirl         /* XXX: TODO */
408a47dddd7SAndreas Färber         cpu_abort(cs, "Embedded floating point data exception "
409c79c73f6SBlue Swirl                   "is not implemented yet !\n");
410c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
411bd6fefe7SBenjamin Herrenschmidt         break;
412c79c73f6SBlue Swirl     case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
413c79c73f6SBlue Swirl         /* XXX: TODO */
414a47dddd7SAndreas Färber         cpu_abort(cs, "Embedded floating point round exception "
415c79c73f6SBlue Swirl                   "is not implemented yet !\n");
416c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
417bd6fefe7SBenjamin Herrenschmidt         break;
418c79c73f6SBlue Swirl     case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
419c79c73f6SBlue Swirl         /* XXX: TODO */
420a47dddd7SAndreas Färber         cpu_abort(cs,
421c79c73f6SBlue Swirl                   "Performance counter exception is not implemented yet !\n");
422bd6fefe7SBenjamin Herrenschmidt         break;
423c79c73f6SBlue Swirl     case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
424bd6fefe7SBenjamin Herrenschmidt         break;
425c79c73f6SBlue Swirl     case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
426c79c73f6SBlue Swirl         srr0 = SPR_BOOKE_CSRR0;
427c79c73f6SBlue Swirl         srr1 = SPR_BOOKE_CSRR1;
428bd6fefe7SBenjamin Herrenschmidt         break;
429c79c73f6SBlue Swirl     case POWERPC_EXCP_RESET:     /* System reset exception                   */
430f85bcec3SNicholas Piggin         /* A power-saving exception sets ME, otherwise it is unchanged */
431c79c73f6SBlue Swirl         if (msr_pow) {
432c79c73f6SBlue Swirl             /* indicate that we resumed from power save mode */
433c79c73f6SBlue Swirl             msr |= 0x10000;
434f85bcec3SNicholas Piggin             new_msr |= ((target_ulong)1 << MSR_ME);
435c79c73f6SBlue Swirl         }
43610c21b5cSNicholas Piggin         if (env->msr_mask & MSR_HVB) {
43747733729SDavid Gibson             /*
43847733729SDavid Gibson              * ISA specifies HV, but can be delivered to guest with HV
43947733729SDavid Gibson              * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
44010c21b5cSNicholas Piggin              */
441c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
44210c21b5cSNicholas Piggin         } else {
44310c21b5cSNicholas Piggin             if (msr_pow) {
44410c21b5cSNicholas Piggin                 cpu_abort(cs, "Trying to deliver power-saving system reset "
44510c21b5cSNicholas Piggin                           "exception %d with no HV support\n", excp);
44610c21b5cSNicholas Piggin             }
44710c21b5cSNicholas Piggin         }
4485c94b2a5SCédric Le Goater         ail = 0;
449bd6fefe7SBenjamin Herrenschmidt         break;
450c79c73f6SBlue Swirl     case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
451c79c73f6SBlue Swirl     case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
452c79c73f6SBlue Swirl     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
453bd6fefe7SBenjamin Herrenschmidt         break;
454bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
455c79c73f6SBlue Swirl     case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
456c79c73f6SBlue Swirl     case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
457c79c73f6SBlue Swirl     case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
458c79c73f6SBlue Swirl     case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
4597af1e7b0SCédric Le Goater     case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
460bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_HV_EMU:
461d8ce5fd6SBenjamin Herrenschmidt     case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
462c79c73f6SBlue Swirl         srr0 = SPR_HSRR0;
463c79c73f6SBlue Swirl         srr1 = SPR_HSRR1;
464c79c73f6SBlue Swirl         new_msr |= (target_ulong)MSR_HVB;
465c79c73f6SBlue Swirl         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
466bd6fefe7SBenjamin Herrenschmidt         break;
467c79c73f6SBlue Swirl     case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
4681f29871cSTom Musta     case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
4697019cb3dSAlexey Kardashevskiy     case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
4705310799aSBalbir Singh #ifdef TARGET_PPC64
4715310799aSBalbir Singh         env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
4725310799aSBalbir Singh #endif
473bd6fefe7SBenjamin Herrenschmidt         break;
474c79c73f6SBlue Swirl     case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
475c79c73f6SBlue Swirl         LOG_EXCP("PIT exception\n");
476bd6fefe7SBenjamin Herrenschmidt         break;
477c79c73f6SBlue Swirl     case POWERPC_EXCP_IO:        /* IO error exception                       */
478c79c73f6SBlue Swirl         /* XXX: TODO */
479a47dddd7SAndreas Färber         cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
480bd6fefe7SBenjamin Herrenschmidt         break;
481c79c73f6SBlue Swirl     case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
482c79c73f6SBlue Swirl         /* XXX: TODO */
483a47dddd7SAndreas Färber         cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
484bd6fefe7SBenjamin Herrenschmidt         break;
485c79c73f6SBlue Swirl     case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
486c79c73f6SBlue Swirl         /* XXX: TODO */
487a47dddd7SAndreas Färber         cpu_abort(cs, "602 emulation trap exception "
488c79c73f6SBlue Swirl                   "is not implemented yet !\n");
489bd6fefe7SBenjamin Herrenschmidt         break;
490c79c73f6SBlue Swirl     case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
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             goto tlb_miss_tgpr;
497c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
498c79c73f6SBlue Swirl             goto tlb_miss;
499c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
500c79c73f6SBlue Swirl             goto tlb_miss_74xx;
501c79c73f6SBlue Swirl         default:
502a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid instruction TLB miss exception\n");
503c79c73f6SBlue Swirl             break;
504c79c73f6SBlue Swirl         }
505c79c73f6SBlue Swirl         break;
506c79c73f6SBlue Swirl     case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
507c79c73f6SBlue Swirl         switch (excp_model) {
508c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
509c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
510c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
511c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
512c79c73f6SBlue Swirl             goto tlb_miss_tgpr;
513c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
514c79c73f6SBlue Swirl             goto tlb_miss;
515c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
516c79c73f6SBlue Swirl             goto tlb_miss_74xx;
517c79c73f6SBlue Swirl         default:
518a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid data load TLB miss exception\n");
519c79c73f6SBlue Swirl             break;
520c79c73f6SBlue Swirl         }
521c79c73f6SBlue Swirl         break;
522c79c73f6SBlue Swirl     case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
523c79c73f6SBlue Swirl         switch (excp_model) {
524c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
525c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
526c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
527c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
528c79c73f6SBlue Swirl         tlb_miss_tgpr:
529c79c73f6SBlue Swirl             /* Swap temporary saved registers with GPRs */
530c79c73f6SBlue Swirl             if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
531c79c73f6SBlue Swirl                 new_msr |= (target_ulong)1 << MSR_TGPR;
532c79c73f6SBlue Swirl                 hreg_swap_gpr_tgpr(env);
533c79c73f6SBlue Swirl             }
534c79c73f6SBlue Swirl             goto tlb_miss;
535c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
536c79c73f6SBlue Swirl         tlb_miss:
537c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB)
538c79c73f6SBlue Swirl             if (qemu_log_enabled()) {
539c79c73f6SBlue Swirl                 const char *es;
540c79c73f6SBlue Swirl                 target_ulong *miss, *cmp;
541c79c73f6SBlue Swirl                 int en;
542c79c73f6SBlue Swirl 
543c79c73f6SBlue Swirl                 if (excp == POWERPC_EXCP_IFTLB) {
544c79c73f6SBlue Swirl                     es = "I";
545c79c73f6SBlue Swirl                     en = 'I';
546c79c73f6SBlue Swirl                     miss = &env->spr[SPR_IMISS];
547c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_ICMP];
548c79c73f6SBlue Swirl                 } else {
549c79c73f6SBlue Swirl                     if (excp == POWERPC_EXCP_DLTLB) {
550c79c73f6SBlue Swirl                         es = "DL";
551c79c73f6SBlue Swirl                     } else {
552c79c73f6SBlue Swirl                         es = "DS";
553c79c73f6SBlue Swirl                     }
554c79c73f6SBlue Swirl                     en = 'D';
555c79c73f6SBlue Swirl                     miss = &env->spr[SPR_DMISS];
556c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_DCMP];
557c79c73f6SBlue Swirl                 }
558c79c73f6SBlue Swirl                 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
559c79c73f6SBlue Swirl                          TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
560c79c73f6SBlue Swirl                          TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
561c79c73f6SBlue Swirl                          env->spr[SPR_HASH1], env->spr[SPR_HASH2],
562c79c73f6SBlue Swirl                          env->error_code);
563c79c73f6SBlue Swirl             }
564c79c73f6SBlue Swirl #endif
565c79c73f6SBlue Swirl             msr |= env->crf[0] << 28;
566c79c73f6SBlue Swirl             msr |= env->error_code; /* key, D/I, S/L bits */
567c79c73f6SBlue Swirl             /* Set way using a LRU mechanism */
568c79c73f6SBlue Swirl             msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
569c79c73f6SBlue Swirl             break;
570c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
571c79c73f6SBlue Swirl         tlb_miss_74xx:
572c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB)
573c79c73f6SBlue Swirl             if (qemu_log_enabled()) {
574c79c73f6SBlue Swirl                 const char *es;
575c79c73f6SBlue Swirl                 target_ulong *miss, *cmp;
576c79c73f6SBlue Swirl                 int en;
577c79c73f6SBlue Swirl 
578c79c73f6SBlue Swirl                 if (excp == POWERPC_EXCP_IFTLB) {
579c79c73f6SBlue Swirl                     es = "I";
580c79c73f6SBlue Swirl                     en = 'I';
581c79c73f6SBlue Swirl                     miss = &env->spr[SPR_TLBMISS];
582c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_PTEHI];
583c79c73f6SBlue Swirl                 } else {
584c79c73f6SBlue Swirl                     if (excp == POWERPC_EXCP_DLTLB) {
585c79c73f6SBlue Swirl                         es = "DL";
586c79c73f6SBlue Swirl                     } else {
587c79c73f6SBlue Swirl                         es = "DS";
588c79c73f6SBlue Swirl                     }
589c79c73f6SBlue Swirl                     en = 'D';
590c79c73f6SBlue Swirl                     miss = &env->spr[SPR_TLBMISS];
591c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_PTEHI];
592c79c73f6SBlue Swirl                 }
593c79c73f6SBlue Swirl                 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
594c79c73f6SBlue Swirl                          TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
595c79c73f6SBlue Swirl                          env->error_code);
596c79c73f6SBlue Swirl             }
597c79c73f6SBlue Swirl #endif
598c79c73f6SBlue Swirl             msr |= env->error_code; /* key bit */
599c79c73f6SBlue Swirl             break;
600c79c73f6SBlue Swirl         default:
601a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid data store TLB miss exception\n");
602c79c73f6SBlue Swirl             break;
603c79c73f6SBlue Swirl         }
604bd6fefe7SBenjamin Herrenschmidt         break;
605c79c73f6SBlue Swirl     case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
606c79c73f6SBlue Swirl         /* XXX: TODO */
607a47dddd7SAndreas Färber         cpu_abort(cs, "Floating point assist exception "
608c79c73f6SBlue Swirl                   "is not implemented yet !\n");
609bd6fefe7SBenjamin Herrenschmidt         break;
610c79c73f6SBlue Swirl     case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
611c79c73f6SBlue Swirl         /* XXX: TODO */
612a47dddd7SAndreas Färber         cpu_abort(cs, "DABR exception is not implemented yet !\n");
613bd6fefe7SBenjamin Herrenschmidt         break;
614c79c73f6SBlue Swirl     case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
615c79c73f6SBlue Swirl         /* XXX: TODO */
616a47dddd7SAndreas Färber         cpu_abort(cs, "IABR exception is not implemented yet !\n");
617bd6fefe7SBenjamin Herrenschmidt         break;
618c79c73f6SBlue Swirl     case POWERPC_EXCP_SMI:       /* System management interrupt              */
619c79c73f6SBlue Swirl         /* XXX: TODO */
620a47dddd7SAndreas Färber         cpu_abort(cs, "SMI exception is not implemented yet !\n");
621bd6fefe7SBenjamin Herrenschmidt         break;
622c79c73f6SBlue Swirl     case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
623c79c73f6SBlue Swirl         /* XXX: TODO */
624a47dddd7SAndreas Färber         cpu_abort(cs, "Thermal management exception "
625c79c73f6SBlue Swirl                   "is not implemented yet !\n");
626bd6fefe7SBenjamin Herrenschmidt         break;
627c79c73f6SBlue Swirl     case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
628c79c73f6SBlue Swirl         /* XXX: TODO */
629a47dddd7SAndreas Färber         cpu_abort(cs,
630c79c73f6SBlue Swirl                   "Performance counter exception is not implemented yet !\n");
631bd6fefe7SBenjamin Herrenschmidt         break;
632c79c73f6SBlue Swirl     case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
633c79c73f6SBlue Swirl         /* XXX: TODO */
634a47dddd7SAndreas Färber         cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
635bd6fefe7SBenjamin Herrenschmidt         break;
636c79c73f6SBlue Swirl     case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
637c79c73f6SBlue Swirl         /* XXX: TODO */
638a47dddd7SAndreas Färber         cpu_abort(cs,
639c79c73f6SBlue Swirl                   "970 soft-patch exception is not implemented yet !\n");
640bd6fefe7SBenjamin Herrenschmidt         break;
641c79c73f6SBlue Swirl     case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
642c79c73f6SBlue Swirl         /* XXX: TODO */
643a47dddd7SAndreas Färber         cpu_abort(cs,
644c79c73f6SBlue Swirl                   "970 maintenance exception is not implemented yet !\n");
645bd6fefe7SBenjamin Herrenschmidt         break;
646c79c73f6SBlue Swirl     case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
647c79c73f6SBlue Swirl         /* XXX: TODO */
648a47dddd7SAndreas Färber         cpu_abort(cs, "Maskable external exception "
649c79c73f6SBlue Swirl                   "is not implemented yet !\n");
650bd6fefe7SBenjamin Herrenschmidt         break;
651c79c73f6SBlue Swirl     case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
652c79c73f6SBlue Swirl         /* XXX: TODO */
653a47dddd7SAndreas Färber         cpu_abort(cs, "Non maskable external exception "
654c79c73f6SBlue Swirl                   "is not implemented yet !\n");
655bd6fefe7SBenjamin Herrenschmidt         break;
656c79c73f6SBlue Swirl     default:
657c79c73f6SBlue Swirl     excp_invalid:
658a47dddd7SAndreas Färber         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
659c79c73f6SBlue Swirl         break;
660c79c73f6SBlue Swirl     }
661bd6fefe7SBenjamin Herrenschmidt 
662bd6fefe7SBenjamin Herrenschmidt     /* Save PC */
663bd6fefe7SBenjamin Herrenschmidt     env->spr[srr0] = env->nip;
664bd6fefe7SBenjamin Herrenschmidt 
665c79c73f6SBlue Swirl     /* Save MSR */
666c79c73f6SBlue Swirl     env->spr[srr1] = msr;
6676d49d6d4SBenjamin Herrenschmidt 
6686d49d6d4SBenjamin Herrenschmidt     /* Sanity check */
66910c21b5cSNicholas Piggin     if (!(env->msr_mask & MSR_HVB)) {
67010c21b5cSNicholas Piggin         if (new_msr & MSR_HVB) {
67110c21b5cSNicholas Piggin             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
6726d49d6d4SBenjamin Herrenschmidt                       "no HV support\n", excp);
6736d49d6d4SBenjamin Herrenschmidt         }
67410c21b5cSNicholas Piggin         if (srr0 == SPR_HSRR0) {
67510c21b5cSNicholas Piggin             cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
67610c21b5cSNicholas Piggin                       "no HV support\n", excp);
67710c21b5cSNicholas Piggin         }
67810c21b5cSNicholas Piggin     }
6796d49d6d4SBenjamin Herrenschmidt 
680c79c73f6SBlue Swirl     /* If any alternate SRR register are defined, duplicate saved values */
681c79c73f6SBlue Swirl     if (asrr0 != -1) {
682c79c73f6SBlue Swirl         env->spr[asrr0] = env->spr[srr0];
683c79c73f6SBlue Swirl     }
684c79c73f6SBlue Swirl     if (asrr1 != -1) {
685c79c73f6SBlue Swirl         env->spr[asrr1] = env->spr[srr1];
686c79c73f6SBlue Swirl     }
687d5ac4f54SAlexey Kardashevskiy 
68847733729SDavid Gibson     /*
68947733729SDavid Gibson      * Sort out endianness of interrupt, this differs depending on the
6906d49d6d4SBenjamin Herrenschmidt      * CPU, the HV mode, etc...
6916d49d6d4SBenjamin Herrenschmidt      */
6921e0c7e55SAnton Blanchard #ifdef TARGET_PPC64
6936d49d6d4SBenjamin Herrenschmidt     if (excp_model == POWERPC_EXCP_POWER7) {
6946d49d6d4SBenjamin Herrenschmidt         if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) {
6956d49d6d4SBenjamin Herrenschmidt             new_msr |= (target_ulong)1 << MSR_LE;
6966d49d6d4SBenjamin Herrenschmidt         }
6976d49d6d4SBenjamin Herrenschmidt     } else if (excp_model == POWERPC_EXCP_POWER8) {
6986d49d6d4SBenjamin Herrenschmidt         if (new_msr & MSR_HVB) {
699a790e82bSBenjamin Herrenschmidt             if (env->spr[SPR_HID0] & HID0_HILE) {
700a790e82bSBenjamin Herrenschmidt                 new_msr |= (target_ulong)1 << MSR_LE;
701a790e82bSBenjamin Herrenschmidt             }
702a790e82bSBenjamin Herrenschmidt         } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
703a790e82bSBenjamin Herrenschmidt             new_msr |= (target_ulong)1 << MSR_LE;
704a790e82bSBenjamin Herrenschmidt         }
705a790e82bSBenjamin Herrenschmidt     } else if (excp_model == POWERPC_EXCP_POWER9) {
706a790e82bSBenjamin Herrenschmidt         if (new_msr & MSR_HVB) {
707a790e82bSBenjamin Herrenschmidt             if (env->spr[SPR_HID0] & HID0_POWER9_HILE) {
7086d49d6d4SBenjamin Herrenschmidt                 new_msr |= (target_ulong)1 << MSR_LE;
7096d49d6d4SBenjamin Herrenschmidt             }
7106d49d6d4SBenjamin Herrenschmidt         } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
7111e0c7e55SAnton Blanchard             new_msr |= (target_ulong)1 << MSR_LE;
7121e0c7e55SAnton Blanchard         }
7131e0c7e55SAnton Blanchard     } else if (msr_ile) {
7141e0c7e55SAnton Blanchard         new_msr |= (target_ulong)1 << MSR_LE;
7151e0c7e55SAnton Blanchard     }
7161e0c7e55SAnton Blanchard #else
717c79c73f6SBlue Swirl     if (msr_ile) {
718c79c73f6SBlue Swirl         new_msr |= (target_ulong)1 << MSR_LE;
719c79c73f6SBlue Swirl     }
7201e0c7e55SAnton Blanchard #endif
721c79c73f6SBlue Swirl 
722c79c73f6SBlue Swirl     /* Jump to handler */
723c79c73f6SBlue Swirl     vector = env->excp_vectors[excp];
724c79c73f6SBlue Swirl     if (vector == (target_ulong)-1ULL) {
725a47dddd7SAndreas Färber         cpu_abort(cs, "Raised an exception without defined vector %d\n",
726c79c73f6SBlue Swirl                   excp);
727c79c73f6SBlue Swirl     }
728c79c73f6SBlue Swirl     vector |= env->excp_prefix;
7295c94b2a5SCédric Le Goater 
73047733729SDavid Gibson     /*
73147733729SDavid Gibson      * AIL only works if there is no HV transition and we are running
73247733729SDavid Gibson      * with translations enabled
7335c94b2a5SCédric Le Goater      */
7346d49d6d4SBenjamin Herrenschmidt     if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) ||
7356d49d6d4SBenjamin Herrenschmidt         ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) {
7365c94b2a5SCédric Le Goater         ail = 0;
7375c94b2a5SCédric Le Goater     }
7385c94b2a5SCédric Le Goater     /* Handle AIL */
7395c94b2a5SCédric Le Goater     if (ail) {
7405c94b2a5SCédric Le Goater         new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
7412586a4d7SFabiano Rosas         vector |= ppc_excp_vector_offset(cs, ail);
7425c94b2a5SCédric Le Goater     }
7435c94b2a5SCédric Le Goater 
744c79c73f6SBlue Swirl #if defined(TARGET_PPC64)
745c79c73f6SBlue Swirl     if (excp_model == POWERPC_EXCP_BOOKE) {
746e42a61f1SAlexander Graf         if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
747e42a61f1SAlexander Graf             /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
748c79c73f6SBlue Swirl             new_msr |= (target_ulong)1 << MSR_CM;
749e42a61f1SAlexander Graf         } else {
750e42a61f1SAlexander Graf             vector = (uint32_t)vector;
751c79c73f6SBlue Swirl         }
752c79c73f6SBlue Swirl     } else {
753c79c73f6SBlue Swirl         if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
754c79c73f6SBlue Swirl             vector = (uint32_t)vector;
755c79c73f6SBlue Swirl         } else {
756c79c73f6SBlue Swirl             new_msr |= (target_ulong)1 << MSR_SF;
757c79c73f6SBlue Swirl         }
758c79c73f6SBlue Swirl     }
759c79c73f6SBlue Swirl #endif
76047733729SDavid Gibson     /*
76147733729SDavid Gibson      * We don't use hreg_store_msr here as already have treated any
76247733729SDavid Gibson      * special case that could occur. Just store MSR and update hflags
7631c953ba5SBenjamin Herrenschmidt      *
7641c953ba5SBenjamin Herrenschmidt      * Note: We *MUST* not use hreg_store_msr() as-is anyway because it
7651c953ba5SBenjamin Herrenschmidt      * will prevent setting of the HV bit which some exceptions might need
7661c953ba5SBenjamin Herrenschmidt      * to do.
767c79c73f6SBlue Swirl      */
768c79c73f6SBlue Swirl     env->msr = new_msr & env->msr_mask;
769c79c73f6SBlue Swirl     hreg_compute_hflags(env);
770c79c73f6SBlue Swirl     env->nip = vector;
771c79c73f6SBlue Swirl     /* Reset exception state */
77227103424SAndreas Färber     cs->exception_index = POWERPC_EXCP_NONE;
773c79c73f6SBlue Swirl     env->error_code = 0;
774cd0c6f47SBenjamin Herrenschmidt 
775139d9023SNikunj A Dadhania     /* Reset the reservation */
776139d9023SNikunj A Dadhania     env->reserve_addr = -1;
777139d9023SNikunj A Dadhania 
77847733729SDavid Gibson     /*
77947733729SDavid Gibson      * Any interrupt is context synchronizing, check if TCG TLB needs
78047733729SDavid Gibson      * a delayed flush on ppc64
781cd0c6f47SBenjamin Herrenschmidt      */
782e3cffe6fSNikunj A Dadhania     check_tlb_flush(env, false);
783c79c73f6SBlue Swirl }
784c79c73f6SBlue Swirl 
78597a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs)
786c79c73f6SBlue Swirl {
78797a8ea5aSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(cs);
78897a8ea5aSAndreas Färber     CPUPPCState *env = &cpu->env;
7895c26a5b3SAndreas Färber 
79027103424SAndreas Färber     powerpc_excp(cpu, env->excp_model, cs->exception_index);
791c79c73f6SBlue Swirl }
792c79c73f6SBlue Swirl 
793458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env)
794c79c73f6SBlue Swirl {
795*db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
7963621e2c9SBenjamin Herrenschmidt     bool async_deliver;
797259186a7SAndreas Färber 
798c79c73f6SBlue Swirl     /* External reset */
799c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
800c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
8015c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
802c79c73f6SBlue Swirl         return;
803c79c73f6SBlue Swirl     }
804c79c73f6SBlue Swirl     /* Machine check exception */
805c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
806c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
8075c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
808c79c73f6SBlue Swirl         return;
809c79c73f6SBlue Swirl     }
810c79c73f6SBlue Swirl #if 0 /* TODO */
811c79c73f6SBlue Swirl     /* External debug exception */
812c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
813c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
8145c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
815c79c73f6SBlue Swirl         return;
816c79c73f6SBlue Swirl     }
817c79c73f6SBlue Swirl #endif
8183621e2c9SBenjamin Herrenschmidt 
8193621e2c9SBenjamin Herrenschmidt     /*
8203621e2c9SBenjamin Herrenschmidt      * For interrupts that gate on MSR:EE, we need to do something a
8213621e2c9SBenjamin Herrenschmidt      * bit more subtle, as we need to let them through even when EE is
8223621e2c9SBenjamin Herrenschmidt      * clear when coming out of some power management states (in order
8233621e2c9SBenjamin Herrenschmidt      * for them to become a 0x100).
8243621e2c9SBenjamin Herrenschmidt      */
8251e7fd61dSBenjamin Herrenschmidt     async_deliver = (msr_ee != 0) || env->resume_as_sreset;
8263621e2c9SBenjamin Herrenschmidt 
827c79c73f6SBlue Swirl     /* Hypervisor decrementer exception */
828c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
8294b236b62SBenjamin Herrenschmidt         /* LPCR will be clear when not supported so this will work */
8304b236b62SBenjamin Herrenschmidt         bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
8313621e2c9SBenjamin Herrenschmidt         if ((async_deliver || msr_hv == 0) && hdice) {
8324b236b62SBenjamin Herrenschmidt             /* HDEC clears on delivery */
8334b236b62SBenjamin Herrenschmidt             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
8345c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
835c79c73f6SBlue Swirl             return;
836c79c73f6SBlue Swirl         }
837c79c73f6SBlue Swirl     }
838d8ce5fd6SBenjamin Herrenschmidt 
839d8ce5fd6SBenjamin Herrenschmidt     /* Hypervisor virtualization interrupt */
840d8ce5fd6SBenjamin Herrenschmidt     if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) {
841d8ce5fd6SBenjamin Herrenschmidt         /* LPCR will be clear when not supported so this will work */
842d8ce5fd6SBenjamin Herrenschmidt         bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
843d8ce5fd6SBenjamin Herrenschmidt         if ((async_deliver || msr_hv == 0) && hvice) {
844d8ce5fd6SBenjamin Herrenschmidt             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT);
845d8ce5fd6SBenjamin Herrenschmidt             return;
846d8ce5fd6SBenjamin Herrenschmidt         }
847d8ce5fd6SBenjamin Herrenschmidt     }
848d8ce5fd6SBenjamin Herrenschmidt 
849d8ce5fd6SBenjamin Herrenschmidt     /* External interrupt can ignore MSR:EE under some circumstances */
850d1dbe37cSBenjamin Herrenschmidt     if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
851d1dbe37cSBenjamin Herrenschmidt         bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
8526eebe6dcSBenjamin Herrenschmidt         bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
8536eebe6dcSBenjamin Herrenschmidt         /* HEIC blocks delivery to the hypervisor */
8546eebe6dcSBenjamin Herrenschmidt         if ((async_deliver && !(heic && msr_hv && !msr_pr)) ||
8556eebe6dcSBenjamin Herrenschmidt             (env->has_hv_mode && msr_hv == 0 && !lpes0)) {
856d1dbe37cSBenjamin Herrenschmidt             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
857d1dbe37cSBenjamin Herrenschmidt             return;
858d1dbe37cSBenjamin Herrenschmidt         }
859d1dbe37cSBenjamin Herrenschmidt     }
860c79c73f6SBlue Swirl     if (msr_ce != 0) {
861c79c73f6SBlue Swirl         /* External critical interrupt */
862c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
8635c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
864c79c73f6SBlue Swirl             return;
865c79c73f6SBlue Swirl         }
866c79c73f6SBlue Swirl     }
8673621e2c9SBenjamin Herrenschmidt     if (async_deliver != 0) {
868c79c73f6SBlue Swirl         /* Watchdog timer on embedded PowerPC */
869c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
870c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
8715c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
872c79c73f6SBlue Swirl             return;
873c79c73f6SBlue Swirl         }
874c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
875c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
8765c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
877c79c73f6SBlue Swirl             return;
878c79c73f6SBlue Swirl         }
879c79c73f6SBlue Swirl         /* Fixed interval timer on embedded PowerPC */
880c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
881c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
8825c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
883c79c73f6SBlue Swirl             return;
884c79c73f6SBlue Swirl         }
885c79c73f6SBlue Swirl         /* Programmable interval timer on embedded PowerPC */
886c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
887c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
8885c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
889c79c73f6SBlue Swirl             return;
890c79c73f6SBlue Swirl         }
891c79c73f6SBlue Swirl         /* Decrementer exception */
892c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
893e81a982aSAlexander Graf             if (ppc_decr_clear_on_delivery(env)) {
894c79c73f6SBlue Swirl                 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
895e81a982aSAlexander Graf             }
8965c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
897c79c73f6SBlue Swirl             return;
898c79c73f6SBlue Swirl         }
899c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
900c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
9015c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
902c79c73f6SBlue Swirl             return;
903c79c73f6SBlue Swirl         }
9047af1e7b0SCédric Le Goater         if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) {
9057af1e7b0SCédric Le Goater             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
9067af1e7b0SCédric Le Goater             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV);
9077af1e7b0SCédric Le Goater             return;
9087af1e7b0SCédric Le Goater         }
909c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
910c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
9115c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
912c79c73f6SBlue Swirl             return;
913c79c73f6SBlue Swirl         }
914c79c73f6SBlue Swirl         /* Thermal interrupt */
915c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
916c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
9175c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
918c79c73f6SBlue Swirl             return;
919c79c73f6SBlue Swirl         }
920c79c73f6SBlue Swirl     }
921f8154fd2SBenjamin Herrenschmidt 
922f8154fd2SBenjamin Herrenschmidt     if (env->resume_as_sreset) {
923f8154fd2SBenjamin Herrenschmidt         /*
924f8154fd2SBenjamin Herrenschmidt          * This is a bug ! It means that has_work took us out of halt without
925f8154fd2SBenjamin Herrenschmidt          * anything to deliver while in a PM state that requires getting
926f8154fd2SBenjamin Herrenschmidt          * out via a 0x100
927f8154fd2SBenjamin Herrenschmidt          *
928f8154fd2SBenjamin Herrenschmidt          * This means we will incorrectly execute past the power management
929f8154fd2SBenjamin Herrenschmidt          * instruction instead of triggering a reset.
930f8154fd2SBenjamin Herrenschmidt          *
931f8154fd2SBenjamin Herrenschmidt          * It generally means a discrepancy between the wakup conditions in the
932f8154fd2SBenjamin Herrenschmidt          * processor has_work implementation and the logic in this function.
933f8154fd2SBenjamin Herrenschmidt          */
934*db70b311SRichard Henderson         cpu_abort(env_cpu(env),
935f8154fd2SBenjamin Herrenschmidt                   "Wakeup from PM state but interrupt Undelivered");
936f8154fd2SBenjamin Herrenschmidt     }
937c79c73f6SBlue Swirl }
93834316482SAlexey Kardashevskiy 
93934316482SAlexey Kardashevskiy void ppc_cpu_do_system_reset(CPUState *cs)
94034316482SAlexey Kardashevskiy {
94134316482SAlexey Kardashevskiy     PowerPCCPU *cpu = POWERPC_CPU(cs);
94234316482SAlexey Kardashevskiy     CPUPPCState *env = &cpu->env;
94334316482SAlexey Kardashevskiy 
94434316482SAlexey Kardashevskiy     powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
94534316482SAlexey Kardashevskiy }
946c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */
947c79c73f6SBlue Swirl 
948458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
949458dd766SRichard Henderson {
950458dd766SRichard Henderson     PowerPCCPU *cpu = POWERPC_CPU(cs);
951458dd766SRichard Henderson     CPUPPCState *env = &cpu->env;
952458dd766SRichard Henderson 
953458dd766SRichard Henderson     if (interrupt_request & CPU_INTERRUPT_HARD) {
954458dd766SRichard Henderson         ppc_hw_interrupt(env);
955458dd766SRichard Henderson         if (env->pending_interrupts == 0) {
956458dd766SRichard Henderson             cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
957458dd766SRichard Henderson         }
958458dd766SRichard Henderson         return true;
959458dd766SRichard Henderson     }
960458dd766SRichard Henderson     return false;
961458dd766SRichard Henderson }
962458dd766SRichard Henderson 
963c79c73f6SBlue Swirl #if defined(DEBUG_OP)
964c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
965c79c73f6SBlue Swirl {
966c79c73f6SBlue Swirl     qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
967c79c73f6SBlue Swirl              TARGET_FMT_lx "\n", RA, msr);
968c79c73f6SBlue Swirl }
969c79c73f6SBlue Swirl #endif
970c79c73f6SBlue Swirl 
971ad71ed68SBlue Swirl /*****************************************************************************/
972ad71ed68SBlue Swirl /* Exceptions processing helpers */
973ad71ed68SBlue Swirl 
974db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
975db789c6cSBenjamin Herrenschmidt                             uint32_t error_code, uintptr_t raddr)
976ad71ed68SBlue Swirl {
977*db70b311SRichard Henderson     CPUState *cs = env_cpu(env);
97827103424SAndreas Färber 
97927103424SAndreas Färber     cs->exception_index = exception;
980ad71ed68SBlue Swirl     env->error_code = error_code;
981db789c6cSBenjamin Herrenschmidt     cpu_loop_exit_restore(cs, raddr);
982db789c6cSBenjamin Herrenschmidt }
983db789c6cSBenjamin Herrenschmidt 
984db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception,
985db789c6cSBenjamin Herrenschmidt                          uint32_t error_code)
986db789c6cSBenjamin Herrenschmidt {
987db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, error_code, 0);
988db789c6cSBenjamin Herrenschmidt }
989db789c6cSBenjamin Herrenschmidt 
990db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception)
991db789c6cSBenjamin Herrenschmidt {
992db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, 0);
993db789c6cSBenjamin Herrenschmidt }
994db789c6cSBenjamin Herrenschmidt 
995db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception,
996db789c6cSBenjamin Herrenschmidt                         uintptr_t raddr)
997db789c6cSBenjamin Herrenschmidt {
998db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, raddr);
999db789c6cSBenjamin Herrenschmidt }
1000db789c6cSBenjamin Herrenschmidt 
1001db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
1002db789c6cSBenjamin Herrenschmidt                                 uint32_t error_code)
1003db789c6cSBenjamin Herrenschmidt {
1004db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, error_code, 0);
1005ad71ed68SBlue Swirl }
1006ad71ed68SBlue Swirl 
1007e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception)
1008ad71ed68SBlue Swirl {
1009db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, 0);
1010ad71ed68SBlue Swirl }
1011ad71ed68SBlue Swirl 
1012ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1013e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val)
1014ad71ed68SBlue Swirl {
1015db789c6cSBenjamin Herrenschmidt     uint32_t excp = hreg_store_msr(env, val, 0);
1016259186a7SAndreas Färber 
1017db789c6cSBenjamin Herrenschmidt     if (excp != 0) {
1018*db70b311SRichard Henderson         CPUState *cs = env_cpu(env);
1019044897efSRichard Purdie         cpu_interrupt_exittb(cs);
1020db789c6cSBenjamin Herrenschmidt         raise_exception(env, excp);
1021ad71ed68SBlue Swirl     }
1022ad71ed68SBlue Swirl }
1023ad71ed68SBlue Swirl 
10247778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64)
10257778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
10267778a575SBenjamin Herrenschmidt {
10277778a575SBenjamin Herrenschmidt     CPUState *cs;
10287778a575SBenjamin Herrenschmidt 
1029*db70b311SRichard Henderson     cs = env_cpu(env);
10307778a575SBenjamin Herrenschmidt     cs->halted = 1;
10317778a575SBenjamin Herrenschmidt 
103247733729SDavid Gibson     /*
103347733729SDavid Gibson      * The architecture specifies that HDEC interrupts are discarded
103447733729SDavid Gibson      * in PM states
10354b236b62SBenjamin Herrenschmidt      */
10364b236b62SBenjamin Herrenschmidt     env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
10374b236b62SBenjamin Herrenschmidt 
10383621e2c9SBenjamin Herrenschmidt     /* Condition for waking up at 0x100 */
10391e7fd61dSBenjamin Herrenschmidt     env->resume_as_sreset = (insn != PPC_PM_STOP) ||
104021c0d66aSBenjamin Herrenschmidt         (env->spr[SPR_PSSCR] & PSSCR_EC);
10417778a575SBenjamin Herrenschmidt }
10427778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */
10437778a575SBenjamin Herrenschmidt 
1044a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
1045ad71ed68SBlue Swirl {
1046*db70b311SRichard Henderson     CPUState *cs = env_cpu(env);
1047259186a7SAndreas Färber 
1048a2e71b28SBenjamin Herrenschmidt     /* MSR:POW cannot be set by any form of rfi */
1049a2e71b28SBenjamin Herrenschmidt     msr &= ~(1ULL << MSR_POW);
1050a2e71b28SBenjamin Herrenschmidt 
1051ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1052a2e71b28SBenjamin Herrenschmidt     /* Switching to 32-bit ? Crop the nip */
1053a2e71b28SBenjamin Herrenschmidt     if (!msr_is_64bit(env, msr)) {
1054ad71ed68SBlue Swirl         nip = (uint32_t)nip;
1055ad71ed68SBlue Swirl     }
1056ad71ed68SBlue Swirl #else
1057ad71ed68SBlue Swirl     nip = (uint32_t)nip;
1058ad71ed68SBlue Swirl #endif
1059ad71ed68SBlue Swirl     /* XXX: beware: this is false if VLE is supported */
1060ad71ed68SBlue Swirl     env->nip = nip & ~((target_ulong)0x00000003);
1061ad71ed68SBlue Swirl     hreg_store_msr(env, msr, 1);
1062ad71ed68SBlue Swirl #if defined(DEBUG_OP)
1063ad71ed68SBlue Swirl     cpu_dump_rfi(env->nip, env->msr);
1064ad71ed68SBlue Swirl #endif
106547733729SDavid Gibson     /*
106647733729SDavid Gibson      * No need to raise an exception here, as rfi is always the last
106747733729SDavid Gibson      * insn of a TB
1068ad71ed68SBlue Swirl      */
1069044897efSRichard Purdie     cpu_interrupt_exittb(cs);
1070a8b73734SNikunj A Dadhania     /* Reset the reservation */
1071a8b73734SNikunj A Dadhania     env->reserve_addr = -1;
1072a8b73734SNikunj A Dadhania 
1073cd0c6f47SBenjamin Herrenschmidt     /* Context synchronizing: check if TCG TLB needs flush */
1074e3cffe6fSNikunj A Dadhania     check_tlb_flush(env, false);
1075ad71ed68SBlue Swirl }
1076ad71ed68SBlue Swirl 
1077e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env)
1078ad71ed68SBlue Swirl {
1079a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful);
1080a1bb7384SScott Wood }
1081ad71ed68SBlue Swirl 
1082a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK
1083ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1084e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env)
1085ad71ed68SBlue Swirl {
108647733729SDavid Gibson     /*
108747733729SDavid Gibson      * The architeture defines a number of rules for which bits can
108847733729SDavid Gibson      * change but in practice, we handle this in hreg_store_msr()
1089a2e71b28SBenjamin Herrenschmidt      * which will be called by do_rfi(), so there is no need to filter
1090a2e71b28SBenjamin Herrenschmidt      * here
1091a2e71b28SBenjamin Herrenschmidt      */
1092a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
1093ad71ed68SBlue Swirl }
1094ad71ed68SBlue Swirl 
1095e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env)
1096ad71ed68SBlue Swirl {
1097a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
1098ad71ed68SBlue Swirl }
1099ad71ed68SBlue Swirl #endif
1100ad71ed68SBlue Swirl 
1101ad71ed68SBlue Swirl /*****************************************************************************/
1102ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */
1103e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env)
1104ad71ed68SBlue Swirl {
1105a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]);
1106ad71ed68SBlue Swirl }
1107ad71ed68SBlue Swirl 
1108e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env)
1109ad71ed68SBlue Swirl {
1110a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]);
1111ad71ed68SBlue Swirl }
1112ad71ed68SBlue Swirl 
1113e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env)
1114ad71ed68SBlue Swirl {
1115a1bb7384SScott Wood     /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
1116a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]);
1117ad71ed68SBlue Swirl }
1118ad71ed68SBlue Swirl 
1119e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env)
1120ad71ed68SBlue Swirl {
1121a1bb7384SScott Wood     /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
1122a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]);
1123ad71ed68SBlue Swirl }
1124ad71ed68SBlue Swirl #endif
1125ad71ed68SBlue Swirl 
1126e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1127e5f17ac6SBlue Swirl                uint32_t flags)
1128ad71ed68SBlue Swirl {
1129ad71ed68SBlue Swirl     if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1130ad71ed68SBlue Swirl                   ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1131ad71ed68SBlue Swirl                   ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1132ad71ed68SBlue Swirl                   ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1133ad71ed68SBlue Swirl                   ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
113472073dccSBenjamin Herrenschmidt         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
113572073dccSBenjamin Herrenschmidt                                POWERPC_EXCP_TRAP, GETPC());
1136ad71ed68SBlue Swirl     }
1137ad71ed68SBlue Swirl }
1138ad71ed68SBlue Swirl 
1139ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1140e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1141e5f17ac6SBlue Swirl                uint32_t flags)
1142ad71ed68SBlue Swirl {
1143ad71ed68SBlue Swirl     if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1144ad71ed68SBlue Swirl                   ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1145ad71ed68SBlue Swirl                   ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1146ad71ed68SBlue Swirl                   ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1147ad71ed68SBlue Swirl                   ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
114872073dccSBenjamin Herrenschmidt         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
114972073dccSBenjamin Herrenschmidt                                POWERPC_EXCP_TRAP, GETPC());
1150ad71ed68SBlue Swirl     }
1151ad71ed68SBlue Swirl }
1152ad71ed68SBlue Swirl #endif
1153ad71ed68SBlue Swirl 
1154ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1155ad71ed68SBlue Swirl /*****************************************************************************/
1156ad71ed68SBlue Swirl /* PowerPC 601 specific instructions (POWER bridge) */
1157ad71ed68SBlue Swirl 
1158e5f17ac6SBlue Swirl void helper_rfsvc(CPUPPCState *env)
1159ad71ed68SBlue Swirl {
1160a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->lr, env->ctr & 0x0000FFFF);
1161ad71ed68SBlue Swirl }
1162ad71ed68SBlue Swirl 
1163ad71ed68SBlue Swirl /* Embedded.Processor Control */
1164ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb)
1165ad71ed68SBlue Swirl {
1166ad71ed68SBlue Swirl     int msg = rb & DBELL_TYPE_MASK;
1167ad71ed68SBlue Swirl     int irq = -1;
1168ad71ed68SBlue Swirl 
1169ad71ed68SBlue Swirl     switch (msg) {
1170ad71ed68SBlue Swirl     case DBELL_TYPE_DBELL:
1171ad71ed68SBlue Swirl         irq = PPC_INTERRUPT_DOORBELL;
1172ad71ed68SBlue Swirl         break;
1173ad71ed68SBlue Swirl     case DBELL_TYPE_DBELL_CRIT:
1174ad71ed68SBlue Swirl         irq = PPC_INTERRUPT_CDOORBELL;
1175ad71ed68SBlue Swirl         break;
1176ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL:
1177ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL_CRIT:
1178ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL_MC:
1179ad71ed68SBlue Swirl         /* XXX implement */
1180ad71ed68SBlue Swirl     default:
1181ad71ed68SBlue Swirl         break;
1182ad71ed68SBlue Swirl     }
1183ad71ed68SBlue Swirl 
1184ad71ed68SBlue Swirl     return irq;
1185ad71ed68SBlue Swirl }
1186ad71ed68SBlue Swirl 
1187e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb)
1188ad71ed68SBlue Swirl {
1189ad71ed68SBlue Swirl     int irq = dbell2irq(rb);
1190ad71ed68SBlue Swirl 
1191ad71ed68SBlue Swirl     if (irq < 0) {
1192ad71ed68SBlue Swirl         return;
1193ad71ed68SBlue Swirl     }
1194ad71ed68SBlue Swirl 
1195ad71ed68SBlue Swirl     env->pending_interrupts &= ~(1 << irq);
1196ad71ed68SBlue Swirl }
1197ad71ed68SBlue Swirl 
1198ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb)
1199ad71ed68SBlue Swirl {
1200ad71ed68SBlue Swirl     int irq = dbell2irq(rb);
1201ad71ed68SBlue Swirl     int pir = rb & DBELL_PIRTAG_MASK;
1202182735efSAndreas Färber     CPUState *cs;
1203ad71ed68SBlue Swirl 
1204ad71ed68SBlue Swirl     if (irq < 0) {
1205ad71ed68SBlue Swirl         return;
1206ad71ed68SBlue Swirl     }
1207ad71ed68SBlue Swirl 
1208f1c29ebcSThomas Huth     qemu_mutex_lock_iothread();
1209bdc44640SAndreas Färber     CPU_FOREACH(cs) {
1210182735efSAndreas Färber         PowerPCCPU *cpu = POWERPC_CPU(cs);
1211182735efSAndreas Färber         CPUPPCState *cenv = &cpu->env;
1212182735efSAndreas Färber 
1213ad71ed68SBlue Swirl         if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
1214ad71ed68SBlue Swirl             cenv->pending_interrupts |= 1 << irq;
1215182735efSAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
1216ad71ed68SBlue Swirl         }
1217ad71ed68SBlue Swirl     }
1218f1c29ebcSThomas Huth     qemu_mutex_unlock_iothread();
1219ad71ed68SBlue Swirl }
12207af1e7b0SCédric Le Goater 
12217af1e7b0SCédric Le Goater /* Server Processor Control */
12227af1e7b0SCédric Le Goater static int book3s_dbell2irq(target_ulong rb)
12237af1e7b0SCédric Le Goater {
12247af1e7b0SCédric Le Goater     int msg = rb & DBELL_TYPE_MASK;
12257af1e7b0SCédric Le Goater 
122647733729SDavid Gibson     /*
122747733729SDavid Gibson      * A Directed Hypervisor Doorbell message is sent only if the
12287af1e7b0SCédric Le Goater      * message type is 5. All other types are reserved and the
122947733729SDavid Gibson      * instruction is a no-op
123047733729SDavid Gibson      */
12317af1e7b0SCédric Le Goater     return msg == DBELL_TYPE_DBELL_SERVER ? PPC_INTERRUPT_HDOORBELL : -1;
12327af1e7b0SCédric Le Goater }
12337af1e7b0SCédric Le Goater 
12347af1e7b0SCédric Le Goater void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
12357af1e7b0SCédric Le Goater {
12367af1e7b0SCédric Le Goater     int irq = book3s_dbell2irq(rb);
12377af1e7b0SCédric Le Goater 
12387af1e7b0SCédric Le Goater     if (irq < 0) {
12397af1e7b0SCédric Le Goater         return;
12407af1e7b0SCédric Le Goater     }
12417af1e7b0SCédric Le Goater 
12427af1e7b0SCédric Le Goater     env->pending_interrupts &= ~(1 << irq);
12437af1e7b0SCédric Le Goater }
12447af1e7b0SCédric Le Goater 
12457af1e7b0SCédric Le Goater void helper_book3s_msgsnd(target_ulong rb)
12467af1e7b0SCédric Le Goater {
12477af1e7b0SCédric Le Goater     int irq = book3s_dbell2irq(rb);
12487af1e7b0SCédric Le Goater     int pir = rb & DBELL_PROCIDTAG_MASK;
12497af1e7b0SCédric Le Goater     CPUState *cs;
12507af1e7b0SCédric Le Goater 
12517af1e7b0SCédric Le Goater     if (irq < 0) {
12527af1e7b0SCédric Le Goater         return;
12537af1e7b0SCédric Le Goater     }
12547af1e7b0SCédric Le Goater 
12557af1e7b0SCédric Le Goater     qemu_mutex_lock_iothread();
12567af1e7b0SCédric Le Goater     CPU_FOREACH(cs) {
12577af1e7b0SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
12587af1e7b0SCédric Le Goater         CPUPPCState *cenv = &cpu->env;
12597af1e7b0SCédric Le Goater 
12607af1e7b0SCédric Le Goater         /* TODO: broadcast message to all threads of the same  processor */
12617af1e7b0SCédric Le Goater         if (cenv->spr_cb[SPR_PIR].default_value == pir) {
12627af1e7b0SCédric Le Goater             cenv->pending_interrupts |= 1 << irq;
12637af1e7b0SCédric Le Goater             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
12647af1e7b0SCédric Le Goater         }
12657af1e7b0SCédric Le Goater     }
12667af1e7b0SCédric Le Goater     qemu_mutex_unlock_iothread();
12677af1e7b0SCédric Le Goater }
1268ad71ed68SBlue Swirl #endif
12690f3110faSRichard Henderson 
12700f3110faSRichard Henderson void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
12710f3110faSRichard Henderson                                  MMUAccessType access_type,
12720f3110faSRichard Henderson                                  int mmu_idx, uintptr_t retaddr)
12730f3110faSRichard Henderson {
12740f3110faSRichard Henderson     CPUPPCState *env = cs->env_ptr;
12750f3110faSRichard Henderson     uint32_t insn;
12760f3110faSRichard Henderson 
12770f3110faSRichard Henderson     /* Restore state and reload the insn we executed, for filling in DSISR.  */
12780f3110faSRichard Henderson     cpu_restore_state(cs, retaddr, true);
12790f3110faSRichard Henderson     insn = cpu_ldl_code(env, env->nip);
12800f3110faSRichard Henderson 
12810f3110faSRichard Henderson     cs->exception_index = POWERPC_EXCP_ALIGN;
12820f3110faSRichard Henderson     env->error_code = insn & 0x03FF0000;
12830f3110faSRichard Henderson     cpu_loop_exit(cs);
12840f3110faSRichard Henderson }
1285