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
,
425 static int get_float64(QEMUFile
*f
, void *pv
, size_t size
,
426 const VMStateField
*field
)
430 *v
= make_float64(qemu_get_be64(f
));
434 static int put_float64(QEMUFile
*f
, void *pv
, size_t size
,
435 const VMStateField
*field
, QJSON
*vmdesc
)
439 qemu_put_be64(f
, float64_val(*v
));
443 const VMStateInfo vmstate_info_float64
= {
449 /* CPU_DoubleU type */
451 static int get_cpudouble(QEMUFile
*f
, void *pv
, size_t size
,
452 const VMStateField
*field
)
455 qemu_get_be32s(f
, &v
->l
.upper
);
456 qemu_get_be32s(f
, &v
->l
.lower
);
460 static int put_cpudouble(QEMUFile
*f
, void *pv
, size_t size
,
461 const VMStateField
*field
, QJSON
*vmdesc
)
464 qemu_put_be32s(f
, &v
->l
.upper
);
465 qemu_put_be32s(f
, &v
->l
.lower
);
469 const VMStateInfo vmstate_info_cpudouble
= {
470 .name
= "CPU_Double_U",
471 .get
= get_cpudouble
,
472 .put
= put_cpudouble
,
475 /* uint8_t buffers */
477 static int get_buffer(QEMUFile
*f
, void *pv
, size_t size
,
478 const VMStateField
*field
)
481 qemu_get_buffer(f
, v
, size
);
485 static int put_buffer(QEMUFile
*f
, void *pv
, size_t size
,
486 const VMStateField
*field
, QJSON
*vmdesc
)
489 qemu_put_buffer(f
, v
, size
);
493 const VMStateInfo vmstate_info_buffer
= {
499 /* unused buffers: space that was used for some fields that are
500 not useful anymore */
502 static int get_unused_buffer(QEMUFile
*f
, void *pv
, size_t size
,
503 const VMStateField
*field
)
509 block_len
= MIN(sizeof(buf
), size
);
511 qemu_get_buffer(f
, buf
, block_len
);
516 static int put_unused_buffer(QEMUFile
*f
, void *pv
, size_t size
,
517 const VMStateField
*field
, QJSON
*vmdesc
)
519 static const uint8_t buf
[1024];
523 block_len
= MIN(sizeof(buf
), size
);
525 qemu_put_buffer(f
, buf
, block_len
);
531 const VMStateInfo vmstate_info_unused_buffer
= {
532 .name
= "unused_buffer",
533 .get
= get_unused_buffer
,
534 .put
= put_unused_buffer
,
537 /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
538 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
539 * copy stuff from the parent into the child and do calculations to fill
540 * in fields that don't really exist in the parent but need to be in the
543 static int get_tmp(QEMUFile
*f
, void *pv
, size_t size
,
544 const VMStateField
*field
)
547 const VMStateDescription
*vmsd
= field
->vmsd
;
548 int version_id
= field
->version_id
;
549 void *tmp
= g_malloc(size
);
551 /* Writes the parent field which is at the start of the tmp */
553 ret
= vmstate_load_state(f
, vmsd
, tmp
, version_id
);
558 static int put_tmp(QEMUFile
*f
, void *pv
, size_t size
,
559 const VMStateField
*field
, QJSON
*vmdesc
)
561 const VMStateDescription
*vmsd
= field
->vmsd
;
562 void *tmp
= g_malloc(size
);
565 /* Writes the parent field which is at the start of the tmp */
567 ret
= vmstate_save_state(f
, vmsd
, tmp
, vmdesc
);
573 const VMStateInfo vmstate_info_tmp
= {
579 /* bitmaps (as defined by bitmap.h). Note that size here is the size
580 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
581 * bit words with the bits in big endian order. The in-memory format
582 * is an array of 'unsigned long', which may be either 32 or 64 bits.
584 /* This is the number of 64 bit words sent over the wire */
585 #define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
586 static int get_bitmap(QEMUFile
*f
, void *pv
, size_t size
,
587 const VMStateField
*field
)
589 unsigned long *bmp
= pv
;
591 for (i
= 0; i
< BITS_TO_U64S(size
); i
++) {
592 uint64_t w
= qemu_get_be64(f
);
594 if (sizeof(unsigned long) == 4 && idx
< BITS_TO_LONGS(size
)) {
595 bmp
[idx
++] = w
>> 32;
601 static int put_bitmap(QEMUFile
*f
, void *pv
, size_t size
,
602 const VMStateField
*field
, QJSON
*vmdesc
)
604 unsigned long *bmp
= pv
;
606 for (i
= 0; i
< BITS_TO_U64S(size
); i
++) {
607 uint64_t w
= bmp
[idx
++];
608 if (sizeof(unsigned long) == 4 && idx
< BITS_TO_LONGS(size
)) {
609 w
|= ((uint64_t)bmp
[idx
++]) << 32;
617 const VMStateInfo vmstate_info_bitmap
= {
624 * meta data about the QTAILQ is encoded in a VMStateField structure
626 static int get_qtailq(QEMUFile
*f
, void *pv
, size_t unused_size
,
627 const VMStateField
*field
)
630 const VMStateDescription
*vmsd
= field
->vmsd
;
631 /* size of a QTAILQ element */
632 size_t size
= field
->size
;
633 /* offset of the QTAILQ entry in a QTAILQ element */
634 size_t entry_offset
= field
->start
;
635 int version_id
= field
->version_id
;
638 trace_get_qtailq(vmsd
->name
, version_id
);
639 if (version_id
> vmsd
->version_id
) {
640 error_report("%s %s", vmsd
->name
, "too new");
641 trace_get_qtailq_end(vmsd
->name
, "too new", -EINVAL
);
645 if (version_id
< vmsd
->minimum_version_id
) {
646 error_report("%s %s", vmsd
->name
, "too old");
647 trace_get_qtailq_end(vmsd
->name
, "too old", -EINVAL
);
651 while (qemu_get_byte(f
)) {
652 elm
= g_malloc(size
);
653 ret
= vmstate_load_state(f
, vmsd
, elm
, version_id
);
657 QTAILQ_RAW_INSERT_TAIL(pv
, elm
, entry_offset
);
660 trace_get_qtailq_end(vmsd
->name
, "end", ret
);
665 static int put_qtailq(QEMUFile
*f
, void *pv
, size_t unused_size
,
666 const VMStateField
*field
, QJSON
*vmdesc
)
668 const VMStateDescription
*vmsd
= field
->vmsd
;
669 /* offset of the QTAILQ entry in a QTAILQ element*/
670 size_t entry_offset
= field
->start
;
674 trace_put_qtailq(vmsd
->name
, vmsd
->version_id
);
676 QTAILQ_RAW_FOREACH(elm
, pv
, entry_offset
) {
677 qemu_put_byte(f
, true);
678 ret
= vmstate_save_state(f
, vmsd
, elm
, vmdesc
);
683 qemu_put_byte(f
, false);
685 trace_put_qtailq_end(vmsd
->name
, "end");
689 const VMStateInfo vmstate_info_qtailq
= {
695 struct put_gtree_data
{
697 const VMStateDescription
*key_vmsd
;
698 const VMStateDescription
*val_vmsd
;
703 static gboolean
put_gtree_elem(gpointer key
, gpointer value
, gpointer data
)
705 struct put_gtree_data
*capsule
= (struct put_gtree_data
*)data
;
706 QEMUFile
*f
= capsule
->f
;
709 qemu_put_byte(f
, true);
712 if (!capsule
->key_vmsd
) {
713 qemu_put_be64(f
, (uint64_t)(uintptr_t)(key
)); /* direct key */
715 ret
= vmstate_save_state(f
, capsule
->key_vmsd
, key
, capsule
->vmdesc
);
723 ret
= vmstate_save_state(f
, capsule
->val_vmsd
, value
, capsule
->vmdesc
);
731 static int put_gtree(QEMUFile
*f
, void *pv
, size_t unused_size
,
732 const VMStateField
*field
, QJSON
*vmdesc
)
734 bool direct_key
= (!field
->start
);
735 const VMStateDescription
*key_vmsd
= direct_key
? NULL
: &field
->vmsd
[1];
736 const VMStateDescription
*val_vmsd
= &field
->vmsd
[0];
737 const char *key_vmsd_name
= direct_key
? "direct" : key_vmsd
->name
;
738 struct put_gtree_data capsule
= {
740 .key_vmsd
= key_vmsd
,
741 .val_vmsd
= val_vmsd
,
746 uint32_t nnodes
= g_tree_nnodes(tree
);
749 trace_put_gtree(field
->name
, key_vmsd_name
, val_vmsd
->name
, nnodes
);
750 qemu_put_be32(f
, nnodes
);
751 g_tree_foreach(tree
, put_gtree_elem
, (gpointer
)&capsule
);
752 qemu_put_byte(f
, false);
755 error_report("%s : failed to save gtree (%d)", field
->name
, ret
);
757 trace_put_gtree_end(field
->name
, key_vmsd_name
, val_vmsd
->name
, ret
);
761 static int get_gtree(QEMUFile
*f
, void *pv
, size_t unused_size
,
762 const VMStateField
*field
)
764 bool direct_key
= (!field
->start
);
765 const VMStateDescription
*key_vmsd
= direct_key
? NULL
: &field
->vmsd
[1];
766 const VMStateDescription
*val_vmsd
= &field
->vmsd
[0];
767 const char *key_vmsd_name
= direct_key
? "direct" : key_vmsd
->name
;
768 int version_id
= field
->version_id
;
769 size_t key_size
= field
->start
;
770 size_t val_size
= field
->size
;
771 int nnodes
, count
= 0;
777 /* in case of direct key, the key vmsd can be {}, ie. check fields */
778 if (!direct_key
&& version_id
> key_vmsd
->version_id
) {
779 error_report("%s %s", key_vmsd
->name
, "too new");
782 if (!direct_key
&& version_id
< key_vmsd
->minimum_version_id
) {
783 error_report("%s %s", key_vmsd
->name
, "too old");
786 if (version_id
> val_vmsd
->version_id
) {
787 error_report("%s %s", val_vmsd
->name
, "too new");
790 if (version_id
< val_vmsd
->minimum_version_id
) {
791 error_report("%s %s", val_vmsd
->name
, "too old");
795 nnodes
= qemu_get_be32(f
);
796 trace_get_gtree(field
->name
, key_vmsd_name
, val_vmsd
->name
, nnodes
);
798 while (qemu_get_byte(f
)) {
799 if ((++count
) > nnodes
) {
804 key
= (void *)(uintptr_t)qemu_get_be64(f
);
806 key
= g_malloc0(key_size
);
807 ret
= vmstate_load_state(f
, key_vmsd
, key
, version_id
);
809 error_report("%s : failed to load %s (%d)",
810 field
->name
, key_vmsd
->name
, ret
);
814 val
= g_malloc0(val_size
);
815 ret
= vmstate_load_state(f
, val_vmsd
, val
, version_id
);
817 error_report("%s : failed to load %s (%d)",
818 field
->name
, val_vmsd
->name
, ret
);
821 g_tree_insert(tree
, key
, val
);
823 if (count
!= nnodes
) {
824 error_report("%s inconsistent stream when loading the gtree",
828 trace_get_gtree_end(field
->name
, key_vmsd_name
, val_vmsd
->name
, ret
);
836 trace_get_gtree_end(field
->name
, key_vmsd_name
, val_vmsd
->name
, ret
);
841 const VMStateInfo vmstate_info_gtree
= {
847 static int put_qlist(QEMUFile
*f
, void *pv
, size_t unused_size
,
848 const VMStateField
*field
, QJSON
*vmdesc
)
850 const VMStateDescription
*vmsd
= field
->vmsd
;
851 /* offset of the QTAILQ entry in a QTAILQ element*/
852 size_t entry_offset
= field
->start
;
856 trace_put_qlist(field
->name
, vmsd
->name
, vmsd
->version_id
);
857 QLIST_RAW_FOREACH(elm
, pv
, entry_offset
) {
858 qemu_put_byte(f
, true);
859 ret
= vmstate_save_state(f
, vmsd
, elm
, vmdesc
);
861 error_report("%s: failed to save %s (%d)", field
->name
,
866 qemu_put_byte(f
, false);
867 trace_put_qlist_end(field
->name
, vmsd
->name
);
872 static int get_qlist(QEMUFile
*f
, void *pv
, size_t unused_size
,
873 const VMStateField
*field
)
876 const VMStateDescription
*vmsd
= field
->vmsd
;
877 /* size of a QLIST element */
878 size_t size
= field
->size
;
879 /* offset of the QLIST entry in a QLIST element */
880 size_t entry_offset
= field
->start
;
881 int version_id
= field
->version_id
;
882 void *elm
, *prev
= NULL
;
884 trace_get_qlist(field
->name
, vmsd
->name
, vmsd
->version_id
);
885 if (version_id
> vmsd
->version_id
) {
886 error_report("%s %s", vmsd
->name
, "too new");
889 if (version_id
< vmsd
->minimum_version_id
) {
890 error_report("%s %s", vmsd
->name
, "too old");
894 while (qemu_get_byte(f
)) {
895 elm
= g_malloc(size
);
896 ret
= vmstate_load_state(f
, vmsd
, elm
, version_id
);
898 error_report("%s: failed to load %s (%d)", field
->name
,
904 QLIST_RAW_INSERT_HEAD(pv
, elm
, entry_offset
);
906 QLIST_RAW_INSERT_AFTER(pv
, prev
, elm
, entry_offset
);
910 trace_get_qlist_end(field
->name
, vmsd
->name
);
915 const VMStateInfo vmstate_info_qlist
= {