xref: /openbmc/qemu/tests/unit/test-vmstate.c (revision 9c4888c9)
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 
37 static int temp_fd;
38 
39 
40 /* Duplicate temp_fd and seek to the beginning of the file */
41 static 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 
69 static 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 
81 static 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 
88 static 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 
110 static 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 
132 static 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 
165 typedef 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 
179 TestSimple 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 
199 static 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 
234 uint8_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 
252 static void obj_simple_copy(void *target, void *source)
253 {
254     memcpy(target, source, sizeof(TestSimple));
255 }
256 
257 static 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 
288 typedef 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 
294 TestSimpleArray 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 
301 static 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 
311 uint8_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 
318 static void obj_simple_arr_copy(void *target, void *source)
319 {
320     memcpy(target, source, sizeof(TestSimpleArray));
321 }
322 
323 static 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 
337 typedef struct TestStruct {
338     uint32_t a, b, c, e;
339     uint64_t d, f;
340     bool skip_c_e;
341 } TestStruct;
342 
343 static 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 
360 static 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 
383 static 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 
408 static bool test_skip(void *opaque, int version_id)
409 {
410     TestStruct *t = (TestStruct *)opaque;
411     return !t->skip_c_e;
412 }
413 
414 static 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 
430 static 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 
452 static 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 
472 static 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 
498 static 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 
522 typedef struct {
523     int32_t i;
524 } TestStructTriv;
525 
526 const 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 
540 typedef struct {
541     TestStructTriv *ar[AR_SIZE];
542 } TestArrayOfPtrToStuct;
543 
544 const 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 
555 static 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 
563 static 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 
572 static 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 
588 static 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 
596 static 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 
605 static 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 
628 typedef struct TestArrayOfPtrToInt {
629     int32_t *ar[AR_SIZE];
630 } TestArrayOfPtrToInt;
631 
632 const 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 
643 static 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 
652 static 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 */
673 typedef struct TestQtailqElement TestQtailqElement;
674 
675 struct TestQtailqElement {
676     bool     b;
677     uint8_t  u8;
678     QTAILQ_ENTRY(TestQtailqElement) next;
679 };
680 
681 typedef struct TestQtailq {
682     int16_t  i16;
683     QTAILQ_HEAD(, TestQtailqElement) q;
684     int32_t  i32;
685 } TestQtailq;
686 
687 static 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 
698 static 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 
711 uint8_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 
724 static 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 
749 static 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) */
817 typedef 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) */
835 typedef 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 
852 static const VMStateDescription vmstate_interval_mapping[2] = {
853     VMSTATE_MAPPING,   /* value */
854     VMSTATE_INTERVAL   /* key   */
855 };
856 
857 typedef struct TestGTreeDomain {
858     int32_t  id;
859     GTree    *mappings;
860 } TestGTreeDomain;
861 
862 typedef struct TestGTreeIOMMU {
863     int32_t  id;
864     GTree    *domains;
865 } TestGTreeIOMMU;
866 
867 /* Interval comparison function */
868 static 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 */
883 static 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 
890 static void destroy_domain(gpointer data)
891 {
892     TestGTreeDomain *domain = (TestGTreeDomain *)data;
893 
894     g_tree_destroy(domain->mappings);
895     g_free(domain);
896 }
897 
898 static 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 
907 static 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 
916 static 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 
932 typedef struct TestQListElement {
933     uint32_t  id;
934     QLIST_ENTRY(TestQListElement) next;
935 } TestQListElement;
936 
937 typedef struct TestQListContainer {
938     uint32_t  id;
939     QLIST_HEAD(, TestQListElement) list;
940 } TestQListContainer;
941 
942 static 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 
952 static 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 
965 static 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 
977 uint8_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 
999 static TestGTreeDomain *create_first_domain(void)
1000 {
1001     TestGTreeDomain *domain;
1002     TestGTreeMapping *map_a, *map_b;
1003     TestGTreeInterval *a, *b;
1004 
1005     domain = g_new0(TestGTreeDomain, 1);
1006     domain->id = 6;
1007 
1008     a = g_new0(TestGTreeInterval, 1);
1009     a->low = 0x1000;
1010     a->high = 0x1FFF;
1011 
1012     b = g_new0(TestGTreeInterval, 1);
1013     b->low = 0x4000;
1014     b->high = 0x4FFF;
1015 
1016     map_a = g_new0(TestGTreeMapping, 1);
1017     map_a->phys_addr = 0xa000;
1018     map_a->flags = 1;
1019 
1020     map_b = g_new0(TestGTreeMapping, 1);
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 
1032 static 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 
1041 struct match_node_data {
1042     GTree *tree;
1043     gpointer key;
1044     gpointer value;
1045 };
1046 
1047 struct tree_cmp_data {
1048     GTree *tree1;
1049     GTree *tree2;
1050     GTraverseFunc match_node;
1051 };
1052 
1053 static 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 
1073 static 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 
1083 static 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 
1093 static 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 
1099 static 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 
1115 static 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 
1121 static void test_gtree_load_domain(void)
1122 {
1123     TestGTreeDomain *dest_domain = g_new0(TestGTreeDomain, 1);
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 
1147 uint8_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 
1186 static TestGTreeIOMMU *create_iommu(void)
1187 {
1188     TestGTreeIOMMU *iommu = g_new0(TestGTreeIOMMU, 1);
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_new0(TestGTreeDomain, 1);
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_new0(TestGTreeInterval, 1);
1210     c->low = 0x1000000;
1211     c->high = 0x1FFFFFF;
1212 
1213     map_c = g_new0(TestGTreeMapping, 1);
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 
1221 static void destroy_iommu(TestGTreeIOMMU *iommu)
1222 {
1223     g_tree_destroy(iommu->domains);
1224     g_free(iommu);
1225 }
1226 
1227 static 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 
1236 static void test_gtree_load_iommu(void)
1237 {
1238     TestGTreeIOMMU *dest_iommu = g_new0(TestGTreeIOMMU, 1);
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 
1261 static 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 
1275 static TestQListContainer *alloc_container(void)
1276 {
1277     TestQListElement *a = g_new(TestQListElement, 1);
1278     TestQListElement *b = g_new(TestQListElement, 1);
1279     TestQListElement *c = g_new(TestQListElement, 1);
1280     TestQListElement *d = g_new(TestQListElement, 1);
1281     TestQListContainer *container = g_new(TestQListContainer, 1);
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 
1297 static 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 
1308 static 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  */
1330 static void manipulate_container(TestQListContainer *c)
1331 {
1332      TestQListElement *prev = NULL, *iter = QLIST_FIRST(&c->list);
1333      TestQListElement *elem;
1334 
1335      elem = g_new(TestQListElement, 1);
1336      elem->id = 0x12;
1337      QLIST_INSERT_AFTER(iter, elem, next);
1338 
1339      elem = g_new(TestQListElement, 1);
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_new(TestQListElement, 1);
1349      elem->id = 0x14;
1350      QLIST_INSERT_BEFORE(prev, elem, next);
1351 
1352      elem = g_new(TestQListElement, 1);
1353      elem->id = 0x15;
1354      QLIST_INSERT_AFTER(prev, elem, next);
1355 
1356      QLIST_REMOVE(prev, next);
1357      g_free(prev);
1358 }
1359 
1360 static 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 
1369 static void test_load_qlist(void)
1370 {
1371     QEMUFile *fsave, *fload;
1372     TestQListContainer *orig_container = alloc_container();
1373     TestQListContainer *dest_container = g_new0(TestQListContainer, 1);
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 
1396 typedef struct TmpTestStruct {
1397     TestStruct *parent;
1398     int64_t diff;
1399 } TmpTestStruct;
1400 
1401 static 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 
1410 static 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 
1419 static 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 
1427 static 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 
1439 static 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 
1450 static void obj_tmp_copy(void *target, void *source)
1451 {
1452     memcpy(target, source, sizeof(TestStruct));
1453 }
1454 
1455 static 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 
1486 int 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 }
1533