cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

vmstate-types.c (22857B)


      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-file.h"
     15#include "migration.h"
     16#include "migration/vmstate.h"
     17#include "qemu/error-report.h"
     18#include "qemu/queue.h"
     19#include "trace.h"
     20
     21/* bool */
     22
     23static int get_bool(QEMUFile *f, void *pv, size_t size,
     24                    const VMStateField *field)
     25{
     26    bool *v = pv;
     27    *v = qemu_get_byte(f);
     28    return 0;
     29}
     30
     31static int put_bool(QEMUFile *f, void *pv, size_t size,
     32                    const VMStateField *field, JSONWriter *vmdesc)
     33{
     34    bool *v = pv;
     35    qemu_put_byte(f, *v);
     36    return 0;
     37}
     38
     39const VMStateInfo vmstate_info_bool = {
     40    .name = "bool",
     41    .get  = get_bool,
     42    .put  = put_bool,
     43};
     44
     45/* 8 bit int */
     46
     47static int get_int8(QEMUFile *f, void *pv, size_t size,
     48                    const 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,
     56                    const VMStateField *field, JSONWriter *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,
     72                     const VMStateField *field)
     73{
     74    int16_t *v = pv;
     75    qemu_get_sbe16s(f, v);
     76    return 0;
     77}
     78
     79static int put_int16(QEMUFile *f, void *pv, size_t size,
     80                     const VMStateField *field, JSONWriter *vmdesc)
     81{
     82    int16_t *v = pv;
     83    qemu_put_sbe16s(f, v);
     84    return 0;
     85}
     86
     87const VMStateInfo vmstate_info_int16 = {
     88    .name = "int16",
     89    .get  = get_int16,
     90    .put  = put_int16,
     91};
     92
     93/* 32 bit int */
     94
     95static int get_int32(QEMUFile *f, void *pv, size_t size,
     96                     const VMStateField *field)
     97{
     98    int32_t *v = pv;
     99    qemu_get_sbe32s(f, v);
    100    return 0;
    101}
    102
    103static int put_int32(QEMUFile *f, void *pv, size_t size,
    104                     const VMStateField *field, JSONWriter *vmdesc)
    105{
    106    int32_t *v = pv;
    107    qemu_put_sbe32s(f, v);
    108    return 0;
    109}
    110
    111const VMStateInfo vmstate_info_int32 = {
    112    .name = "int32",
    113    .get  = get_int32,
    114    .put  = put_int32,
    115};
    116
    117/* 32 bit int. See that the received value is the same than the one
    118   in the field */
    119
    120static int get_int32_equal(QEMUFile *f, void *pv, size_t size,
    121                           const VMStateField *field)
    122{
    123    int32_t *v = pv;
    124    int32_t v2;
    125    qemu_get_sbe32s(f, &v2);
    126
    127    if (*v == v2) {
    128        return 0;
    129    }
    130    error_report("%" PRIx32 " != %" PRIx32, *v, v2);
    131    if (field->err_hint) {
    132        error_printf("%s\n", field->err_hint);
    133    }
    134    return -EINVAL;
    135}
    136
    137const VMStateInfo vmstate_info_int32_equal = {
    138    .name = "int32 equal",
    139    .get  = get_int32_equal,
    140    .put  = put_int32,
    141};
    142
    143/* 32 bit int. Check that the received value is non-negative
    144 * and less than or equal to the one in the field.
    145 */
    146
    147static int get_int32_le(QEMUFile *f, void *pv, size_t size,
    148                        const VMStateField *field)
    149{
    150    int32_t *cur = pv;
    151    int32_t loaded;
    152    qemu_get_sbe32s(f, &loaded);
    153
    154    if (loaded >= 0 && loaded <= *cur) {
    155        *cur = loaded;
    156        return 0;
    157    }
    158    error_report("Invalid value %" PRId32
    159                 " expecting positive value <= %" PRId32,
    160                 loaded, *cur);
    161    return -EINVAL;
    162}
    163
    164const VMStateInfo vmstate_info_int32_le = {
    165    .name = "int32 le",
    166    .get  = get_int32_le,
    167    .put  = put_int32,
    168};
    169
    170/* 64 bit int */
    171
    172static int get_int64(QEMUFile *f, void *pv, size_t size,
    173                     const VMStateField *field)
    174{
    175    int64_t *v = pv;
    176    qemu_get_sbe64s(f, v);
    177    return 0;
    178}
    179
    180static int put_int64(QEMUFile *f, void *pv, size_t size,
    181                     const VMStateField *field, JSONWriter *vmdesc)
    182{
    183    int64_t *v = pv;
    184    qemu_put_sbe64s(f, v);
    185    return 0;
    186}
    187
    188const VMStateInfo vmstate_info_int64 = {
    189    .name = "int64",
    190    .get  = get_int64,
    191    .put  = put_int64,
    192};
    193
    194/* 8 bit unsigned int */
    195
    196static int get_uint8(QEMUFile *f, void *pv, size_t size,
    197                     const VMStateField *field)
    198{
    199    uint8_t *v = pv;
    200    qemu_get_8s(f, v);
    201    return 0;
    202}
    203
    204static int put_uint8(QEMUFile *f, void *pv, size_t size,
    205                     const VMStateField *field, JSONWriter *vmdesc)
    206{
    207    uint8_t *v = pv;
    208    qemu_put_8s(f, v);
    209    return 0;
    210}
    211
    212const VMStateInfo vmstate_info_uint8 = {
    213    .name = "uint8",
    214    .get  = get_uint8,
    215    .put  = put_uint8,
    216};
    217
    218/* 16 bit unsigned int */
    219
    220static int get_uint16(QEMUFile *f, void *pv, size_t size,
    221                      const VMStateField *field)
    222{
    223    uint16_t *v = pv;
    224    qemu_get_be16s(f, v);
    225    return 0;
    226}
    227
    228static int put_uint16(QEMUFile *f, void *pv, size_t size,
    229                      const VMStateField *field, JSONWriter *vmdesc)
    230{
    231    uint16_t *v = pv;
    232    qemu_put_be16s(f, v);
    233    return 0;
    234}
    235
    236const VMStateInfo vmstate_info_uint16 = {
    237    .name = "uint16",
    238    .get  = get_uint16,
    239    .put  = put_uint16,
    240};
    241
    242/* 32 bit unsigned int */
    243
    244static int get_uint32(QEMUFile *f, void *pv, size_t size,
    245                      const VMStateField *field)
    246{
    247    uint32_t *v = pv;
    248    qemu_get_be32s(f, v);
    249    return 0;
    250}
    251
    252static int put_uint32(QEMUFile *f, void *pv, size_t size,
    253                      const VMStateField *field, JSONWriter *vmdesc)
    254{
    255    uint32_t *v = pv;
    256    qemu_put_be32s(f, v);
    257    return 0;
    258}
    259
    260const VMStateInfo vmstate_info_uint32 = {
    261    .name = "uint32",
    262    .get  = get_uint32,
    263    .put  = put_uint32,
    264};
    265
    266/* 32 bit uint. See that the received value is the same than the one
    267   in the field */
    268
    269static int get_uint32_equal(QEMUFile *f, void *pv, size_t size,
    270                            const VMStateField *field)
    271{
    272    uint32_t *v = pv;
    273    uint32_t v2;
    274    qemu_get_be32s(f, &v2);
    275
    276    if (*v == v2) {
    277        return 0;
    278    }
    279    error_report("%" PRIx32 " != %" PRIx32, *v, v2);
    280    if (field->err_hint) {
    281        error_printf("%s\n", field->err_hint);
    282    }
    283    return -EINVAL;
    284}
    285
    286const VMStateInfo vmstate_info_uint32_equal = {
    287    .name = "uint32 equal",
    288    .get  = get_uint32_equal,
    289    .put  = put_uint32,
    290};
    291
    292/* 64 bit unsigned int */
    293
    294static int get_uint64(QEMUFile *f, void *pv, size_t size,
    295                      const VMStateField *field)
    296{
    297    uint64_t *v = pv;
    298    qemu_get_be64s(f, v);
    299    return 0;
    300}
    301
    302static int put_uint64(QEMUFile *f, void *pv, size_t size,
    303                      const VMStateField *field, JSONWriter *vmdesc)
    304{
    305    uint64_t *v = pv;
    306    qemu_put_be64s(f, v);
    307    return 0;
    308}
    309
    310const VMStateInfo vmstate_info_uint64 = {
    311    .name = "uint64",
    312    .get  = get_uint64,
    313    .put  = put_uint64,
    314};
    315
    316static int get_nullptr(QEMUFile *f, void *pv, size_t size,
    317                       const VMStateField *field)
    318
    319{
    320    if (qemu_get_byte(f) == VMS_NULLPTR_MARKER) {
    321        return  0;
    322    }
    323    error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
    324    return -EINVAL;
    325}
    326
    327static int put_nullptr(QEMUFile *f, void *pv, size_t size,
    328                        const VMStateField *field, JSONWriter *vmdesc)
    329
    330{
    331    if (pv == NULL) {
    332        qemu_put_byte(f, VMS_NULLPTR_MARKER);
    333        return 0;
    334    }
    335    error_report("vmstate: put_nullptr must be called with pv == NULL");
    336    return -EINVAL;
    337}
    338
    339const VMStateInfo vmstate_info_nullptr = {
    340    .name = "uint64",
    341    .get  = get_nullptr,
    342    .put  = put_nullptr,
    343};
    344
    345/* 64 bit unsigned int. See that the received value is the same than the one
    346   in the field */
    347
    348static int get_uint64_equal(QEMUFile *f, void *pv, size_t size,
    349                            const VMStateField *field)
    350{
    351    uint64_t *v = pv;
    352    uint64_t v2;
    353    qemu_get_be64s(f, &v2);
    354
    355    if (*v == v2) {
    356        return 0;
    357    }
    358    error_report("%" PRIx64 " != %" PRIx64, *v, v2);
    359    if (field->err_hint) {
    360        error_printf("%s\n", field->err_hint);
    361    }
    362    return -EINVAL;
    363}
    364
    365const VMStateInfo vmstate_info_uint64_equal = {
    366    .name = "int64 equal",
    367    .get  = get_uint64_equal,
    368    .put  = put_uint64,
    369};
    370
    371/* 8 bit int. See that the received value is the same than the one
    372   in the field */
    373
    374static int get_uint8_equal(QEMUFile *f, void *pv, size_t size,
    375                           const VMStateField *field)
    376{
    377    uint8_t *v = pv;
    378    uint8_t v2;
    379    qemu_get_8s(f, &v2);
    380
    381    if (*v == v2) {
    382        return 0;
    383    }
    384    error_report("%x != %x", *v, v2);
    385    if (field->err_hint) {
    386        error_printf("%s\n", field->err_hint);
    387    }
    388    return -EINVAL;
    389}
    390
    391const VMStateInfo vmstate_info_uint8_equal = {
    392    .name = "uint8 equal",
    393    .get  = get_uint8_equal,
    394    .put  = put_uint8,
    395};
    396
    397/* 16 bit unsigned int int. See that the received value is the same than the one
    398   in the field */
    399
    400static int get_uint16_equal(QEMUFile *f, void *pv, size_t size,
    401                            const VMStateField *field)
    402{
    403    uint16_t *v = pv;
    404    uint16_t v2;
    405    qemu_get_be16s(f, &v2);
    406
    407    if (*v == v2) {
    408        return 0;
    409    }
    410    error_report("%x != %x", *v, v2);
    411    if (field->err_hint) {
    412        error_printf("%s\n", field->err_hint);
    413    }
    414    return -EINVAL;
    415}
    416
    417const VMStateInfo vmstate_info_uint16_equal = {
    418    .name = "uint16 equal",
    419    .get  = get_uint16_equal,
    420    .put  = put_uint16,
    421};
    422
    423/* CPU_DoubleU type */
    424
    425static int get_cpudouble(QEMUFile *f, void *pv, size_t size,
    426                         const VMStateField *field)
    427{
    428    CPU_DoubleU *v = pv;
    429    qemu_get_be32s(f, &v->l.upper);
    430    qemu_get_be32s(f, &v->l.lower);
    431    return 0;
    432}
    433
    434static int put_cpudouble(QEMUFile *f, void *pv, size_t size,
    435                         const VMStateField *field, JSONWriter *vmdesc)
    436{
    437    CPU_DoubleU *v = pv;
    438    qemu_put_be32s(f, &v->l.upper);
    439    qemu_put_be32s(f, &v->l.lower);
    440    return 0;
    441}
    442
    443const VMStateInfo vmstate_info_cpudouble = {
    444    .name = "CPU_Double_U",
    445    .get  = get_cpudouble,
    446    .put  = put_cpudouble,
    447};
    448
    449/* uint8_t buffers */
    450
    451static int get_buffer(QEMUFile *f, void *pv, size_t size,
    452                      const VMStateField *field)
    453{
    454    uint8_t *v = pv;
    455    qemu_get_buffer(f, v, size);
    456    return 0;
    457}
    458
    459static int put_buffer(QEMUFile *f, void *pv, size_t size,
    460                      const VMStateField *field, JSONWriter *vmdesc)
    461{
    462    uint8_t *v = pv;
    463    qemu_put_buffer(f, v, size);
    464    return 0;
    465}
    466
    467const VMStateInfo vmstate_info_buffer = {
    468    .name = "buffer",
    469    .get  = get_buffer,
    470    .put  = put_buffer,
    471};
    472
    473/* unused buffers: space that was used for some fields that are
    474   not useful anymore */
    475
    476static int get_unused_buffer(QEMUFile *f, void *pv, size_t size,
    477                             const VMStateField *field)
    478{
    479    uint8_t buf[1024];
    480    int block_len;
    481
    482    while (size > 0) {
    483        block_len = MIN(sizeof(buf), size);
    484        size -= block_len;
    485        qemu_get_buffer(f, buf, block_len);
    486    }
    487   return 0;
    488}
    489
    490static int put_unused_buffer(QEMUFile *f, void *pv, size_t size,
    491                             const VMStateField *field, JSONWriter *vmdesc)
    492{
    493    static const uint8_t buf[1024];
    494    int block_len;
    495
    496    while (size > 0) {
    497        block_len = MIN(sizeof(buf), size);
    498        size -= block_len;
    499        qemu_put_buffer(f, buf, block_len);
    500    }
    501
    502    return 0;
    503}
    504
    505const VMStateInfo vmstate_info_unused_buffer = {
    506    .name = "unused_buffer",
    507    .get  = get_unused_buffer,
    508    .put  = put_unused_buffer,
    509};
    510
    511/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
    512 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
    513 * copy stuff from the parent into the child and do calculations to fill
    514 * in fields that don't really exist in the parent but need to be in the
    515 * stream.
    516 */
    517static int get_tmp(QEMUFile *f, void *pv, size_t size,
    518                   const 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
    532static int put_tmp(QEMUFile *f, void *pv, size_t size,
    533                   const VMStateField *field, JSONWriter *vmdesc)
    534{
    535    const VMStateDescription *vmsd = field->vmsd;
    536    void *tmp = g_malloc(size);
    537    int ret;
    538
    539    /* Writes the parent field which is at the start of the tmp */
    540    *(void **)tmp = pv;
    541    ret = vmstate_save_state(f, vmsd, tmp, vmdesc);
    542    g_free(tmp);
    543
    544    return ret;
    545}
    546
    547const VMStateInfo vmstate_info_tmp = {
    548    .name = "tmp",
    549    .get = get_tmp,
    550    .put = put_tmp,
    551};
    552
    553/* bitmaps (as defined by bitmap.h). Note that size here is the size
    554 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
    555 * bit words with the bits in big endian order. The in-memory format
    556 * is an array of 'unsigned long', which may be either 32 or 64 bits.
    557 */
    558/* This is the number of 64 bit words sent over the wire */
    559#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
    560static int get_bitmap(QEMUFile *f, void *pv, size_t size,
    561                      const VMStateField *field)
    562{
    563    unsigned long *bmp = pv;
    564    int i, idx = 0;
    565    for (i = 0; i < BITS_TO_U64S(size); i++) {
    566        uint64_t w = qemu_get_be64(f);
    567        bmp[idx++] = w;
    568        if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
    569            bmp[idx++] = w >> 32;
    570        }
    571    }
    572    return 0;
    573}
    574
    575static int put_bitmap(QEMUFile *f, void *pv, size_t size,
    576                      const VMStateField *field, JSONWriter *vmdesc)
    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 = bmp[idx++];
    582        if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
    583            w |= ((uint64_t)bmp[idx++]) << 32;
    584        }
    585        qemu_put_be64(f, w);
    586    }
    587
    588    return 0;
    589}
    590
    591const VMStateInfo vmstate_info_bitmap = {
    592    .name = "bitmap",
    593    .get = get_bitmap,
    594    .put = put_bitmap,
    595};
    596
    597/* get for QTAILQ
    598 * meta data about the QTAILQ is encoded in a VMStateField structure
    599 */
    600static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size,
    601                      const VMStateField *field)
    602{
    603    int ret = 0;
    604    const VMStateDescription *vmsd = field->vmsd;
    605    /* size of a QTAILQ element */
    606    size_t size = field->size;
    607    /* offset of the QTAILQ entry in a QTAILQ element */
    608    size_t entry_offset = field->start;
    609    int version_id = field->version_id;
    610    void *elm;
    611
    612    trace_get_qtailq(vmsd->name, version_id);
    613    if (version_id > vmsd->version_id) {
    614        error_report("%s %s",  vmsd->name, "too new");
    615        trace_get_qtailq_end(vmsd->name, "too new", -EINVAL);
    616
    617        return -EINVAL;
    618    }
    619    if (version_id < vmsd->minimum_version_id) {
    620        error_report("%s %s",  vmsd->name, "too old");
    621        trace_get_qtailq_end(vmsd->name, "too old", -EINVAL);
    622        return -EINVAL;
    623    }
    624
    625    while (qemu_get_byte(f)) {
    626        elm = g_malloc(size);
    627        ret = vmstate_load_state(f, vmsd, elm, version_id);
    628        if (ret) {
    629            return ret;
    630        }
    631        QTAILQ_RAW_INSERT_TAIL(pv, elm, entry_offset);
    632    }
    633
    634    trace_get_qtailq_end(vmsd->name, "end", ret);
    635    return ret;
    636}
    637
    638/* put for QTAILQ */
    639static int put_qtailq(QEMUFile *f, void *pv, size_t unused_size,
    640                      const VMStateField *field, JSONWriter *vmdesc)
    641{
    642    const VMStateDescription *vmsd = field->vmsd;
    643    /* offset of the QTAILQ entry in a QTAILQ element*/
    644    size_t entry_offset = field->start;
    645    void *elm;
    646    int ret;
    647
    648    trace_put_qtailq(vmsd->name, vmsd->version_id);
    649
    650    QTAILQ_RAW_FOREACH(elm, pv, entry_offset) {
    651        qemu_put_byte(f, true);
    652        ret = vmstate_save_state(f, vmsd, elm, vmdesc);
    653        if (ret) {
    654            return ret;
    655        }
    656    }
    657    qemu_put_byte(f, false);
    658
    659    trace_put_qtailq_end(vmsd->name, "end");
    660
    661    return 0;
    662}
    663const VMStateInfo vmstate_info_qtailq = {
    664    .name = "qtailq",
    665    .get  = get_qtailq,
    666    .put  = put_qtailq,
    667};
    668
    669struct put_gtree_data {
    670    QEMUFile *f;
    671    const VMStateDescription *key_vmsd;
    672    const VMStateDescription *val_vmsd;
    673    JSONWriter *vmdesc;
    674    int ret;
    675};
    676
    677static gboolean put_gtree_elem(gpointer key, gpointer value, gpointer data)
    678{
    679    struct put_gtree_data *capsule = (struct put_gtree_data *)data;
    680    QEMUFile *f = capsule->f;
    681    int ret;
    682
    683    qemu_put_byte(f, true);
    684
    685    /* put the key */
    686    if (!capsule->key_vmsd) {
    687        qemu_put_be64(f, (uint64_t)(uintptr_t)(key)); /* direct key */
    688    } else {
    689        ret = vmstate_save_state(f, capsule->key_vmsd, key, capsule->vmdesc);
    690        if (ret) {
    691            capsule->ret = ret;
    692            return true;
    693        }
    694    }
    695
    696    /* put the data */
    697    ret = vmstate_save_state(f, capsule->val_vmsd, value, capsule->vmdesc);
    698    if (ret) {
    699        capsule->ret = ret;
    700        return true;
    701    }
    702    return false;
    703}
    704
    705static int put_gtree(QEMUFile *f, void *pv, size_t unused_size,
    706                     const VMStateField *field, JSONWriter *vmdesc)
    707{
    708    bool direct_key = (!field->start);
    709    const VMStateDescription *key_vmsd = direct_key ? NULL : &field->vmsd[1];
    710    const VMStateDescription *val_vmsd = &field->vmsd[0];
    711    const char *key_vmsd_name = direct_key ? "direct" : key_vmsd->name;
    712    struct put_gtree_data capsule = {
    713        .f = f,
    714        .key_vmsd = key_vmsd,
    715        .val_vmsd = val_vmsd,
    716        .vmdesc = vmdesc,
    717        .ret = 0};
    718    GTree **pval = pv;
    719    GTree *tree = *pval;
    720    uint32_t nnodes = g_tree_nnodes(tree);
    721    int ret;
    722
    723    trace_put_gtree(field->name, key_vmsd_name, val_vmsd->name, nnodes);
    724    qemu_put_be32(f, nnodes);
    725    g_tree_foreach(tree, put_gtree_elem, (gpointer)&capsule);
    726    qemu_put_byte(f, false);
    727    ret = capsule.ret;
    728    if (ret) {
    729        error_report("%s : failed to save gtree (%d)", field->name, ret);
    730    }
    731    trace_put_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
    732    return ret;
    733}
    734
    735static int get_gtree(QEMUFile *f, void *pv, size_t unused_size,
    736                     const VMStateField *field)
    737{
    738    bool direct_key = (!field->start);
    739    const VMStateDescription *key_vmsd = direct_key ? NULL : &field->vmsd[1];
    740    const VMStateDescription *val_vmsd = &field->vmsd[0];
    741    const char *key_vmsd_name = direct_key ? "direct" : key_vmsd->name;
    742    int version_id = field->version_id;
    743    size_t key_size = field->start;
    744    size_t val_size = field->size;
    745    int nnodes, count = 0;
    746    GTree **pval = pv;
    747    GTree *tree = *pval;
    748    void *key, *val;
    749    int ret = 0;
    750
    751    /* in case of direct key, the key vmsd can be {}, ie. check fields */
    752    if (!direct_key && version_id > key_vmsd->version_id) {
    753        error_report("%s %s",  key_vmsd->name, "too new");
    754        return -EINVAL;
    755    }
    756    if (!direct_key && version_id < key_vmsd->minimum_version_id) {
    757        error_report("%s %s",  key_vmsd->name, "too old");
    758        return -EINVAL;
    759    }
    760    if (version_id > val_vmsd->version_id) {
    761        error_report("%s %s",  val_vmsd->name, "too new");
    762        return -EINVAL;
    763    }
    764    if (version_id < val_vmsd->minimum_version_id) {
    765        error_report("%s %s",  val_vmsd->name, "too old");
    766        return -EINVAL;
    767    }
    768
    769    nnodes = qemu_get_be32(f);
    770    trace_get_gtree(field->name, key_vmsd_name, val_vmsd->name, nnodes);
    771
    772    while (qemu_get_byte(f)) {
    773        if ((++count) > nnodes) {
    774            ret = -EINVAL;
    775            break;
    776        }
    777        if (direct_key) {
    778            key = (void *)(uintptr_t)qemu_get_be64(f);
    779        } else {
    780            key = g_malloc0(key_size);
    781            ret = vmstate_load_state(f, key_vmsd, key, version_id);
    782            if (ret) {
    783                error_report("%s : failed to load %s (%d)",
    784                             field->name, key_vmsd->name, ret);
    785                goto key_error;
    786            }
    787        }
    788        val = g_malloc0(val_size);
    789        ret = vmstate_load_state(f, val_vmsd, val, version_id);
    790        if (ret) {
    791            error_report("%s : failed to load %s (%d)",
    792                         field->name, val_vmsd->name, ret);
    793            goto val_error;
    794        }
    795        g_tree_insert(tree, key, val);
    796    }
    797    if (count != nnodes) {
    798        error_report("%s inconsistent stream when loading the gtree",
    799                     field->name);
    800        return -EINVAL;
    801    }
    802    trace_get_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
    803    return ret;
    804val_error:
    805    g_free(val);
    806key_error:
    807    if (!direct_key) {
    808        g_free(key);
    809    }
    810    trace_get_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
    811    return ret;
    812}
    813
    814
    815const VMStateInfo vmstate_info_gtree = {
    816    .name = "gtree",
    817    .get  = get_gtree,
    818    .put  = put_gtree,
    819};
    820
    821static int put_qlist(QEMUFile *f, void *pv, size_t unused_size,
    822                     const VMStateField *field, JSONWriter *vmdesc)
    823{
    824    const VMStateDescription *vmsd = field->vmsd;
    825    /* offset of the QTAILQ entry in a QTAILQ element*/
    826    size_t entry_offset = field->start;
    827    void *elm;
    828    int ret;
    829
    830    trace_put_qlist(field->name, vmsd->name, vmsd->version_id);
    831    QLIST_RAW_FOREACH(elm, pv, entry_offset) {
    832        qemu_put_byte(f, true);
    833        ret = vmstate_save_state(f, vmsd, elm, vmdesc);
    834        if (ret) {
    835            error_report("%s: failed to save %s (%d)", field->name,
    836                         vmsd->name, ret);
    837            return ret;
    838        }
    839    }
    840    qemu_put_byte(f, false);
    841    trace_put_qlist_end(field->name, vmsd->name);
    842
    843    return 0;
    844}
    845
    846static int get_qlist(QEMUFile *f, void *pv, size_t unused_size,
    847                     const VMStateField *field)
    848{
    849    int ret = 0;
    850    const VMStateDescription *vmsd = field->vmsd;
    851    /* size of a QLIST element */
    852    size_t size = field->size;
    853    /* offset of the QLIST entry in a QLIST element */
    854    size_t entry_offset = field->start;
    855    int version_id = field->version_id;
    856    void *elm, *prev = NULL;
    857
    858    trace_get_qlist(field->name, vmsd->name, vmsd->version_id);
    859    if (version_id > vmsd->version_id) {
    860        error_report("%s %s",  vmsd->name, "too new");
    861        return -EINVAL;
    862    }
    863    if (version_id < vmsd->minimum_version_id) {
    864        error_report("%s %s",  vmsd->name, "too old");
    865        return -EINVAL;
    866    }
    867
    868    while (qemu_get_byte(f)) {
    869        elm = g_malloc(size);
    870        ret = vmstate_load_state(f, vmsd, elm, version_id);
    871        if (ret) {
    872            error_report("%s: failed to load %s (%d)", field->name,
    873                         vmsd->name, ret);
    874            g_free(elm);
    875            return ret;
    876        }
    877        if (!prev) {
    878            QLIST_RAW_INSERT_HEAD(pv, elm, entry_offset);
    879        } else {
    880            QLIST_RAW_INSERT_AFTER(pv, prev, elm, entry_offset);
    881        }
    882        prev = elm;
    883    }
    884    trace_get_qlist_end(field->name, vmsd->name);
    885
    886    return ret;
    887}
    888
    889const VMStateInfo vmstate_info_qlist = {
    890    .name = "qlist",
    891    .get  = get_qlist,
    892    .put  = put_qlist,
    893};