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 { 606dc6b557SNicholas Piggin qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 616dc6b557SNicholas Piggin " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64 626dc6b557SNicholas Piggin " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64 63c79c73f6SBlue Swirl " nip=" TARGET_FMT_lx "\n", 64c79c73f6SBlue Swirl ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), 65c79c73f6SBlue Swirl ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), 666dc6b557SNicholas Piggin ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7), 676dc6b557SNicholas Piggin ppc_dump_gpr(env, 8), env->nip); 686dc6b557SNicholas Piggin } 696dc6b557SNicholas Piggin 703c89b8d6SNicholas Piggin static inline void dump_syscall_vectored(CPUPPCState *env) 713c89b8d6SNicholas Piggin { 723c89b8d6SNicholas Piggin qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 733c89b8d6SNicholas Piggin " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64 743c89b8d6SNicholas Piggin " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64 753c89b8d6SNicholas Piggin " nip=" TARGET_FMT_lx "\n", 763c89b8d6SNicholas Piggin ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), 773c89b8d6SNicholas Piggin ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), 783c89b8d6SNicholas Piggin ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7), 793c89b8d6SNicholas Piggin ppc_dump_gpr(env, 8), env->nip); 803c89b8d6SNicholas Piggin } 813c89b8d6SNicholas Piggin 826dc6b557SNicholas Piggin static inline void dump_hcall(CPUPPCState *env) 836dc6b557SNicholas Piggin { 846dc6b557SNicholas Piggin qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64 856dc6b557SNicholas Piggin " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 866dc6b557SNicholas Piggin " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64 876dc6b557SNicholas Piggin " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64 886dc6b557SNicholas Piggin " nip=" TARGET_FMT_lx "\n", 896dc6b557SNicholas Piggin ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4), 906dc6b557SNicholas Piggin ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6), 916dc6b557SNicholas Piggin ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8), 926dc6b557SNicholas Piggin ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10), 936dc6b557SNicholas Piggin ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12), 946dc6b557SNicholas Piggin env->nip); 95c79c73f6SBlue Swirl } 96c79c73f6SBlue Swirl 97dead760bSBenjamin Herrenschmidt static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, 98dead760bSBenjamin Herrenschmidt target_ulong *msr) 99dead760bSBenjamin Herrenschmidt { 100dead760bSBenjamin Herrenschmidt /* We no longer are in a PM state */ 1011e7fd61dSBenjamin Herrenschmidt env->resume_as_sreset = false; 102dead760bSBenjamin Herrenschmidt 103dead760bSBenjamin Herrenschmidt /* Pretend to be returning from doze always as we don't lose state */ 1040911a60cSLeonardo Bras *msr |= SRR1_WS_NOLOSS; 105dead760bSBenjamin Herrenschmidt 106dead760bSBenjamin Herrenschmidt /* Machine checks are sent normally */ 107dead760bSBenjamin Herrenschmidt if (excp == POWERPC_EXCP_MCHECK) { 108dead760bSBenjamin Herrenschmidt return excp; 109dead760bSBenjamin Herrenschmidt } 110dead760bSBenjamin Herrenschmidt switch (excp) { 111dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_RESET: 1120911a60cSLeonardo Bras *msr |= SRR1_WAKERESET; 113dead760bSBenjamin Herrenschmidt break; 114dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_EXTERNAL: 1150911a60cSLeonardo Bras *msr |= SRR1_WAKEEE; 116dead760bSBenjamin Herrenschmidt break; 117dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_DECR: 1180911a60cSLeonardo Bras *msr |= SRR1_WAKEDEC; 119dead760bSBenjamin Herrenschmidt break; 120dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_SDOOR: 1210911a60cSLeonardo Bras *msr |= SRR1_WAKEDBELL; 122dead760bSBenjamin Herrenschmidt break; 123dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_SDOOR_HV: 1240911a60cSLeonardo Bras *msr |= SRR1_WAKEHDBELL; 125dead760bSBenjamin Herrenschmidt break; 126dead760bSBenjamin Herrenschmidt case POWERPC_EXCP_HV_MAINT: 1270911a60cSLeonardo Bras *msr |= SRR1_WAKEHMI; 128dead760bSBenjamin Herrenschmidt break; 129d8ce5fd6SBenjamin Herrenschmidt case POWERPC_EXCP_HVIRT: 1300911a60cSLeonardo Bras *msr |= SRR1_WAKEHVI; 131d8ce5fd6SBenjamin Herrenschmidt break; 132dead760bSBenjamin Herrenschmidt default: 133dead760bSBenjamin Herrenschmidt cpu_abort(cs, "Unsupported exception %d in Power Save mode\n", 134dead760bSBenjamin Herrenschmidt excp); 135dead760bSBenjamin Herrenschmidt } 136dead760bSBenjamin Herrenschmidt return POWERPC_EXCP_RESET; 137dead760bSBenjamin Herrenschmidt } 138dead760bSBenjamin Herrenschmidt 1392586a4d7SFabiano Rosas static uint64_t ppc_excp_vector_offset(CPUState *cs, int ail) 1402586a4d7SFabiano Rosas { 1412586a4d7SFabiano Rosas uint64_t offset = 0; 1422586a4d7SFabiano Rosas 1432586a4d7SFabiano Rosas switch (ail) { 144bc5fdfc0SFabiano Rosas case AIL_NONE: 145bc5fdfc0SFabiano Rosas break; 1462586a4d7SFabiano Rosas case AIL_0001_8000: 1472586a4d7SFabiano Rosas offset = 0x18000; 1482586a4d7SFabiano Rosas break; 1492586a4d7SFabiano Rosas case AIL_C000_0000_0000_4000: 1502586a4d7SFabiano Rosas offset = 0xc000000000004000ull; 1512586a4d7SFabiano Rosas break; 1522586a4d7SFabiano Rosas default: 1532586a4d7SFabiano Rosas cpu_abort(cs, "Invalid AIL combination %d\n", ail); 1542586a4d7SFabiano Rosas break; 1552586a4d7SFabiano Rosas } 1562586a4d7SFabiano Rosas 1572586a4d7SFabiano Rosas return offset; 1582586a4d7SFabiano Rosas } 159dead760bSBenjamin Herrenschmidt 160ad77c6caSNicholas Piggin static inline void powerpc_set_excp_state(PowerPCCPU *cpu, 161ad77c6caSNicholas Piggin target_ulong vector, target_ulong msr) 162ad77c6caSNicholas Piggin { 163ad77c6caSNicholas Piggin CPUState *cs = CPU(cpu); 164ad77c6caSNicholas Piggin CPUPPCState *env = &cpu->env; 165ad77c6caSNicholas Piggin 166ad77c6caSNicholas Piggin /* 167ad77c6caSNicholas Piggin * We don't use hreg_store_msr here as already have treated any 168ad77c6caSNicholas Piggin * special case that could occur. Just store MSR and update hflags 169ad77c6caSNicholas Piggin * 170ad77c6caSNicholas Piggin * Note: We *MUST* not use hreg_store_msr() as-is anyway because it 171ad77c6caSNicholas Piggin * will prevent setting of the HV bit which some exceptions might need 172ad77c6caSNicholas Piggin * to do. 173ad77c6caSNicholas Piggin */ 174ad77c6caSNicholas Piggin env->msr = msr & env->msr_mask; 175ad77c6caSNicholas Piggin hreg_compute_hflags(env); 176ad77c6caSNicholas Piggin env->nip = vector; 177ad77c6caSNicholas Piggin /* Reset exception state */ 178ad77c6caSNicholas Piggin cs->exception_index = POWERPC_EXCP_NONE; 179ad77c6caSNicholas Piggin env->error_code = 0; 180ad77c6caSNicholas Piggin 181ad77c6caSNicholas Piggin /* Reset the reservation */ 182ad77c6caSNicholas Piggin env->reserve_addr = -1; 183ad77c6caSNicholas Piggin 184ad77c6caSNicholas Piggin /* 185ad77c6caSNicholas Piggin * Any interrupt is context synchronizing, check if TCG TLB needs 186ad77c6caSNicholas Piggin * a delayed flush on ppc64 187ad77c6caSNicholas Piggin */ 188ad77c6caSNicholas Piggin check_tlb_flush(env, false); 189ad77c6caSNicholas Piggin } 190ad77c6caSNicholas Piggin 19147733729SDavid Gibson /* 19247733729SDavid Gibson * Note that this function should be greatly optimized when called 19347733729SDavid Gibson * with a constant excp, from ppc_hw_interrupt 194c79c73f6SBlue Swirl */ 1955c26a5b3SAndreas Färber static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) 196c79c73f6SBlue Swirl { 19727103424SAndreas Färber CPUState *cs = CPU(cpu); 1985c26a5b3SAndreas Färber CPUPPCState *env = &cpu->env; 199c79c73f6SBlue Swirl target_ulong msr, new_msr, vector; 2003c89b8d6SNicholas Piggin int srr0, srr1, asrr0, asrr1, lev = -1, ail; 2016d49d6d4SBenjamin Herrenschmidt bool lpes0; 202c79c73f6SBlue Swirl 203c79c73f6SBlue Swirl qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx 204c79c73f6SBlue Swirl " => %08x (%02x)\n", env->nip, excp, env->error_code); 205c79c73f6SBlue Swirl 206c79c73f6SBlue Swirl /* new srr1 value excluding must-be-zero bits */ 207a1bb7384SScott Wood if (excp_model == POWERPC_EXCP_BOOKE) { 208a1bb7384SScott Wood msr = env->msr; 209a1bb7384SScott Wood } else { 210c79c73f6SBlue Swirl msr = env->msr & ~0x783f0000ULL; 211a1bb7384SScott Wood } 212c79c73f6SBlue Swirl 21347733729SDavid Gibson /* 21447733729SDavid Gibson * new interrupt handler msr preserves existing HV and ME unless 2156d49d6d4SBenjamin Herrenschmidt * explicitly overriden 2166d49d6d4SBenjamin Herrenschmidt */ 2176d49d6d4SBenjamin Herrenschmidt new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB); 218c79c73f6SBlue Swirl 219c79c73f6SBlue Swirl /* target registers */ 220c79c73f6SBlue Swirl srr0 = SPR_SRR0; 221c79c73f6SBlue Swirl srr1 = SPR_SRR1; 222c79c73f6SBlue Swirl asrr0 = -1; 223c79c73f6SBlue Swirl asrr1 = -1; 224c79c73f6SBlue Swirl 22521c0d66aSBenjamin Herrenschmidt /* 22621c0d66aSBenjamin Herrenschmidt * check for special resume at 0x100 from doze/nap/sleep/winkle on 22721c0d66aSBenjamin Herrenschmidt * P7/P8/P9 22821c0d66aSBenjamin Herrenschmidt */ 2291e7fd61dSBenjamin Herrenschmidt if (env->resume_as_sreset) { 230dead760bSBenjamin Herrenschmidt excp = powerpc_reset_wakeup(cs, env, excp, &msr); 2317778a575SBenjamin Herrenschmidt } 2327778a575SBenjamin Herrenschmidt 23347733729SDavid Gibson /* 234136fbf65Szhaolichang * Exception targeting modifiers 2355c94b2a5SCédric Le Goater * 236a790e82bSBenjamin Herrenschmidt * LPES0 is supported on POWER7/8/9 2376d49d6d4SBenjamin Herrenschmidt * LPES1 is not supported (old iSeries mode) 2386d49d6d4SBenjamin Herrenschmidt * 2396d49d6d4SBenjamin Herrenschmidt * On anything else, we behave as if LPES0 is 1 2406d49d6d4SBenjamin Herrenschmidt * (externals don't alter MSR:HV) 2416d49d6d4SBenjamin Herrenschmidt * 2425c94b2a5SCédric Le Goater * AIL is initialized here but can be cleared by 2435c94b2a5SCédric Le Goater * selected exceptions 2445c94b2a5SCédric Le Goater */ 2455c94b2a5SCédric Le Goater #if defined(TARGET_PPC64) 2465c94b2a5SCédric Le Goater if (excp_model == POWERPC_EXCP_POWER7 || 247a790e82bSBenjamin Herrenschmidt excp_model == POWERPC_EXCP_POWER8 || 248a790e82bSBenjamin Herrenschmidt excp_model == POWERPC_EXCP_POWER9) { 2496d49d6d4SBenjamin Herrenschmidt lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 250a790e82bSBenjamin Herrenschmidt if (excp_model != POWERPC_EXCP_POWER7) { 2515c94b2a5SCédric Le Goater ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT; 2525c94b2a5SCédric Le Goater } else { 2535c94b2a5SCédric Le Goater ail = 0; 2545c94b2a5SCédric Le Goater } 2555c94b2a5SCédric Le Goater } else 2565c94b2a5SCédric Le Goater #endif /* defined(TARGET_PPC64) */ 2575c94b2a5SCédric Le Goater { 2586d49d6d4SBenjamin Herrenschmidt lpes0 = true; 2595c94b2a5SCédric Le Goater ail = 0; 2605c94b2a5SCédric Le Goater } 2615c94b2a5SCédric Le Goater 26247733729SDavid Gibson /* 26347733729SDavid Gibson * Hypervisor emulation assistance interrupt only exists on server 2649b2faddaSBenjamin Herrenschmidt * arch 2.05 server or later. We also don't want to generate it if 2659b2faddaSBenjamin Herrenschmidt * we don't have HVB in msr_mask (PAPR mode). 2669b2faddaSBenjamin Herrenschmidt */ 2679b2faddaSBenjamin Herrenschmidt if (excp == POWERPC_EXCP_HV_EMU 2689b2faddaSBenjamin Herrenschmidt #if defined(TARGET_PPC64) 2699b2faddaSBenjamin Herrenschmidt && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB)) 2709b2faddaSBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 2719b2faddaSBenjamin Herrenschmidt 2729b2faddaSBenjamin Herrenschmidt ) { 2739b2faddaSBenjamin Herrenschmidt excp = POWERPC_EXCP_PROGRAM; 2749b2faddaSBenjamin Herrenschmidt } 2759b2faddaSBenjamin Herrenschmidt 276c79c73f6SBlue Swirl switch (excp) { 277c79c73f6SBlue Swirl case POWERPC_EXCP_NONE: 278c79c73f6SBlue Swirl /* Should never happen */ 279c79c73f6SBlue Swirl return; 280c79c73f6SBlue Swirl case POWERPC_EXCP_CRITICAL: /* Critical input */ 281c79c73f6SBlue Swirl switch (excp_model) { 282c79c73f6SBlue Swirl case POWERPC_EXCP_40x: 283c79c73f6SBlue Swirl srr0 = SPR_40x_SRR2; 284c79c73f6SBlue Swirl srr1 = SPR_40x_SRR3; 285c79c73f6SBlue Swirl break; 286c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 287c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 288c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 289c79c73f6SBlue Swirl break; 290c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 291c79c73f6SBlue Swirl break; 292c79c73f6SBlue Swirl default: 293c79c73f6SBlue Swirl goto excp_invalid; 294c79c73f6SBlue Swirl } 295bd6fefe7SBenjamin Herrenschmidt break; 296c79c73f6SBlue Swirl case POWERPC_EXCP_MCHECK: /* Machine check exception */ 297c79c73f6SBlue Swirl if (msr_me == 0) { 29847733729SDavid Gibson /* 29947733729SDavid Gibson * Machine check exception is not enabled. Enter 30047733729SDavid Gibson * checkstop state. 301c79c73f6SBlue Swirl */ 302c79c73f6SBlue Swirl fprintf(stderr, "Machine check while not allowed. " 303c79c73f6SBlue Swirl "Entering checkstop state\n"); 304013a2942SPaolo Bonzini if (qemu_log_separate()) { 305013a2942SPaolo Bonzini qemu_log("Machine check while not allowed. " 306013a2942SPaolo Bonzini "Entering checkstop state\n"); 307c79c73f6SBlue Swirl } 308259186a7SAndreas Färber cs->halted = 1; 309044897efSRichard Purdie cpu_interrupt_exittb(cs); 310c79c73f6SBlue Swirl } 31110c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 31247733729SDavid Gibson /* 31347733729SDavid Gibson * ISA specifies HV, but can be delivered to guest with HV 31447733729SDavid Gibson * clear (e.g., see FWNMI in PAPR). 31510c21b5cSNicholas Piggin */ 316c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 31710c21b5cSNicholas Piggin } 3185c94b2a5SCédric Le Goater ail = 0; 319c79c73f6SBlue Swirl 320c79c73f6SBlue Swirl /* machine check exceptions don't have ME set */ 321c79c73f6SBlue Swirl new_msr &= ~((target_ulong)1 << MSR_ME); 322c79c73f6SBlue Swirl 323c79c73f6SBlue Swirl /* XXX: should also have something loaded in DAR / DSISR */ 324c79c73f6SBlue Swirl switch (excp_model) { 325c79c73f6SBlue Swirl case POWERPC_EXCP_40x: 326c79c73f6SBlue Swirl srr0 = SPR_40x_SRR2; 327c79c73f6SBlue Swirl srr1 = SPR_40x_SRR3; 328c79c73f6SBlue Swirl break; 329c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 330a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 331c79c73f6SBlue Swirl srr0 = SPR_BOOKE_MCSRR0; 332c79c73f6SBlue Swirl srr1 = SPR_BOOKE_MCSRR1; 333c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 334c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 335c79c73f6SBlue Swirl break; 336c79c73f6SBlue Swirl default: 337c79c73f6SBlue Swirl break; 338c79c73f6SBlue Swirl } 339bd6fefe7SBenjamin Herrenschmidt break; 340c79c73f6SBlue Swirl case POWERPC_EXCP_DSI: /* Data storage exception */ 341c79c73f6SBlue Swirl LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx 342c79c73f6SBlue Swirl "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]); 343bd6fefe7SBenjamin Herrenschmidt break; 344c79c73f6SBlue Swirl case POWERPC_EXCP_ISI: /* Instruction storage exception */ 345c79c73f6SBlue Swirl LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx 346c79c73f6SBlue Swirl "\n", msr, env->nip); 347c79c73f6SBlue Swirl msr |= env->error_code; 348bd6fefe7SBenjamin Herrenschmidt break; 349c79c73f6SBlue Swirl case POWERPC_EXCP_EXTERNAL: /* External input */ 350fdfba1a2SEdgar E. Iglesias cs = CPU(cpu); 351fdfba1a2SEdgar E. Iglesias 3526d49d6d4SBenjamin Herrenschmidt if (!lpes0) { 353c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 3546d49d6d4SBenjamin Herrenschmidt new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 3556d49d6d4SBenjamin Herrenschmidt srr0 = SPR_HSRR0; 3566d49d6d4SBenjamin Herrenschmidt srr1 = SPR_HSRR1; 357c79c73f6SBlue Swirl } 35868c2dd70SAlexander Graf if (env->mpic_proxy) { 35968c2dd70SAlexander Graf /* IACK the IRQ on delivery */ 360fdfba1a2SEdgar E. Iglesias env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack); 36168c2dd70SAlexander Graf } 362bd6fefe7SBenjamin Herrenschmidt break; 363c79c73f6SBlue Swirl case POWERPC_EXCP_ALIGN: /* Alignment exception */ 364c79c73f6SBlue Swirl /* Get rS/rD and rA from faulting opcode */ 36547733729SDavid Gibson /* 36647733729SDavid Gibson * Note: the opcode fields will not be set properly for a 36747733729SDavid Gibson * direct store load/store, but nobody cares as nobody 36847733729SDavid Gibson * actually uses direct store segments. 3693433b732SBenjamin Herrenschmidt */ 3703433b732SBenjamin Herrenschmidt env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; 371bd6fefe7SBenjamin Herrenschmidt break; 372c79c73f6SBlue Swirl case POWERPC_EXCP_PROGRAM: /* Program exception */ 373c79c73f6SBlue Swirl switch (env->error_code & ~0xF) { 374c79c73f6SBlue Swirl case POWERPC_EXCP_FP: 375c79c73f6SBlue Swirl if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { 376c79c73f6SBlue Swirl LOG_EXCP("Ignore floating point exception\n"); 37727103424SAndreas Färber cs->exception_index = POWERPC_EXCP_NONE; 378c79c73f6SBlue Swirl env->error_code = 0; 379c79c73f6SBlue Swirl return; 380c79c73f6SBlue Swirl } 3811b7d17caSBenjamin Herrenschmidt 38247733729SDavid Gibson /* 38347733729SDavid Gibson * FP exceptions always have NIP pointing to the faulting 3841b7d17caSBenjamin Herrenschmidt * instruction, so always use store_next and claim we are 3851b7d17caSBenjamin Herrenschmidt * precise in the MSR. 3861b7d17caSBenjamin Herrenschmidt */ 387c79c73f6SBlue Swirl msr |= 0x00100000; 3880ee604abSAaron Larson env->spr[SPR_BOOKE_ESR] = ESR_FP; 389bd6fefe7SBenjamin Herrenschmidt break; 390c79c73f6SBlue Swirl case POWERPC_EXCP_INVAL: 391c79c73f6SBlue Swirl LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); 392c79c73f6SBlue Swirl msr |= 0x00080000; 393c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PIL; 394c79c73f6SBlue Swirl break; 395c79c73f6SBlue Swirl case POWERPC_EXCP_PRIV: 396c79c73f6SBlue Swirl msr |= 0x00040000; 397c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PPR; 398c79c73f6SBlue Swirl break; 399c79c73f6SBlue Swirl case POWERPC_EXCP_TRAP: 400c79c73f6SBlue Swirl msr |= 0x00020000; 401c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_PTR; 402c79c73f6SBlue Swirl break; 403c79c73f6SBlue Swirl default: 404c79c73f6SBlue Swirl /* Should never occur */ 405a47dddd7SAndreas Färber cpu_abort(cs, "Invalid program exception %d. Aborting\n", 406c79c73f6SBlue Swirl env->error_code); 407c79c73f6SBlue Swirl break; 408c79c73f6SBlue Swirl } 409bd6fefe7SBenjamin Herrenschmidt break; 410c79c73f6SBlue Swirl case POWERPC_EXCP_SYSCALL: /* System call exception */ 411c79c73f6SBlue Swirl lev = env->error_code; 4126d49d6d4SBenjamin Herrenschmidt 4136dc6b557SNicholas Piggin if ((lev == 1) && cpu->vhyp) { 4146dc6b557SNicholas Piggin dump_hcall(env); 4156dc6b557SNicholas Piggin } else { 4166dc6b557SNicholas Piggin dump_syscall(env); 4176dc6b557SNicholas Piggin } 4186dc6b557SNicholas Piggin 41947733729SDavid Gibson /* 42047733729SDavid Gibson * We need to correct the NIP which in this case is supposed 421bd6fefe7SBenjamin Herrenschmidt * to point to the next instruction 422bd6fefe7SBenjamin Herrenschmidt */ 423bd6fefe7SBenjamin Herrenschmidt env->nip += 4; 424bd6fefe7SBenjamin Herrenschmidt 4256d49d6d4SBenjamin Herrenschmidt /* "PAPR mode" built-in hypercall emulation */ 4261d1be34dSDavid Gibson if ((lev == 1) && cpu->vhyp) { 4271d1be34dSDavid Gibson PPCVirtualHypervisorClass *vhc = 4281d1be34dSDavid Gibson PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); 4291d1be34dSDavid Gibson vhc->hypercall(cpu->vhyp, cpu); 430c79c73f6SBlue Swirl return; 431c79c73f6SBlue Swirl } 4326d49d6d4SBenjamin Herrenschmidt if (lev == 1) { 433c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 434c79c73f6SBlue Swirl } 435bd6fefe7SBenjamin Herrenschmidt break; 4363c89b8d6SNicholas Piggin case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */ 4373c89b8d6SNicholas Piggin lev = env->error_code; 4383c89b8d6SNicholas Piggin dump_syscall_vectored(env); 4393c89b8d6SNicholas Piggin env->nip += 4; 4403c89b8d6SNicholas Piggin new_msr |= env->msr & ((target_ulong)1 << MSR_EE); 4413c89b8d6SNicholas Piggin new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 4423c89b8d6SNicholas Piggin break; 443bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 444c79c73f6SBlue Swirl case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ 445c79c73f6SBlue Swirl case POWERPC_EXCP_DECR: /* Decrementer exception */ 446bd6fefe7SBenjamin Herrenschmidt break; 447c79c73f6SBlue Swirl case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ 448c79c73f6SBlue Swirl /* FIT on 4xx */ 449c79c73f6SBlue Swirl LOG_EXCP("FIT exception\n"); 450bd6fefe7SBenjamin Herrenschmidt break; 451c79c73f6SBlue Swirl case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ 452c79c73f6SBlue Swirl LOG_EXCP("WDT exception\n"); 453c79c73f6SBlue Swirl switch (excp_model) { 454c79c73f6SBlue Swirl case POWERPC_EXCP_BOOKE: 455c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 456c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 457c79c73f6SBlue Swirl break; 458c79c73f6SBlue Swirl default: 459c79c73f6SBlue Swirl break; 460c79c73f6SBlue Swirl } 461bd6fefe7SBenjamin Herrenschmidt break; 462c79c73f6SBlue Swirl case POWERPC_EXCP_DTLB: /* Data TLB error */ 463c79c73f6SBlue Swirl case POWERPC_EXCP_ITLB: /* Instruction TLB error */ 464bd6fefe7SBenjamin Herrenschmidt break; 465c79c73f6SBlue Swirl case POWERPC_EXCP_DEBUG: /* Debug interrupt */ 4660e3bf489SRoman Kapl if (env->flags & POWERPC_FLAG_DE) { 467a1bb7384SScott Wood /* FIXME: choose one or the other based on CPU type */ 468c79c73f6SBlue Swirl srr0 = SPR_BOOKE_DSRR0; 469c79c73f6SBlue Swirl srr1 = SPR_BOOKE_DSRR1; 470c79c73f6SBlue Swirl asrr0 = SPR_BOOKE_CSRR0; 471c79c73f6SBlue Swirl asrr1 = SPR_BOOKE_CSRR1; 4720e3bf489SRoman Kapl /* DBSR already modified by caller */ 4730e3bf489SRoman Kapl } else { 4740e3bf489SRoman Kapl cpu_abort(cs, "Debug exception triggered on unsupported model\n"); 475c79c73f6SBlue Swirl } 476bd6fefe7SBenjamin Herrenschmidt break; 477c79c73f6SBlue Swirl case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ 478c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 479bd6fefe7SBenjamin Herrenschmidt break; 480c79c73f6SBlue Swirl case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ 481c79c73f6SBlue Swirl /* XXX: TODO */ 482a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point data exception " 483c79c73f6SBlue Swirl "is not implemented yet !\n"); 484c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 485bd6fefe7SBenjamin Herrenschmidt break; 486c79c73f6SBlue Swirl case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ 487c79c73f6SBlue Swirl /* XXX: TODO */ 488a47dddd7SAndreas Färber cpu_abort(cs, "Embedded floating point round exception " 489c79c73f6SBlue Swirl "is not implemented yet !\n"); 490c79c73f6SBlue Swirl env->spr[SPR_BOOKE_ESR] = ESR_SPV; 491bd6fefe7SBenjamin Herrenschmidt break; 492c79c73f6SBlue Swirl case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ 493c79c73f6SBlue Swirl /* XXX: TODO */ 494a47dddd7SAndreas Färber cpu_abort(cs, 495c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 496bd6fefe7SBenjamin Herrenschmidt break; 497c79c73f6SBlue Swirl case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ 498bd6fefe7SBenjamin Herrenschmidt break; 499c79c73f6SBlue Swirl case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ 500c79c73f6SBlue Swirl srr0 = SPR_BOOKE_CSRR0; 501c79c73f6SBlue Swirl srr1 = SPR_BOOKE_CSRR1; 502bd6fefe7SBenjamin Herrenschmidt break; 503c79c73f6SBlue Swirl case POWERPC_EXCP_RESET: /* System reset exception */ 504f85bcec3SNicholas Piggin /* A power-saving exception sets ME, otherwise it is unchanged */ 505c79c73f6SBlue Swirl if (msr_pow) { 506c79c73f6SBlue Swirl /* indicate that we resumed from power save mode */ 507c79c73f6SBlue Swirl msr |= 0x10000; 508f85bcec3SNicholas Piggin new_msr |= ((target_ulong)1 << MSR_ME); 509c79c73f6SBlue Swirl } 51010c21b5cSNicholas Piggin if (env->msr_mask & MSR_HVB) { 51147733729SDavid Gibson /* 51247733729SDavid Gibson * ISA specifies HV, but can be delivered to guest with HV 51347733729SDavid Gibson * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU). 51410c21b5cSNicholas Piggin */ 515c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 51610c21b5cSNicholas Piggin } else { 51710c21b5cSNicholas Piggin if (msr_pow) { 51810c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver power-saving system reset " 51910c21b5cSNicholas Piggin "exception %d with no HV support\n", excp); 52010c21b5cSNicholas Piggin } 52110c21b5cSNicholas Piggin } 5225c94b2a5SCédric Le Goater ail = 0; 523bd6fefe7SBenjamin Herrenschmidt break; 524c79c73f6SBlue Swirl case POWERPC_EXCP_DSEG: /* Data segment exception */ 525c79c73f6SBlue Swirl case POWERPC_EXCP_ISEG: /* Instruction segment exception */ 526c79c73f6SBlue Swirl case POWERPC_EXCP_TRACE: /* Trace exception */ 527bd6fefe7SBenjamin Herrenschmidt break; 528d04ea940SCédric Le Goater case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ 529d04ea940SCédric Le Goater msr |= env->error_code; 530*295397f5SChen Qun /* fall through */ 531bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ 532c79c73f6SBlue Swirl case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ 533c79c73f6SBlue Swirl case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ 534c79c73f6SBlue Swirl case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ 5357af1e7b0SCédric Le Goater case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ 536bd6fefe7SBenjamin Herrenschmidt case POWERPC_EXCP_HV_EMU: 537d8ce5fd6SBenjamin Herrenschmidt case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */ 538c79c73f6SBlue Swirl srr0 = SPR_HSRR0; 539c79c73f6SBlue Swirl srr1 = SPR_HSRR1; 540c79c73f6SBlue Swirl new_msr |= (target_ulong)MSR_HVB; 541c79c73f6SBlue Swirl new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 542bd6fefe7SBenjamin Herrenschmidt break; 543c79c73f6SBlue Swirl case POWERPC_EXCP_VPU: /* Vector unavailable exception */ 5441f29871cSTom Musta case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ 5457019cb3dSAlexey Kardashevskiy case POWERPC_EXCP_FU: /* Facility unavailable exception */ 5465310799aSBalbir Singh #ifdef TARGET_PPC64 5475310799aSBalbir Singh env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56); 5485310799aSBalbir Singh #endif 549bd6fefe7SBenjamin Herrenschmidt break; 550493028d8SCédric Le Goater case POWERPC_EXCP_HV_FU: /* Hypervisor Facility Unavailable Exception */ 551493028d8SCédric Le Goater #ifdef TARGET_PPC64 552493028d8SCédric Le Goater env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS); 553493028d8SCédric Le Goater srr0 = SPR_HSRR0; 554493028d8SCédric Le Goater srr1 = SPR_HSRR1; 555493028d8SCédric Le Goater new_msr |= (target_ulong)MSR_HVB; 556493028d8SCédric Le Goater new_msr |= env->msr & ((target_ulong)1 << MSR_RI); 557493028d8SCédric Le Goater #endif 558493028d8SCédric Le Goater break; 559c79c73f6SBlue Swirl case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ 560c79c73f6SBlue Swirl LOG_EXCP("PIT exception\n"); 561bd6fefe7SBenjamin Herrenschmidt break; 562c79c73f6SBlue Swirl case POWERPC_EXCP_IO: /* IO error exception */ 563c79c73f6SBlue Swirl /* XXX: TODO */ 564a47dddd7SAndreas Färber cpu_abort(cs, "601 IO error exception is not implemented yet !\n"); 565bd6fefe7SBenjamin Herrenschmidt break; 566c79c73f6SBlue Swirl case POWERPC_EXCP_RUNM: /* Run mode exception */ 567c79c73f6SBlue Swirl /* XXX: TODO */ 568a47dddd7SAndreas Färber cpu_abort(cs, "601 run mode exception is not implemented yet !\n"); 569bd6fefe7SBenjamin Herrenschmidt break; 570c79c73f6SBlue Swirl case POWERPC_EXCP_EMUL: /* Emulation trap exception */ 571c79c73f6SBlue Swirl /* XXX: TODO */ 572a47dddd7SAndreas Färber cpu_abort(cs, "602 emulation trap exception " 573c79c73f6SBlue Swirl "is not implemented yet !\n"); 574bd6fefe7SBenjamin Herrenschmidt break; 575c79c73f6SBlue Swirl case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ 576c79c73f6SBlue Swirl switch (excp_model) { 577c79c73f6SBlue Swirl case POWERPC_EXCP_602: 578c79c73f6SBlue Swirl case POWERPC_EXCP_603: 579c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 580c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 581c79c73f6SBlue Swirl goto tlb_miss_tgpr; 582c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 583c79c73f6SBlue Swirl goto tlb_miss; 584c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 585c79c73f6SBlue Swirl goto tlb_miss_74xx; 586c79c73f6SBlue Swirl default: 587a47dddd7SAndreas Färber cpu_abort(cs, "Invalid instruction TLB miss exception\n"); 588c79c73f6SBlue Swirl break; 589c79c73f6SBlue Swirl } 590c79c73f6SBlue Swirl break; 591c79c73f6SBlue Swirl case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ 592c79c73f6SBlue Swirl switch (excp_model) { 593c79c73f6SBlue Swirl case POWERPC_EXCP_602: 594c79c73f6SBlue Swirl case POWERPC_EXCP_603: 595c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 596c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 597c79c73f6SBlue Swirl goto tlb_miss_tgpr; 598c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 599c79c73f6SBlue Swirl goto tlb_miss; 600c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 601c79c73f6SBlue Swirl goto tlb_miss_74xx; 602c79c73f6SBlue Swirl default: 603a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data load TLB miss exception\n"); 604c79c73f6SBlue Swirl break; 605c79c73f6SBlue Swirl } 606c79c73f6SBlue Swirl break; 607c79c73f6SBlue Swirl case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ 608c79c73f6SBlue Swirl switch (excp_model) { 609c79c73f6SBlue Swirl case POWERPC_EXCP_602: 610c79c73f6SBlue Swirl case POWERPC_EXCP_603: 611c79c73f6SBlue Swirl case POWERPC_EXCP_603E: 612c79c73f6SBlue Swirl case POWERPC_EXCP_G2: 613c79c73f6SBlue Swirl tlb_miss_tgpr: 614c79c73f6SBlue Swirl /* Swap temporary saved registers with GPRs */ 615c79c73f6SBlue Swirl if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { 616c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_TGPR; 617c79c73f6SBlue Swirl hreg_swap_gpr_tgpr(env); 618c79c73f6SBlue Swirl } 619c79c73f6SBlue Swirl goto tlb_miss; 620c79c73f6SBlue Swirl case POWERPC_EXCP_7x5: 621c79c73f6SBlue Swirl tlb_miss: 622c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 623c79c73f6SBlue Swirl if (qemu_log_enabled()) { 624c79c73f6SBlue Swirl const char *es; 625c79c73f6SBlue Swirl target_ulong *miss, *cmp; 626c79c73f6SBlue Swirl int en; 627c79c73f6SBlue Swirl 628c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 629c79c73f6SBlue Swirl es = "I"; 630c79c73f6SBlue Swirl en = 'I'; 631c79c73f6SBlue Swirl miss = &env->spr[SPR_IMISS]; 632c79c73f6SBlue Swirl cmp = &env->spr[SPR_ICMP]; 633c79c73f6SBlue Swirl } else { 634c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 635c79c73f6SBlue Swirl es = "DL"; 636c79c73f6SBlue Swirl } else { 637c79c73f6SBlue Swirl es = "DS"; 638c79c73f6SBlue Swirl } 639c79c73f6SBlue Swirl en = 'D'; 640c79c73f6SBlue Swirl miss = &env->spr[SPR_DMISS]; 641c79c73f6SBlue Swirl cmp = &env->spr[SPR_DCMP]; 642c79c73f6SBlue Swirl } 643c79c73f6SBlue Swirl qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 644c79c73f6SBlue Swirl TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " 645c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 646c79c73f6SBlue Swirl env->spr[SPR_HASH1], env->spr[SPR_HASH2], 647c79c73f6SBlue Swirl env->error_code); 648c79c73f6SBlue Swirl } 649c79c73f6SBlue Swirl #endif 650c79c73f6SBlue Swirl msr |= env->crf[0] << 28; 651c79c73f6SBlue Swirl msr |= env->error_code; /* key, D/I, S/L bits */ 652c79c73f6SBlue Swirl /* Set way using a LRU mechanism */ 653c79c73f6SBlue Swirl msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; 654c79c73f6SBlue Swirl break; 655c79c73f6SBlue Swirl case POWERPC_EXCP_74xx: 656c79c73f6SBlue Swirl tlb_miss_74xx: 657c79c73f6SBlue Swirl #if defined(DEBUG_SOFTWARE_TLB) 658c79c73f6SBlue Swirl if (qemu_log_enabled()) { 659c79c73f6SBlue Swirl const char *es; 660c79c73f6SBlue Swirl target_ulong *miss, *cmp; 661c79c73f6SBlue Swirl int en; 662c79c73f6SBlue Swirl 663c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_IFTLB) { 664c79c73f6SBlue Swirl es = "I"; 665c79c73f6SBlue Swirl en = 'I'; 666c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 667c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 668c79c73f6SBlue Swirl } else { 669c79c73f6SBlue Swirl if (excp == POWERPC_EXCP_DLTLB) { 670c79c73f6SBlue Swirl es = "DL"; 671c79c73f6SBlue Swirl } else { 672c79c73f6SBlue Swirl es = "DS"; 673c79c73f6SBlue Swirl } 674c79c73f6SBlue Swirl en = 'D'; 675c79c73f6SBlue Swirl miss = &env->spr[SPR_TLBMISS]; 676c79c73f6SBlue Swirl cmp = &env->spr[SPR_PTEHI]; 677c79c73f6SBlue Swirl } 678c79c73f6SBlue Swirl qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " 679c79c73f6SBlue Swirl TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, 680c79c73f6SBlue Swirl env->error_code); 681c79c73f6SBlue Swirl } 682c79c73f6SBlue Swirl #endif 683c79c73f6SBlue Swirl msr |= env->error_code; /* key bit */ 684c79c73f6SBlue Swirl break; 685c79c73f6SBlue Swirl default: 686a47dddd7SAndreas Färber cpu_abort(cs, "Invalid data store TLB miss exception\n"); 687c79c73f6SBlue Swirl break; 688c79c73f6SBlue Swirl } 689bd6fefe7SBenjamin Herrenschmidt break; 690c79c73f6SBlue Swirl case POWERPC_EXCP_FPA: /* Floating-point assist exception */ 691c79c73f6SBlue Swirl /* XXX: TODO */ 692a47dddd7SAndreas Färber cpu_abort(cs, "Floating point assist exception " 693c79c73f6SBlue Swirl "is not implemented yet !\n"); 694bd6fefe7SBenjamin Herrenschmidt break; 695c79c73f6SBlue Swirl case POWERPC_EXCP_DABR: /* Data address breakpoint */ 696c79c73f6SBlue Swirl /* XXX: TODO */ 697a47dddd7SAndreas Färber cpu_abort(cs, "DABR exception is not implemented yet !\n"); 698bd6fefe7SBenjamin Herrenschmidt break; 699c79c73f6SBlue Swirl case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ 700c79c73f6SBlue Swirl /* XXX: TODO */ 701a47dddd7SAndreas Färber cpu_abort(cs, "IABR exception is not implemented yet !\n"); 702bd6fefe7SBenjamin Herrenschmidt break; 703c79c73f6SBlue Swirl case POWERPC_EXCP_SMI: /* System management interrupt */ 704c79c73f6SBlue Swirl /* XXX: TODO */ 705a47dddd7SAndreas Färber cpu_abort(cs, "SMI exception is not implemented yet !\n"); 706bd6fefe7SBenjamin Herrenschmidt break; 707c79c73f6SBlue Swirl case POWERPC_EXCP_THERM: /* Thermal interrupt */ 708c79c73f6SBlue Swirl /* XXX: TODO */ 709a47dddd7SAndreas Färber cpu_abort(cs, "Thermal management exception " 710c79c73f6SBlue Swirl "is not implemented yet !\n"); 711bd6fefe7SBenjamin Herrenschmidt break; 712c79c73f6SBlue Swirl case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ 713c79c73f6SBlue Swirl /* XXX: TODO */ 714a47dddd7SAndreas Färber cpu_abort(cs, 715c79c73f6SBlue Swirl "Performance counter exception is not implemented yet !\n"); 716bd6fefe7SBenjamin Herrenschmidt break; 717c79c73f6SBlue Swirl case POWERPC_EXCP_VPUA: /* Vector assist exception */ 718c79c73f6SBlue Swirl /* XXX: TODO */ 719a47dddd7SAndreas Färber cpu_abort(cs, "VPU assist exception is not implemented yet !\n"); 720bd6fefe7SBenjamin Herrenschmidt break; 721c79c73f6SBlue Swirl case POWERPC_EXCP_SOFTP: /* Soft patch exception */ 722c79c73f6SBlue Swirl /* XXX: TODO */ 723a47dddd7SAndreas Färber cpu_abort(cs, 724c79c73f6SBlue Swirl "970 soft-patch exception is not implemented yet !\n"); 725bd6fefe7SBenjamin Herrenschmidt break; 726c79c73f6SBlue Swirl case POWERPC_EXCP_MAINT: /* Maintenance exception */ 727c79c73f6SBlue Swirl /* XXX: TODO */ 728a47dddd7SAndreas Färber cpu_abort(cs, 729c79c73f6SBlue Swirl "970 maintenance exception is not implemented yet !\n"); 730bd6fefe7SBenjamin Herrenschmidt break; 731c79c73f6SBlue Swirl case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ 732c79c73f6SBlue Swirl /* XXX: TODO */ 733a47dddd7SAndreas Färber cpu_abort(cs, "Maskable external exception " 734c79c73f6SBlue Swirl "is not implemented yet !\n"); 735bd6fefe7SBenjamin Herrenschmidt break; 736c79c73f6SBlue Swirl case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ 737c79c73f6SBlue Swirl /* XXX: TODO */ 738a47dddd7SAndreas Färber cpu_abort(cs, "Non maskable external exception " 739c79c73f6SBlue Swirl "is not implemented yet !\n"); 740bd6fefe7SBenjamin Herrenschmidt break; 741c79c73f6SBlue Swirl default: 742c79c73f6SBlue Swirl excp_invalid: 743a47dddd7SAndreas Färber cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); 744c79c73f6SBlue Swirl break; 745c79c73f6SBlue Swirl } 746bd6fefe7SBenjamin Herrenschmidt 7476d49d6d4SBenjamin Herrenschmidt /* Sanity check */ 74810c21b5cSNicholas Piggin if (!(env->msr_mask & MSR_HVB)) { 74910c21b5cSNicholas Piggin if (new_msr & MSR_HVB) { 75010c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with " 7516d49d6d4SBenjamin Herrenschmidt "no HV support\n", excp); 7526d49d6d4SBenjamin Herrenschmidt } 75310c21b5cSNicholas Piggin if (srr0 == SPR_HSRR0) { 75410c21b5cSNicholas Piggin cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with " 75510c21b5cSNicholas Piggin "no HV support\n", excp); 75610c21b5cSNicholas Piggin } 75710c21b5cSNicholas Piggin } 7586d49d6d4SBenjamin Herrenschmidt 75947733729SDavid Gibson /* 76047733729SDavid Gibson * Sort out endianness of interrupt, this differs depending on the 7616d49d6d4SBenjamin Herrenschmidt * CPU, the HV mode, etc... 7626d49d6d4SBenjamin Herrenschmidt */ 7631e0c7e55SAnton Blanchard #ifdef TARGET_PPC64 7646d49d6d4SBenjamin Herrenschmidt if (excp_model == POWERPC_EXCP_POWER7) { 7656d49d6d4SBenjamin Herrenschmidt if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) { 7666d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 7676d49d6d4SBenjamin Herrenschmidt } 7686d49d6d4SBenjamin Herrenschmidt } else if (excp_model == POWERPC_EXCP_POWER8) { 7696d49d6d4SBenjamin Herrenschmidt if (new_msr & MSR_HVB) { 770a790e82bSBenjamin Herrenschmidt if (env->spr[SPR_HID0] & HID0_HILE) { 771a790e82bSBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 772a790e82bSBenjamin Herrenschmidt } 773a790e82bSBenjamin Herrenschmidt } else if (env->spr[SPR_LPCR] & LPCR_ILE) { 774a790e82bSBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 775a790e82bSBenjamin Herrenschmidt } 776a790e82bSBenjamin Herrenschmidt } else if (excp_model == POWERPC_EXCP_POWER9) { 777a790e82bSBenjamin Herrenschmidt if (new_msr & MSR_HVB) { 778a790e82bSBenjamin Herrenschmidt if (env->spr[SPR_HID0] & HID0_POWER9_HILE) { 7796d49d6d4SBenjamin Herrenschmidt new_msr |= (target_ulong)1 << MSR_LE; 7806d49d6d4SBenjamin Herrenschmidt } 7816d49d6d4SBenjamin Herrenschmidt } else if (env->spr[SPR_LPCR] & LPCR_ILE) { 7821e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 7831e0c7e55SAnton Blanchard } 7841e0c7e55SAnton Blanchard } else if (msr_ile) { 7851e0c7e55SAnton Blanchard new_msr |= (target_ulong)1 << MSR_LE; 7861e0c7e55SAnton Blanchard } 7871e0c7e55SAnton Blanchard #else 788c79c73f6SBlue Swirl if (msr_ile) { 789c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_LE; 790c79c73f6SBlue Swirl } 7911e0c7e55SAnton Blanchard #endif 792c79c73f6SBlue Swirl 79347733729SDavid Gibson /* 79447733729SDavid Gibson * AIL only works if there is no HV transition and we are running 79547733729SDavid Gibson * with translations enabled 7965c94b2a5SCédric Le Goater */ 7976d49d6d4SBenjamin Herrenschmidt if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) || 7986d49d6d4SBenjamin Herrenschmidt ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) { 7995c94b2a5SCédric Le Goater ail = 0; 8005c94b2a5SCédric Le Goater } 8013c89b8d6SNicholas Piggin 8023c89b8d6SNicholas Piggin vector = env->excp_vectors[excp]; 8033c89b8d6SNicholas Piggin if (vector == (target_ulong)-1ULL) { 8043c89b8d6SNicholas Piggin cpu_abort(cs, "Raised an exception without defined vector %d\n", 8053c89b8d6SNicholas Piggin excp); 8063c89b8d6SNicholas Piggin } 8073c89b8d6SNicholas Piggin 8083c89b8d6SNicholas Piggin vector |= env->excp_prefix; 8093c89b8d6SNicholas Piggin 8103c89b8d6SNicholas Piggin /* If any alternate SRR register are defined, duplicate saved values */ 8113c89b8d6SNicholas Piggin if (asrr0 != -1) { 8123c89b8d6SNicholas Piggin env->spr[asrr0] = env->nip; 8133c89b8d6SNicholas Piggin } 8143c89b8d6SNicholas Piggin if (asrr1 != -1) { 8153c89b8d6SNicholas Piggin env->spr[asrr1] = msr; 8165c94b2a5SCédric Le Goater } 8175c94b2a5SCédric Le Goater 818c79c73f6SBlue Swirl #if defined(TARGET_PPC64) 819c79c73f6SBlue Swirl if (excp_model == POWERPC_EXCP_BOOKE) { 820e42a61f1SAlexander Graf if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) { 821e42a61f1SAlexander Graf /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */ 822c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_CM; 823e42a61f1SAlexander Graf } else { 824e42a61f1SAlexander Graf vector = (uint32_t)vector; 825c79c73f6SBlue Swirl } 826c79c73f6SBlue Swirl } else { 827c79c73f6SBlue Swirl if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) { 828c79c73f6SBlue Swirl vector = (uint32_t)vector; 829c79c73f6SBlue Swirl } else { 830c79c73f6SBlue Swirl new_msr |= (target_ulong)1 << MSR_SF; 831c79c73f6SBlue Swirl } 832c79c73f6SBlue Swirl } 833c79c73f6SBlue Swirl #endif 834cd0c6f47SBenjamin Herrenschmidt 8353c89b8d6SNicholas Piggin if (excp != POWERPC_EXCP_SYSCALL_VECTORED) { 8363c89b8d6SNicholas Piggin /* Save PC */ 8373c89b8d6SNicholas Piggin env->spr[srr0] = env->nip; 8383c89b8d6SNicholas Piggin 8393c89b8d6SNicholas Piggin /* Save MSR */ 8403c89b8d6SNicholas Piggin env->spr[srr1] = msr; 8413c89b8d6SNicholas Piggin 8423c89b8d6SNicholas Piggin /* Handle AIL */ 8433c89b8d6SNicholas Piggin if (ail) { 8443c89b8d6SNicholas Piggin new_msr |= (1 << MSR_IR) | (1 << MSR_DR); 8453c89b8d6SNicholas Piggin vector |= ppc_excp_vector_offset(cs, ail); 8463c89b8d6SNicholas Piggin } 8473c89b8d6SNicholas Piggin 8483c89b8d6SNicholas Piggin #if defined(TARGET_PPC64) 8493c89b8d6SNicholas Piggin } else { 8503c89b8d6SNicholas Piggin /* scv AIL is a little different */ 8513c89b8d6SNicholas Piggin if (ail) { 8523c89b8d6SNicholas Piggin new_msr |= (1 << MSR_IR) | (1 << MSR_DR); 8533c89b8d6SNicholas Piggin } 8543c89b8d6SNicholas Piggin if (ail == AIL_C000_0000_0000_4000) { 8553c89b8d6SNicholas Piggin vector |= 0xc000000000003000ull; 8563c89b8d6SNicholas Piggin } else { 8573c89b8d6SNicholas Piggin vector |= 0x0000000000017000ull; 8583c89b8d6SNicholas Piggin } 8593c89b8d6SNicholas Piggin vector += lev * 0x20; 8603c89b8d6SNicholas Piggin 8613c89b8d6SNicholas Piggin env->lr = env->nip; 8623c89b8d6SNicholas Piggin env->ctr = msr; 8633c89b8d6SNicholas Piggin #endif 8643c89b8d6SNicholas Piggin } 8653c89b8d6SNicholas Piggin 866ad77c6caSNicholas Piggin powerpc_set_excp_state(cpu, vector, new_msr); 867c79c73f6SBlue Swirl } 868c79c73f6SBlue Swirl 86997a8ea5aSAndreas Färber void ppc_cpu_do_interrupt(CPUState *cs) 870c79c73f6SBlue Swirl { 87197a8ea5aSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 87297a8ea5aSAndreas Färber CPUPPCState *env = &cpu->env; 8735c26a5b3SAndreas Färber 87427103424SAndreas Färber powerpc_excp(cpu, env->excp_model, cs->exception_index); 875c79c73f6SBlue Swirl } 876c79c73f6SBlue Swirl 877458dd766SRichard Henderson static void ppc_hw_interrupt(CPUPPCState *env) 878c79c73f6SBlue Swirl { 879db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env); 8803621e2c9SBenjamin Herrenschmidt bool async_deliver; 881259186a7SAndreas Färber 882c79c73f6SBlue Swirl /* External reset */ 883c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { 884c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); 8855c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 886c79c73f6SBlue Swirl return; 887c79c73f6SBlue Swirl } 888c79c73f6SBlue Swirl /* Machine check exception */ 889c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { 890c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); 8915c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK); 892c79c73f6SBlue Swirl return; 893c79c73f6SBlue Swirl } 894c79c73f6SBlue Swirl #if 0 /* TODO */ 895c79c73f6SBlue Swirl /* External debug exception */ 896c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { 897c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); 8985c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG); 899c79c73f6SBlue Swirl return; 900c79c73f6SBlue Swirl } 901c79c73f6SBlue Swirl #endif 9023621e2c9SBenjamin Herrenschmidt 9033621e2c9SBenjamin Herrenschmidt /* 9043621e2c9SBenjamin Herrenschmidt * For interrupts that gate on MSR:EE, we need to do something a 9053621e2c9SBenjamin Herrenschmidt * bit more subtle, as we need to let them through even when EE is 9063621e2c9SBenjamin Herrenschmidt * clear when coming out of some power management states (in order 9073621e2c9SBenjamin Herrenschmidt * for them to become a 0x100). 9083621e2c9SBenjamin Herrenschmidt */ 9091e7fd61dSBenjamin Herrenschmidt async_deliver = (msr_ee != 0) || env->resume_as_sreset; 9103621e2c9SBenjamin Herrenschmidt 911c79c73f6SBlue Swirl /* Hypervisor decrementer exception */ 912c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { 9134b236b62SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 9144b236b62SBenjamin Herrenschmidt bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); 9153621e2c9SBenjamin Herrenschmidt if ((async_deliver || msr_hv == 0) && hdice) { 9164b236b62SBenjamin Herrenschmidt /* HDEC clears on delivery */ 9174b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 9185c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR); 919c79c73f6SBlue Swirl return; 920c79c73f6SBlue Swirl } 921c79c73f6SBlue Swirl } 922d8ce5fd6SBenjamin Herrenschmidt 923d8ce5fd6SBenjamin Herrenschmidt /* Hypervisor virtualization interrupt */ 924d8ce5fd6SBenjamin Herrenschmidt if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) { 925d8ce5fd6SBenjamin Herrenschmidt /* LPCR will be clear when not supported so this will work */ 926d8ce5fd6SBenjamin Herrenschmidt bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); 927d8ce5fd6SBenjamin Herrenschmidt if ((async_deliver || msr_hv == 0) && hvice) { 928d8ce5fd6SBenjamin Herrenschmidt powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT); 929d8ce5fd6SBenjamin Herrenschmidt return; 930d8ce5fd6SBenjamin Herrenschmidt } 931d8ce5fd6SBenjamin Herrenschmidt } 932d8ce5fd6SBenjamin Herrenschmidt 933d8ce5fd6SBenjamin Herrenschmidt /* External interrupt can ignore MSR:EE under some circumstances */ 934d1dbe37cSBenjamin Herrenschmidt if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { 935d1dbe37cSBenjamin Herrenschmidt bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); 9366eebe6dcSBenjamin Herrenschmidt bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); 9376eebe6dcSBenjamin Herrenschmidt /* HEIC blocks delivery to the hypervisor */ 9386eebe6dcSBenjamin Herrenschmidt if ((async_deliver && !(heic && msr_hv && !msr_pr)) || 9396eebe6dcSBenjamin Herrenschmidt (env->has_hv_mode && msr_hv == 0 && !lpes0)) { 940d1dbe37cSBenjamin Herrenschmidt powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL); 941d1dbe37cSBenjamin Herrenschmidt return; 942d1dbe37cSBenjamin Herrenschmidt } 943d1dbe37cSBenjamin Herrenschmidt } 944c79c73f6SBlue Swirl if (msr_ce != 0) { 945c79c73f6SBlue Swirl /* External critical interrupt */ 946c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { 9475c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL); 948c79c73f6SBlue Swirl return; 949c79c73f6SBlue Swirl } 950c79c73f6SBlue Swirl } 9513621e2c9SBenjamin Herrenschmidt if (async_deliver != 0) { 952c79c73f6SBlue Swirl /* Watchdog timer on embedded PowerPC */ 953c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { 954c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); 9555c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT); 956c79c73f6SBlue Swirl return; 957c79c73f6SBlue Swirl } 958c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { 959c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); 9605c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI); 961c79c73f6SBlue Swirl return; 962c79c73f6SBlue Swirl } 963c79c73f6SBlue Swirl /* Fixed interval timer on embedded PowerPC */ 964c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { 965c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); 9665c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT); 967c79c73f6SBlue Swirl return; 968c79c73f6SBlue Swirl } 969c79c73f6SBlue Swirl /* Programmable interval timer on embedded PowerPC */ 970c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { 971c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); 9725c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT); 973c79c73f6SBlue Swirl return; 974c79c73f6SBlue Swirl } 975c79c73f6SBlue Swirl /* Decrementer exception */ 976c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { 977e81a982aSAlexander Graf if (ppc_decr_clear_on_delivery(env)) { 978c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); 979e81a982aSAlexander Graf } 9805c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR); 981c79c73f6SBlue Swirl return; 982c79c73f6SBlue Swirl } 983c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { 984c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); 9855ba7ba1dSCédric Le Goater if (is_book3s_arch2x(env)) { 9865ba7ba1dSCédric Le Goater powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR); 9875ba7ba1dSCédric Le Goater } else { 9885c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI); 9895ba7ba1dSCédric Le Goater } 990c79c73f6SBlue Swirl return; 991c79c73f6SBlue Swirl } 9927af1e7b0SCédric Le Goater if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) { 9937af1e7b0SCédric Le Goater env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL); 9947af1e7b0SCédric Le Goater powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_SDOOR_HV); 9957af1e7b0SCédric Le Goater return; 9967af1e7b0SCédric Le Goater } 997c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { 998c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); 9995c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM); 1000c79c73f6SBlue Swirl return; 1001c79c73f6SBlue Swirl } 1002c79c73f6SBlue Swirl /* Thermal interrupt */ 1003c79c73f6SBlue Swirl if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { 1004c79c73f6SBlue Swirl env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); 10055c26a5b3SAndreas Färber powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM); 1006c79c73f6SBlue Swirl return; 1007c79c73f6SBlue Swirl } 1008c79c73f6SBlue Swirl } 1009f8154fd2SBenjamin Herrenschmidt 1010f8154fd2SBenjamin Herrenschmidt if (env->resume_as_sreset) { 1011f8154fd2SBenjamin Herrenschmidt /* 1012f8154fd2SBenjamin Herrenschmidt * This is a bug ! It means that has_work took us out of halt without 1013f8154fd2SBenjamin Herrenschmidt * anything to deliver while in a PM state that requires getting 1014f8154fd2SBenjamin Herrenschmidt * out via a 0x100 1015f8154fd2SBenjamin Herrenschmidt * 1016f8154fd2SBenjamin Herrenschmidt * This means we will incorrectly execute past the power management 1017f8154fd2SBenjamin Herrenschmidt * instruction instead of triggering a reset. 1018f8154fd2SBenjamin Herrenschmidt * 1019136fbf65Szhaolichang * It generally means a discrepancy between the wakeup conditions in the 1020f8154fd2SBenjamin Herrenschmidt * processor has_work implementation and the logic in this function. 1021f8154fd2SBenjamin Herrenschmidt */ 1022db70b311SRichard Henderson cpu_abort(env_cpu(env), 1023f8154fd2SBenjamin Herrenschmidt "Wakeup from PM state but interrupt Undelivered"); 1024f8154fd2SBenjamin Herrenschmidt } 1025c79c73f6SBlue Swirl } 102634316482SAlexey Kardashevskiy 1027b5b7f391SNicholas Piggin void ppc_cpu_do_system_reset(CPUState *cs) 102834316482SAlexey Kardashevskiy { 102934316482SAlexey Kardashevskiy PowerPCCPU *cpu = POWERPC_CPU(cs); 103034316482SAlexey Kardashevskiy CPUPPCState *env = &cpu->env; 103134316482SAlexey Kardashevskiy 103234316482SAlexey Kardashevskiy powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); 103334316482SAlexey Kardashevskiy } 1034ad77c6caSNicholas Piggin 1035ad77c6caSNicholas Piggin void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector) 1036ad77c6caSNicholas Piggin { 1037ad77c6caSNicholas Piggin PowerPCCPU *cpu = POWERPC_CPU(cs); 1038ad77c6caSNicholas Piggin CPUPPCState *env = &cpu->env; 1039ad77c6caSNicholas Piggin PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); 1040ad77c6caSNicholas Piggin target_ulong msr = 0; 1041ad77c6caSNicholas Piggin 1042ad77c6caSNicholas Piggin /* 1043ad77c6caSNicholas Piggin * Set MSR and NIP for the handler, SRR0/1, DAR and DSISR have already 1044ad77c6caSNicholas Piggin * been set by KVM. 1045ad77c6caSNicholas Piggin */ 1046ad77c6caSNicholas Piggin msr = (1ULL << MSR_ME); 1047ad77c6caSNicholas Piggin msr |= env->msr & (1ULL << MSR_SF); 1048ad77c6caSNicholas Piggin if (!(*pcc->interrupts_big_endian)(cpu)) { 1049ad77c6caSNicholas Piggin msr |= (1ULL << MSR_LE); 1050ad77c6caSNicholas Piggin } 1051ad77c6caSNicholas Piggin 1052ad77c6caSNicholas Piggin powerpc_set_excp_state(cpu, vector, msr); 1053ad77c6caSNicholas Piggin } 1054c79c73f6SBlue Swirl #endif /* !CONFIG_USER_ONLY */ 1055c79c73f6SBlue Swirl 1056458dd766SRichard Henderson bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 1057458dd766SRichard Henderson { 1058458dd766SRichard Henderson PowerPCCPU *cpu = POWERPC_CPU(cs); 1059458dd766SRichard Henderson CPUPPCState *env = &cpu->env; 1060458dd766SRichard Henderson 1061458dd766SRichard Henderson if (interrupt_request & CPU_INTERRUPT_HARD) { 1062458dd766SRichard Henderson ppc_hw_interrupt(env); 1063458dd766SRichard Henderson if (env->pending_interrupts == 0) { 1064458dd766SRichard Henderson cs->interrupt_request &= ~CPU_INTERRUPT_HARD; 1065458dd766SRichard Henderson } 1066458dd766SRichard Henderson return true; 1067458dd766SRichard Henderson } 1068458dd766SRichard Henderson return false; 1069458dd766SRichard Henderson } 1070458dd766SRichard Henderson 1071c79c73f6SBlue Swirl #if defined(DEBUG_OP) 1072c79c73f6SBlue Swirl static void cpu_dump_rfi(target_ulong RA, target_ulong msr) 1073c79c73f6SBlue Swirl { 1074c79c73f6SBlue Swirl qemu_log("Return from exception at " TARGET_FMT_lx " with flags " 1075c79c73f6SBlue Swirl TARGET_FMT_lx "\n", RA, msr); 1076c79c73f6SBlue Swirl } 1077c79c73f6SBlue Swirl #endif 1078c79c73f6SBlue Swirl 1079ad71ed68SBlue Swirl /*****************************************************************************/ 1080ad71ed68SBlue Swirl /* Exceptions processing helpers */ 1081ad71ed68SBlue Swirl 1082db789c6cSBenjamin Herrenschmidt void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, 1083db789c6cSBenjamin Herrenschmidt uint32_t error_code, uintptr_t raddr) 1084ad71ed68SBlue Swirl { 1085db70b311SRichard Henderson CPUState *cs = env_cpu(env); 108627103424SAndreas Färber 108727103424SAndreas Färber cs->exception_index = exception; 1088ad71ed68SBlue Swirl env->error_code = error_code; 1089db789c6cSBenjamin Herrenschmidt cpu_loop_exit_restore(cs, raddr); 1090db789c6cSBenjamin Herrenschmidt } 1091db789c6cSBenjamin Herrenschmidt 1092db789c6cSBenjamin Herrenschmidt void raise_exception_err(CPUPPCState *env, uint32_t exception, 1093db789c6cSBenjamin Herrenschmidt uint32_t error_code) 1094db789c6cSBenjamin Herrenschmidt { 1095db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 1096db789c6cSBenjamin Herrenschmidt } 1097db789c6cSBenjamin Herrenschmidt 1098db789c6cSBenjamin Herrenschmidt void raise_exception(CPUPPCState *env, uint32_t exception) 1099db789c6cSBenjamin Herrenschmidt { 1100db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 1101db789c6cSBenjamin Herrenschmidt } 1102db789c6cSBenjamin Herrenschmidt 1103db789c6cSBenjamin Herrenschmidt void raise_exception_ra(CPUPPCState *env, uint32_t exception, 1104db789c6cSBenjamin Herrenschmidt uintptr_t raddr) 1105db789c6cSBenjamin Herrenschmidt { 1106db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, raddr); 1107db789c6cSBenjamin Herrenschmidt } 1108db789c6cSBenjamin Herrenschmidt 1109db789c6cSBenjamin Herrenschmidt void helper_raise_exception_err(CPUPPCState *env, uint32_t exception, 1110db789c6cSBenjamin Herrenschmidt uint32_t error_code) 1111db789c6cSBenjamin Herrenschmidt { 1112db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, error_code, 0); 1113ad71ed68SBlue Swirl } 1114ad71ed68SBlue Swirl 1115e5f17ac6SBlue Swirl void helper_raise_exception(CPUPPCState *env, uint32_t exception) 1116ad71ed68SBlue Swirl { 1117db789c6cSBenjamin Herrenschmidt raise_exception_err_ra(env, exception, 0, 0); 1118ad71ed68SBlue Swirl } 1119ad71ed68SBlue Swirl 1120ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 1121e5f17ac6SBlue Swirl void helper_store_msr(CPUPPCState *env, target_ulong val) 1122ad71ed68SBlue Swirl { 1123db789c6cSBenjamin Herrenschmidt uint32_t excp = hreg_store_msr(env, val, 0); 1124259186a7SAndreas Färber 1125db789c6cSBenjamin Herrenschmidt if (excp != 0) { 1126db70b311SRichard Henderson CPUState *cs = env_cpu(env); 1127044897efSRichard Purdie cpu_interrupt_exittb(cs); 1128db789c6cSBenjamin Herrenschmidt raise_exception(env, excp); 1129ad71ed68SBlue Swirl } 1130ad71ed68SBlue Swirl } 1131ad71ed68SBlue Swirl 11327778a575SBenjamin Herrenschmidt #if defined(TARGET_PPC64) 11337778a575SBenjamin Herrenschmidt void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) 11347778a575SBenjamin Herrenschmidt { 11357778a575SBenjamin Herrenschmidt CPUState *cs; 11367778a575SBenjamin Herrenschmidt 1137db70b311SRichard Henderson cs = env_cpu(env); 11387778a575SBenjamin Herrenschmidt cs->halted = 1; 11397778a575SBenjamin Herrenschmidt 114047733729SDavid Gibson /* 114147733729SDavid Gibson * The architecture specifies that HDEC interrupts are discarded 114247733729SDavid Gibson * in PM states 11434b236b62SBenjamin Herrenschmidt */ 11444b236b62SBenjamin Herrenschmidt env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); 11454b236b62SBenjamin Herrenschmidt 11463621e2c9SBenjamin Herrenschmidt /* Condition for waking up at 0x100 */ 11471e7fd61dSBenjamin Herrenschmidt env->resume_as_sreset = (insn != PPC_PM_STOP) || 114821c0d66aSBenjamin Herrenschmidt (env->spr[SPR_PSSCR] & PSSCR_EC); 11497778a575SBenjamin Herrenschmidt } 11507778a575SBenjamin Herrenschmidt #endif /* defined(TARGET_PPC64) */ 11517778a575SBenjamin Herrenschmidt 1152a2e71b28SBenjamin Herrenschmidt static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) 1153ad71ed68SBlue Swirl { 1154db70b311SRichard Henderson CPUState *cs = env_cpu(env); 1155259186a7SAndreas Färber 1156a2e71b28SBenjamin Herrenschmidt /* MSR:POW cannot be set by any form of rfi */ 1157a2e71b28SBenjamin Herrenschmidt msr &= ~(1ULL << MSR_POW); 1158a2e71b28SBenjamin Herrenschmidt 1159ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1160a2e71b28SBenjamin Herrenschmidt /* Switching to 32-bit ? Crop the nip */ 1161a2e71b28SBenjamin Herrenschmidt if (!msr_is_64bit(env, msr)) { 1162ad71ed68SBlue Swirl nip = (uint32_t)nip; 1163ad71ed68SBlue Swirl } 1164ad71ed68SBlue Swirl #else 1165ad71ed68SBlue Swirl nip = (uint32_t)nip; 1166ad71ed68SBlue Swirl #endif 1167ad71ed68SBlue Swirl /* XXX: beware: this is false if VLE is supported */ 1168ad71ed68SBlue Swirl env->nip = nip & ~((target_ulong)0x00000003); 1169ad71ed68SBlue Swirl hreg_store_msr(env, msr, 1); 1170ad71ed68SBlue Swirl #if defined(DEBUG_OP) 1171ad71ed68SBlue Swirl cpu_dump_rfi(env->nip, env->msr); 1172ad71ed68SBlue Swirl #endif 117347733729SDavid Gibson /* 117447733729SDavid Gibson * No need to raise an exception here, as rfi is always the last 117547733729SDavid Gibson * insn of a TB 1176ad71ed68SBlue Swirl */ 1177044897efSRichard Purdie cpu_interrupt_exittb(cs); 1178a8b73734SNikunj A Dadhania /* Reset the reservation */ 1179a8b73734SNikunj A Dadhania env->reserve_addr = -1; 1180a8b73734SNikunj A Dadhania 1181cd0c6f47SBenjamin Herrenschmidt /* Context synchronizing: check if TCG TLB needs flush */ 1182e3cffe6fSNikunj A Dadhania check_tlb_flush(env, false); 1183ad71ed68SBlue Swirl } 1184ad71ed68SBlue Swirl 1185e5f17ac6SBlue Swirl void helper_rfi(CPUPPCState *env) 1186ad71ed68SBlue Swirl { 1187a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); 1188a1bb7384SScott Wood } 1189ad71ed68SBlue Swirl 1190a2e71b28SBenjamin Herrenschmidt #define MSR_BOOK3S_MASK 1191ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1192e5f17ac6SBlue Swirl void helper_rfid(CPUPPCState *env) 1193ad71ed68SBlue Swirl { 119447733729SDavid Gibson /* 1195136fbf65Szhaolichang * The architecture defines a number of rules for which bits can 119647733729SDavid Gibson * change but in practice, we handle this in hreg_store_msr() 1197a2e71b28SBenjamin Herrenschmidt * which will be called by do_rfi(), so there is no need to filter 1198a2e71b28SBenjamin Herrenschmidt * here 1199a2e71b28SBenjamin Herrenschmidt */ 1200a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]); 1201ad71ed68SBlue Swirl } 1202ad71ed68SBlue Swirl 12033c89b8d6SNicholas Piggin void helper_rfscv(CPUPPCState *env) 12043c89b8d6SNicholas Piggin { 12053c89b8d6SNicholas Piggin do_rfi(env, env->lr, env->ctr); 12063c89b8d6SNicholas Piggin } 12073c89b8d6SNicholas Piggin 1208e5f17ac6SBlue Swirl void helper_hrfid(CPUPPCState *env) 1209ad71ed68SBlue Swirl { 1210a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); 1211ad71ed68SBlue Swirl } 1212ad71ed68SBlue Swirl #endif 1213ad71ed68SBlue Swirl 1214ad71ed68SBlue Swirl /*****************************************************************************/ 1215ad71ed68SBlue Swirl /* Embedded PowerPC specific helpers */ 1216e5f17ac6SBlue Swirl void helper_40x_rfci(CPUPPCState *env) 1217ad71ed68SBlue Swirl { 1218a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3]); 1219ad71ed68SBlue Swirl } 1220ad71ed68SBlue Swirl 1221e5f17ac6SBlue Swirl void helper_rfci(CPUPPCState *env) 1222ad71ed68SBlue Swirl { 1223a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1]); 1224ad71ed68SBlue Swirl } 1225ad71ed68SBlue Swirl 1226e5f17ac6SBlue Swirl void helper_rfdi(CPUPPCState *env) 1227ad71ed68SBlue Swirl { 1228a1bb7384SScott Wood /* FIXME: choose CSRR1 or DSRR1 based on cpu type */ 1229a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1]); 1230ad71ed68SBlue Swirl } 1231ad71ed68SBlue Swirl 1232e5f17ac6SBlue Swirl void helper_rfmci(CPUPPCState *env) 1233ad71ed68SBlue Swirl { 1234a1bb7384SScott Wood /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ 1235a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]); 1236ad71ed68SBlue Swirl } 1237ad71ed68SBlue Swirl #endif 1238ad71ed68SBlue Swirl 1239e5f17ac6SBlue Swirl void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1240e5f17ac6SBlue Swirl uint32_t flags) 1241ad71ed68SBlue Swirl { 1242ad71ed68SBlue Swirl if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || 1243ad71ed68SBlue Swirl ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) || 1244ad71ed68SBlue Swirl ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) || 1245ad71ed68SBlue Swirl ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) || 1246ad71ed68SBlue Swirl ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) { 124772073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 124872073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1249ad71ed68SBlue Swirl } 1250ad71ed68SBlue Swirl } 1251ad71ed68SBlue Swirl 1252ad71ed68SBlue Swirl #if defined(TARGET_PPC64) 1253e5f17ac6SBlue Swirl void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2, 1254e5f17ac6SBlue Swirl uint32_t flags) 1255ad71ed68SBlue Swirl { 1256ad71ed68SBlue Swirl if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || 1257ad71ed68SBlue Swirl ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) || 1258ad71ed68SBlue Swirl ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) || 1259ad71ed68SBlue Swirl ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) || 1260ad71ed68SBlue Swirl ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) { 126172073dccSBenjamin Herrenschmidt raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, 126272073dccSBenjamin Herrenschmidt POWERPC_EXCP_TRAP, GETPC()); 1263ad71ed68SBlue Swirl } 1264ad71ed68SBlue Swirl } 1265ad71ed68SBlue Swirl #endif 1266ad71ed68SBlue Swirl 1267ad71ed68SBlue Swirl #if !defined(CONFIG_USER_ONLY) 1268ad71ed68SBlue Swirl /*****************************************************************************/ 1269ad71ed68SBlue Swirl /* PowerPC 601 specific instructions (POWER bridge) */ 1270ad71ed68SBlue Swirl 1271e5f17ac6SBlue Swirl void helper_rfsvc(CPUPPCState *env) 1272ad71ed68SBlue Swirl { 1273a2e71b28SBenjamin Herrenschmidt do_rfi(env, env->lr, env->ctr & 0x0000FFFF); 1274ad71ed68SBlue Swirl } 1275ad71ed68SBlue Swirl 1276ad71ed68SBlue Swirl /* Embedded.Processor Control */ 1277ad71ed68SBlue Swirl static int dbell2irq(target_ulong rb) 1278ad71ed68SBlue Swirl { 1279ad71ed68SBlue Swirl int msg = rb & DBELL_TYPE_MASK; 1280ad71ed68SBlue Swirl int irq = -1; 1281ad71ed68SBlue Swirl 1282ad71ed68SBlue Swirl switch (msg) { 1283ad71ed68SBlue Swirl case DBELL_TYPE_DBELL: 1284ad71ed68SBlue Swirl irq = PPC_INTERRUPT_DOORBELL; 1285ad71ed68SBlue Swirl break; 1286ad71ed68SBlue Swirl case DBELL_TYPE_DBELL_CRIT: 1287ad71ed68SBlue Swirl irq = PPC_INTERRUPT_CDOORBELL; 1288ad71ed68SBlue Swirl break; 1289ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL: 1290ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_CRIT: 1291ad71ed68SBlue Swirl case DBELL_TYPE_G_DBELL_MC: 1292ad71ed68SBlue Swirl /* XXX implement */ 1293ad71ed68SBlue Swirl default: 1294ad71ed68SBlue Swirl break; 1295ad71ed68SBlue Swirl } 1296ad71ed68SBlue Swirl 1297ad71ed68SBlue Swirl return irq; 1298ad71ed68SBlue Swirl } 1299ad71ed68SBlue Swirl 1300e5f17ac6SBlue Swirl void helper_msgclr(CPUPPCState *env, target_ulong rb) 1301ad71ed68SBlue Swirl { 1302ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1303ad71ed68SBlue Swirl 1304ad71ed68SBlue Swirl if (irq < 0) { 1305ad71ed68SBlue Swirl return; 1306ad71ed68SBlue Swirl } 1307ad71ed68SBlue Swirl 1308ad71ed68SBlue Swirl env->pending_interrupts &= ~(1 << irq); 1309ad71ed68SBlue Swirl } 1310ad71ed68SBlue Swirl 1311ad71ed68SBlue Swirl void helper_msgsnd(target_ulong rb) 1312ad71ed68SBlue Swirl { 1313ad71ed68SBlue Swirl int irq = dbell2irq(rb); 1314ad71ed68SBlue Swirl int pir = rb & DBELL_PIRTAG_MASK; 1315182735efSAndreas Färber CPUState *cs; 1316ad71ed68SBlue Swirl 1317ad71ed68SBlue Swirl if (irq < 0) { 1318ad71ed68SBlue Swirl return; 1319ad71ed68SBlue Swirl } 1320ad71ed68SBlue Swirl 1321f1c29ebcSThomas Huth qemu_mutex_lock_iothread(); 1322bdc44640SAndreas Färber CPU_FOREACH(cs) { 1323182735efSAndreas Färber PowerPCCPU *cpu = POWERPC_CPU(cs); 1324182735efSAndreas Färber CPUPPCState *cenv = &cpu->env; 1325182735efSAndreas Färber 1326ad71ed68SBlue Swirl if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { 1327ad71ed68SBlue Swirl cenv->pending_interrupts |= 1 << irq; 1328182735efSAndreas Färber cpu_interrupt(cs, CPU_INTERRUPT_HARD); 1329ad71ed68SBlue Swirl } 1330ad71ed68SBlue Swirl } 1331f1c29ebcSThomas Huth qemu_mutex_unlock_iothread(); 1332ad71ed68SBlue Swirl } 13337af1e7b0SCédric Le Goater 13347af1e7b0SCédric Le Goater /* Server Processor Control */ 13357af1e7b0SCédric Le Goater 13365ba7ba1dSCédric Le Goater static bool dbell_type_server(target_ulong rb) 13375ba7ba1dSCédric Le Goater { 133847733729SDavid Gibson /* 133947733729SDavid Gibson * A Directed Hypervisor Doorbell message is sent only if the 13407af1e7b0SCédric Le Goater * message type is 5. All other types are reserved and the 134147733729SDavid Gibson * instruction is a no-op 134247733729SDavid Gibson */ 13435ba7ba1dSCédric Le Goater return (rb & DBELL_TYPE_MASK) == DBELL_TYPE_DBELL_SERVER; 13447af1e7b0SCédric Le Goater } 13457af1e7b0SCédric Le Goater 13467af1e7b0SCédric Le Goater void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) 13477af1e7b0SCédric Le Goater { 13485ba7ba1dSCédric Le Goater if (!dbell_type_server(rb)) { 13497af1e7b0SCédric Le Goater return; 13507af1e7b0SCédric Le Goater } 13517af1e7b0SCédric Le Goater 13525ba7ba1dSCédric Le Goater env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL); 13537af1e7b0SCédric Le Goater } 13547af1e7b0SCédric Le Goater 13555ba7ba1dSCédric Le Goater static void book3s_msgsnd_common(int pir, int irq) 13567af1e7b0SCédric Le Goater { 13577af1e7b0SCédric Le Goater CPUState *cs; 13587af1e7b0SCédric Le Goater 13597af1e7b0SCédric Le Goater qemu_mutex_lock_iothread(); 13607af1e7b0SCédric Le Goater CPU_FOREACH(cs) { 13617af1e7b0SCédric Le Goater PowerPCCPU *cpu = POWERPC_CPU(cs); 13627af1e7b0SCédric Le Goater CPUPPCState *cenv = &cpu->env; 13637af1e7b0SCédric Le Goater 13647af1e7b0SCédric Le Goater /* TODO: broadcast message to all threads of the same processor */ 13657af1e7b0SCédric Le Goater if (cenv->spr_cb[SPR_PIR].default_value == pir) { 13667af1e7b0SCédric Le Goater cenv->pending_interrupts |= 1 << irq; 13677af1e7b0SCédric Le Goater cpu_interrupt(cs, CPU_INTERRUPT_HARD); 13687af1e7b0SCédric Le Goater } 13697af1e7b0SCédric Le Goater } 13707af1e7b0SCédric Le Goater qemu_mutex_unlock_iothread(); 13717af1e7b0SCédric Le Goater } 13725ba7ba1dSCédric Le Goater 13735ba7ba1dSCédric Le Goater void helper_book3s_msgsnd(target_ulong rb) 13745ba7ba1dSCédric Le Goater { 13755ba7ba1dSCédric Le Goater int pir = rb & DBELL_PROCIDTAG_MASK; 13765ba7ba1dSCédric Le Goater 13775ba7ba1dSCédric Le Goater if (!dbell_type_server(rb)) { 13785ba7ba1dSCédric Le Goater return; 13795ba7ba1dSCédric Le Goater } 13805ba7ba1dSCédric Le Goater 13815ba7ba1dSCédric Le Goater book3s_msgsnd_common(pir, PPC_INTERRUPT_HDOORBELL); 13825ba7ba1dSCédric Le Goater } 13835ba7ba1dSCédric Le Goater 13845ba7ba1dSCédric Le Goater #if defined(TARGET_PPC64) 13855ba7ba1dSCédric Le Goater void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb) 13865ba7ba1dSCédric Le Goater { 1387493028d8SCédric Le Goater helper_hfscr_facility_check(env, HFSCR_MSGP, "msgclrp", HFSCR_IC_MSGP); 1388493028d8SCédric Le Goater 13895ba7ba1dSCédric Le Goater if (!dbell_type_server(rb)) { 13905ba7ba1dSCédric Le Goater return; 13915ba7ba1dSCédric Le Goater } 13925ba7ba1dSCédric Le Goater 13935ba7ba1dSCédric Le Goater env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); 13945ba7ba1dSCédric Le Goater } 13955ba7ba1dSCédric Le Goater 13965ba7ba1dSCédric Le Goater /* 13975ba7ba1dSCédric Le Goater * sends a message to other threads that are on the same 13985ba7ba1dSCédric Le Goater * multi-threaded processor 13995ba7ba1dSCédric Le Goater */ 14005ba7ba1dSCédric Le Goater void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb) 14015ba7ba1dSCédric Le Goater { 14025ba7ba1dSCédric Le Goater int pir = env->spr_cb[SPR_PIR].default_value; 14035ba7ba1dSCédric Le Goater 1404493028d8SCédric Le Goater helper_hfscr_facility_check(env, HFSCR_MSGP, "msgsndp", HFSCR_IC_MSGP); 1405493028d8SCédric Le Goater 14065ba7ba1dSCédric Le Goater if (!dbell_type_server(rb)) { 14075ba7ba1dSCédric Le Goater return; 14085ba7ba1dSCédric Le Goater } 14095ba7ba1dSCédric Le Goater 14105ba7ba1dSCédric Le Goater /* TODO: TCG supports only one thread */ 14115ba7ba1dSCédric Le Goater 14125ba7ba1dSCédric Le Goater book3s_msgsnd_common(pir, PPC_INTERRUPT_DOORBELL); 14135ba7ba1dSCédric Le Goater } 14145ba7ba1dSCédric Le Goater #endif 1415ad71ed68SBlue Swirl #endif 14160f3110faSRichard Henderson 14170f3110faSRichard Henderson void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, 14180f3110faSRichard Henderson MMUAccessType access_type, 14190f3110faSRichard Henderson int mmu_idx, uintptr_t retaddr) 14200f3110faSRichard Henderson { 14210f3110faSRichard Henderson CPUPPCState *env = cs->env_ptr; 14220f3110faSRichard Henderson uint32_t insn; 14230f3110faSRichard Henderson 14240f3110faSRichard Henderson /* Restore state and reload the insn we executed, for filling in DSISR. */ 14250f3110faSRichard Henderson cpu_restore_state(cs, retaddr, true); 14260f3110faSRichard Henderson insn = cpu_ldl_code(env, env->nip); 14270f3110faSRichard Henderson 14280f3110faSRichard Henderson cs->exception_index = POWERPC_EXCP_ALIGN; 14290f3110faSRichard Henderson env->error_code = insn & 0x03FF0000; 14300f3110faSRichard Henderson cpu_loop_exit(cs); 14310f3110faSRichard Henderson } 1432