@@ -23,6 +23,10 @@
#include "internal.h"
#include "helper_regs.h"
+#if !defined(CONFIG_USER_ONLY)
+#include "ppc_intr.h"
+#endif
+
#include "trace.h"
#ifdef CONFIG_TCG
@@ -30,39 +34,10 @@
#include "exec/cpu_ldst.h"
#endif
-/* #define DEBUG_SOFTWARE_TLB */
-
/*****************************************************************************/
/* Exception processing */
#if !defined(CONFIG_USER_ONLY)
-static inline void dump_syscall(CPUPPCState *env)
-{
- qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
- " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64
- " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64
- " nip=" TARGET_FMT_lx "\n",
- ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
- ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
- ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7),
- ppc_dump_gpr(env, 8), env->nip);
-}
-
-static inline void dump_hcall(CPUPPCState *env)
-{
- qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64
- " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
- " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
- " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
- " nip=" TARGET_FMT_lx "\n",
- ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4),
- ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
- ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
- ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
- ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
- env->nip);
-}
-
static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
target_ulong *msr)
{
@@ -289,15 +264,6 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
check_tlb_flush(env, false);
}
-typedef struct PPCIntrArgs {
- target_ulong nip;
- target_ulong msr;
- target_ulong new_nip;
- target_ulong new_msr;
- int sprn_srr0;
- int sprn_srr1;
-} PPCIntrArgs;
-
/*
* Note that this function should be greatly optimized when called
* with a constant excp, from ppc_hw_interrupt
@@ -308,7 +274,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
CPUPPCState *env = &cpu->env;
int excp_model = env->excp_model;
PPCIntrArgs regs;
- int lev = -1;
+ bool ignore = false;
qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
" => %08x (%02x)\n", env->nip, excp, env->error_code);
@@ -374,442 +340,166 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp)
case POWERPC_EXCP_NONE:
/* Should never happen */
return;
+
case POWERPC_EXCP_CRITICAL: /* Critical input */
- switch (excp_model) {
- case POWERPC_EXCP_40x:
- regs.sprn_srr0 = SPR_40x_SRR2;
- regs.sprn_srr1 = SPR_40x_SRR3;
- break;
- case POWERPC_EXCP_BOOKE:
- regs.sprn_srr0 = SPR_BOOKE_CSRR0;
- regs.sprn_srr1 = SPR_BOOKE_CSRR1;
- break;
- case POWERPC_EXCP_G2:
- break;
- default:
- goto excp_invalid;
- }
+ ppc_intr_critical(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_MCHECK: /* Machine check exception */
- if (msr_me == 0) {
- /*
- * Machine check exception is not enabled. Enter
- * checkstop state.
- */
- fprintf(stderr, "Machine check while not allowed. "
- "Entering checkstop state\n");
- if (qemu_log_separate()) {
- qemu_log("Machine check while not allowed. "
- "Entering checkstop state\n");
- }
- cs->halted = 1;
- cpu_interrupt_exittb(cs);
- }
- if (env->msr_mask & MSR_HVB) {
- /*
- * ISA specifies HV, but can be delivered to guest with HV
- * clear (e.g., see FWNMI in PAPR).
- */
- regs.new_msr |= (target_ulong)MSR_HVB;
- }
-
- /* machine check exceptions don't have ME set */
- regs.new_msr &= ~((target_ulong)1 << MSR_ME);
-
- /* XXX: should also have something loaded in DAR / DSISR */
- switch (excp_model) {
- case POWERPC_EXCP_40x:
- regs.sprn_srr0 = SPR_40x_SRR2;
- regs.sprn_srr1 = SPR_40x_SRR3;
- break;
- case POWERPC_EXCP_BOOKE:
- /* FIXME: choose one or the other based on CPU type */
- regs.sprn_srr0 = SPR_BOOKE_MCSRR0;
- regs.sprn_srr1 = SPR_BOOKE_MCSRR1;
-
- env->spr[SPR_BOOKE_CSRR0] = regs.nip;
- env->spr[SPR_BOOKE_CSRR1] = regs.msr;
- break;
- default:
- break;
- }
+ ppc_intr_machine_check(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_DSI: /* Data storage exception */
- trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+ ppc_intr_data_storage(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_ISI: /* Instruction storage exception */
- trace_ppc_excp_isi(regs.msr, regs.nip);
- regs.msr |= env->error_code;
+ ppc_intr_insn_storage(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_EXTERNAL: /* External input */
- {
- bool lpes0;
-
- cs = CPU(cpu);
-
- /*
- * Exception targeting modifiers
- *
- * LPES0 is supported on POWER7/8/9
- * LPES1 is not supported (old iSeries mode)
- *
- * On anything else, we behave as if LPES0 is 1
- * (externals don't alter MSR:HV)
- */
-#if defined(TARGET_PPC64)
- if (excp_model == POWERPC_EXCP_POWER7 ||
- excp_model == POWERPC_EXCP_POWER8 ||
- excp_model == POWERPC_EXCP_POWER9 ||
- excp_model == POWERPC_EXCP_POWER10) {
- lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
- } else
-#endif /* defined(TARGET_PPC64) */
- {
- lpes0 = true;
- }
-
- if (!lpes0) {
- regs.new_msr |= (target_ulong)MSR_HVB;
- regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
- regs.sprn_srr0 = SPR_HSRR0;
- regs.sprn_srr1 = SPR_HSRR1;
- }
- if (env->mpic_proxy) {
- /* IACK the IRQ on delivery */
- env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
- }
+ ppc_intr_external(cpu, ®s, &ignore);
break;
- }
case POWERPC_EXCP_ALIGN: /* Alignment exception */
- /* Get rS/rD and rA from faulting opcode */
- /*
- * Note: the opcode fields will not be set properly for a
- * direct store load/store, but nobody cares as nobody
- * actually uses direct store segments.
- */
- env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
+ ppc_intr_alignment(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_PROGRAM: /* Program exception */
- switch (env->error_code & ~0xF) {
- case POWERPC_EXCP_FP:
- if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
- trace_ppc_excp_fp_ignore();
- cs->exception_index = POWERPC_EXCP_NONE;
- env->error_code = 0;
- return;
- }
-
- /*
- * FP exceptions always have NIP pointing to the faulting
- * instruction, so always use store_next and claim we are
- * precise in the MSR.
- */
- regs.msr |= 0x00100000;
- env->spr[SPR_BOOKE_ESR] = ESR_FP;
- break;
- case POWERPC_EXCP_INVAL:
- trace_ppc_excp_inval(regs.nip);
- regs.msr |= 0x00080000;
- env->spr[SPR_BOOKE_ESR] = ESR_PIL;
- break;
- case POWERPC_EXCP_PRIV:
- regs.msr |= 0x00040000;
- env->spr[SPR_BOOKE_ESR] = ESR_PPR;
- break;
- case POWERPC_EXCP_TRAP:
- regs.msr |= 0x00020000;
- env->spr[SPR_BOOKE_ESR] = ESR_PTR;
- break;
- default:
- /* Should never occur */
- cpu_abort(cs, "Invalid program exception %d. Aborting\n",
- env->error_code);
- break;
- }
+ ppc_intr_program(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_SYSCALL: /* System call exception */
- lev = env->error_code;
-
- if ((lev == 1) && cpu->vhyp) {
- dump_hcall(env);
- } else {
- dump_syscall(env);
- }
-
- /*
- * We need to correct the NIP which in this case is supposed
- * to point to the next instruction. We also set env->nip here
- * because the modification needs to be accessible by the
- * virtual hypervisor code below.
- */
- regs.nip += 4;
- env->nip = regs.nip;
-
- /* "PAPR mode" built-in hypercall emulation */
- if ((lev == 1) && cpu->vhyp) {
- PPCVirtualHypervisorClass *vhc =
- PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
- vhc->hypercall(cpu->vhyp, cpu);
- return;
- }
-
- if (lev == 1) {
- regs.new_msr |= (target_ulong)MSR_HVB;
- }
+ ppc_intr_system_call(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */
- lev = env->error_code;
- dump_syscall(env);
- regs.nip += 4;
- regs.new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
- regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-
- regs.new_nip += lev * 0x20;
-
- env->lr = regs.nip;
- env->ctr = regs.msr;
+ ppc_intr_system_call_vectored(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
case POWERPC_EXCP_DECR: /* Decrementer exception */
break;
case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
- /* FIT on 4xx */
- trace_ppc_excp_print("FIT");
+ ppc_intr_fit(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
- trace_ppc_excp_print("WDT");
- switch (excp_model) {
- case POWERPC_EXCP_BOOKE:
- regs.sprn_srr0 = SPR_BOOKE_CSRR0;
- regs.sprn_srr1 = SPR_BOOKE_CSRR1;
- break;
- default:
- break;
- }
+ ppc_intr_watchdog(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_DTLB: /* Data TLB error */
case POWERPC_EXCP_ITLB: /* Instruction TLB error */
break;
case POWERPC_EXCP_DEBUG: /* Debug interrupt */
- if (env->flags & POWERPC_FLAG_DE) {
- /* FIXME: choose one or the other based on CPU type */
- regs.sprn_srr0 = SPR_BOOKE_DSRR0;
- regs.sprn_srr1 = SPR_BOOKE_DSRR1;
-
- env->spr[SPR_BOOKE_CSRR0] = regs.nip;
- env->spr[SPR_BOOKE_CSRR1] = regs.msr;
- /* DBSR already modified by caller */
- } else {
- cpu_abort(cs, "Debug exception triggered on unsupported model\n");
- }
+ ppc_intr_debug(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable/VPU */
- env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+ ppc_intr_spe_unavailable(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
- /* XXX: TODO */
- cpu_abort(cs, "Embedded floating point data exception "
- "is not implemented yet !\n");
- env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+ ppc_intr_embedded_fp_data(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
- /* XXX: TODO */
- cpu_abort(cs, "Embedded floating point round exception "
- "is not implemented yet !\n");
- env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+ ppc_intr_embedded_fp_round(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
- /* XXX: TODO */
- cpu_abort(cs,
- "Performance counter exception is not implemented yet !\n");
+ ppc_intr_embedded_perf_monitor(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
break;
case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
- regs.sprn_srr0 = SPR_BOOKE_CSRR0;
- regs.sprn_srr1 = SPR_BOOKE_CSRR1;
+ ppc_intr_embedded_doorbell_crit(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_RESET: /* System reset exception */
- /* A power-saving exception sets ME, otherwise it is unchanged */
- if (msr_pow) {
- /* indicate that we resumed from power save mode */
- regs.msr |= 0x10000;
- regs.new_msr |= ((target_ulong)1 << MSR_ME);
- }
- if (env->msr_mask & MSR_HVB) {
- /*
- * ISA specifies HV, but can be delivered to guest with HV
- * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
- */
- regs.new_msr |= (target_ulong)MSR_HVB;
- } else {
- if (msr_pow) {
- cpu_abort(cs, "Trying to deliver power-saving system reset "
- "exception %d with no HV support\n", excp);
- }
- }
+ ppc_intr_system_reset(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_DSEG: /* Data segment exception */
case POWERPC_EXCP_ISEG: /* Instruction segment exception */
case POWERPC_EXCP_TRACE: /* Trace exception */
break;
case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
- regs.msr |= env->error_code;
- /* fall through */
+ ppc_intr_hv_insn_storage(cpu, ®s, &ignore);
+ break;
case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
+ ppc_intr_hv_decrementer(cpu, ®s, &ignore);
+ break;
case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
+ ppc_intr_hv_data_storage(cpu, ®s, &ignore);
+ break;
case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
+ ppc_intr_hv_data_segment(cpu, ®s, &ignore);
+ break;
case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
+ ppc_intr_hv_insn_segment(cpu, ®s, &ignore);
+ break;
case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */
+ ppc_intr_hv_doorbell(cpu, ®s, &ignore);
+ break;
case POWERPC_EXCP_HV_EMU:
+ ppc_intr_hv_emulation(cpu, ®s, &ignore);
+ break;
case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */
- regs.sprn_srr0 = SPR_HSRR0;
- regs.sprn_srr1 = SPR_HSRR1;
- regs.new_msr |= (target_ulong)MSR_HVB;
- regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ ppc_intr_hv_virtualization(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_VPU: /* Vector unavailable exception */
case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
case POWERPC_EXCP_FU: /* Facility unavailable exception */
-#ifdef TARGET_PPC64
- env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
-#endif
+ ppc_intr_facility_unavail(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_HV_FU: /* Hypervisor Facility Unavailable Exception */
-#ifdef TARGET_PPC64
- env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
- regs.sprn_srr0 = SPR_HSRR0;
- regs.sprn_srr1 = SPR_HSRR1;
- regs.new_msr |= (target_ulong)MSR_HVB;
- regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-#endif
+ ppc_intr_hv_facility_unavail(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
- trace_ppc_excp_print("PIT");
+ ppc_intr_programmable_timer(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_IO: /* IO error exception */
- /* XXX: TODO */
- cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
+ ppc_intr_io_error(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_RUNM: /* Run mode exception */
- /* XXX: TODO */
- cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
+ ppc_intr_run_mode(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_EMUL: /* Emulation trap exception */
- /* XXX: TODO */
- cpu_abort(cs, "602 emulation trap exception "
- "is not implemented yet !\n");
+ ppc_intr_emulation(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
- switch (excp_model) {
- case POWERPC_EXCP_602:
- case POWERPC_EXCP_603:
- case POWERPC_EXCP_G2:
- /* Swap temporary saved registers with GPRs */
- if (!(regs.new_msr & ((target_ulong)1 << MSR_TGPR))) {
- regs.new_msr |= (target_ulong)1 << MSR_TGPR;
- hreg_swap_gpr_tgpr(env);
- }
- /* fall through */
- case POWERPC_EXCP_7x5:
-#if defined(DEBUG_SOFTWARE_TLB)
- if (qemu_log_enabled()) {
- const char *es;
- target_ulong *miss, *cmp;
- int en;
-
- if (excp == POWERPC_EXCP_IFTLB) {
- es = "I";
- en = 'I';
- miss = &env->spr[SPR_IMISS];
- cmp = &env->spr[SPR_ICMP];
- } else {
- if (excp == POWERPC_EXCP_DLTLB) {
- es = "DL";
- } else {
- es = "DS";
- }
- en = 'D';
- miss = &env->spr[SPR_DMISS];
- cmp = &env->spr[SPR_DCMP];
- }
- qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
- TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
- TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
- env->spr[SPR_HASH1], env->spr[SPR_HASH2],
- env->error_code);
- }
-#endif
- regs.msr |= env->crf[0] << 28;
- regs.msr |= env->error_code; /* key, D/I, S/L bits */
- /* Set way using a LRU mechanism */
- regs.msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
- break;
- default:
- cpu_abort(cs, "Invalid TLB miss exception\n");
- break;
- }
+ ppc_intr_tlb_miss(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_FPA: /* Floating-point assist exception */
- /* XXX: TODO */
- cpu_abort(cs, "Floating point assist exception "
- "is not implemented yet !\n");
+ ppc_intr_fpa(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_DABR: /* Data address breakpoint */
- /* XXX: TODO */
- cpu_abort(cs, "DABR exception is not implemented yet !\n");
+ ppc_intr_dabr(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
- /* XXX: TODO */
- cpu_abort(cs, "IABR exception is not implemented yet !\n");
+ ppc_intr_iabr(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_SMI: /* System management interrupt */
- /* XXX: TODO */
- cpu_abort(cs, "SMI exception is not implemented yet !\n");
+ ppc_intr_smi(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_THERM: /* Thermal interrupt */
- /* XXX: TODO */
- cpu_abort(cs, "Thermal management exception "
- "is not implemented yet !\n");
+ ppc_intr_therm(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
- /* XXX: TODO */
- cpu_abort(cs,
- "Performance counter exception is not implemented yet !\n");
+ ppc_intr_perfm(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_VPUA: /* Vector assist exception */
- /* XXX: TODO */
- cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
+ ppc_intr_vpua(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_SOFTP: /* Soft patch exception */
- /* XXX: TODO */
- cpu_abort(cs,
- "970 soft-patch exception is not implemented yet !\n");
+ ppc_intr_softp(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_MAINT: /* Maintenance exception */
- /* XXX: TODO */
- cpu_abort(cs,
- "970 maintenance exception is not implemented yet !\n");
+ ppc_intr_maint(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
- /* XXX: TODO */
- cpu_abort(cs, "Maskable external exception "
- "is not implemented yet !\n");
+ ppc_intr_mextbr(cpu, ®s, &ignore);
break;
case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
- /* XXX: TODO */
- cpu_abort(cs, "Non maskable external exception "
- "is not implemented yet !\n");
+ ppc_intr_nmextbr(cpu, ®s, &ignore);
break;
default:
- excp_invalid:
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
break;
}
+ if (ignore) {
+ /* No further setup is needed for this interrupt */
+ return;
+ }
+
/* Sanity check */
if (!(env->msr_mask & MSR_HVB)) {
if (regs.new_msr & MSR_HVB) {
new file mode 100644
@@ -0,0 +1,645 @@
+/*
+ * PowerPC interrupt emulation.
+ *
+ * Copyright (C) 2021 IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "cpu.h"
+#include "ppc_intr.h"
+#include "trace.h"
+
+/* for hreg_swap_gpr_tgpr */
+#include "helper_regs.h"
+
+/* #define DEBUG_SOFTWARE_TLB */
+
+void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+ int excp_model = env->excp_model;
+
+ switch (excp_model) {
+ case POWERPC_EXCP_40x:
+ regs->sprn_srr0 = SPR_40x_SRR2;
+ regs->sprn_srr1 = SPR_40x_SRR3;
+ break;
+ case POWERPC_EXCP_BOOKE:
+ regs->sprn_srr0 = SPR_BOOKE_CSRR0;
+ regs->sprn_srr1 = SPR_BOOKE_CSRR1;
+ break;
+ case POWERPC_EXCP_G2:
+ break;
+ default:
+ cpu_abort(CPU(cpu), "Invalid PowerPC critical exception. Aborting\n");
+ break;
+ }
+}
+
+void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+ int excp_model = env->excp_model;
+
+ if (msr_me == 0) {
+ /*
+ * Machine check exception is not enabled. Enter
+ * checkstop state.
+ */
+ fprintf(stderr, "Machine check while not allowed. "
+ "Entering checkstop state\n");
+ if (qemu_log_separate()) {
+ qemu_log("Machine check while not allowed. "
+ "Entering checkstop state\n");
+ }
+ cs->halted = 1;
+ cpu_interrupt_exittb(cs);
+ }
+ if (env->msr_mask & MSR_HVB) {
+ /*
+ * ISA specifies HV, but can be delivered to guest with HV
+ * clear (e.g., see FWNMI in PAPR).
+ */
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ }
+
+ /* machine check exceptions don't have ME set */
+ regs->new_msr &= ~((target_ulong)1 << MSR_ME);
+
+ /* XXX: should also have something loaded in DAR / DSISR */
+ switch (excp_model) {
+ case POWERPC_EXCP_40x:
+ regs->sprn_srr0 = SPR_40x_SRR2;
+ regs->sprn_srr1 = SPR_40x_SRR3;
+ break;
+ case POWERPC_EXCP_BOOKE:
+ /* FIXME: choose one or the other based on CPU type */
+ regs->sprn_srr0 = SPR_BOOKE_MCSRR0;
+ regs->sprn_srr1 = SPR_BOOKE_MCSRR1;
+
+ env->spr[SPR_BOOKE_CSRR0] = regs->nip;
+ env->spr[SPR_BOOKE_CSRR1] = regs->msr;
+ break;
+ default:
+ break;
+ }
+}
+
+void ppc_intr_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+}
+
+
+void ppc_intr_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ trace_ppc_excp_isi(regs->msr, regs->nip);
+
+ regs->msr |= env->error_code;
+}
+
+void ppc_intr_external(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+ bool lpes0;
+#if defined(TARGET_PPC64)
+ int excp_model = env->excp_model;
+#endif /* defined(TARGET_PPC64) */
+
+ /*
+ * Exception targeting modifiers
+ *
+ * LPES0 is supported on POWER7/8/9
+ * LPES1 is not supported (old iSeries mode)
+ *
+ * On anything else, we behave as if LPES0 is 1
+ * (externals don't alter MSR:HV)
+ */
+#if defined(TARGET_PPC64)
+ if (excp_model == POWERPC_EXCP_POWER7 ||
+ excp_model == POWERPC_EXCP_POWER8 ||
+ excp_model == POWERPC_EXCP_POWER9 ||
+ excp_model == POWERPC_EXCP_POWER10) {
+ lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+ } else
+#endif /* defined(TARGET_PPC64) */
+ {
+ lpes0 = true;
+ }
+
+ if (!lpes0) {
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ regs->sprn_srr0 = SPR_HSRR0;
+ regs->sprn_srr1 = SPR_HSRR1;
+ }
+ if (env->mpic_proxy) {
+ /* IACK the IRQ on delivery */
+ env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
+ }
+}
+
+void ppc_intr_alignment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ /* Get rS/rD and rA from faulting opcode */
+ /*
+ * Note: the opcode fields will not be set properly for a
+ * direct store load/store, but nobody cares as nobody
+ * actually uses direct store segments.
+ */
+ env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
+}
+
+void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+
+ switch (env->error_code & ~0xF) {
+ case POWERPC_EXCP_FP:
+ if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
+ trace_ppc_excp_fp_ignore();
+ cs->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+
+ *ignore = true;
+ return;
+ }
+
+ /*
+ * FP exceptions always have NIP pointing to the faulting
+ * instruction, so always use store_next and claim we are
+ * precise in the MSR.
+ */
+ regs->msr |= 0x00100000;
+ env->spr[SPR_BOOKE_ESR] = ESR_FP;
+ break;
+ case POWERPC_EXCP_INVAL:
+ trace_ppc_excp_inval(regs->nip);
+ regs->msr |= 0x00080000;
+ env->spr[SPR_BOOKE_ESR] = ESR_PIL;
+ break;
+ case POWERPC_EXCP_PRIV:
+ regs->msr |= 0x00040000;
+ env->spr[SPR_BOOKE_ESR] = ESR_PPR;
+ break;
+ case POWERPC_EXCP_TRAP:
+ regs->msr |= 0x00020000;
+ env->spr[SPR_BOOKE_ESR] = ESR_PTR;
+ break;
+ default:
+ /* Should never occur */
+ cpu_abort(cs, "Invalid program exception %d. Aborting\n",
+ env->error_code);
+ break;
+ }
+}
+
+static inline void dump_syscall(CPUPPCState *env)
+{
+ qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
+ " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64
+ " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64
+ " nip=" TARGET_FMT_lx "\n",
+ ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
+ ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
+ ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7),
+ ppc_dump_gpr(env, 8), env->nip);
+}
+
+static inline void dump_hcall(CPUPPCState *env)
+{
+ qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64
+ " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
+ " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
+ " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
+ " nip=" TARGET_FMT_lx "\n",
+ ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4),
+ ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
+ ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
+ ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
+ ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
+ env->nip);
+}
+
+void ppc_intr_system_call(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+ int lev = env->error_code;
+
+ if ((lev == 1) && cpu->vhyp) {
+ dump_hcall(env);
+ } else {
+ dump_syscall(env);
+ }
+
+ /*
+ * We need to correct the NIP which in this case is supposed
+ * to point to the next instruction. We also set env->nip here
+ * because the modification needs to be accessible by the
+ * virtual hypervisor code below.
+ */
+ regs->nip += 4;
+ env->nip = regs->nip;
+
+ /* "PAPR mode" built-in hypercall emulation */
+ if ((lev == 1) && cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ vhc->hypercall(cpu->vhyp, cpu);
+
+ *ignore = true;
+ return;
+ }
+
+ if (lev == 1) {
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ }
+}
+
+void ppc_intr_system_call_vectored(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+ int lev = env->error_code;
+
+ dump_syscall(env);
+
+ regs->nip += 4;
+ regs->new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
+ regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ regs->new_nip += lev * 0x20;
+
+ env->lr = regs->nip;
+ env->ctr = regs->msr;
+}
+
+void ppc_intr_fit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* FIT on 4xx */
+ trace_ppc_excp_print("FIT");
+};
+
+void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+ int excp_model = env->excp_model;
+
+ trace_ppc_excp_print("WDT");
+ switch (excp_model) {
+ case POWERPC_EXCP_BOOKE:
+ regs->sprn_srr0 = SPR_BOOKE_CSRR0;
+ regs->sprn_srr1 = SPR_BOOKE_CSRR1;
+ break;
+ default:
+ break;
+ }
+}
+
+void ppc_intr_debug(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ if (env->flags & POWERPC_FLAG_DE) {
+ /* FIXME: choose one or the other based on CPU type */
+ regs->sprn_srr0 = SPR_BOOKE_DSRR0;
+ regs->sprn_srr1 = SPR_BOOKE_DSRR1;
+
+ env->spr[SPR_BOOKE_CSRR0] = regs->nip;
+ env->spr[SPR_BOOKE_CSRR1] = regs->msr;
+ /* DBSR already modified by caller */
+ } else {
+ cpu_abort(CPU(cpu), "Debug exception triggered on unsupported model\n");
+ }
+}
+
+void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+}
+
+void ppc_intr_embedded_fp_data(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "Embedded floating point data exception "
+ "is not implemented yet !\n");
+ env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+}
+
+void ppc_intr_embedded_fp_round(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "Embedded floating point round exception "
+ "is not implemented yet !\n");
+ env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+}
+
+void ppc_intr_embedded_perf_monitor(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu),
+ "Performance counter exception is not implemented yet !\n");
+}
+
+void ppc_intr_embedded_doorbell_crit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ regs->sprn_srr0 = SPR_BOOKE_CSRR0;
+ regs->sprn_srr1 = SPR_BOOKE_CSRR1;
+}
+
+void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ /* A power-saving exception sets ME, otherwise it is unchanged */
+ if (msr_pow) {
+ /* indicate that we resumed from power save mode */
+ regs->msr |= 0x10000;
+ regs->new_msr |= ((target_ulong)1 << MSR_ME);
+ }
+ if (env->msr_mask & MSR_HVB) {
+ /*
+ * ISA specifies HV, but can be delivered to guest with HV
+ * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
+ */
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ } else {
+ if (msr_pow) {
+ cpu_abort(CPU(cpu), "Trying to deliver power-saving system reset "
+ "exception with no HV support\n");
+ }
+ }
+}
+
+void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ regs->msr |= env->error_code;
+
+ regs->sprn_srr0 = SPR_HSRR0;
+ regs->sprn_srr1 = SPR_HSRR1;
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+}
+
+void ppc_intr_hv_decrementer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ regs->sprn_srr0 = SPR_HSRR0;
+ regs->sprn_srr1 = SPR_HSRR1;
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+}
+
+void ppc_intr_hv_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ regs->sprn_srr0 = SPR_HSRR0;
+ regs->sprn_srr1 = SPR_HSRR1;
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+}
+
+void ppc_intr_hv_data_segment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ regs->sprn_srr0 = SPR_HSRR0;
+ regs->sprn_srr1 = SPR_HSRR1;
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+}
+
+void ppc_intr_hv_insn_segment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ regs->sprn_srr0 = SPR_HSRR0;
+ regs->sprn_srr1 = SPR_HSRR1;
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+}
+
+void ppc_intr_hv_doorbell(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ regs->sprn_srr0 = SPR_HSRR0;
+ regs->sprn_srr1 = SPR_HSRR1;
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+}
+
+void ppc_intr_hv_emulation(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ regs->sprn_srr0 = SPR_HSRR0;
+ regs->sprn_srr1 = SPR_HSRR1;
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+}
+
+void ppc_intr_hv_virtualization(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+
+ regs->sprn_srr0 = SPR_HSRR0;
+ regs->sprn_srr1 = SPR_HSRR1;
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+}
+
+void ppc_intr_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+#ifdef TARGET_PPC64
+ CPUPPCState *env = &cpu->env;
+ env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
+#endif
+}
+
+void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+#ifdef TARGET_PPC64
+ CPUPPCState *env = &cpu->env;
+ env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
+
+ regs->sprn_srr0 = SPR_HSRR0;
+ regs->sprn_srr1 = SPR_HSRR1;
+ regs->new_msr |= (target_ulong)MSR_HVB;
+ regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+#endif
+}
+
+void ppc_intr_programmable_timer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ trace_ppc_excp_print("PIT");
+}
+
+void ppc_intr_io_error(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "601 IO error exception is not implemented yet !\n");
+}
+
+void ppc_intr_run_mode(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "601 run mode exception is not implemented yet !\n");
+}
+
+void ppc_intr_emulation(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "602 emulation trap exception is not implemented yet !\n");
+}
+
+void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ CPUPPCState *env = &cpu->env;
+ int excp_model = env->excp_model;
+
+ switch (excp_model) {
+ case POWERPC_EXCP_602:
+ case POWERPC_EXCP_603:
+ case POWERPC_EXCP_G2:
+ /* Swap temporary saved registers with GPRs */
+ if (!(regs->new_msr & ((target_ulong)1 << MSR_TGPR))) {
+ regs->new_msr |= (target_ulong)1 << MSR_TGPR;
+ hreg_swap_gpr_tgpr(env);
+ }
+ /* fall through */
+ case POWERPC_EXCP_7x5:
+#if defined(DEBUG_SOFTWARE_TLB)
+ if (qemu_log_enabled()) {
+ const char *es;
+ target_ulong *miss, *cmp;
+ int en;
+
+ if (excp == POWERPC_EXCP_IFTLB) {
+ es = "I";
+ en = 'I';
+ miss = &env->spr[imiss_sprn];
+ cmp = &env->spr[icmp_sprn];
+ } else {
+ if (excp == POWERPC_EXCP_DLTLB) {
+ es = "DL";
+ } else {
+ es = "DS";
+ }
+ en = 'D';
+ miss = &env->spr[dmiss_sprn];
+ cmp = &env->spr[dcmp_srpn];
+ }
+
+ qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
+ TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
+ TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
+ env->spr[SPR_HASH1], env->spr[SPR_HASH2],
+ env->error_code);
+ }
+#endif
+ regs->msr |= env->crf[0] << 28;
+ regs->msr |= env->error_code; /* key, D/I, S/L bits */
+
+ /* Set way using a LRU mechanism */
+ regs->msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
+
+ break;
+ default:
+ cpu_abort(CPU(cpu), "Invalid instruction TLB miss exception\n");
+ break;
+ }
+}
+
+void ppc_intr_fpa(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "Floating point assist exception "
+ "is not implemented yet !\n");
+}
+
+void ppc_intr_dabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "DABR exception is not implemented yet !\n");
+}
+
+void ppc_intr_iabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "IABR exception is not implemented yet !\n");
+}
+
+void ppc_intr_smi(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "SMI exception is not implemented yet !\n");
+}
+
+void ppc_intr_therm(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "Thermal management exception "
+ "is not implemented yet !\n");
+}
+
+void ppc_intr_perfm(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu),
+ "Performance counter exception is not implemented yet !\n");
+}
+
+void ppc_intr_vpua(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "VPU assist exception is not implemented yet !\n");
+}
+
+void ppc_intr_softp(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu),
+ "970 soft-patch exception is not implemented yet !\n");
+}
+
+void ppc_intr_maint(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu),
+ "970 maintenance exception is not implemented yet !\n");
+}
+
+void ppc_intr_mextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "Maskable external exception "
+ "is not implemented yet !\n");
+}
+
+void ppc_intr_nmextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore)
+{
+ /* XXX: TODO */
+ cpu_abort(CPU(cpu), "Non maskable external exception "
+ "is not implemented yet !\n");
+}
@@ -39,6 +39,7 @@ ppc_softmmu_ss.add(files(
'mmu-hash32.c',
'mmu_common.c',
'monitor.c',
+ 'interrupts.c',
))
ppc_softmmu_ss.add(when: 'CONFIG_TCG', if_true: files(
'mmu_helper.c',
new file mode 100644
@@ -0,0 +1,61 @@
+#ifndef PPC_INTR_H
+#define PPC_INTR_H
+
+typedef struct PPCIntrArgs PPCIntrArgs;
+
+struct PPCIntrArgs {
+ target_ulong nip;
+ target_ulong msr;
+ target_ulong new_nip;
+ target_ulong new_msr;
+ int sprn_srr0;
+ int sprn_srr1;
+};
+
+void ppc_intr_alignment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_dabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_debug(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_embedded_doorbell_crit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_embedded_fp_data(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_embedded_fp_round(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_embedded_perf_monitor(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_emulation(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_external(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_fit(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_fpa(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_data_segment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_decrementer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_doorbell(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_emulation(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_insn_segment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_hv_virtualization(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_iabr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_io_error(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_maint(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_mextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_nmextbr(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_noop(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_perfm(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_programmable_timer(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_run_mode(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_smi(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_softp(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_system_call(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_system_call_vectored(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_therm(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_vpua(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore);
+
+#endif /* PPC_INTR_H */
Extract the interrupt setup routines into their own functions and put everything in a separate file. These routines will be made independent of exception model in the following patches. This change is just to facilitate the review. No funcional change intended. Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com> --- target/ppc/excp_helper.c | 434 ++++---------------------- target/ppc/interrupts.c | 645 +++++++++++++++++++++++++++++++++++++++ target/ppc/meson.build | 1 + target/ppc/ppc_intr.h | 61 ++++ 4 files changed, 769 insertions(+), 372 deletions(-) create mode 100644 target/ppc/interrupts.c create mode 100644 target/ppc/ppc_intr.h