1ad71ed68SBlue Swirl /* 2ad71ed68SBlue Swirl * PowerPC exception emulation helpers for QEMU. 3ad71ed68SBlue Swirl * 4ad71ed68SBlue Swirl * Copyright (c) 2003-2007 Jocelyn Mayer 5ad71ed68SBlue Swirl * 6ad71ed68SBlue Swirl * This library is free software; you can redistribute it and/or 7ad71ed68SBlue Swirl * modify it under the terms of the GNU Lesser General Public 8ad71ed68SBlue Swirl * License as published by the Free Software Foundation; either 9ad71ed68SBlue Swirl * version 2 of the License, or (at your option) any later version. 10ad71ed68SBlue Swirl * 11ad71ed68SBlue Swirl * This library is distributed in the hope that it will be useful, 12ad71ed68SBlue Swirl * but WITHOUT ANY WARRANTY; without even the implied warranty of 13ad71ed68SBlue Swirl * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14ad71ed68SBlue Swirl * Lesser General Public License for more details. 15ad71ed68SBlue Swirl * 16ad71ed68SBlue Swirl * You should have received a copy of the GNU Lesser General Public 17ad71ed68SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18ad71ed68SBlue Swirl */ 190d75590dSPeter Maydell #include "qemu/osdep.h" 20f1c29ebcSThomas Huth #include "qemu/main-loop.h" 21ad71ed68SBlue Swirl #include "cpu.h" 222ef6175aSRichard Henderson #include "exec/helper-proto.h" 2363c91552SPaolo Bonzini #include "exec/exec-all.h" 24f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h" 250f3110faSRichard Henderson #include "internal.h" 26ad71ed68SBlue Swirl #include "helper_regs.h" 27ad71ed68SBlue Swirl 28ad71ed68SBlue Swirl //#define DEBUG_OP 2948880da6SPaolo Bonzini //#define DEBUG_SOFTWARE_TLB 30ad71ed68SBlue Swirl //#define DEBUG_EXCEPTIONS 31ad71ed68SBlue Swirl 32c79c73f6SBlue Swirl #ifdef DEBUG_EXCEPTIONS 33c79c73f6SBlue Swirl # define LOG_EXCP(...) qemu_log(__VA_ARGS__) 34c79c73f6SBlue Swirl #else 35c79c73f6SBlue Swirl # define LOG_EXCP(...) do { } while (0) 36c79c73f6SBlue Swirl #endif 37c79c73f6SBlue Swirl 38c79c73f6SBlue Swirl /*****************************************************************************/ 39c79c73f6SBlue Swirl /* Exception processing */ 40c79c73f6SBlue Swirl #if defined(CONFIG_USER_ONLY) 4197a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs) 42c79c73f6SBlue Swirl { 4397a8ea5aSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 4497a8ea5aSAndreas Färber CPUPPCState *env = &cpu->env; 4597a8ea5aSAndreas Färber 4627103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 47c79c73f6SBlue Swirl env->error_code = 0; 48c79c73f6SBlue Swirl } 49c79c73f6SBlue Swirl 50458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env) 51c79c73f6SBlue Swirl { 5227103424SAndreas Färber CPUState *cs = CPU(ppc_env_get_cpu(env)); 5327103424SAndreas Färber 5427103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 55c79c73f6SBlue Swirl env->error_code = 0; 56c79c73f6SBlue Swirl } 57c79c73f6SBlue Swirl #else /* defined(CONFIG_USER_ONLY) */ 58c79c73f6SBlue Swirl static inline void dump_syscall(CPUPPCState *env) 59c79c73f6SBlue Swirl { 60c79c73f6SBlue Swirl qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64 61c79c73f6SBlue Swirl " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 62c79c73f6SBlue Swirl " nip=" TARGET_FMT_lx "\n", 63c79c73f6SBlue Swirl ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), 64c79c73f6SBlue Swirl ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), 65c79c73f6SBlue Swirl ppc_dump_gpr(env, 6), env->nip); 66c79c73f6SBlue Swirl } 67c79c73f6SBlue Swirl 68dead760bSBenjamin Herrenschmidt static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, 69dead760bSBenjamin Herrenschmidt target_ulong *msr) 70dead760bSBenjamin Herrenschmidt { 71dead760bSBenjamin Herrenschmidt /* We no longer are in a PM state */ 721e7fd61dSBenjamin Herrenschmidt env->resume_as_sreset = false; 73dead760bSBenjamin Herrenschmidt 74dead760bSBenjamin Herrenschmidt /* Pretend to be returning from doze always as we don't lose state */ 75dead760bSBenjamin Herrenschmidt *msr |= (0x1ull << (63 - 47)); 76dead760bSBenjamin Herrenschmidt 77dead760bSBenjamin Herrenschmidt /* Machine checks are sent normally */ 78dead760bSBenjamin Herrenschmidt if (excp == POWERPC_EXCP_MCHECK) { 79dead760bSBenjamin Herrenschmidt return excp; 80dead760bSBenjamin Herrenschmidt } 81dead760bSBenjamin Herrenschmidt switch (excp) { 82dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_RESET: 83dead760bSBenjamin Herrenschmidt *msr |= 0x4ull << (63 - 45); 84dead760bSBenjamin Herrenschmidt break; 85dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_EXTERNAL: 86dead760bSBenjamin Herrenschmidt *msr |= 0x8ull << (63 - 45); 87dead760bSBenjamin Herrenschmidt break; 88dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_DECR: 89dead760bSBenjamin Herrenschmidt *msr |= 0x6ull << (63 - 45); 90dead760bSBenjamin Herrenschmidt break; 91dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_SDOOR: 92dead760bSBenjamin Herrenschmidt *msr |= 0x5ull << (63 - 45); 93dead760bSBenjamin Herrenschmidt break; 94dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_SDOOR_HV: 95dead760bSBenjamin Herrenschmidt *msr |= 0x3ull << (63 - 45); 96dead760bSBenjamin Herrenschmidt break; 97dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_HV_MAINT: 98dead760bSBenjamin Herrenschmidt *msr |= 0xaull << (63 - 45); 99dead760bSBenjamin Herrenschmidt break; 100d8ce5fd6SBenjamin Herrenschmidt case POWERPC_EXCP_HVIRT: 101d8ce5fd6SBenjamin Herrenschmidt *msr |= 0x9ull << (63 - 45); 102d8ce5fd6SBenjamin Herrenschmidt break; 103dead760bSBenjamin Herrenschmidt default: 104dead760bSBenjamin Herrenschmidt cpu_abort(cs, "Unsupported exception %d in Power Save mode\n", 105dead760bSBenjamin Herrenschmidt excp); 106dead760bSBenjamin Herrenschmidt } 107dead760bSBenjamin Herrenschmidt return POWERPC_EXCP_RESET; 108dead760bSBenjamin Herrenschmidt } 109dead760bSBenjamin Herrenschmidt 110*2586a4d7SFabiano Rosas static uint64_t ppc_excp_vector_offset(CPUState *cs, int ail) 111*2586a4d7SFabiano Rosas { 112*2586a4d7SFabiano Rosas uint64_t offset = 0; 113*2586a4d7SFabiano Rosas 114*2586a4d7SFabiano Rosas switch (ail) { 115*2586a4d7SFabiano Rosas case AIL_0001_8000: 116*2586a4d7SFabiano Rosas offset = 0x18000; 117*2586a4d7SFabiano Rosas break; 118*2586a4d7SFabiano Rosas case AIL_C000_0000_0000_4000: 119*2586a4d7SFabiano Rosas offset = 0xc000000000004000ull; 120*2586a4d7SFabiano Rosas break; 121*2586a4d7SFabiano Rosas default: 122*2586a4d7SFabiano Rosas cpu_abort(cs, "Invalid AIL combination %d\n", ail); 123*2586a4d7SFabiano Rosas break; 124*2586a4d7SFabiano Rosas } 125*2586a4d7SFabiano Rosas 126*2586a4d7SFabiano Rosas return offset; 127*2586a4d7SFabiano Rosas } 128dead760bSBenjamin Herrenschmidt 129c79c73f6SBlue Swirl /* Note that this function should be greatly optimized 130c79c73f6SBlue Swirl * when called with a constant excp, from ppc_hw_interrupt 131c79c73f6SBlue Swirl */ 1325c26a5b3SAndreas Färber static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) 133c79c73f6SBlue Swirl { 13427103424SAndreas Färber CPUState *cs = CPU(cpu); 1355c26a5b3SAndreas Färber CPUPPCState *env = &cpu->env; 136c79c73f6SBlue Swirl target_ulong msr, new_msr, vector; 1376d49d6d4SBenjamin Herrenschmidt int srr0, srr1, asrr0, asrr1, lev, ail; 1386d49d6d4SBenjamin Herrenschmidt bool lpes0; 139c79c73f6SBlue Swirl 140c79c73f6SBlue Swirl qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx 141c79c73f6SBlue Swirl " => %08x (%02x)\n", env->nip, excp, env->error_code); 142c79c73f6SBlue Swirl 143c79c73f6SBlue Swirl /* new srr1 value excluding must-be-zero bits */ 144a1bb7384SScott Wood if (excp_model == POWERPC_EXCP_BOOKE) { 145a1bb7384SScott Wood msr = env->msr; 146a1bb7384SScott Wood } else { 147c79c73f6SBlue Swirl msr = env->msr & ~0x783f0000ULL; 148a1bb7384SScott Wood } 149c79c73f6SBlue Swirl 1506d49d6d4SBenjamin Herrenschmidt /* new interrupt handler msr preserves existing HV and ME unless 1516d49d6d4SBenjamin Herrenschmidt * explicitly overriden 1526d49d6d4SBenjamin Herrenschmidt */ 1536d49d6d4SBenjamin Herrenschmidt new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB); 154c79c73f6SBlue Swirl 155c79c73f6SBlue Swirl /* target registers */ 156c79c73f6SBlue Swirl srr0 = SPR_SRR0; 157c79c73f6SBlue Swirl srr1 = SPR_SRR1; 158c79c73f6SBlue Swirl asrr0 = -1; 159c79c73f6SBlue Swirl asrr1 = -1; 160c79c73f6SBlue Swirl 16121c0d66aSBenjamin Herrenschmidt /* 16221c0d66aSBenjamin Herrenschmidt * check for special resume at 0x100 from doze/nap/sleep/winkle on 16321c0d66aSBenjamin Herrenschmidt * P7/P8/P9 16421c0d66aSBenjamin Herrenschmidt */ 1651e7fd61dSBenjamin Herrenschmidt if (env->resume_as_sreset) { 166dead760bSBenjamin Herrenschmidt excp = powerpc_reset_wakeup(cs, env, excp, &msr); 1677778a575SBenjamin Herrenschmidt } 1687778a575SBenjamin Herrenschmidt 1695c94b2a5SCédric Le Goater /* Exception targetting modifiers 1705c94b2a5SCédric Le Goater * 171a790e82bSBenjamin Herrenschmidt * LPES0 is supported on POWER7/8/9 1726d49d6d4SBenjamin Herrenschmidt * LPES1 is not supported (old iSeries mode) 1736d49d6d4SBenjamin Herrenschmidt * 1746d49d6d4SBenjamin Herrenschmidt * On anything else, we behave as if LPES0 is 1 1756d49d6d4SBenjamin Herrenschmidt * (externals don't alter MSR:HV) 1766d49d6d4SBenjamin Herrenschmidt * 1775c94b2a5SCédric Le Goater * AIL is initialized here but can be cleared by 1785c94b2a5SCédric Le Goater * selected exceptions 1795c94b2a5SCédric Le Goater */ 1805c94b2a5SCédric Le Goater #if defined(TARGET_PPC64) 1815c94b2a5SCédric Le Goater if (excp_model == POWERPC_EXCP_POWER7 || 182a790e82bSBenjamin Herrenschmidt excp_model == POWERPC_EXCP_POWER8 || 183a790e82bSBenjamin Herrenschmidt excp_model == POWERPC_EXCP_POWER9) { 1846d49d6d4SBenjamin Herrenschmidt lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 185a790e82bSBenjamin Herrenschmidt if (excp_model != POWERPC_EXCP_POWER7) { 1865c94b2a5SCédric Le Goater ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT; 1875c94b2a5SCédric Le Goater } else { 1885c94b2a5SCédric Le Goater ail = 0; 1895c94b2a5SCédric Le Goater } 1905c94b2a5SCédric Le Goater } else 1915c94b2a5SCédric Le Goater #endif /* defined(TARGET_PPC64) */ 1925c94b2a5SCédric Le Goater { 1936d49d6d4SBenjamin Herrenschmidt lpes0 = true; 1945c94b2a5SCédric Le Goater ail = 0; 1955c94b2a5SCédric Le Goater } 1965c94b2a5SCédric Le Goater 1979b2faddaSBenjamin Herrenschmidt /* Hypervisor emulation assistance interrupt only exists on server 1989b2faddaSBenjamin Herrenschmidt * arch 2.05 server or later. We also don't want to generate it if 1999b2faddaSBenjamin Herrenschmidt * we don't have HVB in msr_mask (PAPR mode). 2009b2faddaSBenjamin Herrenschmidt */ 2019b2faddaSBenjamin Herrenschmidt if (excp == POWERPC_EXCP_HV_EMU 2029b2faddaSBenjamin Herrenschmidt #if defined(TARGET_PPC64) 2039b2faddaSBenjamin Herrenschmidt && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB)) 2049b2faddaSBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 2059b2faddaSBenjamin Herrenschmidt 2069b2faddaSBenjamin Herrenschmidt ) { 2079b2faddaSBenjamin Herrenschmidt excp = POWERPC_EXCP_PROGRAM; 2089b2faddaSBenjamin Herrenschmidt } 2099b2faddaSBenjamin Herrenschmidt 210c79c73f6SBlue Swirl switch (excp) { 211c79c73f6SBlue Swirl case POWERPC_EXCP_NONE: 212c79c73f6SBlue Swirl /* Should never happen */ 213c79c73f6SBlue Swirl return; 214c79c73f6SBlue Swirl case POWERPC_EXCP_CRITICAL: /* Critical input */ 215c79c73f6SBlue Swirl switch (excp_model) { 216c79c73f6SBlue Swirl case POWERPC_EXCP_40x: 217c79c73f6SBlue Swirl srr0 = SPR_40x_SRR2; 218c79c73f6SBlue Swirl srr1 = SPR_40x_SRR3; 219c79c73f6SBlue Swirl break; 220c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 221c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 222c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 223c79c73f6SBlue Swirl break; 224c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 225c79c73f6SBlue Swirl break; 226c79c73f6SBlue Swirl default: 227c79c73f6SBlue Swirl goto excp_invalid; 228c79c73f6SBlue Swirl } 229bd6fefe7SBenjamin Herrenschmidt break; 230c79c73f6SBlue Swirl case POWERPC_EXCP_MCHECK: /* Machine check exception */ 231c79c73f6SBlue Swirl if (msr_me == 0) { 232c79c73f6SBlue Swirl /* Machine check exception is not enabled. 233c79c73f6SBlue Swirl * Enter checkstop state. 234c79c73f6SBlue Swirl */ 235c79c73f6SBlue Swirl fprintf(stderr, "Machine check while not allowed. " 236c79c73f6SBlue Swirl "Entering checkstop state\n"); 237013a2942SPaolo Bonzini if (qemu_log_separate()) { 238013a2942SPaolo Bonzini qemu_log("Machine check while not allowed. " 239013a2942SPaolo Bonzini "Entering checkstop state\n"); 240c79c73f6SBlue Swirl } 241259186a7SAndreas Färber cs->halted = 1; 242044897efSRichard Purdie cpu_interrupt_exittb(cs); 243c79c73f6SBlue Swirl } 24410c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 24510c21b5cSNicholas Piggin /* ISA specifies HV, but can be delivered to guest with HV clear 24610c21b5cSNicholas Piggin * (e.g., see FWNMI in PAPR). 24710c21b5cSNicholas Piggin */ 248c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 24910c21b5cSNicholas Piggin } 2505c94b2a5SCédric Le Goater ail = 0; 251c79c73f6SBlue Swirl 252c79c73f6SBlue Swirl /* machine check exceptions don't have ME set */ 253c79c73f6SBlue Swirl new_msr &= ~((target_ulong)1 << MSR_ME); 254c79c73f6SBlue Swirl 255c79c73f6SBlue Swirl /* XXX: should also have something loaded in DAR / DSISR */ 256c79c73f6SBlue Swirl switch (excp_model) { 257c79c73f6SBlue Swirl case POWERPC_EXCP_40x: 258c79c73f6SBlue Swirl srr0 = SPR_40x_SRR2; 259c79c73f6SBlue Swirl srr1 = SPR_40x_SRR3; 260c79c73f6SBlue Swirl break; 261c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 262a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 263c79c73f6SBlue Swirl srr0 = SPR_BOOKE_MCSRR0; 264c79c73f6SBlue Swirl srr1 = SPR_BOOKE_MCSRR1; 265c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 266c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 267c79c73f6SBlue Swirl break; 268c79c73f6SBlue Swirl default: 269c79c73f6SBlue Swirl break; 270c79c73f6SBlue Swirl } 271bd6fefe7SBenjamin Herrenschmidt break; 272c79c73f6SBlue Swirl case POWERPC_EXCP_DSI: /* Data storage exception */ 273c79c73f6SBlue Swirl LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx 274c79c73f6SBlue Swirl "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); 275bd6fefe7SBenjamin Herrenschmidt break; 276c79c73f6SBlue Swirl case POWERPC_EXCP_ISI: /* Instruction storage exception */ 277c79c73f6SBlue Swirl LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx 278c79c73f6SBlue Swirl "\n", msr, env->nip); 279c79c73f6SBlue Swirl msr |= env->error_code; 280bd6fefe7SBenjamin Herrenschmidt break; 281c79c73f6SBlue Swirl case POWERPC_EXCP_EXTERNAL: /* External input */ 282fdfba1a2SEdgar E. Iglesias cs = CPU(cpu); 283fdfba1a2SEdgar E. Iglesias 2846d49d6d4SBenjamin Herrenschmidt if (!lpes0) { 285c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 2866d49d6d4SBenjamin Herrenschmidt new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 2876d49d6d4SBenjamin Herrenschmidt srr0 = SPR_HSRR0; 2886d49d6d4SBenjamin Herrenschmidt srr1 = SPR_HSRR1; 289c79c73f6SBlue Swirl } 29068c2dd70SAlexander Graf if (env->mpic_proxy) { 29168c2dd70SAlexander Graf /* IACK the IRQ on delivery */ 292fdfba1a2SEdgar E. Iglesias env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack); 29368c2dd70SAlexander Graf } 294bd6fefe7SBenjamin Herrenschmidt break; 295c79c73f6SBlue Swirl case POWERPC_EXCP_ALIGN: /* Alignment exception */ 296c79c73f6SBlue Swirl /* Get rS/rD and rA from faulting opcode */ 2973433b732SBenjamin Herrenschmidt /* Note: the opcode fields will not be set properly for a direct 2983433b732SBenjamin Herrenschmidt * store load/store, but nobody cares as nobody actually uses 2993433b732SBenjamin Herrenschmidt * direct store segments. 3003433b732SBenjamin Herrenschmidt */ 3013433b732SBenjamin Herrenschmidt env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; 302bd6fefe7SBenjamin Herrenschmidt break; 303c79c73f6SBlue Swirl case POWERPC_EXCP_PROGRAM: /* Program exception */ 304c79c73f6SBlue Swirl switch (env->error_code & ~0xF) { 305c79c73f6SBlue Swirl case POWERPC_EXCP_FP: 306c79c73f6SBlue Swirl if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { 307c79c73f6SBlue Swirl LOG_EXCP("Ignore floating point exception\n"); 30827103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 309c79c73f6SBlue Swirl env->error_code = 0; 310c79c73f6SBlue Swirl return; 311c79c73f6SBlue Swirl } 3121b7d17caSBenjamin Herrenschmidt 3131b7d17caSBenjamin Herrenschmidt /* FP exceptions always have NIP pointing to the faulting 3141b7d17caSBenjamin Herrenschmidt * instruction, so always use store_next and claim we are 3151b7d17caSBenjamin Herrenschmidt * precise in the MSR. 3161b7d17caSBenjamin Herrenschmidt */ 317c79c73f6SBlue Swirl msr |= 0x00100000; 3180ee604abSAaron Larson env->spr[SPR_BOOKE_ESR] = ESR_FP; 319bd6fefe7SBenjamin Herrenschmidt break; 320c79c73f6SBlue Swirl case POWERPC_EXCP_INVAL: 321c79c73f6SBlue Swirl LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); 322c79c73f6SBlue Swirl msr |= 0x00080000; 323c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PIL; 324c79c73f6SBlue Swirl break; 325c79c73f6SBlue Swirl case POWERPC_EXCP_PRIV: 326c79c73f6SBlue Swirl msr |= 0x00040000; 327c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PPR; 328c79c73f6SBlue Swirl break; 329c79c73f6SBlue Swirl case POWERPC_EXCP_TRAP: 330c79c73f6SBlue Swirl msr |= 0x00020000; 331c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PTR; 332c79c73f6SBlue Swirl break; 333c79c73f6SBlue Swirl default: 334c79c73f6SBlue Swirl /* Should never occur */ 335a47dddd7SAndreas Färber cpu_abort(cs, "Invalid program exception %d. Aborting\n", 336c79c73f6SBlue Swirl env->error_code); 337c79c73f6SBlue Swirl break; 338c79c73f6SBlue Swirl } 339bd6fefe7SBenjamin Herrenschmidt break; 340c79c73f6SBlue Swirl case POWERPC_EXCP_SYSCALL: /* System call exception */ 341c79c73f6SBlue Swirl dump_syscall(env); 342c79c73f6SBlue Swirl lev = env->error_code; 3436d49d6d4SBenjamin Herrenschmidt 344bd6fefe7SBenjamin Herrenschmidt /* We need to correct the NIP which in this case is supposed 345bd6fefe7SBenjamin Herrenschmidt * to point to the next instruction 346bd6fefe7SBenjamin Herrenschmidt */ 347bd6fefe7SBenjamin Herrenschmidt env->nip += 4; 348bd6fefe7SBenjamin Herrenschmidt 3496d49d6d4SBenjamin Herrenschmidt /* "PAPR mode" built-in hypercall emulation */ 3501d1be34dSDavid Gibson if ((lev == 1) && cpu->vhyp) { 3511d1be34dSDavid Gibson PPCVirtualHypervisorClass *vhc = 3521d1be34dSDavid Gibson PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); 3531d1be34dSDavid Gibson vhc->hypercall(cpu->vhyp, cpu); 354c79c73f6SBlue Swirl return; 355c79c73f6SBlue Swirl } 3566d49d6d4SBenjamin Herrenschmidt if (lev == 1) { 357c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 358c79c73f6SBlue Swirl } 359bd6fefe7SBenjamin Herrenschmidt break; 360bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 361c79c73f6SBlue Swirl case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ 362c79c73f6SBlue Swirl case POWERPC_EXCP_DECR: /* Decrementer exception */ 363bd6fefe7SBenjamin Herrenschmidt break; 364c79c73f6SBlue Swirl case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ 365c79c73f6SBlue Swirl /* FIT on 4xx */ 366c79c73f6SBlue Swirl LOG_EXCP("FIT exception\n"); 367bd6fefe7SBenjamin Herrenschmidt break; 368c79c73f6SBlue Swirl case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ 369c79c73f6SBlue Swirl LOG_EXCP("WDT exception\n"); 370c79c73f6SBlue Swirl switch (excp_model) { 371c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 372c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 373c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 374c79c73f6SBlue Swirl break; 375c79c73f6SBlue Swirl default: 376c79c73f6SBlue Swirl break; 377c79c73f6SBlue Swirl } 378bd6fefe7SBenjamin Herrenschmidt break; 379c79c73f6SBlue Swirl case POWERPC_EXCP_DTLB: /* Data TLB error */ 380c79c73f6SBlue Swirl case POWERPC_EXCP_ITLB: /* Instruction TLB error */ 381bd6fefe7SBenjamin Herrenschmidt break; 382c79c73f6SBlue Swirl case POWERPC_EXCP_DEBUG: /* Debug interrupt */ 3830e3bf489SRoman Kapl if (env->flags & POWERPC_FLAG_DE) { 384a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 385c79c73f6SBlue Swirl srr0 = SPR_BOOKE_DSRR0; 386c79c73f6SBlue Swirl srr1 = SPR_BOOKE_DSRR1; 387c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 388c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 3890e3bf489SRoman Kapl /* DBSR already modified by caller */ 3900e3bf489SRoman Kapl } else { 3910e3bf489SRoman Kapl cpu_abort(cs, "Debug exception triggered on unsupported model\n"); 392c79c73f6SBlue Swirl } 393bd6fefe7SBenjamin Herrenschmidt break; 394c79c73f6SBlue Swirl case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ 395c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 396bd6fefe7SBenjamin Herrenschmidt break; 397c79c73f6SBlue Swirl case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ 398c79c73f6SBlue Swirl /* XXX: TODO */ 399a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point data exception " 400c79c73f6SBlue Swirl "is not implemented yet !\n"); 401c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 402bd6fefe7SBenjamin Herrenschmidt break; 403c79c73f6SBlue Swirl case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ 404c79c73f6SBlue Swirl /* XXX: TODO */ 405a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point round exception " 406c79c73f6SBlue Swirl "is not implemented yet !\n"); 407c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 408bd6fefe7SBenjamin Herrenschmidt break; 409c79c73f6SBlue Swirl case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ 410c79c73f6SBlue Swirl /* XXX: TODO */ 411a47dddd7SAndreas Färber cpu_abort(cs, 412c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 413bd6fefe7SBenjamin Herrenschmidt break; 414c79c73f6SBlue Swirl case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ 415bd6fefe7SBenjamin Herrenschmidt break; 416c79c73f6SBlue Swirl case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ 417c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 418c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 419bd6fefe7SBenjamin Herrenschmidt break; 420c79c73f6SBlue Swirl case POWERPC_EXCP_RESET: /* System reset exception */ 421f85bcec3SNicholas Piggin /* A power-saving exception sets ME, otherwise it is unchanged */ 422c79c73f6SBlue Swirl if (msr_pow) { 423c79c73f6SBlue Swirl /* indicate that we resumed from power save mode */ 424c79c73f6SBlue Swirl msr |= 0x10000; 425f85bcec3SNicholas Piggin new_msr |= ((target_ulong)1 << MSR_ME); 426c79c73f6SBlue Swirl } 42710c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 42810c21b5cSNicholas Piggin /* ISA specifies HV, but can be delivered to guest with HV clear 42910c21b5cSNicholas Piggin * (e.g., see FWNMI in PAPR, NMI injection in QEMU). 43010c21b5cSNicholas Piggin */ 431c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 43210c21b5cSNicholas Piggin } else { 43310c21b5cSNicholas Piggin if (msr_pow) { 43410c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver power-saving system reset " 43510c21b5cSNicholas Piggin "exception %d with no HV support\n", excp); 43610c21b5cSNicholas Piggin } 43710c21b5cSNicholas Piggin } 4385c94b2a5SCédric Le Goater ail = 0; 439bd6fefe7SBenjamin Herrenschmidt break; 440c79c73f6SBlue Swirl case POWERPC_EXCP_DSEG: /* Data segment exception */ 441c79c73f6SBlue Swirl case POWERPC_EXCP_ISEG: /* Instruction segment exception */ 442c79c73f6SBlue Swirl case POWERPC_EXCP_TRACE: /* Trace exception */ 443bd6fefe7SBenjamin Herrenschmidt break; 444bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ 445c79c73f6SBlue Swirl case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ 446c79c73f6SBlue Swirl case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ 447c79c73f6SBlue Swirl case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ 448c79c73f6SBlue Swirl case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ 4497af1e7b0SCédric Le Goater case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ 450bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HV_EMU: 451d8ce5fd6SBenjamin Herrenschmidt case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */ 452c79c73f6SBlue Swirl srr0 = SPR_HSRR0; 453c79c73f6SBlue Swirl srr1 = SPR_HSRR1; 454c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 455c79c73f6SBlue Swirl new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 456bd6fefe7SBenjamin Herrenschmidt break; 457c79c73f6SBlue Swirl case POWERPC_EXCP_VPU: /* Vector unavailable exception */ 4581f29871cSTom Musta case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ 4597019cb3dSAlexey Kardashevskiy case POWERPC_EXCP_FU: /* Facility unavailable exception */ 4605310799aSBalbir Singh #ifdef TARGET_PPC64 4615310799aSBalbir Singh env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56); 4625310799aSBalbir Singh #endif 463bd6fefe7SBenjamin Herrenschmidt break; 464c79c73f6SBlue Swirl case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ 465c79c73f6SBlue Swirl LOG_EXCP("PIT exception\n"); 466bd6fefe7SBenjamin Herrenschmidt break; 467c79c73f6SBlue Swirl case POWERPC_EXCP_IO: /* IO error exception */ 468c79c73f6SBlue Swirl /* XXX: TODO */ 469a47dddd7SAndreas Färber cpu_abort(cs, "601 IO error exception is not implemented yet !\n"); 470bd6fefe7SBenjamin Herrenschmidt break; 471c79c73f6SBlue Swirl case POWERPC_EXCP_RUNM: /* Run mode exception */ 472c79c73f6SBlue Swirl /* XXX: TODO */ 473a47dddd7SAndreas Färber cpu_abort(cs, "601 run mode exception is not implemented yet !\n"); 474bd6fefe7SBenjamin Herrenschmidt break; 475c79c73f6SBlue Swirl case POWERPC_EXCP_EMUL: /* Emulation trap exception */ 476c79c73f6SBlue Swirl /* XXX: TODO */ 477a47dddd7SAndreas Färber cpu_abort(cs, "602 emulation trap exception " 478c79c73f6SBlue Swirl "is not implemented yet !\n"); 479bd6fefe7SBenjamin Herrenschmidt break; 480c79c73f6SBlue Swirl case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ 481c79c73f6SBlue Swirl switch (excp_model) { 482c79c73f6SBlue Swirl case POWERPC_EXCP_602: 483c79c73f6SBlue Swirl case POWERPC_EXCP_603: 484c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 485c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 486c79c73f6SBlue Swirl goto tlb_miss_tgpr; 487c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 488c79c73f6SBlue Swirl goto tlb_miss; 489c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 490c79c73f6SBlue Swirl goto tlb_miss_74xx; 491c79c73f6SBlue Swirl default: 492a47dddd7SAndreas Färber cpu_abort(cs, "Invalid instruction TLB miss exception\n"); 493c79c73f6SBlue Swirl break; 494c79c73f6SBlue Swirl } 495c79c73f6SBlue Swirl break; 496c79c73f6SBlue Swirl case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ 497c79c73f6SBlue Swirl switch (excp_model) { 498c79c73f6SBlue Swirl case POWERPC_EXCP_602: 499c79c73f6SBlue Swirl case POWERPC_EXCP_603: 500c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 501c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 502c79c73f6SBlue Swirl goto tlb_miss_tgpr; 503c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 504c79c73f6SBlue Swirl goto tlb_miss; 505c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 506c79c73f6SBlue Swirl goto tlb_miss_74xx; 507c79c73f6SBlue Swirl default: 508a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data load TLB miss exception\n"); 509c79c73f6SBlue Swirl break; 510c79c73f6SBlue Swirl } 511c79c73f6SBlue Swirl break; 512c79c73f6SBlue Swirl case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ 513c79c73f6SBlue Swirl switch (excp_model) { 514c79c73f6SBlue Swirl case POWERPC_EXCP_602: 515c79c73f6SBlue Swirl case POWERPC_EXCP_603: 516c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 517c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 518c79c73f6SBlue Swirl tlb_miss_tgpr: 519c79c73f6SBlue Swirl /* Swap temporary saved registers with GPRs */ 520c79c73f6SBlue Swirl if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { 521c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_TGPR; 522c79c73f6SBlue Swirl hreg_swap_gpr_tgpr(env); 523c79c73f6SBlue Swirl } 524c79c73f6SBlue Swirl goto tlb_miss; 525c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 526c79c73f6SBlue Swirl tlb_miss: 527c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 528c79c73f6SBlue Swirl if (qemu_log_enabled()) { 529c79c73f6SBlue Swirl const char *es; 530c79c73f6SBlue Swirl target_ulong *miss, *cmp; 531c79c73f6SBlue Swirl int en; 532c79c73f6SBlue Swirl 533c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 534c79c73f6SBlue Swirl es = "I"; 535c79c73f6SBlue Swirl en = 'I'; 536c79c73f6SBlue Swirl miss = &env->spr[SPR_IMISS]; 537c79c73f6SBlue Swirl cmp = &env->spr[SPR_ICMP]; 538c79c73f6SBlue Swirl } else { 539c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 540c79c73f6SBlue Swirl es = "DL"; 541c79c73f6SBlue Swirl } else { 542c79c73f6SBlue Swirl es = "DS"; 543c79c73f6SBlue Swirl } 544c79c73f6SBlue Swirl en = 'D'; 545c79c73f6SBlue Swirl miss = &env->spr[SPR_DMISS]; 546c79c73f6SBlue Swirl cmp = &env->spr[SPR_DCMP]; 547c79c73f6SBlue Swirl } 548c79c73f6SBlue Swirl qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 549c79c73f6SBlue Swirl TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " 550c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 551c79c73f6SBlue Swirl env->spr[SPR_HASH1], env->spr[SPR_HASH2], 552c79c73f6SBlue Swirl env->error_code); 553c79c73f6SBlue Swirl } 554c79c73f6SBlue Swirl #endif 555c79c73f6SBlue Swirl msr |= env->crf[0] << 28; 556c79c73f6SBlue Swirl msr |= env->error_code; /* key, D/I, S/L bits */ 557c79c73f6SBlue Swirl /* Set way using a LRU mechanism */ 558c79c73f6SBlue Swirl msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; 559c79c73f6SBlue Swirl break; 560c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 561c79c73f6SBlue Swirl tlb_miss_74xx: 562c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 563c79c73f6SBlue Swirl if (qemu_log_enabled()) { 564c79c73f6SBlue Swirl const char *es; 565c79c73f6SBlue Swirl target_ulong *miss, *cmp; 566c79c73f6SBlue Swirl int en; 567c79c73f6SBlue Swirl 568c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 569c79c73f6SBlue Swirl es = "I"; 570c79c73f6SBlue Swirl en = 'I'; 571c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 572c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 573c79c73f6SBlue Swirl } else { 574c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 575c79c73f6SBlue Swirl es = "DL"; 576c79c73f6SBlue Swirl } else { 577c79c73f6SBlue Swirl es = "DS"; 578c79c73f6SBlue Swirl } 579c79c73f6SBlue Swirl en = 'D'; 580c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 581c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 582c79c73f6SBlue Swirl } 583c79c73f6SBlue Swirl qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 584c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 585c79c73f6SBlue Swirl env->error_code); 586c79c73f6SBlue Swirl } 587c79c73f6SBlue Swirl #endif 588c79c73f6SBlue Swirl msr |= env->error_code; /* key bit */ 589c79c73f6SBlue Swirl break; 590c79c73f6SBlue Swirl default: 591a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data store TLB miss exception\n"); 592c79c73f6SBlue Swirl break; 593c79c73f6SBlue Swirl } 594bd6fefe7SBenjamin Herrenschmidt break; 595c79c73f6SBlue Swirl case POWERPC_EXCP_FPA: /* Floating-point assist exception */ 596c79c73f6SBlue Swirl /* XXX: TODO */ 597a47dddd7SAndreas Färber cpu_abort(cs, "Floating point assist exception " 598c79c73f6SBlue Swirl "is not implemented yet !\n"); 599bd6fefe7SBenjamin Herrenschmidt break; 600c79c73f6SBlue Swirl case POWERPC_EXCP_DABR: /* Data address breakpoint */ 601c79c73f6SBlue Swirl /* XXX: TODO */ 602a47dddd7SAndreas Färber cpu_abort(cs, "DABR exception is not implemented yet !\n"); 603bd6fefe7SBenjamin Herrenschmidt break; 604c79c73f6SBlue Swirl case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ 605c79c73f6SBlue Swirl /* XXX: TODO */ 606a47dddd7SAndreas Färber cpu_abort(cs, "IABR exception is not implemented yet !\n"); 607bd6fefe7SBenjamin Herrenschmidt break; 608c79c73f6SBlue Swirl case POWERPC_EXCP_SMI: /* System management interrupt */ 609c79c73f6SBlue Swirl /* XXX: TODO */ 610a47dddd7SAndreas Färber cpu_abort(cs, "SMI exception is not implemented yet !\n"); 611bd6fefe7SBenjamin Herrenschmidt break; 612c79c73f6SBlue Swirl case POWERPC_EXCP_THERM: /* Thermal interrupt */ 613c79c73f6SBlue Swirl /* XXX: TODO */ 614a47dddd7SAndreas Färber cpu_abort(cs, "Thermal management exception " 615c79c73f6SBlue Swirl "is not implemented yet !\n"); 616bd6fefe7SBenjamin Herrenschmidt break; 617c79c73f6SBlue Swirl case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ 618c79c73f6SBlue Swirl /* XXX: TODO */ 619a47dddd7SAndreas Färber cpu_abort(cs, 620c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 621bd6fefe7SBenjamin Herrenschmidt break; 622c79c73f6SBlue Swirl case POWERPC_EXCP_VPUA: /* Vector assist exception */ 623c79c73f6SBlue Swirl /* XXX: TODO */ 624a47dddd7SAndreas Färber cpu_abort(cs, "VPU assist exception is not implemented yet !\n"); 625bd6fefe7SBenjamin Herrenschmidt break; 626c79c73f6SBlue Swirl case POWERPC_EXCP_SOFTP: /* Soft patch exception */ 627c79c73f6SBlue Swirl /* XXX: TODO */ 628a47dddd7SAndreas Färber cpu_abort(cs, 629c79c73f6SBlue Swirl "970 soft-patch exception is not implemented yet !\n"); 630bd6fefe7SBenjamin Herrenschmidt break; 631c79c73f6SBlue Swirl case POWERPC_EXCP_MAINT: /* Maintenance exception */ 632c79c73f6SBlue Swirl /* XXX: TODO */ 633a47dddd7SAndreas Färber cpu_abort(cs, 634c79c73f6SBlue Swirl "970 maintenance exception is not implemented yet !\n"); 635bd6fefe7SBenjamin Herrenschmidt break; 636c79c73f6SBlue Swirl case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ 637c79c73f6SBlue Swirl /* XXX: TODO */ 638a47dddd7SAndreas Färber cpu_abort(cs, "Maskable external exception " 639c79c73f6SBlue Swirl "is not implemented yet !\n"); 640bd6fefe7SBenjamin Herrenschmidt break; 641c79c73f6SBlue Swirl case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ 642c79c73f6SBlue Swirl /* XXX: TODO */ 643a47dddd7SAndreas Färber cpu_abort(cs, "Non maskable external exception " 644c79c73f6SBlue Swirl "is not implemented yet !\n"); 645bd6fefe7SBenjamin Herrenschmidt break; 646c79c73f6SBlue Swirl default: 647c79c73f6SBlue Swirl excp_invalid: 648a47dddd7SAndreas Färber cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 649c79c73f6SBlue Swirl break; 650c79c73f6SBlue Swirl } 651bd6fefe7SBenjamin Herrenschmidt 652bd6fefe7SBenjamin Herrenschmidt /* Save PC */ 653bd6fefe7SBenjamin Herrenschmidt env->spr[srr0] = env->nip; 654bd6fefe7SBenjamin Herrenschmidt 655c79c73f6SBlue Swirl /* Save MSR */ 656c79c73f6SBlue Swirl env->spr[srr1] = msr; 6576d49d6d4SBenjamin Herrenschmidt 6586d49d6d4SBenjamin Herrenschmidt /* Sanity check */ 65910c21b5cSNicholas Piggin if (!(env->msr_mask & MSR_HVB)) { 66010c21b5cSNicholas Piggin if (new_msr & MSR_HVB) { 66110c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with " 6626d49d6d4SBenjamin Herrenschmidt "no HV support\n", excp); 6636d49d6d4SBenjamin Herrenschmidt } 66410c21b5cSNicholas Piggin if (srr0 == SPR_HSRR0) { 66510c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with " 66610c21b5cSNicholas Piggin "no HV support\n", excp); 66710c21b5cSNicholas Piggin } 66810c21b5cSNicholas Piggin } 6696d49d6d4SBenjamin Herrenschmidt 670c79c73f6SBlue Swirl /* If any alternate SRR register are defined, duplicate saved values */ 671c79c73f6SBlue Swirl if (asrr0 != -1) { 672c79c73f6SBlue Swirl env->spr[asrr0] = env->spr[srr0]; 673c79c73f6SBlue Swirl } 674c79c73f6SBlue Swirl if (asrr1 != -1) { 675c79c73f6SBlue Swirl env->spr[asrr1] = env->spr[srr1]; 676c79c73f6SBlue Swirl } 677d5ac4f54SAlexey Kardashevskiy 6786d49d6d4SBenjamin Herrenschmidt /* Sort out endianness of interrupt, this differs depending on the 6796d49d6d4SBenjamin Herrenschmidt * CPU, the HV mode, etc... 6806d49d6d4SBenjamin Herrenschmidt */ 6811e0c7e55SAnton Blanchard #ifdef TARGET_PPC64 6826d49d6d4SBenjamin Herrenschmidt if (excp_model == POWERPC_EXCP_POWER7) { 6836d49d6d4SBenjamin Herrenschmidt if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) { 6846d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 6856d49d6d4SBenjamin Herrenschmidt } 6866d49d6d4SBenjamin Herrenschmidt } else if (excp_model == POWERPC_EXCP_POWER8) { 6876d49d6d4SBenjamin Herrenschmidt if (new_msr & MSR_HVB) { 688a790e82bSBenjamin Herrenschmidt if (env->spr[SPR_HID0] & HID0_HILE) { 689a790e82bSBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 690a790e82bSBenjamin Herrenschmidt } 691a790e82bSBenjamin Herrenschmidt } else if (env->spr[SPR_LPCR] & LPCR_ILE) { 692a790e82bSBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 693a790e82bSBenjamin Herrenschmidt } 694a790e82bSBenjamin Herrenschmidt } else if (excp_model == POWERPC_EXCP_POWER9) { 695a790e82bSBenjamin Herrenschmidt if (new_msr & MSR_HVB) { 696a790e82bSBenjamin Herrenschmidt if (env->spr[SPR_HID0] & HID0_POWER9_HILE) { 6976d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 6986d49d6d4SBenjamin Herrenschmidt } 6996d49d6d4SBenjamin Herrenschmidt } else if (env->spr[SPR_LPCR] & LPCR_ILE) { 7001e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 7011e0c7e55SAnton Blanchard } 7021e0c7e55SAnton Blanchard } else if (msr_ile) { 7031e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 7041e0c7e55SAnton Blanchard } 7051e0c7e55SAnton Blanchard #else 706c79c73f6SBlue Swirl if (msr_ile) { 707c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_LE; 708c79c73f6SBlue Swirl } 7091e0c7e55SAnton Blanchard #endif 710c79c73f6SBlue Swirl 711c79c73f6SBlue Swirl /* Jump to handler */ 712c79c73f6SBlue Swirl vector = env->excp_vectors[excp]; 713c79c73f6SBlue Swirl if (vector == (target_ulong)-1ULL) { 714a47dddd7SAndreas Färber cpu_abort(cs, "Raised an exception without defined vector %d\n", 715c79c73f6SBlue Swirl excp); 716c79c73f6SBlue Swirl } 717c79c73f6SBlue Swirl vector |= env->excp_prefix; 7185c94b2a5SCédric Le Goater 7195c94b2a5SCédric Le Goater /* AIL only works if there is no HV transition and we are running with 7205c94b2a5SCédric Le Goater * translations enabled 7215c94b2a5SCédric Le Goater */ 7226d49d6d4SBenjamin Herrenschmidt if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) || 7236d49d6d4SBenjamin Herrenschmidt ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) { 7245c94b2a5SCédric Le Goater ail = 0; 7255c94b2a5SCédric Le Goater } 7265c94b2a5SCédric Le Goater /* Handle AIL */ 7275c94b2a5SCédric Le Goater if (ail) { 7285c94b2a5SCédric Le Goater new_msr |= (1 << MSR_IR) | (1 << MSR_DR); 729*2586a4d7SFabiano Rosas vector |= ppc_excp_vector_offset(cs, ail); 7305c94b2a5SCédric Le Goater } 7315c94b2a5SCédric Le Goater 732c79c73f6SBlue Swirl #if defined(TARGET_PPC64) 733c79c73f6SBlue Swirl if (excp_model == POWERPC_EXCP_BOOKE) { 734e42a61f1SAlexander Graf if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) { 735e42a61f1SAlexander Graf /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */ 736c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_CM; 737e42a61f1SAlexander Graf } else { 738e42a61f1SAlexander Graf vector = (uint32_t)vector; 739c79c73f6SBlue Swirl } 740c79c73f6SBlue Swirl } else { 741c79c73f6SBlue Swirl if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) { 742c79c73f6SBlue Swirl vector = (uint32_t)vector; 743c79c73f6SBlue Swirl } else { 744c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_SF; 745c79c73f6SBlue Swirl } 746c79c73f6SBlue Swirl } 747c79c73f6SBlue Swirl #endif 7481c953ba5SBenjamin Herrenschmidt /* We don't use hreg_store_msr here as already have treated 749c79c73f6SBlue Swirl * any special case that could occur. Just store MSR and update hflags 7501c953ba5SBenjamin Herrenschmidt * 7511c953ba5SBenjamin Herrenschmidt * Note: We *MUST* not use hreg_store_msr() as-is anyway because it 7521c953ba5SBenjamin Herrenschmidt * will prevent setting of the HV bit which some exceptions might need 7531c953ba5SBenjamin Herrenschmidt * to do. 754c79c73f6SBlue Swirl */ 755c79c73f6SBlue Swirl env->msr = new_msr & env->msr_mask; 756c79c73f6SBlue Swirl hreg_compute_hflags(env); 757c79c73f6SBlue Swirl env->nip = vector; 758c79c73f6SBlue Swirl /* Reset exception state */ 75927103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 760c79c73f6SBlue Swirl env->error_code = 0; 761cd0c6f47SBenjamin Herrenschmidt 762139d9023SNikunj A Dadhania /* Reset the reservation */ 763139d9023SNikunj A Dadhania env->reserve_addr = -1; 764139d9023SNikunj A Dadhania 765cd0c6f47SBenjamin Herrenschmidt /* Any interrupt is context synchronizing, check if TCG TLB 766cd0c6f47SBenjamin Herrenschmidt * needs a delayed flush on ppc64 767cd0c6f47SBenjamin Herrenschmidt */ 768e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 769c79c73f6SBlue Swirl } 770c79c73f6SBlue Swirl 77197a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs) 772c79c73f6SBlue Swirl { 77397a8ea5aSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 77497a8ea5aSAndreas Färber CPUPPCState *env = &cpu->env; 7755c26a5b3SAndreas Färber 77627103424SAndreas Färber powerpc_excp(cpu, env->excp_model, cs->exception_index); 777c79c73f6SBlue Swirl } 778c79c73f6SBlue Swirl 779458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env) 780c79c73f6SBlue Swirl { 7815c26a5b3SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 7823621e2c9SBenjamin Herrenschmidt bool async_deliver; 783259186a7SAndreas Färber 784c79c73f6SBlue Swirl /* External reset */ 785c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { 786c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); 7875c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 788c79c73f6SBlue Swirl return; 789c79c73f6SBlue Swirl } 790c79c73f6SBlue Swirl /* Machine check exception */ 791c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { 792c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); 7935c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK); 794c79c73f6SBlue Swirl return; 795c79c73f6SBlue Swirl } 796c79c73f6SBlue Swirl #if 0 /* TODO */ 797c79c73f6SBlue Swirl /* External debug exception */ 798c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { 799c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); 8005c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG); 801c79c73f6SBlue Swirl return; 802c79c73f6SBlue Swirl } 803c79c73f6SBlue Swirl #endif 8043621e2c9SBenjamin Herrenschmidt 8053621e2c9SBenjamin Herrenschmidt /* 8063621e2c9SBenjamin Herrenschmidt * For interrupts that gate on MSR:EE, we need to do something a 8073621e2c9SBenjamin Herrenschmidt * bit more subtle, as we need to let them through even when EE is 8083621e2c9SBenjamin Herrenschmidt * clear when coming out of some power management states (in order 8093621e2c9SBenjamin Herrenschmidt * for them to become a 0x100). 8103621e2c9SBenjamin Herrenschmidt */ 8111e7fd61dSBenjamin Herrenschmidt async_deliver = (msr_ee != 0) || env->resume_as_sreset; 8123621e2c9SBenjamin Herrenschmidt 813c79c73f6SBlue Swirl /* Hypervisor decrementer exception */ 814c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { 8154b236b62SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 8164b236b62SBenjamin Herrenschmidt bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); 8173621e2c9SBenjamin Herrenschmidt if ((async_deliver || msr_hv == 0) && hdice) { 8184b236b62SBenjamin Herrenschmidt /* HDEC clears on delivery */ 8194b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 8205c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR); 821c79c73f6SBlue Swirl return; 822c79c73f6SBlue Swirl } 823c79c73f6SBlue Swirl } 824d8ce5fd6SBenjamin Herrenschmidt 825d8ce5fd6SBenjamin Herrenschmidt /* Hypervisor virtualization interrupt */ 826d8ce5fd6SBenjamin Herrenschmidt if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) { 827d8ce5fd6SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 828d8ce5fd6SBenjamin Herrenschmidt bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); 829d8ce5fd6SBenjamin Herrenschmidt if ((async_deliver || msr_hv == 0) && hvice) { 830d8ce5fd6SBenjamin Herrenschmidt powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT); 831d8ce5fd6SBenjamin Herrenschmidt return; 832d8ce5fd6SBenjamin Herrenschmidt } 833d8ce5fd6SBenjamin Herrenschmidt } 834d8ce5fd6SBenjamin Herrenschmidt 835d8ce5fd6SBenjamin Herrenschmidt /* External interrupt can ignore MSR:EE under some circumstances */ 836d1dbe37cSBenjamin Herrenschmidt if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { 837d1dbe37cSBenjamin Herrenschmidt bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 8386eebe6dcSBenjamin Herrenschmidt bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); 8396eebe6dcSBenjamin Herrenschmidt /* HEIC blocks delivery to the hypervisor */ 8406eebe6dcSBenjamin Herrenschmidt if ((async_deliver && !(heic && msr_hv && !msr_pr)) || 8416eebe6dcSBenjamin Herrenschmidt (env->has_hv_mode && msr_hv == 0 && !lpes0)) { 842d1dbe37cSBenjamin Herrenschmidt powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL); 843d1dbe37cSBenjamin Herrenschmidt return; 844d1dbe37cSBenjamin Herrenschmidt } 845d1dbe37cSBenjamin Herrenschmidt } 846c79c73f6SBlue Swirl if (msr_ce != 0) { 847c79c73f6SBlue Swirl /* External critical interrupt */ 848c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { 8495c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL); 850c79c73f6SBlue Swirl return; 851c79c73f6SBlue Swirl } 852c79c73f6SBlue Swirl } 8533621e2c9SBenjamin Herrenschmidt if (async_deliver != 0) { 854c79c73f6SBlue Swirl /* Watchdog timer on embedded PowerPC */ 855c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { 856c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); 8575c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT); 858c79c73f6SBlue Swirl return; 859c79c73f6SBlue Swirl } 860c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { 861c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); 8625c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI); 863c79c73f6SBlue Swirl return; 864c79c73f6SBlue Swirl } 865c79c73f6SBlue Swirl /* Fixed interval timer on embedded PowerPC */ 866c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { 867c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); 8685c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT); 869c79c73f6SBlue Swirl return; 870c79c73f6SBlue Swirl } 871c79c73f6SBlue Swirl /* Programmable interval timer on embedded PowerPC */ 872c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { 873c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); 8745c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT); 875c79c73f6SBlue Swirl return; 876c79c73f6SBlue Swirl } 877c79c73f6SBlue Swirl /* Decrementer exception */ 878c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { 879e81a982aSAlexander Graf if (ppc_decr_clear_on_delivery(env)) { 880c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); 881e81a982aSAlexander Graf } 8825c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR); 883c79c73f6SBlue Swirl return; 884c79c73f6SBlue Swirl } 885c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { 886c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); 8875c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI); 888c79c73f6SBlue Swirl return; 889c79c73f6SBlue Swirl } 8907af1e7b0SCédric Le Goater if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) { 8917af1e7b0SCédric Le Goater env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL); 8927af1e7b0SCédric Le Goater powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV); 8937af1e7b0SCédric Le Goater return; 8947af1e7b0SCédric Le Goater } 895c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { 896c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); 8975c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM); 898c79c73f6SBlue Swirl return; 899c79c73f6SBlue Swirl } 900c79c73f6SBlue Swirl /* Thermal interrupt */ 901c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { 902c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); 9035c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM); 904c79c73f6SBlue Swirl return; 905c79c73f6SBlue Swirl } 906c79c73f6SBlue Swirl } 907f8154fd2SBenjamin Herrenschmidt 908f8154fd2SBenjamin Herrenschmidt if (env->resume_as_sreset) { 909f8154fd2SBenjamin Herrenschmidt /* 910f8154fd2SBenjamin Herrenschmidt * This is a bug ! It means that has_work took us out of halt without 911f8154fd2SBenjamin Herrenschmidt * anything to deliver while in a PM state that requires getting 912f8154fd2SBenjamin Herrenschmidt * out via a 0x100 913f8154fd2SBenjamin Herrenschmidt * 914f8154fd2SBenjamin Herrenschmidt * This means we will incorrectly execute past the power management 915f8154fd2SBenjamin Herrenschmidt * instruction instead of triggering a reset. 916f8154fd2SBenjamin Herrenschmidt * 917f8154fd2SBenjamin Herrenschmidt * It generally means a discrepancy between the wakup conditions in the 918f8154fd2SBenjamin Herrenschmidt * processor has_work implementation and the logic in this function. 919f8154fd2SBenjamin Herrenschmidt */ 920f8154fd2SBenjamin Herrenschmidt cpu_abort(CPU(ppc_env_get_cpu(env)), 921f8154fd2SBenjamin Herrenschmidt "Wakeup from PM state but interrupt Undelivered"); 922f8154fd2SBenjamin Herrenschmidt } 923c79c73f6SBlue Swirl } 92434316482SAlexey Kardashevskiy 92534316482SAlexey Kardashevskiy void ppc_cpu_do_system_reset(CPUState *cs) 92634316482SAlexey Kardashevskiy { 92734316482SAlexey Kardashevskiy PowerPCCPU *cpu = POWERPC_CPU(cs); 92834316482SAlexey Kardashevskiy CPUPPCState *env = &cpu->env; 92934316482SAlexey Kardashevskiy 93034316482SAlexey Kardashevskiy powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 93134316482SAlexey Kardashevskiy } 932c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */ 933c79c73f6SBlue Swirl 934458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 935458dd766SRichard Henderson { 936458dd766SRichard Henderson PowerPCCPU *cpu = POWERPC_CPU(cs); 937458dd766SRichard Henderson CPUPPCState *env = &cpu->env; 938458dd766SRichard Henderson 939458dd766SRichard Henderson if (interrupt_request & CPU_INTERRUPT_HARD) { 940458dd766SRichard Henderson ppc_hw_interrupt(env); 941458dd766SRichard Henderson if (env->pending_interrupts == 0) { 942458dd766SRichard Henderson cs->interrupt_request &= ~CPU_INTERRUPT_HARD; 943458dd766SRichard Henderson } 944458dd766SRichard Henderson return true; 945458dd766SRichard Henderson } 946458dd766SRichard Henderson return false; 947458dd766SRichard Henderson } 948458dd766SRichard Henderson 949c79c73f6SBlue Swirl #if defined(DEBUG_OP) 950c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr) 951c79c73f6SBlue Swirl { 952c79c73f6SBlue Swirl qemu_log("Return from exception at " TARGET_FMT_lx " with flags " 953c79c73f6SBlue Swirl TARGET_FMT_lx "\n", RA, msr); 954c79c73f6SBlue Swirl } 955c79c73f6SBlue Swirl #endif 956c79c73f6SBlue Swirl 957ad71ed68SBlue Swirl /*****************************************************************************/ 958ad71ed68SBlue Swirl /* Exceptions processing helpers */ 959ad71ed68SBlue Swirl 960db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, 961db789c6cSBenjamin Herrenschmidt uint32_t error_code, uintptr_t raddr) 962ad71ed68SBlue Swirl { 96327103424SAndreas Färber CPUState *cs = CPU(ppc_env_get_cpu(env)); 96427103424SAndreas Färber 96527103424SAndreas Färber cs->exception_index = exception; 966ad71ed68SBlue Swirl env->error_code = error_code; 967db789c6cSBenjamin Herrenschmidt cpu_loop_exit_restore(cs, raddr); 968db789c6cSBenjamin Herrenschmidt } 969db789c6cSBenjamin Herrenschmidt 970db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception, 971db789c6cSBenjamin Herrenschmidt uint32_t error_code) 972db789c6cSBenjamin Herrenschmidt { 973db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 974db789c6cSBenjamin Herrenschmidt } 975db789c6cSBenjamin Herrenschmidt 976db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception) 977db789c6cSBenjamin Herrenschmidt { 978db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 979db789c6cSBenjamin Herrenschmidt } 980db789c6cSBenjamin Herrenschmidt 981db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception, 982db789c6cSBenjamin Herrenschmidt uintptr_t raddr) 983db789c6cSBenjamin Herrenschmidt { 984db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, raddr); 985db789c6cSBenjamin Herrenschmidt } 986db789c6cSBenjamin Herrenschmidt 987db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, 988db789c6cSBenjamin Herrenschmidt uint32_t error_code) 989db789c6cSBenjamin Herrenschmidt { 990db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 991ad71ed68SBlue Swirl } 992ad71ed68SBlue Swirl 993e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception) 994ad71ed68SBlue Swirl { 995db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 996ad71ed68SBlue Swirl } 997ad71ed68SBlue Swirl 998ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 999e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val) 1000ad71ed68SBlue Swirl { 1001db789c6cSBenjamin Herrenschmidt uint32_t excp = hreg_store_msr(env, val, 0); 1002259186a7SAndreas Färber 1003db789c6cSBenjamin Herrenschmidt if (excp != 0) { 1004db789c6cSBenjamin Herrenschmidt CPUState *cs = CPU(ppc_env_get_cpu(env)); 1005044897efSRichard Purdie cpu_interrupt_exittb(cs); 1006db789c6cSBenjamin Herrenschmidt raise_exception(env, excp); 1007ad71ed68SBlue Swirl } 1008ad71ed68SBlue Swirl } 1009ad71ed68SBlue Swirl 10107778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64) 10117778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) 10127778a575SBenjamin Herrenschmidt { 10137778a575SBenjamin Herrenschmidt CPUState *cs; 10147778a575SBenjamin Herrenschmidt 10157778a575SBenjamin Herrenschmidt cs = CPU(ppc_env_get_cpu(env)); 10167778a575SBenjamin Herrenschmidt cs->halted = 1; 10177778a575SBenjamin Herrenschmidt 10184b236b62SBenjamin Herrenschmidt /* The architecture specifies that HDEC interrupts are 10194b236b62SBenjamin Herrenschmidt * discarded in PM states 10204b236b62SBenjamin Herrenschmidt */ 10214b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 10224b236b62SBenjamin Herrenschmidt 10233621e2c9SBenjamin Herrenschmidt /* Condition for waking up at 0x100 */ 10241e7fd61dSBenjamin Herrenschmidt env->resume_as_sreset = (insn != PPC_PM_STOP) || 102521c0d66aSBenjamin Herrenschmidt (env->spr[SPR_PSSCR] & PSSCR_EC); 10267778a575SBenjamin Herrenschmidt } 10277778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 10287778a575SBenjamin Herrenschmidt 1029a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) 1030ad71ed68SBlue Swirl { 1031259186a7SAndreas Färber CPUState *cs = CPU(ppc_env_get_cpu(env)); 1032259186a7SAndreas Färber 1033a2e71b28SBenjamin Herrenschmidt /* MSR:POW cannot be set by any form of rfi */ 1034a2e71b28SBenjamin Herrenschmidt msr &= ~(1ULL << MSR_POW); 1035a2e71b28SBenjamin Herrenschmidt 1036ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1037a2e71b28SBenjamin Herrenschmidt /* Switching to 32-bit ? Crop the nip */ 1038a2e71b28SBenjamin Herrenschmidt if (!msr_is_64bit(env, msr)) { 1039ad71ed68SBlue Swirl nip = (uint32_t)nip; 1040ad71ed68SBlue Swirl } 1041ad71ed68SBlue Swirl #else 1042ad71ed68SBlue Swirl nip = (uint32_t)nip; 1043ad71ed68SBlue Swirl #endif 1044ad71ed68SBlue Swirl /* XXX: beware: this is false if VLE is supported */ 1045ad71ed68SBlue Swirl env->nip = nip & ~((target_ulong)0x00000003); 1046ad71ed68SBlue Swirl hreg_store_msr(env, msr, 1); 1047ad71ed68SBlue Swirl #if defined(DEBUG_OP) 1048ad71ed68SBlue Swirl cpu_dump_rfi(env->nip, env->msr); 1049ad71ed68SBlue Swirl #endif 1050ad71ed68SBlue Swirl /* No need to raise an exception here, 1051ad71ed68SBlue Swirl * as rfi is always the last insn of a TB 1052ad71ed68SBlue Swirl */ 1053044897efSRichard Purdie cpu_interrupt_exittb(cs); 1054a8b73734SNikunj A Dadhania /* Reset the reservation */ 1055a8b73734SNikunj A Dadhania env->reserve_addr = -1; 1056a8b73734SNikunj A Dadhania 1057cd0c6f47SBenjamin Herrenschmidt /* Context synchronizing: check if TCG TLB needs flush */ 1058e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 1059ad71ed68SBlue Swirl } 1060ad71ed68SBlue Swirl 1061e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env) 1062ad71ed68SBlue Swirl { 1063a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); 1064a1bb7384SScott Wood } 1065ad71ed68SBlue Swirl 1066a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK 1067ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1068e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env) 1069ad71ed68SBlue Swirl { 1070a2e71b28SBenjamin Herrenschmidt /* The architeture defines a number of rules for which bits 1071a2e71b28SBenjamin Herrenschmidt * can change but in practice, we handle this in hreg_store_msr() 1072a2e71b28SBenjamin Herrenschmidt * which will be called by do_rfi(), so there is no need to filter 1073a2e71b28SBenjamin Herrenschmidt * here 1074a2e71b28SBenjamin Herrenschmidt */ 1075a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]); 1076ad71ed68SBlue Swirl } 1077ad71ed68SBlue Swirl 1078e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env) 1079ad71ed68SBlue Swirl { 1080a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); 1081ad71ed68SBlue Swirl } 1082ad71ed68SBlue Swirl #endif 1083ad71ed68SBlue Swirl 1084ad71ed68SBlue Swirl /*****************************************************************************/ 1085ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */ 1086e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env) 1087ad71ed68SBlue Swirl { 1088a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]); 1089ad71ed68SBlue Swirl } 1090ad71ed68SBlue Swirl 1091e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env) 1092ad71ed68SBlue Swirl { 1093a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]); 1094ad71ed68SBlue Swirl } 1095ad71ed68SBlue Swirl 1096e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env) 1097ad71ed68SBlue Swirl { 1098a1bb7384SScott Wood /* FIXME: choose CSRR1 or DSRR1 based on cpu type */ 1099a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]); 1100ad71ed68SBlue Swirl } 1101ad71ed68SBlue Swirl 1102e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env) 1103ad71ed68SBlue Swirl { 1104a1bb7384SScott Wood /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ 1105a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); 1106ad71ed68SBlue Swirl } 1107ad71ed68SBlue Swirl #endif 1108ad71ed68SBlue Swirl 1109e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1110e5f17ac6SBlue Swirl uint32_t flags) 1111ad71ed68SBlue Swirl { 1112ad71ed68SBlue Swirl if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || 1113ad71ed68SBlue Swirl ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) || 1114ad71ed68SBlue Swirl ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || 1115ad71ed68SBlue Swirl ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || 1116ad71ed68SBlue Swirl ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { 111772073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 111872073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1119ad71ed68SBlue Swirl } 1120ad71ed68SBlue Swirl } 1121ad71ed68SBlue Swirl 1122ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1123e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1124e5f17ac6SBlue Swirl uint32_t flags) 1125ad71ed68SBlue Swirl { 1126ad71ed68SBlue Swirl if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || 1127ad71ed68SBlue Swirl ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) || 1128ad71ed68SBlue Swirl ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || 1129ad71ed68SBlue Swirl ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || 1130ad71ed68SBlue Swirl ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { 113172073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 113272073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1133ad71ed68SBlue Swirl } 1134ad71ed68SBlue Swirl } 1135ad71ed68SBlue Swirl #endif 1136ad71ed68SBlue Swirl 1137ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 1138ad71ed68SBlue Swirl /*****************************************************************************/ 1139ad71ed68SBlue Swirl /* PowerPC 601 specific instructions (POWER bridge) */ 1140ad71ed68SBlue Swirl 1141e5f17ac6SBlue Swirl void helper_rfsvc(CPUPPCState *env) 1142ad71ed68SBlue Swirl { 1143a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->lr, env->ctr & 0x0000FFFF); 1144ad71ed68SBlue Swirl } 1145ad71ed68SBlue Swirl 1146ad71ed68SBlue Swirl /* Embedded.Processor Control */ 1147ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb) 1148ad71ed68SBlue Swirl { 1149ad71ed68SBlue Swirl int msg = rb & DBELL_TYPE_MASK; 1150ad71ed68SBlue Swirl int irq = -1; 1151ad71ed68SBlue Swirl 1152ad71ed68SBlue Swirl switch (msg) { 1153ad71ed68SBlue Swirl case DBELL_TYPE_DBELL: 1154ad71ed68SBlue Swirl irq = PPC_INTERRUPT_DOORBELL; 1155ad71ed68SBlue Swirl break; 1156ad71ed68SBlue Swirl case DBELL_TYPE_DBELL_CRIT: 1157ad71ed68SBlue Swirl irq = PPC_INTERRUPT_CDOORBELL; 1158ad71ed68SBlue Swirl break; 1159ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL: 1160ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_CRIT: 1161ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_MC: 1162ad71ed68SBlue Swirl /* XXX implement */ 1163ad71ed68SBlue Swirl default: 1164ad71ed68SBlue Swirl break; 1165ad71ed68SBlue Swirl } 1166ad71ed68SBlue Swirl 1167ad71ed68SBlue Swirl return irq; 1168ad71ed68SBlue Swirl } 1169ad71ed68SBlue Swirl 1170e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb) 1171ad71ed68SBlue Swirl { 1172ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1173ad71ed68SBlue Swirl 1174ad71ed68SBlue Swirl if (irq < 0) { 1175ad71ed68SBlue Swirl return; 1176ad71ed68SBlue Swirl } 1177ad71ed68SBlue Swirl 1178ad71ed68SBlue Swirl env->pending_interrupts &= ~(1 << irq); 1179ad71ed68SBlue Swirl } 1180ad71ed68SBlue Swirl 1181ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb) 1182ad71ed68SBlue Swirl { 1183ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1184ad71ed68SBlue Swirl int pir = rb & DBELL_PIRTAG_MASK; 1185182735efSAndreas Färber CPUState *cs; 1186ad71ed68SBlue Swirl 1187ad71ed68SBlue Swirl if (irq < 0) { 1188ad71ed68SBlue Swirl return; 1189ad71ed68SBlue Swirl } 1190ad71ed68SBlue Swirl 1191f1c29ebcSThomas Huth qemu_mutex_lock_iothread(); 1192bdc44640SAndreas Färber CPU_FOREACH(cs) { 1193182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 1194182735efSAndreas Färber CPUPPCState *cenv = &cpu->env; 1195182735efSAndreas Färber 1196ad71ed68SBlue Swirl if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { 1197ad71ed68SBlue Swirl cenv->pending_interrupts |= 1 << irq; 1198182735efSAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 1199ad71ed68SBlue Swirl } 1200ad71ed68SBlue Swirl } 1201f1c29ebcSThomas Huth qemu_mutex_unlock_iothread(); 1202ad71ed68SBlue Swirl } 12037af1e7b0SCédric Le Goater 12047af1e7b0SCédric Le Goater /* Server Processor Control */ 12057af1e7b0SCédric Le Goater static int book3s_dbell2irq(target_ulong rb) 12067af1e7b0SCédric Le Goater { 12077af1e7b0SCédric Le Goater int msg = rb & DBELL_TYPE_MASK; 12087af1e7b0SCédric Le Goater 12097af1e7b0SCédric Le Goater /* A Directed Hypervisor Doorbell message is sent only if the 12107af1e7b0SCédric Le Goater * message type is 5. All other types are reserved and the 12117af1e7b0SCédric Le Goater * instruction is a no-op */ 12127af1e7b0SCédric Le Goater return msg == DBELL_TYPE_DBELL_SERVER ? PPC_INTERRUPT_HDOORBELL : -1; 12137af1e7b0SCédric Le Goater } 12147af1e7b0SCédric Le Goater 12157af1e7b0SCédric Le Goater void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) 12167af1e7b0SCédric Le Goater { 12177af1e7b0SCédric Le Goater int irq = book3s_dbell2irq(rb); 12187af1e7b0SCédric Le Goater 12197af1e7b0SCédric Le Goater if (irq < 0) { 12207af1e7b0SCédric Le Goater return; 12217af1e7b0SCédric Le Goater } 12227af1e7b0SCédric Le Goater 12237af1e7b0SCédric Le Goater env->pending_interrupts &= ~(1 << irq); 12247af1e7b0SCédric Le Goater } 12257af1e7b0SCédric Le Goater 12267af1e7b0SCédric Le Goater void helper_book3s_msgsnd(target_ulong rb) 12277af1e7b0SCédric Le Goater { 12287af1e7b0SCédric Le Goater int irq = book3s_dbell2irq(rb); 12297af1e7b0SCédric Le Goater int pir = rb & DBELL_PROCIDTAG_MASK; 12307af1e7b0SCédric Le Goater CPUState *cs; 12317af1e7b0SCédric Le Goater 12327af1e7b0SCédric Le Goater if (irq < 0) { 12337af1e7b0SCédric Le Goater return; 12347af1e7b0SCédric Le Goater } 12357af1e7b0SCédric Le Goater 12367af1e7b0SCédric Le Goater qemu_mutex_lock_iothread(); 12377af1e7b0SCédric Le Goater CPU_FOREACH(cs) { 12387af1e7b0SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 12397af1e7b0SCédric Le Goater CPUPPCState *cenv = &cpu->env; 12407af1e7b0SCédric Le Goater 12417af1e7b0SCédric Le Goater /* TODO: broadcast message to all threads of the same processor */ 12427af1e7b0SCédric Le Goater if (cenv->spr_cb[SPR_PIR].default_value == pir) { 12437af1e7b0SCédric Le Goater cenv->pending_interrupts |= 1 << irq; 12447af1e7b0SCédric Le Goater cpu_interrupt(cs, CPU_INTERRUPT_HARD); 12457af1e7b0SCédric Le Goater } 12467af1e7b0SCédric Le Goater } 12477af1e7b0SCédric Le Goater qemu_mutex_unlock_iothread(); 12487af1e7b0SCédric Le Goater } 1249ad71ed68SBlue Swirl #endif 12500f3110faSRichard Henderson 12510f3110faSRichard Henderson void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, 12520f3110faSRichard Henderson MMUAccessType access_type, 12530f3110faSRichard Henderson int mmu_idx, uintptr_t retaddr) 12540f3110faSRichard Henderson { 12550f3110faSRichard Henderson CPUPPCState *env = cs->env_ptr; 12560f3110faSRichard Henderson uint32_t insn; 12570f3110faSRichard Henderson 12580f3110faSRichard Henderson /* Restore state and reload the insn we executed, for filling in DSISR. */ 12590f3110faSRichard Henderson cpu_restore_state(cs, retaddr, true); 12600f3110faSRichard Henderson insn = cpu_ldl_code(env, env->nip); 12610f3110faSRichard Henderson 12620f3110faSRichard Henderson cs->exception_index = POWERPC_EXCP_ALIGN; 12630f3110faSRichard Henderson env->error_code = insn & 0x03FF0000; 12640f3110faSRichard Henderson cpu_loop_exit(cs); 12650f3110faSRichard Henderson } 1266