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