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 <mohamed@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 7beb47caad..766b35f937 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"
@@ -2169,15 +2170,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();
}
@@ -2187,6 +2256,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)