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" 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; 210044897efSRichard Purdie cpu_interrupt_exittb(cs); 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; 2860ee604abSAaron Larson env->spr[SPR_BOOKE_ESR] = ESR_FP; 287bd6fefe7SBenjamin Herrenschmidt break; 288c79c73f6SBlue Swirl case POWERPC_EXCP_INVAL: 289c79c73f6SBlue Swirl LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); 290c79c73f6SBlue Swirl msr |= 0x00080000; 291c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PIL; 292c79c73f6SBlue Swirl break; 293c79c73f6SBlue Swirl case POWERPC_EXCP_PRIV: 294c79c73f6SBlue Swirl msr |= 0x00040000; 295c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PPR; 296c79c73f6SBlue Swirl break; 297c79c73f6SBlue Swirl case POWERPC_EXCP_TRAP: 298c79c73f6SBlue Swirl msr |= 0x00020000; 299c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PTR; 300c79c73f6SBlue Swirl break; 301c79c73f6SBlue Swirl default: 302c79c73f6SBlue Swirl /* Should never occur */ 303a47dddd7SAndreas Färber cpu_abort(cs, "Invalid program exception %d. Aborting\n", 304c79c73f6SBlue Swirl env->error_code); 305c79c73f6SBlue Swirl break; 306c79c73f6SBlue Swirl } 307bd6fefe7SBenjamin Herrenschmidt break; 308c79c73f6SBlue Swirl case POWERPC_EXCP_SYSCALL: /* System call exception */ 309c79c73f6SBlue Swirl dump_syscall(env); 310c79c73f6SBlue Swirl lev = env->error_code; 3116d49d6d4SBenjamin Herrenschmidt 312bd6fefe7SBenjamin Herrenschmidt /* We need to correct the NIP which in this case is supposed 313bd6fefe7SBenjamin Herrenschmidt * to point to the next instruction 314bd6fefe7SBenjamin Herrenschmidt */ 315bd6fefe7SBenjamin Herrenschmidt env->nip += 4; 316bd6fefe7SBenjamin Herrenschmidt 3176d49d6d4SBenjamin Herrenschmidt /* "PAPR mode" built-in hypercall emulation */ 3181d1be34dSDavid Gibson if ((lev == 1) && cpu->vhyp) { 3191d1be34dSDavid Gibson PPCVirtualHypervisorClass *vhc = 3201d1be34dSDavid Gibson PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); 3211d1be34dSDavid Gibson vhc->hypercall(cpu->vhyp, cpu); 322c79c73f6SBlue Swirl return; 323c79c73f6SBlue Swirl } 3246d49d6d4SBenjamin Herrenschmidt if (lev == 1) { 325c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 326c79c73f6SBlue Swirl } 327bd6fefe7SBenjamin Herrenschmidt break; 328bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 329c79c73f6SBlue Swirl case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ 330c79c73f6SBlue Swirl case POWERPC_EXCP_DECR: /* Decrementer exception */ 331bd6fefe7SBenjamin Herrenschmidt break; 332c79c73f6SBlue Swirl case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ 333c79c73f6SBlue Swirl /* FIT on 4xx */ 334c79c73f6SBlue Swirl LOG_EXCP("FIT exception\n"); 335bd6fefe7SBenjamin Herrenschmidt break; 336c79c73f6SBlue Swirl case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ 337c79c73f6SBlue Swirl LOG_EXCP("WDT exception\n"); 338c79c73f6SBlue Swirl switch (excp_model) { 339c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 340c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 341c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 342c79c73f6SBlue Swirl break; 343c79c73f6SBlue Swirl default: 344c79c73f6SBlue Swirl break; 345c79c73f6SBlue Swirl } 346bd6fefe7SBenjamin Herrenschmidt break; 347c79c73f6SBlue Swirl case POWERPC_EXCP_DTLB: /* Data TLB error */ 348c79c73f6SBlue Swirl case POWERPC_EXCP_ITLB: /* Instruction TLB error */ 349bd6fefe7SBenjamin Herrenschmidt break; 350c79c73f6SBlue Swirl case POWERPC_EXCP_DEBUG: /* Debug interrupt */ 351c79c73f6SBlue Swirl switch (excp_model) { 352c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 353a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 354c79c73f6SBlue Swirl srr0 = SPR_BOOKE_DSRR0; 355c79c73f6SBlue Swirl srr1 = SPR_BOOKE_DSRR1; 356c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 357c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 358c79c73f6SBlue Swirl break; 359c79c73f6SBlue Swirl default: 360c79c73f6SBlue Swirl break; 361c79c73f6SBlue Swirl } 362c79c73f6SBlue Swirl /* XXX: TODO */ 363a47dddd7SAndreas Färber cpu_abort(cs, "Debug exception is not implemented yet !\n"); 364bd6fefe7SBenjamin Herrenschmidt break; 365c79c73f6SBlue Swirl case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ 366c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 367bd6fefe7SBenjamin Herrenschmidt break; 368c79c73f6SBlue Swirl case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ 369c79c73f6SBlue Swirl /* XXX: TODO */ 370a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point data exception " 371c79c73f6SBlue Swirl "is not implemented yet !\n"); 372c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 373bd6fefe7SBenjamin Herrenschmidt break; 374c79c73f6SBlue Swirl case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ 375c79c73f6SBlue Swirl /* XXX: TODO */ 376a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point round exception " 377c79c73f6SBlue Swirl "is not implemented yet !\n"); 378c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 379bd6fefe7SBenjamin Herrenschmidt break; 380c79c73f6SBlue Swirl case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ 381c79c73f6SBlue Swirl /* XXX: TODO */ 382a47dddd7SAndreas Färber cpu_abort(cs, 383c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 384bd6fefe7SBenjamin Herrenschmidt break; 385c79c73f6SBlue Swirl case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ 386bd6fefe7SBenjamin Herrenschmidt break; 387c79c73f6SBlue Swirl case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ 388c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 389c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 390bd6fefe7SBenjamin Herrenschmidt break; 391c79c73f6SBlue Swirl case POWERPC_EXCP_RESET: /* System reset exception */ 392f85bcec3SNicholas Piggin /* A power-saving exception sets ME, otherwise it is unchanged */ 393c79c73f6SBlue Swirl if (msr_pow) { 394c79c73f6SBlue Swirl /* indicate that we resumed from power save mode */ 395c79c73f6SBlue Swirl msr |= 0x10000; 396f85bcec3SNicholas Piggin new_msr |= ((target_ulong)1 << MSR_ME); 397c79c73f6SBlue Swirl } 39810c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 39910c21b5cSNicholas Piggin /* ISA specifies HV, but can be delivered to guest with HV clear 40010c21b5cSNicholas Piggin * (e.g., see FWNMI in PAPR, NMI injection in QEMU). 40110c21b5cSNicholas Piggin */ 402c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 40310c21b5cSNicholas Piggin } else { 40410c21b5cSNicholas Piggin if (msr_pow) { 40510c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver power-saving system reset " 40610c21b5cSNicholas Piggin "exception %d with no HV support\n", excp); 40710c21b5cSNicholas Piggin } 40810c21b5cSNicholas Piggin } 4095c94b2a5SCédric Le Goater ail = 0; 410bd6fefe7SBenjamin Herrenschmidt break; 411c79c73f6SBlue Swirl case POWERPC_EXCP_DSEG: /* Data segment exception */ 412c79c73f6SBlue Swirl case POWERPC_EXCP_ISEG: /* Instruction segment exception */ 413c79c73f6SBlue Swirl case POWERPC_EXCP_TRACE: /* Trace exception */ 414bd6fefe7SBenjamin Herrenschmidt break; 415bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ 416c79c73f6SBlue Swirl case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ 417c79c73f6SBlue Swirl case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ 418c79c73f6SBlue Swirl case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ 419c79c73f6SBlue Swirl case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ 420bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HV_EMU: 421c79c73f6SBlue Swirl srr0 = SPR_HSRR0; 422c79c73f6SBlue Swirl srr1 = SPR_HSRR1; 423c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 424c79c73f6SBlue Swirl new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 425bd6fefe7SBenjamin Herrenschmidt break; 426c79c73f6SBlue Swirl case POWERPC_EXCP_VPU: /* Vector unavailable exception */ 4271f29871cSTom Musta case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ 4287019cb3dSAlexey Kardashevskiy case POWERPC_EXCP_FU: /* Facility unavailable exception */ 4295310799aSBalbir Singh #ifdef TARGET_PPC64 4305310799aSBalbir Singh env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56); 4315310799aSBalbir Singh #endif 432bd6fefe7SBenjamin Herrenschmidt break; 433c79c73f6SBlue Swirl case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ 434c79c73f6SBlue Swirl LOG_EXCP("PIT exception\n"); 435bd6fefe7SBenjamin Herrenschmidt break; 436c79c73f6SBlue Swirl case POWERPC_EXCP_IO: /* IO error exception */ 437c79c73f6SBlue Swirl /* XXX: TODO */ 438a47dddd7SAndreas Färber cpu_abort(cs, "601 IO error exception is not implemented yet !\n"); 439bd6fefe7SBenjamin Herrenschmidt break; 440c79c73f6SBlue Swirl case POWERPC_EXCP_RUNM: /* Run mode exception */ 441c79c73f6SBlue Swirl /* XXX: TODO */ 442a47dddd7SAndreas Färber cpu_abort(cs, "601 run mode exception is not implemented yet !\n"); 443bd6fefe7SBenjamin Herrenschmidt break; 444c79c73f6SBlue Swirl case POWERPC_EXCP_EMUL: /* Emulation trap exception */ 445c79c73f6SBlue Swirl /* XXX: TODO */ 446a47dddd7SAndreas Färber cpu_abort(cs, "602 emulation trap exception " 447c79c73f6SBlue Swirl "is not implemented yet !\n"); 448bd6fefe7SBenjamin Herrenschmidt break; 449c79c73f6SBlue Swirl case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ 450c79c73f6SBlue Swirl switch (excp_model) { 451c79c73f6SBlue Swirl case POWERPC_EXCP_602: 452c79c73f6SBlue Swirl case POWERPC_EXCP_603: 453c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 454c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 455c79c73f6SBlue Swirl goto tlb_miss_tgpr; 456c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 457c79c73f6SBlue Swirl goto tlb_miss; 458c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 459c79c73f6SBlue Swirl goto tlb_miss_74xx; 460c79c73f6SBlue Swirl default: 461a47dddd7SAndreas Färber cpu_abort(cs, "Invalid instruction TLB miss exception\n"); 462c79c73f6SBlue Swirl break; 463c79c73f6SBlue Swirl } 464c79c73f6SBlue Swirl break; 465c79c73f6SBlue Swirl case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ 466c79c73f6SBlue Swirl switch (excp_model) { 467c79c73f6SBlue Swirl case POWERPC_EXCP_602: 468c79c73f6SBlue Swirl case POWERPC_EXCP_603: 469c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 470c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 471c79c73f6SBlue Swirl goto tlb_miss_tgpr; 472c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 473c79c73f6SBlue Swirl goto tlb_miss; 474c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 475c79c73f6SBlue Swirl goto tlb_miss_74xx; 476c79c73f6SBlue Swirl default: 477a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data load TLB miss exception\n"); 478c79c73f6SBlue Swirl break; 479c79c73f6SBlue Swirl } 480c79c73f6SBlue Swirl break; 481c79c73f6SBlue Swirl case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ 482c79c73f6SBlue Swirl switch (excp_model) { 483c79c73f6SBlue Swirl case POWERPC_EXCP_602: 484c79c73f6SBlue Swirl case POWERPC_EXCP_603: 485c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 486c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 487c79c73f6SBlue Swirl tlb_miss_tgpr: 488c79c73f6SBlue Swirl /* Swap temporary saved registers with GPRs */ 489c79c73f6SBlue Swirl if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { 490c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_TGPR; 491c79c73f6SBlue Swirl hreg_swap_gpr_tgpr(env); 492c79c73f6SBlue Swirl } 493c79c73f6SBlue Swirl goto tlb_miss; 494c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 495c79c73f6SBlue Swirl tlb_miss: 496c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 497c79c73f6SBlue Swirl if (qemu_log_enabled()) { 498c79c73f6SBlue Swirl const char *es; 499c79c73f6SBlue Swirl target_ulong *miss, *cmp; 500c79c73f6SBlue Swirl int en; 501c79c73f6SBlue Swirl 502c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 503c79c73f6SBlue Swirl es = "I"; 504c79c73f6SBlue Swirl en = 'I'; 505c79c73f6SBlue Swirl miss = &env->spr[SPR_IMISS]; 506c79c73f6SBlue Swirl cmp = &env->spr[SPR_ICMP]; 507c79c73f6SBlue Swirl } else { 508c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 509c79c73f6SBlue Swirl es = "DL"; 510c79c73f6SBlue Swirl } else { 511c79c73f6SBlue Swirl es = "DS"; 512c79c73f6SBlue Swirl } 513c79c73f6SBlue Swirl en = 'D'; 514c79c73f6SBlue Swirl miss = &env->spr[SPR_DMISS]; 515c79c73f6SBlue Swirl cmp = &env->spr[SPR_DCMP]; 516c79c73f6SBlue Swirl } 517c79c73f6SBlue Swirl qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 518c79c73f6SBlue Swirl TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " 519c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 520c79c73f6SBlue Swirl env->spr[SPR_HASH1], env->spr[SPR_HASH2], 521c79c73f6SBlue Swirl env->error_code); 522c79c73f6SBlue Swirl } 523c79c73f6SBlue Swirl #endif 524c79c73f6SBlue Swirl msr |= env->crf[0] << 28; 525c79c73f6SBlue Swirl msr |= env->error_code; /* key, D/I, S/L bits */ 526c79c73f6SBlue Swirl /* Set way using a LRU mechanism */ 527c79c73f6SBlue Swirl msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; 528c79c73f6SBlue Swirl break; 529c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 530c79c73f6SBlue Swirl tlb_miss_74xx: 531c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 532c79c73f6SBlue Swirl if (qemu_log_enabled()) { 533c79c73f6SBlue Swirl const char *es; 534c79c73f6SBlue Swirl target_ulong *miss, *cmp; 535c79c73f6SBlue Swirl int en; 536c79c73f6SBlue Swirl 537c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 538c79c73f6SBlue Swirl es = "I"; 539c79c73f6SBlue Swirl en = 'I'; 540c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 541c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 542c79c73f6SBlue Swirl } else { 543c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 544c79c73f6SBlue Swirl es = "DL"; 545c79c73f6SBlue Swirl } else { 546c79c73f6SBlue Swirl es = "DS"; 547c79c73f6SBlue Swirl } 548c79c73f6SBlue Swirl en = 'D'; 549c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 550c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 551c79c73f6SBlue Swirl } 552c79c73f6SBlue Swirl qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 553c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 554c79c73f6SBlue Swirl env->error_code); 555c79c73f6SBlue Swirl } 556c79c73f6SBlue Swirl #endif 557c79c73f6SBlue Swirl msr |= env->error_code; /* key bit */ 558c79c73f6SBlue Swirl break; 559c79c73f6SBlue Swirl default: 560a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data store TLB miss exception\n"); 561c79c73f6SBlue Swirl break; 562c79c73f6SBlue Swirl } 563bd6fefe7SBenjamin Herrenschmidt break; 564c79c73f6SBlue Swirl case POWERPC_EXCP_FPA: /* Floating-point assist exception */ 565c79c73f6SBlue Swirl /* XXX: TODO */ 566a47dddd7SAndreas Färber cpu_abort(cs, "Floating point assist exception " 567c79c73f6SBlue Swirl "is not implemented yet !\n"); 568bd6fefe7SBenjamin Herrenschmidt break; 569c79c73f6SBlue Swirl case POWERPC_EXCP_DABR: /* Data address breakpoint */ 570c79c73f6SBlue Swirl /* XXX: TODO */ 571a47dddd7SAndreas Färber cpu_abort(cs, "DABR exception is not implemented yet !\n"); 572bd6fefe7SBenjamin Herrenschmidt break; 573c79c73f6SBlue Swirl case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ 574c79c73f6SBlue Swirl /* XXX: TODO */ 575a47dddd7SAndreas Färber cpu_abort(cs, "IABR exception is not implemented yet !\n"); 576bd6fefe7SBenjamin Herrenschmidt break; 577c79c73f6SBlue Swirl case POWERPC_EXCP_SMI: /* System management interrupt */ 578c79c73f6SBlue Swirl /* XXX: TODO */ 579a47dddd7SAndreas Färber cpu_abort(cs, "SMI exception is not implemented yet !\n"); 580bd6fefe7SBenjamin Herrenschmidt break; 581c79c73f6SBlue Swirl case POWERPC_EXCP_THERM: /* Thermal interrupt */ 582c79c73f6SBlue Swirl /* XXX: TODO */ 583a47dddd7SAndreas Färber cpu_abort(cs, "Thermal management exception " 584c79c73f6SBlue Swirl "is not implemented yet !\n"); 585bd6fefe7SBenjamin Herrenschmidt break; 586c79c73f6SBlue Swirl case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ 587c79c73f6SBlue Swirl /* XXX: TODO */ 588a47dddd7SAndreas Färber cpu_abort(cs, 589c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 590bd6fefe7SBenjamin Herrenschmidt break; 591c79c73f6SBlue Swirl case POWERPC_EXCP_VPUA: /* Vector assist exception */ 592c79c73f6SBlue Swirl /* XXX: TODO */ 593a47dddd7SAndreas Färber cpu_abort(cs, "VPU assist exception is not implemented yet !\n"); 594bd6fefe7SBenjamin Herrenschmidt break; 595c79c73f6SBlue Swirl case POWERPC_EXCP_SOFTP: /* Soft patch exception */ 596c79c73f6SBlue Swirl /* XXX: TODO */ 597a47dddd7SAndreas Färber cpu_abort(cs, 598c79c73f6SBlue Swirl "970 soft-patch exception is not implemented yet !\n"); 599bd6fefe7SBenjamin Herrenschmidt break; 600c79c73f6SBlue Swirl case POWERPC_EXCP_MAINT: /* Maintenance exception */ 601c79c73f6SBlue Swirl /* XXX: TODO */ 602a47dddd7SAndreas Färber cpu_abort(cs, 603c79c73f6SBlue Swirl "970 maintenance exception is not implemented yet !\n"); 604bd6fefe7SBenjamin Herrenschmidt break; 605c79c73f6SBlue Swirl case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ 606c79c73f6SBlue Swirl /* XXX: TODO */ 607a47dddd7SAndreas Färber cpu_abort(cs, "Maskable external exception " 608c79c73f6SBlue Swirl "is not implemented yet !\n"); 609bd6fefe7SBenjamin Herrenschmidt break; 610c79c73f6SBlue Swirl case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ 611c79c73f6SBlue Swirl /* XXX: TODO */ 612a47dddd7SAndreas Färber cpu_abort(cs, "Non maskable external exception " 613c79c73f6SBlue Swirl "is not implemented yet !\n"); 614bd6fefe7SBenjamin Herrenschmidt break; 615c79c73f6SBlue Swirl default: 616c79c73f6SBlue Swirl excp_invalid: 617a47dddd7SAndreas Färber cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 618c79c73f6SBlue Swirl break; 619c79c73f6SBlue Swirl } 620bd6fefe7SBenjamin Herrenschmidt 621bd6fefe7SBenjamin Herrenschmidt /* Save PC */ 622bd6fefe7SBenjamin Herrenschmidt env->spr[srr0] = env->nip; 623bd6fefe7SBenjamin Herrenschmidt 624c79c73f6SBlue Swirl /* Save MSR */ 625c79c73f6SBlue Swirl env->spr[srr1] = msr; 6266d49d6d4SBenjamin Herrenschmidt 6276d49d6d4SBenjamin Herrenschmidt /* Sanity check */ 62810c21b5cSNicholas Piggin if (!(env->msr_mask & MSR_HVB)) { 62910c21b5cSNicholas Piggin if (new_msr & MSR_HVB) { 63010c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with " 6316d49d6d4SBenjamin Herrenschmidt "no HV support\n", excp); 6326d49d6d4SBenjamin Herrenschmidt } 63310c21b5cSNicholas Piggin if (srr0 == SPR_HSRR0) { 63410c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with " 63510c21b5cSNicholas Piggin "no HV support\n", excp); 63610c21b5cSNicholas Piggin } 63710c21b5cSNicholas Piggin } 6386d49d6d4SBenjamin Herrenschmidt 639c79c73f6SBlue Swirl /* If any alternate SRR register are defined, duplicate saved values */ 640c79c73f6SBlue Swirl if (asrr0 != -1) { 641c79c73f6SBlue Swirl env->spr[asrr0] = env->spr[srr0]; 642c79c73f6SBlue Swirl } 643c79c73f6SBlue Swirl if (asrr1 != -1) { 644c79c73f6SBlue Swirl env->spr[asrr1] = env->spr[srr1]; 645c79c73f6SBlue Swirl } 646d5ac4f54SAlexey Kardashevskiy 6476d49d6d4SBenjamin Herrenschmidt /* Sort out endianness of interrupt, this differs depending on the 6486d49d6d4SBenjamin Herrenschmidt * CPU, the HV mode, etc... 6496d49d6d4SBenjamin Herrenschmidt */ 6501e0c7e55SAnton Blanchard #ifdef TARGET_PPC64 6516d49d6d4SBenjamin Herrenschmidt if (excp_model == POWERPC_EXCP_POWER7) { 6526d49d6d4SBenjamin Herrenschmidt if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) { 6536d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 6546d49d6d4SBenjamin Herrenschmidt } 6556d49d6d4SBenjamin Herrenschmidt } else if (excp_model == POWERPC_EXCP_POWER8) { 6566d49d6d4SBenjamin Herrenschmidt if (new_msr & MSR_HVB) { 657*0bfc0cf0SCédric Le Goater if (env->spr[SPR_HID0] & (HID0_HILE | HID0_POWER9_HILE)) { 6586d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 6596d49d6d4SBenjamin Herrenschmidt } 6606d49d6d4SBenjamin Herrenschmidt } else if (env->spr[SPR_LPCR] & LPCR_ILE) { 6611e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 6621e0c7e55SAnton Blanchard } 6631e0c7e55SAnton Blanchard } else if (msr_ile) { 6641e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 6651e0c7e55SAnton Blanchard } 6661e0c7e55SAnton Blanchard #else 667c79c73f6SBlue Swirl if (msr_ile) { 668c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_LE; 669c79c73f6SBlue Swirl } 6701e0c7e55SAnton Blanchard #endif 671c79c73f6SBlue Swirl 672c79c73f6SBlue Swirl /* Jump to handler */ 673c79c73f6SBlue Swirl vector = env->excp_vectors[excp]; 674c79c73f6SBlue Swirl if (vector == (target_ulong)-1ULL) { 675a47dddd7SAndreas Färber cpu_abort(cs, "Raised an exception without defined vector %d\n", 676c79c73f6SBlue Swirl excp); 677c79c73f6SBlue Swirl } 678c79c73f6SBlue Swirl vector |= env->excp_prefix; 6795c94b2a5SCédric Le Goater 6805c94b2a5SCédric Le Goater /* AIL only works if there is no HV transition and we are running with 6815c94b2a5SCédric Le Goater * translations enabled 6825c94b2a5SCédric Le Goater */ 6836d49d6d4SBenjamin Herrenschmidt if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) || 6846d49d6d4SBenjamin Herrenschmidt ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) { 6855c94b2a5SCédric Le Goater ail = 0; 6865c94b2a5SCédric Le Goater } 6875c94b2a5SCédric Le Goater /* Handle AIL */ 6885c94b2a5SCédric Le Goater if (ail) { 6895c94b2a5SCédric Le Goater new_msr |= (1 << MSR_IR) | (1 << MSR_DR); 6905c94b2a5SCédric Le Goater switch(ail) { 6915c94b2a5SCédric Le Goater case AIL_0001_8000: 6925c94b2a5SCédric Le Goater vector |= 0x18000; 6935c94b2a5SCédric Le Goater break; 6945c94b2a5SCédric Le Goater case AIL_C000_0000_0000_4000: 6955c94b2a5SCédric Le Goater vector |= 0xc000000000004000ull; 6965c94b2a5SCédric Le Goater break; 6975c94b2a5SCédric Le Goater default: 6985c94b2a5SCédric Le Goater cpu_abort(cs, "Invalid AIL combination %d\n", ail); 6995c94b2a5SCédric Le Goater break; 7005c94b2a5SCédric Le Goater } 7015c94b2a5SCédric Le Goater } 7025c94b2a5SCédric Le Goater 703c79c73f6SBlue Swirl #if defined(TARGET_PPC64) 704c79c73f6SBlue Swirl if (excp_model == POWERPC_EXCP_BOOKE) { 705e42a61f1SAlexander Graf if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) { 706e42a61f1SAlexander Graf /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */ 707c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_CM; 708e42a61f1SAlexander Graf } else { 709e42a61f1SAlexander Graf vector = (uint32_t)vector; 710c79c73f6SBlue Swirl } 711c79c73f6SBlue Swirl } else { 712c79c73f6SBlue Swirl if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) { 713c79c73f6SBlue Swirl vector = (uint32_t)vector; 714c79c73f6SBlue Swirl } else { 715c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_SF; 716c79c73f6SBlue Swirl } 717c79c73f6SBlue Swirl } 718c79c73f6SBlue Swirl #endif 7191c953ba5SBenjamin Herrenschmidt /* We don't use hreg_store_msr here as already have treated 720c79c73f6SBlue Swirl * any special case that could occur. Just store MSR and update hflags 7211c953ba5SBenjamin Herrenschmidt * 7221c953ba5SBenjamin Herrenschmidt * Note: We *MUST* not use hreg_store_msr() as-is anyway because it 7231c953ba5SBenjamin Herrenschmidt * will prevent setting of the HV bit which some exceptions might need 7241c953ba5SBenjamin Herrenschmidt * to do. 725c79c73f6SBlue Swirl */ 726c79c73f6SBlue Swirl env->msr = new_msr & env->msr_mask; 727c79c73f6SBlue Swirl hreg_compute_hflags(env); 728c79c73f6SBlue Swirl env->nip = vector; 729c79c73f6SBlue Swirl /* Reset exception state */ 73027103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 731c79c73f6SBlue Swirl env->error_code = 0; 732cd0c6f47SBenjamin Herrenschmidt 733139d9023SNikunj A Dadhania /* Reset the reservation */ 734139d9023SNikunj A Dadhania env->reserve_addr = -1; 735139d9023SNikunj A Dadhania 736cd0c6f47SBenjamin Herrenschmidt /* Any interrupt is context synchronizing, check if TCG TLB 737cd0c6f47SBenjamin Herrenschmidt * needs a delayed flush on ppc64 738cd0c6f47SBenjamin Herrenschmidt */ 739e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 740c79c73f6SBlue Swirl } 741c79c73f6SBlue Swirl 74297a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs) 743c79c73f6SBlue Swirl { 74497a8ea5aSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 74597a8ea5aSAndreas Färber CPUPPCState *env = &cpu->env; 7465c26a5b3SAndreas Färber 74727103424SAndreas Färber powerpc_excp(cpu, env->excp_model, cs->exception_index); 748c79c73f6SBlue Swirl } 749c79c73f6SBlue Swirl 750458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env) 751c79c73f6SBlue Swirl { 7525c26a5b3SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 753c79c73f6SBlue Swirl #if 0 754259186a7SAndreas Färber CPUState *cs = CPU(cpu); 755259186a7SAndreas Färber 756c79c73f6SBlue Swirl qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n", 757c79c73f6SBlue Swirl __func__, env, env->pending_interrupts, 758259186a7SAndreas Färber cs->interrupt_request, (int)msr_me, (int)msr_ee); 759c79c73f6SBlue Swirl #endif 760c79c73f6SBlue Swirl /* External reset */ 761c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { 762c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); 7635c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 764c79c73f6SBlue Swirl return; 765c79c73f6SBlue Swirl } 766c79c73f6SBlue Swirl /* Machine check exception */ 767c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { 768c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); 7695c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK); 770c79c73f6SBlue Swirl return; 771c79c73f6SBlue Swirl } 772c79c73f6SBlue Swirl #if 0 /* TODO */ 773c79c73f6SBlue Swirl /* External debug exception */ 774c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { 775c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); 7765c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG); 777c79c73f6SBlue Swirl return; 778c79c73f6SBlue Swirl } 779c79c73f6SBlue Swirl #endif 780c79c73f6SBlue Swirl /* Hypervisor decrementer exception */ 781c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { 7824b236b62SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 7834b236b62SBenjamin Herrenschmidt bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); 7844b236b62SBenjamin Herrenschmidt if ((msr_ee != 0 || msr_hv == 0) && hdice) { 7854b236b62SBenjamin Herrenschmidt /* HDEC clears on delivery */ 7864b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 7875c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR); 788c79c73f6SBlue Swirl return; 789c79c73f6SBlue Swirl } 790c79c73f6SBlue Swirl } 791d1dbe37cSBenjamin Herrenschmidt /* Extermal interrupt can ignore MSR:EE under some circumstances */ 792d1dbe37cSBenjamin Herrenschmidt if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { 793d1dbe37cSBenjamin Herrenschmidt bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 794d1dbe37cSBenjamin Herrenschmidt if (msr_ee != 0 || (env->has_hv_mode && msr_hv == 0 && !lpes0)) { 795d1dbe37cSBenjamin Herrenschmidt powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL); 796d1dbe37cSBenjamin Herrenschmidt return; 797d1dbe37cSBenjamin Herrenschmidt } 798d1dbe37cSBenjamin Herrenschmidt } 799c79c73f6SBlue Swirl if (msr_ce != 0) { 800c79c73f6SBlue Swirl /* External critical interrupt */ 801c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { 802c79c73f6SBlue Swirl /* Taking a critical external interrupt does not clear the external 803c79c73f6SBlue Swirl * critical interrupt status 804c79c73f6SBlue Swirl */ 805c79c73f6SBlue Swirl #if 0 806c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT); 807c79c73f6SBlue Swirl #endif 8085c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL); 809c79c73f6SBlue Swirl return; 810c79c73f6SBlue Swirl } 811c79c73f6SBlue Swirl } 812c79c73f6SBlue Swirl if (msr_ee != 0) { 813c79c73f6SBlue Swirl /* Watchdog timer on embedded PowerPC */ 814c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { 815c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); 8165c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT); 817c79c73f6SBlue Swirl return; 818c79c73f6SBlue Swirl } 819c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { 820c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); 8215c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI); 822c79c73f6SBlue Swirl return; 823c79c73f6SBlue Swirl } 824c79c73f6SBlue Swirl /* Fixed interval timer on embedded PowerPC */ 825c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { 826c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); 8275c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT); 828c79c73f6SBlue Swirl return; 829c79c73f6SBlue Swirl } 830c79c73f6SBlue Swirl /* Programmable interval timer on embedded PowerPC */ 831c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { 832c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); 8335c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT); 834c79c73f6SBlue Swirl return; 835c79c73f6SBlue Swirl } 836c79c73f6SBlue Swirl /* Decrementer exception */ 837c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { 838e81a982aSAlexander Graf if (ppc_decr_clear_on_delivery(env)) { 839c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); 840e81a982aSAlexander Graf } 8415c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR); 842c79c73f6SBlue Swirl return; 843c79c73f6SBlue Swirl } 844c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { 845c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); 8465c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI); 847c79c73f6SBlue Swirl return; 848c79c73f6SBlue Swirl } 849c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { 850c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); 8515c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM); 852c79c73f6SBlue Swirl return; 853c79c73f6SBlue Swirl } 854c79c73f6SBlue Swirl /* Thermal interrupt */ 855c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { 856c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); 8575c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM); 858c79c73f6SBlue Swirl return; 859c79c73f6SBlue Swirl } 860c79c73f6SBlue Swirl } 861c79c73f6SBlue Swirl } 86234316482SAlexey Kardashevskiy 86334316482SAlexey Kardashevskiy void ppc_cpu_do_system_reset(CPUState *cs) 86434316482SAlexey Kardashevskiy { 86534316482SAlexey Kardashevskiy PowerPCCPU *cpu = POWERPC_CPU(cs); 86634316482SAlexey Kardashevskiy CPUPPCState *env = &cpu->env; 86734316482SAlexey Kardashevskiy 86834316482SAlexey Kardashevskiy powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 86934316482SAlexey Kardashevskiy } 870c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */ 871c79c73f6SBlue Swirl 872458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 873458dd766SRichard Henderson { 874458dd766SRichard Henderson PowerPCCPU *cpu = POWERPC_CPU(cs); 875458dd766SRichard Henderson CPUPPCState *env = &cpu->env; 876458dd766SRichard Henderson 877458dd766SRichard Henderson if (interrupt_request & CPU_INTERRUPT_HARD) { 878458dd766SRichard Henderson ppc_hw_interrupt(env); 879458dd766SRichard Henderson if (env->pending_interrupts == 0) { 880458dd766SRichard Henderson cs->interrupt_request &= ~CPU_INTERRUPT_HARD; 881458dd766SRichard Henderson } 882458dd766SRichard Henderson return true; 883458dd766SRichard Henderson } 884458dd766SRichard Henderson return false; 885458dd766SRichard Henderson } 886458dd766SRichard Henderson 887c79c73f6SBlue Swirl #if defined(DEBUG_OP) 888c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr) 889c79c73f6SBlue Swirl { 890c79c73f6SBlue Swirl qemu_log("Return from exception at " TARGET_FMT_lx " with flags " 891c79c73f6SBlue Swirl TARGET_FMT_lx "\n", RA, msr); 892c79c73f6SBlue Swirl } 893c79c73f6SBlue Swirl #endif 894c79c73f6SBlue Swirl 895ad71ed68SBlue Swirl /*****************************************************************************/ 896ad71ed68SBlue Swirl /* Exceptions processing helpers */ 897ad71ed68SBlue Swirl 898db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, 899db789c6cSBenjamin Herrenschmidt uint32_t error_code, uintptr_t raddr) 900ad71ed68SBlue Swirl { 90127103424SAndreas Färber CPUState *cs = CPU(ppc_env_get_cpu(env)); 90227103424SAndreas Färber 90327103424SAndreas Färber cs->exception_index = exception; 904ad71ed68SBlue Swirl env->error_code = error_code; 905db789c6cSBenjamin Herrenschmidt cpu_loop_exit_restore(cs, raddr); 906db789c6cSBenjamin Herrenschmidt } 907db789c6cSBenjamin Herrenschmidt 908db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception, 909db789c6cSBenjamin Herrenschmidt uint32_t error_code) 910db789c6cSBenjamin Herrenschmidt { 911db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 912db789c6cSBenjamin Herrenschmidt } 913db789c6cSBenjamin Herrenschmidt 914db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception) 915db789c6cSBenjamin Herrenschmidt { 916db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 917db789c6cSBenjamin Herrenschmidt } 918db789c6cSBenjamin Herrenschmidt 919db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception, 920db789c6cSBenjamin Herrenschmidt uintptr_t raddr) 921db789c6cSBenjamin Herrenschmidt { 922db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, raddr); 923db789c6cSBenjamin Herrenschmidt } 924db789c6cSBenjamin Herrenschmidt 925db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, 926db789c6cSBenjamin Herrenschmidt uint32_t error_code) 927db789c6cSBenjamin Herrenschmidt { 928db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 929ad71ed68SBlue Swirl } 930ad71ed68SBlue Swirl 931e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception) 932ad71ed68SBlue Swirl { 933db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 934ad71ed68SBlue Swirl } 935ad71ed68SBlue Swirl 936ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 937e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val) 938ad71ed68SBlue Swirl { 939db789c6cSBenjamin Herrenschmidt uint32_t excp = hreg_store_msr(env, val, 0); 940259186a7SAndreas Färber 941db789c6cSBenjamin Herrenschmidt if (excp != 0) { 942db789c6cSBenjamin Herrenschmidt CPUState *cs = CPU(ppc_env_get_cpu(env)); 943044897efSRichard Purdie cpu_interrupt_exittb(cs); 944db789c6cSBenjamin Herrenschmidt raise_exception(env, excp); 945ad71ed68SBlue Swirl } 946ad71ed68SBlue Swirl } 947ad71ed68SBlue Swirl 9487778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64) 9497778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) 9507778a575SBenjamin Herrenschmidt { 9517778a575SBenjamin Herrenschmidt CPUState *cs; 9527778a575SBenjamin Herrenschmidt 9537778a575SBenjamin Herrenschmidt cs = CPU(ppc_env_get_cpu(env)); 9547778a575SBenjamin Herrenschmidt cs->halted = 1; 9557778a575SBenjamin Herrenschmidt env->in_pm_state = true; 9567778a575SBenjamin Herrenschmidt 9574b236b62SBenjamin Herrenschmidt /* The architecture specifies that HDEC interrupts are 9584b236b62SBenjamin Herrenschmidt * discarded in PM states 9594b236b62SBenjamin Herrenschmidt */ 9604b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 9614b236b62SBenjamin Herrenschmidt 9627778a575SBenjamin Herrenschmidt /* Technically, nap doesn't set EE, but if we don't set it 9637778a575SBenjamin Herrenschmidt * then ppc_hw_interrupt() won't deliver. We could add some 9647778a575SBenjamin Herrenschmidt * other tests there based on LPCR but it's simpler to just 9657778a575SBenjamin Herrenschmidt * whack EE in. It will be cleared by the 0x100 at wakeup 9667778a575SBenjamin Herrenschmidt * anyway. It will still be observable by the guest in SRR1 9677778a575SBenjamin Herrenschmidt * but this doesn't seem to be a problem. 9687778a575SBenjamin Herrenschmidt */ 9697778a575SBenjamin Herrenschmidt env->msr |= (1ull << MSR_EE); 970db789c6cSBenjamin Herrenschmidt raise_exception(env, EXCP_HLT); 9717778a575SBenjamin Herrenschmidt } 9727778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 9737778a575SBenjamin Herrenschmidt 974a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) 975ad71ed68SBlue Swirl { 976259186a7SAndreas Färber CPUState *cs = CPU(ppc_env_get_cpu(env)); 977259186a7SAndreas Färber 978a2e71b28SBenjamin Herrenschmidt /* MSR:POW cannot be set by any form of rfi */ 979a2e71b28SBenjamin Herrenschmidt msr &= ~(1ULL << MSR_POW); 980a2e71b28SBenjamin Herrenschmidt 981ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 982a2e71b28SBenjamin Herrenschmidt /* Switching to 32-bit ? Crop the nip */ 983a2e71b28SBenjamin Herrenschmidt if (!msr_is_64bit(env, msr)) { 984ad71ed68SBlue Swirl nip = (uint32_t)nip; 985ad71ed68SBlue Swirl } 986ad71ed68SBlue Swirl #else 987ad71ed68SBlue Swirl nip = (uint32_t)nip; 988ad71ed68SBlue Swirl #endif 989ad71ed68SBlue Swirl /* XXX: beware: this is false if VLE is supported */ 990ad71ed68SBlue Swirl env->nip = nip & ~((target_ulong)0x00000003); 991ad71ed68SBlue Swirl hreg_store_msr(env, msr, 1); 992ad71ed68SBlue Swirl #if defined(DEBUG_OP) 993ad71ed68SBlue Swirl cpu_dump_rfi(env->nip, env->msr); 994ad71ed68SBlue Swirl #endif 995ad71ed68SBlue Swirl /* No need to raise an exception here, 996ad71ed68SBlue Swirl * as rfi is always the last insn of a TB 997ad71ed68SBlue Swirl */ 998044897efSRichard Purdie cpu_interrupt_exittb(cs); 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 1136f1c29ebcSThomas 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 } 1146f1c29ebcSThomas Huth qemu_mutex_unlock_iothread(); 1147ad71ed68SBlue Swirl } 1148ad71ed68SBlue Swirl #endif 1149