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