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 */ 316*1d1be34dSDavid Gibson if ((lev == 1) && cpu->vhyp) { 317*1d1be34dSDavid Gibson PPCVirtualHypervisorClass *vhc = 318*1d1be34dSDavid Gibson PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); 319*1d1be34dSDavid 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 731cd0c6f47SBenjamin Herrenschmidt /* Any interrupt is context synchronizing, check if TCG TLB 732cd0c6f47SBenjamin Herrenschmidt * needs a delayed flush on ppc64 733cd0c6f47SBenjamin Herrenschmidt */ 734e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 735c79c73f6SBlue Swirl } 736c79c73f6SBlue Swirl 73797a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs) 738c79c73f6SBlue Swirl { 73997a8ea5aSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 74097a8ea5aSAndreas Färber CPUPPCState *env = &cpu->env; 7415c26a5b3SAndreas Färber 74227103424SAndreas Färber powerpc_excp(cpu, env->excp_model, cs->exception_index); 743c79c73f6SBlue Swirl } 744c79c73f6SBlue Swirl 745458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env) 746c79c73f6SBlue Swirl { 7475c26a5b3SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 748c79c73f6SBlue Swirl #if 0 749259186a7SAndreas Färber CPUState *cs = CPU(cpu); 750259186a7SAndreas Färber 751c79c73f6SBlue Swirl qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n", 752c79c73f6SBlue Swirl __func__, env, env->pending_interrupts, 753259186a7SAndreas Färber cs->interrupt_request, (int)msr_me, (int)msr_ee); 754c79c73f6SBlue Swirl #endif 755c79c73f6SBlue Swirl /* External reset */ 756c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { 757c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); 7585c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 759c79c73f6SBlue Swirl return; 760c79c73f6SBlue Swirl } 761c79c73f6SBlue Swirl /* Machine check exception */ 762c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { 763c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); 7645c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK); 765c79c73f6SBlue Swirl return; 766c79c73f6SBlue Swirl } 767c79c73f6SBlue Swirl #if 0 /* TODO */ 768c79c73f6SBlue Swirl /* External debug exception */ 769c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { 770c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); 7715c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG); 772c79c73f6SBlue Swirl return; 773c79c73f6SBlue Swirl } 774c79c73f6SBlue Swirl #endif 775c79c73f6SBlue Swirl /* Hypervisor decrementer exception */ 776c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { 7774b236b62SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 7784b236b62SBenjamin Herrenschmidt bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); 7794b236b62SBenjamin Herrenschmidt if ((msr_ee != 0 || msr_hv == 0) && hdice) { 7804b236b62SBenjamin Herrenschmidt /* HDEC clears on delivery */ 7814b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 7825c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR); 783c79c73f6SBlue Swirl return; 784c79c73f6SBlue Swirl } 785c79c73f6SBlue Swirl } 786d1dbe37cSBenjamin Herrenschmidt /* Extermal interrupt can ignore MSR:EE under some circumstances */ 787d1dbe37cSBenjamin Herrenschmidt if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { 788d1dbe37cSBenjamin Herrenschmidt bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 789d1dbe37cSBenjamin Herrenschmidt if (msr_ee != 0 || (env->has_hv_mode && msr_hv == 0 && !lpes0)) { 790d1dbe37cSBenjamin Herrenschmidt powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL); 791d1dbe37cSBenjamin Herrenschmidt return; 792d1dbe37cSBenjamin Herrenschmidt } 793d1dbe37cSBenjamin Herrenschmidt } 794c79c73f6SBlue Swirl if (msr_ce != 0) { 795c79c73f6SBlue Swirl /* External critical interrupt */ 796c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { 797c79c73f6SBlue Swirl /* Taking a critical external interrupt does not clear the external 798c79c73f6SBlue Swirl * critical interrupt status 799c79c73f6SBlue Swirl */ 800c79c73f6SBlue Swirl #if 0 801c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT); 802c79c73f6SBlue Swirl #endif 8035c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL); 804c79c73f6SBlue Swirl return; 805c79c73f6SBlue Swirl } 806c79c73f6SBlue Swirl } 807c79c73f6SBlue Swirl if (msr_ee != 0) { 808c79c73f6SBlue Swirl /* Watchdog timer on embedded PowerPC */ 809c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { 810c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); 8115c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT); 812c79c73f6SBlue Swirl return; 813c79c73f6SBlue Swirl } 814c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { 815c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); 8165c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI); 817c79c73f6SBlue Swirl return; 818c79c73f6SBlue Swirl } 819c79c73f6SBlue Swirl /* Fixed interval timer on embedded PowerPC */ 820c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { 821c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); 8225c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT); 823c79c73f6SBlue Swirl return; 824c79c73f6SBlue Swirl } 825c79c73f6SBlue Swirl /* Programmable interval timer on embedded PowerPC */ 826c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { 827c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); 8285c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT); 829c79c73f6SBlue Swirl return; 830c79c73f6SBlue Swirl } 831c79c73f6SBlue Swirl /* Decrementer exception */ 832c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { 833e81a982aSAlexander Graf if (ppc_decr_clear_on_delivery(env)) { 834c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); 835e81a982aSAlexander Graf } 8365c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR); 837c79c73f6SBlue Swirl return; 838c79c73f6SBlue Swirl } 839c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { 840c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); 8415c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI); 842c79c73f6SBlue Swirl return; 843c79c73f6SBlue Swirl } 844c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { 845c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); 8465c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM); 847c79c73f6SBlue Swirl return; 848c79c73f6SBlue Swirl } 849c79c73f6SBlue Swirl /* Thermal interrupt */ 850c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { 851c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); 8525c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM); 853c79c73f6SBlue Swirl return; 854c79c73f6SBlue Swirl } 855c79c73f6SBlue Swirl } 856c79c73f6SBlue Swirl } 85734316482SAlexey Kardashevskiy 85834316482SAlexey Kardashevskiy void ppc_cpu_do_system_reset(CPUState *cs) 85934316482SAlexey Kardashevskiy { 86034316482SAlexey Kardashevskiy PowerPCCPU *cpu = POWERPC_CPU(cs); 86134316482SAlexey Kardashevskiy CPUPPCState *env = &cpu->env; 86234316482SAlexey Kardashevskiy 86334316482SAlexey Kardashevskiy powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 86434316482SAlexey Kardashevskiy } 865c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */ 866c79c73f6SBlue Swirl 867458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 868458dd766SRichard Henderson { 869458dd766SRichard Henderson PowerPCCPU *cpu = POWERPC_CPU(cs); 870458dd766SRichard Henderson CPUPPCState *env = &cpu->env; 871458dd766SRichard Henderson 872458dd766SRichard Henderson if (interrupt_request & CPU_INTERRUPT_HARD) { 873458dd766SRichard Henderson ppc_hw_interrupt(env); 874458dd766SRichard Henderson if (env->pending_interrupts == 0) { 875458dd766SRichard Henderson cs->interrupt_request &= ~CPU_INTERRUPT_HARD; 876458dd766SRichard Henderson } 877458dd766SRichard Henderson return true; 878458dd766SRichard Henderson } 879458dd766SRichard Henderson return false; 880458dd766SRichard Henderson } 881458dd766SRichard Henderson 882c79c73f6SBlue Swirl #if defined(DEBUG_OP) 883c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr) 884c79c73f6SBlue Swirl { 885c79c73f6SBlue Swirl qemu_log("Return from exception at " TARGET_FMT_lx " with flags " 886c79c73f6SBlue Swirl TARGET_FMT_lx "\n", RA, msr); 887c79c73f6SBlue Swirl } 888c79c73f6SBlue Swirl #endif 889c79c73f6SBlue Swirl 890ad71ed68SBlue Swirl /*****************************************************************************/ 891ad71ed68SBlue Swirl /* Exceptions processing helpers */ 892ad71ed68SBlue Swirl 893db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, 894db789c6cSBenjamin Herrenschmidt uint32_t error_code, uintptr_t raddr) 895ad71ed68SBlue Swirl { 89627103424SAndreas Färber CPUState *cs = CPU(ppc_env_get_cpu(env)); 89727103424SAndreas Färber 89827103424SAndreas Färber cs->exception_index = exception; 899ad71ed68SBlue Swirl env->error_code = error_code; 900db789c6cSBenjamin Herrenschmidt cpu_loop_exit_restore(cs, raddr); 901db789c6cSBenjamin Herrenschmidt } 902db789c6cSBenjamin Herrenschmidt 903db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception, 904db789c6cSBenjamin Herrenschmidt uint32_t error_code) 905db789c6cSBenjamin Herrenschmidt { 906db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 907db789c6cSBenjamin Herrenschmidt } 908db789c6cSBenjamin Herrenschmidt 909db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception) 910db789c6cSBenjamin Herrenschmidt { 911db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 912db789c6cSBenjamin Herrenschmidt } 913db789c6cSBenjamin Herrenschmidt 914db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception, 915db789c6cSBenjamin Herrenschmidt uintptr_t raddr) 916db789c6cSBenjamin Herrenschmidt { 917db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, raddr); 918db789c6cSBenjamin Herrenschmidt } 919db789c6cSBenjamin Herrenschmidt 920db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, 921db789c6cSBenjamin Herrenschmidt uint32_t error_code) 922db789c6cSBenjamin Herrenschmidt { 923db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 924ad71ed68SBlue Swirl } 925ad71ed68SBlue Swirl 926e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception) 927ad71ed68SBlue Swirl { 928db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 929ad71ed68SBlue Swirl } 930ad71ed68SBlue Swirl 931ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 932e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val) 933ad71ed68SBlue Swirl { 934db789c6cSBenjamin Herrenschmidt uint32_t excp = hreg_store_msr(env, val, 0); 935259186a7SAndreas Färber 936db789c6cSBenjamin Herrenschmidt if (excp != 0) { 937db789c6cSBenjamin Herrenschmidt CPUState *cs = CPU(ppc_env_get_cpu(env)); 938259186a7SAndreas Färber cs->interrupt_request |= CPU_INTERRUPT_EXITTB; 939db789c6cSBenjamin Herrenschmidt raise_exception(env, excp); 940ad71ed68SBlue Swirl } 941ad71ed68SBlue Swirl } 942ad71ed68SBlue Swirl 9437778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64) 9447778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) 9457778a575SBenjamin Herrenschmidt { 9467778a575SBenjamin Herrenschmidt CPUState *cs; 9477778a575SBenjamin Herrenschmidt 9487778a575SBenjamin Herrenschmidt cs = CPU(ppc_env_get_cpu(env)); 9497778a575SBenjamin Herrenschmidt cs->halted = 1; 9507778a575SBenjamin Herrenschmidt env->in_pm_state = true; 9517778a575SBenjamin Herrenschmidt 9524b236b62SBenjamin Herrenschmidt /* The architecture specifies that HDEC interrupts are 9534b236b62SBenjamin Herrenschmidt * discarded in PM states 9544b236b62SBenjamin Herrenschmidt */ 9554b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 9564b236b62SBenjamin Herrenschmidt 9577778a575SBenjamin Herrenschmidt /* Technically, nap doesn't set EE, but if we don't set it 9587778a575SBenjamin Herrenschmidt * then ppc_hw_interrupt() won't deliver. We could add some 9597778a575SBenjamin Herrenschmidt * other tests there based on LPCR but it's simpler to just 9607778a575SBenjamin Herrenschmidt * whack EE in. It will be cleared by the 0x100 at wakeup 9617778a575SBenjamin Herrenschmidt * anyway. It will still be observable by the guest in SRR1 9627778a575SBenjamin Herrenschmidt * but this doesn't seem to be a problem. 9637778a575SBenjamin Herrenschmidt */ 9647778a575SBenjamin Herrenschmidt env->msr |= (1ull << MSR_EE); 965db789c6cSBenjamin Herrenschmidt raise_exception(env, EXCP_HLT); 9667778a575SBenjamin Herrenschmidt } 9677778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 9687778a575SBenjamin Herrenschmidt 969a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) 970ad71ed68SBlue Swirl { 971259186a7SAndreas Färber CPUState *cs = CPU(ppc_env_get_cpu(env)); 972259186a7SAndreas Färber 973a2e71b28SBenjamin Herrenschmidt /* MSR:POW cannot be set by any form of rfi */ 974a2e71b28SBenjamin Herrenschmidt msr &= ~(1ULL << MSR_POW); 975a2e71b28SBenjamin Herrenschmidt 976ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 977a2e71b28SBenjamin Herrenschmidt /* Switching to 32-bit ? Crop the nip */ 978a2e71b28SBenjamin Herrenschmidt if (!msr_is_64bit(env, msr)) { 979ad71ed68SBlue Swirl nip = (uint32_t)nip; 980ad71ed68SBlue Swirl } 981ad71ed68SBlue Swirl #else 982ad71ed68SBlue Swirl nip = (uint32_t)nip; 983ad71ed68SBlue Swirl #endif 984ad71ed68SBlue Swirl /* XXX: beware: this is false if VLE is supported */ 985ad71ed68SBlue Swirl env->nip = nip & ~((target_ulong)0x00000003); 986ad71ed68SBlue Swirl hreg_store_msr(env, msr, 1); 987ad71ed68SBlue Swirl #if defined(DEBUG_OP) 988ad71ed68SBlue Swirl cpu_dump_rfi(env->nip, env->msr); 989ad71ed68SBlue Swirl #endif 990ad71ed68SBlue Swirl /* No need to raise an exception here, 991ad71ed68SBlue Swirl * as rfi is always the last insn of a TB 992ad71ed68SBlue Swirl */ 993259186a7SAndreas Färber cs->interrupt_request |= CPU_INTERRUPT_EXITTB; 994cd0c6f47SBenjamin Herrenschmidt 995cd0c6f47SBenjamin Herrenschmidt /* Context synchronizing: check if TCG TLB needs flush */ 996e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 997ad71ed68SBlue Swirl } 998ad71ed68SBlue Swirl 999e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env) 1000ad71ed68SBlue Swirl { 1001a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); 1002a1bb7384SScott Wood } 1003ad71ed68SBlue Swirl 1004a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK 1005ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1006e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env) 1007ad71ed68SBlue Swirl { 1008a2e71b28SBenjamin Herrenschmidt /* The architeture defines a number of rules for which bits 1009a2e71b28SBenjamin Herrenschmidt * can change but in practice, we handle this in hreg_store_msr() 1010a2e71b28SBenjamin Herrenschmidt * which will be called by do_rfi(), so there is no need to filter 1011a2e71b28SBenjamin Herrenschmidt * here 1012a2e71b28SBenjamin Herrenschmidt */ 1013a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]); 1014ad71ed68SBlue Swirl } 1015ad71ed68SBlue Swirl 1016e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env) 1017ad71ed68SBlue Swirl { 1018a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); 1019ad71ed68SBlue Swirl } 1020ad71ed68SBlue Swirl #endif 1021ad71ed68SBlue Swirl 1022ad71ed68SBlue Swirl /*****************************************************************************/ 1023ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */ 1024e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env) 1025ad71ed68SBlue Swirl { 1026a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]); 1027ad71ed68SBlue Swirl } 1028ad71ed68SBlue Swirl 1029e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env) 1030ad71ed68SBlue Swirl { 1031a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]); 1032ad71ed68SBlue Swirl } 1033ad71ed68SBlue Swirl 1034e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env) 1035ad71ed68SBlue Swirl { 1036a1bb7384SScott Wood /* FIXME: choose CSRR1 or DSRR1 based on cpu type */ 1037a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]); 1038ad71ed68SBlue Swirl } 1039ad71ed68SBlue Swirl 1040e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env) 1041ad71ed68SBlue Swirl { 1042a1bb7384SScott Wood /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ 1043a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); 1044ad71ed68SBlue Swirl } 1045ad71ed68SBlue Swirl #endif 1046ad71ed68SBlue Swirl 1047e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1048e5f17ac6SBlue Swirl uint32_t flags) 1049ad71ed68SBlue Swirl { 1050ad71ed68SBlue Swirl if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || 1051ad71ed68SBlue Swirl ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) || 1052ad71ed68SBlue Swirl ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || 1053ad71ed68SBlue Swirl ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || 1054ad71ed68SBlue Swirl ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { 105572073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 105672073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1057ad71ed68SBlue Swirl } 1058ad71ed68SBlue Swirl } 1059ad71ed68SBlue Swirl 1060ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1061e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1062e5f17ac6SBlue Swirl uint32_t flags) 1063ad71ed68SBlue Swirl { 1064ad71ed68SBlue Swirl if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || 1065ad71ed68SBlue Swirl ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) || 1066ad71ed68SBlue Swirl ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || 1067ad71ed68SBlue Swirl ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || 1068ad71ed68SBlue Swirl ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { 106972073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 107072073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1071ad71ed68SBlue Swirl } 1072ad71ed68SBlue Swirl } 1073ad71ed68SBlue Swirl #endif 1074ad71ed68SBlue Swirl 1075ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 1076ad71ed68SBlue Swirl /*****************************************************************************/ 1077ad71ed68SBlue Swirl /* PowerPC 601 specific instructions (POWER bridge) */ 1078ad71ed68SBlue Swirl 1079e5f17ac6SBlue Swirl void helper_rfsvc(CPUPPCState *env) 1080ad71ed68SBlue Swirl { 1081a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->lr, env->ctr & 0x0000FFFF); 1082ad71ed68SBlue Swirl } 1083ad71ed68SBlue Swirl 1084ad71ed68SBlue Swirl /* Embedded.Processor Control */ 1085ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb) 1086ad71ed68SBlue Swirl { 1087ad71ed68SBlue Swirl int msg = rb & DBELL_TYPE_MASK; 1088ad71ed68SBlue Swirl int irq = -1; 1089ad71ed68SBlue Swirl 1090ad71ed68SBlue Swirl switch (msg) { 1091ad71ed68SBlue Swirl case DBELL_TYPE_DBELL: 1092ad71ed68SBlue Swirl irq = PPC_INTERRUPT_DOORBELL; 1093ad71ed68SBlue Swirl break; 1094ad71ed68SBlue Swirl case DBELL_TYPE_DBELL_CRIT: 1095ad71ed68SBlue Swirl irq = PPC_INTERRUPT_CDOORBELL; 1096ad71ed68SBlue Swirl break; 1097ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL: 1098ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_CRIT: 1099ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_MC: 1100ad71ed68SBlue Swirl /* XXX implement */ 1101ad71ed68SBlue Swirl default: 1102ad71ed68SBlue Swirl break; 1103ad71ed68SBlue Swirl } 1104ad71ed68SBlue Swirl 1105ad71ed68SBlue Swirl return irq; 1106ad71ed68SBlue Swirl } 1107ad71ed68SBlue Swirl 1108e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb) 1109ad71ed68SBlue Swirl { 1110ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1111ad71ed68SBlue Swirl 1112ad71ed68SBlue Swirl if (irq < 0) { 1113ad71ed68SBlue Swirl return; 1114ad71ed68SBlue Swirl } 1115ad71ed68SBlue Swirl 1116ad71ed68SBlue Swirl env->pending_interrupts &= ~(1 << irq); 1117ad71ed68SBlue Swirl } 1118ad71ed68SBlue Swirl 1119ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb) 1120ad71ed68SBlue Swirl { 1121ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1122ad71ed68SBlue Swirl int pir = rb & DBELL_PIRTAG_MASK; 1123182735efSAndreas Färber CPUState *cs; 1124ad71ed68SBlue Swirl 1125ad71ed68SBlue Swirl if (irq < 0) { 1126ad71ed68SBlue Swirl return; 1127ad71ed68SBlue Swirl } 1128ad71ed68SBlue Swirl 1129bdc44640SAndreas Färber CPU_FOREACH(cs) { 1130182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 1131182735efSAndreas Färber CPUPPCState *cenv = &cpu->env; 1132182735efSAndreas Färber 1133ad71ed68SBlue Swirl if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { 1134ad71ed68SBlue Swirl cenv->pending_interrupts |= 1 << irq; 1135182735efSAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 1136ad71ed68SBlue Swirl } 1137ad71ed68SBlue Swirl } 1138ad71ed68SBlue Swirl } 1139ad71ed68SBlue Swirl #endif 1140