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-file.h"
15 #include "migration.h"
16 #include "migration/vmstate.h"
17 #include "qemu/error-report.h"
18 #include "qemu/queue.h"
23 static int get_bool(QEMUFile
*f
, void *pv
, size_t size
,
24 const VMStateField
*field
)
27 *v
= qemu_get_byte(f
);
31 static int put_bool(QEMUFile
*f
, void *pv
, size_t size
,
32 const VMStateField
*field
, QJSON
*vmdesc
)
39 const VMStateInfo vmstate_info_bool
= {
47 static int get_int8(QEMUFile
*f
, void *pv
, size_t size
,
48 const VMStateField
*field
)
55 static int put_int8(QEMUFile
*f
, void *pv
, size_t size
,
56 const VMStateField
*field
, QJSON
*vmdesc
)
63 const VMStateInfo vmstate_info_int8
= {
71 static int get_int16(QEMUFile
*f
, void *pv
, size_t size
,
72 const VMStateField
*field
)
75 qemu_get_sbe16s(f
, v
);
79 static int put_int16(QEMUFile
*f
, void *pv
, size_t size
,
80 const VMStateField
*field
, QJSON
*vmdesc
)
83 qemu_put_sbe16s(f
, v
);
87 const VMStateInfo vmstate_info_int16
= {
95 static int get_int32(QEMUFile
*f
, void *pv
, size_t size
,
96 const VMStateField
*field
)
99 qemu_get_sbe32s(f
, v
);
103 static int put_int32(QEMUFile
*f
, void *pv
, size_t size
,
104 const VMStateField
*field
, QJSON
*vmdesc
)
107 qemu_put_sbe32s(f
, v
);
111 const VMStateInfo vmstate_info_int32
= {
117 /* 32 bit int. See that the received value is the same than the one
120 static int get_int32_equal(QEMUFile
*f
, void *pv
, size_t size
,
121 const VMStateField
*field
)
125 qemu_get_sbe32s(f
, &v2
);
130 error_report("%" PRIx32
" != %" PRIx32
, *v
, v2
);
131 if (field
->err_hint
) {
132 error_printf("%s\n", field
->err_hint
);
137 const VMStateInfo vmstate_info_int32_equal
= {
138 .name
= "int32 equal",
139 .get
= get_int32_equal
,
143 /* 32 bit int. Check that the received value is non-negative
144 * and less than or equal to the one in the field.
147 static int get_int32_le(QEMUFile
*f
, void *pv
, size_t size
,
148 const VMStateField
*field
)
152 qemu_get_sbe32s(f
, &loaded
);
154 if (loaded
>= 0 && loaded
<= *cur
) {
158 error_report("Invalid value %" PRId32
159 " expecting positive value <= %" PRId32
,
164 const VMStateInfo vmstate_info_int32_le
= {
172 static int get_int64(QEMUFile
*f
, void *pv
, size_t size
,
173 const VMStateField
*field
)
176 qemu_get_sbe64s(f
, v
);
180 static int put_int64(QEMUFile
*f
, void *pv
, size_t size
,
181 const VMStateField
*field
, QJSON
*vmdesc
)
184 qemu_put_sbe64s(f
, v
);
188 const VMStateInfo vmstate_info_int64
= {
194 /* 8 bit unsigned int */
196 static int get_uint8(QEMUFile
*f
, void *pv
, size_t size
,
197 const VMStateField
*field
)
204 static int put_uint8(QEMUFile
*f
, void *pv
, size_t size
,
205 const VMStateField
*field
, QJSON
*vmdesc
)
212 const VMStateInfo vmstate_info_uint8
= {
218 /* 16 bit unsigned int */
220 static int get_uint16(QEMUFile
*f
, void *pv
, size_t size
,
221 const VMStateField
*field
)
224 qemu_get_be16s(f
, v
);
228 static int put_uint16(QEMUFile
*f
, void *pv
, size_t size
,
229 const VMStateField
*field
, QJSON
*vmdesc
)
232 qemu_put_be16s(f
, v
);
236 const VMStateInfo vmstate_info_uint16
= {
242 /* 32 bit unsigned int */
244 static int get_uint32(QEMUFile
*f
, void *pv
, size_t size
,
245 const VMStateField
*field
)
248 qemu_get_be32s(f
, v
);
252 static int put_uint32(QEMUFile
*f
, void *pv
, size_t size
,
253 const VMStateField
*field
, QJSON
*vmdesc
)
256 qemu_put_be32s(f
, v
);
260 const VMStateInfo vmstate_info_uint32
= {
266 /* 32 bit uint. See that the received value is the same than the one
269 static int get_uint32_equal(QEMUFile
*f
, void *pv
, size_t size
,
270 const VMStateField
*field
)
274 qemu_get_be32s(f
, &v2
);
279 error_report("%" PRIx32
" != %" PRIx32
, *v
, v2
);
280 if (field
->err_hint
) {
281 error_printf("%s\n", field
->err_hint
);
286 const VMStateInfo vmstate_info_uint32_equal
= {
287 .name
= "uint32 equal",
288 .get
= get_uint32_equal
,
292 /* 64 bit unsigned int */
294 static int get_uint64(QEMUFile
*f
, void *pv
, size_t size
,
295 const VMStateField
*field
)
298 qemu_get_be64s(f
, v
);
302 static int put_uint64(QEMUFile
*f
, void *pv
, size_t size
,
303 const VMStateField
*field
, QJSON
*vmdesc
)
306 qemu_put_be64s(f
, v
);
310 const VMStateInfo vmstate_info_uint64
= {
316 static int get_nullptr(QEMUFile
*f
, void *pv
, size_t size
,
317 const VMStateField
*field
)
320 if (qemu_get_byte(f
) == VMS_NULLPTR_MARKER
) {
323 error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
327 static int put_nullptr(QEMUFile
*f
, void *pv
, size_t size
,
328 const VMStateField
*field
, QJSON
*vmdesc
)
332 qemu_put_byte(f
, VMS_NULLPTR_MARKER
);
335 error_report("vmstate: put_nullptr must be called with pv == NULL");
339 const VMStateInfo vmstate_info_nullptr
= {
345 /* 64 bit unsigned int. See that the received value is the same than the one
348 static int get_uint64_equal(QEMUFile
*f
, void *pv
, size_t size
,
349 const VMStateField
*field
)
353 qemu_get_be64s(f
, &v2
);
358 error_report("%" PRIx64
" != %" PRIx64
, *v
, v2
);
359 if (field
->err_hint
) {
360 error_printf("%s\n", field
->err_hint
);
365 const VMStateInfo vmstate_info_uint64_equal
= {
366 .name
= "int64 equal",
367 .get
= get_uint64_equal
,
371 /* 8 bit int. See that the received value is the same than the one
374 static int get_uint8_equal(QEMUFile
*f
, void *pv
, size_t size
,
375 const VMStateField
*field
)
384 error_report("%x != %x", *v
, v2
);
385 if (field
->err_hint
) {
386 error_printf("%s\n", field
->err_hint
);
391 const VMStateInfo vmstate_info_uint8_equal
= {
392 .name
= "uint8 equal",
393 .get
= get_uint8_equal
,
397 /* 16 bit unsigned int int. See that the received value is the same than the one
400 static int get_uint16_equal(QEMUFile
*f
, void *pv
, size_t size
,
401 const VMStateField
*field
)
405 qemu_get_be16s(f
, &v2
);
410 error_report("%x != %x", *v
, v2
);
411 if (field
->err_hint
) {
412 error_printf("%s\n", field
->err_hint
);
417 const VMStateInfo vmstate_info_uint16_equal
= {
418 .name
= "uint16 equal",
419 .get
= get_uint16_equal
,
423 /* CPU_DoubleU type */
425 static int get_cpudouble(QEMUFile
*f
, void *pv
, size_t size
,
426 const VMStateField
*field
)
429 qemu_get_be32s(f
, &v
->l
.upper
);
430 qemu_get_be32s(f
, &v
->l
.lower
);
434 static int put_cpudouble(QEMUFile
*f
, void *pv
, size_t size
,
435 const VMStateField
*field
, QJSON
*vmdesc
)
438 qemu_put_be32s(f
, &v
->l
.upper
);
439 qemu_put_be32s(f
, &v
->l
.lower
);
443 const VMStateInfo vmstate_info_cpudouble
= {
444 .name
= "CPU_Double_U",
445 .get
= get_cpudouble
,
446 .put
= put_cpudouble
,
449 /* uint8_t buffers */
451 static int get_buffer(QEMUFile
*f
, void *pv
, size_t size
,
452 const VMStateField
*field
)
455 qemu_get_buffer(f
, v
, size
);
459 static int put_buffer(QEMUFile
*f
, void *pv
, size_t size
,
460 const VMStateField
*field
, QJSON
*vmdesc
)
463 qemu_put_buffer(f
, v
, size
);
467 const VMStateInfo vmstate_info_buffer
= {
473 /* unused buffers: space that was used for some fields that are
474 not useful anymore */
476 static int get_unused_buffer(QEMUFile
*f
, void *pv
, size_t size
,
477 const VMStateField
*field
)
483 block_len
= MIN(sizeof(buf
), size
);
485 qemu_get_buffer(f
, buf
, block_len
);
490 static int put_unused_buffer(QEMUFile
*f
, void *pv
, size_t size
,
491 const VMStateField
*field
, QJSON
*vmdesc
)
493 static const uint8_t buf
[1024];
497 block_len
= MIN(sizeof(buf
), size
);
499 qemu_put_buffer(f
, buf
, block_len
);
505 const VMStateInfo vmstate_info_unused_buffer
= {
506 .name
= "unused_buffer",
507 .get
= get_unused_buffer
,
508 .put
= put_unused_buffer
,
511 /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
512 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
513 * copy stuff from the parent into the child and do calculations to fill
514 * in fields that don't really exist in the parent but need to be in the
517 static int get_tmp(QEMUFile
*f
, void *pv
, size_t size
,
518 const VMStateField
*field
)
521 const VMStateDescription
*vmsd
= field
->vmsd
;
522 int version_id
= field
->version_id
;
523 void *tmp
= g_malloc(size
);
525 /* Writes the parent field which is at the start of the tmp */
527 ret
= vmstate_load_state(f
, vmsd
, tmp
, version_id
);
532 static int put_tmp(QEMUFile
*f
, void *pv
, size_t size
,
533 const VMStateField
*field
, QJSON
*vmdesc
)
535 const VMStateDescription
*vmsd
= field
->vmsd
;
536 void *tmp
= g_malloc(size
);
539 /* Writes the parent field which is at the start of the tmp */
541 ret
= vmstate_save_state(f
, vmsd
, tmp
, vmdesc
);
547 const VMStateInfo vmstate_info_tmp
= {
553 /* bitmaps (as defined by bitmap.h). Note that size here is the size
554 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
555 * bit words with the bits in big endian order. The in-memory format
556 * is an array of 'unsigned long', which may be either 32 or 64 bits.
558 /* This is the number of 64 bit words sent over the wire */
559 #define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
560 static int get_bitmap(QEMUFile
*f
, void *pv
, size_t size
,
561 const VMStateField
*field
)
563 unsigned long *bmp
= pv
;
565 for (i
= 0; i
< BITS_TO_U64S(size
); i
++) {
566 uint64_t w
= qemu_get_be64(f
);
568 if (sizeof(unsigned long) == 4 && idx
< BITS_TO_LONGS(size
)) {
569 bmp
[idx
++] = w
>> 32;
575 static int put_bitmap(QEMUFile
*f
, void *pv
, size_t size
,
576 const VMStateField
*field
, QJSON
*vmdesc
)
578 unsigned long *bmp
= pv
;
580 for (i
= 0; i
< BITS_TO_U64S(size
); i
++) {
581 uint64_t w
= bmp
[idx
++];
582 if (sizeof(unsigned long) == 4 && idx
< BITS_TO_LONGS(size
)) {
583 w
|= ((uint64_t)bmp
[idx
++]) << 32;
591 const VMStateInfo vmstate_info_bitmap
= {
598 * meta data about the QTAILQ is encoded in a VMStateField structure
600 static int get_qtailq(QEMUFile
*f
, void *pv
, size_t unused_size
,
601 const VMStateField
*field
)
604 const VMStateDescription
*vmsd
= field
->vmsd
;
605 /* size of a QTAILQ element */
606 size_t size
= field
->size
;
607 /* offset of the QTAILQ entry in a QTAILQ element */
608 size_t entry_offset
= field
->start
;
609 int version_id
= field
->version_id
;
612 trace_get_qtailq(vmsd
->name
, version_id
);
613 if (version_id
> vmsd
->version_id
) {
614 error_report("%s %s", vmsd
->name
, "too new");
615 trace_get_qtailq_end(vmsd
->name
, "too new", -EINVAL
);
619 if (version_id
< vmsd
->minimum_version_id
) {
620 error_report("%s %s", vmsd
->name
, "too old");
621 trace_get_qtailq_end(vmsd
->name
, "too old", -EINVAL
);
625 while (qemu_get_byte(f
)) {
626 elm
= g_malloc(size
);
627 ret
= vmstate_load_state(f
, vmsd
, elm
, version_id
);
631 QTAILQ_RAW_INSERT_TAIL(pv
, elm
, entry_offset
);
634 trace_get_qtailq_end(vmsd
->name
, "end", ret
);
639 static int put_qtailq(QEMUFile
*f
, void *pv
, size_t unused_size
,
640 const VMStateField
*field
, QJSON
*vmdesc
)
642 const VMStateDescription
*vmsd
= field
->vmsd
;
643 /* offset of the QTAILQ entry in a QTAILQ element*/
644 size_t entry_offset
= field
->start
;
648 trace_put_qtailq(vmsd
->name
, vmsd
->version_id
);
650 QTAILQ_RAW_FOREACH(elm
, pv
, entry_offset
) {
651 qemu_put_byte(f
, true);
652 ret
= vmstate_save_state(f
, vmsd
, elm
, vmdesc
);
657 qemu_put_byte(f
, false);
659 trace_put_qtailq_end(vmsd
->name
, "end");
663 const VMStateInfo vmstate_info_qtailq
= {
669 struct put_gtree_data
{
671 const VMStateDescription
*key_vmsd
;
672 const VMStateDescription
*val_vmsd
;
677 static gboolean
put_gtree_elem(gpointer key
, gpointer value
, gpointer data
)
679 struct put_gtree_data
*capsule
= (struct put_gtree_data
*)data
;
680 QEMUFile
*f
= capsule
->f
;
683 qemu_put_byte(f
, true);
686 if (!capsule
->key_vmsd
) {
687 qemu_put_be64(f
, (uint64_t)(uintptr_t)(key
)); /* direct key */
689 ret
= vmstate_save_state(f
, capsule
->key_vmsd
, key
, capsule
->vmdesc
);
697 ret
= vmstate_save_state(f
, capsule
->val_vmsd
, value
, capsule
->vmdesc
);
705 static int put_gtree(QEMUFile
*f
, void *pv
, size_t unused_size
,
706 const VMStateField
*field
, QJSON
*vmdesc
)
708 bool direct_key
= (!field
->start
);
709 const VMStateDescription
*key_vmsd
= direct_key
? NULL
: &field
->vmsd
[1];
710 const VMStateDescription
*val_vmsd
= &field
->vmsd
[0];
711 const char *key_vmsd_name
= direct_key
? "direct" : key_vmsd
->name
;
712 struct put_gtree_data capsule
= {
714 .key_vmsd
= key_vmsd
,
715 .val_vmsd
= val_vmsd
,
720 uint32_t nnodes
= g_tree_nnodes(tree
);
723 trace_put_gtree(field
->name
, key_vmsd_name
, val_vmsd
->name
, nnodes
);
724 qemu_put_be32(f
, nnodes
);
725 g_tree_foreach(tree
, put_gtree_elem
, (gpointer
)&capsule
);
726 qemu_put_byte(f
, false);
729 error_report("%s : failed to save gtree (%d)", field
->name
, ret
);
731 trace_put_gtree_end(field
->name
, key_vmsd_name
, val_vmsd
->name
, ret
);
735 static int get_gtree(QEMUFile
*f
, void *pv
, size_t unused_size
,
736 const VMStateField
*field
)
738 bool direct_key
= (!field
->start
);
739 const VMStateDescription
*key_vmsd
= direct_key
? NULL
: &field
->vmsd
[1];
740 const VMStateDescription
*val_vmsd
= &field
->vmsd
[0];
741 const char *key_vmsd_name
= direct_key
? "direct" : key_vmsd
->name
;
742 int version_id
= field
->version_id
;
743 size_t key_size
= field
->start
;
744 size_t val_size
= field
->size
;
745 int nnodes
, count
= 0;
751 /* in case of direct key, the key vmsd can be {}, ie. check fields */
752 if (!direct_key
&& version_id
> key_vmsd
->version_id
) {
753 error_report("%s %s", key_vmsd
->name
, "too new");
756 if (!direct_key
&& version_id
< key_vmsd
->minimum_version_id
) {
757 error_report("%s %s", key_vmsd
->name
, "too old");
760 if (version_id
> val_vmsd
->version_id
) {
761 error_report("%s %s", val_vmsd
->name
, "too new");
764 if (version_id
< val_vmsd
->minimum_version_id
) {
765 error_report("%s %s", val_vmsd
->name
, "too old");
769 nnodes
= qemu_get_be32(f
);
770 trace_get_gtree(field
->name
, key_vmsd_name
, val_vmsd
->name
, nnodes
);
772 while (qemu_get_byte(f
)) {
773 if ((++count
) > nnodes
) {
778 key
= (void *)(uintptr_t)qemu_get_be64(f
);
780 key
= g_malloc0(key_size
);
781 ret
= vmstate_load_state(f
, key_vmsd
, key
, version_id
);
783 error_report("%s : failed to load %s (%d)",
784 field
->name
, key_vmsd
->name
, ret
);
788 val
= g_malloc0(val_size
);
789 ret
= vmstate_load_state(f
, val_vmsd
, val
, version_id
);
791 error_report("%s : failed to load %s (%d)",
792 field
->name
, val_vmsd
->name
, ret
);
795 g_tree_insert(tree
, key
, val
);
797 if (count
!= nnodes
) {
798 error_report("%s inconsistent stream when loading the gtree",
802 trace_get_gtree_end(field
->name
, key_vmsd_name
, val_vmsd
->name
, ret
);
810 trace_get_gtree_end(field
->name
, key_vmsd_name
, val_vmsd
->name
, ret
);
815 const VMStateInfo vmstate_info_gtree
= {
821 static int put_qlist(QEMUFile
*f
, void *pv
, size_t unused_size
,
822 const VMStateField
*field
, QJSON
*vmdesc
)
824 const VMStateDescription
*vmsd
= field
->vmsd
;
825 /* offset of the QTAILQ entry in a QTAILQ element*/
826 size_t entry_offset
= field
->start
;
830 trace_put_qlist(field
->name
, vmsd
->name
, vmsd
->version_id
);
831 QLIST_RAW_FOREACH(elm
, pv
, entry_offset
) {
832 qemu_put_byte(f
, true);
833 ret
= vmstate_save_state(f
, vmsd
, elm
, vmdesc
);
835 error_report("%s: failed to save %s (%d)", field
->name
,
840 qemu_put_byte(f
, false);
841 trace_put_qlist_end(field
->name
, vmsd
->name
);
846 static int get_qlist(QEMUFile
*f
, void *pv
, size_t unused_size
,
847 const VMStateField
*field
)
850 const VMStateDescription
*vmsd
= field
->vmsd
;
851 /* size of a QLIST element */
852 size_t size
= field
->size
;
853 /* offset of the QLIST entry in a QLIST element */
854 size_t entry_offset
= field
->start
;
855 int version_id
= field
->version_id
;
856 void *elm
, *prev
= NULL
;
858 trace_get_qlist(field
->name
, vmsd
->name
, vmsd
->version_id
);
859 if (version_id
> vmsd
->version_id
) {
860 error_report("%s %s", vmsd
->name
, "too new");
863 if (version_id
< vmsd
->minimum_version_id
) {
864 error_report("%s %s", vmsd
->name
, "too old");
868 while (qemu_get_byte(f
)) {
869 elm
= g_malloc(size
);
870 ret
= vmstate_load_state(f
, vmsd
, elm
, version_id
);
872 error_report("%s: failed to load %s (%d)", field
->name
,
878 QLIST_RAW_INSERT_HEAD(pv
, elm
, entry_offset
);
880 QLIST_RAW_INSERT_AFTER(pv
, prev
, elm
, entry_offset
);
884 trace_get_qlist_end(field
->name
, vmsd
->name
);
889 const VMStateInfo vmstate_info_qlist
= {