1ad71ed68SBlue Swirl /* 2ad71ed68SBlue Swirl * PowerPC exception emulation helpers for QEMU. 3ad71ed68SBlue Swirl * 4ad71ed68SBlue Swirl * Copyright (c) 2003-2007 Jocelyn Mayer 5ad71ed68SBlue Swirl * 6ad71ed68SBlue Swirl * This library is free software; you can redistribute it and/or 7ad71ed68SBlue Swirl * modify it under the terms of the GNU Lesser General Public 8ad71ed68SBlue Swirl * License as published by the Free Software Foundation; either 9ad71ed68SBlue Swirl * version 2 of the License, or (at your option) any later version. 10ad71ed68SBlue Swirl * 11ad71ed68SBlue Swirl * This library is distributed in the hope that it will be useful, 12ad71ed68SBlue Swirl * but WITHOUT ANY WARRANTY; without even the implied warranty of 13ad71ed68SBlue Swirl * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14ad71ed68SBlue Swirl * Lesser General Public License for more details. 15ad71ed68SBlue Swirl * 16ad71ed68SBlue Swirl * You should have received a copy of the GNU Lesser General Public 17ad71ed68SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18ad71ed68SBlue Swirl */ 190d75590dSPeter Maydell #include "qemu/osdep.h" 20f1c29ebcSThomas Huth #include "qemu/main-loop.h" 21ad71ed68SBlue Swirl #include "cpu.h" 222ef6175aSRichard Henderson #include "exec/helper-proto.h" 2363c91552SPaolo Bonzini #include "exec/exec-all.h" 24f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h" 250f3110faSRichard Henderson #include "internal.h" 26ad71ed68SBlue Swirl #include "helper_regs.h" 27ad71ed68SBlue Swirl 28ad71ed68SBlue Swirl //#define DEBUG_OP 2948880da6SPaolo Bonzini //#define DEBUG_SOFTWARE_TLB 30ad71ed68SBlue Swirl //#define DEBUG_EXCEPTIONS 31ad71ed68SBlue Swirl 32c79c73f6SBlue Swirl #ifdef DEBUG_EXCEPTIONS 33c79c73f6SBlue Swirl # define LOG_EXCP(...) qemu_log(__VA_ARGS__) 34c79c73f6SBlue Swirl #else 35c79c73f6SBlue Swirl # define LOG_EXCP(...) do { } while (0) 36c79c73f6SBlue Swirl #endif 37c79c73f6SBlue Swirl 38c79c73f6SBlue Swirl /*****************************************************************************/ 39c79c73f6SBlue Swirl /* Exception processing */ 40c79c73f6SBlue Swirl #if defined(CONFIG_USER_ONLY) 4197a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs) 42c79c73f6SBlue Swirl { 4397a8ea5aSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 4497a8ea5aSAndreas Färber CPUPPCState *env = &cpu->env; 4597a8ea5aSAndreas Färber 4627103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 47c79c73f6SBlue Swirl env->error_code = 0; 48c79c73f6SBlue Swirl } 49c79c73f6SBlue Swirl 50458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env) 51c79c73f6SBlue Swirl { 5227103424SAndreas Färber CPUState *cs = CPU(ppc_env_get_cpu(env)); 5327103424SAndreas Färber 5427103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 55c79c73f6SBlue Swirl env->error_code = 0; 56c79c73f6SBlue Swirl } 57c79c73f6SBlue Swirl #else /* defined(CONFIG_USER_ONLY) */ 58c79c73f6SBlue Swirl static inline void dump_syscall(CPUPPCState *env) 59c79c73f6SBlue Swirl { 60c79c73f6SBlue Swirl qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64 61c79c73f6SBlue Swirl " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 62c79c73f6SBlue Swirl " nip=" TARGET_FMT_lx "\n", 63c79c73f6SBlue Swirl ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), 64c79c73f6SBlue Swirl ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), 65c79c73f6SBlue Swirl ppc_dump_gpr(env, 6), env->nip); 66c79c73f6SBlue Swirl } 67c79c73f6SBlue Swirl 68dead760bSBenjamin Herrenschmidt static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, 69dead760bSBenjamin Herrenschmidt target_ulong *msr) 70dead760bSBenjamin Herrenschmidt { 71dead760bSBenjamin Herrenschmidt /* We no longer are in a PM state */ 72*1e7fd61dSBenjamin Herrenschmidt env->resume_as_sreset = false; 73dead760bSBenjamin Herrenschmidt 74dead760bSBenjamin Herrenschmidt /* Pretend to be returning from doze always as we don't lose state */ 75dead760bSBenjamin Herrenschmidt *msr |= (0x1ull << (63 - 47)); 76dead760bSBenjamin Herrenschmidt 77dead760bSBenjamin Herrenschmidt /* Machine checks are sent normally */ 78dead760bSBenjamin Herrenschmidt if (excp == POWERPC_EXCP_MCHECK) { 79dead760bSBenjamin Herrenschmidt return excp; 80dead760bSBenjamin Herrenschmidt } 81dead760bSBenjamin Herrenschmidt switch (excp) { 82dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_RESET: 83dead760bSBenjamin Herrenschmidt *msr |= 0x4ull << (63 - 45); 84dead760bSBenjamin Herrenschmidt break; 85dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_EXTERNAL: 86dead760bSBenjamin Herrenschmidt *msr |= 0x8ull << (63 - 45); 87dead760bSBenjamin Herrenschmidt break; 88dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_DECR: 89dead760bSBenjamin Herrenschmidt *msr |= 0x6ull << (63 - 45); 90dead760bSBenjamin Herrenschmidt break; 91dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_SDOOR: 92dead760bSBenjamin Herrenschmidt *msr |= 0x5ull << (63 - 45); 93dead760bSBenjamin Herrenschmidt break; 94dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_SDOOR_HV: 95dead760bSBenjamin Herrenschmidt *msr |= 0x3ull << (63 - 45); 96dead760bSBenjamin Herrenschmidt break; 97dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_HV_MAINT: 98dead760bSBenjamin Herrenschmidt *msr |= 0xaull << (63 - 45); 99dead760bSBenjamin Herrenschmidt break; 100dead760bSBenjamin Herrenschmidt default: 101dead760bSBenjamin Herrenschmidt cpu_abort(cs, "Unsupported exception %d in Power Save mode\n", 102dead760bSBenjamin Herrenschmidt excp); 103dead760bSBenjamin Herrenschmidt } 104dead760bSBenjamin Herrenschmidt return POWERPC_EXCP_RESET; 105dead760bSBenjamin Herrenschmidt } 106dead760bSBenjamin Herrenschmidt 107dead760bSBenjamin Herrenschmidt 108c79c73f6SBlue Swirl /* Note that this function should be greatly optimized 109c79c73f6SBlue Swirl * when called with a constant excp, from ppc_hw_interrupt 110c79c73f6SBlue Swirl */ 1115c26a5b3SAndreas Färber static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) 112c79c73f6SBlue Swirl { 11327103424SAndreas Färber CPUState *cs = CPU(cpu); 1145c26a5b3SAndreas Färber CPUPPCState *env = &cpu->env; 115c79c73f6SBlue Swirl target_ulong msr, new_msr, vector; 1166d49d6d4SBenjamin Herrenschmidt int srr0, srr1, asrr0, asrr1, lev, ail; 1176d49d6d4SBenjamin Herrenschmidt bool lpes0; 118c79c73f6SBlue Swirl 119c79c73f6SBlue Swirl qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx 120c79c73f6SBlue Swirl " => %08x (%02x)\n", env->nip, excp, env->error_code); 121c79c73f6SBlue Swirl 122c79c73f6SBlue Swirl /* new srr1 value excluding must-be-zero bits */ 123a1bb7384SScott Wood if (excp_model == POWERPC_EXCP_BOOKE) { 124a1bb7384SScott Wood msr = env->msr; 125a1bb7384SScott Wood } else { 126c79c73f6SBlue Swirl msr = env->msr & ~0x783f0000ULL; 127a1bb7384SScott Wood } 128c79c73f6SBlue Swirl 1296d49d6d4SBenjamin Herrenschmidt /* new interrupt handler msr preserves existing HV and ME unless 1306d49d6d4SBenjamin Herrenschmidt * explicitly overriden 1316d49d6d4SBenjamin Herrenschmidt */ 1326d49d6d4SBenjamin Herrenschmidt new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB); 133c79c73f6SBlue Swirl 134c79c73f6SBlue Swirl /* target registers */ 135c79c73f6SBlue Swirl srr0 = SPR_SRR0; 136c79c73f6SBlue Swirl srr1 = SPR_SRR1; 137c79c73f6SBlue Swirl asrr0 = -1; 138c79c73f6SBlue Swirl asrr1 = -1; 139c79c73f6SBlue Swirl 14021c0d66aSBenjamin Herrenschmidt /* 14121c0d66aSBenjamin Herrenschmidt * check for special resume at 0x100 from doze/nap/sleep/winkle on 14221c0d66aSBenjamin Herrenschmidt * P7/P8/P9 14321c0d66aSBenjamin Herrenschmidt */ 144*1e7fd61dSBenjamin Herrenschmidt if (env->resume_as_sreset) { 145dead760bSBenjamin Herrenschmidt excp = powerpc_reset_wakeup(cs, env, excp, &msr); 1467778a575SBenjamin Herrenschmidt } 1477778a575SBenjamin Herrenschmidt 1485c94b2a5SCédric Le Goater /* Exception targetting modifiers 1495c94b2a5SCédric Le Goater * 1506d49d6d4SBenjamin Herrenschmidt * LPES0 is supported on POWER7/8 1516d49d6d4SBenjamin Herrenschmidt * LPES1 is not supported (old iSeries mode) 1526d49d6d4SBenjamin Herrenschmidt * 1536d49d6d4SBenjamin Herrenschmidt * On anything else, we behave as if LPES0 is 1 1546d49d6d4SBenjamin Herrenschmidt * (externals don't alter MSR:HV) 1556d49d6d4SBenjamin Herrenschmidt * 1565c94b2a5SCédric Le Goater * AIL is initialized here but can be cleared by 1575c94b2a5SCédric Le Goater * selected exceptions 1585c94b2a5SCédric Le Goater */ 1595c94b2a5SCédric Le Goater #if defined(TARGET_PPC64) 1605c94b2a5SCédric Le Goater if (excp_model == POWERPC_EXCP_POWER7 || 1615c94b2a5SCédric Le Goater excp_model == POWERPC_EXCP_POWER8) { 1626d49d6d4SBenjamin Herrenschmidt lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 1635c94b2a5SCédric Le Goater if (excp_model == POWERPC_EXCP_POWER8) { 1645c94b2a5SCédric Le Goater ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT; 1655c94b2a5SCédric Le Goater } else { 1665c94b2a5SCédric Le Goater ail = 0; 1675c94b2a5SCédric Le Goater } 1685c94b2a5SCédric Le Goater } else 1695c94b2a5SCédric Le Goater #endif /* defined(TARGET_PPC64) */ 1705c94b2a5SCédric Le Goater { 1716d49d6d4SBenjamin Herrenschmidt lpes0 = true; 1725c94b2a5SCédric Le Goater ail = 0; 1735c94b2a5SCédric Le Goater } 1745c94b2a5SCédric Le Goater 1759b2faddaSBenjamin Herrenschmidt /* Hypervisor emulation assistance interrupt only exists on server 1769b2faddaSBenjamin Herrenschmidt * arch 2.05 server or later. We also don't want to generate it if 1779b2faddaSBenjamin Herrenschmidt * we don't have HVB in msr_mask (PAPR mode). 1789b2faddaSBenjamin Herrenschmidt */ 1799b2faddaSBenjamin Herrenschmidt if (excp == POWERPC_EXCP_HV_EMU 1809b2faddaSBenjamin Herrenschmidt #if defined(TARGET_PPC64) 1819b2faddaSBenjamin Herrenschmidt && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB)) 1829b2faddaSBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 1839b2faddaSBenjamin Herrenschmidt 1849b2faddaSBenjamin Herrenschmidt ) { 1859b2faddaSBenjamin Herrenschmidt excp = POWERPC_EXCP_PROGRAM; 1869b2faddaSBenjamin Herrenschmidt } 1879b2faddaSBenjamin Herrenschmidt 188c79c73f6SBlue Swirl switch (excp) { 189c79c73f6SBlue Swirl case POWERPC_EXCP_NONE: 190c79c73f6SBlue Swirl /* Should never happen */ 191c79c73f6SBlue Swirl return; 192c79c73f6SBlue Swirl case POWERPC_EXCP_CRITICAL: /* Critical input */ 193c79c73f6SBlue Swirl switch (excp_model) { 194c79c73f6SBlue Swirl case POWERPC_EXCP_40x: 195c79c73f6SBlue Swirl srr0 = SPR_40x_SRR2; 196c79c73f6SBlue Swirl srr1 = SPR_40x_SRR3; 197c79c73f6SBlue Swirl break; 198c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 199c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 200c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 201c79c73f6SBlue Swirl break; 202c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 203c79c73f6SBlue Swirl break; 204c79c73f6SBlue Swirl default: 205c79c73f6SBlue Swirl goto excp_invalid; 206c79c73f6SBlue Swirl } 207bd6fefe7SBenjamin Herrenschmidt break; 208c79c73f6SBlue Swirl case POWERPC_EXCP_MCHECK: /* Machine check exception */ 209c79c73f6SBlue Swirl if (msr_me == 0) { 210c79c73f6SBlue Swirl /* Machine check exception is not enabled. 211c79c73f6SBlue Swirl * Enter checkstop state. 212c79c73f6SBlue Swirl */ 213c79c73f6SBlue Swirl fprintf(stderr, "Machine check while not allowed. " 214c79c73f6SBlue Swirl "Entering checkstop state\n"); 215013a2942SPaolo Bonzini if (qemu_log_separate()) { 216013a2942SPaolo Bonzini qemu_log("Machine check while not allowed. " 217013a2942SPaolo Bonzini "Entering checkstop state\n"); 218c79c73f6SBlue Swirl } 219259186a7SAndreas Färber cs->halted = 1; 220044897efSRichard Purdie cpu_interrupt_exittb(cs); 221c79c73f6SBlue Swirl } 22210c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 22310c21b5cSNicholas Piggin /* ISA specifies HV, but can be delivered to guest with HV clear 22410c21b5cSNicholas Piggin * (e.g., see FWNMI in PAPR). 22510c21b5cSNicholas Piggin */ 226c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 22710c21b5cSNicholas Piggin } 2285c94b2a5SCédric Le Goater ail = 0; 229c79c73f6SBlue Swirl 230c79c73f6SBlue Swirl /* machine check exceptions don't have ME set */ 231c79c73f6SBlue Swirl new_msr &= ~((target_ulong)1 << MSR_ME); 232c79c73f6SBlue Swirl 233c79c73f6SBlue Swirl /* XXX: should also have something loaded in DAR / DSISR */ 234c79c73f6SBlue Swirl switch (excp_model) { 235c79c73f6SBlue Swirl case POWERPC_EXCP_40x: 236c79c73f6SBlue Swirl srr0 = SPR_40x_SRR2; 237c79c73f6SBlue Swirl srr1 = SPR_40x_SRR3; 238c79c73f6SBlue Swirl break; 239c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 240a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 241c79c73f6SBlue Swirl srr0 = SPR_BOOKE_MCSRR0; 242c79c73f6SBlue Swirl srr1 = SPR_BOOKE_MCSRR1; 243c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 244c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 245c79c73f6SBlue Swirl break; 246c79c73f6SBlue Swirl default: 247c79c73f6SBlue Swirl break; 248c79c73f6SBlue Swirl } 249bd6fefe7SBenjamin Herrenschmidt break; 250c79c73f6SBlue Swirl case POWERPC_EXCP_DSI: /* Data storage exception */ 251c79c73f6SBlue Swirl LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx 252c79c73f6SBlue Swirl "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); 253bd6fefe7SBenjamin Herrenschmidt break; 254c79c73f6SBlue Swirl case POWERPC_EXCP_ISI: /* Instruction storage exception */ 255c79c73f6SBlue Swirl LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx 256c79c73f6SBlue Swirl "\n", msr, env->nip); 257c79c73f6SBlue Swirl msr |= env->error_code; 258bd6fefe7SBenjamin Herrenschmidt break; 259c79c73f6SBlue Swirl case POWERPC_EXCP_EXTERNAL: /* External input */ 260fdfba1a2SEdgar E. Iglesias cs = CPU(cpu); 261fdfba1a2SEdgar E. Iglesias 2626d49d6d4SBenjamin Herrenschmidt if (!lpes0) { 263c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 2646d49d6d4SBenjamin Herrenschmidt new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 2656d49d6d4SBenjamin Herrenschmidt srr0 = SPR_HSRR0; 2666d49d6d4SBenjamin Herrenschmidt srr1 = SPR_HSRR1; 267c79c73f6SBlue Swirl } 26868c2dd70SAlexander Graf if (env->mpic_proxy) { 26968c2dd70SAlexander Graf /* IACK the IRQ on delivery */ 270fdfba1a2SEdgar E. Iglesias env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack); 27168c2dd70SAlexander Graf } 272bd6fefe7SBenjamin Herrenschmidt break; 273c79c73f6SBlue Swirl case POWERPC_EXCP_ALIGN: /* Alignment exception */ 274c79c73f6SBlue Swirl /* Get rS/rD and rA from faulting opcode */ 2753433b732SBenjamin Herrenschmidt /* Note: the opcode fields will not be set properly for a direct 2763433b732SBenjamin Herrenschmidt * store load/store, but nobody cares as nobody actually uses 2773433b732SBenjamin Herrenschmidt * direct store segments. 2783433b732SBenjamin Herrenschmidt */ 2793433b732SBenjamin Herrenschmidt env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; 280bd6fefe7SBenjamin Herrenschmidt break; 281c79c73f6SBlue Swirl case POWERPC_EXCP_PROGRAM: /* Program exception */ 282c79c73f6SBlue Swirl switch (env->error_code & ~0xF) { 283c79c73f6SBlue Swirl case POWERPC_EXCP_FP: 284c79c73f6SBlue Swirl if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { 285c79c73f6SBlue Swirl LOG_EXCP("Ignore floating point exception\n"); 28627103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 287c79c73f6SBlue Swirl env->error_code = 0; 288c79c73f6SBlue Swirl return; 289c79c73f6SBlue Swirl } 2901b7d17caSBenjamin Herrenschmidt 2911b7d17caSBenjamin Herrenschmidt /* FP exceptions always have NIP pointing to the faulting 2921b7d17caSBenjamin Herrenschmidt * instruction, so always use store_next and claim we are 2931b7d17caSBenjamin Herrenschmidt * precise in the MSR. 2941b7d17caSBenjamin Herrenschmidt */ 295c79c73f6SBlue Swirl msr |= 0x00100000; 2960ee604abSAaron Larson env->spr[SPR_BOOKE_ESR] = ESR_FP; 297bd6fefe7SBenjamin Herrenschmidt break; 298c79c73f6SBlue Swirl case POWERPC_EXCP_INVAL: 299c79c73f6SBlue Swirl LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); 300c79c73f6SBlue Swirl msr |= 0x00080000; 301c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PIL; 302c79c73f6SBlue Swirl break; 303c79c73f6SBlue Swirl case POWERPC_EXCP_PRIV: 304c79c73f6SBlue Swirl msr |= 0x00040000; 305c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PPR; 306c79c73f6SBlue Swirl break; 307c79c73f6SBlue Swirl case POWERPC_EXCP_TRAP: 308c79c73f6SBlue Swirl msr |= 0x00020000; 309c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PTR; 310c79c73f6SBlue Swirl break; 311c79c73f6SBlue Swirl default: 312c79c73f6SBlue Swirl /* Should never occur */ 313a47dddd7SAndreas Färber cpu_abort(cs, "Invalid program exception %d. Aborting\n", 314c79c73f6SBlue Swirl env->error_code); 315c79c73f6SBlue Swirl break; 316c79c73f6SBlue Swirl } 317bd6fefe7SBenjamin Herrenschmidt break; 318c79c73f6SBlue Swirl case POWERPC_EXCP_SYSCALL: /* System call exception */ 319c79c73f6SBlue Swirl dump_syscall(env); 320c79c73f6SBlue Swirl lev = env->error_code; 3216d49d6d4SBenjamin Herrenschmidt 322bd6fefe7SBenjamin Herrenschmidt /* We need to correct the NIP which in this case is supposed 323bd6fefe7SBenjamin Herrenschmidt * to point to the next instruction 324bd6fefe7SBenjamin Herrenschmidt */ 325bd6fefe7SBenjamin Herrenschmidt env->nip += 4; 326bd6fefe7SBenjamin Herrenschmidt 3276d49d6d4SBenjamin Herrenschmidt /* "PAPR mode" built-in hypercall emulation */ 3281d1be34dSDavid Gibson if ((lev == 1) && cpu->vhyp) { 3291d1be34dSDavid Gibson PPCVirtualHypervisorClass *vhc = 3301d1be34dSDavid Gibson PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); 3311d1be34dSDavid Gibson vhc->hypercall(cpu->vhyp, cpu); 332c79c73f6SBlue Swirl return; 333c79c73f6SBlue Swirl } 3346d49d6d4SBenjamin Herrenschmidt if (lev == 1) { 335c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 336c79c73f6SBlue Swirl } 337bd6fefe7SBenjamin Herrenschmidt break; 338bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 339c79c73f6SBlue Swirl case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ 340c79c73f6SBlue Swirl case POWERPC_EXCP_DECR: /* Decrementer exception */ 341bd6fefe7SBenjamin Herrenschmidt break; 342c79c73f6SBlue Swirl case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ 343c79c73f6SBlue Swirl /* FIT on 4xx */ 344c79c73f6SBlue Swirl LOG_EXCP("FIT exception\n"); 345bd6fefe7SBenjamin Herrenschmidt break; 346c79c73f6SBlue Swirl case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ 347c79c73f6SBlue Swirl LOG_EXCP("WDT exception\n"); 348c79c73f6SBlue Swirl switch (excp_model) { 349c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 350c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 351c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 352c79c73f6SBlue Swirl break; 353c79c73f6SBlue Swirl default: 354c79c73f6SBlue Swirl break; 355c79c73f6SBlue Swirl } 356bd6fefe7SBenjamin Herrenschmidt break; 357c79c73f6SBlue Swirl case POWERPC_EXCP_DTLB: /* Data TLB error */ 358c79c73f6SBlue Swirl case POWERPC_EXCP_ITLB: /* Instruction TLB error */ 359bd6fefe7SBenjamin Herrenschmidt break; 360c79c73f6SBlue Swirl case POWERPC_EXCP_DEBUG: /* Debug interrupt */ 3610e3bf489SRoman Kapl if (env->flags & POWERPC_FLAG_DE) { 362a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 363c79c73f6SBlue Swirl srr0 = SPR_BOOKE_DSRR0; 364c79c73f6SBlue Swirl srr1 = SPR_BOOKE_DSRR1; 365c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 366c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 3670e3bf489SRoman Kapl /* DBSR already modified by caller */ 3680e3bf489SRoman Kapl } else { 3690e3bf489SRoman Kapl cpu_abort(cs, "Debug exception triggered on unsupported model\n"); 370c79c73f6SBlue Swirl } 371bd6fefe7SBenjamin Herrenschmidt break; 372c79c73f6SBlue Swirl case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ 373c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 374bd6fefe7SBenjamin Herrenschmidt break; 375c79c73f6SBlue Swirl case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ 376c79c73f6SBlue Swirl /* XXX: TODO */ 377a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point data exception " 378c79c73f6SBlue Swirl "is not implemented yet !\n"); 379c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 380bd6fefe7SBenjamin Herrenschmidt break; 381c79c73f6SBlue Swirl case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ 382c79c73f6SBlue Swirl /* XXX: TODO */ 383a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point round exception " 384c79c73f6SBlue Swirl "is not implemented yet !\n"); 385c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 386bd6fefe7SBenjamin Herrenschmidt break; 387c79c73f6SBlue Swirl case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ 388c79c73f6SBlue Swirl /* XXX: TODO */ 389a47dddd7SAndreas Färber cpu_abort(cs, 390c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 391bd6fefe7SBenjamin Herrenschmidt break; 392c79c73f6SBlue Swirl case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ 393bd6fefe7SBenjamin Herrenschmidt break; 394c79c73f6SBlue Swirl case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ 395c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 396c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 397bd6fefe7SBenjamin Herrenschmidt break; 398c79c73f6SBlue Swirl case POWERPC_EXCP_RESET: /* System reset exception */ 399f85bcec3SNicholas Piggin /* A power-saving exception sets ME, otherwise it is unchanged */ 400c79c73f6SBlue Swirl if (msr_pow) { 401c79c73f6SBlue Swirl /* indicate that we resumed from power save mode */ 402c79c73f6SBlue Swirl msr |= 0x10000; 403f85bcec3SNicholas Piggin new_msr |= ((target_ulong)1 << MSR_ME); 404c79c73f6SBlue Swirl } 40510c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 40610c21b5cSNicholas Piggin /* ISA specifies HV, but can be delivered to guest with HV clear 40710c21b5cSNicholas Piggin * (e.g., see FWNMI in PAPR, NMI injection in QEMU). 40810c21b5cSNicholas Piggin */ 409c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 41010c21b5cSNicholas Piggin } else { 41110c21b5cSNicholas Piggin if (msr_pow) { 41210c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver power-saving system reset " 41310c21b5cSNicholas Piggin "exception %d with no HV support\n", excp); 41410c21b5cSNicholas Piggin } 41510c21b5cSNicholas Piggin } 4165c94b2a5SCédric Le Goater ail = 0; 417bd6fefe7SBenjamin Herrenschmidt break; 418c79c73f6SBlue Swirl case POWERPC_EXCP_DSEG: /* Data segment exception */ 419c79c73f6SBlue Swirl case POWERPC_EXCP_ISEG: /* Instruction segment exception */ 420c79c73f6SBlue Swirl case POWERPC_EXCP_TRACE: /* Trace exception */ 421bd6fefe7SBenjamin Herrenschmidt break; 422bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ 423c79c73f6SBlue Swirl case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ 424c79c73f6SBlue Swirl case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ 425c79c73f6SBlue Swirl case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ 426c79c73f6SBlue Swirl case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ 4277af1e7b0SCédric Le Goater case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ 428bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HV_EMU: 429c79c73f6SBlue Swirl srr0 = SPR_HSRR0; 430c79c73f6SBlue Swirl srr1 = SPR_HSRR1; 431c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 432c79c73f6SBlue Swirl new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 433bd6fefe7SBenjamin Herrenschmidt break; 434c79c73f6SBlue Swirl case POWERPC_EXCP_VPU: /* Vector unavailable exception */ 4351f29871cSTom Musta case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ 4367019cb3dSAlexey Kardashevskiy case POWERPC_EXCP_FU: /* Facility unavailable exception */ 4375310799aSBalbir Singh #ifdef TARGET_PPC64 4385310799aSBalbir Singh env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56); 4395310799aSBalbir Singh #endif 440bd6fefe7SBenjamin Herrenschmidt break; 441c79c73f6SBlue Swirl case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ 442c79c73f6SBlue Swirl LOG_EXCP("PIT exception\n"); 443bd6fefe7SBenjamin Herrenschmidt break; 444c79c73f6SBlue Swirl case POWERPC_EXCP_IO: /* IO error exception */ 445c79c73f6SBlue Swirl /* XXX: TODO */ 446a47dddd7SAndreas Färber cpu_abort(cs, "601 IO error exception is not implemented yet !\n"); 447bd6fefe7SBenjamin Herrenschmidt break; 448c79c73f6SBlue Swirl case POWERPC_EXCP_RUNM: /* Run mode exception */ 449c79c73f6SBlue Swirl /* XXX: TODO */ 450a47dddd7SAndreas Färber cpu_abort(cs, "601 run mode exception is not implemented yet !\n"); 451bd6fefe7SBenjamin Herrenschmidt break; 452c79c73f6SBlue Swirl case POWERPC_EXCP_EMUL: /* Emulation trap exception */ 453c79c73f6SBlue Swirl /* XXX: TODO */ 454a47dddd7SAndreas Färber cpu_abort(cs, "602 emulation trap exception " 455c79c73f6SBlue Swirl "is not implemented yet !\n"); 456bd6fefe7SBenjamin Herrenschmidt break; 457c79c73f6SBlue Swirl case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ 458c79c73f6SBlue Swirl switch (excp_model) { 459c79c73f6SBlue Swirl case POWERPC_EXCP_602: 460c79c73f6SBlue Swirl case POWERPC_EXCP_603: 461c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 462c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 463c79c73f6SBlue Swirl goto tlb_miss_tgpr; 464c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 465c79c73f6SBlue Swirl goto tlb_miss; 466c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 467c79c73f6SBlue Swirl goto tlb_miss_74xx; 468c79c73f6SBlue Swirl default: 469a47dddd7SAndreas Färber cpu_abort(cs, "Invalid instruction TLB miss exception\n"); 470c79c73f6SBlue Swirl break; 471c79c73f6SBlue Swirl } 472c79c73f6SBlue Swirl break; 473c79c73f6SBlue Swirl case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ 474c79c73f6SBlue Swirl switch (excp_model) { 475c79c73f6SBlue Swirl case POWERPC_EXCP_602: 476c79c73f6SBlue Swirl case POWERPC_EXCP_603: 477c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 478c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 479c79c73f6SBlue Swirl goto tlb_miss_tgpr; 480c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 481c79c73f6SBlue Swirl goto tlb_miss; 482c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 483c79c73f6SBlue Swirl goto tlb_miss_74xx; 484c79c73f6SBlue Swirl default: 485a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data load TLB miss exception\n"); 486c79c73f6SBlue Swirl break; 487c79c73f6SBlue Swirl } 488c79c73f6SBlue Swirl break; 489c79c73f6SBlue Swirl case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ 490c79c73f6SBlue Swirl switch (excp_model) { 491c79c73f6SBlue Swirl case POWERPC_EXCP_602: 492c79c73f6SBlue Swirl case POWERPC_EXCP_603: 493c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 494c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 495c79c73f6SBlue Swirl tlb_miss_tgpr: 496c79c73f6SBlue Swirl /* Swap temporary saved registers with GPRs */ 497c79c73f6SBlue Swirl if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { 498c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_TGPR; 499c79c73f6SBlue Swirl hreg_swap_gpr_tgpr(env); 500c79c73f6SBlue Swirl } 501c79c73f6SBlue Swirl goto tlb_miss; 502c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 503c79c73f6SBlue Swirl tlb_miss: 504c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 505c79c73f6SBlue Swirl if (qemu_log_enabled()) { 506c79c73f6SBlue Swirl const char *es; 507c79c73f6SBlue Swirl target_ulong *miss, *cmp; 508c79c73f6SBlue Swirl int en; 509c79c73f6SBlue Swirl 510c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 511c79c73f6SBlue Swirl es = "I"; 512c79c73f6SBlue Swirl en = 'I'; 513c79c73f6SBlue Swirl miss = &env->spr[SPR_IMISS]; 514c79c73f6SBlue Swirl cmp = &env->spr[SPR_ICMP]; 515c79c73f6SBlue Swirl } else { 516c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 517c79c73f6SBlue Swirl es = "DL"; 518c79c73f6SBlue Swirl } else { 519c79c73f6SBlue Swirl es = "DS"; 520c79c73f6SBlue Swirl } 521c79c73f6SBlue Swirl en = 'D'; 522c79c73f6SBlue Swirl miss = &env->spr[SPR_DMISS]; 523c79c73f6SBlue Swirl cmp = &env->spr[SPR_DCMP]; 524c79c73f6SBlue Swirl } 525c79c73f6SBlue Swirl qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 526c79c73f6SBlue Swirl TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " 527c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 528c79c73f6SBlue Swirl env->spr[SPR_HASH1], env->spr[SPR_HASH2], 529c79c73f6SBlue Swirl env->error_code); 530c79c73f6SBlue Swirl } 531c79c73f6SBlue Swirl #endif 532c79c73f6SBlue Swirl msr |= env->crf[0] << 28; 533c79c73f6SBlue Swirl msr |= env->error_code; /* key, D/I, S/L bits */ 534c79c73f6SBlue Swirl /* Set way using a LRU mechanism */ 535c79c73f6SBlue Swirl msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; 536c79c73f6SBlue Swirl break; 537c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 538c79c73f6SBlue Swirl tlb_miss_74xx: 539c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 540c79c73f6SBlue Swirl if (qemu_log_enabled()) { 541c79c73f6SBlue Swirl const char *es; 542c79c73f6SBlue Swirl target_ulong *miss, *cmp; 543c79c73f6SBlue Swirl int en; 544c79c73f6SBlue Swirl 545c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 546c79c73f6SBlue Swirl es = "I"; 547c79c73f6SBlue Swirl en = 'I'; 548c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 549c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 550c79c73f6SBlue Swirl } else { 551c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 552c79c73f6SBlue Swirl es = "DL"; 553c79c73f6SBlue Swirl } else { 554c79c73f6SBlue Swirl es = "DS"; 555c79c73f6SBlue Swirl } 556c79c73f6SBlue Swirl en = 'D'; 557c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 558c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 559c79c73f6SBlue Swirl } 560c79c73f6SBlue Swirl qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 561c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 562c79c73f6SBlue Swirl env->error_code); 563c79c73f6SBlue Swirl } 564c79c73f6SBlue Swirl #endif 565c79c73f6SBlue Swirl msr |= env->error_code; /* key bit */ 566c79c73f6SBlue Swirl break; 567c79c73f6SBlue Swirl default: 568a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data store TLB miss exception\n"); 569c79c73f6SBlue Swirl break; 570c79c73f6SBlue Swirl } 571bd6fefe7SBenjamin Herrenschmidt break; 572c79c73f6SBlue Swirl case POWERPC_EXCP_FPA: /* Floating-point assist exception */ 573c79c73f6SBlue Swirl /* XXX: TODO */ 574a47dddd7SAndreas Färber cpu_abort(cs, "Floating point assist exception " 575c79c73f6SBlue Swirl "is not implemented yet !\n"); 576bd6fefe7SBenjamin Herrenschmidt break; 577c79c73f6SBlue Swirl case POWERPC_EXCP_DABR: /* Data address breakpoint */ 578c79c73f6SBlue Swirl /* XXX: TODO */ 579a47dddd7SAndreas Färber cpu_abort(cs, "DABR exception is not implemented yet !\n"); 580bd6fefe7SBenjamin Herrenschmidt break; 581c79c73f6SBlue Swirl case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ 582c79c73f6SBlue Swirl /* XXX: TODO */ 583a47dddd7SAndreas Färber cpu_abort(cs, "IABR exception is not implemented yet !\n"); 584bd6fefe7SBenjamin Herrenschmidt break; 585c79c73f6SBlue Swirl case POWERPC_EXCP_SMI: /* System management interrupt */ 586c79c73f6SBlue Swirl /* XXX: TODO */ 587a47dddd7SAndreas Färber cpu_abort(cs, "SMI exception is not implemented yet !\n"); 588bd6fefe7SBenjamin Herrenschmidt break; 589c79c73f6SBlue Swirl case POWERPC_EXCP_THERM: /* Thermal interrupt */ 590c79c73f6SBlue Swirl /* XXX: TODO */ 591a47dddd7SAndreas Färber cpu_abort(cs, "Thermal management exception " 592c79c73f6SBlue Swirl "is not implemented yet !\n"); 593bd6fefe7SBenjamin Herrenschmidt break; 594c79c73f6SBlue Swirl case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ 595c79c73f6SBlue Swirl /* XXX: TODO */ 596a47dddd7SAndreas Färber cpu_abort(cs, 597c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 598bd6fefe7SBenjamin Herrenschmidt break; 599c79c73f6SBlue Swirl case POWERPC_EXCP_VPUA: /* Vector assist exception */ 600c79c73f6SBlue Swirl /* XXX: TODO */ 601a47dddd7SAndreas Färber cpu_abort(cs, "VPU assist exception is not implemented yet !\n"); 602bd6fefe7SBenjamin Herrenschmidt break; 603c79c73f6SBlue Swirl case POWERPC_EXCP_SOFTP: /* Soft patch exception */ 604c79c73f6SBlue Swirl /* XXX: TODO */ 605a47dddd7SAndreas Färber cpu_abort(cs, 606c79c73f6SBlue Swirl "970 soft-patch exception is not implemented yet !\n"); 607bd6fefe7SBenjamin Herrenschmidt break; 608c79c73f6SBlue Swirl case POWERPC_EXCP_MAINT: /* Maintenance exception */ 609c79c73f6SBlue Swirl /* XXX: TODO */ 610a47dddd7SAndreas Färber cpu_abort(cs, 611c79c73f6SBlue Swirl "970 maintenance exception is not implemented yet !\n"); 612bd6fefe7SBenjamin Herrenschmidt break; 613c79c73f6SBlue Swirl case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ 614c79c73f6SBlue Swirl /* XXX: TODO */ 615a47dddd7SAndreas Färber cpu_abort(cs, "Maskable external exception " 616c79c73f6SBlue Swirl "is not implemented yet !\n"); 617bd6fefe7SBenjamin Herrenschmidt break; 618c79c73f6SBlue Swirl case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ 619c79c73f6SBlue Swirl /* XXX: TODO */ 620a47dddd7SAndreas Färber cpu_abort(cs, "Non maskable external exception " 621c79c73f6SBlue Swirl "is not implemented yet !\n"); 622bd6fefe7SBenjamin Herrenschmidt break; 623c79c73f6SBlue Swirl default: 624c79c73f6SBlue Swirl excp_invalid: 625a47dddd7SAndreas Färber cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 626c79c73f6SBlue Swirl break; 627c79c73f6SBlue Swirl } 628bd6fefe7SBenjamin Herrenschmidt 629bd6fefe7SBenjamin Herrenschmidt /* Save PC */ 630bd6fefe7SBenjamin Herrenschmidt env->spr[srr0] = env->nip; 631bd6fefe7SBenjamin Herrenschmidt 632c79c73f6SBlue Swirl /* Save MSR */ 633c79c73f6SBlue Swirl env->spr[srr1] = msr; 6346d49d6d4SBenjamin Herrenschmidt 6356d49d6d4SBenjamin Herrenschmidt /* Sanity check */ 63610c21b5cSNicholas Piggin if (!(env->msr_mask & MSR_HVB)) { 63710c21b5cSNicholas Piggin if (new_msr & MSR_HVB) { 63810c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with " 6396d49d6d4SBenjamin Herrenschmidt "no HV support\n", excp); 6406d49d6d4SBenjamin Herrenschmidt } 64110c21b5cSNicholas Piggin if (srr0 == SPR_HSRR0) { 64210c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with " 64310c21b5cSNicholas Piggin "no HV support\n", excp); 64410c21b5cSNicholas Piggin } 64510c21b5cSNicholas Piggin } 6466d49d6d4SBenjamin Herrenschmidt 647c79c73f6SBlue Swirl /* If any alternate SRR register are defined, duplicate saved values */ 648c79c73f6SBlue Swirl if (asrr0 != -1) { 649c79c73f6SBlue Swirl env->spr[asrr0] = env->spr[srr0]; 650c79c73f6SBlue Swirl } 651c79c73f6SBlue Swirl if (asrr1 != -1) { 652c79c73f6SBlue Swirl env->spr[asrr1] = env->spr[srr1]; 653c79c73f6SBlue Swirl } 654d5ac4f54SAlexey Kardashevskiy 6556d49d6d4SBenjamin Herrenschmidt /* Sort out endianness of interrupt, this differs depending on the 6566d49d6d4SBenjamin Herrenschmidt * CPU, the HV mode, etc... 6576d49d6d4SBenjamin Herrenschmidt */ 6581e0c7e55SAnton Blanchard #ifdef TARGET_PPC64 6596d49d6d4SBenjamin Herrenschmidt if (excp_model == POWERPC_EXCP_POWER7) { 6606d49d6d4SBenjamin Herrenschmidt if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) { 6616d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 6626d49d6d4SBenjamin Herrenschmidt } 6636d49d6d4SBenjamin Herrenschmidt } else if (excp_model == POWERPC_EXCP_POWER8) { 6646d49d6d4SBenjamin Herrenschmidt if (new_msr & MSR_HVB) { 6650bfc0cf0SCédric Le Goater if (env->spr[SPR_HID0] & (HID0_HILE | HID0_POWER9_HILE)) { 6666d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 6676d49d6d4SBenjamin Herrenschmidt } 6686d49d6d4SBenjamin Herrenschmidt } else if (env->spr[SPR_LPCR] & LPCR_ILE) { 6691e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 6701e0c7e55SAnton Blanchard } 6711e0c7e55SAnton Blanchard } else if (msr_ile) { 6721e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 6731e0c7e55SAnton Blanchard } 6741e0c7e55SAnton Blanchard #else 675c79c73f6SBlue Swirl if (msr_ile) { 676c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_LE; 677c79c73f6SBlue Swirl } 6781e0c7e55SAnton Blanchard #endif 679c79c73f6SBlue Swirl 680c79c73f6SBlue Swirl /* Jump to handler */ 681c79c73f6SBlue Swirl vector = env->excp_vectors[excp]; 682c79c73f6SBlue Swirl if (vector == (target_ulong)-1ULL) { 683a47dddd7SAndreas Färber cpu_abort(cs, "Raised an exception without defined vector %d\n", 684c79c73f6SBlue Swirl excp); 685c79c73f6SBlue Swirl } 686c79c73f6SBlue Swirl vector |= env->excp_prefix; 6875c94b2a5SCédric Le Goater 6885c94b2a5SCédric Le Goater /* AIL only works if there is no HV transition and we are running with 6895c94b2a5SCédric Le Goater * translations enabled 6905c94b2a5SCédric Le Goater */ 6916d49d6d4SBenjamin Herrenschmidt if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) || 6926d49d6d4SBenjamin Herrenschmidt ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) { 6935c94b2a5SCédric Le Goater ail = 0; 6945c94b2a5SCédric Le Goater } 6955c94b2a5SCédric Le Goater /* Handle AIL */ 6965c94b2a5SCédric Le Goater if (ail) { 6975c94b2a5SCédric Le Goater new_msr |= (1 << MSR_IR) | (1 << MSR_DR); 6985c94b2a5SCédric Le Goater switch(ail) { 6995c94b2a5SCédric Le Goater case AIL_0001_8000: 7005c94b2a5SCédric Le Goater vector |= 0x18000; 7015c94b2a5SCédric Le Goater break; 7025c94b2a5SCédric Le Goater case AIL_C000_0000_0000_4000: 7035c94b2a5SCédric Le Goater vector |= 0xc000000000004000ull; 7045c94b2a5SCédric Le Goater break; 7055c94b2a5SCédric Le Goater default: 7065c94b2a5SCédric Le Goater cpu_abort(cs, "Invalid AIL combination %d\n", ail); 7075c94b2a5SCédric Le Goater break; 7085c94b2a5SCédric Le Goater } 7095c94b2a5SCédric Le Goater } 7105c94b2a5SCédric Le Goater 711c79c73f6SBlue Swirl #if defined(TARGET_PPC64) 712c79c73f6SBlue Swirl if (excp_model == POWERPC_EXCP_BOOKE) { 713e42a61f1SAlexander Graf if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) { 714e42a61f1SAlexander Graf /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */ 715c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_CM; 716e42a61f1SAlexander Graf } else { 717e42a61f1SAlexander Graf vector = (uint32_t)vector; 718c79c73f6SBlue Swirl } 719c79c73f6SBlue Swirl } else { 720c79c73f6SBlue Swirl if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) { 721c79c73f6SBlue Swirl vector = (uint32_t)vector; 722c79c73f6SBlue Swirl } else { 723c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_SF; 724c79c73f6SBlue Swirl } 725c79c73f6SBlue Swirl } 726c79c73f6SBlue Swirl #endif 7271c953ba5SBenjamin Herrenschmidt /* We don't use hreg_store_msr here as already have treated 728c79c73f6SBlue Swirl * any special case that could occur. Just store MSR and update hflags 7291c953ba5SBenjamin Herrenschmidt * 7301c953ba5SBenjamin Herrenschmidt * Note: We *MUST* not use hreg_store_msr() as-is anyway because it 7311c953ba5SBenjamin Herrenschmidt * will prevent setting of the HV bit which some exceptions might need 7321c953ba5SBenjamin Herrenschmidt * to do. 733c79c73f6SBlue Swirl */ 734c79c73f6SBlue Swirl env->msr = new_msr & env->msr_mask; 735c79c73f6SBlue Swirl hreg_compute_hflags(env); 736c79c73f6SBlue Swirl env->nip = vector; 737c79c73f6SBlue Swirl /* Reset exception state */ 73827103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 739c79c73f6SBlue Swirl env->error_code = 0; 740cd0c6f47SBenjamin Herrenschmidt 741139d9023SNikunj A Dadhania /* Reset the reservation */ 742139d9023SNikunj A Dadhania env->reserve_addr = -1; 743139d9023SNikunj A Dadhania 744cd0c6f47SBenjamin Herrenschmidt /* Any interrupt is context synchronizing, check if TCG TLB 745cd0c6f47SBenjamin Herrenschmidt * needs a delayed flush on ppc64 746cd0c6f47SBenjamin Herrenschmidt */ 747e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 748c79c73f6SBlue Swirl } 749c79c73f6SBlue Swirl 75097a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs) 751c79c73f6SBlue Swirl { 75297a8ea5aSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 75397a8ea5aSAndreas Färber CPUPPCState *env = &cpu->env; 7545c26a5b3SAndreas Färber 75527103424SAndreas Färber powerpc_excp(cpu, env->excp_model, cs->exception_index); 756c79c73f6SBlue Swirl } 757c79c73f6SBlue Swirl 758458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env) 759c79c73f6SBlue Swirl { 7605c26a5b3SAndreas Färber PowerPCCPU *cpu = ppc_env_get_cpu(env); 7613621e2c9SBenjamin Herrenschmidt bool async_deliver; 762259186a7SAndreas Färber 763c79c73f6SBlue Swirl /* External reset */ 764c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { 765c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); 7665c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 767c79c73f6SBlue Swirl return; 768c79c73f6SBlue Swirl } 769c79c73f6SBlue Swirl /* Machine check exception */ 770c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { 771c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); 7725c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK); 773c79c73f6SBlue Swirl return; 774c79c73f6SBlue Swirl } 775c79c73f6SBlue Swirl #if 0 /* TODO */ 776c79c73f6SBlue Swirl /* External debug exception */ 777c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { 778c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); 7795c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG); 780c79c73f6SBlue Swirl return; 781c79c73f6SBlue Swirl } 782c79c73f6SBlue Swirl #endif 7833621e2c9SBenjamin Herrenschmidt 7843621e2c9SBenjamin Herrenschmidt /* 7853621e2c9SBenjamin Herrenschmidt * For interrupts that gate on MSR:EE, we need to do something a 7863621e2c9SBenjamin Herrenschmidt * bit more subtle, as we need to let them through even when EE is 7873621e2c9SBenjamin Herrenschmidt * clear when coming out of some power management states (in order 7883621e2c9SBenjamin Herrenschmidt * for them to become a 0x100). 7893621e2c9SBenjamin Herrenschmidt */ 790*1e7fd61dSBenjamin Herrenschmidt async_deliver = (msr_ee != 0) || env->resume_as_sreset; 7913621e2c9SBenjamin Herrenschmidt 792c79c73f6SBlue Swirl /* Hypervisor decrementer exception */ 793c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { 7944b236b62SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 7954b236b62SBenjamin Herrenschmidt bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); 7963621e2c9SBenjamin Herrenschmidt if ((async_deliver || msr_hv == 0) && hdice) { 7974b236b62SBenjamin Herrenschmidt /* HDEC clears on delivery */ 7984b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 7995c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR); 800c79c73f6SBlue Swirl return; 801c79c73f6SBlue Swirl } 802c79c73f6SBlue Swirl } 803d1dbe37cSBenjamin Herrenschmidt /* Extermal interrupt can ignore MSR:EE under some circumstances */ 804d1dbe37cSBenjamin Herrenschmidt if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { 805d1dbe37cSBenjamin Herrenschmidt bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 8063621e2c9SBenjamin Herrenschmidt if (async_deliver || (env->has_hv_mode && msr_hv == 0 && !lpes0)) { 807d1dbe37cSBenjamin Herrenschmidt powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL); 808d1dbe37cSBenjamin Herrenschmidt return; 809d1dbe37cSBenjamin Herrenschmidt } 810d1dbe37cSBenjamin Herrenschmidt } 811c79c73f6SBlue Swirl if (msr_ce != 0) { 812c79c73f6SBlue Swirl /* External critical interrupt */ 813c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { 8145c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL); 815c79c73f6SBlue Swirl return; 816c79c73f6SBlue Swirl } 817c79c73f6SBlue Swirl } 8183621e2c9SBenjamin Herrenschmidt if (async_deliver != 0) { 819c79c73f6SBlue Swirl /* Watchdog timer on embedded PowerPC */ 820c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { 821c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); 8225c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT); 823c79c73f6SBlue Swirl return; 824c79c73f6SBlue Swirl } 825c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { 826c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); 8275c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI); 828c79c73f6SBlue Swirl return; 829c79c73f6SBlue Swirl } 830c79c73f6SBlue Swirl /* Fixed interval timer on embedded PowerPC */ 831c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { 832c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); 8335c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT); 834c79c73f6SBlue Swirl return; 835c79c73f6SBlue Swirl } 836c79c73f6SBlue Swirl /* Programmable interval timer on embedded PowerPC */ 837c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { 838c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); 8395c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT); 840c79c73f6SBlue Swirl return; 841c79c73f6SBlue Swirl } 842c79c73f6SBlue Swirl /* Decrementer exception */ 843c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { 844e81a982aSAlexander Graf if (ppc_decr_clear_on_delivery(env)) { 845c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); 846e81a982aSAlexander Graf } 8475c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR); 848c79c73f6SBlue Swirl return; 849c79c73f6SBlue Swirl } 850c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { 851c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); 8525c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI); 853c79c73f6SBlue Swirl return; 854c79c73f6SBlue Swirl } 8557af1e7b0SCédric Le Goater if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) { 8567af1e7b0SCédric Le Goater env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL); 8577af1e7b0SCédric Le Goater powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV); 8587af1e7b0SCédric Le Goater return; 8597af1e7b0SCédric Le Goater } 860c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { 861c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); 8625c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM); 863c79c73f6SBlue Swirl return; 864c79c73f6SBlue Swirl } 865c79c73f6SBlue Swirl /* Thermal interrupt */ 866c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { 867c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); 8685c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM); 869c79c73f6SBlue Swirl return; 870c79c73f6SBlue Swirl } 871c79c73f6SBlue Swirl } 872c79c73f6SBlue Swirl } 87334316482SAlexey Kardashevskiy 87434316482SAlexey Kardashevskiy void ppc_cpu_do_system_reset(CPUState *cs) 87534316482SAlexey Kardashevskiy { 87634316482SAlexey Kardashevskiy PowerPCCPU *cpu = POWERPC_CPU(cs); 87734316482SAlexey Kardashevskiy CPUPPCState *env = &cpu->env; 87834316482SAlexey Kardashevskiy 87934316482SAlexey Kardashevskiy powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 88034316482SAlexey Kardashevskiy } 881c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */ 882c79c73f6SBlue Swirl 883458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 884458dd766SRichard Henderson { 885458dd766SRichard Henderson PowerPCCPU *cpu = POWERPC_CPU(cs); 886458dd766SRichard Henderson CPUPPCState *env = &cpu->env; 887458dd766SRichard Henderson 888458dd766SRichard Henderson if (interrupt_request & CPU_INTERRUPT_HARD) { 889458dd766SRichard Henderson ppc_hw_interrupt(env); 890458dd766SRichard Henderson if (env->pending_interrupts == 0) { 891458dd766SRichard Henderson cs->interrupt_request &= ~CPU_INTERRUPT_HARD; 892458dd766SRichard Henderson } 893458dd766SRichard Henderson return true; 894458dd766SRichard Henderson } 895458dd766SRichard Henderson return false; 896458dd766SRichard Henderson } 897458dd766SRichard Henderson 898c79c73f6SBlue Swirl #if defined(DEBUG_OP) 899c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr) 900c79c73f6SBlue Swirl { 901c79c73f6SBlue Swirl qemu_log("Return from exception at " TARGET_FMT_lx " with flags " 902c79c73f6SBlue Swirl TARGET_FMT_lx "\n", RA, msr); 903c79c73f6SBlue Swirl } 904c79c73f6SBlue Swirl #endif 905c79c73f6SBlue Swirl 906ad71ed68SBlue Swirl /*****************************************************************************/ 907ad71ed68SBlue Swirl /* Exceptions processing helpers */ 908ad71ed68SBlue Swirl 909db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, 910db789c6cSBenjamin Herrenschmidt uint32_t error_code, uintptr_t raddr) 911ad71ed68SBlue Swirl { 91227103424SAndreas Färber CPUState *cs = CPU(ppc_env_get_cpu(env)); 91327103424SAndreas Färber 91427103424SAndreas Färber cs->exception_index = exception; 915ad71ed68SBlue Swirl env->error_code = error_code; 916db789c6cSBenjamin Herrenschmidt cpu_loop_exit_restore(cs, raddr); 917db789c6cSBenjamin Herrenschmidt } 918db789c6cSBenjamin Herrenschmidt 919db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception, 920db789c6cSBenjamin Herrenschmidt uint32_t error_code) 921db789c6cSBenjamin Herrenschmidt { 922db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 923db789c6cSBenjamin Herrenschmidt } 924db789c6cSBenjamin Herrenschmidt 925db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception) 926db789c6cSBenjamin Herrenschmidt { 927db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 928db789c6cSBenjamin Herrenschmidt } 929db789c6cSBenjamin Herrenschmidt 930db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception, 931db789c6cSBenjamin Herrenschmidt uintptr_t raddr) 932db789c6cSBenjamin Herrenschmidt { 933db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, raddr); 934db789c6cSBenjamin Herrenschmidt } 935db789c6cSBenjamin Herrenschmidt 936db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, 937db789c6cSBenjamin Herrenschmidt uint32_t error_code) 938db789c6cSBenjamin Herrenschmidt { 939db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 940ad71ed68SBlue Swirl } 941ad71ed68SBlue Swirl 942e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception) 943ad71ed68SBlue Swirl { 944db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 945ad71ed68SBlue Swirl } 946ad71ed68SBlue Swirl 947ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 948e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val) 949ad71ed68SBlue Swirl { 950db789c6cSBenjamin Herrenschmidt uint32_t excp = hreg_store_msr(env, val, 0); 951259186a7SAndreas Färber 952db789c6cSBenjamin Herrenschmidt if (excp != 0) { 953db789c6cSBenjamin Herrenschmidt CPUState *cs = CPU(ppc_env_get_cpu(env)); 954044897efSRichard Purdie cpu_interrupt_exittb(cs); 955db789c6cSBenjamin Herrenschmidt raise_exception(env, excp); 956ad71ed68SBlue Swirl } 957ad71ed68SBlue Swirl } 958ad71ed68SBlue Swirl 9597778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64) 9607778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) 9617778a575SBenjamin Herrenschmidt { 9627778a575SBenjamin Herrenschmidt CPUState *cs; 9637778a575SBenjamin Herrenschmidt 9647778a575SBenjamin Herrenschmidt cs = CPU(ppc_env_get_cpu(env)); 9657778a575SBenjamin Herrenschmidt cs->halted = 1; 9667778a575SBenjamin Herrenschmidt 9674b236b62SBenjamin Herrenschmidt /* The architecture specifies that HDEC interrupts are 9684b236b62SBenjamin Herrenschmidt * discarded in PM states 9694b236b62SBenjamin Herrenschmidt */ 9704b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 9714b236b62SBenjamin Herrenschmidt 9723621e2c9SBenjamin Herrenschmidt /* Condition for waking up at 0x100 */ 973*1e7fd61dSBenjamin Herrenschmidt env->resume_as_sreset = (insn != PPC_PM_STOP) || 97421c0d66aSBenjamin Herrenschmidt (env->spr[SPR_PSSCR] & PSSCR_EC); 9757778a575SBenjamin Herrenschmidt } 9767778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 9777778a575SBenjamin Herrenschmidt 978a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) 979ad71ed68SBlue Swirl { 980259186a7SAndreas Färber CPUState *cs = CPU(ppc_env_get_cpu(env)); 981259186a7SAndreas Färber 982a2e71b28SBenjamin Herrenschmidt /* MSR:POW cannot be set by any form of rfi */ 983a2e71b28SBenjamin Herrenschmidt msr &= ~(1ULL << MSR_POW); 984a2e71b28SBenjamin Herrenschmidt 985ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 986a2e71b28SBenjamin Herrenschmidt /* Switching to 32-bit ? Crop the nip */ 987a2e71b28SBenjamin Herrenschmidt if (!msr_is_64bit(env, msr)) { 988ad71ed68SBlue Swirl nip = (uint32_t)nip; 989ad71ed68SBlue Swirl } 990ad71ed68SBlue Swirl #else 991ad71ed68SBlue Swirl nip = (uint32_t)nip; 992ad71ed68SBlue Swirl #endif 993ad71ed68SBlue Swirl /* XXX: beware: this is false if VLE is supported */ 994ad71ed68SBlue Swirl env->nip = nip & ~((target_ulong)0x00000003); 995ad71ed68SBlue Swirl hreg_store_msr(env, msr, 1); 996ad71ed68SBlue Swirl #if defined(DEBUG_OP) 997ad71ed68SBlue Swirl cpu_dump_rfi(env->nip, env->msr); 998ad71ed68SBlue Swirl #endif 999ad71ed68SBlue Swirl /* No need to raise an exception here, 1000ad71ed68SBlue Swirl * as rfi is always the last insn of a TB 1001ad71ed68SBlue Swirl */ 1002044897efSRichard Purdie cpu_interrupt_exittb(cs); 1003a8b73734SNikunj A Dadhania /* Reset the reservation */ 1004a8b73734SNikunj A Dadhania env->reserve_addr = -1; 1005a8b73734SNikunj A Dadhania 1006cd0c6f47SBenjamin Herrenschmidt /* Context synchronizing: check if TCG TLB needs flush */ 1007e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 1008ad71ed68SBlue Swirl } 1009ad71ed68SBlue Swirl 1010e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env) 1011ad71ed68SBlue Swirl { 1012a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); 1013a1bb7384SScott Wood } 1014ad71ed68SBlue Swirl 1015a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK 1016ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1017e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env) 1018ad71ed68SBlue Swirl { 1019a2e71b28SBenjamin Herrenschmidt /* The architeture defines a number of rules for which bits 1020a2e71b28SBenjamin Herrenschmidt * can change but in practice, we handle this in hreg_store_msr() 1021a2e71b28SBenjamin Herrenschmidt * which will be called by do_rfi(), so there is no need to filter 1022a2e71b28SBenjamin Herrenschmidt * here 1023a2e71b28SBenjamin Herrenschmidt */ 1024a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]); 1025ad71ed68SBlue Swirl } 1026ad71ed68SBlue Swirl 1027e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env) 1028ad71ed68SBlue Swirl { 1029a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); 1030ad71ed68SBlue Swirl } 1031ad71ed68SBlue Swirl #endif 1032ad71ed68SBlue Swirl 1033ad71ed68SBlue Swirl /*****************************************************************************/ 1034ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */ 1035e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env) 1036ad71ed68SBlue Swirl { 1037a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]); 1038ad71ed68SBlue Swirl } 1039ad71ed68SBlue Swirl 1040e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env) 1041ad71ed68SBlue Swirl { 1042a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]); 1043ad71ed68SBlue Swirl } 1044ad71ed68SBlue Swirl 1045e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env) 1046ad71ed68SBlue Swirl { 1047a1bb7384SScott Wood /* FIXME: choose CSRR1 or DSRR1 based on cpu type */ 1048a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]); 1049ad71ed68SBlue Swirl } 1050ad71ed68SBlue Swirl 1051e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env) 1052ad71ed68SBlue Swirl { 1053a1bb7384SScott Wood /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ 1054a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); 1055ad71ed68SBlue Swirl } 1056ad71ed68SBlue Swirl #endif 1057ad71ed68SBlue Swirl 1058e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1059e5f17ac6SBlue Swirl uint32_t flags) 1060ad71ed68SBlue Swirl { 1061ad71ed68SBlue Swirl if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || 1062ad71ed68SBlue Swirl ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) || 1063ad71ed68SBlue Swirl ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || 1064ad71ed68SBlue Swirl ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || 1065ad71ed68SBlue Swirl ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { 106672073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 106772073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1068ad71ed68SBlue Swirl } 1069ad71ed68SBlue Swirl } 1070ad71ed68SBlue Swirl 1071ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1072e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1073e5f17ac6SBlue Swirl uint32_t flags) 1074ad71ed68SBlue Swirl { 1075ad71ed68SBlue Swirl if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || 1076ad71ed68SBlue Swirl ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) || 1077ad71ed68SBlue Swirl ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || 1078ad71ed68SBlue Swirl ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || 1079ad71ed68SBlue Swirl ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { 108072073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 108172073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1082ad71ed68SBlue Swirl } 1083ad71ed68SBlue Swirl } 1084ad71ed68SBlue Swirl #endif 1085ad71ed68SBlue Swirl 1086ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 1087ad71ed68SBlue Swirl /*****************************************************************************/ 1088ad71ed68SBlue Swirl /* PowerPC 601 specific instructions (POWER bridge) */ 1089ad71ed68SBlue Swirl 1090e5f17ac6SBlue Swirl void helper_rfsvc(CPUPPCState *env) 1091ad71ed68SBlue Swirl { 1092a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->lr, env->ctr & 0x0000FFFF); 1093ad71ed68SBlue Swirl } 1094ad71ed68SBlue Swirl 1095ad71ed68SBlue Swirl /* Embedded.Processor Control */ 1096ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb) 1097ad71ed68SBlue Swirl { 1098ad71ed68SBlue Swirl int msg = rb & DBELL_TYPE_MASK; 1099ad71ed68SBlue Swirl int irq = -1; 1100ad71ed68SBlue Swirl 1101ad71ed68SBlue Swirl switch (msg) { 1102ad71ed68SBlue Swirl case DBELL_TYPE_DBELL: 1103ad71ed68SBlue Swirl irq = PPC_INTERRUPT_DOORBELL; 1104ad71ed68SBlue Swirl break; 1105ad71ed68SBlue Swirl case DBELL_TYPE_DBELL_CRIT: 1106ad71ed68SBlue Swirl irq = PPC_INTERRUPT_CDOORBELL; 1107ad71ed68SBlue Swirl break; 1108ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL: 1109ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_CRIT: 1110ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_MC: 1111ad71ed68SBlue Swirl /* XXX implement */ 1112ad71ed68SBlue Swirl default: 1113ad71ed68SBlue Swirl break; 1114ad71ed68SBlue Swirl } 1115ad71ed68SBlue Swirl 1116ad71ed68SBlue Swirl return irq; 1117ad71ed68SBlue Swirl } 1118ad71ed68SBlue Swirl 1119e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb) 1120ad71ed68SBlue Swirl { 1121ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1122ad71ed68SBlue Swirl 1123ad71ed68SBlue Swirl if (irq < 0) { 1124ad71ed68SBlue Swirl return; 1125ad71ed68SBlue Swirl } 1126ad71ed68SBlue Swirl 1127ad71ed68SBlue Swirl env->pending_interrupts &= ~(1 << irq); 1128ad71ed68SBlue Swirl } 1129ad71ed68SBlue Swirl 1130ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb) 1131ad71ed68SBlue Swirl { 1132ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1133ad71ed68SBlue Swirl int pir = rb & DBELL_PIRTAG_MASK; 1134182735efSAndreas Färber CPUState *cs; 1135ad71ed68SBlue Swirl 1136ad71ed68SBlue Swirl if (irq < 0) { 1137ad71ed68SBlue Swirl return; 1138ad71ed68SBlue Swirl } 1139ad71ed68SBlue Swirl 1140f1c29ebcSThomas Huth qemu_mutex_lock_iothread(); 1141bdc44640SAndreas Färber CPU_FOREACH(cs) { 1142182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 1143182735efSAndreas Färber CPUPPCState *cenv = &cpu->env; 1144182735efSAndreas Färber 1145ad71ed68SBlue Swirl if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { 1146ad71ed68SBlue Swirl cenv->pending_interrupts |= 1 << irq; 1147182735efSAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 1148ad71ed68SBlue Swirl } 1149ad71ed68SBlue Swirl } 1150f1c29ebcSThomas Huth qemu_mutex_unlock_iothread(); 1151ad71ed68SBlue Swirl } 11527af1e7b0SCédric Le Goater 11537af1e7b0SCédric Le Goater /* Server Processor Control */ 11547af1e7b0SCédric Le Goater static int book3s_dbell2irq(target_ulong rb) 11557af1e7b0SCédric Le Goater { 11567af1e7b0SCédric Le Goater int msg = rb & DBELL_TYPE_MASK; 11577af1e7b0SCédric Le Goater 11587af1e7b0SCédric Le Goater /* A Directed Hypervisor Doorbell message is sent only if the 11597af1e7b0SCédric Le Goater * message type is 5. All other types are reserved and the 11607af1e7b0SCédric Le Goater * instruction is a no-op */ 11617af1e7b0SCédric Le Goater return msg == DBELL_TYPE_DBELL_SERVER ? PPC_INTERRUPT_HDOORBELL : -1; 11627af1e7b0SCédric Le Goater } 11637af1e7b0SCédric Le Goater 11647af1e7b0SCédric Le Goater void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) 11657af1e7b0SCédric Le Goater { 11667af1e7b0SCédric Le Goater int irq = book3s_dbell2irq(rb); 11677af1e7b0SCédric Le Goater 11687af1e7b0SCédric Le Goater if (irq < 0) { 11697af1e7b0SCédric Le Goater return; 11707af1e7b0SCédric Le Goater } 11717af1e7b0SCédric Le Goater 11727af1e7b0SCédric Le Goater env->pending_interrupts &= ~(1 << irq); 11737af1e7b0SCédric Le Goater } 11747af1e7b0SCédric Le Goater 11757af1e7b0SCédric Le Goater void helper_book3s_msgsnd(target_ulong rb) 11767af1e7b0SCédric Le Goater { 11777af1e7b0SCédric Le Goater int irq = book3s_dbell2irq(rb); 11787af1e7b0SCédric Le Goater int pir = rb & DBELL_PROCIDTAG_MASK; 11797af1e7b0SCédric Le Goater CPUState *cs; 11807af1e7b0SCédric Le Goater 11817af1e7b0SCédric Le Goater if (irq < 0) { 11827af1e7b0SCédric Le Goater return; 11837af1e7b0SCédric Le Goater } 11847af1e7b0SCédric Le Goater 11857af1e7b0SCédric Le Goater qemu_mutex_lock_iothread(); 11867af1e7b0SCédric Le Goater CPU_FOREACH(cs) { 11877af1e7b0SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 11887af1e7b0SCédric Le Goater CPUPPCState *cenv = &cpu->env; 11897af1e7b0SCédric Le Goater 11907af1e7b0SCédric Le Goater /* TODO: broadcast message to all threads of the same processor */ 11917af1e7b0SCédric Le Goater if (cenv->spr_cb[SPR_PIR].default_value == pir) { 11927af1e7b0SCédric Le Goater cenv->pending_interrupts |= 1 << irq; 11937af1e7b0SCédric Le Goater cpu_interrupt(cs, CPU_INTERRUPT_HARD); 11947af1e7b0SCédric Le Goater } 11957af1e7b0SCédric Le Goater } 11967af1e7b0SCédric Le Goater qemu_mutex_unlock_iothread(); 11977af1e7b0SCédric Le Goater } 1198ad71ed68SBlue Swirl #endif 11990f3110faSRichard Henderson 12000f3110faSRichard Henderson void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, 12010f3110faSRichard Henderson MMUAccessType access_type, 12020f3110faSRichard Henderson int mmu_idx, uintptr_t retaddr) 12030f3110faSRichard Henderson { 12040f3110faSRichard Henderson CPUPPCState *env = cs->env_ptr; 12050f3110faSRichard Henderson uint32_t insn; 12060f3110faSRichard Henderson 12070f3110faSRichard Henderson /* Restore state and reload the insn we executed, for filling in DSISR. */ 12080f3110faSRichard Henderson cpu_restore_state(cs, retaddr, true); 12090f3110faSRichard Henderson insn = cpu_ldl_code(env, env->nip); 12100f3110faSRichard Henderson 12110f3110faSRichard Henderson cs->exception_index = POWERPC_EXCP_ALIGN; 12120f3110faSRichard Henderson env->error_code = insn & 0x03FF0000; 12130f3110faSRichard Henderson cpu_loop_exit(cs); 12140f3110faSRichard Henderson } 1215