xref: /openbmc/qemu/migration/vmstate-types.c (revision 993063fbb531d11f7ede59e5264308eafa6ee4ff)
1 /*
2  * VMStateInfo's for basic typse
3  *
4  * Copyright (c) 2009-2017 Red Hat Inc
5  *
6  * Authors:
7  *  Juan Quintela <quintela@redhat.com>
8  *
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.
11  */
12 
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"
21 
22 /* bool */
23 
24 static int get_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field)
25 {
26     bool *v = pv;
27     *v = qemu_get_byte(f);
28     return 0;
29 }
30 
31 static int put_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field,
32                     QJSON *vmdesc)
33 {
34     bool *v = pv;
35     qemu_put_byte(f, *v);
36     return 0;
37 }
38 
39 const VMStateInfo vmstate_info_bool = {
40     .name = "bool",
41     .get  = get_bool,
42     .put  = put_bool,
43 };
44 
45 /* 8 bit int */
46 
47 static int get_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field)
48 {
49     int8_t *v = pv;
50     qemu_get_s8s(f, v);
51     return 0;
52 }
53 
54 static int put_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field,
55                      QJSON *vmdesc)
56 {
57     int8_t *v = pv;
58     qemu_put_s8s(f, v);
59     return 0;
60 }
61 
62 const VMStateInfo vmstate_info_int8 = {
63     .name = "int8",
64     .get  = get_int8,
65     .put  = put_int8,
66 };
67 
68 /* 16 bit int */
69 
70 static int get_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field)
71 {
72     int16_t *v = pv;
73     qemu_get_sbe16s(f, v);
74     return 0;
75 }
76 
77 static int put_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field,
78                      QJSON *vmdesc)
79 {
80     int16_t *v = pv;
81     qemu_put_sbe16s(f, v);
82     return 0;
83 }
84 
85 const VMStateInfo vmstate_info_int16 = {
86     .name = "int16",
87     .get  = get_int16,
88     .put  = put_int16,
89 };
90 
91 /* 32 bit int */
92 
93 static int get_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field)
94 {
95     int32_t *v = pv;
96     qemu_get_sbe32s(f, v);
97     return 0;
98 }
99 
100 static int put_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field,
101                      QJSON *vmdesc)
102 {
103     int32_t *v = pv;
104     qemu_put_sbe32s(f, v);
105     return 0;
106 }
107 
108 const VMStateInfo vmstate_info_int32 = {
109     .name = "int32",
110     .get  = get_int32,
111     .put  = put_int32,
112 };
113 
114 /* 32 bit int. See that the received value is the same than the one
115    in the field */
116 
117 static int get_int32_equal(QEMUFile *f, void *pv, size_t size,
118                            VMStateField *field)
119 {
120     int32_t *v = pv;
121     int32_t v2;
122     qemu_get_sbe32s(f, &v2);
123 
124     if (*v == v2) {
125         return 0;
126     }
127     error_report("%" PRIx32 " != %" PRIx32, *v, v2);
128     return -EINVAL;
129 }
130 
131 const VMStateInfo vmstate_info_int32_equal = {
132     .name = "int32 equal",
133     .get  = get_int32_equal,
134     .put  = put_int32,
135 };
136 
137 /* 32 bit int. Check that the received value is non-negative
138  * and less than or equal to the one in the field.
139  */
140 
141 static int get_int32_le(QEMUFile *f, void *pv, size_t size, VMStateField *field)
142 {
143     int32_t *cur = pv;
144     int32_t loaded;
145     qemu_get_sbe32s(f, &loaded);
146 
147     if (loaded >= 0 && loaded <= *cur) {
148         *cur = loaded;
149         return 0;
150     }
151     error_report("Invalid value %" PRId32
152                  " expecting positive value <= %" PRId32,
153                  loaded, *cur);
154     return -EINVAL;
155 }
156 
157 const VMStateInfo vmstate_info_int32_le = {
158     .name = "int32 le",
159     .get  = get_int32_le,
160     .put  = put_int32,
161 };
162 
163 /* 64 bit int */
164 
165 static int get_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field)
166 {
167     int64_t *v = pv;
168     qemu_get_sbe64s(f, v);
169     return 0;
170 }
171 
172 static int put_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
173                       QJSON *vmdesc)
174 {
175     int64_t *v = pv;
176     qemu_put_sbe64s(f, v);
177     return 0;
178 }
179 
180 const VMStateInfo vmstate_info_int64 = {
181     .name = "int64",
182     .get  = get_int64,
183     .put  = put_int64,
184 };
185 
186 /* 8 bit unsigned int */
187 
188 static int get_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field)
189 {
190     uint8_t *v = pv;
191     qemu_get_8s(f, v);
192     return 0;
193 }
194 
195 static int put_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field,
196                      QJSON *vmdesc)
197 {
198     uint8_t *v = pv;
199     qemu_put_8s(f, v);
200     return 0;
201 }
202 
203 const VMStateInfo vmstate_info_uint8 = {
204     .name = "uint8",
205     .get  = get_uint8,
206     .put  = put_uint8,
207 };
208 
209 /* 16 bit unsigned int */
210 
211 static int get_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field)
212 {
213     uint16_t *v = pv;
214     qemu_get_be16s(f, v);
215     return 0;
216 }
217 
218 static int put_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field,
219                       QJSON *vmdesc)
220 {
221     uint16_t *v = pv;
222     qemu_put_be16s(f, v);
223     return 0;
224 }
225 
226 const VMStateInfo vmstate_info_uint16 = {
227     .name = "uint16",
228     .get  = get_uint16,
229     .put  = put_uint16,
230 };
231 
232 /* 32 bit unsigned int */
233 
234 static int get_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field)
235 {
236     uint32_t *v = pv;
237     qemu_get_be32s(f, v);
238     return 0;
239 }
240 
241 static int put_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field,
242                       QJSON *vmdesc)
243 {
244     uint32_t *v = pv;
245     qemu_put_be32s(f, v);
246     return 0;
247 }
248 
249 const VMStateInfo vmstate_info_uint32 = {
250     .name = "uint32",
251     .get  = get_uint32,
252     .put  = put_uint32,
253 };
254 
255 /* 32 bit uint. See that the received value is the same than the one
256    in the field */
257 
258 static int get_uint32_equal(QEMUFile *f, void *pv, size_t size,
259                             VMStateField *field)
260 {
261     uint32_t *v = pv;
262     uint32_t v2;
263     qemu_get_be32s(f, &v2);
264 
265     if (*v == v2) {
266         return 0;
267     }
268     error_report("%" PRIx32 " != %" PRIx32, *v, v2);
269     return -EINVAL;
270 }
271 
272 const VMStateInfo vmstate_info_uint32_equal = {
273     .name = "uint32 equal",
274     .get  = get_uint32_equal,
275     .put  = put_uint32,
276 };
277 
278 /* 64 bit unsigned int */
279 
280 static int get_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field)
281 {
282     uint64_t *v = pv;
283     qemu_get_be64s(f, v);
284     return 0;
285 }
286 
287 static int put_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
288                       QJSON *vmdesc)
289 {
290     uint64_t *v = pv;
291     qemu_put_be64s(f, v);
292     return 0;
293 }
294 
295 const VMStateInfo vmstate_info_uint64 = {
296     .name = "uint64",
297     .get  = get_uint64,
298     .put  = put_uint64,
299 };
300 
301 static int get_nullptr(QEMUFile *f, void *pv, size_t size, VMStateField *field)
302 
303 {
304     if (qemu_get_byte(f) == VMS_NULLPTR_MARKER) {
305         return  0;
306     }
307     error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
308     return -EINVAL;
309 }
310 
311 static int put_nullptr(QEMUFile *f, void *pv, size_t size,
312                         VMStateField *field, QJSON *vmdesc)
313 
314 {
315     if (pv == NULL) {
316         qemu_put_byte(f, VMS_NULLPTR_MARKER);
317         return 0;
318     }
319     error_report("vmstate: put_nullptr must be called with pv == NULL");
320     return -EINVAL;
321 }
322 
323 const VMStateInfo vmstate_info_nullptr = {
324     .name = "uint64",
325     .get  = get_nullptr,
326     .put  = put_nullptr,
327 };
328 
329 /* 64 bit unsigned int. See that the received value is the same than the one
330    in the field */
331 
332 static int get_uint64_equal(QEMUFile *f, void *pv, size_t size,
333                             VMStateField *field)
334 {
335     uint64_t *v = pv;
336     uint64_t v2;
337     qemu_get_be64s(f, &v2);
338 
339     if (*v == v2) {
340         return 0;
341     }
342     error_report("%" PRIx64 " != %" PRIx64, *v, v2);
343     return -EINVAL;
344 }
345 
346 const VMStateInfo vmstate_info_uint64_equal = {
347     .name = "int64 equal",
348     .get  = get_uint64_equal,
349     .put  = put_uint64,
350 };
351 
352 /* 8 bit int. See that the received value is the same than the one
353    in the field */
354 
355 static int get_uint8_equal(QEMUFile *f, void *pv, size_t size,
356                            VMStateField *field)
357 {
358     uint8_t *v = pv;
359     uint8_t v2;
360     qemu_get_8s(f, &v2);
361 
362     if (*v == v2) {
363         return 0;
364     }
365     error_report("%x != %x", *v, v2);
366     return -EINVAL;
367 }
368 
369 const VMStateInfo vmstate_info_uint8_equal = {
370     .name = "uint8 equal",
371     .get  = get_uint8_equal,
372     .put  = put_uint8,
373 };
374 
375 /* 16 bit unsigned int int. See that the received value is the same than the one
376    in the field */
377 
378 static int get_uint16_equal(QEMUFile *f, void *pv, size_t size,
379                             VMStateField *field)
380 {
381     uint16_t *v = pv;
382     uint16_t v2;
383     qemu_get_be16s(f, &v2);
384 
385     if (*v == v2) {
386         return 0;
387     }
388     error_report("%x != %x", *v, v2);
389     return -EINVAL;
390 }
391 
392 const VMStateInfo vmstate_info_uint16_equal = {
393     .name = "uint16 equal",
394     .get  = get_uint16_equal,
395     .put  = put_uint16,
396 };
397 
398 /* floating point */
399 
400 static int get_float64(QEMUFile *f, void *pv, size_t size,
401                        VMStateField *field)
402 {
403     float64 *v = pv;
404 
405     *v = make_float64(qemu_get_be64(f));
406     return 0;
407 }
408 
409 static int put_float64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
410                        QJSON *vmdesc)
411 {
412     uint64_t *v = pv;
413 
414     qemu_put_be64(f, float64_val(*v));
415     return 0;
416 }
417 
418 const VMStateInfo vmstate_info_float64 = {
419     .name = "float64",
420     .get  = get_float64,
421     .put  = put_float64,
422 };
423 
424 /* CPU_DoubleU type */
425 
426 static int get_cpudouble(QEMUFile *f, void *pv, size_t size,
427                          VMStateField *field)
428 {
429     CPU_DoubleU *v = pv;
430     qemu_get_be32s(f, &v->l.upper);
431     qemu_get_be32s(f, &v->l.lower);
432     return 0;
433 }
434 
435 static int put_cpudouble(QEMUFile *f, void *pv, size_t size,
436                          VMStateField *field, QJSON *vmdesc)
437 {
438     CPU_DoubleU *v = pv;
439     qemu_put_be32s(f, &v->l.upper);
440     qemu_put_be32s(f, &v->l.lower);
441     return 0;
442 }
443 
444 const VMStateInfo vmstate_info_cpudouble = {
445     .name = "CPU_Double_U",
446     .get  = get_cpudouble,
447     .put  = put_cpudouble,
448 };
449 
450 /* uint8_t buffers */
451 
452 static int get_buffer(QEMUFile *f, void *pv, size_t size,
453                       VMStateField *field)
454 {
455     uint8_t *v = pv;
456     qemu_get_buffer(f, v, size);
457     return 0;
458 }
459 
460 static int put_buffer(QEMUFile *f, void *pv, size_t size, VMStateField *field,
461                       QJSON *vmdesc)
462 {
463     uint8_t *v = pv;
464     qemu_put_buffer(f, v, size);
465     return 0;
466 }
467 
468 const VMStateInfo vmstate_info_buffer = {
469     .name = "buffer",
470     .get  = get_buffer,
471     .put  = put_buffer,
472 };
473 
474 /* unused buffers: space that was used for some fields that are
475    not useful anymore */
476 
477 static int get_unused_buffer(QEMUFile *f, void *pv, size_t size,
478                              VMStateField *field)
479 {
480     uint8_t buf[1024];
481     int block_len;
482 
483     while (size > 0) {
484         block_len = MIN(sizeof(buf), size);
485         size -= block_len;
486         qemu_get_buffer(f, buf, block_len);
487     }
488    return 0;
489 }
490 
491 static int put_unused_buffer(QEMUFile *f, void *pv, size_t size,
492                              VMStateField *field, QJSON *vmdesc)
493 {
494     static const uint8_t buf[1024];
495     int block_len;
496 
497     while (size > 0) {
498         block_len = MIN(sizeof(buf), size);
499         size -= block_len;
500         qemu_put_buffer(f, buf, block_len);
501     }
502 
503     return 0;
504 }
505 
506 const VMStateInfo vmstate_info_unused_buffer = {
507     .name = "unused_buffer",
508     .get  = get_unused_buffer,
509     .put  = put_unused_buffer,
510 };
511 
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.
517  */
518 static int get_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field)
519 {
520     int ret;
521     const VMStateDescription *vmsd = field->vmsd;
522     int version_id = field->version_id;
523     void *tmp = g_malloc(size);
524 
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;
530 }
531 
532 static int put_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field,
533                     QJSON *vmdesc)
534 {
535     const VMStateDescription *vmsd = field->vmsd;
536     void *tmp = g_malloc(size);
537 
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);
542 
543     return 0;
544 }
545 
546 const VMStateInfo vmstate_info_tmp = {
547     .name = "tmp",
548     .get = get_tmp,
549     .put = put_tmp,
550 };
551 
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.
556  */
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)
560 {
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;
568         }
569     }
570     return 0;
571 }
572 
573 static int put_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field,
574                       QJSON *vmdesc)
575 {
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;
582         }
583         qemu_put_be64(f, w);
584     }
585 
586     return 0;
587 }
588 
589 const VMStateInfo vmstate_info_bitmap = {
590     .name = "bitmap",
591     .get = get_bitmap,
592     .put = put_bitmap,
593 };
594 
595 /* get for QTAILQ
596  * meta data about the QTAILQ is encoded in a VMStateField structure
597  */
598 static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size,
599                       VMStateField *field)
600 {
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;
609 
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);
614 
615         return -EINVAL;
616     }
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;
621     }
622 
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;
628         }
629         QTAILQ_RAW_INSERT_TAIL(pv, elm, entry_offset);
630     }
631 
632     trace_get_qtailq_end(vmsd->name, "end", ret);
633     return ret;
634 }
635 
636 /* put for QTAILQ */
637 static int put_qtailq(QEMUFile *f, void *pv, size_t unused_size,
638                       VMStateField *field, QJSON *vmdesc)
639 {
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;
644 
645     trace_put_qtailq(vmsd->name, vmsd->version_id);
646 
647     QTAILQ_RAW_FOREACH(elm, pv, entry_offset) {
648         qemu_put_byte(f, true);
649         vmstate_save_state(f, vmsd, elm, vmdesc);
650     }
651     qemu_put_byte(f, false);
652 
653     trace_put_qtailq_end(vmsd->name, "end");
654 
655     return 0;
656 }
657 const VMStateInfo vmstate_info_qtailq = {
658     .name = "qtailq",
659     .get  = get_qtailq,
660     .put  = put_qtailq,
661 };
662