From 376cdd7e9c94f1e03b2c58e068e8ebfe78b49514 Mon Sep 17 00:00:00 2001 From: Steve Sistare Date: Tue, 26 Aug 2025 11:21:28 +0100 Subject: hw/intc/arm_gicv3_kvm: preserve pending interrupts during cpr Close a race condition that causes cpr-transfer to lose VFIO interrupts on ARM. CPR stops VCPUs but does not disable VFIO interrupts, which may continue to arrive throughout the transition to new QEMU. CPR calls kvm_irqchip_remove_irqfd_notifier_gsi in old QEMU to force future interrupts to the producer eventfd, where they are preserved. Old QEMU then destroys the old KVM instance. However, interrupts may already be pending in KVM state. To preserve them, call ioctl KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES to flush them to guest RAM, where they will be picked up when the new KVM+VCPU instance is created. Cc: qemu-stable@nongnu.org Signed-off-by: Steve Sistare Reviewed-by: Fabiano Rosas Message-id: 1754936384-278328-1-git-send-email-steven.sistare@oracle.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/arm_gicv3_kvm.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'hw/intc') diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 6166283..0cd14d7 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -31,6 +31,7 @@ #include "gicv3_internal.h" #include "vgic_common.h" #include "migration/blocker.h" +#include "migration/misc.h" #include "qom/object.h" #include "target/arm/cpregs.h" @@ -776,6 +777,17 @@ static void vm_change_state_handler(void *opaque, bool running, } } +static int kvm_arm_gicv3_notifier(NotifierWithReturn *notifier, + MigrationEvent *e, Error **errp) +{ + if (e->type == MIG_EVENT_PRECOPY_DONE) { + GICv3State *s = container_of(notifier, GICv3State, cpr_notifier); + return kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES, + NULL, true, errp); + } + return 0; +} static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) { @@ -917,6 +929,9 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES)) { qemu_add_vm_change_state_handler(vm_change_state_handler, s); + migration_add_notifier_mode(&s->cpr_notifier, + kvm_arm_gicv3_notifier, + MIG_MODE_CPR_TRANSFER); } } -- cgit v1.1