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