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.
Signed-off-by: Mohamed Mediouni <moha...@unpredictable.fr> --- target/arm/hvf/hvf.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 4ac42bda32..f14a3a3cbd 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -22,6 +22,7 @@ #include "cpu-sysregs.h" #include <mach/mach_time.h> +#include <stdint.h> #include "system/address-spaces.h" #include "system/memory.h" @@ -2174,15 +2175,83 @@ static const VMStateDescription vmstate_hvf_vtimer = { }, }; +/* Apple specific opaque state for the vGIC */ + +typedef struct HVGICState { + void *state; + uint32_t size; +} HVGICState; + +static HVGICState gic; + +static int hvf_gic_opaque_state_get(void) +{ + hv_gic_state_t gic_state; + hv_return_t err; + size_t size; + + gic_state = hv_gic_state_create(); + if (gic_state == NULL) { + error_report("hvf: vgic: failed to create hv_gic_state_create."); + return 1; + } + err = hv_gic_state_get_size(gic_state, &size); + gic.size = size; + if (err != HV_SUCCESS) { + error_report("hvf: vgic: failed to get GIC state size."); + return 1; + } + gic.state = malloc(gic.size); + err = hv_gic_state_get_data(gic_state, gic.state); + if (err != HV_SUCCESS) { + error_report("hvf: vgic: failed to get GIC state."); + return 1; + } + return 0; +} + +static int hvf_gic_opaque_state_set(void) +{ + hv_return_t err; + if (!gic.size) { + return 0; + } + err = hv_gic_set_state(gic.state, gic.size); + if (err != HV_SUCCESS) { + error_report("hvf: vgic: failed to restore GIC state."); + return 1; + } + return 0; +} + +static const VMStateDescription vmstate_hvf_gic = { + .name = "hvf-gic", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(size, HVGICState), + VMSTATE_VBUFFER_UINT32(state, + HVGICState, 0, 0, + size), + VMSTATE_END_OF_LIST() + }, +}; + static void hvf_vm_state_change(void *opaque, bool running, RunState state) { HVFVTimer *s = opaque; if (running) { + if (hvf_irqchip_in_kernel()) { + hvf_gic_opaque_state_set(); + } /* Update vtimer offset on all CPUs */ hvf_state->vtimer_offset = mach_absolute_time() - s->vtimer_val; cpu_synchronize_all_states(); } else { + if (hvf_irqchip_in_kernel()) { + hvf_gic_opaque_state_get(); + } /* Remember vtimer value on every pause */ s->vtimer_val = hvf_vtimer_val_raw(); } @@ -2192,6 +2261,10 @@ int hvf_arch_init(void) { hvf_state->vtimer_offset = mach_absolute_time(); vmstate_register(NULL, 0, &vmstate_hvf_vtimer, &vtimer); + if (hvf_irqchip_in_kernel()) { + gic.size = 0; + vmstate_register(NULL, 0, &vmstate_hvf_gic, &gic); + } qemu_add_vm_change_state_handler(hvf_vm_state_change, &vtimer); hvf_arm_init_debug(); -- 2.39.5 (Apple Git-154)