qemu/migration/vmstate-types.c
<<
>>
Prefs
   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
  25static 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
  32static 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
  40const VMStateInfo vmstate_info_bool = {
  41    .name = "bool",
  42    .get  = get_bool,
  43    .put  = put_bool,
  44};
  45
  46/* 8 bit int */
  47
  48static 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
  55static 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
  63const VMStateInfo vmstate_info_int8 = {
  64    .name = "int8",
  65    .get  = get_int8,
  66    .put  = put_int8,
  67};
  68
  69/* 16 bit int */
  70
  71static 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
  78static 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
  86const VMStateInfo vmstate_info_int16 = {
  87    .name = "int16",
  88    .get  = get_int16,
  89    .put  = put_int16,
  90};
  91
  92/* 32 bit int */
  93
  94static 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
 101static 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
 109const 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
 118static 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
 135const 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
 145static 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
 161const 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
 169static 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
 176static 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
 184const VMStateInfo vmstate_info_int64 = {
 185    .name = "int64",
 186    .get  = get_int64,
 187    .put  = put_int64,
 188};
 189
 190/* 8 bit unsigned int */
 191
 192static 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
 199static 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
 207const VMStateInfo vmstate_info_uint8 = {
 208    .name = "uint8",
 209    .get  = get_uint8,
 210    .put  = put_uint8,
 211};
 212
 213/* 16 bit unsigned int */
 214
 215static 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
 222static 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
 230const VMStateInfo vmstate_info_uint16 = {
 231    .name = "uint16",
 232    .get  = get_uint16,
 233    .put  = put_uint16,
 234};
 235
 236/* 32 bit unsigned int */
 237
 238static 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
 245static 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
 253const 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
 262static 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
 279const 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
 287static 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
 294static 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
 302const VMStateInfo vmstate_info_uint64 = {
 303    .name = "uint64",
 304    .get  = get_uint64,
 305    .put  = put_uint64,
 306};
 307
 308static 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
 318static 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
 330const 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
 339static 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
 356const 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
 365static 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
 382const 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
 391static 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
 408const VMStateInfo vmstate_info_uint16_equal = {
 409    .name = "uint16 equal",
 410    .get  = get_uint16_equal,
 411    .put  = put_uint16,
 412};
 413
 414/* floating point */
 415
 416static 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
 425static 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
 434const VMStateInfo vmstate_info_float64 = {
 435    .name = "float64",
 436    .get  = get_float64,
 437    .put  = put_float64,
 438};
 439
 440/* CPU_DoubleU type */
 441
 442static 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
 451static 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
 460const VMStateInfo vmstate_info_cpudouble = {
 461    .name = "CPU_Double_U",
 462    .get  = get_cpudouble,
 463    .put  = put_cpudouble,
 464};
 465
 466/* uint8_t buffers */
 467
 468static 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
 476static 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
 484const 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
 493static 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
 507static 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
 522const 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 */
 534static 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
 548static 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
 563const 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)
 576static 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
 590static 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
 606const 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 */
 615static 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 */
 654static 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}
 678const VMStateInfo vmstate_info_qtailq = {
 679    .name = "qtailq",
 680    .get  = get_qtailq,
 681    .put  = put_qtailq,
 682};
 683