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