xref: /qemu/migration/vmstate.c (revision 814bb12a)
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 
10 static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
11                                     void *opaque, QJSON *vmdesc);
12 static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
13                                    void *opaque);
14 
15 static int vmstate_n_elems(void *opaque, VMStateField *field)
16 {
17     int n_elems = 1;
18 
19     if (field->flags & VMS_ARRAY) {
20         n_elems = field->num;
21     } else if (field->flags & VMS_VARRAY_INT32) {
22         n_elems = *(int32_t *)(opaque+field->num_offset);
23     } else if (field->flags & VMS_VARRAY_UINT32) {
24         n_elems = *(uint32_t *)(opaque+field->num_offset);
25     } else if (field->flags & VMS_VARRAY_UINT16) {
26         n_elems = *(uint16_t *)(opaque+field->num_offset);
27     } else if (field->flags & VMS_VARRAY_UINT8) {
28         n_elems = *(uint8_t *)(opaque+field->num_offset);
29     }
30 
31     if (field->flags & VMS_MULTIPLY_ELEMENTS) {
32         n_elems *= field->num;
33     }
34 
35     trace_vmstate_n_elems(field->name, n_elems);
36     return n_elems;
37 }
38 
39 static int vmstate_size(void *opaque, VMStateField *field)
40 {
41     int size = field->size;
42 
43     if (field->flags & VMS_VBUFFER) {
44         size = *(int32_t *)(opaque+field->size_offset);
45         if (field->flags & VMS_MULTIPLY) {
46             size *= field->size;
47         }
48     }
49 
50     return size;
51 }
52 
53 static void *vmstate_base_addr(void *opaque, VMStateField *field, bool alloc)
54 {
55     void *base_addr = opaque + field->offset;
56 
57     if (field->flags & VMS_POINTER) {
58         if (alloc && (field->flags & VMS_ALLOC)) {
59             gsize size = 0;
60             if (field->flags & VMS_VBUFFER) {
61                 size = vmstate_size(opaque, field);
62             } else {
63                 int n_elems = vmstate_n_elems(opaque, field);
64                 if (n_elems) {
65                     size = n_elems * field->size;
66                 }
67             }
68             if (size) {
69                 *((void **)base_addr + field->start) = g_malloc(size);
70             }
71         }
72         base_addr = *(void **)base_addr + field->start;
73     }
74 
75     return base_addr;
76 }
77 
78 int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
79                        void *opaque, int version_id)
80 {
81     VMStateField *field = vmsd->fields;
82     int ret = 0;
83 
84     trace_vmstate_load_state(vmsd->name, version_id);
85     if (version_id > vmsd->version_id) {
86         trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
87         return -EINVAL;
88     }
89     if  (version_id < vmsd->minimum_version_id) {
90         if (vmsd->load_state_old &&
91             version_id >= vmsd->minimum_version_id_old) {
92             ret = vmsd->load_state_old(f, opaque, version_id);
93             trace_vmstate_load_state_end(vmsd->name, "old path", ret);
94             return ret;
95         }
96         trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
97         return -EINVAL;
98     }
99     if (vmsd->pre_load) {
100         int ret = vmsd->pre_load(opaque);
101         if (ret) {
102             return ret;
103         }
104     }
105     while (field->name) {
106         trace_vmstate_load_state_field(vmsd->name, field->name);
107         if ((field->field_exists &&
108              field->field_exists(opaque, version_id)) ||
109             (!field->field_exists &&
110              field->version_id <= version_id)) {
111             void *base_addr = vmstate_base_addr(opaque, field, true);
112             int i, n_elems = vmstate_n_elems(opaque, field);
113             int size = vmstate_size(opaque, field);
114 
115             for (i = 0; i < n_elems; i++) {
116                 void *addr = base_addr + size * i;
117 
118                 if (field->flags & VMS_ARRAY_OF_POINTER) {
119                     addr = *(void **)addr;
120                 }
121                 if (field->flags & VMS_STRUCT) {
122                     ret = vmstate_load_state(f, field->vmsd, addr,
123                                              field->vmsd->version_id);
124                 } else {
125                     ret = field->info->get(f, addr, size);
126 
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);
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)
467 {
468     bool *v = pv;
469     *v = qemu_get_byte(f);
470     return 0;
471 }
472 
473 static void put_bool(QEMUFile *f, void *pv, size_t size)
474 {
475     bool *v = pv;
476     qemu_put_byte(f, *v);
477 }
478 
479 const VMStateInfo vmstate_info_bool = {
480     .name = "bool",
481     .get  = get_bool,
482     .put  = put_bool,
483 };
484 
485 /* 8 bit int */
486 
487 static int get_int8(QEMUFile *f, void *pv, size_t size)
488 {
489     int8_t *v = pv;
490     qemu_get_s8s(f, v);
491     return 0;
492 }
493 
494 static void put_int8(QEMUFile *f, void *pv, size_t size)
495 {
496     int8_t *v = pv;
497     qemu_put_s8s(f, v);
498 }
499 
500 const VMStateInfo vmstate_info_int8 = {
501     .name = "int8",
502     .get  = get_int8,
503     .put  = put_int8,
504 };
505 
506 /* 16 bit int */
507 
508 static int get_int16(QEMUFile *f, void *pv, size_t size)
509 {
510     int16_t *v = pv;
511     qemu_get_sbe16s(f, v);
512     return 0;
513 }
514 
515 static void put_int16(QEMUFile *f, void *pv, size_t size)
516 {
517     int16_t *v = pv;
518     qemu_put_sbe16s(f, v);
519 }
520 
521 const VMStateInfo vmstate_info_int16 = {
522     .name = "int16",
523     .get  = get_int16,
524     .put  = put_int16,
525 };
526 
527 /* 32 bit int */
528 
529 static int get_int32(QEMUFile *f, void *pv, size_t size)
530 {
531     int32_t *v = pv;
532     qemu_get_sbe32s(f, v);
533     return 0;
534 }
535 
536 static void put_int32(QEMUFile *f, void *pv, size_t size)
537 {
538     int32_t *v = pv;
539     qemu_put_sbe32s(f, v);
540 }
541 
542 const VMStateInfo vmstate_info_int32 = {
543     .name = "int32",
544     .get  = get_int32,
545     .put  = put_int32,
546 };
547 
548 /* 32 bit int. See that the received value is the same than the one
549    in the field */
550 
551 static int get_int32_equal(QEMUFile *f, void *pv, size_t size)
552 {
553     int32_t *v = pv;
554     int32_t v2;
555     qemu_get_sbe32s(f, &v2);
556 
557     if (*v == v2) {
558         return 0;
559     }
560     error_report("%" PRIx32 " != %" PRIx32, *v, v2);
561     return -EINVAL;
562 }
563 
564 const VMStateInfo vmstate_info_int32_equal = {
565     .name = "int32 equal",
566     .get  = get_int32_equal,
567     .put  = put_int32,
568 };
569 
570 /* 32 bit int. Check that the received value is non-negative
571  * and less than or equal to the one in the field.
572  */
573 
574 static int get_int32_le(QEMUFile *f, void *pv, size_t size)
575 {
576     int32_t *cur = pv;
577     int32_t loaded;
578     qemu_get_sbe32s(f, &loaded);
579 
580     if (loaded >= 0 && loaded <= *cur) {
581         *cur = loaded;
582         return 0;
583     }
584     error_report("Invalid value %" PRId32
585                  " expecting positive value <= %" PRId32,
586                  loaded, *cur);
587     return -EINVAL;
588 }
589 
590 const VMStateInfo vmstate_info_int32_le = {
591     .name = "int32 le",
592     .get  = get_int32_le,
593     .put  = put_int32,
594 };
595 
596 /* 64 bit int */
597 
598 static int get_int64(QEMUFile *f, void *pv, size_t size)
599 {
600     int64_t *v = pv;
601     qemu_get_sbe64s(f, v);
602     return 0;
603 }
604 
605 static void put_int64(QEMUFile *f, void *pv, size_t size)
606 {
607     int64_t *v = pv;
608     qemu_put_sbe64s(f, v);
609 }
610 
611 const VMStateInfo vmstate_info_int64 = {
612     .name = "int64",
613     .get  = get_int64,
614     .put  = put_int64,
615 };
616 
617 /* 8 bit unsigned int */
618 
619 static int get_uint8(QEMUFile *f, void *pv, size_t size)
620 {
621     uint8_t *v = pv;
622     qemu_get_8s(f, v);
623     return 0;
624 }
625 
626 static void put_uint8(QEMUFile *f, void *pv, size_t size)
627 {
628     uint8_t *v = pv;
629     qemu_put_8s(f, v);
630 }
631 
632 const VMStateInfo vmstate_info_uint8 = {
633     .name = "uint8",
634     .get  = get_uint8,
635     .put  = put_uint8,
636 };
637 
638 /* 16 bit unsigned int */
639 
640 static int get_uint16(QEMUFile *f, void *pv, size_t size)
641 {
642     uint16_t *v = pv;
643     qemu_get_be16s(f, v);
644     return 0;
645 }
646 
647 static void put_uint16(QEMUFile *f, void *pv, size_t size)
648 {
649     uint16_t *v = pv;
650     qemu_put_be16s(f, v);
651 }
652 
653 const VMStateInfo vmstate_info_uint16 = {
654     .name = "uint16",
655     .get  = get_uint16,
656     .put  = put_uint16,
657 };
658 
659 /* 32 bit unsigned int */
660 
661 static int get_uint32(QEMUFile *f, void *pv, size_t size)
662 {
663     uint32_t *v = pv;
664     qemu_get_be32s(f, v);
665     return 0;
666 }
667 
668 static void put_uint32(QEMUFile *f, void *pv, size_t size)
669 {
670     uint32_t *v = pv;
671     qemu_put_be32s(f, v);
672 }
673 
674 const VMStateInfo vmstate_info_uint32 = {
675     .name = "uint32",
676     .get  = get_uint32,
677     .put  = put_uint32,
678 };
679 
680 /* 32 bit uint. See that the received value is the same than the one
681    in the field */
682 
683 static int get_uint32_equal(QEMUFile *f, void *pv, size_t size)
684 {
685     uint32_t *v = pv;
686     uint32_t v2;
687     qemu_get_be32s(f, &v2);
688 
689     if (*v == v2) {
690         return 0;
691     }
692     error_report("%" PRIx32 " != %" PRIx32, *v, v2);
693     return -EINVAL;
694 }
695 
696 const VMStateInfo vmstate_info_uint32_equal = {
697     .name = "uint32 equal",
698     .get  = get_uint32_equal,
699     .put  = put_uint32,
700 };
701 
702 /* 64 bit unsigned int */
703 
704 static int get_uint64(QEMUFile *f, void *pv, size_t size)
705 {
706     uint64_t *v = pv;
707     qemu_get_be64s(f, v);
708     return 0;
709 }
710 
711 static void put_uint64(QEMUFile *f, void *pv, size_t size)
712 {
713     uint64_t *v = pv;
714     qemu_put_be64s(f, v);
715 }
716 
717 const VMStateInfo vmstate_info_uint64 = {
718     .name = "uint64",
719     .get  = get_uint64,
720     .put  = put_uint64,
721 };
722 
723 /* 64 bit unsigned int. See that the received value is the same than the one
724    in the field */
725 
726 static int get_uint64_equal(QEMUFile *f, void *pv, size_t size)
727 {
728     uint64_t *v = pv;
729     uint64_t v2;
730     qemu_get_be64s(f, &v2);
731 
732     if (*v == v2) {
733         return 0;
734     }
735     error_report("%" PRIx64 " != %" PRIx64, *v, v2);
736     return -EINVAL;
737 }
738 
739 const VMStateInfo vmstate_info_uint64_equal = {
740     .name = "int64 equal",
741     .get  = get_uint64_equal,
742     .put  = put_uint64,
743 };
744 
745 /* 8 bit int. See that the received value is the same than the one
746    in the field */
747 
748 static int get_uint8_equal(QEMUFile *f, void *pv, size_t size)
749 {
750     uint8_t *v = pv;
751     uint8_t v2;
752     qemu_get_8s(f, &v2);
753 
754     if (*v == v2) {
755         return 0;
756     }
757     error_report("%x != %x", *v, v2);
758     return -EINVAL;
759 }
760 
761 const VMStateInfo vmstate_info_uint8_equal = {
762     .name = "uint8 equal",
763     .get  = get_uint8_equal,
764     .put  = put_uint8,
765 };
766 
767 /* 16 bit unsigned int int. See that the received value is the same than the one
768    in the field */
769 
770 static int get_uint16_equal(QEMUFile *f, void *pv, size_t size)
771 {
772     uint16_t *v = pv;
773     uint16_t v2;
774     qemu_get_be16s(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_uint16_equal = {
784     .name = "uint16 equal",
785     .get  = get_uint16_equal,
786     .put  = put_uint16,
787 };
788 
789 /* floating point */
790 
791 static int get_float64(QEMUFile *f, void *pv, size_t size)
792 {
793     float64 *v = pv;
794 
795     *v = make_float64(qemu_get_be64(f));
796     return 0;
797 }
798 
799 static void put_float64(QEMUFile *f, void *pv, size_t size)
800 {
801     uint64_t *v = pv;
802 
803     qemu_put_be64(f, float64_val(*v));
804 }
805 
806 const VMStateInfo vmstate_info_float64 = {
807     .name = "float64",
808     .get  = get_float64,
809     .put  = put_float64,
810 };
811 
812 /* CPU_DoubleU type */
813 
814 static int get_cpudouble(QEMUFile *f, void *pv, size_t size)
815 {
816     CPU_DoubleU *v = pv;
817     qemu_get_be32s(f, &v->l.upper);
818     qemu_get_be32s(f, &v->l.lower);
819     return 0;
820 }
821 
822 static void put_cpudouble(QEMUFile *f, void *pv, size_t size)
823 {
824     CPU_DoubleU *v = pv;
825     qemu_put_be32s(f, &v->l.upper);
826     qemu_put_be32s(f, &v->l.lower);
827 }
828 
829 const VMStateInfo vmstate_info_cpudouble = {
830     .name = "CPU_Double_U",
831     .get  = get_cpudouble,
832     .put  = put_cpudouble,
833 };
834 
835 /* uint8_t buffers */
836 
837 static int get_buffer(QEMUFile *f, void *pv, size_t size)
838 {
839     uint8_t *v = pv;
840     qemu_get_buffer(f, v, size);
841     return 0;
842 }
843 
844 static void put_buffer(QEMUFile *f, void *pv, size_t size)
845 {
846     uint8_t *v = pv;
847     qemu_put_buffer(f, v, size);
848 }
849 
850 const VMStateInfo vmstate_info_buffer = {
851     .name = "buffer",
852     .get  = get_buffer,
853     .put  = put_buffer,
854 };
855 
856 /* unused buffers: space that was used for some fields that are
857    not useful anymore */
858 
859 static int get_unused_buffer(QEMUFile *f, void *pv, size_t size)
860 {
861     uint8_t buf[1024];
862     int block_len;
863 
864     while (size > 0) {
865         block_len = MIN(sizeof(buf), size);
866         size -= block_len;
867         qemu_get_buffer(f, buf, block_len);
868     }
869    return 0;
870 }
871 
872 static void put_unused_buffer(QEMUFile *f, void *pv, size_t size)
873 {
874     static const uint8_t buf[1024];
875     int block_len;
876 
877     while (size > 0) {
878         block_len = MIN(sizeof(buf), size);
879         size -= block_len;
880         qemu_put_buffer(f, buf, block_len);
881     }
882 }
883 
884 const VMStateInfo vmstate_info_unused_buffer = {
885     .name = "unused_buffer",
886     .get  = get_unused_buffer,
887     .put  = put_unused_buffer,
888 };
889 
890 /* bitmaps (as defined by bitmap.h). Note that size here is the size
891  * of the bitmap in bits. The on-the-wire format of a bitmap is 64
892  * bit words with the bits in big endian order. The in-memory format
893  * is an array of 'unsigned long', which may be either 32 or 64 bits.
894  */
895 /* This is the number of 64 bit words sent over the wire */
896 #define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
897 static int get_bitmap(QEMUFile *f, void *pv, size_t size)
898 {
899     unsigned long *bmp = pv;
900     int i, idx = 0;
901     for (i = 0; i < BITS_TO_U64S(size); i++) {
902         uint64_t w = qemu_get_be64(f);
903         bmp[idx++] = w;
904         if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
905             bmp[idx++] = w >> 32;
906         }
907     }
908     return 0;
909 }
910 
911 static void put_bitmap(QEMUFile *f, void *pv, size_t size)
912 {
913     unsigned long *bmp = pv;
914     int i, idx = 0;
915     for (i = 0; i < BITS_TO_U64S(size); i++) {
916         uint64_t w = bmp[idx++];
917         if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
918             w |= ((uint64_t)bmp[idx++]) << 32;
919         }
920         qemu_put_be64(f, w);
921     }
922 }
923 
924 const VMStateInfo vmstate_info_bitmap = {
925     .name = "bitmap",
926     .get = get_bitmap,
927     .put = put_bitmap,
928 };
929