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