xref: /qemu/target/ppc/excp_helper.c (revision bc5fdfc0a1377418902e215f8d7be00e46b9ac9c)
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) {
115*bc5fdfc0SFabiano Rosas     case AIL_NONE:
116*bc5fdfc0SFabiano 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 
13147733729SDavid Gibson /*
13247733729SDavid Gibson  * Note that this function should be greatly optimized when called
13347733729SDavid Gibson  * with a constant excp, from ppc_hw_interrupt
134c79c73f6SBlue Swirl  */
1355c26a5b3SAndreas Färber static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
136c79c73f6SBlue Swirl {
13727103424SAndreas Färber     CPUState *cs = CPU(cpu);
1385c26a5b3SAndreas Färber     CPUPPCState *env = &cpu->env;
139c79c73f6SBlue Swirl     target_ulong msr, new_msr, vector;
1406d49d6d4SBenjamin Herrenschmidt     int srr0, srr1, asrr0, asrr1, lev, ail;
1416d49d6d4SBenjamin Herrenschmidt     bool lpes0;
142c79c73f6SBlue Swirl 
143c79c73f6SBlue Swirl     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
144c79c73f6SBlue Swirl                   " => %08x (%02x)\n", env->nip, excp, env->error_code);
145c79c73f6SBlue Swirl 
146c79c73f6SBlue Swirl     /* new srr1 value excluding must-be-zero bits */
147a1bb7384SScott Wood     if (excp_model == POWERPC_EXCP_BOOKE) {
148a1bb7384SScott Wood         msr = env->msr;
149a1bb7384SScott Wood     } else {
150c79c73f6SBlue Swirl         msr = env->msr & ~0x783f0000ULL;
151a1bb7384SScott Wood     }
152c79c73f6SBlue Swirl 
15347733729SDavid Gibson     /*
15447733729SDavid Gibson      * new interrupt handler msr preserves existing HV and ME unless
1556d49d6d4SBenjamin Herrenschmidt      * explicitly overriden
1566d49d6d4SBenjamin Herrenschmidt      */
1576d49d6d4SBenjamin Herrenschmidt     new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
158c79c73f6SBlue Swirl 
159c79c73f6SBlue Swirl     /* target registers */
160c79c73f6SBlue Swirl     srr0 = SPR_SRR0;
161c79c73f6SBlue Swirl     srr1 = SPR_SRR1;
162c79c73f6SBlue Swirl     asrr0 = -1;
163c79c73f6SBlue Swirl     asrr1 = -1;
164c79c73f6SBlue Swirl 
16521c0d66aSBenjamin Herrenschmidt     /*
16621c0d66aSBenjamin Herrenschmidt      * check for special resume at 0x100 from doze/nap/sleep/winkle on
16721c0d66aSBenjamin Herrenschmidt      * P7/P8/P9
16821c0d66aSBenjamin Herrenschmidt      */
1691e7fd61dSBenjamin Herrenschmidt     if (env->resume_as_sreset) {
170dead760bSBenjamin Herrenschmidt         excp = powerpc_reset_wakeup(cs, env, excp, &msr);
1717778a575SBenjamin Herrenschmidt     }
1727778a575SBenjamin Herrenschmidt 
17347733729SDavid Gibson     /*
17447733729SDavid Gibson      * Exception targetting modifiers
1755c94b2a5SCédric Le Goater      *
176a790e82bSBenjamin Herrenschmidt      * LPES0 is supported on POWER7/8/9
1776d49d6d4SBenjamin Herrenschmidt      * LPES1 is not supported (old iSeries mode)
1786d49d6d4SBenjamin Herrenschmidt      *
1796d49d6d4SBenjamin Herrenschmidt      * On anything else, we behave as if LPES0 is 1
1806d49d6d4SBenjamin Herrenschmidt      * (externals don't alter MSR:HV)
1816d49d6d4SBenjamin Herrenschmidt      *
1825c94b2a5SCédric Le Goater      * AIL is initialized here but can be cleared by
1835c94b2a5SCédric Le Goater      * selected exceptions
1845c94b2a5SCédric Le Goater      */
1855c94b2a5SCédric Le Goater #if defined(TARGET_PPC64)
1865c94b2a5SCédric Le Goater     if (excp_model == POWERPC_EXCP_POWER7 ||
187a790e82bSBenjamin Herrenschmidt         excp_model == POWERPC_EXCP_POWER8 ||
188a790e82bSBenjamin Herrenschmidt         excp_model == POWERPC_EXCP_POWER9) {
1896d49d6d4SBenjamin Herrenschmidt         lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
190a790e82bSBenjamin Herrenschmidt         if (excp_model != POWERPC_EXCP_POWER7) {
1915c94b2a5SCédric Le Goater             ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
1925c94b2a5SCédric Le Goater         } else {
1935c94b2a5SCédric Le Goater             ail = 0;
1945c94b2a5SCédric Le Goater         }
1955c94b2a5SCédric Le Goater     } else
1965c94b2a5SCédric Le Goater #endif /* defined(TARGET_PPC64) */
1975c94b2a5SCédric Le Goater     {
1986d49d6d4SBenjamin Herrenschmidt         lpes0 = true;
1995c94b2a5SCédric Le Goater         ail = 0;
2005c94b2a5SCédric Le Goater     }
2015c94b2a5SCédric Le Goater 
20247733729SDavid Gibson     /*
20347733729SDavid Gibson      * Hypervisor emulation assistance interrupt only exists on server
2049b2faddaSBenjamin Herrenschmidt      * arch 2.05 server or later. We also don't want to generate it if
2059b2faddaSBenjamin Herrenschmidt      * we don't have HVB in msr_mask (PAPR mode).
2069b2faddaSBenjamin Herrenschmidt      */
2079b2faddaSBenjamin Herrenschmidt     if (excp == POWERPC_EXCP_HV_EMU
2089b2faddaSBenjamin Herrenschmidt #if defined(TARGET_PPC64)
2099b2faddaSBenjamin Herrenschmidt         && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB))
2109b2faddaSBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */
2119b2faddaSBenjamin Herrenschmidt 
2129b2faddaSBenjamin Herrenschmidt     ) {
2139b2faddaSBenjamin Herrenschmidt         excp = POWERPC_EXCP_PROGRAM;
2149b2faddaSBenjamin Herrenschmidt     }
2159b2faddaSBenjamin Herrenschmidt 
216c79c73f6SBlue Swirl     switch (excp) {
217c79c73f6SBlue Swirl     case POWERPC_EXCP_NONE:
218c79c73f6SBlue Swirl         /* Should never happen */
219c79c73f6SBlue Swirl         return;
220c79c73f6SBlue Swirl     case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
221c79c73f6SBlue Swirl         switch (excp_model) {
222c79c73f6SBlue Swirl         case POWERPC_EXCP_40x:
223c79c73f6SBlue Swirl             srr0 = SPR_40x_SRR2;
224c79c73f6SBlue Swirl             srr1 = SPR_40x_SRR3;
225c79c73f6SBlue Swirl             break;
226c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
227c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_CSRR0;
228c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_CSRR1;
229c79c73f6SBlue Swirl             break;
230c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
231c79c73f6SBlue Swirl             break;
232c79c73f6SBlue Swirl         default:
233c79c73f6SBlue Swirl             goto excp_invalid;
234c79c73f6SBlue Swirl         }
235bd6fefe7SBenjamin Herrenschmidt         break;
236c79c73f6SBlue Swirl     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
237c79c73f6SBlue Swirl         if (msr_me == 0) {
23847733729SDavid Gibson             /*
23947733729SDavid Gibson              * Machine check exception is not enabled.  Enter
24047733729SDavid Gibson              * checkstop state.
241c79c73f6SBlue Swirl              */
242c79c73f6SBlue Swirl             fprintf(stderr, "Machine check while not allowed. "
243c79c73f6SBlue Swirl                     "Entering checkstop state\n");
244013a2942SPaolo Bonzini             if (qemu_log_separate()) {
245013a2942SPaolo Bonzini                 qemu_log("Machine check while not allowed. "
246013a2942SPaolo Bonzini                         "Entering checkstop state\n");
247c79c73f6SBlue Swirl             }
248259186a7SAndreas Färber             cs->halted = 1;
249044897efSRichard Purdie             cpu_interrupt_exittb(cs);
250c79c73f6SBlue Swirl         }
25110c21b5cSNicholas Piggin         if (env->msr_mask & MSR_HVB) {
25247733729SDavid Gibson             /*
25347733729SDavid Gibson              * ISA specifies HV, but can be delivered to guest with HV
25447733729SDavid Gibson              * clear (e.g., see FWNMI in PAPR).
25510c21b5cSNicholas Piggin              */
256c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
25710c21b5cSNicholas Piggin         }
2585c94b2a5SCédric Le Goater         ail = 0;
259c79c73f6SBlue Swirl 
260c79c73f6SBlue Swirl         /* machine check exceptions don't have ME set */
261c79c73f6SBlue Swirl         new_msr &= ~((target_ulong)1 << MSR_ME);
262c79c73f6SBlue Swirl 
263c79c73f6SBlue Swirl         /* XXX: should also have something loaded in DAR / DSISR */
264c79c73f6SBlue Swirl         switch (excp_model) {
265c79c73f6SBlue Swirl         case POWERPC_EXCP_40x:
266c79c73f6SBlue Swirl             srr0 = SPR_40x_SRR2;
267c79c73f6SBlue Swirl             srr1 = SPR_40x_SRR3;
268c79c73f6SBlue Swirl             break;
269c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
270a1bb7384SScott Wood             /* FIXME: choose one or the other based on CPU type */
271c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_MCSRR0;
272c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_MCSRR1;
273c79c73f6SBlue Swirl             asrr0 = SPR_BOOKE_CSRR0;
274c79c73f6SBlue Swirl             asrr1 = SPR_BOOKE_CSRR1;
275c79c73f6SBlue Swirl             break;
276c79c73f6SBlue Swirl         default:
277c79c73f6SBlue Swirl             break;
278c79c73f6SBlue Swirl         }
279bd6fefe7SBenjamin Herrenschmidt         break;
280c79c73f6SBlue Swirl     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
281c79c73f6SBlue Swirl         LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
282c79c73f6SBlue Swirl                  "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
283bd6fefe7SBenjamin Herrenschmidt         break;
284c79c73f6SBlue Swirl     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
285c79c73f6SBlue Swirl         LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
286c79c73f6SBlue Swirl                  "\n", msr, env->nip);
287c79c73f6SBlue Swirl         msr |= env->error_code;
288bd6fefe7SBenjamin Herrenschmidt         break;
289c79c73f6SBlue Swirl     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
290fdfba1a2SEdgar E. Iglesias         cs = CPU(cpu);
291fdfba1a2SEdgar E. Iglesias 
2926d49d6d4SBenjamin Herrenschmidt         if (!lpes0) {
293c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
2946d49d6d4SBenjamin Herrenschmidt             new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
2956d49d6d4SBenjamin Herrenschmidt             srr0 = SPR_HSRR0;
2966d49d6d4SBenjamin Herrenschmidt             srr1 = SPR_HSRR1;
297c79c73f6SBlue Swirl         }
29868c2dd70SAlexander Graf         if (env->mpic_proxy) {
29968c2dd70SAlexander Graf             /* IACK the IRQ on delivery */
300fdfba1a2SEdgar E. Iglesias             env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
30168c2dd70SAlexander Graf         }
302bd6fefe7SBenjamin Herrenschmidt         break;
303c79c73f6SBlue Swirl     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
304c79c73f6SBlue Swirl         /* Get rS/rD and rA from faulting opcode */
30547733729SDavid Gibson         /*
30647733729SDavid Gibson          * Note: the opcode fields will not be set properly for a
30747733729SDavid Gibson          * direct store load/store, but nobody cares as nobody
30847733729SDavid Gibson          * actually uses direct store segments.
3093433b732SBenjamin Herrenschmidt          */
3103433b732SBenjamin Herrenschmidt         env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
311bd6fefe7SBenjamin Herrenschmidt         break;
312c79c73f6SBlue Swirl     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
313c79c73f6SBlue Swirl         switch (env->error_code & ~0xF) {
314c79c73f6SBlue Swirl         case POWERPC_EXCP_FP:
315c79c73f6SBlue Swirl             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
316c79c73f6SBlue Swirl                 LOG_EXCP("Ignore floating point exception\n");
31727103424SAndreas Färber                 cs->exception_index = POWERPC_EXCP_NONE;
318c79c73f6SBlue Swirl                 env->error_code = 0;
319c79c73f6SBlue Swirl                 return;
320c79c73f6SBlue Swirl             }
3211b7d17caSBenjamin Herrenschmidt 
32247733729SDavid Gibson             /*
32347733729SDavid Gibson              * FP exceptions always have NIP pointing to the faulting
3241b7d17caSBenjamin Herrenschmidt              * instruction, so always use store_next and claim we are
3251b7d17caSBenjamin Herrenschmidt              * precise in the MSR.
3261b7d17caSBenjamin Herrenschmidt              */
327c79c73f6SBlue Swirl             msr |= 0x00100000;
3280ee604abSAaron Larson             env->spr[SPR_BOOKE_ESR] = ESR_FP;
329bd6fefe7SBenjamin Herrenschmidt             break;
330c79c73f6SBlue Swirl         case POWERPC_EXCP_INVAL:
331c79c73f6SBlue Swirl             LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
332c79c73f6SBlue Swirl             msr |= 0x00080000;
333c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PIL;
334c79c73f6SBlue Swirl             break;
335c79c73f6SBlue Swirl         case POWERPC_EXCP_PRIV:
336c79c73f6SBlue Swirl             msr |= 0x00040000;
337c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PPR;
338c79c73f6SBlue Swirl             break;
339c79c73f6SBlue Swirl         case POWERPC_EXCP_TRAP:
340c79c73f6SBlue Swirl             msr |= 0x00020000;
341c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PTR;
342c79c73f6SBlue Swirl             break;
343c79c73f6SBlue Swirl         default:
344c79c73f6SBlue Swirl             /* Should never occur */
345a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid program exception %d. Aborting\n",
346c79c73f6SBlue Swirl                       env->error_code);
347c79c73f6SBlue Swirl             break;
348c79c73f6SBlue Swirl         }
349bd6fefe7SBenjamin Herrenschmidt         break;
350c79c73f6SBlue Swirl     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
351c79c73f6SBlue Swirl         dump_syscall(env);
352c79c73f6SBlue Swirl         lev = env->error_code;
3536d49d6d4SBenjamin Herrenschmidt 
35447733729SDavid Gibson         /*
35547733729SDavid Gibson          * We need to correct the NIP which in this case is supposed
356bd6fefe7SBenjamin Herrenschmidt          * to point to the next instruction
357bd6fefe7SBenjamin Herrenschmidt          */
358bd6fefe7SBenjamin Herrenschmidt         env->nip += 4;
359bd6fefe7SBenjamin Herrenschmidt 
3606d49d6d4SBenjamin Herrenschmidt         /* "PAPR mode" built-in hypercall emulation */
3611d1be34dSDavid Gibson         if ((lev == 1) && cpu->vhyp) {
3621d1be34dSDavid Gibson             PPCVirtualHypervisorClass *vhc =
3631d1be34dSDavid Gibson                 PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
3641d1be34dSDavid Gibson             vhc->hypercall(cpu->vhyp, cpu);
365c79c73f6SBlue Swirl             return;
366c79c73f6SBlue Swirl         }
3676d49d6d4SBenjamin Herrenschmidt         if (lev == 1) {
368c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
369c79c73f6SBlue Swirl         }
370bd6fefe7SBenjamin Herrenschmidt         break;
371bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
372c79c73f6SBlue Swirl     case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
373c79c73f6SBlue Swirl     case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
374bd6fefe7SBenjamin Herrenschmidt         break;
375c79c73f6SBlue Swirl     case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
376c79c73f6SBlue Swirl         /* FIT on 4xx */
377c79c73f6SBlue Swirl         LOG_EXCP("FIT exception\n");
378bd6fefe7SBenjamin Herrenschmidt         break;
379c79c73f6SBlue Swirl     case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
380c79c73f6SBlue Swirl         LOG_EXCP("WDT exception\n");
381c79c73f6SBlue Swirl         switch (excp_model) {
382c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
383c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_CSRR0;
384c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_CSRR1;
385c79c73f6SBlue Swirl             break;
386c79c73f6SBlue Swirl         default:
387c79c73f6SBlue Swirl             break;
388c79c73f6SBlue Swirl         }
389bd6fefe7SBenjamin Herrenschmidt         break;
390c79c73f6SBlue Swirl     case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
391c79c73f6SBlue Swirl     case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
392bd6fefe7SBenjamin Herrenschmidt         break;
393c79c73f6SBlue Swirl     case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
3940e3bf489SRoman Kapl         if (env->flags & POWERPC_FLAG_DE) {
395a1bb7384SScott Wood             /* FIXME: choose one or the other based on CPU type */
396c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_DSRR0;
397c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_DSRR1;
398c79c73f6SBlue Swirl             asrr0 = SPR_BOOKE_CSRR0;
399c79c73f6SBlue Swirl             asrr1 = SPR_BOOKE_CSRR1;
4000e3bf489SRoman Kapl             /* DBSR already modified by caller */
4010e3bf489SRoman Kapl         } else {
4020e3bf489SRoman Kapl             cpu_abort(cs, "Debug exception triggered on unsupported model\n");
403c79c73f6SBlue Swirl         }
404bd6fefe7SBenjamin Herrenschmidt         break;
405c79c73f6SBlue Swirl     case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
406c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
407bd6fefe7SBenjamin Herrenschmidt         break;
408c79c73f6SBlue Swirl     case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
409c79c73f6SBlue Swirl         /* XXX: TODO */
410a47dddd7SAndreas Färber         cpu_abort(cs, "Embedded floating point data exception "
411c79c73f6SBlue Swirl                   "is not implemented yet !\n");
412c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
413bd6fefe7SBenjamin Herrenschmidt         break;
414c79c73f6SBlue Swirl     case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
415c79c73f6SBlue Swirl         /* XXX: TODO */
416a47dddd7SAndreas Färber         cpu_abort(cs, "Embedded floating point round exception "
417c79c73f6SBlue Swirl                   "is not implemented yet !\n");
418c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
419bd6fefe7SBenjamin Herrenschmidt         break;
420c79c73f6SBlue Swirl     case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
421c79c73f6SBlue Swirl         /* XXX: TODO */
422a47dddd7SAndreas Färber         cpu_abort(cs,
423c79c73f6SBlue Swirl                   "Performance counter exception is not implemented yet !\n");
424bd6fefe7SBenjamin Herrenschmidt         break;
425c79c73f6SBlue Swirl     case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
426bd6fefe7SBenjamin Herrenschmidt         break;
427c79c73f6SBlue Swirl     case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
428c79c73f6SBlue Swirl         srr0 = SPR_BOOKE_CSRR0;
429c79c73f6SBlue Swirl         srr1 = SPR_BOOKE_CSRR1;
430bd6fefe7SBenjamin Herrenschmidt         break;
431c79c73f6SBlue Swirl     case POWERPC_EXCP_RESET:     /* System reset exception                   */
432f85bcec3SNicholas Piggin         /* A power-saving exception sets ME, otherwise it is unchanged */
433c79c73f6SBlue Swirl         if (msr_pow) {
434c79c73f6SBlue Swirl             /* indicate that we resumed from power save mode */
435c79c73f6SBlue Swirl             msr |= 0x10000;
436f85bcec3SNicholas Piggin             new_msr |= ((target_ulong)1 << MSR_ME);
437c79c73f6SBlue Swirl         }
43810c21b5cSNicholas Piggin         if (env->msr_mask & MSR_HVB) {
43947733729SDavid Gibson             /*
44047733729SDavid Gibson              * ISA specifies HV, but can be delivered to guest with HV
44147733729SDavid Gibson              * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
44210c21b5cSNicholas Piggin              */
443c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
44410c21b5cSNicholas Piggin         } else {
44510c21b5cSNicholas Piggin             if (msr_pow) {
44610c21b5cSNicholas Piggin                 cpu_abort(cs, "Trying to deliver power-saving system reset "
44710c21b5cSNicholas Piggin                           "exception %d with no HV support\n", excp);
44810c21b5cSNicholas Piggin             }
44910c21b5cSNicholas Piggin         }
4505c94b2a5SCédric Le Goater         ail = 0;
451bd6fefe7SBenjamin Herrenschmidt         break;
452c79c73f6SBlue Swirl     case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
453c79c73f6SBlue Swirl     case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
454c79c73f6SBlue Swirl     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
455bd6fefe7SBenjamin Herrenschmidt         break;
456bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
457c79c73f6SBlue Swirl     case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
458c79c73f6SBlue Swirl     case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
459c79c73f6SBlue Swirl     case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
460c79c73f6SBlue Swirl     case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
4617af1e7b0SCédric Le Goater     case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
462bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_HV_EMU:
463d8ce5fd6SBenjamin Herrenschmidt     case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
464c79c73f6SBlue Swirl         srr0 = SPR_HSRR0;
465c79c73f6SBlue Swirl         srr1 = SPR_HSRR1;
466c79c73f6SBlue Swirl         new_msr |= (target_ulong)MSR_HVB;
467c79c73f6SBlue Swirl         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
468bd6fefe7SBenjamin Herrenschmidt         break;
469c79c73f6SBlue Swirl     case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
4701f29871cSTom Musta     case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
4717019cb3dSAlexey Kardashevskiy     case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
4725310799aSBalbir Singh #ifdef TARGET_PPC64
4735310799aSBalbir Singh         env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
4745310799aSBalbir Singh #endif
475bd6fefe7SBenjamin Herrenschmidt         break;
476c79c73f6SBlue Swirl     case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
477c79c73f6SBlue Swirl         LOG_EXCP("PIT exception\n");
478bd6fefe7SBenjamin Herrenschmidt         break;
479c79c73f6SBlue Swirl     case POWERPC_EXCP_IO:        /* IO error exception                       */
480c79c73f6SBlue Swirl         /* XXX: TODO */
481a47dddd7SAndreas Färber         cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
482bd6fefe7SBenjamin Herrenschmidt         break;
483c79c73f6SBlue Swirl     case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
484c79c73f6SBlue Swirl         /* XXX: TODO */
485a47dddd7SAndreas Färber         cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
486bd6fefe7SBenjamin Herrenschmidt         break;
487c79c73f6SBlue Swirl     case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
488c79c73f6SBlue Swirl         /* XXX: TODO */
489a47dddd7SAndreas Färber         cpu_abort(cs, "602 emulation trap exception "
490c79c73f6SBlue Swirl                   "is not implemented yet !\n");
491bd6fefe7SBenjamin Herrenschmidt         break;
492c79c73f6SBlue Swirl     case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
493c79c73f6SBlue Swirl         switch (excp_model) {
494c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
495c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
496c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
497c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
498c79c73f6SBlue Swirl             goto tlb_miss_tgpr;
499c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
500c79c73f6SBlue Swirl             goto tlb_miss;
501c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
502c79c73f6SBlue Swirl             goto tlb_miss_74xx;
503c79c73f6SBlue Swirl         default:
504a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid instruction TLB miss exception\n");
505c79c73f6SBlue Swirl             break;
506c79c73f6SBlue Swirl         }
507c79c73f6SBlue Swirl         break;
508c79c73f6SBlue Swirl     case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
509c79c73f6SBlue Swirl         switch (excp_model) {
510c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
511c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
512c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
513c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
514c79c73f6SBlue Swirl             goto tlb_miss_tgpr;
515c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
516c79c73f6SBlue Swirl             goto tlb_miss;
517c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
518c79c73f6SBlue Swirl             goto tlb_miss_74xx;
519c79c73f6SBlue Swirl         default:
520a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid data load TLB miss exception\n");
521c79c73f6SBlue Swirl             break;
522c79c73f6SBlue Swirl         }
523c79c73f6SBlue Swirl         break;
524c79c73f6SBlue Swirl     case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
525c79c73f6SBlue Swirl         switch (excp_model) {
526c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
527c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
528c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
529c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
530c79c73f6SBlue Swirl         tlb_miss_tgpr:
531c79c73f6SBlue Swirl             /* Swap temporary saved registers with GPRs */
532c79c73f6SBlue Swirl             if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
533c79c73f6SBlue Swirl                 new_msr |= (target_ulong)1 << MSR_TGPR;
534c79c73f6SBlue Swirl                 hreg_swap_gpr_tgpr(env);
535c79c73f6SBlue Swirl             }
536c79c73f6SBlue Swirl             goto tlb_miss;
537c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
538c79c73f6SBlue Swirl         tlb_miss:
539c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB)
540c79c73f6SBlue Swirl             if (qemu_log_enabled()) {
541c79c73f6SBlue Swirl                 const char *es;
542c79c73f6SBlue Swirl                 target_ulong *miss, *cmp;
543c79c73f6SBlue Swirl                 int en;
544c79c73f6SBlue Swirl 
545c79c73f6SBlue Swirl                 if (excp == POWERPC_EXCP_IFTLB) {
546c79c73f6SBlue Swirl                     es = "I";
547c79c73f6SBlue Swirl                     en = 'I';
548c79c73f6SBlue Swirl                     miss = &env->spr[SPR_IMISS];
549c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_ICMP];
550c79c73f6SBlue Swirl                 } else {
551c79c73f6SBlue Swirl                     if (excp == POWERPC_EXCP_DLTLB) {
552c79c73f6SBlue Swirl                         es = "DL";
553c79c73f6SBlue Swirl                     } else {
554c79c73f6SBlue Swirl                         es = "DS";
555c79c73f6SBlue Swirl                     }
556c79c73f6SBlue Swirl                     en = 'D';
557c79c73f6SBlue Swirl                     miss = &env->spr[SPR_DMISS];
558c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_DCMP];
559c79c73f6SBlue Swirl                 }
560c79c73f6SBlue Swirl                 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
561c79c73f6SBlue Swirl                          TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
562c79c73f6SBlue Swirl                          TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
563c79c73f6SBlue Swirl                          env->spr[SPR_HASH1], env->spr[SPR_HASH2],
564c79c73f6SBlue Swirl                          env->error_code);
565c79c73f6SBlue Swirl             }
566c79c73f6SBlue Swirl #endif
567c79c73f6SBlue Swirl             msr |= env->crf[0] << 28;
568c79c73f6SBlue Swirl             msr |= env->error_code; /* key, D/I, S/L bits */
569c79c73f6SBlue Swirl             /* Set way using a LRU mechanism */
570c79c73f6SBlue Swirl             msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
571c79c73f6SBlue Swirl             break;
572c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
573c79c73f6SBlue Swirl         tlb_miss_74xx:
574c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB)
575c79c73f6SBlue Swirl             if (qemu_log_enabled()) {
576c79c73f6SBlue Swirl                 const char *es;
577c79c73f6SBlue Swirl                 target_ulong *miss, *cmp;
578c79c73f6SBlue Swirl                 int en;
579c79c73f6SBlue Swirl 
580c79c73f6SBlue Swirl                 if (excp == POWERPC_EXCP_IFTLB) {
581c79c73f6SBlue Swirl                     es = "I";
582c79c73f6SBlue Swirl                     en = 'I';
583c79c73f6SBlue Swirl                     miss = &env->spr[SPR_TLBMISS];
584c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_PTEHI];
585c79c73f6SBlue Swirl                 } else {
586c79c73f6SBlue Swirl                     if (excp == POWERPC_EXCP_DLTLB) {
587c79c73f6SBlue Swirl                         es = "DL";
588c79c73f6SBlue Swirl                     } else {
589c79c73f6SBlue Swirl                         es = "DS";
590c79c73f6SBlue Swirl                     }
591c79c73f6SBlue Swirl                     en = 'D';
592c79c73f6SBlue Swirl                     miss = &env->spr[SPR_TLBMISS];
593c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_PTEHI];
594c79c73f6SBlue Swirl                 }
595c79c73f6SBlue Swirl                 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
596c79c73f6SBlue Swirl                          TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
597c79c73f6SBlue Swirl                          env->error_code);
598c79c73f6SBlue Swirl             }
599c79c73f6SBlue Swirl #endif
600c79c73f6SBlue Swirl             msr |= env->error_code; /* key bit */
601c79c73f6SBlue Swirl             break;
602c79c73f6SBlue Swirl         default:
603a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid data store TLB miss exception\n");
604c79c73f6SBlue Swirl             break;
605c79c73f6SBlue Swirl         }
606bd6fefe7SBenjamin Herrenschmidt         break;
607c79c73f6SBlue Swirl     case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
608c79c73f6SBlue Swirl         /* XXX: TODO */
609a47dddd7SAndreas Färber         cpu_abort(cs, "Floating point assist exception "
610c79c73f6SBlue Swirl                   "is not implemented yet !\n");
611bd6fefe7SBenjamin Herrenschmidt         break;
612c79c73f6SBlue Swirl     case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
613c79c73f6SBlue Swirl         /* XXX: TODO */
614a47dddd7SAndreas Färber         cpu_abort(cs, "DABR exception is not implemented yet !\n");
615bd6fefe7SBenjamin Herrenschmidt         break;
616c79c73f6SBlue Swirl     case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
617c79c73f6SBlue Swirl         /* XXX: TODO */
618a47dddd7SAndreas Färber         cpu_abort(cs, "IABR exception is not implemented yet !\n");
619bd6fefe7SBenjamin Herrenschmidt         break;
620c79c73f6SBlue Swirl     case POWERPC_EXCP_SMI:       /* System management interrupt              */
621c79c73f6SBlue Swirl         /* XXX: TODO */
622a47dddd7SAndreas Färber         cpu_abort(cs, "SMI exception is not implemented yet !\n");
623bd6fefe7SBenjamin Herrenschmidt         break;
624c79c73f6SBlue Swirl     case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
625c79c73f6SBlue Swirl         /* XXX: TODO */
626a47dddd7SAndreas Färber         cpu_abort(cs, "Thermal management exception "
627c79c73f6SBlue Swirl                   "is not implemented yet !\n");
628bd6fefe7SBenjamin Herrenschmidt         break;
629c79c73f6SBlue Swirl     case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
630c79c73f6SBlue Swirl         /* XXX: TODO */
631a47dddd7SAndreas Färber         cpu_abort(cs,
632c79c73f6SBlue Swirl                   "Performance counter exception is not implemented yet !\n");
633bd6fefe7SBenjamin Herrenschmidt         break;
634c79c73f6SBlue Swirl     case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
635c79c73f6SBlue Swirl         /* XXX: TODO */
636a47dddd7SAndreas Färber         cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
637bd6fefe7SBenjamin Herrenschmidt         break;
638c79c73f6SBlue Swirl     case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
639c79c73f6SBlue Swirl         /* XXX: TODO */
640a47dddd7SAndreas Färber         cpu_abort(cs,
641c79c73f6SBlue Swirl                   "970 soft-patch exception is not implemented yet !\n");
642bd6fefe7SBenjamin Herrenschmidt         break;
643c79c73f6SBlue Swirl     case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
644c79c73f6SBlue Swirl         /* XXX: TODO */
645a47dddd7SAndreas Färber         cpu_abort(cs,
646c79c73f6SBlue Swirl                   "970 maintenance exception is not implemented yet !\n");
647bd6fefe7SBenjamin Herrenschmidt         break;
648c79c73f6SBlue Swirl     case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
649c79c73f6SBlue Swirl         /* XXX: TODO */
650a47dddd7SAndreas Färber         cpu_abort(cs, "Maskable external exception "
651c79c73f6SBlue Swirl                   "is not implemented yet !\n");
652bd6fefe7SBenjamin Herrenschmidt         break;
653c79c73f6SBlue Swirl     case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
654c79c73f6SBlue Swirl         /* XXX: TODO */
655a47dddd7SAndreas Färber         cpu_abort(cs, "Non maskable external exception "
656c79c73f6SBlue Swirl                   "is not implemented yet !\n");
657bd6fefe7SBenjamin Herrenschmidt         break;
658c79c73f6SBlue Swirl     default:
659c79c73f6SBlue Swirl     excp_invalid:
660a47dddd7SAndreas Färber         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
661c79c73f6SBlue Swirl         break;
662c79c73f6SBlue Swirl     }
663bd6fefe7SBenjamin Herrenschmidt 
664bd6fefe7SBenjamin Herrenschmidt     /* Save PC */
665bd6fefe7SBenjamin Herrenschmidt     env->spr[srr0] = env->nip;
666bd6fefe7SBenjamin Herrenschmidt 
667c79c73f6SBlue Swirl     /* Save MSR */
668c79c73f6SBlue Swirl     env->spr[srr1] = msr;
6696d49d6d4SBenjamin Herrenschmidt 
6706d49d6d4SBenjamin Herrenschmidt     /* Sanity check */
67110c21b5cSNicholas Piggin     if (!(env->msr_mask & MSR_HVB)) {
67210c21b5cSNicholas Piggin         if (new_msr & MSR_HVB) {
67310c21b5cSNicholas Piggin             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
6746d49d6d4SBenjamin Herrenschmidt                       "no HV support\n", excp);
6756d49d6d4SBenjamin Herrenschmidt         }
67610c21b5cSNicholas Piggin         if (srr0 == SPR_HSRR0) {
67710c21b5cSNicholas Piggin             cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
67810c21b5cSNicholas Piggin                       "no HV support\n", excp);
67910c21b5cSNicholas Piggin         }
68010c21b5cSNicholas Piggin     }
6816d49d6d4SBenjamin Herrenschmidt 
682c79c73f6SBlue Swirl     /* If any alternate SRR register are defined, duplicate saved values */
683c79c73f6SBlue Swirl     if (asrr0 != -1) {
684c79c73f6SBlue Swirl         env->spr[asrr0] = env->spr[srr0];
685c79c73f6SBlue Swirl     }
686c79c73f6SBlue Swirl     if (asrr1 != -1) {
687c79c73f6SBlue Swirl         env->spr[asrr1] = env->spr[srr1];
688c79c73f6SBlue Swirl     }
689d5ac4f54SAlexey Kardashevskiy 
69047733729SDavid Gibson     /*
69147733729SDavid Gibson      * Sort out endianness of interrupt, this differs depending on the
6926d49d6d4SBenjamin Herrenschmidt      * CPU, the HV mode, etc...
6936d49d6d4SBenjamin Herrenschmidt      */
6941e0c7e55SAnton Blanchard #ifdef TARGET_PPC64
6956d49d6d4SBenjamin Herrenschmidt     if (excp_model == POWERPC_EXCP_POWER7) {
6966d49d6d4SBenjamin Herrenschmidt         if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) {
6976d49d6d4SBenjamin Herrenschmidt             new_msr |= (target_ulong)1 << MSR_LE;
6986d49d6d4SBenjamin Herrenschmidt         }
6996d49d6d4SBenjamin Herrenschmidt     } else if (excp_model == POWERPC_EXCP_POWER8) {
7006d49d6d4SBenjamin Herrenschmidt         if (new_msr & MSR_HVB) {
701a790e82bSBenjamin Herrenschmidt             if (env->spr[SPR_HID0] & HID0_HILE) {
702a790e82bSBenjamin Herrenschmidt                 new_msr |= (target_ulong)1 << MSR_LE;
703a790e82bSBenjamin Herrenschmidt             }
704a790e82bSBenjamin Herrenschmidt         } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
705a790e82bSBenjamin Herrenschmidt             new_msr |= (target_ulong)1 << MSR_LE;
706a790e82bSBenjamin Herrenschmidt         }
707a790e82bSBenjamin Herrenschmidt     } else if (excp_model == POWERPC_EXCP_POWER9) {
708a790e82bSBenjamin Herrenschmidt         if (new_msr & MSR_HVB) {
709a790e82bSBenjamin Herrenschmidt             if (env->spr[SPR_HID0] & HID0_POWER9_HILE) {
7106d49d6d4SBenjamin Herrenschmidt                 new_msr |= (target_ulong)1 << MSR_LE;
7116d49d6d4SBenjamin Herrenschmidt             }
7126d49d6d4SBenjamin Herrenschmidt         } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
7131e0c7e55SAnton Blanchard             new_msr |= (target_ulong)1 << MSR_LE;
7141e0c7e55SAnton Blanchard         }
7151e0c7e55SAnton Blanchard     } else if (msr_ile) {
7161e0c7e55SAnton Blanchard         new_msr |= (target_ulong)1 << MSR_LE;
7171e0c7e55SAnton Blanchard     }
7181e0c7e55SAnton Blanchard #else
719c79c73f6SBlue Swirl     if (msr_ile) {
720c79c73f6SBlue Swirl         new_msr |= (target_ulong)1 << MSR_LE;
721c79c73f6SBlue Swirl     }
7221e0c7e55SAnton Blanchard #endif
723c79c73f6SBlue Swirl 
724c79c73f6SBlue Swirl     /* Jump to handler */
725c79c73f6SBlue Swirl     vector = env->excp_vectors[excp];
726c79c73f6SBlue Swirl     if (vector == (target_ulong)-1ULL) {
727a47dddd7SAndreas Färber         cpu_abort(cs, "Raised an exception without defined vector %d\n",
728c79c73f6SBlue Swirl                   excp);
729c79c73f6SBlue Swirl     }
730c79c73f6SBlue Swirl     vector |= env->excp_prefix;
7315c94b2a5SCédric Le Goater 
73247733729SDavid Gibson     /*
73347733729SDavid Gibson      * AIL only works if there is no HV transition and we are running
73447733729SDavid Gibson      * with translations enabled
7355c94b2a5SCédric Le Goater      */
7366d49d6d4SBenjamin Herrenschmidt     if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) ||
7376d49d6d4SBenjamin Herrenschmidt         ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) {
7385c94b2a5SCédric Le Goater         ail = 0;
7395c94b2a5SCédric Le Goater     }
7405c94b2a5SCédric Le Goater     /* Handle AIL */
7415c94b2a5SCédric Le Goater     if (ail) {
7425c94b2a5SCédric Le Goater         new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
7432586a4d7SFabiano Rosas         vector |= ppc_excp_vector_offset(cs, ail);
7445c94b2a5SCédric Le Goater     }
7455c94b2a5SCédric Le Goater 
746c79c73f6SBlue Swirl #if defined(TARGET_PPC64)
747c79c73f6SBlue Swirl     if (excp_model == POWERPC_EXCP_BOOKE) {
748e42a61f1SAlexander Graf         if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
749e42a61f1SAlexander Graf             /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
750c79c73f6SBlue Swirl             new_msr |= (target_ulong)1 << MSR_CM;
751e42a61f1SAlexander Graf         } else {
752e42a61f1SAlexander Graf             vector = (uint32_t)vector;
753c79c73f6SBlue Swirl         }
754c79c73f6SBlue Swirl     } else {
755c79c73f6SBlue Swirl         if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
756c79c73f6SBlue Swirl             vector = (uint32_t)vector;
757c79c73f6SBlue Swirl         } else {
758c79c73f6SBlue Swirl             new_msr |= (target_ulong)1 << MSR_SF;
759c79c73f6SBlue Swirl         }
760c79c73f6SBlue Swirl     }
761c79c73f6SBlue Swirl #endif
76247733729SDavid Gibson     /*
76347733729SDavid Gibson      * We don't use hreg_store_msr here as already have treated any
76447733729SDavid Gibson      * special case that could occur. Just store MSR and update hflags
7651c953ba5SBenjamin Herrenschmidt      *
7661c953ba5SBenjamin Herrenschmidt      * Note: We *MUST* not use hreg_store_msr() as-is anyway because it
7671c953ba5SBenjamin Herrenschmidt      * will prevent setting of the HV bit which some exceptions might need
7681c953ba5SBenjamin Herrenschmidt      * to do.
769c79c73f6SBlue Swirl      */
770c79c73f6SBlue Swirl     env->msr = new_msr & env->msr_mask;
771c79c73f6SBlue Swirl     hreg_compute_hflags(env);
772c79c73f6SBlue Swirl     env->nip = vector;
773c79c73f6SBlue Swirl     /* Reset exception state */
77427103424SAndreas Färber     cs->exception_index = POWERPC_EXCP_NONE;
775c79c73f6SBlue Swirl     env->error_code = 0;
776cd0c6f47SBenjamin Herrenschmidt 
777139d9023SNikunj A Dadhania     /* Reset the reservation */
778139d9023SNikunj A Dadhania     env->reserve_addr = -1;
779139d9023SNikunj A Dadhania 
78047733729SDavid Gibson     /*
78147733729SDavid Gibson      * Any interrupt is context synchronizing, check if TCG TLB needs
78247733729SDavid Gibson      * a delayed flush on ppc64
783cd0c6f47SBenjamin Herrenschmidt      */
784e3cffe6fSNikunj A Dadhania     check_tlb_flush(env, false);
785c79c73f6SBlue Swirl }
786c79c73f6SBlue Swirl 
78797a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs)
788c79c73f6SBlue Swirl {
78997a8ea5aSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(cs);
79097a8ea5aSAndreas Färber     CPUPPCState *env = &cpu->env;
7915c26a5b3SAndreas Färber 
79227103424SAndreas Färber     powerpc_excp(cpu, env->excp_model, cs->exception_index);
793c79c73f6SBlue Swirl }
794c79c73f6SBlue Swirl 
795458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env)
796c79c73f6SBlue Swirl {
797db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
7983621e2c9SBenjamin Herrenschmidt     bool async_deliver;
799259186a7SAndreas Färber 
800c79c73f6SBlue Swirl     /* External reset */
801c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
802c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
8035c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
804c79c73f6SBlue Swirl         return;
805c79c73f6SBlue Swirl     }
806c79c73f6SBlue Swirl     /* Machine check exception */
807c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
808c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
8095c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
810c79c73f6SBlue Swirl         return;
811c79c73f6SBlue Swirl     }
812c79c73f6SBlue Swirl #if 0 /* TODO */
813c79c73f6SBlue Swirl     /* External debug exception */
814c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
815c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
8165c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
817c79c73f6SBlue Swirl         return;
818c79c73f6SBlue Swirl     }
819c79c73f6SBlue Swirl #endif
8203621e2c9SBenjamin Herrenschmidt 
8213621e2c9SBenjamin Herrenschmidt     /*
8223621e2c9SBenjamin Herrenschmidt      * For interrupts that gate on MSR:EE, we need to do something a
8233621e2c9SBenjamin Herrenschmidt      * bit more subtle, as we need to let them through even when EE is
8243621e2c9SBenjamin Herrenschmidt      * clear when coming out of some power management states (in order
8253621e2c9SBenjamin Herrenschmidt      * for them to become a 0x100).
8263621e2c9SBenjamin Herrenschmidt      */
8271e7fd61dSBenjamin Herrenschmidt     async_deliver = (msr_ee != 0) || env->resume_as_sreset;
8283621e2c9SBenjamin Herrenschmidt 
829c79c73f6SBlue Swirl     /* Hypervisor decrementer exception */
830c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
8314b236b62SBenjamin Herrenschmidt         /* LPCR will be clear when not supported so this will work */
8324b236b62SBenjamin Herrenschmidt         bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
8333621e2c9SBenjamin Herrenschmidt         if ((async_deliver || msr_hv == 0) && hdice) {
8344b236b62SBenjamin Herrenschmidt             /* HDEC clears on delivery */
8354b236b62SBenjamin Herrenschmidt             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
8365c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
837c79c73f6SBlue Swirl             return;
838c79c73f6SBlue Swirl         }
839c79c73f6SBlue Swirl     }
840d8ce5fd6SBenjamin Herrenschmidt 
841d8ce5fd6SBenjamin Herrenschmidt     /* Hypervisor virtualization interrupt */
842d8ce5fd6SBenjamin Herrenschmidt     if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) {
843d8ce5fd6SBenjamin Herrenschmidt         /* LPCR will be clear when not supported so this will work */
844d8ce5fd6SBenjamin Herrenschmidt         bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
845d8ce5fd6SBenjamin Herrenschmidt         if ((async_deliver || msr_hv == 0) && hvice) {
846d8ce5fd6SBenjamin Herrenschmidt             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT);
847d8ce5fd6SBenjamin Herrenschmidt             return;
848d8ce5fd6SBenjamin Herrenschmidt         }
849d8ce5fd6SBenjamin Herrenschmidt     }
850d8ce5fd6SBenjamin Herrenschmidt 
851d8ce5fd6SBenjamin Herrenschmidt     /* External interrupt can ignore MSR:EE under some circumstances */
852d1dbe37cSBenjamin Herrenschmidt     if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
853d1dbe37cSBenjamin Herrenschmidt         bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
8546eebe6dcSBenjamin Herrenschmidt         bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
8556eebe6dcSBenjamin Herrenschmidt         /* HEIC blocks delivery to the hypervisor */
8566eebe6dcSBenjamin Herrenschmidt         if ((async_deliver && !(heic && msr_hv && !msr_pr)) ||
8576eebe6dcSBenjamin Herrenschmidt             (env->has_hv_mode && msr_hv == 0 && !lpes0)) {
858d1dbe37cSBenjamin Herrenschmidt             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
859d1dbe37cSBenjamin Herrenschmidt             return;
860d1dbe37cSBenjamin Herrenschmidt         }
861d1dbe37cSBenjamin Herrenschmidt     }
862c79c73f6SBlue Swirl     if (msr_ce != 0) {
863c79c73f6SBlue Swirl         /* External critical interrupt */
864c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
8655c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
866c79c73f6SBlue Swirl             return;
867c79c73f6SBlue Swirl         }
868c79c73f6SBlue Swirl     }
8693621e2c9SBenjamin Herrenschmidt     if (async_deliver != 0) {
870c79c73f6SBlue Swirl         /* Watchdog timer on embedded PowerPC */
871c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
872c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
8735c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
874c79c73f6SBlue Swirl             return;
875c79c73f6SBlue Swirl         }
876c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
877c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
8785c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
879c79c73f6SBlue Swirl             return;
880c79c73f6SBlue Swirl         }
881c79c73f6SBlue Swirl         /* Fixed interval timer on embedded PowerPC */
882c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
883c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
8845c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
885c79c73f6SBlue Swirl             return;
886c79c73f6SBlue Swirl         }
887c79c73f6SBlue Swirl         /* Programmable interval timer on embedded PowerPC */
888c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
889c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
8905c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
891c79c73f6SBlue Swirl             return;
892c79c73f6SBlue Swirl         }
893c79c73f6SBlue Swirl         /* Decrementer exception */
894c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
895e81a982aSAlexander Graf             if (ppc_decr_clear_on_delivery(env)) {
896c79c73f6SBlue Swirl                 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
897e81a982aSAlexander Graf             }
8985c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
899c79c73f6SBlue Swirl             return;
900c79c73f6SBlue Swirl         }
901c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
902c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
9035c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
904c79c73f6SBlue Swirl             return;
905c79c73f6SBlue Swirl         }
9067af1e7b0SCédric Le Goater         if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) {
9077af1e7b0SCédric Le Goater             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
9087af1e7b0SCédric Le Goater             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV);
9097af1e7b0SCédric Le Goater             return;
9107af1e7b0SCédric Le Goater         }
911c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
912c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
9135c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
914c79c73f6SBlue Swirl             return;
915c79c73f6SBlue Swirl         }
916c79c73f6SBlue Swirl         /* Thermal interrupt */
917c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
918c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
9195c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
920c79c73f6SBlue Swirl             return;
921c79c73f6SBlue Swirl         }
922c79c73f6SBlue Swirl     }
923f8154fd2SBenjamin Herrenschmidt 
924f8154fd2SBenjamin Herrenschmidt     if (env->resume_as_sreset) {
925f8154fd2SBenjamin Herrenschmidt         /*
926f8154fd2SBenjamin Herrenschmidt          * This is a bug ! It means that has_work took us out of halt without
927f8154fd2SBenjamin Herrenschmidt          * anything to deliver while in a PM state that requires getting
928f8154fd2SBenjamin Herrenschmidt          * out via a 0x100
929f8154fd2SBenjamin Herrenschmidt          *
930f8154fd2SBenjamin Herrenschmidt          * This means we will incorrectly execute past the power management
931f8154fd2SBenjamin Herrenschmidt          * instruction instead of triggering a reset.
932f8154fd2SBenjamin Herrenschmidt          *
933f8154fd2SBenjamin Herrenschmidt          * It generally means a discrepancy between the wakup conditions in the
934f8154fd2SBenjamin Herrenschmidt          * processor has_work implementation and the logic in this function.
935f8154fd2SBenjamin Herrenschmidt          */
936db70b311SRichard Henderson         cpu_abort(env_cpu(env),
937f8154fd2SBenjamin Herrenschmidt                   "Wakeup from PM state but interrupt Undelivered");
938f8154fd2SBenjamin Herrenschmidt     }
939c79c73f6SBlue Swirl }
94034316482SAlexey Kardashevskiy 
94134316482SAlexey Kardashevskiy void ppc_cpu_do_system_reset(CPUState *cs)
94234316482SAlexey Kardashevskiy {
94334316482SAlexey Kardashevskiy     PowerPCCPU *cpu = POWERPC_CPU(cs);
94434316482SAlexey Kardashevskiy     CPUPPCState *env = &cpu->env;
94534316482SAlexey Kardashevskiy 
94634316482SAlexey Kardashevskiy     powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
94734316482SAlexey Kardashevskiy }
948c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */
949c79c73f6SBlue Swirl 
950458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
951458dd766SRichard Henderson {
952458dd766SRichard Henderson     PowerPCCPU *cpu = POWERPC_CPU(cs);
953458dd766SRichard Henderson     CPUPPCState *env = &cpu->env;
954458dd766SRichard Henderson 
955458dd766SRichard Henderson     if (interrupt_request & CPU_INTERRUPT_HARD) {
956458dd766SRichard Henderson         ppc_hw_interrupt(env);
957458dd766SRichard Henderson         if (env->pending_interrupts == 0) {
958458dd766SRichard Henderson             cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
959458dd766SRichard Henderson         }
960458dd766SRichard Henderson         return true;
961458dd766SRichard Henderson     }
962458dd766SRichard Henderson     return false;
963458dd766SRichard Henderson }
964458dd766SRichard Henderson 
965c79c73f6SBlue Swirl #if defined(DEBUG_OP)
966c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
967c79c73f6SBlue Swirl {
968c79c73f6SBlue Swirl     qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
969c79c73f6SBlue Swirl              TARGET_FMT_lx "\n", RA, msr);
970c79c73f6SBlue Swirl }
971c79c73f6SBlue Swirl #endif
972c79c73f6SBlue Swirl 
973ad71ed68SBlue Swirl /*****************************************************************************/
974ad71ed68SBlue Swirl /* Exceptions processing helpers */
975ad71ed68SBlue Swirl 
976db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
977db789c6cSBenjamin Herrenschmidt                             uint32_t error_code, uintptr_t raddr)
978ad71ed68SBlue Swirl {
979db70b311SRichard Henderson     CPUState *cs = env_cpu(env);
98027103424SAndreas Färber 
98127103424SAndreas Färber     cs->exception_index = exception;
982ad71ed68SBlue Swirl     env->error_code = error_code;
983db789c6cSBenjamin Herrenschmidt     cpu_loop_exit_restore(cs, raddr);
984db789c6cSBenjamin Herrenschmidt }
985db789c6cSBenjamin Herrenschmidt 
986db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception,
987db789c6cSBenjamin Herrenschmidt                          uint32_t error_code)
988db789c6cSBenjamin Herrenschmidt {
989db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, error_code, 0);
990db789c6cSBenjamin Herrenschmidt }
991db789c6cSBenjamin Herrenschmidt 
992db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception)
993db789c6cSBenjamin Herrenschmidt {
994db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, 0);
995db789c6cSBenjamin Herrenschmidt }
996db789c6cSBenjamin Herrenschmidt 
997db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception,
998db789c6cSBenjamin Herrenschmidt                         uintptr_t raddr)
999db789c6cSBenjamin Herrenschmidt {
1000db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, raddr);
1001db789c6cSBenjamin Herrenschmidt }
1002db789c6cSBenjamin Herrenschmidt 
1003db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
1004db789c6cSBenjamin Herrenschmidt                                 uint32_t error_code)
1005db789c6cSBenjamin Herrenschmidt {
1006db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, error_code, 0);
1007ad71ed68SBlue Swirl }
1008ad71ed68SBlue Swirl 
1009e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception)
1010ad71ed68SBlue Swirl {
1011db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, 0);
1012ad71ed68SBlue Swirl }
1013ad71ed68SBlue Swirl 
1014ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1015e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val)
1016ad71ed68SBlue Swirl {
1017db789c6cSBenjamin Herrenschmidt     uint32_t excp = hreg_store_msr(env, val, 0);
1018259186a7SAndreas Färber 
1019db789c6cSBenjamin Herrenschmidt     if (excp != 0) {
1020db70b311SRichard Henderson         CPUState *cs = env_cpu(env);
1021044897efSRichard Purdie         cpu_interrupt_exittb(cs);
1022db789c6cSBenjamin Herrenschmidt         raise_exception(env, excp);
1023ad71ed68SBlue Swirl     }
1024ad71ed68SBlue Swirl }
1025ad71ed68SBlue Swirl 
10267778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64)
10277778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
10287778a575SBenjamin Herrenschmidt {
10297778a575SBenjamin Herrenschmidt     CPUState *cs;
10307778a575SBenjamin Herrenschmidt 
1031db70b311SRichard Henderson     cs = env_cpu(env);
10327778a575SBenjamin Herrenschmidt     cs->halted = 1;
10337778a575SBenjamin Herrenschmidt 
103447733729SDavid Gibson     /*
103547733729SDavid Gibson      * The architecture specifies that HDEC interrupts are discarded
103647733729SDavid Gibson      * in PM states
10374b236b62SBenjamin Herrenschmidt      */
10384b236b62SBenjamin Herrenschmidt     env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
10394b236b62SBenjamin Herrenschmidt 
10403621e2c9SBenjamin Herrenschmidt     /* Condition for waking up at 0x100 */
10411e7fd61dSBenjamin Herrenschmidt     env->resume_as_sreset = (insn != PPC_PM_STOP) ||
104221c0d66aSBenjamin Herrenschmidt         (env->spr[SPR_PSSCR] & PSSCR_EC);
10437778a575SBenjamin Herrenschmidt }
10447778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */
10457778a575SBenjamin Herrenschmidt 
1046a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
1047ad71ed68SBlue Swirl {
1048db70b311SRichard Henderson     CPUState *cs = env_cpu(env);
1049259186a7SAndreas Färber 
1050a2e71b28SBenjamin Herrenschmidt     /* MSR:POW cannot be set by any form of rfi */
1051a2e71b28SBenjamin Herrenschmidt     msr &= ~(1ULL << MSR_POW);
1052a2e71b28SBenjamin Herrenschmidt 
1053ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1054a2e71b28SBenjamin Herrenschmidt     /* Switching to 32-bit ? Crop the nip */
1055a2e71b28SBenjamin Herrenschmidt     if (!msr_is_64bit(env, msr)) {
1056ad71ed68SBlue Swirl         nip = (uint32_t)nip;
1057ad71ed68SBlue Swirl     }
1058ad71ed68SBlue Swirl #else
1059ad71ed68SBlue Swirl     nip = (uint32_t)nip;
1060ad71ed68SBlue Swirl #endif
1061ad71ed68SBlue Swirl     /* XXX: beware: this is false if VLE is supported */
1062ad71ed68SBlue Swirl     env->nip = nip & ~((target_ulong)0x00000003);
1063ad71ed68SBlue Swirl     hreg_store_msr(env, msr, 1);
1064ad71ed68SBlue Swirl #if defined(DEBUG_OP)
1065ad71ed68SBlue Swirl     cpu_dump_rfi(env->nip, env->msr);
1066ad71ed68SBlue Swirl #endif
106747733729SDavid Gibson     /*
106847733729SDavid Gibson      * No need to raise an exception here, as rfi is always the last
106947733729SDavid Gibson      * insn of a TB
1070ad71ed68SBlue Swirl      */
1071044897efSRichard Purdie     cpu_interrupt_exittb(cs);
1072a8b73734SNikunj A Dadhania     /* Reset the reservation */
1073a8b73734SNikunj A Dadhania     env->reserve_addr = -1;
1074a8b73734SNikunj A Dadhania 
1075cd0c6f47SBenjamin Herrenschmidt     /* Context synchronizing: check if TCG TLB needs flush */
1076e3cffe6fSNikunj A Dadhania     check_tlb_flush(env, false);
1077ad71ed68SBlue Swirl }
1078ad71ed68SBlue Swirl 
1079e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env)
1080ad71ed68SBlue Swirl {
1081a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful);
1082a1bb7384SScott Wood }
1083ad71ed68SBlue Swirl 
1084a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK
1085ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1086e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env)
1087ad71ed68SBlue Swirl {
108847733729SDavid Gibson     /*
108947733729SDavid Gibson      * The architeture defines a number of rules for which bits can
109047733729SDavid Gibson      * change but in practice, we handle this in hreg_store_msr()
1091a2e71b28SBenjamin Herrenschmidt      * which will be called by do_rfi(), so there is no need to filter
1092a2e71b28SBenjamin Herrenschmidt      * here
1093a2e71b28SBenjamin Herrenschmidt      */
1094a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
1095ad71ed68SBlue Swirl }
1096ad71ed68SBlue Swirl 
1097e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env)
1098ad71ed68SBlue Swirl {
1099a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
1100ad71ed68SBlue Swirl }
1101ad71ed68SBlue Swirl #endif
1102ad71ed68SBlue Swirl 
1103ad71ed68SBlue Swirl /*****************************************************************************/
1104ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */
1105e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env)
1106ad71ed68SBlue Swirl {
1107a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]);
1108ad71ed68SBlue Swirl }
1109ad71ed68SBlue Swirl 
1110e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env)
1111ad71ed68SBlue Swirl {
1112a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]);
1113ad71ed68SBlue Swirl }
1114ad71ed68SBlue Swirl 
1115e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env)
1116ad71ed68SBlue Swirl {
1117a1bb7384SScott Wood     /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
1118a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]);
1119ad71ed68SBlue Swirl }
1120ad71ed68SBlue Swirl 
1121e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env)
1122ad71ed68SBlue Swirl {
1123a1bb7384SScott Wood     /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
1124a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]);
1125ad71ed68SBlue Swirl }
1126ad71ed68SBlue Swirl #endif
1127ad71ed68SBlue Swirl 
1128e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1129e5f17ac6SBlue Swirl                uint32_t flags)
1130ad71ed68SBlue Swirl {
1131ad71ed68SBlue Swirl     if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1132ad71ed68SBlue Swirl                   ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1133ad71ed68SBlue Swirl                   ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1134ad71ed68SBlue Swirl                   ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1135ad71ed68SBlue Swirl                   ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
113672073dccSBenjamin Herrenschmidt         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
113772073dccSBenjamin Herrenschmidt                                POWERPC_EXCP_TRAP, GETPC());
1138ad71ed68SBlue Swirl     }
1139ad71ed68SBlue Swirl }
1140ad71ed68SBlue Swirl 
1141ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1142e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1143e5f17ac6SBlue Swirl                uint32_t flags)
1144ad71ed68SBlue Swirl {
1145ad71ed68SBlue Swirl     if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1146ad71ed68SBlue Swirl                   ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1147ad71ed68SBlue Swirl                   ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1148ad71ed68SBlue Swirl                   ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1149ad71ed68SBlue Swirl                   ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
115072073dccSBenjamin Herrenschmidt         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
115172073dccSBenjamin Herrenschmidt                                POWERPC_EXCP_TRAP, GETPC());
1152ad71ed68SBlue Swirl     }
1153ad71ed68SBlue Swirl }
1154ad71ed68SBlue Swirl #endif
1155ad71ed68SBlue Swirl 
1156ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1157ad71ed68SBlue Swirl /*****************************************************************************/
1158ad71ed68SBlue Swirl /* PowerPC 601 specific instructions (POWER bridge) */
1159ad71ed68SBlue Swirl 
1160e5f17ac6SBlue Swirl void helper_rfsvc(CPUPPCState *env)
1161ad71ed68SBlue Swirl {
1162a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->lr, env->ctr & 0x0000FFFF);
1163ad71ed68SBlue Swirl }
1164ad71ed68SBlue Swirl 
1165ad71ed68SBlue Swirl /* Embedded.Processor Control */
1166ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb)
1167ad71ed68SBlue Swirl {
1168ad71ed68SBlue Swirl     int msg = rb & DBELL_TYPE_MASK;
1169ad71ed68SBlue Swirl     int irq = -1;
1170ad71ed68SBlue Swirl 
1171ad71ed68SBlue Swirl     switch (msg) {
1172ad71ed68SBlue Swirl     case DBELL_TYPE_DBELL:
1173ad71ed68SBlue Swirl         irq = PPC_INTERRUPT_DOORBELL;
1174ad71ed68SBlue Swirl         break;
1175ad71ed68SBlue Swirl     case DBELL_TYPE_DBELL_CRIT:
1176ad71ed68SBlue Swirl         irq = PPC_INTERRUPT_CDOORBELL;
1177ad71ed68SBlue Swirl         break;
1178ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL:
1179ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL_CRIT:
1180ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL_MC:
1181ad71ed68SBlue Swirl         /* XXX implement */
1182ad71ed68SBlue Swirl     default:
1183ad71ed68SBlue Swirl         break;
1184ad71ed68SBlue Swirl     }
1185ad71ed68SBlue Swirl 
1186ad71ed68SBlue Swirl     return irq;
1187ad71ed68SBlue Swirl }
1188ad71ed68SBlue Swirl 
1189e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb)
1190ad71ed68SBlue Swirl {
1191ad71ed68SBlue Swirl     int irq = dbell2irq(rb);
1192ad71ed68SBlue Swirl 
1193ad71ed68SBlue Swirl     if (irq < 0) {
1194ad71ed68SBlue Swirl         return;
1195ad71ed68SBlue Swirl     }
1196ad71ed68SBlue Swirl 
1197ad71ed68SBlue Swirl     env->pending_interrupts &= ~(1 << irq);
1198ad71ed68SBlue Swirl }
1199ad71ed68SBlue Swirl 
1200ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb)
1201ad71ed68SBlue Swirl {
1202ad71ed68SBlue Swirl     int irq = dbell2irq(rb);
1203ad71ed68SBlue Swirl     int pir = rb & DBELL_PIRTAG_MASK;
1204182735efSAndreas Färber     CPUState *cs;
1205ad71ed68SBlue Swirl 
1206ad71ed68SBlue Swirl     if (irq < 0) {
1207ad71ed68SBlue Swirl         return;
1208ad71ed68SBlue Swirl     }
1209ad71ed68SBlue Swirl 
1210f1c29ebcSThomas Huth     qemu_mutex_lock_iothread();
1211bdc44640SAndreas Färber     CPU_FOREACH(cs) {
1212182735efSAndreas Färber         PowerPCCPU *cpu = POWERPC_CPU(cs);
1213182735efSAndreas Färber         CPUPPCState *cenv = &cpu->env;
1214182735efSAndreas Färber 
1215ad71ed68SBlue Swirl         if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
1216ad71ed68SBlue Swirl             cenv->pending_interrupts |= 1 << irq;
1217182735efSAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
1218ad71ed68SBlue Swirl         }
1219ad71ed68SBlue Swirl     }
1220f1c29ebcSThomas Huth     qemu_mutex_unlock_iothread();
1221ad71ed68SBlue Swirl }
12227af1e7b0SCédric Le Goater 
12237af1e7b0SCédric Le Goater /* Server Processor Control */
12247af1e7b0SCédric Le Goater static int book3s_dbell2irq(target_ulong rb)
12257af1e7b0SCédric Le Goater {
12267af1e7b0SCédric Le Goater     int msg = rb & DBELL_TYPE_MASK;
12277af1e7b0SCédric Le Goater 
122847733729SDavid Gibson     /*
122947733729SDavid Gibson      * A Directed Hypervisor Doorbell message is sent only if the
12307af1e7b0SCédric Le Goater      * message type is 5. All other types are reserved and the
123147733729SDavid Gibson      * instruction is a no-op
123247733729SDavid Gibson      */
12337af1e7b0SCédric Le Goater     return msg == DBELL_TYPE_DBELL_SERVER ? PPC_INTERRUPT_HDOORBELL : -1;
12347af1e7b0SCédric Le Goater }
12357af1e7b0SCédric Le Goater 
12367af1e7b0SCédric Le Goater void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
12377af1e7b0SCédric Le Goater {
12387af1e7b0SCédric Le Goater     int irq = book3s_dbell2irq(rb);
12397af1e7b0SCédric Le Goater 
12407af1e7b0SCédric Le Goater     if (irq < 0) {
12417af1e7b0SCédric Le Goater         return;
12427af1e7b0SCédric Le Goater     }
12437af1e7b0SCédric Le Goater 
12447af1e7b0SCédric Le Goater     env->pending_interrupts &= ~(1 << irq);
12457af1e7b0SCédric Le Goater }
12467af1e7b0SCédric Le Goater 
12477af1e7b0SCédric Le Goater void helper_book3s_msgsnd(target_ulong rb)
12487af1e7b0SCédric Le Goater {
12497af1e7b0SCédric Le Goater     int irq = book3s_dbell2irq(rb);
12507af1e7b0SCédric Le Goater     int pir = rb & DBELL_PROCIDTAG_MASK;
12517af1e7b0SCédric Le Goater     CPUState *cs;
12527af1e7b0SCédric Le Goater 
12537af1e7b0SCédric Le Goater     if (irq < 0) {
12547af1e7b0SCédric Le Goater         return;
12557af1e7b0SCédric Le Goater     }
12567af1e7b0SCédric Le Goater 
12577af1e7b0SCédric Le Goater     qemu_mutex_lock_iothread();
12587af1e7b0SCédric Le Goater     CPU_FOREACH(cs) {
12597af1e7b0SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
12607af1e7b0SCédric Le Goater         CPUPPCState *cenv = &cpu->env;
12617af1e7b0SCédric Le Goater 
12627af1e7b0SCédric Le Goater         /* TODO: broadcast message to all threads of the same  processor */
12637af1e7b0SCédric Le Goater         if (cenv->spr_cb[SPR_PIR].default_value == pir) {
12647af1e7b0SCédric Le Goater             cenv->pending_interrupts |= 1 << irq;
12657af1e7b0SCédric Le Goater             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
12667af1e7b0SCédric Le Goater         }
12677af1e7b0SCédric Le Goater     }
12687af1e7b0SCédric Le Goater     qemu_mutex_unlock_iothread();
12697af1e7b0SCédric Le Goater }
1270ad71ed68SBlue Swirl #endif
12710f3110faSRichard Henderson 
12720f3110faSRichard Henderson void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
12730f3110faSRichard Henderson                                  MMUAccessType access_type,
12740f3110faSRichard Henderson                                  int mmu_idx, uintptr_t retaddr)
12750f3110faSRichard Henderson {
12760f3110faSRichard Henderson     CPUPPCState *env = cs->env_ptr;
12770f3110faSRichard Henderson     uint32_t insn;
12780f3110faSRichard Henderson 
12790f3110faSRichard Henderson     /* Restore state and reload the insn we executed, for filling in DSISR.  */
12800f3110faSRichard Henderson     cpu_restore_state(cs, retaddr, true);
12810f3110faSRichard Henderson     insn = cpu_ldl_code(env, env->nip);
12820f3110faSRichard Henderson 
12830f3110faSRichard Henderson     cs->exception_index = POWERPC_EXCP_ALIGN;
12840f3110faSRichard Henderson     env->error_code = insn & 0x03FF0000;
12850f3110faSRichard Henderson     cpu_loop_exit(cs);
12860f3110faSRichard Henderson }
1287