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