aboutsummaryrefslogtreecommitdiff
path: root/include/migration/vmstate.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/migration/vmstate.h')
-rw-r--r--include/migration/vmstate.h273
1 files changed, 231 insertions, 42 deletions
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 2b501d0466..294d2d8486 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -27,8 +27,9 @@
#ifndef QEMU_VMSTATE_H
#define QEMU_VMSTATE_H
+#include "hw/vmstate-if.h"
+
typedef struct VMStateInfo VMStateInfo;
-typedef struct VMStateDescription VMStateDescription;
typedef struct VMStateField VMStateField;
/* VMStateInfo allows customized migration of objects that don't fit in
@@ -40,9 +41,11 @@ typedef struct VMStateField VMStateField;
*/
struct VMStateInfo {
const char *name;
- int (*get)(QEMUFile *f, void *pv, size_t size, VMStateField *field);
- int (*put)(QEMUFile *f, void *pv, size_t size, VMStateField *field,
- QJSON *vmdesc);
+ int coroutine_mixed_fn (*get)(QEMUFile *f, void *pv, size_t size,
+ const VMStateField *field);
+ int coroutine_mixed_fn (*put)(QEMUFile *f, void *pv, size_t size,
+ const VMStateField *field,
+ JSONWriter *vmdesc);
};
enum VMStateFlags {
@@ -146,12 +149,16 @@ enum VMStateFlags {
* VMStateField.struct_version_id to tell which version of the
* structure we are referencing to use. */
VMS_VSTRUCT = 0x8000,
+
+ /* Marker for end of list */
+ VMS_END = 0x10000
};
typedef enum {
MIG_PRI_DEFAULT = 0,
MIG_PRI_IOMMU, /* Must happen before PCI devices */
MIG_PRI_PCI_BUS, /* Must happen before IOMMU */
+ MIG_PRI_VIRTIO_MEM, /* Must happen before IOMMU */
MIG_PRI_GICV3_ITS, /* Must happen before PCI devices */
MIG_PRI_GICV3, /* Must happen before the ITS */
MIG_PRI_MAX,
@@ -176,21 +183,34 @@ struct VMStateField {
struct VMStateDescription {
const char *name;
- int unmigratable;
+ bool unmigratable;
+ /*
+ * This VMSD describes something that should be sent during setup phase
+ * of migration. It plays similar role as save_setup() for explicitly
+ * registered vmstate entries, so it can be seen as a way to describe
+ * save_setup() in VMSD structures.
+ *
+ * Note that for now, a SaveStateEntry cannot have a VMSD and
+ * operations (e.g., save_setup()) set at the same time. Consequently,
+ * save_setup() and a VMSD with early_setup set to true are mutually
+ * exclusive. For this reason, also early_setup VMSDs are migrated in a
+ * QEMU_VM_SECTION_FULL section, while save_setup() data is migrated in
+ * a QEMU_VM_SECTION_START section.
+ */
+ bool early_setup;
int version_id;
int minimum_version_id;
- int minimum_version_id_old;
MigrationPriority priority;
- LoadStateHandler *load_state_old;
int (*pre_load)(void *opaque);
int (*post_load)(void *opaque, int version_id);
int (*pre_save)(void *opaque);
+ int (*post_save)(void *opaque);
bool (*needed)(void *opaque);
- VMStateField *fields;
- const VMStateDescription **subsections;
-};
+ bool (*dev_unplug_pending)(void *opaque);
-extern const VMStateDescription vmstate_dummy;
+ const VMStateField *fields;
+ const VMStateDescription * const *subsections;
+};
extern const VMStateInfo vmstate_info_bool;
@@ -215,7 +235,6 @@ extern const VMStateInfo vmstate_info_uint64;
#define VMS_NULLPTR_MARKER (0x30U) /* '0' */
extern const VMStateInfo vmstate_info_nullptr;
-extern const VMStateInfo vmstate_info_float64;
extern const VMStateInfo vmstate_info_cpudouble;
extern const VMStateInfo vmstate_info_timer;
@@ -224,10 +243,26 @@ extern const VMStateInfo vmstate_info_unused_buffer;
extern const VMStateInfo vmstate_info_tmp;
extern const VMStateInfo vmstate_info_bitmap;
extern const VMStateInfo vmstate_info_qtailq;
+extern const VMStateInfo vmstate_info_gtree;
+extern const VMStateInfo vmstate_info_qlist;
#define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)
+/*
+ * Check that type t2 is an array of type t1 of size n,
+ * e.g. if t1 is 'foo' and n is 32 then t2 must be 'foo[32]'
+ */
#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
+/*
+ * type of element 0 of the specified (array) field of the type.
+ * Note that if the field is a pointer then this will return the
+ * pointed-to type rather than complaining.
+ */
+#define typeof_elt_of_field(type, field) typeof(((type *)0)->field[0])
+/* Check that field f in struct type t2 is an array of t1, of any size */
+#define type_check_varray(t1, t2, f) \
+ (type_check(t1, typeof_elt_of_field(t2, f)) \
+ + QEMU_BUILD_BUG_ON_ZERO(!QEMU_IS_ARRAY(((t2 *)0)->f)))
#define vmstate_offset_value(_state, _field, _type) \
(offsetof(_state, _field) + \
@@ -252,6 +287,10 @@ extern const VMStateInfo vmstate_info_qtailq;
vmstate_offset_array(_state, _field, uint8_t, \
sizeof(typeof_field(_state, _field)))
+#define vmstate_offset_varray(_state, _field, _type) \
+ (offsetof(_state, _field) + \
+ type_check_varray(_type, _state, _field))
+
/* In the macros below, if there is a _version, that means the macro's
* field will be processed only if the version being received is >=
* the _version specified. In general, if you add a new field, you
@@ -346,7 +385,7 @@ extern const VMStateInfo vmstate_info_qtailq;
.info = &(_info), \
.size = sizeof(_type), \
.flags = VMS_VARRAY_UINT32|VMS_MULTIPLY_ELEMENTS, \
- .offset = offsetof(_state, _field), \
+ .offset = vmstate_offset_varray(_state, _field, _type), \
}
#define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\
@@ -375,7 +414,7 @@ extern const VMStateInfo vmstate_info_qtailq;
.info = &(_info), \
.size = sizeof(_type), \
.flags = VMS_VARRAY_INT32, \
- .offset = offsetof(_state, _field), \
+ .offset = vmstate_offset_varray(_state, _field, _type), \
}
#define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\
@@ -408,6 +447,16 @@ extern const VMStateInfo vmstate_info_qtailq;
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
+#define VMSTATE_VARRAY_UINT16_ALLOC(_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 | VMS_POINTER | VMS_ALLOC, \
+ .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), \
@@ -415,7 +464,7 @@ extern const VMStateInfo vmstate_info_qtailq;
.info = &(_info), \
.size = sizeof(_type), \
.flags = VMS_VARRAY_UINT16, \
- .offset = offsetof(_state, _field), \
+ .offset = vmstate_offset_varray(_state, _field, _type), \
}
#define VMSTATE_VSTRUCT_TEST(_field, _state, _test, _version, _vmsd, _type, _struct_version) { \
@@ -519,7 +568,7 @@ extern const VMStateInfo vmstate_info_qtailq;
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
.flags = VMS_STRUCT|VMS_VARRAY_UINT8, \
- .offset = offsetof(_state, _field), \
+ .offset = vmstate_offset_varray(_state, _field, _type), \
}
/* a variable length array (i.e. _type *_field) but we know the
@@ -572,7 +621,7 @@ extern const VMStateInfo vmstate_info_qtailq;
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
.flags = VMS_STRUCT|VMS_VARRAY_INT32, \
- .offset = offsetof(_state, _field), \
+ .offset = vmstate_offset_varray(_state, _field, _type), \
}
#define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \
@@ -582,7 +631,7 @@ extern const VMStateInfo vmstate_info_qtailq;
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
.flags = VMS_STRUCT|VMS_VARRAY_UINT32, \
- .offset = offsetof(_state, _field), \
+ .offset = vmstate_offset_varray(_state, _field, _type), \
}
#define VMSTATE_STRUCT_VARRAY_ALLOC(_field, _state, _field_num, _version, _vmsd, _type) {\
@@ -675,8 +724,9 @@ extern const VMStateInfo vmstate_info_qtailq;
* '_state' type
* That the pointer is right at the start of _tmp_type.
*/
-#define VMSTATE_WITH_TMP(_state, _tmp_type, _vmsd) { \
+#define VMSTATE_WITH_TMP_TEST(_state, _test, _tmp_type, _vmsd) { \
.name = "tmp", \
+ .field_exists = (_test), \
.size = sizeof(_tmp_type) + \
QEMU_BUILD_BUG_ON_ZERO(offsetof(_tmp_type, parent) != 0) + \
type_check_pointer(_state, \
@@ -685,6 +735,9 @@ extern const VMStateInfo vmstate_info_qtailq;
.info = &vmstate_info_tmp, \
}
+#define VMSTATE_WITH_TMP(_state, _tmp_type, _vmsd) \
+ VMSTATE_WITH_TMP_TEST(_state, NULL, _tmp_type, _vmsd)
+
#define VMSTATE_UNUSED_BUFFER(_test, _version, _size) { \
.name = "unused", \
.field_exists = (_test), \
@@ -708,8 +761,9 @@ extern const VMStateInfo vmstate_info_qtailq;
/* _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) { \
+#define VMSTATE_BITMAP_TEST(_field, _state, _test, _version, _field_size) { \
.name = (stringify(_field)), \
+ .field_exists = (_test), \
.version_id = (_version), \
.size_offset = vmstate_offset_value(_state, _field_size, int32_t),\
.info = &vmstate_info_bitmap, \
@@ -717,6 +771,9 @@ extern const VMStateInfo vmstate_info_qtailq;
.offset = offsetof(_state, _field), \
}
+#define VMSTATE_BITMAP(_field, _state, _version, _field_size) \
+ VMSTATE_BITMAP_TEST(_field, _state, NULL, _version, _field_size)
+
/* For migrating a QTAILQ.
* Target QTAILQ needs be properly initialized.
* _type: type of QTAILQ element
@@ -736,6 +793,65 @@ extern const VMStateInfo vmstate_info_qtailq;
.start = offsetof(_type, _next), \
}
+/*
+ * For migrating a GTree whose key is a pointer to _key_type and the
+ * value, a pointer to _val_type
+ * The target tree must have been properly initialized
+ * _vmsd: Start address of the 2 element array containing the data vmsd
+ * and the key vmsd, in that order
+ * _key_type: type of the key
+ * _val_type: type of the value
+ */
+#define VMSTATE_GTREE_V(_field, _state, _version, _vmsd, \
+ _key_type, _val_type) \
+{ \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .vmsd = (_vmsd), \
+ .info = &vmstate_info_gtree, \
+ .start = sizeof(_key_type), \
+ .size = sizeof(_val_type), \
+ .offset = offsetof(_state, _field), \
+}
+
+/*
+ * For migrating a GTree with direct key and the value a pointer
+ * to _val_type
+ * The target tree must have been properly initialized
+ * _vmsd: data vmsd
+ * _val_type: type of the value
+ */
+#define VMSTATE_GTREE_DIRECT_KEY_V(_field, _state, _version, _vmsd, _val_type) \
+{ \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .vmsd = (_vmsd), \
+ .info = &vmstate_info_gtree, \
+ .start = 0, \
+ .size = sizeof(_val_type), \
+ .offset = offsetof(_state, _field), \
+}
+
+/*
+ * For migrating a QLIST
+ * Target QLIST needs be properly initialized.
+ * _type: type of QLIST element
+ * _next: name of QLIST_ENTRY entry field in QLIST element
+ * _vmsd: VMSD for QLIST element
+ * size: size of QLIST element
+ * start: offset of QLIST_ENTRY in QTAILQ element
+ */
+#define VMSTATE_QLIST_V(_field, _state, _version, _vmsd, _type, _next) \
+{ \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .info = &vmstate_info_qlist, \
+ .offset = offsetof(_state, _field), \
+ .start = offsetof(_type, _next), \
+}
+
/* _f : field name
_f_n : num of elements field_name
_n : num of elements
@@ -796,6 +912,19 @@ extern const VMStateInfo vmstate_info_qtailq;
#define VMSTATE_UINT64_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64, uint64_t)
+#ifdef CONFIG_LINUX
+
+#define VMSTATE_U8_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint8, __u8)
+#define VMSTATE_U16_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16, __u16)
+#define VMSTATE_U32_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint32, __u32)
+#define VMSTATE_U64_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64, __u64)
+
+#endif
+
#define VMSTATE_BOOL(_f, _s) \
VMSTATE_BOOL_V(_f, _s, 0)
@@ -817,6 +946,19 @@ extern const VMStateInfo vmstate_info_qtailq;
#define VMSTATE_UINT64(_f, _s) \
VMSTATE_UINT64_V(_f, _s, 0)
+#ifdef CONFIG_LINUX
+
+#define VMSTATE_U8(_f, _s) \
+ VMSTATE_U8_V(_f, _s, 0)
+#define VMSTATE_U16(_f, _s) \
+ VMSTATE_U16_V(_f, _s, 0)
+#define VMSTATE_U32(_f, _s) \
+ VMSTATE_U32_V(_f, _s, 0)
+#define VMSTATE_U64(_f, _s) \
+ VMSTATE_U64_V(_f, _s, 0)
+
+#endif
+
#define VMSTATE_UINT8_EQUAL(_f, _s, _err_hint) \
VMSTATE_SINGLE_FULL(_f, _s, 0, 0, \
vmstate_info_uint8_equal, uint8_t, _err_hint)
@@ -850,6 +992,9 @@ extern const VMStateInfo vmstate_info_qtailq;
#define VMSTATE_INT32_POSITIVE_LE(_f, _s) \
VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
+#define VMSTATE_BOOL_TEST(_f, _s, _t) \
+ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_bool, bool)
+
#define VMSTATE_INT8_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_int8, int8_t)
@@ -875,12 +1020,6 @@ extern const VMStateInfo vmstate_info_qtailq;
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint64, uint64_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_PTR_TEST(_f, _s, _test) \
VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *)
@@ -992,12 +1131,6 @@ extern const VMStateInfo vmstate_info_qtailq;
#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_CPUDOUBLE_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_cpudouble, CPU_DoubleU)
@@ -1031,6 +1164,20 @@ extern const VMStateInfo vmstate_info_qtailq;
#define VMSTATE_BUFFER_UNSAFE(_field, _state, _version, _size) \
VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, vmstate_info_buffer, _size)
+/*
+ * These VMSTATE_UNUSED*() macros can be used to fill in the holes
+ * when some of the vmstate fields are obsolete to be compatible with
+ * migrations between new/old binaries.
+ *
+ * CAUTION: when using any of the VMSTATE_UNUSED*() macros please be
+ * sure that the size passed in is the size that was actually *sent*
+ * rather than the size of the *structure*. One example is the
+ * boolean type - the size of the structure can vary depending on the
+ * definition of boolean, however the size we actually sent is always
+ * 1 byte (please refer to implementation of VMSTATE_BOOL_V and
+ * vmstate_info_bool). So here we should always pass in size==1
+ * rather than size==sizeof(bool).
+ */
#define VMSTATE_UNUSED_V(_v, _size) \
VMSTATE_UNUSED_BUFFER(NULL, _v, _size)
@@ -1041,37 +1188,79 @@ extern const VMStateInfo vmstate_info_qtailq;
VMSTATE_UNUSED_BUFFER(_test, 0, _size)
#define VMSTATE_END_OF_LIST() \
- {}
+ { \
+ .flags = VMS_END, \
+ }
int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque, int version_id);
int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
- void *opaque, QJSON *vmdesc);
+ void *opaque, JSONWriter *vmdesc);
+int vmstate_save_state_with_err(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque, JSONWriter *vmdesc, Error **errp);
int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
- void *opaque, QJSON *vmdesc, int version_id);
+ void *opaque, JSONWriter *vmdesc,
+ int version_id, Error **errp);
-bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque);
+bool vmstate_section_needed(const VMStateDescription *vmsd, void *opaque);
+
+#define VMSTATE_INSTANCE_ID_ANY -1
/* Returns: 0 on success, -1 on failure */
-int vmstate_register_with_alias_id(DeviceState *dev, int instance_id,
+int vmstate_register_with_alias_id(VMStateIf *obj, uint32_t instance_id,
const VMStateDescription *vmsd,
void *base, int alias_id,
int required_for_version,
Error **errp);
-/* Returns: 0 on success, -1 on failure */
-static inline int vmstate_register(DeviceState *dev, int instance_id,
+/**
+ * vmstate_register() - legacy function to register state
+ * serialisation description
+ *
+ * New code shouldn't be using this function as QOM-ified devices have
+ * dc->vmsd to store the serialisation description.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static inline int vmstate_register(VMStateIf *obj, int instance_id,
const VMStateDescription *vmsd,
void *opaque)
{
- return vmstate_register_with_alias_id(dev, instance_id, vmsd,
+ return vmstate_register_with_alias_id(obj, instance_id, vmsd,
+ opaque, -1, 0, NULL);
+}
+
+/**
+ * vmstate_replace_hack_for_ppc() - ppc used to abuse vmstate_register
+ *
+ * Don't even think about using this function in new code.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+int vmstate_replace_hack_for_ppc(VMStateIf *obj, int instance_id,
+ const VMStateDescription *vmsd,
+ void *opaque);
+
+/**
+ * vmstate_register_any() - legacy function to register state
+ * serialisation description and let the function choose the id
+ *
+ * New code shouldn't be using this function as QOM-ified devices have
+ * dc->vmsd to store the serialisation description.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static inline int vmstate_register_any(VMStateIf *obj,
+ const VMStateDescription *vmsd,
+ void *opaque)
+{
+ return vmstate_register_with_alias_id(obj, VMSTATE_INSTANCE_ID_ANY, vmsd,
opaque, -1, 0, NULL);
}
-void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd,
+void vmstate_unregister(VMStateIf *obj, const VMStateDescription *vmsd,
void *opaque);
-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);