2 * Test code for VMState
4 * Copyright (c) 2013 Red Hat Inc.
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
25 #include "qemu/osdep.h"
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"
40 /* Duplicate temp_fd and seek to the beginning of the file */
41 static QEMUFile
*open_test_file(bool write
)
49 lseek(fd
, 0, SEEK_SET
);
51 g_assert_cmpint(ftruncate(fd
, 0), ==, 0);
53 ioc
= QIO_CHANNEL(qio_channel_file_new_fd(fd
));
55 f
= qemu_fopen_channel_output(ioc
);
57 f
= qemu_fopen_channel_input(ioc
);
59 object_unref(OBJECT(ioc
));
63 #define SUCCESS(val) \
64 g_assert_cmpint((val), ==, 0)
66 #define FAILURE(val) \
67 g_assert_cmpint((val), !=, 0)
69 static void save_vmstate(const VMStateDescription
*desc
, void *obj
)
71 QEMUFile
*f
= open_test_file(true);
73 /* Save file with vmstate */
74 int ret
= vmstate_save_state(f
, desc
, obj
, NULL
);
76 qemu_put_byte(f
, QEMU_VM_EOF
);
77 g_assert(!qemu_file_get_error(f
));
81 static void save_buffer(const uint8_t *buf
, size_t buf_size
)
83 QEMUFile
*fsave
= open_test_file(true);
84 qemu_put_buffer(fsave
, buf
, buf_size
);
88 static void compare_vmstate(const uint8_t *wire
, size_t size
)
90 QEMUFile
*f
= open_test_file(false);
93 /* read back as binary */
95 g_assert_cmpint(qemu_get_buffer(f
, result
, sizeof(result
)), ==,
97 g_assert(!qemu_file_get_error(f
));
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
)));
105 g_assert_cmpint(qemu_file_get_error(f
), ==, -EIO
);
110 static int load_vmstate_one(const VMStateDescription
*desc
, void *obj
,
111 int version
, const uint8_t *wire
, size_t size
)
116 f
= open_test_file(true);
117 qemu_put_buffer(f
, wire
, size
);
120 f
= open_test_file(false);
121 ret
= vmstate_load_state(f
, desc
, obj
, version
);
123 g_assert(qemu_file_get_error(f
));
125 g_assert(!qemu_file_get_error(f
));
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
)
137 /* We test with zero size */
138 obj_copy(obj_clone
, obj
);
139 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, 0));
141 /* Stream ends with QEMU_EOF, so we need at least 3 bytes to be
142 * able to test in the middle */
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));
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));
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));
159 obj_copy(obj
, obj_clone
);
160 return load_vmstate_one(desc
, obj
, version
, wire
, size
);
163 /* Test struct that we are going to use for our tests */
165 typedef struct TestSimple
{
172 int16_t i16_1
, i16_2
;
173 int32_t i32_1
, i32_2
;
174 int64_t i64_1
, i64_2
;
177 /* Object instantiation, we are going to use it in more than one test */
179 TestSimple obj_simple
= {
196 /* Description of the values. If you add a primitive type
197 you are expected to add a test here */
199 static const VMStateDescription vmstate_simple_primitive
= {
200 .name
= "simple/primitive",
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()
222 /* It describes what goes through the wire. Our tests are basically:
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
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
234 uint8_t wire_simple_primitive
[] = {
238 /* u16_1 */ 0x02, 0x00,
239 /* u32_1 */ 0x00, 0x01, 0x11, 0x70,
240 /* u64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
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 */
252 static void obj_simple_copy(void *target
, void *source
)
254 memcpy(target
, source
, sizeof(TestSimple
));
257 static void test_simple_primitive(void)
259 TestSimple obj
, obj_clone
;
261 memset(&obj
, 0, sizeof(obj
));
262 save_vmstate(&vmstate_simple_primitive
, &obj_simple
);
264 compare_vmstate(wire_simple_primitive
, sizeof(wire_simple_primitive
));
266 SUCCESS(load_vmstate(&vmstate_simple_primitive
, &obj
, &obj_clone
,
267 obj_simple_copy
, 1, wire_simple_primitive
,
268 sizeof(wire_simple_primitive
)));
270 #define FIELD_EQUAL(name) g_assert_cmpint(obj.name, ==, obj_simple.name)
288 typedef struct TestSimpleArray
{
292 /* Object instantiation, we are going to use it in more than one test */
294 TestSimpleArray obj_simple_arr
= {
295 .u16_1
= { 0x42, 0x43, 0x44 },
298 /* Description of the values. If you add a primitive type
299 you are expected to add a test here */
301 static const VMStateDescription vmstate_simple_arr
= {
302 .name
= "simple/array",
304 .minimum_version_id
= 1,
305 .fields
= (VMStateField
[]) {
306 VMSTATE_UINT16_ARRAY(u16_1
, TestSimpleArray
, 3),
307 VMSTATE_END_OF_LIST()
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 */
318 static void obj_simple_arr_copy(void *target
, void *source
)
320 memcpy(target
, source
, sizeof(TestSimpleArray
));
323 static void test_simple_array(void)
325 TestSimpleArray obj
, obj_clone
;
327 memset(&obj
, 0, sizeof(obj
));
328 save_vmstate(&vmstate_simple_arr
, &obj_simple_arr
);
330 compare_vmstate(wire_simple_arr
, sizeof(wire_simple_arr
));
332 SUCCESS(load_vmstate(&vmstate_simple_arr
, &obj
, &obj_clone
,
333 obj_simple_arr_copy
, 1, wire_simple_arr
,
334 sizeof(wire_simple_arr
)));
337 typedef struct TestStruct
{
343 static const VMStateDescription vmstate_versioned
= {
344 .name
= "test/versioned",
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.
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()
360 static void test_load_v1(void)
365 0, 0, 0, 0, 0, 0, 0, 40, /* d */
366 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
368 save_buffer(buf
, sizeof(buf
));
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
);
383 static void test_load_v2(void)
389 0, 0, 0, 0, 0, 0, 0, 40, /* d */
391 0, 0, 0, 0, 0, 0, 0, 60, /* f */
392 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
394 save_buffer(buf
, sizeof(buf
));
396 QEMUFile
*loading
= open_test_file(false);
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
);
408 static bool test_skip(void *opaque
, int version_id
)
410 TestStruct
*t
= (TestStruct
*)opaque
;
414 static const VMStateDescription vmstate_skipping
= {
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()
430 static void test_save_noskip(void)
432 QEMUFile
*fsave
= open_test_file(true);
433 TestStruct obj
= { .a
= 1, .b
= 2, .c
= 3, .d
= 4, .e
= 5, .f
= 6,
435 int ret
= vmstate_save_state(fsave
, &vmstate_skipping
, &obj
, NULL
);
437 g_assert(!qemu_file_get_error(fsave
));
439 uint8_t expected
[] = {
443 0, 0, 0, 0, 0, 0, 0, 4, /* d */
445 0, 0, 0, 0, 0, 0, 0, 6, /* f */
449 compare_vmstate(expected
, sizeof(expected
));
452 static void test_save_skip(void)
454 QEMUFile
*fsave
= open_test_file(true);
455 TestStruct obj
= { .a
= 1, .b
= 2, .c
= 3, .d
= 4, .e
= 5, .f
= 6,
457 int ret
= vmstate_save_state(fsave
, &vmstate_skipping
, &obj
, NULL
);
459 g_assert(!qemu_file_get_error(fsave
));
461 uint8_t expected
[] = {
464 0, 0, 0, 0, 0, 0, 0, 4, /* d */
465 0, 0, 0, 0, 0, 0, 0, 6, /* f */
469 compare_vmstate(expected
, sizeof(expected
));
472 static void test_load_noskip(void)
478 0, 0, 0, 0, 0, 0, 0, 40, /* d */
480 0, 0, 0, 0, 0, 0, 0, 60, /* f */
481 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
483 save_buffer(buf
, sizeof(buf
));
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
);
498 static void test_load_skip(void)
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 */
507 save_buffer(buf
, sizeof(buf
));
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
);
526 const VMStateDescription vmsd_tst
= {
529 .minimum_version_id
= 1,
530 .fields
= (VMStateField
[]) {
531 VMSTATE_INT32(i
, TestStructTriv
),
532 VMSTATE_END_OF_LIST()
536 /* test array migration */
541 TestStructTriv
*ar
[AR_SIZE
];
542 } TestArrayOfPtrToStuct
;
544 const VMStateDescription vmsd_arps
= {
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()
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,
563 static void test_arr_ptr_str_no0_save(void)
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]} };
568 save_vmstate(&vmsd_arps
, &sample
);
569 compare_vmstate(wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
));
572 static void test_arr_ptr_str_no0_load(void)
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]} };
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
);
588 static uint8_t wire_arr_ptr_0
[] = {
589 0x00, 0x00, 0x00, 0x00,
591 0x00, 0x00, 0x00, 0x02,
592 0x00, 0x00, 0x00, 0x03,
596 static void test_arr_ptr_str_0_save(void)
598 TestStructTriv ar
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
599 TestArrayOfPtrToStuct sample
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
601 save_vmstate(&vmsd_arps
, &sample
);
602 compare_vmstate(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
605 static void test_arr_ptr_str_0_load(void)
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]} };
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
);
619 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
621 g_assert_cmpint((uintptr_t)(obj
.ar
[idx
]), ==, 0);
623 g_assert_cmpint((uintptr_t)(obj
.ar
[idx
]), !=, 0);
628 typedef struct TestArrayOfPtrToInt
{
629 int32_t *ar
[AR_SIZE
];
630 } TestArrayOfPtrToInt
;
632 const VMStateDescription vmsd_arpp
= {
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()
643 static void test_arr_ptr_prim_0_save(void)
645 int32_t ar
[AR_SIZE
] = {0 , 1, 2, 3};
646 TestArrayOfPtrToInt sample
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
648 save_vmstate(&vmsd_arpp
, &sample
);
649 compare_vmstate(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
652 static void test_arr_ptr_prim_0_load(void)
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]} };
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 */
665 g_assert_cmpint(42, ==, ar
[idx
]);
667 g_assert_cmpint(ar_gt
[idx
], ==, ar
[idx
]);
672 /* test QTAILQ migration */
673 typedef struct TestQtailqElement TestQtailqElement
;
675 struct TestQtailqElement
{
678 QTAILQ_ENTRY(TestQtailqElement
) next
;
681 typedef struct TestQtailq
{
683 QTAILQ_HEAD(, TestQtailqElement
) q
;
687 static const VMStateDescription vmstate_q_element
= {
688 .name
= "test/queue-element",
690 .minimum_version_id
= 1,
691 .fields
= (VMStateField
[]) {
692 VMSTATE_BOOL(b
, TestQtailqElement
),
693 VMSTATE_UINT8(u8
, TestQtailqElement
),
694 VMSTATE_END_OF_LIST()
698 static const VMStateDescription vmstate_q
= {
699 .name
= "test/queue",
701 .minimum_version_id
= 1,
702 .fields
= (VMStateField
[]) {
703 VMSTATE_INT16(i16
, TestQtailq
),
704 VMSTATE_QTAILQ_V(q
, TestQtailq
, 1, vmstate_q_element
, TestQtailqElement
,
706 VMSTATE_INT32(i32
, TestQtailq
),
707 VMSTATE_END_OF_LIST()
713 /* start of element 0 of q */ 0x01,
716 /* start of element 1 of q */ 0x01,
720 /* i32 */ 0x00, 0x01, 0x11, 0x70,
721 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
724 static void test_save_q(void)
731 TestQtailqElement obj_qe1
= {
736 TestQtailqElement obj_qe2
= {
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
);
745 save_vmstate(&vmstate_q
, &obj_q
);
746 compare_vmstate(wire_q
, sizeof(wire_q
));
749 static void test_load_q(void)
756 TestQtailqElement obj_qe1
= {
761 TestQtailqElement obj_qe2
= {
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
);
770 QEMUFile
*fsave
= open_test_file(true);
772 qemu_put_buffer(fsave
, wire_q
, sizeof(wire_q
));
773 g_assert(!qemu_file_get_error(fsave
));
776 QEMUFile
*fload
= open_test_file(false);
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
);
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
);
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
)) {
798 qele_from
= QTAILQ_NEXT(qele_from
, next
);
799 qele_to
= QTAILQ_NEXT(qele_to
, next
);
802 g_assert_cmpint((uintptr_t) qele_from
, ==, (uintptr_t) qlast_from
);
803 g_assert_cmpint((uintptr_t) qele_to
, ==, (uintptr_t) qlast_to
);
806 TestQtailqElement
*qele
;
807 while (!QTAILQ_EMPTY(&tgt
.q
)) {
808 qele
= QTAILQ_LAST(&tgt
.q
);
809 QTAILQ_REMOVE(&tgt
.q
, qele
, next
);
817 typedef struct TestGTreeInterval
{
822 #define VMSTATE_INTERVAL \
824 .name = "interval", \
826 .minimum_version_id = 1, \
827 .fields = (VMStateField[]) { \
828 VMSTATE_UINT64(low, TestGTreeInterval), \
829 VMSTATE_UINT64(high, TestGTreeInterval), \
830 VMSTATE_END_OF_LIST() \
834 /* mapping (value) */
835 typedef struct TestGTreeMapping
{
840 #define VMSTATE_MAPPING \
844 .minimum_version_id = 1, \
845 .fields = (VMStateField[]) { \
846 VMSTATE_UINT64(phys_addr, TestGTreeMapping), \
847 VMSTATE_UINT32(flags, TestGTreeMapping), \
848 VMSTATE_END_OF_LIST() \
852 static const VMStateDescription vmstate_interval_mapping
[2] = {
853 VMSTATE_MAPPING
, /* value */
854 VMSTATE_INTERVAL
/* key */
857 typedef struct TestGTreeDomain
{
862 typedef struct TestGTreeIOMMU
{
867 /* Interval comparison function */
868 static gint
interval_cmp(gconstpointer a
, gconstpointer b
, gpointer user_data
)
870 TestGTreeInterval
*inta
= (TestGTreeInterval
*)a
;
871 TestGTreeInterval
*intb
= (TestGTreeInterval
*)b
;
873 if (inta
->high
< intb
->low
) {
875 } else if (intb
->high
< inta
->low
) {
882 /* ID comparison function */
883 static gint
int_cmp(gconstpointer a
, gconstpointer b
, gpointer user_data
)
885 guint ua
= GPOINTER_TO_UINT(a
);
886 guint ub
= GPOINTER_TO_UINT(b
);
887 return (ua
> ub
) - (ua
< ub
);
890 static void destroy_domain(gpointer data
)
892 TestGTreeDomain
*domain
= (TestGTreeDomain
*)data
;
894 g_tree_destroy(domain
->mappings
);
898 static int domain_preload(void *opaque
)
900 TestGTreeDomain
*domain
= opaque
;
902 domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
,
903 NULL
, g_free
, g_free
);
907 static int iommu_preload(void *opaque
)
909 TestGTreeIOMMU
*iommu
= opaque
;
911 iommu
->domains
= g_tree_new_full((GCompareDataFunc
)int_cmp
,
912 NULL
, NULL
, destroy_domain
);
916 static const VMStateDescription vmstate_domain
= {
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()
930 /* test QLIST Migration */
932 typedef struct TestQListElement
{
934 QLIST_ENTRY(TestQListElement
) next
;
937 typedef struct TestQListContainer
{
939 QLIST_HEAD(, TestQListElement
) list
;
940 } TestQListContainer
;
942 static const VMStateDescription vmstate_qlist_element
= {
943 .name
= "test/queue list",
945 .minimum_version_id
= 1,
946 .fields
= (VMStateField
[]) {
947 VMSTATE_UINT32(id
, TestQListElement
),
948 VMSTATE_END_OF_LIST()
952 static const VMStateDescription vmstate_iommu
= {
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()
965 static const VMStateDescription vmstate_container
= {
966 .name
= "test/container/qlist",
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()
977 uint8_t first_domain_dump
[] = {
980 0x00, 0x0, 0x0, 0x2, /* 2 mappings */
981 0x1, /* start of a */
983 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
984 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
986 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00,
987 0x00, 0x00, 0x00, 0x01,
988 0x1, /* start of b */
990 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
991 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF,
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 */
999 static TestGTreeDomain
*create_first_domain(void)
1001 TestGTreeDomain
*domain
;
1002 TestGTreeMapping
*map_a
, *map_b
;
1003 TestGTreeInterval
*a
, *b
;
1005 domain
= g_malloc0(sizeof(TestGTreeDomain
));
1008 a
= g_malloc0(sizeof(TestGTreeInterval
));
1012 b
= g_malloc0(sizeof(TestGTreeInterval
));
1016 map_a
= g_malloc0(sizeof(TestGTreeMapping
));
1017 map_a
->phys_addr
= 0xa000;
1020 map_b
= g_malloc0(sizeof(TestGTreeMapping
));
1021 map_b
->phys_addr
= 0xe0000;
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
);
1032 static void test_gtree_save_domain(void)
1034 TestGTreeDomain
*first_domain
= create_first_domain();
1036 save_vmstate(&vmstate_domain
, first_domain
);
1037 compare_vmstate(first_domain_dump
, sizeof(first_domain_dump
));
1038 destroy_domain(first_domain
);
1041 struct match_node_data
{
1047 struct tree_cmp_data
{
1050 GTraverseFunc match_node
;
1053 static gboolean
match_interval_mapping_node(gpointer key
,
1054 gpointer value
, gpointer data
)
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
;
1062 map_a
= (TestGTreeMapping
*)value
;
1063 map_b
= (TestGTreeMapping
*)d
->value
;
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
);
1073 static gboolean
diff_tree(gpointer key
, gpointer value
, gpointer data
)
1075 struct tree_cmp_data
*tp
= (struct tree_cmp_data
*)data
;
1076 struct match_node_data d
= {tp
->tree2
, key
, value
};
1078 g_tree_foreach(tp
->tree2
, tp
->match_node
, &d
);
1079 g_tree_remove(tp
->tree1
, key
);
1083 static void compare_trees(GTree
*tree1
, GTree
*tree2
,
1084 GTraverseFunc function
)
1086 struct tree_cmp_data tp
= {tree1
, tree2
, function
};
1088 g_tree_foreach(tree1
, diff_tree
, &tp
);
1089 assert(g_tree_nnodes(tree1
) == 0);
1090 assert(g_tree_nnodes(tree2
) == 0);
1093 static void diff_domain(TestGTreeDomain
*d1
, TestGTreeDomain
*d2
)
1095 assert(d1
->id
== d2
->id
);
1096 compare_trees(d1
->mappings
, d2
->mappings
, match_interval_mapping_node
);
1099 static gboolean
match_domain_node(gpointer key
, gpointer value
, gpointer data
)
1102 TestGTreeDomain
*d1
, *d2
;
1103 struct match_node_data
*d
= (struct match_node_data
*)data
;
1105 id1
= (uint64_t)(uintptr_t)key
;
1106 id2
= (uint64_t)(uintptr_t)d
->key
;
1107 d1
= (TestGTreeDomain
*)value
;
1108 d2
= (TestGTreeDomain
*)d
->value
;
1110 diff_domain(d1
, d2
);
1111 g_tree_remove(d
->tree
, key
);
1115 static void diff_iommu(TestGTreeIOMMU
*iommu1
, TestGTreeIOMMU
*iommu2
)
1117 assert(iommu1
->id
== iommu2
->id
);
1118 compare_trees(iommu1
->domains
, iommu2
->domains
, match_domain_node
);
1121 static void test_gtree_load_domain(void)
1123 TestGTreeDomain
*dest_domain
= g_malloc0(sizeof(TestGTreeDomain
));
1124 TestGTreeDomain
*orig_domain
= create_first_domain();
1125 QEMUFile
*fload
, *fsave
;
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
));
1133 fload
= open_test_file(false);
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
);
1141 diff_domain(orig_domain
, dest_domain
);
1142 destroy_domain(orig_domain
);
1143 destroy_domain(dest_domain
);
1147 uint8_t iommu_dump
[] = {
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 */
1157 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1158 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF,
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 */
1169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
1172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00,
1173 0x00, 0x00, 0x00, 0x01,
1174 0x1, /* start of b */
1176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
1177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF,
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 */
1186 static TestGTreeIOMMU
*create_iommu(void)
1188 TestGTreeIOMMU
*iommu
= g_malloc0(sizeof(TestGTreeIOMMU
));
1189 TestGTreeDomain
*first_domain
= create_first_domain();
1190 TestGTreeDomain
*second_domain
;
1191 TestGTreeMapping
*map_c
;
1192 TestGTreeInterval
*c
;
1195 iommu
->domains
= g_tree_new_full((GCompareDataFunc
)int_cmp
, NULL
,
1199 second_domain
= g_malloc0(sizeof(TestGTreeDomain
));
1200 second_domain
->id
= 5;
1201 second_domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
,
1203 (GDestroyNotify
)g_free
,
1204 (GDestroyNotify
)g_free
);
1206 g_tree_insert(iommu
->domains
, GUINT_TO_POINTER(6), first_domain
);
1207 g_tree_insert(iommu
->domains
, (gpointer
)0x0000000000000005, second_domain
);
1209 c
= g_malloc0(sizeof(TestGTreeInterval
));
1211 c
->high
= 0x1FFFFFF;
1213 map_c
= g_malloc0(sizeof(TestGTreeMapping
));
1214 map_c
->phys_addr
= 0xF000000;
1217 g_tree_insert(second_domain
->mappings
, c
, map_c
);
1221 static void destroy_iommu(TestGTreeIOMMU
*iommu
)
1223 g_tree_destroy(iommu
->domains
);
1227 static void test_gtree_save_iommu(void)
1229 TestGTreeIOMMU
*iommu
= create_iommu();
1231 save_vmstate(&vmstate_iommu
, iommu
);
1232 compare_vmstate(iommu_dump
, sizeof(iommu_dump
));
1233 destroy_iommu(iommu
);
1236 static void test_gtree_load_iommu(void)
1238 TestGTreeIOMMU
*dest_iommu
= g_malloc0(sizeof(TestGTreeIOMMU
));
1239 TestGTreeIOMMU
*orig_iommu
= create_iommu();
1240 QEMUFile
*fsave
, *fload
;
1243 fsave
= open_test_file(true);
1244 qemu_put_buffer(fsave
, iommu_dump
, sizeof(iommu_dump
));
1245 g_assert(!qemu_file_get_error(fsave
));
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
);
1255 diff_iommu(orig_iommu
, dest_iommu
);
1256 destroy_iommu(orig_iommu
);
1257 destroy_iommu(dest_iommu
);
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 */
1275 static TestQListContainer
*alloc_container(void)
1277 TestQListElement
*a
= g_malloc(sizeof(TestQListElement
));
1278 TestQListElement
*b
= g_malloc(sizeof(TestQListElement
));
1279 TestQListElement
*c
= g_malloc(sizeof(TestQListElement
));
1280 TestQListElement
*d
= g_malloc(sizeof(TestQListElement
));
1281 TestQListContainer
*container
= g_malloc(sizeof(TestQListContainer
));
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
);
1297 static void free_container(TestQListContainer
*container
)
1299 TestQListElement
*iter
, *tmp
;
1301 QLIST_FOREACH_SAFE(iter
, &container
->list
, next
, tmp
) {
1302 QLIST_REMOVE(iter
, next
);
1308 static void compare_containers(TestQListContainer
*c1
, TestQListContainer
*c2
)
1310 TestQListElement
*first_item_c1
, *first_item_c2
;
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
);
1322 assert(QLIST_EMPTY(&c2
->list
));
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
1330 static void manipulate_container(TestQListContainer
*c
)
1332 TestQListElement
*prev
= NULL
, *iter
= QLIST_FIRST(&c
->list
);
1333 TestQListElement
*elem
;
1335 elem
= g_malloc(sizeof(TestQListElement
));
1337 QLIST_INSERT_AFTER(iter
, elem
, next
);
1339 elem
= g_malloc(sizeof(TestQListElement
));
1341 QLIST_INSERT_HEAD(&c
->list
, elem
, next
);
1345 iter
= QLIST_NEXT(iter
, next
);
1348 elem
= g_malloc(sizeof(TestQListElement
));
1350 QLIST_INSERT_BEFORE(prev
, elem
, next
);
1352 elem
= g_malloc(sizeof(TestQListElement
));
1354 QLIST_INSERT_AFTER(prev
, elem
, next
);
1356 QLIST_REMOVE(prev
, next
);
1360 static void test_save_qlist(void)
1362 TestQListContainer
*container
= alloc_container();
1364 save_vmstate(&vmstate_container
, container
);
1365 compare_vmstate(qlist_dump
, sizeof(qlist_dump
));
1366 free_container(container
);
1369 static void test_load_qlist(void)
1371 QEMUFile
*fsave
, *fload
;
1372 TestQListContainer
*orig_container
= alloc_container();
1373 TestQListContainer
*dest_container
= g_malloc0(sizeof(TestQListContainer
));
1376 QLIST_INIT(&dest_container
->list
);
1378 fsave
= open_test_file(true);
1379 qemu_put_buffer(fsave
, qlist_dump
, sizeof(qlist_dump
));
1380 g_assert(!qemu_file_get_error(fsave
));
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
);
1396 typedef struct TmpTestStruct
{
1401 static int tmp_child_pre_save(void *opaque
)
1403 struct TmpTestStruct
*tts
= opaque
;
1405 tts
->diff
= tts
->parent
->b
- tts
->parent
->a
;
1410 static int tmp_child_post_load(void *opaque
, int version_id
)
1412 struct TmpTestStruct
*tts
= opaque
;
1414 tts
->parent
->b
= tts
->parent
->a
+ tts
->diff
;
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()
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()
1439 static const VMStateDescription vmstate_with_tmp
= {
1440 .name
= "test/with_tmp",
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()
1450 static void obj_tmp_copy(void *target
, void *source
)
1452 memcpy(target
, source
, sizeof(TestStruct
));
1455 static void test_tmp_struct(void)
1457 TestStruct obj
, obj_clone
;
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 */
1467 memset(&obj
, 0, sizeof(obj
));
1472 save_vmstate(&vmstate_with_tmp
, &obj
);
1474 compare_vmstate(wire_with_tmp
, sizeof(wire_with_tmp
));
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 */
1486 int main(int argc
, char **argv
)
1488 g_autofree
char *temp_file
= g_strdup_printf("%s/vmst.test.XXXXXX",
1490 temp_fd
= mkstemp(temp_file
);
1491 g_assert(temp_fd
>= 0);
1493 module_call_init(MODULE_INIT_QOM
);
1495 g_setenv("QTEST_SILENT_ERRORS", "1", 1);
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
);