xref: /qemu/target/ppc/excp_helper.c (revision ccfca2fca5ef30078a3b8ed011556b55a098de8c)
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
96bd039cdSChetan Pant  * version 2.1 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"
2263c91552SPaolo Bonzini #include "exec/exec-all.h"
230f3110faSRichard Henderson #include "internal.h"
24ad71ed68SBlue Swirl #include "helper_regs.h"
25ad71ed68SBlue Swirl 
262eb1ef73SCédric Le Goater #include "trace.h"
272eb1ef73SCédric Le Goater 
282b44e219SBruno Larsen (billionai) #ifdef CONFIG_TCG
292b44e219SBruno Larsen (billionai) #include "exec/helper-proto.h"
302b44e219SBruno Larsen (billionai) #include "exec/cpu_ldst.h"
312b44e219SBruno Larsen (billionai) #endif
322b44e219SBruno Larsen (billionai) 
33c79c73f6SBlue Swirl /*****************************************************************************/
34c79c73f6SBlue Swirl /* Exception processing */
35f725245cSPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY)
3697a8ea5aSAndreas Färber 
376789f23bSCédric Le Goater static const char *powerpc_excp_name(int excp)
386789f23bSCédric Le Goater {
396789f23bSCédric Le Goater     switch (excp) {
406789f23bSCédric Le Goater     case POWERPC_EXCP_CRITICAL: return "CRITICAL";
416789f23bSCédric Le Goater     case POWERPC_EXCP_MCHECK:   return "MCHECK";
426789f23bSCédric Le Goater     case POWERPC_EXCP_DSI:      return "DSI";
436789f23bSCédric Le Goater     case POWERPC_EXCP_ISI:      return "ISI";
446789f23bSCédric Le Goater     case POWERPC_EXCP_EXTERNAL: return "EXTERNAL";
456789f23bSCédric Le Goater     case POWERPC_EXCP_ALIGN:    return "ALIGN";
466789f23bSCédric Le Goater     case POWERPC_EXCP_PROGRAM:  return "PROGRAM";
476789f23bSCédric Le Goater     case POWERPC_EXCP_FPU:      return "FPU";
486789f23bSCédric Le Goater     case POWERPC_EXCP_SYSCALL:  return "SYSCALL";
496789f23bSCédric Le Goater     case POWERPC_EXCP_APU:      return "APU";
506789f23bSCédric Le Goater     case POWERPC_EXCP_DECR:     return "DECR";
516789f23bSCédric Le Goater     case POWERPC_EXCP_FIT:      return "FIT";
526789f23bSCédric Le Goater     case POWERPC_EXCP_WDT:      return "WDT";
536789f23bSCédric Le Goater     case POWERPC_EXCP_DTLB:     return "DTLB";
546789f23bSCédric Le Goater     case POWERPC_EXCP_ITLB:     return "ITLB";
556789f23bSCédric Le Goater     case POWERPC_EXCP_DEBUG:    return "DEBUG";
566789f23bSCédric Le Goater     case POWERPC_EXCP_SPEU:     return "SPEU";
576789f23bSCédric Le Goater     case POWERPC_EXCP_EFPDI:    return "EFPDI";
586789f23bSCédric Le Goater     case POWERPC_EXCP_EFPRI:    return "EFPRI";
596789f23bSCédric Le Goater     case POWERPC_EXCP_EPERFM:   return "EPERFM";
606789f23bSCédric Le Goater     case POWERPC_EXCP_DOORI:    return "DOORI";
616789f23bSCédric Le Goater     case POWERPC_EXCP_DOORCI:   return "DOORCI";
626789f23bSCédric Le Goater     case POWERPC_EXCP_GDOORI:   return "GDOORI";
636789f23bSCédric Le Goater     case POWERPC_EXCP_GDOORCI:  return "GDOORCI";
646789f23bSCédric Le Goater     case POWERPC_EXCP_HYPPRIV:  return "HYPPRIV";
656789f23bSCédric Le Goater     case POWERPC_EXCP_RESET:    return "RESET";
666789f23bSCédric Le Goater     case POWERPC_EXCP_DSEG:     return "DSEG";
676789f23bSCédric Le Goater     case POWERPC_EXCP_ISEG:     return "ISEG";
686789f23bSCédric Le Goater     case POWERPC_EXCP_HDECR:    return "HDECR";
696789f23bSCédric Le Goater     case POWERPC_EXCP_TRACE:    return "TRACE";
706789f23bSCédric Le Goater     case POWERPC_EXCP_HDSI:     return "HDSI";
716789f23bSCédric Le Goater     case POWERPC_EXCP_HISI:     return "HISI";
726789f23bSCédric Le Goater     case POWERPC_EXCP_HDSEG:    return "HDSEG";
736789f23bSCédric Le Goater     case POWERPC_EXCP_HISEG:    return "HISEG";
746789f23bSCédric Le Goater     case POWERPC_EXCP_VPU:      return "VPU";
756789f23bSCédric Le Goater     case POWERPC_EXCP_PIT:      return "PIT";
766789f23bSCédric Le Goater     case POWERPC_EXCP_EMUL:     return "EMUL";
776789f23bSCédric Le Goater     case POWERPC_EXCP_IFTLB:    return "IFTLB";
786789f23bSCédric Le Goater     case POWERPC_EXCP_DLTLB:    return "DLTLB";
796789f23bSCédric Le Goater     case POWERPC_EXCP_DSTLB:    return "DSTLB";
806789f23bSCédric Le Goater     case POWERPC_EXCP_FPA:      return "FPA";
816789f23bSCédric Le Goater     case POWERPC_EXCP_DABR:     return "DABR";
826789f23bSCédric Le Goater     case POWERPC_EXCP_IABR:     return "IABR";
836789f23bSCédric Le Goater     case POWERPC_EXCP_SMI:      return "SMI";
846789f23bSCédric Le Goater     case POWERPC_EXCP_PERFM:    return "PERFM";
856789f23bSCédric Le Goater     case POWERPC_EXCP_THERM:    return "THERM";
866789f23bSCédric Le Goater     case POWERPC_EXCP_VPUA:     return "VPUA";
876789f23bSCédric Le Goater     case POWERPC_EXCP_SOFTP:    return "SOFTP";
886789f23bSCédric Le Goater     case POWERPC_EXCP_MAINT:    return "MAINT";
896789f23bSCédric Le Goater     case POWERPC_EXCP_MEXTBR:   return "MEXTBR";
906789f23bSCédric Le Goater     case POWERPC_EXCP_NMEXTBR:  return "NMEXTBR";
916789f23bSCédric Le Goater     case POWERPC_EXCP_ITLBE:    return "ITLBE";
926789f23bSCédric Le Goater     case POWERPC_EXCP_DTLBE:    return "DTLBE";
936789f23bSCédric Le Goater     case POWERPC_EXCP_VSXU:     return "VSXU";
946789f23bSCédric Le Goater     case POWERPC_EXCP_FU:       return "FU";
956789f23bSCédric Le Goater     case POWERPC_EXCP_HV_EMU:   return "HV_EMU";
966789f23bSCédric Le Goater     case POWERPC_EXCP_HV_MAINT: return "HV_MAINT";
976789f23bSCédric Le Goater     case POWERPC_EXCP_HV_FU:    return "HV_FU";
986789f23bSCédric Le Goater     case POWERPC_EXCP_SDOOR:    return "SDOOR";
996789f23bSCédric Le Goater     case POWERPC_EXCP_SDOOR_HV: return "SDOOR_HV";
1006789f23bSCédric Le Goater     case POWERPC_EXCP_HVIRT:    return "HVIRT";
1016789f23bSCédric Le Goater     case POWERPC_EXCP_SYSCALL_VECTORED: return "SYSCALL_VECTORED";
1026789f23bSCédric Le Goater     default:
1036789f23bSCédric Le Goater         g_assert_not_reached();
1046789f23bSCédric Le Goater     }
1056789f23bSCédric Le Goater }
1066789f23bSCédric Le Goater 
10762e79ef9SCédric Le Goater static void dump_syscall(CPUPPCState *env)
108c79c73f6SBlue Swirl {
1096dc6b557SNicholas Piggin     qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
1106dc6b557SNicholas Piggin                   " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64
1116dc6b557SNicholas Piggin                   " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64
112c79c73f6SBlue Swirl                   " nip=" TARGET_FMT_lx "\n",
113c79c73f6SBlue Swirl                   ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
114c79c73f6SBlue Swirl                   ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
1156dc6b557SNicholas Piggin                   ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7),
1166dc6b557SNicholas Piggin                   ppc_dump_gpr(env, 8), env->nip);
1176dc6b557SNicholas Piggin }
1186dc6b557SNicholas Piggin 
11962e79ef9SCédric Le Goater static void dump_hcall(CPUPPCState *env)
1206dc6b557SNicholas Piggin {
1216dc6b557SNicholas Piggin     qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64
1226dc6b557SNicholas Piggin                   " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
1236dc6b557SNicholas Piggin                   " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
1246dc6b557SNicholas Piggin                   " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
1256dc6b557SNicholas Piggin                   " nip=" TARGET_FMT_lx "\n",
1266dc6b557SNicholas Piggin                   ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4),
1276dc6b557SNicholas Piggin                   ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
1286dc6b557SNicholas Piggin                   ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
1296dc6b557SNicholas Piggin                   ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
1306dc6b557SNicholas Piggin                   ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
1316dc6b557SNicholas Piggin                   env->nip);
132c79c73f6SBlue Swirl }
133c79c73f6SBlue Swirl 
134e4e27df7SFabiano Rosas static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp)
135e4e27df7SFabiano Rosas {
136e4e27df7SFabiano Rosas     const char *es;
137e4e27df7SFabiano Rosas     target_ulong *miss, *cmp;
138e4e27df7SFabiano Rosas     int en;
139e4e27df7SFabiano Rosas 
1402e089eceSFabiano Rosas     if (!qemu_loglevel_mask(CPU_LOG_MMU)) {
141e4e27df7SFabiano Rosas         return;
142e4e27df7SFabiano Rosas     }
143e4e27df7SFabiano Rosas 
144e4e27df7SFabiano Rosas     if (excp == POWERPC_EXCP_IFTLB) {
145e4e27df7SFabiano Rosas         es = "I";
146e4e27df7SFabiano Rosas         en = 'I';
147e4e27df7SFabiano Rosas         miss = &env->spr[SPR_IMISS];
148e4e27df7SFabiano Rosas         cmp = &env->spr[SPR_ICMP];
149e4e27df7SFabiano Rosas     } else {
150e4e27df7SFabiano Rosas         if (excp == POWERPC_EXCP_DLTLB) {
151e4e27df7SFabiano Rosas             es = "DL";
152e4e27df7SFabiano Rosas         } else {
153e4e27df7SFabiano Rosas             es = "DS";
154e4e27df7SFabiano Rosas         }
155e4e27df7SFabiano Rosas         en = 'D';
156e4e27df7SFabiano Rosas         miss = &env->spr[SPR_DMISS];
157e4e27df7SFabiano Rosas         cmp = &env->spr[SPR_DCMP];
158e4e27df7SFabiano Rosas     }
159e4e27df7SFabiano Rosas     qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
160e4e27df7SFabiano Rosas              TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
161e4e27df7SFabiano Rosas              TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
162e4e27df7SFabiano Rosas              env->spr[SPR_HASH1], env->spr[SPR_HASH2],
163e4e27df7SFabiano Rosas              env->error_code);
164e4e27df7SFabiano Rosas }
165e4e27df7SFabiano Rosas 
166e4e27df7SFabiano Rosas 
167dead760bSBenjamin Herrenschmidt static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
168dead760bSBenjamin Herrenschmidt                                 target_ulong *msr)
169dead760bSBenjamin Herrenschmidt {
170dead760bSBenjamin Herrenschmidt     /* We no longer are in a PM state */
1711e7fd61dSBenjamin Herrenschmidt     env->resume_as_sreset = false;
172dead760bSBenjamin Herrenschmidt 
173dead760bSBenjamin Herrenschmidt     /* Pretend to be returning from doze always as we don't lose state */
1740911a60cSLeonardo Bras     *msr |= SRR1_WS_NOLOSS;
175dead760bSBenjamin Herrenschmidt 
176dead760bSBenjamin Herrenschmidt     /* Machine checks are sent normally */
177dead760bSBenjamin Herrenschmidt     if (excp == POWERPC_EXCP_MCHECK) {
178dead760bSBenjamin Herrenschmidt         return excp;
179dead760bSBenjamin Herrenschmidt     }
180dead760bSBenjamin Herrenschmidt     switch (excp) {
181dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_RESET:
1820911a60cSLeonardo Bras         *msr |= SRR1_WAKERESET;
183dead760bSBenjamin Herrenschmidt         break;
184dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_EXTERNAL:
1850911a60cSLeonardo Bras         *msr |= SRR1_WAKEEE;
186dead760bSBenjamin Herrenschmidt         break;
187dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_DECR:
1880911a60cSLeonardo Bras         *msr |= SRR1_WAKEDEC;
189dead760bSBenjamin Herrenschmidt         break;
190dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_SDOOR:
1910911a60cSLeonardo Bras         *msr |= SRR1_WAKEDBELL;
192dead760bSBenjamin Herrenschmidt         break;
193dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_SDOOR_HV:
1940911a60cSLeonardo Bras         *msr |= SRR1_WAKEHDBELL;
195dead760bSBenjamin Herrenschmidt         break;
196dead760bSBenjamin Herrenschmidt     case POWERPC_EXCP_HV_MAINT:
1970911a60cSLeonardo Bras         *msr |= SRR1_WAKEHMI;
198dead760bSBenjamin Herrenschmidt         break;
199d8ce5fd6SBenjamin Herrenschmidt     case POWERPC_EXCP_HVIRT:
2000911a60cSLeonardo Bras         *msr |= SRR1_WAKEHVI;
201d8ce5fd6SBenjamin Herrenschmidt         break;
202dead760bSBenjamin Herrenschmidt     default:
203dead760bSBenjamin Herrenschmidt         cpu_abort(cs, "Unsupported exception %d in Power Save mode\n",
204dead760bSBenjamin Herrenschmidt                   excp);
205dead760bSBenjamin Herrenschmidt     }
206dead760bSBenjamin Herrenschmidt     return POWERPC_EXCP_RESET;
207dead760bSBenjamin Herrenschmidt }
208dead760bSBenjamin Herrenschmidt 
2098b7e6b07SNicholas Piggin /*
2108b7e6b07SNicholas Piggin  * AIL - Alternate Interrupt Location, a mode that allows interrupts to be
2118b7e6b07SNicholas Piggin  * taken with the MMU on, and which uses an alternate location (e.g., so the
2128b7e6b07SNicholas Piggin  * kernel/hv can map the vectors there with an effective address).
2138b7e6b07SNicholas Piggin  *
2148b7e6b07SNicholas Piggin  * An interrupt is considered to be taken "with AIL" or "AIL applies" if they
2158b7e6b07SNicholas Piggin  * are delivered in this way. AIL requires the LPCR to be set to enable this
2168b7e6b07SNicholas Piggin  * mode, and then a number of conditions have to be true for AIL to apply.
2178b7e6b07SNicholas Piggin  *
2188b7e6b07SNicholas Piggin  * First of all, SRESET, MCE, and HMI are always delivered without AIL, because
2198b7e6b07SNicholas Piggin  * they specifically want to be in real mode (e.g., the MCE might be signaling
2208b7e6b07SNicholas Piggin  * a SLB multi-hit which requires SLB flush before the MMU can be enabled).
2218b7e6b07SNicholas Piggin  *
2228b7e6b07SNicholas Piggin  * After that, behaviour depends on the current MSR[IR], MSR[DR], MSR[HV],
2238b7e6b07SNicholas Piggin  * whether or not the interrupt changes MSR[HV] from 0 to 1, and the current
2248b7e6b07SNicholas Piggin  * radix mode (LPCR[HR]).
2258b7e6b07SNicholas Piggin  *
2268b7e6b07SNicholas Piggin  * POWER8, POWER9 with LPCR[HR]=0
2278b7e6b07SNicholas Piggin  * | LPCR[AIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL |
2288b7e6b07SNicholas Piggin  * +-----------+-------------+---------+-------------+-----+
2298b7e6b07SNicholas Piggin  * | a         | 00/01/10    | x       | x           | 0   |
2308b7e6b07SNicholas Piggin  * | a         | 11          | 0       | 1           | 0   |
2318b7e6b07SNicholas Piggin  * | a         | 11          | 1       | 1           | a   |
2328b7e6b07SNicholas Piggin  * | a         | 11          | 0       | 0           | a   |
2338b7e6b07SNicholas Piggin  * +-------------------------------------------------------+
2348b7e6b07SNicholas Piggin  *
2358b7e6b07SNicholas Piggin  * POWER9 with LPCR[HR]=1
2368b7e6b07SNicholas Piggin  * | LPCR[AIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL |
2378b7e6b07SNicholas Piggin  * +-----------+-------------+---------+-------------+-----+
2388b7e6b07SNicholas Piggin  * | a         | 00/01/10    | x       | x           | 0   |
2398b7e6b07SNicholas Piggin  * | a         | 11          | x       | x           | a   |
2408b7e6b07SNicholas Piggin  * +-------------------------------------------------------+
2418b7e6b07SNicholas Piggin  *
2428b7e6b07SNicholas Piggin  * The difference with POWER9 being that MSR[HV] 0->1 interrupts can be sent to
243526cdce7SNicholas Piggin  * the hypervisor in AIL mode if the guest is radix. This is good for
244526cdce7SNicholas Piggin  * performance but allows the guest to influence the AIL of hypervisor
245526cdce7SNicholas Piggin  * interrupts using its MSR, and also the hypervisor must disallow guest
246526cdce7SNicholas Piggin  * interrupts (MSR[HV] 0->0) from using AIL if the hypervisor does not want to
247526cdce7SNicholas Piggin  * use AIL for its MSR[HV] 0->1 interrupts.
248526cdce7SNicholas Piggin  *
249526cdce7SNicholas Piggin  * POWER10 addresses those issues with a new LPCR[HAIL] bit that is applied to
250526cdce7SNicholas Piggin  * interrupts that begin execution with MSR[HV]=1 (so both MSR[HV] 0->1 and
251526cdce7SNicholas Piggin  * MSR[HV] 1->1).
252526cdce7SNicholas Piggin  *
253526cdce7SNicholas Piggin  * HAIL=1 is equivalent to AIL=3, for interrupts delivered with MSR[HV]=1.
254526cdce7SNicholas Piggin  *
255526cdce7SNicholas Piggin  * POWER10 behaviour is
256526cdce7SNicholas Piggin  * | LPCR[AIL] | LPCR[HAIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL |
257526cdce7SNicholas Piggin  * +-----------+------------+-------------+---------+-------------+-----+
258526cdce7SNicholas Piggin  * | a         | h          | 00/01/10    | 0       | 0           | 0   |
259526cdce7SNicholas Piggin  * | a         | h          | 11          | 0       | 0           | a   |
260526cdce7SNicholas Piggin  * | a         | h          | x           | 0       | 1           | h   |
261526cdce7SNicholas Piggin  * | a         | h          | 00/01/10    | 1       | 1           | 0   |
262526cdce7SNicholas Piggin  * | a         | h          | 11          | 1       | 1           | h   |
263526cdce7SNicholas Piggin  * +--------------------------------------------------------------------+
2648b7e6b07SNicholas Piggin  */
26562e79ef9SCédric Le Goater static void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
2668b7e6b07SNicholas Piggin                                       target_ulong msr,
2678b7e6b07SNicholas Piggin                                       target_ulong *new_msr,
2688b7e6b07SNicholas Piggin                                       target_ulong *vector)
2692586a4d7SFabiano Rosas {
2708b7e6b07SNicholas Piggin #if defined(TARGET_PPC64)
2718b7e6b07SNicholas Piggin     CPUPPCState *env = &cpu->env;
2728b7e6b07SNicholas Piggin     bool mmu_all_on = ((msr >> MSR_IR) & 1) && ((msr >> MSR_DR) & 1);
2738b7e6b07SNicholas Piggin     bool hv_escalation = !(msr & MSR_HVB) && (*new_msr & MSR_HVB);
2748b7e6b07SNicholas Piggin     int ail = 0;
2752586a4d7SFabiano Rosas 
2768b7e6b07SNicholas Piggin     if (excp == POWERPC_EXCP_MCHECK ||
2778b7e6b07SNicholas Piggin         excp == POWERPC_EXCP_RESET ||
2788b7e6b07SNicholas Piggin         excp == POWERPC_EXCP_HV_MAINT) {
2798b7e6b07SNicholas Piggin         /* SRESET, MCE, HMI never apply AIL */
2808b7e6b07SNicholas Piggin         return;
2812586a4d7SFabiano Rosas     }
2822586a4d7SFabiano Rosas 
2838b7e6b07SNicholas Piggin     if (excp_model == POWERPC_EXCP_POWER8 ||
2848b7e6b07SNicholas Piggin         excp_model == POWERPC_EXCP_POWER9) {
2858b7e6b07SNicholas Piggin         if (!mmu_all_on) {
2868b7e6b07SNicholas Piggin             /* AIL only works if MSR[IR] and MSR[DR] are both enabled. */
2878b7e6b07SNicholas Piggin             return;
2888b7e6b07SNicholas Piggin         }
2898b7e6b07SNicholas Piggin         if (hv_escalation && !(env->spr[SPR_LPCR] & LPCR_HR)) {
2908b7e6b07SNicholas Piggin             /*
2918b7e6b07SNicholas Piggin              * AIL does not work if there is a MSR[HV] 0->1 transition and the
2928b7e6b07SNicholas Piggin              * partition is in HPT mode. For radix guests, such interrupts are
2938b7e6b07SNicholas Piggin              * allowed to be delivered to the hypervisor in ail mode.
2948b7e6b07SNicholas Piggin              */
2958b7e6b07SNicholas Piggin             return;
2968b7e6b07SNicholas Piggin         }
2978b7e6b07SNicholas Piggin 
2988b7e6b07SNicholas Piggin         ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
2998b7e6b07SNicholas Piggin         if (ail == 0) {
3008b7e6b07SNicholas Piggin             return;
3018b7e6b07SNicholas Piggin         }
3028b7e6b07SNicholas Piggin         if (ail == 1) {
3038b7e6b07SNicholas Piggin             /* AIL=1 is reserved, treat it like AIL=0 */
3048b7e6b07SNicholas Piggin             return;
3058b7e6b07SNicholas Piggin         }
306526cdce7SNicholas Piggin 
307526cdce7SNicholas Piggin     } else if (excp_model == POWERPC_EXCP_POWER10) {
308526cdce7SNicholas Piggin         if (!mmu_all_on && !hv_escalation) {
309526cdce7SNicholas Piggin             /*
310526cdce7SNicholas Piggin              * AIL works for HV interrupts even with guest MSR[IR/DR] disabled.
311526cdce7SNicholas Piggin              * Guest->guest and HV->HV interrupts do require MMU on.
312526cdce7SNicholas Piggin              */
313526cdce7SNicholas Piggin             return;
314526cdce7SNicholas Piggin         }
315526cdce7SNicholas Piggin 
316526cdce7SNicholas Piggin         if (*new_msr & MSR_HVB) {
317526cdce7SNicholas Piggin             if (!(env->spr[SPR_LPCR] & LPCR_HAIL)) {
318526cdce7SNicholas Piggin                 /* HV interrupts depend on LPCR[HAIL] */
319526cdce7SNicholas Piggin                 return;
320526cdce7SNicholas Piggin             }
321526cdce7SNicholas Piggin             ail = 3; /* HAIL=1 gives AIL=3 behaviour for HV interrupts */
322526cdce7SNicholas Piggin         } else {
323526cdce7SNicholas Piggin             ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
324526cdce7SNicholas Piggin         }
325526cdce7SNicholas Piggin         if (ail == 0) {
326526cdce7SNicholas Piggin             return;
327526cdce7SNicholas Piggin         }
328526cdce7SNicholas Piggin         if (ail == 1 || ail == 2) {
329526cdce7SNicholas Piggin             /* AIL=1 and AIL=2 are reserved, treat them like AIL=0 */
330526cdce7SNicholas Piggin             return;
331526cdce7SNicholas Piggin         }
3328b7e6b07SNicholas Piggin     } else {
3338b7e6b07SNicholas Piggin         /* Other processors do not support AIL */
3348b7e6b07SNicholas Piggin         return;
3358b7e6b07SNicholas Piggin     }
3368b7e6b07SNicholas Piggin 
3378b7e6b07SNicholas Piggin     /*
3388b7e6b07SNicholas Piggin      * AIL applies, so the new MSR gets IR and DR set, and an offset applied
3398b7e6b07SNicholas Piggin      * to the new IP.
3408b7e6b07SNicholas Piggin      */
3418b7e6b07SNicholas Piggin     *new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
3428b7e6b07SNicholas Piggin 
3438b7e6b07SNicholas Piggin     if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
3448b7e6b07SNicholas Piggin         if (ail == 2) {
3458b7e6b07SNicholas Piggin             *vector |= 0x0000000000018000ull;
3468b7e6b07SNicholas Piggin         } else if (ail == 3) {
3478b7e6b07SNicholas Piggin             *vector |= 0xc000000000004000ull;
3488b7e6b07SNicholas Piggin         }
3498b7e6b07SNicholas Piggin     } else {
3508b7e6b07SNicholas Piggin         /*
3518b7e6b07SNicholas Piggin          * scv AIL is a little different. AIL=2 does not change the address,
3528b7e6b07SNicholas Piggin          * only the MSR. AIL=3 replaces the 0x17000 base with 0xc...3000.
3538b7e6b07SNicholas Piggin          */
3548b7e6b07SNicholas Piggin         if (ail == 3) {
3558b7e6b07SNicholas Piggin             *vector &= ~0x0000000000017000ull; /* Un-apply the base offset */
3568b7e6b07SNicholas Piggin             *vector |= 0xc000000000003000ull; /* Apply scv's AIL=3 offset */
3578b7e6b07SNicholas Piggin         }
3588b7e6b07SNicholas Piggin     }
3598b7e6b07SNicholas Piggin #endif
3602586a4d7SFabiano Rosas }
361dead760bSBenjamin Herrenschmidt 
36262e79ef9SCédric Le Goater static void powerpc_set_excp_state(PowerPCCPU *cpu,
363ad77c6caSNicholas Piggin                                           target_ulong vector, target_ulong msr)
364ad77c6caSNicholas Piggin {
365ad77c6caSNicholas Piggin     CPUState *cs = CPU(cpu);
366ad77c6caSNicholas Piggin     CPUPPCState *env = &cpu->env;
367ad77c6caSNicholas Piggin 
368ad77c6caSNicholas Piggin     /*
369ad77c6caSNicholas Piggin      * We don't use hreg_store_msr here as already have treated any
370ad77c6caSNicholas Piggin      * special case that could occur. Just store MSR and update hflags
371ad77c6caSNicholas Piggin      *
372ad77c6caSNicholas Piggin      * Note: We *MUST* not use hreg_store_msr() as-is anyway because it
373ad77c6caSNicholas Piggin      * will prevent setting of the HV bit which some exceptions might need
374ad77c6caSNicholas Piggin      * to do.
375ad77c6caSNicholas Piggin      */
376ad77c6caSNicholas Piggin     env->msr = msr & env->msr_mask;
377ad77c6caSNicholas Piggin     hreg_compute_hflags(env);
378ad77c6caSNicholas Piggin     env->nip = vector;
379ad77c6caSNicholas Piggin     /* Reset exception state */
380ad77c6caSNicholas Piggin     cs->exception_index = POWERPC_EXCP_NONE;
381ad77c6caSNicholas Piggin     env->error_code = 0;
382ad77c6caSNicholas Piggin 
383ad77c6caSNicholas Piggin     /* Reset the reservation */
384ad77c6caSNicholas Piggin     env->reserve_addr = -1;
385ad77c6caSNicholas Piggin 
386ad77c6caSNicholas Piggin     /*
387ad77c6caSNicholas Piggin      * Any interrupt is context synchronizing, check if TCG TLB needs
388ad77c6caSNicholas Piggin      * a delayed flush on ppc64
389ad77c6caSNicholas Piggin      */
390ad77c6caSNicholas Piggin     check_tlb_flush(env, false);
391ad77c6caSNicholas Piggin }
392ad77c6caSNicholas Piggin 
393e808c2edSFabiano Rosas static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
394e808c2edSFabiano Rosas {
395e808c2edSFabiano Rosas     CPUState *cs = CPU(cpu);
396e808c2edSFabiano Rosas     CPUPPCState *env = &cpu->env;
397e808c2edSFabiano Rosas     target_ulong msr, new_msr, vector;
3988428cdb2SFabiano Rosas     int srr0, srr1;
399e808c2edSFabiano Rosas 
400e808c2edSFabiano Rosas     if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
401e808c2edSFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
402e808c2edSFabiano Rosas     }
403e808c2edSFabiano Rosas 
404e808c2edSFabiano Rosas     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
405e808c2edSFabiano Rosas                   " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
406e808c2edSFabiano Rosas                   excp, env->error_code);
407e808c2edSFabiano Rosas 
408e808c2edSFabiano Rosas     /* new srr1 value excluding must-be-zero bits */
409e808c2edSFabiano Rosas     msr = env->msr & ~0x783f0000ULL;
410e808c2edSFabiano Rosas 
411e808c2edSFabiano Rosas     /*
412495fc7ffSFabiano Rosas      * new interrupt handler msr preserves existing ME unless
413495fc7ffSFabiano Rosas      * explicitly overriden.
414e808c2edSFabiano Rosas      */
415495fc7ffSFabiano Rosas     new_msr = env->msr & (((target_ulong)1 << MSR_ME));
416e808c2edSFabiano Rosas 
417e808c2edSFabiano Rosas     /* target registers */
418e808c2edSFabiano Rosas     srr0 = SPR_SRR0;
419e808c2edSFabiano Rosas     srr1 = SPR_SRR1;
420e808c2edSFabiano Rosas 
421e808c2edSFabiano Rosas     /*
422e808c2edSFabiano Rosas      * Hypervisor emulation assistance interrupt only exists on server
423495fc7ffSFabiano Rosas      * arch 2.05 server or later.
424e808c2edSFabiano Rosas      */
425495fc7ffSFabiano Rosas     if (excp == POWERPC_EXCP_HV_EMU) {
426e808c2edSFabiano Rosas         excp = POWERPC_EXCP_PROGRAM;
427e808c2edSFabiano Rosas     }
428e808c2edSFabiano Rosas 
429e808c2edSFabiano Rosas     vector = env->excp_vectors[excp];
430e808c2edSFabiano Rosas     if (vector == (target_ulong)-1ULL) {
431e808c2edSFabiano Rosas         cpu_abort(cs, "Raised an exception without defined vector %d\n",
432e808c2edSFabiano Rosas                   excp);
433e808c2edSFabiano Rosas     }
434e808c2edSFabiano Rosas 
435e808c2edSFabiano Rosas     vector |= env->excp_prefix;
436e808c2edSFabiano Rosas 
437e808c2edSFabiano Rosas     switch (excp) {
438e808c2edSFabiano Rosas     case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
439e808c2edSFabiano Rosas         srr0 = SPR_40x_SRR2;
440e808c2edSFabiano Rosas         srr1 = SPR_40x_SRR3;
441e808c2edSFabiano Rosas         break;
442e808c2edSFabiano Rosas     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
443e808c2edSFabiano Rosas         if (msr_me == 0) {
444e808c2edSFabiano Rosas             /*
445e808c2edSFabiano Rosas              * Machine check exception is not enabled.  Enter
446e808c2edSFabiano Rosas              * checkstop state.
447e808c2edSFabiano Rosas              */
448e808c2edSFabiano Rosas             fprintf(stderr, "Machine check while not allowed. "
449e808c2edSFabiano Rosas                     "Entering checkstop state\n");
450e808c2edSFabiano Rosas             if (qemu_log_separate()) {
451e808c2edSFabiano Rosas                 qemu_log("Machine check while not allowed. "
452e808c2edSFabiano Rosas                         "Entering checkstop state\n");
453e808c2edSFabiano Rosas             }
454e808c2edSFabiano Rosas             cs->halted = 1;
455e808c2edSFabiano Rosas             cpu_interrupt_exittb(cs);
456e808c2edSFabiano Rosas         }
457e808c2edSFabiano Rosas 
458e808c2edSFabiano Rosas         /* machine check exceptions don't have ME set */
459e808c2edSFabiano Rosas         new_msr &= ~((target_ulong)1 << MSR_ME);
460e808c2edSFabiano Rosas 
461e808c2edSFabiano Rosas         srr0 = SPR_40x_SRR2;
462e808c2edSFabiano Rosas         srr1 = SPR_40x_SRR3;
463e808c2edSFabiano Rosas         break;
464e808c2edSFabiano Rosas     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
465f9911e1eSFabiano Rosas         trace_ppc_excp_dsi(env->spr[SPR_40x_ESR], env->spr[SPR_40x_DEAR]);
466e808c2edSFabiano Rosas         break;
467e808c2edSFabiano Rosas     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
468e808c2edSFabiano Rosas         trace_ppc_excp_isi(msr, env->nip);
469e808c2edSFabiano Rosas         break;
470e808c2edSFabiano Rosas     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
471e808c2edSFabiano Rosas         break;
472e808c2edSFabiano Rosas     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
473e808c2edSFabiano Rosas         break;
474e808c2edSFabiano Rosas     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
475e808c2edSFabiano Rosas         switch (env->error_code & ~0xF) {
476e808c2edSFabiano Rosas         case POWERPC_EXCP_FP:
477e808c2edSFabiano Rosas             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
478e808c2edSFabiano Rosas                 trace_ppc_excp_fp_ignore();
479e808c2edSFabiano Rosas                 cs->exception_index = POWERPC_EXCP_NONE;
480e808c2edSFabiano Rosas                 env->error_code = 0;
481e808c2edSFabiano Rosas                 return;
482e808c2edSFabiano Rosas             }
48364e62cfbSFabiano Rosas             env->spr[SPR_40x_ESR] = ESR_FP;
484e808c2edSFabiano Rosas             break;
485e808c2edSFabiano Rosas         case POWERPC_EXCP_INVAL:
486e808c2edSFabiano Rosas             trace_ppc_excp_inval(env->nip);
48764e62cfbSFabiano Rosas             env->spr[SPR_40x_ESR] = ESR_PIL;
488e808c2edSFabiano Rosas             break;
489e808c2edSFabiano Rosas         case POWERPC_EXCP_PRIV:
49064e62cfbSFabiano Rosas             env->spr[SPR_40x_ESR] = ESR_PPR;
491e808c2edSFabiano Rosas             break;
492e808c2edSFabiano Rosas         case POWERPC_EXCP_TRAP:
49364e62cfbSFabiano Rosas             env->spr[SPR_40x_ESR] = ESR_PTR;
494e808c2edSFabiano Rosas             break;
495e808c2edSFabiano Rosas         default:
496e808c2edSFabiano Rosas             cpu_abort(cs, "Invalid program exception %d. Aborting\n",
497e808c2edSFabiano Rosas                       env->error_code);
498e808c2edSFabiano Rosas             break;
499e808c2edSFabiano Rosas         }
500e808c2edSFabiano Rosas         break;
501e808c2edSFabiano Rosas     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
502e808c2edSFabiano Rosas         dump_syscall(env);
503e808c2edSFabiano Rosas 
504e808c2edSFabiano Rosas         /*
505e808c2edSFabiano Rosas          * We need to correct the NIP which in this case is supposed
506e808c2edSFabiano Rosas          * to point to the next instruction
507e808c2edSFabiano Rosas          */
508e808c2edSFabiano Rosas         env->nip += 4;
509e808c2edSFabiano Rosas         break;
510e808c2edSFabiano Rosas     case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
511e808c2edSFabiano Rosas         trace_ppc_excp_print("FIT");
512e808c2edSFabiano Rosas         break;
513e808c2edSFabiano Rosas     case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
514e808c2edSFabiano Rosas         trace_ppc_excp_print("WDT");
515e808c2edSFabiano Rosas         break;
516e808c2edSFabiano Rosas     case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
517e808c2edSFabiano Rosas     case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
518e808c2edSFabiano Rosas         break;
519e808c2edSFabiano Rosas     case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
520e808c2edSFabiano Rosas         trace_ppc_excp_print("PIT");
521e808c2edSFabiano Rosas         break;
5224d8ac1d1SFabiano Rosas     case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
5234d8ac1d1SFabiano Rosas         cpu_abort(cs, "%s exception not implemented\n",
5244d8ac1d1SFabiano Rosas                   powerpc_excp_name(excp));
5254d8ac1d1SFabiano Rosas         break;
526e808c2edSFabiano Rosas     default:
527e808c2edSFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
528e808c2edSFabiano Rosas         break;
529e808c2edSFabiano Rosas     }
530e808c2edSFabiano Rosas 
531e808c2edSFabiano Rosas     /* Sanity check */
532e808c2edSFabiano Rosas     if (!(env->msr_mask & MSR_HVB)) {
533e808c2edSFabiano Rosas         if (new_msr & MSR_HVB) {
534e808c2edSFabiano Rosas             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
535e808c2edSFabiano Rosas                       "no HV support\n", excp);
536e808c2edSFabiano Rosas         }
537e808c2edSFabiano Rosas         if (srr0 == SPR_HSRR0) {
538e808c2edSFabiano Rosas             cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
539e808c2edSFabiano Rosas                       "no HV support\n", excp);
540e808c2edSFabiano Rosas         }
541e808c2edSFabiano Rosas     }
542e808c2edSFabiano Rosas 
543e808c2edSFabiano Rosas     /* Save PC */
544e808c2edSFabiano Rosas     env->spr[srr0] = env->nip;
545e808c2edSFabiano Rosas 
546e808c2edSFabiano Rosas     /* Save MSR */
547e808c2edSFabiano Rosas     env->spr[srr1] = msr;
548e808c2edSFabiano Rosas 
549e808c2edSFabiano Rosas     powerpc_set_excp_state(cpu, vector, new_msr);
550e808c2edSFabiano Rosas }
551e808c2edSFabiano Rosas 
55258d178fbSFabiano Rosas static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp)
55358d178fbSFabiano Rosas {
55458d178fbSFabiano Rosas     CPUState *cs = CPU(cpu);
55558d178fbSFabiano Rosas     CPUPPCState *env = &cpu->env;
55658d178fbSFabiano Rosas     target_ulong msr, new_msr, vector;
55758d178fbSFabiano Rosas 
55858d178fbSFabiano Rosas     if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
55958d178fbSFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
56058d178fbSFabiano Rosas     }
56158d178fbSFabiano Rosas 
56258d178fbSFabiano Rosas     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
56358d178fbSFabiano Rosas                   " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
56458d178fbSFabiano Rosas                   excp, env->error_code);
56558d178fbSFabiano Rosas 
56658d178fbSFabiano Rosas     /* new srr1 value excluding must-be-zero bits */
56758d178fbSFabiano Rosas     msr = env->msr & ~0x783f0000ULL;
56858d178fbSFabiano Rosas 
56958d178fbSFabiano Rosas     /*
570082d783bSFabiano Rosas      * new interrupt handler msr preserves existing ME unless
57158d178fbSFabiano Rosas      * explicitly overriden
57258d178fbSFabiano Rosas      */
573082d783bSFabiano Rosas     new_msr = env->msr & ((target_ulong)1 << MSR_ME);
57458d178fbSFabiano Rosas 
57558d178fbSFabiano Rosas     /*
57658d178fbSFabiano Rosas      * Hypervisor emulation assistance interrupt only exists on server
577082d783bSFabiano Rosas      * arch 2.05 server or later.
57858d178fbSFabiano Rosas      */
579082d783bSFabiano Rosas     if (excp == POWERPC_EXCP_HV_EMU) {
58058d178fbSFabiano Rosas         excp = POWERPC_EXCP_PROGRAM;
58158d178fbSFabiano Rosas     }
58258d178fbSFabiano Rosas 
58358d178fbSFabiano Rosas     vector = env->excp_vectors[excp];
58458d178fbSFabiano Rosas     if (vector == (target_ulong)-1ULL) {
58558d178fbSFabiano Rosas         cpu_abort(cs, "Raised an exception without defined vector %d\n",
58658d178fbSFabiano Rosas                   excp);
58758d178fbSFabiano Rosas     }
58858d178fbSFabiano Rosas 
58958d178fbSFabiano Rosas     vector |= env->excp_prefix;
59058d178fbSFabiano Rosas 
59158d178fbSFabiano Rosas     switch (excp) {
59258d178fbSFabiano Rosas     case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
59358d178fbSFabiano Rosas         break;
59458d178fbSFabiano Rosas     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
59558d178fbSFabiano Rosas         if (msr_me == 0) {
59658d178fbSFabiano Rosas             /*
59758d178fbSFabiano Rosas              * Machine check exception is not enabled.  Enter
59858d178fbSFabiano Rosas              * checkstop state.
59958d178fbSFabiano Rosas              */
60058d178fbSFabiano Rosas             fprintf(stderr, "Machine check while not allowed. "
60158d178fbSFabiano Rosas                     "Entering checkstop state\n");
60258d178fbSFabiano Rosas             if (qemu_log_separate()) {
60358d178fbSFabiano Rosas                 qemu_log("Machine check while not allowed. "
60458d178fbSFabiano Rosas                         "Entering checkstop state\n");
60558d178fbSFabiano Rosas             }
60658d178fbSFabiano Rosas             cs->halted = 1;
60758d178fbSFabiano Rosas             cpu_interrupt_exittb(cs);
60858d178fbSFabiano Rosas         }
60958d178fbSFabiano Rosas 
61058d178fbSFabiano Rosas         /* machine check exceptions don't have ME set */
61158d178fbSFabiano Rosas         new_msr &= ~((target_ulong)1 << MSR_ME);
61258d178fbSFabiano Rosas 
61358d178fbSFabiano Rosas         break;
61458d178fbSFabiano Rosas     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
61558d178fbSFabiano Rosas         trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
61658d178fbSFabiano Rosas         break;
61758d178fbSFabiano Rosas     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
61858d178fbSFabiano Rosas         trace_ppc_excp_isi(msr, env->nip);
61958d178fbSFabiano Rosas         msr |= env->error_code;
62058d178fbSFabiano Rosas         break;
62158d178fbSFabiano Rosas     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
62258d178fbSFabiano Rosas         break;
62358d178fbSFabiano Rosas     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
62458d178fbSFabiano Rosas         /* Get rS/rD and rA from faulting opcode */
62558d178fbSFabiano Rosas         /*
62658d178fbSFabiano Rosas          * Note: the opcode fields will not be set properly for a
62758d178fbSFabiano Rosas          * direct store load/store, but nobody cares as nobody
62858d178fbSFabiano Rosas          * actually uses direct store segments.
62958d178fbSFabiano Rosas          */
63058d178fbSFabiano Rosas         env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
63158d178fbSFabiano Rosas         break;
63258d178fbSFabiano Rosas     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
63358d178fbSFabiano Rosas         switch (env->error_code & ~0xF) {
63458d178fbSFabiano Rosas         case POWERPC_EXCP_FP:
63558d178fbSFabiano Rosas             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
63658d178fbSFabiano Rosas                 trace_ppc_excp_fp_ignore();
63758d178fbSFabiano Rosas                 cs->exception_index = POWERPC_EXCP_NONE;
63858d178fbSFabiano Rosas                 env->error_code = 0;
63958d178fbSFabiano Rosas                 return;
64058d178fbSFabiano Rosas             }
64158d178fbSFabiano Rosas 
64258d178fbSFabiano Rosas             /*
64358d178fbSFabiano Rosas              * FP exceptions always have NIP pointing to the faulting
64458d178fbSFabiano Rosas              * instruction, so always use store_next and claim we are
64558d178fbSFabiano Rosas              * precise in the MSR.
64658d178fbSFabiano Rosas              */
64758d178fbSFabiano Rosas             msr |= 0x00100000;
64858d178fbSFabiano Rosas             break;
64958d178fbSFabiano Rosas         case POWERPC_EXCP_INVAL:
65058d178fbSFabiano Rosas             trace_ppc_excp_inval(env->nip);
65158d178fbSFabiano Rosas             msr |= 0x00080000;
65258d178fbSFabiano Rosas             break;
65358d178fbSFabiano Rosas         case POWERPC_EXCP_PRIV:
65458d178fbSFabiano Rosas             msr |= 0x00040000;
65558d178fbSFabiano Rosas             break;
65658d178fbSFabiano Rosas         case POWERPC_EXCP_TRAP:
65758d178fbSFabiano Rosas             msr |= 0x00020000;
65858d178fbSFabiano Rosas             break;
65958d178fbSFabiano Rosas         default:
66058d178fbSFabiano Rosas             /* Should never occur */
66158d178fbSFabiano Rosas             cpu_abort(cs, "Invalid program exception %d. Aborting\n",
66258d178fbSFabiano Rosas                       env->error_code);
66358d178fbSFabiano Rosas             break;
66458d178fbSFabiano Rosas         }
66558d178fbSFabiano Rosas         break;
66658d178fbSFabiano Rosas     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
66758d178fbSFabiano Rosas         dump_syscall(env);
66858d178fbSFabiano Rosas 
66958d178fbSFabiano Rosas         /*
67058d178fbSFabiano Rosas          * We need to correct the NIP which in this case is supposed
67158d178fbSFabiano Rosas          * to point to the next instruction
67258d178fbSFabiano Rosas          */
67358d178fbSFabiano Rosas         env->nip += 4;
67458d178fbSFabiano Rosas         break;
67558d178fbSFabiano Rosas     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
67658d178fbSFabiano Rosas     case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
67758d178fbSFabiano Rosas         break;
67858d178fbSFabiano Rosas     case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
67958d178fbSFabiano Rosas     case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
68058d178fbSFabiano Rosas         break;
68158d178fbSFabiano Rosas     case POWERPC_EXCP_RESET:     /* System reset exception                   */
68258d178fbSFabiano Rosas         if (msr_pow) {
68358d178fbSFabiano Rosas             cpu_abort(cs, "Trying to deliver power-saving system reset "
68458d178fbSFabiano Rosas                       "exception %d with no HV support\n", excp);
68558d178fbSFabiano Rosas         }
68658d178fbSFabiano Rosas         break;
68758d178fbSFabiano Rosas     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
68858d178fbSFabiano Rosas         break;
68958d178fbSFabiano Rosas     case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
69058d178fbSFabiano Rosas     case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
69158d178fbSFabiano Rosas     case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
69258d178fbSFabiano Rosas         /* Swap temporary saved registers with GPRs */
69358d178fbSFabiano Rosas         if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
69458d178fbSFabiano Rosas             new_msr |= (target_ulong)1 << MSR_TGPR;
69558d178fbSFabiano Rosas             hreg_swap_gpr_tgpr(env);
69658d178fbSFabiano Rosas         }
6978f8c7932SFabiano Rosas 
69858d178fbSFabiano Rosas         ppc_excp_debug_sw_tlb(env, excp);
69958d178fbSFabiano Rosas 
70058d178fbSFabiano Rosas         msr |= env->crf[0] << 28;
70158d178fbSFabiano Rosas         msr |= env->error_code; /* key, D/I, S/L bits */
70258d178fbSFabiano Rosas         /* Set way using a LRU mechanism */
70358d178fbSFabiano Rosas         msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
70458d178fbSFabiano Rosas         break;
70558d178fbSFabiano Rosas     case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
70658d178fbSFabiano Rosas     case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
70758d178fbSFabiano Rosas     case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
70858d178fbSFabiano Rosas     case POWERPC_EXCP_SMI:       /* System management interrupt              */
70958d178fbSFabiano Rosas     case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
71058d178fbSFabiano Rosas     case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
71158d178fbSFabiano Rosas         cpu_abort(cs, "%s exception not implemented\n",
71258d178fbSFabiano Rosas                   powerpc_excp_name(excp));
71358d178fbSFabiano Rosas         break;
71458d178fbSFabiano Rosas     default:
71558d178fbSFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
71658d178fbSFabiano Rosas         break;
71758d178fbSFabiano Rosas     }
71858d178fbSFabiano Rosas 
71958d178fbSFabiano Rosas     /* Sanity check */
72058d178fbSFabiano Rosas     if (!(env->msr_mask & MSR_HVB)) {
72158d178fbSFabiano Rosas         if (new_msr & MSR_HVB) {
72258d178fbSFabiano Rosas             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
72358d178fbSFabiano Rosas                       "no HV support\n", excp);
72458d178fbSFabiano Rosas         }
72558d178fbSFabiano Rosas     }
72658d178fbSFabiano Rosas 
72758d178fbSFabiano Rosas     /*
72858d178fbSFabiano Rosas      * Sort out endianness of interrupt, this differs depending on the
72958d178fbSFabiano Rosas      * CPU, the HV mode, etc...
73058d178fbSFabiano Rosas      */
73158d178fbSFabiano Rosas     if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
73258d178fbSFabiano Rosas         new_msr |= (target_ulong)1 << MSR_LE;
73358d178fbSFabiano Rosas     }
73458d178fbSFabiano Rosas 
73558d178fbSFabiano Rosas     /* Save PC */
736c50eaed1SFabiano Rosas     env->spr[SPR_SRR0] = env->nip;
73758d178fbSFabiano Rosas 
73858d178fbSFabiano Rosas     /* Save MSR */
739c50eaed1SFabiano Rosas     env->spr[SPR_SRR1] = msr;
74058d178fbSFabiano Rosas 
74158d178fbSFabiano Rosas     powerpc_set_excp_state(cpu, vector, new_msr);
74258d178fbSFabiano Rosas }
74358d178fbSFabiano Rosas 
744*ccfca2fcSFabiano Rosas static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp)
745*ccfca2fcSFabiano Rosas {
746*ccfca2fcSFabiano Rosas     CPUState *cs = CPU(cpu);
747*ccfca2fcSFabiano Rosas     CPUPPCState *env = &cpu->env;
748*ccfca2fcSFabiano Rosas     int excp_model = env->excp_model;
749*ccfca2fcSFabiano Rosas     target_ulong msr, new_msr, vector;
750*ccfca2fcSFabiano Rosas     int srr0, srr1, lev = -1;
751*ccfca2fcSFabiano Rosas 
752*ccfca2fcSFabiano Rosas     if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
753*ccfca2fcSFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
754*ccfca2fcSFabiano Rosas     }
755*ccfca2fcSFabiano Rosas 
756*ccfca2fcSFabiano Rosas     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
757*ccfca2fcSFabiano Rosas                   " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
758*ccfca2fcSFabiano Rosas                   excp, env->error_code);
759*ccfca2fcSFabiano Rosas 
760*ccfca2fcSFabiano Rosas     /* new srr1 value excluding must-be-zero bits */
761*ccfca2fcSFabiano Rosas     if (excp_model == POWERPC_EXCP_BOOKE) {
762*ccfca2fcSFabiano Rosas         msr = env->msr;
763*ccfca2fcSFabiano Rosas     } else {
764*ccfca2fcSFabiano Rosas         msr = env->msr & ~0x783f0000ULL;
765*ccfca2fcSFabiano Rosas     }
766*ccfca2fcSFabiano Rosas 
767*ccfca2fcSFabiano Rosas     /*
768*ccfca2fcSFabiano Rosas      * new interrupt handler msr preserves existing HV and ME unless
769*ccfca2fcSFabiano Rosas      * explicitly overriden
770*ccfca2fcSFabiano Rosas      */
771*ccfca2fcSFabiano Rosas     new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
772*ccfca2fcSFabiano Rosas 
773*ccfca2fcSFabiano Rosas     /* target registers */
774*ccfca2fcSFabiano Rosas     srr0 = SPR_SRR0;
775*ccfca2fcSFabiano Rosas     srr1 = SPR_SRR1;
776*ccfca2fcSFabiano Rosas 
777*ccfca2fcSFabiano Rosas     /*
778*ccfca2fcSFabiano Rosas      * check for special resume at 0x100 from doze/nap/sleep/winkle on
779*ccfca2fcSFabiano Rosas      * P7/P8/P9
780*ccfca2fcSFabiano Rosas      */
781*ccfca2fcSFabiano Rosas     if (env->resume_as_sreset) {
782*ccfca2fcSFabiano Rosas         excp = powerpc_reset_wakeup(cs, env, excp, &msr);
783*ccfca2fcSFabiano Rosas     }
784*ccfca2fcSFabiano Rosas 
785*ccfca2fcSFabiano Rosas     /*
786*ccfca2fcSFabiano Rosas      * Hypervisor emulation assistance interrupt only exists on server
787*ccfca2fcSFabiano Rosas      * arch 2.05 server or later. We also don't want to generate it if
788*ccfca2fcSFabiano Rosas      * we don't have HVB in msr_mask (PAPR mode).
789*ccfca2fcSFabiano Rosas      */
790*ccfca2fcSFabiano Rosas     if (excp == POWERPC_EXCP_HV_EMU
791*ccfca2fcSFabiano Rosas #if defined(TARGET_PPC64)
792*ccfca2fcSFabiano Rosas         && !(mmu_is_64bit(env->mmu_model) && (env->msr_mask & MSR_HVB))
793*ccfca2fcSFabiano Rosas #endif /* defined(TARGET_PPC64) */
794*ccfca2fcSFabiano Rosas 
795*ccfca2fcSFabiano Rosas     ) {
796*ccfca2fcSFabiano Rosas         excp = POWERPC_EXCP_PROGRAM;
797*ccfca2fcSFabiano Rosas     }
798*ccfca2fcSFabiano Rosas 
799*ccfca2fcSFabiano Rosas #ifdef TARGET_PPC64
800*ccfca2fcSFabiano Rosas     /*
801*ccfca2fcSFabiano Rosas      * SPEU and VPU share the same IVOR but they exist in different
802*ccfca2fcSFabiano Rosas      * processors. SPEU is e500v1/2 only and VPU is e6500 only.
803*ccfca2fcSFabiano Rosas      */
804*ccfca2fcSFabiano Rosas     if (excp_model == POWERPC_EXCP_BOOKE && excp == POWERPC_EXCP_VPU) {
805*ccfca2fcSFabiano Rosas         excp = POWERPC_EXCP_SPEU;
806*ccfca2fcSFabiano Rosas     }
807*ccfca2fcSFabiano Rosas #endif
808*ccfca2fcSFabiano Rosas 
809*ccfca2fcSFabiano Rosas     vector = env->excp_vectors[excp];
810*ccfca2fcSFabiano Rosas     if (vector == (target_ulong)-1ULL) {
811*ccfca2fcSFabiano Rosas         cpu_abort(cs, "Raised an exception without defined vector %d\n",
812*ccfca2fcSFabiano Rosas                   excp);
813*ccfca2fcSFabiano Rosas     }
814*ccfca2fcSFabiano Rosas 
815*ccfca2fcSFabiano Rosas     vector |= env->excp_prefix;
816*ccfca2fcSFabiano Rosas 
817*ccfca2fcSFabiano Rosas     switch (excp) {
818*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
819*ccfca2fcSFabiano Rosas         switch (excp_model) {
820*ccfca2fcSFabiano Rosas         case POWERPC_EXCP_40x:
821*ccfca2fcSFabiano Rosas             srr0 = SPR_40x_SRR2;
822*ccfca2fcSFabiano Rosas             srr1 = SPR_40x_SRR3;
823*ccfca2fcSFabiano Rosas             break;
824*ccfca2fcSFabiano Rosas         case POWERPC_EXCP_BOOKE:
825*ccfca2fcSFabiano Rosas             srr0 = SPR_BOOKE_CSRR0;
826*ccfca2fcSFabiano Rosas             srr1 = SPR_BOOKE_CSRR1;
827*ccfca2fcSFabiano Rosas             break;
828*ccfca2fcSFabiano Rosas         case POWERPC_EXCP_6xx:
829*ccfca2fcSFabiano Rosas             break;
830*ccfca2fcSFabiano Rosas         default:
831*ccfca2fcSFabiano Rosas             goto excp_invalid;
832*ccfca2fcSFabiano Rosas         }
833*ccfca2fcSFabiano Rosas         break;
834*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
835*ccfca2fcSFabiano Rosas         if (msr_me == 0) {
836*ccfca2fcSFabiano Rosas             /*
837*ccfca2fcSFabiano Rosas              * Machine check exception is not enabled.  Enter
838*ccfca2fcSFabiano Rosas              * checkstop state.
839*ccfca2fcSFabiano Rosas              */
840*ccfca2fcSFabiano Rosas             fprintf(stderr, "Machine check while not allowed. "
841*ccfca2fcSFabiano Rosas                     "Entering checkstop state\n");
842*ccfca2fcSFabiano Rosas             if (qemu_log_separate()) {
843*ccfca2fcSFabiano Rosas                 qemu_log("Machine check while not allowed. "
844*ccfca2fcSFabiano Rosas                         "Entering checkstop state\n");
845*ccfca2fcSFabiano Rosas             }
846*ccfca2fcSFabiano Rosas             cs->halted = 1;
847*ccfca2fcSFabiano Rosas             cpu_interrupt_exittb(cs);
848*ccfca2fcSFabiano Rosas         }
849*ccfca2fcSFabiano Rosas         if (env->msr_mask & MSR_HVB) {
850*ccfca2fcSFabiano Rosas             /*
851*ccfca2fcSFabiano Rosas              * ISA specifies HV, but can be delivered to guest with HV
852*ccfca2fcSFabiano Rosas              * clear (e.g., see FWNMI in PAPR).
853*ccfca2fcSFabiano Rosas              */
854*ccfca2fcSFabiano Rosas             new_msr |= (target_ulong)MSR_HVB;
855*ccfca2fcSFabiano Rosas         }
856*ccfca2fcSFabiano Rosas 
857*ccfca2fcSFabiano Rosas         /* machine check exceptions don't have ME set */
858*ccfca2fcSFabiano Rosas         new_msr &= ~((target_ulong)1 << MSR_ME);
859*ccfca2fcSFabiano Rosas 
860*ccfca2fcSFabiano Rosas         /* XXX: should also have something loaded in DAR / DSISR */
861*ccfca2fcSFabiano Rosas         switch (excp_model) {
862*ccfca2fcSFabiano Rosas         case POWERPC_EXCP_40x:
863*ccfca2fcSFabiano Rosas             srr0 = SPR_40x_SRR2;
864*ccfca2fcSFabiano Rosas             srr1 = SPR_40x_SRR3;
865*ccfca2fcSFabiano Rosas             break;
866*ccfca2fcSFabiano Rosas         case POWERPC_EXCP_BOOKE:
867*ccfca2fcSFabiano Rosas             /* FIXME: choose one or the other based on CPU type */
868*ccfca2fcSFabiano Rosas             srr0 = SPR_BOOKE_MCSRR0;
869*ccfca2fcSFabiano Rosas             srr1 = SPR_BOOKE_MCSRR1;
870*ccfca2fcSFabiano Rosas 
871*ccfca2fcSFabiano Rosas             env->spr[SPR_BOOKE_CSRR0] = env->nip;
872*ccfca2fcSFabiano Rosas             env->spr[SPR_BOOKE_CSRR1] = msr;
873*ccfca2fcSFabiano Rosas             break;
874*ccfca2fcSFabiano Rosas         default:
875*ccfca2fcSFabiano Rosas             break;
876*ccfca2fcSFabiano Rosas         }
877*ccfca2fcSFabiano Rosas         break;
878*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
879*ccfca2fcSFabiano Rosas         trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
880*ccfca2fcSFabiano Rosas         break;
881*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
882*ccfca2fcSFabiano Rosas         trace_ppc_excp_isi(msr, env->nip);
883*ccfca2fcSFabiano Rosas         msr |= env->error_code;
884*ccfca2fcSFabiano Rosas         break;
885*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
886*ccfca2fcSFabiano Rosas     {
887*ccfca2fcSFabiano Rosas         bool lpes0;
888*ccfca2fcSFabiano Rosas 
889*ccfca2fcSFabiano Rosas         cs = CPU(cpu);
890*ccfca2fcSFabiano Rosas 
891*ccfca2fcSFabiano Rosas         /*
892*ccfca2fcSFabiano Rosas          * Exception targeting modifiers
893*ccfca2fcSFabiano Rosas          *
894*ccfca2fcSFabiano Rosas          * LPES0 is supported on POWER7/8/9
895*ccfca2fcSFabiano Rosas          * LPES1 is not supported (old iSeries mode)
896*ccfca2fcSFabiano Rosas          *
897*ccfca2fcSFabiano Rosas          * On anything else, we behave as if LPES0 is 1
898*ccfca2fcSFabiano Rosas          * (externals don't alter MSR:HV)
899*ccfca2fcSFabiano Rosas          */
900*ccfca2fcSFabiano Rosas #if defined(TARGET_PPC64)
901*ccfca2fcSFabiano Rosas         if (excp_model == POWERPC_EXCP_POWER7 ||
902*ccfca2fcSFabiano Rosas             excp_model == POWERPC_EXCP_POWER8 ||
903*ccfca2fcSFabiano Rosas             excp_model == POWERPC_EXCP_POWER9 ||
904*ccfca2fcSFabiano Rosas             excp_model == POWERPC_EXCP_POWER10) {
905*ccfca2fcSFabiano Rosas             lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
906*ccfca2fcSFabiano Rosas         } else
907*ccfca2fcSFabiano Rosas #endif /* defined(TARGET_PPC64) */
908*ccfca2fcSFabiano Rosas         {
909*ccfca2fcSFabiano Rosas             lpes0 = true;
910*ccfca2fcSFabiano Rosas         }
911*ccfca2fcSFabiano Rosas 
912*ccfca2fcSFabiano Rosas         if (!lpes0) {
913*ccfca2fcSFabiano Rosas             new_msr |= (target_ulong)MSR_HVB;
914*ccfca2fcSFabiano Rosas             new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
915*ccfca2fcSFabiano Rosas             srr0 = SPR_HSRR0;
916*ccfca2fcSFabiano Rosas             srr1 = SPR_HSRR1;
917*ccfca2fcSFabiano Rosas         }
918*ccfca2fcSFabiano Rosas         if (env->mpic_proxy) {
919*ccfca2fcSFabiano Rosas             /* IACK the IRQ on delivery */
920*ccfca2fcSFabiano Rosas             env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
921*ccfca2fcSFabiano Rosas         }
922*ccfca2fcSFabiano Rosas         break;
923*ccfca2fcSFabiano Rosas     }
924*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
925*ccfca2fcSFabiano Rosas         /* Get rS/rD and rA from faulting opcode */
926*ccfca2fcSFabiano Rosas         /*
927*ccfca2fcSFabiano Rosas          * Note: the opcode fields will not be set properly for a
928*ccfca2fcSFabiano Rosas          * direct store load/store, but nobody cares as nobody
929*ccfca2fcSFabiano Rosas          * actually uses direct store segments.
930*ccfca2fcSFabiano Rosas          */
931*ccfca2fcSFabiano Rosas         env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
932*ccfca2fcSFabiano Rosas         break;
933*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
934*ccfca2fcSFabiano Rosas         switch (env->error_code & ~0xF) {
935*ccfca2fcSFabiano Rosas         case POWERPC_EXCP_FP:
936*ccfca2fcSFabiano Rosas             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
937*ccfca2fcSFabiano Rosas                 trace_ppc_excp_fp_ignore();
938*ccfca2fcSFabiano Rosas                 cs->exception_index = POWERPC_EXCP_NONE;
939*ccfca2fcSFabiano Rosas                 env->error_code = 0;
940*ccfca2fcSFabiano Rosas                 return;
941*ccfca2fcSFabiano Rosas             }
942*ccfca2fcSFabiano Rosas 
943*ccfca2fcSFabiano Rosas             /*
944*ccfca2fcSFabiano Rosas              * FP exceptions always have NIP pointing to the faulting
945*ccfca2fcSFabiano Rosas              * instruction, so always use store_next and claim we are
946*ccfca2fcSFabiano Rosas              * precise in the MSR.
947*ccfca2fcSFabiano Rosas              */
948*ccfca2fcSFabiano Rosas             msr |= 0x00100000;
949*ccfca2fcSFabiano Rosas             env->spr[SPR_BOOKE_ESR] = ESR_FP;
950*ccfca2fcSFabiano Rosas             break;
951*ccfca2fcSFabiano Rosas         case POWERPC_EXCP_INVAL:
952*ccfca2fcSFabiano Rosas             trace_ppc_excp_inval(env->nip);
953*ccfca2fcSFabiano Rosas             msr |= 0x00080000;
954*ccfca2fcSFabiano Rosas             env->spr[SPR_BOOKE_ESR] = ESR_PIL;
955*ccfca2fcSFabiano Rosas             break;
956*ccfca2fcSFabiano Rosas         case POWERPC_EXCP_PRIV:
957*ccfca2fcSFabiano Rosas             msr |= 0x00040000;
958*ccfca2fcSFabiano Rosas             env->spr[SPR_BOOKE_ESR] = ESR_PPR;
959*ccfca2fcSFabiano Rosas             break;
960*ccfca2fcSFabiano Rosas         case POWERPC_EXCP_TRAP:
961*ccfca2fcSFabiano Rosas             msr |= 0x00020000;
962*ccfca2fcSFabiano Rosas             env->spr[SPR_BOOKE_ESR] = ESR_PTR;
963*ccfca2fcSFabiano Rosas             break;
964*ccfca2fcSFabiano Rosas         default:
965*ccfca2fcSFabiano Rosas             /* Should never occur */
966*ccfca2fcSFabiano Rosas             cpu_abort(cs, "Invalid program exception %d. Aborting\n",
967*ccfca2fcSFabiano Rosas                       env->error_code);
968*ccfca2fcSFabiano Rosas             break;
969*ccfca2fcSFabiano Rosas         }
970*ccfca2fcSFabiano Rosas         break;
971*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
972*ccfca2fcSFabiano Rosas         lev = env->error_code;
973*ccfca2fcSFabiano Rosas 
974*ccfca2fcSFabiano Rosas         if ((lev == 1) && cpu->vhyp) {
975*ccfca2fcSFabiano Rosas             dump_hcall(env);
976*ccfca2fcSFabiano Rosas         } else {
977*ccfca2fcSFabiano Rosas             dump_syscall(env);
978*ccfca2fcSFabiano Rosas         }
979*ccfca2fcSFabiano Rosas 
980*ccfca2fcSFabiano Rosas         /*
981*ccfca2fcSFabiano Rosas          * We need to correct the NIP which in this case is supposed
982*ccfca2fcSFabiano Rosas          * to point to the next instruction
983*ccfca2fcSFabiano Rosas          */
984*ccfca2fcSFabiano Rosas         env->nip += 4;
985*ccfca2fcSFabiano Rosas 
986*ccfca2fcSFabiano Rosas         /* "PAPR mode" built-in hypercall emulation */
987*ccfca2fcSFabiano Rosas         if ((lev == 1) && cpu->vhyp) {
988*ccfca2fcSFabiano Rosas             PPCVirtualHypervisorClass *vhc =
989*ccfca2fcSFabiano Rosas                 PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
990*ccfca2fcSFabiano Rosas             vhc->hypercall(cpu->vhyp, cpu);
991*ccfca2fcSFabiano Rosas             return;
992*ccfca2fcSFabiano Rosas         }
993*ccfca2fcSFabiano Rosas         if (lev == 1) {
994*ccfca2fcSFabiano Rosas             new_msr |= (target_ulong)MSR_HVB;
995*ccfca2fcSFabiano Rosas         }
996*ccfca2fcSFabiano Rosas         break;
997*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception                     */
998*ccfca2fcSFabiano Rosas         lev = env->error_code;
999*ccfca2fcSFabiano Rosas         dump_syscall(env);
1000*ccfca2fcSFabiano Rosas         env->nip += 4;
1001*ccfca2fcSFabiano Rosas         new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
1002*ccfca2fcSFabiano Rosas         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
1003*ccfca2fcSFabiano Rosas 
1004*ccfca2fcSFabiano Rosas         vector += lev * 0x20;
1005*ccfca2fcSFabiano Rosas 
1006*ccfca2fcSFabiano Rosas         env->lr = env->nip;
1007*ccfca2fcSFabiano Rosas         env->ctr = msr;
1008*ccfca2fcSFabiano Rosas         break;
1009*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
1010*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
1011*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
1012*ccfca2fcSFabiano Rosas         break;
1013*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
1014*ccfca2fcSFabiano Rosas         /* FIT on 4xx */
1015*ccfca2fcSFabiano Rosas         trace_ppc_excp_print("FIT");
1016*ccfca2fcSFabiano Rosas         break;
1017*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
1018*ccfca2fcSFabiano Rosas         trace_ppc_excp_print("WDT");
1019*ccfca2fcSFabiano Rosas         switch (excp_model) {
1020*ccfca2fcSFabiano Rosas         case POWERPC_EXCP_BOOKE:
1021*ccfca2fcSFabiano Rosas             srr0 = SPR_BOOKE_CSRR0;
1022*ccfca2fcSFabiano Rosas             srr1 = SPR_BOOKE_CSRR1;
1023*ccfca2fcSFabiano Rosas             break;
1024*ccfca2fcSFabiano Rosas         default:
1025*ccfca2fcSFabiano Rosas             break;
1026*ccfca2fcSFabiano Rosas         }
1027*ccfca2fcSFabiano Rosas         break;
1028*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
1029*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
1030*ccfca2fcSFabiano Rosas         break;
1031*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
1032*ccfca2fcSFabiano Rosas         if (env->flags & POWERPC_FLAG_DE) {
1033*ccfca2fcSFabiano Rosas             /* FIXME: choose one or the other based on CPU type */
1034*ccfca2fcSFabiano Rosas             srr0 = SPR_BOOKE_DSRR0;
1035*ccfca2fcSFabiano Rosas             srr1 = SPR_BOOKE_DSRR1;
1036*ccfca2fcSFabiano Rosas 
1037*ccfca2fcSFabiano Rosas             env->spr[SPR_BOOKE_CSRR0] = env->nip;
1038*ccfca2fcSFabiano Rosas             env->spr[SPR_BOOKE_CSRR1] = msr;
1039*ccfca2fcSFabiano Rosas 
1040*ccfca2fcSFabiano Rosas             /* DBSR already modified by caller */
1041*ccfca2fcSFabiano Rosas         } else {
1042*ccfca2fcSFabiano Rosas             cpu_abort(cs, "Debug exception triggered on unsupported model\n");
1043*ccfca2fcSFabiano Rosas         }
1044*ccfca2fcSFabiano Rosas         break;
1045*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_SPEU:   /* SPE/embedded floating-point unavailable/VPU  */
1046*ccfca2fcSFabiano Rosas         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
1047*ccfca2fcSFabiano Rosas         break;
1048*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
1049*ccfca2fcSFabiano Rosas         break;
1050*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
1051*ccfca2fcSFabiano Rosas         srr0 = SPR_BOOKE_CSRR0;
1052*ccfca2fcSFabiano Rosas         srr1 = SPR_BOOKE_CSRR1;
1053*ccfca2fcSFabiano Rosas         break;
1054*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_RESET:     /* System reset exception                   */
1055*ccfca2fcSFabiano Rosas         /* A power-saving exception sets ME, otherwise it is unchanged */
1056*ccfca2fcSFabiano Rosas         if (msr_pow) {
1057*ccfca2fcSFabiano Rosas             /* indicate that we resumed from power save mode */
1058*ccfca2fcSFabiano Rosas             msr |= 0x10000;
1059*ccfca2fcSFabiano Rosas             new_msr |= ((target_ulong)1 << MSR_ME);
1060*ccfca2fcSFabiano Rosas         }
1061*ccfca2fcSFabiano Rosas         if (env->msr_mask & MSR_HVB) {
1062*ccfca2fcSFabiano Rosas             /*
1063*ccfca2fcSFabiano Rosas              * ISA specifies HV, but can be delivered to guest with HV
1064*ccfca2fcSFabiano Rosas              * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
1065*ccfca2fcSFabiano Rosas              */
1066*ccfca2fcSFabiano Rosas             new_msr |= (target_ulong)MSR_HVB;
1067*ccfca2fcSFabiano Rosas         } else {
1068*ccfca2fcSFabiano Rosas             if (msr_pow) {
1069*ccfca2fcSFabiano Rosas                 cpu_abort(cs, "Trying to deliver power-saving system reset "
1070*ccfca2fcSFabiano Rosas                           "exception %d with no HV support\n", excp);
1071*ccfca2fcSFabiano Rosas             }
1072*ccfca2fcSFabiano Rosas         }
1073*ccfca2fcSFabiano Rosas         break;
1074*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
1075*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
1076*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
1077*ccfca2fcSFabiano Rosas         break;
1078*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
1079*ccfca2fcSFabiano Rosas         msr |= env->error_code;
1080*ccfca2fcSFabiano Rosas         /* fall through */
1081*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
1082*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
1083*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
1084*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
1085*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
1086*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_HV_EMU:
1087*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
1088*ccfca2fcSFabiano Rosas         srr0 = SPR_HSRR0;
1089*ccfca2fcSFabiano Rosas         srr1 = SPR_HSRR1;
1090*ccfca2fcSFabiano Rosas         new_msr |= (target_ulong)MSR_HVB;
1091*ccfca2fcSFabiano Rosas         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
1092*ccfca2fcSFabiano Rosas         break;
1093*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
1094*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
1095*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
1096*ccfca2fcSFabiano Rosas #ifdef TARGET_PPC64
1097*ccfca2fcSFabiano Rosas         env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
1098*ccfca2fcSFabiano Rosas #endif
1099*ccfca2fcSFabiano Rosas         break;
1100*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_HV_FU:     /* Hypervisor Facility Unavailable Exception */
1101*ccfca2fcSFabiano Rosas #ifdef TARGET_PPC64
1102*ccfca2fcSFabiano Rosas         env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
1103*ccfca2fcSFabiano Rosas         srr0 = SPR_HSRR0;
1104*ccfca2fcSFabiano Rosas         srr1 = SPR_HSRR1;
1105*ccfca2fcSFabiano Rosas         new_msr |= (target_ulong)MSR_HVB;
1106*ccfca2fcSFabiano Rosas         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
1107*ccfca2fcSFabiano Rosas #endif
1108*ccfca2fcSFabiano Rosas         break;
1109*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
1110*ccfca2fcSFabiano Rosas         trace_ppc_excp_print("PIT");
1111*ccfca2fcSFabiano Rosas         break;
1112*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
1113*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
1114*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
1115*ccfca2fcSFabiano Rosas         switch (excp_model) {
1116*ccfca2fcSFabiano Rosas         case POWERPC_EXCP_6xx:
1117*ccfca2fcSFabiano Rosas             /* Swap temporary saved registers with GPRs */
1118*ccfca2fcSFabiano Rosas             if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
1119*ccfca2fcSFabiano Rosas                 new_msr |= (target_ulong)1 << MSR_TGPR;
1120*ccfca2fcSFabiano Rosas                 hreg_swap_gpr_tgpr(env);
1121*ccfca2fcSFabiano Rosas             }
1122*ccfca2fcSFabiano Rosas             /* fall through */
1123*ccfca2fcSFabiano Rosas         case POWERPC_EXCP_7xx:
1124*ccfca2fcSFabiano Rosas             ppc_excp_debug_sw_tlb(env, excp);
1125*ccfca2fcSFabiano Rosas 
1126*ccfca2fcSFabiano Rosas             msr |= env->crf[0] << 28;
1127*ccfca2fcSFabiano Rosas             msr |= env->error_code; /* key, D/I, S/L bits */
1128*ccfca2fcSFabiano Rosas             /* Set way using a LRU mechanism */
1129*ccfca2fcSFabiano Rosas             msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
1130*ccfca2fcSFabiano Rosas             break;
1131*ccfca2fcSFabiano Rosas         default:
1132*ccfca2fcSFabiano Rosas             cpu_abort(cs, "Invalid TLB miss exception\n");
1133*ccfca2fcSFabiano Rosas             break;
1134*ccfca2fcSFabiano Rosas         }
1135*ccfca2fcSFabiano Rosas         break;
1136*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
1137*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
1138*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
1139*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
1140*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
1141*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
1142*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_SMI:       /* System management interrupt              */
1143*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
1144*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
1145*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
1146*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
1147*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
1148*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
1149*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
1150*ccfca2fcSFabiano Rosas         cpu_abort(cs, "%s exception not implemented\n",
1151*ccfca2fcSFabiano Rosas                   powerpc_excp_name(excp));
1152*ccfca2fcSFabiano Rosas         break;
1153*ccfca2fcSFabiano Rosas     default:
1154*ccfca2fcSFabiano Rosas     excp_invalid:
1155*ccfca2fcSFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
1156*ccfca2fcSFabiano Rosas         break;
1157*ccfca2fcSFabiano Rosas     }
1158*ccfca2fcSFabiano Rosas 
1159*ccfca2fcSFabiano Rosas     /* Sanity check */
1160*ccfca2fcSFabiano Rosas     if (!(env->msr_mask & MSR_HVB)) {
1161*ccfca2fcSFabiano Rosas         if (new_msr & MSR_HVB) {
1162*ccfca2fcSFabiano Rosas             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
1163*ccfca2fcSFabiano Rosas                       "no HV support\n", excp);
1164*ccfca2fcSFabiano Rosas         }
1165*ccfca2fcSFabiano Rosas         if (srr0 == SPR_HSRR0) {
1166*ccfca2fcSFabiano Rosas             cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
1167*ccfca2fcSFabiano Rosas                       "no HV support\n", excp);
1168*ccfca2fcSFabiano Rosas         }
1169*ccfca2fcSFabiano Rosas     }
1170*ccfca2fcSFabiano Rosas 
1171*ccfca2fcSFabiano Rosas     /*
1172*ccfca2fcSFabiano Rosas      * Sort out endianness of interrupt, this differs depending on the
1173*ccfca2fcSFabiano Rosas      * CPU, the HV mode, etc...
1174*ccfca2fcSFabiano Rosas      */
1175*ccfca2fcSFabiano Rosas     if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
1176*ccfca2fcSFabiano Rosas         new_msr |= (target_ulong)1 << MSR_LE;
1177*ccfca2fcSFabiano Rosas     }
1178*ccfca2fcSFabiano Rosas 
1179*ccfca2fcSFabiano Rosas #if defined(TARGET_PPC64)
1180*ccfca2fcSFabiano Rosas     if (excp_model == POWERPC_EXCP_BOOKE) {
1181*ccfca2fcSFabiano Rosas         if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
1182*ccfca2fcSFabiano Rosas             /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
1183*ccfca2fcSFabiano Rosas             new_msr |= (target_ulong)1 << MSR_CM;
1184*ccfca2fcSFabiano Rosas         } else {
1185*ccfca2fcSFabiano Rosas             vector = (uint32_t)vector;
1186*ccfca2fcSFabiano Rosas         }
1187*ccfca2fcSFabiano Rosas     } else {
1188*ccfca2fcSFabiano Rosas         if (!msr_isf && !mmu_is_64bit(env->mmu_model)) {
1189*ccfca2fcSFabiano Rosas             vector = (uint32_t)vector;
1190*ccfca2fcSFabiano Rosas         } else {
1191*ccfca2fcSFabiano Rosas             new_msr |= (target_ulong)1 << MSR_SF;
1192*ccfca2fcSFabiano Rosas         }
1193*ccfca2fcSFabiano Rosas     }
1194*ccfca2fcSFabiano Rosas #endif
1195*ccfca2fcSFabiano Rosas 
1196*ccfca2fcSFabiano Rosas     if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
1197*ccfca2fcSFabiano Rosas         /* Save PC */
1198*ccfca2fcSFabiano Rosas         env->spr[srr0] = env->nip;
1199*ccfca2fcSFabiano Rosas 
1200*ccfca2fcSFabiano Rosas         /* Save MSR */
1201*ccfca2fcSFabiano Rosas         env->spr[srr1] = msr;
1202*ccfca2fcSFabiano Rosas     }
1203*ccfca2fcSFabiano Rosas 
1204*ccfca2fcSFabiano Rosas     /* This can update new_msr and vector if AIL applies */
1205*ccfca2fcSFabiano Rosas     ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector);
1206*ccfca2fcSFabiano Rosas 
1207*ccfca2fcSFabiano Rosas     powerpc_set_excp_state(cpu, vector, new_msr);
1208*ccfca2fcSFabiano Rosas }
1209*ccfca2fcSFabiano Rosas 
121052926b0dSFabiano Rosas static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
121152926b0dSFabiano Rosas {
121252926b0dSFabiano Rosas     CPUState *cs = CPU(cpu);
121352926b0dSFabiano Rosas     CPUPPCState *env = &cpu->env;
121452926b0dSFabiano Rosas     target_ulong msr, new_msr, vector;
121552926b0dSFabiano Rosas 
121652926b0dSFabiano Rosas     if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
121752926b0dSFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
121852926b0dSFabiano Rosas     }
121952926b0dSFabiano Rosas 
122052926b0dSFabiano Rosas     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
122152926b0dSFabiano Rosas                   " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
122252926b0dSFabiano Rosas                   excp, env->error_code);
122352926b0dSFabiano Rosas 
122452926b0dSFabiano Rosas     /* new srr1 value excluding must-be-zero bits */
122552926b0dSFabiano Rosas     msr = env->msr & ~0x783f0000ULL;
122652926b0dSFabiano Rosas 
122752926b0dSFabiano Rosas     /*
12281f6faf8bSFabiano Rosas      * new interrupt handler msr preserves existing ME unless
122952926b0dSFabiano Rosas      * explicitly overriden
123052926b0dSFabiano Rosas      */
12311f6faf8bSFabiano Rosas     new_msr = env->msr & ((target_ulong)1 << MSR_ME);
123252926b0dSFabiano Rosas 
123352926b0dSFabiano Rosas     /*
123452926b0dSFabiano Rosas      * Hypervisor emulation assistance interrupt only exists on server
12351f6faf8bSFabiano Rosas      * arch 2.05 server or later.
123652926b0dSFabiano Rosas      */
12371f6faf8bSFabiano Rosas     if (excp == POWERPC_EXCP_HV_EMU) {
123852926b0dSFabiano Rosas         excp = POWERPC_EXCP_PROGRAM;
123952926b0dSFabiano Rosas     }
124052926b0dSFabiano Rosas 
124152926b0dSFabiano Rosas     vector = env->excp_vectors[excp];
124252926b0dSFabiano Rosas     if (vector == (target_ulong)-1ULL) {
124352926b0dSFabiano Rosas         cpu_abort(cs, "Raised an exception without defined vector %d\n",
124452926b0dSFabiano Rosas                   excp);
124552926b0dSFabiano Rosas     }
124652926b0dSFabiano Rosas 
124752926b0dSFabiano Rosas     vector |= env->excp_prefix;
124852926b0dSFabiano Rosas 
124952926b0dSFabiano Rosas     switch (excp) {
125052926b0dSFabiano Rosas     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
125152926b0dSFabiano Rosas         if (msr_me == 0) {
125252926b0dSFabiano Rosas             /*
125352926b0dSFabiano Rosas              * Machine check exception is not enabled.  Enter
125452926b0dSFabiano Rosas              * checkstop state.
125552926b0dSFabiano Rosas              */
125652926b0dSFabiano Rosas             fprintf(stderr, "Machine check while not allowed. "
125752926b0dSFabiano Rosas                     "Entering checkstop state\n");
125852926b0dSFabiano Rosas             if (qemu_log_separate()) {
125952926b0dSFabiano Rosas                 qemu_log("Machine check while not allowed. "
126052926b0dSFabiano Rosas                         "Entering checkstop state\n");
126152926b0dSFabiano Rosas             }
126252926b0dSFabiano Rosas             cs->halted = 1;
126352926b0dSFabiano Rosas             cpu_interrupt_exittb(cs);
126452926b0dSFabiano Rosas         }
126552926b0dSFabiano Rosas 
126652926b0dSFabiano Rosas         /* machine check exceptions don't have ME set */
126752926b0dSFabiano Rosas         new_msr &= ~((target_ulong)1 << MSR_ME);
126852926b0dSFabiano Rosas 
126952926b0dSFabiano Rosas         break;
127052926b0dSFabiano Rosas     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
127152926b0dSFabiano Rosas         trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
127252926b0dSFabiano Rosas         break;
127352926b0dSFabiano Rosas     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
127452926b0dSFabiano Rosas         trace_ppc_excp_isi(msr, env->nip);
127552926b0dSFabiano Rosas         msr |= env->error_code;
127652926b0dSFabiano Rosas         break;
127752926b0dSFabiano Rosas     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
127852926b0dSFabiano Rosas         break;
127952926b0dSFabiano Rosas     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
128052926b0dSFabiano Rosas         /* Get rS/rD and rA from faulting opcode */
128152926b0dSFabiano Rosas         /*
128252926b0dSFabiano Rosas          * Note: the opcode fields will not be set properly for a
128352926b0dSFabiano Rosas          * direct store load/store, but nobody cares as nobody
128452926b0dSFabiano Rosas          * actually uses direct store segments.
128552926b0dSFabiano Rosas          */
128652926b0dSFabiano Rosas         env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
128752926b0dSFabiano Rosas         break;
128852926b0dSFabiano Rosas     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
128952926b0dSFabiano Rosas         switch (env->error_code & ~0xF) {
129052926b0dSFabiano Rosas         case POWERPC_EXCP_FP:
129152926b0dSFabiano Rosas             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
129252926b0dSFabiano Rosas                 trace_ppc_excp_fp_ignore();
129352926b0dSFabiano Rosas                 cs->exception_index = POWERPC_EXCP_NONE;
129452926b0dSFabiano Rosas                 env->error_code = 0;
129552926b0dSFabiano Rosas                 return;
129652926b0dSFabiano Rosas             }
129752926b0dSFabiano Rosas 
129852926b0dSFabiano Rosas             /*
129952926b0dSFabiano Rosas              * FP exceptions always have NIP pointing to the faulting
130052926b0dSFabiano Rosas              * instruction, so always use store_next and claim we are
130152926b0dSFabiano Rosas              * precise in the MSR.
130252926b0dSFabiano Rosas              */
130352926b0dSFabiano Rosas             msr |= 0x00100000;
130452926b0dSFabiano Rosas             break;
130552926b0dSFabiano Rosas         case POWERPC_EXCP_INVAL:
130652926b0dSFabiano Rosas             trace_ppc_excp_inval(env->nip);
130752926b0dSFabiano Rosas             msr |= 0x00080000;
130852926b0dSFabiano Rosas             break;
130952926b0dSFabiano Rosas         case POWERPC_EXCP_PRIV:
131052926b0dSFabiano Rosas             msr |= 0x00040000;
131152926b0dSFabiano Rosas             break;
131252926b0dSFabiano Rosas         case POWERPC_EXCP_TRAP:
131352926b0dSFabiano Rosas             msr |= 0x00020000;
131452926b0dSFabiano Rosas             break;
131552926b0dSFabiano Rosas         default:
131652926b0dSFabiano Rosas             /* Should never occur */
131752926b0dSFabiano Rosas             cpu_abort(cs, "Invalid program exception %d. Aborting\n",
131852926b0dSFabiano Rosas                       env->error_code);
131952926b0dSFabiano Rosas             break;
132052926b0dSFabiano Rosas         }
132152926b0dSFabiano Rosas         break;
132252926b0dSFabiano Rosas     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
1323bca2c6d9SFabiano Rosas     {
1324bca2c6d9SFabiano Rosas         int lev = env->error_code;
132552926b0dSFabiano Rosas 
132652926b0dSFabiano Rosas         if ((lev == 1) && cpu->vhyp) {
132752926b0dSFabiano Rosas             dump_hcall(env);
132852926b0dSFabiano Rosas         } else {
132952926b0dSFabiano Rosas             dump_syscall(env);
133052926b0dSFabiano Rosas         }
133152926b0dSFabiano Rosas 
133252926b0dSFabiano Rosas         /*
133352926b0dSFabiano Rosas          * We need to correct the NIP which in this case is supposed
133452926b0dSFabiano Rosas          * to point to the next instruction
133552926b0dSFabiano Rosas          */
133652926b0dSFabiano Rosas         env->nip += 4;
133752926b0dSFabiano Rosas 
1338bca2c6d9SFabiano Rosas         /*
1339bca2c6d9SFabiano Rosas          * The Virtual Open Firmware (VOF) relies on the 'sc 1'
1340bca2c6d9SFabiano Rosas          * instruction to communicate with QEMU. The pegasos2 machine
1341bca2c6d9SFabiano Rosas          * uses VOF and the 74xx CPUs, so although the 74xx don't have
1342bca2c6d9SFabiano Rosas          * HV mode, we need to keep hypercall support.
1343bca2c6d9SFabiano Rosas          */
134452926b0dSFabiano Rosas         if ((lev == 1) && cpu->vhyp) {
134552926b0dSFabiano Rosas             PPCVirtualHypervisorClass *vhc =
134652926b0dSFabiano Rosas                 PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
134752926b0dSFabiano Rosas             vhc->hypercall(cpu->vhyp, cpu);
134852926b0dSFabiano Rosas             return;
134952926b0dSFabiano Rosas         }
1350bca2c6d9SFabiano Rosas 
135152926b0dSFabiano Rosas         break;
1352bca2c6d9SFabiano Rosas     }
135352926b0dSFabiano Rosas     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
135452926b0dSFabiano Rosas     case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
135552926b0dSFabiano Rosas         break;
135652926b0dSFabiano Rosas     case POWERPC_EXCP_RESET:     /* System reset exception                   */
135752926b0dSFabiano Rosas         if (msr_pow) {
135852926b0dSFabiano Rosas             cpu_abort(cs, "Trying to deliver power-saving system reset "
135952926b0dSFabiano Rosas                       "exception %d with no HV support\n", excp);
136052926b0dSFabiano Rosas         }
136152926b0dSFabiano Rosas         break;
136252926b0dSFabiano Rosas     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
136352926b0dSFabiano Rosas         break;
136452926b0dSFabiano Rosas     case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
136552926b0dSFabiano Rosas         break;
136652926b0dSFabiano Rosas     case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
136752926b0dSFabiano Rosas     case POWERPC_EXCP_SMI:       /* System management interrupt              */
136852926b0dSFabiano Rosas     case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
136952926b0dSFabiano Rosas     case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
137052926b0dSFabiano Rosas     case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
137152926b0dSFabiano Rosas         cpu_abort(cs, "%s exception not implemented\n",
137252926b0dSFabiano Rosas                   powerpc_excp_name(excp));
137352926b0dSFabiano Rosas         break;
137452926b0dSFabiano Rosas     default:
137552926b0dSFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
137652926b0dSFabiano Rosas         break;
137752926b0dSFabiano Rosas     }
137852926b0dSFabiano Rosas 
137952926b0dSFabiano Rosas     /* Sanity check */
138052926b0dSFabiano Rosas     if (!(env->msr_mask & MSR_HVB)) {
138152926b0dSFabiano Rosas         if (new_msr & MSR_HVB) {
138252926b0dSFabiano Rosas             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
138352926b0dSFabiano Rosas                       "no HV support\n", excp);
138452926b0dSFabiano Rosas         }
138552926b0dSFabiano Rosas     }
138652926b0dSFabiano Rosas 
138752926b0dSFabiano Rosas     /*
138852926b0dSFabiano Rosas      * Sort out endianness of interrupt, this differs depending on the
138952926b0dSFabiano Rosas      * CPU, the HV mode, etc...
139052926b0dSFabiano Rosas      */
139152926b0dSFabiano Rosas     if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
139252926b0dSFabiano Rosas         new_msr |= (target_ulong)1 << MSR_LE;
139352926b0dSFabiano Rosas     }
139452926b0dSFabiano Rosas 
139552926b0dSFabiano Rosas     /* Save PC */
1396f82db777SFabiano Rosas     env->spr[SPR_SRR0] = env->nip;
139752926b0dSFabiano Rosas 
139852926b0dSFabiano Rosas     /* Save MSR */
1399f82db777SFabiano Rosas     env->spr[SPR_SRR1] = msr;
140052926b0dSFabiano Rosas 
140152926b0dSFabiano Rosas     powerpc_set_excp_state(cpu, vector, new_msr);
140252926b0dSFabiano Rosas }
140352926b0dSFabiano Rosas 
1404180952ceSFabiano Rosas static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
1405180952ceSFabiano Rosas {
1406180952ceSFabiano Rosas     CPUState *cs = CPU(cpu);
1407180952ceSFabiano Rosas     CPUPPCState *env = &cpu->env;
1408180952ceSFabiano Rosas     target_ulong msr, new_msr, vector;
1409904e8428SFabiano Rosas     int srr0, srr1;
1410180952ceSFabiano Rosas 
1411180952ceSFabiano Rosas     if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
1412180952ceSFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
1413180952ceSFabiano Rosas     }
1414180952ceSFabiano Rosas 
1415180952ceSFabiano Rosas     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
1416180952ceSFabiano Rosas                   " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
1417180952ceSFabiano Rosas                   excp, env->error_code);
1418180952ceSFabiano Rosas 
1419180952ceSFabiano Rosas     msr = env->msr;
1420180952ceSFabiano Rosas 
1421180952ceSFabiano Rosas     /*
14229dc20cc3SFabiano Rosas      * new interrupt handler msr preserves existing ME unless
1423180952ceSFabiano Rosas      * explicitly overriden
1424180952ceSFabiano Rosas      */
14259dc20cc3SFabiano Rosas     new_msr = env->msr & ((target_ulong)1 << MSR_ME);
1426180952ceSFabiano Rosas 
1427180952ceSFabiano Rosas     /* target registers */
1428180952ceSFabiano Rosas     srr0 = SPR_SRR0;
1429180952ceSFabiano Rosas     srr1 = SPR_SRR1;
1430180952ceSFabiano Rosas 
1431180952ceSFabiano Rosas     /*
1432180952ceSFabiano Rosas      * Hypervisor emulation assistance interrupt only exists on server
14339dc20cc3SFabiano Rosas      * arch 2.05 server or later.
1434180952ceSFabiano Rosas      */
14359dc20cc3SFabiano Rosas     if (excp == POWERPC_EXCP_HV_EMU) {
1436180952ceSFabiano Rosas         excp = POWERPC_EXCP_PROGRAM;
1437180952ceSFabiano Rosas     }
1438180952ceSFabiano Rosas 
1439180952ceSFabiano Rosas #ifdef TARGET_PPC64
1440180952ceSFabiano Rosas     /*
1441180952ceSFabiano Rosas      * SPEU and VPU share the same IVOR but they exist in different
1442180952ceSFabiano Rosas      * processors. SPEU is e500v1/2 only and VPU is e6500 only.
1443180952ceSFabiano Rosas      */
14449dc20cc3SFabiano Rosas     if (excp == POWERPC_EXCP_VPU) {
1445180952ceSFabiano Rosas         excp = POWERPC_EXCP_SPEU;
1446180952ceSFabiano Rosas     }
1447180952ceSFabiano Rosas #endif
1448180952ceSFabiano Rosas 
1449180952ceSFabiano Rosas     vector = env->excp_vectors[excp];
1450180952ceSFabiano Rosas     if (vector == (target_ulong)-1ULL) {
1451180952ceSFabiano Rosas         cpu_abort(cs, "Raised an exception without defined vector %d\n",
1452180952ceSFabiano Rosas                   excp);
1453180952ceSFabiano Rosas     }
1454180952ceSFabiano Rosas 
1455180952ceSFabiano Rosas     vector |= env->excp_prefix;
1456180952ceSFabiano Rosas 
1457180952ceSFabiano Rosas     switch (excp) {
1458180952ceSFabiano Rosas     case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
1459180952ceSFabiano Rosas         srr0 = SPR_BOOKE_CSRR0;
1460180952ceSFabiano Rosas         srr1 = SPR_BOOKE_CSRR1;
1461180952ceSFabiano Rosas         break;
1462180952ceSFabiano Rosas     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
1463180952ceSFabiano Rosas         if (msr_me == 0) {
1464180952ceSFabiano Rosas             /*
1465180952ceSFabiano Rosas              * Machine check exception is not enabled.  Enter
1466180952ceSFabiano Rosas              * checkstop state.
1467180952ceSFabiano Rosas              */
1468180952ceSFabiano Rosas             fprintf(stderr, "Machine check while not allowed. "
1469180952ceSFabiano Rosas                     "Entering checkstop state\n");
1470180952ceSFabiano Rosas             if (qemu_log_separate()) {
1471180952ceSFabiano Rosas                 qemu_log("Machine check while not allowed. "
1472180952ceSFabiano Rosas                         "Entering checkstop state\n");
1473180952ceSFabiano Rosas             }
1474180952ceSFabiano Rosas             cs->halted = 1;
1475180952ceSFabiano Rosas             cpu_interrupt_exittb(cs);
1476180952ceSFabiano Rosas         }
1477180952ceSFabiano Rosas 
1478180952ceSFabiano Rosas         /* machine check exceptions don't have ME set */
1479180952ceSFabiano Rosas         new_msr &= ~((target_ulong)1 << MSR_ME);
1480180952ceSFabiano Rosas 
1481180952ceSFabiano Rosas         /* FIXME: choose one or the other based on CPU type */
1482180952ceSFabiano Rosas         srr0 = SPR_BOOKE_MCSRR0;
1483180952ceSFabiano Rosas         srr1 = SPR_BOOKE_MCSRR1;
1484180952ceSFabiano Rosas 
1485180952ceSFabiano Rosas         env->spr[SPR_BOOKE_CSRR0] = env->nip;
1486180952ceSFabiano Rosas         env->spr[SPR_BOOKE_CSRR1] = msr;
1487db403211SFabiano Rosas 
1488180952ceSFabiano Rosas         break;
1489180952ceSFabiano Rosas     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
1490afdbc869SFabiano Rosas         trace_ppc_excp_dsi(env->spr[SPR_BOOKE_ESR], env->spr[SPR_BOOKE_DEAR]);
1491180952ceSFabiano Rosas         break;
1492180952ceSFabiano Rosas     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
1493180952ceSFabiano Rosas         trace_ppc_excp_isi(msr, env->nip);
1494180952ceSFabiano Rosas         break;
1495180952ceSFabiano Rosas     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
1496180952ceSFabiano Rosas         if (env->mpic_proxy) {
1497180952ceSFabiano Rosas             /* IACK the IRQ on delivery */
1498180952ceSFabiano Rosas             env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
1499180952ceSFabiano Rosas         }
1500180952ceSFabiano Rosas         break;
1501180952ceSFabiano Rosas     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
1502180952ceSFabiano Rosas         break;
1503180952ceSFabiano Rosas     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
1504180952ceSFabiano Rosas         switch (env->error_code & ~0xF) {
1505180952ceSFabiano Rosas         case POWERPC_EXCP_FP:
1506180952ceSFabiano Rosas             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
1507180952ceSFabiano Rosas                 trace_ppc_excp_fp_ignore();
1508180952ceSFabiano Rosas                 cs->exception_index = POWERPC_EXCP_NONE;
1509180952ceSFabiano Rosas                 env->error_code = 0;
1510180952ceSFabiano Rosas                 return;
1511180952ceSFabiano Rosas             }
1512180952ceSFabiano Rosas 
1513180952ceSFabiano Rosas             /*
1514180952ceSFabiano Rosas              * FP exceptions always have NIP pointing to the faulting
1515180952ceSFabiano Rosas              * instruction, so always use store_next and claim we are
1516180952ceSFabiano Rosas              * precise in the MSR.
1517180952ceSFabiano Rosas              */
1518180952ceSFabiano Rosas             msr |= 0x00100000;
1519180952ceSFabiano Rosas             env->spr[SPR_BOOKE_ESR] = ESR_FP;
1520180952ceSFabiano Rosas             break;
1521180952ceSFabiano Rosas         case POWERPC_EXCP_INVAL:
1522180952ceSFabiano Rosas             trace_ppc_excp_inval(env->nip);
1523180952ceSFabiano Rosas             msr |= 0x00080000;
1524180952ceSFabiano Rosas             env->spr[SPR_BOOKE_ESR] = ESR_PIL;
1525180952ceSFabiano Rosas             break;
1526180952ceSFabiano Rosas         case POWERPC_EXCP_PRIV:
1527180952ceSFabiano Rosas             msr |= 0x00040000;
1528180952ceSFabiano Rosas             env->spr[SPR_BOOKE_ESR] = ESR_PPR;
1529180952ceSFabiano Rosas             break;
1530180952ceSFabiano Rosas         case POWERPC_EXCP_TRAP:
1531180952ceSFabiano Rosas             msr |= 0x00020000;
1532180952ceSFabiano Rosas             env->spr[SPR_BOOKE_ESR] = ESR_PTR;
1533180952ceSFabiano Rosas             break;
1534180952ceSFabiano Rosas         default:
1535180952ceSFabiano Rosas             /* Should never occur */
1536180952ceSFabiano Rosas             cpu_abort(cs, "Invalid program exception %d. Aborting\n",
1537180952ceSFabiano Rosas                       env->error_code);
1538180952ceSFabiano Rosas             break;
1539180952ceSFabiano Rosas         }
1540180952ceSFabiano Rosas         break;
1541180952ceSFabiano Rosas     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
1542180952ceSFabiano Rosas         dump_syscall(env);
1543180952ceSFabiano Rosas 
1544180952ceSFabiano Rosas         /*
1545180952ceSFabiano Rosas          * We need to correct the NIP which in this case is supposed
1546180952ceSFabiano Rosas          * to point to the next instruction
1547180952ceSFabiano Rosas          */
1548180952ceSFabiano Rosas         env->nip += 4;
1549180952ceSFabiano Rosas         break;
1550180952ceSFabiano Rosas     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
1551180952ceSFabiano Rosas     case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
1552180952ceSFabiano Rosas     case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
1553180952ceSFabiano Rosas         break;
1554180952ceSFabiano Rosas     case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
1555180952ceSFabiano Rosas         /* FIT on 4xx */
1556180952ceSFabiano Rosas         trace_ppc_excp_print("FIT");
1557180952ceSFabiano Rosas         break;
1558180952ceSFabiano Rosas     case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
1559180952ceSFabiano Rosas         trace_ppc_excp_print("WDT");
1560180952ceSFabiano Rosas         srr0 = SPR_BOOKE_CSRR0;
1561180952ceSFabiano Rosas         srr1 = SPR_BOOKE_CSRR1;
1562180952ceSFabiano Rosas         break;
1563180952ceSFabiano Rosas     case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
1564180952ceSFabiano Rosas     case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
1565180952ceSFabiano Rosas         break;
1566180952ceSFabiano Rosas     case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
1567180952ceSFabiano Rosas         if (env->flags & POWERPC_FLAG_DE) {
1568180952ceSFabiano Rosas             /* FIXME: choose one or the other based on CPU type */
1569180952ceSFabiano Rosas             srr0 = SPR_BOOKE_DSRR0;
1570180952ceSFabiano Rosas             srr1 = SPR_BOOKE_DSRR1;
1571180952ceSFabiano Rosas 
1572180952ceSFabiano Rosas             env->spr[SPR_BOOKE_CSRR0] = env->nip;
1573180952ceSFabiano Rosas             env->spr[SPR_BOOKE_CSRR1] = msr;
1574180952ceSFabiano Rosas 
1575180952ceSFabiano Rosas             /* DBSR already modified by caller */
1576180952ceSFabiano Rosas         } else {
1577180952ceSFabiano Rosas             cpu_abort(cs, "Debug exception triggered on unsupported model\n");
1578180952ceSFabiano Rosas         }
1579180952ceSFabiano Rosas         break;
1580180952ceSFabiano Rosas     case POWERPC_EXCP_SPEU:   /* SPE/embedded floating-point unavailable/VPU  */
1581180952ceSFabiano Rosas         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
1582180952ceSFabiano Rosas         break;
1583180952ceSFabiano Rosas     case POWERPC_EXCP_RESET:     /* System reset exception                   */
1584180952ceSFabiano Rosas         if (msr_pow) {
1585180952ceSFabiano Rosas             cpu_abort(cs, "Trying to deliver power-saving system reset "
1586180952ceSFabiano Rosas                       "exception %d with no HV support\n", excp);
1587180952ceSFabiano Rosas         }
1588180952ceSFabiano Rosas         break;
1589180952ceSFabiano Rosas     case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
1590180952ceSFabiano Rosas     case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
1591180952ceSFabiano Rosas         cpu_abort(cs, "%s exception not implemented\n",
1592180952ceSFabiano Rosas                   powerpc_excp_name(excp));
1593180952ceSFabiano Rosas         break;
1594180952ceSFabiano Rosas     default:
1595180952ceSFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
1596180952ceSFabiano Rosas         break;
1597180952ceSFabiano Rosas     }
1598180952ceSFabiano Rosas 
1599180952ceSFabiano Rosas     /* Sanity check */
1600180952ceSFabiano Rosas     if (!(env->msr_mask & MSR_HVB)) {
1601180952ceSFabiano Rosas         if (new_msr & MSR_HVB) {
1602180952ceSFabiano Rosas             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
1603180952ceSFabiano Rosas                       "no HV support\n", excp);
1604180952ceSFabiano Rosas         }
1605180952ceSFabiano Rosas         if (srr0 == SPR_HSRR0) {
1606180952ceSFabiano Rosas             cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
1607180952ceSFabiano Rosas                       "no HV support\n", excp);
1608180952ceSFabiano Rosas         }
1609180952ceSFabiano Rosas     }
1610180952ceSFabiano Rosas 
1611180952ceSFabiano Rosas #if defined(TARGET_PPC64)
1612180952ceSFabiano Rosas     if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
1613180952ceSFabiano Rosas         /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
1614180952ceSFabiano Rosas         new_msr |= (target_ulong)1 << MSR_CM;
1615180952ceSFabiano Rosas     } else {
1616180952ceSFabiano Rosas         vector = (uint32_t)vector;
1617180952ceSFabiano Rosas     }
1618180952ceSFabiano Rosas #endif
1619180952ceSFabiano Rosas 
1620180952ceSFabiano Rosas     /* Save PC */
1621180952ceSFabiano Rosas     env->spr[srr0] = env->nip;
1622180952ceSFabiano Rosas 
1623180952ceSFabiano Rosas     /* Save MSR */
1624180952ceSFabiano Rosas     env->spr[srr1] = msr;
1625180952ceSFabiano Rosas 
1626180952ceSFabiano Rosas     powerpc_set_excp_state(cpu, vector, new_msr);
1627180952ceSFabiano Rosas }
1628180952ceSFabiano Rosas 
162930c4e426SFabiano Rosas #ifdef TARGET_PPC64
16309f338e4dSFabiano Rosas static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
16319f338e4dSFabiano Rosas {
16329f338e4dSFabiano Rosas     CPUState *cs = CPU(cpu);
16339f338e4dSFabiano Rosas     CPUPPCState *env = &cpu->env;
16349f338e4dSFabiano Rosas     int excp_model = env->excp_model;
16359f338e4dSFabiano Rosas     target_ulong msr, new_msr, vector;
16369f338e4dSFabiano Rosas     int srr0, srr1, lev = -1;
16379f338e4dSFabiano Rosas 
16389f338e4dSFabiano Rosas     if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
16399f338e4dSFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
16409f338e4dSFabiano Rosas     }
16419f338e4dSFabiano Rosas 
16429f338e4dSFabiano Rosas     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
16439f338e4dSFabiano Rosas                   " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
16449f338e4dSFabiano Rosas                   excp, env->error_code);
16459f338e4dSFabiano Rosas 
16469f338e4dSFabiano Rosas     /* new srr1 value excluding must-be-zero bits */
16479f338e4dSFabiano Rosas     msr = env->msr & ~0x783f0000ULL;
16489f338e4dSFabiano Rosas 
16499f338e4dSFabiano Rosas     /*
16509f338e4dSFabiano Rosas      * new interrupt handler msr preserves existing HV and ME unless
16519f338e4dSFabiano Rosas      * explicitly overriden
16529f338e4dSFabiano Rosas      */
16539f338e4dSFabiano Rosas     new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
16549f338e4dSFabiano Rosas 
16559f338e4dSFabiano Rosas     /* target registers */
16569f338e4dSFabiano Rosas     srr0 = SPR_SRR0;
16579f338e4dSFabiano Rosas     srr1 = SPR_SRR1;
16589f338e4dSFabiano Rosas 
16599f338e4dSFabiano Rosas     /*
16609f338e4dSFabiano Rosas      * check for special resume at 0x100 from doze/nap/sleep/winkle on
16619f338e4dSFabiano Rosas      * P7/P8/P9
16629f338e4dSFabiano Rosas      */
16639f338e4dSFabiano Rosas     if (env->resume_as_sreset) {
16649f338e4dSFabiano Rosas         excp = powerpc_reset_wakeup(cs, env, excp, &msr);
16659f338e4dSFabiano Rosas     }
16669f338e4dSFabiano Rosas 
16679f338e4dSFabiano Rosas     /*
166830c4e426SFabiano Rosas      * We don't want to generate a Hypervisor Emulation Assistance
166930c4e426SFabiano Rosas      * Interrupt if we don't have HVB in msr_mask (PAPR mode).
16709f338e4dSFabiano Rosas      */
167130c4e426SFabiano Rosas     if (excp == POWERPC_EXCP_HV_EMU && !(env->msr_mask & MSR_HVB)) {
16729f338e4dSFabiano Rosas         excp = POWERPC_EXCP_PROGRAM;
16739f338e4dSFabiano Rosas     }
16749f338e4dSFabiano Rosas 
16759f338e4dSFabiano Rosas     vector = env->excp_vectors[excp];
16769f338e4dSFabiano Rosas     if (vector == (target_ulong)-1ULL) {
16779f338e4dSFabiano Rosas         cpu_abort(cs, "Raised an exception without defined vector %d\n",
16789f338e4dSFabiano Rosas                   excp);
16799f338e4dSFabiano Rosas     }
16809f338e4dSFabiano Rosas 
16819f338e4dSFabiano Rosas     vector |= env->excp_prefix;
16829f338e4dSFabiano Rosas 
16839f338e4dSFabiano Rosas     switch (excp) {
16849f338e4dSFabiano Rosas     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
16859f338e4dSFabiano Rosas         if (msr_me == 0) {
16869f338e4dSFabiano Rosas             /*
16879f338e4dSFabiano Rosas              * Machine check exception is not enabled.  Enter
16889f338e4dSFabiano Rosas              * checkstop state.
16899f338e4dSFabiano Rosas              */
16909f338e4dSFabiano Rosas             fprintf(stderr, "Machine check while not allowed. "
16919f338e4dSFabiano Rosas                     "Entering checkstop state\n");
16929f338e4dSFabiano Rosas             if (qemu_log_separate()) {
16939f338e4dSFabiano Rosas                 qemu_log("Machine check while not allowed. "
16949f338e4dSFabiano Rosas                         "Entering checkstop state\n");
16959f338e4dSFabiano Rosas             }
16969f338e4dSFabiano Rosas             cs->halted = 1;
16979f338e4dSFabiano Rosas             cpu_interrupt_exittb(cs);
16989f338e4dSFabiano Rosas         }
16999f338e4dSFabiano Rosas         if (env->msr_mask & MSR_HVB) {
17009f338e4dSFabiano Rosas             /*
17019f338e4dSFabiano Rosas              * ISA specifies HV, but can be delivered to guest with HV
17029f338e4dSFabiano Rosas              * clear (e.g., see FWNMI in PAPR).
17039f338e4dSFabiano Rosas              */
17049f338e4dSFabiano Rosas             new_msr |= (target_ulong)MSR_HVB;
17059f338e4dSFabiano Rosas         }
17069f338e4dSFabiano Rosas 
17079f338e4dSFabiano Rosas         /* machine check exceptions don't have ME set */
17089f338e4dSFabiano Rosas         new_msr &= ~((target_ulong)1 << MSR_ME);
17099f338e4dSFabiano Rosas 
17109f338e4dSFabiano Rosas         break;
17119f338e4dSFabiano Rosas     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
17129f338e4dSFabiano Rosas         trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
17139f338e4dSFabiano Rosas         break;
17149f338e4dSFabiano Rosas     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
17159f338e4dSFabiano Rosas         trace_ppc_excp_isi(msr, env->nip);
17169f338e4dSFabiano Rosas         msr |= env->error_code;
17179f338e4dSFabiano Rosas         break;
17189f338e4dSFabiano Rosas     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
17199f338e4dSFabiano Rosas     {
17209f338e4dSFabiano Rosas         bool lpes0;
17219f338e4dSFabiano Rosas 
17229f338e4dSFabiano Rosas         /*
172367baff77SFabiano Rosas          * LPES0 is only taken into consideration if we support HV
172467baff77SFabiano Rosas          * mode for this CPU.
17259f338e4dSFabiano Rosas          */
172667baff77SFabiano Rosas         if (!env->has_hv_mode) {
172767baff77SFabiano Rosas             break;
17289f338e4dSFabiano Rosas         }
17299f338e4dSFabiano Rosas 
173067baff77SFabiano Rosas         lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
173167baff77SFabiano Rosas 
17329f338e4dSFabiano Rosas         if (!lpes0) {
17339f338e4dSFabiano Rosas             new_msr |= (target_ulong)MSR_HVB;
17349f338e4dSFabiano Rosas             new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
17359f338e4dSFabiano Rosas             srr0 = SPR_HSRR0;
17369f338e4dSFabiano Rosas             srr1 = SPR_HSRR1;
17379f338e4dSFabiano Rosas         }
173867baff77SFabiano Rosas 
17399f338e4dSFabiano Rosas         break;
17409f338e4dSFabiano Rosas     }
17419f338e4dSFabiano Rosas     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
17429f338e4dSFabiano Rosas         /* Get rS/rD and rA from faulting opcode */
17439f338e4dSFabiano Rosas         /*
17449f338e4dSFabiano Rosas          * Note: the opcode fields will not be set properly for a
17459f338e4dSFabiano Rosas          * direct store load/store, but nobody cares as nobody
17469f338e4dSFabiano Rosas          * actually uses direct store segments.
17479f338e4dSFabiano Rosas          */
17489f338e4dSFabiano Rosas         env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
17499f338e4dSFabiano Rosas         break;
17509f338e4dSFabiano Rosas     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
17519f338e4dSFabiano Rosas         switch (env->error_code & ~0xF) {
17529f338e4dSFabiano Rosas         case POWERPC_EXCP_FP:
17539f338e4dSFabiano Rosas             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
17549f338e4dSFabiano Rosas                 trace_ppc_excp_fp_ignore();
17559f338e4dSFabiano Rosas                 cs->exception_index = POWERPC_EXCP_NONE;
17569f338e4dSFabiano Rosas                 env->error_code = 0;
17579f338e4dSFabiano Rosas                 return;
17589f338e4dSFabiano Rosas             }
17599f338e4dSFabiano Rosas 
17609f338e4dSFabiano Rosas             /*
17619f338e4dSFabiano Rosas              * FP exceptions always have NIP pointing to the faulting
17629f338e4dSFabiano Rosas              * instruction, so always use store_next and claim we are
17639f338e4dSFabiano Rosas              * precise in the MSR.
17649f338e4dSFabiano Rosas              */
17659f338e4dSFabiano Rosas             msr |= 0x00100000;
17669f338e4dSFabiano Rosas             break;
17679f338e4dSFabiano Rosas         case POWERPC_EXCP_INVAL:
17689f338e4dSFabiano Rosas             trace_ppc_excp_inval(env->nip);
17699f338e4dSFabiano Rosas             msr |= 0x00080000;
17709f338e4dSFabiano Rosas             break;
17719f338e4dSFabiano Rosas         case POWERPC_EXCP_PRIV:
17729f338e4dSFabiano Rosas             msr |= 0x00040000;
17739f338e4dSFabiano Rosas             break;
17749f338e4dSFabiano Rosas         case POWERPC_EXCP_TRAP:
17759f338e4dSFabiano Rosas             msr |= 0x00020000;
17769f338e4dSFabiano Rosas             break;
17779f338e4dSFabiano Rosas         default:
17789f338e4dSFabiano Rosas             /* Should never occur */
17799f338e4dSFabiano Rosas             cpu_abort(cs, "Invalid program exception %d. Aborting\n",
17809f338e4dSFabiano Rosas                       env->error_code);
17819f338e4dSFabiano Rosas             break;
17829f338e4dSFabiano Rosas         }
17839f338e4dSFabiano Rosas         break;
17849f338e4dSFabiano Rosas     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
17859f338e4dSFabiano Rosas         lev = env->error_code;
17869f338e4dSFabiano Rosas 
17879f338e4dSFabiano Rosas         if ((lev == 1) && cpu->vhyp) {
17889f338e4dSFabiano Rosas             dump_hcall(env);
17899f338e4dSFabiano Rosas         } else {
17909f338e4dSFabiano Rosas             dump_syscall(env);
17919f338e4dSFabiano Rosas         }
17929f338e4dSFabiano Rosas 
17939f338e4dSFabiano Rosas         /*
17949f338e4dSFabiano Rosas          * We need to correct the NIP which in this case is supposed
17959f338e4dSFabiano Rosas          * to point to the next instruction
17969f338e4dSFabiano Rosas          */
17979f338e4dSFabiano Rosas         env->nip += 4;
17989f338e4dSFabiano Rosas 
17999f338e4dSFabiano Rosas         /* "PAPR mode" built-in hypercall emulation */
18009f338e4dSFabiano Rosas         if ((lev == 1) && cpu->vhyp) {
18019f338e4dSFabiano Rosas             PPCVirtualHypervisorClass *vhc =
18029f338e4dSFabiano Rosas                 PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
18039f338e4dSFabiano Rosas             vhc->hypercall(cpu->vhyp, cpu);
18049f338e4dSFabiano Rosas             return;
18059f338e4dSFabiano Rosas         }
18069f338e4dSFabiano Rosas         if (lev == 1) {
18079f338e4dSFabiano Rosas             new_msr |= (target_ulong)MSR_HVB;
18089f338e4dSFabiano Rosas         }
18099f338e4dSFabiano Rosas         break;
18109f338e4dSFabiano Rosas     case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception                     */
18119f338e4dSFabiano Rosas         lev = env->error_code;
18129f338e4dSFabiano Rosas         dump_syscall(env);
18139f338e4dSFabiano Rosas         env->nip += 4;
18149f338e4dSFabiano Rosas         new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
18159f338e4dSFabiano Rosas         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
18169f338e4dSFabiano Rosas 
18179f338e4dSFabiano Rosas         vector += lev * 0x20;
18189f338e4dSFabiano Rosas 
18199f338e4dSFabiano Rosas         env->lr = env->nip;
18209f338e4dSFabiano Rosas         env->ctr = msr;
18219f338e4dSFabiano Rosas         break;
18229f338e4dSFabiano Rosas     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
18239f338e4dSFabiano Rosas     case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
18249f338e4dSFabiano Rosas         break;
18259f338e4dSFabiano Rosas     case POWERPC_EXCP_RESET:     /* System reset exception                   */
18269f338e4dSFabiano Rosas         /* A power-saving exception sets ME, otherwise it is unchanged */
18279f338e4dSFabiano Rosas         if (msr_pow) {
18289f338e4dSFabiano Rosas             /* indicate that we resumed from power save mode */
18299f338e4dSFabiano Rosas             msr |= 0x10000;
18309f338e4dSFabiano Rosas             new_msr |= ((target_ulong)1 << MSR_ME);
18319f338e4dSFabiano Rosas         }
18329f338e4dSFabiano Rosas         if (env->msr_mask & MSR_HVB) {
18339f338e4dSFabiano Rosas             /*
18349f338e4dSFabiano Rosas              * ISA specifies HV, but can be delivered to guest with HV
18359f338e4dSFabiano Rosas              * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
18369f338e4dSFabiano Rosas              */
18379f338e4dSFabiano Rosas             new_msr |= (target_ulong)MSR_HVB;
18389f338e4dSFabiano Rosas         } else {
18399f338e4dSFabiano Rosas             if (msr_pow) {
18409f338e4dSFabiano Rosas                 cpu_abort(cs, "Trying to deliver power-saving system reset "
18419f338e4dSFabiano Rosas                           "exception %d with no HV support\n", excp);
18429f338e4dSFabiano Rosas             }
18439f338e4dSFabiano Rosas         }
18449f338e4dSFabiano Rosas         break;
18459f338e4dSFabiano Rosas     case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
18469f338e4dSFabiano Rosas     case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
18479f338e4dSFabiano Rosas     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
18489f338e4dSFabiano Rosas         break;
18499f338e4dSFabiano Rosas     case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
18509f338e4dSFabiano Rosas         msr |= env->error_code;
18519f338e4dSFabiano Rosas         /* fall through */
18529f338e4dSFabiano Rosas     case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
18539f338e4dSFabiano Rosas     case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
18549f338e4dSFabiano Rosas     case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
18559f338e4dSFabiano Rosas     case POWERPC_EXCP_HV_EMU:
18569f338e4dSFabiano Rosas     case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
18579f338e4dSFabiano Rosas         srr0 = SPR_HSRR0;
18589f338e4dSFabiano Rosas         srr1 = SPR_HSRR1;
18599f338e4dSFabiano Rosas         new_msr |= (target_ulong)MSR_HVB;
18609f338e4dSFabiano Rosas         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
18619f338e4dSFabiano Rosas         break;
18629f338e4dSFabiano Rosas     case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
18639f338e4dSFabiano Rosas     case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
18649f338e4dSFabiano Rosas     case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
18659f338e4dSFabiano Rosas         env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
18669f338e4dSFabiano Rosas         break;
18679f338e4dSFabiano Rosas     case POWERPC_EXCP_HV_FU:     /* Hypervisor Facility Unavailable Exception */
18689f338e4dSFabiano Rosas         env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
18699f338e4dSFabiano Rosas         srr0 = SPR_HSRR0;
18709f338e4dSFabiano Rosas         srr1 = SPR_HSRR1;
18719f338e4dSFabiano Rosas         new_msr |= (target_ulong)MSR_HVB;
18729f338e4dSFabiano Rosas         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
18739f338e4dSFabiano Rosas         break;
18749f338e4dSFabiano Rosas     case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
18759f338e4dSFabiano Rosas     case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
18769f338e4dSFabiano Rosas     case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
18779f338e4dSFabiano Rosas     case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
187830c4e426SFabiano Rosas     case POWERPC_EXCP_SDOOR:     /* Doorbell interrupt                       */
187930c4e426SFabiano Rosas     case POWERPC_EXCP_HV_MAINT:  /* Hypervisor Maintenance exception         */
18809f338e4dSFabiano Rosas         cpu_abort(cs, "%s exception not implemented\n",
18819f338e4dSFabiano Rosas                   powerpc_excp_name(excp));
18829f338e4dSFabiano Rosas         break;
18839f338e4dSFabiano Rosas     default:
18849f338e4dSFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
18859f338e4dSFabiano Rosas         break;
18869f338e4dSFabiano Rosas     }
18879f338e4dSFabiano Rosas 
18889f338e4dSFabiano Rosas     /* Sanity check */
18899f338e4dSFabiano Rosas     if (!(env->msr_mask & MSR_HVB)) {
18909f338e4dSFabiano Rosas         if (new_msr & MSR_HVB) {
18919f338e4dSFabiano Rosas             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
18929f338e4dSFabiano Rosas                       "no HV support\n", excp);
18939f338e4dSFabiano Rosas         }
18949f338e4dSFabiano Rosas         if (srr0 == SPR_HSRR0) {
18959f338e4dSFabiano Rosas             cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
18969f338e4dSFabiano Rosas                       "no HV support\n", excp);
18979f338e4dSFabiano Rosas         }
18989f338e4dSFabiano Rosas     }
18999f338e4dSFabiano Rosas 
19009f338e4dSFabiano Rosas     /*
19019f338e4dSFabiano Rosas      * Sort out endianness of interrupt, this differs depending on the
19029f338e4dSFabiano Rosas      * CPU, the HV mode, etc...
19039f338e4dSFabiano Rosas      */
19049f338e4dSFabiano Rosas     if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
19059f338e4dSFabiano Rosas         new_msr |= (target_ulong)1 << MSR_LE;
19069f338e4dSFabiano Rosas     }
19079f338e4dSFabiano Rosas 
19089f338e4dSFabiano Rosas     new_msr |= (target_ulong)1 << MSR_SF;
19099f338e4dSFabiano Rosas 
19109f338e4dSFabiano Rosas     if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
19119f338e4dSFabiano Rosas         /* Save PC */
19129f338e4dSFabiano Rosas         env->spr[srr0] = env->nip;
19139f338e4dSFabiano Rosas 
19149f338e4dSFabiano Rosas         /* Save MSR */
19159f338e4dSFabiano Rosas         env->spr[srr1] = msr;
19169f338e4dSFabiano Rosas     }
19179f338e4dSFabiano Rosas 
19189f338e4dSFabiano Rosas     /* This can update new_msr and vector if AIL applies */
19199f338e4dSFabiano Rosas     ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector);
19209f338e4dSFabiano Rosas 
19219f338e4dSFabiano Rosas     powerpc_set_excp_state(cpu, vector, new_msr);
19229f338e4dSFabiano Rosas }
192330c4e426SFabiano Rosas #else
192430c4e426SFabiano Rosas static inline void powerpc_excp_books(PowerPCCPU *cpu, int excp)
192530c4e426SFabiano Rosas {
192630c4e426SFabiano Rosas     g_assert_not_reached();
192730c4e426SFabiano Rosas }
192830c4e426SFabiano Rosas #endif
19299f338e4dSFabiano Rosas 
193047733729SDavid Gibson /*
193147733729SDavid Gibson  * Note that this function should be greatly optimized when called
193247733729SDavid Gibson  * with a constant excp, from ppc_hw_interrupt
1933c79c73f6SBlue Swirl  */
1934dc88dd0aSFabiano Rosas static inline void powerpc_excp_legacy(PowerPCCPU *cpu, int excp)
1935c79c73f6SBlue Swirl {
193627103424SAndreas Färber     CPUState *cs = CPU(cpu);
19375c26a5b3SAndreas Färber     CPUPPCState *env = &cpu->env;
193893130c84SFabiano Rosas     int excp_model = env->excp_model;
1939c79c73f6SBlue Swirl     target_ulong msr, new_msr, vector;
194019e70626SFabiano Rosas     int srr0, srr1, lev = -1;
1941c79c73f6SBlue Swirl 
19422541e686SFabiano Rosas     if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
19432541e686SFabiano Rosas         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
19442541e686SFabiano Rosas     }
19452541e686SFabiano Rosas 
1946c79c73f6SBlue Swirl     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
19476789f23bSCédric Le Goater                   " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
19486789f23bSCédric Le Goater                   excp, env->error_code);
1949c79c73f6SBlue Swirl 
1950c79c73f6SBlue Swirl     /* new srr1 value excluding must-be-zero bits */
1951a1bb7384SScott Wood     if (excp_model == POWERPC_EXCP_BOOKE) {
1952a1bb7384SScott Wood         msr = env->msr;
1953a1bb7384SScott Wood     } else {
1954c79c73f6SBlue Swirl         msr = env->msr & ~0x783f0000ULL;
1955a1bb7384SScott Wood     }
1956c79c73f6SBlue Swirl 
195747733729SDavid Gibson     /*
195847733729SDavid Gibson      * new interrupt handler msr preserves existing HV and ME unless
19596d49d6d4SBenjamin Herrenschmidt      * explicitly overriden
19606d49d6d4SBenjamin Herrenschmidt      */
19616d49d6d4SBenjamin Herrenschmidt     new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
1962c79c73f6SBlue Swirl 
1963c79c73f6SBlue Swirl     /* target registers */
1964c79c73f6SBlue Swirl     srr0 = SPR_SRR0;
1965c79c73f6SBlue Swirl     srr1 = SPR_SRR1;
1966c79c73f6SBlue Swirl 
196721c0d66aSBenjamin Herrenschmidt     /*
196821c0d66aSBenjamin Herrenschmidt      * check for special resume at 0x100 from doze/nap/sleep/winkle on
196921c0d66aSBenjamin Herrenschmidt      * P7/P8/P9
197021c0d66aSBenjamin Herrenschmidt      */
19711e7fd61dSBenjamin Herrenschmidt     if (env->resume_as_sreset) {
1972dead760bSBenjamin Herrenschmidt         excp = powerpc_reset_wakeup(cs, env, excp, &msr);
19737778a575SBenjamin Herrenschmidt     }
19747778a575SBenjamin Herrenschmidt 
197547733729SDavid Gibson     /*
197647733729SDavid Gibson      * Hypervisor emulation assistance interrupt only exists on server
19779b2faddaSBenjamin Herrenschmidt      * arch 2.05 server or later. We also don't want to generate it if
19789b2faddaSBenjamin Herrenschmidt      * we don't have HVB in msr_mask (PAPR mode).
19799b2faddaSBenjamin Herrenschmidt      */
19809b2faddaSBenjamin Herrenschmidt     if (excp == POWERPC_EXCP_HV_EMU
19819b2faddaSBenjamin Herrenschmidt #if defined(TARGET_PPC64)
1982d57d72a8SGreg Kurz         && !(mmu_is_64bit(env->mmu_model) && (env->msr_mask & MSR_HVB))
19839b2faddaSBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */
19849b2faddaSBenjamin Herrenschmidt 
19859b2faddaSBenjamin Herrenschmidt     ) {
19869b2faddaSBenjamin Herrenschmidt         excp = POWERPC_EXCP_PROGRAM;
19879b2faddaSBenjamin Herrenschmidt     }
19889b2faddaSBenjamin Herrenschmidt 
19897fc1dc83SFabiano Rosas #ifdef TARGET_PPC64
19907fc1dc83SFabiano Rosas     /*
19917fc1dc83SFabiano Rosas      * SPEU and VPU share the same IVOR but they exist in different
19927fc1dc83SFabiano Rosas      * processors. SPEU is e500v1/2 only and VPU is e6500 only.
19937fc1dc83SFabiano Rosas      */
19947fc1dc83SFabiano Rosas     if (excp_model == POWERPC_EXCP_BOOKE && excp == POWERPC_EXCP_VPU) {
19957fc1dc83SFabiano Rosas         excp = POWERPC_EXCP_SPEU;
19967fc1dc83SFabiano Rosas     }
19977fc1dc83SFabiano Rosas #endif
19987fc1dc83SFabiano Rosas 
1999d1cbee61SFabiano Rosas     vector = env->excp_vectors[excp];
2000d1cbee61SFabiano Rosas     if (vector == (target_ulong)-1ULL) {
2001d1cbee61SFabiano Rosas         cpu_abort(cs, "Raised an exception without defined vector %d\n",
2002d1cbee61SFabiano Rosas                   excp);
2003d1cbee61SFabiano Rosas     }
2004d1cbee61SFabiano Rosas 
2005d1cbee61SFabiano Rosas     vector |= env->excp_prefix;
2006d1cbee61SFabiano Rosas 
2007c79c73f6SBlue Swirl     switch (excp) {
2008c79c73f6SBlue Swirl     case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
2009c79c73f6SBlue Swirl         switch (excp_model) {
2010c79c73f6SBlue Swirl         case POWERPC_EXCP_40x:
2011c79c73f6SBlue Swirl             srr0 = SPR_40x_SRR2;
2012c79c73f6SBlue Swirl             srr1 = SPR_40x_SRR3;
2013c79c73f6SBlue Swirl             break;
2014c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
2015c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_CSRR0;
2016c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_CSRR1;
2017c79c73f6SBlue Swirl             break;
20189323650fSFabiano Rosas         case POWERPC_EXCP_6xx:
2019c79c73f6SBlue Swirl             break;
2020c79c73f6SBlue Swirl         default:
2021c79c73f6SBlue Swirl             goto excp_invalid;
2022c79c73f6SBlue Swirl         }
2023bd6fefe7SBenjamin Herrenschmidt         break;
2024c79c73f6SBlue Swirl     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
2025c79c73f6SBlue Swirl         if (msr_me == 0) {
202647733729SDavid Gibson             /*
202747733729SDavid Gibson              * Machine check exception is not enabled.  Enter
202847733729SDavid Gibson              * checkstop state.
2029c79c73f6SBlue Swirl              */
2030c79c73f6SBlue Swirl             fprintf(stderr, "Machine check while not allowed. "
2031c79c73f6SBlue Swirl                     "Entering checkstop state\n");
2032013a2942SPaolo Bonzini             if (qemu_log_separate()) {
2033013a2942SPaolo Bonzini                 qemu_log("Machine check while not allowed. "
2034013a2942SPaolo Bonzini                         "Entering checkstop state\n");
2035c79c73f6SBlue Swirl             }
2036259186a7SAndreas Färber             cs->halted = 1;
2037044897efSRichard Purdie             cpu_interrupt_exittb(cs);
2038c79c73f6SBlue Swirl         }
203910c21b5cSNicholas Piggin         if (env->msr_mask & MSR_HVB) {
204047733729SDavid Gibson             /*
204147733729SDavid Gibson              * ISA specifies HV, but can be delivered to guest with HV
204247733729SDavid Gibson              * clear (e.g., see FWNMI in PAPR).
204310c21b5cSNicholas Piggin              */
2044c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
204510c21b5cSNicholas Piggin         }
2046c79c73f6SBlue Swirl 
2047c79c73f6SBlue Swirl         /* machine check exceptions don't have ME set */
2048c79c73f6SBlue Swirl         new_msr &= ~((target_ulong)1 << MSR_ME);
2049c79c73f6SBlue Swirl 
2050c79c73f6SBlue Swirl         /* XXX: should also have something loaded in DAR / DSISR */
2051c79c73f6SBlue Swirl         switch (excp_model) {
2052c79c73f6SBlue Swirl         case POWERPC_EXCP_40x:
2053c79c73f6SBlue Swirl             srr0 = SPR_40x_SRR2;
2054c79c73f6SBlue Swirl             srr1 = SPR_40x_SRR3;
2055c79c73f6SBlue Swirl             break;
2056c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
2057a1bb7384SScott Wood             /* FIXME: choose one or the other based on CPU type */
2058c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_MCSRR0;
2059c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_MCSRR1;
206019e70626SFabiano Rosas 
206119e70626SFabiano Rosas             env->spr[SPR_BOOKE_CSRR0] = env->nip;
206219e70626SFabiano Rosas             env->spr[SPR_BOOKE_CSRR1] = msr;
2063c79c73f6SBlue Swirl             break;
2064c79c73f6SBlue Swirl         default:
2065c79c73f6SBlue Swirl             break;
2066c79c73f6SBlue Swirl         }
2067bd6fefe7SBenjamin Herrenschmidt         break;
2068c79c73f6SBlue Swirl     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
20692eb1ef73SCédric Le Goater         trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
2070bd6fefe7SBenjamin Herrenschmidt         break;
2071c79c73f6SBlue Swirl     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
20722eb1ef73SCédric Le Goater         trace_ppc_excp_isi(msr, env->nip);
2073c79c73f6SBlue Swirl         msr |= env->error_code;
2074bd6fefe7SBenjamin Herrenschmidt         break;
2075c79c73f6SBlue Swirl     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
2076bbc443cfSFabiano Rosas     {
2077bbc443cfSFabiano Rosas         bool lpes0;
2078bbc443cfSFabiano Rosas 
2079fdfba1a2SEdgar E. Iglesias         cs = CPU(cpu);
2080fdfba1a2SEdgar E. Iglesias 
2081bbc443cfSFabiano Rosas         /*
2082bbc443cfSFabiano Rosas          * Exception targeting modifiers
2083bbc443cfSFabiano Rosas          *
2084bbc443cfSFabiano Rosas          * LPES0 is supported on POWER7/8/9
2085bbc443cfSFabiano Rosas          * LPES1 is not supported (old iSeries mode)
2086bbc443cfSFabiano Rosas          *
2087bbc443cfSFabiano Rosas          * On anything else, we behave as if LPES0 is 1
2088bbc443cfSFabiano Rosas          * (externals don't alter MSR:HV)
2089bbc443cfSFabiano Rosas          */
2090bbc443cfSFabiano Rosas #if defined(TARGET_PPC64)
2091bbc443cfSFabiano Rosas         if (excp_model == POWERPC_EXCP_POWER7 ||
2092bbc443cfSFabiano Rosas             excp_model == POWERPC_EXCP_POWER8 ||
2093bbc443cfSFabiano Rosas             excp_model == POWERPC_EXCP_POWER9 ||
2094bbc443cfSFabiano Rosas             excp_model == POWERPC_EXCP_POWER10) {
2095bbc443cfSFabiano Rosas             lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
2096bbc443cfSFabiano Rosas         } else
2097bbc443cfSFabiano Rosas #endif /* defined(TARGET_PPC64) */
2098bbc443cfSFabiano Rosas         {
2099bbc443cfSFabiano Rosas             lpes0 = true;
2100bbc443cfSFabiano Rosas         }
2101bbc443cfSFabiano Rosas 
21026d49d6d4SBenjamin Herrenschmidt         if (!lpes0) {
2103c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
21046d49d6d4SBenjamin Herrenschmidt             new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
21056d49d6d4SBenjamin Herrenschmidt             srr0 = SPR_HSRR0;
21066d49d6d4SBenjamin Herrenschmidt             srr1 = SPR_HSRR1;
2107c79c73f6SBlue Swirl         }
210868c2dd70SAlexander Graf         if (env->mpic_proxy) {
210968c2dd70SAlexander Graf             /* IACK the IRQ on delivery */
2110fdfba1a2SEdgar E. Iglesias             env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
211168c2dd70SAlexander Graf         }
2112bd6fefe7SBenjamin Herrenschmidt         break;
2113bbc443cfSFabiano Rosas     }
2114c79c73f6SBlue Swirl     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
211529c4a336SFabiano Rosas         /* Get rS/rD and rA from faulting opcode */
211647733729SDavid Gibson         /*
211729c4a336SFabiano Rosas          * Note: the opcode fields will not be set properly for a
211829c4a336SFabiano Rosas          * direct store load/store, but nobody cares as nobody
211929c4a336SFabiano Rosas          * actually uses direct store segments.
21203433b732SBenjamin Herrenschmidt          */
212129c4a336SFabiano Rosas         env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
2122bd6fefe7SBenjamin Herrenschmidt         break;
2123c79c73f6SBlue Swirl     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
2124c79c73f6SBlue Swirl         switch (env->error_code & ~0xF) {
2125c79c73f6SBlue Swirl         case POWERPC_EXCP_FP:
2126c79c73f6SBlue Swirl             if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
21272eb1ef73SCédric Le Goater                 trace_ppc_excp_fp_ignore();
212827103424SAndreas Färber                 cs->exception_index = POWERPC_EXCP_NONE;
2129c79c73f6SBlue Swirl                 env->error_code = 0;
2130c79c73f6SBlue Swirl                 return;
2131c79c73f6SBlue Swirl             }
21321b7d17caSBenjamin Herrenschmidt 
213347733729SDavid Gibson             /*
213447733729SDavid Gibson              * FP exceptions always have NIP pointing to the faulting
21351b7d17caSBenjamin Herrenschmidt              * instruction, so always use store_next and claim we are
21361b7d17caSBenjamin Herrenschmidt              * precise in the MSR.
21371b7d17caSBenjamin Herrenschmidt              */
2138c79c73f6SBlue Swirl             msr |= 0x00100000;
21390ee604abSAaron Larson             env->spr[SPR_BOOKE_ESR] = ESR_FP;
2140bd6fefe7SBenjamin Herrenschmidt             break;
2141c79c73f6SBlue Swirl         case POWERPC_EXCP_INVAL:
21422eb1ef73SCédric Le Goater             trace_ppc_excp_inval(env->nip);
2143c79c73f6SBlue Swirl             msr |= 0x00080000;
2144c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PIL;
2145c79c73f6SBlue Swirl             break;
2146c79c73f6SBlue Swirl         case POWERPC_EXCP_PRIV:
2147c79c73f6SBlue Swirl             msr |= 0x00040000;
2148c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PPR;
2149c79c73f6SBlue Swirl             break;
2150c79c73f6SBlue Swirl         case POWERPC_EXCP_TRAP:
2151c79c73f6SBlue Swirl             msr |= 0x00020000;
2152c79c73f6SBlue Swirl             env->spr[SPR_BOOKE_ESR] = ESR_PTR;
2153c79c73f6SBlue Swirl             break;
2154c79c73f6SBlue Swirl         default:
2155c79c73f6SBlue Swirl             /* Should never occur */
2156a47dddd7SAndreas Färber             cpu_abort(cs, "Invalid program exception %d. Aborting\n",
2157c79c73f6SBlue Swirl                       env->error_code);
2158c79c73f6SBlue Swirl             break;
2159c79c73f6SBlue Swirl         }
2160bd6fefe7SBenjamin Herrenschmidt         break;
2161c79c73f6SBlue Swirl     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
2162c79c73f6SBlue Swirl         lev = env->error_code;
21636d49d6d4SBenjamin Herrenschmidt 
21646dc6b557SNicholas Piggin         if ((lev == 1) && cpu->vhyp) {
21656dc6b557SNicholas Piggin             dump_hcall(env);
21666dc6b557SNicholas Piggin         } else {
21676dc6b557SNicholas Piggin             dump_syscall(env);
21686dc6b557SNicholas Piggin         }
21696dc6b557SNicholas Piggin 
217047733729SDavid Gibson         /*
217147733729SDavid Gibson          * We need to correct the NIP which in this case is supposed
2172bd6fefe7SBenjamin Herrenschmidt          * to point to the next instruction
2173bd6fefe7SBenjamin Herrenschmidt          */
2174bd6fefe7SBenjamin Herrenschmidt         env->nip += 4;
2175bd6fefe7SBenjamin Herrenschmidt 
21766d49d6d4SBenjamin Herrenschmidt         /* "PAPR mode" built-in hypercall emulation */
21771d1be34dSDavid Gibson         if ((lev == 1) && cpu->vhyp) {
21781d1be34dSDavid Gibson             PPCVirtualHypervisorClass *vhc =
21791d1be34dSDavid Gibson                 PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
21801d1be34dSDavid Gibson             vhc->hypercall(cpu->vhyp, cpu);
2181c79c73f6SBlue Swirl             return;
2182c79c73f6SBlue Swirl         }
21836d49d6d4SBenjamin Herrenschmidt         if (lev == 1) {
2184c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
2185c79c73f6SBlue Swirl         }
2186bd6fefe7SBenjamin Herrenschmidt         break;
21873c89b8d6SNicholas Piggin     case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception                     */
21883c89b8d6SNicholas Piggin         lev = env->error_code;
21890c87018cSFabiano Rosas         dump_syscall(env);
21903c89b8d6SNicholas Piggin         env->nip += 4;
21913c89b8d6SNicholas Piggin         new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
21923c89b8d6SNicholas Piggin         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
21935ac11b12SFabiano Rosas 
21945ac11b12SFabiano Rosas         vector += lev * 0x20;
21955ac11b12SFabiano Rosas 
21965ac11b12SFabiano Rosas         env->lr = env->nip;
21975ac11b12SFabiano Rosas         env->ctr = msr;
21983c89b8d6SNicholas Piggin         break;
2199bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
2200c79c73f6SBlue Swirl     case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
2201c79c73f6SBlue Swirl     case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
2202bd6fefe7SBenjamin Herrenschmidt         break;
2203c79c73f6SBlue Swirl     case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
2204c79c73f6SBlue Swirl         /* FIT on 4xx */
22052eb1ef73SCédric Le Goater         trace_ppc_excp_print("FIT");
2206bd6fefe7SBenjamin Herrenschmidt         break;
2207c79c73f6SBlue Swirl     case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
22082eb1ef73SCédric Le Goater         trace_ppc_excp_print("WDT");
2209c79c73f6SBlue Swirl         switch (excp_model) {
2210c79c73f6SBlue Swirl         case POWERPC_EXCP_BOOKE:
2211c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_CSRR0;
2212c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_CSRR1;
2213c79c73f6SBlue Swirl             break;
2214c79c73f6SBlue Swirl         default:
2215c79c73f6SBlue Swirl             break;
2216c79c73f6SBlue Swirl         }
2217bd6fefe7SBenjamin Herrenschmidt         break;
2218c79c73f6SBlue Swirl     case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
2219c79c73f6SBlue Swirl     case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
2220bd6fefe7SBenjamin Herrenschmidt         break;
2221c79c73f6SBlue Swirl     case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
22220e3bf489SRoman Kapl         if (env->flags & POWERPC_FLAG_DE) {
2223a1bb7384SScott Wood             /* FIXME: choose one or the other based on CPU type */
2224c79c73f6SBlue Swirl             srr0 = SPR_BOOKE_DSRR0;
2225c79c73f6SBlue Swirl             srr1 = SPR_BOOKE_DSRR1;
222619e70626SFabiano Rosas 
222719e70626SFabiano Rosas             env->spr[SPR_BOOKE_CSRR0] = env->nip;
222819e70626SFabiano Rosas             env->spr[SPR_BOOKE_CSRR1] = msr;
222919e70626SFabiano Rosas 
22300e3bf489SRoman Kapl             /* DBSR already modified by caller */
22310e3bf489SRoman Kapl         } else {
22320e3bf489SRoman Kapl             cpu_abort(cs, "Debug exception triggered on unsupported model\n");
2233c79c73f6SBlue Swirl         }
2234bd6fefe7SBenjamin Herrenschmidt         break;
22357fc1dc83SFabiano Rosas     case POWERPC_EXCP_SPEU:   /* SPE/embedded floating-point unavailable/VPU  */
2236c79c73f6SBlue Swirl         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
2237bd6fefe7SBenjamin Herrenschmidt         break;
2238c79c73f6SBlue Swirl     case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
2239bd6fefe7SBenjamin Herrenschmidt         break;
2240c79c73f6SBlue Swirl     case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
2241c79c73f6SBlue Swirl         srr0 = SPR_BOOKE_CSRR0;
2242c79c73f6SBlue Swirl         srr1 = SPR_BOOKE_CSRR1;
2243bd6fefe7SBenjamin Herrenschmidt         break;
2244c79c73f6SBlue Swirl     case POWERPC_EXCP_RESET:     /* System reset exception                   */
2245f85bcec3SNicholas Piggin         /* A power-saving exception sets ME, otherwise it is unchanged */
2246c79c73f6SBlue Swirl         if (msr_pow) {
2247c79c73f6SBlue Swirl             /* indicate that we resumed from power save mode */
2248c79c73f6SBlue Swirl             msr |= 0x10000;
2249f85bcec3SNicholas Piggin             new_msr |= ((target_ulong)1 << MSR_ME);
2250c79c73f6SBlue Swirl         }
225110c21b5cSNicholas Piggin         if (env->msr_mask & MSR_HVB) {
225247733729SDavid Gibson             /*
225347733729SDavid Gibson              * ISA specifies HV, but can be delivered to guest with HV
225447733729SDavid Gibson              * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
225510c21b5cSNicholas Piggin              */
2256c79c73f6SBlue Swirl             new_msr |= (target_ulong)MSR_HVB;
225710c21b5cSNicholas Piggin         } else {
225810c21b5cSNicholas Piggin             if (msr_pow) {
225910c21b5cSNicholas Piggin                 cpu_abort(cs, "Trying to deliver power-saving system reset "
226010c21b5cSNicholas Piggin                           "exception %d with no HV support\n", excp);
226110c21b5cSNicholas Piggin             }
226210c21b5cSNicholas Piggin         }
2263bd6fefe7SBenjamin Herrenschmidt         break;
2264c79c73f6SBlue Swirl     case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
2265c79c73f6SBlue Swirl     case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
2266c79c73f6SBlue Swirl     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
2267bd6fefe7SBenjamin Herrenschmidt         break;
2268d04ea940SCédric Le Goater     case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
2269d04ea940SCédric Le Goater         msr |= env->error_code;
2270295397f5SChen Qun         /* fall through */
2271bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
2272c79c73f6SBlue Swirl     case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
2273c79c73f6SBlue Swirl     case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
2274c79c73f6SBlue Swirl     case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
22757af1e7b0SCédric Le Goater     case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
2276bd6fefe7SBenjamin Herrenschmidt     case POWERPC_EXCP_HV_EMU:
2277d8ce5fd6SBenjamin Herrenschmidt     case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
2278c79c73f6SBlue Swirl         srr0 = SPR_HSRR0;
2279c79c73f6SBlue Swirl         srr1 = SPR_HSRR1;
2280c79c73f6SBlue Swirl         new_msr |= (target_ulong)MSR_HVB;
2281c79c73f6SBlue Swirl         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
2282bd6fefe7SBenjamin Herrenschmidt         break;
2283c79c73f6SBlue Swirl     case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
22841f29871cSTom Musta     case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
22857019cb3dSAlexey Kardashevskiy     case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
22865310799aSBalbir Singh #ifdef TARGET_PPC64
22875310799aSBalbir Singh         env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
22885310799aSBalbir Singh #endif
2289bd6fefe7SBenjamin Herrenschmidt         break;
2290493028d8SCédric Le Goater     case POWERPC_EXCP_HV_FU:     /* Hypervisor Facility Unavailable Exception */
2291493028d8SCédric Le Goater #ifdef TARGET_PPC64
2292493028d8SCédric Le Goater         env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
2293493028d8SCédric Le Goater         srr0 = SPR_HSRR0;
2294493028d8SCédric Le Goater         srr1 = SPR_HSRR1;
2295493028d8SCédric Le Goater         new_msr |= (target_ulong)MSR_HVB;
2296493028d8SCédric Le Goater         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
2297493028d8SCédric Le Goater #endif
2298493028d8SCédric Le Goater         break;
2299c79c73f6SBlue Swirl     case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
23002eb1ef73SCédric Le Goater         trace_ppc_excp_print("PIT");
2301bd6fefe7SBenjamin Herrenschmidt         break;
2302c79c73f6SBlue Swirl     case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
2303c79c73f6SBlue Swirl     case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
2304c79c73f6SBlue Swirl     case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
2305c79c73f6SBlue Swirl         switch (excp_model) {
23069323650fSFabiano Rosas         case POWERPC_EXCP_6xx:
2307c79c73f6SBlue Swirl             /* Swap temporary saved registers with GPRs */
2308c79c73f6SBlue Swirl             if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
2309c79c73f6SBlue Swirl                 new_msr |= (target_ulong)1 << MSR_TGPR;
2310c79c73f6SBlue Swirl                 hreg_swap_gpr_tgpr(env);
2311c79c73f6SBlue Swirl             }
231251b385dbSFabiano Rosas             /* fall through */
2313fd7dc4bbSFabiano Rosas         case POWERPC_EXCP_7xx:
2314e4e27df7SFabiano Rosas             ppc_excp_debug_sw_tlb(env, excp);
2315c79c73f6SBlue Swirl 
2316c79c73f6SBlue Swirl             msr |= env->crf[0] << 28;
2317c79c73f6SBlue Swirl             msr |= env->error_code; /* key, D/I, S/L bits */
2318c79c73f6SBlue Swirl             /* Set way using a LRU mechanism */
2319c79c73f6SBlue Swirl             msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
2320c79c73f6SBlue Swirl             break;
2321c79c73f6SBlue Swirl         default:
232251b385dbSFabiano Rosas             cpu_abort(cs, "Invalid TLB miss exception\n");
2323c79c73f6SBlue Swirl             break;
2324c79c73f6SBlue Swirl         }
2325bd6fefe7SBenjamin Herrenschmidt         break;
23264dff75feSFabiano Rosas     case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
23274dff75feSFabiano Rosas     case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
23284dff75feSFabiano Rosas     case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
2329c79c73f6SBlue Swirl     case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
2330c79c73f6SBlue Swirl     case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
2331c79c73f6SBlue Swirl     case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
2332c79c73f6SBlue Swirl     case POWERPC_EXCP_SMI:       /* System management interrupt              */
2333c79c73f6SBlue Swirl     case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
2334c79c73f6SBlue Swirl     case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
2335c79c73f6SBlue Swirl     case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
2336c79c73f6SBlue Swirl     case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
2337c79c73f6SBlue Swirl     case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
2338c79c73f6SBlue Swirl     case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
2339c79c73f6SBlue Swirl     case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
23404dff75feSFabiano Rosas         cpu_abort(cs, "%s exception not implemented\n",
23414dff75feSFabiano Rosas                   powerpc_excp_name(excp));
2342bd6fefe7SBenjamin Herrenschmidt         break;
2343c79c73f6SBlue Swirl     default:
2344c79c73f6SBlue Swirl     excp_invalid:
2345a47dddd7SAndreas Färber         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
2346c79c73f6SBlue Swirl         break;
2347c79c73f6SBlue Swirl     }
2348bd6fefe7SBenjamin Herrenschmidt 
23496d49d6d4SBenjamin Herrenschmidt     /* Sanity check */
235010c21b5cSNicholas Piggin     if (!(env->msr_mask & MSR_HVB)) {
235110c21b5cSNicholas Piggin         if (new_msr & MSR_HVB) {
235210c21b5cSNicholas Piggin             cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
23536d49d6d4SBenjamin Herrenschmidt                       "no HV support\n", excp);
23546d49d6d4SBenjamin Herrenschmidt         }
235510c21b5cSNicholas Piggin         if (srr0 == SPR_HSRR0) {
235610c21b5cSNicholas Piggin             cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
235710c21b5cSNicholas Piggin                       "no HV support\n", excp);
235810c21b5cSNicholas Piggin         }
235910c21b5cSNicholas Piggin     }
23606d49d6d4SBenjamin Herrenschmidt 
236147733729SDavid Gibson     /*
236247733729SDavid Gibson      * Sort out endianness of interrupt, this differs depending on the
23636d49d6d4SBenjamin Herrenschmidt      * CPU, the HV mode, etc...
23646d49d6d4SBenjamin Herrenschmidt      */
236519bd7f57SFabiano Rosas     if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
23666d49d6d4SBenjamin Herrenschmidt         new_msr |= (target_ulong)1 << MSR_LE;
23676d49d6d4SBenjamin Herrenschmidt     }
2368c79c73f6SBlue Swirl 
2369c79c73f6SBlue Swirl #if defined(TARGET_PPC64)
2370c79c73f6SBlue Swirl     if (excp_model == POWERPC_EXCP_BOOKE) {
2371e42a61f1SAlexander Graf         if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
2372e42a61f1SAlexander Graf             /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
2373c79c73f6SBlue Swirl             new_msr |= (target_ulong)1 << MSR_CM;
2374e42a61f1SAlexander Graf         } else {
2375e42a61f1SAlexander Graf             vector = (uint32_t)vector;
2376c79c73f6SBlue Swirl         }
2377c79c73f6SBlue Swirl     } else {
2378d57d72a8SGreg Kurz         if (!msr_isf && !mmu_is_64bit(env->mmu_model)) {
2379c79c73f6SBlue Swirl             vector = (uint32_t)vector;
2380c79c73f6SBlue Swirl         } else {
2381c79c73f6SBlue Swirl             new_msr |= (target_ulong)1 << MSR_SF;
2382c79c73f6SBlue Swirl         }
2383c79c73f6SBlue Swirl     }
2384c79c73f6SBlue Swirl #endif
2385cd0c6f47SBenjamin Herrenschmidt 
23863c89b8d6SNicholas Piggin     if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
23873c89b8d6SNicholas Piggin         /* Save PC */
23883c89b8d6SNicholas Piggin         env->spr[srr0] = env->nip;
23893c89b8d6SNicholas Piggin 
23903c89b8d6SNicholas Piggin         /* Save MSR */
23913c89b8d6SNicholas Piggin         env->spr[srr1] = msr;
23923c89b8d6SNicholas Piggin     }
23933c89b8d6SNicholas Piggin 
23948b7e6b07SNicholas Piggin     /* This can update new_msr and vector if AIL applies */
23958b7e6b07SNicholas Piggin     ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector);
23968b7e6b07SNicholas Piggin 
2397ad77c6caSNicholas Piggin     powerpc_set_excp_state(cpu, vector, new_msr);
2398c79c73f6SBlue Swirl }
2399c79c73f6SBlue Swirl 
2400dc88dd0aSFabiano Rosas static void powerpc_excp(PowerPCCPU *cpu, int excp)
2401dc88dd0aSFabiano Rosas {
2402dc88dd0aSFabiano Rosas     CPUPPCState *env = &cpu->env;
2403dc88dd0aSFabiano Rosas 
2404dc88dd0aSFabiano Rosas     switch (env->excp_model) {
2405e808c2edSFabiano Rosas     case POWERPC_EXCP_40x:
2406e808c2edSFabiano Rosas         powerpc_excp_40x(cpu, excp);
2407e808c2edSFabiano Rosas         break;
240858d178fbSFabiano Rosas     case POWERPC_EXCP_6xx:
240958d178fbSFabiano Rosas         powerpc_excp_6xx(cpu, excp);
241058d178fbSFabiano Rosas         break;
2411*ccfca2fcSFabiano Rosas     case POWERPC_EXCP_7xx:
2412*ccfca2fcSFabiano Rosas         powerpc_excp_7xx(cpu, excp);
2413*ccfca2fcSFabiano Rosas         break;
241452926b0dSFabiano Rosas     case POWERPC_EXCP_74xx:
241552926b0dSFabiano Rosas         powerpc_excp_74xx(cpu, excp);
241652926b0dSFabiano Rosas         break;
2417180952ceSFabiano Rosas     case POWERPC_EXCP_BOOKE:
2418180952ceSFabiano Rosas         powerpc_excp_booke(cpu, excp);
2419180952ceSFabiano Rosas         break;
24209f338e4dSFabiano Rosas     case POWERPC_EXCP_970:
24219f338e4dSFabiano Rosas     case POWERPC_EXCP_POWER7:
24229f338e4dSFabiano Rosas     case POWERPC_EXCP_POWER8:
24239f338e4dSFabiano Rosas     case POWERPC_EXCP_POWER9:
24249f338e4dSFabiano Rosas     case POWERPC_EXCP_POWER10:
24259f338e4dSFabiano Rosas         powerpc_excp_books(cpu, excp);
24269f338e4dSFabiano Rosas         break;
2427dc88dd0aSFabiano Rosas     default:
2428dc88dd0aSFabiano Rosas         powerpc_excp_legacy(cpu, excp);
2429dc88dd0aSFabiano Rosas     }
2430dc88dd0aSFabiano Rosas }
2431dc88dd0aSFabiano Rosas 
243297a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs)
2433c79c73f6SBlue Swirl {
243497a8ea5aSAndreas Färber     PowerPCCPU *cpu = POWERPC_CPU(cs);
24355c26a5b3SAndreas Färber 
243693130c84SFabiano Rosas     powerpc_excp(cpu, cs->exception_index);
2437c79c73f6SBlue Swirl }
2438c79c73f6SBlue Swirl 
2439458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env)
2440c79c73f6SBlue Swirl {
2441db70b311SRichard Henderson     PowerPCCPU *cpu = env_archcpu(env);
24423621e2c9SBenjamin Herrenschmidt     bool async_deliver;
2443259186a7SAndreas Färber 
2444c79c73f6SBlue Swirl     /* External reset */
2445c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
2446c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
244793130c84SFabiano Rosas         powerpc_excp(cpu, POWERPC_EXCP_RESET);
2448c79c73f6SBlue Swirl         return;
2449c79c73f6SBlue Swirl     }
2450c79c73f6SBlue Swirl     /* Machine check exception */
2451c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
2452c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
245393130c84SFabiano Rosas         powerpc_excp(cpu, POWERPC_EXCP_MCHECK);
2454c79c73f6SBlue Swirl         return;
2455c79c73f6SBlue Swirl     }
2456c79c73f6SBlue Swirl #if 0 /* TODO */
2457c79c73f6SBlue Swirl     /* External debug exception */
2458c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
2459c79c73f6SBlue Swirl         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
246093130c84SFabiano Rosas         powerpc_excp(cpu, POWERPC_EXCP_DEBUG);
2461c79c73f6SBlue Swirl         return;
2462c79c73f6SBlue Swirl     }
2463c79c73f6SBlue Swirl #endif
24643621e2c9SBenjamin Herrenschmidt 
24653621e2c9SBenjamin Herrenschmidt     /*
24663621e2c9SBenjamin Herrenschmidt      * For interrupts that gate on MSR:EE, we need to do something a
24673621e2c9SBenjamin Herrenschmidt      * bit more subtle, as we need to let them through even when EE is
24683621e2c9SBenjamin Herrenschmidt      * clear when coming out of some power management states (in order
24693621e2c9SBenjamin Herrenschmidt      * for them to become a 0x100).
24703621e2c9SBenjamin Herrenschmidt      */
24711e7fd61dSBenjamin Herrenschmidt     async_deliver = (msr_ee != 0) || env->resume_as_sreset;
24723621e2c9SBenjamin Herrenschmidt 
2473c79c73f6SBlue Swirl     /* Hypervisor decrementer exception */
2474c79c73f6SBlue Swirl     if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
24754b236b62SBenjamin Herrenschmidt         /* LPCR will be clear when not supported so this will work */
24764b236b62SBenjamin Herrenschmidt         bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE);
24773621e2c9SBenjamin Herrenschmidt         if ((async_deliver || msr_hv == 0) && hdice) {
24784b236b62SBenjamin Herrenschmidt             /* HDEC clears on delivery */
24794b236b62SBenjamin Herrenschmidt             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
248093130c84SFabiano Rosas             powerpc_excp(cpu, POWERPC_EXCP_HDECR);
2481c79c73f6SBlue Swirl             return;
2482c79c73f6SBlue Swirl         }
2483c79c73f6SBlue Swirl     }
2484d8ce5fd6SBenjamin Herrenschmidt 
2485d8ce5fd6SBenjamin Herrenschmidt     /* Hypervisor virtualization interrupt */
2486d8ce5fd6SBenjamin Herrenschmidt     if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) {
2487d8ce5fd6SBenjamin Herrenschmidt         /* LPCR will be clear when not supported so this will work */
2488d8ce5fd6SBenjamin Herrenschmidt         bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
2489d8ce5fd6SBenjamin Herrenschmidt         if ((async_deliver || msr_hv == 0) && hvice) {
249093130c84SFabiano Rosas             powerpc_excp(cpu, POWERPC_EXCP_HVIRT);
2491d8ce5fd6SBenjamin Herrenschmidt             return;
2492d8ce5fd6SBenjamin Herrenschmidt         }
2493d8ce5fd6SBenjamin Herrenschmidt     }
2494d8ce5fd6SBenjamin Herrenschmidt 
2495d8ce5fd6SBenjamin Herrenschmidt     /* External interrupt can ignore MSR:EE under some circumstances */
2496d1dbe37cSBenjamin Herrenschmidt     if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
2497d1dbe37cSBenjamin Herrenschmidt         bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
24986eebe6dcSBenjamin Herrenschmidt         bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC);
24996eebe6dcSBenjamin Herrenschmidt         /* HEIC blocks delivery to the hypervisor */
25006eebe6dcSBenjamin Herrenschmidt         if ((async_deliver && !(heic && msr_hv && !msr_pr)) ||
25016eebe6dcSBenjamin Herrenschmidt             (env->has_hv_mode && msr_hv == 0 && !lpes0)) {
250293130c84SFabiano Rosas             powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL);
2503d1dbe37cSBenjamin Herrenschmidt             return;
2504d1dbe37cSBenjamin Herrenschmidt         }
2505d1dbe37cSBenjamin Herrenschmidt     }
2506c79c73f6SBlue Swirl     if (msr_ce != 0) {
2507c79c73f6SBlue Swirl         /* External critical interrupt */
2508c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
250993130c84SFabiano Rosas             powerpc_excp(cpu, POWERPC_EXCP_CRITICAL);
2510c79c73f6SBlue Swirl             return;
2511c79c73f6SBlue Swirl         }
2512c79c73f6SBlue Swirl     }
25133621e2c9SBenjamin Herrenschmidt     if (async_deliver != 0) {
2514c79c73f6SBlue Swirl         /* Watchdog timer on embedded PowerPC */
2515c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
2516c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
251793130c84SFabiano Rosas             powerpc_excp(cpu, POWERPC_EXCP_WDT);
2518c79c73f6SBlue Swirl             return;
2519c79c73f6SBlue Swirl         }
2520c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
2521c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
252293130c84SFabiano Rosas             powerpc_excp(cpu, POWERPC_EXCP_DOORCI);
2523c79c73f6SBlue Swirl             return;
2524c79c73f6SBlue Swirl         }
2525c79c73f6SBlue Swirl         /* Fixed interval timer on embedded PowerPC */
2526c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
2527c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
252893130c84SFabiano Rosas             powerpc_excp(cpu, POWERPC_EXCP_FIT);
2529c79c73f6SBlue Swirl             return;
2530c79c73f6SBlue Swirl         }
2531c79c73f6SBlue Swirl         /* Programmable interval timer on embedded PowerPC */
2532c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
2533c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
253493130c84SFabiano Rosas             powerpc_excp(cpu, POWERPC_EXCP_PIT);
2535c79c73f6SBlue Swirl             return;
2536c79c73f6SBlue Swirl         }
2537c79c73f6SBlue Swirl         /* Decrementer exception */
2538c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
2539e81a982aSAlexander Graf             if (ppc_decr_clear_on_delivery(env)) {
2540c79c73f6SBlue Swirl                 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
2541e81a982aSAlexander Graf             }
254293130c84SFabiano Rosas             powerpc_excp(cpu, POWERPC_EXCP_DECR);
2543c79c73f6SBlue Swirl             return;
2544c79c73f6SBlue Swirl         }
2545c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
2546c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
25475ba7ba1dSCédric Le Goater             if (is_book3s_arch2x(env)) {
254893130c84SFabiano Rosas                 powerpc_excp(cpu, POWERPC_EXCP_SDOOR);
25495ba7ba1dSCédric Le Goater             } else {
255093130c84SFabiano Rosas                 powerpc_excp(cpu, POWERPC_EXCP_DOORI);
25515ba7ba1dSCédric Le Goater             }
2552c79c73f6SBlue Swirl             return;
2553c79c73f6SBlue Swirl         }
25547af1e7b0SCédric Le Goater         if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) {
25557af1e7b0SCédric Le Goater             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
255693130c84SFabiano Rosas             powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV);
25577af1e7b0SCédric Le Goater             return;
25587af1e7b0SCédric Le Goater         }
2559c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
2560c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
256193130c84SFabiano Rosas             powerpc_excp(cpu, POWERPC_EXCP_PERFM);
2562c79c73f6SBlue Swirl             return;
2563c79c73f6SBlue Swirl         }
2564c79c73f6SBlue Swirl         /* Thermal interrupt */
2565c79c73f6SBlue Swirl         if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
2566c79c73f6SBlue Swirl             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
256793130c84SFabiano Rosas             powerpc_excp(cpu, POWERPC_EXCP_THERM);
2568c79c73f6SBlue Swirl             return;
2569c79c73f6SBlue Swirl         }
2570c79c73f6SBlue Swirl     }
2571f8154fd2SBenjamin Herrenschmidt 
2572f8154fd2SBenjamin Herrenschmidt     if (env->resume_as_sreset) {
2573f8154fd2SBenjamin Herrenschmidt         /*
2574f8154fd2SBenjamin Herrenschmidt          * This is a bug ! It means that has_work took us out of halt without
2575f8154fd2SBenjamin Herrenschmidt          * anything to deliver while in a PM state that requires getting
2576f8154fd2SBenjamin Herrenschmidt          * out via a 0x100
2577f8154fd2SBenjamin Herrenschmidt          *
2578f8154fd2SBenjamin Herrenschmidt          * This means we will incorrectly execute past the power management
2579f8154fd2SBenjamin Herrenschmidt          * instruction instead of triggering a reset.
2580f8154fd2SBenjamin Herrenschmidt          *
2581136fbf65Szhaolichang          * It generally means a discrepancy between the wakeup conditions in the
2582f8154fd2SBenjamin Herrenschmidt          * processor has_work implementation and the logic in this function.
2583f8154fd2SBenjamin Herrenschmidt          */
2584db70b311SRichard Henderson         cpu_abort(env_cpu(env),
2585f8154fd2SBenjamin Herrenschmidt                   "Wakeup from PM state but interrupt Undelivered");
2586f8154fd2SBenjamin Herrenschmidt     }
2587c79c73f6SBlue Swirl }
258834316482SAlexey Kardashevskiy 
2589b5b7f391SNicholas Piggin void ppc_cpu_do_system_reset(CPUState *cs)
259034316482SAlexey Kardashevskiy {
259134316482SAlexey Kardashevskiy     PowerPCCPU *cpu = POWERPC_CPU(cs);
259234316482SAlexey Kardashevskiy 
259393130c84SFabiano Rosas     powerpc_excp(cpu, POWERPC_EXCP_RESET);
259434316482SAlexey Kardashevskiy }
2595ad77c6caSNicholas Piggin 
2596ad77c6caSNicholas Piggin void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
2597ad77c6caSNicholas Piggin {
2598ad77c6caSNicholas Piggin     PowerPCCPU *cpu = POWERPC_CPU(cs);
2599ad77c6caSNicholas Piggin     CPUPPCState *env = &cpu->env;
2600ad77c6caSNicholas Piggin     target_ulong msr = 0;
2601ad77c6caSNicholas Piggin 
2602ad77c6caSNicholas Piggin     /*
2603ad77c6caSNicholas Piggin      * Set MSR and NIP for the handler, SRR0/1, DAR and DSISR have already
2604ad77c6caSNicholas Piggin      * been set by KVM.
2605ad77c6caSNicholas Piggin      */
2606ad77c6caSNicholas Piggin     msr = (1ULL << MSR_ME);
2607ad77c6caSNicholas Piggin     msr |= env->msr & (1ULL << MSR_SF);
2608516fc103SFabiano Rosas     if (ppc_interrupts_little_endian(cpu, false)) {
2609ad77c6caSNicholas Piggin         msr |= (1ULL << MSR_LE);
2610ad77c6caSNicholas Piggin     }
2611ad77c6caSNicholas Piggin 
2612ad77c6caSNicholas Piggin     powerpc_set_excp_state(cpu, vector, msr);
2613ad77c6caSNicholas Piggin }
2614c79c73f6SBlue Swirl 
2615458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
2616458dd766SRichard Henderson {
2617458dd766SRichard Henderson     PowerPCCPU *cpu = POWERPC_CPU(cs);
2618458dd766SRichard Henderson     CPUPPCState *env = &cpu->env;
2619458dd766SRichard Henderson 
2620458dd766SRichard Henderson     if (interrupt_request & CPU_INTERRUPT_HARD) {
2621458dd766SRichard Henderson         ppc_hw_interrupt(env);
2622458dd766SRichard Henderson         if (env->pending_interrupts == 0) {
2623458dd766SRichard Henderson             cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
2624458dd766SRichard Henderson         }
2625458dd766SRichard Henderson         return true;
2626458dd766SRichard Henderson     }
2627458dd766SRichard Henderson     return false;
2628458dd766SRichard Henderson }
2629458dd766SRichard Henderson 
2630f725245cSPhilippe Mathieu-Daudé #endif /* !CONFIG_USER_ONLY */
2631f725245cSPhilippe Mathieu-Daudé 
2632ad71ed68SBlue Swirl /*****************************************************************************/
2633ad71ed68SBlue Swirl /* Exceptions processing helpers */
2634ad71ed68SBlue Swirl 
2635db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
2636db789c6cSBenjamin Herrenschmidt                             uint32_t error_code, uintptr_t raddr)
2637ad71ed68SBlue Swirl {
2638db70b311SRichard Henderson     CPUState *cs = env_cpu(env);
263927103424SAndreas Färber 
264027103424SAndreas Färber     cs->exception_index = exception;
2641ad71ed68SBlue Swirl     env->error_code = error_code;
2642db789c6cSBenjamin Herrenschmidt     cpu_loop_exit_restore(cs, raddr);
2643db789c6cSBenjamin Herrenschmidt }
2644db789c6cSBenjamin Herrenschmidt 
2645db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception,
2646db789c6cSBenjamin Herrenschmidt                          uint32_t error_code)
2647db789c6cSBenjamin Herrenschmidt {
2648db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, error_code, 0);
2649db789c6cSBenjamin Herrenschmidt }
2650db789c6cSBenjamin Herrenschmidt 
2651db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception)
2652db789c6cSBenjamin Herrenschmidt {
2653db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, 0);
2654db789c6cSBenjamin Herrenschmidt }
2655db789c6cSBenjamin Herrenschmidt 
2656db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception,
2657db789c6cSBenjamin Herrenschmidt                         uintptr_t raddr)
2658db789c6cSBenjamin Herrenschmidt {
2659db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, raddr);
2660db789c6cSBenjamin Herrenschmidt }
2661db789c6cSBenjamin Herrenschmidt 
26622b44e219SBruno Larsen (billionai) #ifdef CONFIG_TCG
2663db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
2664db789c6cSBenjamin Herrenschmidt                                 uint32_t error_code)
2665db789c6cSBenjamin Herrenschmidt {
2666db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, error_code, 0);
2667ad71ed68SBlue Swirl }
2668ad71ed68SBlue Swirl 
2669e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception)
2670ad71ed68SBlue Swirl {
2671db789c6cSBenjamin Herrenschmidt     raise_exception_err_ra(env, exception, 0, 0);
2672ad71ed68SBlue Swirl }
26732b44e219SBruno Larsen (billionai) #endif
2674ad71ed68SBlue Swirl 
2675ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY)
26762b44e219SBruno Larsen (billionai) #ifdef CONFIG_TCG
2677e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val)
2678ad71ed68SBlue Swirl {
2679db789c6cSBenjamin Herrenschmidt     uint32_t excp = hreg_store_msr(env, val, 0);
2680259186a7SAndreas Färber 
2681db789c6cSBenjamin Herrenschmidt     if (excp != 0) {
2682db70b311SRichard Henderson         CPUState *cs = env_cpu(env);
2683044897efSRichard Purdie         cpu_interrupt_exittb(cs);
2684db789c6cSBenjamin Herrenschmidt         raise_exception(env, excp);
2685ad71ed68SBlue Swirl     }
2686ad71ed68SBlue Swirl }
2687ad71ed68SBlue Swirl 
26887778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64)
2689f43520e5SRichard Henderson void helper_scv(CPUPPCState *env, uint32_t lev)
2690f43520e5SRichard Henderson {
2691f43520e5SRichard Henderson     if (env->spr[SPR_FSCR] & (1ull << FSCR_SCV)) {
2692f43520e5SRichard Henderson         raise_exception_err(env, POWERPC_EXCP_SYSCALL_VECTORED, lev);
2693f43520e5SRichard Henderson     } else {
2694f43520e5SRichard Henderson         raise_exception_err(env, POWERPC_EXCP_FU, FSCR_IC_SCV);
2695f43520e5SRichard Henderson     }
2696f43520e5SRichard Henderson }
2697f43520e5SRichard Henderson 
26987778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
26997778a575SBenjamin Herrenschmidt {
27007778a575SBenjamin Herrenschmidt     CPUState *cs;
27017778a575SBenjamin Herrenschmidt 
2702db70b311SRichard Henderson     cs = env_cpu(env);
27037778a575SBenjamin Herrenschmidt     cs->halted = 1;
27047778a575SBenjamin Herrenschmidt 
27053621e2c9SBenjamin Herrenschmidt     /* Condition for waking up at 0x100 */
27061e7fd61dSBenjamin Herrenschmidt     env->resume_as_sreset = (insn != PPC_PM_STOP) ||
270721c0d66aSBenjamin Herrenschmidt         (env->spr[SPR_PSSCR] & PSSCR_EC);
27087778a575SBenjamin Herrenschmidt }
27097778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */
27107778a575SBenjamin Herrenschmidt 
271162e79ef9SCédric Le Goater static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
2712ad71ed68SBlue Swirl {
2713db70b311SRichard Henderson     CPUState *cs = env_cpu(env);
2714259186a7SAndreas Färber 
2715a2e71b28SBenjamin Herrenschmidt     /* MSR:POW cannot be set by any form of rfi */
2716a2e71b28SBenjamin Herrenschmidt     msr &= ~(1ULL << MSR_POW);
2717a2e71b28SBenjamin Herrenschmidt 
27185aad0457SChristophe Leroy     /* MSR:TGPR cannot be set by any form of rfi */
27195aad0457SChristophe Leroy     if (env->flags & POWERPC_FLAG_TGPR)
27205aad0457SChristophe Leroy         msr &= ~(1ULL << MSR_TGPR);
27215aad0457SChristophe Leroy 
2722ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
2723a2e71b28SBenjamin Herrenschmidt     /* Switching to 32-bit ? Crop the nip */
2724a2e71b28SBenjamin Herrenschmidt     if (!msr_is_64bit(env, msr)) {
2725ad71ed68SBlue Swirl         nip = (uint32_t)nip;
2726ad71ed68SBlue Swirl     }
2727ad71ed68SBlue Swirl #else
2728ad71ed68SBlue Swirl     nip = (uint32_t)nip;
2729ad71ed68SBlue Swirl #endif
2730ad71ed68SBlue Swirl     /* XXX: beware: this is false if VLE is supported */
2731ad71ed68SBlue Swirl     env->nip = nip & ~((target_ulong)0x00000003);
2732ad71ed68SBlue Swirl     hreg_store_msr(env, msr, 1);
27332eb1ef73SCédric Le Goater     trace_ppc_excp_rfi(env->nip, env->msr);
273447733729SDavid Gibson     /*
273547733729SDavid Gibson      * No need to raise an exception here, as rfi is always the last
273647733729SDavid Gibson      * insn of a TB
2737ad71ed68SBlue Swirl      */
2738044897efSRichard Purdie     cpu_interrupt_exittb(cs);
2739a8b73734SNikunj A Dadhania     /* Reset the reservation */
2740a8b73734SNikunj A Dadhania     env->reserve_addr = -1;
2741a8b73734SNikunj A Dadhania 
2742cd0c6f47SBenjamin Herrenschmidt     /* Context synchronizing: check if TCG TLB needs flush */
2743e3cffe6fSNikunj A Dadhania     check_tlb_flush(env, false);
2744ad71ed68SBlue Swirl }
2745ad71ed68SBlue Swirl 
2746e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env)
2747ad71ed68SBlue Swirl {
2748a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful);
2749a1bb7384SScott Wood }
2750ad71ed68SBlue Swirl 
2751a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK
2752ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
2753e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env)
2754ad71ed68SBlue Swirl {
275547733729SDavid Gibson     /*
2756136fbf65Szhaolichang      * The architecture defines a number of rules for which bits can
275747733729SDavid Gibson      * change but in practice, we handle this in hreg_store_msr()
2758a2e71b28SBenjamin Herrenschmidt      * which will be called by do_rfi(), so there is no need to filter
2759a2e71b28SBenjamin Herrenschmidt      * here
2760a2e71b28SBenjamin Herrenschmidt      */
2761a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]);
2762ad71ed68SBlue Swirl }
2763ad71ed68SBlue Swirl 
27643c89b8d6SNicholas Piggin void helper_rfscv(CPUPPCState *env)
27653c89b8d6SNicholas Piggin {
27663c89b8d6SNicholas Piggin     do_rfi(env, env->lr, env->ctr);
27673c89b8d6SNicholas Piggin }
27683c89b8d6SNicholas Piggin 
2769e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env)
2770ad71ed68SBlue Swirl {
2771a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
2772ad71ed68SBlue Swirl }
2773ad71ed68SBlue Swirl #endif
2774ad71ed68SBlue Swirl 
27751f26c751SDaniel Henrique Barboza #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
27761f26c751SDaniel Henrique Barboza void helper_rfebb(CPUPPCState *env, target_ulong s)
27771f26c751SDaniel Henrique Barboza {
27781f26c751SDaniel Henrique Barboza     target_ulong msr = env->msr;
27791f26c751SDaniel Henrique Barboza 
27801f26c751SDaniel Henrique Barboza     /*
27811f26c751SDaniel Henrique Barboza      * Handling of BESCR bits 32:33 according to PowerISA v3.1:
27821f26c751SDaniel Henrique Barboza      *
27831f26c751SDaniel Henrique Barboza      * "If BESCR 32:33 != 0b00 the instruction is treated as if
27841f26c751SDaniel Henrique Barboza      *  the instruction form were invalid."
27851f26c751SDaniel Henrique Barboza      */
27861f26c751SDaniel Henrique Barboza     if (env->spr[SPR_BESCR] & BESCR_INVALID) {
27871f26c751SDaniel Henrique Barboza         raise_exception_err(env, POWERPC_EXCP_PROGRAM,
27881f26c751SDaniel Henrique Barboza                             POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
27891f26c751SDaniel Henrique Barboza     }
27901f26c751SDaniel Henrique Barboza 
27911f26c751SDaniel Henrique Barboza     env->nip = env->spr[SPR_EBBRR];
27921f26c751SDaniel Henrique Barboza 
27931f26c751SDaniel Henrique Barboza     /* Switching to 32-bit ? Crop the nip */
27941f26c751SDaniel Henrique Barboza     if (!msr_is_64bit(env, msr)) {
27951f26c751SDaniel Henrique Barboza         env->nip = (uint32_t)env->spr[SPR_EBBRR];
27961f26c751SDaniel Henrique Barboza     }
27971f26c751SDaniel Henrique Barboza 
27981f26c751SDaniel Henrique Barboza     if (s) {
27991f26c751SDaniel Henrique Barboza         env->spr[SPR_BESCR] |= BESCR_GE;
28001f26c751SDaniel Henrique Barboza     } else {
28011f26c751SDaniel Henrique Barboza         env->spr[SPR_BESCR] &= ~BESCR_GE;
28021f26c751SDaniel Henrique Barboza     }
28031f26c751SDaniel Henrique Barboza }
28041f26c751SDaniel Henrique Barboza #endif
28051f26c751SDaniel Henrique Barboza 
2806ad71ed68SBlue Swirl /*****************************************************************************/
2807ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */
2808e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env)
2809ad71ed68SBlue Swirl {
2810a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]);
2811ad71ed68SBlue Swirl }
2812ad71ed68SBlue Swirl 
2813e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env)
2814ad71ed68SBlue Swirl {
2815a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]);
2816ad71ed68SBlue Swirl }
2817ad71ed68SBlue Swirl 
2818e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env)
2819ad71ed68SBlue Swirl {
2820a1bb7384SScott Wood     /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
2821a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]);
2822ad71ed68SBlue Swirl }
2823ad71ed68SBlue Swirl 
2824e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env)
2825ad71ed68SBlue Swirl {
2826a1bb7384SScott Wood     /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
2827a2e71b28SBenjamin Herrenschmidt     do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]);
2828ad71ed68SBlue Swirl }
28292b44e219SBruno Larsen (billionai) #endif /* CONFIG_TCG */
28302b44e219SBruno Larsen (billionai) #endif /* !defined(CONFIG_USER_ONLY) */
2831ad71ed68SBlue Swirl 
28322b44e219SBruno Larsen (billionai) #ifdef CONFIG_TCG
2833e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
2834e5f17ac6SBlue Swirl                uint32_t flags)
2835ad71ed68SBlue Swirl {
2836ad71ed68SBlue Swirl     if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
2837ad71ed68SBlue Swirl                   ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
2838ad71ed68SBlue Swirl                   ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
2839ad71ed68SBlue Swirl                   ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
2840ad71ed68SBlue Swirl                   ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
284172073dccSBenjamin Herrenschmidt         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
284272073dccSBenjamin Herrenschmidt                                POWERPC_EXCP_TRAP, GETPC());
2843ad71ed68SBlue Swirl     }
2844ad71ed68SBlue Swirl }
2845ad71ed68SBlue Swirl 
2846ad71ed68SBlue Swirl #if defined(TARGET_PPC64)
2847e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
2848e5f17ac6SBlue Swirl                uint32_t flags)
2849ad71ed68SBlue Swirl {
2850ad71ed68SBlue Swirl     if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
2851ad71ed68SBlue Swirl                   ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
2852ad71ed68SBlue Swirl                   ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
2853ad71ed68SBlue Swirl                   ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
2854ad71ed68SBlue Swirl                   ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
285572073dccSBenjamin Herrenschmidt         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
285672073dccSBenjamin Herrenschmidt                                POWERPC_EXCP_TRAP, GETPC());
2857ad71ed68SBlue Swirl     }
2858ad71ed68SBlue Swirl }
2859ad71ed68SBlue Swirl #endif
28602b44e219SBruno Larsen (billionai) #endif
2861ad71ed68SBlue Swirl 
2862ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY)
2863ad71ed68SBlue Swirl 
28642b44e219SBruno Larsen (billionai) #ifdef CONFIG_TCG
2865ad71ed68SBlue Swirl 
2866ad71ed68SBlue Swirl /* Embedded.Processor Control */
2867ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb)
2868ad71ed68SBlue Swirl {
2869ad71ed68SBlue Swirl     int msg = rb & DBELL_TYPE_MASK;
2870ad71ed68SBlue Swirl     int irq = -1;
2871ad71ed68SBlue Swirl 
2872ad71ed68SBlue Swirl     switch (msg) {
2873ad71ed68SBlue Swirl     case DBELL_TYPE_DBELL:
2874ad71ed68SBlue Swirl         irq = PPC_INTERRUPT_DOORBELL;
2875ad71ed68SBlue Swirl         break;
2876ad71ed68SBlue Swirl     case DBELL_TYPE_DBELL_CRIT:
2877ad71ed68SBlue Swirl         irq = PPC_INTERRUPT_CDOORBELL;
2878ad71ed68SBlue Swirl         break;
2879ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL:
2880ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL_CRIT:
2881ad71ed68SBlue Swirl     case DBELL_TYPE_G_DBELL_MC:
2882ad71ed68SBlue Swirl         /* XXX implement */
2883ad71ed68SBlue Swirl     default:
2884ad71ed68SBlue Swirl         break;
2885ad71ed68SBlue Swirl     }
2886ad71ed68SBlue Swirl 
2887ad71ed68SBlue Swirl     return irq;
2888ad71ed68SBlue Swirl }
2889ad71ed68SBlue Swirl 
2890e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb)
2891ad71ed68SBlue Swirl {
2892ad71ed68SBlue Swirl     int irq = dbell2irq(rb);
2893ad71ed68SBlue Swirl 
2894ad71ed68SBlue Swirl     if (irq < 0) {
2895ad71ed68SBlue Swirl         return;
2896ad71ed68SBlue Swirl     }
2897ad71ed68SBlue Swirl 
2898ad71ed68SBlue Swirl     env->pending_interrupts &= ~(1 << irq);
2899ad71ed68SBlue Swirl }
2900ad71ed68SBlue Swirl 
2901ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb)
2902ad71ed68SBlue Swirl {
2903ad71ed68SBlue Swirl     int irq = dbell2irq(rb);
2904ad71ed68SBlue Swirl     int pir = rb & DBELL_PIRTAG_MASK;
2905182735efSAndreas Färber     CPUState *cs;
2906ad71ed68SBlue Swirl 
2907ad71ed68SBlue Swirl     if (irq < 0) {
2908ad71ed68SBlue Swirl         return;
2909ad71ed68SBlue Swirl     }
2910ad71ed68SBlue Swirl 
2911f1c29ebcSThomas Huth     qemu_mutex_lock_iothread();
2912bdc44640SAndreas Färber     CPU_FOREACH(cs) {
2913182735efSAndreas Färber         PowerPCCPU *cpu = POWERPC_CPU(cs);
2914182735efSAndreas Färber         CPUPPCState *cenv = &cpu->env;
2915182735efSAndreas Färber 
2916ad71ed68SBlue Swirl         if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
2917ad71ed68SBlue Swirl             cenv->pending_interrupts |= 1 << irq;
2918182735efSAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
2919ad71ed68SBlue Swirl         }
2920ad71ed68SBlue Swirl     }
2921f1c29ebcSThomas Huth     qemu_mutex_unlock_iothread();
2922ad71ed68SBlue Swirl }
29237af1e7b0SCédric Le Goater 
29247af1e7b0SCédric Le Goater /* Server Processor Control */
29257af1e7b0SCédric Le Goater 
29265ba7ba1dSCédric Le Goater static bool dbell_type_server(target_ulong rb)
29275ba7ba1dSCédric Le Goater {
292847733729SDavid Gibson     /*
292947733729SDavid Gibson      * A Directed Hypervisor Doorbell message is sent only if the
29307af1e7b0SCédric Le Goater      * message type is 5. All other types are reserved and the
293147733729SDavid Gibson      * instruction is a no-op
293247733729SDavid Gibson      */
29335ba7ba1dSCédric Le Goater     return (rb & DBELL_TYPE_MASK) == DBELL_TYPE_DBELL_SERVER;
29347af1e7b0SCédric Le Goater }
29357af1e7b0SCédric Le Goater 
29367af1e7b0SCédric Le Goater void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
29377af1e7b0SCédric Le Goater {
29385ba7ba1dSCédric Le Goater     if (!dbell_type_server(rb)) {
29397af1e7b0SCédric Le Goater         return;
29407af1e7b0SCédric Le Goater     }
29417af1e7b0SCédric Le Goater 
29425ba7ba1dSCédric Le Goater     env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL);
29437af1e7b0SCédric Le Goater }
29447af1e7b0SCédric Le Goater 
29455ba7ba1dSCédric Le Goater static void book3s_msgsnd_common(int pir, int irq)
29467af1e7b0SCédric Le Goater {
29477af1e7b0SCédric Le Goater     CPUState *cs;
29487af1e7b0SCédric Le Goater 
29497af1e7b0SCédric Le Goater     qemu_mutex_lock_iothread();
29507af1e7b0SCédric Le Goater     CPU_FOREACH(cs) {
29517af1e7b0SCédric Le Goater         PowerPCCPU *cpu = POWERPC_CPU(cs);
29527af1e7b0SCédric Le Goater         CPUPPCState *cenv = &cpu->env;
29537af1e7b0SCédric Le Goater 
29547af1e7b0SCédric Le Goater         /* TODO: broadcast message to all threads of the same  processor */
29557af1e7b0SCédric Le Goater         if (cenv->spr_cb[SPR_PIR].default_value == pir) {
29567af1e7b0SCédric Le Goater             cenv->pending_interrupts |= 1 << irq;
29577af1e7b0SCédric Le Goater             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
29587af1e7b0SCédric Le Goater         }
29597af1e7b0SCédric Le Goater     }
29607af1e7b0SCédric Le Goater     qemu_mutex_unlock_iothread();
29617af1e7b0SCédric Le Goater }
29625ba7ba1dSCédric Le Goater 
29635ba7ba1dSCédric Le Goater void helper_book3s_msgsnd(target_ulong rb)
29645ba7ba1dSCédric Le Goater {
29655ba7ba1dSCédric Le Goater     int pir = rb & DBELL_PROCIDTAG_MASK;
29665ba7ba1dSCédric Le Goater 
29675ba7ba1dSCédric Le Goater     if (!dbell_type_server(rb)) {
29685ba7ba1dSCédric Le Goater         return;
29695ba7ba1dSCédric Le Goater     }
29705ba7ba1dSCédric Le Goater 
29715ba7ba1dSCédric Le Goater     book3s_msgsnd_common(pir, PPC_INTERRUPT_HDOORBELL);
29725ba7ba1dSCédric Le Goater }
29735ba7ba1dSCédric Le Goater 
29745ba7ba1dSCédric Le Goater #if defined(TARGET_PPC64)
29755ba7ba1dSCédric Le Goater void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb)
29765ba7ba1dSCédric Le Goater {
2977493028d8SCédric Le Goater     helper_hfscr_facility_check(env, HFSCR_MSGP, "msgclrp", HFSCR_IC_MSGP);
2978493028d8SCédric Le Goater 
29795ba7ba1dSCédric Le Goater     if (!dbell_type_server(rb)) {
29805ba7ba1dSCédric Le Goater         return;
29815ba7ba1dSCédric Le Goater     }
29825ba7ba1dSCédric Le Goater 
29835ba7ba1dSCédric Le Goater     env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
29845ba7ba1dSCédric Le Goater }
29855ba7ba1dSCédric Le Goater 
29865ba7ba1dSCédric Le Goater /*
29875ba7ba1dSCédric Le Goater  * sends a message to other threads that are on the same
29885ba7ba1dSCédric Le Goater  * multi-threaded processor
29895ba7ba1dSCédric Le Goater  */
29905ba7ba1dSCédric Le Goater void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb)
29915ba7ba1dSCédric Le Goater {
29925ba7ba1dSCédric Le Goater     int pir = env->spr_cb[SPR_PIR].default_value;
29935ba7ba1dSCédric Le Goater 
2994493028d8SCédric Le Goater     helper_hfscr_facility_check(env, HFSCR_MSGP, "msgsndp", HFSCR_IC_MSGP);
2995493028d8SCédric Le Goater 
29965ba7ba1dSCédric Le Goater     if (!dbell_type_server(rb)) {
29975ba7ba1dSCédric Le Goater         return;
29985ba7ba1dSCédric Le Goater     }
29995ba7ba1dSCédric Le Goater 
30005ba7ba1dSCédric Le Goater     /* TODO: TCG supports only one thread */
30015ba7ba1dSCédric Le Goater 
30025ba7ba1dSCédric Le Goater     book3s_msgsnd_common(pir, PPC_INTERRUPT_DOORBELL);
30035ba7ba1dSCédric Le Goater }
3004996473e4SRichard Henderson #endif /* TARGET_PPC64 */
30050f3110faSRichard Henderson 
30060f3110faSRichard Henderson void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
30070f3110faSRichard Henderson                                  MMUAccessType access_type,
30080f3110faSRichard Henderson                                  int mmu_idx, uintptr_t retaddr)
30090f3110faSRichard Henderson {
30100f3110faSRichard Henderson     CPUPPCState *env = cs->env_ptr;
301129c4a336SFabiano Rosas     uint32_t insn;
301229c4a336SFabiano Rosas 
301329c4a336SFabiano Rosas     /* Restore state and reload the insn we executed, for filling in DSISR.  */
301429c4a336SFabiano Rosas     cpu_restore_state(cs, retaddr, true);
301529c4a336SFabiano Rosas     insn = cpu_ldl_code(env, env->nip);
30160f3110faSRichard Henderson 
3017a7e3af13SRichard Henderson     switch (env->mmu_model) {
3018a7e3af13SRichard Henderson     case POWERPC_MMU_SOFT_4xx:
3019a7e3af13SRichard Henderson         env->spr[SPR_40x_DEAR] = vaddr;
3020a7e3af13SRichard Henderson         break;
3021a7e3af13SRichard Henderson     case POWERPC_MMU_BOOKE:
3022a7e3af13SRichard Henderson     case POWERPC_MMU_BOOKE206:
3023a7e3af13SRichard Henderson         env->spr[SPR_BOOKE_DEAR] = vaddr;
3024a7e3af13SRichard Henderson         break;
3025a7e3af13SRichard Henderson     default:
3026a7e3af13SRichard Henderson         env->spr[SPR_DAR] = vaddr;
3027a7e3af13SRichard Henderson         break;
3028a7e3af13SRichard Henderson     }
3029a7e3af13SRichard Henderson 
30300f3110faSRichard Henderson     cs->exception_index = POWERPC_EXCP_ALIGN;
303129c4a336SFabiano Rosas     env->error_code = insn & 0x03FF0000;
303229c4a336SFabiano Rosas     cpu_loop_exit(cs);
30330f3110faSRichard Henderson }
3034996473e4SRichard Henderson #endif /* CONFIG_TCG */
3035996473e4SRichard Henderson #endif /* !CONFIG_USER_ONLY */
3036