savevm.c: Getting closer to upstream.
This patch refactors savevm.c considerably to get much closer
to upstream. The main benefit is the introduction of savevm_register()
and savevm_unregister() functions, which allow the client to provide
a description of the state through a VMStateDescription structure.
The 'legacy' register_savevm() and unregister_savevm() are still
provided (just like upstream does). Future patches will 'upgrade'
our virtual devices to the new interface.
NOTE: Since DeviceState is not implemented properly yet, qdev_get_path()
is stubbed to always return NULL.
Change-Id: I7bfa201da40a0e470fafde6ccc002a4216ecd9c1
diff --git a/android/hw-qemud.c b/android/hw-qemud.c
index 191ce01..79040f7 100644
--- a/android/hw-qemud.c
+++ b/android/hw-qemud.c
@@ -2254,8 +2254,13 @@
qemud_multiplexer_init(_multiplexer, cs);
- register_savevm( "qemud", 0, QEMUD_SAVE_VERSION,
- qemud_save, qemud_load, _multiplexer);
+ register_savevm(NULL,
+ "qemud",
+ 0,
+ QEMUD_SAVE_VERSION,
+ qemud_save,
+ qemud_load,
+ _multiplexer);
}
extern void
diff --git a/audio/audio.c b/audio/audio.c
index f3de998..8523cdf 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -2047,7 +2047,7 @@
initialized = 1;
QLIST_INIT (&s->card_head);
- register_savevm ("audio", 0, 1, audio_save, audio_load, s);
+ register_savevm(NULL, "audio", 0, 1, audio_save, audio_load, s);
audio_reset_timer();
}
diff --git a/cpus.c b/cpus.c
index ab34ad0..795ea38 100644
--- a/cpus.c
+++ b/cpus.c
@@ -290,7 +290,13 @@
TimersState timers_state;
void qemu_timer_register_savevm(void) {
- register_savevm("timer", 0, 2, timer_save, timer_load, &timers_state);
+ register_savevm(NULL,
+ "timer",
+ 0,
+ 2,
+ timer_save,
+ timer_load,
+ &timers_state);
}
/* Return the virtual CPU time, based on the instruction counter. */
diff --git a/exec.c b/exec.c
index 2f44aa4..4f27734 100644
--- a/exec.c
+++ b/exec.c
@@ -569,10 +569,20 @@
cpu_list_unlock();
#endif
#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
- register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
- cpu_common_save, cpu_common_load, env);
- register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
- cpu_save, cpu_load, env);
+ register_savevm(NULL,
+ "cpu_common",
+ cpu_index,
+ CPU_COMMON_SAVE_VERSION,
+ cpu_common_save,
+ cpu_common_load,
+ env);
+ register_savevm(NULL,
+ "cpu",
+ cpu_index,
+ CPU_SAVE_VERSION,
+ cpu_save,
+ cpu_load,
+ env);
#endif
}
diff --git a/hw/android/android_mips.c b/hw/android/android_mips.c
index ed9f42f..1d0f34f 100644
--- a/hw/android/android_mips.c
+++ b/hw/android/android_mips.c
@@ -167,7 +167,13 @@
env = cpu_init(cpu_model);
- register_savevm( "cpu", 0, MIPS_CPU_SAVE_VERSION, cpu_save, cpu_load, env );
+ register_savevm(NULL,
+ "cpu",
+ 0,
+ MIPS_CPU_SAVE_VERSION,
+ cpu_save,
+ cpu_load,
+ env);
if (ram_size > GOLDFISH_IO_SPACE)
ram_size = GOLDFISH_IO_SPACE; /* avoid overlap of ram and IO regs */
diff --git a/hw/android/goldfish/audio.c b/hw/android/goldfish/audio.c
index 228a7ca..9259a75 100644
--- a/hw/android/goldfish/audio.c
+++ b/hw/android/goldfish/audio.c
@@ -665,7 +665,12 @@
goldfish_device_add(&s->dev, goldfish_audio_readfn, goldfish_audio_writefn, s);
- register_savevm( "audio_state", 0, AUDIO_STATE_SAVE_VERSION,
- audio_state_save, audio_state_load, s );
+ register_savevm(NULL,
+ "audio_state",
+ 0,
+ AUDIO_STATE_SAVE_VERSION,
+ audio_state_save,
+ audio_state_load,
+ s);
}
diff --git a/hw/android/goldfish/battery.c b/hw/android/goldfish/battery.c
index 4797bbb..6624176 100644
--- a/hw/android/goldfish/battery.c
+++ b/hw/android/goldfish/battery.c
@@ -178,8 +178,13 @@
goldfish_device_add(&s->dev, goldfish_battery_readfn, goldfish_battery_writefn, s);
- register_savevm( "battery_state", 0, BATTERY_STATE_SAVE_VERSION,
- goldfish_battery_save, goldfish_battery_load, s);
+ register_savevm(NULL,
+ "battery_state",
+ 0,
+ BATTERY_STATE_SAVE_VERSION,
+ goldfish_battery_save,
+ goldfish_battery_load,
+ s);
}
void goldfish_battery_set_prop(int ac, int property, int value)
diff --git a/hw/android/goldfish/events_device.c b/hw/android/goldfish/events_device.c
index f11e7ab..6672678 100644
--- a/hw/android/goldfish/events_device.c
+++ b/hw/android/goldfish/events_device.c
@@ -537,6 +537,11 @@
*/
user_event_register_generic(s, events_put_generic);
- register_savevm( "events_state", 0, EVENTS_STATE_SAVE_VERSION,
- events_state_save, events_state_load, s );
+ register_savevm(NULL,
+ "events_state",
+ 0,
+ EVENTS_STATE_SAVE_VERSION,
+ events_state_save,
+ events_state_load,
+ s);
}
diff --git a/hw/android/goldfish/fb.c b/hw/android/goldfish/fb.c
index da7376f..8738321 100644
--- a/hw/android/goldfish/fb.c
+++ b/hw/android/goldfish/fb.c
@@ -672,6 +672,11 @@
goldfish_device_add(&s->dev, goldfish_fb_readfn, goldfish_fb_writefn, s);
- register_savevm( "goldfish_fb", 0, GOLDFISH_FB_SAVE_VERSION,
- goldfish_fb_save, goldfish_fb_load, s);
+ register_savevm(NULL,
+ "goldfish_fb",
+ 0,
+ GOLDFISH_FB_SAVE_VERSION,
+ goldfish_fb_save,
+ goldfish_fb_load,
+ s);
}
diff --git a/hw/android/goldfish/interrupt.c b/hw/android/goldfish/interrupt.c
index b7738e6..6b6abb0 100644
--- a/hw/android/goldfish/interrupt.c
+++ b/hw/android/goldfish/interrupt.c
@@ -181,8 +181,13 @@
return NULL;
}
- register_savevm( "goldfish_int", 0, GOLDFISH_INT_SAVE_VERSION,
- goldfish_int_save, goldfish_int_load, s);
+ register_savevm(NULL,
+ "goldfish_int",
+ 0,
+ GOLDFISH_INT_SAVE_VERSION,
+ goldfish_int_save,
+ goldfish_int_load,
+ s);
return qi;
}
diff --git a/hw/android/goldfish/mmc.c b/hw/android/goldfish/mmc.c
index a4e1177..cfd483a 100644
--- a/hw/android/goldfish/mmc.c
+++ b/hw/android/goldfish/mmc.c
@@ -533,7 +533,12 @@
goldfish_device_add(&s->dev, goldfish_mmc_readfn, goldfish_mmc_writefn, s);
- register_savevm( "goldfish_mmc", 0, GOLDFISH_MMC_SAVE_VERSION,
- goldfish_mmc_save, goldfish_mmc_load, s);
+ register_savevm(NULL,
+ "goldfish_mmc",
+ 0,
+ GOLDFISH_MMC_SAVE_VERSION,
+ goldfish_mmc_save,
+ goldfish_mmc_load,
+ s);
}
diff --git a/hw/android/goldfish/nand.c b/hw/android/goldfish/nand.c
index d52b377..b3c7e6f 100644
--- a/hw/android/goldfish/nand.c
+++ b/hw/android/goldfish/nand.c
@@ -681,8 +681,13 @@
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
s->base = base;
- register_savevm( "nand_dev", instance_id++, NAND_DEV_STATE_SAVE_VERSION,
- nand_dev_controller_state_save, nand_dev_controller_state_load, s);
+ register_savevm(NULL,
+ "nand_dev",
+ instance_id++,
+ NAND_DEV_STATE_SAVE_VERSION,
+ nand_dev_controller_state_save,
+ nand_dev_controller_state_load,
+ s);
}
static int arg_match(const char *a, const char *b, size_t b_len)
diff --git a/hw/android/goldfish/pipe.c b/hw/android/goldfish/pipe.c
index 719dce7..95b29e6 100644
--- a/hw/android/goldfish/pipe.c
+++ b/hw/android/goldfish/pipe.c
@@ -1327,8 +1327,13 @@
goldfish_device_add(&s->dev, pipe_dev_readfn, pipe_dev_writefn, s);
- register_savevm( "goldfish_pipe", 0, GOLDFISH_PIPE_SAVE_VERSION,
- goldfish_pipe_save, goldfish_pipe_load, s);
+ register_savevm(NULL,
+ "goldfish_pipe",
+ 0,
+ GOLDFISH_PIPE_SAVE_VERSION,
+ goldfish_pipe_save,
+ goldfish_pipe_load,
+ s);
#if DEBUG_ZERO_PIPE
goldfish_pipe_add_type("zero", NULL, &zeroPipe_funcs);
diff --git a/hw/android/goldfish/switch.c b/hw/android/goldfish/switch.c
index 5f5eaae..4208545 100644
--- a/hw/android/goldfish/switch.c
+++ b/hw/android/goldfish/switch.c
@@ -164,8 +164,13 @@
return NULL;
}
- register_savevm( "goldfish_switch", 0, GOLDFISH_SWITCH_SAVE_VERSION,
- goldfish_switch_save, goldfish_switch_load, s);
+ register_savevm(NULL,
+ "goldfish_switch",
+ 0,
+ GOLDFISH_SWITCH_SAVE_VERSION,
+ goldfish_switch_save,
+ goldfish_switch_load,
+ s);
return s;
}
diff --git a/hw/android/goldfish/timer.c b/hw/android/goldfish/timer.c
index 3d46db0..b8921e5 100644
--- a/hw/android/goldfish/timer.c
+++ b/hw/android/goldfish/timer.c
@@ -238,11 +238,21 @@
timer_state.dev.irq = timerirq;
timer_state.timer = timer_new(QEMU_CLOCK_VIRTUAL, SCALE_NS, goldfish_timer_tick, &timer_state);
goldfish_device_add(&timer_state.dev, goldfish_timer_readfn, goldfish_timer_writefn, &timer_state);
- register_savevm( "goldfish_timer", 0, GOLDFISH_TIMER_SAVE_VERSION,
- goldfish_timer_save, goldfish_timer_load, &timer_state);
+ register_savevm(NULL,
+ "goldfish_timer",
+ 0,
+ GOLDFISH_TIMER_SAVE_VERSION,
+ goldfish_timer_save,
+ goldfish_timer_load,
+ &timer_state);
goldfish_device_add(&rtc_state.dev, goldfish_rtc_readfn, goldfish_rtc_writefn, &rtc_state);
- register_savevm( "goldfish_rtc", 0, GOLDFISH_RTC_SAVE_VERSION,
- goldfish_rtc_save, goldfish_rtc_load, &rtc_state);
+ register_savevm(NULL,
+ "goldfish_rtc",
+ 0,
+ GOLDFISH_RTC_SAVE_VERSION,
+ goldfish_rtc_save,
+ goldfish_rtc_load,
+ &rtc_state);
}
diff --git a/hw/android/goldfish/tty.c b/hw/android/goldfish/tty.c
index cd8db89..066448b 100644
--- a/hw/android/goldfish/tty.c
+++ b/hw/android/goldfish/tty.c
@@ -229,8 +229,13 @@
if(ret) {
g_free(s);
} else {
- register_savevm( "goldfish_tty", instance_id++, GOLDFISH_TTY_SAVE_VERSION,
- goldfish_tty_save, goldfish_tty_load, s);
+ register_savevm(NULL,
+ "goldfish_tty",
+ instance_id++,
+ GOLDFISH_TTY_SAVE_VERSION,
+ goldfish_tty_save,
+ goldfish_tty_load,
+ s);
}
return ret;
}
diff --git a/hw/arm/arm_gic.c b/hw/arm/arm_gic.c
index 1f5af8b..9eae169 100644
--- a/hw/arm/arm_gic.c
+++ b/hw/arm/arm_gic.c
@@ -728,5 +728,11 @@
s->iomemtype = cpu_register_io_memory(gic_dist_readfn,
gic_dist_writefn, s);
gic_reset(s);
- register_savevm("arm_gic", -1, 1, gic_save, gic_load, s);
+ register_savevm(NULL,
+ "arm_gic",
+ -1,
+ 1,
+ gic_save,
+ gic_load,
+ s);
}
diff --git a/hw/arm/armv7m_nvic.c b/hw/arm/armv7m_nvic.c
index c2c239b..7ca353b 100644
--- a/hw/arm/armv7m_nvic.c
+++ b/hw/arm/armv7m_nvic.c
@@ -397,7 +397,7 @@
gic_init(&s->gic);
cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype);
s->systick.timer = timer_new(QEMU_CLOCK_VIRTUAL, SCALE_NS, systick_timer_tick, s);
- register_savevm("armv7m_nvic", -1, 1, nvic_save, nvic_load, s);
+ register_savevm(NULL, "armv7m_nvic", -1, 1, nvic_save, nvic_load, s);
}
static void armv7m_nvic_register_devices(void)
diff --git a/hw/core/dma.c b/hw/core/dma.c
index 5e9bc8d..93695ff 100644
--- a/hw/core/dma.c
+++ b/hw/core/dma.c
@@ -567,8 +567,21 @@
high_page_enable ? 0x480 : -1);
dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
high_page_enable ? 0x488 : -1);
- register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
- register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
+ register_savevm(NULL,
+ "dma",
+ 0,
+ 1,
+ dma_save,
+ dma_load,
+ &dma_controllers[0]);
+
+ register_savevm(NULL,
+ "dma",
+ 1,
+ 1,
+ dma_save,
+ dma_load,
+ &dma_controllers[1]);
dma_bh = qemu_bh_new(DMA_run_bh, NULL);
}
diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c
index e4c3816..d5effe6 100644
--- a/hw/input/pckbd.c
+++ b/hw/input/pckbd.c
@@ -370,7 +370,7 @@
s->irq_mouse = mouse_irq;
kbd_reset(s);
- register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
+ register_savevm(NULL, "pckbd", 0, 3, kbd_save, kbd_load, s);
register_ioport_read(io_base, 1, 1, kbd_read_data, s);
register_ioport_write(io_base, 1, 1, kbd_write_data, s);
register_ioport_read(io_base + 4, 1, 1, kbd_read_status, s);
@@ -431,7 +431,7 @@
s->mask = mask;
kbd_reset(s);
- register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
+ register_savevm(NULL, "pckbd", 0, 3, kbd_save, kbd_load, s);
s_io_memory = cpu_register_io_memory(kbd_mm_read, kbd_mm_write, s);
cpu_register_physical_memory(base, size, s_io_memory);
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index e965da6..778ab67 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -591,7 +591,7 @@
s->common.update_arg = update_arg;
s->scancode_set = 2;
ps2_reset(&s->common);
- register_savevm("ps2kbd", 0, 3, ps2_kbd_save, ps2_kbd_load, s);
+ register_savevm(NULL, "ps2kbd", 0, 3, ps2_kbd_save, ps2_kbd_load, s);
//qemu_add_kbd_event_handler(ps2_put_keycode, s);
qemu_register_reset(ps2_reset, 0, &s->common);
return s;
@@ -604,7 +604,7 @@
s->common.update_irq = update_irq;
s->common.update_arg = update_arg;
ps2_reset(&s->common);
- register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s);
+ register_savevm(NULL, "ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s);
//qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
qemu_register_reset(ps2_reset, 0, &s->common);
return s;
diff --git a/hw/intc/apic.c b/hw/intc/apic.c
index 31a164e..173131e 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -958,7 +958,7 @@
}
s->timer = timer_new(QEMU_CLOCK_VIRTUAL, SCALE_NS, apic_timer, s);
- register_savevm("apic", s->idx, 2, apic_save, apic_load, s);
+ register_savevm(NULL, "apic", s->idx, 2, apic_save, apic_load, s);
qemu_register_reset(apic_reset, 0, s);
local_apics[s->idx] = s;
diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
index 3c38de0..e77ed8a 100644
--- a/hw/intc/i8259.c
+++ b/hw/intc/i8259.c
@@ -508,7 +508,7 @@
register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
}
- register_savevm("i8259", io_addr, 1, pic_save, pic_load, s);
+ register_savevm(NULL, "i8259", io_addr, 1, pic_save, pic_load, s);
qemu_register_reset(pic_reset, 0, s);
}
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 8e0cd77..aff9b9c 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -254,7 +254,7 @@
ioapic_mem_write, s);
cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
- register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
+ register_savevm(NULL, "ioapic", 0, 1, ioapic_save, ioapic_load, s);
qemu_register_reset(ioapic_reset, 0, s);
return s;
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
index 98b15c1..d4ca0d5 100644
--- a/hw/net/ne2000.c
+++ b/hw/net/ne2000.c
@@ -726,7 +726,7 @@
{
NE2000State *s = vc->opaque;
- unregister_savevm("ne2000", s);
+ unregister_savevm(NULL, "ne2000", s);
isa_unassign_ioport(s->isa_io_base, 16);
isa_unassign_ioport(s->isa_io_base + 0x10, 2);
@@ -765,7 +765,7 @@
qemu_format_nic_info_str(s->vc, s->macaddr);
- register_savevm("ne2000", -1, 2, ne2000_save, ne2000_load, s);
+ register_savevm(NULL, "ne2000", -1, 2, ne2000_save, ne2000_load, s);
}
/***********************************************************/
@@ -800,7 +800,7 @@
{
NE2000State *s = vc->opaque;
- unregister_savevm("ne2000", s);
+ unregister_savevm(NULL, "ne2000", s);
}
static void pci_ne2000_init(PCIDevice *pci_dev)
@@ -829,7 +829,7 @@
qemu_format_nic_info_str(s->vc, s->macaddr);
- register_savevm("ne2000", -1, 3, ne2000_save, ne2000_load, s);
+ register_savevm(NULL, "ne2000", -1, 3, ne2000_save, ne2000_load, s);
}
static void ne2000_register_devices(void)
diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c
index 755a296..feaa687 100644
--- a/hw/net/smc91c111.c
+++ b/hw/net/smc91c111.c
@@ -791,8 +791,8 @@
smc91c111_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr);
- register_savevm( "smc91c111", 0, SMC91C111_SAVE_VERSION,
- smc91c111_save, smc91c111_load, s);
+ register_savevm(NULL, "smc91c111", 0, SMC91C111_SAVE_VERSION,
+ smc91c111_save, smc91c111_load, s);
}
static void smc91c111_register_devices(void)
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index da637a6..3fe29ad 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -281,7 +281,7 @@
fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
- register_savevm("fw_cfg", -1, 1, fw_cfg_save, fw_cfg_load, s);
+ register_savevm(NULL, "fw_cfg", -1, 1, fw_cfg_save, fw_cfg_load, s);
qemu_register_reset(fw_cfg_reset, 0, s);
fw_cfg_reset(s);
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index 01bd623..c396909 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -201,7 +201,7 @@
d->config[0x72] = 0x02; /* SMRAM */
- register_savevm("I440FX", 0, 2, i440fx_save, i440fx_load, d);
+ register_savevm(NULL, "I440FX", 0, 2, i440fx_save, i440fx_load, d);
*pi440fx_state = d;
return b;
}
@@ -333,7 +333,7 @@
d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice),
devfn, NULL, NULL);
- register_savevm("PIIX3", 0, 2, piix_save, piix_load, d);
+ register_savevm(NULL, "PIIX3", 0, 2, piix_save, piix_load, d);
piix3_dev = d;
pci_conf = d->config;
@@ -356,7 +356,7 @@
d = pci_register_device(bus, "PIIX4", sizeof(PCIDevice),
devfn, NULL, NULL);
- register_savevm("PIIX4", 0, 2, piix_save, piix_load, d);
+ register_savevm(NULL, "PIIX4", 0, 2, piix_save, piix_load, d);
piix4_dev = d;
pci_conf = d->config;
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 42ac3f7..d8c5b22 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -105,7 +105,7 @@
bus->nirq = nirq;
bus->next = first_bus;
first_bus = bus;
- register_savevm("PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus);
+ register_savevm(NULL, "PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus);
return bus;
}
diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c
index 1347511..2bd1ef0 100644
--- a/hw/timer/i8254.c
+++ b/hw/timer/i8254.c
@@ -495,7 +495,7 @@
s->irq_timer = timer_new(QEMU_CLOCK_VIRTUAL, SCALE_NS, pit_irq_timer, s);
s->irq = irq;
- register_savevm("i8254", base, 1, pit_save, pit_load, pit);
+ register_savevm(NULL, "i8254", base, 1, pit_save, pit_load, pit);
qemu_register_reset(pit_reset, 0, pit);
register_ioport_write(base, 4, 1, pit_ioport_write, pit);
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index 5d6c4a0..568a0c3 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -627,10 +627,16 @@
register_ioport_write(base, 2, 1, cmos_ioport_write, s);
register_ioport_read(base, 2, 1, cmos_ioport_read, s);
- register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
+ register_savevm(NULL, "mc146818rtc", base, 1, rtc_save, rtc_load, s);
#ifdef TARGET_I386
if (rtc_td_hack)
- register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
+ register_savevm(NULL,
+ "mc146818rtc-td",
+ base,
+ 1,
+ rtc_save_td,
+ rtc_load_td,
+ s);
#endif
qemu_register_reset(rtc_reset, 0, s);
@@ -744,10 +750,16 @@
io_memory = cpu_register_io_memory(rtc_mm_read, rtc_mm_write, s);
cpu_register_physical_memory(base, 2 << it_shift, io_memory);
- register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
+ register_savevm(NULL, "mc146818rtc", base, 1, rtc_save, rtc_load, s);
#ifdef TARGET_I386
if (rtc_td_hack)
- register_savevm("mc146818rtc-td", base, 1, rtc_save_td, rtc_load_td, s);
+ register_savevm(NULL,
+ "mc146818rtc-td",
+ base,
+ 1,
+ rtc_save_td,
+ rtc_load_td,
+ s);
#endif
qemu_register_reset(rtc_reset, 0, s);
return s;
diff --git a/include/hw/hw.h b/include/hw/hw.h
index 82f9767..21dc8ba 100644
--- a/include/hw/hw.h
+++ b/include/hw/hw.h
@@ -5,6 +5,7 @@
#include "qemu-common.h"
#include "hw/irq.h"
#include "migration/qemu-file.h"
+#include "migration/vmstate.h"
#ifdef NEED_CPU_H
#include "cpu.h"
@@ -38,27 +39,6 @@
#endif
#endif
-typedef void SaveStateHandler(QEMUFile *f, void *opaque);
-typedef int SaveLiveStateHandler(QEMUFile *f, int stage, void *opaque);
-typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
-
-int register_savevm(const char *idstr,
- int instance_id,
- int version_id,
- SaveStateHandler *save_state,
- LoadStateHandler *load_state,
- void *opaque);
-
-int register_savevm_live(const char *idstr,
- int instance_id,
- int version_id,
- SaveLiveStateHandler *save_live_state,
- SaveStateHandler *save_state,
- LoadStateHandler *load_state,
- void *opaque);
-
-void unregister_savevm(const char *idstr, void *opaque);
-
typedef void QEMUResetHandler(void *opaque);
void qemu_register_reset(QEMUResetHandler *func, int order, void *opaque);
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
new file mode 100644
index 0000000..f52582b
--- /dev/null
+++ b/include/migration/vmstate.h
@@ -0,0 +1,758 @@
+/*
+ * QEMU migration/snapshot declarations
+ *
+ * Copyright (c) 2009-2011 Red Hat, Inc.
+ *
+ * Original author: Juan Quintela <quintela@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef QEMU_VMSTATE_H
+#define QEMU_VMSTATE_H 1
+
+#ifndef CONFIG_USER_ONLY
+#include <migration/qemu-file.h>
+#endif
+
+typedef void SaveStateHandler(QEMUFile *f, void *opaque);
+typedef int SaveLiveStateHandler(QEMUFile *f, int stage, void *opaque);
+typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
+
+typedef struct SaveVMHandlers {
+#if 0
+ /* This runs inside the iothread lock. */
+ void (*set_params)(const MigrationParams *params, void * opaque);
+#endif
+ SaveStateHandler *save_state;
+ SaveLiveStateHandler *save_live_state;
+#if 0
+ void (*cancel)(void *opaque);
+ int (*save_live_complete)(QEMUFile *f, void *opaque);
+
+ /* This runs both outside and inside the iothread lock. */
+ bool (*is_active)(void *opaque);
+
+ /* This runs outside the iothread lock in the migration case, and
+ * within the lock in the savevm case. The callback had better only
+ * use data that is local to the migration thread or protected
+ * by other locks.
+ */
+ int (*save_live_iterate)(QEMUFile *f, void *opaque);
+
+ /* This runs outside the iothread lock! */
+ int (*save_live_setup)(QEMUFile *f, void *opaque);
+ uint64_t (*save_live_pending)(QEMUFile *f, void *opaque, uint64_t max_size);
+#endif
+ LoadStateHandler *load_state;
+} SaveVMHandlers;
+
+int register_savevm(DeviceState* dev,
+ const char *idstr,
+ int instance_id,
+ int version_id,
+ SaveStateHandler *save_state,
+ LoadStateHandler *load_state,
+ void *opaque);
+
+int register_savevm_live(DeviceState* dev,
+ const char *idstr,
+ int instance_id,
+ int version_id,
+ SaveVMHandlers *ops,
+ void *opaque);
+
+void unregister_savevm(DeviceState* dev, const char *idstr, void *opaque);
+void register_device_unmigratable(DeviceState *dev, const char *idstr,
+ void *opaque);
+
+typedef struct VMStateInfo VMStateInfo;
+typedef struct VMStateDescription VMStateDescription;
+
+struct VMStateInfo {
+ const char *name;
+ int (*get)(QEMUFile *f, void *pv, size_t size);
+ void (*put)(QEMUFile *f, void *pv, size_t size);
+};
+
+enum VMStateFlags {
+ VMS_SINGLE = 0x001,
+ VMS_POINTER = 0x002,
+ VMS_ARRAY = 0x004,
+ VMS_STRUCT = 0x008,
+ VMS_VARRAY_INT32 = 0x010, /* Array with size in int32_t field*/
+ VMS_BUFFER = 0x020, /* static sized buffer */
+ VMS_ARRAY_OF_POINTER = 0x040,
+ VMS_VARRAY_UINT16 = 0x080, /* Array with size in uint16_t field */
+ VMS_VBUFFER = 0x100, /* Buffer with size in int32_t field */
+ VMS_MULTIPLY = 0x200, /* multiply "size" field by field_size */
+ VMS_VARRAY_UINT8 = 0x400, /* Array with size in uint8_t field*/
+ VMS_VARRAY_UINT32 = 0x800, /* Array with size in uint32_t field*/
+};
+
+typedef struct {
+ const char *name;
+ size_t offset;
+ size_t size;
+ size_t start;
+ int num;
+ size_t num_offset;
+ size_t size_offset;
+ const VMStateInfo *info;
+ enum VMStateFlags flags;
+ const VMStateDescription *vmsd;
+ int version_id;
+ bool (*field_exists)(void *opaque, int version_id);
+} VMStateField;
+
+typedef struct VMStateSubsection {
+ const VMStateDescription *vmsd;
+ bool (*needed)(void *opaque);
+} VMStateSubsection;
+
+struct VMStateDescription {
+ const char *name;
+ int unmigratable;
+ int version_id;
+ int minimum_version_id;
+ int minimum_version_id_old;
+ LoadStateHandler *load_state_old;
+ int (*pre_load)(void *opaque);
+ int (*post_load)(void *opaque, int version_id);
+ void (*pre_save)(void *opaque);
+ VMStateField *fields;
+ const VMStateSubsection *subsections;
+};
+
+#ifdef CONFIG_USER_ONLY
+extern const VMStateDescription vmstate_dummy;
+#endif
+
+extern const VMStateInfo vmstate_info_bool;
+
+extern const VMStateInfo vmstate_info_int8;
+extern const VMStateInfo vmstate_info_int16;
+extern const VMStateInfo vmstate_info_int32;
+extern const VMStateInfo vmstate_info_int64;
+
+extern const VMStateInfo vmstate_info_uint8_equal;
+extern const VMStateInfo vmstate_info_uint16_equal;
+extern const VMStateInfo vmstate_info_int32_equal;
+extern const VMStateInfo vmstate_info_uint32_equal;
+extern const VMStateInfo vmstate_info_uint64_equal;
+extern const VMStateInfo vmstate_info_int32_le;
+
+extern const VMStateInfo vmstate_info_uint8;
+extern const VMStateInfo vmstate_info_uint16;
+extern const VMStateInfo vmstate_info_uint32;
+extern const VMStateInfo vmstate_info_uint64;
+
+extern const VMStateInfo vmstate_info_float64;
+
+extern const VMStateInfo vmstate_info_timer;
+extern const VMStateInfo vmstate_info_buffer;
+extern const VMStateInfo vmstate_info_unused_buffer;
+extern const VMStateInfo vmstate_info_bitmap;
+
+#define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)
+#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
+#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
+
+#define vmstate_offset_value(_state, _field, _type) \
+ (offsetof(_state, _field) + \
+ type_check(_type, typeof_field(_state, _field)))
+
+#define vmstate_offset_pointer(_state, _field, _type) \
+ (offsetof(_state, _field) + \
+ type_check_pointer(_type, typeof_field(_state, _field)))
+
+#define vmstate_offset_array(_state, _field, _type, _num) \
+ (offsetof(_state, _field) + \
+ type_check_array(_type, typeof_field(_state, _field), _num))
+
+#define vmstate_offset_2darray(_state, _field, _type, _n1, _n2) \
+ (offsetof(_state, _field) + \
+ type_check_2darray(_type, typeof_field(_state, _field), _n1, _n2))
+
+#define vmstate_offset_sub_array(_state, _field, _type, _start) \
+ (offsetof(_state, _field[_start]))
+
+#define vmstate_offset_buffer(_state, _field) \
+ vmstate_offset_array(_state, _field, uint8_t, \
+ sizeof(typeof_field(_state, _field)))
+
+#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .size = sizeof(_type), \
+ .info = &(_info), \
+ .flags = VMS_SINGLE, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
+#define VMSTATE_POINTER(_field, _state, _version, _info, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_SINGLE|VMS_POINTER, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
+#define VMSTATE_POINTER_TEST(_field, _state, _test, _info, _type) { \
+ .name = (stringify(_field)), \
+ .info = &(_info), \
+ .field_exists = (_test), \
+ .size = sizeof(_type), \
+ .flags = VMS_SINGLE|VMS_POINTER, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
+#define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) {\
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num = (_num), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_ARRAY, \
+ .offset = vmstate_offset_array(_state, _field, _type, _num), \
+}
+
+#define VMSTATE_2DARRAY(_field, _state, _n1, _n2, _version, _info, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num = (_n1) * (_n2), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_ARRAY, \
+ .offset = vmstate_offset_2darray(_state, _field, _type, _n1, _n2), \
+}
+
+#define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\
+ .name = (stringify(_field)), \
+ .field_exists = (_test), \
+ .num = (_num), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_ARRAY, \
+ .offset = vmstate_offset_array(_state, _field, _type, _num),\
+}
+
+#define VMSTATE_SUB_ARRAY(_field, _state, _start, _num, _version, _info, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num = (_num), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_ARRAY, \
+ .offset = vmstate_offset_sub_array(_state, _field, _type, _start), \
+}
+
+#define VMSTATE_ARRAY_INT32_UNSAFE(_field, _state, _field_num, _info, _type) {\
+ .name = (stringify(_field)), \
+ .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_VARRAY_INT32, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_VARRAY_INT32|VMS_POINTER, \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
+}
+
+#define VMSTATE_VARRAY_UINT32(_field, _state, _field_num, _version, _info, _type) {\
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_VARRAY_UINT32|VMS_POINTER, \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
+}
+
+#define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_VARRAY_UINT16, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
+#define VMSTATE_STRUCT_POINTER_V(_field, _state, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_POINTER, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
+#define VMSTATE_STRUCT_POINTER_TEST_V(_field, _state, _test, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_POINTER, \
+ .offset = vmstate_offset_value(_state, _field, _type), \
+}
+
+#define VMSTATE_ARRAY_OF_POINTER(_field, _state, _num, _version, _info, _type) {\
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num = (_num), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_ARRAY|VMS_ARRAY_OF_POINTER, \
+ .offset = vmstate_offset_array(_state, _field, _type, _num), \
+}
+
+#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .num = (_num), \
+ .field_exists = (_test), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_ARRAY, \
+ .offset = vmstate_offset_array(_state, _field, _type, _num),\
+}
+
+#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_VARRAY_UINT8, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_STRUCT_VARRAY_POINTER_INT32(_field, _state, _field_num, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = 0, \
+ .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .size = sizeof(_type), \
+ .vmsd = &(_vmsd), \
+ .flags = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT, \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
+}
+
+#define VMSTATE_STRUCT_VARRAY_POINTER_UINT32(_field, _state, _field_num, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = 0, \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
+ .size = sizeof(_type), \
+ .vmsd = &(_vmsd), \
+ .flags = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT, \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
+}
+
+#define VMSTATE_STRUCT_VARRAY_POINTER_UINT16(_field, _state, _field_num, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = 0, \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
+ .size = sizeof(_type), \
+ .vmsd = &(_vmsd), \
+ .flags = VMS_POINTER | VMS_VARRAY_UINT16 | VMS_STRUCT, \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
+}
+
+#define VMSTATE_STRUCT_VARRAY_INT32(_field, _state, _field_num, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_VARRAY_INT32, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_VARRAY_UINT32, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .size = (_size - _start), \
+ .info = &vmstate_info_buffer, \
+ .flags = VMS_BUFFER, \
+ .offset = vmstate_offset_buffer(_state, _field) + _start, \
+}
+
+#define VMSTATE_VBUFFER_MULTIPLY(_field, _state, _version, _test, _start, _field_size, _multiply) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\
+ .size = (_multiply), \
+ .info = &vmstate_info_buffer, \
+ .flags = VMS_VBUFFER|VMS_POINTER|VMS_MULTIPLY, \
+ .offset = offsetof(_state, _field), \
+ .start = (_start), \
+}
+
+#define VMSTATE_VBUFFER(_field, _state, _version, _test, _start, _field_size) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .size_offset = vmstate_offset_value(_state, _field_size, int32_t),\
+ .info = &vmstate_info_buffer, \
+ .flags = VMS_VBUFFER|VMS_POINTER, \
+ .offset = offsetof(_state, _field), \
+ .start = (_start), \
+}
+
+#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _start, _field_size) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\
+ .info = &vmstate_info_buffer, \
+ .flags = VMS_VBUFFER|VMS_POINTER, \
+ .offset = offsetof(_state, _field), \
+ .start = (_start), \
+}
+
+#define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .size = (_size), \
+ .info = &(_info), \
+ .flags = VMS_BUFFER, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_BUFFER_POINTER_UNSAFE(_field, _state, _version, _size) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .size = (_size), \
+ .info = &vmstate_info_buffer, \
+ .flags = VMS_BUFFER|VMS_POINTER, \
+ .offset = offsetof(_state, _field), \
+}
+
+#define VMSTATE_UNUSED_BUFFER(_test, _version, _size) { \
+ .name = "unused", \
+ .field_exists = (_test), \
+ .version_id = (_version), \
+ .size = (_size), \
+ .info = &vmstate_info_unused_buffer, \
+ .flags = VMS_BUFFER, \
+}
+
+/* _field_size should be a int32_t field in the _state struct giving the
+ * size of the bitmap _field in bits.
+ */
+#define VMSTATE_BITMAP(_field, _state, _version, _field_size) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .size_offset = vmstate_offset_value(_state, _field_size, int32_t),\
+ .info = &vmstate_info_bitmap, \
+ .flags = VMS_VBUFFER|VMS_POINTER, \
+ .offset = offsetof(_state, _field), \
+}
+
+/* _f : field name
+ _f_n : num of elements field_name
+ _n : num of elements
+ _s : struct state name
+ _v : version
+*/
+
+#define VMSTATE_SINGLE(_field, _state, _version, _info, _type) \
+ VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type)
+
+#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \
+ VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type)
+
+#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) \
+ VMSTATE_STRUCT_POINTER_V(_field, _state, 0, _vmsd, _type)
+
+#define VMSTATE_STRUCT_POINTER_TEST(_field, _state, _test, _vmsd, _type) \
+ VMSTATE_STRUCT_POINTER_TEST_V(_field, _state, _test, 0, _vmsd, _type)
+
+#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \
+ VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version, \
+ _vmsd, _type)
+
+#define VMSTATE_BOOL_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_bool, bool)
+
+#define VMSTATE_INT8_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int8, int8_t)
+#define VMSTATE_INT16_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int16, int16_t)
+#define VMSTATE_INT32_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int32, int32_t)
+#define VMSTATE_INT64_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int64, int64_t)
+
+#define VMSTATE_UINT8_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint8, uint8_t)
+#define VMSTATE_UINT16_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16, uint16_t)
+#define VMSTATE_UINT32_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint32, uint32_t)
+#define VMSTATE_UINT64_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64, uint64_t)
+
+#define VMSTATE_BOOL(_f, _s) \
+ VMSTATE_BOOL_V(_f, _s, 0)
+
+#define VMSTATE_INT8(_f, _s) \
+ VMSTATE_INT8_V(_f, _s, 0)
+#define VMSTATE_INT16(_f, _s) \
+ VMSTATE_INT16_V(_f, _s, 0)
+#define VMSTATE_INT32(_f, _s) \
+ VMSTATE_INT32_V(_f, _s, 0)
+#define VMSTATE_INT64(_f, _s) \
+ VMSTATE_INT64_V(_f, _s, 0)
+
+#define VMSTATE_UINT8(_f, _s) \
+ VMSTATE_UINT8_V(_f, _s, 0)
+#define VMSTATE_UINT16(_f, _s) \
+ VMSTATE_UINT16_V(_f, _s, 0)
+#define VMSTATE_UINT32(_f, _s) \
+ VMSTATE_UINT32_V(_f, _s, 0)
+#define VMSTATE_UINT64(_f, _s) \
+ VMSTATE_UINT64_V(_f, _s, 0)
+
+#define VMSTATE_UINT8_EQUAL(_f, _s) \
+ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint8_equal, uint8_t)
+
+#define VMSTATE_UINT16_EQUAL(_f, _s) \
+ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint16_equal, uint16_t)
+
+#define VMSTATE_UINT16_EQUAL_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16_equal, uint16_t)
+
+#define VMSTATE_INT32_EQUAL(_f, _s) \
+ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_equal, int32_t)
+
+#define VMSTATE_UINT32_EQUAL_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint32_equal, uint32_t)
+
+#define VMSTATE_UINT32_EQUAL(_f, _s) \
+ VMSTATE_UINT32_EQUAL_V(_f, _s, 0)
+
+#define VMSTATE_UINT64_EQUAL_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64_equal, uint64_t)
+
+#define VMSTATE_UINT64_EQUAL(_f, _s) \
+ VMSTATE_UINT64_EQUAL_V(_f, _s, 0)
+
+#define VMSTATE_INT32_LE(_f, _s) \
+ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
+
+#define VMSTATE_UINT8_TEST(_f, _s, _t) \
+ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint8, uint8_t)
+
+#define VMSTATE_UINT16_TEST(_f, _s, _t) \
+ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint16, uint16_t)
+
+#define VMSTATE_UINT32_TEST(_f, _s, _t) \
+ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint32, uint32_t)
+
+
+#define VMSTATE_FLOAT64_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_float64, float64)
+
+#define VMSTATE_FLOAT64(_f, _s) \
+ VMSTATE_FLOAT64_V(_f, _s, 0)
+
+#define VMSTATE_TIMER_TEST(_f, _s, _test) \
+ VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *)
+
+#define VMSTATE_TIMER_V(_f, _s, _v) \
+ VMSTATE_POINTER(_f, _s, _v, vmstate_info_timer, QEMUTimer *)
+
+#define VMSTATE_TIMER(_f, _s) \
+ VMSTATE_TIMER_V(_f, _s, 0)
+
+#define VMSTATE_TIMER_ARRAY(_f, _s, _n) \
+ VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *)
+
+#define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool)
+
+#define VMSTATE_BOOL_ARRAY(_f, _s, _n) \
+ VMSTATE_BOOL_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t)
+
+#define VMSTATE_UINT16_2DARRAY_V(_f, _s, _n1, _n2, _v) \
+ VMSTATE_2DARRAY(_f, _s, _n1, _n2, _v, vmstate_info_uint16, uint16_t)
+
+#define VMSTATE_UINT16_ARRAY(_f, _s, _n) \
+ VMSTATE_UINT16_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT16_2DARRAY(_f, _s, _n1, _n2) \
+ VMSTATE_UINT16_2DARRAY_V(_f, _s, _n1, _n2, 0)
+
+#define VMSTATE_UINT8_2DARRAY_V(_f, _s, _n1, _n2, _v) \
+ VMSTATE_2DARRAY(_f, _s, _n1, _n2, _v, vmstate_info_uint8, uint8_t)
+
+#define VMSTATE_UINT8_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint8, uint8_t)
+
+#define VMSTATE_UINT8_ARRAY(_f, _s, _n) \
+ VMSTATE_UINT8_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT8_2DARRAY(_f, _s, _n1, _n2) \
+ VMSTATE_UINT8_2DARRAY_V(_f, _s, _n1, _n2, 0)
+
+#define VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_UINT32_ARRAY(_f, _s, _n) \
+ VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint64, uint64_t)
+
+#define VMSTATE_UINT64_ARRAY(_f, _s, _n) \
+ VMSTATE_UINT64_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int16, int16_t)
+
+#define VMSTATE_INT16_ARRAY(_f, _s, _n) \
+ VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_INT32_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int32, int32_t)
+
+#define VMSTATE_INT32_ARRAY(_f, _s, _n) \
+ VMSTATE_INT32_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_UINT32_SUB_ARRAY(_f, _s, _start, _num) \
+ VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_UINT32_ARRAY(_f, _s, _n) \
+ VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_INT64_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int64, int64_t)
+
+#define VMSTATE_INT64_ARRAY(_f, _s, _n) \
+ VMSTATE_INT64_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_FLOAT64_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_float64, float64)
+
+#define VMSTATE_FLOAT64_ARRAY(_f, _s, _n) \
+ VMSTATE_FLOAT64_ARRAY_V(_f, _s, _n, 0)
+
+#define VMSTATE_BUFFER_V(_f, _s, _v) \
+ VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_BUFFER(_f, _s) \
+ VMSTATE_BUFFER_V(_f, _s, 0)
+
+#define VMSTATE_PARTIAL_BUFFER(_f, _s, _size) \
+ VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, 0, _size)
+
+#define VMSTATE_BUFFER_START_MIDDLE(_f, _s, _start) \
+ VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, _start, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size) \
+ VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size)
+
+#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size) \
+ VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, 0, _size)
+
+#define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size) \
+ VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size)
+
+#define VMSTATE_BUFFER_TEST(_f, _s, _test) \
+ VMSTATE_STATIC_BUFFER(_f, _s, 0, _test, 0, sizeof(typeof_field(_s, _f)))
+
+#define VMSTATE_BUFFER_UNSAFE(_field, _state, _version, _size) \
+ VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, vmstate_info_buffer, _size)
+
+#define VMSTATE_UNUSED_V(_v, _size) \
+ VMSTATE_UNUSED_BUFFER(NULL, _v, _size)
+
+#define VMSTATE_UNUSED(_size) \
+ VMSTATE_UNUSED_V(0, _size)
+
+#define VMSTATE_UNUSED_TEST(_test, _size) \
+ VMSTATE_UNUSED_BUFFER(_test, 0, _size)
+
+#define VMSTATE_END_OF_LIST() \
+ {}
+
+int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque, int version_id);
+void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque);
+
+int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
+ const VMStateDescription *vmsd,
+ void *base, int alias_id,
+ int required_for_version);
+
+static inline int vmstate_register(DeviceState *dev, int instance_id,
+ const VMStateDescription *vmsd,
+ void *opaque)
+{
+ return vmstate_register_with_alias_id(dev, instance_id, vmsd,
+ opaque, -1, 0);
+}
+
+void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
+ void *opaque);
+
+#ifndef CONFIG_ANDROID
+struct MemoryRegion;
+void vmstate_register_ram(struct MemoryRegion *memory, DeviceState *dev);
+void vmstate_unregister_ram(struct MemoryRegion *memory, DeviceState *dev);
+void vmstate_register_ram_global(struct MemoryRegion *memory);
+#endif // !CONFIG_ANDROID
+
+#endif
diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h
new file mode 100644
index 0000000..308bbb7
--- /dev/null
+++ b/include/qemu/bitmap.h
@@ -0,0 +1,222 @@
+/*
+ * Bitmap Module
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
+ *
+ * Mostly inspired by (stolen from) linux/bitmap.h and linux/bitops.h
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#ifndef BITMAP_H
+#define BITMAP_H
+
+#include "qemu-common.h"
+#include "qemu/bitops.h"
+
+/*
+ * The available bitmap operations and their rough meaning in the
+ * case that the bitmap is a single unsigned long are thus:
+ *
+ * Note that nbits should be always a compile time evaluable constant.
+ * Otherwise many inlines will generate horrible code.
+ *
+ * bitmap_zero(dst, nbits) *dst = 0UL
+ * bitmap_fill(dst, nbits) *dst = ~0UL
+ * bitmap_copy(dst, src, nbits) *dst = *src
+ * bitmap_and(dst, src1, src2, nbits) *dst = *src1 & *src2
+ * bitmap_or(dst, src1, src2, nbits) *dst = *src1 | *src2
+ * bitmap_xor(dst, src1, src2, nbits) *dst = *src1 ^ *src2
+ * bitmap_andnot(dst, src1, src2, nbits) *dst = *src1 & ~(*src2)
+ * bitmap_complement(dst, src, nbits) *dst = ~(*src)
+ * bitmap_equal(src1, src2, nbits) Are *src1 and *src2 equal?
+ * bitmap_intersects(src1, src2, nbits) Do *src1 and *src2 overlap?
+ * bitmap_empty(src, nbits) Are all bits zero in *src?
+ * bitmap_full(src, nbits) Are all bits set in *src?
+ * bitmap_set(dst, pos, nbits) Set specified bit area
+ * bitmap_clear(dst, pos, nbits) Clear specified bit area
+ * bitmap_find_next_zero_area(buf, len, pos, n, mask) Find bit free area
+ */
+
+/*
+ * Also the following operations apply to bitmaps.
+ *
+ * set_bit(bit, addr) *addr |= bit
+ * clear_bit(bit, addr) *addr &= ~bit
+ * change_bit(bit, addr) *addr ^= bit
+ * test_bit(bit, addr) Is bit set in *addr?
+ * test_and_set_bit(bit, addr) Set bit and return old value
+ * test_and_clear_bit(bit, addr) Clear bit and return old value
+ * test_and_change_bit(bit, addr) Change bit and return old value
+ * find_first_zero_bit(addr, nbits) Position first zero bit in *addr
+ * find_first_bit(addr, nbits) Position first set bit in *addr
+ * find_next_zero_bit(addr, nbits, bit) Position next zero bit in *addr >= bit
+ * find_next_bit(addr, nbits, bit) Position next set bit in *addr >= bit
+ */
+
+#define BITMAP_LAST_WORD_MASK(nbits) \
+ ( \
+ ((nbits) % BITS_PER_LONG) ? \
+ (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL \
+ )
+
+#define DECLARE_BITMAP(name,bits) \
+ unsigned long name[BITS_TO_LONGS(bits)]
+
+#define small_nbits(nbits) \
+ ((nbits) <= BITS_PER_LONG)
+
+int slow_bitmap_empty(const unsigned long *bitmap, int bits);
+int slow_bitmap_full(const unsigned long *bitmap, int bits);
+int slow_bitmap_equal(const unsigned long *bitmap1,
+ const unsigned long *bitmap2, int bits);
+void slow_bitmap_complement(unsigned long *dst, const unsigned long *src,
+ int bits);
+void slow_bitmap_shift_right(unsigned long *dst,
+ const unsigned long *src, int shift, int bits);
+void slow_bitmap_shift_left(unsigned long *dst,
+ const unsigned long *src, int shift, int bits);
+int slow_bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2, int bits);
+void slow_bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2, int bits);
+void slow_bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2, int bits);
+int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2, int bits);
+int slow_bitmap_intersects(const unsigned long *bitmap1,
+ const unsigned long *bitmap2, int bits);
+
+static inline unsigned long *bitmap_new(int nbits)
+{
+ int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+ return g_malloc0(len);
+}
+
+static inline void bitmap_zero(unsigned long *dst, int nbits)
+{
+ if (small_nbits(nbits)) {
+ *dst = 0UL;
+ } else {
+ int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+ memset(dst, 0, len);
+ }
+}
+
+static inline void bitmap_fill(unsigned long *dst, int nbits)
+{
+ size_t nlongs = BITS_TO_LONGS(nbits);
+ if (!small_nbits(nbits)) {
+ int len = (nlongs - 1) * sizeof(unsigned long);
+ memset(dst, 0xff, len);
+ }
+ dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
+}
+
+static inline void bitmap_copy(unsigned long *dst, const unsigned long *src,
+ int nbits)
+{
+ if (small_nbits(nbits)) {
+ *dst = *src;
+ } else {
+ int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+ memcpy(dst, src, len);
+ }
+}
+
+static inline int bitmap_and(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, int nbits)
+{
+ if (small_nbits(nbits)) {
+ return (*dst = *src1 & *src2) != 0;
+ }
+ return slow_bitmap_and(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, int nbits)
+{
+ if (small_nbits(nbits)) {
+ *dst = *src1 | *src2;
+ } else {
+ slow_bitmap_or(dst, src1, src2, nbits);
+ }
+}
+
+static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, int nbits)
+{
+ if (small_nbits(nbits)) {
+ *dst = *src1 ^ *src2;
+ } else {
+ slow_bitmap_xor(dst, src1, src2, nbits);
+ }
+}
+
+static inline int bitmap_andnot(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, int nbits)
+{
+ if (small_nbits(nbits)) {
+ return (*dst = *src1 & ~(*src2)) != 0;
+ }
+ return slow_bitmap_andnot(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_complement(unsigned long *dst, const unsigned long *src,
+ int nbits)
+{
+ if (small_nbits(nbits)) {
+ *dst = ~(*src) & BITMAP_LAST_WORD_MASK(nbits);
+ } else {
+ slow_bitmap_complement(dst, src, nbits);
+ }
+}
+
+static inline int bitmap_equal(const unsigned long *src1,
+ const unsigned long *src2, int nbits)
+{
+ if (small_nbits(nbits)) {
+ return ! ((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
+ } else {
+ return slow_bitmap_equal(src1, src2, nbits);
+ }
+}
+
+static inline int bitmap_empty(const unsigned long *src, int nbits)
+{
+ if (small_nbits(nbits)) {
+ return ! (*src & BITMAP_LAST_WORD_MASK(nbits));
+ } else {
+ return slow_bitmap_empty(src, nbits);
+ }
+}
+
+static inline int bitmap_full(const unsigned long *src, int nbits)
+{
+ if (small_nbits(nbits)) {
+ return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits));
+ } else {
+ return slow_bitmap_full(src, nbits);
+ }
+}
+
+static inline int bitmap_intersects(const unsigned long *src1,
+ const unsigned long *src2, int nbits)
+{
+ if (small_nbits(nbits)) {
+ return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
+ } else {
+ return slow_bitmap_intersects(src1, src2, nbits);
+ }
+}
+
+void bitmap_set(unsigned long *map, int i, int len);
+void bitmap_clear(unsigned long *map, int start, int nr);
+unsigned long bitmap_find_next_zero_area(unsigned long *map,
+ unsigned long size,
+ unsigned long start,
+ unsigned int nr,
+ unsigned long align_mask);
+
+#endif /* BITMAP_H */
diff --git a/savevm.c b/savevm.c
index 69f56b9..b5a4167 100644
--- a/savevm.c
+++ b/savevm.c
@@ -75,16 +75,18 @@
#include "net/net.h"
#include "monitor/monitor.h"
#include "sysemu/sysemu.h"
-#include "qemu/iov.h"
-#include "qemu/timer.h"
#include "sysemu/char.h"
#include "sysemu/blockdev.h"
#include "block/block.h"
#include "audio/audio.h"
#include "migration/migration.h"
-#include "qemu/sockets.h"
-#include "qemu/queue.h"
#include "migration/qemu-file.h"
+#include "migration/vmstate.h"
+#include "qemu/bitmap.h"
+#include "qemu/iov.h"
+#include "qemu/sockets.h"
+#include "qemu/timer.h"
+#include "qemu/queue.h"
#include "android/snapshot.h"
@@ -1081,28 +1083,6 @@
}
-/* timer */
-
-void timer_put(QEMUFile *f, QEMUTimer *ts)
-{
- uint64_t expire_time;
-
- expire_time = timer_expire_time_ns(ts);
- qemu_put_be64(f, expire_time);
-}
-
-void timer_get(QEMUFile *f, QEMUTimer *ts)
-{
- uint64_t expire_time;
-
- expire_time = qemu_get_be64(f);
- if (expire_time != -1) {
- timer_mod_ns(ts, expire_time);
- } else {
- timer_del(ts);
- }
-}
-
void qemu_put_struct(QEMUFile* f, const QField* fields, const void* s)
{
const QField* qf = fields;
@@ -1214,84 +1194,849 @@
return *((float*) bytes);
}
-typedef struct SaveStateEntry {
+/* timer */
+
+void timer_put(QEMUFile *f, QEMUTimer *ts)
+{
+ uint64_t expire_time;
+
+ expire_time = timer_expire_time_ns(ts);
+ qemu_put_be64(f, expire_time);
+}
+
+void timer_get(QEMUFile *f, QEMUTimer *ts)
+{
+ uint64_t expire_time;
+
+ expire_time = qemu_get_be64(f);
+ if (expire_time != -1) {
+ timer_mod_ns(ts, expire_time);
+ } else {
+ timer_del(ts);
+ }
+}
+
+
+/* bool */
+
+static int get_bool(QEMUFile *f, void *pv, size_t size)
+{
+ bool *v = pv;
+ *v = qemu_get_byte(f);
+ return 0;
+}
+
+static void put_bool(QEMUFile *f, void *pv, size_t size)
+{
+ bool *v = pv;
+ qemu_put_byte(f, *v);
+}
+
+const VMStateInfo vmstate_info_bool = {
+ .name = "bool",
+ .get = get_bool,
+ .put = put_bool,
+};
+
+/* 8 bit int */
+
+static int get_int8(QEMUFile *f, void *pv, size_t size)
+{
+ int8_t *v = pv;
+ qemu_get_s8s(f, v);
+ return 0;
+}
+
+static void put_int8(QEMUFile *f, void *pv, size_t size)
+{
+ int8_t *v = pv;
+ qemu_put_s8s(f, v);
+}
+
+const VMStateInfo vmstate_info_int8 = {
+ .name = "int8",
+ .get = get_int8,
+ .put = put_int8,
+};
+
+/* 16 bit int */
+
+static int get_int16(QEMUFile *f, void *pv, size_t size)
+{
+ int16_t *v = pv;
+ qemu_get_sbe16s(f, v);
+ return 0;
+}
+
+static void put_int16(QEMUFile *f, void *pv, size_t size)
+{
+ int16_t *v = pv;
+ qemu_put_sbe16s(f, v);
+}
+
+const VMStateInfo vmstate_info_int16 = {
+ .name = "int16",
+ .get = get_int16,
+ .put = put_int16,
+};
+
+/* 32 bit int */
+
+static int get_int32(QEMUFile *f, void *pv, size_t size)
+{
+ int32_t *v = pv;
+ qemu_get_sbe32s(f, v);
+ return 0;
+}
+
+static void put_int32(QEMUFile *f, void *pv, size_t size)
+{
+ int32_t *v = pv;
+ qemu_put_sbe32s(f, v);
+}
+
+const VMStateInfo vmstate_info_int32 = {
+ .name = "int32",
+ .get = get_int32,
+ .put = put_int32,
+};
+
+/* 32 bit int. See that the received value is the same than the one
+ in the field */
+
+static int get_int32_equal(QEMUFile *f, void *pv, size_t size)
+{
+ int32_t *v = pv;
+ int32_t v2;
+ qemu_get_sbe32s(f, &v2);
+
+ if (*v == v2)
+ return 0;
+ return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_int32_equal = {
+ .name = "int32 equal",
+ .get = get_int32_equal,
+ .put = put_int32,
+};
+
+/* 32 bit int. See that the received value is the less or the same
+ than the one in the field */
+
+static int get_int32_le(QEMUFile *f, void *pv, size_t size)
+{
+ int32_t *old = pv;
+ int32_t new;
+ qemu_get_sbe32s(f, &new);
+
+ if (*old <= new)
+ return 0;
+ return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_int32_le = {
+ .name = "int32 equal",
+ .get = get_int32_le,
+ .put = put_int32,
+};
+
+/* 64 bit int */
+
+static int get_int64(QEMUFile *f, void *pv, size_t size)
+{
+ int64_t *v = pv;
+ qemu_get_sbe64s(f, v);
+ return 0;
+}
+
+static void put_int64(QEMUFile *f, void *pv, size_t size)
+{
+ int64_t *v = pv;
+ qemu_put_sbe64s(f, v);
+}
+
+const VMStateInfo vmstate_info_int64 = {
+ .name = "int64",
+ .get = get_int64,
+ .put = put_int64,
+};
+
+/* 8 bit unsigned int */
+
+static int get_uint8(QEMUFile *f, void *pv, size_t size)
+{
+ uint8_t *v = pv;
+ qemu_get_8s(f, v);
+ return 0;
+}
+
+static void put_uint8(QEMUFile *f, void *pv, size_t size)
+{
+ uint8_t *v = pv;
+ qemu_put_8s(f, v);
+}
+
+const VMStateInfo vmstate_info_uint8 = {
+ .name = "uint8",
+ .get = get_uint8,
+ .put = put_uint8,
+};
+
+/* 16 bit unsigned int */
+
+static int get_uint16(QEMUFile *f, void *pv, size_t size)
+{
+ uint16_t *v = pv;
+ qemu_get_be16s(f, v);
+ return 0;
+}
+
+static void put_uint16(QEMUFile *f, void *pv, size_t size)
+{
+ uint16_t *v = pv;
+ qemu_put_be16s(f, v);
+}
+
+const VMStateInfo vmstate_info_uint16 = {
+ .name = "uint16",
+ .get = get_uint16,
+ .put = put_uint16,
+};
+
+/* 32 bit unsigned int */
+
+static int get_uint32(QEMUFile *f, void *pv, size_t size)
+{
+ uint32_t *v = pv;
+ qemu_get_be32s(f, v);
+ return 0;
+}
+
+static void put_uint32(QEMUFile *f, void *pv, size_t size)
+{
+ uint32_t *v = pv;
+ qemu_put_be32s(f, v);
+}
+
+const VMStateInfo vmstate_info_uint32 = {
+ .name = "uint32",
+ .get = get_uint32,
+ .put = put_uint32,
+};
+
+/* 32 bit uint. See that the received value is the same than the one
+ in the field */
+
+static int get_uint32_equal(QEMUFile *f, void *pv, size_t size)
+{
+ uint32_t *v = pv;
+ uint32_t v2;
+ qemu_get_be32s(f, &v2);
+
+ if (*v == v2) {
+ return 0;
+ }
+ return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_uint32_equal = {
+ .name = "uint32 equal",
+ .get = get_uint32_equal,
+ .put = put_uint32,
+};
+
+/* 64 bit unsigned int */
+
+static int get_uint64(QEMUFile *f, void *pv, size_t size)
+{
+ uint64_t *v = pv;
+ qemu_get_be64s(f, v);
+ return 0;
+}
+
+static void put_uint64(QEMUFile *f, void *pv, size_t size)
+{
+ uint64_t *v = pv;
+ qemu_put_be64s(f, v);
+}
+
+const VMStateInfo vmstate_info_uint64 = {
+ .name = "uint64",
+ .get = get_uint64,
+ .put = put_uint64,
+};
+
+/* 64 bit unsigned int. See that the received value is the same than the one
+ in the field */
+
+static int get_uint64_equal(QEMUFile *f, void *pv, size_t size)
+{
+ uint64_t *v = pv;
+ uint64_t v2;
+ qemu_get_be64s(f, &v2);
+
+ if (*v == v2) {
+ return 0;
+ }
+ return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_uint64_equal = {
+ .name = "int64 equal",
+ .get = get_uint64_equal,
+ .put = put_uint64,
+};
+
+/* 8 bit int. See that the received value is the same than the one
+ in the field */
+
+static int get_uint8_equal(QEMUFile *f, void *pv, size_t size)
+{
+ uint8_t *v = pv;
+ uint8_t v2;
+ qemu_get_8s(f, &v2);
+
+ if (*v == v2)
+ return 0;
+ return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_uint8_equal = {
+ .name = "uint8 equal",
+ .get = get_uint8_equal,
+ .put = put_uint8,
+};
+
+/* 16 bit unsigned int int. See that the received value is the same than the one
+ in the field */
+
+static int get_uint16_equal(QEMUFile *f, void *pv, size_t size)
+{
+ uint16_t *v = pv;
+ uint16_t v2;
+ qemu_get_be16s(f, &v2);
+
+ if (*v == v2)
+ return 0;
+ return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_uint16_equal = {
+ .name = "uint16 equal",
+ .get = get_uint16_equal,
+ .put = put_uint16,
+};
+
+/* floating point */
+
+static int get_float64(QEMUFile *f, void *pv, size_t size)
+{
+ float64 *v = pv;
+
+ *v = make_float64(qemu_get_be64(f));
+ return 0;
+}
+
+static void put_float64(QEMUFile *f, void *pv, size_t size)
+{
+ uint64_t *v = pv;
+
+ qemu_put_be64(f, float64_val(*v));
+}
+
+const VMStateInfo vmstate_info_float64 = {
+ .name = "float64",
+ .get = get_float64,
+ .put = put_float64,
+};
+
+/* timers */
+
+static int get_timer(QEMUFile *f, void *pv, size_t size)
+{
+ QEMUTimer *v = pv;
+ timer_get(f, v);
+ return 0;
+}
+
+static void put_timer(QEMUFile *f, void *pv, size_t size)
+{
+ QEMUTimer *v = pv;
+ timer_put(f, v);
+}
+
+const VMStateInfo vmstate_info_timer = {
+ .name = "timer",
+ .get = get_timer,
+ .put = put_timer,
+};
+
+/* uint8_t buffers */
+
+static int get_buffer(QEMUFile *f, void *pv, size_t size)
+{
+ uint8_t *v = pv;
+ qemu_get_buffer(f, v, size);
+ return 0;
+}
+
+static void put_buffer(QEMUFile *f, void *pv, size_t size)
+{
+ uint8_t *v = pv;
+ qemu_put_buffer(f, v, size);
+}
+
+const VMStateInfo vmstate_info_buffer = {
+ .name = "buffer",
+ .get = get_buffer,
+ .put = put_buffer,
+};
+
+/* unused buffers: space that was used for some fields that are
+ not useful anymore */
+
+static int get_unused_buffer(QEMUFile *f, void *pv, size_t size)
+{
+ uint8_t buf[1024];
+ int block_len;
+
+ while (size > 0) {
+ block_len = MIN(sizeof(buf), size);
+ size -= block_len;
+ qemu_get_buffer(f, buf, block_len);
+ }
+ return 0;
+}
+
+static void put_unused_buffer(QEMUFile *f, void *pv, size_t size)
+{
+ static const uint8_t buf[1024];
+ int block_len;
+
+ while (size > 0) {
+ block_len = MIN(sizeof(buf), size);
+ size -= block_len;
+ qemu_put_buffer(f, buf, block_len);
+ }
+}
+
+const VMStateInfo vmstate_info_unused_buffer = {
+ .name = "unused_buffer",
+ .get = get_unused_buffer,
+ .put = put_unused_buffer,
+};
+
+/* bitmaps (as defined by bitmap.h). Note that size here is the size
+ * of the bitmap in bits. The on-the-wire format of a bitmap is 64
+ * bit words with the bits in big endian order. The in-memory format
+ * is an array of 'unsigned long', which may be either 32 or 64 bits.
+ */
+/* This is the number of 64 bit words sent over the wire */
+#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
+static int get_bitmap(QEMUFile *f, void *pv, size_t size)
+{
+ unsigned long *bmp = pv;
+ int i, idx = 0;
+ for (i = 0; i < BITS_TO_U64S(size); i++) {
+ uint64_t w = qemu_get_be64(f);
+ bmp[idx++] = w;
+ if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
+ bmp[idx++] = w >> 32;
+ }
+ }
+ return 0;
+}
+
+static void put_bitmap(QEMUFile *f, void *pv, size_t size)
+{
+ unsigned long *bmp = pv;
+ int i, idx = 0;
+ for (i = 0; i < BITS_TO_U64S(size); i++) {
+ uint64_t w = bmp[idx++];
+ if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
+ w |= ((uint64_t)bmp[idx++]) << 32;
+ }
+ qemu_put_be64(f, w);
+ }
+}
+
+const VMStateInfo vmstate_info_bitmap = {
+ .name = "bitmap",
+ .get = get_bitmap,
+ .put = put_bitmap,
+};
+
+typedef struct CompatEntry {
char idstr[256];
int instance_id;
+} CompatEntry;
+
+typedef struct SaveStateEntry {
+ QTAILQ_ENTRY(SaveStateEntry) entry;
+ char idstr[256];
+ int instance_id;
+ int alias_id;
int version_id;
int section_id;
- SaveLiveStateHandler *save_live_state;
- SaveStateHandler *save_state;
- LoadStateHandler *load_state;
+ SaveVMHandlers *ops;
+ const VMStateDescription *vmsd;
void *opaque;
- struct SaveStateEntry *next;
+ CompatEntry *compat;
+ int no_migrate;
+ int is_ram;
} SaveStateEntry;
-static SaveStateEntry *first_se;
+
+static QTAILQ_HEAD(savevm_handlers, SaveStateEntry) savevm_handlers =
+ QTAILQ_HEAD_INITIALIZER(savevm_handlers);
+static int global_section_id;
+
+static int calculate_new_instance_id(const char *idstr)
+{
+ SaveStateEntry *se;
+ int instance_id = 0;
+
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ if (strcmp(idstr, se->idstr) == 0
+ && instance_id <= se->instance_id) {
+ instance_id = se->instance_id + 1;
+ }
+ }
+ return instance_id;
+}
+
+static int calculate_compat_instance_id(const char *idstr)
+{
+ SaveStateEntry *se;
+ int instance_id = 0;
+
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ if (!se->compat)
+ continue;
+
+ if (strcmp(idstr, se->compat->idstr) == 0
+ && instance_id <= se->compat->instance_id) {
+ instance_id = se->compat->instance_id + 1;
+ }
+ }
+ return instance_id;
+}
+
+#ifdef CONFIG_ANDROID
+// TODO(digit): Implement this properly once we switch all devices to
+// be DeviceState instances.
+char* qdev_get_dev_path(DeviceState* dev) {
+ return NULL;
+}
+#endif
/* TODO: Individual devices generally have very little idea about the rest
of the system, so instance_id should be removed/replaced.
Meanwhile pass -1 as instance_id if you do not already have a clearly
distinguishing id for all instances of your device class. */
-int register_savevm_live(const char *idstr,
+int register_savevm_live(DeviceState *dev,
+ const char *idstr,
int instance_id,
int version_id,
- SaveLiveStateHandler *save_live_state,
- SaveStateHandler *save_state,
- LoadStateHandler *load_state,
+ SaveVMHandlers *ops,
void *opaque)
{
- SaveStateEntry *se, **pse;
- static int global_section_id;
+ SaveStateEntry *se;
- se = g_malloc(sizeof(SaveStateEntry));
- pstrcpy(se->idstr, sizeof(se->idstr), idstr);
- se->instance_id = (instance_id == -1) ? 0 : instance_id;
+ se = g_malloc0(sizeof(SaveStateEntry));
se->version_id = version_id;
se->section_id = global_section_id++;
- se->save_live_state = save_live_state;
- se->save_state = save_state;
- se->load_state = load_state;
+ se->ops = ops;
se->opaque = opaque;
- se->next = NULL;
-
- /* add at the end of list */
- pse = &first_se;
- while (*pse != NULL) {
- if (instance_id == -1
- && strcmp(se->idstr, (*pse)->idstr) == 0
- && se->instance_id <= (*pse)->instance_id)
- se->instance_id = (*pse)->instance_id + 1;
- pse = &(*pse)->next;
+ se->vmsd = NULL;
+ se->no_migrate = 0;
+ /* if this is a live_savem then set is_ram */
+ if (ops->save_live_state != NULL) {
+ se->is_ram = 1;
}
- *pse = se;
+
+ if (dev) {
+ char *id = qdev_get_dev_path(dev);
+ if (id) {
+ pstrcpy(se->idstr, sizeof(se->idstr), id);
+ pstrcat(se->idstr, sizeof(se->idstr), "/");
+ g_free(id);
+
+ se->compat = g_malloc0(sizeof(CompatEntry));
+ pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), idstr);
+ se->compat->instance_id = instance_id == -1 ?
+ calculate_compat_instance_id(idstr) : instance_id;
+ instance_id = -1;
+ }
+ }
+ pstrcat(se->idstr, sizeof(se->idstr), idstr);
+
+ if (instance_id == -1) {
+ se->instance_id = calculate_new_instance_id(se->idstr);
+ } else {
+ se->instance_id = instance_id;
+ }
+ assert(!se->compat || se->instance_id == 0);
+ /* add at the end of list */
+ QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
return 0;
}
-int register_savevm(const char *idstr,
+int register_savevm(DeviceState *dev,
+ const char *idstr,
int instance_id,
int version_id,
SaveStateHandler *save_state,
LoadStateHandler *load_state,
void *opaque)
{
- return register_savevm_live(idstr, instance_id, version_id,
- NULL, save_state, load_state, opaque);
+ SaveVMHandlers *ops = g_malloc0(sizeof(SaveVMHandlers));
+ ops->save_state = save_state;
+ ops->load_state = load_state;
+ return register_savevm_live(dev, idstr, instance_id, version_id,
+ ops, opaque);
}
-void unregister_savevm(const char *idstr, void *opaque)
+void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
{
- SaveStateEntry **pse;
+ SaveStateEntry *se, *new_se;
+ char id[256] = "";
- pse = &first_se;
- while (*pse != NULL) {
- if (strcmp((*pse)->idstr, idstr) == 0 && (*pse)->opaque == opaque) {
- SaveStateEntry *next = (*pse)->next;
- g_free(*pse);
- *pse = next;
- continue;
+ if (dev) {
+ char *path = qdev_get_dev_path(dev);
+ if (path) {
+ pstrcpy(id, sizeof(id), path);
+ pstrcat(id, sizeof(id), "/");
+ g_free(path);
}
- pse = &(*pse)->next;
}
+ pstrcat(id, sizeof(id), idstr);
+
+ QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
+ if (strcmp(se->idstr, id) == 0 && se->opaque == opaque) {
+ QTAILQ_REMOVE(&savevm_handlers, se, entry);
+ if (se->compat) {
+ g_free(se->compat);
+ }
+ g_free(se->ops);
+ g_free(se);
+ }
+ }
+}
+
+int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
+ const VMStateDescription *vmsd,
+ void *opaque, int alias_id,
+ int required_for_version)
+{
+ SaveStateEntry *se;
+
+ /* If this triggers, alias support can be dropped for the vmsd. */
+ assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id);
+
+ se = g_malloc0(sizeof(SaveStateEntry));
+ se->version_id = vmsd->version_id;
+ se->section_id = global_section_id++;
+ se->opaque = opaque;
+ se->vmsd = vmsd;
+ se->alias_id = alias_id;
+ se->no_migrate = vmsd->unmigratable;
+
+ if (dev) {
+ char *id = qdev_get_dev_path(dev);
+ if (id) {
+ pstrcpy(se->idstr, sizeof(se->idstr), id);
+ pstrcat(se->idstr, sizeof(se->idstr), "/");
+ g_free(id);
+
+ se->compat = g_malloc0(sizeof(CompatEntry));
+ pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), vmsd->name);
+ se->compat->instance_id = instance_id == -1 ?
+ calculate_compat_instance_id(vmsd->name) : instance_id;
+ instance_id = -1;
+ }
+ }
+ pstrcat(se->idstr, sizeof(se->idstr), vmsd->name);
+
+ if (instance_id == -1) {
+ se->instance_id = calculate_new_instance_id(se->idstr);
+ } else {
+ se->instance_id = instance_id;
+ }
+ assert(!se->compat || se->instance_id == 0);
+ /* add at the end of list */
+ QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
+ return 0;
+}
+
+void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
+ void *opaque)
+{
+ SaveStateEntry *se, *new_se;
+
+ QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
+ if (se->vmsd == vmsd && se->opaque == opaque) {
+ QTAILQ_REMOVE(&savevm_handlers, se, entry);
+ if (se->compat) {
+ g_free(se->compat);
+ }
+ g_free(se);
+ }
+ }
+}
+
+static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque);
+static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque);
+
+int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque, int version_id)
+{
+ VMStateField *field = vmsd->fields;
+ int ret;
+
+ if (version_id > vmsd->version_id) {
+ return -EINVAL;
+ }
+ if (version_id < vmsd->minimum_version_id_old) {
+ return -EINVAL;
+ }
+ if (version_id < vmsd->minimum_version_id) {
+ return vmsd->load_state_old(f, opaque, version_id);
+ }
+ if (vmsd->pre_load) {
+ int ret = vmsd->pre_load(opaque);
+ if (ret)
+ return ret;
+ }
+ while(field->name) {
+ if ((field->field_exists &&
+ field->field_exists(opaque, version_id)) ||
+ (!field->field_exists &&
+ field->version_id <= version_id)) {
+ void *base_addr = opaque + field->offset;
+ int i, n_elems = 1;
+ int size = field->size;
+
+ if (field->flags & VMS_VBUFFER) {
+ size = *(int32_t *)(opaque+field->size_offset);
+ if (field->flags & VMS_MULTIPLY) {
+ size *= field->size;
+ }
+ }
+ if (field->flags & VMS_ARRAY) {
+ n_elems = field->num;
+ } else if (field->flags & VMS_VARRAY_INT32) {
+ n_elems = *(int32_t *)(opaque+field->num_offset);
+ } else if (field->flags & VMS_VARRAY_UINT32) {
+ n_elems = *(uint32_t *)(opaque+field->num_offset);
+ } else if (field->flags & VMS_VARRAY_UINT16) {
+ n_elems = *(uint16_t *)(opaque+field->num_offset);
+ } else if (field->flags & VMS_VARRAY_UINT8) {
+ n_elems = *(uint8_t *)(opaque+field->num_offset);
+ }
+ if (field->flags & VMS_POINTER) {
+ base_addr = *(void **)base_addr + field->start;
+ }
+ for (i = 0; i < n_elems; i++) {
+ void *addr = base_addr + size * i;
+
+ if (field->flags & VMS_ARRAY_OF_POINTER) {
+ addr = *(void **)addr;
+ }
+ if (field->flags & VMS_STRUCT) {
+ ret = vmstate_load_state(f, field->vmsd, addr, field->vmsd->version_id);
+ } else {
+ ret = field->info->get(f, addr, size);
+
+ }
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ }
+ field++;
+ }
+ ret = vmstate_subsection_load(f, vmsd, opaque);
+ if (ret != 0) {
+ return ret;
+ }
+ if (vmsd->post_load) {
+ return vmsd->post_load(opaque, version_id);
+ }
+ return 0;
+}
+
+void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque)
+{
+ VMStateField *field = vmsd->fields;
+
+ if (vmsd->pre_save) {
+ vmsd->pre_save(opaque);
+ }
+ while(field->name) {
+ if (!field->field_exists ||
+ field->field_exists(opaque, vmsd->version_id)) {
+ void *base_addr = opaque + field->offset;
+ int i, n_elems = 1;
+ int size = field->size;
+
+ if (field->flags & VMS_VBUFFER) {
+ size = *(int32_t *)(opaque+field->size_offset);
+ if (field->flags & VMS_MULTIPLY) {
+ size *= field->size;
+ }
+ }
+ if (field->flags & VMS_ARRAY) {
+ n_elems = field->num;
+ } else if (field->flags & VMS_VARRAY_INT32) {
+ n_elems = *(int32_t *)(opaque+field->num_offset);
+ } else if (field->flags & VMS_VARRAY_UINT32) {
+ n_elems = *(uint32_t *)(opaque+field->num_offset);
+ } else if (field->flags & VMS_VARRAY_UINT16) {
+ n_elems = *(uint16_t *)(opaque+field->num_offset);
+ } else if (field->flags & VMS_VARRAY_UINT8) {
+ n_elems = *(uint8_t *)(opaque+field->num_offset);
+ }
+ if (field->flags & VMS_POINTER) {
+ base_addr = *(void **)base_addr + field->start;
+ }
+ for (i = 0; i < n_elems; i++) {
+ void *addr = base_addr + size * i;
+
+ if (field->flags & VMS_ARRAY_OF_POINTER) {
+ addr = *(void **)addr;
+ }
+ if (field->flags & VMS_STRUCT) {
+ vmstate_save_state(f, field->vmsd, addr);
+ } else {
+ field->info->put(f, addr, size);
+ }
+ }
+ }
+ field++;
+ }
+ vmstate_subsection_save(f, vmsd, opaque);
+}
+
+static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
+{
+ if (!se->vmsd) { /* Old style */
+ return se->ops->load_state(f, se->opaque, version_id);
+ }
+ return vmstate_load_state(f, se->vmsd, se->opaque, version_id);
+}
+
+static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
+{
+ if (!se->vmsd) { /* Old style */
+ se->ops->save_state(f, se->opaque);
+ return;
+ }
+ vmstate_save_state(f,se->vmsd, se->opaque);
}
#define QEMU_VM_FILE_MAGIC 0x5145564d
@@ -1303,6 +2048,20 @@
#define QEMU_VM_SECTION_PART 0x02
#define QEMU_VM_SECTION_END 0x03
#define QEMU_VM_SECTION_FULL 0x04
+#define QEMU_VM_SUBSECTION 0x05
+
+bool qemu_savevm_state_blocked(Error **errp)
+{
+ SaveStateEntry *se;
+
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ if (se->no_migrate) {
+ error_set(errp, QERR_MIGRATION_NOT_SUPPORTED, se->idstr);
+ return true;
+ }
+ }
+ return false;
+}
int qemu_savevm_state_begin(QEMUFile *f)
{
@@ -1311,12 +2070,19 @@
qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
qemu_put_be32(f, QEMU_VM_FILE_VERSION);
- for (se = first_se; se != NULL; se = se->next) {
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
int len;
- if (se->save_live_state == NULL)
+ if (!se->ops || !se->ops->save_live_state) {
continue;
-
+ }
+#if 0
+ if (se->ops && se->ops->is_active) {
+ if (!se->ops->is_active(se->opaque)) {
+ continue;
+ }
+ }
+#endif
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_START);
qemu_put_be32(f, se->section_id);
@@ -1329,7 +2095,7 @@
qemu_put_be32(f, se->instance_id);
qemu_put_be32(f, se->version_id);
- se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
+ se->ops->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
}
return qemu_file_get_error(f);
@@ -1340,15 +2106,26 @@
SaveStateEntry *se;
int ret = 1;
- for (se = first_se; se != NULL; se = se->next) {
- if (se->save_live_state == NULL)
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ if (!se->ops || !se->ops->save_live_state) {
continue;
-
+ }
+#if 0
+ if (se->ops && se->ops->is_active) {
+ if (!se->ops->is_active(se->opaque)) {
+ continue;
+ }
+ }
+#endif
+ if (qemu_file_rate_limit(f)) {
+ return 0;
+ }
+ //trace_savevm_section_start();
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_PART);
qemu_put_be32(f, se->section_id);
- ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque);
+ ret &= !!se->ops->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque);
}
if (ret)
@@ -1361,22 +2138,33 @@
{
SaveStateEntry *se;
- for (se = first_se; se != NULL; se = se->next) {
- if (se->save_live_state == NULL)
- continue;
+ // cpu_synchronize_all_states();
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+ if (!se->ops || se->ops->save_live_state == NULL) {
+ continue;
+ }
+#if 0
+ if (se->ops && se->ops->is_active) {
+ if (!se->ops->is_active(se->opaque)) {
+ continue;
+ }
+ }
+#endif
+ //trace_savevm_section_start();
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_END);
qemu_put_be32(f, se->section_id);
- se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
+ se->ops->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
}
- for(se = first_se; se != NULL; se = se->next) {
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
int len;
- if (se->save_state == NULL)
+ if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
continue;
+ }
/* Section type */
qemu_put_byte(f, QEMU_VM_SECTION_FULL);
@@ -1390,10 +2178,11 @@
qemu_put_be32(f, se->instance_id);
qemu_put_be32(f, se->version_id);
- se->save_state(f, se->opaque);
+ vmstate_save(f, se);
}
qemu_put_byte(f, QEMU_VM_EOF);
+ qemu_fflush(f);
return qemu_file_get_error(f);
}
@@ -1403,6 +2192,10 @@
int saved_vm_running;
int ret;
+ if (qemu_savevm_state_blocked(NULL)) {
+ return -EINVAL;
+ }
+
saved_vm_running = vm_running;
vm_stop(0);
@@ -1433,73 +2226,120 @@
{
SaveStateEntry *se;
- for(se = first_se; se != NULL; se = se->next) {
+ QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if (!strcmp(se->idstr, idstr) &&
- instance_id == se->instance_id)
+ (instance_id == se->instance_id ||
+ instance_id == se->alias_id))
return se;
+ /* Migrating from an older version? */
+ if (strstr(se->idstr, idstr) && se->compat) {
+ if (!strcmp(se->compat->idstr, idstr) &&
+ (instance_id == se->compat->instance_id ||
+ instance_id == se->alias_id))
+ return se;
+ }
}
return NULL;
}
+static const VMStateDescription *vmstate_get_subsection(const VMStateSubsection *sub, char *idstr)
+{
+ while(sub && sub->needed) {
+ if (strcmp(idstr, sub->vmsd->name) == 0) {
+ return sub->vmsd;
+ }
+ sub++;
+ }
+ return NULL;
+}
+
+static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque)
+{
+ while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
+ char idstr[256];
+ int ret;
+ uint8_t version_id, len, size;
+ const VMStateDescription *sub_vmsd;
+
+ len = qemu_peek_byte(f, 1);
+ if (len < strlen(vmsd->name) + 1) {
+ /* subsection name has be be "section_name/a" */
+ return 0;
+ }
+ size = qemu_peek_buffer(f, (uint8_t *)idstr, len, 2);
+ if (size != len) {
+ return 0;
+ }
+ idstr[size] = 0;
+
+ if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
+ /* it don't have a valid subsection name */
+ return 0;
+ }
+ sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
+ if (sub_vmsd == NULL) {
+ return -ENOENT;
+ }
+ qemu_file_skip(f, 1); /* subsection */
+ qemu_file_skip(f, 1); /* len */
+ qemu_file_skip(f, len); /* idstr */
+ version_id = qemu_get_be32(f);
+
+ ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
+ if (ret) {
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque)
+{
+ const VMStateSubsection *sub = vmsd->subsections;
+
+ while (sub && sub->needed) {
+ if (sub->needed(opaque)) {
+ const VMStateDescription *vmsd = sub->vmsd;
+ uint8_t len;
+
+ qemu_put_byte(f, QEMU_VM_SUBSECTION);
+ len = strlen(vmsd->name);
+ qemu_put_byte(f, len);
+ qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
+ qemu_put_be32(f, vmsd->version_id);
+ vmstate_save_state(f, vmsd, opaque);
+ }
+ sub++;
+ }
+}
+
typedef struct LoadStateEntry {
+ QLIST_ENTRY(LoadStateEntry) entry;
SaveStateEntry *se;
int section_id;
int version_id;
- struct LoadStateEntry *next;
} LoadStateEntry;
-static int qemu_loadvm_state_v2(QEMUFile *f)
-{
- SaveStateEntry *se;
- int len, ret, instance_id, record_len, version_id;
- int64_t total_len, end_pos, cur_pos;
- char idstr[256];
-
- total_len = qemu_get_be64(f);
- end_pos = total_len + qemu_ftell(f);
- for(;;) {
- if (qemu_ftell(f) >= end_pos)
- break;
- len = qemu_get_byte(f);
- qemu_get_buffer(f, (uint8_t *)idstr, len);
- idstr[len] = '\0';
- instance_id = qemu_get_be32(f);
- version_id = qemu_get_be32(f);
- record_len = qemu_get_be32(f);
- cur_pos = qemu_ftell(f);
- se = find_se(idstr, instance_id);
- if (!se) {
- fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
- instance_id, idstr);
- } else {
- ret = se->load_state(f, se->opaque, version_id);
- if (ret < 0) {
- fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
- instance_id, idstr);
- return ret;
- }
- }
- /* always seek to exact end of record */
- qemu_file_skip(f, cur_pos + record_len - qemu_ftell(f));
- }
-
- return qemu_file_get_error(f);
-}
-
int qemu_loadvm_state(QEMUFile *f)
{
- LoadStateEntry *first_le = NULL;
+ QLIST_HEAD(, LoadStateEntry) loadvm_handlers =
+ QLIST_HEAD_INITIALIZER(loadvm_handlers);
+ LoadStateEntry *le, *new_le;
uint8_t section_type;
unsigned int v;
int ret;
+ if (qemu_savevm_state_blocked(NULL)) {
+ return -EINVAL;
+ }
+
v = qemu_get_be32(f);
if (v != QEMU_VM_FILE_MAGIC)
return -EINVAL;
v = qemu_get_be32(f);
- if (v == QEMU_VM_FILE_VERSION_COMPAT)
- return qemu_loadvm_state_v2(f);
if (v < QEMU_VM_FILE_VERSION) {
fprintf(stderr, "Snapshot format %d is too old for this version of the emulator, please create a new one.\n", v);
return -ENOTSUP;
@@ -1510,7 +2350,6 @@
while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
uint32_t instance_id, version_id, section_id;
- LoadStateEntry *le;
SaveStateEntry *se;
char idstr[257];
int len;
@@ -1548,12 +2387,12 @@
le->se = se;
le->section_id = section_id;
le->version_id = version_id;
- le->next = first_le;
- first_le = le;
+ QLIST_INSERT_HEAD(&loadvm_handlers, le, entry);
- if (le->se->load_state(f, le->se->opaque, le->version_id)) {
- fprintf(stderr, "savevm: unable to load section %s\n", idstr);
- ret = -EINVAL;
+ ret = vmstate_load(f, le->se, le->version_id);
+ if (ret < 0) {
+ fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
+ instance_id, idstr);
goto out;
}
break;
@@ -1561,14 +2400,23 @@
case QEMU_VM_SECTION_END:
section_id = qemu_get_be32(f);
- for (le = first_le; le && le->section_id != section_id; le = le->next);
+ QLIST_FOREACH(le, &loadvm_handlers, entry) {
+ if (le->section_id == section_id) {
+ break;
+ }
+ }
if (le == NULL) {
fprintf(stderr, "Unknown savevm section %d\n", section_id);
ret = -EINVAL;
goto out;
}
- le->se->load_state(f, le->se->opaque, le->version_id);
+ ret = vmstate_load(f, le->se, le->version_id);
+ if (ret < 0) {
+ fprintf(stderr, "qemu: warning: error while loading state section id %d\n",
+ section_id);
+ goto out;
+ }
break;
default:
fprintf(stderr, "Unknown savevm section type %d\n", section_type);
@@ -1577,17 +2425,19 @@
}
}
+ //cpu_synchronize_all_post_init();
+
ret = 0;
out:
- while (first_le) {
- LoadStateEntry *le = first_le;
- first_le = first_le->next;
+ QLIST_FOREACH_SAFE(le, &loadvm_handlers, entry, new_le) {
+ QLIST_REMOVE(le, entry);
g_free(le);
}
- if (qemu_file_get_error(f))
- ret = qemu_file_get_error(f);
+ if (ret == 0) {
+ ret = qemu_file_get_error(f);
+ }
return ret;
}
diff --git a/slirp-android/slirp.c b/slirp-android/slirp.c
index 4d3dc9f..b739320 100644
--- a/slirp-android/slirp.c
+++ b/slirp-android/slirp.c
@@ -264,7 +264,7 @@
alias_addr_ip = special_addr_ip | CTL_ALIAS;
getouraddr();
- register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL);
+ register_savevm(NULL, "slirp", 0, 1, slirp_state_save, slirp_state_load, NULL);
slirp_net_forward_init();
}
diff --git a/telephony/android_modem.c b/telephony/android_modem.c
index 4b06d69..f9730a3 100644
--- a/telephony/android_modem.c
+++ b/telephony/android_modem.c
@@ -596,9 +596,13 @@
modem->sim = asimcard_create(base_port);
sys_main_init();
- register_savevm( "android_modem", 0, MODEM_DEV_STATE_SAVE_VERSION,
- android_modem_state_save,
- android_modem_state_load, modem);
+ register_savevm(NULL,
+ "android_modem",
+ 0,
+ MODEM_DEV_STATE_SAVE_VERSION,
+ android_modem_state_save,
+ android_modem_state_load,
+ modem);
aconfig_save_file( modem->nvram_config, modem->nvram_config_filename );
return modem;
diff --git a/vl-android.c b/vl-android.c
index 4493597..9c5b4d9 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -3861,8 +3861,18 @@
if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func, &machine->use_scsi, 1) != 0)
exit(1);
- //register_savevm("timer", 0, 2, timer_save, timer_load, &timers_state);
- register_savevm_live("ram", 0, 3, ram_save_live, NULL, ram_load, NULL);
+ //register_savevm(NULL, "timer", 0, 2, timer_save, timer_load, &timers_state);
+
+ SaveVMHandlers* ops = g_malloc0(sizeof(*ops));
+ ops->save_live_state = ram_save_live;
+ ops->load_state = ram_load;
+
+ register_savevm_live(NULL,
+ "ram",
+ 0,
+ 3,
+ ops,
+ NULL);
/* must be after terminal init, SDL library changes signal handlers */
os_setup_signal_handling();
diff --git a/vl.c b/vl.c
index 88933aa..d964e9b 100644
--- a/vl.c
+++ b/vl.c
@@ -2889,7 +2889,14 @@
exit(1);
//register_savevm("timer", 0, 2, timer_save, timer_load, NULL);
- register_savevm_live("ram", 0, 3, ram_save_live, NULL, ram_load, NULL);
+ register_savevm_live(NULL,
+ "ram",
+ 0,
+ 3,
+ ram_save_live,
+ NULL,
+ ram_load,
+ NULL);
/* must be after terminal init, SDL library changes signal handlers */
os_setup_signal_handling();