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