Signed-off-by: Michael Roth <mdr...@linux.vnet.ibm.com> --- hw/eeprom93xx.c | 12 +- hw/fw_cfg.c | 12 +- hw/hw.h | 8 +- hw/pci.c | 38 +++- hw/twl92230.c | 18 +- qemu-timer.h | 5 + savevm.c | 521 ++++++++++++++++++++++++++++++------------------ target-alpha/machine.c | 13 +- target-i386/machine.c | 49 +++-- 9 files changed, 436 insertions(+), 240 deletions(-)
diff --git a/hw/eeprom93xx.c b/hw/eeprom93xx.c index 4c7158d..2d6cbe7 100644 --- a/hw/eeprom93xx.c +++ b/hw/eeprom93xx.c @@ -93,14 +93,18 @@ struct _eeprom_t { This is a Big hack, but it is how the old state did it. */ -static int get_uint16_from_uint8(QEMUFile *f, void *pv, size_t size) +static int get_uint16_from_uint8(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { - uint16_t *v = pv; - *v = qemu_get_ubyte(f); + uint16_t *v1 = pv; + uint8_t v2; + visit_type_uint8(v, &v2, NULL, err); + *v1 = v2; return 0; } -static void put_unused(QEMUFile *f, void *pv, size_t size) +static void put_unused(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { fprintf(stderr, "uint16_from_uint8 is used only for backwards compatibility.\n"); fprintf(stderr, "Never should be used to write a new state.\n"); diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 8df265c..8a8033e 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -326,14 +326,18 @@ static void fw_cfg_reset(DeviceState *d) Or we broke compatibility in the state, or we can't use struct tm */ -static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size) +static int get_uint32_as_uint16(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { - uint32_t *v = pv; - *v = qemu_get_be16(f); + uint32_t *val = pv; + uint16_t val2; + visit_type_uint16(v, &val2, name, err); + *val = val2; return 0; } -static void put_unused(QEMUFile *f, void *pv, size_t size) +static void put_unused(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n"); fprintf(stderr, "This functions shouldn't be called.\n"); diff --git a/hw/hw.h b/hw/hw.h index 5c0eb65..0e189da 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -293,8 +293,8 @@ 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); + int (*get)(Visitor *v, const char *name, void *pv, size_t size, Error **err); + void (*put)(Visitor *v, const char *name, void *pv, size_t size, Error **err); }; enum VMStateFlags { @@ -941,10 +941,14 @@ extern const VMStateDescription vmstate_hid_ptr_device; #define VMSTATE_END_OF_LIST() \ {} +#define VMS_LOAD true +#define VMS_SAVE false 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_process(Visitor *v, const VMStateDescription *vmsd, + void *opaque, int version_id, bool load,Error **errp); int vmstate_register(DeviceState *dev, int instance_id, const VMStateDescription *vmsd, void *base); int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, diff --git a/hw/pci.c b/hw/pci.c index e8cc1b0..a0ab0e0 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -334,23 +334,25 @@ int pci_bus_num(PCIBus *s) return s->parent_dev->config[PCI_SECONDARY_BUS]; } -static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) +static int get_pci_config_device(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { PCIDevice *s = container_of(pv, PCIDevice, config); - uint8_t *config; + uint8_t *config = NULL; int i; assert(size == pci_config_size(s)); - config = g_malloc(size); - qemu_get_buffer(f, config, size); + visit_start_array(v, (void **)&config, name, size, 1, err); for (i = 0; i < size; ++i) { + visit_type_uint8(v, &config[i], NULL, err); if ((config[i] ^ s->config[i]) & s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) { g_free(config); return -EINVAL; } } + visit_end_array(v, err); memcpy(s->config, config, size); pci_update_mappings(s); @@ -360,11 +362,17 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) } /* just put buffer */ -static void put_pci_config_device(QEMUFile *f, void *pv, size_t size) +static void put_pci_config_device(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { - const uint8_t **v = pv; + uint8_t *config = *(uint8_t **)pv; + int i; assert(size == pci_config_size(container_of(pv, PCIDevice, config))); - qemu_put_buffer(f, *v, size); + visit_start_array(v, (void **)&config, name, size, 1, err); + for (i = 0; i < size; i++) { + visit_type_uint8(v, &config[i], NULL, err); + } + visit_end_array(v, err); } static VMStateInfo vmstate_info_pci_config = { @@ -373,19 +381,22 @@ static VMStateInfo vmstate_info_pci_config = { .put = put_pci_config_device, }; -static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) +static int get_pci_irq_state(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { PCIDevice *s = container_of(pv, PCIDevice, irq_state); uint32_t irq_state[PCI_NUM_PINS]; int i; + visit_start_array(v, NULL, name, PCI_NUM_PINS, 4, err); for (i = 0; i < PCI_NUM_PINS; ++i) { - irq_state[i] = qemu_get_be32(f); + visit_type_uint32(v, &irq_state[i], NULL, err); if (irq_state[i] != 0x1 && irq_state[i] != 0) { fprintf(stderr, "irq state %d: must be 0 or 1.\n", irq_state[i]); return -EINVAL; } } + visit_end_array(v, err); for (i = 0; i < PCI_NUM_PINS; ++i) { pci_set_irq_state(s, i, irq_state[i]); @@ -394,14 +405,19 @@ static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size) return 0; } -static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size) +static void put_pci_irq_state(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { int i; PCIDevice *s = container_of(pv, PCIDevice, irq_state); + uint32_t irq_state; + visit_start_array(v, NULL, name, PCI_NUM_PINS, 4, err); for (i = 0; i < PCI_NUM_PINS; ++i) { - qemu_put_be32(f, pci_irq_state(s, i)); + irq_state = pci_irq_state(s, i); + visit_type_uint32(v, &irq_state, NULL, err); } + visit_end_array(v, err); } static VMStateInfo vmstate_info_pci_irq_state = { diff --git a/hw/twl92230.c b/hw/twl92230.c index a75448f..732f2d6 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -742,17 +742,23 @@ static int menelaus_rx(i2c_slave *i2c) Or we broke compatibility in the state, or we can't use struct tm */ -static int get_int32_as_uint16(QEMUFile *f, void *pv, size_t size) +static int get_int32_as_uint16(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { - int *v = pv; - *v = qemu_get_be16(f); + uint32_t *val = pv; + uint16_t val2; + visit_type_uint16(v, &val2, name, err); + *val = val2; return 0; } -static void put_int32_as_uint16(QEMUFile *f, void *pv, size_t size) +static void put_int32_as_uint16(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { - int *v = pv; - qemu_put_be16(f, *v); + uint32_t *val = pv; + uint16_t val2; + visit_type_uint16(v, &val2, name, err); + *val = val2; } static const VMStateInfo vmstate_hack_int32_as_uint16 = { diff --git a/qemu-timer.h b/qemu-timer.h index 67ca72e..043b1e1 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -6,6 +6,7 @@ #include "notify.h" #include <time.h> #include <sys/time.h> +#include "qapi/qapi-visit-core.h" #ifdef _WIN32 #include <windows.h> @@ -137,7 +138,11 @@ static inline int64_t get_clock(void) #endif void qemu_get_timer(QEMUFile *f, QEMUTimer *ts); +void qemu_get_timer_visitor(Visitor *v, const char *name, QEMUTimer *ts, + Error **err); void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); +void qemu_put_timer_visitor(Visitor *v, const char *name, QEMUTimer *ts, + Error **err); /* ptimer.c */ typedef struct ptimer_state ptimer_state; diff --git a/savevm.c b/savevm.c index 0b8e46f..3ce7fd3 100644 --- a/savevm.c +++ b/savevm.c @@ -183,19 +183,28 @@ static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable) /* timer */ -void qemu_put_timer(QEMUFile *f, QEMUTimer *ts) +void qemu_put_timer_visitor(Visitor *v, const char *name, QEMUTimer *ts, + Error **err) { uint64_t expire_time; - expire_time = qemu_timer_expire_time_ns(ts); - qemu_put_be64(f, expire_time); + + visit_type_uint64(v, &expire_time, name, err); } -void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) +void qemu_put_timer(QEMUFile *f, QEMUTimer *ts) +{ + Visitor *v = qemu_file_get_visitor(f); + assert(v); + qemu_put_timer_visitor(v, "timer", ts, NULL); +} + +void qemu_get_timer_visitor(Visitor *v, const char *name, QEMUTimer *ts, + Error **err) { uint64_t expire_time; - expire_time = qemu_get_be64(f); + visit_type_uint64(v, &expire_time, name, err); if (expire_time != -1) { qemu_mod_timer_ns(ts, expire_time); } else { @@ -203,19 +212,28 @@ void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) } } +void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) +{ + Visitor *v = qemu_file_get_visitor(f); + assert(v); + qemu_get_timer_visitor(v, "timer", ts, NULL); +} + /* bool */ -static int get_bool(QEMUFile *f, void *pv, size_t size) +static int get_bool(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - bool *v = pv; - *v = qemu_get_byte(f); + bool *val = pv; + visit_type_bool(v, val, name, err); return 0; } -static void put_bool(QEMUFile *f, void *pv, size_t size) +static void put_bool(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - bool *v = pv; - qemu_put_byte(f, *v); + bool *val = pv; + visit_type_bool(v, val, name, err); } const VMStateInfo vmstate_info_bool = { @@ -226,17 +244,19 @@ const VMStateInfo vmstate_info_bool = { /* 8 bit int */ -static int get_int8(QEMUFile *f, void *pv, size_t size) +static int get_int8(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - int8_t *v = pv; - qemu_get_s8s(f, v); + int8_t *val = pv; + visit_type_int8(v, val, name, err); return 0; } -static void put_int8(QEMUFile *f, void *pv, size_t size) +static void put_int8(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - int8_t *v = pv; - qemu_put_s8s(f, v); + int8_t *val = pv; + visit_type_int8(v, val, name, err); } const VMStateInfo vmstate_info_int8 = { @@ -247,17 +267,19 @@ const VMStateInfo vmstate_info_int8 = { /* 16 bit int */ -static int get_int16(QEMUFile *f, void *pv, size_t size) +static int get_int16(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - int16_t *v = pv; - qemu_get_sbe16s(f, v); + int16_t *val = pv; + visit_type_int16(v, val, name, err); return 0; } -static void put_int16(QEMUFile *f, void *pv, size_t size) +static void put_int16(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - int16_t *v = pv; - qemu_put_sbe16s(f, v); + int16_t *val = pv; + visit_type_int16(v, val, name, err); } const VMStateInfo vmstate_info_int16 = { @@ -268,17 +290,19 @@ const VMStateInfo vmstate_info_int16 = { /* 32 bit int */ -static int get_int32(QEMUFile *f, void *pv, size_t size) +static int get_int32(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - int32_t *v = pv; - qemu_get_sbe32s(f, v); + int32_t *val = pv; + visit_type_int32(v, val, name, err); return 0; } -static void put_int32(QEMUFile *f, void *pv, size_t size) +static void put_int32(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - int32_t *v = pv; - qemu_put_sbe32s(f, v); + int32_t *val = pv; + visit_type_int32(v, val, name, err); } const VMStateInfo vmstate_info_int32 = { @@ -290,13 +314,14 @@ const VMStateInfo vmstate_info_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) +static int get_int32_equal(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - int32_t *v = pv; + int32_t *v1 = pv; int32_t v2; - qemu_get_sbe32s(f, &v2); + visit_type_int32(v, &v2, name, err); - if (*v == v2) + if (*v1 == v2) return 0; return -EINVAL; } @@ -310,11 +335,12 @@ const VMStateInfo vmstate_info_int32_equal = { /* 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) +static int get_int32_le(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { int32_t *old = pv; int32_t new; - qemu_get_sbe32s(f, &new); + visit_type_int32(v, &new, name, err); if (*old <= new) return 0; @@ -329,17 +355,19 @@ const VMStateInfo vmstate_info_int32_le = { /* 64 bit int */ -static int get_int64(QEMUFile *f, void *pv, size_t size) +static int get_int64(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - int64_t *v = pv; - qemu_get_sbe64s(f, v); + int64_t *val = pv; + visit_type_int64(v, val, name, err); return 0; } -static void put_int64(QEMUFile *f, void *pv, size_t size) +static void put_int64(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - int64_t *v = pv; - qemu_put_sbe64s(f, v); + int64_t *val = pv; + visit_type_int64(v, val, name, err); } const VMStateInfo vmstate_info_int64 = { @@ -350,17 +378,19 @@ const VMStateInfo vmstate_info_int64 = { /* 8 bit unsigned int */ -static int get_uint8(QEMUFile *f, void *pv, size_t size) +static int get_uint8(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint8_t *v = pv; - qemu_get_8s(f, v); + uint8_t *val = pv; + visit_type_uint8(v, val, name, err); return 0; } -static void put_uint8(QEMUFile *f, void *pv, size_t size) +static void put_uint8(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint8_t *v = pv; - qemu_put_8s(f, v); + uint8_t *val = pv; + visit_type_uint8(v, val, name, err); } const VMStateInfo vmstate_info_uint8 = { @@ -371,17 +401,19 @@ const VMStateInfo vmstate_info_uint8 = { /* 16 bit unsigned int */ -static int get_uint16(QEMUFile *f, void *pv, size_t size) +static int get_uint16(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint16_t *v = pv; - qemu_get_be16s(f, v); + uint16_t *val = pv; + visit_type_uint16(v, val, name, err); return 0; } -static void put_uint16(QEMUFile *f, void *pv, size_t size) +static void put_uint16(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint16_t *v = pv; - qemu_put_be16s(f, v); + uint16_t *val = pv; + visit_type_uint16(v, val, name, err); } const VMStateInfo vmstate_info_uint16 = { @@ -392,17 +424,19 @@ const VMStateInfo vmstate_info_uint16 = { /* 32 bit unsigned int */ -static int get_uint32(QEMUFile *f, void *pv, size_t size) +static int get_uint32(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint32_t *v = pv; - qemu_get_be32s(f, v); + uint32_t *val = pv; + visit_type_uint32(v, val, name, err); return 0; } -static void put_uint32(QEMUFile *f, void *pv, size_t size) +static void put_uint32(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint32_t *v = pv; - qemu_put_be32s(f, v); + uint32_t *val = pv; + visit_type_uint32(v, val, name, err); } const VMStateInfo vmstate_info_uint32 = { @@ -414,13 +448,14 @@ const VMStateInfo vmstate_info_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) +static int get_uint32_equal(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint32_t *v = pv; + uint32_t *v1 = pv; uint32_t v2; - qemu_get_be32s(f, &v2); + visit_type_uint32(v, &v2, name, err); - if (*v == v2) { + if (*v1 == v2) { return 0; } return -EINVAL; @@ -434,17 +469,19 @@ const VMStateInfo vmstate_info_uint32_equal = { /* 64 bit unsigned int */ -static int get_uint64(QEMUFile *f, void *pv, size_t size) +static int get_uint64(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint64_t *v = pv; - qemu_get_be64s(f, v); + uint64_t *val = pv; + visit_type_uint64(v, val, name, err); return 0; } -static void put_uint64(QEMUFile *f, void *pv, size_t size) +static void put_uint64(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint64_t *v = pv; - qemu_put_be64s(f, v); + uint64_t *val = pv; + visit_type_uint64(v, val, name, err); } const VMStateInfo vmstate_info_uint64 = { @@ -456,13 +493,14 @@ const VMStateInfo vmstate_info_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) +static int get_uint8_equal(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint8_t *v = pv; + uint8_t *v1 = pv; uint8_t v2; - qemu_get_8s(f, &v2); + visit_type_uint8(v, &v2, name, err); - if (*v == v2) + if (*v1 == v2) return 0; return -EINVAL; } @@ -476,13 +514,14 @@ const VMStateInfo vmstate_info_uint8_equal = { /* 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) +static int get_uint16_equal(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint16_t *v = pv; + uint16_t *v1 = pv; uint16_t v2; - qemu_get_be16s(f, &v2); + visit_type_uint16(v, &v2, name, err); - if (*v == v2) + if (*v1 == v2) return 0; return -EINVAL; } @@ -495,17 +534,19 @@ const VMStateInfo vmstate_info_uint16_equal = { /* timers */ -static int get_timer(QEMUFile *f, void *pv, size_t size) +static int get_timer(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - QEMUTimer *v = pv; - qemu_get_timer(f, v); + QEMUTimer *t = pv; + qemu_get_timer_visitor(v, name, t, err); return 0; } -static void put_timer(QEMUFile *f, void *pv, size_t size) +static void put_timer(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - QEMUTimer *v = pv; - qemu_put_timer(f, v); + QEMUTimer *t = pv; + qemu_put_timer_visitor(v, name, t, err); } const VMStateInfo vmstate_info_timer = { @@ -516,17 +557,29 @@ const VMStateInfo vmstate_info_timer = { /* uint8_t buffers */ -static int get_buffer(QEMUFile *f, void *pv, size_t size) +static int get_buffer(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint8_t *v = pv; - qemu_get_buffer(f, v, size); + uint8_t *val = pv; + int i; + visit_start_array(v, NULL, name, size, 1, err); + for (i = 0; i < size; i++) { + visit_type_uint8(v, &val[i], NULL, err); + } + visit_end_array(v, err); return 0; } -static void put_buffer(QEMUFile *f, void *pv, size_t size) +static void put_buffer(Visitor *v, const char *name, void *pv, size_t size, + Error **err) { - uint8_t *v = pv; - qemu_put_buffer(f, v, size); + uint8_t *val = pv; + int i; + visit_start_array(v, NULL, name, size, 1, err); + for (i = 0; i < size; i++) { + visit_type_uint8(v, &val[i], NULL, err); + } + visit_end_array(v, err); } const VMStateInfo vmstate_info_buffer = { @@ -538,29 +591,39 @@ const VMStateInfo vmstate_info_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) +static int get_unused_buffer(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { uint8_t buf[1024]; - int block_len; + int block_len, i; + visit_start_array(v, NULL, name, size, 1, err); while (size > 0) { block_len = MIN(sizeof(buf), size); size -= block_len; - qemu_get_buffer(f, buf, block_len); + for (i = 0; i < block_len; i++) { + visit_type_uint8(v, &buf[i], NULL, err); + } } + visit_end_array(v, err); return 0; } -static void put_unused_buffer(QEMUFile *f, void *pv, size_t size) +static void put_unused_buffer(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { - static const uint8_t buf[1024]; - int block_len; + static uint8_t buf[1024]; + int block_len, i; + visit_start_array(v, NULL, name, size, 1, err); while (size > 0) { block_len = MIN(sizeof(buf), size); size -= block_len; - qemu_put_buffer(f, buf, block_len); + for (i = 0; i < block_len; i++) { + visit_type_uint8(v, &buf[i], NULL, err); + } } + visit_end_array(v, err); } const VMStateInfo vmstate_info_unused_buffer = { @@ -820,34 +883,57 @@ static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, 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) +static bool vmstate_field_needed(VMStateField *field, + const VMStateDescription *vmsd, + void *opaque, int version_id, bool load) +{ + if (load) { + return ((field->field_exists && + field->field_exists(opaque, version_id)) || + (!field->field_exists && field->version_id <= version_id)); + } + return (!field->field_exists || + field->field_exists(opaque, vmsd->version_id)); +} + +static int vmstate_process_qf(QEMUFile *f, const VMStateDescription *vmsd, + void *opaque, int version_id, bool load, Error **errp) { VMStateField *field = vmsd->fields; int ret; + Visitor *v = qemu_file_get_visitor(f); + Error *err = NULL; - 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; + assert(v); + if (load) { + 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; + } + } + } else { + if (vmsd->pre_save) { + vmsd->pre_save(opaque); + } } + + visit_start_struct(v, NULL, NULL, vmsd->name, 0, &err); while(field->name) { - if ((field->field_exists && - field->field_exists(opaque, version_id)) || - (!field->field_exists && - field->version_id <= version_id)) { + if (vmstate_field_needed(field, vmsd, opaque, version_id, load)) { void *base_addr = opaque + field->offset; int i, n_elems = 1; int size = field->size; + bool is_array = false; if (field->flags & VMS_VBUFFER) { size = *(int32_t *)(opaque+field->size_offset); @@ -857,14 +943,28 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, } if (field->flags & VMS_ARRAY) { n_elems = field->num; + visit_start_array(v, NULL, field->name, n_elems, size, &err); + is_array = true; } else if (field->flags & VMS_VARRAY_INT32) { n_elems = *(int32_t *)(opaque+field->num_offset); + visit_start_array(v, NULL, field->name, n_elems, + sizeof(int32_t), &err); + is_array = true; } else if (field->flags & VMS_VARRAY_UINT32) { n_elems = *(uint32_t *)(opaque+field->num_offset); + visit_start_array(v, NULL, field->name, n_elems, + sizeof(uint32_t), &err); + is_array = true; } else if (field->flags & VMS_VARRAY_UINT16) { n_elems = *(uint16_t *)(opaque+field->num_offset); + visit_start_array(v, NULL, field->name, n_elems, + sizeof(uint16_t), &err); + is_array = true; } else if (field->flags & VMS_VARRAY_UINT8) { n_elems = *(uint8_t *)(opaque+field->num_offset); + visit_start_array(v, NULL, field->name, n_elems, + sizeof(uint8_t), &err); + is_array = true; } if (field->flags & VMS_POINTER) { base_addr = *(void **)base_addr + field->start; @@ -876,77 +976,63 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, addr = *(void **)addr; } if (field->flags & VMS_STRUCT) { - ret = vmstate_load_state(f, field->vmsd, addr, field->vmsd->version_id); + if (load) { + ret = vmstate_load_state(f, field->vmsd, addr, + field->vmsd->version_id); + } else { + vmstate_save_state(f, field->vmsd, addr); + } } else { - ret = field->info->get(f, addr, size); - + if (load) { + ret = field->info->get(v, field->name, addr, size, &err); + } else { + field->info->put(v, field->name, addr, size, &err); + } } - if (ret < 0) { + if (load && ret < 0) { return ret; } } + if (is_array) { + visit_end_array(v, &err); + } } field++; } - ret = vmstate_subsection_load(f, vmsd, opaque); - if (ret != 0) { - return ret; + + if (error_is_set(&err)) { + error_report("error %s state: %s", load ? "loading" : "saving", + error_get_pretty(err)); + error_propagate(errp, err); } - if (vmsd->post_load) { + + if (load) { + ret = vmstate_subsection_load(f, vmsd, opaque); + if (ret != 0) { + return ret; + } + } else { + vmstate_subsection_save(f, vmsd, opaque); + } + + visit_end_struct(v, &err); + + if (load && vmsd->post_load) { return vmsd->post_load(opaque, version_id); } + return 0; } -void vmstate_save_state(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; - - 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_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; + return vmstate_process_qf(f, vmsd, opaque, version_id, VMS_LOAD, NULL); +} - 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); +void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque) +{ + vmstate_process_qf(f, vmsd, opaque, 0, VMS_SAVE, NULL); } static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id) @@ -963,7 +1049,22 @@ static void vmstate_save(QEMUFile *f, SaveStateEntry *se) se->save_state(f, se->opaque); return; } - vmstate_save_state(f,se->vmsd, se->opaque); + vmstate_save_state(f, se->vmsd, se->opaque); +} + +/* This wrapper allows direct callers of vmstate_load_state/vmstate_save_state + * to be migrated to Visitors even though internally we still use QEMUFile + * for old-style LoadStateHandler/SaveStateHandler users. Once the latter users + * are converted we can modify the interfaces accordingly, allowing us to drop + * references to QEMUFile in the vmstate path. Thus, both old-style users and + * vmstate users are decoupled from QEMUFile, leaving only live save/load users + * and savevm.c, which can then be reworked without touching device code. + */ +int vmstate_process(Visitor *v, const VMStateDescription *vmsd, + void *opaque, int version_id, bool load, Error **errp) +{ + return vmstate_process_qf(qemu_file_from_visitor(v), vmsd, opaque, + version_id, load, errp); } #define QEMU_VM_FILE_MAGIC 0x5145564d @@ -1199,40 +1300,60 @@ static const VMStateDescription *vmstate_get_subsection(const VMStateSubsection static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd, void *opaque) { + Visitor *v = qemu_file_get_visitor(f); + Error *err = NULL; + + assert(v); + + visit_start_list(v, "subsections", &err); + /* FIXME: unforunately there's no way around using a peek here, since + * when using an input visitor we *must* read to know whether or not to + * continue, which will misalign the rest of the stream. + * When we switch interfaces to be Visitor-centric and move to + * and non-QEMUFile-based Visitor this will need to be one of the first + * migration compatibility breaks. + */ while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) { char idstr[256]; - int ret; - uint8_t version_id, len, size; + int ret, i; + uint32_t version_id, len; const VMStateDescription *sub_vmsd; + uint8_t tag; - 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; + visit_start_struct(v, NULL, NULL, NULL, 0, &err); + visit_type_uint8(v, &tag, "__SUBSECTION__", &err); + visit_type_uint8(v, (uint8_t *)&len, "len", &err); + visit_start_array(v, NULL, "name", len, 1, &err); + for (i = 0; i < len; i++) { + visit_type_uint8(v, (uint8_t *)&idstr[i], NULL, &err); + } + visit_end_array(v, &err); + idstr[len] = 0; if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) { - /* it don't have a valid subsection name */ + /* doesn't have a valid subsection name */ return 0; } + visit_type_uint32(v, &version_id, "version_id", &err); + 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; } + + visit_end_struct(v, &err); + } + visit_end_list(v, &err); + + if (error_is_set(&err)) { + error_report("error loading subsections: %s", error_get_pretty(err)); + error_free(err); + return -EINVAL; } return 0; } @@ -1241,21 +1362,37 @@ static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, void *opaque) { const VMStateSubsection *sub = vmsd->subsections; + uint8_t tag = QEMU_VM_SUBSECTION; + int i; + Visitor *v = qemu_file_get_visitor(f); + Error *err = NULL; + assert(v); + visit_start_list(v, "subsections", &err); while (sub && sub->needed) { if (sub->needed(opaque)) { const VMStateDescription *vmsd = sub->vmsd; uint8_t len; - qemu_put_byte(f, QEMU_VM_SUBSECTION); + visit_start_struct(v, NULL, NULL, NULL, 0, &err); + + visit_type_uint8(v, &tag, "__SUBSECTION__", &err); 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); + visit_type_uint8(v, &len, "len", &err); + visit_start_array(v, (void **)&vmsd->name, "name", len, 1, &err); + for (i = 0; i < len; i++) { + visit_type_uint8(v, (uint8_t *)&vmsd->name[i], NULL, &err); + } + visit_end_array(v, &err); + visit_type_uint32(v, (uint32_t *)&vmsd->version_id, "version_id", &err); + assert(!vmsd->subsections); vmstate_save_state(f, vmsd, opaque); + + visit_end_struct(v, &err); } sub++; } + visit_end_list(v, &err); } typedef struct LoadStateEntry { diff --git a/target-alpha/machine.c b/target-alpha/machine.c index 76d70d9..4e6c549 100644 --- a/target-alpha/machine.c +++ b/target-alpha/machine.c @@ -1,17 +1,22 @@ #include "hw/hw.h" #include "hw/boards.h" -static int get_fpcr(QEMUFile *f, void *opaque, size_t size) +static int get_fpcr(Visitor *v, const char *name, void *opaque, + size_t size, Error **err) { CPUAlphaState *env = opaque; - cpu_alpha_store_fpcr(env, qemu_get_be64(f)); + uint64_t fpcr; + visit_type_uint64(v, &fpcr, name, err); + cpu_alpha_store_fpcr(env, fpcr); return 0; } -static void put_fpcr(QEMUFile *f, void *opaque, size_t size) +static void put_fpcr(Visitor *v, const char *name, void *opaque, + size_t size, Error **err) { CPUAlphaState *env = opaque; - qemu_put_be64(f, cpu_alpha_load_fpcr(env)); + uint64_t fpcr = cpu_alpha_load_fpcr(env); + visit_type_uint64(v, &fpcr, name, err); } static const VMStateInfo vmstate_fpcr = { diff --git a/target-i386/machine.c b/target-i386/machine.c index 25fa97d..1a4281c 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -78,7 +78,8 @@ static const VMStateDescription vmstate_mtrr_var = { #define VMSTATE_MTRR_VARS(_field, _state, _n, _v) \ VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_mtrr_var, MTRRVar) -static void put_fpreg_error(QEMUFile *f, void *opaque, size_t size) +static void put_fpreg_error(Visitor *v, const char *name, void *opaque, + size_t size, Error **err) { fprintf(stderr, "call put_fpreg() with invalid arguments\n"); exit(0); @@ -106,19 +107,23 @@ static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp) p->exp = e; } -static int get_fpreg(QEMUFile *f, void *opaque, size_t size) +static int get_fpreg(Visitor *v, const char *name, void *opaque, + size_t size, Error **err) { FPReg *fp_reg = opaque; uint64_t mant; uint16_t exp; - qemu_get_be64s(f, &mant); - qemu_get_be16s(f, &exp); + visit_start_struct(v, NULL, NULL, name, 0, err); + visit_type_uint64(v, &mant, "mant", err); + visit_type_uint16(v, &exp, "exp", err); + visit_end_struct(v, err); fp_reg->d = cpu_set_fp80(mant, exp); return 0; } -static void put_fpreg(QEMUFile *f, void *opaque, size_t size) +static void put_fpreg(Visitor *v, const char *name, void *opaque, + size_t size, Error **err) { FPReg *fp_reg = opaque; uint64_t mant; @@ -126,8 +131,10 @@ static void put_fpreg(QEMUFile *f, void *opaque, size_t size) /* we save the real CPU data (in case of MMX usage only 'mant' contains the MMX register */ cpu_get_fp80(&mant, &exp, fp_reg->d); - qemu_put_be64s(f, &mant); - qemu_put_be16s(f, &exp); + visit_start_struct(v, NULL, NULL, name, 0, err); + visit_type_uint64(v, &mant, "mant", err); + visit_type_uint16(v, &exp, "exp", err); + visit_end_struct(v, err); } static const VMStateInfo vmstate_fpreg = { @@ -136,12 +143,13 @@ static const VMStateInfo vmstate_fpreg = { .put = put_fpreg, }; -static int get_fpreg_1_mmx(QEMUFile *f, void *opaque, size_t size) +static int get_fpreg_1_mmx(Visitor *v, const char *name, void *opaque, + size_t size, Error **err) { union x86_longdouble *p = opaque; uint64_t mant; - qemu_get_be64s(f, &mant); + visit_type_uint64(v, &mant, name, err); p->mant = mant; p->exp = 0xffff; return 0; @@ -153,12 +161,13 @@ static const VMStateInfo vmstate_fpreg_1_mmx = { .put = put_fpreg_error, }; -static int get_fpreg_1_no_mmx(QEMUFile *f, void *opaque, size_t size) +static int get_fpreg_1_no_mmx(Visitor *v, const char *name, void *opaque, + size_t size, Error **err) { union x86_longdouble *p = opaque; uint64_t mant; - qemu_get_be64s(f, &mant); + visit_type_uint64(v, &mant, name, err); fp64_to_fp80(p, mant); return 0; } @@ -212,17 +221,23 @@ static bool less_than_7(void *opaque, int version_id) return version_id < 7; } -static int get_uint64_as_uint32(QEMUFile *f, void *pv, size_t size) +static int get_uint64_as_uint32(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { - uint64_t *v = pv; - *v = qemu_get_be32(f); + uint64_t *val1 = pv; + uint32_t val2; + visit_type_uint32(v, &val2, name, err); + *val1 = val2; return 0; } -static void put_uint64_as_uint32(QEMUFile *f, void *pv, size_t size) +static void put_uint64_as_uint32(Visitor *v, const char *name, void *pv, + size_t size, Error **err) { - uint64_t *v = pv; - qemu_put_be32(f, *v); + uint64_t *val1 = pv; + uint32_t val2; + visit_type_uint32(v, &val2, name, err); + *val1 = val2; } static const VMStateInfo vmstate_hack_uint64_as_uint32 = { -- 1.7.4.1