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

test-vmstate.c (45968B)


      1/*
      2 *  Test code for VMState
      3 *
      4 *  Copyright (c) 2013 Red Hat Inc.
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25#include "qemu/osdep.h"
     26
     27#include "../migration/migration.h"
     28#include "migration/vmstate.h"
     29#include "migration/qemu-file-types.h"
     30#include "../migration/qemu-file.h"
     31#include "../migration/qemu-file-channel.h"
     32#include "../migration/savevm.h"
     33#include "qemu/coroutine.h"
     34#include "qemu/module.h"
     35#include "io/channel-file.h"
     36
     37static int temp_fd;
     38
     39
     40/* Duplicate temp_fd and seek to the beginning of the file */
     41static QEMUFile *open_test_file(bool write)
     42{
     43    int fd;
     44    QIOChannel *ioc;
     45    QEMUFile *f;
     46
     47    fd = dup(temp_fd);
     48    g_assert(fd >= 0);
     49    lseek(fd, 0, SEEK_SET);
     50    if (write) {
     51        g_assert_cmpint(ftruncate(fd, 0), ==, 0);
     52    }
     53    ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
     54    if (write) {
     55        f = qemu_fopen_channel_output(ioc);
     56    } else {
     57        f = qemu_fopen_channel_input(ioc);
     58    }
     59    object_unref(OBJECT(ioc));
     60    return f;
     61}
     62
     63#define SUCCESS(val) \
     64    g_assert_cmpint((val), ==, 0)
     65
     66#define FAILURE(val) \
     67    g_assert_cmpint((val), !=, 0)
     68
     69static void save_vmstate(const VMStateDescription *desc, void *obj)
     70{
     71    QEMUFile *f = open_test_file(true);
     72
     73    /* Save file with vmstate */
     74    int ret = vmstate_save_state(f, desc, obj, NULL);
     75    g_assert(!ret);
     76    qemu_put_byte(f, QEMU_VM_EOF);
     77    g_assert(!qemu_file_get_error(f));
     78    qemu_fclose(f);
     79}
     80
     81static void save_buffer(const uint8_t *buf, size_t buf_size)
     82{
     83    QEMUFile *fsave = open_test_file(true);
     84    qemu_put_buffer(fsave, buf, buf_size);
     85    qemu_fclose(fsave);
     86}
     87
     88static void compare_vmstate(const uint8_t *wire, size_t size)
     89{
     90    QEMUFile *f = open_test_file(false);
     91    uint8_t result[size];
     92
     93    /* read back as binary */
     94
     95    g_assert_cmpint(qemu_get_buffer(f, result, sizeof(result)), ==,
     96                    sizeof(result));
     97    g_assert(!qemu_file_get_error(f));
     98
     99    /* Compare that what is on the file is the same that what we
    100       expected to be there */
    101    SUCCESS(memcmp(result, wire, sizeof(result)));
    102
    103    /* Must reach EOF */
    104    qemu_get_byte(f);
    105    g_assert_cmpint(qemu_file_get_error(f), ==, -EIO);
    106
    107    qemu_fclose(f);
    108}
    109
    110static int load_vmstate_one(const VMStateDescription *desc, void *obj,
    111                            int version, const uint8_t *wire, size_t size)
    112{
    113    QEMUFile *f;
    114    int ret;
    115
    116    f = open_test_file(true);
    117    qemu_put_buffer(f, wire, size);
    118    qemu_fclose(f);
    119
    120    f = open_test_file(false);
    121    ret = vmstate_load_state(f, desc, obj, version);
    122    if (ret) {
    123        g_assert(qemu_file_get_error(f));
    124    } else{
    125        g_assert(!qemu_file_get_error(f));
    126    }
    127    qemu_fclose(f);
    128    return ret;
    129}
    130
    131
    132static int load_vmstate(const VMStateDescription *desc,
    133                        void *obj, void *obj_clone,
    134                        void (*obj_copy)(void *, void*),
    135                        int version, const uint8_t *wire, size_t size)
    136{
    137    /* We test with zero size */
    138    obj_copy(obj_clone, obj);
    139    FAILURE(load_vmstate_one(desc, obj, version, wire, 0));
    140
    141    /* Stream ends with QEMU_EOF, so we need at least 3 bytes to be
    142     * able to test in the middle */
    143
    144    if (size > 3) {
    145
    146        /* We test with size - 2. We can't test size - 1 due to EOF tricks */
    147        obj_copy(obj, obj_clone);
    148        FAILURE(load_vmstate_one(desc, obj, version, wire, size - 2));
    149
    150        /* Test with size/2, first half of real state */
    151        obj_copy(obj, obj_clone);
    152        FAILURE(load_vmstate_one(desc, obj, version, wire, size/2));
    153
    154        /* Test with size/2, second half of real state */
    155        obj_copy(obj, obj_clone);
    156        FAILURE(load_vmstate_one(desc, obj, version, wire + (size/2), size/2));
    157
    158    }
    159    obj_copy(obj, obj_clone);
    160    return load_vmstate_one(desc, obj, version, wire, size);
    161}
    162
    163/* Test struct that we are going to use for our tests */
    164
    165typedef struct TestSimple {
    166    bool     b_1,   b_2;
    167    uint8_t  u8_1;
    168    uint16_t u16_1;
    169    uint32_t u32_1;
    170    uint64_t u64_1;
    171    int8_t   i8_1,  i8_2;
    172    int16_t  i16_1, i16_2;
    173    int32_t  i32_1, i32_2;
    174    int64_t  i64_1, i64_2;
    175} TestSimple;
    176
    177/* Object instantiation, we are going to use it in more than one test */
    178
    179TestSimple obj_simple = {
    180    .b_1 = true,
    181    .b_2 = false,
    182    .u8_1 = 130,
    183    .u16_1 = 512,
    184    .u32_1 = 70000,
    185    .u64_1 = 12121212,
    186    .i8_1 = 65,
    187    .i8_2 = -65,
    188    .i16_1 = 512,
    189    .i16_2 = -512,
    190    .i32_1 = 70000,
    191    .i32_2 = -70000,
    192    .i64_1 = 12121212,
    193    .i64_2 = -12121212,
    194};
    195
    196/* Description of the values.  If you add a primitive type
    197   you are expected to add a test here */
    198
    199static const VMStateDescription vmstate_simple_primitive = {
    200    .name = "simple/primitive",
    201    .version_id = 1,
    202    .minimum_version_id = 1,
    203    .fields = (VMStateField[]) {
    204        VMSTATE_BOOL(b_1, TestSimple),
    205        VMSTATE_BOOL(b_2, TestSimple),
    206        VMSTATE_UINT8(u8_1, TestSimple),
    207        VMSTATE_UINT16(u16_1, TestSimple),
    208        VMSTATE_UINT32(u32_1, TestSimple),
    209        VMSTATE_UINT64(u64_1, TestSimple),
    210        VMSTATE_INT8(i8_1, TestSimple),
    211        VMSTATE_INT8(i8_2, TestSimple),
    212        VMSTATE_INT16(i16_1, TestSimple),
    213        VMSTATE_INT16(i16_2, TestSimple),
    214        VMSTATE_INT32(i32_1, TestSimple),
    215        VMSTATE_INT32(i32_2, TestSimple),
    216        VMSTATE_INT64(i64_1, TestSimple),
    217        VMSTATE_INT64(i64_2, TestSimple),
    218        VMSTATE_END_OF_LIST()
    219    }
    220};
    221
    222/* It describes what goes through the wire.  Our tests are basically:
    223
    224   * save test
    225     - save a struct a vmstate to a file
    226     - read that file back (binary read, no vmstate)
    227     - compare it with what we expect to be on the wire
    228   * load test
    229     - save to the file what we expect to be on the wire
    230     - read struct back with vmstate in a different
    231     - compare back with the original struct
    232*/
    233
    234uint8_t wire_simple_primitive[] = {
    235    /* b_1 */   0x01,
    236    /* b_2 */   0x00,
    237    /* u8_1 */  0x82,
    238    /* u16_1 */ 0x02, 0x00,
    239    /* u32_1 */ 0x00, 0x01, 0x11, 0x70,
    240    /* u64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
    241    /* i8_1 */  0x41,
    242    /* i8_2 */  0xbf,
    243    /* i16_1 */ 0x02, 0x00,
    244    /* i16_2 */ 0xfe, 0x0,
    245    /* i32_1 */ 0x00, 0x01, 0x11, 0x70,
    246    /* i32_2 */ 0xff, 0xfe, 0xee, 0x90,
    247    /* i64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
    248    /* i64_2 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x0b, 0x84,
    249    QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
    250};
    251
    252static void obj_simple_copy(void *target, void *source)
    253{
    254    memcpy(target, source, sizeof(TestSimple));
    255}
    256
    257static void test_simple_primitive(void)
    258{
    259    TestSimple obj, obj_clone;
    260
    261    memset(&obj, 0, sizeof(obj));
    262    save_vmstate(&vmstate_simple_primitive, &obj_simple);
    263
    264    compare_vmstate(wire_simple_primitive, sizeof(wire_simple_primitive));
    265
    266    SUCCESS(load_vmstate(&vmstate_simple_primitive, &obj, &obj_clone,
    267                         obj_simple_copy, 1, wire_simple_primitive,
    268                         sizeof(wire_simple_primitive)));
    269
    270#define FIELD_EQUAL(name)   g_assert_cmpint(obj.name, ==, obj_simple.name)
    271
    272    FIELD_EQUAL(b_1);
    273    FIELD_EQUAL(b_2);
    274    FIELD_EQUAL(u8_1);
    275    FIELD_EQUAL(u16_1);
    276    FIELD_EQUAL(u32_1);
    277    FIELD_EQUAL(u64_1);
    278    FIELD_EQUAL(i8_1);
    279    FIELD_EQUAL(i8_2);
    280    FIELD_EQUAL(i16_1);
    281    FIELD_EQUAL(i16_2);
    282    FIELD_EQUAL(i32_1);
    283    FIELD_EQUAL(i32_2);
    284    FIELD_EQUAL(i64_1);
    285    FIELD_EQUAL(i64_2);
    286}
    287
    288typedef struct TestSimpleArray {
    289    uint16_t u16_1[3];
    290} TestSimpleArray;
    291
    292/* Object instantiation, we are going to use it in more than one test */
    293
    294TestSimpleArray obj_simple_arr = {
    295    .u16_1 = { 0x42, 0x43, 0x44 },
    296};
    297
    298/* Description of the values.  If you add a primitive type
    299   you are expected to add a test here */
    300
    301static const VMStateDescription vmstate_simple_arr = {
    302    .name = "simple/array",
    303    .version_id = 1,
    304    .minimum_version_id = 1,
    305    .fields = (VMStateField[]) {
    306        VMSTATE_UINT16_ARRAY(u16_1, TestSimpleArray, 3),
    307        VMSTATE_END_OF_LIST()
    308    }
    309};
    310
    311uint8_t wire_simple_arr[] = {
    312    /* u16_1 */ 0x00, 0x42,
    313    /* u16_1 */ 0x00, 0x43,
    314    /* u16_1 */ 0x00, 0x44,
    315    QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
    316};
    317
    318static void obj_simple_arr_copy(void *target, void *source)
    319{
    320    memcpy(target, source, sizeof(TestSimpleArray));
    321}
    322
    323static void test_simple_array(void)
    324{
    325    TestSimpleArray obj, obj_clone;
    326
    327    memset(&obj, 0, sizeof(obj));
    328    save_vmstate(&vmstate_simple_arr, &obj_simple_arr);
    329
    330    compare_vmstate(wire_simple_arr, sizeof(wire_simple_arr));
    331
    332    SUCCESS(load_vmstate(&vmstate_simple_arr, &obj, &obj_clone,
    333                         obj_simple_arr_copy, 1, wire_simple_arr,
    334                         sizeof(wire_simple_arr)));
    335}
    336
    337typedef struct TestStruct {
    338    uint32_t a, b, c, e;
    339    uint64_t d, f;
    340    bool skip_c_e;
    341} TestStruct;
    342
    343static const VMStateDescription vmstate_versioned = {
    344    .name = "test/versioned",
    345    .version_id = 2,
    346    .minimum_version_id = 1,
    347    .fields = (VMStateField[]) {
    348        VMSTATE_UINT32(a, TestStruct),
    349        VMSTATE_UINT32_V(b, TestStruct, 2), /* Versioned field in the middle, so
    350                                             * we catch bugs more easily.
    351                                             */
    352        VMSTATE_UINT32(c, TestStruct),
    353        VMSTATE_UINT64(d, TestStruct),
    354        VMSTATE_UINT32_V(e, TestStruct, 2),
    355        VMSTATE_UINT64_V(f, TestStruct, 2),
    356        VMSTATE_END_OF_LIST()
    357    }
    358};
    359
    360static void test_load_v1(void)
    361{
    362    uint8_t buf[] = {
    363        0, 0, 0, 10,             /* a */
    364        0, 0, 0, 30,             /* c */
    365        0, 0, 0, 0, 0, 0, 0, 40, /* d */
    366        QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
    367    };
    368    save_buffer(buf, sizeof(buf));
    369
    370    QEMUFile *loading = open_test_file(false);
    371    TestStruct obj = { .b = 200, .e = 500, .f = 600 };
    372    vmstate_load_state(loading, &vmstate_versioned, &obj, 1);
    373    g_assert(!qemu_file_get_error(loading));
    374    g_assert_cmpint(obj.a, ==, 10);
    375    g_assert_cmpint(obj.b, ==, 200);
    376    g_assert_cmpint(obj.c, ==, 30);
    377    g_assert_cmpint(obj.d, ==, 40);
    378    g_assert_cmpint(obj.e, ==, 500);
    379    g_assert_cmpint(obj.f, ==, 600);
    380    qemu_fclose(loading);
    381}
    382
    383static void test_load_v2(void)
    384{
    385    uint8_t buf[] = {
    386        0, 0, 0, 10,             /* a */
    387        0, 0, 0, 20,             /* b */
    388        0, 0, 0, 30,             /* c */
    389        0, 0, 0, 0, 0, 0, 0, 40, /* d */
    390        0, 0, 0, 50,             /* e */
    391        0, 0, 0, 0, 0, 0, 0, 60, /* f */
    392        QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
    393    };
    394    save_buffer(buf, sizeof(buf));
    395
    396    QEMUFile *loading = open_test_file(false);
    397    TestStruct obj;
    398    vmstate_load_state(loading, &vmstate_versioned, &obj, 2);
    399    g_assert_cmpint(obj.a, ==, 10);
    400    g_assert_cmpint(obj.b, ==, 20);
    401    g_assert_cmpint(obj.c, ==, 30);
    402    g_assert_cmpint(obj.d, ==, 40);
    403    g_assert_cmpint(obj.e, ==, 50);
    404    g_assert_cmpint(obj.f, ==, 60);
    405    qemu_fclose(loading);
    406}
    407
    408static bool test_skip(void *opaque, int version_id)
    409{
    410    TestStruct *t = (TestStruct *)opaque;
    411    return !t->skip_c_e;
    412}
    413
    414static const VMStateDescription vmstate_skipping = {
    415    .name = "test/skip",
    416    .version_id = 2,
    417    .minimum_version_id = 1,
    418    .fields = (VMStateField[]) {
    419        VMSTATE_UINT32(a, TestStruct),
    420        VMSTATE_UINT32(b, TestStruct),
    421        VMSTATE_UINT32_TEST(c, TestStruct, test_skip),
    422        VMSTATE_UINT64(d, TestStruct),
    423        VMSTATE_UINT32_TEST(e, TestStruct, test_skip),
    424        VMSTATE_UINT64_V(f, TestStruct, 2),
    425        VMSTATE_END_OF_LIST()
    426    }
    427};
    428
    429
    430static void test_save_noskip(void)
    431{
    432    QEMUFile *fsave = open_test_file(true);
    433    TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
    434                       .skip_c_e = false };
    435    int ret = vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL);
    436    g_assert(!ret);
    437    g_assert(!qemu_file_get_error(fsave));
    438
    439    uint8_t expected[] = {
    440        0, 0, 0, 1,             /* a */
    441        0, 0, 0, 2,             /* b */
    442        0, 0, 0, 3,             /* c */
    443        0, 0, 0, 0, 0, 0, 0, 4, /* d */
    444        0, 0, 0, 5,             /* e */
    445        0, 0, 0, 0, 0, 0, 0, 6, /* f */
    446    };
    447
    448    qemu_fclose(fsave);
    449    compare_vmstate(expected, sizeof(expected));
    450}
    451
    452static void test_save_skip(void)
    453{
    454    QEMUFile *fsave = open_test_file(true);
    455    TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
    456                       .skip_c_e = true };
    457    int ret = vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL);
    458    g_assert(!ret);
    459    g_assert(!qemu_file_get_error(fsave));
    460
    461    uint8_t expected[] = {
    462        0, 0, 0, 1,             /* a */
    463        0, 0, 0, 2,             /* b */
    464        0, 0, 0, 0, 0, 0, 0, 4, /* d */
    465        0, 0, 0, 0, 0, 0, 0, 6, /* f */
    466    };
    467
    468    qemu_fclose(fsave);
    469    compare_vmstate(expected, sizeof(expected));
    470}
    471
    472static void test_load_noskip(void)
    473{
    474    uint8_t buf[] = {
    475        0, 0, 0, 10,             /* a */
    476        0, 0, 0, 20,             /* b */
    477        0, 0, 0, 30,             /* c */
    478        0, 0, 0, 0, 0, 0, 0, 40, /* d */
    479        0, 0, 0, 50,             /* e */
    480        0, 0, 0, 0, 0, 0, 0, 60, /* f */
    481        QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
    482    };
    483    save_buffer(buf, sizeof(buf));
    484
    485    QEMUFile *loading = open_test_file(false);
    486    TestStruct obj = { .skip_c_e = false };
    487    vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
    488    g_assert(!qemu_file_get_error(loading));
    489    g_assert_cmpint(obj.a, ==, 10);
    490    g_assert_cmpint(obj.b, ==, 20);
    491    g_assert_cmpint(obj.c, ==, 30);
    492    g_assert_cmpint(obj.d, ==, 40);
    493    g_assert_cmpint(obj.e, ==, 50);
    494    g_assert_cmpint(obj.f, ==, 60);
    495    qemu_fclose(loading);
    496}
    497
    498static void test_load_skip(void)
    499{
    500    uint8_t buf[] = {
    501        0, 0, 0, 10,             /* a */
    502        0, 0, 0, 20,             /* b */
    503        0, 0, 0, 0, 0, 0, 0, 40, /* d */
    504        0, 0, 0, 0, 0, 0, 0, 60, /* f */
    505        QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
    506    };
    507    save_buffer(buf, sizeof(buf));
    508
    509    QEMUFile *loading = open_test_file(false);
    510    TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
    511    vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
    512    g_assert(!qemu_file_get_error(loading));
    513    g_assert_cmpint(obj.a, ==, 10);
    514    g_assert_cmpint(obj.b, ==, 20);
    515    g_assert_cmpint(obj.c, ==, 300);
    516    g_assert_cmpint(obj.d, ==, 40);
    517    g_assert_cmpint(obj.e, ==, 500);
    518    g_assert_cmpint(obj.f, ==, 60);
    519    qemu_fclose(loading);
    520}
    521
    522typedef struct {
    523    int32_t i;
    524} TestStructTriv;
    525
    526const VMStateDescription vmsd_tst = {
    527    .name = "test/tst",
    528    .version_id = 1,
    529    .minimum_version_id = 1,
    530    .fields = (VMStateField[]) {
    531        VMSTATE_INT32(i, TestStructTriv),
    532        VMSTATE_END_OF_LIST()
    533    }
    534};
    535
    536/* test array migration */
    537
    538#define AR_SIZE 4
    539
    540typedef struct {
    541    TestStructTriv *ar[AR_SIZE];
    542} TestArrayOfPtrToStuct;
    543
    544const VMStateDescription vmsd_arps = {
    545    .name = "test/arps",
    546    .version_id = 1,
    547    .minimum_version_id = 1,
    548    .fields = (VMStateField[]) {
    549        VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(ar, TestArrayOfPtrToStuct,
    550                AR_SIZE, 0, vmsd_tst, TestStructTriv),
    551        VMSTATE_END_OF_LIST()
    552    }
    553};
    554
    555static uint8_t wire_arr_ptr_no0[] = {
    556    0x00, 0x00, 0x00, 0x00,
    557    0x00, 0x00, 0x00, 0x01,
    558    0x00, 0x00, 0x00, 0x02,
    559    0x00, 0x00, 0x00, 0x03,
    560    QEMU_VM_EOF
    561};
    562
    563static void test_arr_ptr_str_no0_save(void)
    564{
    565    TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
    566    TestArrayOfPtrToStuct sample = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} };
    567
    568    save_vmstate(&vmsd_arps, &sample);
    569    compare_vmstate(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0));
    570}
    571
    572static void test_arr_ptr_str_no0_load(void)
    573{
    574    TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
    575    TestStructTriv ar[AR_SIZE] = {};
    576    TestArrayOfPtrToStuct obj = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} };
    577    int idx;
    578
    579    save_buffer(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0));
    580    SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1,
    581                          wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0)));
    582    for (idx = 0; idx < AR_SIZE; ++idx) {
    583        /* compare the target array ar with the ground truth array ar_gt */
    584        g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i);
    585    }
    586}
    587
    588static uint8_t wire_arr_ptr_0[] = {
    589    0x00, 0x00, 0x00, 0x00,
    590    VMS_NULLPTR_MARKER,
    591    0x00, 0x00, 0x00, 0x02,
    592    0x00, 0x00, 0x00, 0x03,
    593    QEMU_VM_EOF
    594};
    595
    596static void test_arr_ptr_str_0_save(void)
    597{
    598    TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
    599    TestArrayOfPtrToStuct sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
    600
    601    save_vmstate(&vmsd_arps, &sample);
    602    compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
    603}
    604
    605static void test_arr_ptr_str_0_load(void)
    606{
    607    TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 0}, {.i = 2}, {.i = 3} };
    608    TestStructTriv ar[AR_SIZE] = {};
    609    TestArrayOfPtrToStuct obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
    610    int idx;
    611
    612    save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
    613    SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1,
    614                          wire_arr_ptr_0, sizeof(wire_arr_ptr_0)));
    615    for (idx = 0; idx < AR_SIZE; ++idx) {
    616        /* compare the target array ar with the ground truth array ar_gt */
    617        g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i);
    618    }
    619    for (idx = 0; idx < AR_SIZE; ++idx) {
    620        if (idx == 1) {
    621            g_assert_cmpint((uintptr_t)(obj.ar[idx]), ==, 0);
    622        } else {
    623            g_assert_cmpint((uintptr_t)(obj.ar[idx]), !=, 0);
    624        }
    625    }
    626}
    627
    628typedef struct TestArrayOfPtrToInt {
    629    int32_t *ar[AR_SIZE];
    630} TestArrayOfPtrToInt;
    631
    632const VMStateDescription vmsd_arpp = {
    633    .name = "test/arps",
    634    .version_id = 1,
    635    .minimum_version_id = 1,
    636    .fields = (VMStateField[]) {
    637        VMSTATE_ARRAY_OF_POINTER(ar, TestArrayOfPtrToInt,
    638                AR_SIZE, 0, vmstate_info_int32, int32_t*),
    639        VMSTATE_END_OF_LIST()
    640    }
    641};
    642
    643static void test_arr_ptr_prim_0_save(void)
    644{
    645    int32_t ar[AR_SIZE] = {0 , 1, 2, 3};
    646    TestArrayOfPtrToInt  sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
    647
    648    save_vmstate(&vmsd_arpp, &sample);
    649    compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
    650}
    651
    652static void test_arr_ptr_prim_0_load(void)
    653{
    654    int32_t ar_gt[AR_SIZE] = {0, 1, 2, 3};
    655    int32_t ar[AR_SIZE] = {3 , 42, 1, 0};
    656    TestArrayOfPtrToInt obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
    657    int idx;
    658
    659    save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
    660    SUCCESS(load_vmstate_one(&vmsd_arpp, &obj, 1,
    661                          wire_arr_ptr_0, sizeof(wire_arr_ptr_0)));
    662    for (idx = 0; idx < AR_SIZE; ++idx) {
    663        /* compare the target array ar with the ground truth array ar_gt */
    664        if (idx == 1) {
    665            g_assert_cmpint(42, ==, ar[idx]);
    666        } else {
    667            g_assert_cmpint(ar_gt[idx], ==, ar[idx]);
    668        }
    669    }
    670}
    671
    672/* test QTAILQ migration */
    673typedef struct TestQtailqElement TestQtailqElement;
    674
    675struct TestQtailqElement {
    676    bool     b;
    677    uint8_t  u8;
    678    QTAILQ_ENTRY(TestQtailqElement) next;
    679};
    680
    681typedef struct TestQtailq {
    682    int16_t  i16;
    683    QTAILQ_HEAD(, TestQtailqElement) q;
    684    int32_t  i32;
    685} TestQtailq;
    686
    687static const VMStateDescription vmstate_q_element = {
    688    .name = "test/queue-element",
    689    .version_id = 1,
    690    .minimum_version_id = 1,
    691    .fields = (VMStateField[]) {
    692        VMSTATE_BOOL(b, TestQtailqElement),
    693        VMSTATE_UINT8(u8, TestQtailqElement),
    694        VMSTATE_END_OF_LIST()
    695    },
    696};
    697
    698static const VMStateDescription vmstate_q = {
    699    .name = "test/queue",
    700    .version_id = 1,
    701    .minimum_version_id = 1,
    702    .fields = (VMStateField[]) {
    703        VMSTATE_INT16(i16, TestQtailq),
    704        VMSTATE_QTAILQ_V(q, TestQtailq, 1, vmstate_q_element, TestQtailqElement,
    705                         next),
    706        VMSTATE_INT32(i32, TestQtailq),
    707        VMSTATE_END_OF_LIST()
    708    }
    709};
    710
    711uint8_t wire_q[] = {
    712    /* i16 */                     0xfe, 0x0,
    713    /* start of element 0 of q */ 0x01,
    714    /* .b  */                     0x01,
    715    /* .u8 */                     0x82,
    716    /* start of element 1 of q */ 0x01,
    717    /* b */                       0x00,
    718    /* u8 */                      0x41,
    719    /* end of q */                0x00,
    720    /* i32 */                     0x00, 0x01, 0x11, 0x70,
    721    QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
    722};
    723
    724static void test_save_q(void)
    725{
    726    TestQtailq obj_q = {
    727        .i16 = -512,
    728        .i32 = 70000,
    729    };
    730
    731    TestQtailqElement obj_qe1 = {
    732        .b = true,
    733        .u8 = 130,
    734    };
    735
    736    TestQtailqElement obj_qe2 = {
    737        .b = false,
    738        .u8 = 65,
    739    };
    740
    741    QTAILQ_INIT(&obj_q.q);
    742    QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next);
    743    QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next);
    744
    745    save_vmstate(&vmstate_q, &obj_q);
    746    compare_vmstate(wire_q, sizeof(wire_q));
    747}
    748
    749static void test_load_q(void)
    750{
    751    TestQtailq obj_q = {
    752        .i16 = -512,
    753        .i32 = 70000,
    754    };
    755
    756    TestQtailqElement obj_qe1 = {
    757        .b = true,
    758        .u8 = 130,
    759    };
    760
    761    TestQtailqElement obj_qe2 = {
    762        .b = false,
    763        .u8 = 65,
    764    };
    765
    766    QTAILQ_INIT(&obj_q.q);
    767    QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next);
    768    QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next);
    769
    770    QEMUFile *fsave = open_test_file(true);
    771
    772    qemu_put_buffer(fsave, wire_q, sizeof(wire_q));
    773    g_assert(!qemu_file_get_error(fsave));
    774    qemu_fclose(fsave);
    775
    776    QEMUFile *fload = open_test_file(false);
    777    TestQtailq tgt;
    778
    779    QTAILQ_INIT(&tgt.q);
    780    vmstate_load_state(fload, &vmstate_q, &tgt, 1);
    781    char eof = qemu_get_byte(fload);
    782    g_assert(!qemu_file_get_error(fload));
    783    g_assert_cmpint(tgt.i16, ==, obj_q.i16);
    784    g_assert_cmpint(tgt.i32, ==, obj_q.i32);
    785    g_assert_cmpint(eof, ==, QEMU_VM_EOF);
    786
    787    TestQtailqElement *qele_from = QTAILQ_FIRST(&obj_q.q);
    788    TestQtailqElement *qlast_from = QTAILQ_LAST(&obj_q.q);
    789    TestQtailqElement *qele_to = QTAILQ_FIRST(&tgt.q);
    790    TestQtailqElement *qlast_to = QTAILQ_LAST(&tgt.q);
    791
    792    while (1) {
    793        g_assert_cmpint(qele_to->b, ==, qele_from->b);
    794        g_assert_cmpint(qele_to->u8, ==, qele_from->u8);
    795        if ((qele_from == qlast_from) || (qele_to == qlast_to)) {
    796            break;
    797        }
    798        qele_from = QTAILQ_NEXT(qele_from, next);
    799        qele_to = QTAILQ_NEXT(qele_to, next);
    800    }
    801
    802    g_assert_cmpint((uintptr_t) qele_from, ==, (uintptr_t) qlast_from);
    803    g_assert_cmpint((uintptr_t) qele_to, ==, (uintptr_t) qlast_to);
    804
    805    /* clean up */
    806    TestQtailqElement *qele;
    807    while (!QTAILQ_EMPTY(&tgt.q)) {
    808        qele = QTAILQ_LAST(&tgt.q);
    809        QTAILQ_REMOVE(&tgt.q, qele, next);
    810        free(qele);
    811        qele = NULL;
    812    }
    813    qemu_fclose(fload);
    814}
    815
    816/* interval (key) */
    817typedef struct TestGTreeInterval {
    818    uint64_t low;
    819    uint64_t high;
    820} TestGTreeInterval;
    821
    822#define VMSTATE_INTERVAL                               \
    823{                                                      \
    824    .name = "interval",                                \
    825    .version_id = 1,                                   \
    826    .minimum_version_id = 1,                           \
    827    .fields = (VMStateField[]) {                       \
    828        VMSTATE_UINT64(low, TestGTreeInterval),        \
    829        VMSTATE_UINT64(high, TestGTreeInterval),       \
    830        VMSTATE_END_OF_LIST()                          \
    831    }                                                  \
    832}
    833
    834/* mapping (value) */
    835typedef struct TestGTreeMapping {
    836    uint64_t phys_addr;
    837    uint32_t flags;
    838} TestGTreeMapping;
    839
    840#define VMSTATE_MAPPING                               \
    841{                                                     \
    842    .name = "mapping",                                \
    843    .version_id = 1,                                  \
    844    .minimum_version_id = 1,                          \
    845    .fields = (VMStateField[]) {                      \
    846        VMSTATE_UINT64(phys_addr, TestGTreeMapping),  \
    847        VMSTATE_UINT32(flags, TestGTreeMapping),      \
    848        VMSTATE_END_OF_LIST()                         \
    849    },                                                \
    850}
    851
    852static const VMStateDescription vmstate_interval_mapping[2] = {
    853    VMSTATE_MAPPING,   /* value */
    854    VMSTATE_INTERVAL   /* key   */
    855};
    856
    857typedef struct TestGTreeDomain {
    858    int32_t  id;
    859    GTree    *mappings;
    860} TestGTreeDomain;
    861
    862typedef struct TestGTreeIOMMU {
    863    int32_t  id;
    864    GTree    *domains;
    865} TestGTreeIOMMU;
    866
    867/* Interval comparison function */
    868static gint interval_cmp(gconstpointer a, gconstpointer b, gpointer user_data)
    869{
    870    TestGTreeInterval *inta = (TestGTreeInterval *)a;
    871    TestGTreeInterval *intb = (TestGTreeInterval *)b;
    872
    873    if (inta->high < intb->low) {
    874        return -1;
    875    } else if (intb->high < inta->low) {
    876        return 1;
    877    } else {
    878        return 0;
    879    }
    880}
    881
    882/* ID comparison function */
    883static gint int_cmp(gconstpointer a, gconstpointer b, gpointer user_data)
    884{
    885    guint ua = GPOINTER_TO_UINT(a);
    886    guint ub = GPOINTER_TO_UINT(b);
    887    return (ua > ub) - (ua < ub);
    888}
    889
    890static void destroy_domain(gpointer data)
    891{
    892    TestGTreeDomain *domain = (TestGTreeDomain *)data;
    893
    894    g_tree_destroy(domain->mappings);
    895    g_free(domain);
    896}
    897
    898static int domain_preload(void *opaque)
    899{
    900    TestGTreeDomain *domain = opaque;
    901
    902    domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp,
    903                                       NULL, g_free, g_free);
    904    return 0;
    905}
    906
    907static int iommu_preload(void *opaque)
    908{
    909    TestGTreeIOMMU *iommu = opaque;
    910
    911    iommu->domains = g_tree_new_full((GCompareDataFunc)int_cmp,
    912                                     NULL, NULL, destroy_domain);
    913    return 0;
    914}
    915
    916static const VMStateDescription vmstate_domain = {
    917    .name = "domain",
    918    .version_id = 1,
    919    .minimum_version_id = 1,
    920    .pre_load = domain_preload,
    921    .fields = (VMStateField[]) {
    922        VMSTATE_INT32(id, TestGTreeDomain),
    923        VMSTATE_GTREE_V(mappings, TestGTreeDomain, 1,
    924                        vmstate_interval_mapping,
    925                        TestGTreeInterval, TestGTreeMapping),
    926        VMSTATE_END_OF_LIST()
    927    }
    928};
    929
    930/* test QLIST Migration */
    931
    932typedef struct TestQListElement {
    933    uint32_t  id;
    934    QLIST_ENTRY(TestQListElement) next;
    935} TestQListElement;
    936
    937typedef struct TestQListContainer {
    938    uint32_t  id;
    939    QLIST_HEAD(, TestQListElement) list;
    940} TestQListContainer;
    941
    942static const VMStateDescription vmstate_qlist_element = {
    943    .name = "test/queue list",
    944    .version_id = 1,
    945    .minimum_version_id = 1,
    946    .fields = (VMStateField[]) {
    947        VMSTATE_UINT32(id, TestQListElement),
    948        VMSTATE_END_OF_LIST()
    949    }
    950};
    951
    952static const VMStateDescription vmstate_iommu = {
    953    .name = "iommu",
    954    .version_id = 1,
    955    .minimum_version_id = 1,
    956    .pre_load = iommu_preload,
    957    .fields = (VMStateField[]) {
    958        VMSTATE_INT32(id, TestGTreeIOMMU),
    959        VMSTATE_GTREE_DIRECT_KEY_V(domains, TestGTreeIOMMU, 1,
    960                                   &vmstate_domain, TestGTreeDomain),
    961        VMSTATE_END_OF_LIST()
    962    }
    963};
    964
    965static const VMStateDescription vmstate_container = {
    966    .name = "test/container/qlist",
    967    .version_id = 1,
    968    .minimum_version_id = 1,
    969    .fields = (VMStateField[]) {
    970        VMSTATE_UINT32(id, TestQListContainer),
    971        VMSTATE_QLIST_V(list, TestQListContainer, 1, vmstate_qlist_element,
    972                        TestQListElement, next),
    973        VMSTATE_END_OF_LIST()
    974    }
    975};
    976
    977uint8_t first_domain_dump[] = {
    978    /* id */
    979    0x00, 0x0, 0x0, 0x6,
    980    0x00, 0x0, 0x0, 0x2, /* 2 mappings */
    981    0x1, /* start of a */
    982    /* a */
    983    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
    984    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
    985    /* map_a */
    986    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00,
    987    0x00, 0x00, 0x00, 0x01,
    988    0x1, /* start of b */
    989    /* b */
    990    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
    991    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF,
    992    /* map_b */
    993    0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
    994    0x00, 0x00, 0x00, 0x02,
    995    0x0, /* end of gtree */
    996    QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
    997};
    998
    999static TestGTreeDomain *create_first_domain(void)
   1000{
   1001    TestGTreeDomain *domain;
   1002    TestGTreeMapping *map_a, *map_b;
   1003    TestGTreeInterval *a, *b;
   1004
   1005    domain = g_malloc0(sizeof(TestGTreeDomain));
   1006    domain->id = 6;
   1007
   1008    a = g_malloc0(sizeof(TestGTreeInterval));
   1009    a->low = 0x1000;
   1010    a->high = 0x1FFF;
   1011
   1012    b = g_malloc0(sizeof(TestGTreeInterval));
   1013    b->low = 0x4000;
   1014    b->high = 0x4FFF;
   1015
   1016    map_a = g_malloc0(sizeof(TestGTreeMapping));
   1017    map_a->phys_addr = 0xa000;
   1018    map_a->flags = 1;
   1019
   1020    map_b = g_malloc0(sizeof(TestGTreeMapping));
   1021    map_b->phys_addr = 0xe0000;
   1022    map_b->flags = 2;
   1023
   1024    domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp, NULL,
   1025                                        (GDestroyNotify)g_free,
   1026                                        (GDestroyNotify)g_free);
   1027    g_tree_insert(domain->mappings, a, map_a);
   1028    g_tree_insert(domain->mappings, b, map_b);
   1029    return domain;
   1030}
   1031
   1032static void test_gtree_save_domain(void)
   1033{
   1034    TestGTreeDomain *first_domain = create_first_domain();
   1035
   1036    save_vmstate(&vmstate_domain, first_domain);
   1037    compare_vmstate(first_domain_dump, sizeof(first_domain_dump));
   1038    destroy_domain(first_domain);
   1039}
   1040
   1041struct match_node_data {
   1042    GTree *tree;
   1043    gpointer key;
   1044    gpointer value;
   1045};
   1046
   1047struct tree_cmp_data {
   1048    GTree *tree1;
   1049    GTree *tree2;
   1050    GTraverseFunc match_node;
   1051};
   1052
   1053static gboolean match_interval_mapping_node(gpointer key,
   1054                                            gpointer value, gpointer data)
   1055{
   1056    TestGTreeMapping *map_a, *map_b;
   1057    TestGTreeInterval *a, *b;
   1058    struct match_node_data *d = (struct match_node_data *)data;
   1059    a = (TestGTreeInterval *)key;
   1060    b = (TestGTreeInterval *)d->key;
   1061
   1062    map_a = (TestGTreeMapping *)value;
   1063    map_b = (TestGTreeMapping *)d->value;
   1064
   1065    assert(a->low == b->low);
   1066    assert(a->high == b->high);
   1067    assert(map_a->phys_addr == map_b->phys_addr);
   1068    assert(map_a->flags == map_b->flags);
   1069    g_tree_remove(d->tree, key);
   1070    return true;
   1071}
   1072
   1073static gboolean diff_tree(gpointer key, gpointer value, gpointer data)
   1074{
   1075    struct tree_cmp_data *tp = (struct tree_cmp_data *)data;
   1076    struct match_node_data d = {tp->tree2, key, value};
   1077
   1078    g_tree_foreach(tp->tree2, tp->match_node, &d);
   1079    g_tree_remove(tp->tree1, key);
   1080    return false;
   1081}
   1082
   1083static void compare_trees(GTree *tree1, GTree *tree2,
   1084                          GTraverseFunc function)
   1085{
   1086    struct tree_cmp_data tp = {tree1, tree2, function};
   1087
   1088    g_tree_foreach(tree1, diff_tree, &tp);
   1089    assert(g_tree_nnodes(tree1) == 0);
   1090    assert(g_tree_nnodes(tree2) == 0);
   1091}
   1092
   1093static void diff_domain(TestGTreeDomain *d1, TestGTreeDomain *d2)
   1094{
   1095    assert(d1->id == d2->id);
   1096    compare_trees(d1->mappings, d2->mappings, match_interval_mapping_node);
   1097}
   1098
   1099static gboolean match_domain_node(gpointer key, gpointer value, gpointer data)
   1100{
   1101    uint64_t id1, id2;
   1102    TestGTreeDomain *d1, *d2;
   1103    struct match_node_data *d = (struct match_node_data *)data;
   1104
   1105    id1 = (uint64_t)(uintptr_t)key;
   1106    id2 = (uint64_t)(uintptr_t)d->key;
   1107    d1 = (TestGTreeDomain *)value;
   1108    d2 = (TestGTreeDomain *)d->value;
   1109    assert(id1 == id2);
   1110    diff_domain(d1, d2);
   1111    g_tree_remove(d->tree, key);
   1112    return true;
   1113}
   1114
   1115static void diff_iommu(TestGTreeIOMMU *iommu1, TestGTreeIOMMU *iommu2)
   1116{
   1117    assert(iommu1->id == iommu2->id);
   1118    compare_trees(iommu1->domains, iommu2->domains, match_domain_node);
   1119}
   1120
   1121static void test_gtree_load_domain(void)
   1122{
   1123    TestGTreeDomain *dest_domain = g_malloc0(sizeof(TestGTreeDomain));
   1124    TestGTreeDomain *orig_domain = create_first_domain();
   1125    QEMUFile *fload, *fsave;
   1126    char eof;
   1127
   1128    fsave = open_test_file(true);
   1129    qemu_put_buffer(fsave, first_domain_dump, sizeof(first_domain_dump));
   1130    g_assert(!qemu_file_get_error(fsave));
   1131    qemu_fclose(fsave);
   1132
   1133    fload = open_test_file(false);
   1134
   1135    vmstate_load_state(fload, &vmstate_domain, dest_domain, 1);
   1136    eof = qemu_get_byte(fload);
   1137    g_assert(!qemu_file_get_error(fload));
   1138    g_assert_cmpint(orig_domain->id, ==, dest_domain->id);
   1139    g_assert_cmpint(eof, ==, QEMU_VM_EOF);
   1140
   1141    diff_domain(orig_domain, dest_domain);
   1142    destroy_domain(orig_domain);
   1143    destroy_domain(dest_domain);
   1144    qemu_fclose(fload);
   1145}
   1146
   1147uint8_t iommu_dump[] = {
   1148    /* iommu id */
   1149    0x00, 0x0, 0x0, 0x7,
   1150    0x00, 0x0, 0x0, 0x2, /* 2 domains */
   1151    0x1,/* start of domain 5 */
   1152        0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x5, /* key = 5 */
   1153        0x00, 0x0, 0x0, 0x5, /* domain1 id */
   1154        0x00, 0x0, 0x0, 0x1, /* 1 mapping */
   1155        0x1, /* start of mappings */
   1156            /* c */
   1157            0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   1158            0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF,
   1159            /* map_c */
   1160            0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
   1161            0x00, 0x0, 0x0, 0x3,
   1162            0x0, /* end of domain1 mappings*/
   1163    0x1,/* start of domain 6 */
   1164        0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x6, /* key = 6 */
   1165        0x00, 0x0, 0x0, 0x6, /* domain6 id */
   1166            0x00, 0x0, 0x0, 0x2, /* 2 mappings */
   1167            0x1, /* start of a */
   1168            /* a */
   1169            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
   1170            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
   1171            /* map_a */
   1172            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00,
   1173            0x00, 0x00, 0x00, 0x01,
   1174            0x1, /* start of b */
   1175            /* b */
   1176            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
   1177            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF,
   1178            /* map_b */
   1179            0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
   1180            0x00, 0x00, 0x00, 0x02,
   1181            0x0, /* end of domain6 mappings*/
   1182    0x0, /* end of domains */
   1183    QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
   1184};
   1185
   1186static TestGTreeIOMMU *create_iommu(void)
   1187{
   1188    TestGTreeIOMMU *iommu = g_malloc0(sizeof(TestGTreeIOMMU));
   1189    TestGTreeDomain *first_domain = create_first_domain();
   1190    TestGTreeDomain *second_domain;
   1191    TestGTreeMapping *map_c;
   1192    TestGTreeInterval *c;
   1193
   1194    iommu->id = 7;
   1195    iommu->domains = g_tree_new_full((GCompareDataFunc)int_cmp, NULL,
   1196                                     NULL,
   1197                                     destroy_domain);
   1198
   1199    second_domain = g_malloc0(sizeof(TestGTreeDomain));
   1200    second_domain->id = 5;
   1201    second_domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp,
   1202                                              NULL,
   1203                                              (GDestroyNotify)g_free,
   1204                                              (GDestroyNotify)g_free);
   1205
   1206    g_tree_insert(iommu->domains, GUINT_TO_POINTER(6), first_domain);
   1207    g_tree_insert(iommu->domains, (gpointer)0x0000000000000005, second_domain);
   1208
   1209    c = g_malloc0(sizeof(TestGTreeInterval));
   1210    c->low = 0x1000000;
   1211    c->high = 0x1FFFFFF;
   1212
   1213    map_c = g_malloc0(sizeof(TestGTreeMapping));
   1214    map_c->phys_addr = 0xF000000;
   1215    map_c->flags = 0x3;
   1216
   1217    g_tree_insert(second_domain->mappings, c, map_c);
   1218    return iommu;
   1219}
   1220
   1221static void destroy_iommu(TestGTreeIOMMU *iommu)
   1222{
   1223    g_tree_destroy(iommu->domains);
   1224    g_free(iommu);
   1225}
   1226
   1227static void test_gtree_save_iommu(void)
   1228{
   1229    TestGTreeIOMMU *iommu = create_iommu();
   1230
   1231    save_vmstate(&vmstate_iommu, iommu);
   1232    compare_vmstate(iommu_dump, sizeof(iommu_dump));
   1233    destroy_iommu(iommu);
   1234}
   1235
   1236static void test_gtree_load_iommu(void)
   1237{
   1238    TestGTreeIOMMU *dest_iommu = g_malloc0(sizeof(TestGTreeIOMMU));
   1239    TestGTreeIOMMU *orig_iommu = create_iommu();
   1240    QEMUFile *fsave, *fload;
   1241    char eof;
   1242
   1243    fsave = open_test_file(true);
   1244    qemu_put_buffer(fsave, iommu_dump, sizeof(iommu_dump));
   1245    g_assert(!qemu_file_get_error(fsave));
   1246    qemu_fclose(fsave);
   1247
   1248    fload = open_test_file(false);
   1249    vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1);
   1250    eof = qemu_get_byte(fload);
   1251    g_assert(!qemu_file_get_error(fload));
   1252    g_assert_cmpint(orig_iommu->id, ==, dest_iommu->id);
   1253    g_assert_cmpint(eof, ==, QEMU_VM_EOF);
   1254
   1255    diff_iommu(orig_iommu, dest_iommu);
   1256    destroy_iommu(orig_iommu);
   1257    destroy_iommu(dest_iommu);
   1258    qemu_fclose(fload);
   1259}
   1260
   1261static uint8_t qlist_dump[] = {
   1262    0x00, 0x00, 0x00, 0x01, /* container id */
   1263    0x1, /* start of a */
   1264    0x00, 0x00, 0x00, 0x0a,
   1265    0x1, /* start of b */
   1266    0x00, 0x00, 0x0b, 0x00,
   1267    0x1, /* start of c */
   1268    0x00, 0x0c, 0x00, 0x00,
   1269    0x1, /* start of d */
   1270    0x0d, 0x00, 0x00, 0x00,
   1271    0x0, /* end of list */
   1272    QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
   1273};
   1274
   1275static TestQListContainer *alloc_container(void)
   1276{
   1277    TestQListElement *a = g_malloc(sizeof(TestQListElement));
   1278    TestQListElement *b = g_malloc(sizeof(TestQListElement));
   1279    TestQListElement *c = g_malloc(sizeof(TestQListElement));
   1280    TestQListElement *d = g_malloc(sizeof(TestQListElement));
   1281    TestQListContainer *container = g_malloc(sizeof(TestQListContainer));
   1282
   1283    a->id = 0x0a;
   1284    b->id = 0x0b00;
   1285    c->id = 0xc0000;
   1286    d->id = 0xd000000;
   1287    container->id = 1;
   1288
   1289    QLIST_INIT(&container->list);
   1290    QLIST_INSERT_HEAD(&container->list, d, next);
   1291    QLIST_INSERT_HEAD(&container->list, c, next);
   1292    QLIST_INSERT_HEAD(&container->list, b, next);
   1293    QLIST_INSERT_HEAD(&container->list, a, next);
   1294    return container;
   1295}
   1296
   1297static void free_container(TestQListContainer *container)
   1298{
   1299    TestQListElement *iter, *tmp;
   1300
   1301    QLIST_FOREACH_SAFE(iter, &container->list, next, tmp) {
   1302        QLIST_REMOVE(iter, next);
   1303        g_free(iter);
   1304    }
   1305    g_free(container);
   1306}
   1307
   1308static void compare_containers(TestQListContainer *c1, TestQListContainer *c2)
   1309{
   1310    TestQListElement *first_item_c1, *first_item_c2;
   1311
   1312    while (!QLIST_EMPTY(&c1->list)) {
   1313        first_item_c1 = QLIST_FIRST(&c1->list);
   1314        first_item_c2 = QLIST_FIRST(&c2->list);
   1315        assert(first_item_c2);
   1316        assert(first_item_c1->id == first_item_c2->id);
   1317        QLIST_REMOVE(first_item_c1, next);
   1318        QLIST_REMOVE(first_item_c2, next);
   1319        g_free(first_item_c1);
   1320        g_free(first_item_c2);
   1321    }
   1322    assert(QLIST_EMPTY(&c2->list));
   1323}
   1324
   1325/*
   1326 * Check the prev & next fields are correct by doing list
   1327 * manipulations on the container. We will do that for both
   1328 * the source and the destination containers
   1329 */
   1330static void manipulate_container(TestQListContainer *c)
   1331{
   1332     TestQListElement *prev = NULL, *iter = QLIST_FIRST(&c->list);
   1333     TestQListElement *elem;
   1334
   1335     elem = g_malloc(sizeof(TestQListElement));
   1336     elem->id = 0x12;
   1337     QLIST_INSERT_AFTER(iter, elem, next);
   1338
   1339     elem = g_malloc(sizeof(TestQListElement));
   1340     elem->id = 0x13;
   1341     QLIST_INSERT_HEAD(&c->list, elem, next);
   1342
   1343     while (iter) {
   1344        prev = iter;
   1345        iter = QLIST_NEXT(iter, next);
   1346     }
   1347
   1348     elem = g_malloc(sizeof(TestQListElement));
   1349     elem->id = 0x14;
   1350     QLIST_INSERT_BEFORE(prev, elem, next);
   1351
   1352     elem = g_malloc(sizeof(TestQListElement));
   1353     elem->id = 0x15;
   1354     QLIST_INSERT_AFTER(prev, elem, next);
   1355
   1356     QLIST_REMOVE(prev, next);
   1357     g_free(prev);
   1358}
   1359
   1360static void test_save_qlist(void)
   1361{
   1362    TestQListContainer *container = alloc_container();
   1363
   1364    save_vmstate(&vmstate_container, container);
   1365    compare_vmstate(qlist_dump, sizeof(qlist_dump));
   1366    free_container(container);
   1367}
   1368
   1369static void test_load_qlist(void)
   1370{
   1371    QEMUFile *fsave, *fload;
   1372    TestQListContainer *orig_container = alloc_container();
   1373    TestQListContainer *dest_container = g_malloc0(sizeof(TestQListContainer));
   1374    char eof;
   1375
   1376    QLIST_INIT(&dest_container->list);
   1377
   1378    fsave = open_test_file(true);
   1379    qemu_put_buffer(fsave, qlist_dump, sizeof(qlist_dump));
   1380    g_assert(!qemu_file_get_error(fsave));
   1381    qemu_fclose(fsave);
   1382
   1383    fload = open_test_file(false);
   1384    vmstate_load_state(fload, &vmstate_container, dest_container, 1);
   1385    eof = qemu_get_byte(fload);
   1386    g_assert(!qemu_file_get_error(fload));
   1387    g_assert_cmpint(eof, ==, QEMU_VM_EOF);
   1388    manipulate_container(orig_container);
   1389    manipulate_container(dest_container);
   1390    compare_containers(orig_container, dest_container);
   1391    free_container(orig_container);
   1392    free_container(dest_container);
   1393    qemu_fclose(fload);
   1394}
   1395
   1396typedef struct TmpTestStruct {
   1397    TestStruct *parent;
   1398    int64_t diff;
   1399} TmpTestStruct;
   1400
   1401static int tmp_child_pre_save(void *opaque)
   1402{
   1403    struct TmpTestStruct *tts = opaque;
   1404
   1405    tts->diff = tts->parent->b - tts->parent->a;
   1406
   1407    return 0;
   1408}
   1409
   1410static int tmp_child_post_load(void *opaque, int version_id)
   1411{
   1412    struct TmpTestStruct *tts = opaque;
   1413
   1414    tts->parent->b = tts->parent->a + tts->diff;
   1415
   1416    return 0;
   1417}
   1418
   1419static const VMStateDescription vmstate_tmp_back_to_parent = {
   1420    .name = "test/tmp_child_parent",
   1421    .fields = (VMStateField[]) {
   1422        VMSTATE_UINT64(f, TestStruct),
   1423        VMSTATE_END_OF_LIST()
   1424    }
   1425};
   1426
   1427static const VMStateDescription vmstate_tmp_child = {
   1428    .name = "test/tmp_child",
   1429    .pre_save = tmp_child_pre_save,
   1430    .post_load = tmp_child_post_load,
   1431    .fields = (VMStateField[]) {
   1432        VMSTATE_INT64(diff, TmpTestStruct),
   1433        VMSTATE_STRUCT_POINTER(parent, TmpTestStruct,
   1434                               vmstate_tmp_back_to_parent, TestStruct),
   1435        VMSTATE_END_OF_LIST()
   1436    }
   1437};
   1438
   1439static const VMStateDescription vmstate_with_tmp = {
   1440    .name = "test/with_tmp",
   1441    .version_id = 1,
   1442    .fields = (VMStateField[]) {
   1443        VMSTATE_UINT32(a, TestStruct),
   1444        VMSTATE_UINT64(d, TestStruct),
   1445        VMSTATE_WITH_TMP(TestStruct, TmpTestStruct, vmstate_tmp_child),
   1446        VMSTATE_END_OF_LIST()
   1447    }
   1448};
   1449
   1450static void obj_tmp_copy(void *target, void *source)
   1451{
   1452    memcpy(target, source, sizeof(TestStruct));
   1453}
   1454
   1455static void test_tmp_struct(void)
   1456{
   1457    TestStruct obj, obj_clone;
   1458
   1459    uint8_t const wire_with_tmp[] = {
   1460        /* u32 a */ 0x00, 0x00, 0x00, 0x02,
   1461        /* u64 d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
   1462        /* diff  */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
   1463        /* u64 f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
   1464        QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
   1465    };
   1466
   1467    memset(&obj, 0, sizeof(obj));
   1468    obj.a = 2;
   1469    obj.b = 4;
   1470    obj.d = 1;
   1471    obj.f = 8;
   1472    save_vmstate(&vmstate_with_tmp, &obj);
   1473
   1474    compare_vmstate(wire_with_tmp, sizeof(wire_with_tmp));
   1475
   1476    memset(&obj, 0, sizeof(obj));
   1477    SUCCESS(load_vmstate(&vmstate_with_tmp, &obj, &obj_clone,
   1478                         obj_tmp_copy, 1, wire_with_tmp,
   1479                         sizeof(wire_with_tmp)));
   1480    g_assert_cmpint(obj.a, ==, 2); /* From top level vmsd */
   1481    g_assert_cmpint(obj.b, ==, 4); /* from the post_load */
   1482    g_assert_cmpint(obj.d, ==, 1); /* From top level vmsd */
   1483    g_assert_cmpint(obj.f, ==, 8); /* From the child->parent */
   1484}
   1485
   1486int main(int argc, char **argv)
   1487{
   1488    g_autofree char *temp_file = g_strdup_printf("%s/vmst.test.XXXXXX",
   1489                                                 g_get_tmp_dir());
   1490    temp_fd = mkstemp(temp_file);
   1491    g_assert(temp_fd >= 0);
   1492
   1493    module_call_init(MODULE_INIT_QOM);
   1494
   1495    g_setenv("QTEST_SILENT_ERRORS", "1", 1);
   1496
   1497    g_test_init(&argc, &argv, NULL);
   1498    g_test_add_func("/vmstate/simple/primitive", test_simple_primitive);
   1499    g_test_add_func("/vmstate/simple/array", test_simple_array);
   1500    g_test_add_func("/vmstate/versioned/load/v1", test_load_v1);
   1501    g_test_add_func("/vmstate/versioned/load/v2", test_load_v2);
   1502    g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip);
   1503    g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip);
   1504    g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip);
   1505    g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip);
   1506    g_test_add_func("/vmstate/array/ptr/str/no0/save",
   1507                    test_arr_ptr_str_no0_save);
   1508    g_test_add_func("/vmstate/array/ptr/str/no0/load",
   1509                    test_arr_ptr_str_no0_load);
   1510    g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save);
   1511    g_test_add_func("/vmstate/array/ptr/str/0/load",
   1512                    test_arr_ptr_str_0_load);
   1513    g_test_add_func("/vmstate/array/ptr/prim/0/save",
   1514                    test_arr_ptr_prim_0_save);
   1515    g_test_add_func("/vmstate/array/ptr/prim/0/load",
   1516                    test_arr_ptr_prim_0_load);
   1517    g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q);
   1518    g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q);
   1519    g_test_add_func("/vmstate/gtree/save/savedomain", test_gtree_save_domain);
   1520    g_test_add_func("/vmstate/gtree/load/loaddomain", test_gtree_load_domain);
   1521    g_test_add_func("/vmstate/gtree/save/saveiommu", test_gtree_save_iommu);
   1522    g_test_add_func("/vmstate/gtree/load/loadiommu", test_gtree_load_iommu);
   1523    g_test_add_func("/vmstate/qlist/save/saveqlist", test_save_qlist);
   1524    g_test_add_func("/vmstate/qlist/load/loadqlist", test_load_qlist);
   1525    g_test_add_func("/vmstate/tmp_struct", test_tmp_struct);
   1526    g_test_run();
   1527
   1528    close(temp_fd);
   1529    unlink(temp_file);
   1530
   1531    return 0;
   1532}