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