xref: /qemu/target/ppc/excp_helper.c (revision 1e7fd61d97fd4b25c7c8f70eed6a3ffd50893b74)
1ad71ed68SBlue Swirl /*
2ad71ed68SBlue Swirl  *  PowerPC exception emulation helpers for QEMU.
3ad71ed68SBlue Swirl  *
4ad71ed68SBlue Swirl  *  Copyright (c) 2003-2007 Jocelyn Mayer
5ad71ed68SBlue Swirl  *
6ad71ed68SBlue Swirl  * This library is free software; you can redistribute it and/or
7ad71ed68SBlue Swirl  * modify it under the terms of the GNU Lesser General Public
8ad71ed68SBlue Swirl  * License as published by the Free Software Foundation; either
9ad71ed68SBlue Swirl  * version 2 of the License, or (at your option) any later version.
10ad71ed68SBlue Swirl  *
11ad71ed68SBlue Swirl  * This library is distributed in the hope that it will be useful,
12ad71ed68SBlue Swirl  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13ad71ed68SBlue Swirl  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14ad71ed68SBlue Swirl  * Lesser General Public License for more details.
15ad71ed68SBlue Swirl  *
16ad71ed68SBlue Swirl  * You should have received a copy of the GNU Lesser General Public
17ad71ed68SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18ad71ed68SBlue Swirl  */
190d75590dSPeter Maydell #include "qemu/osdep.h"
20f1c29ebcSThomas Huth #include "qemu/main-loop.h"
21ad71ed68SBlue Swirl #include "cpu.h"
222ef6175aSRichard Henderson #include "exec/helper-proto.h"
2363c91552SPaolo Bonzini #include "exec/exec-all.h"
24f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h"
250f3110faSRichard Henderson #include "internal.h"
26ad71ed68SBlue Swirl #include "helper_regs.h"
27ad71ed68SBlue Swirl 
28ad71ed68SBlue Swirl //#define DEBUG_OP
2948880da6SPaolo Bonzini //#define DEBUG_SOFTWARE_TLB
30ad71ed68SBlue Swirl //#define DEBUG_EXCEPTIONS
31ad71ed68SBlue Swirl 
32c79c73f6SBlue Swirl #ifdef DEBUG_EXCEPTIONS
33c79c73f6SBlue Swirl #  define LOG_EXCP(...) qemu_log(__VA_ARGS__)
34c79c73f6SBlue Swirl #else
35c79c73f6SBlue Swirl #  define LOG_EXCP(...) do { } while (0)
36c79c73f6SBlue Swirl #endif
37c79c73f6SBlue Swirl 
38c79c73f6SBlue Swirl /*****************************************************************************/
39c79c73f6SBlue Swirl /* Exception processing */
40c79c73f6SBlue Swirl #if defined(CONFIG_USER_ONLY)
4197a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs)
42c79c73f6SBlue Swirl {
4397a8ea5aSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(cs);
4497a8ea5aSAndreas Färber     CPUPPCState *env = &cpu->env;
4597a8ea5aSAndreas Färber 
4627103424SAndreas Färber     cs->exception_index = POWERPC_EXCP_NONE;
47c79c73f6SBlue Swirl     env->error_code = 0;
48c79c73f6SBlue Swirl }
49c79c73f6SBlue Swirl 
50458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env)
51c79c73f6SBlue Swirl {
5227103424SAndreas Färber     CPUState *cs = CPU(ppc_env_get_cpu(env));
5327103424SAndreas Färber 
5427103424SAndreas Färber     cs->exception_index = POWERPC_EXCP_NONE;
55c79c73f6SBlue Swirl     env->error_code = 0;
56c79c73f6SBlue Swirl }
57c79c73f6SBlue Swirl #else /* defined(CONFIG_USER_ONLY) */
58c79c73f6SBlue Swirl static inline void dump_syscall(CPUPPCState *env)
59c79c73f6SBlue Swirl {
60c79c73f6SBlue Swirl     qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
61c79c73f6SBlue Swirl                   " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
62c79c73f6SBlue Swirl                   " nip=" TARGET_FMT_lx "\n",
63c79c73f6SBlue Swirl                   ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
64c79c73f6SBlue Swirl                   ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
65c79c73f6SBlue Swirl                   ppc_dump_gpr(env, 6), env->nip);
66c79c73f6SBlue Swirl }
67c79c73f6SBlue Swirl 
68dead760bSBenjamin Herrenschmidt static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
69dead760bSBenjamin Herrenschmidt                                 target_ulong *msr)
70dead760bSBenjamin Herrenschmidt {
71dead760bSBenjamin Herrenschmidt     /* We no longer are in a PM state */
72*1e7fd61dSBenjamin Herrenschmidt     env->resume_as_sreset = false;
73dead760bSBenjamin Herrenschmidt 
74dead760bSBenjamin Herrenschmidt     /* Pretend to be returning from doze always as we don't lose state */
75dead760bSBenjamin Herrenschmidt     *msr |= (0x1ull << (63 - 47));
76dead760bSBenjamin Herrenschmidt 
77dead760bSBenjamin Herrenschmidt     /* Machine checks are sent normally */
78dead760bSBenjamin Herrenschmidt     if (excp == POWERPC_EXCP_MCHECK) {
79dead760bSBenjamin Herrenschmidt         return excp;
80dead760bSBenjamin Herrenschmidt     }
81dead760bSBenjamin Herrenschmidt     switch (excp) {
82dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_RESET:
83dead760bSBenjamin Herrenschmidt         *msr |= 0x4ull << (63 - 45);
84dead760bSBenjamin Herrenschmidt         break;
85dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_EXTERNAL:
86dead760bSBenjamin Herrenschmidt         *msr |= 0x8ull << (63 - 45);
87dead760bSBenjamin Herrenschmidt         break;
88dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_DECR:
89dead760bSBenjamin Herrenschmidt         *msr |= 0x6ull << (63 - 45);
90dead760bSBenjamin Herrenschmidt         break;
91dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_SDOOR:
92dead760bSBenjamin Herrenschmidt         *msr |= 0x5ull << (63 - 45);
93dead760bSBenjamin Herrenschmidt         break;
94dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_SDOOR_HV:
95dead760bSBenjamin Herrenschmidt         *msr |= 0x3ull << (63 - 45);
96dead760bSBenjamin Herrenschmidt         break;
97dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_HV_MAINT:
98dead760bSBenjamin Herrenschmidt         *msr |= 0xaull << (63 - 45);
99dead760bSBenjamin Herrenschmidt         break;
100dead760bSBenjamin Herrenschmidt     default:
101dead760bSBenjamin Herrenschmidt         cpu_abort(cs, "Unsupported exception %d in Power Save mode\n",
102dead760bSBenjamin Herrenschmidt                   excp);
103dead760bSBenjamin Herrenschmidt     }
104dead760bSBenjamin Herrenschmidt     return POWERPC_EXCP_RESET;
105dead760bSBenjamin Herrenschmidt }
106dead760bSBenjamin Herrenschmidt 
107dead760bSBenjamin Herrenschmidt 
108c79c73f6SBlue Swirl /* Note that this function should be greatly optimized
109c79c73f6SBlue Swirl  * when called with a constant excp, from ppc_hw_interrupt
110c79c73f6SBlue Swirl  */
1115c26a5b3SAndreas Färber static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
112c79c73f6SBlue Swirl {
11327103424SAndreas Färber     CPUState *cs = CPU(cpu);
1145c26a5b3SAndreas Färber     CPUPPCState *env = &cpu->env;
115c79c73f6SBlue Swirl     target_ulong msr, new_msr, vector;
1166d49d6d4SBenjamin Herrenschmidt     int srr0, srr1, asrr0, asrr1, lev, ail;
1176d49d6d4SBenjamin Herrenschmidt     bool lpes0;
118c79c73f6SBlue Swirl 
119c79c73f6SBlue Swirl     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
120c79c73f6SBlue Swirl                   " => %08x (%02x)\n", env->nip, excp, env->error_code);
121c79c73f6SBlue Swirl 
122c79c73f6SBlue Swirl     /* new srr1 value excluding must-be-zero bits */
123a1bb7384SScott Wood     if (excp_model == POWERPC_EXCP_BOOKE) {
124a1bb7384SScott Wood         msr = env->msr;
125a1bb7384SScott Wood     } else {
126c79c73f6SBlue Swirl         msr = env->msr & ~0x783f0000ULL;
127a1bb7384SScott Wood     }
128c79c73f6SBlue Swirl 
1296d49d6d4SBenjamin Herrenschmidt     /* new interrupt handler msr preserves existing HV and ME unless
1306d49d6d4SBenjamin Herrenschmidt      * explicitly overriden
1316d49d6d4SBenjamin Herrenschmidt      */
1326d49d6d4SBenjamin Herrenschmidt     new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
133c79c73f6SBlue Swirl 
134c79c73f6SBlue Swirl     /* target registers */
135c79c73f6SBlue Swirl     srr0 = SPR_SRR0;
136c79c73f6SBlue Swirl     srr1 = SPR_SRR1;
137c79c73f6SBlue Swirl     asrr0 = -1;
138c79c73f6SBlue Swirl     asrr1 = -1;
139c79c73f6SBlue Swirl 
14021c0d66aSBenjamin Herrenschmidt     /*
14121c0d66aSBenjamin Herrenschmidt      * check for special resume at 0x100 from doze/nap/sleep/winkle on
14221c0d66aSBenjamin Herrenschmidt      * P7/P8/P9
14321c0d66aSBenjamin Herrenschmidt      */
144*1e7fd61dSBenjamin Herrenschmidt     if (env->resume_as_sreset) {
145dead760bSBenjamin Herrenschmidt         excp = powerpc_reset_wakeup(cs, env, excp, &msr);
1467778a575SBenjamin Herrenschmidt     }
1477778a575SBenjamin Herrenschmidt 
1485c94b2a5SCédric Le Goater     /* Exception targetting modifiers
1495c94b2a5SCédric Le Goater      *
1506d49d6d4SBenjamin Herrenschmidt      * LPES0 is supported on POWER7/8
1516d49d6d4SBenjamin Herrenschmidt      * LPES1 is not supported (old iSeries mode)
1526d49d6d4SBenjamin Herrenschmidt      *
1536d49d6d4SBenjamin Herrenschmidt      * On anything else, we behave as if LPES0 is 1
1546d49d6d4SBenjamin Herrenschmidt      * (externals don't alter MSR:HV)
1556d49d6d4SBenjamin Herrenschmidt      *
1565c94b2a5SCédric Le Goater      * AIL is initialized here but can be cleared by
1575c94b2a5SCédric Le Goater      * selected exceptions
1585c94b2a5SCédric Le Goater      */
1595c94b2a5SCédric Le Goater #if defined(TARGET_PPC64)
1605c94b2a5SCédric Le Goater     if (excp_model == POWERPC_EXCP_POWER7 ||
1615c94b2a5SCédric Le Goater         excp_model == POWERPC_EXCP_POWER8) {
1626d49d6d4SBenjamin Herrenschmidt         lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
1635c94b2a5SCédric Le Goater         if (excp_model == POWERPC_EXCP_POWER8) {
1645c94b2a5SCédric Le Goater             ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
1655c94b2a5SCédric Le Goater         } else {
1665c94b2a5SCédric Le Goater             ail = 0;
1675c94b2a5SCédric Le Goater         }
1685c94b2a5SCédric Le Goater     } else
1695c94b2a5SCédric Le Goater #endif /* defined(TARGET_PPC64) */
1705c94b2a5SCédric Le Goater     {
1716d49d6d4SBenjamin Herrenschmidt         lpes0 = true;
1725c94b2a5SCédric Le Goater         ail = 0;
1735c94b2a5SCédric Le Goater     }
1745c94b2a5SCédric Le Goater 
1759b2faddaSBenjamin Herrenschmidt     /* Hypervisor emulation assistance interrupt only exists on server
1769b2faddaSBenjamin Herrenschmidt      * arch 2.05 server or later. We also don't want to generate it if
1779b2faddaSBenjamin Herrenschmidt      * we don't have HVB in msr_mask (PAPR mode).
1789b2faddaSBenjamin Herrenschmidt      */
1799b2faddaSBenjamin Herrenschmidt     if (excp == POWERPC_EXCP_HV_EMU
1809b2faddaSBenjamin Herrenschmidt #if defined(TARGET_PPC64)
1819b2faddaSBenjamin Herrenschmidt         && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB))
1829b2faddaSBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */
1839b2faddaSBenjamin Herrenschmidt 
1849b2faddaSBenjamin Herrenschmidt     ) {
1859b2faddaSBenjamin Herrenschmidt         excp = POWERPC_EXCP_PROGRAM;
1869b2faddaSBenjamin Herrenschmidt     }
1879b2faddaSBenjamin Herrenschmidt 
188c79c73f6SBlue Swirl     switch (excp) {
189c79c73f6SBlue Swirl     case POWERPC_EXCP_NONE:
190c79c73f6SBlue Swirl         /* Should never happen */
191c79c73f6SBlue Swirl         return;
192c79c73f6SBlue Swirl     case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
193c79c73f6SBlue Swirl         switch (excp_model) {
194c79c73f6SBlue Swirl         case POWERPC_EXCP_40x:
195c79c73f6SBlue Swirl             srr0 = SPR_40x_SRR2;
196c79c73f6SBlue Swirl             srr1 = SPR_40x_SRR3;
197c79c73f6SBlue Swirl             break;
198c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
199c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_CSRR0;
200c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_CSRR1;
201c79c73f6SBlue Swirl             break;
202c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
203c79c73f6SBlue Swirl             break;
204c79c73f6SBlue Swirl         default:
205c79c73f6SBlue Swirl             goto excp_invalid;
206c79c73f6SBlue Swirl         }
207bd6fefe7SBenjamin Herrenschmidt         break;
208c79c73f6SBlue Swirl     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
209c79c73f6SBlue Swirl         if (msr_me == 0) {
210c79c73f6SBlue Swirl             /* Machine check exception is not enabled.
211c79c73f6SBlue Swirl              * Enter checkstop state.
212c79c73f6SBlue Swirl              */
213c79c73f6SBlue Swirl             fprintf(stderr, "Machine check while not allowed. "
214c79c73f6SBlue Swirl                     "Entering checkstop state\n");
215013a2942SPaolo Bonzini             if (qemu_log_separate()) {
216013a2942SPaolo Bonzini                 qemu_log("Machine check while not allowed. "
217013a2942SPaolo Bonzini                         "Entering checkstop state\n");
218c79c73f6SBlue Swirl             }
219259186a7SAndreas Färber             cs->halted = 1;
220044897efSRichard Purdie             cpu_interrupt_exittb(cs);
221c79c73f6SBlue Swirl         }
22210c21b5cSNicholas Piggin         if (env->msr_mask & MSR_HVB) {
22310c21b5cSNicholas Piggin             /* ISA specifies HV, but can be delivered to guest with HV clear
22410c21b5cSNicholas Piggin              * (e.g., see FWNMI in PAPR).
22510c21b5cSNicholas Piggin              */
226c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
22710c21b5cSNicholas Piggin         }
2285c94b2a5SCédric Le Goater         ail = 0;
229c79c73f6SBlue Swirl 
230c79c73f6SBlue Swirl         /* machine check exceptions don't have ME set */
231c79c73f6SBlue Swirl         new_msr &= ~((target_ulong)1 << MSR_ME);
232c79c73f6SBlue Swirl 
233c79c73f6SBlue Swirl         /* XXX: should also have something loaded in DAR / DSISR */
234c79c73f6SBlue Swirl         switch (excp_model) {
235c79c73f6SBlue Swirl         case POWERPC_EXCP_40x:
236c79c73f6SBlue Swirl             srr0 = SPR_40x_SRR2;
237c79c73f6SBlue Swirl             srr1 = SPR_40x_SRR3;
238c79c73f6SBlue Swirl             break;
239c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
240a1bb7384SScott Wood             /* FIXME: choose one or the other based on CPU type */
241c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_MCSRR0;
242c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_MCSRR1;
243c79c73f6SBlue Swirl             asrr0 = SPR_BOOKE_CSRR0;
244c79c73f6SBlue Swirl             asrr1 = SPR_BOOKE_CSRR1;
245c79c73f6SBlue Swirl             break;
246c79c73f6SBlue Swirl         default:
247c79c73f6SBlue Swirl             break;
248c79c73f6SBlue Swirl         }
249bd6fefe7SBenjamin Herrenschmidt         break;
250c79c73f6SBlue Swirl     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
251c79c73f6SBlue Swirl         LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
252c79c73f6SBlue Swirl                  "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
253bd6fefe7SBenjamin Herrenschmidt         break;
254c79c73f6SBlue Swirl     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
255c79c73f6SBlue Swirl         LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
256c79c73f6SBlue Swirl                  "\n", msr, env->nip);
257c79c73f6SBlue Swirl         msr |= env->error_code;
258bd6fefe7SBenjamin Herrenschmidt         break;
259c79c73f6SBlue Swirl     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
260fdfba1a2SEdgar E. Iglesias         cs = CPU(cpu);
261fdfba1a2SEdgar E. Iglesias 
2626d49d6d4SBenjamin Herrenschmidt         if (!lpes0) {
263c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
2646d49d6d4SBenjamin Herrenschmidt             new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
2656d49d6d4SBenjamin Herrenschmidt             srr0 = SPR_HSRR0;
2666d49d6d4SBenjamin Herrenschmidt             srr1 = SPR_HSRR1;
267c79c73f6SBlue Swirl         }
26868c2dd70SAlexander Graf         if (env->mpic_proxy) {
26968c2dd70SAlexander Graf             /* IACK the IRQ on delivery */
270fdfba1a2SEdgar E. Iglesias             env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
27168c2dd70SAlexander Graf         }
272bd6fefe7SBenjamin Herrenschmidt         break;
273c79c73f6SBlue Swirl     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
274c79c73f6SBlue Swirl         /* Get rS/rD and rA from faulting opcode */
2753433b732SBenjamin Herrenschmidt         /* Note: the opcode fields will not be set properly for a direct
2763433b732SBenjamin Herrenschmidt          * store load/store, but nobody cares as nobody actually uses
2773433b732SBenjamin Herrenschmidt          * direct store segments.
2783433b732SBenjamin Herrenschmidt          */
2793433b732SBenjamin Herrenschmidt         env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
280bd6fefe7SBenjamin Herrenschmidt         break;
281c79c73f6SBlue Swirl     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
282c79c73f6SBlue Swirl         switch (env->error_code & ~0xF) {
283c79c73f6SBlue Swirl         case POWERPC_EXCP_FP:
284c79c73f6SBlue Swirl             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
285c79c73f6SBlue Swirl                 LOG_EXCP("Ignore floating point exception\n");
28627103424SAndreas Färber                 cs->exception_index = POWERPC_EXCP_NONE;
287c79c73f6SBlue Swirl                 env->error_code = 0;
288c79c73f6SBlue Swirl                 return;
289c79c73f6SBlue Swirl             }
2901b7d17caSBenjamin Herrenschmidt 
2911b7d17caSBenjamin Herrenschmidt             /* FP exceptions always have NIP pointing to the faulting
2921b7d17caSBenjamin Herrenschmidt              * instruction, so always use store_next and claim we are
2931b7d17caSBenjamin Herrenschmidt              * precise in the MSR.
2941b7d17caSBenjamin Herrenschmidt              */
295c79c73f6SBlue Swirl             msr |= 0x00100000;
2960ee604abSAaron Larson             env->spr[SPR_BOOKE_ESR] = ESR_FP;
297bd6fefe7SBenjamin Herrenschmidt             break;
298c79c73f6SBlue Swirl         case POWERPC_EXCP_INVAL:
299c79c73f6SBlue Swirl             LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
300c79c73f6SBlue Swirl             msr |= 0x00080000;
301c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PIL;
302c79c73f6SBlue Swirl             break;
303c79c73f6SBlue Swirl         case POWERPC_EXCP_PRIV:
304c79c73f6SBlue Swirl             msr |= 0x00040000;
305c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PPR;
306c79c73f6SBlue Swirl             break;
307c79c73f6SBlue Swirl         case POWERPC_EXCP_TRAP:
308c79c73f6SBlue Swirl             msr |= 0x00020000;
309c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PTR;
310c79c73f6SBlue Swirl             break;
311c79c73f6SBlue Swirl         default:
312c79c73f6SBlue Swirl             /* Should never occur */
313a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid program exception %d. Aborting\n",
314c79c73f6SBlue Swirl                       env->error_code);
315c79c73f6SBlue Swirl             break;
316c79c73f6SBlue Swirl         }
317bd6fefe7SBenjamin Herrenschmidt         break;
318c79c73f6SBlue Swirl     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
319c79c73f6SBlue Swirl         dump_syscall(env);
320c79c73f6SBlue Swirl         lev = env->error_code;
3216d49d6d4SBenjamin Herrenschmidt 
322bd6fefe7SBenjamin Herrenschmidt         /* We need to correct the NIP which in this case is supposed
323bd6fefe7SBenjamin Herrenschmidt          * to point to the next instruction
324bd6fefe7SBenjamin Herrenschmidt          */
325bd6fefe7SBenjamin Herrenschmidt         env->nip += 4;
326bd6fefe7SBenjamin Herrenschmidt 
3276d49d6d4SBenjamin Herrenschmidt         /* "PAPR mode" built-in hypercall emulation */
3281d1be34dSDavid Gibson         if ((lev == 1) && cpu->vhyp) {
3291d1be34dSDavid Gibson             PPCVirtualHypervisorClass *vhc =
3301d1be34dSDavid Gibson                 PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
3311d1be34dSDavid Gibson             vhc->hypercall(cpu->vhyp, cpu);
332c79c73f6SBlue Swirl             return;
333c79c73f6SBlue Swirl         }
3346d49d6d4SBenjamin Herrenschmidt         if (lev == 1) {
335c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
336c79c73f6SBlue Swirl         }
337bd6fefe7SBenjamin Herrenschmidt         break;
338bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
339c79c73f6SBlue Swirl     case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
340c79c73f6SBlue Swirl     case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
341bd6fefe7SBenjamin Herrenschmidt         break;
342c79c73f6SBlue Swirl     case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
343c79c73f6SBlue Swirl         /* FIT on 4xx */
344c79c73f6SBlue Swirl         LOG_EXCP("FIT exception\n");
345bd6fefe7SBenjamin Herrenschmidt         break;
346c79c73f6SBlue Swirl     case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
347c79c73f6SBlue Swirl         LOG_EXCP("WDT exception\n");
348c79c73f6SBlue Swirl         switch (excp_model) {
349c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
350c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_CSRR0;
351c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_CSRR1;
352c79c73f6SBlue Swirl             break;
353c79c73f6SBlue Swirl         default:
354c79c73f6SBlue Swirl             break;
355c79c73f6SBlue Swirl         }
356bd6fefe7SBenjamin Herrenschmidt         break;
357c79c73f6SBlue Swirl     case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
358c79c73f6SBlue Swirl     case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
359bd6fefe7SBenjamin Herrenschmidt         break;
360c79c73f6SBlue Swirl     case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
3610e3bf489SRoman Kapl         if (env->flags & POWERPC_FLAG_DE) {
362a1bb7384SScott Wood             /* FIXME: choose one or the other based on CPU type */
363c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_DSRR0;
364c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_DSRR1;
365c79c73f6SBlue Swirl             asrr0 = SPR_BOOKE_CSRR0;
366c79c73f6SBlue Swirl             asrr1 = SPR_BOOKE_CSRR1;
3670e3bf489SRoman Kapl             /* DBSR already modified by caller */
3680e3bf489SRoman Kapl         } else {
3690e3bf489SRoman Kapl             cpu_abort(cs, "Debug exception triggered on unsupported model\n");
370c79c73f6SBlue Swirl         }
371bd6fefe7SBenjamin Herrenschmidt         break;
372c79c73f6SBlue Swirl     case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
373c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
374bd6fefe7SBenjamin Herrenschmidt         break;
375c79c73f6SBlue Swirl     case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
376c79c73f6SBlue Swirl         /* XXX: TODO */
377a47dddd7SAndreas Färber         cpu_abort(cs, "Embedded floating point data exception "
378c79c73f6SBlue Swirl                   "is not implemented yet !\n");
379c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
380bd6fefe7SBenjamin Herrenschmidt         break;
381c79c73f6SBlue Swirl     case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
382c79c73f6SBlue Swirl         /* XXX: TODO */
383a47dddd7SAndreas Färber         cpu_abort(cs, "Embedded floating point round exception "
384c79c73f6SBlue Swirl                   "is not implemented yet !\n");
385c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
386bd6fefe7SBenjamin Herrenschmidt         break;
387c79c73f6SBlue Swirl     case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
388c79c73f6SBlue Swirl         /* XXX: TODO */
389a47dddd7SAndreas Färber         cpu_abort(cs,
390c79c73f6SBlue Swirl                   "Performance counter exception is not implemented yet !\n");
391bd6fefe7SBenjamin Herrenschmidt         break;
392c79c73f6SBlue Swirl     case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
393bd6fefe7SBenjamin Herrenschmidt         break;
394c79c73f6SBlue Swirl     case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
395c79c73f6SBlue Swirl         srr0 = SPR_BOOKE_CSRR0;
396c79c73f6SBlue Swirl         srr1 = SPR_BOOKE_CSRR1;
397bd6fefe7SBenjamin Herrenschmidt         break;
398c79c73f6SBlue Swirl     case POWERPC_EXCP_RESET:     /* System reset exception                   */
399f85bcec3SNicholas Piggin         /* A power-saving exception sets ME, otherwise it is unchanged */
400c79c73f6SBlue Swirl         if (msr_pow) {
401c79c73f6SBlue Swirl             /* indicate that we resumed from power save mode */
402c79c73f6SBlue Swirl             msr |= 0x10000;
403f85bcec3SNicholas Piggin             new_msr |= ((target_ulong)1 << MSR_ME);
404c79c73f6SBlue Swirl         }
40510c21b5cSNicholas Piggin         if (env->msr_mask & MSR_HVB) {
40610c21b5cSNicholas Piggin             /* ISA specifies HV, but can be delivered to guest with HV clear
40710c21b5cSNicholas Piggin              * (e.g., see FWNMI in PAPR, NMI injection in QEMU).
40810c21b5cSNicholas Piggin              */
409c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
41010c21b5cSNicholas Piggin         } else {
41110c21b5cSNicholas Piggin             if (msr_pow) {
41210c21b5cSNicholas Piggin                 cpu_abort(cs, "Trying to deliver power-saving system reset "
41310c21b5cSNicholas Piggin                           "exception %d with no HV support\n", excp);
41410c21b5cSNicholas Piggin             }
41510c21b5cSNicholas Piggin         }
4165c94b2a5SCédric Le Goater         ail = 0;
417bd6fefe7SBenjamin Herrenschmidt         break;
418c79c73f6SBlue Swirl     case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
419c79c73f6SBlue Swirl     case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
420c79c73f6SBlue Swirl     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
421bd6fefe7SBenjamin Herrenschmidt         break;
422bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
423c79c73f6SBlue Swirl     case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
424c79c73f6SBlue Swirl     case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
425c79c73f6SBlue Swirl     case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
426c79c73f6SBlue Swirl     case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
4277af1e7b0SCédric Le Goater     case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
428bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_HV_EMU:
429c79c73f6SBlue Swirl         srr0 = SPR_HSRR0;
430c79c73f6SBlue Swirl         srr1 = SPR_HSRR1;
431c79c73f6SBlue Swirl         new_msr |= (target_ulong)MSR_HVB;
432c79c73f6SBlue Swirl         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
433bd6fefe7SBenjamin Herrenschmidt         break;
434c79c73f6SBlue Swirl     case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
4351f29871cSTom Musta     case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
4367019cb3dSAlexey Kardashevskiy     case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
4375310799aSBalbir Singh #ifdef TARGET_PPC64
4385310799aSBalbir Singh         env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
4395310799aSBalbir Singh #endif
440bd6fefe7SBenjamin Herrenschmidt         break;
441c79c73f6SBlue Swirl     case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
442c79c73f6SBlue Swirl         LOG_EXCP("PIT exception\n");
443bd6fefe7SBenjamin Herrenschmidt         break;
444c79c73f6SBlue Swirl     case POWERPC_EXCP_IO:        /* IO error exception                       */
445c79c73f6SBlue Swirl         /* XXX: TODO */
446a47dddd7SAndreas Färber         cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
447bd6fefe7SBenjamin Herrenschmidt         break;
448c79c73f6SBlue Swirl     case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
449c79c73f6SBlue Swirl         /* XXX: TODO */
450a47dddd7SAndreas Färber         cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
451bd6fefe7SBenjamin Herrenschmidt         break;
452c79c73f6SBlue Swirl     case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
453c79c73f6SBlue Swirl         /* XXX: TODO */
454a47dddd7SAndreas Färber         cpu_abort(cs, "602 emulation trap exception "
455c79c73f6SBlue Swirl                   "is not implemented yet !\n");
456bd6fefe7SBenjamin Herrenschmidt         break;
457c79c73f6SBlue Swirl     case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
458c79c73f6SBlue Swirl         switch (excp_model) {
459c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
460c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
461c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
462c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
463c79c73f6SBlue Swirl             goto tlb_miss_tgpr;
464c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
465c79c73f6SBlue Swirl             goto tlb_miss;
466c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
467c79c73f6SBlue Swirl             goto tlb_miss_74xx;
468c79c73f6SBlue Swirl         default:
469a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid instruction TLB miss exception\n");
470c79c73f6SBlue Swirl             break;
471c79c73f6SBlue Swirl         }
472c79c73f6SBlue Swirl         break;
473c79c73f6SBlue Swirl     case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
474c79c73f6SBlue Swirl         switch (excp_model) {
475c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
476c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
477c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
478c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
479c79c73f6SBlue Swirl             goto tlb_miss_tgpr;
480c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
481c79c73f6SBlue Swirl             goto tlb_miss;
482c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
483c79c73f6SBlue Swirl             goto tlb_miss_74xx;
484c79c73f6SBlue Swirl         default:
485a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid data load TLB miss exception\n");
486c79c73f6SBlue Swirl             break;
487c79c73f6SBlue Swirl         }
488c79c73f6SBlue Swirl         break;
489c79c73f6SBlue Swirl     case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
490c79c73f6SBlue Swirl         switch (excp_model) {
491c79c73f6SBlue Swirl         case POWERPC_EXCP_602:
492c79c73f6SBlue Swirl         case POWERPC_EXCP_603:
493c79c73f6SBlue Swirl         case POWERPC_EXCP_603E:
494c79c73f6SBlue Swirl         case POWERPC_EXCP_G2:
495c79c73f6SBlue Swirl         tlb_miss_tgpr:
496c79c73f6SBlue Swirl             /* Swap temporary saved registers with GPRs */
497c79c73f6SBlue Swirl             if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
498c79c73f6SBlue Swirl                 new_msr |= (target_ulong)1 << MSR_TGPR;
499c79c73f6SBlue Swirl                 hreg_swap_gpr_tgpr(env);
500c79c73f6SBlue Swirl             }
501c79c73f6SBlue Swirl             goto tlb_miss;
502c79c73f6SBlue Swirl         case POWERPC_EXCP_7x5:
503c79c73f6SBlue Swirl         tlb_miss:
504c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB)
505c79c73f6SBlue Swirl             if (qemu_log_enabled()) {
506c79c73f6SBlue Swirl                 const char *es;
507c79c73f6SBlue Swirl                 target_ulong *miss, *cmp;
508c79c73f6SBlue Swirl                 int en;
509c79c73f6SBlue Swirl 
510c79c73f6SBlue Swirl                 if (excp == POWERPC_EXCP_IFTLB) {
511c79c73f6SBlue Swirl                     es = "I";
512c79c73f6SBlue Swirl                     en = 'I';
513c79c73f6SBlue Swirl                     miss = &env->spr[SPR_IMISS];
514c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_ICMP];
515c79c73f6SBlue Swirl                 } else {
516c79c73f6SBlue Swirl                     if (excp == POWERPC_EXCP_DLTLB) {
517c79c73f6SBlue Swirl                         es = "DL";
518c79c73f6SBlue Swirl                     } else {
519c79c73f6SBlue Swirl                         es = "DS";
520c79c73f6SBlue Swirl                     }
521c79c73f6SBlue Swirl                     en = 'D';
522c79c73f6SBlue Swirl                     miss = &env->spr[SPR_DMISS];
523c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_DCMP];
524c79c73f6SBlue Swirl                 }
525c79c73f6SBlue Swirl                 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
526c79c73f6SBlue Swirl                          TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
527c79c73f6SBlue Swirl                          TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
528c79c73f6SBlue Swirl                          env->spr[SPR_HASH1], env->spr[SPR_HASH2],
529c79c73f6SBlue Swirl                          env->error_code);
530c79c73f6SBlue Swirl             }
531c79c73f6SBlue Swirl #endif
532c79c73f6SBlue Swirl             msr |= env->crf[0] << 28;
533c79c73f6SBlue Swirl             msr |= env->error_code; /* key, D/I, S/L bits */
534c79c73f6SBlue Swirl             /* Set way using a LRU mechanism */
535c79c73f6SBlue Swirl             msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
536c79c73f6SBlue Swirl             break;
537c79c73f6SBlue Swirl         case POWERPC_EXCP_74xx:
538c79c73f6SBlue Swirl         tlb_miss_74xx:
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_TLBMISS];
549c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_PTEHI];
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_TLBMISS];
558c79c73f6SBlue Swirl                     cmp = &env->spr[SPR_PTEHI];
559c79c73f6SBlue Swirl                 }
560c79c73f6SBlue Swirl                 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
561c79c73f6SBlue Swirl                          TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
562c79c73f6SBlue Swirl                          env->error_code);
563c79c73f6SBlue Swirl             }
564c79c73f6SBlue Swirl #endif
565c79c73f6SBlue Swirl             msr |= env->error_code; /* key bit */
566c79c73f6SBlue Swirl             break;
567c79c73f6SBlue Swirl         default:
568a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid data store TLB miss exception\n");
569c79c73f6SBlue Swirl             break;
570c79c73f6SBlue Swirl         }
571bd6fefe7SBenjamin Herrenschmidt         break;
572c79c73f6SBlue Swirl     case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
573c79c73f6SBlue Swirl         /* XXX: TODO */
574a47dddd7SAndreas Färber         cpu_abort(cs, "Floating point assist exception "
575c79c73f6SBlue Swirl                   "is not implemented yet !\n");
576bd6fefe7SBenjamin Herrenschmidt         break;
577c79c73f6SBlue Swirl     case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
578c79c73f6SBlue Swirl         /* XXX: TODO */
579a47dddd7SAndreas Färber         cpu_abort(cs, "DABR exception is not implemented yet !\n");
580bd6fefe7SBenjamin Herrenschmidt         break;
581c79c73f6SBlue Swirl     case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
582c79c73f6SBlue Swirl         /* XXX: TODO */
583a47dddd7SAndreas Färber         cpu_abort(cs, "IABR exception is not implemented yet !\n");
584bd6fefe7SBenjamin Herrenschmidt         break;
585c79c73f6SBlue Swirl     case POWERPC_EXCP_SMI:       /* System management interrupt              */
586c79c73f6SBlue Swirl         /* XXX: TODO */
587a47dddd7SAndreas Färber         cpu_abort(cs, "SMI exception is not implemented yet !\n");
588bd6fefe7SBenjamin Herrenschmidt         break;
589c79c73f6SBlue Swirl     case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
590c79c73f6SBlue Swirl         /* XXX: TODO */
591a47dddd7SAndreas Färber         cpu_abort(cs, "Thermal management exception "
592c79c73f6SBlue Swirl                   "is not implemented yet !\n");
593bd6fefe7SBenjamin Herrenschmidt         break;
594c79c73f6SBlue Swirl     case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
595c79c73f6SBlue Swirl         /* XXX: TODO */
596a47dddd7SAndreas Färber         cpu_abort(cs,
597c79c73f6SBlue Swirl                   "Performance counter exception is not implemented yet !\n");
598bd6fefe7SBenjamin Herrenschmidt         break;
599c79c73f6SBlue Swirl     case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
600c79c73f6SBlue Swirl         /* XXX: TODO */
601a47dddd7SAndreas Färber         cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
602bd6fefe7SBenjamin Herrenschmidt         break;
603c79c73f6SBlue Swirl     case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
604c79c73f6SBlue Swirl         /* XXX: TODO */
605a47dddd7SAndreas Färber         cpu_abort(cs,
606c79c73f6SBlue Swirl                   "970 soft-patch exception is not implemented yet !\n");
607bd6fefe7SBenjamin Herrenschmidt         break;
608c79c73f6SBlue Swirl     case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
609c79c73f6SBlue Swirl         /* XXX: TODO */
610a47dddd7SAndreas Färber         cpu_abort(cs,
611c79c73f6SBlue Swirl                   "970 maintenance exception is not implemented yet !\n");
612bd6fefe7SBenjamin Herrenschmidt         break;
613c79c73f6SBlue Swirl     case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
614c79c73f6SBlue Swirl         /* XXX: TODO */
615a47dddd7SAndreas Färber         cpu_abort(cs, "Maskable external exception "
616c79c73f6SBlue Swirl                   "is not implemented yet !\n");
617bd6fefe7SBenjamin Herrenschmidt         break;
618c79c73f6SBlue Swirl     case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
619c79c73f6SBlue Swirl         /* XXX: TODO */
620a47dddd7SAndreas Färber         cpu_abort(cs, "Non maskable external exception "
621c79c73f6SBlue Swirl                   "is not implemented yet !\n");
622bd6fefe7SBenjamin Herrenschmidt         break;
623c79c73f6SBlue Swirl     default:
624c79c73f6SBlue Swirl     excp_invalid:
625a47dddd7SAndreas Färber         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
626c79c73f6SBlue Swirl         break;
627c79c73f6SBlue Swirl     }
628bd6fefe7SBenjamin Herrenschmidt 
629bd6fefe7SBenjamin Herrenschmidt     /* Save PC */
630bd6fefe7SBenjamin Herrenschmidt     env->spr[srr0] = env->nip;
631bd6fefe7SBenjamin Herrenschmidt 
632c79c73f6SBlue Swirl     /* Save MSR */
633c79c73f6SBlue Swirl     env->spr[srr1] = msr;
6346d49d6d4SBenjamin Herrenschmidt 
6356d49d6d4SBenjamin Herrenschmidt     /* Sanity check */
63610c21b5cSNicholas Piggin     if (!(env->msr_mask & MSR_HVB)) {
63710c21b5cSNicholas Piggin         if (new_msr & MSR_HVB) {
63810c21b5cSNicholas Piggin             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
6396d49d6d4SBenjamin Herrenschmidt                       "no HV support\n", excp);
6406d49d6d4SBenjamin Herrenschmidt         }
64110c21b5cSNicholas Piggin         if (srr0 == SPR_HSRR0) {
64210c21b5cSNicholas Piggin             cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
64310c21b5cSNicholas Piggin                       "no HV support\n", excp);
64410c21b5cSNicholas Piggin         }
64510c21b5cSNicholas Piggin     }
6466d49d6d4SBenjamin Herrenschmidt 
647c79c73f6SBlue Swirl     /* If any alternate SRR register are defined, duplicate saved values */
648c79c73f6SBlue Swirl     if (asrr0 != -1) {
649c79c73f6SBlue Swirl         env->spr[asrr0] = env->spr[srr0];
650c79c73f6SBlue Swirl     }
651c79c73f6SBlue Swirl     if (asrr1 != -1) {
652c79c73f6SBlue Swirl         env->spr[asrr1] = env->spr[srr1];
653c79c73f6SBlue Swirl     }
654d5ac4f54SAlexey Kardashevskiy 
6556d49d6d4SBenjamin Herrenschmidt     /* Sort out endianness of interrupt, this differs depending on the
6566d49d6d4SBenjamin Herrenschmidt      * CPU, the HV mode, etc...
6576d49d6d4SBenjamin Herrenschmidt      */
6581e0c7e55SAnton Blanchard #ifdef TARGET_PPC64
6596d49d6d4SBenjamin Herrenschmidt     if (excp_model == POWERPC_EXCP_POWER7) {
6606d49d6d4SBenjamin Herrenschmidt         if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) {
6616d49d6d4SBenjamin Herrenschmidt             new_msr |= (target_ulong)1 << MSR_LE;
6626d49d6d4SBenjamin Herrenschmidt         }
6636d49d6d4SBenjamin Herrenschmidt     } else if (excp_model == POWERPC_EXCP_POWER8) {
6646d49d6d4SBenjamin Herrenschmidt         if (new_msr & MSR_HVB) {
6650bfc0cf0SCédric Le Goater             if (env->spr[SPR_HID0] & (HID0_HILE | HID0_POWER9_HILE)) {
6666d49d6d4SBenjamin Herrenschmidt                 new_msr |= (target_ulong)1 << MSR_LE;
6676d49d6d4SBenjamin Herrenschmidt             }
6686d49d6d4SBenjamin Herrenschmidt         } else if (env->spr[SPR_LPCR] & LPCR_ILE) {
6691e0c7e55SAnton Blanchard             new_msr |= (target_ulong)1 << MSR_LE;
6701e0c7e55SAnton Blanchard         }
6711e0c7e55SAnton Blanchard     } else if (msr_ile) {
6721e0c7e55SAnton Blanchard         new_msr |= (target_ulong)1 << MSR_LE;
6731e0c7e55SAnton Blanchard     }
6741e0c7e55SAnton Blanchard #else
675c79c73f6SBlue Swirl     if (msr_ile) {
676c79c73f6SBlue Swirl         new_msr |= (target_ulong)1 << MSR_LE;
677c79c73f6SBlue Swirl     }
6781e0c7e55SAnton Blanchard #endif
679c79c73f6SBlue Swirl 
680c79c73f6SBlue Swirl     /* Jump to handler */
681c79c73f6SBlue Swirl     vector = env->excp_vectors[excp];
682c79c73f6SBlue Swirl     if (vector == (target_ulong)-1ULL) {
683a47dddd7SAndreas Färber         cpu_abort(cs, "Raised an exception without defined vector %d\n",
684c79c73f6SBlue Swirl                   excp);
685c79c73f6SBlue Swirl     }
686c79c73f6SBlue Swirl     vector |= env->excp_prefix;
6875c94b2a5SCédric Le Goater 
6885c94b2a5SCédric Le Goater     /* AIL only works if there is no HV transition and we are running with
6895c94b2a5SCédric Le Goater      * translations enabled
6905c94b2a5SCédric Le Goater      */
6916d49d6d4SBenjamin Herrenschmidt     if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) ||
6926d49d6d4SBenjamin Herrenschmidt         ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) {
6935c94b2a5SCédric Le Goater         ail = 0;
6945c94b2a5SCédric Le Goater     }
6955c94b2a5SCédric Le Goater     /* Handle AIL */
6965c94b2a5SCédric Le Goater     if (ail) {
6975c94b2a5SCédric Le Goater         new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
6985c94b2a5SCédric Le Goater         switch(ail) {
6995c94b2a5SCédric Le Goater         case AIL_0001_8000:
7005c94b2a5SCédric Le Goater             vector |= 0x18000;
7015c94b2a5SCédric Le Goater             break;
7025c94b2a5SCédric Le Goater         case AIL_C000_0000_0000_4000:
7035c94b2a5SCédric Le Goater             vector |= 0xc000000000004000ull;
7045c94b2a5SCédric Le Goater             break;
7055c94b2a5SCédric Le Goater         default:
7065c94b2a5SCédric Le Goater             cpu_abort(cs, "Invalid AIL combination %d\n", ail);
7075c94b2a5SCédric Le Goater             break;
7085c94b2a5SCédric Le Goater         }
7095c94b2a5SCédric Le Goater     }
7105c94b2a5SCédric Le Goater 
711c79c73f6SBlue Swirl #if defined(TARGET_PPC64)
712c79c73f6SBlue Swirl     if (excp_model == POWERPC_EXCP_BOOKE) {
713e42a61f1SAlexander Graf         if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
714e42a61f1SAlexander Graf             /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
715c79c73f6SBlue Swirl             new_msr |= (target_ulong)1 << MSR_CM;
716e42a61f1SAlexander Graf         } else {
717e42a61f1SAlexander Graf             vector = (uint32_t)vector;
718c79c73f6SBlue Swirl         }
719c79c73f6SBlue Swirl     } else {
720c79c73f6SBlue Swirl         if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
721c79c73f6SBlue Swirl             vector = (uint32_t)vector;
722c79c73f6SBlue Swirl         } else {
723c79c73f6SBlue Swirl             new_msr |= (target_ulong)1 << MSR_SF;
724c79c73f6SBlue Swirl         }
725c79c73f6SBlue Swirl     }
726c79c73f6SBlue Swirl #endif
7271c953ba5SBenjamin Herrenschmidt     /* We don't use hreg_store_msr here as already have treated
728c79c73f6SBlue Swirl      * any special case that could occur. Just store MSR and update hflags
7291c953ba5SBenjamin Herrenschmidt      *
7301c953ba5SBenjamin Herrenschmidt      * Note: We *MUST* not use hreg_store_msr() as-is anyway because it
7311c953ba5SBenjamin Herrenschmidt      * will prevent setting of the HV bit which some exceptions might need
7321c953ba5SBenjamin Herrenschmidt      * to do.
733c79c73f6SBlue Swirl      */
734c79c73f6SBlue Swirl     env->msr = new_msr & env->msr_mask;
735c79c73f6SBlue Swirl     hreg_compute_hflags(env);
736c79c73f6SBlue Swirl     env->nip = vector;
737c79c73f6SBlue Swirl     /* Reset exception state */
73827103424SAndreas Färber     cs->exception_index = POWERPC_EXCP_NONE;
739c79c73f6SBlue Swirl     env->error_code = 0;
740cd0c6f47SBenjamin Herrenschmidt 
741139d9023SNikunj A Dadhania     /* Reset the reservation */
742139d9023SNikunj A Dadhania     env->reserve_addr = -1;
743139d9023SNikunj A Dadhania 
744cd0c6f47SBenjamin Herrenschmidt     /* Any interrupt is context synchronizing, check if TCG TLB
745cd0c6f47SBenjamin Herrenschmidt      * needs a delayed flush on ppc64
746cd0c6f47SBenjamin Herrenschmidt      */
747e3cffe6fSNikunj A Dadhania     check_tlb_flush(env, false);
748c79c73f6SBlue Swirl }
749c79c73f6SBlue Swirl 
75097a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs)
751c79c73f6SBlue Swirl {
75297a8ea5aSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(cs);
75397a8ea5aSAndreas Färber     CPUPPCState *env = &cpu->env;
7545c26a5b3SAndreas Färber 
75527103424SAndreas Färber     powerpc_excp(cpu, env->excp_model, cs->exception_index);
756c79c73f6SBlue Swirl }
757c79c73f6SBlue Swirl 
758458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env)
759c79c73f6SBlue Swirl {
7605c26a5b3SAndreas Färber     PowerPCCPU *cpu = ppc_env_get_cpu(env);
7613621e2c9SBenjamin Herrenschmidt     bool async_deliver;
762259186a7SAndreas Färber 
763c79c73f6SBlue Swirl     /* External reset */
764c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
765c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
7665c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
767c79c73f6SBlue Swirl         return;
768c79c73f6SBlue Swirl     }
769c79c73f6SBlue Swirl     /* Machine check exception */
770c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
771c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
7725c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
773c79c73f6SBlue Swirl         return;
774c79c73f6SBlue Swirl     }
775c79c73f6SBlue Swirl #if 0 /* TODO */
776c79c73f6SBlue Swirl     /* External debug exception */
777c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
778c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
7795c26a5b3SAndreas Färber         powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
780c79c73f6SBlue Swirl         return;
781c79c73f6SBlue Swirl     }
782c79c73f6SBlue Swirl #endif
7833621e2c9SBenjamin Herrenschmidt 
7843621e2c9SBenjamin Herrenschmidt     /*
7853621e2c9SBenjamin Herrenschmidt      * For interrupts that gate on MSR:EE, we need to do something a
7863621e2c9SBenjamin Herrenschmidt      * bit more subtle, as we need to let them through even when EE is
7873621e2c9SBenjamin Herrenschmidt      * clear when coming out of some power management states (in order
7883621e2c9SBenjamin Herrenschmidt      * for them to become a 0x100).
7893621e2c9SBenjamin Herrenschmidt      */
790*1e7fd61dSBenjamin Herrenschmidt     async_deliver = (msr_ee != 0) || env->resume_as_sreset;
7913621e2c9SBenjamin Herrenschmidt 
792c79c73f6SBlue Swirl     /* Hypervisor decrementer exception */
793c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
7944b236b62SBenjamin Herrenschmidt         /* LPCR will be clear when not supported so this will work */
7954b236b62SBenjamin Herrenschmidt         bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
7963621e2c9SBenjamin Herrenschmidt         if ((async_deliver || msr_hv == 0) && hdice) {
7974b236b62SBenjamin Herrenschmidt             /* HDEC clears on delivery */
7984b236b62SBenjamin Herrenschmidt             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
7995c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
800c79c73f6SBlue Swirl             return;
801c79c73f6SBlue Swirl         }
802c79c73f6SBlue Swirl     }
803d1dbe37cSBenjamin Herrenschmidt     /* Extermal interrupt can ignore MSR:EE under some circumstances */
804d1dbe37cSBenjamin Herrenschmidt     if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
805d1dbe37cSBenjamin Herrenschmidt         bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
8063621e2c9SBenjamin Herrenschmidt         if (async_deliver || (env->has_hv_mode && msr_hv == 0 && !lpes0)) {
807d1dbe37cSBenjamin Herrenschmidt             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
808d1dbe37cSBenjamin Herrenschmidt             return;
809d1dbe37cSBenjamin Herrenschmidt         }
810d1dbe37cSBenjamin Herrenschmidt     }
811c79c73f6SBlue Swirl     if (msr_ce != 0) {
812c79c73f6SBlue Swirl         /* External critical interrupt */
813c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
8145c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
815c79c73f6SBlue Swirl             return;
816c79c73f6SBlue Swirl         }
817c79c73f6SBlue Swirl     }
8183621e2c9SBenjamin Herrenschmidt     if (async_deliver != 0) {
819c79c73f6SBlue Swirl         /* Watchdog timer on embedded PowerPC */
820c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
821c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
8225c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
823c79c73f6SBlue Swirl             return;
824c79c73f6SBlue Swirl         }
825c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
826c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
8275c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
828c79c73f6SBlue Swirl             return;
829c79c73f6SBlue Swirl         }
830c79c73f6SBlue Swirl         /* Fixed interval timer on embedded PowerPC */
831c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
832c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
8335c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
834c79c73f6SBlue Swirl             return;
835c79c73f6SBlue Swirl         }
836c79c73f6SBlue Swirl         /* Programmable interval timer on embedded PowerPC */
837c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
838c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
8395c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
840c79c73f6SBlue Swirl             return;
841c79c73f6SBlue Swirl         }
842c79c73f6SBlue Swirl         /* Decrementer exception */
843c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
844e81a982aSAlexander Graf             if (ppc_decr_clear_on_delivery(env)) {
845c79c73f6SBlue Swirl                 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
846e81a982aSAlexander Graf             }
8475c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
848c79c73f6SBlue Swirl             return;
849c79c73f6SBlue Swirl         }
850c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
851c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
8525c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
853c79c73f6SBlue Swirl             return;
854c79c73f6SBlue Swirl         }
8557af1e7b0SCédric Le Goater         if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) {
8567af1e7b0SCédric Le Goater             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
8577af1e7b0SCédric Le Goater             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV);
8587af1e7b0SCédric Le Goater             return;
8597af1e7b0SCédric Le Goater         }
860c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
861c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
8625c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
863c79c73f6SBlue Swirl             return;
864c79c73f6SBlue Swirl         }
865c79c73f6SBlue Swirl         /* Thermal interrupt */
866c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
867c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
8685c26a5b3SAndreas Färber             powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
869c79c73f6SBlue Swirl             return;
870c79c73f6SBlue Swirl         }
871c79c73f6SBlue Swirl     }
872c79c73f6SBlue Swirl }
87334316482SAlexey Kardashevskiy 
87434316482SAlexey Kardashevskiy void ppc_cpu_do_system_reset(CPUState *cs)
87534316482SAlexey Kardashevskiy {
87634316482SAlexey Kardashevskiy     PowerPCCPU *cpu = POWERPC_CPU(cs);
87734316482SAlexey Kardashevskiy     CPUPPCState *env = &cpu->env;
87834316482SAlexey Kardashevskiy 
87934316482SAlexey Kardashevskiy     powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
88034316482SAlexey Kardashevskiy }
881c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */
882c79c73f6SBlue Swirl 
883458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
884458dd766SRichard Henderson {
885458dd766SRichard Henderson     PowerPCCPU *cpu = POWERPC_CPU(cs);
886458dd766SRichard Henderson     CPUPPCState *env = &cpu->env;
887458dd766SRichard Henderson 
888458dd766SRichard Henderson     if (interrupt_request & CPU_INTERRUPT_HARD) {
889458dd766SRichard Henderson         ppc_hw_interrupt(env);
890458dd766SRichard Henderson         if (env->pending_interrupts == 0) {
891458dd766SRichard Henderson             cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
892458dd766SRichard Henderson         }
893458dd766SRichard Henderson         return true;
894458dd766SRichard Henderson     }
895458dd766SRichard Henderson     return false;
896458dd766SRichard Henderson }
897458dd766SRichard Henderson 
898c79c73f6SBlue Swirl #if defined(DEBUG_OP)
899c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
900c79c73f6SBlue Swirl {
901c79c73f6SBlue Swirl     qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
902c79c73f6SBlue Swirl              TARGET_FMT_lx "\n", RA, msr);
903c79c73f6SBlue Swirl }
904c79c73f6SBlue Swirl #endif
905c79c73f6SBlue Swirl 
906ad71ed68SBlue Swirl /*****************************************************************************/
907ad71ed68SBlue Swirl /* Exceptions processing helpers */
908ad71ed68SBlue Swirl 
909db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
910db789c6cSBenjamin Herrenschmidt                             uint32_t error_code, uintptr_t raddr)
911ad71ed68SBlue Swirl {
91227103424SAndreas Färber     CPUState *cs = CPU(ppc_env_get_cpu(env));
91327103424SAndreas Färber 
91427103424SAndreas Färber     cs->exception_index = exception;
915ad71ed68SBlue Swirl     env->error_code = error_code;
916db789c6cSBenjamin Herrenschmidt     cpu_loop_exit_restore(cs, raddr);
917db789c6cSBenjamin Herrenschmidt }
918db789c6cSBenjamin Herrenschmidt 
919db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception,
920db789c6cSBenjamin Herrenschmidt                          uint32_t error_code)
921db789c6cSBenjamin Herrenschmidt {
922db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, error_code, 0);
923db789c6cSBenjamin Herrenschmidt }
924db789c6cSBenjamin Herrenschmidt 
925db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception)
926db789c6cSBenjamin Herrenschmidt {
927db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, 0);
928db789c6cSBenjamin Herrenschmidt }
929db789c6cSBenjamin Herrenschmidt 
930db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception,
931db789c6cSBenjamin Herrenschmidt                         uintptr_t raddr)
932db789c6cSBenjamin Herrenschmidt {
933db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, raddr);
934db789c6cSBenjamin Herrenschmidt }
935db789c6cSBenjamin Herrenschmidt 
936db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
937db789c6cSBenjamin Herrenschmidt                                 uint32_t error_code)
938db789c6cSBenjamin Herrenschmidt {
939db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, error_code, 0);
940ad71ed68SBlue Swirl }
941ad71ed68SBlue Swirl 
942e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception)
943ad71ed68SBlue Swirl {
944db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, 0);
945ad71ed68SBlue Swirl }
946ad71ed68SBlue Swirl 
947ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY)
948e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val)
949ad71ed68SBlue Swirl {
950db789c6cSBenjamin Herrenschmidt     uint32_t excp = hreg_store_msr(env, val, 0);
951259186a7SAndreas Färber 
952db789c6cSBenjamin Herrenschmidt     if (excp != 0) {
953db789c6cSBenjamin Herrenschmidt         CPUState *cs = CPU(ppc_env_get_cpu(env));
954044897efSRichard Purdie         cpu_interrupt_exittb(cs);
955db789c6cSBenjamin Herrenschmidt         raise_exception(env, excp);
956ad71ed68SBlue Swirl     }
957ad71ed68SBlue Swirl }
958ad71ed68SBlue Swirl 
9597778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64)
9607778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
9617778a575SBenjamin Herrenschmidt {
9627778a575SBenjamin Herrenschmidt     CPUState *cs;
9637778a575SBenjamin Herrenschmidt 
9647778a575SBenjamin Herrenschmidt     cs = CPU(ppc_env_get_cpu(env));
9657778a575SBenjamin Herrenschmidt     cs->halted = 1;
9667778a575SBenjamin Herrenschmidt 
9674b236b62SBenjamin Herrenschmidt     /* The architecture specifies that HDEC interrupts are
9684b236b62SBenjamin Herrenschmidt      * discarded in PM states
9694b236b62SBenjamin Herrenschmidt      */
9704b236b62SBenjamin Herrenschmidt     env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
9714b236b62SBenjamin Herrenschmidt 
9723621e2c9SBenjamin Herrenschmidt     /* Condition for waking up at 0x100 */
973*1e7fd61dSBenjamin Herrenschmidt     env->resume_as_sreset = (insn != PPC_PM_STOP) ||
97421c0d66aSBenjamin Herrenschmidt         (env->spr[SPR_PSSCR] & PSSCR_EC);
9757778a575SBenjamin Herrenschmidt }
9767778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */
9777778a575SBenjamin Herrenschmidt 
978a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
979ad71ed68SBlue Swirl {
980259186a7SAndreas Färber     CPUState *cs = CPU(ppc_env_get_cpu(env));
981259186a7SAndreas Färber 
982a2e71b28SBenjamin Herrenschmidt     /* MSR:POW cannot be set by any form of rfi */
983a2e71b28SBenjamin Herrenschmidt     msr &= ~(1ULL << MSR_POW);
984a2e71b28SBenjamin Herrenschmidt 
985ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
986a2e71b28SBenjamin Herrenschmidt     /* Switching to 32-bit ? Crop the nip */
987a2e71b28SBenjamin Herrenschmidt     if (!msr_is_64bit(env, msr)) {
988ad71ed68SBlue Swirl         nip = (uint32_t)nip;
989ad71ed68SBlue Swirl     }
990ad71ed68SBlue Swirl #else
991ad71ed68SBlue Swirl     nip = (uint32_t)nip;
992ad71ed68SBlue Swirl #endif
993ad71ed68SBlue Swirl     /* XXX: beware: this is false if VLE is supported */
994ad71ed68SBlue Swirl     env->nip = nip & ~((target_ulong)0x00000003);
995ad71ed68SBlue Swirl     hreg_store_msr(env, msr, 1);
996ad71ed68SBlue Swirl #if defined(DEBUG_OP)
997ad71ed68SBlue Swirl     cpu_dump_rfi(env->nip, env->msr);
998ad71ed68SBlue Swirl #endif
999ad71ed68SBlue Swirl     /* No need to raise an exception here,
1000ad71ed68SBlue Swirl      * as rfi is always the last insn of a TB
1001ad71ed68SBlue Swirl      */
1002044897efSRichard Purdie     cpu_interrupt_exittb(cs);
1003a8b73734SNikunj A Dadhania     /* Reset the reservation */
1004a8b73734SNikunj A Dadhania     env->reserve_addr = -1;
1005a8b73734SNikunj A Dadhania 
1006cd0c6f47SBenjamin Herrenschmidt     /* Context synchronizing: check if TCG TLB needs flush */
1007e3cffe6fSNikunj A Dadhania     check_tlb_flush(env, false);
1008ad71ed68SBlue Swirl }
1009ad71ed68SBlue Swirl 
1010e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env)
1011ad71ed68SBlue Swirl {
1012a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful);
1013a1bb7384SScott Wood }
1014ad71ed68SBlue Swirl 
1015a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK
1016ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1017e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env)
1018ad71ed68SBlue Swirl {
1019a2e71b28SBenjamin Herrenschmidt     /* The architeture defines a number of rules for which bits
1020a2e71b28SBenjamin Herrenschmidt      * can change but in practice, we handle this in hreg_store_msr()
1021a2e71b28SBenjamin Herrenschmidt      * which will be called by do_rfi(), so there is no need to filter
1022a2e71b28SBenjamin Herrenschmidt      * here
1023a2e71b28SBenjamin Herrenschmidt      */
1024a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
1025ad71ed68SBlue Swirl }
1026ad71ed68SBlue Swirl 
1027e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env)
1028ad71ed68SBlue Swirl {
1029a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
1030ad71ed68SBlue Swirl }
1031ad71ed68SBlue Swirl #endif
1032ad71ed68SBlue Swirl 
1033ad71ed68SBlue Swirl /*****************************************************************************/
1034ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */
1035e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env)
1036ad71ed68SBlue Swirl {
1037a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]);
1038ad71ed68SBlue Swirl }
1039ad71ed68SBlue Swirl 
1040e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env)
1041ad71ed68SBlue Swirl {
1042a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]);
1043ad71ed68SBlue Swirl }
1044ad71ed68SBlue Swirl 
1045e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env)
1046ad71ed68SBlue Swirl {
1047a1bb7384SScott Wood     /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
1048a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]);
1049ad71ed68SBlue Swirl }
1050ad71ed68SBlue Swirl 
1051e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env)
1052ad71ed68SBlue Swirl {
1053a1bb7384SScott Wood     /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
1054a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]);
1055ad71ed68SBlue Swirl }
1056ad71ed68SBlue Swirl #endif
1057ad71ed68SBlue Swirl 
1058e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1059e5f17ac6SBlue Swirl                uint32_t flags)
1060ad71ed68SBlue Swirl {
1061ad71ed68SBlue Swirl     if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1062ad71ed68SBlue Swirl                   ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1063ad71ed68SBlue Swirl                   ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1064ad71ed68SBlue Swirl                   ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1065ad71ed68SBlue Swirl                   ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
106672073dccSBenjamin Herrenschmidt         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
106772073dccSBenjamin Herrenschmidt                                POWERPC_EXCP_TRAP, GETPC());
1068ad71ed68SBlue Swirl     }
1069ad71ed68SBlue Swirl }
1070ad71ed68SBlue Swirl 
1071ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
1072e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1073e5f17ac6SBlue Swirl                uint32_t flags)
1074ad71ed68SBlue Swirl {
1075ad71ed68SBlue Swirl     if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1076ad71ed68SBlue Swirl                   ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1077ad71ed68SBlue Swirl                   ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1078ad71ed68SBlue Swirl                   ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1079ad71ed68SBlue Swirl                   ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
108072073dccSBenjamin Herrenschmidt         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
108172073dccSBenjamin Herrenschmidt                                POWERPC_EXCP_TRAP, GETPC());
1082ad71ed68SBlue Swirl     }
1083ad71ed68SBlue Swirl }
1084ad71ed68SBlue Swirl #endif
1085ad71ed68SBlue Swirl 
1086ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1087ad71ed68SBlue Swirl /*****************************************************************************/
1088ad71ed68SBlue Swirl /* PowerPC 601 specific instructions (POWER bridge) */
1089ad71ed68SBlue Swirl 
1090e5f17ac6SBlue Swirl void helper_rfsvc(CPUPPCState *env)
1091ad71ed68SBlue Swirl {
1092a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->lr, env->ctr & 0x0000FFFF);
1093ad71ed68SBlue Swirl }
1094ad71ed68SBlue Swirl 
1095ad71ed68SBlue Swirl /* Embedded.Processor Control */
1096ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb)
1097ad71ed68SBlue Swirl {
1098ad71ed68SBlue Swirl     int msg = rb & DBELL_TYPE_MASK;
1099ad71ed68SBlue Swirl     int irq = -1;
1100ad71ed68SBlue Swirl 
1101ad71ed68SBlue Swirl     switch (msg) {
1102ad71ed68SBlue Swirl     case DBELL_TYPE_DBELL:
1103ad71ed68SBlue Swirl         irq = PPC_INTERRUPT_DOORBELL;
1104ad71ed68SBlue Swirl         break;
1105ad71ed68SBlue Swirl     case DBELL_TYPE_DBELL_CRIT:
1106ad71ed68SBlue Swirl         irq = PPC_INTERRUPT_CDOORBELL;
1107ad71ed68SBlue Swirl         break;
1108ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL:
1109ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL_CRIT:
1110ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL_MC:
1111ad71ed68SBlue Swirl         /* XXX implement */
1112ad71ed68SBlue Swirl     default:
1113ad71ed68SBlue Swirl         break;
1114ad71ed68SBlue Swirl     }
1115ad71ed68SBlue Swirl 
1116ad71ed68SBlue Swirl     return irq;
1117ad71ed68SBlue Swirl }
1118ad71ed68SBlue Swirl 
1119e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb)
1120ad71ed68SBlue Swirl {
1121ad71ed68SBlue Swirl     int irq = dbell2irq(rb);
1122ad71ed68SBlue Swirl 
1123ad71ed68SBlue Swirl     if (irq < 0) {
1124ad71ed68SBlue Swirl         return;
1125ad71ed68SBlue Swirl     }
1126ad71ed68SBlue Swirl 
1127ad71ed68SBlue Swirl     env->pending_interrupts &= ~(1 << irq);
1128ad71ed68SBlue Swirl }
1129ad71ed68SBlue Swirl 
1130ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb)
1131ad71ed68SBlue Swirl {
1132ad71ed68SBlue Swirl     int irq = dbell2irq(rb);
1133ad71ed68SBlue Swirl     int pir = rb & DBELL_PIRTAG_MASK;
1134182735efSAndreas Färber     CPUState *cs;
1135ad71ed68SBlue Swirl 
1136ad71ed68SBlue Swirl     if (irq < 0) {
1137ad71ed68SBlue Swirl         return;
1138ad71ed68SBlue Swirl     }
1139ad71ed68SBlue Swirl 
1140f1c29ebcSThomas Huth     qemu_mutex_lock_iothread();
1141bdc44640SAndreas Färber     CPU_FOREACH(cs) {
1142182735efSAndreas Färber         PowerPCCPU *cpu = POWERPC_CPU(cs);
1143182735efSAndreas Färber         CPUPPCState *cenv = &cpu->env;
1144182735efSAndreas Färber 
1145ad71ed68SBlue Swirl         if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
1146ad71ed68SBlue Swirl             cenv->pending_interrupts |= 1 << irq;
1147182735efSAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
1148ad71ed68SBlue Swirl         }
1149ad71ed68SBlue Swirl     }
1150f1c29ebcSThomas Huth     qemu_mutex_unlock_iothread();
1151ad71ed68SBlue Swirl }
11527af1e7b0SCédric Le Goater 
11537af1e7b0SCédric Le Goater /* Server Processor Control */
11547af1e7b0SCédric Le Goater static int book3s_dbell2irq(target_ulong rb)
11557af1e7b0SCédric Le Goater {
11567af1e7b0SCédric Le Goater     int msg = rb & DBELL_TYPE_MASK;
11577af1e7b0SCédric Le Goater 
11587af1e7b0SCédric Le Goater     /* A Directed Hypervisor Doorbell message is sent only if the
11597af1e7b0SCédric Le Goater      * message type is 5. All other types are reserved and the
11607af1e7b0SCédric Le Goater      * instruction is a no-op */
11617af1e7b0SCédric Le Goater     return msg == DBELL_TYPE_DBELL_SERVER ? PPC_INTERRUPT_HDOORBELL : -1;
11627af1e7b0SCédric Le Goater }
11637af1e7b0SCédric Le Goater 
11647af1e7b0SCédric Le Goater void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
11657af1e7b0SCédric Le Goater {
11667af1e7b0SCédric Le Goater     int irq = book3s_dbell2irq(rb);
11677af1e7b0SCédric Le Goater 
11687af1e7b0SCédric Le Goater     if (irq < 0) {
11697af1e7b0SCédric Le Goater         return;
11707af1e7b0SCédric Le Goater     }
11717af1e7b0SCédric Le Goater 
11727af1e7b0SCédric Le Goater     env->pending_interrupts &= ~(1 << irq);
11737af1e7b0SCédric Le Goater }
11747af1e7b0SCédric Le Goater 
11757af1e7b0SCédric Le Goater void helper_book3s_msgsnd(target_ulong rb)
11767af1e7b0SCédric Le Goater {
11777af1e7b0SCédric Le Goater     int irq = book3s_dbell2irq(rb);
11787af1e7b0SCédric Le Goater     int pir = rb & DBELL_PROCIDTAG_MASK;
11797af1e7b0SCédric Le Goater     CPUState *cs;
11807af1e7b0SCédric Le Goater 
11817af1e7b0SCédric Le Goater     if (irq < 0) {
11827af1e7b0SCédric Le Goater         return;
11837af1e7b0SCédric Le Goater     }
11847af1e7b0SCédric Le Goater 
11857af1e7b0SCédric Le Goater     qemu_mutex_lock_iothread();
11867af1e7b0SCédric Le Goater     CPU_FOREACH(cs) {
11877af1e7b0SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
11887af1e7b0SCédric Le Goater         CPUPPCState *cenv = &cpu->env;
11897af1e7b0SCédric Le Goater 
11907af1e7b0SCédric Le Goater         /* TODO: broadcast message to all threads of the same  processor */
11917af1e7b0SCédric Le Goater         if (cenv->spr_cb[SPR_PIR].default_value == pir) {
11927af1e7b0SCédric Le Goater             cenv->pending_interrupts |= 1 << irq;
11937af1e7b0SCédric Le Goater             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
11947af1e7b0SCédric Le Goater         }
11957af1e7b0SCédric Le Goater     }
11967af1e7b0SCédric Le Goater     qemu_mutex_unlock_iothread();
11977af1e7b0SCédric Le Goater }
1198ad71ed68SBlue Swirl #endif
11990f3110faSRichard Henderson 
12000f3110faSRichard Henderson void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
12010f3110faSRichard Henderson                                  MMUAccessType access_type,
12020f3110faSRichard Henderson                                  int mmu_idx, uintptr_t retaddr)
12030f3110faSRichard Henderson {
12040f3110faSRichard Henderson     CPUPPCState *env = cs->env_ptr;
12050f3110faSRichard Henderson     uint32_t insn;
12060f3110faSRichard Henderson 
12070f3110faSRichard Henderson     /* Restore state and reload the insn we executed, for filling in DSISR.  */
12080f3110faSRichard Henderson     cpu_restore_state(cs, retaddr, true);
12090f3110faSRichard Henderson     insn = cpu_ldl_code(env, env->nip);
12100f3110faSRichard Henderson 
12110f3110faSRichard Henderson     cs->exception_index = POWERPC_EXCP_ALIGN;
12120f3110faSRichard Henderson     env->error_code = insn & 0x03FF0000;
12130f3110faSRichard Henderson     cpu_loop_exit(cs);
12140f3110faSRichard Henderson }
1215