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 2847733729SDavid Gibson /* #define DEBUG_OP */ 2947733729SDavid Gibson /* #define DEBUG_SOFTWARE_TLB */ 3047733729SDavid Gibson /* #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 { 52*db70b311SRichard Henderson CPUState *cs = env_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 */ 721e7fd61dSBenjamin 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; 100d8ce5fd6SBenjamin Herrenschmidt case POWERPC_EXCP_HVIRT: 101d8ce5fd6SBenjamin Herrenschmidt *msr |= 0x9ull << (63 - 45); 102d8ce5fd6SBenjamin Herrenschmidt break; 103dead760bSBenjamin Herrenschmidt default: 104dead760bSBenjamin Herrenschmidt cpu_abort(cs, "Unsupported exception %d in Power Save mode\n", 105dead760bSBenjamin Herrenschmidt excp); 106dead760bSBenjamin Herrenschmidt } 107dead760bSBenjamin Herrenschmidt return POWERPC_EXCP_RESET; 108dead760bSBenjamin Herrenschmidt } 109dead760bSBenjamin Herrenschmidt 1102586a4d7SFabiano Rosas static uint64_t ppc_excp_vector_offset(CPUState *cs, int ail) 1112586a4d7SFabiano Rosas { 1122586a4d7SFabiano Rosas uint64_t offset = 0; 1132586a4d7SFabiano Rosas 1142586a4d7SFabiano Rosas switch (ail) { 1152586a4d7SFabiano Rosas case AIL_0001_8000: 1162586a4d7SFabiano Rosas offset = 0x18000; 1172586a4d7SFabiano Rosas break; 1182586a4d7SFabiano Rosas case AIL_C000_0000_0000_4000: 1192586a4d7SFabiano Rosas offset = 0xc000000000004000ull; 1202586a4d7SFabiano Rosas break; 1212586a4d7SFabiano Rosas default: 1222586a4d7SFabiano Rosas cpu_abort(cs, "Invalid AIL combination %d\n", ail); 1232586a4d7SFabiano Rosas break; 1242586a4d7SFabiano Rosas } 1252586a4d7SFabiano Rosas 1262586a4d7SFabiano Rosas return offset; 1272586a4d7SFabiano Rosas } 128dead760bSBenjamin Herrenschmidt 12947733729SDavid Gibson /* 13047733729SDavid Gibson * Note that this function should be greatly optimized when called 13147733729SDavid Gibson * with a constant excp, from ppc_hw_interrupt 132c79c73f6SBlue Swirl */ 1335c26a5b3SAndreas Färber static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) 134c79c73f6SBlue Swirl { 13527103424SAndreas Färber CPUState *cs = CPU(cpu); 1365c26a5b3SAndreas Färber CPUPPCState *env = &cpu->env; 137c79c73f6SBlue Swirl target_ulong msr, new_msr, vector; 1386d49d6d4SBenjamin Herrenschmidt int srr0, srr1, asrr0, asrr1, lev, ail; 1396d49d6d4SBenjamin Herrenschmidt bool lpes0; 140c79c73f6SBlue Swirl 141c79c73f6SBlue Swirl qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx 142c79c73f6SBlue Swirl " => %08x (%02x)\n", env->nip, excp, env->error_code); 143c79c73f6SBlue Swirl 144c79c73f6SBlue Swirl /* new srr1 value excluding must-be-zero bits */ 145a1bb7384SScott Wood if (excp_model == POWERPC_EXCP_BOOKE) { 146a1bb7384SScott Wood msr = env->msr; 147a1bb7384SScott Wood } else { 148c79c73f6SBlue Swirl msr = env->msr & ~0x783f0000ULL; 149a1bb7384SScott Wood } 150c79c73f6SBlue Swirl 15147733729SDavid Gibson /* 15247733729SDavid Gibson * new interrupt handler msr preserves existing HV and ME unless 1536d49d6d4SBenjamin Herrenschmidt * explicitly overriden 1546d49d6d4SBenjamin Herrenschmidt */ 1556d49d6d4SBenjamin Herrenschmidt new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB); 156c79c73f6SBlue Swirl 157c79c73f6SBlue Swirl /* target registers */ 158c79c73f6SBlue Swirl srr0 = SPR_SRR0; 159c79c73f6SBlue Swirl srr1 = SPR_SRR1; 160c79c73f6SBlue Swirl asrr0 = -1; 161c79c73f6SBlue Swirl asrr1 = -1; 162c79c73f6SBlue Swirl 16321c0d66aSBenjamin Herrenschmidt /* 16421c0d66aSBenjamin Herrenschmidt * check for special resume at 0x100 from doze/nap/sleep/winkle on 16521c0d66aSBenjamin Herrenschmidt * P7/P8/P9 16621c0d66aSBenjamin Herrenschmidt */ 1671e7fd61dSBenjamin Herrenschmidt if (env->resume_as_sreset) { 168dead760bSBenjamin Herrenschmidt excp = powerpc_reset_wakeup(cs, env, excp, &msr); 1697778a575SBenjamin Herrenschmidt } 1707778a575SBenjamin Herrenschmidt 17147733729SDavid Gibson /* 17247733729SDavid Gibson * Exception targetting modifiers 1735c94b2a5SCédric Le Goater * 174a790e82bSBenjamin Herrenschmidt * LPES0 is supported on POWER7/8/9 1756d49d6d4SBenjamin Herrenschmidt * LPES1 is not supported (old iSeries mode) 1766d49d6d4SBenjamin Herrenschmidt * 1776d49d6d4SBenjamin Herrenschmidt * On anything else, we behave as if LPES0 is 1 1786d49d6d4SBenjamin Herrenschmidt * (externals don't alter MSR:HV) 1796d49d6d4SBenjamin Herrenschmidt * 1805c94b2a5SCédric Le Goater * AIL is initialized here but can be cleared by 1815c94b2a5SCédric Le Goater * selected exceptions 1825c94b2a5SCédric Le Goater */ 1835c94b2a5SCédric Le Goater #if defined(TARGET_PPC64) 1845c94b2a5SCédric Le Goater if (excp_model == POWERPC_EXCP_POWER7 || 185a790e82bSBenjamin Herrenschmidt excp_model == POWERPC_EXCP_POWER8 || 186a790e82bSBenjamin Herrenschmidt excp_model == POWERPC_EXCP_POWER9) { 1876d49d6d4SBenjamin Herrenschmidt lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 188a790e82bSBenjamin Herrenschmidt if (excp_model != POWERPC_EXCP_POWER7) { 1895c94b2a5SCédric Le Goater ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT; 1905c94b2a5SCédric Le Goater } else { 1915c94b2a5SCédric Le Goater ail = 0; 1925c94b2a5SCédric Le Goater } 1935c94b2a5SCédric Le Goater } else 1945c94b2a5SCédric Le Goater #endif /* defined(TARGET_PPC64) */ 1955c94b2a5SCédric Le Goater { 1966d49d6d4SBenjamin Herrenschmidt lpes0 = true; 1975c94b2a5SCédric Le Goater ail = 0; 1985c94b2a5SCédric Le Goater } 1995c94b2a5SCédric Le Goater 20047733729SDavid Gibson /* 20147733729SDavid Gibson * Hypervisor emulation assistance interrupt only exists on server 2029b2faddaSBenjamin Herrenschmidt * arch 2.05 server or later. We also don't want to generate it if 2039b2faddaSBenjamin Herrenschmidt * we don't have HVB in msr_mask (PAPR mode). 2049b2faddaSBenjamin Herrenschmidt */ 2059b2faddaSBenjamin Herrenschmidt if (excp == POWERPC_EXCP_HV_EMU 2069b2faddaSBenjamin Herrenschmidt #if defined(TARGET_PPC64) 2079b2faddaSBenjamin Herrenschmidt && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB)) 2089b2faddaSBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 2099b2faddaSBenjamin Herrenschmidt 2109b2faddaSBenjamin Herrenschmidt ) { 2119b2faddaSBenjamin Herrenschmidt excp = POWERPC_EXCP_PROGRAM; 2129b2faddaSBenjamin Herrenschmidt } 2139b2faddaSBenjamin Herrenschmidt 214c79c73f6SBlue Swirl switch (excp) { 215c79c73f6SBlue Swirl case POWERPC_EXCP_NONE: 216c79c73f6SBlue Swirl /* Should never happen */ 217c79c73f6SBlue Swirl return; 218c79c73f6SBlue Swirl case POWERPC_EXCP_CRITICAL: /* Critical input */ 219c79c73f6SBlue Swirl switch (excp_model) { 220c79c73f6SBlue Swirl case POWERPC_EXCP_40x: 221c79c73f6SBlue Swirl srr0 = SPR_40x_SRR2; 222c79c73f6SBlue Swirl srr1 = SPR_40x_SRR3; 223c79c73f6SBlue Swirl break; 224c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 225c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 226c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 227c79c73f6SBlue Swirl break; 228c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 229c79c73f6SBlue Swirl break; 230c79c73f6SBlue Swirl default: 231c79c73f6SBlue Swirl goto excp_invalid; 232c79c73f6SBlue Swirl } 233bd6fefe7SBenjamin Herrenschmidt break; 234c79c73f6SBlue Swirl case POWERPC_EXCP_MCHECK: /* Machine check exception */ 235c79c73f6SBlue Swirl if (msr_me == 0) { 23647733729SDavid Gibson /* 23747733729SDavid Gibson * Machine check exception is not enabled. Enter 23847733729SDavid Gibson * checkstop state. 239c79c73f6SBlue Swirl */ 240c79c73f6SBlue Swirl fprintf(stderr, "Machine check while not allowed. " 241c79c73f6SBlue Swirl "Entering checkstop state\n"); 242013a2942SPaolo Bonzini if (qemu_log_separate()) { 243013a2942SPaolo Bonzini qemu_log("Machine check while not allowed. " 244013a2942SPaolo Bonzini "Entering checkstop state\n"); 245c79c73f6SBlue Swirl } 246259186a7SAndreas Färber cs->halted = 1; 247044897efSRichard Purdie cpu_interrupt_exittb(cs); 248c79c73f6SBlue Swirl } 24910c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 25047733729SDavid Gibson /* 25147733729SDavid Gibson * ISA specifies HV, but can be delivered to guest with HV 25247733729SDavid Gibson * clear (e.g., see FWNMI in PAPR). 25310c21b5cSNicholas Piggin */ 254c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 25510c21b5cSNicholas Piggin } 2565c94b2a5SCédric Le Goater ail = 0; 257c79c73f6SBlue Swirl 258c79c73f6SBlue Swirl /* machine check exceptions don't have ME set */ 259c79c73f6SBlue Swirl new_msr &= ~((target_ulong)1 << MSR_ME); 260c79c73f6SBlue Swirl 261c79c73f6SBlue Swirl /* XXX: should also have something loaded in DAR / DSISR */ 262c79c73f6SBlue Swirl switch (excp_model) { 263c79c73f6SBlue Swirl case POWERPC_EXCP_40x: 264c79c73f6SBlue Swirl srr0 = SPR_40x_SRR2; 265c79c73f6SBlue Swirl srr1 = SPR_40x_SRR3; 266c79c73f6SBlue Swirl break; 267c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 268a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 269c79c73f6SBlue Swirl srr0 = SPR_BOOKE_MCSRR0; 270c79c73f6SBlue Swirl srr1 = SPR_BOOKE_MCSRR1; 271c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 272c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 273c79c73f6SBlue Swirl break; 274c79c73f6SBlue Swirl default: 275c79c73f6SBlue Swirl break; 276c79c73f6SBlue Swirl } 277bd6fefe7SBenjamin Herrenschmidt break; 278c79c73f6SBlue Swirl case POWERPC_EXCP_DSI: /* Data storage exception */ 279c79c73f6SBlue Swirl LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx 280c79c73f6SBlue Swirl "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); 281bd6fefe7SBenjamin Herrenschmidt break; 282c79c73f6SBlue Swirl case POWERPC_EXCP_ISI: /* Instruction storage exception */ 283c79c73f6SBlue Swirl LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx 284c79c73f6SBlue Swirl "\n", msr, env->nip); 285c79c73f6SBlue Swirl msr |= env->error_code; 286bd6fefe7SBenjamin Herrenschmidt break; 287c79c73f6SBlue Swirl case POWERPC_EXCP_EXTERNAL: /* External input */ 288fdfba1a2SEdgar E. Iglesias cs = CPU(cpu); 289fdfba1a2SEdgar E. Iglesias 2906d49d6d4SBenjamin Herrenschmidt if (!lpes0) { 291c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 2926d49d6d4SBenjamin Herrenschmidt new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 2936d49d6d4SBenjamin Herrenschmidt srr0 = SPR_HSRR0; 2946d49d6d4SBenjamin Herrenschmidt srr1 = SPR_HSRR1; 295c79c73f6SBlue Swirl } 29668c2dd70SAlexander Graf if (env->mpic_proxy) { 29768c2dd70SAlexander Graf /* IACK the IRQ on delivery */ 298fdfba1a2SEdgar E. Iglesias env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack); 29968c2dd70SAlexander Graf } 300bd6fefe7SBenjamin Herrenschmidt break; 301c79c73f6SBlue Swirl case POWERPC_EXCP_ALIGN: /* Alignment exception */ 302c79c73f6SBlue Swirl /* Get rS/rD and rA from faulting opcode */ 30347733729SDavid Gibson /* 30447733729SDavid Gibson * Note: the opcode fields will not be set properly for a 30547733729SDavid Gibson * direct store load/store, but nobody cares as nobody 30647733729SDavid Gibson * actually uses direct store segments. 3073433b732SBenjamin Herrenschmidt */ 3083433b732SBenjamin Herrenschmidt env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; 309bd6fefe7SBenjamin Herrenschmidt break; 310c79c73f6SBlue Swirl case POWERPC_EXCP_PROGRAM: /* Program exception */ 311c79c73f6SBlue Swirl switch (env->error_code & ~0xF) { 312c79c73f6SBlue Swirl case POWERPC_EXCP_FP: 313c79c73f6SBlue Swirl if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { 314c79c73f6SBlue Swirl LOG_EXCP("Ignore floating point exception\n"); 31527103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 316c79c73f6SBlue Swirl env->error_code = 0; 317c79c73f6SBlue Swirl return; 318c79c73f6SBlue Swirl } 3191b7d17caSBenjamin Herrenschmidt 32047733729SDavid Gibson /* 32147733729SDavid Gibson * FP exceptions always have NIP pointing to the faulting 3221b7d17caSBenjamin Herrenschmidt * instruction, so always use store_next and claim we are 3231b7d17caSBenjamin Herrenschmidt * precise in the MSR. 3241b7d17caSBenjamin Herrenschmidt */ 325c79c73f6SBlue Swirl msr |= 0x00100000; 3260ee604abSAaron Larson env->spr[SPR_BOOKE_ESR] = ESR_FP; 327bd6fefe7SBenjamin Herrenschmidt break; 328c79c73f6SBlue Swirl case POWERPC_EXCP_INVAL: 329c79c73f6SBlue Swirl LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); 330c79c73f6SBlue Swirl msr |= 0x00080000; 331c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PIL; 332c79c73f6SBlue Swirl break; 333c79c73f6SBlue Swirl case POWERPC_EXCP_PRIV: 334c79c73f6SBlue Swirl msr |= 0x00040000; 335c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PPR; 336c79c73f6SBlue Swirl break; 337c79c73f6SBlue Swirl case POWERPC_EXCP_TRAP: 338c79c73f6SBlue Swirl msr |= 0x00020000; 339c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PTR; 340c79c73f6SBlue Swirl break; 341c79c73f6SBlue Swirl default: 342c79c73f6SBlue Swirl /* Should never occur */ 343a47dddd7SAndreas Färber cpu_abort(cs, "Invalid program exception %d. Aborting\n", 344c79c73f6SBlue Swirl env->error_code); 345c79c73f6SBlue Swirl break; 346c79c73f6SBlue Swirl } 347bd6fefe7SBenjamin Herrenschmidt break; 348c79c73f6SBlue Swirl case POWERPC_EXCP_SYSCALL: /* System call exception */ 349c79c73f6SBlue Swirl dump_syscall(env); 350c79c73f6SBlue Swirl lev = env->error_code; 3516d49d6d4SBenjamin Herrenschmidt 35247733729SDavid Gibson /* 35347733729SDavid Gibson * We need to correct the NIP which in this case is supposed 354bd6fefe7SBenjamin Herrenschmidt * to point to the next instruction 355bd6fefe7SBenjamin Herrenschmidt */ 356bd6fefe7SBenjamin Herrenschmidt env->nip += 4; 357bd6fefe7SBenjamin Herrenschmidt 3586d49d6d4SBenjamin Herrenschmidt /* "PAPR mode" built-in hypercall emulation */ 3591d1be34dSDavid Gibson if ((lev == 1) && cpu->vhyp) { 3601d1be34dSDavid Gibson PPCVirtualHypervisorClass *vhc = 3611d1be34dSDavid Gibson PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); 3621d1be34dSDavid Gibson vhc->hypercall(cpu->vhyp, cpu); 363c79c73f6SBlue Swirl return; 364c79c73f6SBlue Swirl } 3656d49d6d4SBenjamin Herrenschmidt if (lev == 1) { 366c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 367c79c73f6SBlue Swirl } 368bd6fefe7SBenjamin Herrenschmidt break; 369bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 370c79c73f6SBlue Swirl case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ 371c79c73f6SBlue Swirl case POWERPC_EXCP_DECR: /* Decrementer exception */ 372bd6fefe7SBenjamin Herrenschmidt break; 373c79c73f6SBlue Swirl case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ 374c79c73f6SBlue Swirl /* FIT on 4xx */ 375c79c73f6SBlue Swirl LOG_EXCP("FIT exception\n"); 376bd6fefe7SBenjamin Herrenschmidt break; 377c79c73f6SBlue Swirl case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ 378c79c73f6SBlue Swirl LOG_EXCP("WDT exception\n"); 379c79c73f6SBlue Swirl switch (excp_model) { 380c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 381c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 382c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 383c79c73f6SBlue Swirl break; 384c79c73f6SBlue Swirl default: 385c79c73f6SBlue Swirl break; 386c79c73f6SBlue Swirl } 387bd6fefe7SBenjamin Herrenschmidt break; 388c79c73f6SBlue Swirl case POWERPC_EXCP_DTLB: /* Data TLB error */ 389c79c73f6SBlue Swirl case POWERPC_EXCP_ITLB: /* Instruction TLB error */ 390bd6fefe7SBenjamin Herrenschmidt break; 391c79c73f6SBlue Swirl case POWERPC_EXCP_DEBUG: /* Debug interrupt */ 3920e3bf489SRoman Kapl if (env->flags & POWERPC_FLAG_DE) { 393a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 394c79c73f6SBlue Swirl srr0 = SPR_BOOKE_DSRR0; 395c79c73f6SBlue Swirl srr1 = SPR_BOOKE_DSRR1; 396c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 397c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 3980e3bf489SRoman Kapl /* DBSR already modified by caller */ 3990e3bf489SRoman Kapl } else { 4000e3bf489SRoman Kapl cpu_abort(cs, "Debug exception triggered on unsupported model\n"); 401c79c73f6SBlue Swirl } 402bd6fefe7SBenjamin Herrenschmidt break; 403c79c73f6SBlue Swirl case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ 404c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 405bd6fefe7SBenjamin Herrenschmidt break; 406c79c73f6SBlue Swirl case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ 407c79c73f6SBlue Swirl /* XXX: TODO */ 408a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point data exception " 409c79c73f6SBlue Swirl "is not implemented yet !\n"); 410c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 411bd6fefe7SBenjamin Herrenschmidt break; 412c79c73f6SBlue Swirl case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ 413c79c73f6SBlue Swirl /* XXX: TODO */ 414a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point round exception " 415c79c73f6SBlue Swirl "is not implemented yet !\n"); 416c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 417bd6fefe7SBenjamin Herrenschmidt break; 418c79c73f6SBlue Swirl case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ 419c79c73f6SBlue Swirl /* XXX: TODO */ 420a47dddd7SAndreas Färber cpu_abort(cs, 421c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 422bd6fefe7SBenjamin Herrenschmidt break; 423c79c73f6SBlue Swirl case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ 424bd6fefe7SBenjamin Herrenschmidt break; 425c79c73f6SBlue Swirl case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ 426c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 427c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 428bd6fefe7SBenjamin Herrenschmidt break; 429c79c73f6SBlue Swirl case POWERPC_EXCP_RESET: /* System reset exception */ 430f85bcec3SNicholas Piggin /* A power-saving exception sets ME, otherwise it is unchanged */ 431c79c73f6SBlue Swirl if (msr_pow) { 432c79c73f6SBlue Swirl /* indicate that we resumed from power save mode */ 433c79c73f6SBlue Swirl msr |= 0x10000; 434f85bcec3SNicholas Piggin new_msr |= ((target_ulong)1 << MSR_ME); 435c79c73f6SBlue Swirl } 43610c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 43747733729SDavid Gibson /* 43847733729SDavid Gibson * ISA specifies HV, but can be delivered to guest with HV 43947733729SDavid Gibson * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU). 44010c21b5cSNicholas Piggin */ 441c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 44210c21b5cSNicholas Piggin } else { 44310c21b5cSNicholas Piggin if (msr_pow) { 44410c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver power-saving system reset " 44510c21b5cSNicholas Piggin "exception %d with no HV support\n", excp); 44610c21b5cSNicholas Piggin } 44710c21b5cSNicholas Piggin } 4485c94b2a5SCédric Le Goater ail = 0; 449bd6fefe7SBenjamin Herrenschmidt break; 450c79c73f6SBlue Swirl case POWERPC_EXCP_DSEG: /* Data segment exception */ 451c79c73f6SBlue Swirl case POWERPC_EXCP_ISEG: /* Instruction segment exception */ 452c79c73f6SBlue Swirl case POWERPC_EXCP_TRACE: /* Trace exception */ 453bd6fefe7SBenjamin Herrenschmidt break; 454bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ 455c79c73f6SBlue Swirl case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ 456c79c73f6SBlue Swirl case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ 457c79c73f6SBlue Swirl case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ 458c79c73f6SBlue Swirl case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ 4597af1e7b0SCédric Le Goater case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ 460bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HV_EMU: 461d8ce5fd6SBenjamin Herrenschmidt case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */ 462c79c73f6SBlue Swirl srr0 = SPR_HSRR0; 463c79c73f6SBlue Swirl srr1 = SPR_HSRR1; 464c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 465c79c73f6SBlue Swirl new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 466bd6fefe7SBenjamin Herrenschmidt break; 467c79c73f6SBlue Swirl case POWERPC_EXCP_VPU: /* Vector unavailable exception */ 4681f29871cSTom Musta case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ 4697019cb3dSAlexey Kardashevskiy case POWERPC_EXCP_FU: /* Facility unavailable exception */ 4705310799aSBalbir Singh #ifdef TARGET_PPC64 4715310799aSBalbir Singh env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56); 4725310799aSBalbir Singh #endif 473bd6fefe7SBenjamin Herrenschmidt break; 474c79c73f6SBlue Swirl case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ 475c79c73f6SBlue Swirl LOG_EXCP("PIT exception\n"); 476bd6fefe7SBenjamin Herrenschmidt break; 477c79c73f6SBlue Swirl case POWERPC_EXCP_IO: /* IO error exception */ 478c79c73f6SBlue Swirl /* XXX: TODO */ 479a47dddd7SAndreas Färber cpu_abort(cs, "601 IO error exception is not implemented yet !\n"); 480bd6fefe7SBenjamin Herrenschmidt break; 481c79c73f6SBlue Swirl case POWERPC_EXCP_RUNM: /* Run mode exception */ 482c79c73f6SBlue Swirl /* XXX: TODO */ 483a47dddd7SAndreas Färber cpu_abort(cs, "601 run mode exception is not implemented yet !\n"); 484bd6fefe7SBenjamin Herrenschmidt break; 485c79c73f6SBlue Swirl case POWERPC_EXCP_EMUL: /* Emulation trap exception */ 486c79c73f6SBlue Swirl /* XXX: TODO */ 487a47dddd7SAndreas Färber cpu_abort(cs, "602 emulation trap exception " 488c79c73f6SBlue Swirl "is not implemented yet !\n"); 489bd6fefe7SBenjamin Herrenschmidt break; 490c79c73f6SBlue Swirl case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ 491c79c73f6SBlue Swirl switch (excp_model) { 492c79c73f6SBlue Swirl case POWERPC_EXCP_602: 493c79c73f6SBlue Swirl case POWERPC_EXCP_603: 494c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 495c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 496c79c73f6SBlue Swirl goto tlb_miss_tgpr; 497c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 498c79c73f6SBlue Swirl goto tlb_miss; 499c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 500c79c73f6SBlue Swirl goto tlb_miss_74xx; 501c79c73f6SBlue Swirl default: 502a47dddd7SAndreas Färber cpu_abort(cs, "Invalid instruction TLB miss exception\n"); 503c79c73f6SBlue Swirl break; 504c79c73f6SBlue Swirl } 505c79c73f6SBlue Swirl break; 506c79c73f6SBlue Swirl case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ 507c79c73f6SBlue Swirl switch (excp_model) { 508c79c73f6SBlue Swirl case POWERPC_EXCP_602: 509c79c73f6SBlue Swirl case POWERPC_EXCP_603: 510c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 511c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 512c79c73f6SBlue Swirl goto tlb_miss_tgpr; 513c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 514c79c73f6SBlue Swirl goto tlb_miss; 515c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 516c79c73f6SBlue Swirl goto tlb_miss_74xx; 517c79c73f6SBlue Swirl default: 518a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data load TLB miss exception\n"); 519c79c73f6SBlue Swirl break; 520c79c73f6SBlue Swirl } 521c79c73f6SBlue Swirl break; 522c79c73f6SBlue Swirl case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ 523c79c73f6SBlue Swirl switch (excp_model) { 524c79c73f6SBlue Swirl case POWERPC_EXCP_602: 525c79c73f6SBlue Swirl case POWERPC_EXCP_603: 526c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 527c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 528c79c73f6SBlue Swirl tlb_miss_tgpr: 529c79c73f6SBlue Swirl /* Swap temporary saved registers with GPRs */ 530c79c73f6SBlue Swirl if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { 531c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_TGPR; 532c79c73f6SBlue Swirl hreg_swap_gpr_tgpr(env); 533c79c73f6SBlue Swirl } 534c79c73f6SBlue Swirl goto tlb_miss; 535c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 536c79c73f6SBlue Swirl tlb_miss: 537c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 538c79c73f6SBlue Swirl if (qemu_log_enabled()) { 539c79c73f6SBlue Swirl const char *es; 540c79c73f6SBlue Swirl target_ulong *miss, *cmp; 541c79c73f6SBlue Swirl int en; 542c79c73f6SBlue Swirl 543c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 544c79c73f6SBlue Swirl es = "I"; 545c79c73f6SBlue Swirl en = 'I'; 546c79c73f6SBlue Swirl miss = &env->spr[SPR_IMISS]; 547c79c73f6SBlue Swirl cmp = &env->spr[SPR_ICMP]; 548c79c73f6SBlue Swirl } else { 549c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 550c79c73f6SBlue Swirl es = "DL"; 551c79c73f6SBlue Swirl } else { 552c79c73f6SBlue Swirl es = "DS"; 553c79c73f6SBlue Swirl } 554c79c73f6SBlue Swirl en = 'D'; 555c79c73f6SBlue Swirl miss = &env->spr[SPR_DMISS]; 556c79c73f6SBlue Swirl cmp = &env->spr[SPR_DCMP]; 557c79c73f6SBlue Swirl } 558c79c73f6SBlue Swirl qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 559c79c73f6SBlue Swirl TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " 560c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 561c79c73f6SBlue Swirl env->spr[SPR_HASH1], env->spr[SPR_HASH2], 562c79c73f6SBlue Swirl env->error_code); 563c79c73f6SBlue Swirl } 564c79c73f6SBlue Swirl #endif 565c79c73f6SBlue Swirl msr |= env->crf[0] << 28; 566c79c73f6SBlue Swirl msr |= env->error_code; /* key, D/I, S/L bits */ 567c79c73f6SBlue Swirl /* Set way using a LRU mechanism */ 568c79c73f6SBlue Swirl msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; 569c79c73f6SBlue Swirl break; 570c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 571c79c73f6SBlue Swirl tlb_miss_74xx: 572c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 573c79c73f6SBlue Swirl if (qemu_log_enabled()) { 574c79c73f6SBlue Swirl const char *es; 575c79c73f6SBlue Swirl target_ulong *miss, *cmp; 576c79c73f6SBlue Swirl int en; 577c79c73f6SBlue Swirl 578c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 579c79c73f6SBlue Swirl es = "I"; 580c79c73f6SBlue Swirl en = 'I'; 581c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 582c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 583c79c73f6SBlue Swirl } else { 584c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 585c79c73f6SBlue Swirl es = "DL"; 586c79c73f6SBlue Swirl } else { 587c79c73f6SBlue Swirl es = "DS"; 588c79c73f6SBlue Swirl } 589c79c73f6SBlue Swirl en = 'D'; 590c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 591c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 592c79c73f6SBlue Swirl } 593c79c73f6SBlue Swirl qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 594c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 595c79c73f6SBlue Swirl env->error_code); 596c79c73f6SBlue Swirl } 597c79c73f6SBlue Swirl #endif 598c79c73f6SBlue Swirl msr |= env->error_code; /* key bit */ 599c79c73f6SBlue Swirl break; 600c79c73f6SBlue Swirl default: 601a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data store TLB miss exception\n"); 602c79c73f6SBlue Swirl break; 603c79c73f6SBlue Swirl } 604bd6fefe7SBenjamin Herrenschmidt break; 605c79c73f6SBlue Swirl case POWERPC_EXCP_FPA: /* Floating-point assist exception */ 606c79c73f6SBlue Swirl /* XXX: TODO */ 607a47dddd7SAndreas Färber cpu_abort(cs, "Floating point assist exception " 608c79c73f6SBlue Swirl "is not implemented yet !\n"); 609bd6fefe7SBenjamin Herrenschmidt break; 610c79c73f6SBlue Swirl case POWERPC_EXCP_DABR: /* Data address breakpoint */ 611c79c73f6SBlue Swirl /* XXX: TODO */ 612a47dddd7SAndreas Färber cpu_abort(cs, "DABR exception is not implemented yet !\n"); 613bd6fefe7SBenjamin Herrenschmidt break; 614c79c73f6SBlue Swirl case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ 615c79c73f6SBlue Swirl /* XXX: TODO */ 616a47dddd7SAndreas Färber cpu_abort(cs, "IABR exception is not implemented yet !\n"); 617bd6fefe7SBenjamin Herrenschmidt break; 618c79c73f6SBlue Swirl case POWERPC_EXCP_SMI: /* System management interrupt */ 619c79c73f6SBlue Swirl /* XXX: TODO */ 620a47dddd7SAndreas Färber cpu_abort(cs, "SMI exception is not implemented yet !\n"); 621bd6fefe7SBenjamin Herrenschmidt break; 622c79c73f6SBlue Swirl case POWERPC_EXCP_THERM: /* Thermal interrupt */ 623c79c73f6SBlue Swirl /* XXX: TODO */ 624a47dddd7SAndreas Färber cpu_abort(cs, "Thermal management exception " 625c79c73f6SBlue Swirl "is not implemented yet !\n"); 626bd6fefe7SBenjamin Herrenschmidt break; 627c79c73f6SBlue Swirl case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ 628c79c73f6SBlue Swirl /* XXX: TODO */ 629a47dddd7SAndreas Färber cpu_abort(cs, 630c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 631bd6fefe7SBenjamin Herrenschmidt break; 632c79c73f6SBlue Swirl case POWERPC_EXCP_VPUA: /* Vector assist exception */ 633c79c73f6SBlue Swirl /* XXX: TODO */ 634a47dddd7SAndreas Färber cpu_abort(cs, "VPU assist exception is not implemented yet !\n"); 635bd6fefe7SBenjamin Herrenschmidt break; 636c79c73f6SBlue Swirl case POWERPC_EXCP_SOFTP: /* Soft patch exception */ 637c79c73f6SBlue Swirl /* XXX: TODO */ 638a47dddd7SAndreas Färber cpu_abort(cs, 639c79c73f6SBlue Swirl "970 soft-patch exception is not implemented yet !\n"); 640bd6fefe7SBenjamin Herrenschmidt break; 641c79c73f6SBlue Swirl case POWERPC_EXCP_MAINT: /* Maintenance exception */ 642c79c73f6SBlue Swirl /* XXX: TODO */ 643a47dddd7SAndreas Färber cpu_abort(cs, 644c79c73f6SBlue Swirl "970 maintenance exception is not implemented yet !\n"); 645bd6fefe7SBenjamin Herrenschmidt break; 646c79c73f6SBlue Swirl case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ 647c79c73f6SBlue Swirl /* XXX: TODO */ 648a47dddd7SAndreas Färber cpu_abort(cs, "Maskable external exception " 649c79c73f6SBlue Swirl "is not implemented yet !\n"); 650bd6fefe7SBenjamin Herrenschmidt break; 651c79c73f6SBlue Swirl case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ 652c79c73f6SBlue Swirl /* XXX: TODO */ 653a47dddd7SAndreas Färber cpu_abort(cs, "Non maskable external exception " 654c79c73f6SBlue Swirl "is not implemented yet !\n"); 655bd6fefe7SBenjamin Herrenschmidt break; 656c79c73f6SBlue Swirl default: 657c79c73f6SBlue Swirl excp_invalid: 658a47dddd7SAndreas Färber cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 659c79c73f6SBlue Swirl break; 660c79c73f6SBlue Swirl } 661bd6fefe7SBenjamin Herrenschmidt 662bd6fefe7SBenjamin Herrenschmidt /* Save PC */ 663bd6fefe7SBenjamin Herrenschmidt env->spr[srr0] = env->nip; 664bd6fefe7SBenjamin Herrenschmidt 665c79c73f6SBlue Swirl /* Save MSR */ 666c79c73f6SBlue Swirl env->spr[srr1] = msr; 6676d49d6d4SBenjamin Herrenschmidt 6686d49d6d4SBenjamin Herrenschmidt /* Sanity check */ 66910c21b5cSNicholas Piggin if (!(env->msr_mask & MSR_HVB)) { 67010c21b5cSNicholas Piggin if (new_msr & MSR_HVB) { 67110c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with " 6726d49d6d4SBenjamin Herrenschmidt "no HV support\n", excp); 6736d49d6d4SBenjamin Herrenschmidt } 67410c21b5cSNicholas Piggin if (srr0 == SPR_HSRR0) { 67510c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with " 67610c21b5cSNicholas Piggin "no HV support\n", excp); 67710c21b5cSNicholas Piggin } 67810c21b5cSNicholas Piggin } 6796d49d6d4SBenjamin Herrenschmidt 680c79c73f6SBlue Swirl /* If any alternate SRR register are defined, duplicate saved values */ 681c79c73f6SBlue Swirl if (asrr0 != -1) { 682c79c73f6SBlue Swirl env->spr[asrr0] = env->spr[srr0]; 683c79c73f6SBlue Swirl } 684c79c73f6SBlue Swirl if (asrr1 != -1) { 685c79c73f6SBlue Swirl env->spr[asrr1] = env->spr[srr1]; 686c79c73f6SBlue Swirl } 687d5ac4f54SAlexey Kardashevskiy 68847733729SDavid Gibson /* 68947733729SDavid Gibson * Sort out endianness of interrupt, this differs depending on the 6906d49d6d4SBenjamin Herrenschmidt * CPU, the HV mode, etc... 6916d49d6d4SBenjamin Herrenschmidt */ 6921e0c7e55SAnton Blanchard #ifdef TARGET_PPC64 6936d49d6d4SBenjamin Herrenschmidt if (excp_model == POWERPC_EXCP_POWER7) { 6946d49d6d4SBenjamin Herrenschmidt if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) { 6956d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 6966d49d6d4SBenjamin Herrenschmidt } 6976d49d6d4SBenjamin Herrenschmidt } else if (excp_model == POWERPC_EXCP_POWER8) { 6986d49d6d4SBenjamin Herrenschmidt if (new_msr & MSR_HVB) { 699a790e82bSBenjamin Herrenschmidt if (env->spr[SPR_HID0] & HID0_HILE) { 700a790e82bSBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 701a790e82bSBenjamin Herrenschmidt } 702a790e82bSBenjamin Herrenschmidt } else if (env->spr[SPR_LPCR] & LPCR_ILE) { 703a790e82bSBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 704a790e82bSBenjamin Herrenschmidt } 705a790e82bSBenjamin Herrenschmidt } else if (excp_model == POWERPC_EXCP_POWER9) { 706a790e82bSBenjamin Herrenschmidt if (new_msr & MSR_HVB) { 707a790e82bSBenjamin Herrenschmidt if (env->spr[SPR_HID0] & HID0_POWER9_HILE) { 7086d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 7096d49d6d4SBenjamin Herrenschmidt } 7106d49d6d4SBenjamin Herrenschmidt } else if (env->spr[SPR_LPCR] & LPCR_ILE) { 7111e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 7121e0c7e55SAnton Blanchard } 7131e0c7e55SAnton Blanchard } else if (msr_ile) { 7141e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 7151e0c7e55SAnton Blanchard } 7161e0c7e55SAnton Blanchard #else 717c79c73f6SBlue Swirl if (msr_ile) { 718c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_LE; 719c79c73f6SBlue Swirl } 7201e0c7e55SAnton Blanchard #endif 721c79c73f6SBlue Swirl 722c79c73f6SBlue Swirl /* Jump to handler */ 723c79c73f6SBlue Swirl vector = env->excp_vectors[excp]; 724c79c73f6SBlue Swirl if (vector == (target_ulong)-1ULL) { 725a47dddd7SAndreas Färber cpu_abort(cs, "Raised an exception without defined vector %d\n", 726c79c73f6SBlue Swirl excp); 727c79c73f6SBlue Swirl } 728c79c73f6SBlue Swirl vector |= env->excp_prefix; 7295c94b2a5SCédric Le Goater 73047733729SDavid Gibson /* 73147733729SDavid Gibson * AIL only works if there is no HV transition and we are running 73247733729SDavid Gibson * with translations enabled 7335c94b2a5SCédric Le Goater */ 7346d49d6d4SBenjamin Herrenschmidt if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) || 7356d49d6d4SBenjamin Herrenschmidt ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) { 7365c94b2a5SCédric Le Goater ail = 0; 7375c94b2a5SCédric Le Goater } 7385c94b2a5SCédric Le Goater /* Handle AIL */ 7395c94b2a5SCédric Le Goater if (ail) { 7405c94b2a5SCédric Le Goater new_msr |= (1 << MSR_IR) | (1 << MSR_DR); 7412586a4d7SFabiano Rosas vector |= ppc_excp_vector_offset(cs, ail); 7425c94b2a5SCédric Le Goater } 7435c94b2a5SCédric Le Goater 744c79c73f6SBlue Swirl #if defined(TARGET_PPC64) 745c79c73f6SBlue Swirl if (excp_model == POWERPC_EXCP_BOOKE) { 746e42a61f1SAlexander Graf if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) { 747e42a61f1SAlexander Graf /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */ 748c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_CM; 749e42a61f1SAlexander Graf } else { 750e42a61f1SAlexander Graf vector = (uint32_t)vector; 751c79c73f6SBlue Swirl } 752c79c73f6SBlue Swirl } else { 753c79c73f6SBlue Swirl if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) { 754c79c73f6SBlue Swirl vector = (uint32_t)vector; 755c79c73f6SBlue Swirl } else { 756c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_SF; 757c79c73f6SBlue Swirl } 758c79c73f6SBlue Swirl } 759c79c73f6SBlue Swirl #endif 76047733729SDavid Gibson /* 76147733729SDavid Gibson * We don't use hreg_store_msr here as already have treated any 76247733729SDavid Gibson * special case that could occur. Just store MSR and update hflags 7631c953ba5SBenjamin Herrenschmidt * 7641c953ba5SBenjamin Herrenschmidt * Note: We *MUST* not use hreg_store_msr() as-is anyway because it 7651c953ba5SBenjamin Herrenschmidt * will prevent setting of the HV bit which some exceptions might need 7661c953ba5SBenjamin Herrenschmidt * to do. 767c79c73f6SBlue Swirl */ 768c79c73f6SBlue Swirl env->msr = new_msr & env->msr_mask; 769c79c73f6SBlue Swirl hreg_compute_hflags(env); 770c79c73f6SBlue Swirl env->nip = vector; 771c79c73f6SBlue Swirl /* Reset exception state */ 77227103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 773c79c73f6SBlue Swirl env->error_code = 0; 774cd0c6f47SBenjamin Herrenschmidt 775139d9023SNikunj A Dadhania /* Reset the reservation */ 776139d9023SNikunj A Dadhania env->reserve_addr = -1; 777139d9023SNikunj A Dadhania 77847733729SDavid Gibson /* 77947733729SDavid Gibson * Any interrupt is context synchronizing, check if TCG TLB needs 78047733729SDavid Gibson * a delayed flush on ppc64 781cd0c6f47SBenjamin Herrenschmidt */ 782e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 783c79c73f6SBlue Swirl } 784c79c73f6SBlue Swirl 78597a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs) 786c79c73f6SBlue Swirl { 78797a8ea5aSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 78897a8ea5aSAndreas Färber CPUPPCState *env = &cpu->env; 7895c26a5b3SAndreas Färber 79027103424SAndreas Färber powerpc_excp(cpu, env->excp_model, cs->exception_index); 791c79c73f6SBlue Swirl } 792c79c73f6SBlue Swirl 793458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env) 794c79c73f6SBlue Swirl { 795*db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 7963621e2c9SBenjamin Herrenschmidt bool async_deliver; 797259186a7SAndreas Färber 798c79c73f6SBlue Swirl /* External reset */ 799c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { 800c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); 8015c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 802c79c73f6SBlue Swirl return; 803c79c73f6SBlue Swirl } 804c79c73f6SBlue Swirl /* Machine check exception */ 805c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { 806c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); 8075c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK); 808c79c73f6SBlue Swirl return; 809c79c73f6SBlue Swirl } 810c79c73f6SBlue Swirl #if 0 /* TODO */ 811c79c73f6SBlue Swirl /* External debug exception */ 812c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { 813c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); 8145c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG); 815c79c73f6SBlue Swirl return; 816c79c73f6SBlue Swirl } 817c79c73f6SBlue Swirl #endif 8183621e2c9SBenjamin Herrenschmidt 8193621e2c9SBenjamin Herrenschmidt /* 8203621e2c9SBenjamin Herrenschmidt * For interrupts that gate on MSR:EE, we need to do something a 8213621e2c9SBenjamin Herrenschmidt * bit more subtle, as we need to let them through even when EE is 8223621e2c9SBenjamin Herrenschmidt * clear when coming out of some power management states (in order 8233621e2c9SBenjamin Herrenschmidt * for them to become a 0x100). 8243621e2c9SBenjamin Herrenschmidt */ 8251e7fd61dSBenjamin Herrenschmidt async_deliver = (msr_ee != 0) || env->resume_as_sreset; 8263621e2c9SBenjamin Herrenschmidt 827c79c73f6SBlue Swirl /* Hypervisor decrementer exception */ 828c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { 8294b236b62SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 8304b236b62SBenjamin Herrenschmidt bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); 8313621e2c9SBenjamin Herrenschmidt if ((async_deliver || msr_hv == 0) && hdice) { 8324b236b62SBenjamin Herrenschmidt /* HDEC clears on delivery */ 8334b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 8345c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR); 835c79c73f6SBlue Swirl return; 836c79c73f6SBlue Swirl } 837c79c73f6SBlue Swirl } 838d8ce5fd6SBenjamin Herrenschmidt 839d8ce5fd6SBenjamin Herrenschmidt /* Hypervisor virtualization interrupt */ 840d8ce5fd6SBenjamin Herrenschmidt if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) { 841d8ce5fd6SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 842d8ce5fd6SBenjamin Herrenschmidt bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); 843d8ce5fd6SBenjamin Herrenschmidt if ((async_deliver || msr_hv == 0) && hvice) { 844d8ce5fd6SBenjamin Herrenschmidt powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT); 845d8ce5fd6SBenjamin Herrenschmidt return; 846d8ce5fd6SBenjamin Herrenschmidt } 847d8ce5fd6SBenjamin Herrenschmidt } 848d8ce5fd6SBenjamin Herrenschmidt 849d8ce5fd6SBenjamin Herrenschmidt /* External interrupt can ignore MSR:EE under some circumstances */ 850d1dbe37cSBenjamin Herrenschmidt if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { 851d1dbe37cSBenjamin Herrenschmidt bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 8526eebe6dcSBenjamin Herrenschmidt bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); 8536eebe6dcSBenjamin Herrenschmidt /* HEIC blocks delivery to the hypervisor */ 8546eebe6dcSBenjamin Herrenschmidt if ((async_deliver && !(heic && msr_hv && !msr_pr)) || 8556eebe6dcSBenjamin Herrenschmidt (env->has_hv_mode && msr_hv == 0 && !lpes0)) { 856d1dbe37cSBenjamin Herrenschmidt powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL); 857d1dbe37cSBenjamin Herrenschmidt return; 858d1dbe37cSBenjamin Herrenschmidt } 859d1dbe37cSBenjamin Herrenschmidt } 860c79c73f6SBlue Swirl if (msr_ce != 0) { 861c79c73f6SBlue Swirl /* External critical interrupt */ 862c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { 8635c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL); 864c79c73f6SBlue Swirl return; 865c79c73f6SBlue Swirl } 866c79c73f6SBlue Swirl } 8673621e2c9SBenjamin Herrenschmidt if (async_deliver != 0) { 868c79c73f6SBlue Swirl /* Watchdog timer on embedded PowerPC */ 869c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { 870c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); 8715c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT); 872c79c73f6SBlue Swirl return; 873c79c73f6SBlue Swirl } 874c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { 875c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); 8765c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI); 877c79c73f6SBlue Swirl return; 878c79c73f6SBlue Swirl } 879c79c73f6SBlue Swirl /* Fixed interval timer on embedded PowerPC */ 880c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { 881c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); 8825c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT); 883c79c73f6SBlue Swirl return; 884c79c73f6SBlue Swirl } 885c79c73f6SBlue Swirl /* Programmable interval timer on embedded PowerPC */ 886c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { 887c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); 8885c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT); 889c79c73f6SBlue Swirl return; 890c79c73f6SBlue Swirl } 891c79c73f6SBlue Swirl /* Decrementer exception */ 892c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { 893e81a982aSAlexander Graf if (ppc_decr_clear_on_delivery(env)) { 894c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); 895e81a982aSAlexander Graf } 8965c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR); 897c79c73f6SBlue Swirl return; 898c79c73f6SBlue Swirl } 899c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { 900c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); 9015c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI); 902c79c73f6SBlue Swirl return; 903c79c73f6SBlue Swirl } 9047af1e7b0SCédric Le Goater if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) { 9057af1e7b0SCédric Le Goater env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL); 9067af1e7b0SCédric Le Goater powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV); 9077af1e7b0SCédric Le Goater return; 9087af1e7b0SCédric Le Goater } 909c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { 910c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); 9115c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM); 912c79c73f6SBlue Swirl return; 913c79c73f6SBlue Swirl } 914c79c73f6SBlue Swirl /* Thermal interrupt */ 915c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { 916c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); 9175c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM); 918c79c73f6SBlue Swirl return; 919c79c73f6SBlue Swirl } 920c79c73f6SBlue Swirl } 921f8154fd2SBenjamin Herrenschmidt 922f8154fd2SBenjamin Herrenschmidt if (env->resume_as_sreset) { 923f8154fd2SBenjamin Herrenschmidt /* 924f8154fd2SBenjamin Herrenschmidt * This is a bug ! It means that has_work took us out of halt without 925f8154fd2SBenjamin Herrenschmidt * anything to deliver while in a PM state that requires getting 926f8154fd2SBenjamin Herrenschmidt * out via a 0x100 927f8154fd2SBenjamin Herrenschmidt * 928f8154fd2SBenjamin Herrenschmidt * This means we will incorrectly execute past the power management 929f8154fd2SBenjamin Herrenschmidt * instruction instead of triggering a reset. 930f8154fd2SBenjamin Herrenschmidt * 931f8154fd2SBenjamin Herrenschmidt * It generally means a discrepancy between the wakup conditions in the 932f8154fd2SBenjamin Herrenschmidt * processor has_work implementation and the logic in this function. 933f8154fd2SBenjamin Herrenschmidt */ 934*db70b311SRichard Henderson cpu_abort(env_cpu(env), 935f8154fd2SBenjamin Herrenschmidt "Wakeup from PM state but interrupt Undelivered"); 936f8154fd2SBenjamin Herrenschmidt } 937c79c73f6SBlue Swirl } 93834316482SAlexey Kardashevskiy 93934316482SAlexey Kardashevskiy void ppc_cpu_do_system_reset(CPUState *cs) 94034316482SAlexey Kardashevskiy { 94134316482SAlexey Kardashevskiy PowerPCCPU *cpu = POWERPC_CPU(cs); 94234316482SAlexey Kardashevskiy CPUPPCState *env = &cpu->env; 94334316482SAlexey Kardashevskiy 94434316482SAlexey Kardashevskiy powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 94534316482SAlexey Kardashevskiy } 946c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */ 947c79c73f6SBlue Swirl 948458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 949458dd766SRichard Henderson { 950458dd766SRichard Henderson PowerPCCPU *cpu = POWERPC_CPU(cs); 951458dd766SRichard Henderson CPUPPCState *env = &cpu->env; 952458dd766SRichard Henderson 953458dd766SRichard Henderson if (interrupt_request & CPU_INTERRUPT_HARD) { 954458dd766SRichard Henderson ppc_hw_interrupt(env); 955458dd766SRichard Henderson if (env->pending_interrupts == 0) { 956458dd766SRichard Henderson cs->interrupt_request &= ~CPU_INTERRUPT_HARD; 957458dd766SRichard Henderson } 958458dd766SRichard Henderson return true; 959458dd766SRichard Henderson } 960458dd766SRichard Henderson return false; 961458dd766SRichard Henderson } 962458dd766SRichard Henderson 963c79c73f6SBlue Swirl #if defined(DEBUG_OP) 964c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr) 965c79c73f6SBlue Swirl { 966c79c73f6SBlue Swirl qemu_log("Return from exception at " TARGET_FMT_lx " with flags " 967c79c73f6SBlue Swirl TARGET_FMT_lx "\n", RA, msr); 968c79c73f6SBlue Swirl } 969c79c73f6SBlue Swirl #endif 970c79c73f6SBlue Swirl 971ad71ed68SBlue Swirl /*****************************************************************************/ 972ad71ed68SBlue Swirl /* Exceptions processing helpers */ 973ad71ed68SBlue Swirl 974db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, 975db789c6cSBenjamin Herrenschmidt uint32_t error_code, uintptr_t raddr) 976ad71ed68SBlue Swirl { 977*db70b311SRichard Henderson CPUState *cs = env_cpu(env); 97827103424SAndreas Färber 97927103424SAndreas Färber cs->exception_index = exception; 980ad71ed68SBlue Swirl env->error_code = error_code; 981db789c6cSBenjamin Herrenschmidt cpu_loop_exit_restore(cs, raddr); 982db789c6cSBenjamin Herrenschmidt } 983db789c6cSBenjamin Herrenschmidt 984db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception, 985db789c6cSBenjamin Herrenschmidt uint32_t error_code) 986db789c6cSBenjamin Herrenschmidt { 987db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 988db789c6cSBenjamin Herrenschmidt } 989db789c6cSBenjamin Herrenschmidt 990db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception) 991db789c6cSBenjamin Herrenschmidt { 992db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 993db789c6cSBenjamin Herrenschmidt } 994db789c6cSBenjamin Herrenschmidt 995db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception, 996db789c6cSBenjamin Herrenschmidt uintptr_t raddr) 997db789c6cSBenjamin Herrenschmidt { 998db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, raddr); 999db789c6cSBenjamin Herrenschmidt } 1000db789c6cSBenjamin Herrenschmidt 1001db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, 1002db789c6cSBenjamin Herrenschmidt uint32_t error_code) 1003db789c6cSBenjamin Herrenschmidt { 1004db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 1005ad71ed68SBlue Swirl } 1006ad71ed68SBlue Swirl 1007e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception) 1008ad71ed68SBlue Swirl { 1009db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 1010ad71ed68SBlue Swirl } 1011ad71ed68SBlue Swirl 1012ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 1013e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val) 1014ad71ed68SBlue Swirl { 1015db789c6cSBenjamin Herrenschmidt uint32_t excp = hreg_store_msr(env, val, 0); 1016259186a7SAndreas Färber 1017db789c6cSBenjamin Herrenschmidt if (excp != 0) { 1018*db70b311SRichard Henderson CPUState *cs = env_cpu(env); 1019044897efSRichard Purdie cpu_interrupt_exittb(cs); 1020db789c6cSBenjamin Herrenschmidt raise_exception(env, excp); 1021ad71ed68SBlue Swirl } 1022ad71ed68SBlue Swirl } 1023ad71ed68SBlue Swirl 10247778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64) 10257778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) 10267778a575SBenjamin Herrenschmidt { 10277778a575SBenjamin Herrenschmidt CPUState *cs; 10287778a575SBenjamin Herrenschmidt 1029*db70b311SRichard Henderson cs = env_cpu(env); 10307778a575SBenjamin Herrenschmidt cs->halted = 1; 10317778a575SBenjamin Herrenschmidt 103247733729SDavid Gibson /* 103347733729SDavid Gibson * The architecture specifies that HDEC interrupts are discarded 103447733729SDavid Gibson * in PM states 10354b236b62SBenjamin Herrenschmidt */ 10364b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 10374b236b62SBenjamin Herrenschmidt 10383621e2c9SBenjamin Herrenschmidt /* Condition for waking up at 0x100 */ 10391e7fd61dSBenjamin Herrenschmidt env->resume_as_sreset = (insn != PPC_PM_STOP) || 104021c0d66aSBenjamin Herrenschmidt (env->spr[SPR_PSSCR] & PSSCR_EC); 10417778a575SBenjamin Herrenschmidt } 10427778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 10437778a575SBenjamin Herrenschmidt 1044a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) 1045ad71ed68SBlue Swirl { 1046*db70b311SRichard Henderson CPUState *cs = env_cpu(env); 1047259186a7SAndreas Färber 1048a2e71b28SBenjamin Herrenschmidt /* MSR:POW cannot be set by any form of rfi */ 1049a2e71b28SBenjamin Herrenschmidt msr &= ~(1ULL << MSR_POW); 1050a2e71b28SBenjamin Herrenschmidt 1051ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1052a2e71b28SBenjamin Herrenschmidt /* Switching to 32-bit ? Crop the nip */ 1053a2e71b28SBenjamin Herrenschmidt if (!msr_is_64bit(env, msr)) { 1054ad71ed68SBlue Swirl nip = (uint32_t)nip; 1055ad71ed68SBlue Swirl } 1056ad71ed68SBlue Swirl #else 1057ad71ed68SBlue Swirl nip = (uint32_t)nip; 1058ad71ed68SBlue Swirl #endif 1059ad71ed68SBlue Swirl /* XXX: beware: this is false if VLE is supported */ 1060ad71ed68SBlue Swirl env->nip = nip & ~((target_ulong)0x00000003); 1061ad71ed68SBlue Swirl hreg_store_msr(env, msr, 1); 1062ad71ed68SBlue Swirl #if defined(DEBUG_OP) 1063ad71ed68SBlue Swirl cpu_dump_rfi(env->nip, env->msr); 1064ad71ed68SBlue Swirl #endif 106547733729SDavid Gibson /* 106647733729SDavid Gibson * No need to raise an exception here, as rfi is always the last 106747733729SDavid Gibson * insn of a TB 1068ad71ed68SBlue Swirl */ 1069044897efSRichard Purdie cpu_interrupt_exittb(cs); 1070a8b73734SNikunj A Dadhania /* Reset the reservation */ 1071a8b73734SNikunj A Dadhania env->reserve_addr = -1; 1072a8b73734SNikunj A Dadhania 1073cd0c6f47SBenjamin Herrenschmidt /* Context synchronizing: check if TCG TLB needs flush */ 1074e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 1075ad71ed68SBlue Swirl } 1076ad71ed68SBlue Swirl 1077e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env) 1078ad71ed68SBlue Swirl { 1079a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); 1080a1bb7384SScott Wood } 1081ad71ed68SBlue Swirl 1082a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK 1083ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1084e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env) 1085ad71ed68SBlue Swirl { 108647733729SDavid Gibson /* 108747733729SDavid Gibson * The architeture defines a number of rules for which bits can 108847733729SDavid Gibson * change but in practice, we handle this in hreg_store_msr() 1089a2e71b28SBenjamin Herrenschmidt * which will be called by do_rfi(), so there is no need to filter 1090a2e71b28SBenjamin Herrenschmidt * here 1091a2e71b28SBenjamin Herrenschmidt */ 1092a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]); 1093ad71ed68SBlue Swirl } 1094ad71ed68SBlue Swirl 1095e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env) 1096ad71ed68SBlue Swirl { 1097a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); 1098ad71ed68SBlue Swirl } 1099ad71ed68SBlue Swirl #endif 1100ad71ed68SBlue Swirl 1101ad71ed68SBlue Swirl /*****************************************************************************/ 1102ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */ 1103e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env) 1104ad71ed68SBlue Swirl { 1105a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]); 1106ad71ed68SBlue Swirl } 1107ad71ed68SBlue Swirl 1108e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env) 1109ad71ed68SBlue Swirl { 1110a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]); 1111ad71ed68SBlue Swirl } 1112ad71ed68SBlue Swirl 1113e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env) 1114ad71ed68SBlue Swirl { 1115a1bb7384SScott Wood /* FIXME: choose CSRR1 or DSRR1 based on cpu type */ 1116a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]); 1117ad71ed68SBlue Swirl } 1118ad71ed68SBlue Swirl 1119e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env) 1120ad71ed68SBlue Swirl { 1121a1bb7384SScott Wood /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ 1122a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); 1123ad71ed68SBlue Swirl } 1124ad71ed68SBlue Swirl #endif 1125ad71ed68SBlue Swirl 1126e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1127e5f17ac6SBlue Swirl uint32_t flags) 1128ad71ed68SBlue Swirl { 1129ad71ed68SBlue Swirl if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || 1130ad71ed68SBlue Swirl ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) || 1131ad71ed68SBlue Swirl ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || 1132ad71ed68SBlue Swirl ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || 1133ad71ed68SBlue Swirl ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { 113472073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 113572073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1136ad71ed68SBlue Swirl } 1137ad71ed68SBlue Swirl } 1138ad71ed68SBlue Swirl 1139ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1140e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1141e5f17ac6SBlue Swirl uint32_t flags) 1142ad71ed68SBlue Swirl { 1143ad71ed68SBlue Swirl if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || 1144ad71ed68SBlue Swirl ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) || 1145ad71ed68SBlue Swirl ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || 1146ad71ed68SBlue Swirl ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || 1147ad71ed68SBlue Swirl ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { 114872073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 114972073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1150ad71ed68SBlue Swirl } 1151ad71ed68SBlue Swirl } 1152ad71ed68SBlue Swirl #endif 1153ad71ed68SBlue Swirl 1154ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 1155ad71ed68SBlue Swirl /*****************************************************************************/ 1156ad71ed68SBlue Swirl /* PowerPC 601 specific instructions (POWER bridge) */ 1157ad71ed68SBlue Swirl 1158e5f17ac6SBlue Swirl void helper_rfsvc(CPUPPCState *env) 1159ad71ed68SBlue Swirl { 1160a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->lr, env->ctr & 0x0000FFFF); 1161ad71ed68SBlue Swirl } 1162ad71ed68SBlue Swirl 1163ad71ed68SBlue Swirl /* Embedded.Processor Control */ 1164ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb) 1165ad71ed68SBlue Swirl { 1166ad71ed68SBlue Swirl int msg = rb & DBELL_TYPE_MASK; 1167ad71ed68SBlue Swirl int irq = -1; 1168ad71ed68SBlue Swirl 1169ad71ed68SBlue Swirl switch (msg) { 1170ad71ed68SBlue Swirl case DBELL_TYPE_DBELL: 1171ad71ed68SBlue Swirl irq = PPC_INTERRUPT_DOORBELL; 1172ad71ed68SBlue Swirl break; 1173ad71ed68SBlue Swirl case DBELL_TYPE_DBELL_CRIT: 1174ad71ed68SBlue Swirl irq = PPC_INTERRUPT_CDOORBELL; 1175ad71ed68SBlue Swirl break; 1176ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL: 1177ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_CRIT: 1178ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_MC: 1179ad71ed68SBlue Swirl /* XXX implement */ 1180ad71ed68SBlue Swirl default: 1181ad71ed68SBlue Swirl break; 1182ad71ed68SBlue Swirl } 1183ad71ed68SBlue Swirl 1184ad71ed68SBlue Swirl return irq; 1185ad71ed68SBlue Swirl } 1186ad71ed68SBlue Swirl 1187e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb) 1188ad71ed68SBlue Swirl { 1189ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1190ad71ed68SBlue Swirl 1191ad71ed68SBlue Swirl if (irq < 0) { 1192ad71ed68SBlue Swirl return; 1193ad71ed68SBlue Swirl } 1194ad71ed68SBlue Swirl 1195ad71ed68SBlue Swirl env->pending_interrupts &= ~(1 << irq); 1196ad71ed68SBlue Swirl } 1197ad71ed68SBlue Swirl 1198ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb) 1199ad71ed68SBlue Swirl { 1200ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1201ad71ed68SBlue Swirl int pir = rb & DBELL_PIRTAG_MASK; 1202182735efSAndreas Färber CPUState *cs; 1203ad71ed68SBlue Swirl 1204ad71ed68SBlue Swirl if (irq < 0) { 1205ad71ed68SBlue Swirl return; 1206ad71ed68SBlue Swirl } 1207ad71ed68SBlue Swirl 1208f1c29ebcSThomas Huth qemu_mutex_lock_iothread(); 1209bdc44640SAndreas Färber CPU_FOREACH(cs) { 1210182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 1211182735efSAndreas Färber CPUPPCState *cenv = &cpu->env; 1212182735efSAndreas Färber 1213ad71ed68SBlue Swirl if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { 1214ad71ed68SBlue Swirl cenv->pending_interrupts |= 1 << irq; 1215182735efSAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 1216ad71ed68SBlue Swirl } 1217ad71ed68SBlue Swirl } 1218f1c29ebcSThomas Huth qemu_mutex_unlock_iothread(); 1219ad71ed68SBlue Swirl } 12207af1e7b0SCédric Le Goater 12217af1e7b0SCédric Le Goater /* Server Processor Control */ 12227af1e7b0SCédric Le Goater static int book3s_dbell2irq(target_ulong rb) 12237af1e7b0SCédric Le Goater { 12247af1e7b0SCédric Le Goater int msg = rb & DBELL_TYPE_MASK; 12257af1e7b0SCédric Le Goater 122647733729SDavid Gibson /* 122747733729SDavid Gibson * A Directed Hypervisor Doorbell message is sent only if the 12287af1e7b0SCédric Le Goater * message type is 5. All other types are reserved and the 122947733729SDavid Gibson * instruction is a no-op 123047733729SDavid Gibson */ 12317af1e7b0SCédric Le Goater return msg == DBELL_TYPE_DBELL_SERVER ? PPC_INTERRUPT_HDOORBELL : -1; 12327af1e7b0SCédric Le Goater } 12337af1e7b0SCédric Le Goater 12347af1e7b0SCédric Le Goater void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) 12357af1e7b0SCédric Le Goater { 12367af1e7b0SCédric Le Goater int irq = book3s_dbell2irq(rb); 12377af1e7b0SCédric Le Goater 12387af1e7b0SCédric Le Goater if (irq < 0) { 12397af1e7b0SCédric Le Goater return; 12407af1e7b0SCédric Le Goater } 12417af1e7b0SCédric Le Goater 12427af1e7b0SCédric Le Goater env->pending_interrupts &= ~(1 << irq); 12437af1e7b0SCédric Le Goater } 12447af1e7b0SCédric Le Goater 12457af1e7b0SCédric Le Goater void helper_book3s_msgsnd(target_ulong rb) 12467af1e7b0SCédric Le Goater { 12477af1e7b0SCédric Le Goater int irq = book3s_dbell2irq(rb); 12487af1e7b0SCédric Le Goater int pir = rb & DBELL_PROCIDTAG_MASK; 12497af1e7b0SCédric Le Goater CPUState *cs; 12507af1e7b0SCédric Le Goater 12517af1e7b0SCédric Le Goater if (irq < 0) { 12527af1e7b0SCédric Le Goater return; 12537af1e7b0SCédric Le Goater } 12547af1e7b0SCédric Le Goater 12557af1e7b0SCédric Le Goater qemu_mutex_lock_iothread(); 12567af1e7b0SCédric Le Goater CPU_FOREACH(cs) { 12577af1e7b0SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 12587af1e7b0SCédric Le Goater CPUPPCState *cenv = &cpu->env; 12597af1e7b0SCédric Le Goater 12607af1e7b0SCédric Le Goater /* TODO: broadcast message to all threads of the same processor */ 12617af1e7b0SCédric Le Goater if (cenv->spr_cb[SPR_PIR].default_value == pir) { 12627af1e7b0SCédric Le Goater cenv->pending_interrupts |= 1 << irq; 12637af1e7b0SCédric Le Goater cpu_interrupt(cs, CPU_INTERRUPT_HARD); 12647af1e7b0SCédric Le Goater } 12657af1e7b0SCédric Le Goater } 12667af1e7b0SCédric Le Goater qemu_mutex_unlock_iothread(); 12677af1e7b0SCédric Le Goater } 1268ad71ed68SBlue Swirl #endif 12690f3110faSRichard Henderson 12700f3110faSRichard Henderson void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, 12710f3110faSRichard Henderson MMUAccessType access_type, 12720f3110faSRichard Henderson int mmu_idx, uintptr_t retaddr) 12730f3110faSRichard Henderson { 12740f3110faSRichard Henderson CPUPPCState *env = cs->env_ptr; 12750f3110faSRichard Henderson uint32_t insn; 12760f3110faSRichard Henderson 12770f3110faSRichard Henderson /* Restore state and reload the insn we executed, for filling in DSISR. */ 12780f3110faSRichard Henderson cpu_restore_state(cs, retaddr, true); 12790f3110faSRichard Henderson insn = cpu_ldl_code(env, env->nip); 12800f3110faSRichard Henderson 12810f3110faSRichard Henderson cs->exception_index = POWERPC_EXCP_ALIGN; 12820f3110faSRichard Henderson env->error_code = insn & 0x03FF0000; 12830f3110faSRichard Henderson cpu_loop_exit(cs); 12840f3110faSRichard Henderson } 1285