]> git.proxmox.com Git - mirror_qemu.git/blame - migration/vmstate.c
Changing error message of QMP 'migrate_set_downtime' to seconds
[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) {
59046ec2 71 *(void **)base_addr = g_malloc(size);
f32935ea
AK
72 }
73 }
59046ec2 74 base_addr = *(void **)base_addr;
35fc1f71
MT
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
46a02a74
DDAG
309 trace_vmstate_save_state_top(vmsd->name);
310
b6fcfa59
EH
311 if (vmsd->pre_save) {
312 vmsd->pre_save(opaque);
313 }
8118f095
AG
314
315 if (vmdesc) {
316 json_prop_str(vmdesc, "vmsd_name", vmsd->name);
317 json_prop_int(vmdesc, "version", vmsd->version_id);
318 json_start_array(vmdesc, "fields");
319 }
320
b6fcfa59
EH
321 while (field->name) {
322 if (!field->field_exists ||
323 field->field_exists(opaque, vmsd->version_id)) {
f32935ea 324 void *base_addr = vmstate_base_addr(opaque, field, false);
35fc1f71
MT
325 int i, n_elems = vmstate_n_elems(opaque, field);
326 int size = vmstate_size(opaque, field);
8118f095
AG
327 int64_t old_offset, written_bytes;
328 QJSON *vmdesc_loop = vmdesc;
35fc1f71 329
46a02a74 330 trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems);
b6fcfa59
EH
331 for (i = 0; i < n_elems; i++) {
332 void *addr = base_addr + size * i;
333
8118f095
AG
334 vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems);
335 old_offset = qemu_ftell_fast(f);
336
b6fcfa59
EH
337 if (field->flags & VMS_ARRAY_OF_POINTER) {
338 addr = *(void **)addr;
339 }
340 if (field->flags & VMS_STRUCT) {
8118f095 341 vmstate_save_state(f, field->vmsd, addr, vmdesc_loop);
b6fcfa59 342 } else {
2c21ee76 343 field->info->put(f, addr, size, field, vmdesc_loop);
b6fcfa59 344 }
8118f095
AG
345
346 written_bytes = qemu_ftell_fast(f) - old_offset;
347 vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i);
348
349 /* Compressed arrays only care about the first element */
350 if (vmdesc_loop && vmsd_can_compress(field)) {
351 vmdesc_loop = NULL;
352 }
b6fcfa59 353 }
5bf81c8d
MT
354 } else {
355 if (field->flags & VMS_MUST_EXIST) {
6a64b644 356 error_report("Output state validation failed: %s/%s",
5bf81c8d
MT
357 vmsd->name, field->name);
358 assert(!(field->flags & VMS_MUST_EXIST));
359 }
b6fcfa59
EH
360 }
361 field++;
362 }
8118f095
AG
363
364 if (vmdesc) {
365 json_end_array(vmdesc);
366 }
367
368 vmstate_subsection_save(f, vmsd, opaque, vmdesc);
b6fcfa59
EH
369}
370
371static const VMStateDescription *
5cd8cada 372vmstate_get_subsection(const VMStateDescription **sub, char *idstr)
b6fcfa59 373{
5cd8cada
JQ
374 while (sub && *sub && (*sub)->needed) {
375 if (strcmp(idstr, (*sub)->name) == 0) {
376 return *sub;
b6fcfa59
EH
377 }
378 sub++;
379 }
380 return NULL;
381}
382
383static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
384 void *opaque)
385{
a5df2a02
DDAG
386 trace_vmstate_subsection_load(vmsd->name);
387
b6fcfa59 388 while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
7c1e52ba 389 char idstr[256], *idstr_ret;
b6fcfa59
EH
390 int ret;
391 uint8_t version_id, len, size;
392 const VMStateDescription *sub_vmsd;
393
394 len = qemu_peek_byte(f, 1);
395 if (len < strlen(vmsd->name) + 1) {
396 /* subsection name has be be "section_name/a" */
023ad1a6 397 trace_vmstate_subsection_load_bad(vmsd->name, "(short)", "");
b6fcfa59
EH
398 return 0;
399 }
7c1e52ba 400 size = qemu_peek_buffer(f, (uint8_t **)&idstr_ret, len, 2);
b6fcfa59 401 if (size != len) {
023ad1a6 402 trace_vmstate_subsection_load_bad(vmsd->name, "(peek fail)", "");
b6fcfa59
EH
403 return 0;
404 }
7c1e52ba 405 memcpy(idstr, idstr_ret, size);
b6fcfa59
EH
406 idstr[size] = 0;
407
408 if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
023ad1a6
DDAG
409 trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(prefix)");
410 /* it doesn't have a valid subsection name */
b6fcfa59
EH
411 return 0;
412 }
413 sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
414 if (sub_vmsd == NULL) {
023ad1a6 415 trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(lookup)");
b6fcfa59
EH
416 return -ENOENT;
417 }
418 qemu_file_skip(f, 1); /* subsection */
419 qemu_file_skip(f, 1); /* len */
420 qemu_file_skip(f, len); /* idstr */
421 version_id = qemu_get_be32(f);
422
423 ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
424 if (ret) {
023ad1a6 425 trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
b6fcfa59
EH
426 return ret;
427 }
428 }
a5df2a02
DDAG
429
430 trace_vmstate_subsection_load_good(vmsd->name);
b6fcfa59
EH
431 return 0;
432}
433
434static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
8118f095 435 void *opaque, QJSON *vmdesc)
b6fcfa59 436{
5cd8cada 437 const VMStateDescription **sub = vmsd->subsections;
8118f095 438 bool subsection_found = false;
b6fcfa59 439
46a02a74 440 trace_vmstate_subsection_save_top(vmsd->name);
5cd8cada
JQ
441 while (sub && *sub && (*sub)->needed) {
442 if ((*sub)->needed(opaque)) {
46a02a74 443 const VMStateDescription *vmsdsub = *sub;
b6fcfa59
EH
444 uint8_t len;
445
46a02a74 446 trace_vmstate_subsection_save_loop(vmsd->name, vmsdsub->name);
8118f095
AG
447 if (vmdesc) {
448 /* Only create subsection array when we have any */
449 if (!subsection_found) {
450 json_start_array(vmdesc, "subsections");
451 subsection_found = true;
452 }
453
454 json_start_object(vmdesc, NULL);
455 }
456
b6fcfa59 457 qemu_put_byte(f, QEMU_VM_SUBSECTION);
46a02a74 458 len = strlen(vmsdsub->name);
b6fcfa59 459 qemu_put_byte(f, len);
46a02a74
DDAG
460 qemu_put_buffer(f, (uint8_t *)vmsdsub->name, len);
461 qemu_put_be32(f, vmsdsub->version_id);
462 vmstate_save_state(f, vmsdsub, opaque, vmdesc);
8118f095
AG
463
464 if (vmdesc) {
465 json_end_object(vmdesc);
466 }
b6fcfa59
EH
467 }
468 sub++;
469 }
8118f095
AG
470
471 if (vmdesc && subsection_found) {
472 json_end_array(vmdesc);
473 }
b6fcfa59
EH
474}
475
476/* bool */
477
2c21ee76 478static int get_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
479{
480 bool *v = pv;
481 *v = qemu_get_byte(f);
482 return 0;
483}
484
2c21ee76
JD
485static int put_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field,
486 QJSON *vmdesc)
b6fcfa59
EH
487{
488 bool *v = pv;
489 qemu_put_byte(f, *v);
2c21ee76 490 return 0;
b6fcfa59
EH
491}
492
493const VMStateInfo vmstate_info_bool = {
494 .name = "bool",
495 .get = get_bool,
496 .put = put_bool,
497};
498
499/* 8 bit int */
500
2c21ee76 501static int get_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
502{
503 int8_t *v = pv;
504 qemu_get_s8s(f, v);
505 return 0;
506}
507
2c21ee76
JD
508static int put_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field,
509 QJSON *vmdesc)
b6fcfa59
EH
510{
511 int8_t *v = pv;
512 qemu_put_s8s(f, v);
2c21ee76 513 return 0;
b6fcfa59
EH
514}
515
516const VMStateInfo vmstate_info_int8 = {
517 .name = "int8",
518 .get = get_int8,
519 .put = put_int8,
520};
521
522/* 16 bit int */
523
2c21ee76 524static int get_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
525{
526 int16_t *v = pv;
527 qemu_get_sbe16s(f, v);
528 return 0;
529}
530
2c21ee76
JD
531static int put_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field,
532 QJSON *vmdesc)
b6fcfa59
EH
533{
534 int16_t *v = pv;
535 qemu_put_sbe16s(f, v);
2c21ee76 536 return 0;
b6fcfa59
EH
537}
538
539const VMStateInfo vmstate_info_int16 = {
540 .name = "int16",
541 .get = get_int16,
542 .put = put_int16,
543};
544
545/* 32 bit int */
546
2c21ee76 547static int get_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
548{
549 int32_t *v = pv;
550 qemu_get_sbe32s(f, v);
551 return 0;
552}
553
2c21ee76
JD
554static int put_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field,
555 QJSON *vmdesc)
b6fcfa59
EH
556{
557 int32_t *v = pv;
558 qemu_put_sbe32s(f, v);
2c21ee76 559 return 0;
b6fcfa59
EH
560}
561
562const VMStateInfo vmstate_info_int32 = {
563 .name = "int32",
564 .get = get_int32,
565 .put = put_int32,
566};
567
568/* 32 bit int. See that the received value is the same than the one
569 in the field */
570
2c21ee76
JD
571static int get_int32_equal(QEMUFile *f, void *pv, size_t size,
572 VMStateField *field)
b6fcfa59
EH
573{
574 int32_t *v = pv;
575 int32_t v2;
576 qemu_get_sbe32s(f, &v2);
577
578 if (*v == v2) {
579 return 0;
580 }
49228e17 581 error_report("%" PRIx32 " != %" PRIx32, *v, v2);
b6fcfa59
EH
582 return -EINVAL;
583}
584
585const VMStateInfo vmstate_info_int32_equal = {
586 .name = "int32 equal",
587 .get = get_int32_equal,
588 .put = put_int32,
589};
590
d2ef4b61
MT
591/* 32 bit int. Check that the received value is non-negative
592 * and less than or equal to the one in the field.
593 */
b6fcfa59 594
2c21ee76 595static int get_int32_le(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59 596{
24a370ef
DDAG
597 int32_t *cur = pv;
598 int32_t loaded;
599 qemu_get_sbe32s(f, &loaded);
b6fcfa59 600
d2ef4b61 601 if (loaded >= 0 && loaded <= *cur) {
24a370ef 602 *cur = loaded;
b6fcfa59
EH
603 return 0;
604 }
49228e17
DDAG
605 error_report("Invalid value %" PRId32
606 " expecting positive value <= %" PRId32,
607 loaded, *cur);
b6fcfa59
EH
608 return -EINVAL;
609}
610
611const VMStateInfo vmstate_info_int32_le = {
24a370ef 612 .name = "int32 le",
b6fcfa59
EH
613 .get = get_int32_le,
614 .put = put_int32,
615};
616
617/* 64 bit int */
618
2c21ee76 619static int get_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
620{
621 int64_t *v = pv;
622 qemu_get_sbe64s(f, v);
623 return 0;
624}
625
2c21ee76
JD
626static int put_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
627 QJSON *vmdesc)
b6fcfa59
EH
628{
629 int64_t *v = pv;
630 qemu_put_sbe64s(f, v);
2c21ee76 631 return 0;
b6fcfa59
EH
632}
633
634const VMStateInfo vmstate_info_int64 = {
635 .name = "int64",
636 .get = get_int64,
637 .put = put_int64,
638};
639
640/* 8 bit unsigned int */
641
2c21ee76 642static int get_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
643{
644 uint8_t *v = pv;
645 qemu_get_8s(f, v);
646 return 0;
647}
648
2c21ee76
JD
649static int put_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field,
650 QJSON *vmdesc)
b6fcfa59
EH
651{
652 uint8_t *v = pv;
653 qemu_put_8s(f, v);
2c21ee76 654 return 0;
b6fcfa59
EH
655}
656
657const VMStateInfo vmstate_info_uint8 = {
658 .name = "uint8",
659 .get = get_uint8,
660 .put = put_uint8,
661};
662
663/* 16 bit unsigned int */
664
2c21ee76 665static int get_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
666{
667 uint16_t *v = pv;
668 qemu_get_be16s(f, v);
669 return 0;
670}
671
2c21ee76
JD
672static int put_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field,
673 QJSON *vmdesc)
b6fcfa59
EH
674{
675 uint16_t *v = pv;
676 qemu_put_be16s(f, v);
2c21ee76 677 return 0;
b6fcfa59
EH
678}
679
680const VMStateInfo vmstate_info_uint16 = {
681 .name = "uint16",
682 .get = get_uint16,
683 .put = put_uint16,
684};
685
686/* 32 bit unsigned int */
687
2c21ee76 688static int get_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
689{
690 uint32_t *v = pv;
691 qemu_get_be32s(f, v);
692 return 0;
693}
694
2c21ee76
JD
695static int put_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field,
696 QJSON *vmdesc)
b6fcfa59
EH
697{
698 uint32_t *v = pv;
699 qemu_put_be32s(f, v);
2c21ee76 700 return 0;
b6fcfa59
EH
701}
702
703const VMStateInfo vmstate_info_uint32 = {
704 .name = "uint32",
705 .get = get_uint32,
706 .put = put_uint32,
707};
708
709/* 32 bit uint. See that the received value is the same than the one
710 in the field */
711
2c21ee76
JD
712static int get_uint32_equal(QEMUFile *f, void *pv, size_t size,
713 VMStateField *field)
b6fcfa59
EH
714{
715 uint32_t *v = pv;
716 uint32_t v2;
717 qemu_get_be32s(f, &v2);
718
719 if (*v == v2) {
720 return 0;
721 }
49228e17 722 error_report("%" PRIx32 " != %" PRIx32, *v, v2);
b6fcfa59
EH
723 return -EINVAL;
724}
725
726const VMStateInfo vmstate_info_uint32_equal = {
727 .name = "uint32 equal",
728 .get = get_uint32_equal,
729 .put = put_uint32,
730};
731
732/* 64 bit unsigned int */
733
2c21ee76 734static int get_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
735{
736 uint64_t *v = pv;
737 qemu_get_be64s(f, v);
738 return 0;
739}
740
2c21ee76
JD
741static int put_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
742 QJSON *vmdesc)
b6fcfa59
EH
743{
744 uint64_t *v = pv;
745 qemu_put_be64s(f, v);
2c21ee76 746 return 0;
b6fcfa59
EH
747}
748
749const VMStateInfo vmstate_info_uint64 = {
750 .name = "uint64",
751 .get = get_uint64,
752 .put = put_uint64,
753};
754
755/* 64 bit unsigned int. See that the received value is the same than the one
756 in the field */
757
2c21ee76
JD
758static int get_uint64_equal(QEMUFile *f, void *pv, size_t size,
759 VMStateField *field)
b6fcfa59
EH
760{
761 uint64_t *v = pv;
762 uint64_t v2;
763 qemu_get_be64s(f, &v2);
764
765 if (*v == v2) {
766 return 0;
767 }
49228e17 768 error_report("%" PRIx64 " != %" PRIx64, *v, v2);
b6fcfa59
EH
769 return -EINVAL;
770}
771
772const VMStateInfo vmstate_info_uint64_equal = {
773 .name = "int64 equal",
774 .get = get_uint64_equal,
775 .put = put_uint64,
776};
777
778/* 8 bit int. See that the received value is the same than the one
779 in the field */
780
2c21ee76
JD
781static int get_uint8_equal(QEMUFile *f, void *pv, size_t size,
782 VMStateField *field)
b6fcfa59
EH
783{
784 uint8_t *v = pv;
785 uint8_t v2;
786 qemu_get_8s(f, &v2);
787
788 if (*v == v2) {
789 return 0;
790 }
49228e17 791 error_report("%x != %x", *v, v2);
b6fcfa59
EH
792 return -EINVAL;
793}
794
795const VMStateInfo vmstate_info_uint8_equal = {
796 .name = "uint8 equal",
797 .get = get_uint8_equal,
798 .put = put_uint8,
799};
800
801/* 16 bit unsigned int int. See that the received value is the same than the one
802 in the field */
803
2c21ee76
JD
804static int get_uint16_equal(QEMUFile *f, void *pv, size_t size,
805 VMStateField *field)
b6fcfa59
EH
806{
807 uint16_t *v = pv;
808 uint16_t v2;
809 qemu_get_be16s(f, &v2);
810
811 if (*v == v2) {
812 return 0;
813 }
49228e17 814 error_report("%x != %x", *v, v2);
b6fcfa59
EH
815 return -EINVAL;
816}
817
818const VMStateInfo vmstate_info_uint16_equal = {
819 .name = "uint16 equal",
820 .get = get_uint16_equal,
821 .put = put_uint16,
822};
823
824/* floating point */
825
2c21ee76
JD
826static int get_float64(QEMUFile *f, void *pv, size_t size,
827 VMStateField *field)
b6fcfa59
EH
828{
829 float64 *v = pv;
830
831 *v = make_float64(qemu_get_be64(f));
832 return 0;
833}
834
2c21ee76
JD
835static int put_float64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
836 QJSON *vmdesc)
b6fcfa59
EH
837{
838 uint64_t *v = pv;
839
840 qemu_put_be64(f, float64_val(*v));
2c21ee76 841 return 0;
b6fcfa59
EH
842}
843
844const VMStateInfo vmstate_info_float64 = {
845 .name = "float64",
846 .get = get_float64,
847 .put = put_float64,
848};
849
55174749
JQ
850/* CPU_DoubleU type */
851
2c21ee76
JD
852static int get_cpudouble(QEMUFile *f, void *pv, size_t size,
853 VMStateField *field)
55174749
JQ
854{
855 CPU_DoubleU *v = pv;
856 qemu_get_be32s(f, &v->l.upper);
857 qemu_get_be32s(f, &v->l.lower);
858 return 0;
859}
860
2c21ee76
JD
861static int put_cpudouble(QEMUFile *f, void *pv, size_t size,
862 VMStateField *field, QJSON *vmdesc)
55174749
JQ
863{
864 CPU_DoubleU *v = pv;
865 qemu_put_be32s(f, &v->l.upper);
866 qemu_put_be32s(f, &v->l.lower);
2c21ee76 867 return 0;
55174749
JQ
868}
869
870const VMStateInfo vmstate_info_cpudouble = {
871 .name = "CPU_Double_U",
872 .get = get_cpudouble,
873 .put = put_cpudouble,
874};
875
b6fcfa59
EH
876/* uint8_t buffers */
877
2c21ee76
JD
878static int get_buffer(QEMUFile *f, void *pv, size_t size,
879 VMStateField *field)
b6fcfa59
EH
880{
881 uint8_t *v = pv;
882 qemu_get_buffer(f, v, size);
883 return 0;
884}
885
2c21ee76
JD
886static int put_buffer(QEMUFile *f, void *pv, size_t size, VMStateField *field,
887 QJSON *vmdesc)
b6fcfa59
EH
888{
889 uint8_t *v = pv;
890 qemu_put_buffer(f, v, size);
2c21ee76 891 return 0;
b6fcfa59
EH
892}
893
894const VMStateInfo vmstate_info_buffer = {
895 .name = "buffer",
896 .get = get_buffer,
897 .put = put_buffer,
898};
899
900/* unused buffers: space that was used for some fields that are
901 not useful anymore */
902
2c21ee76
JD
903static int get_unused_buffer(QEMUFile *f, void *pv, size_t size,
904 VMStateField *field)
b6fcfa59
EH
905{
906 uint8_t buf[1024];
907 int block_len;
908
909 while (size > 0) {
910 block_len = MIN(sizeof(buf), size);
911 size -= block_len;
912 qemu_get_buffer(f, buf, block_len);
913 }
914 return 0;
915}
916
2c21ee76
JD
917static int put_unused_buffer(QEMUFile *f, void *pv, size_t size,
918 VMStateField *field, QJSON *vmdesc)
b6fcfa59
EH
919{
920 static const uint8_t buf[1024];
921 int block_len;
922
923 while (size > 0) {
924 block_len = MIN(sizeof(buf), size);
925 size -= block_len;
926 qemu_put_buffer(f, buf, block_len);
927 }
2c21ee76
JD
928
929 return 0;
b6fcfa59
EH
930}
931
932const VMStateInfo vmstate_info_unused_buffer = {
933 .name = "unused_buffer",
934 .get = get_unused_buffer,
935 .put = put_unused_buffer,
936};
937
bcf45131
DDAG
938/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
939 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
940 * copy stuff from the parent into the child and do calculations to fill
941 * in fields that don't really exist in the parent but need to be in the
942 * stream.
943 */
944static int get_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field)
945{
946 int ret;
947 const VMStateDescription *vmsd = field->vmsd;
948 int version_id = field->version_id;
949 void *tmp = g_malloc(size);
950
951 /* Writes the parent field which is at the start of the tmp */
952 *(void **)tmp = pv;
953 ret = vmstate_load_state(f, vmsd, tmp, version_id);
954 g_free(tmp);
955 return ret;
956}
957
958static int put_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field,
959 QJSON *vmdesc)
960{
961 const VMStateDescription *vmsd = field->vmsd;
962 void *tmp = g_malloc(size);
963
964 /* Writes the parent field which is at the start of the tmp */
965 *(void **)tmp = pv;
966 vmstate_save_state(f, vmsd, tmp, vmdesc);
967 g_free(tmp);
968
969 return 0;
970}
971
972const VMStateInfo vmstate_info_tmp = {
973 .name = "tmp",
974 .get = get_tmp,
975 .put = put_tmp,
976};
977
b6fcfa59
EH
978/* bitmaps (as defined by bitmap.h). Note that size here is the size
979 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
980 * bit words with the bits in big endian order. The in-memory format
981 * is an array of 'unsigned long', which may be either 32 or 64 bits.
982 */
983/* This is the number of 64 bit words sent over the wire */
984#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
2c21ee76 985static int get_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
986{
987 unsigned long *bmp = pv;
988 int i, idx = 0;
989 for (i = 0; i < BITS_TO_U64S(size); i++) {
990 uint64_t w = qemu_get_be64(f);
991 bmp[idx++] = w;
992 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
993 bmp[idx++] = w >> 32;
994 }
995 }
996 return 0;
997}
998
2c21ee76
JD
999static int put_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field,
1000 QJSON *vmdesc)
b6fcfa59
EH
1001{
1002 unsigned long *bmp = pv;
1003 int i, idx = 0;
1004 for (i = 0; i < BITS_TO_U64S(size); i++) {
1005 uint64_t w = bmp[idx++];
1006 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
1007 w |= ((uint64_t)bmp[idx++]) << 32;
1008 }
1009 qemu_put_be64(f, w);
1010 }
2c21ee76
JD
1011
1012 return 0;
b6fcfa59
EH
1013}
1014
1015const VMStateInfo vmstate_info_bitmap = {
1016 .name = "bitmap",
1017 .get = get_bitmap,
1018 .put = put_bitmap,
1019};
94869d5c
JD
1020
1021/* get for QTAILQ
1022 * meta data about the QTAILQ is encoded in a VMStateField structure
1023 */
1024static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size,
1025 VMStateField *field)
1026{
1027 int ret = 0;
1028 const VMStateDescription *vmsd = field->vmsd;
1029 /* size of a QTAILQ element */
1030 size_t size = field->size;
1031 /* offset of the QTAILQ entry in a QTAILQ element */
1032 size_t entry_offset = field->start;
1033 int version_id = field->version_id;
1034 void *elm;
1035
1036 trace_get_qtailq(vmsd->name, version_id);
1037 if (version_id > vmsd->version_id) {
1038 error_report("%s %s", vmsd->name, "too new");
1039 trace_get_qtailq_end(vmsd->name, "too new", -EINVAL);
1040
1041 return -EINVAL;
1042 }
1043 if (version_id < vmsd->minimum_version_id) {
1044 error_report("%s %s", vmsd->name, "too old");
1045 trace_get_qtailq_end(vmsd->name, "too old", -EINVAL);
1046 return -EINVAL;
1047 }
1048
1049 while (qemu_get_byte(f)) {
1050 elm = g_malloc(size);
1051 ret = vmstate_load_state(f, vmsd, elm, version_id);
1052 if (ret) {
1053 return ret;
1054 }
1055 QTAILQ_RAW_INSERT_TAIL(pv, elm, entry_offset);
1056 }
1057
1058 trace_get_qtailq_end(vmsd->name, "end", ret);
1059 return ret;
1060}
1061
1062/* put for QTAILQ */
1063static int put_qtailq(QEMUFile *f, void *pv, size_t unused_size,
1064 VMStateField *field, QJSON *vmdesc)
1065{
1066 const VMStateDescription *vmsd = field->vmsd;
1067 /* offset of the QTAILQ entry in a QTAILQ element*/
1068 size_t entry_offset = field->start;
1069 void *elm;
1070
1071 trace_put_qtailq(vmsd->name, vmsd->version_id);
1072
1073 QTAILQ_RAW_FOREACH(elm, pv, entry_offset) {
1074 qemu_put_byte(f, true);
1075 vmstate_save_state(f, vmsd, elm, vmdesc);
1076 }
1077 qemu_put_byte(f, false);
1078
1079 trace_put_qtailq_end(vmsd->name, "end");
1080
1081 return 0;
1082}
1083const VMStateInfo vmstate_info_qtailq = {
1084 .name = "qtailq",
1085 .get = get_qtailq,
1086 .put = put_qtailq,
1087};