]> git.proxmox.com Git - mirror_qemu.git/blame - migration/vmstate.c
migration: transform remaining DPRINTF into trace_
[mirror_qemu.git] / migration / vmstate.c
CommitLineData
1393a485 1#include "qemu/osdep.h"
b6fcfa59
EH
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"
6a64b644 7#include "qemu/error-report.h"
94869d5c 8#include "qemu/queue.h"
9013dca5 9#include "trace.h"
2c21ee76 10#include "migration/qjson.h"
b6fcfa59
EH
11
12static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
8118f095 13 void *opaque, QJSON *vmdesc);
b6fcfa59
EH
14static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
15 void *opaque);
16
35fc1f71
MT
17static 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
b47d3af7
JQ
33 if (field->flags & VMS_MULTIPLY_ELEMENTS) {
34 n_elems *= field->num;
35 }
36
023ad1a6 37 trace_vmstate_n_elems(field->name, n_elems);
35fc1f71
MT
38 return n_elems;
39}
40
41static 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
f32935ea 55static void *vmstate_base_addr(void *opaque, VMStateField *field, bool alloc)
35fc1f71
MT
56{
57 void *base_addr = opaque + field->offset;
58
59 if (field->flags & VMS_POINTER) {
f32935ea 60 if (alloc && (field->flags & VMS_ALLOC)) {
94ed706d
AK
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) {
f32935ea
AK
71 *((void **)base_addr + field->start) = g_malloc(size);
72 }
73 }
35fc1f71
MT
74 base_addr = *(void **)base_addr + field->start;
75 }
76
77 return base_addr;
78}
79
b6fcfa59
EH
80int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
81 void *opaque, int version_id)
82{
83 VMStateField *field = vmsd->fields;
a5df2a02 84 int ret = 0;
b6fcfa59 85
a5df2a02 86 trace_vmstate_load_state(vmsd->name, version_id);
b6fcfa59 87 if (version_id > vmsd->version_id) {
cde7ee59
JD
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);
a5df2a02 91 trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
b6fcfa59
EH
92 return -EINVAL;
93 }
b6fcfa59 94 if (version_id < vmsd->minimum_version_id) {
767adce2
PM
95 if (vmsd->load_state_old &&
96 version_id >= vmsd->minimum_version_id_old) {
a5df2a02
DDAG
97 ret = vmsd->load_state_old(f, opaque, version_id);
98 trace_vmstate_load_state_end(vmsd->name, "old path", ret);
99 return ret;
767adce2 100 }
cde7ee59
JD
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);
a5df2a02 104 trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
767adce2 105 return -EINVAL;
b6fcfa59
EH
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) {
a5df2a02 114 trace_vmstate_load_state_field(vmsd->name, field->name);
b6fcfa59
EH
115 if ((field->field_exists &&
116 field->field_exists(opaque, version_id)) ||
117 (!field->field_exists &&
118 field->version_id <= version_id)) {
f32935ea 119 void *base_addr = vmstate_base_addr(opaque, field, true);
35fc1f71
MT
120 int i, n_elems = vmstate_n_elems(opaque, field);
121 int size = vmstate_size(opaque, field);
122
b6fcfa59
EH
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 {
2c21ee76 133 ret = field->info->get(f, addr, size, field);
b6fcfa59 134 }
13cde508
JQ
135 if (ret >= 0) {
136 ret = qemu_file_get_error(f);
137 }
b6fcfa59 138 if (ret < 0) {
13cde508 139 qemu_file_set_error(f, ret);
a1771070
DDAG
140 error_report("Failed to load %s:%s", vmsd->name,
141 field->name);
9013dca5 142 trace_vmstate_load_field_error(field->name, ret);
b6fcfa59
EH
143 return ret;
144 }
145 }
5bf81c8d 146 } else if (field->flags & VMS_MUST_EXIST) {
6a64b644
DDAG
147 error_report("Input validation failed: %s/%s",
148 vmsd->name, field->name);
5bf81c8d 149 return -1;
b6fcfa59
EH
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) {
a5df2a02 158 ret = vmsd->post_load(opaque, version_id);
b6fcfa59 159 }
a5df2a02
DDAG
160 trace_vmstate_load_state_end(vmsd->name, "end", ret);
161 return ret;
b6fcfa59
EH
162}
163
8118f095
AG
164static 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
181static 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
199static 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
212static 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
238static 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
277static 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
df896152
JQ
293
294bool 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
b6fcfa59 304void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
8118f095 305 void *opaque, QJSON *vmdesc)
b6fcfa59
EH
306{
307 VMStateField *field = vmsd->fields;
308
309 if (vmsd->pre_save) {
310 vmsd->pre_save(opaque);
311 }
8118f095
AG
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
b6fcfa59
EH
319 while (field->name) {
320 if (!field->field_exists ||
321 field->field_exists(opaque, vmsd->version_id)) {
f32935ea 322 void *base_addr = vmstate_base_addr(opaque, field, false);
35fc1f71
MT
323 int i, n_elems = vmstate_n_elems(opaque, field);
324 int size = vmstate_size(opaque, field);
8118f095
AG
325 int64_t old_offset, written_bytes;
326 QJSON *vmdesc_loop = vmdesc;
35fc1f71 327
b6fcfa59
EH
328 for (i = 0; i < n_elems; i++) {
329 void *addr = base_addr + size * i;
330
8118f095
AG
331 vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems);
332 old_offset = qemu_ftell_fast(f);
333
b6fcfa59
EH
334 if (field->flags & VMS_ARRAY_OF_POINTER) {
335 addr = *(void **)addr;
336 }
337 if (field->flags & VMS_STRUCT) {
8118f095 338 vmstate_save_state(f, field->vmsd, addr, vmdesc_loop);
b6fcfa59 339 } else {
2c21ee76 340 field->info->put(f, addr, size, field, vmdesc_loop);
b6fcfa59 341 }
8118f095
AG
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 }
b6fcfa59 350 }
5bf81c8d
MT
351 } else {
352 if (field->flags & VMS_MUST_EXIST) {
6a64b644 353 error_report("Output state validation failed: %s/%s",
5bf81c8d
MT
354 vmsd->name, field->name);
355 assert(!(field->flags & VMS_MUST_EXIST));
356 }
b6fcfa59
EH
357 }
358 field++;
359 }
8118f095
AG
360
361 if (vmdesc) {
362 json_end_array(vmdesc);
363 }
364
365 vmstate_subsection_save(f, vmsd, opaque, vmdesc);
b6fcfa59
EH
366}
367
368static const VMStateDescription *
5cd8cada 369vmstate_get_subsection(const VMStateDescription **sub, char *idstr)
b6fcfa59 370{
5cd8cada
JQ
371 while (sub && *sub && (*sub)->needed) {
372 if (strcmp(idstr, (*sub)->name) == 0) {
373 return *sub;
b6fcfa59
EH
374 }
375 sub++;
376 }
377 return NULL;
378}
379
380static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
381 void *opaque)
382{
a5df2a02
DDAG
383 trace_vmstate_subsection_load(vmsd->name);
384
b6fcfa59 385 while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
7c1e52ba 386 char idstr[256], *idstr_ret;
b6fcfa59
EH
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" */
023ad1a6 394 trace_vmstate_subsection_load_bad(vmsd->name, "(short)", "");
b6fcfa59
EH
395 return 0;
396 }
7c1e52ba 397 size = qemu_peek_buffer(f, (uint8_t **)&idstr_ret, len, 2);
b6fcfa59 398 if (size != len) {
023ad1a6 399 trace_vmstate_subsection_load_bad(vmsd->name, "(peek fail)", "");
b6fcfa59
EH
400 return 0;
401 }
7c1e52ba 402 memcpy(idstr, idstr_ret, size);
b6fcfa59
EH
403 idstr[size] = 0;
404
405 if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
023ad1a6
DDAG
406 trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(prefix)");
407 /* it doesn't have a valid subsection name */
b6fcfa59
EH
408 return 0;
409 }
410 sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
411 if (sub_vmsd == NULL) {
023ad1a6 412 trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(lookup)");
b6fcfa59
EH
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) {
023ad1a6 422 trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
b6fcfa59
EH
423 return ret;
424 }
425 }
a5df2a02
DDAG
426
427 trace_vmstate_subsection_load_good(vmsd->name);
b6fcfa59
EH
428 return 0;
429}
430
431static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
8118f095 432 void *opaque, QJSON *vmdesc)
b6fcfa59 433{
5cd8cada 434 const VMStateDescription **sub = vmsd->subsections;
8118f095 435 bool subsection_found = false;
b6fcfa59 436
5cd8cada
JQ
437 while (sub && *sub && (*sub)->needed) {
438 if ((*sub)->needed(opaque)) {
439 const VMStateDescription *vmsd = *sub;
b6fcfa59
EH
440 uint8_t len;
441
8118f095
AG
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
b6fcfa59
EH
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);
8118f095
AG
457 vmstate_save_state(f, vmsd, opaque, vmdesc);
458
459 if (vmdesc) {
460 json_end_object(vmdesc);
461 }
b6fcfa59
EH
462 }
463 sub++;
464 }
8118f095
AG
465
466 if (vmdesc && subsection_found) {
467 json_end_array(vmdesc);
468 }
b6fcfa59
EH
469}
470
471/* bool */
472
2c21ee76 473static int get_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
474{
475 bool *v = pv;
476 *v = qemu_get_byte(f);
477 return 0;
478}
479
2c21ee76
JD
480static int put_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field,
481 QJSON *vmdesc)
b6fcfa59
EH
482{
483 bool *v = pv;
484 qemu_put_byte(f, *v);
2c21ee76 485 return 0;
b6fcfa59
EH
486}
487
488const VMStateInfo vmstate_info_bool = {
489 .name = "bool",
490 .get = get_bool,
491 .put = put_bool,
492};
493
494/* 8 bit int */
495
2c21ee76 496static int get_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
497{
498 int8_t *v = pv;
499 qemu_get_s8s(f, v);
500 return 0;
501}
502
2c21ee76
JD
503static int put_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field,
504 QJSON *vmdesc)
b6fcfa59
EH
505{
506 int8_t *v = pv;
507 qemu_put_s8s(f, v);
2c21ee76 508 return 0;
b6fcfa59
EH
509}
510
511const VMStateInfo vmstate_info_int8 = {
512 .name = "int8",
513 .get = get_int8,
514 .put = put_int8,
515};
516
517/* 16 bit int */
518
2c21ee76 519static int get_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
520{
521 int16_t *v = pv;
522 qemu_get_sbe16s(f, v);
523 return 0;
524}
525
2c21ee76
JD
526static int put_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field,
527 QJSON *vmdesc)
b6fcfa59
EH
528{
529 int16_t *v = pv;
530 qemu_put_sbe16s(f, v);
2c21ee76 531 return 0;
b6fcfa59
EH
532}
533
534const VMStateInfo vmstate_info_int16 = {
535 .name = "int16",
536 .get = get_int16,
537 .put = put_int16,
538};
539
540/* 32 bit int */
541
2c21ee76 542static int get_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
543{
544 int32_t *v = pv;
545 qemu_get_sbe32s(f, v);
546 return 0;
547}
548
2c21ee76
JD
549static int put_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field,
550 QJSON *vmdesc)
b6fcfa59
EH
551{
552 int32_t *v = pv;
553 qemu_put_sbe32s(f, v);
2c21ee76 554 return 0;
b6fcfa59
EH
555}
556
557const 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
2c21ee76
JD
566static int get_int32_equal(QEMUFile *f, void *pv, size_t size,
567 VMStateField *field)
b6fcfa59
EH
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 }
49228e17 576 error_report("%" PRIx32 " != %" PRIx32, *v, v2);
b6fcfa59
EH
577 return -EINVAL;
578}
579
580const VMStateInfo vmstate_info_int32_equal = {
581 .name = "int32 equal",
582 .get = get_int32_equal,
583 .put = put_int32,
584};
585
d2ef4b61
MT
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 */
b6fcfa59 589
2c21ee76 590static int get_int32_le(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59 591{
24a370ef
DDAG
592 int32_t *cur = pv;
593 int32_t loaded;
594 qemu_get_sbe32s(f, &loaded);
b6fcfa59 595
d2ef4b61 596 if (loaded >= 0 && loaded <= *cur) {
24a370ef 597 *cur = loaded;
b6fcfa59
EH
598 return 0;
599 }
49228e17
DDAG
600 error_report("Invalid value %" PRId32
601 " expecting positive value <= %" PRId32,
602 loaded, *cur);
b6fcfa59
EH
603 return -EINVAL;
604}
605
606const VMStateInfo vmstate_info_int32_le = {
24a370ef 607 .name = "int32 le",
b6fcfa59
EH
608 .get = get_int32_le,
609 .put = put_int32,
610};
611
612/* 64 bit int */
613
2c21ee76 614static int get_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
615{
616 int64_t *v = pv;
617 qemu_get_sbe64s(f, v);
618 return 0;
619}
620
2c21ee76
JD
621static int put_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
622 QJSON *vmdesc)
b6fcfa59
EH
623{
624 int64_t *v = pv;
625 qemu_put_sbe64s(f, v);
2c21ee76 626 return 0;
b6fcfa59
EH
627}
628
629const VMStateInfo vmstate_info_int64 = {
630 .name = "int64",
631 .get = get_int64,
632 .put = put_int64,
633};
634
635/* 8 bit unsigned int */
636
2c21ee76 637static int get_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
638{
639 uint8_t *v = pv;
640 qemu_get_8s(f, v);
641 return 0;
642}
643
2c21ee76
JD
644static int put_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field,
645 QJSON *vmdesc)
b6fcfa59
EH
646{
647 uint8_t *v = pv;
648 qemu_put_8s(f, v);
2c21ee76 649 return 0;
b6fcfa59
EH
650}
651
652const VMStateInfo vmstate_info_uint8 = {
653 .name = "uint8",
654 .get = get_uint8,
655 .put = put_uint8,
656};
657
658/* 16 bit unsigned int */
659
2c21ee76 660static int get_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
661{
662 uint16_t *v = pv;
663 qemu_get_be16s(f, v);
664 return 0;
665}
666
2c21ee76
JD
667static int put_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field,
668 QJSON *vmdesc)
b6fcfa59
EH
669{
670 uint16_t *v = pv;
671 qemu_put_be16s(f, v);
2c21ee76 672 return 0;
b6fcfa59
EH
673}
674
675const VMStateInfo vmstate_info_uint16 = {
676 .name = "uint16",
677 .get = get_uint16,
678 .put = put_uint16,
679};
680
681/* 32 bit unsigned int */
682
2c21ee76 683static int get_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
684{
685 uint32_t *v = pv;
686 qemu_get_be32s(f, v);
687 return 0;
688}
689
2c21ee76
JD
690static int put_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field,
691 QJSON *vmdesc)
b6fcfa59
EH
692{
693 uint32_t *v = pv;
694 qemu_put_be32s(f, v);
2c21ee76 695 return 0;
b6fcfa59
EH
696}
697
698const 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
2c21ee76
JD
707static int get_uint32_equal(QEMUFile *f, void *pv, size_t size,
708 VMStateField *field)
b6fcfa59
EH
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 }
49228e17 717 error_report("%" PRIx32 " != %" PRIx32, *v, v2);
b6fcfa59
EH
718 return -EINVAL;
719}
720
721const 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
2c21ee76 729static int get_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
730{
731 uint64_t *v = pv;
732 qemu_get_be64s(f, v);
733 return 0;
734}
735
2c21ee76
JD
736static int put_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
737 QJSON *vmdesc)
b6fcfa59
EH
738{
739 uint64_t *v = pv;
740 qemu_put_be64s(f, v);
2c21ee76 741 return 0;
b6fcfa59
EH
742}
743
744const 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
2c21ee76
JD
753static int get_uint64_equal(QEMUFile *f, void *pv, size_t size,
754 VMStateField *field)
b6fcfa59
EH
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 }
49228e17 763 error_report("%" PRIx64 " != %" PRIx64, *v, v2);
b6fcfa59
EH
764 return -EINVAL;
765}
766
767const 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
2c21ee76
JD
776static int get_uint8_equal(QEMUFile *f, void *pv, size_t size,
777 VMStateField *field)
b6fcfa59
EH
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 }
49228e17 786 error_report("%x != %x", *v, v2);
b6fcfa59
EH
787 return -EINVAL;
788}
789
790const 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
2c21ee76
JD
799static int get_uint16_equal(QEMUFile *f, void *pv, size_t size,
800 VMStateField *field)
b6fcfa59
EH
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 }
49228e17 809 error_report("%x != %x", *v, v2);
b6fcfa59
EH
810 return -EINVAL;
811}
812
813const VMStateInfo vmstate_info_uint16_equal = {
814 .name = "uint16 equal",
815 .get = get_uint16_equal,
816 .put = put_uint16,
817};
818
819/* floating point */
820
2c21ee76
JD
821static int get_float64(QEMUFile *f, void *pv, size_t size,
822 VMStateField *field)
b6fcfa59
EH
823{
824 float64 *v = pv;
825
826 *v = make_float64(qemu_get_be64(f));
827 return 0;
828}
829
2c21ee76
JD
830static int put_float64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
831 QJSON *vmdesc)
b6fcfa59
EH
832{
833 uint64_t *v = pv;
834
835 qemu_put_be64(f, float64_val(*v));
2c21ee76 836 return 0;
b6fcfa59
EH
837}
838
839const VMStateInfo vmstate_info_float64 = {
840 .name = "float64",
841 .get = get_float64,
842 .put = put_float64,
843};
844
55174749
JQ
845/* CPU_DoubleU type */
846
2c21ee76
JD
847static int get_cpudouble(QEMUFile *f, void *pv, size_t size,
848 VMStateField *field)
55174749
JQ
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
2c21ee76
JD
856static int put_cpudouble(QEMUFile *f, void *pv, size_t size,
857 VMStateField *field, QJSON *vmdesc)
55174749
JQ
858{
859 CPU_DoubleU *v = pv;
860 qemu_put_be32s(f, &v->l.upper);
861 qemu_put_be32s(f, &v->l.lower);
2c21ee76 862 return 0;
55174749
JQ
863}
864
865const VMStateInfo vmstate_info_cpudouble = {
866 .name = "CPU_Double_U",
867 .get = get_cpudouble,
868 .put = put_cpudouble,
869};
870
b6fcfa59
EH
871/* uint8_t buffers */
872
2c21ee76
JD
873static int get_buffer(QEMUFile *f, void *pv, size_t size,
874 VMStateField *field)
b6fcfa59
EH
875{
876 uint8_t *v = pv;
877 qemu_get_buffer(f, v, size);
878 return 0;
879}
880
2c21ee76
JD
881static int put_buffer(QEMUFile *f, void *pv, size_t size, VMStateField *field,
882 QJSON *vmdesc)
b6fcfa59
EH
883{
884 uint8_t *v = pv;
885 qemu_put_buffer(f, v, size);
2c21ee76 886 return 0;
b6fcfa59
EH
887}
888
889const 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
2c21ee76
JD
898static int get_unused_buffer(QEMUFile *f, void *pv, size_t size,
899 VMStateField *field)
b6fcfa59
EH
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
2c21ee76
JD
912static int put_unused_buffer(QEMUFile *f, void *pv, size_t size,
913 VMStateField *field, QJSON *vmdesc)
b6fcfa59
EH
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 }
2c21ee76
JD
923
924 return 0;
b6fcfa59
EH
925}
926
927const 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)
2c21ee76 940static int get_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
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
2c21ee76
JD
954static int put_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field,
955 QJSON *vmdesc)
b6fcfa59
EH
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 }
2c21ee76
JD
966
967 return 0;
b6fcfa59
EH
968}
969
970const VMStateInfo vmstate_info_bitmap = {
971 .name = "bitmap",
972 .get = get_bitmap,
973 .put = put_bitmap,
974};
94869d5c
JD
975
976/* get for QTAILQ
977 * meta data about the QTAILQ is encoded in a VMStateField structure
978 */
979static 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 */
1018static 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}
1038const VMStateInfo vmstate_info_qtailq = {
1039 .name = "qtailq",
1040 .get = get_qtailq,
1041 .put = put_qtailq,
1042};