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