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