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 "migration/migration.h"
16 #include "migration/qemu-file.h"
17 #include "migration/vmstate.h"
18 #include "qemu/error-report.h"
19 #include "qemu/queue.h"
24 static int get_bool(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
27 *v
= qemu_get_byte(f
);
31 static int put_bool(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
39 const VMStateInfo vmstate_info_bool
= {
47 static int get_int8(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
54 static int put_int8(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
62 const VMStateInfo vmstate_info_int8
= {
70 static int get_int16(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
73 qemu_get_sbe16s(f
, v
);
77 static int put_int16(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
81 qemu_put_sbe16s(f
, v
);
85 const VMStateInfo vmstate_info_int16
= {
93 static int get_int32(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
96 qemu_get_sbe32s(f
, v
);
100 static int put_int32(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
104 qemu_put_sbe32s(f
, v
);
108 const VMStateInfo vmstate_info_int32
= {
114 /* 32 bit int. See that the received value is the same than the one
117 static int get_int32_equal(QEMUFile
*f
, void *pv
, size_t size
,
122 qemu_get_sbe32s(f
, &v2
);
127 error_report("%" PRIx32
" != %" PRIx32
, *v
, v2
);
131 const VMStateInfo vmstate_info_int32_equal
= {
132 .name
= "int32 equal",
133 .get
= get_int32_equal
,
137 /* 32 bit int. Check that the received value is non-negative
138 * and less than or equal to the one in the field.
141 static int get_int32_le(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
145 qemu_get_sbe32s(f
, &loaded
);
147 if (loaded
>= 0 && loaded
<= *cur
) {
151 error_report("Invalid value %" PRId32
152 " expecting positive value <= %" PRId32
,
157 const VMStateInfo vmstate_info_int32_le
= {
165 static int get_int64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
168 qemu_get_sbe64s(f
, v
);
172 static int put_int64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
176 qemu_put_sbe64s(f
, v
);
180 const VMStateInfo vmstate_info_int64
= {
186 /* 8 bit unsigned int */
188 static int get_uint8(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
195 static int put_uint8(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
203 const VMStateInfo vmstate_info_uint8
= {
209 /* 16 bit unsigned int */
211 static int get_uint16(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
214 qemu_get_be16s(f
, v
);
218 static int put_uint16(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
222 qemu_put_be16s(f
, v
);
226 const VMStateInfo vmstate_info_uint16
= {
232 /* 32 bit unsigned int */
234 static int get_uint32(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
237 qemu_get_be32s(f
, v
);
241 static int put_uint32(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
245 qemu_put_be32s(f
, v
);
249 const VMStateInfo vmstate_info_uint32
= {
255 /* 32 bit uint. See that the received value is the same than the one
258 static int get_uint32_equal(QEMUFile
*f
, void *pv
, size_t size
,
263 qemu_get_be32s(f
, &v2
);
268 error_report("%" PRIx32
" != %" PRIx32
, *v
, v2
);
272 const VMStateInfo vmstate_info_uint32_equal
= {
273 .name
= "uint32 equal",
274 .get
= get_uint32_equal
,
278 /* 64 bit unsigned int */
280 static int get_uint64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
283 qemu_get_be64s(f
, v
);
287 static int put_uint64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
291 qemu_put_be64s(f
, v
);
295 const VMStateInfo vmstate_info_uint64
= {
301 static int get_nullptr(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
304 if (qemu_get_byte(f
) == VMS_NULLPTR_MARKER
) {
307 error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
311 static int put_nullptr(QEMUFile
*f
, void *pv
, size_t size
,
312 VMStateField
*field
, QJSON
*vmdesc
)
316 qemu_put_byte(f
, VMS_NULLPTR_MARKER
);
319 error_report("vmstate: put_nullptr must be called with pv == NULL");
323 const VMStateInfo vmstate_info_nullptr
= {
329 /* 64 bit unsigned int. See that the received value is the same than the one
332 static int get_uint64_equal(QEMUFile
*f
, void *pv
, size_t size
,
337 qemu_get_be64s(f
, &v2
);
342 error_report("%" PRIx64
" != %" PRIx64
, *v
, v2
);
346 const VMStateInfo vmstate_info_uint64_equal
= {
347 .name
= "int64 equal",
348 .get
= get_uint64_equal
,
352 /* 8 bit int. See that the received value is the same than the one
355 static int get_uint8_equal(QEMUFile
*f
, void *pv
, size_t size
,
365 error_report("%x != %x", *v
, v2
);
369 const VMStateInfo vmstate_info_uint8_equal
= {
370 .name
= "uint8 equal",
371 .get
= get_uint8_equal
,
375 /* 16 bit unsigned int int. See that the received value is the same than the one
378 static int get_uint16_equal(QEMUFile
*f
, void *pv
, size_t size
,
383 qemu_get_be16s(f
, &v2
);
388 error_report("%x != %x", *v
, v2
);
392 const VMStateInfo vmstate_info_uint16_equal
= {
393 .name
= "uint16 equal",
394 .get
= get_uint16_equal
,
400 static int get_float64(QEMUFile
*f
, void *pv
, size_t size
,
405 *v
= make_float64(qemu_get_be64(f
));
409 static int put_float64(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
414 qemu_put_be64(f
, float64_val(*v
));
418 const VMStateInfo vmstate_info_float64
= {
424 /* CPU_DoubleU type */
426 static int get_cpudouble(QEMUFile
*f
, void *pv
, size_t size
,
430 qemu_get_be32s(f
, &v
->l
.upper
);
431 qemu_get_be32s(f
, &v
->l
.lower
);
435 static int put_cpudouble(QEMUFile
*f
, void *pv
, size_t size
,
436 VMStateField
*field
, QJSON
*vmdesc
)
439 qemu_put_be32s(f
, &v
->l
.upper
);
440 qemu_put_be32s(f
, &v
->l
.lower
);
444 const VMStateInfo vmstate_info_cpudouble
= {
445 .name
= "CPU_Double_U",
446 .get
= get_cpudouble
,
447 .put
= put_cpudouble
,
450 /* uint8_t buffers */
452 static int get_buffer(QEMUFile
*f
, void *pv
, size_t size
,
456 qemu_get_buffer(f
, v
, size
);
460 static int put_buffer(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
464 qemu_put_buffer(f
, v
, size
);
468 const VMStateInfo vmstate_info_buffer
= {
474 /* unused buffers: space that was used for some fields that are
475 not useful anymore */
477 static int get_unused_buffer(QEMUFile
*f
, void *pv
, size_t size
,
484 block_len
= MIN(sizeof(buf
), size
);
486 qemu_get_buffer(f
, buf
, block_len
);
491 static int put_unused_buffer(QEMUFile
*f
, void *pv
, size_t size
,
492 VMStateField
*field
, QJSON
*vmdesc
)
494 static const uint8_t buf
[1024];
498 block_len
= MIN(sizeof(buf
), size
);
500 qemu_put_buffer(f
, buf
, block_len
);
506 const VMStateInfo vmstate_info_unused_buffer
= {
507 .name
= "unused_buffer",
508 .get
= get_unused_buffer
,
509 .put
= put_unused_buffer
,
512 /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
513 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
514 * copy stuff from the parent into the child and do calculations to fill
515 * in fields that don't really exist in the parent but need to be in the
518 static int get_tmp(QEMUFile
*f
, void *pv
, size_t size
, 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
, VMStateField
*field
,
535 const VMStateDescription
*vmsd
= field
->vmsd
;
536 void *tmp
= g_malloc(size
);
538 /* Writes the parent field which is at the start of the tmp */
540 vmstate_save_state(f
, vmsd
, tmp
, vmdesc
);
546 const VMStateInfo vmstate_info_tmp
= {
552 /* bitmaps (as defined by bitmap.h). Note that size here is the size
553 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
554 * bit words with the bits in big endian order. The in-memory format
555 * is an array of 'unsigned long', which may be either 32 or 64 bits.
557 /* This is the number of 64 bit words sent over the wire */
558 #define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
559 static int get_bitmap(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
)
561 unsigned long *bmp
= pv
;
563 for (i
= 0; i
< BITS_TO_U64S(size
); i
++) {
564 uint64_t w
= qemu_get_be64(f
);
566 if (sizeof(unsigned long) == 4 && idx
< BITS_TO_LONGS(size
)) {
567 bmp
[idx
++] = w
>> 32;
573 static int put_bitmap(QEMUFile
*f
, void *pv
, size_t size
, VMStateField
*field
,
576 unsigned long *bmp
= pv
;
578 for (i
= 0; i
< BITS_TO_U64S(size
); i
++) {
579 uint64_t w
= bmp
[idx
++];
580 if (sizeof(unsigned long) == 4 && idx
< BITS_TO_LONGS(size
)) {
581 w
|= ((uint64_t)bmp
[idx
++]) << 32;
589 const VMStateInfo vmstate_info_bitmap
= {
596 * meta data about the QTAILQ is encoded in a VMStateField structure
598 static int get_qtailq(QEMUFile
*f
, void *pv
, size_t unused_size
,
602 const VMStateDescription
*vmsd
= field
->vmsd
;
603 /* size of a QTAILQ element */
604 size_t size
= field
->size
;
605 /* offset of the QTAILQ entry in a QTAILQ element */
606 size_t entry_offset
= field
->start
;
607 int version_id
= field
->version_id
;
610 trace_get_qtailq(vmsd
->name
, version_id
);
611 if (version_id
> vmsd
->version_id
) {
612 error_report("%s %s", vmsd
->name
, "too new");
613 trace_get_qtailq_end(vmsd
->name
, "too new", -EINVAL
);
617 if (version_id
< vmsd
->minimum_version_id
) {
618 error_report("%s %s", vmsd
->name
, "too old");
619 trace_get_qtailq_end(vmsd
->name
, "too old", -EINVAL
);
623 while (qemu_get_byte(f
)) {
624 elm
= g_malloc(size
);
625 ret
= vmstate_load_state(f
, vmsd
, elm
, version_id
);
629 QTAILQ_RAW_INSERT_TAIL(pv
, elm
, entry_offset
);
632 trace_get_qtailq_end(vmsd
->name
, "end", ret
);
637 static int put_qtailq(QEMUFile
*f
, void *pv
, size_t unused_size
,
638 VMStateField
*field
, QJSON
*vmdesc
)
640 const VMStateDescription
*vmsd
= field
->vmsd
;
641 /* offset of the QTAILQ entry in a QTAILQ element*/
642 size_t entry_offset
= field
->start
;
645 trace_put_qtailq(vmsd
->name
, vmsd
->version_id
);
647 QTAILQ_RAW_FOREACH(elm
, pv
, entry_offset
) {
648 qemu_put_byte(f
, true);
649 vmstate_save_state(f
, vmsd
, elm
, vmdesc
);
651 qemu_put_byte(f
, false);
653 trace_put_qtailq_end(vmsd
->name
, "end");
657 const VMStateInfo vmstate_info_qtailq
= {