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
= {