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