migration: Create savevm.h for functions exported from savevm.c
[qemu/ar7.git] / migration / vmstate-types.c
blobcc95e4777599dd581b54a76918a006437347a18c
1 /*
2 * VMStateInfo's for basic typse
4 * Copyright (c) 2009-2017 Red Hat Inc
6 * Authors:
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"
20 #include "trace.h"
22 /* bool */
24 static int get_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field)
26 bool *v = pv;
27 *v = qemu_get_byte(f);
28 return 0;
31 static int put_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field,
32 QJSON *vmdesc)
34 bool *v = pv;
35 qemu_put_byte(f, *v);
36 return 0;
39 const VMStateInfo vmstate_info_bool = {
40 .name = "bool",
41 .get = get_bool,
42 .put = put_bool,
45 /* 8 bit int */
47 static int get_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field)
49 int8_t *v = pv;
50 qemu_get_s8s(f, v);
51 return 0;
54 static int put_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field,
55 QJSON *vmdesc)
57 int8_t *v = pv;
58 qemu_put_s8s(f, v);
59 return 0;
62 const VMStateInfo vmstate_info_int8 = {
63 .name = "int8",
64 .get = get_int8,
65 .put = put_int8,
68 /* 16 bit int */
70 static int get_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field)
72 int16_t *v = pv;
73 qemu_get_sbe16s(f, v);
74 return 0;
77 static int put_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field,
78 QJSON *vmdesc)
80 int16_t *v = pv;
81 qemu_put_sbe16s(f, v);
82 return 0;
85 const VMStateInfo vmstate_info_int16 = {
86 .name = "int16",
87 .get = get_int16,
88 .put = put_int16,
91 /* 32 bit int */
93 static int get_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field)
95 int32_t *v = pv;
96 qemu_get_sbe32s(f, v);
97 return 0;
100 static int put_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field,
101 QJSON *vmdesc)
103 int32_t *v = pv;
104 qemu_put_sbe32s(f, v);
105 return 0;
108 const VMStateInfo vmstate_info_int32 = {
109 .name = "int32",
110 .get = get_int32,
111 .put = put_int32,
114 /* 32 bit int. See that the received value is the same than the one
115 in the field */
117 static int get_int32_equal(QEMUFile *f, void *pv, size_t size,
118 VMStateField *field)
120 int32_t *v = pv;
121 int32_t v2;
122 qemu_get_sbe32s(f, &v2);
124 if (*v == v2) {
125 return 0;
127 error_report("%" PRIx32 " != %" PRIx32, *v, v2);
128 return -EINVAL;
131 const VMStateInfo vmstate_info_int32_equal = {
132 .name = "int32 equal",
133 .get = get_int32_equal,
134 .put = put_int32,
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)
143 int32_t *cur = pv;
144 int32_t loaded;
145 qemu_get_sbe32s(f, &loaded);
147 if (loaded >= 0 && loaded <= *cur) {
148 *cur = loaded;
149 return 0;
151 error_report("Invalid value %" PRId32
152 " expecting positive value <= %" PRId32,
153 loaded, *cur);
154 return -EINVAL;
157 const VMStateInfo vmstate_info_int32_le = {
158 .name = "int32 le",
159 .get = get_int32_le,
160 .put = put_int32,
163 /* 64 bit int */
165 static int get_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field)
167 int64_t *v = pv;
168 qemu_get_sbe64s(f, v);
169 return 0;
172 static int put_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
173 QJSON *vmdesc)
175 int64_t *v = pv;
176 qemu_put_sbe64s(f, v);
177 return 0;
180 const VMStateInfo vmstate_info_int64 = {
181 .name = "int64",
182 .get = get_int64,
183 .put = put_int64,
186 /* 8 bit unsigned int */
188 static int get_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field)
190 uint8_t *v = pv;
191 qemu_get_8s(f, v);
192 return 0;
195 static int put_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field,
196 QJSON *vmdesc)
198 uint8_t *v = pv;
199 qemu_put_8s(f, v);
200 return 0;
203 const VMStateInfo vmstate_info_uint8 = {
204 .name = "uint8",
205 .get = get_uint8,
206 .put = put_uint8,
209 /* 16 bit unsigned int */
211 static int get_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field)
213 uint16_t *v = pv;
214 qemu_get_be16s(f, v);
215 return 0;
218 static int put_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field,
219 QJSON *vmdesc)
221 uint16_t *v = pv;
222 qemu_put_be16s(f, v);
223 return 0;
226 const VMStateInfo vmstate_info_uint16 = {
227 .name = "uint16",
228 .get = get_uint16,
229 .put = put_uint16,
232 /* 32 bit unsigned int */
234 static int get_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field)
236 uint32_t *v = pv;
237 qemu_get_be32s(f, v);
238 return 0;
241 static int put_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field,
242 QJSON *vmdesc)
244 uint32_t *v = pv;
245 qemu_put_be32s(f, v);
246 return 0;
249 const VMStateInfo vmstate_info_uint32 = {
250 .name = "uint32",
251 .get = get_uint32,
252 .put = put_uint32,
255 /* 32 bit uint. See that the received value is the same than the one
256 in the field */
258 static int get_uint32_equal(QEMUFile *f, void *pv, size_t size,
259 VMStateField *field)
261 uint32_t *v = pv;
262 uint32_t v2;
263 qemu_get_be32s(f, &v2);
265 if (*v == v2) {
266 return 0;
268 error_report("%" PRIx32 " != %" PRIx32, *v, v2);
269 return -EINVAL;
272 const VMStateInfo vmstate_info_uint32_equal = {
273 .name = "uint32 equal",
274 .get = get_uint32_equal,
275 .put = put_uint32,
278 /* 64 bit unsigned int */
280 static int get_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field)
282 uint64_t *v = pv;
283 qemu_get_be64s(f, v);
284 return 0;
287 static int put_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
288 QJSON *vmdesc)
290 uint64_t *v = pv;
291 qemu_put_be64s(f, v);
292 return 0;
295 const VMStateInfo vmstate_info_uint64 = {
296 .name = "uint64",
297 .get = get_uint64,
298 .put = put_uint64,
301 static int get_nullptr(QEMUFile *f, void *pv, size_t size, VMStateField *field)
304 if (qemu_get_byte(f) == VMS_NULLPTR_MARKER) {
305 return 0;
307 error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
308 return -EINVAL;
311 static int put_nullptr(QEMUFile *f, void *pv, size_t size,
312 VMStateField *field, QJSON *vmdesc)
315 if (pv == NULL) {
316 qemu_put_byte(f, VMS_NULLPTR_MARKER);
317 return 0;
319 error_report("vmstate: put_nullptr must be called with pv == NULL");
320 return -EINVAL;
323 const VMStateInfo vmstate_info_nullptr = {
324 .name = "uint64",
325 .get = get_nullptr,
326 .put = put_nullptr,
329 /* 64 bit unsigned int. See that the received value is the same than the one
330 in the field */
332 static int get_uint64_equal(QEMUFile *f, void *pv, size_t size,
333 VMStateField *field)
335 uint64_t *v = pv;
336 uint64_t v2;
337 qemu_get_be64s(f, &v2);
339 if (*v == v2) {
340 return 0;
342 error_report("%" PRIx64 " != %" PRIx64, *v, v2);
343 return -EINVAL;
346 const VMStateInfo vmstate_info_uint64_equal = {
347 .name = "int64 equal",
348 .get = get_uint64_equal,
349 .put = put_uint64,
352 /* 8 bit int. See that the received value is the same than the one
353 in the field */
355 static int get_uint8_equal(QEMUFile *f, void *pv, size_t size,
356 VMStateField *field)
358 uint8_t *v = pv;
359 uint8_t v2;
360 qemu_get_8s(f, &v2);
362 if (*v == v2) {
363 return 0;
365 error_report("%x != %x", *v, v2);
366 return -EINVAL;
369 const VMStateInfo vmstate_info_uint8_equal = {
370 .name = "uint8 equal",
371 .get = get_uint8_equal,
372 .put = put_uint8,
375 /* 16 bit unsigned int int. See that the received value is the same than the one
376 in the field */
378 static int get_uint16_equal(QEMUFile *f, void *pv, size_t size,
379 VMStateField *field)
381 uint16_t *v = pv;
382 uint16_t v2;
383 qemu_get_be16s(f, &v2);
385 if (*v == v2) {
386 return 0;
388 error_report("%x != %x", *v, v2);
389 return -EINVAL;
392 const VMStateInfo vmstate_info_uint16_equal = {
393 .name = "uint16 equal",
394 .get = get_uint16_equal,
395 .put = put_uint16,
398 /* floating point */
400 static int get_float64(QEMUFile *f, void *pv, size_t size,
401 VMStateField *field)
403 float64 *v = pv;
405 *v = make_float64(qemu_get_be64(f));
406 return 0;
409 static int put_float64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
410 QJSON *vmdesc)
412 uint64_t *v = pv;
414 qemu_put_be64(f, float64_val(*v));
415 return 0;
418 const VMStateInfo vmstate_info_float64 = {
419 .name = "float64",
420 .get = get_float64,
421 .put = put_float64,
424 /* CPU_DoubleU type */
426 static int get_cpudouble(QEMUFile *f, void *pv, size_t size,
427 VMStateField *field)
429 CPU_DoubleU *v = pv;
430 qemu_get_be32s(f, &v->l.upper);
431 qemu_get_be32s(f, &v->l.lower);
432 return 0;
435 static int put_cpudouble(QEMUFile *f, void *pv, size_t size,
436 VMStateField *field, QJSON *vmdesc)
438 CPU_DoubleU *v = pv;
439 qemu_put_be32s(f, &v->l.upper);
440 qemu_put_be32s(f, &v->l.lower);
441 return 0;
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,
453 VMStateField *field)
455 uint8_t *v = pv;
456 qemu_get_buffer(f, v, size);
457 return 0;
460 static int put_buffer(QEMUFile *f, void *pv, size_t size, VMStateField *field,
461 QJSON *vmdesc)
463 uint8_t *v = pv;
464 qemu_put_buffer(f, v, size);
465 return 0;
468 const VMStateInfo vmstate_info_buffer = {
469 .name = "buffer",
470 .get = get_buffer,
471 .put = put_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,
478 VMStateField *field)
480 uint8_t buf[1024];
481 int block_len;
483 while (size > 0) {
484 block_len = MIN(sizeof(buf), size);
485 size -= block_len;
486 qemu_get_buffer(f, buf, block_len);
488 return 0;
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];
495 int block_len;
497 while (size > 0) {
498 block_len = MIN(sizeof(buf), size);
499 size -= block_len;
500 qemu_put_buffer(f, buf, block_len);
503 return 0;
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
516 * stream.
518 static int get_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field)
520 int ret;
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 */
526 *(void **)tmp = pv;
527 ret = vmstate_load_state(f, vmsd, tmp, version_id);
528 g_free(tmp);
529 return ret;
532 static int put_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field,
533 QJSON *vmdesc)
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 */
539 *(void **)tmp = pv;
540 vmstate_save_state(f, vmsd, tmp, vmdesc);
541 g_free(tmp);
543 return 0;
546 const VMStateInfo vmstate_info_tmp = {
547 .name = "tmp",
548 .get = get_tmp,
549 .put = put_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;
562 int i, idx = 0;
563 for (i = 0; i < BITS_TO_U64S(size); i++) {
564 uint64_t w = qemu_get_be64(f);
565 bmp[idx++] = w;
566 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
567 bmp[idx++] = w >> 32;
570 return 0;
573 static int put_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field,
574 QJSON *vmdesc)
576 unsigned long *bmp = pv;
577 int i, idx = 0;
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;
583 qemu_put_be64(f, w);
586 return 0;
589 const VMStateInfo vmstate_info_bitmap = {
590 .name = "bitmap",
591 .get = get_bitmap,
592 .put = put_bitmap,
595 /* get for QTAILQ
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,
599 VMStateField *field)
601 int ret = 0;
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;
608 void *elm;
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);
615 return -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);
620 return -EINVAL;
623 while (qemu_get_byte(f)) {
624 elm = g_malloc(size);
625 ret = vmstate_load_state(f, vmsd, elm, version_id);
626 if (ret) {
627 return ret;
629 QTAILQ_RAW_INSERT_TAIL(pv, elm, entry_offset);
632 trace_get_qtailq_end(vmsd->name, "end", ret);
633 return ret;
636 /* put for QTAILQ */
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;
643 void *elm;
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");
655 return 0;
657 const VMStateInfo vmstate_info_qtailq = {
658 .name = "qtailq",
659 .get = get_qtailq,
660 .put = put_qtailq,