]> git.proxmox.com Git - mirror_qemu.git/blame - migration/vmstate.c
block: add missed aio_context_acquire into release_drive
[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
cbfda0e6 55static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque)
35fc1f71 56{
cbfda0e6
HP
57 if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {
58 gsize size = vmstate_size(opaque, field);
59 size *= vmstate_n_elems(opaque, field);
60 if (size) {
61 *(void **)ptr = g_malloc(size);
f32935ea 62 }
35fc1f71 63 }
35fc1f71
MT
64}
65
b6fcfa59
EH
66int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
67 void *opaque, int version_id)
68{
69 VMStateField *field = vmsd->fields;
a5df2a02 70 int ret = 0;
b6fcfa59 71
a5df2a02 72 trace_vmstate_load_state(vmsd->name, version_id);
b6fcfa59 73 if (version_id > vmsd->version_id) {
cde7ee59
JD
74 error_report("%s: incoming version_id %d is too new "
75 "for local version_id %d",
76 vmsd->name, version_id, vmsd->version_id);
a5df2a02 77 trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
b6fcfa59
EH
78 return -EINVAL;
79 }
b6fcfa59 80 if (version_id < vmsd->minimum_version_id) {
767adce2
PM
81 if (vmsd->load_state_old &&
82 version_id >= vmsd->minimum_version_id_old) {
a5df2a02
DDAG
83 ret = vmsd->load_state_old(f, opaque, version_id);
84 trace_vmstate_load_state_end(vmsd->name, "old path", ret);
85 return ret;
767adce2 86 }
cde7ee59
JD
87 error_report("%s: incoming version_id %d is too old "
88 "for local minimum version_id %d",
89 vmsd->name, version_id, vmsd->minimum_version_id);
a5df2a02 90 trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
767adce2 91 return -EINVAL;
b6fcfa59
EH
92 }
93 if (vmsd->pre_load) {
94 int ret = vmsd->pre_load(opaque);
95 if (ret) {
96 return ret;
97 }
98 }
99 while (field->name) {
a5df2a02 100 trace_vmstate_load_state_field(vmsd->name, field->name);
b6fcfa59
EH
101 if ((field->field_exists &&
102 field->field_exists(opaque, version_id)) ||
103 (!field->field_exists &&
104 field->version_id <= version_id)) {
cbfda0e6 105 void *first_elem = opaque + field->offset;
35fc1f71
MT
106 int i, n_elems = vmstate_n_elems(opaque, field);
107 int size = vmstate_size(opaque, field);
108
cbfda0e6
HP
109 vmstate_handle_alloc(first_elem, field, opaque);
110 if (field->flags & VMS_POINTER) {
111 first_elem = *(void **)first_elem;
e1e686c1 112 assert(first_elem || !n_elems || !size);
cbfda0e6 113 }
b6fcfa59 114 for (i = 0; i < n_elems; i++) {
e84641f7 115 void *curr_elem = first_elem + size * i;
b6fcfa59
EH
116
117 if (field->flags & VMS_ARRAY_OF_POINTER) {
e84641f7 118 curr_elem = *(void **)curr_elem;
b6fcfa59 119 }
e1e686c1 120 if (!curr_elem && size) {
07d4e691
HP
121 /* if null pointer check placeholder and do not follow */
122 assert(field->flags & VMS_ARRAY_OF_POINTER);
123 ret = vmstate_info_nullptr.get(f, curr_elem, size, NULL);
124 } else if (field->flags & VMS_STRUCT) {
e84641f7 125 ret = vmstate_load_state(f, field->vmsd, curr_elem,
b6fcfa59
EH
126 field->vmsd->version_id);
127 } else {
e84641f7 128 ret = field->info->get(f, curr_elem, size, field);
b6fcfa59 129 }
13cde508
JQ
130 if (ret >= 0) {
131 ret = qemu_file_get_error(f);
132 }
b6fcfa59 133 if (ret < 0) {
13cde508 134 qemu_file_set_error(f, ret);
a1771070
DDAG
135 error_report("Failed to load %s:%s", vmsd->name,
136 field->name);
9013dca5 137 trace_vmstate_load_field_error(field->name, ret);
b6fcfa59
EH
138 return ret;
139 }
140 }
5bf81c8d 141 } else if (field->flags & VMS_MUST_EXIST) {
6a64b644
DDAG
142 error_report("Input validation failed: %s/%s",
143 vmsd->name, field->name);
5bf81c8d 144 return -1;
b6fcfa59
EH
145 }
146 field++;
147 }
148 ret = vmstate_subsection_load(f, vmsd, opaque);
149 if (ret != 0) {
150 return ret;
151 }
152 if (vmsd->post_load) {
a5df2a02 153 ret = vmsd->post_load(opaque, version_id);
b6fcfa59 154 }
a5df2a02
DDAG
155 trace_vmstate_load_state_end(vmsd->name, "end", ret);
156 return ret;
b6fcfa59
EH
157}
158
8118f095
AG
159static int vmfield_name_num(VMStateField *start, VMStateField *search)
160{
161 VMStateField *field;
162 int found = 0;
163
164 for (field = start; field->name; field++) {
165 if (!strcmp(field->name, search->name)) {
166 if (field == search) {
167 return found;
168 }
169 found++;
170 }
171 }
172
173 return -1;
174}
175
176static bool vmfield_name_is_unique(VMStateField *start, VMStateField *search)
177{
178 VMStateField *field;
179 int found = 0;
180
181 for (field = start; field->name; field++) {
182 if (!strcmp(field->name, search->name)) {
183 found++;
184 /* name found more than once, so it's not unique */
185 if (found > 1) {
186 return false;
187 }
188 }
189 }
190
191 return true;
192}
193
194static const char *vmfield_get_type_name(VMStateField *field)
195{
196 const char *type = "unknown";
197
198 if (field->flags & VMS_STRUCT) {
199 type = "struct";
200 } else if (field->info->name) {
201 type = field->info->name;
202 }
203
204 return type;
205}
206
207static bool vmsd_can_compress(VMStateField *field)
208{
209 if (field->field_exists) {
210 /* Dynamically existing fields mess up compression */
211 return false;
212 }
213
214 if (field->flags & VMS_STRUCT) {
215 VMStateField *sfield = field->vmsd->fields;
216 while (sfield->name) {
217 if (!vmsd_can_compress(sfield)) {
218 /* Child elements can't compress, so can't we */
219 return false;
220 }
221 sfield++;
222 }
223
224 if (field->vmsd->subsections) {
225 /* Subsections may come and go, better don't compress */
226 return false;
227 }
228 }
229
230 return true;
231}
232
233static void vmsd_desc_field_start(const VMStateDescription *vmsd, QJSON *vmdesc,
234 VMStateField *field, int i, int max)
235{
236 char *name, *old_name;
237 bool is_array = max > 1;
238 bool can_compress = vmsd_can_compress(field);
239
240 if (!vmdesc) {
241 return;
242 }
243
244 name = g_strdup(field->name);
245
246 /* Field name is not unique, need to make it unique */
247 if (!vmfield_name_is_unique(vmsd->fields, field)) {
248 int num = vmfield_name_num(vmsd->fields, field);
249 old_name = name;
250 name = g_strdup_printf("%s[%d]", name, num);
251 g_free(old_name);
252 }
253
254 json_start_object(vmdesc, NULL);
255 json_prop_str(vmdesc, "name", name);
256 if (is_array) {
257 if (can_compress) {
258 json_prop_int(vmdesc, "array_len", max);
259 } else {
260 json_prop_int(vmdesc, "index", i);
261 }
262 }
263 json_prop_str(vmdesc, "type", vmfield_get_type_name(field));
264
265 if (field->flags & VMS_STRUCT) {
266 json_start_object(vmdesc, "struct");
267 }
268
269 g_free(name);
270}
271
272static void vmsd_desc_field_end(const VMStateDescription *vmsd, QJSON *vmdesc,
273 VMStateField *field, size_t size, int i)
274{
275 if (!vmdesc) {
276 return;
277 }
278
279 if (field->flags & VMS_STRUCT) {
280 /* We printed a struct in between, close its child object */
281 json_end_object(vmdesc);
282 }
283
284 json_prop_int(vmdesc, "size", size);
285 json_end_object(vmdesc);
286}
287
df896152
JQ
288
289bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque)
290{
291 if (vmsd->needed && !vmsd->needed(opaque)) {
292 /* optional section not needed */
293 return false;
294 }
295 return true;
296}
297
298
b6fcfa59 299void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
8118f095 300 void *opaque, QJSON *vmdesc)
b6fcfa59
EH
301{
302 VMStateField *field = vmsd->fields;
303
46a02a74
DDAG
304 trace_vmstate_save_state_top(vmsd->name);
305
b6fcfa59
EH
306 if (vmsd->pre_save) {
307 vmsd->pre_save(opaque);
308 }
8118f095
AG
309
310 if (vmdesc) {
311 json_prop_str(vmdesc, "vmsd_name", vmsd->name);
312 json_prop_int(vmdesc, "version", vmsd->version_id);
313 json_start_array(vmdesc, "fields");
314 }
315
b6fcfa59
EH
316 while (field->name) {
317 if (!field->field_exists ||
318 field->field_exists(opaque, vmsd->version_id)) {
cbfda0e6 319 void *first_elem = opaque + field->offset;
35fc1f71
MT
320 int i, n_elems = vmstate_n_elems(opaque, field);
321 int size = vmstate_size(opaque, field);
8118f095
AG
322 int64_t old_offset, written_bytes;
323 QJSON *vmdesc_loop = vmdesc;
35fc1f71 324
46a02a74 325 trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems);
cbfda0e6
HP
326 if (field->flags & VMS_POINTER) {
327 first_elem = *(void **)first_elem;
e1e686c1 328 assert(first_elem || !n_elems || !size);
cbfda0e6 329 }
b6fcfa59 330 for (i = 0; i < n_elems; i++) {
e84641f7 331 void *curr_elem = first_elem + size * i;
b6fcfa59 332
8118f095
AG
333 vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems);
334 old_offset = qemu_ftell_fast(f);
b6fcfa59 335 if (field->flags & VMS_ARRAY_OF_POINTER) {
e84641f7
HP
336 assert(curr_elem);
337 curr_elem = *(void **)curr_elem;
b6fcfa59 338 }
e1e686c1 339 if (!curr_elem && size) {
07d4e691
HP
340 /* if null pointer write placeholder and do not follow */
341 assert(field->flags & VMS_ARRAY_OF_POINTER);
342 vmstate_info_nullptr.put(f, curr_elem, size, NULL, NULL);
343 } else if (field->flags & VMS_STRUCT) {
e84641f7 344 vmstate_save_state(f, field->vmsd, curr_elem, vmdesc_loop);
b6fcfa59 345 } else {
e84641f7 346 field->info->put(f, curr_elem, size, field, vmdesc_loop);
b6fcfa59 347 }
8118f095
AG
348
349 written_bytes = qemu_ftell_fast(f) - old_offset;
350 vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i);
351
352 /* Compressed arrays only care about the first element */
353 if (vmdesc_loop && vmsd_can_compress(field)) {
354 vmdesc_loop = NULL;
355 }
b6fcfa59 356 }
5bf81c8d
MT
357 } else {
358 if (field->flags & VMS_MUST_EXIST) {
6a64b644 359 error_report("Output state validation failed: %s/%s",
5bf81c8d
MT
360 vmsd->name, field->name);
361 assert(!(field->flags & VMS_MUST_EXIST));
362 }
b6fcfa59
EH
363 }
364 field++;
365 }
8118f095
AG
366
367 if (vmdesc) {
368 json_end_array(vmdesc);
369 }
370
371 vmstate_subsection_save(f, vmsd, opaque, vmdesc);
b6fcfa59
EH
372}
373
374static const VMStateDescription *
5cd8cada 375vmstate_get_subsection(const VMStateDescription **sub, char *idstr)
b6fcfa59 376{
5cd8cada
JQ
377 while (sub && *sub && (*sub)->needed) {
378 if (strcmp(idstr, (*sub)->name) == 0) {
379 return *sub;
b6fcfa59
EH
380 }
381 sub++;
382 }
383 return NULL;
384}
385
386static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
387 void *opaque)
388{
a5df2a02
DDAG
389 trace_vmstate_subsection_load(vmsd->name);
390
b6fcfa59 391 while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
7c1e52ba 392 char idstr[256], *idstr_ret;
b6fcfa59
EH
393 int ret;
394 uint8_t version_id, len, size;
395 const VMStateDescription *sub_vmsd;
396
397 len = qemu_peek_byte(f, 1);
398 if (len < strlen(vmsd->name) + 1) {
399 /* subsection name has be be "section_name/a" */
023ad1a6 400 trace_vmstate_subsection_load_bad(vmsd->name, "(short)", "");
b6fcfa59
EH
401 return 0;
402 }
7c1e52ba 403 size = qemu_peek_buffer(f, (uint8_t **)&idstr_ret, len, 2);
b6fcfa59 404 if (size != len) {
023ad1a6 405 trace_vmstate_subsection_load_bad(vmsd->name, "(peek fail)", "");
b6fcfa59
EH
406 return 0;
407 }
7c1e52ba 408 memcpy(idstr, idstr_ret, size);
b6fcfa59
EH
409 idstr[size] = 0;
410
411 if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
023ad1a6
DDAG
412 trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(prefix)");
413 /* it doesn't have a valid subsection name */
b6fcfa59
EH
414 return 0;
415 }
416 sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
417 if (sub_vmsd == NULL) {
023ad1a6 418 trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(lookup)");
b6fcfa59
EH
419 return -ENOENT;
420 }
421 qemu_file_skip(f, 1); /* subsection */
422 qemu_file_skip(f, 1); /* len */
423 qemu_file_skip(f, len); /* idstr */
424 version_id = qemu_get_be32(f);
425
426 ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
427 if (ret) {
023ad1a6 428 trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
b6fcfa59
EH
429 return ret;
430 }
431 }
a5df2a02
DDAG
432
433 trace_vmstate_subsection_load_good(vmsd->name);
b6fcfa59
EH
434 return 0;
435}
436
437static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
8118f095 438 void *opaque, QJSON *vmdesc)
b6fcfa59 439{
5cd8cada 440 const VMStateDescription **sub = vmsd->subsections;
8118f095 441 bool subsection_found = false;
b6fcfa59 442
46a02a74 443 trace_vmstate_subsection_save_top(vmsd->name);
5cd8cada
JQ
444 while (sub && *sub && (*sub)->needed) {
445 if ((*sub)->needed(opaque)) {
46a02a74 446 const VMStateDescription *vmsdsub = *sub;
b6fcfa59
EH
447 uint8_t len;
448
46a02a74 449 trace_vmstate_subsection_save_loop(vmsd->name, vmsdsub->name);
8118f095
AG
450 if (vmdesc) {
451 /* Only create subsection array when we have any */
452 if (!subsection_found) {
453 json_start_array(vmdesc, "subsections");
454 subsection_found = true;
455 }
456
457 json_start_object(vmdesc, NULL);
458 }
459
b6fcfa59 460 qemu_put_byte(f, QEMU_VM_SUBSECTION);
46a02a74 461 len = strlen(vmsdsub->name);
b6fcfa59 462 qemu_put_byte(f, len);
46a02a74
DDAG
463 qemu_put_buffer(f, (uint8_t *)vmsdsub->name, len);
464 qemu_put_be32(f, vmsdsub->version_id);
465 vmstate_save_state(f, vmsdsub, opaque, vmdesc);
8118f095
AG
466
467 if (vmdesc) {
468 json_end_object(vmdesc);
469 }
b6fcfa59
EH
470 }
471 sub++;
472 }
8118f095
AG
473
474 if (vmdesc && subsection_found) {
475 json_end_array(vmdesc);
476 }
b6fcfa59
EH
477}
478
479/* bool */
480
2c21ee76 481static int get_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
482{
483 bool *v = pv;
484 *v = qemu_get_byte(f);
485 return 0;
486}
487
2c21ee76
JD
488static int put_bool(QEMUFile *f, void *pv, size_t size, VMStateField *field,
489 QJSON *vmdesc)
b6fcfa59
EH
490{
491 bool *v = pv;
492 qemu_put_byte(f, *v);
2c21ee76 493 return 0;
b6fcfa59
EH
494}
495
496const VMStateInfo vmstate_info_bool = {
497 .name = "bool",
498 .get = get_bool,
499 .put = put_bool,
500};
501
502/* 8 bit int */
503
2c21ee76 504static int get_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
505{
506 int8_t *v = pv;
507 qemu_get_s8s(f, v);
508 return 0;
509}
510
2c21ee76
JD
511static int put_int8(QEMUFile *f, void *pv, size_t size, VMStateField *field,
512 QJSON *vmdesc)
b6fcfa59
EH
513{
514 int8_t *v = pv;
515 qemu_put_s8s(f, v);
2c21ee76 516 return 0;
b6fcfa59
EH
517}
518
519const VMStateInfo vmstate_info_int8 = {
520 .name = "int8",
521 .get = get_int8,
522 .put = put_int8,
523};
524
525/* 16 bit int */
526
2c21ee76 527static int get_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
528{
529 int16_t *v = pv;
530 qemu_get_sbe16s(f, v);
531 return 0;
532}
533
2c21ee76
JD
534static int put_int16(QEMUFile *f, void *pv, size_t size, VMStateField *field,
535 QJSON *vmdesc)
b6fcfa59
EH
536{
537 int16_t *v = pv;
538 qemu_put_sbe16s(f, v);
2c21ee76 539 return 0;
b6fcfa59
EH
540}
541
542const VMStateInfo vmstate_info_int16 = {
543 .name = "int16",
544 .get = get_int16,
545 .put = put_int16,
546};
547
548/* 32 bit int */
549
2c21ee76 550static int get_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
551{
552 int32_t *v = pv;
553 qemu_get_sbe32s(f, v);
554 return 0;
555}
556
2c21ee76
JD
557static int put_int32(QEMUFile *f, void *pv, size_t size, VMStateField *field,
558 QJSON *vmdesc)
b6fcfa59
EH
559{
560 int32_t *v = pv;
561 qemu_put_sbe32s(f, v);
2c21ee76 562 return 0;
b6fcfa59
EH
563}
564
565const VMStateInfo vmstate_info_int32 = {
566 .name = "int32",
567 .get = get_int32,
568 .put = put_int32,
569};
570
571/* 32 bit int. See that the received value is the same than the one
572 in the field */
573
2c21ee76
JD
574static int get_int32_equal(QEMUFile *f, void *pv, size_t size,
575 VMStateField *field)
b6fcfa59
EH
576{
577 int32_t *v = pv;
578 int32_t v2;
579 qemu_get_sbe32s(f, &v2);
580
581 if (*v == v2) {
582 return 0;
583 }
49228e17 584 error_report("%" PRIx32 " != %" PRIx32, *v, v2);
b6fcfa59
EH
585 return -EINVAL;
586}
587
588const VMStateInfo vmstate_info_int32_equal = {
589 .name = "int32 equal",
590 .get = get_int32_equal,
591 .put = put_int32,
592};
593
d2ef4b61
MT
594/* 32 bit int. Check that the received value is non-negative
595 * and less than or equal to the one in the field.
596 */
b6fcfa59 597
2c21ee76 598static int get_int32_le(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59 599{
24a370ef
DDAG
600 int32_t *cur = pv;
601 int32_t loaded;
602 qemu_get_sbe32s(f, &loaded);
b6fcfa59 603
d2ef4b61 604 if (loaded >= 0 && loaded <= *cur) {
24a370ef 605 *cur = loaded;
b6fcfa59
EH
606 return 0;
607 }
49228e17
DDAG
608 error_report("Invalid value %" PRId32
609 " expecting positive value <= %" PRId32,
610 loaded, *cur);
b6fcfa59
EH
611 return -EINVAL;
612}
613
614const VMStateInfo vmstate_info_int32_le = {
24a370ef 615 .name = "int32 le",
b6fcfa59
EH
616 .get = get_int32_le,
617 .put = put_int32,
618};
619
620/* 64 bit int */
621
2c21ee76 622static int get_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
623{
624 int64_t *v = pv;
625 qemu_get_sbe64s(f, v);
626 return 0;
627}
628
2c21ee76
JD
629static int put_int64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
630 QJSON *vmdesc)
b6fcfa59
EH
631{
632 int64_t *v = pv;
633 qemu_put_sbe64s(f, v);
2c21ee76 634 return 0;
b6fcfa59
EH
635}
636
637const VMStateInfo vmstate_info_int64 = {
638 .name = "int64",
639 .get = get_int64,
640 .put = put_int64,
641};
642
643/* 8 bit unsigned int */
644
2c21ee76 645static int get_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
646{
647 uint8_t *v = pv;
648 qemu_get_8s(f, v);
649 return 0;
650}
651
2c21ee76
JD
652static int put_uint8(QEMUFile *f, void *pv, size_t size, VMStateField *field,
653 QJSON *vmdesc)
b6fcfa59
EH
654{
655 uint8_t *v = pv;
656 qemu_put_8s(f, v);
2c21ee76 657 return 0;
b6fcfa59
EH
658}
659
660const VMStateInfo vmstate_info_uint8 = {
661 .name = "uint8",
662 .get = get_uint8,
663 .put = put_uint8,
664};
665
666/* 16 bit unsigned int */
667
2c21ee76 668static int get_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
669{
670 uint16_t *v = pv;
671 qemu_get_be16s(f, v);
672 return 0;
673}
674
2c21ee76
JD
675static int put_uint16(QEMUFile *f, void *pv, size_t size, VMStateField *field,
676 QJSON *vmdesc)
b6fcfa59
EH
677{
678 uint16_t *v = pv;
679 qemu_put_be16s(f, v);
2c21ee76 680 return 0;
b6fcfa59
EH
681}
682
683const VMStateInfo vmstate_info_uint16 = {
684 .name = "uint16",
685 .get = get_uint16,
686 .put = put_uint16,
687};
688
689/* 32 bit unsigned int */
690
2c21ee76 691static int get_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
692{
693 uint32_t *v = pv;
694 qemu_get_be32s(f, v);
695 return 0;
696}
697
2c21ee76
JD
698static int put_uint32(QEMUFile *f, void *pv, size_t size, VMStateField *field,
699 QJSON *vmdesc)
b6fcfa59
EH
700{
701 uint32_t *v = pv;
702 qemu_put_be32s(f, v);
2c21ee76 703 return 0;
b6fcfa59
EH
704}
705
706const VMStateInfo vmstate_info_uint32 = {
707 .name = "uint32",
708 .get = get_uint32,
709 .put = put_uint32,
710};
711
712/* 32 bit uint. See that the received value is the same than the one
713 in the field */
714
2c21ee76
JD
715static int get_uint32_equal(QEMUFile *f, void *pv, size_t size,
716 VMStateField *field)
b6fcfa59
EH
717{
718 uint32_t *v = pv;
719 uint32_t v2;
720 qemu_get_be32s(f, &v2);
721
722 if (*v == v2) {
723 return 0;
724 }
49228e17 725 error_report("%" PRIx32 " != %" PRIx32, *v, v2);
b6fcfa59
EH
726 return -EINVAL;
727}
728
729const VMStateInfo vmstate_info_uint32_equal = {
730 .name = "uint32 equal",
731 .get = get_uint32_equal,
732 .put = put_uint32,
733};
734
735/* 64 bit unsigned int */
736
2c21ee76 737static int get_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
738{
739 uint64_t *v = pv;
740 qemu_get_be64s(f, v);
741 return 0;
742}
743
2c21ee76
JD
744static int put_uint64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
745 QJSON *vmdesc)
b6fcfa59
EH
746{
747 uint64_t *v = pv;
748 qemu_put_be64s(f, v);
2c21ee76 749 return 0;
b6fcfa59
EH
750}
751
752const VMStateInfo vmstate_info_uint64 = {
753 .name = "uint64",
754 .get = get_uint64,
755 .put = put_uint64,
756};
757
07d4e691
HP
758static int get_nullptr(QEMUFile *f, void *pv, size_t size, VMStateField *field)
759
760{
761 if (qemu_get_byte(f) == VMS_NULLPTR_MARKER) {
762 return 0;
763 }
764 error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
765 return -EINVAL;
766}
767
768static int put_nullptr(QEMUFile *f, void *pv, size_t size,
769 VMStateField *field, QJSON *vmdesc)
770
771{
772 if (pv == NULL) {
773 qemu_put_byte(f, VMS_NULLPTR_MARKER);
774 return 0;
775 }
776 error_report("vmstate: put_nullptr must be called with pv == NULL");
777 return -EINVAL;
778}
779
780const VMStateInfo vmstate_info_nullptr = {
781 .name = "uint64",
782 .get = get_nullptr,
783 .put = put_nullptr,
784};
785
b6fcfa59
EH
786/* 64 bit unsigned int. See that the received value is the same than the one
787 in the field */
788
2c21ee76
JD
789static int get_uint64_equal(QEMUFile *f, void *pv, size_t size,
790 VMStateField *field)
b6fcfa59
EH
791{
792 uint64_t *v = pv;
793 uint64_t v2;
794 qemu_get_be64s(f, &v2);
795
796 if (*v == v2) {
797 return 0;
798 }
49228e17 799 error_report("%" PRIx64 " != %" PRIx64, *v, v2);
b6fcfa59
EH
800 return -EINVAL;
801}
802
803const VMStateInfo vmstate_info_uint64_equal = {
804 .name = "int64 equal",
805 .get = get_uint64_equal,
806 .put = put_uint64,
807};
808
809/* 8 bit int. See that the received value is the same than the one
810 in the field */
811
2c21ee76
JD
812static int get_uint8_equal(QEMUFile *f, void *pv, size_t size,
813 VMStateField *field)
b6fcfa59
EH
814{
815 uint8_t *v = pv;
816 uint8_t v2;
817 qemu_get_8s(f, &v2);
818
819 if (*v == v2) {
820 return 0;
821 }
49228e17 822 error_report("%x != %x", *v, v2);
b6fcfa59
EH
823 return -EINVAL;
824}
825
826const VMStateInfo vmstate_info_uint8_equal = {
827 .name = "uint8 equal",
828 .get = get_uint8_equal,
829 .put = put_uint8,
830};
831
832/* 16 bit unsigned int int. See that the received value is the same than the one
833 in the field */
834
2c21ee76
JD
835static int get_uint16_equal(QEMUFile *f, void *pv, size_t size,
836 VMStateField *field)
b6fcfa59
EH
837{
838 uint16_t *v = pv;
839 uint16_t v2;
840 qemu_get_be16s(f, &v2);
841
842 if (*v == v2) {
843 return 0;
844 }
49228e17 845 error_report("%x != %x", *v, v2);
b6fcfa59
EH
846 return -EINVAL;
847}
848
849const VMStateInfo vmstate_info_uint16_equal = {
850 .name = "uint16 equal",
851 .get = get_uint16_equal,
852 .put = put_uint16,
853};
854
855/* floating point */
856
2c21ee76
JD
857static int get_float64(QEMUFile *f, void *pv, size_t size,
858 VMStateField *field)
b6fcfa59
EH
859{
860 float64 *v = pv;
861
862 *v = make_float64(qemu_get_be64(f));
863 return 0;
864}
865
2c21ee76
JD
866static int put_float64(QEMUFile *f, void *pv, size_t size, VMStateField *field,
867 QJSON *vmdesc)
b6fcfa59
EH
868{
869 uint64_t *v = pv;
870
871 qemu_put_be64(f, float64_val(*v));
2c21ee76 872 return 0;
b6fcfa59
EH
873}
874
875const VMStateInfo vmstate_info_float64 = {
876 .name = "float64",
877 .get = get_float64,
878 .put = put_float64,
879};
880
55174749
JQ
881/* CPU_DoubleU type */
882
2c21ee76
JD
883static int get_cpudouble(QEMUFile *f, void *pv, size_t size,
884 VMStateField *field)
55174749
JQ
885{
886 CPU_DoubleU *v = pv;
887 qemu_get_be32s(f, &v->l.upper);
888 qemu_get_be32s(f, &v->l.lower);
889 return 0;
890}
891
2c21ee76
JD
892static int put_cpudouble(QEMUFile *f, void *pv, size_t size,
893 VMStateField *field, QJSON *vmdesc)
55174749
JQ
894{
895 CPU_DoubleU *v = pv;
896 qemu_put_be32s(f, &v->l.upper);
897 qemu_put_be32s(f, &v->l.lower);
2c21ee76 898 return 0;
55174749
JQ
899}
900
901const VMStateInfo vmstate_info_cpudouble = {
902 .name = "CPU_Double_U",
903 .get = get_cpudouble,
904 .put = put_cpudouble,
905};
906
b6fcfa59
EH
907/* uint8_t buffers */
908
2c21ee76
JD
909static int get_buffer(QEMUFile *f, void *pv, size_t size,
910 VMStateField *field)
b6fcfa59
EH
911{
912 uint8_t *v = pv;
913 qemu_get_buffer(f, v, size);
914 return 0;
915}
916
2c21ee76
JD
917static int put_buffer(QEMUFile *f, void *pv, size_t size, VMStateField *field,
918 QJSON *vmdesc)
b6fcfa59
EH
919{
920 uint8_t *v = pv;
921 qemu_put_buffer(f, v, size);
2c21ee76 922 return 0;
b6fcfa59
EH
923}
924
925const VMStateInfo vmstate_info_buffer = {
926 .name = "buffer",
927 .get = get_buffer,
928 .put = put_buffer,
929};
930
931/* unused buffers: space that was used for some fields that are
932 not useful anymore */
933
2c21ee76
JD
934static int get_unused_buffer(QEMUFile *f, void *pv, size_t size,
935 VMStateField *field)
b6fcfa59
EH
936{
937 uint8_t buf[1024];
938 int block_len;
939
940 while (size > 0) {
941 block_len = MIN(sizeof(buf), size);
942 size -= block_len;
943 qemu_get_buffer(f, buf, block_len);
944 }
945 return 0;
946}
947
2c21ee76
JD
948static int put_unused_buffer(QEMUFile *f, void *pv, size_t size,
949 VMStateField *field, QJSON *vmdesc)
b6fcfa59
EH
950{
951 static const uint8_t buf[1024];
952 int block_len;
953
954 while (size > 0) {
955 block_len = MIN(sizeof(buf), size);
956 size -= block_len;
957 qemu_put_buffer(f, buf, block_len);
958 }
2c21ee76
JD
959
960 return 0;
b6fcfa59
EH
961}
962
963const VMStateInfo vmstate_info_unused_buffer = {
964 .name = "unused_buffer",
965 .get = get_unused_buffer,
966 .put = put_unused_buffer,
967};
968
bcf45131
DDAG
969/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
970 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
971 * copy stuff from the parent into the child and do calculations to fill
972 * in fields that don't really exist in the parent but need to be in the
973 * stream.
974 */
975static int get_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field)
976{
977 int ret;
978 const VMStateDescription *vmsd = field->vmsd;
979 int version_id = field->version_id;
980 void *tmp = g_malloc(size);
981
982 /* Writes the parent field which is at the start of the tmp */
983 *(void **)tmp = pv;
984 ret = vmstate_load_state(f, vmsd, tmp, version_id);
985 g_free(tmp);
986 return ret;
987}
988
989static int put_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field,
990 QJSON *vmdesc)
991{
992 const VMStateDescription *vmsd = field->vmsd;
993 void *tmp = g_malloc(size);
994
995 /* Writes the parent field which is at the start of the tmp */
996 *(void **)tmp = pv;
997 vmstate_save_state(f, vmsd, tmp, vmdesc);
998 g_free(tmp);
999
1000 return 0;
1001}
1002
1003const VMStateInfo vmstate_info_tmp = {
1004 .name = "tmp",
1005 .get = get_tmp,
1006 .put = put_tmp,
1007};
1008
b6fcfa59
EH
1009/* bitmaps (as defined by bitmap.h). Note that size here is the size
1010 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
1011 * bit words with the bits in big endian order. The in-memory format
1012 * is an array of 'unsigned long', which may be either 32 or 64 bits.
1013 */
1014/* This is the number of 64 bit words sent over the wire */
1015#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
2c21ee76 1016static int get_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field)
b6fcfa59
EH
1017{
1018 unsigned long *bmp = pv;
1019 int i, idx = 0;
1020 for (i = 0; i < BITS_TO_U64S(size); i++) {
1021 uint64_t w = qemu_get_be64(f);
1022 bmp[idx++] = w;
1023 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
1024 bmp[idx++] = w >> 32;
1025 }
1026 }
1027 return 0;
1028}
1029
2c21ee76
JD
1030static int put_bitmap(QEMUFile *f, void *pv, size_t size, VMStateField *field,
1031 QJSON *vmdesc)
b6fcfa59
EH
1032{
1033 unsigned long *bmp = pv;
1034 int i, idx = 0;
1035 for (i = 0; i < BITS_TO_U64S(size); i++) {
1036 uint64_t w = bmp[idx++];
1037 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
1038 w |= ((uint64_t)bmp[idx++]) << 32;
1039 }
1040 qemu_put_be64(f, w);
1041 }
2c21ee76
JD
1042
1043 return 0;
b6fcfa59
EH
1044}
1045
1046const VMStateInfo vmstate_info_bitmap = {
1047 .name = "bitmap",
1048 .get = get_bitmap,
1049 .put = put_bitmap,
1050};
94869d5c
JD
1051
1052/* get for QTAILQ
1053 * meta data about the QTAILQ is encoded in a VMStateField structure
1054 */
1055static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size,
1056 VMStateField *field)
1057{
1058 int ret = 0;
1059 const VMStateDescription *vmsd = field->vmsd;
1060 /* size of a QTAILQ element */
1061 size_t size = field->size;
1062 /* offset of the QTAILQ entry in a QTAILQ element */
1063 size_t entry_offset = field->start;
1064 int version_id = field->version_id;
1065 void *elm;
1066
1067 trace_get_qtailq(vmsd->name, version_id);
1068 if (version_id > vmsd->version_id) {
1069 error_report("%s %s", vmsd->name, "too new");
1070 trace_get_qtailq_end(vmsd->name, "too new", -EINVAL);
1071
1072 return -EINVAL;
1073 }
1074 if (version_id < vmsd->minimum_version_id) {
1075 error_report("%s %s", vmsd->name, "too old");
1076 trace_get_qtailq_end(vmsd->name, "too old", -EINVAL);
1077 return -EINVAL;
1078 }
1079
1080 while (qemu_get_byte(f)) {
1081 elm = g_malloc(size);
1082 ret = vmstate_load_state(f, vmsd, elm, version_id);
1083 if (ret) {
1084 return ret;
1085 }
1086 QTAILQ_RAW_INSERT_TAIL(pv, elm, entry_offset);
1087 }
1088
1089 trace_get_qtailq_end(vmsd->name, "end", ret);
1090 return ret;
1091}
1092
1093/* put for QTAILQ */
1094static int put_qtailq(QEMUFile *f, void *pv, size_t unused_size,
1095 VMStateField *field, QJSON *vmdesc)
1096{
1097 const VMStateDescription *vmsd = field->vmsd;
1098 /* offset of the QTAILQ entry in a QTAILQ element*/
1099 size_t entry_offset = field->start;
1100 void *elm;
1101
1102 trace_put_qtailq(vmsd->name, vmsd->version_id);
1103
1104 QTAILQ_RAW_FOREACH(elm, pv, entry_offset) {
1105 qemu_put_byte(f, true);
1106 vmstate_save_state(f, vmsd, elm, vmdesc);
1107 }
1108 qemu_put_byte(f, false);
1109
1110 trace_put_qtailq_end(vmsd->name, "end");
1111
1112 return 0;
1113}
1114const VMStateInfo vmstate_info_qtailq = {
1115 .name = "qtailq",
1116 .get = get_qtailq,
1117 .put = put_qtailq,
1118};