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