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" 21cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h" 22ad71ed68SBlue Swirl #include "cpu.h" 2363c91552SPaolo Bonzini #include "exec/exec-all.h" 240f3110faSRichard Henderson #include "internal.h" 25ad71ed68SBlue Swirl #include "helper_regs.h" 267b694df6SMatheus Ferst #include "hw/ppc/ppc.h" 27ad71ed68SBlue Swirl 282eb1ef73SCédric Le Goater #include "trace.h" 292eb1ef73SCédric Le Goater 302b44e219SBruno Larsen (billionai) #ifdef CONFIG_TCG 315a5d3b23SNicholas Piggin #include "sysemu/tcg.h" 322b44e219SBruno Larsen (billionai) #include "exec/helper-proto.h" 332b44e219SBruno Larsen (billionai) #include "exec/cpu_ldst.h" 342b44e219SBruno Larsen (billionai) #endif 352b44e219SBruno Larsen (billionai) 36c79c73f6SBlue Swirl /*****************************************************************************/ 37c79c73f6SBlue Swirl /* Exception processing */ 38f725245cSPhilippe Mathieu-Daudé #if !defined(CONFIG_USER_ONLY) 3997a8ea5aSAndreas Färber 406789f23bSCédric Le Goater static const char *powerpc_excp_name(int excp) 416789f23bSCédric Le Goater { 426789f23bSCédric Le Goater switch (excp) { 436789f23bSCédric Le Goater case POWERPC_EXCP_CRITICAL: return "CRITICAL"; 446789f23bSCédric Le Goater case POWERPC_EXCP_MCHECK: return "MCHECK"; 456789f23bSCédric Le Goater case POWERPC_EXCP_DSI: return "DSI"; 466789f23bSCédric Le Goater case POWERPC_EXCP_ISI: return "ISI"; 476789f23bSCédric Le Goater case POWERPC_EXCP_EXTERNAL: return "EXTERNAL"; 486789f23bSCédric Le Goater case POWERPC_EXCP_ALIGN: return "ALIGN"; 496789f23bSCédric Le Goater case POWERPC_EXCP_PROGRAM: return "PROGRAM"; 506789f23bSCédric Le Goater case POWERPC_EXCP_FPU: return "FPU"; 516789f23bSCédric Le Goater case POWERPC_EXCP_SYSCALL: return "SYSCALL"; 526789f23bSCédric Le Goater case POWERPC_EXCP_APU: return "APU"; 536789f23bSCédric Le Goater case POWERPC_EXCP_DECR: return "DECR"; 546789f23bSCédric Le Goater case POWERPC_EXCP_FIT: return "FIT"; 556789f23bSCédric Le Goater case POWERPC_EXCP_WDT: return "WDT"; 566789f23bSCédric Le Goater case POWERPC_EXCP_DTLB: return "DTLB"; 576789f23bSCédric Le Goater case POWERPC_EXCP_ITLB: return "ITLB"; 586789f23bSCédric Le Goater case POWERPC_EXCP_DEBUG: return "DEBUG"; 596789f23bSCédric Le Goater case POWERPC_EXCP_SPEU: return "SPEU"; 606789f23bSCédric Le Goater case POWERPC_EXCP_EFPDI: return "EFPDI"; 616789f23bSCédric Le Goater case POWERPC_EXCP_EFPRI: return "EFPRI"; 626789f23bSCédric Le Goater case POWERPC_EXCP_EPERFM: return "EPERFM"; 636789f23bSCédric Le Goater case POWERPC_EXCP_DOORI: return "DOORI"; 646789f23bSCédric Le Goater case POWERPC_EXCP_DOORCI: return "DOORCI"; 656789f23bSCédric Le Goater case POWERPC_EXCP_GDOORI: return "GDOORI"; 666789f23bSCédric Le Goater case POWERPC_EXCP_GDOORCI: return "GDOORCI"; 676789f23bSCédric Le Goater case POWERPC_EXCP_HYPPRIV: return "HYPPRIV"; 686789f23bSCédric Le Goater case POWERPC_EXCP_RESET: return "RESET"; 696789f23bSCédric Le Goater case POWERPC_EXCP_DSEG: return "DSEG"; 706789f23bSCédric Le Goater case POWERPC_EXCP_ISEG: return "ISEG"; 716789f23bSCédric Le Goater case POWERPC_EXCP_HDECR: return "HDECR"; 726789f23bSCédric Le Goater case POWERPC_EXCP_TRACE: return "TRACE"; 736789f23bSCédric Le Goater case POWERPC_EXCP_HDSI: return "HDSI"; 746789f23bSCédric Le Goater case POWERPC_EXCP_HISI: return "HISI"; 756789f23bSCédric Le Goater case POWERPC_EXCP_HDSEG: return "HDSEG"; 766789f23bSCédric Le Goater case POWERPC_EXCP_HISEG: return "HISEG"; 776789f23bSCédric Le Goater case POWERPC_EXCP_VPU: return "VPU"; 786789f23bSCédric Le Goater case POWERPC_EXCP_PIT: return "PIT"; 796789f23bSCédric Le Goater case POWERPC_EXCP_EMUL: return "EMUL"; 806789f23bSCédric Le Goater case POWERPC_EXCP_IFTLB: return "IFTLB"; 816789f23bSCédric Le Goater case POWERPC_EXCP_DLTLB: return "DLTLB"; 826789f23bSCédric Le Goater case POWERPC_EXCP_DSTLB: return "DSTLB"; 836789f23bSCédric Le Goater case POWERPC_EXCP_FPA: return "FPA"; 846789f23bSCédric Le Goater case POWERPC_EXCP_DABR: return "DABR"; 856789f23bSCédric Le Goater case POWERPC_EXCP_IABR: return "IABR"; 866789f23bSCédric Le Goater case POWERPC_EXCP_SMI: return "SMI"; 876789f23bSCédric Le Goater case POWERPC_EXCP_PERFM: return "PERFM"; 886789f23bSCédric Le Goater case POWERPC_EXCP_THERM: return "THERM"; 896789f23bSCédric Le Goater case POWERPC_EXCP_VPUA: return "VPUA"; 906789f23bSCédric Le Goater case POWERPC_EXCP_SOFTP: return "SOFTP"; 916789f23bSCédric Le Goater case POWERPC_EXCP_MAINT: return "MAINT"; 926789f23bSCédric Le Goater case POWERPC_EXCP_MEXTBR: return "MEXTBR"; 936789f23bSCédric Le Goater case POWERPC_EXCP_NMEXTBR: return "NMEXTBR"; 946789f23bSCédric Le Goater case POWERPC_EXCP_ITLBE: return "ITLBE"; 956789f23bSCédric Le Goater case POWERPC_EXCP_DTLBE: return "DTLBE"; 966789f23bSCédric Le Goater case POWERPC_EXCP_VSXU: return "VSXU"; 976789f23bSCédric Le Goater case POWERPC_EXCP_FU: return "FU"; 986789f23bSCédric Le Goater case POWERPC_EXCP_HV_EMU: return "HV_EMU"; 996789f23bSCédric Le Goater case POWERPC_EXCP_HV_MAINT: return "HV_MAINT"; 1006789f23bSCédric Le Goater case POWERPC_EXCP_HV_FU: return "HV_FU"; 1016789f23bSCédric Le Goater case POWERPC_EXCP_SDOOR: return "SDOOR"; 1026789f23bSCédric Le Goater case POWERPC_EXCP_SDOOR_HV: return "SDOOR_HV"; 1036789f23bSCédric Le Goater case POWERPC_EXCP_HVIRT: return "HVIRT"; 1046789f23bSCédric Le Goater case POWERPC_EXCP_SYSCALL_VECTORED: return "SYSCALL_VECTORED"; 1056789f23bSCédric Le Goater default: 1066789f23bSCédric Le Goater g_assert_not_reached(); 1076789f23bSCédric Le Goater } 1086789f23bSCédric Le Goater } 1096789f23bSCédric Le Goater 11062e79ef9SCédric Le Goater static void dump_syscall(CPUPPCState *env) 111c79c73f6SBlue Swirl { 1126dc6b557SNicholas Piggin qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 1136dc6b557SNicholas Piggin " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64 1146dc6b557SNicholas Piggin " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64 115c79c73f6SBlue Swirl " nip=" TARGET_FMT_lx "\n", 116c79c73f6SBlue Swirl ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), 117c79c73f6SBlue Swirl ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), 1186dc6b557SNicholas Piggin ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7), 1196dc6b557SNicholas Piggin ppc_dump_gpr(env, 8), env->nip); 1206dc6b557SNicholas Piggin } 1216dc6b557SNicholas Piggin 12262e79ef9SCédric Le Goater static void dump_hcall(CPUPPCState *env) 1236dc6b557SNicholas Piggin { 1246dc6b557SNicholas Piggin qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64 1256dc6b557SNicholas Piggin " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 1266dc6b557SNicholas Piggin " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64 1276dc6b557SNicholas Piggin " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64 1286dc6b557SNicholas Piggin " nip=" TARGET_FMT_lx "\n", 1296dc6b557SNicholas Piggin ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4), 1306dc6b557SNicholas Piggin ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6), 1316dc6b557SNicholas Piggin ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8), 1326dc6b557SNicholas Piggin ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10), 1336dc6b557SNicholas Piggin ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12), 1346dc6b557SNicholas Piggin env->nip); 135c79c73f6SBlue Swirl } 136c79c73f6SBlue Swirl 137888050cfSNicholas Piggin #ifdef CONFIG_TCG 138888050cfSNicholas Piggin /* Return true iff byteswap is needed to load instruction */ 139888050cfSNicholas Piggin static inline bool insn_need_byteswap(CPUArchState *env) 140888050cfSNicholas Piggin { 141888050cfSNicholas Piggin /* SYSTEM builds TARGET_BIG_ENDIAN. Need to swap when MSR[LE] is set */ 142888050cfSNicholas Piggin return !!(env->msr & ((target_ulong)1 << MSR_LE)); 143888050cfSNicholas Piggin } 144888050cfSNicholas Piggin 1455a5d3b23SNicholas Piggin static uint32_t ppc_ldl_code(CPUArchState *env, abi_ptr addr) 146888050cfSNicholas Piggin { 147888050cfSNicholas Piggin uint32_t insn = cpu_ldl_code(env, addr); 148888050cfSNicholas Piggin 149888050cfSNicholas Piggin if (insn_need_byteswap(env)) { 150888050cfSNicholas Piggin insn = bswap32(insn); 151888050cfSNicholas Piggin } 152888050cfSNicholas Piggin 153888050cfSNicholas Piggin return insn; 154888050cfSNicholas Piggin } 155888050cfSNicholas Piggin #endif 156888050cfSNicholas Piggin 157e4e27df7SFabiano Rosas static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp) 158e4e27df7SFabiano Rosas { 159e4e27df7SFabiano Rosas const char *es; 160e4e27df7SFabiano Rosas target_ulong *miss, *cmp; 161e4e27df7SFabiano Rosas int en; 162e4e27df7SFabiano Rosas 1632e089eceSFabiano Rosas if (!qemu_loglevel_mask(CPU_LOG_MMU)) { 164e4e27df7SFabiano Rosas return; 165e4e27df7SFabiano Rosas } 166e4e27df7SFabiano Rosas 167e4e27df7SFabiano Rosas if (excp == POWERPC_EXCP_IFTLB) { 168e4e27df7SFabiano Rosas es = "I"; 169e4e27df7SFabiano Rosas en = 'I'; 170e4e27df7SFabiano Rosas miss = &env->spr[SPR_IMISS]; 171e4e27df7SFabiano Rosas cmp = &env->spr[SPR_ICMP]; 172e4e27df7SFabiano Rosas } else { 173e4e27df7SFabiano Rosas if (excp == POWERPC_EXCP_DLTLB) { 174e4e27df7SFabiano Rosas es = "DL"; 175e4e27df7SFabiano Rosas } else { 176e4e27df7SFabiano Rosas es = "DS"; 177e4e27df7SFabiano Rosas } 178e4e27df7SFabiano Rosas en = 'D'; 179e4e27df7SFabiano Rosas miss = &env->spr[SPR_DMISS]; 180e4e27df7SFabiano Rosas cmp = &env->spr[SPR_DCMP]; 181e4e27df7SFabiano Rosas } 182e4e27df7SFabiano Rosas qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 183e4e27df7SFabiano Rosas TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " 184e4e27df7SFabiano Rosas TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 185e4e27df7SFabiano Rosas env->spr[SPR_HASH1], env->spr[SPR_HASH2], 186e4e27df7SFabiano Rosas env->error_code); 187e4e27df7SFabiano Rosas } 188e4e27df7SFabiano Rosas 18928091374SFabiano Rosas #if defined(TARGET_PPC64) 190*3f88a89dSBALATON Zoltan static int powerpc_reset_wakeup(CPUPPCState *env, int excp, target_ulong *msr) 191dead760bSBenjamin Herrenschmidt { 192dead760bSBenjamin Herrenschmidt /* We no longer are in a PM state */ 1931e7fd61dSBenjamin Herrenschmidt env->resume_as_sreset = false; 194dead760bSBenjamin Herrenschmidt 195dead760bSBenjamin Herrenschmidt /* Pretend to be returning from doze always as we don't lose state */ 1960911a60cSLeonardo Bras *msr |= SRR1_WS_NOLOSS; 197dead760bSBenjamin Herrenschmidt 198dead760bSBenjamin Herrenschmidt /* Machine checks are sent normally */ 199dead760bSBenjamin Herrenschmidt if (excp == POWERPC_EXCP_MCHECK) { 200dead760bSBenjamin Herrenschmidt return excp; 201dead760bSBenjamin Herrenschmidt } 202dead760bSBenjamin Herrenschmidt switch (excp) { 203dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_RESET: 2040911a60cSLeonardo Bras *msr |= SRR1_WAKERESET; 205dead760bSBenjamin Herrenschmidt break; 206dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_EXTERNAL: 2070911a60cSLeonardo Bras *msr |= SRR1_WAKEEE; 208dead760bSBenjamin Herrenschmidt break; 209dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_DECR: 2100911a60cSLeonardo Bras *msr |= SRR1_WAKEDEC; 211dead760bSBenjamin Herrenschmidt break; 212dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_SDOOR: 2130911a60cSLeonardo Bras *msr |= SRR1_WAKEDBELL; 214dead760bSBenjamin Herrenschmidt break; 215dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_SDOOR_HV: 2160911a60cSLeonardo Bras *msr |= SRR1_WAKEHDBELL; 217dead760bSBenjamin Herrenschmidt break; 218dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_HV_MAINT: 2190911a60cSLeonardo Bras *msr |= SRR1_WAKEHMI; 220dead760bSBenjamin Herrenschmidt break; 221d8ce5fd6SBenjamin Herrenschmidt case POWERPC_EXCP_HVIRT: 2220911a60cSLeonardo Bras *msr |= SRR1_WAKEHVI; 223d8ce5fd6SBenjamin Herrenschmidt break; 224dead760bSBenjamin Herrenschmidt default: 225*3f88a89dSBALATON Zoltan cpu_abort(env_cpu(env), 226*3f88a89dSBALATON Zoltan "Unsupported exception %d in Power Save mode\n", excp); 227dead760bSBenjamin Herrenschmidt } 228dead760bSBenjamin Herrenschmidt return POWERPC_EXCP_RESET; 229dead760bSBenjamin Herrenschmidt } 230dead760bSBenjamin Herrenschmidt 2318b7e6b07SNicholas Piggin /* 2328b7e6b07SNicholas Piggin * AIL - Alternate Interrupt Location, a mode that allows interrupts to be 2338b7e6b07SNicholas Piggin * taken with the MMU on, and which uses an alternate location (e.g., so the 2348b7e6b07SNicholas Piggin * kernel/hv can map the vectors there with an effective address). 2358b7e6b07SNicholas Piggin * 2368b7e6b07SNicholas Piggin * An interrupt is considered to be taken "with AIL" or "AIL applies" if they 2378b7e6b07SNicholas Piggin * are delivered in this way. AIL requires the LPCR to be set to enable this 2388b7e6b07SNicholas Piggin * mode, and then a number of conditions have to be true for AIL to apply. 2398b7e6b07SNicholas Piggin * 2408b7e6b07SNicholas Piggin * First of all, SRESET, MCE, and HMI are always delivered without AIL, because 2418b7e6b07SNicholas Piggin * they specifically want to be in real mode (e.g., the MCE might be signaling 2428b7e6b07SNicholas Piggin * a SLB multi-hit which requires SLB flush before the MMU can be enabled). 2438b7e6b07SNicholas Piggin * 2448b7e6b07SNicholas Piggin * After that, behaviour depends on the current MSR[IR], MSR[DR], MSR[HV], 2458b7e6b07SNicholas Piggin * whether or not the interrupt changes MSR[HV] from 0 to 1, and the current 2468b7e6b07SNicholas Piggin * radix mode (LPCR[HR]). 2478b7e6b07SNicholas Piggin * 2488b7e6b07SNicholas Piggin * POWER8, POWER9 with LPCR[HR]=0 2498b7e6b07SNicholas Piggin * | LPCR[AIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL | 2508b7e6b07SNicholas Piggin * +-----------+-------------+---------+-------------+-----+ 2518b7e6b07SNicholas Piggin * | a | 00/01/10 | x | x | 0 | 2528b7e6b07SNicholas Piggin * | a | 11 | 0 | 1 | 0 | 2538b7e6b07SNicholas Piggin * | a | 11 | 1 | 1 | a | 2548b7e6b07SNicholas Piggin * | a | 11 | 0 | 0 | a | 2558b7e6b07SNicholas Piggin * +-------------------------------------------------------+ 2568b7e6b07SNicholas Piggin * 2578b7e6b07SNicholas Piggin * POWER9 with LPCR[HR]=1 2588b7e6b07SNicholas Piggin * | LPCR[AIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL | 2598b7e6b07SNicholas Piggin * +-----------+-------------+---------+-------------+-----+ 2608b7e6b07SNicholas Piggin * | a | 00/01/10 | x | x | 0 | 2618b7e6b07SNicholas Piggin * | a | 11 | x | x | a | 2628b7e6b07SNicholas Piggin * +-------------------------------------------------------+ 2638b7e6b07SNicholas Piggin * 2648b7e6b07SNicholas Piggin * The difference with POWER9 being that MSR[HV] 0->1 interrupts can be sent to 265526cdce7SNicholas Piggin * the hypervisor in AIL mode if the guest is radix. This is good for 266526cdce7SNicholas Piggin * performance but allows the guest to influence the AIL of hypervisor 267526cdce7SNicholas Piggin * interrupts using its MSR, and also the hypervisor must disallow guest 268526cdce7SNicholas Piggin * interrupts (MSR[HV] 0->0) from using AIL if the hypervisor does not want to 269526cdce7SNicholas Piggin * use AIL for its MSR[HV] 0->1 interrupts. 270526cdce7SNicholas Piggin * 271526cdce7SNicholas Piggin * POWER10 addresses those issues with a new LPCR[HAIL] bit that is applied to 272526cdce7SNicholas Piggin * interrupts that begin execution with MSR[HV]=1 (so both MSR[HV] 0->1 and 273526cdce7SNicholas Piggin * MSR[HV] 1->1). 274526cdce7SNicholas Piggin * 275526cdce7SNicholas Piggin * HAIL=1 is equivalent to AIL=3, for interrupts delivered with MSR[HV]=1. 276526cdce7SNicholas Piggin * 277526cdce7SNicholas Piggin * POWER10 behaviour is 278526cdce7SNicholas Piggin * | LPCR[AIL] | LPCR[HAIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL | 279526cdce7SNicholas Piggin * +-----------+------------+-------------+---------+-------------+-----+ 280526cdce7SNicholas Piggin * | a | h | 00/01/10 | 0 | 0 | 0 | 281526cdce7SNicholas Piggin * | a | h | 11 | 0 | 0 | a | 282526cdce7SNicholas Piggin * | a | h | x | 0 | 1 | h | 283526cdce7SNicholas Piggin * | a | h | 00/01/10 | 1 | 1 | 0 | 284526cdce7SNicholas Piggin * | a | h | 11 | 1 | 1 | h | 285526cdce7SNicholas Piggin * +--------------------------------------------------------------------+ 2868b7e6b07SNicholas Piggin */ 28710895ab6SFabiano Rosas static void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp, target_ulong msr, 28810895ab6SFabiano Rosas target_ulong *new_msr, target_ulong *vector) 2892586a4d7SFabiano Rosas { 29010895ab6SFabiano Rosas PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 2918b7e6b07SNicholas Piggin CPUPPCState *env = &cpu->env; 2928b7e6b07SNicholas Piggin bool mmu_all_on = ((msr >> MSR_IR) & 1) && ((msr >> MSR_DR) & 1); 2938b7e6b07SNicholas Piggin bool hv_escalation = !(msr & MSR_HVB) && (*new_msr & MSR_HVB); 2948b7e6b07SNicholas Piggin int ail = 0; 2952586a4d7SFabiano Rosas 2968b7e6b07SNicholas Piggin if (excp == POWERPC_EXCP_MCHECK || 2978b7e6b07SNicholas Piggin excp == POWERPC_EXCP_RESET || 2988b7e6b07SNicholas Piggin excp == POWERPC_EXCP_HV_MAINT) { 2998b7e6b07SNicholas Piggin /* SRESET, MCE, HMI never apply AIL */ 3008b7e6b07SNicholas Piggin return; 3012586a4d7SFabiano Rosas } 3022586a4d7SFabiano Rosas 30310895ab6SFabiano Rosas if (!(pcc->lpcr_mask & LPCR_AIL)) { 30410895ab6SFabiano Rosas /* This CPU does not have AIL */ 30510895ab6SFabiano Rosas return; 30610895ab6SFabiano Rosas } 30710895ab6SFabiano Rosas 30810895ab6SFabiano Rosas /* P8 & P9 */ 30910895ab6SFabiano Rosas if (!(pcc->lpcr_mask & LPCR_HAIL)) { 3108b7e6b07SNicholas Piggin if (!mmu_all_on) { 3118b7e6b07SNicholas Piggin /* AIL only works if MSR[IR] and MSR[DR] are both enabled. */ 3128b7e6b07SNicholas Piggin return; 3138b7e6b07SNicholas Piggin } 3148b7e6b07SNicholas Piggin if (hv_escalation && !(env->spr[SPR_LPCR] & LPCR_HR)) { 3158b7e6b07SNicholas Piggin /* 3168b7e6b07SNicholas Piggin * AIL does not work if there is a MSR[HV] 0->1 transition and the 3178b7e6b07SNicholas Piggin * partition is in HPT mode. For radix guests, such interrupts are 3188b7e6b07SNicholas Piggin * allowed to be delivered to the hypervisor in ail mode. 3198b7e6b07SNicholas Piggin */ 3208b7e6b07SNicholas Piggin return; 3218b7e6b07SNicholas Piggin } 3228b7e6b07SNicholas Piggin 3238b7e6b07SNicholas Piggin ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT; 3248b7e6b07SNicholas Piggin if (ail == 0) { 3258b7e6b07SNicholas Piggin return; 3268b7e6b07SNicholas Piggin } 3278b7e6b07SNicholas Piggin if (ail == 1) { 3288b7e6b07SNicholas Piggin /* AIL=1 is reserved, treat it like AIL=0 */ 3298b7e6b07SNicholas Piggin return; 3308b7e6b07SNicholas Piggin } 331526cdce7SNicholas Piggin 33210895ab6SFabiano Rosas /* P10 and up */ 33310895ab6SFabiano Rosas } else { 334526cdce7SNicholas Piggin if (!mmu_all_on && !hv_escalation) { 335526cdce7SNicholas Piggin /* 336526cdce7SNicholas Piggin * AIL works for HV interrupts even with guest MSR[IR/DR] disabled. 337526cdce7SNicholas Piggin * Guest->guest and HV->HV interrupts do require MMU on. 338526cdce7SNicholas Piggin */ 339526cdce7SNicholas Piggin return; 340526cdce7SNicholas Piggin } 341526cdce7SNicholas Piggin 342526cdce7SNicholas Piggin if (*new_msr & MSR_HVB) { 343526cdce7SNicholas Piggin if (!(env->spr[SPR_LPCR] & LPCR_HAIL)) { 344526cdce7SNicholas Piggin /* HV interrupts depend on LPCR[HAIL] */ 345526cdce7SNicholas Piggin return; 346526cdce7SNicholas Piggin } 347526cdce7SNicholas Piggin ail = 3; /* HAIL=1 gives AIL=3 behaviour for HV interrupts */ 348526cdce7SNicholas Piggin } else { 349526cdce7SNicholas Piggin ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT; 350526cdce7SNicholas Piggin } 351526cdce7SNicholas Piggin if (ail == 0) { 352526cdce7SNicholas Piggin return; 353526cdce7SNicholas Piggin } 354526cdce7SNicholas Piggin if (ail == 1 || ail == 2) { 355526cdce7SNicholas Piggin /* AIL=1 and AIL=2 are reserved, treat them like AIL=0 */ 356526cdce7SNicholas Piggin return; 357526cdce7SNicholas Piggin } 3588b7e6b07SNicholas Piggin } 3598b7e6b07SNicholas Piggin 3608b7e6b07SNicholas Piggin /* 3618b7e6b07SNicholas Piggin * AIL applies, so the new MSR gets IR and DR set, and an offset applied 3628b7e6b07SNicholas Piggin * to the new IP. 3638b7e6b07SNicholas Piggin */ 3648b7e6b07SNicholas Piggin *new_msr |= (1 << MSR_IR) | (1 << MSR_DR); 3658b7e6b07SNicholas Piggin 3668b7e6b07SNicholas Piggin if (excp != POWERPC_EXCP_SYSCALL_VECTORED) { 3678b7e6b07SNicholas Piggin if (ail == 2) { 3688b7e6b07SNicholas Piggin *vector |= 0x0000000000018000ull; 3698b7e6b07SNicholas Piggin } else if (ail == 3) { 3708b7e6b07SNicholas Piggin *vector |= 0xc000000000004000ull; 3718b7e6b07SNicholas Piggin } 3728b7e6b07SNicholas Piggin } else { 3738b7e6b07SNicholas Piggin /* 3748b7e6b07SNicholas Piggin * scv AIL is a little different. AIL=2 does not change the address, 3758b7e6b07SNicholas Piggin * only the MSR. AIL=3 replaces the 0x17000 base with 0xc...3000. 3768b7e6b07SNicholas Piggin */ 3778b7e6b07SNicholas Piggin if (ail == 3) { 3788b7e6b07SNicholas Piggin *vector &= ~0x0000000000017000ull; /* Un-apply the base offset */ 3798b7e6b07SNicholas Piggin *vector |= 0xc000000000003000ull; /* Apply scv's AIL=3 offset */ 3808b7e6b07SNicholas Piggin } 3818b7e6b07SNicholas Piggin } 3822586a4d7SFabiano Rosas } 38328091374SFabiano Rosas #endif 384dead760bSBenjamin Herrenschmidt 3853680e994SNicholas Piggin static void powerpc_reset_excp_state(PowerPCCPU *cpu) 386ad77c6caSNicholas Piggin { 387ad77c6caSNicholas Piggin CPUState *cs = CPU(cpu); 388ad77c6caSNicholas Piggin CPUPPCState *env = &cpu->env; 389ad77c6caSNicholas Piggin 3903680e994SNicholas Piggin /* Reset exception state */ 3913680e994SNicholas Piggin cs->exception_index = POWERPC_EXCP_NONE; 3923680e994SNicholas Piggin env->error_code = 0; 3933680e994SNicholas Piggin } 3943680e994SNicholas Piggin 3953680e994SNicholas Piggin static void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector, 3963680e994SNicholas Piggin target_ulong msr) 3973680e994SNicholas Piggin { 3983680e994SNicholas Piggin CPUPPCState *env = &cpu->env; 3993680e994SNicholas Piggin 400fce9fbafSFabiano Rosas assert((msr & env->msr_mask) == msr); 401fce9fbafSFabiano Rosas 402ad77c6caSNicholas Piggin /* 403ad77c6caSNicholas Piggin * We don't use hreg_store_msr here as already have treated any 404ad77c6caSNicholas Piggin * special case that could occur. Just store MSR and update hflags 405ad77c6caSNicholas Piggin * 406ad77c6caSNicholas Piggin * Note: We *MUST* not use hreg_store_msr() as-is anyway because it 407ad77c6caSNicholas Piggin * will prevent setting of the HV bit which some exceptions might need 408ad77c6caSNicholas Piggin * to do. 409ad77c6caSNicholas Piggin */ 4103680e994SNicholas Piggin env->nip = vector; 411fce9fbafSFabiano Rosas env->msr = msr; 412ad77c6caSNicholas Piggin hreg_compute_hflags(env); 4132fdedcbcSMatheus Ferst ppc_maybe_interrupt(env); 414ad77c6caSNicholas Piggin 4153680e994SNicholas Piggin powerpc_reset_excp_state(cpu); 416ad77c6caSNicholas Piggin 417ad77c6caSNicholas Piggin /* 418ad77c6caSNicholas Piggin * Any interrupt is context synchronizing, check if TCG TLB needs 419ad77c6caSNicholas Piggin * a delayed flush on ppc64 420ad77c6caSNicholas Piggin */ 421ad77c6caSNicholas Piggin check_tlb_flush(env, false); 4223680e994SNicholas Piggin 4233680e994SNicholas Piggin /* Reset the reservation */ 4243680e994SNicholas Piggin env->reserve_addr = -1; 425ad77c6caSNicholas Piggin } 426ad77c6caSNicholas Piggin 427e808c2edSFabiano Rosas static void powerpc_excp_40x(PowerPCCPU *cpu, int excp) 428e808c2edSFabiano Rosas { 429e808c2edSFabiano Rosas CPUState *cs = CPU(cpu); 430e808c2edSFabiano Rosas CPUPPCState *env = &cpu->env; 431e808c2edSFabiano Rosas target_ulong msr, new_msr, vector; 4328428cdb2SFabiano Rosas int srr0, srr1; 433e808c2edSFabiano Rosas 434e808c2edSFabiano Rosas /* new srr1 value excluding must-be-zero bits */ 435e808c2edSFabiano Rosas msr = env->msr & ~0x783f0000ULL; 436e808c2edSFabiano Rosas 437e808c2edSFabiano Rosas /* 438495fc7ffSFabiano Rosas * new interrupt handler msr preserves existing ME unless 439495fc7ffSFabiano Rosas * explicitly overriden. 440e808c2edSFabiano Rosas */ 441495fc7ffSFabiano Rosas new_msr = env->msr & (((target_ulong)1 << MSR_ME)); 442e808c2edSFabiano Rosas 443e808c2edSFabiano Rosas /* target registers */ 444e808c2edSFabiano Rosas srr0 = SPR_SRR0; 445e808c2edSFabiano Rosas srr1 = SPR_SRR1; 446e808c2edSFabiano Rosas 447e808c2edSFabiano Rosas /* 448e808c2edSFabiano Rosas * Hypervisor emulation assistance interrupt only exists on server 449495fc7ffSFabiano Rosas * arch 2.05 server or later. 450e808c2edSFabiano Rosas */ 451495fc7ffSFabiano Rosas if (excp == POWERPC_EXCP_HV_EMU) { 452e808c2edSFabiano Rosas excp = POWERPC_EXCP_PROGRAM; 453e808c2edSFabiano Rosas } 454e808c2edSFabiano Rosas 455e808c2edSFabiano Rosas vector = env->excp_vectors[excp]; 456e808c2edSFabiano Rosas if (vector == (target_ulong)-1ULL) { 457e808c2edSFabiano Rosas cpu_abort(cs, "Raised an exception without defined vector %d\n", 458e808c2edSFabiano Rosas excp); 459e808c2edSFabiano Rosas } 460e808c2edSFabiano Rosas 461e808c2edSFabiano Rosas vector |= env->excp_prefix; 462e808c2edSFabiano Rosas 463e808c2edSFabiano Rosas switch (excp) { 464e808c2edSFabiano Rosas case POWERPC_EXCP_CRITICAL: /* Critical input */ 465e808c2edSFabiano Rosas srr0 = SPR_40x_SRR2; 466e808c2edSFabiano Rosas srr1 = SPR_40x_SRR3; 467e808c2edSFabiano Rosas break; 468e808c2edSFabiano Rosas case POWERPC_EXCP_MCHECK: /* Machine check exception */ 469c354d858SVíctor Colombo if (!FIELD_EX64(env->msr, MSR, ME)) { 470e808c2edSFabiano Rosas /* 471e808c2edSFabiano Rosas * Machine check exception is not enabled. Enter 472e808c2edSFabiano Rosas * checkstop state. 473e808c2edSFabiano Rosas */ 474e808c2edSFabiano Rosas fprintf(stderr, "Machine check while not allowed. " 475e808c2edSFabiano Rosas "Entering checkstop state\n"); 476e808c2edSFabiano Rosas if (qemu_log_separate()) { 477e808c2edSFabiano Rosas qemu_log("Machine check while not allowed. " 478e808c2edSFabiano Rosas "Entering checkstop state\n"); 479e808c2edSFabiano Rosas } 480e808c2edSFabiano Rosas cs->halted = 1; 481e808c2edSFabiano Rosas cpu_interrupt_exittb(cs); 482e808c2edSFabiano Rosas } 483e808c2edSFabiano Rosas 484e808c2edSFabiano Rosas /* machine check exceptions don't have ME set */ 485e808c2edSFabiano Rosas new_msr &= ~((target_ulong)1 << MSR_ME); 486e808c2edSFabiano Rosas 487e808c2edSFabiano Rosas srr0 = SPR_40x_SRR2; 488e808c2edSFabiano Rosas srr1 = SPR_40x_SRR3; 489e808c2edSFabiano Rosas break; 490e808c2edSFabiano Rosas case POWERPC_EXCP_DSI: /* Data storage exception */ 491f9911e1eSFabiano Rosas trace_ppc_excp_dsi(env->spr[SPR_40x_ESR], env->spr[SPR_40x_DEAR]); 492e808c2edSFabiano Rosas break; 493e808c2edSFabiano Rosas case POWERPC_EXCP_ISI: /* Instruction storage exception */ 494e808c2edSFabiano Rosas trace_ppc_excp_isi(msr, env->nip); 495e808c2edSFabiano Rosas break; 496e808c2edSFabiano Rosas case POWERPC_EXCP_EXTERNAL: /* External input */ 497e808c2edSFabiano Rosas break; 498e808c2edSFabiano Rosas case POWERPC_EXCP_ALIGN: /* Alignment exception */ 499e808c2edSFabiano Rosas break; 500e808c2edSFabiano Rosas case POWERPC_EXCP_PROGRAM: /* Program exception */ 501e808c2edSFabiano Rosas switch (env->error_code & ~0xF) { 502e808c2edSFabiano Rosas case POWERPC_EXCP_FP: 503da806a6cSVíctor Colombo if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { 504e808c2edSFabiano Rosas trace_ppc_excp_fp_ignore(); 5053680e994SNicholas Piggin powerpc_reset_excp_state(cpu); 506e808c2edSFabiano Rosas return; 507e808c2edSFabiano Rosas } 50864e62cfbSFabiano Rosas env->spr[SPR_40x_ESR] = ESR_FP; 509e808c2edSFabiano Rosas break; 510e808c2edSFabiano Rosas case POWERPC_EXCP_INVAL: 511e808c2edSFabiano Rosas trace_ppc_excp_inval(env->nip); 51264e62cfbSFabiano Rosas env->spr[SPR_40x_ESR] = ESR_PIL; 513e808c2edSFabiano Rosas break; 514e808c2edSFabiano Rosas case POWERPC_EXCP_PRIV: 51564e62cfbSFabiano Rosas env->spr[SPR_40x_ESR] = ESR_PPR; 516e808c2edSFabiano Rosas break; 517e808c2edSFabiano Rosas case POWERPC_EXCP_TRAP: 51864e62cfbSFabiano Rosas env->spr[SPR_40x_ESR] = ESR_PTR; 519e808c2edSFabiano Rosas break; 520e808c2edSFabiano Rosas default: 521e808c2edSFabiano Rosas cpu_abort(cs, "Invalid program exception %d. Aborting\n", 522e808c2edSFabiano Rosas env->error_code); 523e808c2edSFabiano Rosas break; 524e808c2edSFabiano Rosas } 525e808c2edSFabiano Rosas break; 526e808c2edSFabiano Rosas case POWERPC_EXCP_SYSCALL: /* System call exception */ 527e808c2edSFabiano Rosas dump_syscall(env); 528e808c2edSFabiano Rosas 529e808c2edSFabiano Rosas /* 530e808c2edSFabiano Rosas * We need to correct the NIP which in this case is supposed 531e808c2edSFabiano Rosas * to point to the next instruction 532e808c2edSFabiano Rosas */ 533e808c2edSFabiano Rosas env->nip += 4; 534e808c2edSFabiano Rosas break; 535e808c2edSFabiano Rosas case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ 536e808c2edSFabiano Rosas trace_ppc_excp_print("FIT"); 537e808c2edSFabiano Rosas break; 538e808c2edSFabiano Rosas case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ 539e808c2edSFabiano Rosas trace_ppc_excp_print("WDT"); 540e808c2edSFabiano Rosas break; 541e808c2edSFabiano Rosas case POWERPC_EXCP_DTLB: /* Data TLB error */ 542e808c2edSFabiano Rosas case POWERPC_EXCP_ITLB: /* Instruction TLB error */ 543e808c2edSFabiano Rosas break; 544e808c2edSFabiano Rosas case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ 545e808c2edSFabiano Rosas trace_ppc_excp_print("PIT"); 546e808c2edSFabiano Rosas break; 5474d8ac1d1SFabiano Rosas case POWERPC_EXCP_DEBUG: /* Debug interrupt */ 5484d8ac1d1SFabiano Rosas cpu_abort(cs, "%s exception not implemented\n", 5494d8ac1d1SFabiano Rosas powerpc_excp_name(excp)); 5504d8ac1d1SFabiano Rosas break; 551e808c2edSFabiano Rosas default: 552e808c2edSFabiano Rosas cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 553e808c2edSFabiano Rosas break; 554e808c2edSFabiano Rosas } 555e808c2edSFabiano Rosas 556e808c2edSFabiano Rosas /* Save PC */ 557e808c2edSFabiano Rosas env->spr[srr0] = env->nip; 558e808c2edSFabiano Rosas 559e808c2edSFabiano Rosas /* Save MSR */ 560e808c2edSFabiano Rosas env->spr[srr1] = msr; 561e808c2edSFabiano Rosas 562e808c2edSFabiano Rosas powerpc_set_excp_state(cpu, vector, new_msr); 563e808c2edSFabiano Rosas } 564e808c2edSFabiano Rosas 56558d178fbSFabiano Rosas static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp) 56658d178fbSFabiano Rosas { 56758d178fbSFabiano Rosas CPUState *cs = CPU(cpu); 56858d178fbSFabiano Rosas CPUPPCState *env = &cpu->env; 56958d178fbSFabiano Rosas target_ulong msr, new_msr, vector; 57058d178fbSFabiano Rosas 57158d178fbSFabiano Rosas /* new srr1 value excluding must-be-zero bits */ 57258d178fbSFabiano Rosas msr = env->msr & ~0x783f0000ULL; 57358d178fbSFabiano Rosas 57458d178fbSFabiano Rosas /* 575082d783bSFabiano Rosas * new interrupt handler msr preserves existing ME unless 57658d178fbSFabiano Rosas * explicitly overriden 57758d178fbSFabiano Rosas */ 578082d783bSFabiano Rosas new_msr = env->msr & ((target_ulong)1 << MSR_ME); 57958d178fbSFabiano Rosas 58058d178fbSFabiano Rosas /* 58158d178fbSFabiano Rosas * Hypervisor emulation assistance interrupt only exists on server 582082d783bSFabiano Rosas * arch 2.05 server or later. 58358d178fbSFabiano Rosas */ 584082d783bSFabiano Rosas if (excp == POWERPC_EXCP_HV_EMU) { 58558d178fbSFabiano Rosas excp = POWERPC_EXCP_PROGRAM; 58658d178fbSFabiano Rosas } 58758d178fbSFabiano Rosas 58858d178fbSFabiano Rosas vector = env->excp_vectors[excp]; 58958d178fbSFabiano Rosas if (vector == (target_ulong)-1ULL) { 59058d178fbSFabiano Rosas cpu_abort(cs, "Raised an exception without defined vector %d\n", 59158d178fbSFabiano Rosas excp); 59258d178fbSFabiano Rosas } 59358d178fbSFabiano Rosas 59458d178fbSFabiano Rosas vector |= env->excp_prefix; 59558d178fbSFabiano Rosas 59658d178fbSFabiano Rosas switch (excp) { 59758d178fbSFabiano Rosas case POWERPC_EXCP_CRITICAL: /* Critical input */ 59858d178fbSFabiano Rosas break; 59958d178fbSFabiano Rosas case POWERPC_EXCP_MCHECK: /* Machine check exception */ 600c354d858SVíctor Colombo if (!FIELD_EX64(env->msr, MSR, ME)) { 60158d178fbSFabiano Rosas /* 60258d178fbSFabiano Rosas * Machine check exception is not enabled. Enter 60358d178fbSFabiano Rosas * checkstop state. 60458d178fbSFabiano Rosas */ 60558d178fbSFabiano Rosas fprintf(stderr, "Machine check while not allowed. " 60658d178fbSFabiano Rosas "Entering checkstop state\n"); 60758d178fbSFabiano Rosas if (qemu_log_separate()) { 60858d178fbSFabiano Rosas qemu_log("Machine check while not allowed. " 60958d178fbSFabiano Rosas "Entering checkstop state\n"); 61058d178fbSFabiano Rosas } 61158d178fbSFabiano Rosas cs->halted = 1; 61258d178fbSFabiano Rosas cpu_interrupt_exittb(cs); 61358d178fbSFabiano Rosas } 61458d178fbSFabiano Rosas 61558d178fbSFabiano Rosas /* machine check exceptions don't have ME set */ 61658d178fbSFabiano Rosas new_msr &= ~((target_ulong)1 << MSR_ME); 61758d178fbSFabiano Rosas 61858d178fbSFabiano Rosas break; 61958d178fbSFabiano Rosas case POWERPC_EXCP_DSI: /* Data storage exception */ 62058d178fbSFabiano Rosas trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]); 62158d178fbSFabiano Rosas break; 62258d178fbSFabiano Rosas case POWERPC_EXCP_ISI: /* Instruction storage exception */ 62358d178fbSFabiano Rosas trace_ppc_excp_isi(msr, env->nip); 62458d178fbSFabiano Rosas msr |= env->error_code; 62558d178fbSFabiano Rosas break; 62658d178fbSFabiano Rosas case POWERPC_EXCP_EXTERNAL: /* External input */ 62758d178fbSFabiano Rosas break; 62858d178fbSFabiano Rosas case POWERPC_EXCP_ALIGN: /* Alignment exception */ 62958d178fbSFabiano Rosas /* Get rS/rD and rA from faulting opcode */ 63058d178fbSFabiano Rosas /* 63158d178fbSFabiano Rosas * Note: the opcode fields will not be set properly for a 63258d178fbSFabiano Rosas * direct store load/store, but nobody cares as nobody 63358d178fbSFabiano Rosas * actually uses direct store segments. 63458d178fbSFabiano Rosas */ 63558d178fbSFabiano Rosas env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; 63658d178fbSFabiano Rosas break; 63758d178fbSFabiano Rosas case POWERPC_EXCP_PROGRAM: /* Program exception */ 63858d178fbSFabiano Rosas switch (env->error_code & ~0xF) { 63958d178fbSFabiano Rosas case POWERPC_EXCP_FP: 640da806a6cSVíctor Colombo if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { 64158d178fbSFabiano Rosas trace_ppc_excp_fp_ignore(); 6423680e994SNicholas Piggin powerpc_reset_excp_state(cpu); 64358d178fbSFabiano Rosas return; 64458d178fbSFabiano Rosas } 64558d178fbSFabiano Rosas 64658d178fbSFabiano Rosas /* 64758d178fbSFabiano Rosas * FP exceptions always have NIP pointing to the faulting 64858d178fbSFabiano Rosas * instruction, so always use store_next and claim we are 64958d178fbSFabiano Rosas * precise in the MSR. 65058d178fbSFabiano Rosas */ 65158d178fbSFabiano Rosas msr |= 0x00100000; 65258d178fbSFabiano Rosas break; 65358d178fbSFabiano Rosas case POWERPC_EXCP_INVAL: 65458d178fbSFabiano Rosas trace_ppc_excp_inval(env->nip); 65558d178fbSFabiano Rosas msr |= 0x00080000; 65658d178fbSFabiano Rosas break; 65758d178fbSFabiano Rosas case POWERPC_EXCP_PRIV: 65858d178fbSFabiano Rosas msr |= 0x00040000; 65958d178fbSFabiano Rosas break; 66058d178fbSFabiano Rosas case POWERPC_EXCP_TRAP: 66158d178fbSFabiano Rosas msr |= 0x00020000; 66258d178fbSFabiano Rosas break; 66358d178fbSFabiano Rosas default: 66458d178fbSFabiano Rosas /* Should never occur */ 66558d178fbSFabiano Rosas cpu_abort(cs, "Invalid program exception %d. Aborting\n", 66658d178fbSFabiano Rosas env->error_code); 66758d178fbSFabiano Rosas break; 66858d178fbSFabiano Rosas } 66958d178fbSFabiano Rosas break; 67058d178fbSFabiano Rosas case POWERPC_EXCP_SYSCALL: /* System call exception */ 67158d178fbSFabiano Rosas dump_syscall(env); 67258d178fbSFabiano Rosas 67358d178fbSFabiano Rosas /* 67458d178fbSFabiano Rosas * We need to correct the NIP which in this case is supposed 67558d178fbSFabiano Rosas * to point to the next instruction 67658d178fbSFabiano Rosas */ 67758d178fbSFabiano Rosas env->nip += 4; 67858d178fbSFabiano Rosas break; 67958d178fbSFabiano Rosas case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 68058d178fbSFabiano Rosas case POWERPC_EXCP_DECR: /* Decrementer exception */ 68158d178fbSFabiano Rosas break; 68258d178fbSFabiano Rosas case POWERPC_EXCP_DTLB: /* Data TLB error */ 68358d178fbSFabiano Rosas case POWERPC_EXCP_ITLB: /* Instruction TLB error */ 68458d178fbSFabiano Rosas break; 68558d178fbSFabiano Rosas case POWERPC_EXCP_RESET: /* System reset exception */ 6868e54ad65SVíctor Colombo if (FIELD_EX64(env->msr, MSR, POW)) { 68758d178fbSFabiano Rosas cpu_abort(cs, "Trying to deliver power-saving system reset " 68858d178fbSFabiano Rosas "exception %d with no HV support\n", excp); 68958d178fbSFabiano Rosas } 69058d178fbSFabiano Rosas break; 69158d178fbSFabiano Rosas case POWERPC_EXCP_TRACE: /* Trace exception */ 69258d178fbSFabiano Rosas break; 69358d178fbSFabiano Rosas case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ 69458d178fbSFabiano Rosas case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ 69558d178fbSFabiano Rosas case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ 69658d178fbSFabiano Rosas /* Swap temporary saved registers with GPRs */ 69758d178fbSFabiano Rosas if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { 69858d178fbSFabiano Rosas new_msr |= (target_ulong)1 << MSR_TGPR; 69958d178fbSFabiano Rosas hreg_swap_gpr_tgpr(env); 70058d178fbSFabiano Rosas } 7018f8c7932SFabiano Rosas 70258d178fbSFabiano Rosas ppc_excp_debug_sw_tlb(env, excp); 70358d178fbSFabiano Rosas 70458d178fbSFabiano Rosas msr |= env->crf[0] << 28; 70558d178fbSFabiano Rosas msr |= env->error_code; /* key, D/I, S/L bits */ 70658d178fbSFabiano Rosas /* Set way using a LRU mechanism */ 70758d178fbSFabiano Rosas msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; 70858d178fbSFabiano Rosas break; 70958d178fbSFabiano Rosas case POWERPC_EXCP_FPA: /* Floating-point assist exception */ 71058d178fbSFabiano Rosas case POWERPC_EXCP_DABR: /* Data address breakpoint */ 71158d178fbSFabiano Rosas case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ 71258d178fbSFabiano Rosas case POWERPC_EXCP_SMI: /* System management interrupt */ 71358d178fbSFabiano Rosas case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ 71458d178fbSFabiano Rosas case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ 71558d178fbSFabiano Rosas cpu_abort(cs, "%s exception not implemented\n", 71658d178fbSFabiano Rosas powerpc_excp_name(excp)); 71758d178fbSFabiano Rosas break; 71858d178fbSFabiano Rosas default: 71958d178fbSFabiano Rosas cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 72058d178fbSFabiano Rosas break; 72158d178fbSFabiano Rosas } 72258d178fbSFabiano Rosas 72358d178fbSFabiano Rosas /* 72458d178fbSFabiano Rosas * Sort out endianness of interrupt, this differs depending on the 72558d178fbSFabiano Rosas * CPU, the HV mode, etc... 72658d178fbSFabiano Rosas */ 72758d178fbSFabiano Rosas if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) { 72858d178fbSFabiano Rosas new_msr |= (target_ulong)1 << MSR_LE; 72958d178fbSFabiano Rosas } 73058d178fbSFabiano Rosas 73158d178fbSFabiano Rosas /* Save PC */ 732c50eaed1SFabiano Rosas env->spr[SPR_SRR0] = env->nip; 73358d178fbSFabiano Rosas 73458d178fbSFabiano Rosas /* Save MSR */ 735c50eaed1SFabiano Rosas env->spr[SPR_SRR1] = msr; 73658d178fbSFabiano Rosas 73758d178fbSFabiano Rosas powerpc_set_excp_state(cpu, vector, new_msr); 73858d178fbSFabiano Rosas } 73958d178fbSFabiano Rosas 740ccfca2fcSFabiano Rosas static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp) 741ccfca2fcSFabiano Rosas { 742ccfca2fcSFabiano Rosas CPUState *cs = CPU(cpu); 743ccfca2fcSFabiano Rosas CPUPPCState *env = &cpu->env; 744ccfca2fcSFabiano Rosas target_ulong msr, new_msr, vector; 745ccfca2fcSFabiano Rosas 746ccfca2fcSFabiano Rosas /* new srr1 value excluding must-be-zero bits */ 747ccfca2fcSFabiano Rosas msr = env->msr & ~0x783f0000ULL; 748ccfca2fcSFabiano Rosas 749ccfca2fcSFabiano Rosas /* 75093848d6aSFabiano Rosas * new interrupt handler msr preserves existing ME unless 751ccfca2fcSFabiano Rosas * explicitly overriden 752ccfca2fcSFabiano Rosas */ 75393848d6aSFabiano Rosas new_msr = env->msr & ((target_ulong)1 << MSR_ME); 754ccfca2fcSFabiano Rosas 755ccfca2fcSFabiano Rosas /* 756ccfca2fcSFabiano Rosas * Hypervisor emulation assistance interrupt only exists on server 75793848d6aSFabiano Rosas * arch 2.05 server or later. 758ccfca2fcSFabiano Rosas */ 75993848d6aSFabiano Rosas if (excp == POWERPC_EXCP_HV_EMU) { 760ccfca2fcSFabiano Rosas excp = POWERPC_EXCP_PROGRAM; 761ccfca2fcSFabiano Rosas } 762ccfca2fcSFabiano Rosas 763ccfca2fcSFabiano Rosas vector = env->excp_vectors[excp]; 764ccfca2fcSFabiano Rosas if (vector == (target_ulong)-1ULL) { 765ccfca2fcSFabiano Rosas cpu_abort(cs, "Raised an exception without defined vector %d\n", 766ccfca2fcSFabiano Rosas excp); 767ccfca2fcSFabiano Rosas } 768ccfca2fcSFabiano Rosas 769ccfca2fcSFabiano Rosas vector |= env->excp_prefix; 770ccfca2fcSFabiano Rosas 771ccfca2fcSFabiano Rosas switch (excp) { 772ccfca2fcSFabiano Rosas case POWERPC_EXCP_MCHECK: /* Machine check exception */ 773c354d858SVíctor Colombo if (!FIELD_EX64(env->msr, MSR, ME)) { 774ccfca2fcSFabiano Rosas /* 775ccfca2fcSFabiano Rosas * Machine check exception is not enabled. Enter 776ccfca2fcSFabiano Rosas * checkstop state. 777ccfca2fcSFabiano Rosas */ 778ccfca2fcSFabiano Rosas fprintf(stderr, "Machine check while not allowed. " 779ccfca2fcSFabiano Rosas "Entering checkstop state\n"); 780ccfca2fcSFabiano Rosas if (qemu_log_separate()) { 781ccfca2fcSFabiano Rosas qemu_log("Machine check while not allowed. " 782ccfca2fcSFabiano Rosas "Entering checkstop state\n"); 783ccfca2fcSFabiano Rosas } 784ccfca2fcSFabiano Rosas cs->halted = 1; 785ccfca2fcSFabiano Rosas cpu_interrupt_exittb(cs); 786ccfca2fcSFabiano Rosas } 787ccfca2fcSFabiano Rosas 788ccfca2fcSFabiano Rosas /* machine check exceptions don't have ME set */ 789ccfca2fcSFabiano Rosas new_msr &= ~((target_ulong)1 << MSR_ME); 790ccfca2fcSFabiano Rosas 791ccfca2fcSFabiano Rosas break; 792ccfca2fcSFabiano Rosas case POWERPC_EXCP_DSI: /* Data storage exception */ 793ccfca2fcSFabiano Rosas trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]); 794ccfca2fcSFabiano Rosas break; 795ccfca2fcSFabiano Rosas case POWERPC_EXCP_ISI: /* Instruction storage exception */ 796ccfca2fcSFabiano Rosas trace_ppc_excp_isi(msr, env->nip); 797ccfca2fcSFabiano Rosas msr |= env->error_code; 798ccfca2fcSFabiano Rosas break; 799ccfca2fcSFabiano Rosas case POWERPC_EXCP_EXTERNAL: /* External input */ 800ccfca2fcSFabiano Rosas break; 801ccfca2fcSFabiano Rosas case POWERPC_EXCP_ALIGN: /* Alignment exception */ 802ccfca2fcSFabiano Rosas /* Get rS/rD and rA from faulting opcode */ 803ccfca2fcSFabiano Rosas /* 804ccfca2fcSFabiano Rosas * Note: the opcode fields will not be set properly for a 805ccfca2fcSFabiano Rosas * direct store load/store, but nobody cares as nobody 806ccfca2fcSFabiano Rosas * actually uses direct store segments. 807ccfca2fcSFabiano Rosas */ 808ccfca2fcSFabiano Rosas env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; 809ccfca2fcSFabiano Rosas break; 810ccfca2fcSFabiano Rosas case POWERPC_EXCP_PROGRAM: /* Program exception */ 811ccfca2fcSFabiano Rosas switch (env->error_code & ~0xF) { 812ccfca2fcSFabiano Rosas case POWERPC_EXCP_FP: 813da806a6cSVíctor Colombo if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { 814ccfca2fcSFabiano Rosas trace_ppc_excp_fp_ignore(); 8153680e994SNicholas Piggin powerpc_reset_excp_state(cpu); 816ccfca2fcSFabiano Rosas return; 817ccfca2fcSFabiano Rosas } 818ccfca2fcSFabiano Rosas 819ccfca2fcSFabiano Rosas /* 820ccfca2fcSFabiano Rosas * FP exceptions always have NIP pointing to the faulting 821ccfca2fcSFabiano Rosas * instruction, so always use store_next and claim we are 822ccfca2fcSFabiano Rosas * precise in the MSR. 823ccfca2fcSFabiano Rosas */ 824ccfca2fcSFabiano Rosas msr |= 0x00100000; 825ccfca2fcSFabiano Rosas break; 826ccfca2fcSFabiano Rosas case POWERPC_EXCP_INVAL: 827ccfca2fcSFabiano Rosas trace_ppc_excp_inval(env->nip); 828ccfca2fcSFabiano Rosas msr |= 0x00080000; 829ccfca2fcSFabiano Rosas break; 830ccfca2fcSFabiano Rosas case POWERPC_EXCP_PRIV: 831ccfca2fcSFabiano Rosas msr |= 0x00040000; 832ccfca2fcSFabiano Rosas break; 833ccfca2fcSFabiano Rosas case POWERPC_EXCP_TRAP: 834ccfca2fcSFabiano Rosas msr |= 0x00020000; 835ccfca2fcSFabiano Rosas break; 836ccfca2fcSFabiano Rosas default: 837ccfca2fcSFabiano Rosas /* Should never occur */ 838ccfca2fcSFabiano Rosas cpu_abort(cs, "Invalid program exception %d. Aborting\n", 839ccfca2fcSFabiano Rosas env->error_code); 840ccfca2fcSFabiano Rosas break; 841ccfca2fcSFabiano Rosas } 842ccfca2fcSFabiano Rosas break; 843ccfca2fcSFabiano Rosas case POWERPC_EXCP_SYSCALL: /* System call exception */ 8443b578635SFabiano Rosas { 8453b578635SFabiano Rosas int lev = env->error_code; 846ccfca2fcSFabiano Rosas 8473b578635SFabiano Rosas if (lev == 1 && cpu->vhyp) { 848ccfca2fcSFabiano Rosas dump_hcall(env); 849ccfca2fcSFabiano Rosas } else { 850ccfca2fcSFabiano Rosas dump_syscall(env); 851ccfca2fcSFabiano Rosas } 852ccfca2fcSFabiano Rosas 853ccfca2fcSFabiano Rosas /* 854ccfca2fcSFabiano Rosas * We need to correct the NIP which in this case is supposed 855ccfca2fcSFabiano Rosas * to point to the next instruction 856ccfca2fcSFabiano Rosas */ 857ccfca2fcSFabiano Rosas env->nip += 4; 858ccfca2fcSFabiano Rosas 8593b578635SFabiano Rosas /* 8603b578635SFabiano Rosas * The Virtual Open Firmware (VOF) relies on the 'sc 1' 8613b578635SFabiano Rosas * instruction to communicate with QEMU. The pegasos2 machine 8623b578635SFabiano Rosas * uses VOF and the 7xx CPUs, so although the 7xx don't have 8633b578635SFabiano Rosas * HV mode, we need to keep hypercall support. 8643b578635SFabiano Rosas */ 8653b578635SFabiano Rosas if (lev == 1 && cpu->vhyp) { 866ccfca2fcSFabiano Rosas PPCVirtualHypervisorClass *vhc = 867ccfca2fcSFabiano Rosas PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); 868ccfca2fcSFabiano Rosas vhc->hypercall(cpu->vhyp, cpu); 869ccfca2fcSFabiano Rosas return; 870ccfca2fcSFabiano Rosas } 8713b578635SFabiano Rosas 872ccfca2fcSFabiano Rosas break; 8733b578635SFabiano Rosas } 874ccfca2fcSFabiano Rosas case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 875ccfca2fcSFabiano Rosas case POWERPC_EXCP_DECR: /* Decrementer exception */ 876ccfca2fcSFabiano Rosas break; 877ccfca2fcSFabiano Rosas case POWERPC_EXCP_RESET: /* System reset exception */ 8788e54ad65SVíctor Colombo if (FIELD_EX64(env->msr, MSR, POW)) { 879ccfca2fcSFabiano Rosas cpu_abort(cs, "Trying to deliver power-saving system reset " 880ccfca2fcSFabiano Rosas "exception %d with no HV support\n", excp); 881ccfca2fcSFabiano Rosas } 882ccfca2fcSFabiano Rosas break; 883ccfca2fcSFabiano Rosas case POWERPC_EXCP_TRACE: /* Trace exception */ 884ccfca2fcSFabiano Rosas break; 885ccfca2fcSFabiano Rosas case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ 886ccfca2fcSFabiano Rosas case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ 887ccfca2fcSFabiano Rosas case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ 888ccfca2fcSFabiano Rosas ppc_excp_debug_sw_tlb(env, excp); 889ccfca2fcSFabiano Rosas 890ccfca2fcSFabiano Rosas msr |= env->crf[0] << 28; 891ccfca2fcSFabiano Rosas msr |= env->error_code; /* key, D/I, S/L bits */ 892ccfca2fcSFabiano Rosas /* Set way using a LRU mechanism */ 893ccfca2fcSFabiano Rosas msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; 8947df40c54SFabiano Rosas 895ccfca2fcSFabiano Rosas break; 896ccfca2fcSFabiano Rosas case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ 897ccfca2fcSFabiano Rosas case POWERPC_EXCP_SMI: /* System management interrupt */ 898ccfca2fcSFabiano Rosas case POWERPC_EXCP_THERM: /* Thermal interrupt */ 899ccfca2fcSFabiano Rosas case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ 900ccfca2fcSFabiano Rosas cpu_abort(cs, "%s exception not implemented\n", 901ccfca2fcSFabiano Rosas powerpc_excp_name(excp)); 902ccfca2fcSFabiano Rosas break; 903ccfca2fcSFabiano Rosas default: 904ccfca2fcSFabiano Rosas cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 905ccfca2fcSFabiano Rosas break; 906ccfca2fcSFabiano Rosas } 907ccfca2fcSFabiano Rosas 908ccfca2fcSFabiano Rosas /* 909ccfca2fcSFabiano Rosas * Sort out endianness of interrupt, this differs depending on the 910ccfca2fcSFabiano Rosas * CPU, the HV mode, etc... 911ccfca2fcSFabiano Rosas */ 912ccfca2fcSFabiano Rosas if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) { 913ccfca2fcSFabiano Rosas new_msr |= (target_ulong)1 << MSR_LE; 914ccfca2fcSFabiano Rosas } 915ccfca2fcSFabiano Rosas 916ccfca2fcSFabiano Rosas /* Save PC */ 917fe4b5c4cSFabiano Rosas env->spr[SPR_SRR0] = env->nip; 918ccfca2fcSFabiano Rosas 919ccfca2fcSFabiano Rosas /* Save MSR */ 920fe4b5c4cSFabiano Rosas env->spr[SPR_SRR1] = msr; 921ccfca2fcSFabiano Rosas 922ccfca2fcSFabiano Rosas powerpc_set_excp_state(cpu, vector, new_msr); 923ccfca2fcSFabiano Rosas } 924ccfca2fcSFabiano Rosas 92552926b0dSFabiano Rosas static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp) 92652926b0dSFabiano Rosas { 92752926b0dSFabiano Rosas CPUState *cs = CPU(cpu); 92852926b0dSFabiano Rosas CPUPPCState *env = &cpu->env; 92952926b0dSFabiano Rosas target_ulong msr, new_msr, vector; 93052926b0dSFabiano Rosas 93152926b0dSFabiano Rosas /* new srr1 value excluding must-be-zero bits */ 93252926b0dSFabiano Rosas msr = env->msr & ~0x783f0000ULL; 93352926b0dSFabiano Rosas 93452926b0dSFabiano Rosas /* 9351f6faf8bSFabiano Rosas * new interrupt handler msr preserves existing ME unless 93652926b0dSFabiano Rosas * explicitly overriden 93752926b0dSFabiano Rosas */ 9381f6faf8bSFabiano Rosas new_msr = env->msr & ((target_ulong)1 << MSR_ME); 93952926b0dSFabiano Rosas 94052926b0dSFabiano Rosas /* 94152926b0dSFabiano Rosas * Hypervisor emulation assistance interrupt only exists on server 9421f6faf8bSFabiano Rosas * arch 2.05 server or later. 94352926b0dSFabiano Rosas */ 9441f6faf8bSFabiano Rosas if (excp == POWERPC_EXCP_HV_EMU) { 94552926b0dSFabiano Rosas excp = POWERPC_EXCP_PROGRAM; 94652926b0dSFabiano Rosas } 94752926b0dSFabiano Rosas 94852926b0dSFabiano Rosas vector = env->excp_vectors[excp]; 94952926b0dSFabiano Rosas if (vector == (target_ulong)-1ULL) { 95052926b0dSFabiano Rosas cpu_abort(cs, "Raised an exception without defined vector %d\n", 95152926b0dSFabiano Rosas excp); 95252926b0dSFabiano Rosas } 95352926b0dSFabiano Rosas 95452926b0dSFabiano Rosas vector |= env->excp_prefix; 95552926b0dSFabiano Rosas 95652926b0dSFabiano Rosas switch (excp) { 95752926b0dSFabiano Rosas case POWERPC_EXCP_MCHECK: /* Machine check exception */ 958c354d858SVíctor Colombo if (!FIELD_EX64(env->msr, MSR, ME)) { 95952926b0dSFabiano Rosas /* 96052926b0dSFabiano Rosas * Machine check exception is not enabled. Enter 96152926b0dSFabiano Rosas * checkstop state. 96252926b0dSFabiano Rosas */ 96352926b0dSFabiano Rosas fprintf(stderr, "Machine check while not allowed. " 96452926b0dSFabiano Rosas "Entering checkstop state\n"); 96552926b0dSFabiano Rosas if (qemu_log_separate()) { 96652926b0dSFabiano Rosas qemu_log("Machine check while not allowed. " 96752926b0dSFabiano Rosas "Entering checkstop state\n"); 96852926b0dSFabiano Rosas } 96952926b0dSFabiano Rosas cs->halted = 1; 97052926b0dSFabiano Rosas cpu_interrupt_exittb(cs); 97152926b0dSFabiano Rosas } 97252926b0dSFabiano Rosas 97352926b0dSFabiano Rosas /* machine check exceptions don't have ME set */ 97452926b0dSFabiano Rosas new_msr &= ~((target_ulong)1 << MSR_ME); 97552926b0dSFabiano Rosas 97652926b0dSFabiano Rosas break; 97752926b0dSFabiano Rosas case POWERPC_EXCP_DSI: /* Data storage exception */ 97852926b0dSFabiano Rosas trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]); 97952926b0dSFabiano Rosas break; 98052926b0dSFabiano Rosas case POWERPC_EXCP_ISI: /* Instruction storage exception */ 98152926b0dSFabiano Rosas trace_ppc_excp_isi(msr, env->nip); 98252926b0dSFabiano Rosas msr |= env->error_code; 98352926b0dSFabiano Rosas break; 98452926b0dSFabiano Rosas case POWERPC_EXCP_EXTERNAL: /* External input */ 98552926b0dSFabiano Rosas break; 98652926b0dSFabiano Rosas case POWERPC_EXCP_ALIGN: /* Alignment exception */ 98752926b0dSFabiano Rosas /* Get rS/rD and rA from faulting opcode */ 98852926b0dSFabiano Rosas /* 98952926b0dSFabiano Rosas * Note: the opcode fields will not be set properly for a 99052926b0dSFabiano Rosas * direct store load/store, but nobody cares as nobody 99152926b0dSFabiano Rosas * actually uses direct store segments. 99252926b0dSFabiano Rosas */ 99352926b0dSFabiano Rosas env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; 99452926b0dSFabiano Rosas break; 99552926b0dSFabiano Rosas case POWERPC_EXCP_PROGRAM: /* Program exception */ 99652926b0dSFabiano Rosas switch (env->error_code & ~0xF) { 99752926b0dSFabiano Rosas case POWERPC_EXCP_FP: 998da806a6cSVíctor Colombo if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { 99952926b0dSFabiano Rosas trace_ppc_excp_fp_ignore(); 10003680e994SNicholas Piggin powerpc_reset_excp_state(cpu); 100152926b0dSFabiano Rosas return; 100252926b0dSFabiano Rosas } 100352926b0dSFabiano Rosas 100452926b0dSFabiano Rosas /* 100552926b0dSFabiano Rosas * FP exceptions always have NIP pointing to the faulting 100652926b0dSFabiano Rosas * instruction, so always use store_next and claim we are 100752926b0dSFabiano Rosas * precise in the MSR. 100852926b0dSFabiano Rosas */ 100952926b0dSFabiano Rosas msr |= 0x00100000; 101052926b0dSFabiano Rosas break; 101152926b0dSFabiano Rosas case POWERPC_EXCP_INVAL: 101252926b0dSFabiano Rosas trace_ppc_excp_inval(env->nip); 101352926b0dSFabiano Rosas msr |= 0x00080000; 101452926b0dSFabiano Rosas break; 101552926b0dSFabiano Rosas case POWERPC_EXCP_PRIV: 101652926b0dSFabiano Rosas msr |= 0x00040000; 101752926b0dSFabiano Rosas break; 101852926b0dSFabiano Rosas case POWERPC_EXCP_TRAP: 101952926b0dSFabiano Rosas msr |= 0x00020000; 102052926b0dSFabiano Rosas break; 102152926b0dSFabiano Rosas default: 102252926b0dSFabiano Rosas /* Should never occur */ 102352926b0dSFabiano Rosas cpu_abort(cs, "Invalid program exception %d. Aborting\n", 102452926b0dSFabiano Rosas env->error_code); 102552926b0dSFabiano Rosas break; 102652926b0dSFabiano Rosas } 102752926b0dSFabiano Rosas break; 102852926b0dSFabiano Rosas case POWERPC_EXCP_SYSCALL: /* System call exception */ 1029bca2c6d9SFabiano Rosas { 1030bca2c6d9SFabiano Rosas int lev = env->error_code; 103152926b0dSFabiano Rosas 10322306c606SBALATON Zoltan if (lev == 1 && cpu->vhyp) { 103352926b0dSFabiano Rosas dump_hcall(env); 103452926b0dSFabiano Rosas } else { 103552926b0dSFabiano Rosas dump_syscall(env); 103652926b0dSFabiano Rosas } 103752926b0dSFabiano Rosas 103852926b0dSFabiano Rosas /* 103952926b0dSFabiano Rosas * We need to correct the NIP which in this case is supposed 104052926b0dSFabiano Rosas * to point to the next instruction 104152926b0dSFabiano Rosas */ 104252926b0dSFabiano Rosas env->nip += 4; 104352926b0dSFabiano Rosas 1044bca2c6d9SFabiano Rosas /* 1045bca2c6d9SFabiano Rosas * The Virtual Open Firmware (VOF) relies on the 'sc 1' 1046bca2c6d9SFabiano Rosas * instruction to communicate with QEMU. The pegasos2 machine 1047bca2c6d9SFabiano Rosas * uses VOF and the 74xx CPUs, so although the 74xx don't have 1048bca2c6d9SFabiano Rosas * HV mode, we need to keep hypercall support. 1049bca2c6d9SFabiano Rosas */ 10502306c606SBALATON Zoltan if (lev == 1 && cpu->vhyp) { 105152926b0dSFabiano Rosas PPCVirtualHypervisorClass *vhc = 105252926b0dSFabiano Rosas PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); 105352926b0dSFabiano Rosas vhc->hypercall(cpu->vhyp, cpu); 105452926b0dSFabiano Rosas return; 105552926b0dSFabiano Rosas } 1056bca2c6d9SFabiano Rosas 105752926b0dSFabiano Rosas break; 1058bca2c6d9SFabiano Rosas } 105952926b0dSFabiano Rosas case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 106052926b0dSFabiano Rosas case POWERPC_EXCP_DECR: /* Decrementer exception */ 106152926b0dSFabiano Rosas break; 106252926b0dSFabiano Rosas case POWERPC_EXCP_RESET: /* System reset exception */ 10638e54ad65SVíctor Colombo if (FIELD_EX64(env->msr, MSR, POW)) { 106452926b0dSFabiano Rosas cpu_abort(cs, "Trying to deliver power-saving system reset " 106552926b0dSFabiano Rosas "exception %d with no HV support\n", excp); 106652926b0dSFabiano Rosas } 106752926b0dSFabiano Rosas break; 106852926b0dSFabiano Rosas case POWERPC_EXCP_TRACE: /* Trace exception */ 106952926b0dSFabiano Rosas break; 107052926b0dSFabiano Rosas case POWERPC_EXCP_VPU: /* Vector unavailable exception */ 107152926b0dSFabiano Rosas break; 107252926b0dSFabiano Rosas case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ 107352926b0dSFabiano Rosas case POWERPC_EXCP_SMI: /* System management interrupt */ 107452926b0dSFabiano Rosas case POWERPC_EXCP_THERM: /* Thermal interrupt */ 107552926b0dSFabiano Rosas case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ 107652926b0dSFabiano Rosas case POWERPC_EXCP_VPUA: /* Vector assist exception */ 107752926b0dSFabiano Rosas cpu_abort(cs, "%s exception not implemented\n", 107852926b0dSFabiano Rosas powerpc_excp_name(excp)); 107952926b0dSFabiano Rosas break; 108052926b0dSFabiano Rosas default: 108152926b0dSFabiano Rosas cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 108252926b0dSFabiano Rosas break; 108352926b0dSFabiano Rosas } 108452926b0dSFabiano Rosas 108552926b0dSFabiano Rosas /* 108652926b0dSFabiano Rosas * Sort out endianness of interrupt, this differs depending on the 108752926b0dSFabiano Rosas * CPU, the HV mode, etc... 108852926b0dSFabiano Rosas */ 108952926b0dSFabiano Rosas if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) { 109052926b0dSFabiano Rosas new_msr |= (target_ulong)1 << MSR_LE; 109152926b0dSFabiano Rosas } 109252926b0dSFabiano Rosas 109352926b0dSFabiano Rosas /* Save PC */ 1094f82db777SFabiano Rosas env->spr[SPR_SRR0] = env->nip; 109552926b0dSFabiano Rosas 109652926b0dSFabiano Rosas /* Save MSR */ 1097f82db777SFabiano Rosas env->spr[SPR_SRR1] = msr; 109852926b0dSFabiano Rosas 109952926b0dSFabiano Rosas powerpc_set_excp_state(cpu, vector, new_msr); 110052926b0dSFabiano Rosas } 110152926b0dSFabiano Rosas 1102180952ceSFabiano Rosas static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) 1103180952ceSFabiano Rosas { 1104180952ceSFabiano Rosas CPUState *cs = CPU(cpu); 1105180952ceSFabiano Rosas CPUPPCState *env = &cpu->env; 1106180952ceSFabiano Rosas target_ulong msr, new_msr, vector; 1107904e8428SFabiano Rosas int srr0, srr1; 1108180952ceSFabiano Rosas 1109180952ceSFabiano Rosas msr = env->msr; 1110180952ceSFabiano Rosas 1111180952ceSFabiano Rosas /* 11129dc20cc3SFabiano Rosas * new interrupt handler msr preserves existing ME unless 1113180952ceSFabiano Rosas * explicitly overriden 1114180952ceSFabiano Rosas */ 11159dc20cc3SFabiano Rosas new_msr = env->msr & ((target_ulong)1 << MSR_ME); 1116180952ceSFabiano Rosas 1117180952ceSFabiano Rosas /* target registers */ 1118180952ceSFabiano Rosas srr0 = SPR_SRR0; 1119180952ceSFabiano Rosas srr1 = SPR_SRR1; 1120180952ceSFabiano Rosas 1121180952ceSFabiano Rosas /* 1122180952ceSFabiano Rosas * Hypervisor emulation assistance interrupt only exists on server 11239dc20cc3SFabiano Rosas * arch 2.05 server or later. 1124180952ceSFabiano Rosas */ 11259dc20cc3SFabiano Rosas if (excp == POWERPC_EXCP_HV_EMU) { 1126180952ceSFabiano Rosas excp = POWERPC_EXCP_PROGRAM; 1127180952ceSFabiano Rosas } 1128180952ceSFabiano Rosas 1129180952ceSFabiano Rosas #ifdef TARGET_PPC64 1130180952ceSFabiano Rosas /* 1131180952ceSFabiano Rosas * SPEU and VPU share the same IVOR but they exist in different 1132180952ceSFabiano Rosas * processors. SPEU is e500v1/2 only and VPU is e6500 only. 1133180952ceSFabiano Rosas */ 11349dc20cc3SFabiano Rosas if (excp == POWERPC_EXCP_VPU) { 1135180952ceSFabiano Rosas excp = POWERPC_EXCP_SPEU; 1136180952ceSFabiano Rosas } 1137180952ceSFabiano Rosas #endif 1138180952ceSFabiano Rosas 1139180952ceSFabiano Rosas vector = env->excp_vectors[excp]; 1140180952ceSFabiano Rosas if (vector == (target_ulong)-1ULL) { 1141180952ceSFabiano Rosas cpu_abort(cs, "Raised an exception without defined vector %d\n", 1142180952ceSFabiano Rosas excp); 1143180952ceSFabiano Rosas } 1144180952ceSFabiano Rosas 1145180952ceSFabiano Rosas vector |= env->excp_prefix; 1146180952ceSFabiano Rosas 1147180952ceSFabiano Rosas switch (excp) { 1148180952ceSFabiano Rosas case POWERPC_EXCP_CRITICAL: /* Critical input */ 1149180952ceSFabiano Rosas srr0 = SPR_BOOKE_CSRR0; 1150180952ceSFabiano Rosas srr1 = SPR_BOOKE_CSRR1; 1151180952ceSFabiano Rosas break; 1152180952ceSFabiano Rosas case POWERPC_EXCP_MCHECK: /* Machine check exception */ 1153c354d858SVíctor Colombo if (!FIELD_EX64(env->msr, MSR, ME)) { 1154180952ceSFabiano Rosas /* 1155180952ceSFabiano Rosas * Machine check exception is not enabled. Enter 1156180952ceSFabiano Rosas * checkstop state. 1157180952ceSFabiano Rosas */ 1158180952ceSFabiano Rosas fprintf(stderr, "Machine check while not allowed. " 1159180952ceSFabiano Rosas "Entering checkstop state\n"); 1160180952ceSFabiano Rosas if (qemu_log_separate()) { 1161180952ceSFabiano Rosas qemu_log("Machine check while not allowed. " 1162180952ceSFabiano Rosas "Entering checkstop state\n"); 1163180952ceSFabiano Rosas } 1164180952ceSFabiano Rosas cs->halted = 1; 1165180952ceSFabiano Rosas cpu_interrupt_exittb(cs); 1166180952ceSFabiano Rosas } 1167180952ceSFabiano Rosas 1168180952ceSFabiano Rosas /* machine check exceptions don't have ME set */ 1169180952ceSFabiano Rosas new_msr &= ~((target_ulong)1 << MSR_ME); 1170180952ceSFabiano Rosas 1171180952ceSFabiano Rosas /* FIXME: choose one or the other based on CPU type */ 1172180952ceSFabiano Rosas srr0 = SPR_BOOKE_MCSRR0; 1173180952ceSFabiano Rosas srr1 = SPR_BOOKE_MCSRR1; 1174180952ceSFabiano Rosas 1175180952ceSFabiano Rosas env->spr[SPR_BOOKE_CSRR0] = env->nip; 1176180952ceSFabiano Rosas env->spr[SPR_BOOKE_CSRR1] = msr; 1177db403211SFabiano Rosas 1178180952ceSFabiano Rosas break; 1179180952ceSFabiano Rosas case POWERPC_EXCP_DSI: /* Data storage exception */ 1180afdbc869SFabiano Rosas trace_ppc_excp_dsi(env->spr[SPR_BOOKE_ESR], env->spr[SPR_BOOKE_DEAR]); 1181180952ceSFabiano Rosas break; 1182180952ceSFabiano Rosas case POWERPC_EXCP_ISI: /* Instruction storage exception */ 1183180952ceSFabiano Rosas trace_ppc_excp_isi(msr, env->nip); 1184180952ceSFabiano Rosas break; 1185180952ceSFabiano Rosas case POWERPC_EXCP_EXTERNAL: /* External input */ 1186180952ceSFabiano Rosas if (env->mpic_proxy) { 1187180952ceSFabiano Rosas /* IACK the IRQ on delivery */ 1188180952ceSFabiano Rosas env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack); 1189180952ceSFabiano Rosas } 1190180952ceSFabiano Rosas break; 1191180952ceSFabiano Rosas case POWERPC_EXCP_ALIGN: /* Alignment exception */ 1192180952ceSFabiano Rosas break; 1193180952ceSFabiano Rosas case POWERPC_EXCP_PROGRAM: /* Program exception */ 1194180952ceSFabiano Rosas switch (env->error_code & ~0xF) { 1195180952ceSFabiano Rosas case POWERPC_EXCP_FP: 1196da806a6cSVíctor Colombo if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { 1197180952ceSFabiano Rosas trace_ppc_excp_fp_ignore(); 11983680e994SNicholas Piggin powerpc_reset_excp_state(cpu); 1199180952ceSFabiano Rosas return; 1200180952ceSFabiano Rosas } 1201180952ceSFabiano Rosas 1202180952ceSFabiano Rosas /* 1203180952ceSFabiano Rosas * FP exceptions always have NIP pointing to the faulting 1204180952ceSFabiano Rosas * instruction, so always use store_next and claim we are 1205180952ceSFabiano Rosas * precise in the MSR. 1206180952ceSFabiano Rosas */ 1207180952ceSFabiano Rosas msr |= 0x00100000; 1208180952ceSFabiano Rosas env->spr[SPR_BOOKE_ESR] = ESR_FP; 1209180952ceSFabiano Rosas break; 1210180952ceSFabiano Rosas case POWERPC_EXCP_INVAL: 1211180952ceSFabiano Rosas trace_ppc_excp_inval(env->nip); 1212180952ceSFabiano Rosas msr |= 0x00080000; 1213180952ceSFabiano Rosas env->spr[SPR_BOOKE_ESR] = ESR_PIL; 1214180952ceSFabiano Rosas break; 1215180952ceSFabiano Rosas case POWERPC_EXCP_PRIV: 1216180952ceSFabiano Rosas msr |= 0x00040000; 1217180952ceSFabiano Rosas env->spr[SPR_BOOKE_ESR] = ESR_PPR; 1218180952ceSFabiano Rosas break; 1219180952ceSFabiano Rosas case POWERPC_EXCP_TRAP: 1220180952ceSFabiano Rosas msr |= 0x00020000; 1221180952ceSFabiano Rosas env->spr[SPR_BOOKE_ESR] = ESR_PTR; 1222180952ceSFabiano Rosas break; 1223180952ceSFabiano Rosas default: 1224180952ceSFabiano Rosas /* Should never occur */ 1225180952ceSFabiano Rosas cpu_abort(cs, "Invalid program exception %d. Aborting\n", 1226180952ceSFabiano Rosas env->error_code); 1227180952ceSFabiano Rosas break; 1228180952ceSFabiano Rosas } 1229180952ceSFabiano Rosas break; 1230180952ceSFabiano Rosas case POWERPC_EXCP_SYSCALL: /* System call exception */ 1231180952ceSFabiano Rosas dump_syscall(env); 1232180952ceSFabiano Rosas 1233180952ceSFabiano Rosas /* 1234180952ceSFabiano Rosas * We need to correct the NIP which in this case is supposed 1235180952ceSFabiano Rosas * to point to the next instruction 1236180952ceSFabiano Rosas */ 1237180952ceSFabiano Rosas env->nip += 4; 1238180952ceSFabiano Rosas break; 1239180952ceSFabiano Rosas case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 1240180952ceSFabiano Rosas case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ 1241180952ceSFabiano Rosas case POWERPC_EXCP_DECR: /* Decrementer exception */ 1242180952ceSFabiano Rosas break; 1243180952ceSFabiano Rosas case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ 1244180952ceSFabiano Rosas /* FIT on 4xx */ 1245180952ceSFabiano Rosas trace_ppc_excp_print("FIT"); 1246180952ceSFabiano Rosas break; 1247180952ceSFabiano Rosas case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ 1248180952ceSFabiano Rosas trace_ppc_excp_print("WDT"); 1249180952ceSFabiano Rosas srr0 = SPR_BOOKE_CSRR0; 1250180952ceSFabiano Rosas srr1 = SPR_BOOKE_CSRR1; 1251180952ceSFabiano Rosas break; 1252180952ceSFabiano Rosas case POWERPC_EXCP_DTLB: /* Data TLB error */ 1253180952ceSFabiano Rosas case POWERPC_EXCP_ITLB: /* Instruction TLB error */ 1254180952ceSFabiano Rosas break; 1255180952ceSFabiano Rosas case POWERPC_EXCP_DEBUG: /* Debug interrupt */ 1256180952ceSFabiano Rosas if (env->flags & POWERPC_FLAG_DE) { 1257180952ceSFabiano Rosas /* FIXME: choose one or the other based on CPU type */ 1258180952ceSFabiano Rosas srr0 = SPR_BOOKE_DSRR0; 1259180952ceSFabiano Rosas srr1 = SPR_BOOKE_DSRR1; 1260180952ceSFabiano Rosas 1261180952ceSFabiano Rosas env->spr[SPR_BOOKE_CSRR0] = env->nip; 1262180952ceSFabiano Rosas env->spr[SPR_BOOKE_CSRR1] = msr; 1263180952ceSFabiano Rosas 1264180952ceSFabiano Rosas /* DBSR already modified by caller */ 1265180952ceSFabiano Rosas } else { 1266180952ceSFabiano Rosas cpu_abort(cs, "Debug exception triggered on unsupported model\n"); 1267180952ceSFabiano Rosas } 1268180952ceSFabiano Rosas break; 1269180952ceSFabiano Rosas case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable/VPU */ 1270180952ceSFabiano Rosas env->spr[SPR_BOOKE_ESR] = ESR_SPV; 1271180952ceSFabiano Rosas break; 12729364df26SNicholas Piggin case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ 12739364df26SNicholas Piggin break; 12749364df26SNicholas Piggin case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ 12759364df26SNicholas Piggin srr0 = SPR_BOOKE_CSRR0; 12769364df26SNicholas Piggin srr1 = SPR_BOOKE_CSRR1; 12779364df26SNicholas Piggin break; 1278180952ceSFabiano Rosas case POWERPC_EXCP_RESET: /* System reset exception */ 12798e54ad65SVíctor Colombo if (FIELD_EX64(env->msr, MSR, POW)) { 1280180952ceSFabiano Rosas cpu_abort(cs, "Trying to deliver power-saving system reset " 1281180952ceSFabiano Rosas "exception %d with no HV support\n", excp); 1282180952ceSFabiano Rosas } 1283180952ceSFabiano Rosas break; 1284180952ceSFabiano Rosas case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ 1285180952ceSFabiano Rosas case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ 1286180952ceSFabiano Rosas cpu_abort(cs, "%s exception not implemented\n", 1287180952ceSFabiano Rosas powerpc_excp_name(excp)); 1288180952ceSFabiano Rosas break; 1289180952ceSFabiano Rosas default: 1290180952ceSFabiano Rosas cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 1291180952ceSFabiano Rosas break; 1292180952ceSFabiano Rosas } 1293180952ceSFabiano Rosas 1294180952ceSFabiano Rosas #if defined(TARGET_PPC64) 1295180952ceSFabiano Rosas if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) { 1296180952ceSFabiano Rosas /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */ 1297180952ceSFabiano Rosas new_msr |= (target_ulong)1 << MSR_CM; 1298180952ceSFabiano Rosas } else { 1299180952ceSFabiano Rosas vector = (uint32_t)vector; 1300180952ceSFabiano Rosas } 1301180952ceSFabiano Rosas #endif 1302180952ceSFabiano Rosas 1303180952ceSFabiano Rosas /* Save PC */ 1304180952ceSFabiano Rosas env->spr[srr0] = env->nip; 1305180952ceSFabiano Rosas 1306180952ceSFabiano Rosas /* Save MSR */ 1307180952ceSFabiano Rosas env->spr[srr1] = msr; 1308180952ceSFabiano Rosas 1309180952ceSFabiano Rosas powerpc_set_excp_state(cpu, vector, new_msr); 1310180952ceSFabiano Rosas } 1311180952ceSFabiano Rosas 13127cebc5dbSNicholas Piggin /* 13137cebc5dbSNicholas Piggin * When running a nested HV guest under vhyp, external interrupts are 13147cebc5dbSNicholas Piggin * delivered as HVIRT. 13157cebc5dbSNicholas Piggin */ 13167cebc5dbSNicholas Piggin static bool books_vhyp_promotes_external_to_hvirt(PowerPCCPU *cpu) 13177cebc5dbSNicholas Piggin { 13187cebc5dbSNicholas Piggin if (cpu->vhyp) { 13197cebc5dbSNicholas Piggin return vhyp_cpu_in_nested(cpu); 13207cebc5dbSNicholas Piggin } 13217cebc5dbSNicholas Piggin return false; 13227cebc5dbSNicholas Piggin } 13237cebc5dbSNicholas Piggin 132430c4e426SFabiano Rosas #ifdef TARGET_PPC64 13254c6cf6b2SNicholas Piggin /* 13264c6cf6b2SNicholas Piggin * When running under vhyp, hcalls are always intercepted and sent to the 13274c6cf6b2SNicholas Piggin * vhc->hypercall handler. 13284c6cf6b2SNicholas Piggin */ 13294c6cf6b2SNicholas Piggin static bool books_vhyp_handles_hcall(PowerPCCPU *cpu) 13304c6cf6b2SNicholas Piggin { 13314c6cf6b2SNicholas Piggin if (cpu->vhyp) { 13327cebc5dbSNicholas Piggin return !vhyp_cpu_in_nested(cpu); 13337cebc5dbSNicholas Piggin } 13347cebc5dbSNicholas Piggin return false; 13357cebc5dbSNicholas Piggin } 13367cebc5dbSNicholas Piggin 13377cebc5dbSNicholas Piggin /* 13387cebc5dbSNicholas Piggin * When running a nested KVM HV guest under vhyp, HV exceptions are not 13397cebc5dbSNicholas Piggin * delivered to the guest (because there is no concept of HV support), but 13407cebc5dbSNicholas Piggin * rather they are sent tothe vhyp to exit from the L2 back to the L1 and 13417cebc5dbSNicholas Piggin * return from the H_ENTER_NESTED hypercall. 13427cebc5dbSNicholas Piggin */ 13437cebc5dbSNicholas Piggin static bool books_vhyp_handles_hv_excp(PowerPCCPU *cpu) 13447cebc5dbSNicholas Piggin { 13457cebc5dbSNicholas Piggin if (cpu->vhyp) { 13467cebc5dbSNicholas Piggin return vhyp_cpu_in_nested(cpu); 13474c6cf6b2SNicholas Piggin } 13484c6cf6b2SNicholas Piggin return false; 13494c6cf6b2SNicholas Piggin } 13504c6cf6b2SNicholas Piggin 13515a5d3b23SNicholas Piggin #ifdef CONFIG_TCG 13525a5d3b23SNicholas Piggin static bool is_prefix_insn(CPUPPCState *env, uint32_t insn) 13535a5d3b23SNicholas Piggin { 13545a5d3b23SNicholas Piggin if (!(env->insns_flags2 & PPC2_ISA310)) { 13555a5d3b23SNicholas Piggin return false; 13565a5d3b23SNicholas Piggin } 13575a5d3b23SNicholas Piggin return ((insn & 0xfc000000) == 0x04000000); 13585a5d3b23SNicholas Piggin } 13595a5d3b23SNicholas Piggin 13605a5d3b23SNicholas Piggin static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp) 13615a5d3b23SNicholas Piggin { 13625a5d3b23SNicholas Piggin CPUPPCState *env = &cpu->env; 13635a5d3b23SNicholas Piggin 13645a5d3b23SNicholas Piggin if (!tcg_enabled()) { 13655a5d3b23SNicholas Piggin /* 13665a5d3b23SNicholas Piggin * This does not load instructions and set the prefix bit correctly 13675a5d3b23SNicholas Piggin * for injected interrupts with KVM. That may have to be discovered 13685a5d3b23SNicholas Piggin * and set by the KVM layer before injecting. 13695a5d3b23SNicholas Piggin */ 13705a5d3b23SNicholas Piggin return false; 13715a5d3b23SNicholas Piggin } 13725a5d3b23SNicholas Piggin 13735a5d3b23SNicholas Piggin switch (excp) { 13745a5d3b23SNicholas Piggin case POWERPC_EXCP_HDSI: 13755a5d3b23SNicholas Piggin /* HDSI PRTABLE_FAULT has the originating access type in error_code */ 13765a5d3b23SNicholas Piggin if ((env->spr[SPR_HDSISR] & DSISR_PRTABLE_FAULT) && 13775a5d3b23SNicholas Piggin (env->error_code == MMU_INST_FETCH)) { 13785a5d3b23SNicholas Piggin /* 13795a5d3b23SNicholas Piggin * Fetch failed due to partition scope translation, so prefix 13805a5d3b23SNicholas Piggin * indication is not relevant (and attempting to load the 13815a5d3b23SNicholas Piggin * instruction at NIP would cause recursive faults with the same 13825a5d3b23SNicholas Piggin * translation). 13835a5d3b23SNicholas Piggin */ 13845a5d3b23SNicholas Piggin break; 13855a5d3b23SNicholas Piggin } 13865a5d3b23SNicholas Piggin /* fall through */ 13875a5d3b23SNicholas Piggin case POWERPC_EXCP_MCHECK: 13885a5d3b23SNicholas Piggin case POWERPC_EXCP_DSI: 13895a5d3b23SNicholas Piggin case POWERPC_EXCP_DSEG: 13905a5d3b23SNicholas Piggin case POWERPC_EXCP_ALIGN: 13915a5d3b23SNicholas Piggin case POWERPC_EXCP_PROGRAM: 13925a5d3b23SNicholas Piggin case POWERPC_EXCP_FPU: 13935a5d3b23SNicholas Piggin case POWERPC_EXCP_TRACE: 13945a5d3b23SNicholas Piggin case POWERPC_EXCP_HV_EMU: 13955a5d3b23SNicholas Piggin case POWERPC_EXCP_VPU: 13965a5d3b23SNicholas Piggin case POWERPC_EXCP_VSXU: 13975a5d3b23SNicholas Piggin case POWERPC_EXCP_FU: 13985a5d3b23SNicholas Piggin case POWERPC_EXCP_HV_FU: { 13995a5d3b23SNicholas Piggin uint32_t insn = ppc_ldl_code(env, env->nip); 14005a5d3b23SNicholas Piggin if (is_prefix_insn(env, insn)) { 14015a5d3b23SNicholas Piggin return true; 14025a5d3b23SNicholas Piggin } 14035a5d3b23SNicholas Piggin break; 14045a5d3b23SNicholas Piggin } 14055a5d3b23SNicholas Piggin default: 14065a5d3b23SNicholas Piggin break; 14075a5d3b23SNicholas Piggin } 14085a5d3b23SNicholas Piggin return false; 14095a5d3b23SNicholas Piggin } 14105a5d3b23SNicholas Piggin #else 14115a5d3b23SNicholas Piggin static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp) 14125a5d3b23SNicholas Piggin { 14135a5d3b23SNicholas Piggin return false; 14145a5d3b23SNicholas Piggin } 14155a5d3b23SNicholas Piggin #endif 14165a5d3b23SNicholas Piggin 14179f338e4dSFabiano Rosas static void powerpc_excp_books(PowerPCCPU *cpu, int excp) 14189f338e4dSFabiano Rosas { 14199f338e4dSFabiano Rosas CPUState *cs = CPU(cpu); 14209f338e4dSFabiano Rosas CPUPPCState *env = &cpu->env; 14219f338e4dSFabiano Rosas target_ulong msr, new_msr, vector; 14229f338e4dSFabiano Rosas int srr0, srr1, lev = -1; 14239f338e4dSFabiano Rosas 14249f338e4dSFabiano Rosas /* new srr1 value excluding must-be-zero bits */ 14259f338e4dSFabiano Rosas msr = env->msr & ~0x783f0000ULL; 14269f338e4dSFabiano Rosas 14279f338e4dSFabiano Rosas /* 14289f338e4dSFabiano Rosas * new interrupt handler msr preserves existing HV and ME unless 14299f338e4dSFabiano Rosas * explicitly overriden 14309f338e4dSFabiano Rosas */ 14319f338e4dSFabiano Rosas new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB); 14329f338e4dSFabiano Rosas 14339f338e4dSFabiano Rosas /* target registers */ 14349f338e4dSFabiano Rosas srr0 = SPR_SRR0; 14359f338e4dSFabiano Rosas srr1 = SPR_SRR1; 14369f338e4dSFabiano Rosas 14379f338e4dSFabiano Rosas /* 14389f338e4dSFabiano Rosas * check for special resume at 0x100 from doze/nap/sleep/winkle on 14399f338e4dSFabiano Rosas * P7/P8/P9 14409f338e4dSFabiano Rosas */ 14419f338e4dSFabiano Rosas if (env->resume_as_sreset) { 1442*3f88a89dSBALATON Zoltan excp = powerpc_reset_wakeup(env, excp, &msr); 14439f338e4dSFabiano Rosas } 14449f338e4dSFabiano Rosas 14459f338e4dSFabiano Rosas /* 144630c4e426SFabiano Rosas * We don't want to generate a Hypervisor Emulation Assistance 14476c242e79SNicholas Piggin * Interrupt if we don't have HVB in msr_mask (PAPR mode), 14486c242e79SNicholas Piggin * unless running a nested-hv guest, in which case the L1 14496c242e79SNicholas Piggin * kernel wants the interrupt. 14509f338e4dSFabiano Rosas */ 14516c242e79SNicholas Piggin if (excp == POWERPC_EXCP_HV_EMU && !(env->msr_mask & MSR_HVB) && 14526c242e79SNicholas Piggin !books_vhyp_handles_hv_excp(cpu)) { 14539f338e4dSFabiano Rosas excp = POWERPC_EXCP_PROGRAM; 14549f338e4dSFabiano Rosas } 14559f338e4dSFabiano Rosas 14569f338e4dSFabiano Rosas vector = env->excp_vectors[excp]; 14579f338e4dSFabiano Rosas if (vector == (target_ulong)-1ULL) { 14589f338e4dSFabiano Rosas cpu_abort(cs, "Raised an exception without defined vector %d\n", 14599f338e4dSFabiano Rosas excp); 14609f338e4dSFabiano Rosas } 14619f338e4dSFabiano Rosas 14629f338e4dSFabiano Rosas vector |= env->excp_prefix; 14639f338e4dSFabiano Rosas 14645a5d3b23SNicholas Piggin if (is_prefix_insn_excp(cpu, excp)) { 14655a5d3b23SNicholas Piggin msr |= PPC_BIT(34); 14665a5d3b23SNicholas Piggin } 14675a5d3b23SNicholas Piggin 14689f338e4dSFabiano Rosas switch (excp) { 14699f338e4dSFabiano Rosas case POWERPC_EXCP_MCHECK: /* Machine check exception */ 1470c354d858SVíctor Colombo if (!FIELD_EX64(env->msr, MSR, ME)) { 14719f338e4dSFabiano Rosas /* 14729f338e4dSFabiano Rosas * Machine check exception is not enabled. Enter 14739f338e4dSFabiano Rosas * checkstop state. 14749f338e4dSFabiano Rosas */ 14759f338e4dSFabiano Rosas fprintf(stderr, "Machine check while not allowed. " 14769f338e4dSFabiano Rosas "Entering checkstop state\n"); 14779f338e4dSFabiano Rosas if (qemu_log_separate()) { 14789f338e4dSFabiano Rosas qemu_log("Machine check while not allowed. " 14799f338e4dSFabiano Rosas "Entering checkstop state\n"); 14809f338e4dSFabiano Rosas } 14819f338e4dSFabiano Rosas cs->halted = 1; 14829f338e4dSFabiano Rosas cpu_interrupt_exittb(cs); 14839f338e4dSFabiano Rosas } 14849f338e4dSFabiano Rosas if (env->msr_mask & MSR_HVB) { 14859f338e4dSFabiano Rosas /* 14869f338e4dSFabiano Rosas * ISA specifies HV, but can be delivered to guest with HV 14879f338e4dSFabiano Rosas * clear (e.g., see FWNMI in PAPR). 14889f338e4dSFabiano Rosas */ 14899f338e4dSFabiano Rosas new_msr |= (target_ulong)MSR_HVB; 14909f338e4dSFabiano Rosas } 14919f338e4dSFabiano Rosas 14929f338e4dSFabiano Rosas /* machine check exceptions don't have ME set */ 14939f338e4dSFabiano Rosas new_msr &= ~((target_ulong)1 << MSR_ME); 14949f338e4dSFabiano Rosas 14959f338e4dSFabiano Rosas break; 14969f338e4dSFabiano Rosas case POWERPC_EXCP_DSI: /* Data storage exception */ 14979f338e4dSFabiano Rosas trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]); 14989f338e4dSFabiano Rosas break; 14999f338e4dSFabiano Rosas case POWERPC_EXCP_ISI: /* Instruction storage exception */ 15009f338e4dSFabiano Rosas trace_ppc_excp_isi(msr, env->nip); 15019f338e4dSFabiano Rosas msr |= env->error_code; 15029f338e4dSFabiano Rosas break; 15039f338e4dSFabiano Rosas case POWERPC_EXCP_EXTERNAL: /* External input */ 15049f338e4dSFabiano Rosas { 15059f338e4dSFabiano Rosas bool lpes0; 15069f338e4dSFabiano Rosas 15079f338e4dSFabiano Rosas /* 150867baff77SFabiano Rosas * LPES0 is only taken into consideration if we support HV 150967baff77SFabiano Rosas * mode for this CPU. 15109f338e4dSFabiano Rosas */ 151167baff77SFabiano Rosas if (!env->has_hv_mode) { 151267baff77SFabiano Rosas break; 15139f338e4dSFabiano Rosas } 15149f338e4dSFabiano Rosas 151567baff77SFabiano Rosas lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 151667baff77SFabiano Rosas 15179f338e4dSFabiano Rosas if (!lpes0) { 15189f338e4dSFabiano Rosas new_msr |= (target_ulong)MSR_HVB; 15199f338e4dSFabiano Rosas new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 15209f338e4dSFabiano Rosas srr0 = SPR_HSRR0; 15219f338e4dSFabiano Rosas srr1 = SPR_HSRR1; 15229f338e4dSFabiano Rosas } 152367baff77SFabiano Rosas 15249f338e4dSFabiano Rosas break; 15259f338e4dSFabiano Rosas } 15269f338e4dSFabiano Rosas case POWERPC_EXCP_ALIGN: /* Alignment exception */ 15274ee5d281SNicholas Piggin /* Optional DSISR update was removed from ISA v3.0 */ 15284ee5d281SNicholas Piggin if (!(env->insns_flags2 & PPC2_ISA300)) { 15299f338e4dSFabiano Rosas /* Get rS/rD and rA from faulting opcode */ 15309f338e4dSFabiano Rosas /* 15319f338e4dSFabiano Rosas * Note: the opcode fields will not be set properly for a 15329f338e4dSFabiano Rosas * direct store load/store, but nobody cares as nobody 15339f338e4dSFabiano Rosas * actually uses direct store segments. 15349f338e4dSFabiano Rosas */ 15359f338e4dSFabiano Rosas env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; 15364ee5d281SNicholas Piggin } 15379f338e4dSFabiano Rosas break; 15389f338e4dSFabiano Rosas case POWERPC_EXCP_PROGRAM: /* Program exception */ 15399f338e4dSFabiano Rosas switch (env->error_code & ~0xF) { 15409f338e4dSFabiano Rosas case POWERPC_EXCP_FP: 1541da806a6cSVíctor Colombo if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) { 15429f338e4dSFabiano Rosas trace_ppc_excp_fp_ignore(); 15433680e994SNicholas Piggin powerpc_reset_excp_state(cpu); 15449f338e4dSFabiano Rosas return; 15459f338e4dSFabiano Rosas } 15469f338e4dSFabiano Rosas 15479f338e4dSFabiano Rosas /* 15489f338e4dSFabiano Rosas * FP exceptions always have NIP pointing to the faulting 15499f338e4dSFabiano Rosas * instruction, so always use store_next and claim we are 15509f338e4dSFabiano Rosas * precise in the MSR. 15519f338e4dSFabiano Rosas */ 15529f338e4dSFabiano Rosas msr |= 0x00100000; 15539f338e4dSFabiano Rosas break; 15549f338e4dSFabiano Rosas case POWERPC_EXCP_INVAL: 15559f338e4dSFabiano Rosas trace_ppc_excp_inval(env->nip); 15569f338e4dSFabiano Rosas msr |= 0x00080000; 15579f338e4dSFabiano Rosas break; 15589f338e4dSFabiano Rosas case POWERPC_EXCP_PRIV: 15599f338e4dSFabiano Rosas msr |= 0x00040000; 15609f338e4dSFabiano Rosas break; 15619f338e4dSFabiano Rosas case POWERPC_EXCP_TRAP: 15629f338e4dSFabiano Rosas msr |= 0x00020000; 15639f338e4dSFabiano Rosas break; 15649f338e4dSFabiano Rosas default: 15659f338e4dSFabiano Rosas /* Should never occur */ 15669f338e4dSFabiano Rosas cpu_abort(cs, "Invalid program exception %d. Aborting\n", 15679f338e4dSFabiano Rosas env->error_code); 15689f338e4dSFabiano Rosas break; 15699f338e4dSFabiano Rosas } 15709f338e4dSFabiano Rosas break; 15719f338e4dSFabiano Rosas case POWERPC_EXCP_SYSCALL: /* System call exception */ 15729f338e4dSFabiano Rosas lev = env->error_code; 15739f338e4dSFabiano Rosas 15742306c606SBALATON Zoltan if (lev == 1 && cpu->vhyp) { 15759f338e4dSFabiano Rosas dump_hcall(env); 15769f338e4dSFabiano Rosas } else { 15779f338e4dSFabiano Rosas dump_syscall(env); 15789f338e4dSFabiano Rosas } 15799f338e4dSFabiano Rosas 15809f338e4dSFabiano Rosas /* 15819f338e4dSFabiano Rosas * We need to correct the NIP which in this case is supposed 15829f338e4dSFabiano Rosas * to point to the next instruction 15839f338e4dSFabiano Rosas */ 15849f338e4dSFabiano Rosas env->nip += 4; 15859f338e4dSFabiano Rosas 15869f338e4dSFabiano Rosas /* "PAPR mode" built-in hypercall emulation */ 15872306c606SBALATON Zoltan if (lev == 1 && books_vhyp_handles_hcall(cpu)) { 15889f338e4dSFabiano Rosas PPCVirtualHypervisorClass *vhc = 15899f338e4dSFabiano Rosas PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); 15909f338e4dSFabiano Rosas vhc->hypercall(cpu->vhyp, cpu); 15919f338e4dSFabiano Rosas return; 15929f338e4dSFabiano Rosas } 1593eb701f30SNicholas Piggin if (env->insns_flags2 & PPC2_ISA310) { 1594eb701f30SNicholas Piggin /* ISAv3.1 puts LEV into SRR1 */ 1595eb701f30SNicholas Piggin msr |= lev << 20; 1596eb701f30SNicholas Piggin } 15979f338e4dSFabiano Rosas if (lev == 1) { 15989f338e4dSFabiano Rosas new_msr |= (target_ulong)MSR_HVB; 15999f338e4dSFabiano Rosas } 16009f338e4dSFabiano Rosas break; 16019f338e4dSFabiano Rosas case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */ 16029f338e4dSFabiano Rosas lev = env->error_code; 16039f338e4dSFabiano Rosas dump_syscall(env); 16049f338e4dSFabiano Rosas env->nip += 4; 16059f338e4dSFabiano Rosas new_msr |= env->msr & ((target_ulong)1 << MSR_EE); 16069f338e4dSFabiano Rosas new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 16079f338e4dSFabiano Rosas 16089f338e4dSFabiano Rosas vector += lev * 0x20; 16099f338e4dSFabiano Rosas 16109f338e4dSFabiano Rosas env->lr = env->nip; 16119f338e4dSFabiano Rosas env->ctr = msr; 16129f338e4dSFabiano Rosas break; 16139f338e4dSFabiano Rosas case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 16149f338e4dSFabiano Rosas case POWERPC_EXCP_DECR: /* Decrementer exception */ 16159f338e4dSFabiano Rosas break; 16169f338e4dSFabiano Rosas case POWERPC_EXCP_RESET: /* System reset exception */ 16179f338e4dSFabiano Rosas /* A power-saving exception sets ME, otherwise it is unchanged */ 16188e54ad65SVíctor Colombo if (FIELD_EX64(env->msr, MSR, POW)) { 16199f338e4dSFabiano Rosas /* indicate that we resumed from power save mode */ 16209f338e4dSFabiano Rosas msr |= 0x10000; 16219f338e4dSFabiano Rosas new_msr |= ((target_ulong)1 << MSR_ME); 16229f338e4dSFabiano Rosas } 16239f338e4dSFabiano Rosas if (env->msr_mask & MSR_HVB) { 16249f338e4dSFabiano Rosas /* 16259f338e4dSFabiano Rosas * ISA specifies HV, but can be delivered to guest with HV 16269f338e4dSFabiano Rosas * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU). 16279f338e4dSFabiano Rosas */ 16289f338e4dSFabiano Rosas new_msr |= (target_ulong)MSR_HVB; 16299f338e4dSFabiano Rosas } else { 16308e54ad65SVíctor Colombo if (FIELD_EX64(env->msr, MSR, POW)) { 16319f338e4dSFabiano Rosas cpu_abort(cs, "Trying to deliver power-saving system reset " 16329f338e4dSFabiano Rosas "exception %d with no HV support\n", excp); 16339f338e4dSFabiano Rosas } 16349f338e4dSFabiano Rosas } 16359f338e4dSFabiano Rosas break; 16369f338e4dSFabiano Rosas case POWERPC_EXCP_DSEG: /* Data segment exception */ 16379f338e4dSFabiano Rosas case POWERPC_EXCP_ISEG: /* Instruction segment exception */ 16389f338e4dSFabiano Rosas case POWERPC_EXCP_TRACE: /* Trace exception */ 1639fd7abfabSNicholas Piggin case POWERPC_EXCP_SDOOR: /* Doorbell interrupt */ 1640c29b0704SNicholas Piggin case POWERPC_EXCP_PERFM: /* Performance monitor interrupt */ 16419f338e4dSFabiano Rosas break; 16429f338e4dSFabiano Rosas case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ 16439f338e4dSFabiano Rosas msr |= env->error_code; 16449f338e4dSFabiano Rosas /* fall through */ 16459f338e4dSFabiano Rosas case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ 16469f338e4dSFabiano Rosas case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ 16479f338e4dSFabiano Rosas case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ 16489f338e4dSFabiano Rosas case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */ 16499f338e4dSFabiano Rosas srr0 = SPR_HSRR0; 16509f338e4dSFabiano Rosas srr1 = SPR_HSRR1; 16519f338e4dSFabiano Rosas new_msr |= (target_ulong)MSR_HVB; 16529f338e4dSFabiano Rosas new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 16539f338e4dSFabiano Rosas break; 1654a3c020d8SNicholas Piggin #ifdef CONFIG_TCG 1655a3c020d8SNicholas Piggin case POWERPC_EXCP_HV_EMU: { 1656a3c020d8SNicholas Piggin uint32_t insn = ppc_ldl_code(env, env->nip); 1657a3c020d8SNicholas Piggin env->spr[SPR_HEIR] = insn; 1658a3c020d8SNicholas Piggin if (is_prefix_insn(env, insn)) { 1659a3c020d8SNicholas Piggin uint32_t insn2 = ppc_ldl_code(env, env->nip + 4); 1660a3c020d8SNicholas Piggin env->spr[SPR_HEIR] <<= 32; 1661a3c020d8SNicholas Piggin env->spr[SPR_HEIR] |= insn2; 1662a3c020d8SNicholas Piggin } 1663a3c020d8SNicholas Piggin srr0 = SPR_HSRR0; 1664a3c020d8SNicholas Piggin srr1 = SPR_HSRR1; 1665a3c020d8SNicholas Piggin new_msr |= (target_ulong)MSR_HVB; 1666a3c020d8SNicholas Piggin new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 1667a3c020d8SNicholas Piggin break; 1668a3c020d8SNicholas Piggin } 1669a3c020d8SNicholas Piggin #endif 16709f338e4dSFabiano Rosas case POWERPC_EXCP_VPU: /* Vector unavailable exception */ 16719f338e4dSFabiano Rosas case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ 16729f338e4dSFabiano Rosas case POWERPC_EXCP_FU: /* Facility unavailable exception */ 16739f338e4dSFabiano Rosas env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56); 16749f338e4dSFabiano Rosas break; 16759f338e4dSFabiano Rosas case POWERPC_EXCP_HV_FU: /* Hypervisor Facility Unavailable Exception */ 16769f338e4dSFabiano Rosas env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS); 16779f338e4dSFabiano Rosas srr0 = SPR_HSRR0; 16789f338e4dSFabiano Rosas srr1 = SPR_HSRR1; 16799f338e4dSFabiano Rosas new_msr |= (target_ulong)MSR_HVB; 16809f338e4dSFabiano Rosas new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 16819f338e4dSFabiano Rosas break; 1682cb76bbc4SDaniel Henrique Barboza case POWERPC_EXCP_PERFM_EBB: /* Performance Monitor EBB Exception */ 1683cb76bbc4SDaniel Henrique Barboza case POWERPC_EXCP_EXTERNAL_EBB: /* External EBB Exception */ 1684cb76bbc4SDaniel Henrique Barboza env->spr[SPR_BESCR] &= ~BESCR_GE; 1685cb76bbc4SDaniel Henrique Barboza 1686cb76bbc4SDaniel Henrique Barboza /* 1687cb76bbc4SDaniel Henrique Barboza * Save NIP for rfebb insn in SPR_EBBRR. Next nip is 1688cb76bbc4SDaniel Henrique Barboza * stored in the EBB Handler SPR_EBBHR. 1689cb76bbc4SDaniel Henrique Barboza */ 1690cb76bbc4SDaniel Henrique Barboza env->spr[SPR_EBBRR] = env->nip; 1691cb76bbc4SDaniel Henrique Barboza powerpc_set_excp_state(cpu, env->spr[SPR_EBBHR], env->msr); 1692cb76bbc4SDaniel Henrique Barboza 1693cb76bbc4SDaniel Henrique Barboza /* 1694cb76bbc4SDaniel Henrique Barboza * This exception is handled in userspace. No need to proceed. 1695cb76bbc4SDaniel Henrique Barboza */ 1696cb76bbc4SDaniel Henrique Barboza return; 16979f338e4dSFabiano Rosas case POWERPC_EXCP_THERM: /* Thermal interrupt */ 16989f338e4dSFabiano Rosas case POWERPC_EXCP_VPUA: /* Vector assist exception */ 16999f338e4dSFabiano Rosas case POWERPC_EXCP_MAINT: /* Maintenance exception */ 170030c4e426SFabiano Rosas case POWERPC_EXCP_HV_MAINT: /* Hypervisor Maintenance exception */ 17019f338e4dSFabiano Rosas cpu_abort(cs, "%s exception not implemented\n", 17029f338e4dSFabiano Rosas powerpc_excp_name(excp)); 17039f338e4dSFabiano Rosas break; 17049f338e4dSFabiano Rosas default: 17059f338e4dSFabiano Rosas cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 17069f338e4dSFabiano Rosas break; 17079f338e4dSFabiano Rosas } 17089f338e4dSFabiano Rosas 17099f338e4dSFabiano Rosas /* 17109f338e4dSFabiano Rosas * Sort out endianness of interrupt, this differs depending on the 17119f338e4dSFabiano Rosas * CPU, the HV mode, etc... 17129f338e4dSFabiano Rosas */ 17139f338e4dSFabiano Rosas if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) { 17149f338e4dSFabiano Rosas new_msr |= (target_ulong)1 << MSR_LE; 17159f338e4dSFabiano Rosas } 17169f338e4dSFabiano Rosas 17179f338e4dSFabiano Rosas new_msr |= (target_ulong)1 << MSR_SF; 17189f338e4dSFabiano Rosas 17199f338e4dSFabiano Rosas if (excp != POWERPC_EXCP_SYSCALL_VECTORED) { 17209f338e4dSFabiano Rosas /* Save PC */ 17219f338e4dSFabiano Rosas env->spr[srr0] = env->nip; 17229f338e4dSFabiano Rosas 17239f338e4dSFabiano Rosas /* Save MSR */ 17249f338e4dSFabiano Rosas env->spr[srr1] = msr; 17259f338e4dSFabiano Rosas } 17269f338e4dSFabiano Rosas 17277cebc5dbSNicholas Piggin if ((new_msr & MSR_HVB) && books_vhyp_handles_hv_excp(cpu)) { 17287cebc5dbSNicholas Piggin PPCVirtualHypervisorClass *vhc = 17297cebc5dbSNicholas Piggin PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); 17307cebc5dbSNicholas Piggin /* Deliver interrupt to L1 by returning from the H_ENTER_NESTED call */ 17317cebc5dbSNicholas Piggin vhc->deliver_hv_excp(cpu, excp); 17327cebc5dbSNicholas Piggin 17337cebc5dbSNicholas Piggin powerpc_reset_excp_state(cpu); 17347cebc5dbSNicholas Piggin 17357cebc5dbSNicholas Piggin } else { 17367cebc5dbSNicholas Piggin /* Sanity check */ 17377cebc5dbSNicholas Piggin if (!(env->msr_mask & MSR_HVB) && srr0 == SPR_HSRR0) { 17387cebc5dbSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with " 17397cebc5dbSNicholas Piggin "no HV support\n", excp); 17407cebc5dbSNicholas Piggin } 17417cebc5dbSNicholas Piggin 17429f338e4dSFabiano Rosas /* This can update new_msr and vector if AIL applies */ 174310895ab6SFabiano Rosas ppc_excp_apply_ail(cpu, excp, msr, &new_msr, &vector); 17449f338e4dSFabiano Rosas 17459f338e4dSFabiano Rosas powerpc_set_excp_state(cpu, vector, new_msr); 17469f338e4dSFabiano Rosas } 17477cebc5dbSNicholas Piggin } 174830c4e426SFabiano Rosas #else 174930c4e426SFabiano Rosas static inline void powerpc_excp_books(PowerPCCPU *cpu, int excp) 175030c4e426SFabiano Rosas { 175130c4e426SFabiano Rosas g_assert_not_reached(); 175230c4e426SFabiano Rosas } 175330c4e426SFabiano Rosas #endif 17549f338e4dSFabiano Rosas 1755dc88dd0aSFabiano Rosas static void powerpc_excp(PowerPCCPU *cpu, int excp) 1756dc88dd0aSFabiano Rosas { 1757c6eaac89SFabiano Rosas CPUState *cs = CPU(cpu); 1758dc88dd0aSFabiano Rosas CPUPPCState *env = &cpu->env; 1759dc88dd0aSFabiano Rosas 1760c6eaac89SFabiano Rosas if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) { 1761c6eaac89SFabiano Rosas cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 1762c6eaac89SFabiano Rosas } 1763c6eaac89SFabiano Rosas 1764c6eaac89SFabiano Rosas qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx 1765c6eaac89SFabiano Rosas " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp), 1766c6eaac89SFabiano Rosas excp, env->error_code); 17678a15cceeSBALATON Zoltan env->excp_stats[excp]++; 1768c6eaac89SFabiano Rosas 1769dc88dd0aSFabiano Rosas switch (env->excp_model) { 1770e808c2edSFabiano Rosas case POWERPC_EXCP_40x: 1771e808c2edSFabiano Rosas powerpc_excp_40x(cpu, excp); 1772e808c2edSFabiano Rosas break; 177358d178fbSFabiano Rosas case POWERPC_EXCP_6xx: 177458d178fbSFabiano Rosas powerpc_excp_6xx(cpu, excp); 177558d178fbSFabiano Rosas break; 1776ccfca2fcSFabiano Rosas case POWERPC_EXCP_7xx: 1777ccfca2fcSFabiano Rosas powerpc_excp_7xx(cpu, excp); 1778ccfca2fcSFabiano Rosas break; 177952926b0dSFabiano Rosas case POWERPC_EXCP_74xx: 178052926b0dSFabiano Rosas powerpc_excp_74xx(cpu, excp); 178152926b0dSFabiano Rosas break; 1782180952ceSFabiano Rosas case POWERPC_EXCP_BOOKE: 1783180952ceSFabiano Rosas powerpc_excp_booke(cpu, excp); 1784180952ceSFabiano Rosas break; 17859f338e4dSFabiano Rosas case POWERPC_EXCP_970: 17869f338e4dSFabiano Rosas case POWERPC_EXCP_POWER7: 17879f338e4dSFabiano Rosas case POWERPC_EXCP_POWER8: 17889f338e4dSFabiano Rosas case POWERPC_EXCP_POWER9: 17899f338e4dSFabiano Rosas case POWERPC_EXCP_POWER10: 17909f338e4dSFabiano Rosas powerpc_excp_books(cpu, excp); 17919f338e4dSFabiano Rosas break; 1792dc88dd0aSFabiano Rosas default: 179328091374SFabiano Rosas g_assert_not_reached(); 1794dc88dd0aSFabiano Rosas } 1795dc88dd0aSFabiano Rosas } 1796dc88dd0aSFabiano Rosas 179797a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs) 1798c79c73f6SBlue Swirl { 179997a8ea5aSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 18005c26a5b3SAndreas Färber 180193130c84SFabiano Rosas powerpc_excp(cpu, cs->exception_index); 1802c79c73f6SBlue Swirl } 1803c79c73f6SBlue Swirl 18042dfecf01SMatheus Ferst #if defined(TARGET_PPC64) 1805c8e1de2eSMatheus Ferst #define P7_UNUSED_INTERRUPTS \ 1806c8e1de2eSMatheus Ferst (PPC_INTERRUPT_RESET | PPC_INTERRUPT_HVIRT | PPC_INTERRUPT_CEXT | \ 1807c8e1de2eSMatheus Ferst PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT | \ 1808c8e1de2eSMatheus Ferst PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL | PPC_INTERRUPT_HDOORBELL | \ 1809c8e1de2eSMatheus Ferst PPC_INTERRUPT_THERM | PPC_INTERRUPT_EBB) 1810c8e1de2eSMatheus Ferst 18119c713713SMatheus Ferst static int p7_interrupt_powersave(CPUPPCState *env) 18129c713713SMatheus Ferst { 18139c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && 18149c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) { 18159c713713SMatheus Ferst return PPC_INTERRUPT_EXT; 18169c713713SMatheus Ferst } 18179c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && 18189c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) { 18199c713713SMatheus Ferst return PPC_INTERRUPT_DECR; 18209c713713SMatheus Ferst } 18219c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && 18229c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { 18239c713713SMatheus Ferst return PPC_INTERRUPT_MCK; 18249c713713SMatheus Ferst } 18259c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && 18269c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { 18279c713713SMatheus Ferst return PPC_INTERRUPT_HMI; 18289c713713SMatheus Ferst } 18299c713713SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_RESET) { 18309c713713SMatheus Ferst return PPC_INTERRUPT_RESET; 18319c713713SMatheus Ferst } 18329c713713SMatheus Ferst return 0; 18339c713713SMatheus Ferst } 18349c713713SMatheus Ferst 1835bf303fb3SMatheus Ferst static int p7_next_unmasked_interrupt(CPUPPCState *env) 1836bf303fb3SMatheus Ferst { 1837022b7128SMatheus Ferst PowerPCCPU *cpu = env_archcpu(env); 1838022b7128SMatheus Ferst CPUState *cs = CPU(cpu); 1839022b7128SMatheus Ferst /* Ignore MSR[EE] when coming out of some power management states */ 1840022b7128SMatheus Ferst bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; 1841bf303fb3SMatheus Ferst 1842c8e1de2eSMatheus Ferst assert((env->pending_interrupts & P7_UNUSED_INTERRUPTS) == 0); 1843c8e1de2eSMatheus Ferst 1844022b7128SMatheus Ferst if (cs->halted) { 1845022b7128SMatheus Ferst /* LPCR[PECE] controls which interrupts can exit power-saving mode */ 1846022b7128SMatheus Ferst return p7_interrupt_powersave(env); 1847022b7128SMatheus Ferst } 1848022b7128SMatheus Ferst 1849bf303fb3SMatheus Ferst /* Machine check exception */ 1850bf303fb3SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_MCK) { 1851bf303fb3SMatheus Ferst return PPC_INTERRUPT_MCK; 1852bf303fb3SMatheus Ferst } 1853bf303fb3SMatheus Ferst 1854bf303fb3SMatheus Ferst /* Hypervisor decrementer exception */ 1855bf303fb3SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { 1856bf303fb3SMatheus Ferst /* LPCR will be clear when not supported so this will work */ 1857bf303fb3SMatheus Ferst bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); 1858022b7128SMatheus Ferst if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) { 1859bf303fb3SMatheus Ferst /* HDEC clears on delivery */ 1860bf303fb3SMatheus Ferst return PPC_INTERRUPT_HDECR; 1861bf303fb3SMatheus Ferst } 1862bf303fb3SMatheus Ferst } 1863bf303fb3SMatheus Ferst 1864bf303fb3SMatheus Ferst /* External interrupt can ignore MSR:EE under some circumstances */ 1865bf303fb3SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_EXT) { 1866bf303fb3SMatheus Ferst bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 1867bf303fb3SMatheus Ferst bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); 1868bf303fb3SMatheus Ferst /* HEIC blocks delivery to the hypervisor */ 1869022b7128SMatheus Ferst if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) && 1870bf303fb3SMatheus Ferst !FIELD_EX64(env->msr, MSR, PR))) || 1871bf303fb3SMatheus Ferst (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { 1872bf303fb3SMatheus Ferst return PPC_INTERRUPT_EXT; 1873bf303fb3SMatheus Ferst } 1874bf303fb3SMatheus Ferst } 1875022b7128SMatheus Ferst if (msr_ee != 0) { 1876bf303fb3SMatheus Ferst /* Decrementer exception */ 1877bf303fb3SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_DECR) { 1878bf303fb3SMatheus Ferst return PPC_INTERRUPT_DECR; 1879bf303fb3SMatheus Ferst } 1880bf303fb3SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { 1881bf303fb3SMatheus Ferst return PPC_INTERRUPT_PERFM; 1882bf303fb3SMatheus Ferst } 1883bf303fb3SMatheus Ferst } 1884bf303fb3SMatheus Ferst 1885bf303fb3SMatheus Ferst return 0; 1886bf303fb3SMatheus Ferst } 1887bf303fb3SMatheus Ferst 1888f6194fddSMatheus Ferst #define P8_UNUSED_INTERRUPTS \ 1889f6194fddSMatheus Ferst (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_HVIRT | \ 1890f6194fddSMatheus Ferst PPC_INTERRUPT_CEXT | PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | \ 1891f6194fddSMatheus Ferst PPC_INTERRUPT_FIT | PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM) 1892f6194fddSMatheus Ferst 18939c713713SMatheus Ferst static int p8_interrupt_powersave(CPUPPCState *env) 18949c713713SMatheus Ferst { 18959c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && 18969c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) { 18979c713713SMatheus Ferst return PPC_INTERRUPT_EXT; 18989c713713SMatheus Ferst } 18999c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && 19009c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) { 19019c713713SMatheus Ferst return PPC_INTERRUPT_DECR; 19029c713713SMatheus Ferst } 19039c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && 19049c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { 19059c713713SMatheus Ferst return PPC_INTERRUPT_MCK; 19069c713713SMatheus Ferst } 19079c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && 19089c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { 19099c713713SMatheus Ferst return PPC_INTERRUPT_HMI; 19109c713713SMatheus Ferst } 19119c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && 19129c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) { 19139c713713SMatheus Ferst return PPC_INTERRUPT_DOORBELL; 19149c713713SMatheus Ferst } 19159c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && 19169c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) { 19179c713713SMatheus Ferst return PPC_INTERRUPT_HDOORBELL; 19189c713713SMatheus Ferst } 19199c713713SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_RESET) { 19209c713713SMatheus Ferst return PPC_INTERRUPT_RESET; 19219c713713SMatheus Ferst } 19229c713713SMatheus Ferst return 0; 19239c713713SMatheus Ferst } 19249c713713SMatheus Ferst 1925a9899d42SMatheus Ferst static int p8_next_unmasked_interrupt(CPUPPCState *env) 1926a9899d42SMatheus Ferst { 192764a9b5eeSMatheus Ferst PowerPCCPU *cpu = env_archcpu(env); 192864a9b5eeSMatheus Ferst CPUState *cs = CPU(cpu); 192964a9b5eeSMatheus Ferst /* Ignore MSR[EE] when coming out of some power management states */ 193064a9b5eeSMatheus Ferst bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; 1931a9899d42SMatheus Ferst 1932f6194fddSMatheus Ferst assert((env->pending_interrupts & P8_UNUSED_INTERRUPTS) == 0); 1933f6194fddSMatheus Ferst 193464a9b5eeSMatheus Ferst if (cs->halted) { 193564a9b5eeSMatheus Ferst /* LPCR[PECE] controls which interrupts can exit power-saving mode */ 193664a9b5eeSMatheus Ferst return p8_interrupt_powersave(env); 193764a9b5eeSMatheus Ferst } 193864a9b5eeSMatheus Ferst 1939a9899d42SMatheus Ferst /* Machine check exception */ 1940a9899d42SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_MCK) { 1941a9899d42SMatheus Ferst return PPC_INTERRUPT_MCK; 1942a9899d42SMatheus Ferst } 1943a9899d42SMatheus Ferst 1944a9899d42SMatheus Ferst /* Hypervisor decrementer exception */ 1945a9899d42SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { 1946a9899d42SMatheus Ferst /* LPCR will be clear when not supported so this will work */ 1947a9899d42SMatheus Ferst bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); 194864a9b5eeSMatheus Ferst if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) { 1949a9899d42SMatheus Ferst /* HDEC clears on delivery */ 1950a9899d42SMatheus Ferst return PPC_INTERRUPT_HDECR; 1951a9899d42SMatheus Ferst } 1952a9899d42SMatheus Ferst } 1953a9899d42SMatheus Ferst 1954a9899d42SMatheus Ferst /* External interrupt can ignore MSR:EE under some circumstances */ 1955a9899d42SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_EXT) { 1956a9899d42SMatheus Ferst bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 1957a9899d42SMatheus Ferst bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); 1958a9899d42SMatheus Ferst /* HEIC blocks delivery to the hypervisor */ 195964a9b5eeSMatheus Ferst if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) && 1960a9899d42SMatheus Ferst !FIELD_EX64(env->msr, MSR, PR))) || 1961a9899d42SMatheus Ferst (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { 1962a9899d42SMatheus Ferst return PPC_INTERRUPT_EXT; 1963a9899d42SMatheus Ferst } 1964a9899d42SMatheus Ferst } 196564a9b5eeSMatheus Ferst if (msr_ee != 0) { 1966a9899d42SMatheus Ferst /* Decrementer exception */ 1967a9899d42SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_DECR) { 1968a9899d42SMatheus Ferst return PPC_INTERRUPT_DECR; 1969a9899d42SMatheus Ferst } 1970a9899d42SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { 1971a9899d42SMatheus Ferst return PPC_INTERRUPT_DOORBELL; 1972a9899d42SMatheus Ferst } 1973a9899d42SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) { 1974a9899d42SMatheus Ferst return PPC_INTERRUPT_HDOORBELL; 1975a9899d42SMatheus Ferst } 1976a9899d42SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { 1977a9899d42SMatheus Ferst return PPC_INTERRUPT_PERFM; 1978a9899d42SMatheus Ferst } 1979a9899d42SMatheus Ferst /* EBB exception */ 1980a9899d42SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_EBB) { 1981a9899d42SMatheus Ferst /* 1982a9899d42SMatheus Ferst * EBB exception must be taken in problem state and 1983a9899d42SMatheus Ferst * with BESCR_GE set. 1984a9899d42SMatheus Ferst */ 1985a9899d42SMatheus Ferst if (FIELD_EX64(env->msr, MSR, PR) && 1986a9899d42SMatheus Ferst (env->spr[SPR_BESCR] & BESCR_GE)) { 1987a9899d42SMatheus Ferst return PPC_INTERRUPT_EBB; 1988a9899d42SMatheus Ferst } 1989a9899d42SMatheus Ferst } 1990a9899d42SMatheus Ferst } 1991a9899d42SMatheus Ferst 1992a9899d42SMatheus Ferst return 0; 1993a9899d42SMatheus Ferst } 1994a9899d42SMatheus Ferst 1995b00e9a2fSMatheus Ferst #define P9_UNUSED_INTERRUPTS \ 1996b00e9a2fSMatheus Ferst (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_CEXT | \ 1997b00e9a2fSMatheus Ferst PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT | \ 1998b00e9a2fSMatheus Ferst PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM) 1999b00e9a2fSMatheus Ferst 20009c713713SMatheus Ferst static int p9_interrupt_powersave(CPUPPCState *env) 20019c713713SMatheus Ferst { 20029c713713SMatheus Ferst /* External Exception */ 20039c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && 20049c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_EEE)) { 20059c713713SMatheus Ferst bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); 20069c713713SMatheus Ferst if (!heic || !FIELD_EX64_HV(env->msr) || 20079c713713SMatheus Ferst FIELD_EX64(env->msr, MSR, PR)) { 20089c713713SMatheus Ferst return PPC_INTERRUPT_EXT; 20099c713713SMatheus Ferst } 20109c713713SMatheus Ferst } 20119c713713SMatheus Ferst /* Decrementer Exception */ 20129c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && 20139c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_DEE)) { 20149c713713SMatheus Ferst return PPC_INTERRUPT_DECR; 20159c713713SMatheus Ferst } 20169c713713SMatheus Ferst /* Machine Check or Hypervisor Maintenance Exception */ 20179c713713SMatheus Ferst if (env->spr[SPR_LPCR] & LPCR_OEE) { 20189c713713SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_MCK) { 20199c713713SMatheus Ferst return PPC_INTERRUPT_MCK; 20209c713713SMatheus Ferst } 20219c713713SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_HMI) { 20229c713713SMatheus Ferst return PPC_INTERRUPT_HMI; 20239c713713SMatheus Ferst } 20249c713713SMatheus Ferst } 20259c713713SMatheus Ferst /* Privileged Doorbell Exception */ 20269c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && 20279c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_PDEE)) { 20289c713713SMatheus Ferst return PPC_INTERRUPT_DOORBELL; 20299c713713SMatheus Ferst } 20309c713713SMatheus Ferst /* Hypervisor Doorbell Exception */ 20319c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && 20329c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_HDEE)) { 20339c713713SMatheus Ferst return PPC_INTERRUPT_HDOORBELL; 20349c713713SMatheus Ferst } 20359c713713SMatheus Ferst /* Hypervisor virtualization exception */ 20369c713713SMatheus Ferst if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) && 20379c713713SMatheus Ferst (env->spr[SPR_LPCR] & LPCR_HVEE)) { 20389c713713SMatheus Ferst return PPC_INTERRUPT_HVIRT; 20399c713713SMatheus Ferst } 20409c713713SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_RESET) { 20419c713713SMatheus Ferst return PPC_INTERRUPT_RESET; 20429c713713SMatheus Ferst } 20439c713713SMatheus Ferst return 0; 20449c713713SMatheus Ferst } 20459c713713SMatheus Ferst 20462dfecf01SMatheus Ferst static int p9_next_unmasked_interrupt(CPUPPCState *env) 20472dfecf01SMatheus Ferst { 204827796411SMatheus Ferst PowerPCCPU *cpu = env_archcpu(env); 204927796411SMatheus Ferst CPUState *cs = CPU(cpu); 205027796411SMatheus Ferst /* Ignore MSR[EE] when coming out of some power management states */ 205127796411SMatheus Ferst bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; 20522dfecf01SMatheus Ferst 2053b00e9a2fSMatheus Ferst assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0); 2054b00e9a2fSMatheus Ferst 205527796411SMatheus Ferst if (cs->halted) { 205627796411SMatheus Ferst if (env->spr[SPR_PSSCR] & PSSCR_EC) { 205727796411SMatheus Ferst /* 205827796411SMatheus Ferst * When PSSCR[EC] is set, LPCR[PECE] controls which interrupts can 205927796411SMatheus Ferst * wakeup the processor 206027796411SMatheus Ferst */ 206127796411SMatheus Ferst return p9_interrupt_powersave(env); 206227796411SMatheus Ferst } else { 206327796411SMatheus Ferst /* 206427796411SMatheus Ferst * When it's clear, any system-caused exception exits power-saving 206527796411SMatheus Ferst * mode, even the ones that gate on MSR[EE]. 206627796411SMatheus Ferst */ 206727796411SMatheus Ferst msr_ee = true; 206827796411SMatheus Ferst } 206927796411SMatheus Ferst } 207027796411SMatheus Ferst 20712dfecf01SMatheus Ferst /* Machine check exception */ 20722dfecf01SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_MCK) { 20732dfecf01SMatheus Ferst return PPC_INTERRUPT_MCK; 20742dfecf01SMatheus Ferst } 20752dfecf01SMatheus Ferst 20762dfecf01SMatheus Ferst /* Hypervisor decrementer exception */ 20772dfecf01SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { 20782dfecf01SMatheus Ferst /* LPCR will be clear when not supported so this will work */ 20792dfecf01SMatheus Ferst bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); 208027796411SMatheus Ferst if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) { 20812dfecf01SMatheus Ferst /* HDEC clears on delivery */ 20822dfecf01SMatheus Ferst return PPC_INTERRUPT_HDECR; 20832dfecf01SMatheus Ferst } 20842dfecf01SMatheus Ferst } 20852dfecf01SMatheus Ferst 20862dfecf01SMatheus Ferst /* Hypervisor virtualization interrupt */ 20872dfecf01SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) { 20882dfecf01SMatheus Ferst /* LPCR will be clear when not supported so this will work */ 20892dfecf01SMatheus Ferst bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); 209027796411SMatheus Ferst if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hvice) { 20912dfecf01SMatheus Ferst return PPC_INTERRUPT_HVIRT; 20922dfecf01SMatheus Ferst } 20932dfecf01SMatheus Ferst } 20942dfecf01SMatheus Ferst 20952dfecf01SMatheus Ferst /* External interrupt can ignore MSR:EE under some circumstances */ 20962dfecf01SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_EXT) { 20972dfecf01SMatheus Ferst bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 20982dfecf01SMatheus Ferst bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); 20992dfecf01SMatheus Ferst /* HEIC blocks delivery to the hypervisor */ 210027796411SMatheus Ferst if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) && 21012dfecf01SMatheus Ferst !FIELD_EX64(env->msr, MSR, PR))) || 21022dfecf01SMatheus Ferst (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { 21032dfecf01SMatheus Ferst return PPC_INTERRUPT_EXT; 21042dfecf01SMatheus Ferst } 21052dfecf01SMatheus Ferst } 210627796411SMatheus Ferst if (msr_ee != 0) { 21072dfecf01SMatheus Ferst /* Decrementer exception */ 21082dfecf01SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_DECR) { 21092dfecf01SMatheus Ferst return PPC_INTERRUPT_DECR; 21102dfecf01SMatheus Ferst } 21112dfecf01SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { 21122dfecf01SMatheus Ferst return PPC_INTERRUPT_DOORBELL; 21132dfecf01SMatheus Ferst } 21142dfecf01SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) { 21152dfecf01SMatheus Ferst return PPC_INTERRUPT_HDOORBELL; 21162dfecf01SMatheus Ferst } 21172dfecf01SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { 21182dfecf01SMatheus Ferst return PPC_INTERRUPT_PERFM; 21192dfecf01SMatheus Ferst } 21202dfecf01SMatheus Ferst /* EBB exception */ 21212dfecf01SMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_EBB) { 21222dfecf01SMatheus Ferst /* 21232dfecf01SMatheus Ferst * EBB exception must be taken in problem state and 21242dfecf01SMatheus Ferst * with BESCR_GE set. 21252dfecf01SMatheus Ferst */ 21262dfecf01SMatheus Ferst if (FIELD_EX64(env->msr, MSR, PR) && 21272dfecf01SMatheus Ferst (env->spr[SPR_BESCR] & BESCR_GE)) { 21282dfecf01SMatheus Ferst return PPC_INTERRUPT_EBB; 21292dfecf01SMatheus Ferst } 21302dfecf01SMatheus Ferst } 21312dfecf01SMatheus Ferst } 21322dfecf01SMatheus Ferst 21332dfecf01SMatheus Ferst return 0; 21342dfecf01SMatheus Ferst } 21352dfecf01SMatheus Ferst #endif 21362dfecf01SMatheus Ferst 2137ba2898f7SMatheus Ferst static int ppc_next_unmasked_interrupt_generic(CPUPPCState *env) 2138c79c73f6SBlue Swirl { 21393621e2c9SBenjamin Herrenschmidt bool async_deliver; 2140259186a7SAndreas Färber 2141c79c73f6SBlue Swirl /* External reset */ 2142f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_RESET) { 2143de76b85cSMatheus Ferst return PPC_INTERRUPT_RESET; 2144c79c73f6SBlue Swirl } 2145c79c73f6SBlue Swirl /* Machine check exception */ 2146f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_MCK) { 2147de76b85cSMatheus Ferst return PPC_INTERRUPT_MCK; 2148c79c73f6SBlue Swirl } 2149c79c73f6SBlue Swirl #if 0 /* TODO */ 2150c79c73f6SBlue Swirl /* External debug exception */ 2151f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) { 2152de76b85cSMatheus Ferst return PPC_INTERRUPT_DEBUG; 2153c79c73f6SBlue Swirl } 2154c79c73f6SBlue Swirl #endif 21553621e2c9SBenjamin Herrenschmidt 21563621e2c9SBenjamin Herrenschmidt /* 21573621e2c9SBenjamin Herrenschmidt * For interrupts that gate on MSR:EE, we need to do something a 21583621e2c9SBenjamin Herrenschmidt * bit more subtle, as we need to let them through even when EE is 21593621e2c9SBenjamin Herrenschmidt * clear when coming out of some power management states (in order 21603621e2c9SBenjamin Herrenschmidt * for them to become a 0x100). 21613621e2c9SBenjamin Herrenschmidt */ 21620939b8f8SVíctor Colombo async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; 21633621e2c9SBenjamin Herrenschmidt 2164c79c73f6SBlue Swirl /* Hypervisor decrementer exception */ 2165f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { 21664b236b62SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 21674b236b62SBenjamin Herrenschmidt bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); 21689de754d3SVíctor Colombo if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) { 21694b236b62SBenjamin Herrenschmidt /* HDEC clears on delivery */ 2170de76b85cSMatheus Ferst return PPC_INTERRUPT_HDECR; 2171c79c73f6SBlue Swirl } 2172c79c73f6SBlue Swirl } 2173d8ce5fd6SBenjamin Herrenschmidt 2174d8ce5fd6SBenjamin Herrenschmidt /* Hypervisor virtualization interrupt */ 2175f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) { 2176d8ce5fd6SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 2177d8ce5fd6SBenjamin Herrenschmidt bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); 21789de754d3SVíctor Colombo if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) { 2179de76b85cSMatheus Ferst return PPC_INTERRUPT_HVIRT; 2180d8ce5fd6SBenjamin Herrenschmidt } 2181d8ce5fd6SBenjamin Herrenschmidt } 2182d8ce5fd6SBenjamin Herrenschmidt 2183d8ce5fd6SBenjamin Herrenschmidt /* External interrupt can ignore MSR:EE under some circumstances */ 2184f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_EXT) { 2185d1dbe37cSBenjamin Herrenschmidt bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 21866eebe6dcSBenjamin Herrenschmidt bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); 21876eebe6dcSBenjamin Herrenschmidt /* HEIC blocks delivery to the hypervisor */ 21889de754d3SVíctor Colombo if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) && 2189d41ccf6eSVíctor Colombo !FIELD_EX64(env->msr, MSR, PR))) || 21909de754d3SVíctor Colombo (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { 2191de76b85cSMatheus Ferst return PPC_INTERRUPT_EXT; 2192d1dbe37cSBenjamin Herrenschmidt } 2193d1dbe37cSBenjamin Herrenschmidt } 2194acc861c2SVíctor Colombo if (FIELD_EX64(env->msr, MSR, CE)) { 2195c79c73f6SBlue Swirl /* External critical interrupt */ 2196f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_CEXT) { 2197de76b85cSMatheus Ferst return PPC_INTERRUPT_CEXT; 2198c79c73f6SBlue Swirl } 2199c79c73f6SBlue Swirl } 22003621e2c9SBenjamin Herrenschmidt if (async_deliver != 0) { 2201c79c73f6SBlue Swirl /* Watchdog timer on embedded PowerPC */ 2202f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_WDT) { 2203de76b85cSMatheus Ferst return PPC_INTERRUPT_WDT; 2204c79c73f6SBlue Swirl } 2205f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) { 2206de76b85cSMatheus Ferst return PPC_INTERRUPT_CDOORBELL; 2207c79c73f6SBlue Swirl } 2208c79c73f6SBlue Swirl /* Fixed interval timer on embedded PowerPC */ 2209f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_FIT) { 2210de76b85cSMatheus Ferst return PPC_INTERRUPT_FIT; 2211c79c73f6SBlue Swirl } 2212c79c73f6SBlue Swirl /* Programmable interval timer on embedded PowerPC */ 2213f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_PIT) { 2214de76b85cSMatheus Ferst return PPC_INTERRUPT_PIT; 2215c79c73f6SBlue Swirl } 2216c79c73f6SBlue Swirl /* Decrementer exception */ 2217f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_DECR) { 2218de76b85cSMatheus Ferst return PPC_INTERRUPT_DECR; 2219c79c73f6SBlue Swirl } 2220f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { 2221de76b85cSMatheus Ferst return PPC_INTERRUPT_DOORBELL; 2222c79c73f6SBlue Swirl } 2223f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) { 2224de76b85cSMatheus Ferst return PPC_INTERRUPT_HDOORBELL; 22257af1e7b0SCédric Le Goater } 2226f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { 2227de76b85cSMatheus Ferst return PPC_INTERRUPT_PERFM; 2228c79c73f6SBlue Swirl } 2229c79c73f6SBlue Swirl /* Thermal interrupt */ 2230f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_THERM) { 2231de76b85cSMatheus Ferst return PPC_INTERRUPT_THERM; 2232c79c73f6SBlue Swirl } 2233cb76bbc4SDaniel Henrique Barboza /* EBB exception */ 2234f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_EBB) { 2235cb76bbc4SDaniel Henrique Barboza /* 2236cb76bbc4SDaniel Henrique Barboza * EBB exception must be taken in problem state and 2237cb76bbc4SDaniel Henrique Barboza * with BESCR_GE set. 2238cb76bbc4SDaniel Henrique Barboza */ 2239d41ccf6eSVíctor Colombo if (FIELD_EX64(env->msr, MSR, PR) && 2240d41ccf6eSVíctor Colombo (env->spr[SPR_BESCR] & BESCR_GE)) { 2241de76b85cSMatheus Ferst return PPC_INTERRUPT_EBB; 2242de76b85cSMatheus Ferst } 2243de76b85cSMatheus Ferst } 2244de76b85cSMatheus Ferst } 2245cb76bbc4SDaniel Henrique Barboza 2246de76b85cSMatheus Ferst return 0; 2247de76b85cSMatheus Ferst } 2248de76b85cSMatheus Ferst 2249ba2898f7SMatheus Ferst static int ppc_next_unmasked_interrupt(CPUPPCState *env) 2250ba2898f7SMatheus Ferst { 2251ba2898f7SMatheus Ferst switch (env->excp_model) { 22522dfecf01SMatheus Ferst #if defined(TARGET_PPC64) 2253bf303fb3SMatheus Ferst case POWERPC_EXCP_POWER7: 2254bf303fb3SMatheus Ferst return p7_next_unmasked_interrupt(env); 2255a9899d42SMatheus Ferst case POWERPC_EXCP_POWER8: 2256a9899d42SMatheus Ferst return p8_next_unmasked_interrupt(env); 22572dfecf01SMatheus Ferst case POWERPC_EXCP_POWER9: 22582dfecf01SMatheus Ferst case POWERPC_EXCP_POWER10: 22592dfecf01SMatheus Ferst return p9_next_unmasked_interrupt(env); 22602dfecf01SMatheus Ferst #endif 2261ba2898f7SMatheus Ferst default: 2262ba2898f7SMatheus Ferst return ppc_next_unmasked_interrupt_generic(env); 2263ba2898f7SMatheus Ferst } 2264ba2898f7SMatheus Ferst } 2265ba2898f7SMatheus Ferst 22662fdedcbcSMatheus Ferst /* 22672fdedcbcSMatheus Ferst * Sets CPU_INTERRUPT_HARD if there is at least one unmasked interrupt to be 22682fdedcbcSMatheus Ferst * delivered and clears CPU_INTERRUPT_HARD otherwise. 22692fdedcbcSMatheus Ferst * 22702fdedcbcSMatheus Ferst * This method is called by ppc_set_interrupt when an interrupt is raised or 22712fdedcbcSMatheus Ferst * lowered, and should also be called whenever an interrupt masking condition 22722fdedcbcSMatheus Ferst * is changed, e.g.: 22732fdedcbcSMatheus Ferst * - When relevant bits of MSR are altered, like EE, HV, PR, etc.; 22742fdedcbcSMatheus Ferst * - When relevant bits of LPCR are altered, like PECE, HDICE, HVICE, etc.; 22752fdedcbcSMatheus Ferst * - When PSSCR[EC] or env->resume_as_sreset are changed; 22762fdedcbcSMatheus Ferst * - When cs->halted is changed and the CPU has a different interrupt masking 22772fdedcbcSMatheus Ferst * logic in power-saving mode (e.g., POWER7/8/9/10); 22782fdedcbcSMatheus Ferst */ 22792fdedcbcSMatheus Ferst void ppc_maybe_interrupt(CPUPPCState *env) 22802fdedcbcSMatheus Ferst { 22812fdedcbcSMatheus Ferst CPUState *cs = env_cpu(env); 22822fc4f9f3SRichard Henderson QEMU_IOTHREAD_LOCK_GUARD(); 22832fdedcbcSMatheus Ferst 22842fdedcbcSMatheus Ferst if (ppc_next_unmasked_interrupt(env)) { 22852fdedcbcSMatheus Ferst cpu_interrupt(cs, CPU_INTERRUPT_HARD); 22862fdedcbcSMatheus Ferst } else { 22872fdedcbcSMatheus Ferst cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 22882fdedcbcSMatheus Ferst } 22892fdedcbcSMatheus Ferst } 22902fdedcbcSMatheus Ferst 22913654e238SMatheus Ferst #if defined(TARGET_PPC64) 2292d93a4856SMatheus Ferst static void p7_deliver_interrupt(CPUPPCState *env, int interrupt) 2293d93a4856SMatheus Ferst { 2294d93a4856SMatheus Ferst PowerPCCPU *cpu = env_archcpu(env); 2295d93a4856SMatheus Ferst CPUState *cs = env_cpu(env); 2296d93a4856SMatheus Ferst 2297d93a4856SMatheus Ferst switch (interrupt) { 2298d93a4856SMatheus Ferst case PPC_INTERRUPT_MCK: /* Machine check exception */ 2299d93a4856SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_MCK; 2300d93a4856SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_MCHECK); 2301d93a4856SMatheus Ferst break; 2302d93a4856SMatheus Ferst 2303d93a4856SMatheus Ferst case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */ 2304d93a4856SMatheus Ferst /* HDEC clears on delivery */ 2305d93a4856SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; 2306d93a4856SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_HDECR); 2307d93a4856SMatheus Ferst break; 2308d93a4856SMatheus Ferst 2309d93a4856SMatheus Ferst case PPC_INTERRUPT_EXT: 2310d93a4856SMatheus Ferst if (books_vhyp_promotes_external_to_hvirt(cpu)) { 2311d93a4856SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_HVIRT); 2312d93a4856SMatheus Ferst } else { 2313d93a4856SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); 2314d93a4856SMatheus Ferst } 2315d93a4856SMatheus Ferst break; 2316d93a4856SMatheus Ferst 2317d93a4856SMatheus Ferst case PPC_INTERRUPT_DECR: /* Decrementer exception */ 2318d93a4856SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_DECR); 2319d93a4856SMatheus Ferst break; 2320d93a4856SMatheus Ferst case PPC_INTERRUPT_PERFM: 2321d93a4856SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; 2322d93a4856SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_PERFM); 2323d93a4856SMatheus Ferst break; 2324d93a4856SMatheus Ferst case 0: 2325d93a4856SMatheus Ferst /* 2326d93a4856SMatheus Ferst * This is a bug ! It means that has_work took us out of halt without 2327d93a4856SMatheus Ferst * anything to deliver while in a PM state that requires getting 2328d93a4856SMatheus Ferst * out via a 0x100 2329d93a4856SMatheus Ferst * 2330d93a4856SMatheus Ferst * This means we will incorrectly execute past the power management 2331d93a4856SMatheus Ferst * instruction instead of triggering a reset. 2332d93a4856SMatheus Ferst * 2333d93a4856SMatheus Ferst * It generally means a discrepancy between the wakeup conditions in the 2334d93a4856SMatheus Ferst * processor has_work implementation and the logic in this function. 2335d93a4856SMatheus Ferst */ 2336d93a4856SMatheus Ferst assert(!env->resume_as_sreset); 2337d93a4856SMatheus Ferst break; 2338d93a4856SMatheus Ferst default: 2339d93a4856SMatheus Ferst cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt); 2340d93a4856SMatheus Ferst } 2341d93a4856SMatheus Ferst } 2342d93a4856SMatheus Ferst 23436527e757SMatheus Ferst static void p8_deliver_interrupt(CPUPPCState *env, int interrupt) 23446527e757SMatheus Ferst { 23456527e757SMatheus Ferst PowerPCCPU *cpu = env_archcpu(env); 23466527e757SMatheus Ferst CPUState *cs = env_cpu(env); 23476527e757SMatheus Ferst 23486527e757SMatheus Ferst switch (interrupt) { 23496527e757SMatheus Ferst case PPC_INTERRUPT_MCK: /* Machine check exception */ 23506527e757SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_MCK; 23516527e757SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_MCHECK); 23526527e757SMatheus Ferst break; 23536527e757SMatheus Ferst 23546527e757SMatheus Ferst case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */ 23556527e757SMatheus Ferst /* HDEC clears on delivery */ 23566527e757SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; 23576527e757SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_HDECR); 23586527e757SMatheus Ferst break; 23596527e757SMatheus Ferst 23606527e757SMatheus Ferst case PPC_INTERRUPT_EXT: 23616527e757SMatheus Ferst if (books_vhyp_promotes_external_to_hvirt(cpu)) { 23626527e757SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_HVIRT); 23636527e757SMatheus Ferst } else { 23646527e757SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); 23656527e757SMatheus Ferst } 23666527e757SMatheus Ferst break; 23676527e757SMatheus Ferst 23686527e757SMatheus Ferst case PPC_INTERRUPT_DECR: /* Decrementer exception */ 23696527e757SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_DECR); 23706527e757SMatheus Ferst break; 23716527e757SMatheus Ferst case PPC_INTERRUPT_DOORBELL: 23726527e757SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; 23736527e757SMatheus Ferst if (is_book3s_arch2x(env)) { 23746527e757SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_SDOOR); 23756527e757SMatheus Ferst } else { 23766527e757SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_DOORI); 23776527e757SMatheus Ferst } 23786527e757SMatheus Ferst break; 23796527e757SMatheus Ferst case PPC_INTERRUPT_HDOORBELL: 23806527e757SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; 23816527e757SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); 23826527e757SMatheus Ferst break; 23836527e757SMatheus Ferst case PPC_INTERRUPT_PERFM: 23846527e757SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; 23856527e757SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_PERFM); 23866527e757SMatheus Ferst break; 23876527e757SMatheus Ferst case PPC_INTERRUPT_EBB: /* EBB exception */ 23886527e757SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_EBB; 23896527e757SMatheus Ferst if (env->spr[SPR_BESCR] & BESCR_PMEO) { 23906527e757SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); 23916527e757SMatheus Ferst } else if (env->spr[SPR_BESCR] & BESCR_EEO) { 23926527e757SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); 23936527e757SMatheus Ferst } 23946527e757SMatheus Ferst break; 23956527e757SMatheus Ferst case 0: 23966527e757SMatheus Ferst /* 23976527e757SMatheus Ferst * This is a bug ! It means that has_work took us out of halt without 23986527e757SMatheus Ferst * anything to deliver while in a PM state that requires getting 23996527e757SMatheus Ferst * out via a 0x100 24006527e757SMatheus Ferst * 24016527e757SMatheus Ferst * This means we will incorrectly execute past the power management 24026527e757SMatheus Ferst * instruction instead of triggering a reset. 24036527e757SMatheus Ferst * 24046527e757SMatheus Ferst * It generally means a discrepancy between the wakeup conditions in the 24056527e757SMatheus Ferst * processor has_work implementation and the logic in this function. 24066527e757SMatheus Ferst */ 24076527e757SMatheus Ferst assert(!env->resume_as_sreset); 24086527e757SMatheus Ferst break; 24096527e757SMatheus Ferst default: 24106527e757SMatheus Ferst cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt); 24116527e757SMatheus Ferst } 24126527e757SMatheus Ferst } 24136527e757SMatheus Ferst 24143654e238SMatheus Ferst static void p9_deliver_interrupt(CPUPPCState *env, int interrupt) 24153654e238SMatheus Ferst { 24163654e238SMatheus Ferst PowerPCCPU *cpu = env_archcpu(env); 24173654e238SMatheus Ferst CPUState *cs = env_cpu(env); 24183654e238SMatheus Ferst 241927796411SMatheus Ferst if (cs->halted && !(env->spr[SPR_PSSCR] & PSSCR_EC) && 242027796411SMatheus Ferst !FIELD_EX64(env->msr, MSR, EE)) { 242127796411SMatheus Ferst /* 242227796411SMatheus Ferst * A pending interrupt took us out of power-saving, but MSR[EE] says 242327796411SMatheus Ferst * that we should return to NIP+4 instead of delivering it. 242427796411SMatheus Ferst */ 242527796411SMatheus Ferst return; 242627796411SMatheus Ferst } 242727796411SMatheus Ferst 24283654e238SMatheus Ferst switch (interrupt) { 24293654e238SMatheus Ferst case PPC_INTERRUPT_MCK: /* Machine check exception */ 24303654e238SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_MCK; 24313654e238SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_MCHECK); 24323654e238SMatheus Ferst break; 24333654e238SMatheus Ferst 24343654e238SMatheus Ferst case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */ 24353654e238SMatheus Ferst /* HDEC clears on delivery */ 24363654e238SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; 24373654e238SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_HDECR); 24383654e238SMatheus Ferst break; 24393654e238SMatheus Ferst case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */ 24403654e238SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_HVIRT); 24413654e238SMatheus Ferst break; 24423654e238SMatheus Ferst 24433654e238SMatheus Ferst case PPC_INTERRUPT_EXT: 24443654e238SMatheus Ferst if (books_vhyp_promotes_external_to_hvirt(cpu)) { 24453654e238SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_HVIRT); 24463654e238SMatheus Ferst } else { 24473654e238SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); 24483654e238SMatheus Ferst } 24493654e238SMatheus Ferst break; 24503654e238SMatheus Ferst 24513654e238SMatheus Ferst case PPC_INTERRUPT_DECR: /* Decrementer exception */ 24523654e238SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_DECR); 24533654e238SMatheus Ferst break; 24543654e238SMatheus Ferst case PPC_INTERRUPT_DOORBELL: 24553654e238SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; 24563654e238SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_SDOOR); 24573654e238SMatheus Ferst break; 24583654e238SMatheus Ferst case PPC_INTERRUPT_HDOORBELL: 24593654e238SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; 24603654e238SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); 24613654e238SMatheus Ferst break; 24623654e238SMatheus Ferst case PPC_INTERRUPT_PERFM: 24633654e238SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; 24643654e238SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_PERFM); 24653654e238SMatheus Ferst break; 24663654e238SMatheus Ferst case PPC_INTERRUPT_EBB: /* EBB exception */ 24673654e238SMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_EBB; 24683654e238SMatheus Ferst if (env->spr[SPR_BESCR] & BESCR_PMEO) { 24693654e238SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); 24703654e238SMatheus Ferst } else if (env->spr[SPR_BESCR] & BESCR_EEO) { 24713654e238SMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); 24723654e238SMatheus Ferst } 24733654e238SMatheus Ferst break; 24743654e238SMatheus Ferst case 0: 24753654e238SMatheus Ferst /* 24763654e238SMatheus Ferst * This is a bug ! It means that has_work took us out of halt without 24773654e238SMatheus Ferst * anything to deliver while in a PM state that requires getting 24783654e238SMatheus Ferst * out via a 0x100 24793654e238SMatheus Ferst * 24803654e238SMatheus Ferst * This means we will incorrectly execute past the power management 24813654e238SMatheus Ferst * instruction instead of triggering a reset. 24823654e238SMatheus Ferst * 24833654e238SMatheus Ferst * It generally means a discrepancy between the wakeup conditions in the 24843654e238SMatheus Ferst * processor has_work implementation and the logic in this function. 24853654e238SMatheus Ferst */ 24863654e238SMatheus Ferst assert(!env->resume_as_sreset); 24873654e238SMatheus Ferst break; 24883654e238SMatheus Ferst default: 24893654e238SMatheus Ferst cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt); 24903654e238SMatheus Ferst } 24913654e238SMatheus Ferst } 24923654e238SMatheus Ferst #endif 24933654e238SMatheus Ferst 2494ba2898f7SMatheus Ferst static void ppc_deliver_interrupt_generic(CPUPPCState *env, int interrupt) 2495de76b85cSMatheus Ferst { 2496de76b85cSMatheus Ferst PowerPCCPU *cpu = env_archcpu(env); 2497de76b85cSMatheus Ferst CPUState *cs = env_cpu(env); 2498de76b85cSMatheus Ferst 2499de76b85cSMatheus Ferst switch (interrupt) { 2500de76b85cSMatheus Ferst case PPC_INTERRUPT_RESET: /* External reset */ 2501de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_RESET; 2502de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_RESET); 2503de76b85cSMatheus Ferst break; 2504de76b85cSMatheus Ferst case PPC_INTERRUPT_MCK: /* Machine check exception */ 2505de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_MCK; 2506de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_MCHECK); 2507de76b85cSMatheus Ferst break; 2508de76b85cSMatheus Ferst 2509de76b85cSMatheus Ferst case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */ 2510de76b85cSMatheus Ferst /* HDEC clears on delivery */ 2511de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; 2512de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_HDECR); 2513de76b85cSMatheus Ferst break; 2514de76b85cSMatheus Ferst case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */ 2515de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_HVIRT); 2516de76b85cSMatheus Ferst break; 2517de76b85cSMatheus Ferst 2518de76b85cSMatheus Ferst case PPC_INTERRUPT_EXT: 2519de76b85cSMatheus Ferst if (books_vhyp_promotes_external_to_hvirt(cpu)) { 2520de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_HVIRT); 2521de76b85cSMatheus Ferst } else { 2522de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); 2523de76b85cSMatheus Ferst } 2524de76b85cSMatheus Ferst break; 2525de76b85cSMatheus Ferst case PPC_INTERRUPT_CEXT: /* External critical interrupt */ 2526de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); 2527de76b85cSMatheus Ferst break; 2528de76b85cSMatheus Ferst 2529de76b85cSMatheus Ferst case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */ 2530de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_WDT; 2531de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_WDT); 2532de76b85cSMatheus Ferst break; 2533de76b85cSMatheus Ferst case PPC_INTERRUPT_CDOORBELL: 2534de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL; 2535de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_DOORCI); 2536de76b85cSMatheus Ferst break; 2537de76b85cSMatheus Ferst case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */ 2538de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_FIT; 2539de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_FIT); 2540de76b85cSMatheus Ferst break; 2541de76b85cSMatheus Ferst case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded ppc */ 2542de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_PIT; 2543de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_PIT); 2544de76b85cSMatheus Ferst break; 2545de76b85cSMatheus Ferst case PPC_INTERRUPT_DECR: /* Decrementer exception */ 2546de76b85cSMatheus Ferst if (ppc_decr_clear_on_delivery(env)) { 2547de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_DECR; 2548de76b85cSMatheus Ferst } 2549de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_DECR); 2550de76b85cSMatheus Ferst break; 2551de76b85cSMatheus Ferst case PPC_INTERRUPT_DOORBELL: 2552de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; 2553de76b85cSMatheus Ferst if (is_book3s_arch2x(env)) { 2554de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_SDOOR); 2555de76b85cSMatheus Ferst } else { 2556de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_DOORI); 2557de76b85cSMatheus Ferst } 2558de76b85cSMatheus Ferst break; 2559de76b85cSMatheus Ferst case PPC_INTERRUPT_HDOORBELL: 2560de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; 2561de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); 2562de76b85cSMatheus Ferst break; 2563de76b85cSMatheus Ferst case PPC_INTERRUPT_PERFM: 2564de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; 2565de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_PERFM); 2566de76b85cSMatheus Ferst break; 2567de76b85cSMatheus Ferst case PPC_INTERRUPT_THERM: /* Thermal interrupt */ 2568de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_THERM; 2569de76b85cSMatheus Ferst powerpc_excp(cpu, POWERPC_EXCP_THERM); 2570de76b85cSMatheus Ferst break; 2571de76b85cSMatheus Ferst case PPC_INTERRUPT_EBB: /* EBB exception */ 2572de76b85cSMatheus Ferst env->pending_interrupts &= ~PPC_INTERRUPT_EBB; 2573cb76bbc4SDaniel Henrique Barboza if (env->spr[SPR_BESCR] & BESCR_PMEO) { 2574cb76bbc4SDaniel Henrique Barboza powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); 2575cb76bbc4SDaniel Henrique Barboza } else if (env->spr[SPR_BESCR] & BESCR_EEO) { 2576cb76bbc4SDaniel Henrique Barboza powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); 2577cb76bbc4SDaniel Henrique Barboza } 2578de76b85cSMatheus Ferst break; 2579de76b85cSMatheus Ferst case 0: 2580f8154fd2SBenjamin Herrenschmidt /* 2581f8154fd2SBenjamin Herrenschmidt * This is a bug ! It means that has_work took us out of halt without 2582f8154fd2SBenjamin Herrenschmidt * anything to deliver while in a PM state that requires getting 2583f8154fd2SBenjamin Herrenschmidt * out via a 0x100 2584f8154fd2SBenjamin Herrenschmidt * 2585f8154fd2SBenjamin Herrenschmidt * This means we will incorrectly execute past the power management 2586f8154fd2SBenjamin Herrenschmidt * instruction instead of triggering a reset. 2587f8154fd2SBenjamin Herrenschmidt * 2588136fbf65Szhaolichang * It generally means a discrepancy between the wakeup conditions in the 2589f8154fd2SBenjamin Herrenschmidt * processor has_work implementation and the logic in this function. 2590f8154fd2SBenjamin Herrenschmidt */ 2591de76b85cSMatheus Ferst assert(!env->resume_as_sreset); 2592de76b85cSMatheus Ferst break; 2593de76b85cSMatheus Ferst default: 2594de76b85cSMatheus Ferst cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt); 2595f8154fd2SBenjamin Herrenschmidt } 2596c79c73f6SBlue Swirl } 259734316482SAlexey Kardashevskiy 2598ba2898f7SMatheus Ferst static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt) 2599ba2898f7SMatheus Ferst { 2600ba2898f7SMatheus Ferst switch (env->excp_model) { 26013654e238SMatheus Ferst #if defined(TARGET_PPC64) 2602d93a4856SMatheus Ferst case POWERPC_EXCP_POWER7: 2603d93a4856SMatheus Ferst p7_deliver_interrupt(env, interrupt); 2604d93a4856SMatheus Ferst break; 26056527e757SMatheus Ferst case POWERPC_EXCP_POWER8: 26066527e757SMatheus Ferst p8_deliver_interrupt(env, interrupt); 26076527e757SMatheus Ferst break; 26083654e238SMatheus Ferst case POWERPC_EXCP_POWER9: 26093654e238SMatheus Ferst case POWERPC_EXCP_POWER10: 26103654e238SMatheus Ferst p9_deliver_interrupt(env, interrupt); 26113654e238SMatheus Ferst break; 26123654e238SMatheus Ferst #endif 2613ba2898f7SMatheus Ferst default: 2614ba2898f7SMatheus Ferst ppc_deliver_interrupt_generic(env, interrupt); 2615ba2898f7SMatheus Ferst } 2616ba2898f7SMatheus Ferst } 2617ba2898f7SMatheus Ferst 2618b5b7f391SNicholas Piggin void ppc_cpu_do_system_reset(CPUState *cs) 261934316482SAlexey Kardashevskiy { 262034316482SAlexey Kardashevskiy PowerPCCPU *cpu = POWERPC_CPU(cs); 262134316482SAlexey Kardashevskiy 262293130c84SFabiano Rosas powerpc_excp(cpu, POWERPC_EXCP_RESET); 262334316482SAlexey Kardashevskiy } 2624ad77c6caSNicholas Piggin 2625ad77c6caSNicholas Piggin void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector) 2626ad77c6caSNicholas Piggin { 2627ad77c6caSNicholas Piggin PowerPCCPU *cpu = POWERPC_CPU(cs); 2628ad77c6caSNicholas Piggin CPUPPCState *env = &cpu->env; 2629ad77c6caSNicholas Piggin target_ulong msr = 0; 2630ad77c6caSNicholas Piggin 2631ad77c6caSNicholas Piggin /* 2632ad77c6caSNicholas Piggin * Set MSR and NIP for the handler, SRR0/1, DAR and DSISR have already 2633ad77c6caSNicholas Piggin * been set by KVM. 2634ad77c6caSNicholas Piggin */ 2635ad77c6caSNicholas Piggin msr = (1ULL << MSR_ME); 2636ad77c6caSNicholas Piggin msr |= env->msr & (1ULL << MSR_SF); 2637516fc103SFabiano Rosas if (ppc_interrupts_little_endian(cpu, false)) { 2638ad77c6caSNicholas Piggin msr |= (1ULL << MSR_LE); 2639ad77c6caSNicholas Piggin } 2640ad77c6caSNicholas Piggin 26417cebc5dbSNicholas Piggin /* Anything for nested required here? MSR[HV] bit? */ 26427cebc5dbSNicholas Piggin 2643ad77c6caSNicholas Piggin powerpc_set_excp_state(cpu, vector, msr); 2644ad77c6caSNicholas Piggin } 2645c79c73f6SBlue Swirl 2646458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 2647458dd766SRichard Henderson { 2648458dd766SRichard Henderson PowerPCCPU *cpu = POWERPC_CPU(cs); 2649458dd766SRichard Henderson CPUPPCState *env = &cpu->env; 2650de76b85cSMatheus Ferst int interrupt; 2651458dd766SRichard Henderson 2652de76b85cSMatheus Ferst if ((interrupt_request & CPU_INTERRUPT_HARD) == 0) { 2653de76b85cSMatheus Ferst return false; 2654de76b85cSMatheus Ferst } 2655de76b85cSMatheus Ferst 2656de76b85cSMatheus Ferst interrupt = ppc_next_unmasked_interrupt(env); 2657de76b85cSMatheus Ferst if (interrupt == 0) { 2658de76b85cSMatheus Ferst return false; 2659de76b85cSMatheus Ferst } 2660de76b85cSMatheus Ferst 2661de76b85cSMatheus Ferst ppc_deliver_interrupt(env, interrupt); 2662458dd766SRichard Henderson if (env->pending_interrupts == 0) { 2663de76b85cSMatheus Ferst cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); 2664458dd766SRichard Henderson } 2665458dd766SRichard Henderson return true; 2666458dd766SRichard Henderson } 2667458dd766SRichard Henderson 2668f725245cSPhilippe Mathieu-Daudé #endif /* !CONFIG_USER_ONLY */ 2669f725245cSPhilippe Mathieu-Daudé 2670ad71ed68SBlue Swirl /*****************************************************************************/ 2671ad71ed68SBlue Swirl /* Exceptions processing helpers */ 2672ad71ed68SBlue Swirl 2673db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, 2674db789c6cSBenjamin Herrenschmidt uint32_t error_code, uintptr_t raddr) 2675ad71ed68SBlue Swirl { 2676db70b311SRichard Henderson CPUState *cs = env_cpu(env); 267727103424SAndreas Färber 267827103424SAndreas Färber cs->exception_index = exception; 2679ad71ed68SBlue Swirl env->error_code = error_code; 2680db789c6cSBenjamin Herrenschmidt cpu_loop_exit_restore(cs, raddr); 2681db789c6cSBenjamin Herrenschmidt } 2682db789c6cSBenjamin Herrenschmidt 2683db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception, 2684db789c6cSBenjamin Herrenschmidt uint32_t error_code) 2685db789c6cSBenjamin Herrenschmidt { 2686db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 2687db789c6cSBenjamin Herrenschmidt } 2688db789c6cSBenjamin Herrenschmidt 2689db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception) 2690db789c6cSBenjamin Herrenschmidt { 2691db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 2692db789c6cSBenjamin Herrenschmidt } 2693db789c6cSBenjamin Herrenschmidt 2694db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception, 2695db789c6cSBenjamin Herrenschmidt uintptr_t raddr) 2696db789c6cSBenjamin Herrenschmidt { 2697db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, raddr); 2698db789c6cSBenjamin Herrenschmidt } 2699db789c6cSBenjamin Herrenschmidt 27002b44e219SBruno Larsen (billionai) #ifdef CONFIG_TCG 2701db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, 2702db789c6cSBenjamin Herrenschmidt uint32_t error_code) 2703db789c6cSBenjamin Herrenschmidt { 2704db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 2705ad71ed68SBlue Swirl } 2706ad71ed68SBlue Swirl 2707e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception) 2708ad71ed68SBlue Swirl { 2709db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 2710ad71ed68SBlue Swirl } 27112b44e219SBruno Larsen (billionai) #endif 2712ad71ed68SBlue Swirl 2713ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 27142b44e219SBruno Larsen (billionai) #ifdef CONFIG_TCG 2715e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val) 2716ad71ed68SBlue Swirl { 2717db789c6cSBenjamin Herrenschmidt uint32_t excp = hreg_store_msr(env, val, 0); 2718259186a7SAndreas Färber 2719db789c6cSBenjamin Herrenschmidt if (excp != 0) { 2720db70b311SRichard Henderson CPUState *cs = env_cpu(env); 2721044897efSRichard Purdie cpu_interrupt_exittb(cs); 2722db789c6cSBenjamin Herrenschmidt raise_exception(env, excp); 2723ad71ed68SBlue Swirl } 2724ad71ed68SBlue Swirl } 2725ad71ed68SBlue Swirl 27262fdedcbcSMatheus Ferst void helper_ppc_maybe_interrupt(CPUPPCState *env) 27272fdedcbcSMatheus Ferst { 27282fdedcbcSMatheus Ferst ppc_maybe_interrupt(env); 27292fdedcbcSMatheus Ferst } 27302fdedcbcSMatheus Ferst 27317778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64) 2732f43520e5SRichard Henderson void helper_scv(CPUPPCState *env, uint32_t lev) 2733f43520e5SRichard Henderson { 2734f43520e5SRichard Henderson if (env->spr[SPR_FSCR] & (1ull << FSCR_SCV)) { 2735f43520e5SRichard Henderson raise_exception_err(env, POWERPC_EXCP_SYSCALL_VECTORED, lev); 2736f43520e5SRichard Henderson } else { 2737f43520e5SRichard Henderson raise_exception_err(env, POWERPC_EXCP_FU, FSCR_IC_SCV); 2738f43520e5SRichard Henderson } 2739f43520e5SRichard Henderson } 2740f43520e5SRichard Henderson 274107e4804fSCédric Le Goater void helper_pminsn(CPUPPCState *env, uint32_t insn) 27427778a575SBenjamin Herrenschmidt { 27437778a575SBenjamin Herrenschmidt CPUState *cs; 27447778a575SBenjamin Herrenschmidt 2745db70b311SRichard Henderson cs = env_cpu(env); 27467778a575SBenjamin Herrenschmidt cs->halted = 1; 27477778a575SBenjamin Herrenschmidt 27483621e2c9SBenjamin Herrenschmidt /* Condition for waking up at 0x100 */ 27491e7fd61dSBenjamin Herrenschmidt env->resume_as_sreset = (insn != PPC_PM_STOP) || 275021c0d66aSBenjamin Herrenschmidt (env->spr[SPR_PSSCR] & PSSCR_EC); 27512fdedcbcSMatheus Ferst 27522fdedcbcSMatheus Ferst ppc_maybe_interrupt(env); 27537778a575SBenjamin Herrenschmidt } 27547778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 27557778a575SBenjamin Herrenschmidt 275662e79ef9SCédric Le Goater static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) 2757ad71ed68SBlue Swirl { 2758db70b311SRichard Henderson CPUState *cs = env_cpu(env); 2759259186a7SAndreas Färber 2760a2e71b28SBenjamin Herrenschmidt /* MSR:POW cannot be set by any form of rfi */ 2761a2e71b28SBenjamin Herrenschmidt msr &= ~(1ULL << MSR_POW); 2762a2e71b28SBenjamin Herrenschmidt 27635aad0457SChristophe Leroy /* MSR:TGPR cannot be set by any form of rfi */ 27645aad0457SChristophe Leroy if (env->flags & POWERPC_FLAG_TGPR) 27655aad0457SChristophe Leroy msr &= ~(1ULL << MSR_TGPR); 27665aad0457SChristophe Leroy 2767ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 2768a2e71b28SBenjamin Herrenschmidt /* Switching to 32-bit ? Crop the nip */ 2769a2e71b28SBenjamin Herrenschmidt if (!msr_is_64bit(env, msr)) { 2770ad71ed68SBlue Swirl nip = (uint32_t)nip; 2771ad71ed68SBlue Swirl } 2772ad71ed68SBlue Swirl #else 2773ad71ed68SBlue Swirl nip = (uint32_t)nip; 2774ad71ed68SBlue Swirl #endif 2775ad71ed68SBlue Swirl /* XXX: beware: this is false if VLE is supported */ 2776ad71ed68SBlue Swirl env->nip = nip & ~((target_ulong)0x00000003); 2777ad71ed68SBlue Swirl hreg_store_msr(env, msr, 1); 27782eb1ef73SCédric Le Goater trace_ppc_excp_rfi(env->nip, env->msr); 277947733729SDavid Gibson /* 278047733729SDavid Gibson * No need to raise an exception here, as rfi is always the last 278147733729SDavid Gibson * insn of a TB 2782ad71ed68SBlue Swirl */ 2783044897efSRichard Purdie cpu_interrupt_exittb(cs); 2784a8b73734SNikunj A Dadhania /* Reset the reservation */ 2785a8b73734SNikunj A Dadhania env->reserve_addr = -1; 2786a8b73734SNikunj A Dadhania 2787cd0c6f47SBenjamin Herrenschmidt /* Context synchronizing: check if TCG TLB needs flush */ 2788e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 2789ad71ed68SBlue Swirl } 2790ad71ed68SBlue Swirl 2791e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env) 2792ad71ed68SBlue Swirl { 2793a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); 2794a1bb7384SScott Wood } 2795ad71ed68SBlue Swirl 2796ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 2797e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env) 2798ad71ed68SBlue Swirl { 279947733729SDavid Gibson /* 2800136fbf65Szhaolichang * The architecture defines a number of rules for which bits can 280147733729SDavid Gibson * change but in practice, we handle this in hreg_store_msr() 2802a2e71b28SBenjamin Herrenschmidt * which will be called by do_rfi(), so there is no need to filter 2803a2e71b28SBenjamin Herrenschmidt * here 2804a2e71b28SBenjamin Herrenschmidt */ 2805a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]); 2806ad71ed68SBlue Swirl } 2807ad71ed68SBlue Swirl 28083c89b8d6SNicholas Piggin void helper_rfscv(CPUPPCState *env) 28093c89b8d6SNicholas Piggin { 28103c89b8d6SNicholas Piggin do_rfi(env, env->lr, env->ctr); 28113c89b8d6SNicholas Piggin } 28123c89b8d6SNicholas Piggin 2813e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env) 2814ad71ed68SBlue Swirl { 2815a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); 2816ad71ed68SBlue Swirl } 2817ad71ed68SBlue Swirl #endif 2818ad71ed68SBlue Swirl 28191f26c751SDaniel Henrique Barboza #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) 28201f26c751SDaniel Henrique Barboza void helper_rfebb(CPUPPCState *env, target_ulong s) 28211f26c751SDaniel Henrique Barboza { 28221f26c751SDaniel Henrique Barboza target_ulong msr = env->msr; 28231f26c751SDaniel Henrique Barboza 28241f26c751SDaniel Henrique Barboza /* 28251f26c751SDaniel Henrique Barboza * Handling of BESCR bits 32:33 according to PowerISA v3.1: 28261f26c751SDaniel Henrique Barboza * 28271f26c751SDaniel Henrique Barboza * "If BESCR 32:33 != 0b00 the instruction is treated as if 28281f26c751SDaniel Henrique Barboza * the instruction form were invalid." 28291f26c751SDaniel Henrique Barboza */ 28301f26c751SDaniel Henrique Barboza if (env->spr[SPR_BESCR] & BESCR_INVALID) { 28311f26c751SDaniel Henrique Barboza raise_exception_err(env, POWERPC_EXCP_PROGRAM, 28321f26c751SDaniel Henrique Barboza POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL); 28331f26c751SDaniel Henrique Barboza } 28341f26c751SDaniel Henrique Barboza 28351f26c751SDaniel Henrique Barboza env->nip = env->spr[SPR_EBBRR]; 28361f26c751SDaniel Henrique Barboza 28371f26c751SDaniel Henrique Barboza /* Switching to 32-bit ? Crop the nip */ 28381f26c751SDaniel Henrique Barboza if (!msr_is_64bit(env, msr)) { 28391f26c751SDaniel Henrique Barboza env->nip = (uint32_t)env->spr[SPR_EBBRR]; 28401f26c751SDaniel Henrique Barboza } 28411f26c751SDaniel Henrique Barboza 28421f26c751SDaniel Henrique Barboza if (s) { 28431f26c751SDaniel Henrique Barboza env->spr[SPR_BESCR] |= BESCR_GE; 28441f26c751SDaniel Henrique Barboza } else { 28451f26c751SDaniel Henrique Barboza env->spr[SPR_BESCR] &= ~BESCR_GE; 28461f26c751SDaniel Henrique Barboza } 28471f26c751SDaniel Henrique Barboza } 2848d3412df2SDaniel Henrique Barboza 2849d3412df2SDaniel Henrique Barboza /* 2850d3412df2SDaniel Henrique Barboza * Triggers or queues an 'ebb_excp' EBB exception. All checks 2851d3412df2SDaniel Henrique Barboza * but FSCR, HFSCR and msr_pr must be done beforehand. 2852d3412df2SDaniel Henrique Barboza * 2853d3412df2SDaniel Henrique Barboza * PowerISA v3.1 isn't clear about whether an EBB should be 2854d3412df2SDaniel Henrique Barboza * postponed or cancelled if the EBB facility is unavailable. 2855d3412df2SDaniel Henrique Barboza * Our assumption here is that the EBB is cancelled if both 2856d3412df2SDaniel Henrique Barboza * FSCR and HFSCR EBB facilities aren't available. 2857d3412df2SDaniel Henrique Barboza */ 2858d3412df2SDaniel Henrique Barboza static void do_ebb(CPUPPCState *env, int ebb_excp) 2859d3412df2SDaniel Henrique Barboza { 2860d3412df2SDaniel Henrique Barboza PowerPCCPU *cpu = env_archcpu(env); 2861d3412df2SDaniel Henrique Barboza 2862d3412df2SDaniel Henrique Barboza /* 2863d3412df2SDaniel Henrique Barboza * FSCR_EBB and FSCR_IC_EBB are the same bits used with 2864d3412df2SDaniel Henrique Barboza * HFSCR. 2865d3412df2SDaniel Henrique Barboza */ 2866d3412df2SDaniel Henrique Barboza helper_fscr_facility_check(env, FSCR_EBB, 0, FSCR_IC_EBB); 2867d3412df2SDaniel Henrique Barboza helper_hfscr_facility_check(env, FSCR_EBB, "EBB", FSCR_IC_EBB); 2868d3412df2SDaniel Henrique Barboza 2869d3412df2SDaniel Henrique Barboza if (ebb_excp == POWERPC_EXCP_PERFM_EBB) { 2870d3412df2SDaniel Henrique Barboza env->spr[SPR_BESCR] |= BESCR_PMEO; 2871d3412df2SDaniel Henrique Barboza } else if (ebb_excp == POWERPC_EXCP_EXTERNAL_EBB) { 2872d3412df2SDaniel Henrique Barboza env->spr[SPR_BESCR] |= BESCR_EEO; 2873d3412df2SDaniel Henrique Barboza } 2874d3412df2SDaniel Henrique Barboza 2875d41ccf6eSVíctor Colombo if (FIELD_EX64(env->msr, MSR, PR)) { 2876d3412df2SDaniel Henrique Barboza powerpc_excp(cpu, ebb_excp); 2877d3412df2SDaniel Henrique Barboza } else { 28787b694df6SMatheus Ferst ppc_set_irq(cpu, PPC_INTERRUPT_EBB, 1); 2879d3412df2SDaniel Henrique Barboza } 2880d3412df2SDaniel Henrique Barboza } 2881d3412df2SDaniel Henrique Barboza 2882d3412df2SDaniel Henrique Barboza void raise_ebb_perfm_exception(CPUPPCState *env) 2883d3412df2SDaniel Henrique Barboza { 2884d3412df2SDaniel Henrique Barboza bool perfm_ebb_enabled = env->spr[SPR_POWER_MMCR0] & MMCR0_EBE && 2885d3412df2SDaniel Henrique Barboza env->spr[SPR_BESCR] & BESCR_PME && 2886d3412df2SDaniel Henrique Barboza env->spr[SPR_BESCR] & BESCR_GE; 2887d3412df2SDaniel Henrique Barboza 2888d3412df2SDaniel Henrique Barboza if (!perfm_ebb_enabled) { 2889d3412df2SDaniel Henrique Barboza return; 2890d3412df2SDaniel Henrique Barboza } 2891d3412df2SDaniel Henrique Barboza 2892d3412df2SDaniel Henrique Barboza do_ebb(env, POWERPC_EXCP_PERFM_EBB); 2893d3412df2SDaniel Henrique Barboza } 28941f26c751SDaniel Henrique Barboza #endif 28951f26c751SDaniel Henrique Barboza 2896ad71ed68SBlue Swirl /*****************************************************************************/ 2897ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */ 2898e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env) 2899ad71ed68SBlue Swirl { 2900a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]); 2901ad71ed68SBlue Swirl } 2902ad71ed68SBlue Swirl 2903e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env) 2904ad71ed68SBlue Swirl { 2905a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]); 2906ad71ed68SBlue Swirl } 2907ad71ed68SBlue Swirl 2908e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env) 2909ad71ed68SBlue Swirl { 2910a1bb7384SScott Wood /* FIXME: choose CSRR1 or DSRR1 based on cpu type */ 2911a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]); 2912ad71ed68SBlue Swirl } 2913ad71ed68SBlue Swirl 2914e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env) 2915ad71ed68SBlue Swirl { 2916a1bb7384SScott Wood /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ 2917a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); 2918ad71ed68SBlue Swirl } 29192b44e219SBruno Larsen (billionai) #endif /* CONFIG_TCG */ 29202b44e219SBruno Larsen (billionai) #endif /* !defined(CONFIG_USER_ONLY) */ 2921ad71ed68SBlue Swirl 29222b44e219SBruno Larsen (billionai) #ifdef CONFIG_TCG 2923e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 2924e5f17ac6SBlue Swirl uint32_t flags) 2925ad71ed68SBlue Swirl { 2926ad71ed68SBlue Swirl if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || 2927ad71ed68SBlue Swirl ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) || 2928ad71ed68SBlue Swirl ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || 2929ad71ed68SBlue Swirl ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || 2930ad71ed68SBlue Swirl ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { 293172073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 293272073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 2933ad71ed68SBlue Swirl } 2934ad71ed68SBlue Swirl } 2935ad71ed68SBlue Swirl 2936ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 2937e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 2938e5f17ac6SBlue Swirl uint32_t flags) 2939ad71ed68SBlue Swirl { 2940ad71ed68SBlue Swirl if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || 2941ad71ed68SBlue Swirl ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) || 2942ad71ed68SBlue Swirl ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || 2943ad71ed68SBlue Swirl ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || 2944ad71ed68SBlue Swirl ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { 294572073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 294672073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 2947ad71ed68SBlue Swirl } 2948ad71ed68SBlue Swirl } 2949ad71ed68SBlue Swirl #endif 29502b44e219SBruno Larsen (billionai) #endif 2951ad71ed68SBlue Swirl 2952049b4ad6SVaibhav Jain #ifdef CONFIG_TCG 2953670f1da3SVíctor Colombo static uint32_t helper_SIMON_LIKE_32_64(uint32_t x, uint64_t key, uint32_t lane) 2954670f1da3SVíctor Colombo { 2955670f1da3SVíctor Colombo const uint16_t c = 0xfffc; 2956670f1da3SVíctor Colombo const uint64_t z0 = 0xfa2561cdf44ac398ULL; 2957670f1da3SVíctor Colombo uint16_t z = 0, temp; 2958670f1da3SVíctor Colombo uint16_t k[32], eff_k[32], xleft[33], xright[33], fxleft[32]; 2959670f1da3SVíctor Colombo 2960670f1da3SVíctor Colombo for (int i = 3; i >= 0; i--) { 2961670f1da3SVíctor Colombo k[i] = key & 0xffff; 2962670f1da3SVíctor Colombo key >>= 16; 2963670f1da3SVíctor Colombo } 2964670f1da3SVíctor Colombo xleft[0] = x & 0xffff; 2965670f1da3SVíctor Colombo xright[0] = (x >> 16) & 0xffff; 2966670f1da3SVíctor Colombo 2967670f1da3SVíctor Colombo for (int i = 0; i < 28; i++) { 2968670f1da3SVíctor Colombo z = (z0 >> (63 - i)) & 1; 2969670f1da3SVíctor Colombo temp = ror16(k[i + 3], 3) ^ k[i + 1]; 2970670f1da3SVíctor Colombo k[i + 4] = c ^ z ^ k[i] ^ temp ^ ror16(temp, 1); 2971670f1da3SVíctor Colombo } 2972670f1da3SVíctor Colombo 2973670f1da3SVíctor Colombo for (int i = 0; i < 8; i++) { 2974670f1da3SVíctor Colombo eff_k[4 * i + 0] = k[4 * i + ((0 + lane) % 4)]; 2975670f1da3SVíctor Colombo eff_k[4 * i + 1] = k[4 * i + ((1 + lane) % 4)]; 2976670f1da3SVíctor Colombo eff_k[4 * i + 2] = k[4 * i + ((2 + lane) % 4)]; 2977670f1da3SVíctor Colombo eff_k[4 * i + 3] = k[4 * i + ((3 + lane) % 4)]; 2978670f1da3SVíctor Colombo } 2979670f1da3SVíctor Colombo 2980670f1da3SVíctor Colombo for (int i = 0; i < 32; i++) { 2981670f1da3SVíctor Colombo fxleft[i] = (rol16(xleft[i], 1) & 2982670f1da3SVíctor Colombo rol16(xleft[i], 8)) ^ rol16(xleft[i], 2); 2983670f1da3SVíctor Colombo xleft[i + 1] = xright[i] ^ fxleft[i] ^ eff_k[i]; 2984670f1da3SVíctor Colombo xright[i + 1] = xleft[i]; 2985670f1da3SVíctor Colombo } 2986670f1da3SVíctor Colombo 2987670f1da3SVíctor Colombo return (((uint32_t)xright[32]) << 16) | xleft[32]; 2988670f1da3SVíctor Colombo } 2989670f1da3SVíctor Colombo 2990670f1da3SVíctor Colombo static uint64_t hash_digest(uint64_t ra, uint64_t rb, uint64_t key) 2991670f1da3SVíctor Colombo { 2992670f1da3SVíctor Colombo uint64_t stage0_h = 0ULL, stage0_l = 0ULL; 2993670f1da3SVíctor Colombo uint64_t stage1_h, stage1_l; 2994670f1da3SVíctor Colombo 2995670f1da3SVíctor Colombo for (int i = 0; i < 4; i++) { 2996670f1da3SVíctor Colombo stage0_h |= ror64(rb & 0xff, 8 * (2 * i + 1)); 2997670f1da3SVíctor Colombo stage0_h |= ((ra >> 32) & 0xff) << (8 * 2 * i); 2998670f1da3SVíctor Colombo stage0_l |= ror64((rb >> 32) & 0xff, 8 * (2 * i + 1)); 2999670f1da3SVíctor Colombo stage0_l |= (ra & 0xff) << (8 * 2 * i); 3000670f1da3SVíctor Colombo rb >>= 8; 3001670f1da3SVíctor Colombo ra >>= 8; 3002670f1da3SVíctor Colombo } 3003670f1da3SVíctor Colombo 3004670f1da3SVíctor Colombo stage1_h = (uint64_t)helper_SIMON_LIKE_32_64(stage0_h >> 32, key, 0) << 32; 3005670f1da3SVíctor Colombo stage1_h |= helper_SIMON_LIKE_32_64(stage0_h, key, 1); 3006670f1da3SVíctor Colombo stage1_l = (uint64_t)helper_SIMON_LIKE_32_64(stage0_l >> 32, key, 2) << 32; 3007670f1da3SVíctor Colombo stage1_l |= helper_SIMON_LIKE_32_64(stage0_l, key, 3); 3008670f1da3SVíctor Colombo 3009670f1da3SVíctor Colombo return stage1_h ^ stage1_l; 3010670f1da3SVíctor Colombo } 3011670f1da3SVíctor Colombo 30124091fabfSNicholas Miehlbradt static void do_hash(CPUPPCState *env, target_ulong ea, target_ulong ra, 30134091fabfSNicholas Miehlbradt target_ulong rb, uint64_t key, bool store) 30144091fabfSNicholas Miehlbradt { 30154091fabfSNicholas Miehlbradt uint64_t calculated_hash = hash_digest(ra, rb, key), loaded_hash; 30164091fabfSNicholas Miehlbradt 30174091fabfSNicholas Miehlbradt if (store) { 30184091fabfSNicholas Miehlbradt cpu_stq_data_ra(env, ea, calculated_hash, GETPC()); 30194091fabfSNicholas Miehlbradt } else { 30204091fabfSNicholas Miehlbradt loaded_hash = cpu_ldq_data_ra(env, ea, GETPC()); 30214091fabfSNicholas Miehlbradt if (loaded_hash != calculated_hash) { 30224091fabfSNicholas Miehlbradt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 30234091fabfSNicholas Miehlbradt POWERPC_EXCP_TRAP, GETPC()); 30244091fabfSNicholas Miehlbradt } 30254091fabfSNicholas Miehlbradt } 30264091fabfSNicholas Miehlbradt } 30274091fabfSNicholas Miehlbradt 3028670f1da3SVíctor Colombo #include "qemu/guest-random.h" 3029670f1da3SVíctor Colombo 30304091fabfSNicholas Miehlbradt #ifdef TARGET_PPC64 30314091fabfSNicholas Miehlbradt #define HELPER_HASH(op, key, store, dexcr_aspect) \ 3032670f1da3SVíctor Colombo void helper_##op(CPUPPCState *env, target_ulong ea, target_ulong ra, \ 3033670f1da3SVíctor Colombo target_ulong rb) \ 3034670f1da3SVíctor Colombo { \ 30354091fabfSNicholas Miehlbradt if (env->msr & R_MSR_PR_MASK) { \ 30364091fabfSNicholas Miehlbradt if (!(env->spr[SPR_DEXCR] & R_DEXCR_PRO_##dexcr_aspect##_MASK || \ 30374091fabfSNicholas Miehlbradt env->spr[SPR_HDEXCR] & R_HDEXCR_ENF_##dexcr_aspect##_MASK)) \ 30384091fabfSNicholas Miehlbradt return; \ 30394091fabfSNicholas Miehlbradt } else if (!(env->msr & R_MSR_HV_MASK)) { \ 30404091fabfSNicholas Miehlbradt if (!(env->spr[SPR_DEXCR] & R_DEXCR_PNH_##dexcr_aspect##_MASK || \ 30414091fabfSNicholas Miehlbradt env->spr[SPR_HDEXCR] & R_HDEXCR_ENF_##dexcr_aspect##_MASK)) \ 30424091fabfSNicholas Miehlbradt return; \ 30434091fabfSNicholas Miehlbradt } else if (!(env->msr & R_MSR_S_MASK)) { \ 30444091fabfSNicholas Miehlbradt if (!(env->spr[SPR_HDEXCR] & R_HDEXCR_HNU_##dexcr_aspect##_MASK)) \ 30454091fabfSNicholas Miehlbradt return; \ 30464091fabfSNicholas Miehlbradt } \ 3047670f1da3SVíctor Colombo \ 30484091fabfSNicholas Miehlbradt do_hash(env, ea, ra, rb, key, store); \ 3049670f1da3SVíctor Colombo } 30504091fabfSNicholas Miehlbradt #else 30514091fabfSNicholas Miehlbradt #define HELPER_HASH(op, key, store, dexcr_aspect) \ 30524091fabfSNicholas Miehlbradt void helper_##op(CPUPPCState *env, target_ulong ea, target_ulong ra, \ 30534091fabfSNicholas Miehlbradt target_ulong rb) \ 30544091fabfSNicholas Miehlbradt { \ 30554091fabfSNicholas Miehlbradt do_hash(env, ea, ra, rb, key, store); \ 30564091fabfSNicholas Miehlbradt } 30574091fabfSNicholas Miehlbradt #endif /* TARGET_PPC64 */ 3058670f1da3SVíctor Colombo 30594091fabfSNicholas Miehlbradt HELPER_HASH(HASHST, env->spr[SPR_HASHKEYR], true, NPHIE) 30604091fabfSNicholas Miehlbradt HELPER_HASH(HASHCHK, env->spr[SPR_HASHKEYR], false, NPHIE) 30614091fabfSNicholas Miehlbradt HELPER_HASH(HASHSTP, env->spr[SPR_HASHPKEYR], true, PHIE) 30624091fabfSNicholas Miehlbradt HELPER_HASH(HASHCHKP, env->spr[SPR_HASHPKEYR], false, PHIE) 3063049b4ad6SVaibhav Jain #endif /* CONFIG_TCG */ 3064670f1da3SVíctor Colombo 3065ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 3066ad71ed68SBlue Swirl 30672b44e219SBruno Larsen (billionai) #ifdef CONFIG_TCG 3068ad71ed68SBlue Swirl 3069ad71ed68SBlue Swirl /* Embedded.Processor Control */ 3070ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb) 3071ad71ed68SBlue Swirl { 3072ad71ed68SBlue Swirl int msg = rb & DBELL_TYPE_MASK; 3073ad71ed68SBlue Swirl int irq = -1; 3074ad71ed68SBlue Swirl 3075ad71ed68SBlue Swirl switch (msg) { 3076ad71ed68SBlue Swirl case DBELL_TYPE_DBELL: 3077ad71ed68SBlue Swirl irq = PPC_INTERRUPT_DOORBELL; 3078ad71ed68SBlue Swirl break; 3079ad71ed68SBlue Swirl case DBELL_TYPE_DBELL_CRIT: 3080ad71ed68SBlue Swirl irq = PPC_INTERRUPT_CDOORBELL; 3081ad71ed68SBlue Swirl break; 3082ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL: 3083ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_CRIT: 3084ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_MC: 3085ad71ed68SBlue Swirl /* XXX implement */ 3086ad71ed68SBlue Swirl default: 3087ad71ed68SBlue Swirl break; 3088ad71ed68SBlue Swirl } 3089ad71ed68SBlue Swirl 3090ad71ed68SBlue Swirl return irq; 3091ad71ed68SBlue Swirl } 3092ad71ed68SBlue Swirl 3093e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb) 3094ad71ed68SBlue Swirl { 3095ad71ed68SBlue Swirl int irq = dbell2irq(rb); 3096ad71ed68SBlue Swirl 3097ad71ed68SBlue Swirl if (irq < 0) { 3098ad71ed68SBlue Swirl return; 3099ad71ed68SBlue Swirl } 3100ad71ed68SBlue Swirl 31017b694df6SMatheus Ferst ppc_set_irq(env_archcpu(env), irq, 0); 3102ad71ed68SBlue Swirl } 3103ad71ed68SBlue Swirl 3104ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb) 3105ad71ed68SBlue Swirl { 3106ad71ed68SBlue Swirl int irq = dbell2irq(rb); 3107ad71ed68SBlue Swirl int pir = rb & DBELL_PIRTAG_MASK; 3108182735efSAndreas Färber CPUState *cs; 3109ad71ed68SBlue Swirl 3110ad71ed68SBlue Swirl if (irq < 0) { 3111ad71ed68SBlue Swirl return; 3112ad71ed68SBlue Swirl } 3113ad71ed68SBlue Swirl 3114f1c29ebcSThomas Huth qemu_mutex_lock_iothread(); 3115bdc44640SAndreas Färber CPU_FOREACH(cs) { 3116182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 3117182735efSAndreas Färber CPUPPCState *cenv = &cpu->env; 3118182735efSAndreas Färber 3119ad71ed68SBlue Swirl if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { 31207b694df6SMatheus Ferst ppc_set_irq(cpu, irq, 1); 3121ad71ed68SBlue Swirl } 3122ad71ed68SBlue Swirl } 3123f1c29ebcSThomas Huth qemu_mutex_unlock_iothread(); 3124ad71ed68SBlue Swirl } 31257af1e7b0SCédric Le Goater 31267af1e7b0SCédric Le Goater /* Server Processor Control */ 31277af1e7b0SCédric Le Goater 31285ba7ba1dSCédric Le Goater static bool dbell_type_server(target_ulong rb) 31295ba7ba1dSCédric Le Goater { 313047733729SDavid Gibson /* 313147733729SDavid Gibson * A Directed Hypervisor Doorbell message is sent only if the 31327af1e7b0SCédric Le Goater * message type is 5. All other types are reserved and the 313347733729SDavid Gibson * instruction is a no-op 313447733729SDavid Gibson */ 31355ba7ba1dSCédric Le Goater return (rb & DBELL_TYPE_MASK) == DBELL_TYPE_DBELL_SERVER; 31367af1e7b0SCédric Le Goater } 31377af1e7b0SCédric Le Goater 31387af1e7b0SCédric Le Goater void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) 31397af1e7b0SCédric Le Goater { 31405ba7ba1dSCédric Le Goater if (!dbell_type_server(rb)) { 31417af1e7b0SCédric Le Goater return; 31427af1e7b0SCédric Le Goater } 31437af1e7b0SCédric Le Goater 31447b694df6SMatheus Ferst ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0); 31457af1e7b0SCédric Le Goater } 31467af1e7b0SCédric Le Goater 31475ba7ba1dSCédric Le Goater static void book3s_msgsnd_common(int pir, int irq) 31487af1e7b0SCédric Le Goater { 31497af1e7b0SCédric Le Goater CPUState *cs; 31507af1e7b0SCédric Le Goater 31517af1e7b0SCédric Le Goater qemu_mutex_lock_iothread(); 31527af1e7b0SCédric Le Goater CPU_FOREACH(cs) { 31537af1e7b0SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 31547af1e7b0SCédric Le Goater CPUPPCState *cenv = &cpu->env; 31557af1e7b0SCédric Le Goater 31567af1e7b0SCédric Le Goater /* TODO: broadcast message to all threads of the same processor */ 31577af1e7b0SCédric Le Goater if (cenv->spr_cb[SPR_PIR].default_value == pir) { 31587b694df6SMatheus Ferst ppc_set_irq(cpu, irq, 1); 31597af1e7b0SCédric Le Goater } 31607af1e7b0SCédric Le Goater } 31617af1e7b0SCédric Le Goater qemu_mutex_unlock_iothread(); 31627af1e7b0SCédric Le Goater } 31635ba7ba1dSCédric Le Goater 31645ba7ba1dSCédric Le Goater void helper_book3s_msgsnd(target_ulong rb) 31655ba7ba1dSCédric Le Goater { 31665ba7ba1dSCédric Le Goater int pir = rb & DBELL_PROCIDTAG_MASK; 31675ba7ba1dSCédric Le Goater 31685ba7ba1dSCédric Le Goater if (!dbell_type_server(rb)) { 31695ba7ba1dSCédric Le Goater return; 31705ba7ba1dSCédric Le Goater } 31715ba7ba1dSCédric Le Goater 31725ba7ba1dSCédric Le Goater book3s_msgsnd_common(pir, PPC_INTERRUPT_HDOORBELL); 31735ba7ba1dSCédric Le Goater } 31745ba7ba1dSCédric Le Goater 31755ba7ba1dSCédric Le Goater #if defined(TARGET_PPC64) 31765ba7ba1dSCédric Le Goater void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb) 31775ba7ba1dSCédric Le Goater { 3178493028d8SCédric Le Goater helper_hfscr_facility_check(env, HFSCR_MSGP, "msgclrp", HFSCR_IC_MSGP); 3179493028d8SCédric Le Goater 31805ba7ba1dSCédric Le Goater if (!dbell_type_server(rb)) { 31815ba7ba1dSCédric Le Goater return; 31825ba7ba1dSCédric Le Goater } 31835ba7ba1dSCédric Le Goater 31842e985555SNicholas Piggin ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_DOORBELL, 0); 31855ba7ba1dSCédric Le Goater } 31865ba7ba1dSCédric Le Goater 31875ba7ba1dSCédric Le Goater /* 3188d24e80b2SNicholas Piggin * sends a message to another thread on the same 31895ba7ba1dSCédric Le Goater * multi-threaded processor 31905ba7ba1dSCédric Le Goater */ 31915ba7ba1dSCédric Le Goater void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb) 31925ba7ba1dSCédric Le Goater { 3193d24e80b2SNicholas Piggin CPUState *cs = env_cpu(env); 3194d24e80b2SNicholas Piggin PowerPCCPU *cpu = POWERPC_CPU(cs); 3195d24e80b2SNicholas Piggin CPUState *ccs; 3196d24e80b2SNicholas Piggin uint32_t nr_threads = cs->nr_threads; 3197d24e80b2SNicholas Piggin int ttir = rb & PPC_BITMASK(57, 63); 31985ba7ba1dSCédric Le Goater 3199493028d8SCédric Le Goater helper_hfscr_facility_check(env, HFSCR_MSGP, "msgsndp", HFSCR_IC_MSGP); 3200493028d8SCédric Le Goater 3201d24e80b2SNicholas Piggin if (!dbell_type_server(rb) || ttir >= nr_threads) { 32025ba7ba1dSCédric Le Goater return; 32035ba7ba1dSCédric Le Goater } 32045ba7ba1dSCédric Le Goater 3205d24e80b2SNicholas Piggin if (nr_threads == 1) { 3206d24e80b2SNicholas Piggin ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, 1); 3207d24e80b2SNicholas Piggin return; 3208d24e80b2SNicholas Piggin } 32095ba7ba1dSCédric Le Goater 3210d24e80b2SNicholas Piggin /* Does iothread need to be locked for walking CPU list? */ 3211d24e80b2SNicholas Piggin qemu_mutex_lock_iothread(); 3212d24e80b2SNicholas Piggin THREAD_SIBLING_FOREACH(cs, ccs) { 3213d24e80b2SNicholas Piggin PowerPCCPU *ccpu = POWERPC_CPU(ccs); 3214d24e80b2SNicholas Piggin uint32_t thread_id = ppc_cpu_tir(ccpu); 3215d24e80b2SNicholas Piggin 3216d24e80b2SNicholas Piggin if (ttir == thread_id) { 3217d24e80b2SNicholas Piggin ppc_set_irq(ccpu, PPC_INTERRUPT_DOORBELL, 1); 3218d24e80b2SNicholas Piggin qemu_mutex_unlock_iothread(); 3219d24e80b2SNicholas Piggin return; 3220d24e80b2SNicholas Piggin } 3221d24e80b2SNicholas Piggin } 3222d24e80b2SNicholas Piggin 3223d24e80b2SNicholas Piggin g_assert_not_reached(); 32245ba7ba1dSCédric Le Goater } 3225996473e4SRichard Henderson #endif /* TARGET_PPC64 */ 32260f3110faSRichard Henderson 32270f3110faSRichard Henderson void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, 32280f3110faSRichard Henderson MMUAccessType access_type, 32290f3110faSRichard Henderson int mmu_idx, uintptr_t retaddr) 32300f3110faSRichard Henderson { 32310f3110faSRichard Henderson CPUPPCState *env = cs->env_ptr; 323229c4a336SFabiano Rosas uint32_t insn; 323329c4a336SFabiano Rosas 323429c4a336SFabiano Rosas /* Restore state and reload the insn we executed, for filling in DSISR. */ 32353d419a4dSRichard Henderson cpu_restore_state(cs, retaddr); 3236888050cfSNicholas Piggin insn = ppc_ldl_code(env, env->nip); 32370f3110faSRichard Henderson 3238a7e3af13SRichard Henderson switch (env->mmu_model) { 3239a7e3af13SRichard Henderson case POWERPC_MMU_SOFT_4xx: 3240a7e3af13SRichard Henderson env->spr[SPR_40x_DEAR] = vaddr; 3241a7e3af13SRichard Henderson break; 3242a7e3af13SRichard Henderson case POWERPC_MMU_BOOKE: 3243a7e3af13SRichard Henderson case POWERPC_MMU_BOOKE206: 3244a7e3af13SRichard Henderson env->spr[SPR_BOOKE_DEAR] = vaddr; 3245a7e3af13SRichard Henderson break; 3246a7e3af13SRichard Henderson default: 3247a7e3af13SRichard Henderson env->spr[SPR_DAR] = vaddr; 3248a7e3af13SRichard Henderson break; 3249a7e3af13SRichard Henderson } 3250a7e3af13SRichard Henderson 32510f3110faSRichard Henderson cs->exception_index = POWERPC_EXCP_ALIGN; 325229c4a336SFabiano Rosas env->error_code = insn & 0x03FF0000; 325329c4a336SFabiano Rosas cpu_loop_exit(cs); 32540f3110faSRichard Henderson } 3255996473e4SRichard Henderson #endif /* CONFIG_TCG */ 3256996473e4SRichard Henderson #endif /* !CONFIG_USER_ONLY */ 3257