qemu/migration/vmstate.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2#include "qemu-common.h"
   3#include "migration/migration.h"
   4#include "migration/qemu-file.h"
   5#include "migration/vmstate.h"
   6#include "qemu/bitops.h"
   7#include "qemu/error-report.h"
   8#include "trace.h"
   9#include "qjson.h"
  10
  11static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
  12                                    void *opaque, QJSON *vmdesc);
  13static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
  14                                   void *opaque);
  15
  16static int vmstate_n_elems(void *opaque, VMStateField *field)
  17{
  18    int n_elems = 1;
  19
  20    if (field->flags & VMS_ARRAY) {
  21        n_elems = field->num;
  22    } else if (field->flags & VMS_VARRAY_INT32) {
  23        n_elems = *(int32_t *)(opaque+field->num_offset);
  24    } else if (field->flags & VMS_VARRAY_UINT32) {
  25        n_elems = *(uint32_t *)(opaque+field->num_offset);
  26    } else if (field->flags & VMS_VARRAY_UINT16) {
  27        n_elems = *(uint16_t *)(opaque+field->num_offset);
  28    } else if (field->flags & VMS_VARRAY_UINT8) {
  29        n_elems = *(uint8_t *)(opaque+field->num_offset);
  30    }
  31
  32    if (field->flags & VMS_MULTIPLY_ELEMENTS) {
  33        n_elems *= field->num;
  34    }
  35
  36    return n_elems;
  37}
  38
  39static int vmstate_size(void *opaque, VMStateField *field)
  40{
  41    int size = field->size;
  42
  43    if (field->flags & VMS_VBUFFER) {
  44        size = *(int32_t *)(opaque+field->size_offset);
  45        if (field->flags & VMS_MULTIPLY) {
  46            size *= field->size;
  47        }
  48    }
  49
  50    return size;
  51}
  52
  53static void *vmstate_base_addr(void *opaque, VMStateField *field, bool alloc)
  54{
  55    void *base_addr = opaque + field->offset;
  56
  57    if (field->flags & VMS_POINTER) {
  58        if (alloc && (field->flags & VMS_ALLOC)) {
  59            gsize size = 0;
  60            if (field->flags & VMS_VBUFFER) {
  61                size = vmstate_size(opaque, field);
  62            } else {
  63                int n_elems = vmstate_n_elems(opaque, field);
  64                if (n_elems) {
  65                    size = n_elems * field->size;
  66                }
  67            }
  68            if (size) {
  69                *((void **)base_addr + field->start) = g_malloc(size);
  70            }
  71        }
  72        base_addr = *(void **)base_addr + field->start;
  73    }
  74
  75    return base_addr;
  76}
  77
  78int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
  79                       void *opaque, int version_id)
  80{
  81    VMStateField *field = vmsd->fields;
  82    int ret = 0;
  83
  84    trace_vmstate_load_state(vmsd->name, version_id);
  85    if (version_id > vmsd->version_id) {
  86        trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
  87        return -EINVAL;
  88    }
  89    if  (version_id < vmsd->minimum_version_id) {
  90        if (vmsd->load_state_old &&
  91            version_id >= vmsd->minimum_version_id_old) {
  92            ret = vmsd->load_state_old(f, opaque, version_id);
  93            trace_vmstate_load_state_end(vmsd->name, "old path", ret);
  94            return ret;
  95        }
  96        trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
  97        return -EINVAL;
  98    }
  99    if (vmsd->pre_load) {
 100        int ret = vmsd->pre_load(opaque);
 101        if (ret) {
 102            return ret;
 103        }
 104    }
 105    while (field->name) {
 106        trace_vmstate_load_state_field(vmsd->name, field->name);
 107        if ((field->field_exists &&
 108             field->field_exists(opaque, version_id)) ||
 109            (!field->field_exists &&
 110             field->version_id <= version_id)) {
 111            void *base_addr = vmstate_base_addr(opaque, field, true);
 112            int i, n_elems = vmstate_n_elems(opaque, field);
 113            int size = vmstate_size(opaque, field);
 114
 115            for (i = 0; i < n_elems; i++) {
 116                void *addr = base_addr + size * i;
 117
 118                if (field->flags & VMS_ARRAY_OF_POINTER) {
 119                    addr = *(void **)addr;
 120                }
 121                if (field->flags & VMS_STRUCT) {
 122                    ret = vmstate_load_state(f, field->vmsd, addr,
 123                                             field->vmsd->version_id);
 124                } else {
 125                    ret = field->info->get(f, addr, size);
 126
 127                }
 128                if (ret >= 0) {
 129                    ret = qemu_file_get_error(f);
 130                }
 131                if (ret < 0) {
 132                    qemu_file_set_error(f, ret);
 133                    trace_vmstate_load_field_error(field->name, ret);
 134                    return ret;
 135                }
 136            }
 137        } else if (field->flags & VMS_MUST_EXIST) {
 138            error_report("Input validation failed: %s/%s",
 139                         vmsd->name, field->name);
 140            return -1;
 141        }
 142        field++;
 143    }
 144    ret = vmstate_subsection_load(f, vmsd, opaque);
 145    if (ret != 0) {
 146        return ret;
 147    }
 148    if (vmsd->post_load) {
 149        ret = vmsd->post_load(opaque, version_id);
 150    }
 151    trace_vmstate_load_state_end(vmsd->name, "end", ret);
 152    return ret;
 153}
 154
 155static int vmfield_name_num(VMStateField *start, VMStateField *search)
 156{
 157    VMStateField *field;
 158    int found = 0;
 159
 160    for (field = start; field->name; field++) {
 161        if (!strcmp(field->name, search->name)) {
 162            if (field == search) {
 163                return found;
 164            }
 165            found++;
 166        }
 167    }
 168
 169    return -1;
 170}
 171
 172static bool vmfield_name_is_unique(VMStateField *start, VMStateField *search)
 173{
 174    VMStateField *field;
 175    int found = 0;
 176
 177    for (field = start; field->name; field++) {
 178        if (!strcmp(field->name, search->name)) {
 179            found++;
 180            /* name found more than once, so it's not unique */
 181            if (found > 1) {
 182                return false;
 183            }
 184        }
 185    }
 186
 187    return true;
 188}
 189
 190static const char *vmfield_get_type_name(VMStateField *field)
 191{
 192    const char *type = "unknown";
 193
 194    if (field->flags & VMS_STRUCT) {
 195        type = "struct";
 196    } else if (field->info->name) {
 197        type = field->info->name;
 198    }
 199
 200    return type;
 201}
 202
 203static bool vmsd_can_compress(VMStateField *field)
 204{
 205    if (field->field_exists) {
 206        /* Dynamically existing fields mess up compression */
 207        return false;
 208    }
 209
 210    if (field->flags & VMS_STRUCT) {
 211        VMStateField *sfield = field->vmsd->fields;
 212        while (sfield->name) {
 213            if (!vmsd_can_compress(sfield)) {
 214                /* Child elements can't compress, so can't we */
 215                return false;
 216            }
 217            sfield++;
 218        }
 219
 220        if (field->vmsd->subsections) {
 221            /* Subsections may come and go, better don't compress */
 222            return false;
 223        }
 224    }
 225
 226    return true;
 227}
 228
 229static void vmsd_desc_field_start(const VMStateDescription *vmsd, QJSON *vmdesc,
 230                                  VMStateField *field, int i, int max)
 231{
 232    char *name, *old_name;
 233    bool is_array = max > 1;
 234    bool can_compress = vmsd_can_compress(field);
 235
 236    if (!vmdesc) {
 237        return;
 238    }
 239
 240    name = g_strdup(field->name);
 241
 242    /* Field name is not unique, need to make it unique */
 243    if (!vmfield_name_is_unique(vmsd->fields, field)) {
 244        int num = vmfield_name_num(vmsd->fields, field);
 245        old_name = name;
 246        name = g_strdup_printf("%s[%d]", name, num);
 247        g_free(old_name);
 248    }
 249
 250    json_start_object(vmdesc, NULL);
 251    json_prop_str(vmdesc, "name", name);
 252    if (is_array) {
 253        if (can_compress) {
 254            json_prop_int(vmdesc, "array_len", max);
 255        } else {
 256            json_prop_int(vmdesc, "index", i);
 257        }
 258    }
 259    json_prop_str(vmdesc, "type", vmfield_get_type_name(field));
 260
 261    if (field->flags & VMS_STRUCT) {
 262        json_start_object(vmdesc, "struct");
 263    }
 264
 265    g_free(name);
 266}
 267
 268static void vmsd_desc_field_end(const VMStateDescription *vmsd, QJSON *vmdesc,
 269                                VMStateField *field, size_t size, int i)
 270{
 271    if (!vmdesc) {
 272        return;
 273    }
 274
 275    if (field->flags & VMS_STRUCT) {
 276        /* We printed a struct in between, close its child object */
 277        json_end_object(vmdesc);
 278    }
 279
 280    json_prop_int(vmdesc, "size", size);
 281    json_end_object(vmdesc);
 282}
 283
 284
 285bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque)
 286{
 287    if (vmsd->needed && !vmsd->needed(opaque)) {
 288        /* optional section not needed */
 289        return false;
 290    }
 291    return true;
 292}
 293
 294
 295void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
 296                        void *opaque, QJSON *vmdesc)
 297{
 298    VMStateField *field = vmsd->fields;
 299
 300    if (vmsd->pre_save) {
 301        vmsd->pre_save(opaque);
 302    }
 303
 304    if (vmdesc) {
 305        json_prop_str(vmdesc, "vmsd_name", vmsd->name);
 306        json_prop_int(vmdesc, "version", vmsd->version_id);
 307        json_start_array(vmdesc, "fields");
 308    }
 309
 310    while (field->name) {
 311        if (!field->field_exists ||
 312            field->field_exists(opaque, vmsd->version_id)) {
 313            void *base_addr = vmstate_base_addr(opaque, field, false);
 314            int i, n_elems = vmstate_n_elems(opaque, field);
 315            int size = vmstate_size(opaque, field);
 316            int64_t old_offset, written_bytes;
 317            QJSON *vmdesc_loop = vmdesc;
 318
 319            for (i = 0; i < n_elems; i++) {
 320                void *addr = base_addr + size * i;
 321
 322                vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems);
 323                old_offset = qemu_ftell_fast(f);
 324
 325                if (field->flags & VMS_ARRAY_OF_POINTER) {
 326                    addr = *(void **)addr;
 327                }
 328                if (field->flags & VMS_STRUCT) {
 329                    vmstate_save_state(f, field->vmsd, addr, vmdesc_loop);
 330                } else {
 331                    field->info->put(f, addr, size);
 332                }
 333
 334                written_bytes = qemu_ftell_fast(f) - old_offset;
 335                vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i);
 336
 337                /* Compressed arrays only care about the first element */
 338                if (vmdesc_loop && vmsd_can_compress(field)) {
 339                    vmdesc_loop = NULL;
 340                }
 341            }
 342        } else {
 343            if (field->flags & VMS_MUST_EXIST) {
 344                error_report("Output state validation failed: %s/%s",
 345                        vmsd->name, field->name);
 346                assert(!(field->flags & VMS_MUST_EXIST));
 347            }
 348        }
 349        field++;
 350    }
 351
 352    if (vmdesc) {
 353        json_end_array(vmdesc);
 354    }
 355
 356    vmstate_subsection_save(f, vmsd, opaque, vmdesc);
 357}
 358
 359static const VMStateDescription *
 360vmstate_get_subsection(const VMStateDescription **sub, char *idstr)
 361{
 362    while (sub && *sub && (*sub)->needed) {
 363        if (strcmp(idstr, (*sub)->name) == 0) {
 364            return *sub;
 365        }
 366        sub++;
 367    }
 368    return NULL;
 369}
 370
 371static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
 372                                   void *opaque)
 373{
 374    trace_vmstate_subsection_load(vmsd->name);
 375
 376    while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
 377        char idstr[256], *idstr_ret;
 378        int ret;
 379        uint8_t version_id, len, size;
 380        const VMStateDescription *sub_vmsd;
 381
 382        len = qemu_peek_byte(f, 1);
 383        if (len < strlen(vmsd->name) + 1) {
 384            /* subsection name has be be "section_name/a" */
 385            trace_vmstate_subsection_load_bad(vmsd->name, "(short)");
 386            return 0;
 387        }
 388        size = qemu_peek_buffer(f, (uint8_t **)&idstr_ret, len, 2);
 389        if (size != len) {
 390            trace_vmstate_subsection_load_bad(vmsd->name, "(peek fail)");
 391            return 0;
 392        }
 393        memcpy(idstr, idstr_ret, size);
 394        idstr[size] = 0;
 395
 396        if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
 397            trace_vmstate_subsection_load_bad(vmsd->name, idstr);
 398            /* it don't have a valid subsection name */
 399            return 0;
 400        }
 401        sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
 402        if (sub_vmsd == NULL) {
 403            trace_vmstate_subsection_load_bad(vmsd->name, "(lookup)");
 404            return -ENOENT;
 405        }
 406        qemu_file_skip(f, 1); /* subsection */
 407        qemu_file_skip(f, 1); /* len */
 408        qemu_file_skip(f, len); /* idstr */
 409        version_id = qemu_get_be32(f);
 410
 411        ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
 412        if (ret) {
 413            trace_vmstate_subsection_load_bad(vmsd->name, "(child)");
 414            return ret;
 415        }
 416    }
 417
 418    trace_vmstate_subsection_load_good(vmsd->name);
 419    return 0;
 420}
 421
 422static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
 423                                    void *opaque, QJSON *vmdesc)
 424{
 425    const VMStateDescription **sub = vmsd->subsections;
 426    bool subsection_found = false;
 427
 428    while (sub && *sub && (*sub)->needed) {
 429        if ((*sub)->needed(opaque)) {
 430            const VMStateDescription *vmsd = *sub;
 431            uint8_t len;
 432
 433            if (vmdesc) {
 434                /* Only create subsection array when we have any */
 435                if (!subsection_found) {
 436                    json_start_array(vmdesc, "subsections");
 437                    subsection_found = true;
 438                }
 439
 440                json_start_object(vmdesc, NULL);
 441            }
 442
 443            qemu_put_byte(f, QEMU_VM_SUBSECTION);
 444            len = strlen(vmsd->name);
 445            qemu_put_byte(f, len);
 446            qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
 447            qemu_put_be32(f, vmsd->version_id);
 448            vmstate_save_state(f, vmsd, opaque, vmdesc);
 449
 450            if (vmdesc) {
 451                json_end_object(vmdesc);
 452            }
 453        }
 454        sub++;
 455    }
 456
 457    if (vmdesc && subsection_found) {
 458        json_end_array(vmdesc);
 459    }
 460}
 461
 462/* bool */
 463
 464static int get_bool(QEMUFile *f, void *pv, size_t size)
 465{
 466    bool *v = pv;
 467    *v = qemu_get_byte(f);
 468    return 0;
 469}
 470
 471static void put_bool(QEMUFile *f, void *pv, size_t size)
 472{
 473    bool *v = pv;
 474    qemu_put_byte(f, *v);
 475}
 476
 477const VMStateInfo vmstate_info_bool = {
 478    .name = "bool",
 479    .get  = get_bool,
 480    .put  = put_bool,
 481};
 482
 483/* 8 bit int */
 484
 485static int get_int8(QEMUFile *f, void *pv, size_t size)
 486{
 487    int8_t *v = pv;
 488    qemu_get_s8s(f, v);
 489    return 0;
 490}
 491
 492static void put_int8(QEMUFile *f, void *pv, size_t size)
 493{
 494    int8_t *v = pv;
 495    qemu_put_s8s(f, v);
 496}
 497
 498const VMStateInfo vmstate_info_int8 = {
 499    .name = "int8",
 500    .get  = get_int8,
 501    .put  = put_int8,
 502};
 503
 504/* 16 bit int */
 505
 506static int get_int16(QEMUFile *f, void *pv, size_t size)
 507{
 508    int16_t *v = pv;
 509    qemu_get_sbe16s(f, v);
 510    return 0;
 511}
 512
 513static void put_int16(QEMUFile *f, void *pv, size_t size)
 514{
 515    int16_t *v = pv;
 516    qemu_put_sbe16s(f, v);
 517}
 518
 519const VMStateInfo vmstate_info_int16 = {
 520    .name = "int16",
 521    .get  = get_int16,
 522    .put  = put_int16,
 523};
 524
 525/* 32 bit int */
 526
 527static int get_int32(QEMUFile *f, void *pv, size_t size)
 528{
 529    int32_t *v = pv;
 530    qemu_get_sbe32s(f, v);
 531    return 0;
 532}
 533
 534static void put_int32(QEMUFile *f, void *pv, size_t size)
 535{
 536    int32_t *v = pv;
 537    qemu_put_sbe32s(f, v);
 538}
 539
 540const VMStateInfo vmstate_info_int32 = {
 541    .name = "int32",
 542    .get  = get_int32,
 543    .put  = put_int32,
 544};
 545
 546/* 32 bit int. See that the received value is the same than the one
 547   in the field */
 548
 549static int get_int32_equal(QEMUFile *f, void *pv, size_t size)
 550{
 551    int32_t *v = pv;
 552    int32_t v2;
 553    qemu_get_sbe32s(f, &v2);
 554
 555    if (*v == v2) {
 556        return 0;
 557    }
 558    return -EINVAL;
 559}
 560
 561const VMStateInfo vmstate_info_int32_equal = {
 562    .name = "int32 equal",
 563    .get  = get_int32_equal,
 564    .put  = put_int32,
 565};
 566
 567/* 32 bit int. Check that the received value is non-negative
 568 * and less than or equal to the one in the field.
 569 */
 570
 571static int get_int32_le(QEMUFile *f, void *pv, size_t size)
 572{
 573    int32_t *cur = pv;
 574    int32_t loaded;
 575    qemu_get_sbe32s(f, &loaded);
 576
 577    if (loaded >= 0 && loaded <= *cur) {
 578        *cur = loaded;
 579        return 0;
 580    }
 581    return -EINVAL;
 582}
 583
 584const VMStateInfo vmstate_info_int32_le = {
 585    .name = "int32 le",
 586    .get  = get_int32_le,
 587    .put  = put_int32,
 588};
 589
 590/* 64 bit int */
 591
 592static int get_int64(QEMUFile *f, void *pv, size_t size)
 593{
 594    int64_t *v = pv;
 595    qemu_get_sbe64s(f, v);
 596    return 0;
 597}
 598
 599static void put_int64(QEMUFile *f, void *pv, size_t size)
 600{
 601    int64_t *v = pv;
 602    qemu_put_sbe64s(f, v);
 603}
 604
 605const VMStateInfo vmstate_info_int64 = {
 606    .name = "int64",
 607    .get  = get_int64,
 608    .put  = put_int64,
 609};
 610
 611/* 8 bit unsigned int */
 612
 613static int get_uint8(QEMUFile *f, void *pv, size_t size)
 614{
 615    uint8_t *v = pv;
 616    qemu_get_8s(f, v);
 617    return 0;
 618}
 619
 620static void put_uint8(QEMUFile *f, void *pv, size_t size)
 621{
 622    uint8_t *v = pv;
 623    qemu_put_8s(f, v);
 624}
 625
 626const VMStateInfo vmstate_info_uint8 = {
 627    .name = "uint8",
 628    .get  = get_uint8,
 629    .put  = put_uint8,
 630};
 631
 632/* 16 bit unsigned int */
 633
 634static int get_uint16(QEMUFile *f, void *pv, size_t size)
 635{
 636    uint16_t *v = pv;
 637    qemu_get_be16s(f, v);
 638    return 0;
 639}
 640
 641static void put_uint16(QEMUFile *f, void *pv, size_t size)
 642{
 643    uint16_t *v = pv;
 644    qemu_put_be16s(f, v);
 645}
 646
 647const VMStateInfo vmstate_info_uint16 = {
 648    .name = "uint16",
 649    .get  = get_uint16,
 650    .put  = put_uint16,
 651};
 652
 653/* 32 bit unsigned int */
 654
 655static int get_uint32(QEMUFile *f, void *pv, size_t size)
 656{
 657    uint32_t *v = pv;
 658    qemu_get_be32s(f, v);
 659    return 0;
 660}
 661
 662static void put_uint32(QEMUFile *f, void *pv, size_t size)
 663{
 664    uint32_t *v = pv;
 665    qemu_put_be32s(f, v);
 666}
 667
 668const VMStateInfo vmstate_info_uint32 = {
 669    .name = "uint32",
 670    .get  = get_uint32,
 671    .put  = put_uint32,
 672};
 673
 674/* 32 bit uint. See that the received value is the same than the one
 675   in the field */
 676
 677static int get_uint32_equal(QEMUFile *f, void *pv, size_t size)
 678{
 679    uint32_t *v = pv;
 680    uint32_t v2;
 681    qemu_get_be32s(f, &v2);
 682
 683    if (*v == v2) {
 684        return 0;
 685    }
 686    return -EINVAL;
 687}
 688
 689const VMStateInfo vmstate_info_uint32_equal = {
 690    .name = "uint32 equal",
 691    .get  = get_uint32_equal,
 692    .put  = put_uint32,
 693};
 694
 695/* 64 bit unsigned int */
 696
 697static int get_uint64(QEMUFile *f, void *pv, size_t size)
 698{
 699    uint64_t *v = pv;
 700    qemu_get_be64s(f, v);
 701    return 0;
 702}
 703
 704static void put_uint64(QEMUFile *f, void *pv, size_t size)
 705{
 706    uint64_t *v = pv;
 707    qemu_put_be64s(f, v);
 708}
 709
 710const VMStateInfo vmstate_info_uint64 = {
 711    .name = "uint64",
 712    .get  = get_uint64,
 713    .put  = put_uint64,
 714};
 715
 716/* 64 bit unsigned int. See that the received value is the same than the one
 717   in the field */
 718
 719static int get_uint64_equal(QEMUFile *f, void *pv, size_t size)
 720{
 721    uint64_t *v = pv;
 722    uint64_t v2;
 723    qemu_get_be64s(f, &v2);
 724
 725    if (*v == v2) {
 726        return 0;
 727    }
 728    return -EINVAL;
 729}
 730
 731const VMStateInfo vmstate_info_uint64_equal = {
 732    .name = "int64 equal",
 733    .get  = get_uint64_equal,
 734    .put  = put_uint64,
 735};
 736
 737/* 8 bit int. See that the received value is the same than the one
 738   in the field */
 739
 740static int get_uint8_equal(QEMUFile *f, void *pv, size_t size)
 741{
 742    uint8_t *v = pv;
 743    uint8_t v2;
 744    qemu_get_8s(f, &v2);
 745
 746    if (*v == v2) {
 747        return 0;
 748    }
 749    return -EINVAL;
 750}
 751
 752const VMStateInfo vmstate_info_uint8_equal = {
 753    .name = "uint8 equal",
 754    .get  = get_uint8_equal,
 755    .put  = put_uint8,
 756};
 757
 758/* 16 bit unsigned int int. See that the received value is the same than the one
 759   in the field */
 760
 761static int get_uint16_equal(QEMUFile *f, void *pv, size_t size)
 762{
 763    uint16_t *v = pv;
 764    uint16_t v2;
 765    qemu_get_be16s(f, &v2);
 766
 767    if (*v == v2) {
 768        return 0;
 769    }
 770    return -EINVAL;
 771}
 772
 773const VMStateInfo vmstate_info_uint16_equal = {
 774    .name = "uint16 equal",
 775    .get  = get_uint16_equal,
 776    .put  = put_uint16,
 777};
 778
 779/* floating point */
 780
 781static int get_float64(QEMUFile *f, void *pv, size_t size)
 782{
 783    float64 *v = pv;
 784
 785    *v = make_float64(qemu_get_be64(f));
 786    return 0;
 787}
 788
 789static void put_float64(QEMUFile *f, void *pv, size_t size)
 790{
 791    uint64_t *v = pv;
 792
 793    qemu_put_be64(f, float64_val(*v));
 794}
 795
 796const VMStateInfo vmstate_info_float64 = {
 797    .name = "float64",
 798    .get  = get_float64,
 799    .put  = put_float64,
 800};
 801
 802/* CPU_DoubleU type */
 803
 804static int get_cpudouble(QEMUFile *f, void *pv, size_t size)
 805{
 806    CPU_DoubleU *v = pv;
 807    qemu_get_be32s(f, &v->l.upper);
 808    qemu_get_be32s(f, &v->l.lower);
 809    return 0;
 810}
 811
 812static void put_cpudouble(QEMUFile *f, void *pv, size_t size)
 813{
 814    CPU_DoubleU *v = pv;
 815    qemu_put_be32s(f, &v->l.upper);
 816    qemu_put_be32s(f, &v->l.lower);
 817}
 818
 819const VMStateInfo vmstate_info_cpudouble = {
 820    .name = "CPU_Double_U",
 821    .get  = get_cpudouble,
 822    .put  = put_cpudouble,
 823};
 824
 825/* uint8_t buffers */
 826
 827static int get_buffer(QEMUFile *f, void *pv, size_t size)
 828{
 829    uint8_t *v = pv;
 830    qemu_get_buffer(f, v, size);
 831    return 0;
 832}
 833
 834static void put_buffer(QEMUFile *f, void *pv, size_t size)
 835{
 836    uint8_t *v = pv;
 837    qemu_put_buffer(f, v, size);
 838}
 839
 840const VMStateInfo vmstate_info_buffer = {
 841    .name = "buffer",
 842    .get  = get_buffer,
 843    .put  = put_buffer,
 844};
 845
 846/* unused buffers: space that was used for some fields that are
 847   not useful anymore */
 848
 849static int get_unused_buffer(QEMUFile *f, void *pv, size_t size)
 850{
 851    uint8_t buf[1024];
 852    int block_len;
 853
 854    while (size > 0) {
 855        block_len = MIN(sizeof(buf), size);
 856        size -= block_len;
 857        qemu_get_buffer(f, buf, block_len);
 858    }
 859   return 0;
 860}
 861
 862static void put_unused_buffer(QEMUFile *f, void *pv, size_t size)
 863{
 864    static const uint8_t buf[1024];
 865    int block_len;
 866
 867    while (size > 0) {
 868        block_len = MIN(sizeof(buf), size);
 869        size -= block_len;
 870        qemu_put_buffer(f, buf, block_len);
 871    }
 872}
 873
 874const VMStateInfo vmstate_info_unused_buffer = {
 875    .name = "unused_buffer",
 876    .get  = get_unused_buffer,
 877    .put  = put_unused_buffer,
 878};
 879
 880/* bitmaps (as defined by bitmap.h). Note that size here is the size
 881 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
 882 * bit words with the bits in big endian order. The in-memory format
 883 * is an array of 'unsigned long', which may be either 32 or 64 bits.
 884 */
 885/* This is the number of 64 bit words sent over the wire */
 886#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
 887static int get_bitmap(QEMUFile *f, void *pv, size_t size)
 888{
 889    unsigned long *bmp = pv;
 890    int i, idx = 0;
 891    for (i = 0; i < BITS_TO_U64S(size); i++) {
 892        uint64_t w = qemu_get_be64(f);
 893        bmp[idx++] = w;
 894        if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
 895            bmp[idx++] = w >> 32;
 896        }
 897    }
 898    return 0;
 899}
 900
 901static void put_bitmap(QEMUFile *f, void *pv, size_t size)
 902{
 903    unsigned long *bmp = pv;
 904    int i, idx = 0;
 905    for (i = 0; i < BITS_TO_U64S(size); i++) {
 906        uint64_t w = bmp[idx++];
 907        if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
 908            w |= ((uint64_t)bmp[idx++]) << 32;
 909        }
 910        qemu_put_be64(f, w);
 911    }
 912}
 913
 914const VMStateInfo vmstate_info_bitmap = {
 915    .name = "bitmap",
 916    .get = get_bitmap,
 917    .put = put_bitmap,
 918};
 919