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" 20*f1c29ebcSThomas 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" 25ad71ed68SBlue Swirl 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 68c79c73f6SBlue Swirl /* Note that this function should be greatly optimized 69c79c73f6SBlue Swirl * when called with a constant excp, from ppc_hw_interrupt 70c79c73f6SBlue Swirl */ 715c26a5b3SAndreas Färber static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) 72c79c73f6SBlue Swirl { 7327103424SAndreas Färber CPUState *cs = CPU(cpu); 745c26a5b3SAndreas Färber CPUPPCState *env = &cpu->env; 75c79c73f6SBlue Swirl target_ulong msr, new_msr, vector; 766d49d6d4SBenjamin Herrenschmidt int srr0, srr1, asrr0, asrr1, lev, ail; 776d49d6d4SBenjamin Herrenschmidt bool lpes0; 78c79c73f6SBlue Swirl 79c79c73f6SBlue Swirl qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx 80c79c73f6SBlue Swirl " => %08x (%02x)\n", env->nip, excp, env->error_code); 81c79c73f6SBlue Swirl 82c79c73f6SBlue Swirl /* new srr1 value excluding must-be-zero bits */ 83a1bb7384SScott Wood if (excp_model == POWERPC_EXCP_BOOKE) { 84a1bb7384SScott Wood msr = env->msr; 85a1bb7384SScott Wood } else { 86c79c73f6SBlue Swirl msr = env->msr & ~0x783f0000ULL; 87a1bb7384SScott Wood } 88c79c73f6SBlue Swirl 896d49d6d4SBenjamin Herrenschmidt /* new interrupt handler msr preserves existing HV and ME unless 906d49d6d4SBenjamin Herrenschmidt * explicitly overriden 916d49d6d4SBenjamin Herrenschmidt */ 926d49d6d4SBenjamin Herrenschmidt new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB); 93c79c73f6SBlue Swirl 94c79c73f6SBlue Swirl /* target registers */ 95c79c73f6SBlue Swirl srr0 = SPR_SRR0; 96c79c73f6SBlue Swirl srr1 = SPR_SRR1; 97c79c73f6SBlue Swirl asrr0 = -1; 98c79c73f6SBlue Swirl asrr1 = -1; 99c79c73f6SBlue Swirl 1007778a575SBenjamin Herrenschmidt /* check for special resume at 0x100 from doze/nap/sleep/winkle on P7/P8 */ 1017778a575SBenjamin Herrenschmidt if (env->in_pm_state) { 1027778a575SBenjamin Herrenschmidt env->in_pm_state = false; 1037778a575SBenjamin Herrenschmidt 1047778a575SBenjamin Herrenschmidt /* Pretend to be returning from doze always as we don't lose state */ 1057778a575SBenjamin Herrenschmidt msr |= (0x1ull << (63 - 47)); 1067778a575SBenjamin Herrenschmidt 1077778a575SBenjamin Herrenschmidt /* Non-machine check are routed to 0x100 with a wakeup cause 1087778a575SBenjamin Herrenschmidt * encoded in SRR1 1097778a575SBenjamin Herrenschmidt */ 1107778a575SBenjamin Herrenschmidt if (excp != POWERPC_EXCP_MCHECK) { 1117778a575SBenjamin Herrenschmidt switch (excp) { 1127778a575SBenjamin Herrenschmidt case POWERPC_EXCP_RESET: 1137778a575SBenjamin Herrenschmidt msr |= 0x4ull << (63 - 45); 1147778a575SBenjamin Herrenschmidt break; 1157778a575SBenjamin Herrenschmidt case POWERPC_EXCP_EXTERNAL: 1167778a575SBenjamin Herrenschmidt msr |= 0x8ull << (63 - 45); 1177778a575SBenjamin Herrenschmidt break; 1187778a575SBenjamin Herrenschmidt case POWERPC_EXCP_DECR: 1197778a575SBenjamin Herrenschmidt msr |= 0x6ull << (63 - 45); 1207778a575SBenjamin Herrenschmidt break; 1217778a575SBenjamin Herrenschmidt case POWERPC_EXCP_SDOOR: 1227778a575SBenjamin Herrenschmidt msr |= 0x5ull << (63 - 45); 1237778a575SBenjamin Herrenschmidt break; 1247778a575SBenjamin Herrenschmidt case POWERPC_EXCP_SDOOR_HV: 1257778a575SBenjamin Herrenschmidt msr |= 0x3ull << (63 - 45); 1267778a575SBenjamin Herrenschmidt break; 1277778a575SBenjamin Herrenschmidt case POWERPC_EXCP_HV_MAINT: 1287778a575SBenjamin Herrenschmidt msr |= 0xaull << (63 - 45); 1297778a575SBenjamin Herrenschmidt break; 1307778a575SBenjamin Herrenschmidt default: 1317778a575SBenjamin Herrenschmidt cpu_abort(cs, "Unsupported exception %d in Power Save mode\n", 1327778a575SBenjamin Herrenschmidt excp); 1337778a575SBenjamin Herrenschmidt } 1347778a575SBenjamin Herrenschmidt excp = POWERPC_EXCP_RESET; 1357778a575SBenjamin Herrenschmidt } 1367778a575SBenjamin Herrenschmidt } 1377778a575SBenjamin Herrenschmidt 1385c94b2a5SCédric Le Goater /* Exception targetting modifiers 1395c94b2a5SCédric Le Goater * 1406d49d6d4SBenjamin Herrenschmidt * LPES0 is supported on POWER7/8 1416d49d6d4SBenjamin Herrenschmidt * LPES1 is not supported (old iSeries mode) 1426d49d6d4SBenjamin Herrenschmidt * 1436d49d6d4SBenjamin Herrenschmidt * On anything else, we behave as if LPES0 is 1 1446d49d6d4SBenjamin Herrenschmidt * (externals don't alter MSR:HV) 1456d49d6d4SBenjamin Herrenschmidt * 1465c94b2a5SCédric Le Goater * AIL is initialized here but can be cleared by 1475c94b2a5SCédric Le Goater * selected exceptions 1485c94b2a5SCédric Le Goater */ 1495c94b2a5SCédric Le Goater #if defined(TARGET_PPC64) 1505c94b2a5SCédric Le Goater if (excp_model == POWERPC_EXCP_POWER7 || 1515c94b2a5SCédric Le Goater excp_model == POWERPC_EXCP_POWER8) { 1526d49d6d4SBenjamin Herrenschmidt lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 1535c94b2a5SCédric Le Goater if (excp_model == POWERPC_EXCP_POWER8) { 1545c94b2a5SCédric Le Goater ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT; 1555c94b2a5SCédric Le Goater } else { 1565c94b2a5SCédric Le Goater ail = 0; 1575c94b2a5SCédric Le Goater } 1585c94b2a5SCédric Le Goater } else 1595c94b2a5SCédric Le Goater #endif /* defined(TARGET_PPC64) */ 1605c94b2a5SCédric Le Goater { 1616d49d6d4SBenjamin Herrenschmidt lpes0 = true; 1625c94b2a5SCédric Le Goater ail = 0; 1635c94b2a5SCédric Le Goater } 1645c94b2a5SCédric Le Goater 1659b2faddaSBenjamin Herrenschmidt /* Hypervisor emulation assistance interrupt only exists on server 1669b2faddaSBenjamin Herrenschmidt * arch 2.05 server or later. We also don't want to generate it if 1679b2faddaSBenjamin Herrenschmidt * we don't have HVB in msr_mask (PAPR mode). 1689b2faddaSBenjamin Herrenschmidt */ 1699b2faddaSBenjamin Herrenschmidt if (excp == POWERPC_EXCP_HV_EMU 1709b2faddaSBenjamin Herrenschmidt #if defined(TARGET_PPC64) 1719b2faddaSBenjamin Herrenschmidt && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB)) 1729b2faddaSBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 1739b2faddaSBenjamin Herrenschmidt 1749b2faddaSBenjamin Herrenschmidt ) { 1759b2faddaSBenjamin Herrenschmidt excp = POWERPC_EXCP_PROGRAM; 1769b2faddaSBenjamin Herrenschmidt } 1779b2faddaSBenjamin Herrenschmidt 178c79c73f6SBlue Swirl switch (excp) { 179c79c73f6SBlue Swirl case POWERPC_EXCP_NONE: 180c79c73f6SBlue Swirl /* Should never happen */ 181c79c73f6SBlue Swirl return; 182c79c73f6SBlue Swirl case POWERPC_EXCP_CRITICAL: /* Critical input */ 183c79c73f6SBlue Swirl switch (excp_model) { 184c79c73f6SBlue Swirl case POWERPC_EXCP_40x: 185c79c73f6SBlue Swirl srr0 = SPR_40x_SRR2; 186c79c73f6SBlue Swirl srr1 = SPR_40x_SRR3; 187c79c73f6SBlue Swirl break; 188c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 189c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 190c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 191c79c73f6SBlue Swirl break; 192c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 193c79c73f6SBlue Swirl break; 194c79c73f6SBlue Swirl default: 195c79c73f6SBlue Swirl goto excp_invalid; 196c79c73f6SBlue Swirl } 197bd6fefe7SBenjamin Herrenschmidt break; 198c79c73f6SBlue Swirl case POWERPC_EXCP_MCHECK: /* Machine check exception */ 199c79c73f6SBlue Swirl if (msr_me == 0) { 200c79c73f6SBlue Swirl /* Machine check exception is not enabled. 201c79c73f6SBlue Swirl * Enter checkstop state. 202c79c73f6SBlue Swirl */ 203c79c73f6SBlue Swirl fprintf(stderr, "Machine check while not allowed. " 204c79c73f6SBlue Swirl "Entering checkstop state\n"); 205013a2942SPaolo Bonzini if (qemu_log_separate()) { 206013a2942SPaolo Bonzini qemu_log("Machine check while not allowed. " 207013a2942SPaolo Bonzini "Entering checkstop state\n"); 208c79c73f6SBlue Swirl } 209259186a7SAndreas Färber cs->halted = 1; 210259186a7SAndreas Färber cs->interrupt_request |= CPU_INTERRUPT_EXITTB; 211c79c73f6SBlue Swirl } 21210c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 21310c21b5cSNicholas Piggin /* ISA specifies HV, but can be delivered to guest with HV clear 21410c21b5cSNicholas Piggin * (e.g., see FWNMI in PAPR). 21510c21b5cSNicholas Piggin */ 216c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 21710c21b5cSNicholas Piggin } 2185c94b2a5SCédric Le Goater ail = 0; 219c79c73f6SBlue Swirl 220c79c73f6SBlue Swirl /* machine check exceptions don't have ME set */ 221c79c73f6SBlue Swirl new_msr &= ~((target_ulong)1 << MSR_ME); 222c79c73f6SBlue Swirl 223c79c73f6SBlue Swirl /* XXX: should also have something loaded in DAR / DSISR */ 224c79c73f6SBlue Swirl switch (excp_model) { 225c79c73f6SBlue Swirl case POWERPC_EXCP_40x: 226c79c73f6SBlue Swirl srr0 = SPR_40x_SRR2; 227c79c73f6SBlue Swirl srr1 = SPR_40x_SRR3; 228c79c73f6SBlue Swirl break; 229c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 230a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 231c79c73f6SBlue Swirl srr0 = SPR_BOOKE_MCSRR0; 232c79c73f6SBlue Swirl srr1 = SPR_BOOKE_MCSRR1; 233c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 234c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 235c79c73f6SBlue Swirl break; 236c79c73f6SBlue Swirl default: 237c79c73f6SBlue Swirl break; 238c79c73f6SBlue Swirl } 239bd6fefe7SBenjamin Herrenschmidt break; 240c79c73f6SBlue Swirl case POWERPC_EXCP_DSI: /* Data storage exception */ 241c79c73f6SBlue Swirl LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx 242c79c73f6SBlue Swirl "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); 243bd6fefe7SBenjamin Herrenschmidt break; 244c79c73f6SBlue Swirl case POWERPC_EXCP_ISI: /* Instruction storage exception */ 245c79c73f6SBlue Swirl LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx 246c79c73f6SBlue Swirl "\n", msr, env->nip); 247c79c73f6SBlue Swirl msr |= env->error_code; 248bd6fefe7SBenjamin Herrenschmidt break; 249c79c73f6SBlue Swirl case POWERPC_EXCP_EXTERNAL: /* External input */ 250fdfba1a2SEdgar E. Iglesias cs = CPU(cpu); 251fdfba1a2SEdgar E. Iglesias 2526d49d6d4SBenjamin Herrenschmidt if (!lpes0) { 253c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 2546d49d6d4SBenjamin Herrenschmidt new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 2556d49d6d4SBenjamin Herrenschmidt srr0 = SPR_HSRR0; 2566d49d6d4SBenjamin Herrenschmidt srr1 = SPR_HSRR1; 257c79c73f6SBlue Swirl } 25868c2dd70SAlexander Graf if (env->mpic_proxy) { 25968c2dd70SAlexander Graf /* IACK the IRQ on delivery */ 260fdfba1a2SEdgar E. Iglesias env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack); 26168c2dd70SAlexander Graf } 262bd6fefe7SBenjamin Herrenschmidt break; 263c79c73f6SBlue Swirl case POWERPC_EXCP_ALIGN: /* Alignment exception */ 264c79c73f6SBlue Swirl /* Get rS/rD and rA from faulting opcode */ 2653433b732SBenjamin Herrenschmidt /* Note: the opcode fields will not be set properly for a direct 2663433b732SBenjamin Herrenschmidt * store load/store, but nobody cares as nobody actually uses 2673433b732SBenjamin Herrenschmidt * direct store segments. 2683433b732SBenjamin Herrenschmidt */ 2693433b732SBenjamin Herrenschmidt env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; 270bd6fefe7SBenjamin Herrenschmidt break; 271c79c73f6SBlue Swirl case POWERPC_EXCP_PROGRAM: /* Program exception */ 272c79c73f6SBlue Swirl switch (env->error_code & ~0xF) { 273c79c73f6SBlue Swirl case POWERPC_EXCP_FP: 274c79c73f6SBlue Swirl if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { 275c79c73f6SBlue Swirl LOG_EXCP("Ignore floating point exception\n"); 27627103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 277c79c73f6SBlue Swirl env->error_code = 0; 278c79c73f6SBlue Swirl return; 279c79c73f6SBlue Swirl } 2801b7d17caSBenjamin Herrenschmidt 2811b7d17caSBenjamin Herrenschmidt /* FP exceptions always have NIP pointing to the faulting 2821b7d17caSBenjamin Herrenschmidt * instruction, so always use store_next and claim we are 2831b7d17caSBenjamin Herrenschmidt * precise in the MSR. 2841b7d17caSBenjamin Herrenschmidt */ 285c79c73f6SBlue Swirl msr |= 0x00100000; 286bd6fefe7SBenjamin Herrenschmidt break; 287c79c73f6SBlue Swirl case POWERPC_EXCP_INVAL: 288c79c73f6SBlue Swirl LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); 289c79c73f6SBlue Swirl msr |= 0x00080000; 290c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PIL; 291c79c73f6SBlue Swirl break; 292c79c73f6SBlue Swirl case POWERPC_EXCP_PRIV: 293c79c73f6SBlue Swirl msr |= 0x00040000; 294c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PPR; 295c79c73f6SBlue Swirl break; 296c79c73f6SBlue Swirl case POWERPC_EXCP_TRAP: 297c79c73f6SBlue Swirl msr |= 0x00020000; 298c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PTR; 299c79c73f6SBlue Swirl break; 300c79c73f6SBlue Swirl default: 301c79c73f6SBlue Swirl /* Should never occur */ 302a47dddd7SAndreas Färber cpu_abort(cs, "Invalid program exception %d. Aborting\n", 303c79c73f6SBlue Swirl env->error_code); 304c79c73f6SBlue Swirl break; 305c79c73f6SBlue Swirl } 306bd6fefe7SBenjamin Herrenschmidt break; 307c79c73f6SBlue Swirl case POWERPC_EXCP_SYSCALL: /* System call exception */ 308c79c73f6SBlue Swirl dump_syscall(env); 309c79c73f6SBlue Swirl lev = env->error_code; 3106d49d6d4SBenjamin Herrenschmidt 311bd6fefe7SBenjamin Herrenschmidt /* We need to correct the NIP which in this case is supposed 312bd6fefe7SBenjamin Herrenschmidt * to point to the next instruction 313bd6fefe7SBenjamin Herrenschmidt */ 314bd6fefe7SBenjamin Herrenschmidt env->nip += 4; 315bd6fefe7SBenjamin Herrenschmidt 3166d49d6d4SBenjamin Herrenschmidt /* "PAPR mode" built-in hypercall emulation */ 3171d1be34dSDavid Gibson if ((lev == 1) && cpu->vhyp) { 3181d1be34dSDavid Gibson PPCVirtualHypervisorClass *vhc = 3191d1be34dSDavid Gibson PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); 3201d1be34dSDavid Gibson vhc->hypercall(cpu->vhyp, cpu); 321c79c73f6SBlue Swirl return; 322c79c73f6SBlue Swirl } 3236d49d6d4SBenjamin Herrenschmidt if (lev == 1) { 324c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 325c79c73f6SBlue Swirl } 326bd6fefe7SBenjamin Herrenschmidt break; 327bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 328c79c73f6SBlue Swirl case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ 329c79c73f6SBlue Swirl case POWERPC_EXCP_DECR: /* Decrementer exception */ 330bd6fefe7SBenjamin Herrenschmidt break; 331c79c73f6SBlue Swirl case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ 332c79c73f6SBlue Swirl /* FIT on 4xx */ 333c79c73f6SBlue Swirl LOG_EXCP("FIT exception\n"); 334bd6fefe7SBenjamin Herrenschmidt break; 335c79c73f6SBlue Swirl case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ 336c79c73f6SBlue Swirl LOG_EXCP("WDT exception\n"); 337c79c73f6SBlue Swirl switch (excp_model) { 338c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 339c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 340c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 341c79c73f6SBlue Swirl break; 342c79c73f6SBlue Swirl default: 343c79c73f6SBlue Swirl break; 344c79c73f6SBlue Swirl } 345bd6fefe7SBenjamin Herrenschmidt break; 346c79c73f6SBlue Swirl case POWERPC_EXCP_DTLB: /* Data TLB error */ 347c79c73f6SBlue Swirl case POWERPC_EXCP_ITLB: /* Instruction TLB error */ 348bd6fefe7SBenjamin Herrenschmidt break; 349c79c73f6SBlue Swirl case POWERPC_EXCP_DEBUG: /* Debug interrupt */ 350c79c73f6SBlue Swirl switch (excp_model) { 351c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 352a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 353c79c73f6SBlue Swirl srr0 = SPR_BOOKE_DSRR0; 354c79c73f6SBlue Swirl srr1 = SPR_BOOKE_DSRR1; 355c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 356c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 357c79c73f6SBlue Swirl break; 358c79c73f6SBlue Swirl default: 359c79c73f6SBlue Swirl break; 360c79c73f6SBlue Swirl } 361c79c73f6SBlue Swirl /* XXX: TODO */ 362a47dddd7SAndreas Färber cpu_abort(cs, "Debug exception is not implemented yet !\n"); 363bd6fefe7SBenjamin Herrenschmidt break; 364c79c73f6SBlue Swirl case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ 365c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 366bd6fefe7SBenjamin Herrenschmidt break; 367c79c73f6SBlue Swirl case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ 368c79c73f6SBlue Swirl /* XXX: TODO */ 369a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point data exception " 370c79c73f6SBlue Swirl "is not implemented yet !\n"); 371c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 372bd6fefe7SBenjamin Herrenschmidt break; 373c79c73f6SBlue Swirl case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ 374c79c73f6SBlue Swirl /* XXX: TODO */ 375a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point round exception " 376c79c73f6SBlue Swirl "is not implemented yet !\n"); 377c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 378bd6fefe7SBenjamin Herrenschmidt break; 379c79c73f6SBlue Swirl case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ 380c79c73f6SBlue Swirl /* XXX: TODO */ 381a47dddd7SAndreas Färber cpu_abort(cs, 382c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 383bd6fefe7SBenjamin Herrenschmidt break; 384c79c73f6SBlue Swirl case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ 385bd6fefe7SBenjamin Herrenschmidt break; 386c79c73f6SBlue Swirl case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ 387c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 388c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 389bd6fefe7SBenjamin Herrenschmidt break; 390c79c73f6SBlue Swirl case POWERPC_EXCP_RESET: /* System reset exception */ 391f85bcec3SNicholas Piggin /* A power-saving exception sets ME, otherwise it is unchanged */ 392c79c73f6SBlue Swirl if (msr_pow) { 393c79c73f6SBlue Swirl /* indicate that we resumed from power save mode */ 394c79c73f6SBlue Swirl msr |= 0x10000; 395f85bcec3SNicholas Piggin new_msr |= ((target_ulong)1 << MSR_ME); 396c79c73f6SBlue Swirl } 39710c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 39810c21b5cSNicholas Piggin /* ISA specifies HV, but can be delivered to guest with HV clear 39910c21b5cSNicholas Piggin * (e.g., see FWNMI in PAPR, NMI injection in QEMU). 40010c21b5cSNicholas Piggin */ 401c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 40210c21b5cSNicholas Piggin } else { 40310c21b5cSNicholas Piggin if (msr_pow) { 40410c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver power-saving system reset " 40510c21b5cSNicholas Piggin "exception %d with no HV support\n", excp); 40610c21b5cSNicholas Piggin } 40710c21b5cSNicholas Piggin } 4085c94b2a5SCédric Le Goater ail = 0; 409bd6fefe7SBenjamin Herrenschmidt break; 410c79c73f6SBlue Swirl case POWERPC_EXCP_DSEG: /* Data segment exception */ 411c79c73f6SBlue Swirl case POWERPC_EXCP_ISEG: /* Instruction segment exception */ 412c79c73f6SBlue Swirl case POWERPC_EXCP_TRACE: /* Trace exception */ 413bd6fefe7SBenjamin Herrenschmidt break; 414bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ 415c79c73f6SBlue Swirl case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ 416c79c73f6SBlue Swirl case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ 417c79c73f6SBlue Swirl case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ 418c79c73f6SBlue Swirl case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ 419bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HV_EMU: 420c79c73f6SBlue Swirl srr0 = SPR_HSRR0; 421c79c73f6SBlue Swirl srr1 = SPR_HSRR1; 422c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 423c79c73f6SBlue Swirl new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 424bd6fefe7SBenjamin Herrenschmidt break; 425c79c73f6SBlue Swirl case POWERPC_EXCP_VPU: /* Vector unavailable exception */ 4261f29871cSTom Musta case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ 4277019cb3dSAlexey Kardashevskiy case POWERPC_EXCP_FU: /* Facility unavailable exception */ 4285310799aSBalbir Singh #ifdef TARGET_PPC64 4295310799aSBalbir Singh env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56); 4305310799aSBalbir Singh #endif 431bd6fefe7SBenjamin Herrenschmidt break; 432c79c73f6SBlue Swirl case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ 433c79c73f6SBlue Swirl LOG_EXCP("PIT exception\n"); 434bd6fefe7SBenjamin Herrenschmidt break; 435c79c73f6SBlue Swirl case POWERPC_EXCP_IO: /* IO error exception */ 436c79c73f6SBlue Swirl /* XXX: TODO */ 437a47dddd7SAndreas Färber cpu_abort(cs, "601 IO error exception is not implemented yet !\n"); 438bd6fefe7SBenjamin Herrenschmidt break; 439c79c73f6SBlue Swirl case POWERPC_EXCP_RUNM: /* Run mode exception */ 440c79c73f6SBlue Swirl /* XXX: TODO */ 441a47dddd7SAndreas Färber cpu_abort(cs, "601 run mode exception is not implemented yet !\n"); 442bd6fefe7SBenjamin Herrenschmidt break; 443c79c73f6SBlue Swirl case POWERPC_EXCP_EMUL: /* Emulation trap exception */ 444c79c73f6SBlue Swirl /* XXX: TODO */ 445a47dddd7SAndreas Färber cpu_abort(cs, "602 emulation trap exception " 446c79c73f6SBlue Swirl "is not implemented yet !\n"); 447bd6fefe7SBenjamin Herrenschmidt break; 448c79c73f6SBlue Swirl case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ 449c79c73f6SBlue Swirl switch (excp_model) { 450c79c73f6SBlue Swirl case POWERPC_EXCP_602: 451c79c73f6SBlue Swirl case POWERPC_EXCP_603: 452c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 453c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 454c79c73f6SBlue Swirl goto tlb_miss_tgpr; 455c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 456c79c73f6SBlue Swirl goto tlb_miss; 457c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 458c79c73f6SBlue Swirl goto tlb_miss_74xx; 459c79c73f6SBlue Swirl default: 460a47dddd7SAndreas Färber cpu_abort(cs, "Invalid instruction TLB miss exception\n"); 461c79c73f6SBlue Swirl break; 462c79c73f6SBlue Swirl } 463c79c73f6SBlue Swirl break; 464c79c73f6SBlue Swirl case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ 465c79c73f6SBlue Swirl switch (excp_model) { 466c79c73f6SBlue Swirl case POWERPC_EXCP_602: 467c79c73f6SBlue Swirl case POWERPC_EXCP_603: 468c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 469c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 470c79c73f6SBlue Swirl goto tlb_miss_tgpr; 471c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 472c79c73f6SBlue Swirl goto tlb_miss; 473c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 474c79c73f6SBlue Swirl goto tlb_miss_74xx; 475c79c73f6SBlue Swirl default: 476a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data load TLB miss exception\n"); 477c79c73f6SBlue Swirl break; 478c79c73f6SBlue Swirl } 479c79c73f6SBlue Swirl break; 480c79c73f6SBlue Swirl case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ 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 tlb_miss_tgpr: 487c79c73f6SBlue Swirl /* Swap temporary saved registers with GPRs */ 488c79c73f6SBlue Swirl if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { 489c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_TGPR; 490c79c73f6SBlue Swirl hreg_swap_gpr_tgpr(env); 491c79c73f6SBlue Swirl } 492c79c73f6SBlue Swirl goto tlb_miss; 493c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 494c79c73f6SBlue Swirl tlb_miss: 495c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 496c79c73f6SBlue Swirl if (qemu_log_enabled()) { 497c79c73f6SBlue Swirl const char *es; 498c79c73f6SBlue Swirl target_ulong *miss, *cmp; 499c79c73f6SBlue Swirl int en; 500c79c73f6SBlue Swirl 501c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 502c79c73f6SBlue Swirl es = "I"; 503c79c73f6SBlue Swirl en = 'I'; 504c79c73f6SBlue Swirl miss = &env->spr[SPR_IMISS]; 505c79c73f6SBlue Swirl cmp = &env->spr[SPR_ICMP]; 506c79c73f6SBlue Swirl } else { 507c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 508c79c73f6SBlue Swirl es = "DL"; 509c79c73f6SBlue Swirl } else { 510c79c73f6SBlue Swirl es = "DS"; 511c79c73f6SBlue Swirl } 512c79c73f6SBlue Swirl en = 'D'; 513c79c73f6SBlue Swirl miss = &env->spr[SPR_DMISS]; 514c79c73f6SBlue Swirl cmp = &env->spr[SPR_DCMP]; 515c79c73f6SBlue Swirl } 516c79c73f6SBlue Swirl qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 517c79c73f6SBlue Swirl TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " 518c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 519c79c73f6SBlue Swirl env->spr[SPR_HASH1], env->spr[SPR_HASH2], 520c79c73f6SBlue Swirl env->error_code); 521c79c73f6SBlue Swirl } 522c79c73f6SBlue Swirl #endif 523c79c73f6SBlue Swirl msr |= env->crf[0] << 28; 524c79c73f6SBlue Swirl msr |= env->error_code; /* key, D/I, S/L bits */ 525c79c73f6SBlue Swirl /* Set way using a LRU mechanism */ 526c79c73f6SBlue Swirl msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; 527c79c73f6SBlue Swirl break; 528c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 529c79c73f6SBlue Swirl tlb_miss_74xx: 530c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 531c79c73f6SBlue Swirl if (qemu_log_enabled()) { 532c79c73f6SBlue Swirl const char *es; 533c79c73f6SBlue Swirl target_ulong *miss, *cmp; 534c79c73f6SBlue Swirl int en; 535c79c73f6SBlue Swirl 536c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 537c79c73f6SBlue Swirl es = "I"; 538c79c73f6SBlue Swirl en = 'I'; 539c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 540c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 541c79c73f6SBlue Swirl } else { 542c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 543c79c73f6SBlue Swirl es = "DL"; 544c79c73f6SBlue Swirl } else { 545c79c73f6SBlue Swirl es = "DS"; 546c79c73f6SBlue Swirl } 547c79c73f6SBlue Swirl en = 'D'; 548c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 549c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 550c79c73f6SBlue Swirl } 551c79c73f6SBlue Swirl qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 552c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 553c79c73f6SBlue Swirl env->error_code); 554c79c73f6SBlue Swirl } 555c79c73f6SBlue Swirl #endif 556c79c73f6SBlue Swirl msr |= env->error_code; /* key bit */ 557c79c73f6SBlue Swirl break; 558c79c73f6SBlue Swirl default: 559a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data store TLB miss exception\n"); 560c79c73f6SBlue Swirl break; 561c79c73f6SBlue Swirl } 562bd6fefe7SBenjamin Herrenschmidt break; 563c79c73f6SBlue Swirl case POWERPC_EXCP_FPA: /* Floating-point assist exception */ 564c79c73f6SBlue Swirl /* XXX: TODO */ 565a47dddd7SAndreas Färber cpu_abort(cs, "Floating point assist exception " 566c79c73f6SBlue Swirl "is not implemented yet !\n"); 567bd6fefe7SBenjamin Herrenschmidt break; 568c79c73f6SBlue Swirl case POWERPC_EXCP_DABR: /* Data address breakpoint */ 569c79c73f6SBlue Swirl /* XXX: TODO */ 570a47dddd7SAndreas Färber cpu_abort(cs, "DABR exception is not implemented yet !\n"); 571bd6fefe7SBenjamin Herrenschmidt break; 572c79c73f6SBlue Swirl case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ 573c79c73f6SBlue Swirl /* XXX: TODO */ 574a47dddd7SAndreas Färber cpu_abort(cs, "IABR exception is not implemented yet !\n"); 575bd6fefe7SBenjamin Herrenschmidt break; 576c79c73f6SBlue Swirl case POWERPC_EXCP_SMI: /* System management interrupt */ 577c79c73f6SBlue Swirl /* XXX: TODO */ 578a47dddd7SAndreas Färber cpu_abort(cs, "SMI exception is not implemented yet !\n"); 579bd6fefe7SBenjamin Herrenschmidt break; 580c79c73f6SBlue Swirl case POWERPC_EXCP_THERM: /* Thermal interrupt */ 581c79c73f6SBlue Swirl /* XXX: TODO */ 582a47dddd7SAndreas Färber cpu_abort(cs, "Thermal management exception " 583c79c73f6SBlue Swirl "is not implemented yet !\n"); 584bd6fefe7SBenjamin Herrenschmidt break; 585c79c73f6SBlue Swirl case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ 586c79c73f6SBlue Swirl /* XXX: TODO */ 587a47dddd7SAndreas Färber cpu_abort(cs, 588c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 589bd6fefe7SBenjamin Herrenschmidt break; 590c79c73f6SBlue Swirl case POWERPC_EXCP_VPUA: /* Vector assist exception */ 591c79c73f6SBlue Swirl /* XXX: TODO */ 592a47dddd7SAndreas Färber cpu_abort(cs, "VPU assist exception is not implemented yet !\n"); 593bd6fefe7SBenjamin Herrenschmidt break; 594c79c73f6SBlue Swirl case POWERPC_EXCP_SOFTP: /* Soft patch exception */ 595c79c73f6SBlue Swirl /* XXX: TODO */ 596a47dddd7SAndreas Färber cpu_abort(cs, 597c79c73f6SBlue Swirl "970 soft-patch exception is not implemented yet !\n"); 598bd6fefe7SBenjamin Herrenschmidt break; 599c79c73f6SBlue Swirl case POWERPC_EXCP_MAINT: /* Maintenance exception */ 600c79c73f6SBlue Swirl /* XXX: TODO */ 601a47dddd7SAndreas Färber cpu_abort(cs, 602c79c73f6SBlue Swirl "970 maintenance exception is not implemented yet !\n"); 603bd6fefe7SBenjamin Herrenschmidt break; 604c79c73f6SBlue Swirl case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ 605c79c73f6SBlue Swirl /* XXX: TODO */ 606a47dddd7SAndreas Färber cpu_abort(cs, "Maskable external exception " 607c79c73f6SBlue Swirl "is not implemented yet !\n"); 608bd6fefe7SBenjamin Herrenschmidt break; 609c79c73f6SBlue Swirl case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ 610c79c73f6SBlue Swirl /* XXX: TODO */ 611a47dddd7SAndreas Färber cpu_abort(cs, "Non maskable external exception " 612c79c73f6SBlue Swirl "is not implemented yet !\n"); 613bd6fefe7SBenjamin Herrenschmidt break; 614c79c73f6SBlue Swirl default: 615c79c73f6SBlue Swirl excp_invalid: 616a47dddd7SAndreas Färber cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 617c79c73f6SBlue Swirl break; 618c79c73f6SBlue Swirl } 619bd6fefe7SBenjamin Herrenschmidt 620bd6fefe7SBenjamin Herrenschmidt /* Save PC */ 621bd6fefe7SBenjamin Herrenschmidt env->spr[srr0] = env->nip; 622bd6fefe7SBenjamin Herrenschmidt 623c79c73f6SBlue Swirl /* Save MSR */ 624c79c73f6SBlue Swirl env->spr[srr1] = msr; 6256d49d6d4SBenjamin Herrenschmidt 6266d49d6d4SBenjamin Herrenschmidt /* Sanity check */ 62710c21b5cSNicholas Piggin if (!(env->msr_mask & MSR_HVB)) { 62810c21b5cSNicholas Piggin if (new_msr & MSR_HVB) { 62910c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with " 6306d49d6d4SBenjamin Herrenschmidt "no HV support\n", excp); 6316d49d6d4SBenjamin Herrenschmidt } 63210c21b5cSNicholas Piggin if (srr0 == SPR_HSRR0) { 63310c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with " 63410c21b5cSNicholas Piggin "no HV support\n", excp); 63510c21b5cSNicholas Piggin } 63610c21b5cSNicholas Piggin } 6376d49d6d4SBenjamin Herrenschmidt 638c79c73f6SBlue Swirl /* If any alternate SRR register are defined, duplicate saved values */ 639c79c73f6SBlue Swirl if (asrr0 != -1) { 640c79c73f6SBlue Swirl env->spr[asrr0] = env->spr[srr0]; 641c79c73f6SBlue Swirl } 642c79c73f6SBlue Swirl if (asrr1 != -1) { 643c79c73f6SBlue Swirl env->spr[asrr1] = env->spr[srr1]; 644c79c73f6SBlue Swirl } 645d5ac4f54SAlexey Kardashevskiy 6466d49d6d4SBenjamin Herrenschmidt /* Sort out endianness of interrupt, this differs depending on the 6476d49d6d4SBenjamin Herrenschmidt * CPU, the HV mode, etc... 6486d49d6d4SBenjamin Herrenschmidt */ 6491e0c7e55SAnton Blanchard #ifdef TARGET_PPC64 6506d49d6d4SBenjamin Herrenschmidt if (excp_model == POWERPC_EXCP_POWER7) { 6516d49d6d4SBenjamin Herrenschmidt if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) { 6526d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 6536d49d6d4SBenjamin Herrenschmidt } 6546d49d6d4SBenjamin Herrenschmidt } else if (excp_model == POWERPC_EXCP_POWER8) { 6556d49d6d4SBenjamin Herrenschmidt if (new_msr & MSR_HVB) { 6566d49d6d4SBenjamin Herrenschmidt if (env->spr[SPR_HID0] & HID0_HILE) { 6576d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 6586d49d6d4SBenjamin Herrenschmidt } 6596d49d6d4SBenjamin Herrenschmidt } else if (env->spr[SPR_LPCR] & LPCR_ILE) { 6601e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 6611e0c7e55SAnton Blanchard } 6621e0c7e55SAnton Blanchard } else if (msr_ile) { 6631e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 6641e0c7e55SAnton Blanchard } 6651e0c7e55SAnton Blanchard #else 666c79c73f6SBlue Swirl if (msr_ile) { 667c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_LE; 668c79c73f6SBlue Swirl } 6691e0c7e55SAnton Blanchard #endif 670c79c73f6SBlue Swirl 671c79c73f6SBlue Swirl /* Jump to handler */ 672c79c73f6SBlue Swirl vector = env->excp_vectors[excp]; 673c79c73f6SBlue Swirl if (vector == (target_ulong)-1ULL) { 674a47dddd7SAndreas Färber cpu_abort(cs, "Raised an exception without defined vector %d\n", 675c79c73f6SBlue Swirl excp); 676c79c73f6SBlue Swirl } 677c79c73f6SBlue Swirl vector |= env->excp_prefix; 6785c94b2a5SCédric Le Goater 6795c94b2a5SCédric Le Goater /* AIL only works if there is no HV transition and we are running with 6805c94b2a5SCédric Le Goater * translations enabled 6815c94b2a5SCédric Le Goater */ 6826d49d6d4SBenjamin Herrenschmidt if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) || 6836d49d6d4SBenjamin Herrenschmidt ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) { 6845c94b2a5SCédric Le Goater ail = 0; 6855c94b2a5SCédric Le Goater } 6865c94b2a5SCédric Le Goater /* Handle AIL */ 6875c94b2a5SCédric Le Goater if (ail) { 6885c94b2a5SCédric Le Goater new_msr |= (1 << MSR_IR) | (1 << MSR_DR); 6895c94b2a5SCédric Le Goater switch(ail) { 6905c94b2a5SCédric Le Goater case AIL_0001_8000: 6915c94b2a5SCédric Le Goater vector |= 0x18000; 6925c94b2a5SCédric Le Goater break; 6935c94b2a5SCédric Le Goater case AIL_C000_0000_0000_4000: 6945c94b2a5SCédric Le Goater vector |= 0xc000000000004000ull; 6955c94b2a5SCédric Le Goater break; 6965c94b2a5SCédric Le Goater default: 6975c94b2a5SCédric Le Goater cpu_abort(cs, "Invalid AIL combination %d\n", ail); 6985c94b2a5SCédric Le Goater break; 6995c94b2a5SCédric Le Goater } 7005c94b2a5SCédric Le Goater } 7015c94b2a5SCédric Le Goater 702c79c73f6SBlue Swirl #if defined(TARGET_PPC64) 703c79c73f6SBlue Swirl if (excp_model == POWERPC_EXCP_BOOKE) { 704e42a61f1SAlexander Graf if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) { 705e42a61f1SAlexander Graf /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */ 706c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_CM; 707e42a61f1SAlexander Graf } else { 708e42a61f1SAlexander Graf vector = (uint32_t)vector; 709c79c73f6SBlue Swirl } 710c79c73f6SBlue Swirl } else { 711c79c73f6SBlue Swirl if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) { 712c79c73f6SBlue Swirl vector = (uint32_t)vector; 713c79c73f6SBlue Swirl } else { 714c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_SF; 715c79c73f6SBlue Swirl } 716c79c73f6SBlue Swirl } 717c79c73f6SBlue Swirl #endif 7181c953ba5SBenjamin Herrenschmidt /* We don't use hreg_store_msr here as already have treated 719c79c73f6SBlue Swirl * any special case that could occur. Just store MSR and update hflags 7201c953ba5SBenjamin Herrenschmidt * 7211c953ba5SBenjamin Herrenschmidt * Note: We *MUST* not use hreg_store_msr() as-is anyway because it 7221c953ba5SBenjamin Herrenschmidt * will prevent setting of the HV bit which some exceptions might need 7231c953ba5SBenjamin Herrenschmidt * to do. 724c79c73f6SBlue Swirl */ 725c79c73f6SBlue Swirl env->msr = new_msr & env->msr_mask; 726c79c73f6SBlue Swirl hreg_compute_hflags(env); 727c79c73f6SBlue Swirl env->nip = vector; 728c79c73f6SBlue Swirl /* Reset exception state */ 72927103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 730c79c73f6SBlue Swirl env->error_code = 0; 731cd0c6f47SBenjamin Herrenschmidt 732139d9023SNikunj A Dadhania /* Reset the reservation */ 733139d9023SNikunj A Dadhania env->reserve_addr = -1; 734139d9023SNikunj A Dadhania 735cd0c6f47SBenjamin Herrenschmidt /* Any interrupt is context synchronizing, check if TCG TLB 736cd0c6f47SBenjamin Herrenschmidt * needs a delayed flush on ppc64 737cd0c6f47SBenjamin Herrenschmidt */ 738e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 739c79c73f6SBlue Swirl } 740c79c73f6SBlue Swirl 74197a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs) 742c79c73f6SBlue Swirl { 74397a8ea5aSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 74497a8ea5aSAndreas Färber CPUPPCState *env = &cpu->env; 7455c26a5b3SAndreas Färber 74627103424SAndreas Färber powerpc_excp(cpu, env->excp_model, cs->exception_index); 747c79c73f6SBlue Swirl } 748c79c73f6SBlue Swirl 749458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env) 750c79c73f6SBlue Swirl { 7515c26a5b3SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 752c79c73f6SBlue Swirl #if 0 753259186a7SAndreas Färber CPUState *cs = CPU(cpu); 754259186a7SAndreas Färber 755c79c73f6SBlue Swirl qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n", 756c79c73f6SBlue Swirl __func__, env, env->pending_interrupts, 757259186a7SAndreas Färber cs->interrupt_request, (int)msr_me, (int)msr_ee); 758c79c73f6SBlue Swirl #endif 759c79c73f6SBlue Swirl /* External reset */ 760c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { 761c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); 7625c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 763c79c73f6SBlue Swirl return; 764c79c73f6SBlue Swirl } 765c79c73f6SBlue Swirl /* Machine check exception */ 766c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { 767c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); 7685c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK); 769c79c73f6SBlue Swirl return; 770c79c73f6SBlue Swirl } 771c79c73f6SBlue Swirl #if 0 /* TODO */ 772c79c73f6SBlue Swirl /* External debug exception */ 773c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { 774c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); 7755c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG); 776c79c73f6SBlue Swirl return; 777c79c73f6SBlue Swirl } 778c79c73f6SBlue Swirl #endif 779c79c73f6SBlue Swirl /* Hypervisor decrementer exception */ 780c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { 7814b236b62SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 7824b236b62SBenjamin Herrenschmidt bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); 7834b236b62SBenjamin Herrenschmidt if ((msr_ee != 0 || msr_hv == 0) && hdice) { 7844b236b62SBenjamin Herrenschmidt /* HDEC clears on delivery */ 7854b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 7865c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR); 787c79c73f6SBlue Swirl return; 788c79c73f6SBlue Swirl } 789c79c73f6SBlue Swirl } 790d1dbe37cSBenjamin Herrenschmidt /* Extermal interrupt can ignore MSR:EE under some circumstances */ 791d1dbe37cSBenjamin Herrenschmidt if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { 792d1dbe37cSBenjamin Herrenschmidt bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 793d1dbe37cSBenjamin Herrenschmidt if (msr_ee != 0 || (env->has_hv_mode && msr_hv == 0 && !lpes0)) { 794d1dbe37cSBenjamin Herrenschmidt powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL); 795d1dbe37cSBenjamin Herrenschmidt return; 796d1dbe37cSBenjamin Herrenschmidt } 797d1dbe37cSBenjamin Herrenschmidt } 798c79c73f6SBlue Swirl if (msr_ce != 0) { 799c79c73f6SBlue Swirl /* External critical interrupt */ 800c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { 801c79c73f6SBlue Swirl /* Taking a critical external interrupt does not clear the external 802c79c73f6SBlue Swirl * critical interrupt status 803c79c73f6SBlue Swirl */ 804c79c73f6SBlue Swirl #if 0 805c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT); 806c79c73f6SBlue Swirl #endif 8075c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL); 808c79c73f6SBlue Swirl return; 809c79c73f6SBlue Swirl } 810c79c73f6SBlue Swirl } 811c79c73f6SBlue Swirl if (msr_ee != 0) { 812c79c73f6SBlue Swirl /* Watchdog timer on embedded PowerPC */ 813c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { 814c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); 8155c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT); 816c79c73f6SBlue Swirl return; 817c79c73f6SBlue Swirl } 818c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { 819c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); 8205c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI); 821c79c73f6SBlue Swirl return; 822c79c73f6SBlue Swirl } 823c79c73f6SBlue Swirl /* Fixed interval timer on embedded PowerPC */ 824c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { 825c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); 8265c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT); 827c79c73f6SBlue Swirl return; 828c79c73f6SBlue Swirl } 829c79c73f6SBlue Swirl /* Programmable interval timer on embedded PowerPC */ 830c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { 831c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); 8325c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT); 833c79c73f6SBlue Swirl return; 834c79c73f6SBlue Swirl } 835c79c73f6SBlue Swirl /* Decrementer exception */ 836c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { 837e81a982aSAlexander Graf if (ppc_decr_clear_on_delivery(env)) { 838c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); 839e81a982aSAlexander Graf } 8405c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR); 841c79c73f6SBlue Swirl return; 842c79c73f6SBlue Swirl } 843c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { 844c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); 8455c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI); 846c79c73f6SBlue Swirl return; 847c79c73f6SBlue Swirl } 848c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { 849c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); 8505c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM); 851c79c73f6SBlue Swirl return; 852c79c73f6SBlue Swirl } 853c79c73f6SBlue Swirl /* Thermal interrupt */ 854c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { 855c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); 8565c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM); 857c79c73f6SBlue Swirl return; 858c79c73f6SBlue Swirl } 859c79c73f6SBlue Swirl } 860c79c73f6SBlue Swirl } 86134316482SAlexey Kardashevskiy 86234316482SAlexey Kardashevskiy void ppc_cpu_do_system_reset(CPUState *cs) 86334316482SAlexey Kardashevskiy { 86434316482SAlexey Kardashevskiy PowerPCCPU *cpu = POWERPC_CPU(cs); 86534316482SAlexey Kardashevskiy CPUPPCState *env = &cpu->env; 86634316482SAlexey Kardashevskiy 86734316482SAlexey Kardashevskiy powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 86834316482SAlexey Kardashevskiy } 869c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */ 870c79c73f6SBlue Swirl 871458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 872458dd766SRichard Henderson { 873458dd766SRichard Henderson PowerPCCPU *cpu = POWERPC_CPU(cs); 874458dd766SRichard Henderson CPUPPCState *env = &cpu->env; 875458dd766SRichard Henderson 876458dd766SRichard Henderson if (interrupt_request & CPU_INTERRUPT_HARD) { 877458dd766SRichard Henderson ppc_hw_interrupt(env); 878458dd766SRichard Henderson if (env->pending_interrupts == 0) { 879458dd766SRichard Henderson cs->interrupt_request &= ~CPU_INTERRUPT_HARD; 880458dd766SRichard Henderson } 881458dd766SRichard Henderson return true; 882458dd766SRichard Henderson } 883458dd766SRichard Henderson return false; 884458dd766SRichard Henderson } 885458dd766SRichard Henderson 886c79c73f6SBlue Swirl #if defined(DEBUG_OP) 887c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr) 888c79c73f6SBlue Swirl { 889c79c73f6SBlue Swirl qemu_log("Return from exception at " TARGET_FMT_lx " with flags " 890c79c73f6SBlue Swirl TARGET_FMT_lx "\n", RA, msr); 891c79c73f6SBlue Swirl } 892c79c73f6SBlue Swirl #endif 893c79c73f6SBlue Swirl 894ad71ed68SBlue Swirl /*****************************************************************************/ 895ad71ed68SBlue Swirl /* Exceptions processing helpers */ 896ad71ed68SBlue Swirl 897db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, 898db789c6cSBenjamin Herrenschmidt uint32_t error_code, uintptr_t raddr) 899ad71ed68SBlue Swirl { 90027103424SAndreas Färber CPUState *cs = CPU(ppc_env_get_cpu(env)); 90127103424SAndreas Färber 90227103424SAndreas Färber cs->exception_index = exception; 903ad71ed68SBlue Swirl env->error_code = error_code; 904db789c6cSBenjamin Herrenschmidt cpu_loop_exit_restore(cs, raddr); 905db789c6cSBenjamin Herrenschmidt } 906db789c6cSBenjamin Herrenschmidt 907db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception, 908db789c6cSBenjamin Herrenschmidt uint32_t error_code) 909db789c6cSBenjamin Herrenschmidt { 910db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 911db789c6cSBenjamin Herrenschmidt } 912db789c6cSBenjamin Herrenschmidt 913db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception) 914db789c6cSBenjamin Herrenschmidt { 915db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 916db789c6cSBenjamin Herrenschmidt } 917db789c6cSBenjamin Herrenschmidt 918db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception, 919db789c6cSBenjamin Herrenschmidt uintptr_t raddr) 920db789c6cSBenjamin Herrenschmidt { 921db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, raddr); 922db789c6cSBenjamin Herrenschmidt } 923db789c6cSBenjamin Herrenschmidt 924db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, 925db789c6cSBenjamin Herrenschmidt uint32_t error_code) 926db789c6cSBenjamin Herrenschmidt { 927db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 928ad71ed68SBlue Swirl } 929ad71ed68SBlue Swirl 930e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception) 931ad71ed68SBlue Swirl { 932db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 933ad71ed68SBlue Swirl } 934ad71ed68SBlue Swirl 935ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 936e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val) 937ad71ed68SBlue Swirl { 938db789c6cSBenjamin Herrenschmidt uint32_t excp = hreg_store_msr(env, val, 0); 939259186a7SAndreas Färber 940db789c6cSBenjamin Herrenschmidt if (excp != 0) { 941db789c6cSBenjamin Herrenschmidt CPUState *cs = CPU(ppc_env_get_cpu(env)); 942259186a7SAndreas Färber cs->interrupt_request |= CPU_INTERRUPT_EXITTB; 943db789c6cSBenjamin Herrenschmidt raise_exception(env, excp); 944ad71ed68SBlue Swirl } 945ad71ed68SBlue Swirl } 946ad71ed68SBlue Swirl 9477778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64) 9487778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) 9497778a575SBenjamin Herrenschmidt { 9507778a575SBenjamin Herrenschmidt CPUState *cs; 9517778a575SBenjamin Herrenschmidt 9527778a575SBenjamin Herrenschmidt cs = CPU(ppc_env_get_cpu(env)); 9537778a575SBenjamin Herrenschmidt cs->halted = 1; 9547778a575SBenjamin Herrenschmidt env->in_pm_state = true; 9557778a575SBenjamin Herrenschmidt 9564b236b62SBenjamin Herrenschmidt /* The architecture specifies that HDEC interrupts are 9574b236b62SBenjamin Herrenschmidt * discarded in PM states 9584b236b62SBenjamin Herrenschmidt */ 9594b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 9604b236b62SBenjamin Herrenschmidt 9617778a575SBenjamin Herrenschmidt /* Technically, nap doesn't set EE, but if we don't set it 9627778a575SBenjamin Herrenschmidt * then ppc_hw_interrupt() won't deliver. We could add some 9637778a575SBenjamin Herrenschmidt * other tests there based on LPCR but it's simpler to just 9647778a575SBenjamin Herrenschmidt * whack EE in. It will be cleared by the 0x100 at wakeup 9657778a575SBenjamin Herrenschmidt * anyway. It will still be observable by the guest in SRR1 9667778a575SBenjamin Herrenschmidt * but this doesn't seem to be a problem. 9677778a575SBenjamin Herrenschmidt */ 9687778a575SBenjamin Herrenschmidt env->msr |= (1ull << MSR_EE); 969db789c6cSBenjamin Herrenschmidt raise_exception(env, EXCP_HLT); 9707778a575SBenjamin Herrenschmidt } 9717778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 9727778a575SBenjamin Herrenschmidt 973a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) 974ad71ed68SBlue Swirl { 975259186a7SAndreas Färber CPUState *cs = CPU(ppc_env_get_cpu(env)); 976259186a7SAndreas Färber 977a2e71b28SBenjamin Herrenschmidt /* MSR:POW cannot be set by any form of rfi */ 978a2e71b28SBenjamin Herrenschmidt msr &= ~(1ULL << MSR_POW); 979a2e71b28SBenjamin Herrenschmidt 980ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 981a2e71b28SBenjamin Herrenschmidt /* Switching to 32-bit ? Crop the nip */ 982a2e71b28SBenjamin Herrenschmidt if (!msr_is_64bit(env, msr)) { 983ad71ed68SBlue Swirl nip = (uint32_t)nip; 984ad71ed68SBlue Swirl } 985ad71ed68SBlue Swirl #else 986ad71ed68SBlue Swirl nip = (uint32_t)nip; 987ad71ed68SBlue Swirl #endif 988ad71ed68SBlue Swirl /* XXX: beware: this is false if VLE is supported */ 989ad71ed68SBlue Swirl env->nip = nip & ~((target_ulong)0x00000003); 990ad71ed68SBlue Swirl hreg_store_msr(env, msr, 1); 991ad71ed68SBlue Swirl #if defined(DEBUG_OP) 992ad71ed68SBlue Swirl cpu_dump_rfi(env->nip, env->msr); 993ad71ed68SBlue Swirl #endif 994ad71ed68SBlue Swirl /* No need to raise an exception here, 995ad71ed68SBlue Swirl * as rfi is always the last insn of a TB 996ad71ed68SBlue Swirl */ 997259186a7SAndreas Färber cs->interrupt_request |= CPU_INTERRUPT_EXITTB; 998cd0c6f47SBenjamin Herrenschmidt 999a8b73734SNikunj A Dadhania /* Reset the reservation */ 1000a8b73734SNikunj A Dadhania env->reserve_addr = -1; 1001a8b73734SNikunj A Dadhania 1002cd0c6f47SBenjamin Herrenschmidt /* Context synchronizing: check if TCG TLB needs flush */ 1003e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 1004ad71ed68SBlue Swirl } 1005ad71ed68SBlue Swirl 1006e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env) 1007ad71ed68SBlue Swirl { 1008a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); 1009a1bb7384SScott Wood } 1010ad71ed68SBlue Swirl 1011a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK 1012ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1013e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env) 1014ad71ed68SBlue Swirl { 1015a2e71b28SBenjamin Herrenschmidt /* The architeture defines a number of rules for which bits 1016a2e71b28SBenjamin Herrenschmidt * can change but in practice, we handle this in hreg_store_msr() 1017a2e71b28SBenjamin Herrenschmidt * which will be called by do_rfi(), so there is no need to filter 1018a2e71b28SBenjamin Herrenschmidt * here 1019a2e71b28SBenjamin Herrenschmidt */ 1020a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]); 1021ad71ed68SBlue Swirl } 1022ad71ed68SBlue Swirl 1023e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env) 1024ad71ed68SBlue Swirl { 1025a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); 1026ad71ed68SBlue Swirl } 1027ad71ed68SBlue Swirl #endif 1028ad71ed68SBlue Swirl 1029ad71ed68SBlue Swirl /*****************************************************************************/ 1030ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */ 1031e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env) 1032ad71ed68SBlue Swirl { 1033a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]); 1034ad71ed68SBlue Swirl } 1035ad71ed68SBlue Swirl 1036e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env) 1037ad71ed68SBlue Swirl { 1038a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]); 1039ad71ed68SBlue Swirl } 1040ad71ed68SBlue Swirl 1041e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env) 1042ad71ed68SBlue Swirl { 1043a1bb7384SScott Wood /* FIXME: choose CSRR1 or DSRR1 based on cpu type */ 1044a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]); 1045ad71ed68SBlue Swirl } 1046ad71ed68SBlue Swirl 1047e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env) 1048ad71ed68SBlue Swirl { 1049a1bb7384SScott Wood /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ 1050a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); 1051ad71ed68SBlue Swirl } 1052ad71ed68SBlue Swirl #endif 1053ad71ed68SBlue Swirl 1054e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1055e5f17ac6SBlue Swirl uint32_t flags) 1056ad71ed68SBlue Swirl { 1057ad71ed68SBlue Swirl if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || 1058ad71ed68SBlue Swirl ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) || 1059ad71ed68SBlue Swirl ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || 1060ad71ed68SBlue Swirl ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || 1061ad71ed68SBlue Swirl ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { 106272073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 106372073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1064ad71ed68SBlue Swirl } 1065ad71ed68SBlue Swirl } 1066ad71ed68SBlue Swirl 1067ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1068e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1069e5f17ac6SBlue Swirl uint32_t flags) 1070ad71ed68SBlue Swirl { 1071ad71ed68SBlue Swirl if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || 1072ad71ed68SBlue Swirl ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) || 1073ad71ed68SBlue Swirl ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || 1074ad71ed68SBlue Swirl ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || 1075ad71ed68SBlue Swirl ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { 107672073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 107772073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1078ad71ed68SBlue Swirl } 1079ad71ed68SBlue Swirl } 1080ad71ed68SBlue Swirl #endif 1081ad71ed68SBlue Swirl 1082ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 1083ad71ed68SBlue Swirl /*****************************************************************************/ 1084ad71ed68SBlue Swirl /* PowerPC 601 specific instructions (POWER bridge) */ 1085ad71ed68SBlue Swirl 1086e5f17ac6SBlue Swirl void helper_rfsvc(CPUPPCState *env) 1087ad71ed68SBlue Swirl { 1088a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->lr, env->ctr & 0x0000FFFF); 1089ad71ed68SBlue Swirl } 1090ad71ed68SBlue Swirl 1091ad71ed68SBlue Swirl /* Embedded.Processor Control */ 1092ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb) 1093ad71ed68SBlue Swirl { 1094ad71ed68SBlue Swirl int msg = rb & DBELL_TYPE_MASK; 1095ad71ed68SBlue Swirl int irq = -1; 1096ad71ed68SBlue Swirl 1097ad71ed68SBlue Swirl switch (msg) { 1098ad71ed68SBlue Swirl case DBELL_TYPE_DBELL: 1099ad71ed68SBlue Swirl irq = PPC_INTERRUPT_DOORBELL; 1100ad71ed68SBlue Swirl break; 1101ad71ed68SBlue Swirl case DBELL_TYPE_DBELL_CRIT: 1102ad71ed68SBlue Swirl irq = PPC_INTERRUPT_CDOORBELL; 1103ad71ed68SBlue Swirl break; 1104ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL: 1105ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_CRIT: 1106ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_MC: 1107ad71ed68SBlue Swirl /* XXX implement */ 1108ad71ed68SBlue Swirl default: 1109ad71ed68SBlue Swirl break; 1110ad71ed68SBlue Swirl } 1111ad71ed68SBlue Swirl 1112ad71ed68SBlue Swirl return irq; 1113ad71ed68SBlue Swirl } 1114ad71ed68SBlue Swirl 1115e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb) 1116ad71ed68SBlue Swirl { 1117ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1118ad71ed68SBlue Swirl 1119ad71ed68SBlue Swirl if (irq < 0) { 1120ad71ed68SBlue Swirl return; 1121ad71ed68SBlue Swirl } 1122ad71ed68SBlue Swirl 1123ad71ed68SBlue Swirl env->pending_interrupts &= ~(1 << irq); 1124ad71ed68SBlue Swirl } 1125ad71ed68SBlue Swirl 1126ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb) 1127ad71ed68SBlue Swirl { 1128ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1129ad71ed68SBlue Swirl int pir = rb & DBELL_PIRTAG_MASK; 1130182735efSAndreas Färber CPUState *cs; 1131ad71ed68SBlue Swirl 1132ad71ed68SBlue Swirl if (irq < 0) { 1133ad71ed68SBlue Swirl return; 1134ad71ed68SBlue Swirl } 1135ad71ed68SBlue Swirl 1136*f1c29ebcSThomas Huth qemu_mutex_lock_iothread(); 1137bdc44640SAndreas Färber CPU_FOREACH(cs) { 1138182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 1139182735efSAndreas Färber CPUPPCState *cenv = &cpu->env; 1140182735efSAndreas Färber 1141ad71ed68SBlue Swirl if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { 1142ad71ed68SBlue Swirl cenv->pending_interrupts |= 1 << irq; 1143182735efSAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 1144ad71ed68SBlue Swirl } 1145ad71ed68SBlue Swirl } 1146*f1c29ebcSThomas Huth qemu_mutex_unlock_iothread(); 1147ad71ed68SBlue Swirl } 1148ad71ed68SBlue Swirl #endif 1149