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,
  26                    const VMStateField *field)
  27{
  28    bool *v = pv;
  29    *v = qemu_get_byte(f);
  30    return 0;
  31}
  32
  33static 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
  41const VMStateInfo vmstate_info_bool = {
  42    .name = "bool",
  43    .get  = get_bool,
  44    .put  = put_bool,
  45};
  46
  47/* 8 bit int */
  48
  49static 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
  57static 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
  65const VMStateInfo vmstate_info_int8 = {
  66    .name = "int8",
  67    .get  = get_int8,
  68    .put  = put_int8,
  69};
  70
  71/* 16 bit int */
  72
  73static 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
  81static 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
  89const VMStateInfo vmstate_info_int16 = {
  90    .name = "int16",
  91    .get  = get_int16,
  92    .put  = put_int16,
  93};
  94
  95/* 32 bit int */
  96
  97static 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
 105static 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
 113const 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
 122static 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
 139const 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
 149static 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
 166const 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
 174static 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
 182static 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
 190const VMStateInfo vmstate_info_int64 = {
 191    .name = "int64",
 192    .get  = get_int64,
 193    .put  = put_int64,
 194};
 195
 196/* 8 bit unsigned int */
 197
 198static 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
 206static 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
 214const VMStateInfo vmstate_info_uint8 = {
 215    .name = "uint8",
 216    .get  = get_uint8,
 217    .put  = put_uint8,
 218};
 219
 220/* 16 bit unsigned int */
 221
 222static 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
 230static 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
 238const VMStateInfo vmstate_info_uint16 = {
 239    .name = "uint16",
 240    .get  = get_uint16,
 241    .put  = put_uint16,
 242};
 243
 244/* 32 bit unsigned int */
 245
 246static 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
 254static 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
 262const 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
 271static 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
 288const 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
 296static 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
 304static 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
 312const VMStateInfo vmstate_info_uint64 = {
 313    .name = "uint64",
 314    .get  = get_uint64,
 315    .put  = put_uint64,
 316};
 317
 318static 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
 329static 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
 341const 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
 350static 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
 367const 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
 376static 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
 393const 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
 402static 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
 419const VMStateInfo vmstate_info_uint16_equal = {
 420    .name = "uint16 equal",
 421    .get  = get_uint16_equal,
 422    .put  = put_uint16,
 423};
 424
 425/* floating point */
 426
 427static 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
 436static 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
 445const VMStateInfo vmstate_info_float64 = {
 446    .name = "float64",
 447    .get  = get_float64,
 448    .put  = put_float64,
 449};
 450
 451/* CPU_DoubleU type */
 452
 453static 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
 462static 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
 471const VMStateInfo vmstate_info_cpudouble = {
 472    .name = "CPU_Double_U",
 473    .get  = get_cpudouble,
 474    .put  = put_cpudouble,
 475};
 476
 477/* uint8_t buffers */
 478
 479static 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
 487static 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
 495const 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
 504static 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
 518static 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
 533const 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 */
 545static 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
 560static 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
 575const 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)
 588static 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
 603static 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
 619const 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 */
 628static 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 */
 667static 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}
 691const VMStateInfo vmstate_info_qtailq = {
 692    .name = "qtailq",
 693    .get  = get_qtailq,
 694    .put  = put_qtailq,
 695};
 696