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/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
);
132 const VMStateInfo vmstate_info_int32_equal
= {
133 .name
= "int32 equal",
134 .get
= get_int32_equal
,
138 /* 32 bit int. Check that the received value is non-negative
139 * and less than or equal to the one in the field.
142 static int get_int32_le(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
146 qemu_get_sbe32s(f
, &loaded
);
148 if (loaded
>= 0 && loaded
<= *cur
) {
152 error_report("Invalid value %" PRId32
153 " expecting positive value <= %" PRId32
,
158 const VMStateInfo vmstate_info_int32_le
= {
166 static int get_int64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
169 qemu_get_sbe64s(f
, v
);
173 static int put_int64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
177 qemu_put_sbe64s(f
, v
);
181 const VMStateInfo vmstate_info_int64
= {
187 /* 8 bit unsigned int */
189 static int get_uint8(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
196 static int put_uint8(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
204 const VMStateInfo vmstate_info_uint8
= {
210 /* 16 bit unsigned int */
212 static int get_uint16(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
215 qemu_get_be16s(f
, v
);
219 static int put_uint16(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
223 qemu_put_be16s(f
, v
);
227 const VMStateInfo vmstate_info_uint16
= {
233 /* 32 bit unsigned int */
235 static int get_uint32(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
238 qemu_get_be32s(f
, v
);
242 static int put_uint32(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
246 qemu_put_be32s(f
, v
);
250 const VMStateInfo vmstate_info_uint32
= {
256 /* 32 bit uint. See that the received value is the same than the one
259 static int get_uint32_equal(QEMUFile
*f
, void *pv
, size_t size
,
264 qemu_get_be32s(f
, &v2
);
269 error_report("%" PRIx32
" != %" PRIx32
, *v
, v2
);
273 const VMStateInfo vmstate_info_uint32_equal
= {
274 .name
= "uint32 equal",
275 .get
= get_uint32_equal
,
279 /* 64 bit unsigned int */
281 static int get_uint64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
284 qemu_get_be64s(f
, v
);
288 static int put_uint64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
292 qemu_put_be64s(f
, v
);
296 const VMStateInfo vmstate_info_uint64
= {
302 static int get_nullptr(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
305 if (qemu_get_byte(f
) == VMS_NULLPTR_MARKER
) {
308 error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
312 static int put_nullptr(QEMUFile
*f
, void *pv
, size_t size
,
313 VMStateField
*field
, QJSON
*vmdesc
)
317 qemu_put_byte(f
, VMS_NULLPTR_MARKER
);
320 error_report("vmstate: put_nullptr must be called with pv == NULL");
324 const VMStateInfo vmstate_info_nullptr
= {
330 /* 64 bit unsigned int. See that the received value is the same than the one
333 static int get_uint64_equal(QEMUFile
*f
, void *pv
, size_t size
,
338 qemu_get_be64s(f
, &v2
);
343 error_report("%" PRIx64
" != %" PRIx64
, *v
, v2
);
347 const VMStateInfo vmstate_info_uint64_equal
= {
348 .name
= "int64 equal",
349 .get
= get_uint64_equal
,
353 /* 8 bit int. See that the received value is the same than the one
356 static int get_uint8_equal(QEMUFile
*f
, void *pv
, size_t size
,
366 error_report("%x != %x", *v
, v2
);
370 const VMStateInfo vmstate_info_uint8_equal
= {
371 .name
= "uint8 equal",
372 .get
= get_uint8_equal
,
376 /* 16 bit unsigned int int. See that the received value is the same than the one
379 static int get_uint16_equal(QEMUFile
*f
, void *pv
, size_t size
,
384 qemu_get_be16s(f
, &v2
);
389 error_report("%x != %x", *v
, v2
);
393 const VMStateInfo vmstate_info_uint16_equal
= {
394 .name
= "uint16 equal",
395 .get
= get_uint16_equal
,
401 static int get_float64(QEMUFile
*f
, void *pv
, size_t size
,
406 *v
= make_float64(qemu_get_be64(f
));
410 static int put_float64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
415 qemu_put_be64(f
, float64_val(*v
));
419 const VMStateInfo vmstate_info_float64
= {
425 /* CPU_DoubleU type */
427 static int get_cpudouble(QEMUFile
*f
, void *pv
, size_t size
,
431 qemu_get_be32s(f
, &v
->l
.upper
);
432 qemu_get_be32s(f
, &v
->l
.lower
);
436 static int put_cpudouble(QEMUFile
*f
, void *pv
, size_t size
,
437 VMStateField
*field
, QJSON
*vmdesc
)
440 qemu_put_be32s(f
, &v
->l
.upper
);
441 qemu_put_be32s(f
, &v
->l
.lower
);
445 const VMStateInfo vmstate_info_cpudouble
= {
446 .name
= "CPU_Double_U",
447 .get
= get_cpudouble
,
448 .put
= put_cpudouble
,
451 /* uint8_t buffers */
453 static int get_buffer(QEMUFile
*f
, void *pv
, size_t size
,
457 qemu_get_buffer(f
, v
, size
);
461 static int put_buffer(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
465 qemu_put_buffer(f
, v
, size
);
469 const VMStateInfo vmstate_info_buffer
= {
475 /* unused buffers: space that was used for some fields that are
476 not useful anymore */
478 static int get_unused_buffer(QEMUFile
*f
, void *pv
, size_t size
,
485 block_len
= MIN(sizeof(buf
), size
);
487 qemu_get_buffer(f
, buf
, block_len
);
492 static int put_unused_buffer(QEMUFile
*f
, void *pv
, size_t size
,
493 VMStateField
*field
, QJSON
*vmdesc
)
495 static const uint8_t buf
[1024];
499 block_len
= MIN(sizeof(buf
), size
);
501 qemu_put_buffer(f
, buf
, block_len
);
507 const VMStateInfo vmstate_info_unused_buffer
= {
508 .name
= "unused_buffer",
509 .get
= get_unused_buffer
,
510 .put
= put_unused_buffer
,
513 /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
514 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
515 * copy stuff from the parent into the child and do calculations to fill
516 * in fields that don't really exist in the parent but need to be in the
519 static int get_tmp(QEMUFile
*f
, void *pv
, size_t size
, 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
, VMStateField
*field
,
536 const VMStateDescription
*vmsd
= field
->vmsd
;
537 void *tmp
= g_malloc(size
);
539 /* Writes the parent field which is at the start of the tmp */
541 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
, VMStateField
*field
)
562 unsigned long *bmp
= pv
;
564 for (i
= 0; i
< BITS_TO_U64S(size
); i
++) {
565 uint64_t w
= qemu_get_be64(f
);
567 if (sizeof(unsigned long) == 4 && idx
< BITS_TO_LONGS(size
)) {
568 bmp
[idx
++] = w
>> 32;
574 static int put_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
= bmp
[idx
++];
581 if (sizeof(unsigned long) == 4 && idx
< BITS_TO_LONGS(size
)) {
582 w
|= ((uint64_t)bmp
[idx
++]) << 32;
590 const VMStateInfo vmstate_info_bitmap
= {
597 * meta data about the QTAILQ is encoded in a VMStateField structure
599 static int get_qtailq(QEMUFile
*f
, void *pv
, size_t unused_size
,
603 const VMStateDescription
*vmsd
= field
->vmsd
;
604 /* size of a QTAILQ element */
605 size_t size
= field
->size
;
606 /* offset of the QTAILQ entry in a QTAILQ element */
607 size_t entry_offset
= field
->start
;
608 int version_id
= field
->version_id
;
611 trace_get_qtailq(vmsd
->name
, version_id
);
612 if (version_id
> vmsd
->version_id
) {
613 error_report("%s %s", vmsd
->name
, "too new");
614 trace_get_qtailq_end(vmsd
->name
, "too new", -EINVAL
);
618 if (version_id
< vmsd
->minimum_version_id
) {
619 error_report("%s %s", vmsd
->name
, "too old");
620 trace_get_qtailq_end(vmsd
->name
, "too old", -EINVAL
);
624 while (qemu_get_byte(f
)) {
625 elm
= g_malloc(size
);
626 ret
= vmstate_load_state(f
, vmsd
, elm
, version_id
);
630 QTAILQ_RAW_INSERT_TAIL(pv
, elm
, entry_offset
);
633 trace_get_qtailq_end(vmsd
->name
, "end", ret
);
638 static int put_qtailq(QEMUFile
*f
, void *pv
, size_t unused_size
,
639 VMStateField
*field
, QJSON
*vmdesc
)
641 const VMStateDescription
*vmsd
= field
->vmsd
;
642 /* offset of the QTAILQ entry in a QTAILQ element*/
643 size_t entry_offset
= field
->start
;
646 trace_put_qtailq(vmsd
->name
, vmsd
->version_id
);
648 QTAILQ_RAW_FOREACH(elm
, pv
, entry_offset
) {
649 qemu_put_byte(f
, true);
650 vmstate_save_state(f
, vmsd
, elm
, vmdesc
);
652 qemu_put_byte(f
, false);
654 trace_put_qtailq_end(vmsd
->name
, "end");
658 const VMStateInfo vmstate_info_qtailq
= {