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-common.h"
15 #include "exec/cpu-common.h"
16 #include "qemu-file.h"
17 #include "migration.h"
18 #include "migration/vmstate.h"
19 #include "qemu/error-report.h"
20 #include "qemu/queue.h"
25 static int get_bool(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
28 *v
= qemu_get_byte(f
);
32 static int put_bool(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
40 const VMStateInfo vmstate_info_bool
= {
48 static int get_int8(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
55 static int put_int8(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
63 const VMStateInfo vmstate_info_int8
= {
71 static int get_int16(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
74 qemu_get_sbe16s(f
, v
);
78 static int put_int16(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
82 qemu_put_sbe16s(f
, v
);
86 const VMStateInfo vmstate_info_int16
= {
94 static int get_int32(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
97 qemu_get_sbe32s(f
, v
);
101 static int put_int32(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
105 qemu_put_sbe32s(f
, v
);
109 const VMStateInfo vmstate_info_int32
= {
115 /* 32 bit int. See that the received value is the same than the one
118 static int get_int32_equal(QEMUFile
*f
, void *pv
, size_t size
,
123 qemu_get_sbe32s(f
, &v2
);
128 error_report("%" PRIx32
" != %" PRIx32
, *v
, v2
);
129 if (field
->err_hint
) {
130 error_printf("%s\n", field
->err_hint
);
135 const VMStateInfo vmstate_info_int32_equal
= {
136 .name
= "int32 equal",
137 .get
= get_int32_equal
,
141 /* 32 bit int. Check that the received value is non-negative
142 * and less than or equal to the one in the field.
145 static int get_int32_le(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
149 qemu_get_sbe32s(f
, &loaded
);
151 if (loaded
>= 0 && loaded
<= *cur
) {
155 error_report("Invalid value %" PRId32
156 " expecting positive value <= %" PRId32
,
161 const VMStateInfo vmstate_info_int32_le
= {
169 static int get_int64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
172 qemu_get_sbe64s(f
, v
);
176 static int put_int64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
180 qemu_put_sbe64s(f
, v
);
184 const VMStateInfo vmstate_info_int64
= {
190 /* 8 bit unsigned int */
192 static int get_uint8(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
199 static int put_uint8(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
207 const VMStateInfo vmstate_info_uint8
= {
213 /* 16 bit unsigned int */
215 static int get_uint16(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
218 qemu_get_be16s(f
, v
);
222 static int put_uint16(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
226 qemu_put_be16s(f
, v
);
230 const VMStateInfo vmstate_info_uint16
= {
236 /* 32 bit unsigned int */
238 static int get_uint32(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
241 qemu_get_be32s(f
, v
);
245 static int put_uint32(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
249 qemu_put_be32s(f
, v
);
253 const VMStateInfo vmstate_info_uint32
= {
259 /* 32 bit uint. See that the received value is the same than the one
262 static int get_uint32_equal(QEMUFile
*f
, void *pv
, size_t size
,
267 qemu_get_be32s(f
, &v2
);
272 error_report("%" PRIx32
" != %" PRIx32
, *v
, v2
);
273 if (field
->err_hint
) {
274 error_printf("%s\n", field
->err_hint
);
279 const VMStateInfo vmstate_info_uint32_equal
= {
280 .name
= "uint32 equal",
281 .get
= get_uint32_equal
,
285 /* 64 bit unsigned int */
287 static int get_uint64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
290 qemu_get_be64s(f
, v
);
294 static int put_uint64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
298 qemu_put_be64s(f
, v
);
302 const VMStateInfo vmstate_info_uint64
= {
308 static int get_nullptr(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
311 if (qemu_get_byte(f
) == VMS_NULLPTR_MARKER
) {
314 error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
318 static int put_nullptr(QEMUFile
*f
, void *pv
, size_t size
,
319 VMStateField
*field
, QJSON
*vmdesc
)
323 qemu_put_byte(f
, VMS_NULLPTR_MARKER
);
326 error_report("vmstate: put_nullptr must be called with pv == NULL");
330 const VMStateInfo vmstate_info_nullptr
= {
336 /* 64 bit unsigned int. See that the received value is the same than the one
339 static int get_uint64_equal(QEMUFile
*f
, void *pv
, size_t size
,
344 qemu_get_be64s(f
, &v2
);
349 error_report("%" PRIx64
" != %" PRIx64
, *v
, v2
);
350 if (field
->err_hint
) {
351 error_printf("%s\n", field
->err_hint
);
356 const VMStateInfo vmstate_info_uint64_equal
= {
357 .name
= "int64 equal",
358 .get
= get_uint64_equal
,
362 /* 8 bit int. See that the received value is the same than the one
365 static int get_uint8_equal(QEMUFile
*f
, void *pv
, size_t size
,
375 error_report("%x != %x", *v
, v2
);
376 if (field
->err_hint
) {
377 error_printf("%s\n", field
->err_hint
);
382 const VMStateInfo vmstate_info_uint8_equal
= {
383 .name
= "uint8 equal",
384 .get
= get_uint8_equal
,
388 /* 16 bit unsigned int int. See that the received value is the same than the one
391 static int get_uint16_equal(QEMUFile
*f
, void *pv
, size_t size
,
396 qemu_get_be16s(f
, &v2
);
401 error_report("%x != %x", *v
, v2
);
402 if (field
->err_hint
) {
403 error_printf("%s\n", field
->err_hint
);
408 const VMStateInfo vmstate_info_uint16_equal
= {
409 .name
= "uint16 equal",
410 .get
= get_uint16_equal
,
416 static int get_float64(QEMUFile
*f
, void *pv
, size_t size
,
421 *v
= make_float64(qemu_get_be64(f
));
425 static int put_float64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
430 qemu_put_be64(f
, float64_val(*v
));
434 const VMStateInfo vmstate_info_float64
= {
440 /* CPU_DoubleU type */
442 static int get_cpudouble(QEMUFile
*f
, void *pv
, size_t size
,
446 qemu_get_be32s(f
, &v
->l
.upper
);
447 qemu_get_be32s(f
, &v
->l
.lower
);
451 static int put_cpudouble(QEMUFile
*f
, void *pv
, size_t size
,
452 VMStateField
*field
, QJSON
*vmdesc
)
455 qemu_put_be32s(f
, &v
->l
.upper
);
456 qemu_put_be32s(f
, &v
->l
.lower
);
460 const VMStateInfo vmstate_info_cpudouble
= {
461 .name
= "CPU_Double_U",
462 .get
= get_cpudouble
,
463 .put
= put_cpudouble
,
466 /* uint8_t buffers */
468 static int get_buffer(QEMUFile
*f
, void *pv
, size_t size
,
472 qemu_get_buffer(f
, v
, size
);
476 static int put_buffer(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
480 qemu_put_buffer(f
, v
, size
);
484 const VMStateInfo vmstate_info_buffer
= {
490 /* unused buffers: space that was used for some fields that are
491 not useful anymore */
493 static int get_unused_buffer(QEMUFile
*f
, void *pv
, size_t size
,
500 block_len
= MIN(sizeof(buf
), size
);
502 qemu_get_buffer(f
, buf
, block_len
);
507 static int put_unused_buffer(QEMUFile
*f
, void *pv
, size_t size
,
508 VMStateField
*field
, QJSON
*vmdesc
)
510 static const uint8_t buf
[1024];
514 block_len
= MIN(sizeof(buf
), size
);
516 qemu_put_buffer(f
, buf
, block_len
);
522 const VMStateInfo vmstate_info_unused_buffer
= {
523 .name
= "unused_buffer",
524 .get
= get_unused_buffer
,
525 .put
= put_unused_buffer
,
528 /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
529 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
530 * copy stuff from the parent into the child and do calculations to fill
531 * in fields that don't really exist in the parent but need to be in the
534 static int get_tmp(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
537 const VMStateDescription
*vmsd
= field
->vmsd
;
538 int version_id
= field
->version_id
;
539 void *tmp
= g_malloc(size
);
541 /* Writes the parent field which is at the start of the tmp */
543 ret
= vmstate_load_state(f
, vmsd
, tmp
, version_id
);
548 static int put_tmp(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
551 const VMStateDescription
*vmsd
= field
->vmsd
;
552 void *tmp
= g_malloc(size
);
554 /* Writes the parent field which is at the start of the tmp */
556 vmstate_save_state(f
, vmsd
, tmp
, vmdesc
);
562 const VMStateInfo vmstate_info_tmp
= {
568 /* bitmaps (as defined by bitmap.h). Note that size here is the size
569 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
570 * bit words with the bits in big endian order. The in-memory format
571 * is an array of 'unsigned long', which may be either 32 or 64 bits.
573 /* This is the number of 64 bit words sent over the wire */
574 #define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
575 static int get_bitmap(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
577 unsigned long *bmp
= pv
;
579 for (i
= 0; i
< BITS_TO_U64S(size
); i
++) {
580 uint64_t w
= qemu_get_be64(f
);
582 if (sizeof(unsigned long) == 4 && idx
< BITS_TO_LONGS(size
)) {
583 bmp
[idx
++] = w
>> 32;
589 static int put_bitmap(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
592 unsigned long *bmp
= pv
;
594 for (i
= 0; i
< BITS_TO_U64S(size
); i
++) {
595 uint64_t w
= bmp
[idx
++];
596 if (sizeof(unsigned long) == 4 && idx
< BITS_TO_LONGS(size
)) {
597 w
|= ((uint64_t)bmp
[idx
++]) << 32;
605 const VMStateInfo vmstate_info_bitmap
= {
612 * meta data about the QTAILQ is encoded in a VMStateField structure
614 static int get_qtailq(QEMUFile
*f
, void *pv
, size_t unused_size
,
618 const VMStateDescription
*vmsd
= field
->vmsd
;
619 /* size of a QTAILQ element */
620 size_t size
= field
->size
;
621 /* offset of the QTAILQ entry in a QTAILQ element */
622 size_t entry_offset
= field
->start
;
623 int version_id
= field
->version_id
;
626 trace_get_qtailq(vmsd
->name
, version_id
);
627 if (version_id
> vmsd
->version_id
) {
628 error_report("%s %s", vmsd
->name
, "too new");
629 trace_get_qtailq_end(vmsd
->name
, "too new", -EINVAL
);
633 if (version_id
< vmsd
->minimum_version_id
) {
634 error_report("%s %s", vmsd
->name
, "too old");
635 trace_get_qtailq_end(vmsd
->name
, "too old", -EINVAL
);
639 while (qemu_get_byte(f
)) {
640 elm
= g_malloc(size
);
641 ret
= vmstate_load_state(f
, vmsd
, elm
, version_id
);
645 QTAILQ_RAW_INSERT_TAIL(pv
, elm
, entry_offset
);
648 trace_get_qtailq_end(vmsd
->name
, "end", ret
);
653 static int put_qtailq(QEMUFile
*f
, void *pv
, size_t unused_size
,
654 VMStateField
*field
, QJSON
*vmdesc
)
656 const VMStateDescription
*vmsd
= field
->vmsd
;
657 /* offset of the QTAILQ entry in a QTAILQ element*/
658 size_t entry_offset
= field
->start
;
661 trace_put_qtailq(vmsd
->name
, vmsd
->version_id
);
663 QTAILQ_RAW_FOREACH(elm
, pv
, entry_offset
) {
664 qemu_put_byte(f
, true);
665 vmstate_save_state(f
, vmsd
, elm
, vmdesc
);
667 qemu_put_byte(f
, false);
669 trace_put_qtailq_end(vmsd
->name
, "end");
673 const VMStateInfo vmstate_info_qtailq
= {