When running with KVM, QEMU only needs to dispatch a few interrupts in specific occasions, so we don't need to have all interrupts registered. We also want to better identify code that is used with KVM to avoid breaking the --disable-tcg|kvm builds, so this patch also adds ifdefs to make that distinction.
Signed-off-by: Fabiano Rosas <faro...@linux.ibm.com> --- target/ppc/interrupts.c | 268 ++++++++++++++++++++++----------------- target/ppc/intr-book3s.c | 2 + target/ppc/intr-booke.c | 2 + target/ppc/ppc_intr.h | 12 +- 4 files changed, 161 insertions(+), 123 deletions(-) diff --git a/target/ppc/interrupts.c b/target/ppc/interrupts.c index 6f956029fd..be2755b1a8 100644 --- a/target/ppc/interrupts.c +++ b/target/ppc/interrupts.c @@ -11,7 +11,9 @@ #include "cpu.h" #include "ppc_intr.h" #include "trace.h" +#include "sysemu/kvm.h" +#ifdef CONFIG_TCG /* for hreg_swap_gpr_tgpr */ #include "helper_regs.h" @@ -43,56 +45,6 @@ void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore) } } -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; @@ -165,51 +117,6 @@ void ppc_intr_alignment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore) 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 @@ -334,30 +241,6 @@ void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore) env->spr[SPR_BOOKE_ESR] = ESR_SPV; } -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"); - } - } -} - #ifdef TARGET_PPC64 void ppc_intr_hv(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore) { @@ -455,6 +338,149 @@ void ppc_intr_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore) break; } } +#endif /* CONFIG_TCG */ + +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; +#if defined(CONFIG_TCG) + cpu_interrupt_exittb(cs); +#endif + } + 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_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; + } +} + +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"); + } + } +} + +/* + * Book3S and BookE support KVM, but QEMU only dispatches a small + * set of interrupts in very specific ocasions. All other + * interrupts are dispatched by the real harware and QEMU knows + * nothing about them. + */ +PPCInterrupt interrupts_kvm[POWERPC_EXCP_NB] = { + + [POWERPC_EXCP_MCHECK] = { + "Machine check", ppc_intr_machine_check + }, + + [POWERPC_EXCP_PROGRAM] = { + "Program", ppc_intr_program + }, + + [POWERPC_EXCP_RESET] = { + "System reset", ppc_intr_system_reset + }, +}; int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts, PPCIntrArgs *regs, int excp) @@ -464,6 +490,10 @@ int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts, PPCInterrupt *intr; bool ignore = false; + if (kvm_enabled()) { + interrupts = interrupts_kvm; + } + intr = &interrupts[excp]; if (!intr->name) { cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); diff --git a/target/ppc/intr-book3s.c b/target/ppc/intr-book3s.c index cd279de346..a475c668ed 100644 --- a/target/ppc/intr-book3s.c +++ b/target/ppc/intr-book3s.c @@ -11,6 +11,7 @@ #include "ppc_intr.h" static PPCInterrupt interrupts_book3s[POWERPC_EXCP_NB] = { +#ifdef CONFIG_TCG [POWERPC_EXCP_ALIGN] = { "Alignment", ppc_intr_alignment }, @@ -88,6 +89,7 @@ static PPCInterrupt interrupts_book3s[POWERPC_EXCP_NB] = { [POWERPC_EXCP_SDOOR] = { "Server doorbell" }, [POWERPC_EXCP_THERM] = { "Thermal management" }, [POWERPC_EXCP_VPUA] = { "Vector assist" }, +#endif }; static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, diff --git a/target/ppc/intr-booke.c b/target/ppc/intr-booke.c index 598d372069..9297b14ed6 100644 --- a/target/ppc/intr-booke.c +++ b/target/ppc/intr-booke.c @@ -11,6 +11,7 @@ #include "ppc_intr.h" static PPCInterrupt interrupts_booke[POWERPC_EXCP_NB] = { +#ifdef CONFIG_TCG [POWERPC_EXCP_ALIGN] = { "Alignment", ppc_intr_alignment }, @@ -76,6 +77,7 @@ static PPCInterrupt interrupts_booke[POWERPC_EXCP_NB] = { /* Not impleemented */ [POWERPC_EXCP_EFPDI] = { "Embedded floating-point data" }, [POWERPC_EXCP_EFPRI] = { "Embedded floating-point round" }, +#endif }; void booke_excp(PowerPCCPU *cpu, int excp) diff --git a/target/ppc/ppc_intr.h b/target/ppc/ppc_intr.h index a0362f4248..4aab37ea28 100644 --- a/target/ppc/ppc_intr.h +++ b/target/ppc/ppc_intr.h @@ -19,6 +19,7 @@ struct PPCInterrupt { ppc_intr_fn_t fn; }; +#ifdef CONFIG_TCG void ppc_intr_alignment(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); void ppc_intr_critical(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); void ppc_intr_data_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); @@ -28,14 +29,11 @@ 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_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); -void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); void ppc_intr_noop(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_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_tlb_miss(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); @@ -43,7 +41,13 @@ void ppc_intr_watchdog(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); void ppc_intr_hv(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); -#endif +#endif /* TARGET_PPC64 */ + +#endif /* CONFIG_TCG */ + +void ppc_intr_machine_check(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); +void ppc_intr_program(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); +void ppc_intr_system_reset(PowerPCCPU *cpu, PPCIntrArgs *regs, bool *ignore); int ppc_intr_prepare(PowerPCCPU *cpu, PPCInterrupt *interrupts, PPCIntrArgs *regs, int excp); -- 2.33.1