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 { 52db70b311SRichard 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) { 115*bc5fdfc0SFabiano Rosas case AIL_NONE: 116*bc5fdfc0SFabiano Rosas break; 1172586a4d7SFabiano Rosas case AIL_0001_8000: 1182586a4d7SFabiano Rosas offset = 0x18000; 1192586a4d7SFabiano Rosas break; 1202586a4d7SFabiano Rosas case AIL_C000_0000_0000_4000: 1212586a4d7SFabiano Rosas offset = 0xc000000000004000ull; 1222586a4d7SFabiano Rosas break; 1232586a4d7SFabiano Rosas default: 1242586a4d7SFabiano Rosas cpu_abort(cs, "Invalid AIL combination %d\n", ail); 1252586a4d7SFabiano Rosas break; 1262586a4d7SFabiano Rosas } 1272586a4d7SFabiano Rosas 1282586a4d7SFabiano Rosas return offset; 1292586a4d7SFabiano Rosas } 130dead760bSBenjamin Herrenschmidt 13147733729SDavid Gibson /* 13247733729SDavid Gibson * Note that this function should be greatly optimized when called 13347733729SDavid Gibson * with a constant excp, from ppc_hw_interrupt 134c79c73f6SBlue Swirl */ 1355c26a5b3SAndreas Färber static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) 136c79c73f6SBlue Swirl { 13727103424SAndreas Färber CPUState *cs = CPU(cpu); 1385c26a5b3SAndreas Färber CPUPPCState *env = &cpu->env; 139c79c73f6SBlue Swirl target_ulong msr, new_msr, vector; 1406d49d6d4SBenjamin Herrenschmidt int srr0, srr1, asrr0, asrr1, lev, ail; 1416d49d6d4SBenjamin Herrenschmidt bool lpes0; 142c79c73f6SBlue Swirl 143c79c73f6SBlue Swirl qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx 144c79c73f6SBlue Swirl " => %08x (%02x)\n", env->nip, excp, env->error_code); 145c79c73f6SBlue Swirl 146c79c73f6SBlue Swirl /* new srr1 value excluding must-be-zero bits */ 147a1bb7384SScott Wood if (excp_model == POWERPC_EXCP_BOOKE) { 148a1bb7384SScott Wood msr = env->msr; 149a1bb7384SScott Wood } else { 150c79c73f6SBlue Swirl msr = env->msr & ~0x783f0000ULL; 151a1bb7384SScott Wood } 152c79c73f6SBlue Swirl 15347733729SDavid Gibson /* 15447733729SDavid Gibson * new interrupt handler msr preserves existing HV and ME unless 1556d49d6d4SBenjamin Herrenschmidt * explicitly overriden 1566d49d6d4SBenjamin Herrenschmidt */ 1576d49d6d4SBenjamin Herrenschmidt new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB); 158c79c73f6SBlue Swirl 159c79c73f6SBlue Swirl /* target registers */ 160c79c73f6SBlue Swirl srr0 = SPR_SRR0; 161c79c73f6SBlue Swirl srr1 = SPR_SRR1; 162c79c73f6SBlue Swirl asrr0 = -1; 163c79c73f6SBlue Swirl asrr1 = -1; 164c79c73f6SBlue Swirl 16521c0d66aSBenjamin Herrenschmidt /* 16621c0d66aSBenjamin Herrenschmidt * check for special resume at 0x100 from doze/nap/sleep/winkle on 16721c0d66aSBenjamin Herrenschmidt * P7/P8/P9 16821c0d66aSBenjamin Herrenschmidt */ 1691e7fd61dSBenjamin Herrenschmidt if (env->resume_as_sreset) { 170dead760bSBenjamin Herrenschmidt excp = powerpc_reset_wakeup(cs, env, excp, &msr); 1717778a575SBenjamin Herrenschmidt } 1727778a575SBenjamin Herrenschmidt 17347733729SDavid Gibson /* 17447733729SDavid Gibson * Exception targetting modifiers 1755c94b2a5SCédric Le Goater * 176a790e82bSBenjamin Herrenschmidt * LPES0 is supported on POWER7/8/9 1776d49d6d4SBenjamin Herrenschmidt * LPES1 is not supported (old iSeries mode) 1786d49d6d4SBenjamin Herrenschmidt * 1796d49d6d4SBenjamin Herrenschmidt * On anything else, we behave as if LPES0 is 1 1806d49d6d4SBenjamin Herrenschmidt * (externals don't alter MSR:HV) 1816d49d6d4SBenjamin Herrenschmidt * 1825c94b2a5SCédric Le Goater * AIL is initialized here but can be cleared by 1835c94b2a5SCédric Le Goater * selected exceptions 1845c94b2a5SCédric Le Goater */ 1855c94b2a5SCédric Le Goater #if defined(TARGET_PPC64) 1865c94b2a5SCédric Le Goater if (excp_model == POWERPC_EXCP_POWER7 || 187a790e82bSBenjamin Herrenschmidt excp_model == POWERPC_EXCP_POWER8 || 188a790e82bSBenjamin Herrenschmidt excp_model == POWERPC_EXCP_POWER9) { 1896d49d6d4SBenjamin Herrenschmidt lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 190a790e82bSBenjamin Herrenschmidt if (excp_model != POWERPC_EXCP_POWER7) { 1915c94b2a5SCédric Le Goater ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT; 1925c94b2a5SCédric Le Goater } else { 1935c94b2a5SCédric Le Goater ail = 0; 1945c94b2a5SCédric Le Goater } 1955c94b2a5SCédric Le Goater } else 1965c94b2a5SCédric Le Goater #endif /* defined(TARGET_PPC64) */ 1975c94b2a5SCédric Le Goater { 1986d49d6d4SBenjamin Herrenschmidt lpes0 = true; 1995c94b2a5SCédric Le Goater ail = 0; 2005c94b2a5SCédric Le Goater } 2015c94b2a5SCédric Le Goater 20247733729SDavid Gibson /* 20347733729SDavid Gibson * Hypervisor emulation assistance interrupt only exists on server 2049b2faddaSBenjamin Herrenschmidt * arch 2.05 server or later. We also don't want to generate it if 2059b2faddaSBenjamin Herrenschmidt * we don't have HVB in msr_mask (PAPR mode). 2069b2faddaSBenjamin Herrenschmidt */ 2079b2faddaSBenjamin Herrenschmidt if (excp == POWERPC_EXCP_HV_EMU 2089b2faddaSBenjamin Herrenschmidt #if defined(TARGET_PPC64) 2099b2faddaSBenjamin Herrenschmidt && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB)) 2109b2faddaSBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 2119b2faddaSBenjamin Herrenschmidt 2129b2faddaSBenjamin Herrenschmidt ) { 2139b2faddaSBenjamin Herrenschmidt excp = POWERPC_EXCP_PROGRAM; 2149b2faddaSBenjamin Herrenschmidt } 2159b2faddaSBenjamin Herrenschmidt 216c79c73f6SBlue Swirl switch (excp) { 217c79c73f6SBlue Swirl case POWERPC_EXCP_NONE: 218c79c73f6SBlue Swirl /* Should never happen */ 219c79c73f6SBlue Swirl return; 220c79c73f6SBlue Swirl case POWERPC_EXCP_CRITICAL: /* Critical input */ 221c79c73f6SBlue Swirl switch (excp_model) { 222c79c73f6SBlue Swirl case POWERPC_EXCP_40x: 223c79c73f6SBlue Swirl srr0 = SPR_40x_SRR2; 224c79c73f6SBlue Swirl srr1 = SPR_40x_SRR3; 225c79c73f6SBlue Swirl break; 226c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 227c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 228c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 229c79c73f6SBlue Swirl break; 230c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 231c79c73f6SBlue Swirl break; 232c79c73f6SBlue Swirl default: 233c79c73f6SBlue Swirl goto excp_invalid; 234c79c73f6SBlue Swirl } 235bd6fefe7SBenjamin Herrenschmidt break; 236c79c73f6SBlue Swirl case POWERPC_EXCP_MCHECK: /* Machine check exception */ 237c79c73f6SBlue Swirl if (msr_me == 0) { 23847733729SDavid Gibson /* 23947733729SDavid Gibson * Machine check exception is not enabled. Enter 24047733729SDavid Gibson * checkstop state. 241c79c73f6SBlue Swirl */ 242c79c73f6SBlue Swirl fprintf(stderr, "Machine check while not allowed. " 243c79c73f6SBlue Swirl "Entering checkstop state\n"); 244013a2942SPaolo Bonzini if (qemu_log_separate()) { 245013a2942SPaolo Bonzini qemu_log("Machine check while not allowed. " 246013a2942SPaolo Bonzini "Entering checkstop state\n"); 247c79c73f6SBlue Swirl } 248259186a7SAndreas Färber cs->halted = 1; 249044897efSRichard Purdie cpu_interrupt_exittb(cs); 250c79c73f6SBlue Swirl } 25110c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 25247733729SDavid Gibson /* 25347733729SDavid Gibson * ISA specifies HV, but can be delivered to guest with HV 25447733729SDavid Gibson * clear (e.g., see FWNMI in PAPR). 25510c21b5cSNicholas Piggin */ 256c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 25710c21b5cSNicholas Piggin } 2585c94b2a5SCédric Le Goater ail = 0; 259c79c73f6SBlue Swirl 260c79c73f6SBlue Swirl /* machine check exceptions don't have ME set */ 261c79c73f6SBlue Swirl new_msr &= ~((target_ulong)1 << MSR_ME); 262c79c73f6SBlue Swirl 263c79c73f6SBlue Swirl /* XXX: should also have something loaded in DAR / DSISR */ 264c79c73f6SBlue Swirl switch (excp_model) { 265c79c73f6SBlue Swirl case POWERPC_EXCP_40x: 266c79c73f6SBlue Swirl srr0 = SPR_40x_SRR2; 267c79c73f6SBlue Swirl srr1 = SPR_40x_SRR3; 268c79c73f6SBlue Swirl break; 269c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 270a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 271c79c73f6SBlue Swirl srr0 = SPR_BOOKE_MCSRR0; 272c79c73f6SBlue Swirl srr1 = SPR_BOOKE_MCSRR1; 273c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 274c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 275c79c73f6SBlue Swirl break; 276c79c73f6SBlue Swirl default: 277c79c73f6SBlue Swirl break; 278c79c73f6SBlue Swirl } 279bd6fefe7SBenjamin Herrenschmidt break; 280c79c73f6SBlue Swirl case POWERPC_EXCP_DSI: /* Data storage exception */ 281c79c73f6SBlue Swirl LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx 282c79c73f6SBlue Swirl "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); 283bd6fefe7SBenjamin Herrenschmidt break; 284c79c73f6SBlue Swirl case POWERPC_EXCP_ISI: /* Instruction storage exception */ 285c79c73f6SBlue Swirl LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx 286c79c73f6SBlue Swirl "\n", msr, env->nip); 287c79c73f6SBlue Swirl msr |= env->error_code; 288bd6fefe7SBenjamin Herrenschmidt break; 289c79c73f6SBlue Swirl case POWERPC_EXCP_EXTERNAL: /* External input */ 290fdfba1a2SEdgar E. Iglesias cs = CPU(cpu); 291fdfba1a2SEdgar E. Iglesias 2926d49d6d4SBenjamin Herrenschmidt if (!lpes0) { 293c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 2946d49d6d4SBenjamin Herrenschmidt new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 2956d49d6d4SBenjamin Herrenschmidt srr0 = SPR_HSRR0; 2966d49d6d4SBenjamin Herrenschmidt srr1 = SPR_HSRR1; 297c79c73f6SBlue Swirl } 29868c2dd70SAlexander Graf if (env->mpic_proxy) { 29968c2dd70SAlexander Graf /* IACK the IRQ on delivery */ 300fdfba1a2SEdgar E. Iglesias env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack); 30168c2dd70SAlexander Graf } 302bd6fefe7SBenjamin Herrenschmidt break; 303c79c73f6SBlue Swirl case POWERPC_EXCP_ALIGN: /* Alignment exception */ 304c79c73f6SBlue Swirl /* Get rS/rD and rA from faulting opcode */ 30547733729SDavid Gibson /* 30647733729SDavid Gibson * Note: the opcode fields will not be set properly for a 30747733729SDavid Gibson * direct store load/store, but nobody cares as nobody 30847733729SDavid Gibson * actually uses direct store segments. 3093433b732SBenjamin Herrenschmidt */ 3103433b732SBenjamin Herrenschmidt env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; 311bd6fefe7SBenjamin Herrenschmidt break; 312c79c73f6SBlue Swirl case POWERPC_EXCP_PROGRAM: /* Program exception */ 313c79c73f6SBlue Swirl switch (env->error_code & ~0xF) { 314c79c73f6SBlue Swirl case POWERPC_EXCP_FP: 315c79c73f6SBlue Swirl if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { 316c79c73f6SBlue Swirl LOG_EXCP("Ignore floating point exception\n"); 31727103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 318c79c73f6SBlue Swirl env->error_code = 0; 319c79c73f6SBlue Swirl return; 320c79c73f6SBlue Swirl } 3211b7d17caSBenjamin Herrenschmidt 32247733729SDavid Gibson /* 32347733729SDavid Gibson * FP exceptions always have NIP pointing to the faulting 3241b7d17caSBenjamin Herrenschmidt * instruction, so always use store_next and claim we are 3251b7d17caSBenjamin Herrenschmidt * precise in the MSR. 3261b7d17caSBenjamin Herrenschmidt */ 327c79c73f6SBlue Swirl msr |= 0x00100000; 3280ee604abSAaron Larson env->spr[SPR_BOOKE_ESR] = ESR_FP; 329bd6fefe7SBenjamin Herrenschmidt break; 330c79c73f6SBlue Swirl case POWERPC_EXCP_INVAL: 331c79c73f6SBlue Swirl LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); 332c79c73f6SBlue Swirl msr |= 0x00080000; 333c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PIL; 334c79c73f6SBlue Swirl break; 335c79c73f6SBlue Swirl case POWERPC_EXCP_PRIV: 336c79c73f6SBlue Swirl msr |= 0x00040000; 337c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PPR; 338c79c73f6SBlue Swirl break; 339c79c73f6SBlue Swirl case POWERPC_EXCP_TRAP: 340c79c73f6SBlue Swirl msr |= 0x00020000; 341c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PTR; 342c79c73f6SBlue Swirl break; 343c79c73f6SBlue Swirl default: 344c79c73f6SBlue Swirl /* Should never occur */ 345a47dddd7SAndreas Färber cpu_abort(cs, "Invalid program exception %d. Aborting\n", 346c79c73f6SBlue Swirl env->error_code); 347c79c73f6SBlue Swirl break; 348c79c73f6SBlue Swirl } 349bd6fefe7SBenjamin Herrenschmidt break; 350c79c73f6SBlue Swirl case POWERPC_EXCP_SYSCALL: /* System call exception */ 351c79c73f6SBlue Swirl dump_syscall(env); 352c79c73f6SBlue Swirl lev = env->error_code; 3536d49d6d4SBenjamin Herrenschmidt 35447733729SDavid Gibson /* 35547733729SDavid Gibson * We need to correct the NIP which in this case is supposed 356bd6fefe7SBenjamin Herrenschmidt * to point to the next instruction 357bd6fefe7SBenjamin Herrenschmidt */ 358bd6fefe7SBenjamin Herrenschmidt env->nip += 4; 359bd6fefe7SBenjamin Herrenschmidt 3606d49d6d4SBenjamin Herrenschmidt /* "PAPR mode" built-in hypercall emulation */ 3611d1be34dSDavid Gibson if ((lev == 1) && cpu->vhyp) { 3621d1be34dSDavid Gibson PPCVirtualHypervisorClass *vhc = 3631d1be34dSDavid Gibson PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); 3641d1be34dSDavid Gibson vhc->hypercall(cpu->vhyp, cpu); 365c79c73f6SBlue Swirl return; 366c79c73f6SBlue Swirl } 3676d49d6d4SBenjamin Herrenschmidt if (lev == 1) { 368c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 369c79c73f6SBlue Swirl } 370bd6fefe7SBenjamin Herrenschmidt break; 371bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 372c79c73f6SBlue Swirl case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ 373c79c73f6SBlue Swirl case POWERPC_EXCP_DECR: /* Decrementer exception */ 374bd6fefe7SBenjamin Herrenschmidt break; 375c79c73f6SBlue Swirl case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ 376c79c73f6SBlue Swirl /* FIT on 4xx */ 377c79c73f6SBlue Swirl LOG_EXCP("FIT exception\n"); 378bd6fefe7SBenjamin Herrenschmidt break; 379c79c73f6SBlue Swirl case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ 380c79c73f6SBlue Swirl LOG_EXCP("WDT exception\n"); 381c79c73f6SBlue Swirl switch (excp_model) { 382c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 383c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 384c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 385c79c73f6SBlue Swirl break; 386c79c73f6SBlue Swirl default: 387c79c73f6SBlue Swirl break; 388c79c73f6SBlue Swirl } 389bd6fefe7SBenjamin Herrenschmidt break; 390c79c73f6SBlue Swirl case POWERPC_EXCP_DTLB: /* Data TLB error */ 391c79c73f6SBlue Swirl case POWERPC_EXCP_ITLB: /* Instruction TLB error */ 392bd6fefe7SBenjamin Herrenschmidt break; 393c79c73f6SBlue Swirl case POWERPC_EXCP_DEBUG: /* Debug interrupt */ 3940e3bf489SRoman Kapl if (env->flags & POWERPC_FLAG_DE) { 395a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 396c79c73f6SBlue Swirl srr0 = SPR_BOOKE_DSRR0; 397c79c73f6SBlue Swirl srr1 = SPR_BOOKE_DSRR1; 398c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 399c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 4000e3bf489SRoman Kapl /* DBSR already modified by caller */ 4010e3bf489SRoman Kapl } else { 4020e3bf489SRoman Kapl cpu_abort(cs, "Debug exception triggered on unsupported model\n"); 403c79c73f6SBlue Swirl } 404bd6fefe7SBenjamin Herrenschmidt break; 405c79c73f6SBlue Swirl case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ 406c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 407bd6fefe7SBenjamin Herrenschmidt break; 408c79c73f6SBlue Swirl case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ 409c79c73f6SBlue Swirl /* XXX: TODO */ 410a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point data exception " 411c79c73f6SBlue Swirl "is not implemented yet !\n"); 412c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 413bd6fefe7SBenjamin Herrenschmidt break; 414c79c73f6SBlue Swirl case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ 415c79c73f6SBlue Swirl /* XXX: TODO */ 416a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point round exception " 417c79c73f6SBlue Swirl "is not implemented yet !\n"); 418c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 419bd6fefe7SBenjamin Herrenschmidt break; 420c79c73f6SBlue Swirl case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ 421c79c73f6SBlue Swirl /* XXX: TODO */ 422a47dddd7SAndreas Färber cpu_abort(cs, 423c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 424bd6fefe7SBenjamin Herrenschmidt break; 425c79c73f6SBlue Swirl case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ 426bd6fefe7SBenjamin Herrenschmidt break; 427c79c73f6SBlue Swirl case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ 428c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 429c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 430bd6fefe7SBenjamin Herrenschmidt break; 431c79c73f6SBlue Swirl case POWERPC_EXCP_RESET: /* System reset exception */ 432f85bcec3SNicholas Piggin /* A power-saving exception sets ME, otherwise it is unchanged */ 433c79c73f6SBlue Swirl if (msr_pow) { 434c79c73f6SBlue Swirl /* indicate that we resumed from power save mode */ 435c79c73f6SBlue Swirl msr |= 0x10000; 436f85bcec3SNicholas Piggin new_msr |= ((target_ulong)1 << MSR_ME); 437c79c73f6SBlue Swirl } 43810c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 43947733729SDavid Gibson /* 44047733729SDavid Gibson * ISA specifies HV, but can be delivered to guest with HV 44147733729SDavid Gibson * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU). 44210c21b5cSNicholas Piggin */ 443c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 44410c21b5cSNicholas Piggin } else { 44510c21b5cSNicholas Piggin if (msr_pow) { 44610c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver power-saving system reset " 44710c21b5cSNicholas Piggin "exception %d with no HV support\n", excp); 44810c21b5cSNicholas Piggin } 44910c21b5cSNicholas Piggin } 4505c94b2a5SCédric Le Goater ail = 0; 451bd6fefe7SBenjamin Herrenschmidt break; 452c79c73f6SBlue Swirl case POWERPC_EXCP_DSEG: /* Data segment exception */ 453c79c73f6SBlue Swirl case POWERPC_EXCP_ISEG: /* Instruction segment exception */ 454c79c73f6SBlue Swirl case POWERPC_EXCP_TRACE: /* Trace exception */ 455bd6fefe7SBenjamin Herrenschmidt break; 456bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ 457c79c73f6SBlue Swirl case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ 458c79c73f6SBlue Swirl case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ 459c79c73f6SBlue Swirl case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ 460c79c73f6SBlue Swirl case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ 4617af1e7b0SCédric Le Goater case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ 462bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HV_EMU: 463d8ce5fd6SBenjamin Herrenschmidt case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */ 464c79c73f6SBlue Swirl srr0 = SPR_HSRR0; 465c79c73f6SBlue Swirl srr1 = SPR_HSRR1; 466c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 467c79c73f6SBlue Swirl new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 468bd6fefe7SBenjamin Herrenschmidt break; 469c79c73f6SBlue Swirl case POWERPC_EXCP_VPU: /* Vector unavailable exception */ 4701f29871cSTom Musta case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ 4717019cb3dSAlexey Kardashevskiy case POWERPC_EXCP_FU: /* Facility unavailable exception */ 4725310799aSBalbir Singh #ifdef TARGET_PPC64 4735310799aSBalbir Singh env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56); 4745310799aSBalbir Singh #endif 475bd6fefe7SBenjamin Herrenschmidt break; 476c79c73f6SBlue Swirl case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ 477c79c73f6SBlue Swirl LOG_EXCP("PIT exception\n"); 478bd6fefe7SBenjamin Herrenschmidt break; 479c79c73f6SBlue Swirl case POWERPC_EXCP_IO: /* IO error exception */ 480c79c73f6SBlue Swirl /* XXX: TODO */ 481a47dddd7SAndreas Färber cpu_abort(cs, "601 IO error exception is not implemented yet !\n"); 482bd6fefe7SBenjamin Herrenschmidt break; 483c79c73f6SBlue Swirl case POWERPC_EXCP_RUNM: /* Run mode exception */ 484c79c73f6SBlue Swirl /* XXX: TODO */ 485a47dddd7SAndreas Färber cpu_abort(cs, "601 run mode exception is not implemented yet !\n"); 486bd6fefe7SBenjamin Herrenschmidt break; 487c79c73f6SBlue Swirl case POWERPC_EXCP_EMUL: /* Emulation trap exception */ 488c79c73f6SBlue Swirl /* XXX: TODO */ 489a47dddd7SAndreas Färber cpu_abort(cs, "602 emulation trap exception " 490c79c73f6SBlue Swirl "is not implemented yet !\n"); 491bd6fefe7SBenjamin Herrenschmidt break; 492c79c73f6SBlue Swirl case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ 493c79c73f6SBlue Swirl switch (excp_model) { 494c79c73f6SBlue Swirl case POWERPC_EXCP_602: 495c79c73f6SBlue Swirl case POWERPC_EXCP_603: 496c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 497c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 498c79c73f6SBlue Swirl goto tlb_miss_tgpr; 499c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 500c79c73f6SBlue Swirl goto tlb_miss; 501c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 502c79c73f6SBlue Swirl goto tlb_miss_74xx; 503c79c73f6SBlue Swirl default: 504a47dddd7SAndreas Färber cpu_abort(cs, "Invalid instruction TLB miss exception\n"); 505c79c73f6SBlue Swirl break; 506c79c73f6SBlue Swirl } 507c79c73f6SBlue Swirl break; 508c79c73f6SBlue Swirl case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ 509c79c73f6SBlue Swirl switch (excp_model) { 510c79c73f6SBlue Swirl case POWERPC_EXCP_602: 511c79c73f6SBlue Swirl case POWERPC_EXCP_603: 512c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 513c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 514c79c73f6SBlue Swirl goto tlb_miss_tgpr; 515c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 516c79c73f6SBlue Swirl goto tlb_miss; 517c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 518c79c73f6SBlue Swirl goto tlb_miss_74xx; 519c79c73f6SBlue Swirl default: 520a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data load TLB miss exception\n"); 521c79c73f6SBlue Swirl break; 522c79c73f6SBlue Swirl } 523c79c73f6SBlue Swirl break; 524c79c73f6SBlue Swirl case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ 525c79c73f6SBlue Swirl switch (excp_model) { 526c79c73f6SBlue Swirl case POWERPC_EXCP_602: 527c79c73f6SBlue Swirl case POWERPC_EXCP_603: 528c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 529c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 530c79c73f6SBlue Swirl tlb_miss_tgpr: 531c79c73f6SBlue Swirl /* Swap temporary saved registers with GPRs */ 532c79c73f6SBlue Swirl if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { 533c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_TGPR; 534c79c73f6SBlue Swirl hreg_swap_gpr_tgpr(env); 535c79c73f6SBlue Swirl } 536c79c73f6SBlue Swirl goto tlb_miss; 537c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 538c79c73f6SBlue Swirl tlb_miss: 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_IMISS]; 549c79c73f6SBlue Swirl cmp = &env->spr[SPR_ICMP]; 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_DMISS]; 558c79c73f6SBlue Swirl cmp = &env->spr[SPR_DCMP]; 559c79c73f6SBlue Swirl } 560c79c73f6SBlue Swirl qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 561c79c73f6SBlue Swirl TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " 562c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 563c79c73f6SBlue Swirl env->spr[SPR_HASH1], env->spr[SPR_HASH2], 564c79c73f6SBlue Swirl env->error_code); 565c79c73f6SBlue Swirl } 566c79c73f6SBlue Swirl #endif 567c79c73f6SBlue Swirl msr |= env->crf[0] << 28; 568c79c73f6SBlue Swirl msr |= env->error_code; /* key, D/I, S/L bits */ 569c79c73f6SBlue Swirl /* Set way using a LRU mechanism */ 570c79c73f6SBlue Swirl msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; 571c79c73f6SBlue Swirl break; 572c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 573c79c73f6SBlue Swirl tlb_miss_74xx: 574c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 575c79c73f6SBlue Swirl if (qemu_log_enabled()) { 576c79c73f6SBlue Swirl const char *es; 577c79c73f6SBlue Swirl target_ulong *miss, *cmp; 578c79c73f6SBlue Swirl int en; 579c79c73f6SBlue Swirl 580c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 581c79c73f6SBlue Swirl es = "I"; 582c79c73f6SBlue Swirl en = 'I'; 583c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 584c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 585c79c73f6SBlue Swirl } else { 586c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 587c79c73f6SBlue Swirl es = "DL"; 588c79c73f6SBlue Swirl } else { 589c79c73f6SBlue Swirl es = "DS"; 590c79c73f6SBlue Swirl } 591c79c73f6SBlue Swirl en = 'D'; 592c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 593c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 594c79c73f6SBlue Swirl } 595c79c73f6SBlue Swirl qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 596c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 597c79c73f6SBlue Swirl env->error_code); 598c79c73f6SBlue Swirl } 599c79c73f6SBlue Swirl #endif 600c79c73f6SBlue Swirl msr |= env->error_code; /* key bit */ 601c79c73f6SBlue Swirl break; 602c79c73f6SBlue Swirl default: 603a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data store TLB miss exception\n"); 604c79c73f6SBlue Swirl break; 605c79c73f6SBlue Swirl } 606bd6fefe7SBenjamin Herrenschmidt break; 607c79c73f6SBlue Swirl case POWERPC_EXCP_FPA: /* Floating-point assist exception */ 608c79c73f6SBlue Swirl /* XXX: TODO */ 609a47dddd7SAndreas Färber cpu_abort(cs, "Floating point assist exception " 610c79c73f6SBlue Swirl "is not implemented yet !\n"); 611bd6fefe7SBenjamin Herrenschmidt break; 612c79c73f6SBlue Swirl case POWERPC_EXCP_DABR: /* Data address breakpoint */ 613c79c73f6SBlue Swirl /* XXX: TODO */ 614a47dddd7SAndreas Färber cpu_abort(cs, "DABR exception is not implemented yet !\n"); 615bd6fefe7SBenjamin Herrenschmidt break; 616c79c73f6SBlue Swirl case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ 617c79c73f6SBlue Swirl /* XXX: TODO */ 618a47dddd7SAndreas Färber cpu_abort(cs, "IABR exception is not implemented yet !\n"); 619bd6fefe7SBenjamin Herrenschmidt break; 620c79c73f6SBlue Swirl case POWERPC_EXCP_SMI: /* System management interrupt */ 621c79c73f6SBlue Swirl /* XXX: TODO */ 622a47dddd7SAndreas Färber cpu_abort(cs, "SMI exception is not implemented yet !\n"); 623bd6fefe7SBenjamin Herrenschmidt break; 624c79c73f6SBlue Swirl case POWERPC_EXCP_THERM: /* Thermal interrupt */ 625c79c73f6SBlue Swirl /* XXX: TODO */ 626a47dddd7SAndreas Färber cpu_abort(cs, "Thermal management exception " 627c79c73f6SBlue Swirl "is not implemented yet !\n"); 628bd6fefe7SBenjamin Herrenschmidt break; 629c79c73f6SBlue Swirl case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ 630c79c73f6SBlue Swirl /* XXX: TODO */ 631a47dddd7SAndreas Färber cpu_abort(cs, 632c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 633bd6fefe7SBenjamin Herrenschmidt break; 634c79c73f6SBlue Swirl case POWERPC_EXCP_VPUA: /* Vector assist exception */ 635c79c73f6SBlue Swirl /* XXX: TODO */ 636a47dddd7SAndreas Färber cpu_abort(cs, "VPU assist exception is not implemented yet !\n"); 637bd6fefe7SBenjamin Herrenschmidt break; 638c79c73f6SBlue Swirl case POWERPC_EXCP_SOFTP: /* Soft patch exception */ 639c79c73f6SBlue Swirl /* XXX: TODO */ 640a47dddd7SAndreas Färber cpu_abort(cs, 641c79c73f6SBlue Swirl "970 soft-patch exception is not implemented yet !\n"); 642bd6fefe7SBenjamin Herrenschmidt break; 643c79c73f6SBlue Swirl case POWERPC_EXCP_MAINT: /* Maintenance exception */ 644c79c73f6SBlue Swirl /* XXX: TODO */ 645a47dddd7SAndreas Färber cpu_abort(cs, 646c79c73f6SBlue Swirl "970 maintenance exception is not implemented yet !\n"); 647bd6fefe7SBenjamin Herrenschmidt break; 648c79c73f6SBlue Swirl case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ 649c79c73f6SBlue Swirl /* XXX: TODO */ 650a47dddd7SAndreas Färber cpu_abort(cs, "Maskable external exception " 651c79c73f6SBlue Swirl "is not implemented yet !\n"); 652bd6fefe7SBenjamin Herrenschmidt break; 653c79c73f6SBlue Swirl case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ 654c79c73f6SBlue Swirl /* XXX: TODO */ 655a47dddd7SAndreas Färber cpu_abort(cs, "Non maskable external exception " 656c79c73f6SBlue Swirl "is not implemented yet !\n"); 657bd6fefe7SBenjamin Herrenschmidt break; 658c79c73f6SBlue Swirl default: 659c79c73f6SBlue Swirl excp_invalid: 660a47dddd7SAndreas Färber cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 661c79c73f6SBlue Swirl break; 662c79c73f6SBlue Swirl } 663bd6fefe7SBenjamin Herrenschmidt 664bd6fefe7SBenjamin Herrenschmidt /* Save PC */ 665bd6fefe7SBenjamin Herrenschmidt env->spr[srr0] = env->nip; 666bd6fefe7SBenjamin Herrenschmidt 667c79c73f6SBlue Swirl /* Save MSR */ 668c79c73f6SBlue Swirl env->spr[srr1] = msr; 6696d49d6d4SBenjamin Herrenschmidt 6706d49d6d4SBenjamin Herrenschmidt /* Sanity check */ 67110c21b5cSNicholas Piggin if (!(env->msr_mask & MSR_HVB)) { 67210c21b5cSNicholas Piggin if (new_msr & MSR_HVB) { 67310c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with " 6746d49d6d4SBenjamin Herrenschmidt "no HV support\n", excp); 6756d49d6d4SBenjamin Herrenschmidt } 67610c21b5cSNicholas Piggin if (srr0 == SPR_HSRR0) { 67710c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with " 67810c21b5cSNicholas Piggin "no HV support\n", excp); 67910c21b5cSNicholas Piggin } 68010c21b5cSNicholas Piggin } 6816d49d6d4SBenjamin Herrenschmidt 682c79c73f6SBlue Swirl /* If any alternate SRR register are defined, duplicate saved values */ 683c79c73f6SBlue Swirl if (asrr0 != -1) { 684c79c73f6SBlue Swirl env->spr[asrr0] = env->spr[srr0]; 685c79c73f6SBlue Swirl } 686c79c73f6SBlue Swirl if (asrr1 != -1) { 687c79c73f6SBlue Swirl env->spr[asrr1] = env->spr[srr1]; 688c79c73f6SBlue Swirl } 689d5ac4f54SAlexey Kardashevskiy 69047733729SDavid Gibson /* 69147733729SDavid Gibson * Sort out endianness of interrupt, this differs depending on the 6926d49d6d4SBenjamin Herrenschmidt * CPU, the HV mode, etc... 6936d49d6d4SBenjamin Herrenschmidt */ 6941e0c7e55SAnton Blanchard #ifdef TARGET_PPC64 6956d49d6d4SBenjamin Herrenschmidt if (excp_model == POWERPC_EXCP_POWER7) { 6966d49d6d4SBenjamin Herrenschmidt if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) { 6976d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 6986d49d6d4SBenjamin Herrenschmidt } 6996d49d6d4SBenjamin Herrenschmidt } else if (excp_model == POWERPC_EXCP_POWER8) { 7006d49d6d4SBenjamin Herrenschmidt if (new_msr & MSR_HVB) { 701a790e82bSBenjamin Herrenschmidt if (env->spr[SPR_HID0] & HID0_HILE) { 702a790e82bSBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 703a790e82bSBenjamin Herrenschmidt } 704a790e82bSBenjamin Herrenschmidt } else if (env->spr[SPR_LPCR] & LPCR_ILE) { 705a790e82bSBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 706a790e82bSBenjamin Herrenschmidt } 707a790e82bSBenjamin Herrenschmidt } else if (excp_model == POWERPC_EXCP_POWER9) { 708a790e82bSBenjamin Herrenschmidt if (new_msr & MSR_HVB) { 709a790e82bSBenjamin Herrenschmidt if (env->spr[SPR_HID0] & HID0_POWER9_HILE) { 7106d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 7116d49d6d4SBenjamin Herrenschmidt } 7126d49d6d4SBenjamin Herrenschmidt } else if (env->spr[SPR_LPCR] & LPCR_ILE) { 7131e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 7141e0c7e55SAnton Blanchard } 7151e0c7e55SAnton Blanchard } else if (msr_ile) { 7161e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 7171e0c7e55SAnton Blanchard } 7181e0c7e55SAnton Blanchard #else 719c79c73f6SBlue Swirl if (msr_ile) { 720c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_LE; 721c79c73f6SBlue Swirl } 7221e0c7e55SAnton Blanchard #endif 723c79c73f6SBlue Swirl 724c79c73f6SBlue Swirl /* Jump to handler */ 725c79c73f6SBlue Swirl vector = env->excp_vectors[excp]; 726c79c73f6SBlue Swirl if (vector == (target_ulong)-1ULL) { 727a47dddd7SAndreas Färber cpu_abort(cs, "Raised an exception without defined vector %d\n", 728c79c73f6SBlue Swirl excp); 729c79c73f6SBlue Swirl } 730c79c73f6SBlue Swirl vector |= env->excp_prefix; 7315c94b2a5SCédric Le Goater 73247733729SDavid Gibson /* 73347733729SDavid Gibson * AIL only works if there is no HV transition and we are running 73447733729SDavid Gibson * with translations enabled 7355c94b2a5SCédric Le Goater */ 7366d49d6d4SBenjamin Herrenschmidt if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) || 7376d49d6d4SBenjamin Herrenschmidt ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) { 7385c94b2a5SCédric Le Goater ail = 0; 7395c94b2a5SCédric Le Goater } 7405c94b2a5SCédric Le Goater /* Handle AIL */ 7415c94b2a5SCédric Le Goater if (ail) { 7425c94b2a5SCédric Le Goater new_msr |= (1 << MSR_IR) | (1 << MSR_DR); 7432586a4d7SFabiano Rosas vector |= ppc_excp_vector_offset(cs, ail); 7445c94b2a5SCédric Le Goater } 7455c94b2a5SCédric Le Goater 746c79c73f6SBlue Swirl #if defined(TARGET_PPC64) 747c79c73f6SBlue Swirl if (excp_model == POWERPC_EXCP_BOOKE) { 748e42a61f1SAlexander Graf if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) { 749e42a61f1SAlexander Graf /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */ 750c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_CM; 751e42a61f1SAlexander Graf } else { 752e42a61f1SAlexander Graf vector = (uint32_t)vector; 753c79c73f6SBlue Swirl } 754c79c73f6SBlue Swirl } else { 755c79c73f6SBlue Swirl if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) { 756c79c73f6SBlue Swirl vector = (uint32_t)vector; 757c79c73f6SBlue Swirl } else { 758c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_SF; 759c79c73f6SBlue Swirl } 760c79c73f6SBlue Swirl } 761c79c73f6SBlue Swirl #endif 76247733729SDavid Gibson /* 76347733729SDavid Gibson * We don't use hreg_store_msr here as already have treated any 76447733729SDavid Gibson * special case that could occur. Just store MSR and update hflags 7651c953ba5SBenjamin Herrenschmidt * 7661c953ba5SBenjamin Herrenschmidt * Note: We *MUST* not use hreg_store_msr() as-is anyway because it 7671c953ba5SBenjamin Herrenschmidt * will prevent setting of the HV bit which some exceptions might need 7681c953ba5SBenjamin Herrenschmidt * to do. 769c79c73f6SBlue Swirl */ 770c79c73f6SBlue Swirl env->msr = new_msr & env->msr_mask; 771c79c73f6SBlue Swirl hreg_compute_hflags(env); 772c79c73f6SBlue Swirl env->nip = vector; 773c79c73f6SBlue Swirl /* Reset exception state */ 77427103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 775c79c73f6SBlue Swirl env->error_code = 0; 776cd0c6f47SBenjamin Herrenschmidt 777139d9023SNikunj A Dadhania /* Reset the reservation */ 778139d9023SNikunj A Dadhania env->reserve_addr = -1; 779139d9023SNikunj A Dadhania 78047733729SDavid Gibson /* 78147733729SDavid Gibson * Any interrupt is context synchronizing, check if TCG TLB needs 78247733729SDavid Gibson * a delayed flush on ppc64 783cd0c6f47SBenjamin Herrenschmidt */ 784e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 785c79c73f6SBlue Swirl } 786c79c73f6SBlue Swirl 78797a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs) 788c79c73f6SBlue Swirl { 78997a8ea5aSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 79097a8ea5aSAndreas Färber CPUPPCState *env = &cpu->env; 7915c26a5b3SAndreas Färber 79227103424SAndreas Färber powerpc_excp(cpu, env->excp_model, cs->exception_index); 793c79c73f6SBlue Swirl } 794c79c73f6SBlue Swirl 795458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env) 796c79c73f6SBlue Swirl { 797db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 7983621e2c9SBenjamin Herrenschmidt bool async_deliver; 799259186a7SAndreas Färber 800c79c73f6SBlue Swirl /* External reset */ 801c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { 802c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); 8035c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 804c79c73f6SBlue Swirl return; 805c79c73f6SBlue Swirl } 806c79c73f6SBlue Swirl /* Machine check exception */ 807c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { 808c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); 8095c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK); 810c79c73f6SBlue Swirl return; 811c79c73f6SBlue Swirl } 812c79c73f6SBlue Swirl #if 0 /* TODO */ 813c79c73f6SBlue Swirl /* External debug exception */ 814c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { 815c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); 8165c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG); 817c79c73f6SBlue Swirl return; 818c79c73f6SBlue Swirl } 819c79c73f6SBlue Swirl #endif 8203621e2c9SBenjamin Herrenschmidt 8213621e2c9SBenjamin Herrenschmidt /* 8223621e2c9SBenjamin Herrenschmidt * For interrupts that gate on MSR:EE, we need to do something a 8233621e2c9SBenjamin Herrenschmidt * bit more subtle, as we need to let them through even when EE is 8243621e2c9SBenjamin Herrenschmidt * clear when coming out of some power management states (in order 8253621e2c9SBenjamin Herrenschmidt * for them to become a 0x100). 8263621e2c9SBenjamin Herrenschmidt */ 8271e7fd61dSBenjamin Herrenschmidt async_deliver = (msr_ee != 0) || env->resume_as_sreset; 8283621e2c9SBenjamin Herrenschmidt 829c79c73f6SBlue Swirl /* Hypervisor decrementer exception */ 830c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { 8314b236b62SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 8324b236b62SBenjamin Herrenschmidt bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); 8333621e2c9SBenjamin Herrenschmidt if ((async_deliver || msr_hv == 0) && hdice) { 8344b236b62SBenjamin Herrenschmidt /* HDEC clears on delivery */ 8354b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 8365c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR); 837c79c73f6SBlue Swirl return; 838c79c73f6SBlue Swirl } 839c79c73f6SBlue Swirl } 840d8ce5fd6SBenjamin Herrenschmidt 841d8ce5fd6SBenjamin Herrenschmidt /* Hypervisor virtualization interrupt */ 842d8ce5fd6SBenjamin Herrenschmidt if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) { 843d8ce5fd6SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 844d8ce5fd6SBenjamin Herrenschmidt bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); 845d8ce5fd6SBenjamin Herrenschmidt if ((async_deliver || msr_hv == 0) && hvice) { 846d8ce5fd6SBenjamin Herrenschmidt powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT); 847d8ce5fd6SBenjamin Herrenschmidt return; 848d8ce5fd6SBenjamin Herrenschmidt } 849d8ce5fd6SBenjamin Herrenschmidt } 850d8ce5fd6SBenjamin Herrenschmidt 851d8ce5fd6SBenjamin Herrenschmidt /* External interrupt can ignore MSR:EE under some circumstances */ 852d1dbe37cSBenjamin Herrenschmidt if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { 853d1dbe37cSBenjamin Herrenschmidt bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 8546eebe6dcSBenjamin Herrenschmidt bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); 8556eebe6dcSBenjamin Herrenschmidt /* HEIC blocks delivery to the hypervisor */ 8566eebe6dcSBenjamin Herrenschmidt if ((async_deliver && !(heic && msr_hv && !msr_pr)) || 8576eebe6dcSBenjamin Herrenschmidt (env->has_hv_mode && msr_hv == 0 && !lpes0)) { 858d1dbe37cSBenjamin Herrenschmidt powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL); 859d1dbe37cSBenjamin Herrenschmidt return; 860d1dbe37cSBenjamin Herrenschmidt } 861d1dbe37cSBenjamin Herrenschmidt } 862c79c73f6SBlue Swirl if (msr_ce != 0) { 863c79c73f6SBlue Swirl /* External critical interrupt */ 864c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { 8655c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL); 866c79c73f6SBlue Swirl return; 867c79c73f6SBlue Swirl } 868c79c73f6SBlue Swirl } 8693621e2c9SBenjamin Herrenschmidt if (async_deliver != 0) { 870c79c73f6SBlue Swirl /* Watchdog timer on embedded PowerPC */ 871c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { 872c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); 8735c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT); 874c79c73f6SBlue Swirl return; 875c79c73f6SBlue Swirl } 876c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { 877c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); 8785c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI); 879c79c73f6SBlue Swirl return; 880c79c73f6SBlue Swirl } 881c79c73f6SBlue Swirl /* Fixed interval timer on embedded PowerPC */ 882c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { 883c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); 8845c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT); 885c79c73f6SBlue Swirl return; 886c79c73f6SBlue Swirl } 887c79c73f6SBlue Swirl /* Programmable interval timer on embedded PowerPC */ 888c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { 889c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); 8905c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT); 891c79c73f6SBlue Swirl return; 892c79c73f6SBlue Swirl } 893c79c73f6SBlue Swirl /* Decrementer exception */ 894c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { 895e81a982aSAlexander Graf if (ppc_decr_clear_on_delivery(env)) { 896c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); 897e81a982aSAlexander Graf } 8985c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR); 899c79c73f6SBlue Swirl return; 900c79c73f6SBlue Swirl } 901c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { 902c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); 9035c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI); 904c79c73f6SBlue Swirl return; 905c79c73f6SBlue Swirl } 9067af1e7b0SCédric Le Goater if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) { 9077af1e7b0SCédric Le Goater env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL); 9087af1e7b0SCédric Le Goater powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV); 9097af1e7b0SCédric Le Goater return; 9107af1e7b0SCédric Le Goater } 911c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { 912c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); 9135c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM); 914c79c73f6SBlue Swirl return; 915c79c73f6SBlue Swirl } 916c79c73f6SBlue Swirl /* Thermal interrupt */ 917c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { 918c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); 9195c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM); 920c79c73f6SBlue Swirl return; 921c79c73f6SBlue Swirl } 922c79c73f6SBlue Swirl } 923f8154fd2SBenjamin Herrenschmidt 924f8154fd2SBenjamin Herrenschmidt if (env->resume_as_sreset) { 925f8154fd2SBenjamin Herrenschmidt /* 926f8154fd2SBenjamin Herrenschmidt * This is a bug ! It means that has_work took us out of halt without 927f8154fd2SBenjamin Herrenschmidt * anything to deliver while in a PM state that requires getting 928f8154fd2SBenjamin Herrenschmidt * out via a 0x100 929f8154fd2SBenjamin Herrenschmidt * 930f8154fd2SBenjamin Herrenschmidt * This means we will incorrectly execute past the power management 931f8154fd2SBenjamin Herrenschmidt * instruction instead of triggering a reset. 932f8154fd2SBenjamin Herrenschmidt * 933f8154fd2SBenjamin Herrenschmidt * It generally means a discrepancy between the wakup conditions in the 934f8154fd2SBenjamin Herrenschmidt * processor has_work implementation and the logic in this function. 935f8154fd2SBenjamin Herrenschmidt */ 936db70b311SRichard Henderson cpu_abort(env_cpu(env), 937f8154fd2SBenjamin Herrenschmidt "Wakeup from PM state but interrupt Undelivered"); 938f8154fd2SBenjamin Herrenschmidt } 939c79c73f6SBlue Swirl } 94034316482SAlexey Kardashevskiy 94134316482SAlexey Kardashevskiy void ppc_cpu_do_system_reset(CPUState *cs) 94234316482SAlexey Kardashevskiy { 94334316482SAlexey Kardashevskiy PowerPCCPU *cpu = POWERPC_CPU(cs); 94434316482SAlexey Kardashevskiy CPUPPCState *env = &cpu->env; 94534316482SAlexey Kardashevskiy 94634316482SAlexey Kardashevskiy powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 94734316482SAlexey Kardashevskiy } 948c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */ 949c79c73f6SBlue Swirl 950458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 951458dd766SRichard Henderson { 952458dd766SRichard Henderson PowerPCCPU *cpu = POWERPC_CPU(cs); 953458dd766SRichard Henderson CPUPPCState *env = &cpu->env; 954458dd766SRichard Henderson 955458dd766SRichard Henderson if (interrupt_request & CPU_INTERRUPT_HARD) { 956458dd766SRichard Henderson ppc_hw_interrupt(env); 957458dd766SRichard Henderson if (env->pending_interrupts == 0) { 958458dd766SRichard Henderson cs->interrupt_request &= ~CPU_INTERRUPT_HARD; 959458dd766SRichard Henderson } 960458dd766SRichard Henderson return true; 961458dd766SRichard Henderson } 962458dd766SRichard Henderson return false; 963458dd766SRichard Henderson } 964458dd766SRichard Henderson 965c79c73f6SBlue Swirl #if defined(DEBUG_OP) 966c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr) 967c79c73f6SBlue Swirl { 968c79c73f6SBlue Swirl qemu_log("Return from exception at " TARGET_FMT_lx " with flags " 969c79c73f6SBlue Swirl TARGET_FMT_lx "\n", RA, msr); 970c79c73f6SBlue Swirl } 971c79c73f6SBlue Swirl #endif 972c79c73f6SBlue Swirl 973ad71ed68SBlue Swirl /*****************************************************************************/ 974ad71ed68SBlue Swirl /* Exceptions processing helpers */ 975ad71ed68SBlue Swirl 976db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, 977db789c6cSBenjamin Herrenschmidt uint32_t error_code, uintptr_t raddr) 978ad71ed68SBlue Swirl { 979db70b311SRichard Henderson CPUState *cs = env_cpu(env); 98027103424SAndreas Färber 98127103424SAndreas Färber cs->exception_index = exception; 982ad71ed68SBlue Swirl env->error_code = error_code; 983db789c6cSBenjamin Herrenschmidt cpu_loop_exit_restore(cs, raddr); 984db789c6cSBenjamin Herrenschmidt } 985db789c6cSBenjamin Herrenschmidt 986db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception, 987db789c6cSBenjamin Herrenschmidt uint32_t error_code) 988db789c6cSBenjamin Herrenschmidt { 989db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 990db789c6cSBenjamin Herrenschmidt } 991db789c6cSBenjamin Herrenschmidt 992db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception) 993db789c6cSBenjamin Herrenschmidt { 994db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 995db789c6cSBenjamin Herrenschmidt } 996db789c6cSBenjamin Herrenschmidt 997db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception, 998db789c6cSBenjamin Herrenschmidt uintptr_t raddr) 999db789c6cSBenjamin Herrenschmidt { 1000db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, raddr); 1001db789c6cSBenjamin Herrenschmidt } 1002db789c6cSBenjamin Herrenschmidt 1003db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, 1004db789c6cSBenjamin Herrenschmidt uint32_t error_code) 1005db789c6cSBenjamin Herrenschmidt { 1006db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 1007ad71ed68SBlue Swirl } 1008ad71ed68SBlue Swirl 1009e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception) 1010ad71ed68SBlue Swirl { 1011db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 1012ad71ed68SBlue Swirl } 1013ad71ed68SBlue Swirl 1014ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 1015e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val) 1016ad71ed68SBlue Swirl { 1017db789c6cSBenjamin Herrenschmidt uint32_t excp = hreg_store_msr(env, val, 0); 1018259186a7SAndreas Färber 1019db789c6cSBenjamin Herrenschmidt if (excp != 0) { 1020db70b311SRichard Henderson CPUState *cs = env_cpu(env); 1021044897efSRichard Purdie cpu_interrupt_exittb(cs); 1022db789c6cSBenjamin Herrenschmidt raise_exception(env, excp); 1023ad71ed68SBlue Swirl } 1024ad71ed68SBlue Swirl } 1025ad71ed68SBlue Swirl 10267778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64) 10277778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) 10287778a575SBenjamin Herrenschmidt { 10297778a575SBenjamin Herrenschmidt CPUState *cs; 10307778a575SBenjamin Herrenschmidt 1031db70b311SRichard Henderson cs = env_cpu(env); 10327778a575SBenjamin Herrenschmidt cs->halted = 1; 10337778a575SBenjamin Herrenschmidt 103447733729SDavid Gibson /* 103547733729SDavid Gibson * The architecture specifies that HDEC interrupts are discarded 103647733729SDavid Gibson * in PM states 10374b236b62SBenjamin Herrenschmidt */ 10384b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 10394b236b62SBenjamin Herrenschmidt 10403621e2c9SBenjamin Herrenschmidt /* Condition for waking up at 0x100 */ 10411e7fd61dSBenjamin Herrenschmidt env->resume_as_sreset = (insn != PPC_PM_STOP) || 104221c0d66aSBenjamin Herrenschmidt (env->spr[SPR_PSSCR] & PSSCR_EC); 10437778a575SBenjamin Herrenschmidt } 10447778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 10457778a575SBenjamin Herrenschmidt 1046a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) 1047ad71ed68SBlue Swirl { 1048db70b311SRichard Henderson CPUState *cs = env_cpu(env); 1049259186a7SAndreas Färber 1050a2e71b28SBenjamin Herrenschmidt /* MSR:POW cannot be set by any form of rfi */ 1051a2e71b28SBenjamin Herrenschmidt msr &= ~(1ULL << MSR_POW); 1052a2e71b28SBenjamin Herrenschmidt 1053ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1054a2e71b28SBenjamin Herrenschmidt /* Switching to 32-bit ? Crop the nip */ 1055a2e71b28SBenjamin Herrenschmidt if (!msr_is_64bit(env, msr)) { 1056ad71ed68SBlue Swirl nip = (uint32_t)nip; 1057ad71ed68SBlue Swirl } 1058ad71ed68SBlue Swirl #else 1059ad71ed68SBlue Swirl nip = (uint32_t)nip; 1060ad71ed68SBlue Swirl #endif 1061ad71ed68SBlue Swirl /* XXX: beware: this is false if VLE is supported */ 1062ad71ed68SBlue Swirl env->nip = nip & ~((target_ulong)0x00000003); 1063ad71ed68SBlue Swirl hreg_store_msr(env, msr, 1); 1064ad71ed68SBlue Swirl #if defined(DEBUG_OP) 1065ad71ed68SBlue Swirl cpu_dump_rfi(env->nip, env->msr); 1066ad71ed68SBlue Swirl #endif 106747733729SDavid Gibson /* 106847733729SDavid Gibson * No need to raise an exception here, as rfi is always the last 106947733729SDavid Gibson * insn of a TB 1070ad71ed68SBlue Swirl */ 1071044897efSRichard Purdie cpu_interrupt_exittb(cs); 1072a8b73734SNikunj A Dadhania /* Reset the reservation */ 1073a8b73734SNikunj A Dadhania env->reserve_addr = -1; 1074a8b73734SNikunj A Dadhania 1075cd0c6f47SBenjamin Herrenschmidt /* Context synchronizing: check if TCG TLB needs flush */ 1076e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 1077ad71ed68SBlue Swirl } 1078ad71ed68SBlue Swirl 1079e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env) 1080ad71ed68SBlue Swirl { 1081a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); 1082a1bb7384SScott Wood } 1083ad71ed68SBlue Swirl 1084a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK 1085ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1086e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env) 1087ad71ed68SBlue Swirl { 108847733729SDavid Gibson /* 108947733729SDavid Gibson * The architeture defines a number of rules for which bits can 109047733729SDavid Gibson * change but in practice, we handle this in hreg_store_msr() 1091a2e71b28SBenjamin Herrenschmidt * which will be called by do_rfi(), so there is no need to filter 1092a2e71b28SBenjamin Herrenschmidt * here 1093a2e71b28SBenjamin Herrenschmidt */ 1094a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]); 1095ad71ed68SBlue Swirl } 1096ad71ed68SBlue Swirl 1097e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env) 1098ad71ed68SBlue Swirl { 1099a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); 1100ad71ed68SBlue Swirl } 1101ad71ed68SBlue Swirl #endif 1102ad71ed68SBlue Swirl 1103ad71ed68SBlue Swirl /*****************************************************************************/ 1104ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */ 1105e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env) 1106ad71ed68SBlue Swirl { 1107a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]); 1108ad71ed68SBlue Swirl } 1109ad71ed68SBlue Swirl 1110e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env) 1111ad71ed68SBlue Swirl { 1112a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]); 1113ad71ed68SBlue Swirl } 1114ad71ed68SBlue Swirl 1115e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env) 1116ad71ed68SBlue Swirl { 1117a1bb7384SScott Wood /* FIXME: choose CSRR1 or DSRR1 based on cpu type */ 1118a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]); 1119ad71ed68SBlue Swirl } 1120ad71ed68SBlue Swirl 1121e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env) 1122ad71ed68SBlue Swirl { 1123a1bb7384SScott Wood /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ 1124a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); 1125ad71ed68SBlue Swirl } 1126ad71ed68SBlue Swirl #endif 1127ad71ed68SBlue Swirl 1128e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1129e5f17ac6SBlue Swirl uint32_t flags) 1130ad71ed68SBlue Swirl { 1131ad71ed68SBlue Swirl if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || 1132ad71ed68SBlue Swirl ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) || 1133ad71ed68SBlue Swirl ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || 1134ad71ed68SBlue Swirl ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || 1135ad71ed68SBlue Swirl ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { 113672073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 113772073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1138ad71ed68SBlue Swirl } 1139ad71ed68SBlue Swirl } 1140ad71ed68SBlue Swirl 1141ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1142e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1143e5f17ac6SBlue Swirl uint32_t flags) 1144ad71ed68SBlue Swirl { 1145ad71ed68SBlue Swirl if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || 1146ad71ed68SBlue Swirl ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) || 1147ad71ed68SBlue Swirl ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || 1148ad71ed68SBlue Swirl ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || 1149ad71ed68SBlue Swirl ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { 115072073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 115172073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1152ad71ed68SBlue Swirl } 1153ad71ed68SBlue Swirl } 1154ad71ed68SBlue Swirl #endif 1155ad71ed68SBlue Swirl 1156ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 1157ad71ed68SBlue Swirl /*****************************************************************************/ 1158ad71ed68SBlue Swirl /* PowerPC 601 specific instructions (POWER bridge) */ 1159ad71ed68SBlue Swirl 1160e5f17ac6SBlue Swirl void helper_rfsvc(CPUPPCState *env) 1161ad71ed68SBlue Swirl { 1162a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->lr, env->ctr & 0x0000FFFF); 1163ad71ed68SBlue Swirl } 1164ad71ed68SBlue Swirl 1165ad71ed68SBlue Swirl /* Embedded.Processor Control */ 1166ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb) 1167ad71ed68SBlue Swirl { 1168ad71ed68SBlue Swirl int msg = rb & DBELL_TYPE_MASK; 1169ad71ed68SBlue Swirl int irq = -1; 1170ad71ed68SBlue Swirl 1171ad71ed68SBlue Swirl switch (msg) { 1172ad71ed68SBlue Swirl case DBELL_TYPE_DBELL: 1173ad71ed68SBlue Swirl irq = PPC_INTERRUPT_DOORBELL; 1174ad71ed68SBlue Swirl break; 1175ad71ed68SBlue Swirl case DBELL_TYPE_DBELL_CRIT: 1176ad71ed68SBlue Swirl irq = PPC_INTERRUPT_CDOORBELL; 1177ad71ed68SBlue Swirl break; 1178ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL: 1179ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_CRIT: 1180ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_MC: 1181ad71ed68SBlue Swirl /* XXX implement */ 1182ad71ed68SBlue Swirl default: 1183ad71ed68SBlue Swirl break; 1184ad71ed68SBlue Swirl } 1185ad71ed68SBlue Swirl 1186ad71ed68SBlue Swirl return irq; 1187ad71ed68SBlue Swirl } 1188ad71ed68SBlue Swirl 1189e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb) 1190ad71ed68SBlue Swirl { 1191ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1192ad71ed68SBlue Swirl 1193ad71ed68SBlue Swirl if (irq < 0) { 1194ad71ed68SBlue Swirl return; 1195ad71ed68SBlue Swirl } 1196ad71ed68SBlue Swirl 1197ad71ed68SBlue Swirl env->pending_interrupts &= ~(1 << irq); 1198ad71ed68SBlue Swirl } 1199ad71ed68SBlue Swirl 1200ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb) 1201ad71ed68SBlue Swirl { 1202ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1203ad71ed68SBlue Swirl int pir = rb & DBELL_PIRTAG_MASK; 1204182735efSAndreas Färber CPUState *cs; 1205ad71ed68SBlue Swirl 1206ad71ed68SBlue Swirl if (irq < 0) { 1207ad71ed68SBlue Swirl return; 1208ad71ed68SBlue Swirl } 1209ad71ed68SBlue Swirl 1210f1c29ebcSThomas Huth qemu_mutex_lock_iothread(); 1211bdc44640SAndreas Färber CPU_FOREACH(cs) { 1212182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 1213182735efSAndreas Färber CPUPPCState *cenv = &cpu->env; 1214182735efSAndreas Färber 1215ad71ed68SBlue Swirl if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { 1216ad71ed68SBlue Swirl cenv->pending_interrupts |= 1 << irq; 1217182735efSAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 1218ad71ed68SBlue Swirl } 1219ad71ed68SBlue Swirl } 1220f1c29ebcSThomas Huth qemu_mutex_unlock_iothread(); 1221ad71ed68SBlue Swirl } 12227af1e7b0SCédric Le Goater 12237af1e7b0SCédric Le Goater /* Server Processor Control */ 12247af1e7b0SCédric Le Goater static int book3s_dbell2irq(target_ulong rb) 12257af1e7b0SCédric Le Goater { 12267af1e7b0SCédric Le Goater int msg = rb & DBELL_TYPE_MASK; 12277af1e7b0SCédric Le Goater 122847733729SDavid Gibson /* 122947733729SDavid Gibson * A Directed Hypervisor Doorbell message is sent only if the 12307af1e7b0SCédric Le Goater * message type is 5. All other types are reserved and the 123147733729SDavid Gibson * instruction is a no-op 123247733729SDavid Gibson */ 12337af1e7b0SCédric Le Goater return msg == DBELL_TYPE_DBELL_SERVER ? PPC_INTERRUPT_HDOORBELL : -1; 12347af1e7b0SCédric Le Goater } 12357af1e7b0SCédric Le Goater 12367af1e7b0SCédric Le Goater void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) 12377af1e7b0SCédric Le Goater { 12387af1e7b0SCédric Le Goater int irq = book3s_dbell2irq(rb); 12397af1e7b0SCédric Le Goater 12407af1e7b0SCédric Le Goater if (irq < 0) { 12417af1e7b0SCédric Le Goater return; 12427af1e7b0SCédric Le Goater } 12437af1e7b0SCédric Le Goater 12447af1e7b0SCédric Le Goater env->pending_interrupts &= ~(1 << irq); 12457af1e7b0SCédric Le Goater } 12467af1e7b0SCédric Le Goater 12477af1e7b0SCédric Le Goater void helper_book3s_msgsnd(target_ulong rb) 12487af1e7b0SCédric Le Goater { 12497af1e7b0SCédric Le Goater int irq = book3s_dbell2irq(rb); 12507af1e7b0SCédric Le Goater int pir = rb & DBELL_PROCIDTAG_MASK; 12517af1e7b0SCédric Le Goater CPUState *cs; 12527af1e7b0SCédric Le Goater 12537af1e7b0SCédric Le Goater if (irq < 0) { 12547af1e7b0SCédric Le Goater return; 12557af1e7b0SCédric Le Goater } 12567af1e7b0SCédric Le Goater 12577af1e7b0SCédric Le Goater qemu_mutex_lock_iothread(); 12587af1e7b0SCédric Le Goater CPU_FOREACH(cs) { 12597af1e7b0SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 12607af1e7b0SCédric Le Goater CPUPPCState *cenv = &cpu->env; 12617af1e7b0SCédric Le Goater 12627af1e7b0SCédric Le Goater /* TODO: broadcast message to all threads of the same processor */ 12637af1e7b0SCédric Le Goater if (cenv->spr_cb[SPR_PIR].default_value == pir) { 12647af1e7b0SCédric Le Goater cenv->pending_interrupts |= 1 << irq; 12657af1e7b0SCédric Le Goater cpu_interrupt(cs, CPU_INTERRUPT_HARD); 12667af1e7b0SCédric Le Goater } 12677af1e7b0SCédric Le Goater } 12687af1e7b0SCédric Le Goater qemu_mutex_unlock_iothread(); 12697af1e7b0SCédric Le Goater } 1270ad71ed68SBlue Swirl #endif 12710f3110faSRichard Henderson 12720f3110faSRichard Henderson void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, 12730f3110faSRichard Henderson MMUAccessType access_type, 12740f3110faSRichard Henderson int mmu_idx, uintptr_t retaddr) 12750f3110faSRichard Henderson { 12760f3110faSRichard Henderson CPUPPCState *env = cs->env_ptr; 12770f3110faSRichard Henderson uint32_t insn; 12780f3110faSRichard Henderson 12790f3110faSRichard Henderson /* Restore state and reload the insn we executed, for filling in DSISR. */ 12800f3110faSRichard Henderson cpu_restore_state(cs, retaddr, true); 12810f3110faSRichard Henderson insn = cpu_ldl_code(env, env->nip); 12820f3110faSRichard Henderson 12830f3110faSRichard Henderson cs->exception_index = POWERPC_EXCP_ALIGN; 12840f3110faSRichard Henderson env->error_code = insn & 0x03FF0000; 12850f3110faSRichard Henderson cpu_loop_exit(cs); 12860f3110faSRichard Henderson } 1287