qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

test-vmstate.c (45719B)


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