From 22fc9bd7e7ae0b72c6f6e483eb66cf996f519766 Mon Sep 17 00:00:00 2001 From: David Gibson <dgibson@redhat.com> Date: Tue, 21 Jan 2020 05:16:11 +0000 Subject: [PATCH 01/15] ppc: Deassert the external interrupt pin in KVM on reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RH-Author: David Gibson <dgibson@redhat.com> Message-id: <20200121051613.388295-2-dgibson@redhat.com> Patchwork-id: 93429 O-Subject: [RHEL-AV-8.2 qemu-kvm PATCH 1/3] ppc: Deassert the external interrupt pin in KVM on reset Bugzilla: 1776638 RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com> RH-Acked-by: Laurent Vivier <lvivier@redhat.com> RH-Acked-by: Thomas Huth <thuth@redhat.com> From: Greg Kurz <groug@kaod.org> When a CPU is reset, QEMU makes sure no interrupt is pending by clearing CPUPPCstate::pending_interrupts in ppc_cpu_reset(). In the case of a complete machine emulation, eg. a sPAPR machine, an external interrupt request could still be pending in KVM though, eg. an IPI. It will be eventually presented to the guest, which is supposed to acknowledge it at the interrupt controller. If the interrupt controller is emulated in QEMU, either XICS or XIVE, ppc_set_irq() won't deassert the external interrupt pin in KVM since it isn't pending anymore for QEMU. When the vCPU re-enters the guest, the interrupt request is still pending and the vCPU will try again to acknowledge it. This causes an infinite loop and eventually hangs the guest. The code has been broken since the beginning. The issue wasn't hit before because accel=kvm,kernel-irqchip=off is an awkward setup that never got used until recently with the LC92x IBM systems (aka, Boston). Add a ppc_irq_reset() function to do the necessary cleanup, ie. deassert the IRQ pins of the CPU in QEMU and most importantly the external interrupt pin for this vCPU in KVM. Reported-by: Satheesh Rajendran <sathnaga@linux.vnet.ibm.com> Signed-off-by: Greg Kurz <groug@kaod.org> Message-Id: <157548861740.3650476.16879693165328764758.stgit@bahia.lan> Signed-off-by: David Gibson <david@gibson.dropbear.id.au> (cherry picked from commit 401774387aeb37f2ada9bb18f7c7e307b21a3e93) Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1776638 Signed-off-by: David Gibson <dgibson@redhat.com> Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com> --- hw/ppc/ppc.c | 8 ++++++++ include/hw/ppc/ppc.h | 2 ++ target/ppc/translate_init.inc.c | 1 + 3 files changed, 11 insertions(+) diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index 52a18eb..d554b64 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -1510,3 +1510,11 @@ PowerPCCPU *ppc_get_vcpu_by_pir(int pir) return NULL; } + +void ppc_irq_reset(PowerPCCPU *cpu) +{ + CPUPPCState *env = &cpu->env; + + env->irq_input_state = 0; + kvmppc_set_interrupt(cpu, PPC_INTERRUPT_EXT, 0); +} diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h index 4bdcb8b..5dd7531 100644 --- a/include/hw/ppc/ppc.h +++ b/include/hw/ppc/ppc.h @@ -76,6 +76,7 @@ static inline void ppc970_irq_init(PowerPCCPU *cpu) {} static inline void ppcPOWER7_irq_init(PowerPCCPU *cpu) {} static inline void ppcPOWER9_irq_init(PowerPCCPU *cpu) {} static inline void ppce500_irq_init(PowerPCCPU *cpu) {} +static inline void ppc_irq_reset(PowerPCCPU *cpu) {} #else void ppc40x_irq_init(PowerPCCPU *cpu); void ppce500_irq_init(PowerPCCPU *cpu); @@ -83,6 +84,7 @@ void ppc6xx_irq_init(PowerPCCPU *cpu); void ppc970_irq_init(PowerPCCPU *cpu); void ppcPOWER7_irq_init(PowerPCCPU *cpu); void ppcPOWER9_irq_init(PowerPCCPU *cpu); +void ppc_irq_reset(PowerPCCPU *cpu); #endif /* PPC machines for OpenBIOS */ diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index ba726de..64a8380 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -10461,6 +10461,7 @@ static void ppc_cpu_reset(CPUState *s) env->pending_interrupts = 0; s->exception_index = POWERPC_EXCP_NONE; env->error_code = 0; + ppc_irq_reset(cpu); /* tininess for underflow is detected before rounding */ set_float_detect_tininess(float_tininess_before_rounding, -- 1.8.3.1