2 * VMStateInfo's for basic typse
4 * Copyright (c) 2009-2017 Red Hat Inc
7 * Juan Quintela <quintela@redhat.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include "qemu/cpu-float.h"
15 #include "qemu-file.h"
16 #include "migration.h"
17 #include "migration/vmstate.h"
18 #include "qemu/error-report.h"
19 #include "qemu/queue.h"
24 static int get_bool(QEMUFile
*f
, void *pv
, size_t size
,
25 const VMStateField
*field
)
28 *v
= qemu_get_byte(f
);
32 static int put_bool(QEMUFile
*f
, void *pv
, size_t size
,
33 const VMStateField
*field
, JSONWriter
*vmdesc
)
40 const VMStateInfo vmstate_info_bool
= {
48 static int get_int8(QEMUFile
*f
, void *pv
, size_t size
,
49 const VMStateField
*field
)
56 static int put_int8(QEMUFile
*f
, void *pv
, size_t size
,
57 const VMStateField
*field
, JSONWriter
*vmdesc
)
64 const VMStateInfo vmstate_info_int8
= {
72 static int get_int16(QEMUFile
*f
, void *pv
, size_t size
,
73 const VMStateField
*field
)
76 qemu_get_sbe16s(f
, v
);
80 static int put_int16(QEMUFile
*f
, void *pv
, size_t size
,
81 const VMStateField
*field
, JSONWriter
*vmdesc
)
84 qemu_put_sbe16s(f
, v
);
88 const VMStateInfo vmstate_info_int16
= {
96 static int get_int32(QEMUFile
*f
, void *pv
, size_t size
,
97 const VMStateField
*field
)
100 qemu_get_sbe32s(f
, v
);
104 static int put_int32(QEMUFile
*f
, void *pv
, size_t size
,
105 const VMStateField
*field
, JSONWriter
*vmdesc
)
108 qemu_put_sbe32s(f
, v
);
112 const VMStateInfo vmstate_info_int32
= {
118 /* 32 bit int. See that the received value is the same than the one
121 static int get_int32_equal(QEMUFile
*f
, void *pv
, size_t size
,
122 const VMStateField
*field
)
126 qemu_get_sbe32s(f
, &v2
);
131 error_report("%" PRIx32
" != %" PRIx32
, *v
, v2
);
132 if (field
->err_hint
) {
133 error_printf("%s\n", field
->err_hint
);
138 const VMStateInfo vmstate_info_int32_equal
= {
139 .name
= "int32 equal",
140 .get
= get_int32_equal
,
144 /* 32 bit int. Check that the received value is non-negative
145 * and less than or equal to the one in the field.
148 static int get_int32_le(QEMUFile
*f
, void *pv
, size_t size
,
149 const VMStateField
*field
)
153 qemu_get_sbe32s(f
, &loaded
);
155 if (loaded
>= 0 && loaded
<= *cur
) {
159 error_report("Invalid value %" PRId32
160 " expecting positive value <= %" PRId32
,
165 const VMStateInfo vmstate_info_int32_le
= {
173 static int get_int64(QEMUFile
*f
, void *pv
, size_t size
,
174 const VMStateField
*field
)
177 qemu_get_sbe64s(f
, v
);
181 static int put_int64(QEMUFile
*f
, void *pv
, size_t size
,
182 const VMStateField
*field
, JSONWriter
*vmdesc
)
185 qemu_put_sbe64s(f
, v
);
189 const VMStateInfo vmstate_info_int64
= {
195 /* 8 bit unsigned int */
197 static int get_uint8(QEMUFile
*f
, void *pv
, size_t size
,
198 const VMStateField
*field
)
205 static int put_uint8(QEMUFile
*f
, void *pv
, size_t size
,
206 const VMStateField
*field
, JSONWriter
*vmdesc
)
213 const VMStateInfo vmstate_info_uint8
= {
219 /* 16 bit unsigned int */
221 static int get_uint16(QEMUFile
*f
, void *pv
, size_t size
,
222 const VMStateField
*field
)
225 qemu_get_be16s(f
, v
);
229 static int put_uint16(QEMUFile
*f
, void *pv
, size_t size
,
230 const VMStateField
*field
, JSONWriter
*vmdesc
)
233 qemu_put_be16s(f
, v
);
237 const VMStateInfo vmstate_info_uint16
= {
243 /* 32 bit unsigned int */
245 static int get_uint32(QEMUFile
*f
, void *pv
, size_t size
,
246 const VMStateField
*field
)
249 qemu_get_be32s(f
, v
);
253 static int put_uint32(QEMUFile
*f
, void *pv
, size_t size
,
254 const VMStateField
*field
, JSONWriter
*vmdesc
)
257 qemu_put_be32s(f
, v
);
261 const VMStateInfo vmstate_info_uint32
= {
267 /* 32 bit uint. See that the received value is the same than the one
270 static int get_uint32_equal(QEMUFile
*f
, void *pv
, size_t size
,
271 const VMStateField
*field
)
275 qemu_get_be32s(f
, &v2
);
280 error_report("%" PRIx32
" != %" PRIx32
, *v
, v2
);
281 if (field
->err_hint
) {
282 error_printf("%s\n", field
->err_hint
);
287 const VMStateInfo vmstate_info_uint32_equal
= {
288 .name
= "uint32 equal",
289 .get
= get_uint32_equal
,
293 /* 64 bit unsigned int */
295 static int get_uint64(QEMUFile
*f
, void *pv
, size_t size
,
296 const VMStateField
*field
)
299 qemu_get_be64s(f
, v
);
303 static int put_uint64(QEMUFile
*f
, void *pv
, size_t size
,
304 const VMStateField
*field
, JSONWriter
*vmdesc
)
307 qemu_put_be64s(f
, v
);
311 const VMStateInfo vmstate_info_uint64
= {
317 static int get_nullptr(QEMUFile
*f
, void *pv
, size_t size
,
318 const VMStateField
*field
)
321 if (qemu_get_byte(f
) == VMS_NULLPTR_MARKER
) {
324 error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
328 static int put_nullptr(QEMUFile
*f
, void *pv
, size_t size
,
329 const VMStateField
*field
, JSONWriter
*vmdesc
)
333 qemu_put_byte(f
, VMS_NULLPTR_MARKER
);
336 error_report("vmstate: put_nullptr must be called with pv == NULL");
340 const VMStateInfo vmstate_info_nullptr
= {
346 /* 64 bit unsigned int. See that the received value is the same than the one
349 static int get_uint64_equal(QEMUFile
*f
, void *pv
, size_t size
,
350 const VMStateField
*field
)
354 qemu_get_be64s(f
, &v2
);
359 error_report("%" PRIx64
" != %" PRIx64
, *v
, v2
);
360 if (field
->err_hint
) {
361 error_printf("%s\n", field
->err_hint
);
366 const VMStateInfo vmstate_info_uint64_equal
= {
367 .name
= "int64 equal",
368 .get
= get_uint64_equal
,
372 /* 8 bit int. See that the received value is the same than the one
375 static int get_uint8_equal(QEMUFile
*f
, void *pv
, size_t size
,
376 const VMStateField
*field
)
385 error_report("%x != %x", *v
, v2
);
386 if (field
->err_hint
) {
387 error_printf("%s\n", field
->err_hint
);
392 const VMStateInfo vmstate_info_uint8_equal
= {
393 .name
= "uint8 equal",
394 .get
= get_uint8_equal
,
398 /* 16 bit unsigned int int. See that the received value is the same than the one
401 static int get_uint16_equal(QEMUFile
*f
, void *pv
, size_t size
,
402 const VMStateField
*field
)
406 qemu_get_be16s(f
, &v2
);
411 error_report("%x != %x", *v
, v2
);
412 if (field
->err_hint
) {
413 error_printf("%s\n", field
->err_hint
);
418 const VMStateInfo vmstate_info_uint16_equal
= {
419 .name
= "uint16 equal",
420 .get
= get_uint16_equal
,
424 /* CPU_DoubleU type */
426 static int get_cpudouble(QEMUFile
*f
, void *pv
, size_t size
,
427 const VMStateField
*field
)
430 qemu_get_be32s(f
, &v
->l
.upper
);
431 qemu_get_be32s(f
, &v
->l
.lower
);
435 static int put_cpudouble(QEMUFile
*f
, void *pv
, size_t size
,
436 const VMStateField
*field
, JSONWriter
*vmdesc
)
439 qemu_put_be32s(f
, &v
->l
.upper
);
440 qemu_put_be32s(f
, &v
->l
.lower
);
444 const VMStateInfo vmstate_info_cpudouble
= {
445 .name
= "CPU_Double_U",
446 .get
= get_cpudouble
,
447 .put
= put_cpudouble
,
450 /* uint8_t buffers */
452 static int get_buffer(QEMUFile
*f
, void *pv
, size_t size
,
453 const VMStateField
*field
)
456 qemu_get_buffer(f
, v
, size
);
460 static int put_buffer(QEMUFile
*f
, void *pv
, size_t size
,
461 const VMStateField
*field
, JSONWriter
*vmdesc
)
464 qemu_put_buffer(f
, v
, size
);
468 const VMStateInfo vmstate_info_buffer
= {
474 /* unused buffers: space that was used for some fields that are
475 not useful anymore */
477 static int get_unused_buffer(QEMUFile
*f
, void *pv
, size_t size
,
478 const VMStateField
*field
)
484 block_len
= MIN(sizeof(buf
), size
);
486 qemu_get_buffer(f
, buf
, block_len
);
491 static int put_unused_buffer(QEMUFile
*f
, void *pv
, size_t size
,
492 const VMStateField
*field
, JSONWriter
*vmdesc
)
494 static const uint8_t buf
[1024];
498 block_len
= MIN(sizeof(buf
), size
);
500 qemu_put_buffer(f
, buf
, block_len
);
506 const VMStateInfo vmstate_info_unused_buffer
= {
507 .name
= "unused_buffer",
508 .get
= get_unused_buffer
,
509 .put
= put_unused_buffer
,
512 /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
513 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
514 * copy stuff from the parent into the child and do calculations to fill
515 * in fields that don't really exist in the parent but need to be in the
518 static int get_tmp(QEMUFile
*f
, void *pv
, size_t size
,
519 const VMStateField
*field
)
522 const VMStateDescription
*vmsd
= field
->vmsd
;
523 int version_id
= field
->version_id
;
524 void *tmp
= g_malloc(size
);
526 /* Writes the parent field which is at the start of the tmp */
528 ret
= vmstate_load_state(f
, vmsd
, tmp
, version_id
);
533 static int put_tmp(QEMUFile
*f
, void *pv
, size_t size
,
534 const VMStateField
*field
, JSONWriter
*vmdesc
)
536 const VMStateDescription
*vmsd
= field
->vmsd
;
537 void *tmp
= g_malloc(size
);
540 /* Writes the parent field which is at the start of the tmp */
542 ret
= vmstate_save_state(f
, vmsd
, tmp
, vmdesc
);
548 const VMStateInfo vmstate_info_tmp
= {
554 /* bitmaps (as defined by bitmap.h). Note that size here is the size
555 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
556 * bit words with the bits in big endian order. The in-memory format
557 * is an array of 'unsigned long', which may be either 32 or 64 bits.
559 /* This is the number of 64 bit words sent over the wire */
560 #define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
561 static int get_bitmap(QEMUFile
*f
, void *pv
, size_t size
,
562 const VMStateField
*field
)
564 unsigned long *bmp
= pv
;
566 for (i
= 0; i
< BITS_TO_U64S(size
); i
++) {
567 uint64_t w
= qemu_get_be64(f
);
569 if (sizeof(unsigned long) == 4 && idx
< BITS_TO_LONGS(size
)) {
570 bmp
[idx
++] = w
>> 32;
576 static int put_bitmap(QEMUFile
*f
, void *pv
, size_t size
,
577 const VMStateField
*field
, JSONWriter
*vmdesc
)
579 unsigned long *bmp
= pv
;
581 for (i
= 0; i
< BITS_TO_U64S(size
); i
++) {
582 uint64_t w
= bmp
[idx
++];
583 if (sizeof(unsigned long) == 4 && idx
< BITS_TO_LONGS(size
)) {
584 w
|= ((uint64_t)bmp
[idx
++]) << 32;
592 const VMStateInfo vmstate_info_bitmap
= {
599 * meta data about the QTAILQ is encoded in a VMStateField structure
601 static int get_qtailq(QEMUFile
*f
, void *pv
, size_t unused_size
,
602 const VMStateField
*field
)
605 const VMStateDescription
*vmsd
= field
->vmsd
;
606 /* size of a QTAILQ element */
607 size_t size
= field
->size
;
608 /* offset of the QTAILQ entry in a QTAILQ element */
609 size_t entry_offset
= field
->start
;
610 int version_id
= field
->version_id
;
613 trace_get_qtailq(vmsd
->name
, version_id
);
614 if (version_id
> vmsd
->version_id
) {
615 error_report("%s %s", vmsd
->name
, "too new");
616 trace_get_qtailq_end(vmsd
->name
, "too new", -EINVAL
);
620 if (version_id
< vmsd
->minimum_version_id
) {
621 error_report("%s %s", vmsd
->name
, "too old");
622 trace_get_qtailq_end(vmsd
->name
, "too old", -EINVAL
);
626 while (qemu_get_byte(f
)) {
627 elm
= g_malloc(size
);
628 ret
= vmstate_load_state(f
, vmsd
, elm
, version_id
);
632 QTAILQ_RAW_INSERT_TAIL(pv
, elm
, entry_offset
);
635 trace_get_qtailq_end(vmsd
->name
, "end", ret
);
640 static int put_qtailq(QEMUFile
*f
, void *pv
, size_t unused_size
,
641 const VMStateField
*field
, JSONWriter
*vmdesc
)
643 const VMStateDescription
*vmsd
= field
->vmsd
;
644 /* offset of the QTAILQ entry in a QTAILQ element*/
645 size_t entry_offset
= field
->start
;
649 trace_put_qtailq(vmsd
->name
, vmsd
->version_id
);
651 QTAILQ_RAW_FOREACH(elm
, pv
, entry_offset
) {
652 qemu_put_byte(f
, true);
653 ret
= vmstate_save_state(f
, vmsd
, elm
, vmdesc
);
658 qemu_put_byte(f
, false);
660 trace_put_qtailq_end(vmsd
->name
, "end");
664 const VMStateInfo vmstate_info_qtailq
= {
670 struct put_gtree_data
{
672 const VMStateDescription
*key_vmsd
;
673 const VMStateDescription
*val_vmsd
;
678 static gboolean
put_gtree_elem(gpointer key
, gpointer value
, gpointer data
)
680 struct put_gtree_data
*capsule
= (struct put_gtree_data
*)data
;
681 QEMUFile
*f
= capsule
->f
;
684 qemu_put_byte(f
, true);
687 if (!capsule
->key_vmsd
) {
688 qemu_put_be64(f
, (uint64_t)(uintptr_t)(key
)); /* direct key */
690 ret
= vmstate_save_state(f
, capsule
->key_vmsd
, key
, capsule
->vmdesc
);
698 ret
= vmstate_save_state(f
, capsule
->val_vmsd
, value
, capsule
->vmdesc
);
706 static int put_gtree(QEMUFile
*f
, void *pv
, size_t unused_size
,
707 const VMStateField
*field
, JSONWriter
*vmdesc
)
709 bool direct_key
= (!field
->start
);
710 const VMStateDescription
*key_vmsd
= direct_key
? NULL
: &field
->vmsd
[1];
711 const VMStateDescription
*val_vmsd
= &field
->vmsd
[0];
712 const char *key_vmsd_name
= direct_key
? "direct" : key_vmsd
->name
;
713 struct put_gtree_data capsule
= {
715 .key_vmsd
= key_vmsd
,
716 .val_vmsd
= val_vmsd
,
721 uint32_t nnodes
= g_tree_nnodes(tree
);
724 trace_put_gtree(field
->name
, key_vmsd_name
, val_vmsd
->name
, nnodes
);
725 qemu_put_be32(f
, nnodes
);
726 g_tree_foreach(tree
, put_gtree_elem
, (gpointer
)&capsule
);
727 qemu_put_byte(f
, false);
730 error_report("%s : failed to save gtree (%d)", field
->name
, ret
);
732 trace_put_gtree_end(field
->name
, key_vmsd_name
, val_vmsd
->name
, ret
);
736 static int get_gtree(QEMUFile
*f
, void *pv
, size_t unused_size
,
737 const VMStateField
*field
)
739 bool direct_key
= (!field
->start
);
740 const VMStateDescription
*key_vmsd
= direct_key
? NULL
: &field
->vmsd
[1];
741 const VMStateDescription
*val_vmsd
= &field
->vmsd
[0];
742 const char *key_vmsd_name
= direct_key
? "direct" : key_vmsd
->name
;
743 int version_id
= field
->version_id
;
744 size_t key_size
= field
->start
;
745 size_t val_size
= field
->size
;
746 int nnodes
, count
= 0;
752 /* in case of direct key, the key vmsd can be {}, ie. check fields */
753 if (!direct_key
&& version_id
> key_vmsd
->version_id
) {
754 error_report("%s %s", key_vmsd
->name
, "too new");
757 if (!direct_key
&& version_id
< key_vmsd
->minimum_version_id
) {
758 error_report("%s %s", key_vmsd
->name
, "too old");
761 if (version_id
> val_vmsd
->version_id
) {
762 error_report("%s %s", val_vmsd
->name
, "too new");
765 if (version_id
< val_vmsd
->minimum_version_id
) {
766 error_report("%s %s", val_vmsd
->name
, "too old");
770 nnodes
= qemu_get_be32(f
);
771 trace_get_gtree(field
->name
, key_vmsd_name
, val_vmsd
->name
, nnodes
);
773 while (qemu_get_byte(f
)) {
774 if ((++count
) > nnodes
) {
779 key
= (void *)(uintptr_t)qemu_get_be64(f
);
781 key
= g_malloc0(key_size
);
782 ret
= vmstate_load_state(f
, key_vmsd
, key
, version_id
);
784 error_report("%s : failed to load %s (%d)",
785 field
->name
, key_vmsd
->name
, ret
);
789 val
= g_malloc0(val_size
);
790 ret
= vmstate_load_state(f
, val_vmsd
, val
, version_id
);
792 error_report("%s : failed to load %s (%d)",
793 field
->name
, val_vmsd
->name
, ret
);
796 g_tree_insert(tree
, key
, val
);
798 if (count
!= nnodes
) {
799 error_report("%s inconsistent stream when loading the gtree",
803 trace_get_gtree_end(field
->name
, key_vmsd_name
, val_vmsd
->name
, ret
);
811 trace_get_gtree_end(field
->name
, key_vmsd_name
, val_vmsd
->name
, ret
);
816 const VMStateInfo vmstate_info_gtree
= {
822 static int put_qlist(QEMUFile
*f
, void *pv
, size_t unused_size
,
823 const VMStateField
*field
, JSONWriter
*vmdesc
)
825 const VMStateDescription
*vmsd
= field
->vmsd
;
826 /* offset of the QTAILQ entry in a QTAILQ element*/
827 size_t entry_offset
= field
->start
;
831 trace_put_qlist(field
->name
, vmsd
->name
, vmsd
->version_id
);
832 QLIST_RAW_FOREACH(elm
, pv
, entry_offset
) {
833 qemu_put_byte(f
, true);
834 ret
= vmstate_save_state(f
, vmsd
, elm
, vmdesc
);
836 error_report("%s: failed to save %s (%d)", field
->name
,
841 qemu_put_byte(f
, false);
842 trace_put_qlist_end(field
->name
, vmsd
->name
);
847 static int get_qlist(QEMUFile
*f
, void *pv
, size_t unused_size
,
848 const VMStateField
*field
)
851 const VMStateDescription
*vmsd
= field
->vmsd
;
852 /* size of a QLIST element */
853 size_t size
= field
->size
;
854 /* offset of the QLIST entry in a QLIST element */
855 size_t entry_offset
= field
->start
;
856 int version_id
= field
->version_id
;
857 void *elm
, *prev
= NULL
;
859 trace_get_qlist(field
->name
, vmsd
->name
, vmsd
->version_id
);
860 if (version_id
> vmsd
->version_id
) {
861 error_report("%s %s", vmsd
->name
, "too new");
864 if (version_id
< vmsd
->minimum_version_id
) {
865 error_report("%s %s", vmsd
->name
, "too old");
869 while (qemu_get_byte(f
)) {
870 elm
= g_malloc(size
);
871 ret
= vmstate_load_state(f
, vmsd
, elm
, version_id
);
873 error_report("%s: failed to load %s (%d)", field
->name
,
879 QLIST_RAW_INSERT_HEAD(pv
, elm
, entry_offset
);
881 QLIST_RAW_INSERT_AFTER(pv
, prev
, elm
, entry_offset
);
885 trace_get_qlist_end(field
->name
, vmsd
->name
);
890 const VMStateInfo vmstate_info_qlist
= {