This change along with the next few patches which move the powerpc_excp_foo functions into the cpu_foo.c files has the following purposes:
- Move the exception dispatching (powerpc_excp) closer to the exception vectors initialization (init_excp); - Make it immediately clear which CPUs are affected by the exception dispatching code; - Move code which is not a TCG helper out of excp_helpers.c. Aside from the obvious, this also helps with separation between TCG and KVM code; excp_helpers could be TCG-only (we're not quite there yet); - We could start thinking about ways of simplifying the init_excp/powerpc_excp relationship since both users of the POWERPC_EXCP vector addresses are now in the same place. Signed-off-by: Fabiano Rosas <faro...@linux.ibm.com> --- target/ppc/cpu.h | 1 + target/ppc/cpu_40x.c | 150 ++++++++++++++++++++++++++++++++++++++- target/ppc/excp_helper.c | 138 ----------------------------------- 3 files changed, 150 insertions(+), 139 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index c7bb10b0bf..ba3740ea92 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -179,6 +179,7 @@ const char *powerpc_excp_name(int excp); void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector, target_ulong msr); void powerpc_reset_excp_state(PowerPCCPU *cpu); +void powerpc_excp_40x(PowerPCCPU *cpu, int excp); #define PPC_INPUT(env) ((env)->bus_model) diff --git a/target/ppc/cpu_40x.c b/target/ppc/cpu_40x.c index 4ed2cbc305..4b7bbeb28c 100644 --- a/target/ppc/cpu_40x.c +++ b/target/ppc/cpu_40x.c @@ -1,5 +1,5 @@ /* - * CPU initialization for PowerPC 40x CPUs + * CPU initialization and exception dispatching for PowerPC 40x CPUs * * Copyright IBM Corp. 2022 * @@ -8,9 +8,157 @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "hw/ppc/ppc.h" #include "cpu.h" #include "spr_common.h" +#include "trace.h" +#include "helper_regs.h" + +#if !defined(CONFIG_USER_ONLY) +void powerpc_excp_40x(PowerPCCPU *cpu, int excp) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + target_ulong msr, new_msr, vector; + int srr0, srr1; + + /* new srr1 value excluding must-be-zero bits */ + msr = env->msr & ~0x783f0000ULL; + + /* + * new interrupt handler msr preserves existing ME unless + * explicitly overriden. + */ + new_msr = env->msr & (((target_ulong)1 << MSR_ME)); + + /* target registers */ + srr0 = SPR_SRR0; + srr1 = SPR_SRR1; + + /* + * Hypervisor emulation assistance interrupt only exists on server + * arch 2.05 server or later. + */ + if (excp == POWERPC_EXCP_HV_EMU) { + excp = POWERPC_EXCP_PROGRAM; + } + + vector = env->excp_vectors[excp]; + if (vector == (target_ulong)-1ULL) { + cpu_abort(cs, "Raised an exception without defined vector %d\n", + excp); + } + + vector |= env->excp_prefix; + + switch (excp) { + case POWERPC_EXCP_CRITICAL: /* Critical input */ + srr0 = SPR_40x_SRR2; + srr1 = SPR_40x_SRR3; + 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); + } + + /* machine check exceptions don't have ME set */ + new_msr &= ~((target_ulong)1 << MSR_ME); + + srr0 = SPR_40x_SRR2; + srr1 = SPR_40x_SRR3; + break; + case POWERPC_EXCP_DSI: /* Data storage exception */ + trace_ppc_excp_dsi(env->spr[SPR_40x_ESR], env->spr[SPR_40x_DEAR]); + break; + case POWERPC_EXCP_ISI: /* Instruction storage exception */ + trace_ppc_excp_isi(msr, env->nip); + break; + case POWERPC_EXCP_EXTERNAL: /* External input */ + break; + case POWERPC_EXCP_ALIGN: /* Alignment exception */ + 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(); + powerpc_reset_excp_state(cpu); + return; + } + env->spr[SPR_40x_ESR] = ESR_FP; + break; + case POWERPC_EXCP_INVAL: + trace_ppc_excp_inval(env->nip); + env->spr[SPR_40x_ESR] = ESR_PIL; + break; + case POWERPC_EXCP_PRIV: + env->spr[SPR_40x_ESR] = ESR_PPR; + break; + case POWERPC_EXCP_TRAP: + env->spr[SPR_40x_ESR] = ESR_PTR; + break; + default: + cpu_abort(cs, "Invalid program exception %d. Aborting\n", + env->error_code); + break; + } + break; + case POWERPC_EXCP_SYSCALL: /* System call exception */ + trace_ppc_syscall(env, 0); + + /* + * We need to correct the NIP which in this case is supposed + * to point to the next instruction + */ + env->nip += 4; + break; + case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ + trace_ppc_excp_print("FIT"); + break; + case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ + trace_ppc_excp_print("WDT"); + break; + case POWERPC_EXCP_DTLB: /* Data TLB error */ + case POWERPC_EXCP_ITLB: /* Instruction TLB error */ + break; + case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ + trace_ppc_excp_print("PIT"); + break; + case POWERPC_EXCP_DEBUG: /* Debug interrupt */ + cpu_abort(cs, "%s exception not implemented\n", + powerpc_excp_name(excp)); + break; + default: + cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); + break; + } + + /* Save PC */ + env->spr[srr0] = env->nip; + + /* Save MSR */ + env->spr[srr1] = msr; + + powerpc_set_excp_state(cpu, vector, new_msr); +} +#else +void powerpc_excp_40x(PowerPCCPU *cpu, int excp) +{ + g_assert_not_reached(); +} +#endif /* SPR shared between PowerPC 40x implementations */ static void register_40x_sprs(CPUPPCState *env) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 07190d785a..3ae3f4cc45 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -376,144 +376,6 @@ void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector, env->reserve_addr = -1; } -static void powerpc_excp_40x(PowerPCCPU *cpu, int excp) -{ - CPUState *cs = CPU(cpu); - CPUPPCState *env = &cpu->env; - target_ulong msr, new_msr, vector; - int srr0, srr1; - - /* new srr1 value excluding must-be-zero bits */ - msr = env->msr & ~0x783f0000ULL; - - /* - * new interrupt handler msr preserves existing ME unless - * explicitly overriden. - */ - new_msr = env->msr & (((target_ulong)1 << MSR_ME)); - - /* target registers */ - srr0 = SPR_SRR0; - srr1 = SPR_SRR1; - - /* - * Hypervisor emulation assistance interrupt only exists on server - * arch 2.05 server or later. - */ - if (excp == POWERPC_EXCP_HV_EMU) { - excp = POWERPC_EXCP_PROGRAM; - } - - vector = env->excp_vectors[excp]; - if (vector == (target_ulong)-1ULL) { - cpu_abort(cs, "Raised an exception without defined vector %d\n", - excp); - } - - vector |= env->excp_prefix; - - switch (excp) { - case POWERPC_EXCP_CRITICAL: /* Critical input */ - srr0 = SPR_40x_SRR2; - srr1 = SPR_40x_SRR3; - 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); - } - - /* machine check exceptions don't have ME set */ - new_msr &= ~((target_ulong)1 << MSR_ME); - - srr0 = SPR_40x_SRR2; - srr1 = SPR_40x_SRR3; - break; - case POWERPC_EXCP_DSI: /* Data storage exception */ - trace_ppc_excp_dsi(env->spr[SPR_40x_ESR], env->spr[SPR_40x_DEAR]); - break; - case POWERPC_EXCP_ISI: /* Instruction storage exception */ - trace_ppc_excp_isi(msr, env->nip); - break; - case POWERPC_EXCP_EXTERNAL: /* External input */ - break; - case POWERPC_EXCP_ALIGN: /* Alignment exception */ - 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(); - powerpc_reset_excp_state(cpu); - return; - } - env->spr[SPR_40x_ESR] = ESR_FP; - break; - case POWERPC_EXCP_INVAL: - trace_ppc_excp_inval(env->nip); - env->spr[SPR_40x_ESR] = ESR_PIL; - break; - case POWERPC_EXCP_PRIV: - env->spr[SPR_40x_ESR] = ESR_PPR; - break; - case POWERPC_EXCP_TRAP: - env->spr[SPR_40x_ESR] = ESR_PTR; - break; - default: - cpu_abort(cs, "Invalid program exception %d. Aborting\n", - env->error_code); - break; - } - break; - case POWERPC_EXCP_SYSCALL: /* System call exception */ - trace_ppc_syscall(env, 0); - - /* - * We need to correct the NIP which in this case is supposed - * to point to the next instruction - */ - env->nip += 4; - break; - case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ - trace_ppc_excp_print("FIT"); - break; - case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ - trace_ppc_excp_print("WDT"); - break; - case POWERPC_EXCP_DTLB: /* Data TLB error */ - case POWERPC_EXCP_ITLB: /* Instruction TLB error */ - break; - case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ - trace_ppc_excp_print("PIT"); - break; - case POWERPC_EXCP_DEBUG: /* Debug interrupt */ - cpu_abort(cs, "%s exception not implemented\n", - powerpc_excp_name(excp)); - break; - default: - cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); - break; - } - - /* Save PC */ - env->spr[srr0] = env->nip; - - /* Save MSR */ - env->spr[srr1] = msr; - - powerpc_set_excp_state(cpu, vector, new_msr); -} - static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp) { CPUState *cs = CPU(cpu); -- 2.34.1