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