@samitouri / QOSamiQemu / commits / 48396ad6ce

hw/intc: arm_gicv3_hvf: save/restore Apple GIC state

On HVF, some of the GIC state is in an opaque Apple-provided structure. Save/restore that state to be able to save/restore VMs that use the hardware GIC. Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Message-id: 20260429190532.26538-3-mohamed@unpredictable.fr Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Mohamed Mediouni committed May 5, 2026 at 09:25 UTC 48396ad6ce9ac4ec5ec97d45435c947b582c7f39
5 files changed +120 -4
hw/intc/arm_gicv3_common.c
+1
@@ -305,6 +305,7 @@ static const VMStateDescription vmstate_gicv3 = {
305 .subsections = (const VMStateDescription * const []) {
306 &vmstate_gicv3_gicd_no_migration_shift_bug,
307 &vmstate_gicv3_gicd_nmi,
308 + &vmstate_gicv3_hvf,
309 NULL
310 }
311 };
hw/intc/arm_gicv3_hvf.c
+90 -4
@@ -13,6 +13,7 @@
13 #include "qemu/error-report.h"
14 #include "qemu/module.h"
15 #include "system/runstate.h"
16 +#include "migration/vmstate.h"
17 #include "system/hvf.h"
18 #include "system/hvf_int.h"
19 #include "hvf_arm.h"
@@ -37,8 +38,13 @@ struct HVFARMGICv3Class {
38
39 typedef struct HVFARMGICv3Class HVFARMGICv3Class;
40
40 -/* This is reusing the GICv3State typedef from ARM_GICV3_ITS_COMMON */
41 -DECLARE_OBJ_CHECKERS(GICv3State, HVFARMGICv3Class,
41 +typedef struct HVFGICv3State {
42 + GICv3State parent_obj;
43 + uint32_t size;
44 + void *state;
45 +} HVFGICv3State;
46 +
47 +DECLARE_OBJ_CHECKERS(HVFGICv3State, HVFARMGICv3Class,
48 HVF_GICV3, TYPE_HVF_GICV3);
49
50 /*
@@ -668,7 +674,7 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
674 static void hvf_gicv3_realize(DeviceState *dev, Error **errp)
675 {
676 ERRP_GUARD();
671 - GICv3State *s = HVF_GICV3(dev);
677 + GICv3State *s = (GICv3State *)HVF_GICV3(dev);
678 HVFARMGICv3Class *kgc = HVF_GICV3_GET_CLASS(s);
679 int i;
680
@@ -715,6 +721,86 @@ static void hvf_gicv3_realize(DeviceState *dev, Error **errp)
721 }
722 }
723
724 +/*
725 + * HVF doesn't have a way to save the RDIST pending tables
726 + * to guest memory, only to an opaque data structure.
727 + */
728 +static bool gicv3_is_hvf(void *opaque)
729 +{
730 + return hvf_enabled() && hvf_irqchip_in_kernel();
731 +}
732 +
733 +static int hvf_gic_opaque_state_save(void *opaque)
734 +{
735 + HVFGICv3State *gic = opaque;
736 + hv_gic_state_t gic_state;
737 + hv_return_t err;
738 + size_t size;
739 +
740 + gic_state = hv_gic_state_create();
741 + if (gic_state == NULL) {
742 + error_report("hvf: vgic: failed to create hv_gic_state_create.");
743 + return 1;
744 + }
745 + err = hv_gic_state_get_size(gic_state, &size);
746 + gic->size = size;
747 + if (err != HV_SUCCESS) {
748 + error_report("hvf: vgic: failed to get GIC state size.");
749 + os_release(gic_state);
750 + return 1;
751 + }
752 + gic->state = g_malloc0(gic->size);
753 + err = hv_gic_state_get_data(gic_state, gic->state);
754 + if (err != HV_SUCCESS) {
755 + error_report("hvf: vgic: failed to get GIC state.");
756 + os_release(gic_state);
757 + return 1;
758 + }
759 +
760 + os_release(gic_state);
761 + return 0;
762 +}
763 +
764 +static void hvf_gic_opaque_state_free(void *opaque)
765 +{
766 + HVFGICv3State *gic = opaque;
767 + free(gic->state);
768 +}
769 +
770 +static int hvf_gic_opaque_state_restore(void *opaque, int version_id)
771 +{
772 + HVFGICv3State *gic = opaque;
773 + hv_return_t err;
774 + if (!gic->size) {
775 + return 0;
776 + }
777 + err = hv_gic_set_state(gic->state, gic->size);
778 + if (err != HV_SUCCESS) {
779 + error_report("hvf: vgic: failed to restore GIC state.");
780 + return 1;
781 + }
782 + return 0;
783 +}
784 +
785 +const VMStateDescription vmstate_gicv3_hvf = {
786 + .name = "arm_gicv3/hvf_gic_state",
787 + .version_id = 1,
788 + .minimum_version_id = 1,
789 + .needed = gicv3_is_hvf,
790 + .pre_save = hvf_gic_opaque_state_save,
791 + .post_save = hvf_gic_opaque_state_free,
792 + .post_load = hvf_gic_opaque_state_restore,
793 + .version_id = 1,
794 + .minimum_version_id = 1,
795 + .fields = (const VMStateField[]) {
796 + VMSTATE_UINT32(size, HVFGICv3State),
797 + VMSTATE_VBUFFER_ALLOC_UINT32(state,
798 + HVFGICv3State, 0, 0,
799 + size),
800 + VMSTATE_END_OF_LIST()
801 + },
802 +};
803 +
804 static void hvf_gicv3_class_init(ObjectClass *klass, const void *data)
805 {
806 DeviceClass *dc = DEVICE_CLASS(klass);
@@ -734,7 +820,7 @@ static void hvf_gicv3_class_init(ObjectClass *klass, const void *data)
820 static const TypeInfo hvf_arm_gicv3_info = {
821 .name = TYPE_HVF_GICV3,
822 .parent = TYPE_ARM_GICV3_COMMON,
737 - .instance_size = sizeof(GICv3State),
823 + .instance_size = sizeof(HVFGICv3State),
824 .class_init = hvf_gicv3_class_init,
825 .class_size = sizeof(HVFARMGICv3Class),
826 };
hw/intc/arm_gicv3_hvf_stub.c new
+25
@@ -0,0 +1,25 @@
1 +/* SPDX-License-Identifier: GPL-2.0-or-later */
2 +/*
3 + * ARM Generic Interrupt Controller using HVF platform support stub
4 + *
5 + * Copyright (c) 2026 Mohamed Mediouni
6 + *
7 + */
8 +#include "qemu/osdep.h"
9 +#include "hw/intc/arm_gicv3_common.h"
10 +#include "migration/vmstate.h"
11 +#include "qemu/typedefs.h"
12 +
13 +static bool needed_never(void *opaque)
14 +{
15 + return false;
16 +}
17 +
18 +const VMStateDescription vmstate_gicv3_hvf = {
19 + .name = "arm_gicv3/hvf_gic_state",
20 + .version_id = 1,
21 + .minimum_version_id = 1,
22 + .needed = needed_never,
23 + .version_id = 1,
24 + .minimum_version_id = 1,
25 +};
hw/intc/meson.build
+1
@@ -43,6 +43,7 @@ arm_common_ss.add(when: 'CONFIG_ARM_GICV3', if_true: files('arm_gicv3_cpuif.c'))
43 specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gic_kvm.c'))
44 specific_ss.add(when: ['CONFIG_WHPX', 'TARGET_AARCH64'], if_true: files('arm_gicv3_whpx.c'))
45 specific_ss.add(when: ['CONFIG_HVF', 'CONFIG_ARM_GICV3'], if_true: files('arm_gicv3_hvf.c'))
46 +specific_ss.add(when: ['CONFIG_HVF', 'CONFIG_ARM_GICV3'], if_false: files('arm_gicv3_hvf_stub.c'))
47 specific_ss.add(when: ['CONFIG_ARM_GIC_KVM', 'TARGET_AARCH64'], if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c'))
48 arm_common_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c'))
49 specific_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_irqmp.c'))
include/hw/intc/arm_gicv3_common.h
+3
@@ -339,4 +339,7 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
339 */
340 const char *gicv3_class_name(void);
341
342 +/* HVF vGIC-specific state: stubbed out on a build with HVF disabled */
343 +extern const VMStateDescription vmstate_gicv3_hvf;
344 +
345 #endif