xref: /openbmc/qemu/migration/vmstate.c (revision 2c21ee769e4674348560480cecc7b20f3750ee84)
1 #include "qemu/osdep.h"
2 #include "qemu-common.h"
3 #include "migration/migration.h"
4 #include "migration/qemu-file.h"
5 #include "migration/vmstate.h"
6 #include "qemu/bitops.h"
7 #include "qemu/error-report.h"
8 #include "trace.h"
9 #include "migration/qjson.h"
10 
11 static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
12                                     void *opaque, QJSON *vmdesc);
13 static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
14                                    void *opaque);
15 
16 static int vmstate_n_elems(void *opaque, VMStateField *field)
17 {
18     int n_elems = 1;
19 
20     if (field->flags & VMS_ARRAY) {
21         n_elems = field->num;
22     } else if (field->flags & VMS_VARRAY_INT32) {
23         n_elems = *(int32_t *)(opaque+field->num_offset);
24     } else if (field->flags & VMS_VARRAY_UINT32) {
25         n_elems = *(uint32_t *)(opaque+field->num_offset);
26     } else if (field->flags & VMS_VARRAY_UINT16) {
27         n_elems = *(uint16_t *)(opaque+field->num_offset);
28     } else if (field->flags & VMS_VARRAY_UINT8) {
29         n_elems = *(uint8_t *)(opaque+field->num_offset);
30     }
31 
32     if (field->flags & VMS_MULTIPLY_ELEMENTS) {
33         n_elems *= field->num;
34     }
35 
36     trace_vmstate_n_elems(field->name, n_elems);
37     return n_elems;
38 }
39 
40 static int vmstate_size(void *opaque, VMStateField *field)
41 {
42     int size = field->size;
43 
44     if (field->flags & VMS_VBUFFER) {
45         size = *(int32_t *)(opaque+field->size_offset);
46         if (field->flags & VMS_MULTIPLY) {
47             size *= field->size;
48         }
49     }
50 
51     return size;
52 }
53 
54 static void *vmstate_base_addr(void *opaque, VMStateField *field, bool alloc)
55 {
56     void *base_addr = opaque + field->offset;
57 
58     if (field->flags & VMS_POINTER) {
59         if (alloc && (field->flags & VMS_ALLOC)) {
60             gsize size = 0;
61             if (field->flags & VMS_VBUFFER) {
62                 size = vmstate_size(opaque, field);
63             } else {
64                 int n_elems = vmstate_n_elems(opaque, field);
65                 if (n_elems) {
66                     size = n_elems * field->size;
67                 }
68             }
69             if (size) {
70                 *((void **)base_addr + field->start) = g_malloc(size);
71             }
72         }
73         base_addr = *(void **)base_addr + field->start;
74     }
75 
76     return base_addr;
77 }
78 
79 int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
80                        void *opaque, int version_id)
81 {
82     VMStateField *field = vmsd->fields;
83     int ret = 0;
84 
85     trace_vmstate_load_state(vmsd->name, version_id);
86     if (version_id > vmsd->version_id) {
87         trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
88         return -EINVAL;
89     }
90     if  (version_id < vmsd->minimum_version_id) {
91         if (vmsd->load_state_old &&
92             version_id >= vmsd->minimum_version_id_old) {
93             ret = vmsd->load_state_old(f, opaque, version_id);
94             trace_vmstate_load_state_end(vmsd->name, "old path", ret);
95             return ret;
96         }
97         trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
98         return -EINVAL;
99     }
100     if (vmsd->pre_load) {
101         int ret = vmsd->pre_load(opaque);
102         if (ret) {
103             return ret;
104         }
105     }
106     while (field->name) {
107         trace_vmstate_load_state_field(vmsd->name, field->name);
108         if ((field->field_exists &&
109              field->field_exists(opaque, version_id)) ||
110             (!field->field_exists &&
111              field->version_id <= version_id)) {
112             void *base_addr = vmstate_base_addr(opaque, field, true);
113             int i, n_elems = vmstate_n_elems(opaque, field);
114             int size = vmstate_size(opaque, field);
115 
116             for (i = 0; i < n_elems; i++) {
117                 void *addr = base_addr + size * i;
118 
119                 if (field->flags & VMS_ARRAY_OF_POINTER) {
120                     addr = *(void **)addr;
121                 }
122                 if (field->flags & VMS_STRUCT) {
123                     ret = vmstate_load_state(f, field->vmsd, addr,
124                                              field->vmsd->version_id);
125                 } else {
126                    ret = field->info->get(f, addr, size, field);
127                 }
128                 if (ret >= 0) {
129                     ret = qemu_file_get_error(f);
130                 }
131                 if (ret < 0) {
132                     qemu_file_set_error(f, ret);
133                     error_report("Failed to load %s:%s", vmsd->name,
134                                  field->name);
135                     trace_vmstate_load_field_error(field->name, ret);
136                     return ret;
137                 }
138             }
139         } else if (field->flags & VMS_MUST_EXIST) {
140             error_report("Input validation failed: %s/%s",
141                          vmsd->name, field->name);
142             return -1;
143         }
144         field++;
145     }
146     ret = vmstate_subsection_load(f, vmsd, opaque);
147     if (ret != 0) {
148         return ret;
149     }
150     if (vmsd->post_load) {
151         ret = vmsd->post_load(opaque, version_id);
152     }
153     trace_vmstate_load_state_end(vmsd->name, "end", ret);
154     return ret;
155 }
156 
157 static int vmfield_name_num(VMStateField *start, VMStateField *search)
158 {
159     VMStateField *field;
160     int found = 0;
161 
162     for (field = start; field->name; field++) {
163         if (!strcmp(field->name, search->name)) {
164             if (field == search) {
165                 return found;
166             }
167             found++;
168         }
169     }
170 
171     return -1;
172 }
173 
174 static bool vmfield_name_is_unique(VMStateField *start, VMStateField *search)
175 {
176     VMStateField *field;
177     int found = 0;
178 
179     for (field = start; field->name; field++) {
180         if (!strcmp(field->name, search->name)) {
181             found++;
182             /* name found more than once, so it's not unique */
183             if (found > 1) {
184                 return false;
185             }
186         }
187     }
188 
189     return true;
190 }
191 
192 static const char *vmfield_get_type_name(VMStateField *field)
193 {
194     const char *type = "unknown";
195 
196     if (field->flags & VMS_STRUCT) {
197         type = "struct";
198     } else if (field->info->name) {
199         type = field->info->name;
200     }
201 
202     return type;
203 }
204 
205 static bool vmsd_can_compress(VMStateField *field)
206 {
207     if (field->field_exists) {
208         /* Dynamically existing fields mess up compression */
209         return false;
210     }
211 
212     if (field->flags & VMS_STRUCT) {
213         VMStateField *sfield = field->vmsd->fields;
214         while (sfield->name) {
215             if (!vmsd_can_compress(sfield)) {
216                 /* Child elements can't compress, so can't we */
217                 return false;
218             }
219             sfield++;
220         }
221 
222         if (field->vmsd->subsections) {
223             /* Subsections may come and go, better don't compress */
224             return false;
225         }
226     }
227 
228     return true;
229 }
230 
231 static void vmsd_desc_field_start(const VMStateDescription *vmsd, QJSON *vmdesc,
232                                   VMStateField *field, int i, int max)
233 {
234     char *name, *old_name;
235     bool is_array = max > 1;
236     bool can_compress = vmsd_can_compress(field);
237 
238     if (!vmdesc) {
239         return;
240     }
241 
242     name = g_strdup(field->name);
243 
244     /* Field name is not unique, need to make it unique */
245     if (!vmfield_name_is_unique(vmsd->fields, field)) {
246         int num = vmfield_name_num(vmsd->fields, field);
247         old_name = name;
248         name = g_strdup_printf("%s[%d]", name, num);
249         g_free(old_name);
250     }
251 
252     json_start_object(vmdesc, NULL);
253     json_prop_str(vmdesc, "name", name);
254     if (is_array) {
255         if (can_compress) {
256             json_prop_int(vmdesc, "array_len", max);
257         } else {
258             json_prop_int(vmdesc, "index", i);
259         }
260     }
261     json_prop_str(vmdesc, "type", vmfield_get_type_name(field));
262 
263     if (field->flags & VMS_STRUCT) {
264         json_start_object(vmdesc, "struct");
265     }
266 
267     g_free(name);
268 }
269 
270 static void vmsd_desc_field_end(const VMStateDescription *vmsd, QJSON *vmdesc,
271                                 VMStateField *field, size_t size, int i)
272 {
273     if (!vmdesc) {
274         return;
275     }
276 
277     if (field->flags & VMS_STRUCT) {
278         /* We printed a struct in between, close its child object */
279         json_end_object(vmdesc);
280     }
281 
282     json_prop_int(vmdesc, "size", size);
283     json_end_object(vmdesc);
284 }
285 
286 
287 bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque)
288 {
289     if (vmsd->needed && !vmsd->needed(opaque)) {
290         /* optional section not needed */
291         return false;
292     }
293     return true;
294 }
295 
296 
297 void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
298                         void *opaque, QJSON *vmdesc)
299 {
300     VMStateField *field = vmsd->fields;
301 
302     if (vmsd->pre_save) {
303         vmsd->pre_save(opaque);
304     }
305 
306     if (vmdesc) {
307         json_prop_str(vmdesc, "vmsd_name", vmsd->name);
308         json_prop_int(vmdesc, "version", vmsd->version_id);
309         json_start_array(vmdesc, "fields");
310     }
311 
312     while (field->name) {
313         if (!field->field_exists ||
314             field->field_exists(opaque, vmsd->version_id)) {
315             void *base_addr = vmstate_base_addr(opaque, field, false);
316             int i, n_elems = vmstate_n_elems(opaque, field);
317             int size = vmstate_size(opaque, field);
318             int64_t old_offset, written_bytes;
319             QJSON *vmdesc_loop = vmdesc;
320 
321             for (i = 0; i < n_elems; i++) {
322                 void *addr = base_addr + size * i;
323 
324                 vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems);
325                 old_offset = qemu_ftell_fast(f);
326 
327                 if (field->flags & VMS_ARRAY_OF_POINTER) {
328                     addr = *(void **)addr;
329                 }
330                 if (field->flags & VMS_STRUCT) {
331                     vmstate_save_state(f, field->vmsd, addr, vmdesc_loop);
332                 } else {
333                     field->info->put(f, addr, size, field, vmdesc_loop);
334                 }
335 
336                 written_bytes = qemu_ftell_fast(f) - old_offset;
337                 vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i);
338 
339                 /* Compressed arrays only care about the first element */
340                 if (vmdesc_loop && vmsd_can_compress(field)) {
341                     vmdesc_loop = NULL;
342                 }
343             }
344         } else {
345             if (field->flags & VMS_MUST_EXIST) {
346                 error_report("Output state validation failed: %s/%s",
347                         vmsd->name, field->name);
348                 assert(!(field->flags & VMS_MUST_EXIST));
349             }
350         }
351         field++;
352     }
353 
354     if (vmdesc) {
355         json_end_array(vmdesc);
356     }
357 
358     vmstate_subsection_save(f, vmsd, opaque, vmdesc);
359 }
360 
361 static const VMStateDescription *
362 vmstate_get_subsection(const VMStateDescription **sub, char *idstr)
363 {
364     while (sub && *sub && (*sub)->needed) {
365         if (strcmp(idstr, (*sub)->name) == 0) {
366             return *sub;
367         }
368         sub++;
369     }
370     return NULL;
371 }
372 
373 static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
374                                    void *opaque)
375 {
376     trace_vmstate_subsection_load(vmsd->name);
377 
378     while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
379         char idstr[256], *idstr_ret;
380         int ret;
381         uint8_t version_id, len, size;
382         const VMStateDescription *sub_vmsd;
383 
384         len = qemu_peek_byte(f, 1);
385         if (len < strlen(vmsd->name) + 1) {
386             /* subsection name has be be "section_name/a" */
387             trace_vmstate_subsection_load_bad(vmsd->name, "(short)", "");
388             return 0;
389         }
390         size = qemu_peek_buffer(f, (uint8_t **)&idstr_ret, len, 2);
391         if (size != len) {
392             trace_vmstate_subsection_load_bad(vmsd->name, "(peek fail)", "");
393             return 0;
394         }
395         memcpy(idstr, idstr_ret, size);
396         idstr[size] = 0;
397 
398         if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
399             trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(prefix)");
400             /* it doesn't have a valid subsection name */
401             return 0;
402         }
403         sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
404         if (sub_vmsd == NULL) {
405             trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(lookup)");
406             return -ENOENT;
407         }
408         qemu_file_skip(f, 1); /* subsection */
409         qemu_file_skip(f, 1); /* len */
410         qemu_file_skip(f, len); /* idstr */
411         version_id = qemu_get_be32(f);
412 
413         ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
414         if (ret) {
415             trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
416             return ret;
417         }
418     }
419 
420     trace_vmstate_subsection_load_good(vmsd->name);
421     return 0;
422 }
423 
424 static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
425                                     void *opaque, QJSON *vmdesc)
426 {
427     const VMStateDescription **sub = vmsd->subsections;
428     bool subsection_found = false;
429 
430     while (sub && *sub && (*sub)->needed) {
431         if ((*sub)->needed(opaque)) {
432             const VMStateDescription *vmsd = *sub;
433             uint8_t len;
434 
435             if (vmdesc) {
436                 /* Only create subsection array when we have any */
437                 if (!subsection_found) {
438                     json_start_array(vmdesc, "subsections");
439                     subsection_found = true;
440                 }
441 
442                 json_start_object(vmdesc, NULL);
443             }
444 
445             qemu_put_byte(f, QEMU_VM_SUBSECTION);
446             len = strlen(vmsd->name);
447             qemu_put_byte(f, len);
448             qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
449             qemu_put_be32(f, vmsd->version_id);
450             vmstate_save_state(f, vmsd, opaque, vmdesc);
451 
452             if (vmdesc) {
453                 json_end_object(vmdesc);
454             }
455         }
456         sub++;
457     }
458 
459     if (vmdesc && subsection_found) {
460         json_end_array(vmdesc);
461     }
462 }
463 
464 /* bool */
465 
466 static int get_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field)
467 {
468     bool *v = pv;
469     *v = qemu_get_byte(f);
470     return 0;
471 }
472 
473 static int put_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field,
474                     QJSON *vmdesc)
475 {
476     bool *v = pv;
477     qemu_put_byte(f, *v);
478     return 0;
479 }
480 
481 const VMStateInfo vmstate_info_bool = {
482     .name = "bool",
483     .get  = get_bool,
484     .put  = put_bool,
485 };
486 
487 /* 8 bit int */
488 
489 static int get_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field)
490 {
491     int8_t *v = pv;
492     qemu_get_s8s(f, v);
493     return 0;
494 }
495 
496 static int put_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field,
497                      QJSON *vmdesc)
498 {
499     int8_t *v = pv;
500     qemu_put_s8s(f, v);
501     return 0;
502 }
503 
504 const VMStateInfo vmstate_info_int8 = {
505     .name = "int8",
506     .get  = get_int8,
507     .put  = put_int8,
508 };
509 
510 /* 16 bit int */
511 
512 static int get_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field)
513 {
514     int16_t *v = pv;
515     qemu_get_sbe16s(f, v);
516     return 0;
517 }
518 
519 static int put_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field,
520                      QJSON *vmdesc)
521 {
522     int16_t *v = pv;
523     qemu_put_sbe16s(f, v);
524     return 0;
525 }
526 
527 const VMStateInfo vmstate_info_int16 = {
528     .name = "int16",
529     .get  = get_int16,
530     .put  = put_int16,
531 };
532 
533 /* 32 bit int */
534 
535 static int get_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field)
536 {
537     int32_t *v = pv;
538     qemu_get_sbe32s(f, v);
539     return 0;
540 }
541 
542 static int put_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field,
543                      QJSON *vmdesc)
544 {
545     int32_t *v = pv;
546     qemu_put_sbe32s(f, v);
547     return 0;
548 }
549 
550 const VMStateInfo vmstate_info_int32 = {
551     .name = "int32",
552     .get  = get_int32,
553     .put  = put_int32,
554 };
555 
556 /* 32 bit int. See that the received value is the same than the one
557    in the field */
558 
559 static int get_int32_equal(QEMUFile *f, void *pv, size_t size,
560                            VMStateField *field)
561 {
562     int32_t *v = pv;
563     int32_t v2;
564     qemu_get_sbe32s(f, &v2);
565 
566     if (*v == v2) {
567         return 0;
568     }
569     error_report("%" PRIx32 " != %" PRIx32, *v, v2);
570     return -EINVAL;
571 }
572 
573 const VMStateInfo vmstate_info_int32_equal = {
574     .name = "int32 equal",
575     .get  = get_int32_equal,
576     .put  = put_int32,
577 };
578 
579 /* 32 bit int. Check that the received value is non-negative
580  * and less than or equal to the one in the field.
581  */
582 
583 static int get_int32_le(QEMUFile *f, void *pv, size_t size, VMStateField *field)
584 {
585     int32_t *cur = pv;
586     int32_t loaded;
587     qemu_get_sbe32s(f, &loaded);
588 
589     if (loaded >= 0 && loaded <= *cur) {
590         *cur = loaded;
591         return 0;
592     }
593     error_report("Invalid value %" PRId32
594                  " expecting positive value <= %" PRId32,
595                  loaded, *cur);
596     return -EINVAL;
597 }
598 
599 const VMStateInfo vmstate_info_int32_le = {
600     .name = "int32 le",
601     .get  = get_int32_le,
602     .put  = put_int32,
603 };
604 
605 /* 64 bit int */
606 
607 static int get_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field)
608 {
609     int64_t *v = pv;
610     qemu_get_sbe64s(f, v);
611     return 0;
612 }
613 
614 static int put_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
615                       QJSON *vmdesc)
616 {
617     int64_t *v = pv;
618     qemu_put_sbe64s(f, v);
619     return 0;
620 }
621 
622 const VMStateInfo vmstate_info_int64 = {
623     .name = "int64",
624     .get  = get_int64,
625     .put  = put_int64,
626 };
627 
628 /* 8 bit unsigned int */
629 
630 static int get_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field)
631 {
632     uint8_t *v = pv;
633     qemu_get_8s(f, v);
634     return 0;
635 }
636 
637 static int put_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field,
638                      QJSON *vmdesc)
639 {
640     uint8_t *v = pv;
641     qemu_put_8s(f, v);
642     return 0;
643 }
644 
645 const VMStateInfo vmstate_info_uint8 = {
646     .name = "uint8",
647     .get  = get_uint8,
648     .put  = put_uint8,
649 };
650 
651 /* 16 bit unsigned int */
652 
653 static int get_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field)
654 {
655     uint16_t *v = pv;
656     qemu_get_be16s(f, v);
657     return 0;
658 }
659 
660 static int put_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field,
661                       QJSON *vmdesc)
662 {
663     uint16_t *v = pv;
664     qemu_put_be16s(f, v);
665     return 0;
666 }
667 
668 const VMStateInfo vmstate_info_uint16 = {
669     .name = "uint16",
670     .get  = get_uint16,
671     .put  = put_uint16,
672 };
673 
674 /* 32 bit unsigned int */
675 
676 static int get_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field)
677 {
678     uint32_t *v = pv;
679     qemu_get_be32s(f, v);
680     return 0;
681 }
682 
683 static int put_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field,
684                       QJSON *vmdesc)
685 {
686     uint32_t *v = pv;
687     qemu_put_be32s(f, v);
688     return 0;
689 }
690 
691 const VMStateInfo vmstate_info_uint32 = {
692     .name = "uint32",
693     .get  = get_uint32,
694     .put  = put_uint32,
695 };
696 
697 /* 32 bit uint. See that the received value is the same than the one
698    in the field */
699 
700 static int get_uint32_equal(QEMUFile *f, void *pv, size_t size,
701                             VMStateField *field)
702 {
703     uint32_t *v = pv;
704     uint32_t v2;
705     qemu_get_be32s(f, &v2);
706 
707     if (*v == v2) {
708         return 0;
709     }
710     error_report("%" PRIx32 " != %" PRIx32, *v, v2);
711     return -EINVAL;
712 }
713 
714 const VMStateInfo vmstate_info_uint32_equal = {
715     .name = "uint32 equal",
716     .get  = get_uint32_equal,
717     .put  = put_uint32,
718 };
719 
720 /* 64 bit unsigned int */
721 
722 static int get_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field)
723 {
724     uint64_t *v = pv;
725     qemu_get_be64s(f, v);
726     return 0;
727 }
728 
729 static int put_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
730                       QJSON *vmdesc)
731 {
732     uint64_t *v = pv;
733     qemu_put_be64s(f, v);
734     return 0;
735 }
736 
737 const VMStateInfo vmstate_info_uint64 = {
738     .name = "uint64",
739     .get  = get_uint64,
740     .put  = put_uint64,
741 };
742 
743 /* 64 bit unsigned int. See that the received value is the same than the one
744    in the field */
745 
746 static int get_uint64_equal(QEMUFile *f, void *pv, size_t size,
747                             VMStateField *field)
748 {
749     uint64_t *v = pv;
750     uint64_t v2;
751     qemu_get_be64s(f, &v2);
752 
753     if (*v == v2) {
754         return 0;
755     }
756     error_report("%" PRIx64 " != %" PRIx64, *v, v2);
757     return -EINVAL;
758 }
759 
760 const VMStateInfo vmstate_info_uint64_equal = {
761     .name = "int64 equal",
762     .get  = get_uint64_equal,
763     .put  = put_uint64,
764 };
765 
766 /* 8 bit int. See that the received value is the same than the one
767    in the field */
768 
769 static int get_uint8_equal(QEMUFile *f, void *pv, size_t size,
770                            VMStateField *field)
771 {
772     uint8_t *v = pv;
773     uint8_t v2;
774     qemu_get_8s(f, &v2);
775 
776     if (*v == v2) {
777         return 0;
778     }
779     error_report("%x != %x", *v, v2);
780     return -EINVAL;
781 }
782 
783 const VMStateInfo vmstate_info_uint8_equal = {
784     .name = "uint8 equal",
785     .get  = get_uint8_equal,
786     .put  = put_uint8,
787 };
788 
789 /* 16 bit unsigned int int. See that the received value is the same than the one
790    in the field */
791 
792 static int get_uint16_equal(QEMUFile *f, void *pv, size_t size,
793                             VMStateField *field)
794 {
795     uint16_t *v = pv;
796     uint16_t v2;
797     qemu_get_be16s(f, &v2);
798 
799     if (*v == v2) {
800         return 0;
801     }
802     error_report("%x != %x", *v, v2);
803     return -EINVAL;
804 }
805 
806 const VMStateInfo vmstate_info_uint16_equal = {
807     .name = "uint16 equal",
808     .get  = get_uint16_equal,
809     .put  = put_uint16,
810 };
811 
812 /* floating point */
813 
814 static int get_float64(QEMUFile *f, void *pv, size_t size,
815                        VMStateField *field)
816 {
817     float64 *v = pv;
818 
819     *v = make_float64(qemu_get_be64(f));
820     return 0;
821 }
822 
823 static int put_float64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
824                        QJSON *vmdesc)
825 {
826     uint64_t *v = pv;
827 
828     qemu_put_be64(f, float64_val(*v));
829     return 0;
830 }
831 
832 const VMStateInfo vmstate_info_float64 = {
833     .name = "float64",
834     .get  = get_float64,
835     .put  = put_float64,
836 };
837 
838 /* CPU_DoubleU type */
839 
840 static int get_cpudouble(QEMUFile *f, void *pv, size_t size,
841                          VMStateField *field)
842 {
843     CPU_DoubleU *v = pv;
844     qemu_get_be32s(f, &v->l.upper);
845     qemu_get_be32s(f, &v->l.lower);
846     return 0;
847 }
848 
849 static int put_cpudouble(QEMUFile *f, void *pv, size_t size,
850                          VMStateField *field, QJSON *vmdesc)
851 {
852     CPU_DoubleU *v = pv;
853     qemu_put_be32s(f, &v->l.upper);
854     qemu_put_be32s(f, &v->l.lower);
855     return 0;
856 }
857 
858 const VMStateInfo vmstate_info_cpudouble = {
859     .name = "CPU_Double_U",
860     .get  = get_cpudouble,
861     .put  = put_cpudouble,
862 };
863 
864 /* uint8_t buffers */
865 
866 static int get_buffer(QEMUFile *f, void *pv, size_t size,
867                       VMStateField *field)
868 {
869     uint8_t *v = pv;
870     qemu_get_buffer(f, v, size);
871     return 0;
872 }
873 
874 static int put_buffer(QEMUFile *f, void *pv, size_t size, VMStateField *field,
875                       QJSON *vmdesc)
876 {
877     uint8_t *v = pv;
878     qemu_put_buffer(f, v, size);
879     return 0;
880 }
881 
882 const VMStateInfo vmstate_info_buffer = {
883     .name = "buffer",
884     .get  = get_buffer,
885     .put  = put_buffer,
886 };
887 
888 /* unused buffers: space that was used for some fields that are
889    not useful anymore */
890 
891 static int get_unused_buffer(QEMUFile *f, void *pv, size_t size,
892                              VMStateField *field)
893 {
894     uint8_t buf[1024];
895     int block_len;
896 
897     while (size > 0) {
898         block_len = MIN(sizeof(buf), size);
899         size -= block_len;
900         qemu_get_buffer(f, buf, block_len);
901     }
902    return 0;
903 }
904 
905 static int put_unused_buffer(QEMUFile *f, void *pv, size_t size,
906                              VMStateField *field, QJSON *vmdesc)
907 {
908     static const uint8_t buf[1024];
909     int block_len;
910 
911     while (size > 0) {
912         block_len = MIN(sizeof(buf), size);
913         size -= block_len;
914         qemu_put_buffer(f, buf, block_len);
915     }
916 
917     return 0;
918 }
919 
920 const VMStateInfo vmstate_info_unused_buffer = {
921     .name = "unused_buffer",
922     .get  = get_unused_buffer,
923     .put  = put_unused_buffer,
924 };
925 
926 /* bitmaps (as defined by bitmap.h). Note that size here is the size
927  * of the bitmap in bits. The on-the-wire format of a bitmap is 64
928  * bit words with the bits in big endian order. The in-memory format
929  * is an array of 'unsigned long', which may be either 32 or 64 bits.
930  */
931 /* This is the number of 64 bit words sent over the wire */
932 #define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
933 static int get_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field)
934 {
935     unsigned long *bmp = pv;
936     int i, idx = 0;
937     for (i = 0; i < BITS_TO_U64S(size); i++) {
938         uint64_t w = qemu_get_be64(f);
939         bmp[idx++] = w;
940         if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
941             bmp[idx++] = w >> 32;
942         }
943     }
944     return 0;
945 }
946 
947 static int put_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field,
948                       QJSON *vmdesc)
949 {
950     unsigned long *bmp = pv;
951     int i, idx = 0;
952     for (i = 0; i < BITS_TO_U64S(size); i++) {
953         uint64_t w = bmp[idx++];
954         if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
955             w |= ((uint64_t)bmp[idx++]) << 32;
956         }
957         qemu_put_be64(f, w);
958     }
959 
960     return 0;
961 }
962 
963 const VMStateInfo vmstate_info_bitmap = {
964     .name = "bitmap",
965     .get = get_bitmap,
966     .put = put_bitmap,
967 };
968