aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/intc/arm_gicv3_kvm.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index b70ee27..6051c77 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -25,6 +25,7 @@
#include "hw/sysbus.h"
#include "qemu/error-report.h"
#include "sysemu/kvm.h"
+#include "sysemu/sysemu.h"
#include "kvm_arm.h"
#include "gicv3_internal.h"
#include "vgic_common.h"
@@ -680,6 +681,35 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
REGINFO_SENTINEL
};
+/**
+ * vm_change_state_handler - VM change state callback aiming at flushing
+ * RDIST pending tables into guest RAM
+ *
+ * The tables get flushed to guest RAM whenever the VM gets stopped.
+ */
+static void vm_change_state_handler(void *opaque, int running,
+ RunState state)
+{
+ GICv3State *s = (GICv3State *)opaque;
+ Error *err = NULL;
+ int ret;
+
+ if (running) {
+ return;
+ }
+
+ ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
+ KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES,
+ NULL, true, &err);
+ if (err) {
+ error_report_err(err);
+ }
+ if (ret < 0 && ret != -EFAULT) {
+ abort();
+ }
+}
+
+
static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
{
GICv3State *s = KVM_ARM_GICV3(dev);
@@ -751,6 +781,10 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
return;
}
}
+ 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);
+ }
}
static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)