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
)
43 int fd
= dup(temp_fd
);
47 lseek(fd
, 0, SEEK_SET
);
49 g_assert_cmpint(ftruncate(fd
, 0), ==, 0);
51 ioc
= QIO_CHANNEL(qio_channel_file_new_fd(fd
));
53 f
= qemu_fopen_channel_output(ioc
);
55 f
= qemu_fopen_channel_input(ioc
);
57 object_unref(OBJECT(ioc
));
61 #define SUCCESS(val) \
62 g_assert_cmpint((val), ==, 0)
64 #define FAILURE(val) \
65 g_assert_cmpint((val), !=, 0)
67 static void save_vmstate(const VMStateDescription
*desc
, void *obj
)
69 QEMUFile
*f
= open_test_file(true);
71 /* Save file with vmstate */
72 int ret
= vmstate_save_state(f
, desc
, obj
, NULL
);
74 qemu_put_byte(f
, QEMU_VM_EOF
);
75 g_assert(!qemu_file_get_error(f
));
79 static void save_buffer(const uint8_t *buf
, size_t buf_size
)
81 QEMUFile
*fsave
= open_test_file(true);
82 qemu_put_buffer(fsave
, buf
, buf_size
);
86 static void compare_vmstate(const uint8_t *wire
, size_t size
)
88 QEMUFile
*f
= open_test_file(false);
91 /* read back as binary */
93 g_assert_cmpint(qemu_get_buffer(f
, result
, sizeof(result
)), ==,
95 g_assert(!qemu_file_get_error(f
));
97 /* Compare that what is on the file is the same that what we
98 expected to be there */
99 SUCCESS(memcmp(result
, wire
, sizeof(result
)));
103 g_assert_cmpint(qemu_file_get_error(f
), ==, -EIO
);
108 static int load_vmstate_one(const VMStateDescription
*desc
, void *obj
,
109 int version
, const uint8_t *wire
, size_t size
)
114 f
= open_test_file(true);
115 qemu_put_buffer(f
, wire
, size
);
118 f
= open_test_file(false);
119 ret
= vmstate_load_state(f
, desc
, obj
, version
);
121 g_assert(qemu_file_get_error(f
));
123 g_assert(!qemu_file_get_error(f
));
130 static int load_vmstate(const VMStateDescription
*desc
,
131 void *obj
, void *obj_clone
,
132 void (*obj_copy
)(void *, void*),
133 int version
, const uint8_t *wire
, size_t size
)
135 /* We test with zero size */
136 obj_copy(obj_clone
, obj
);
137 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, 0));
139 /* Stream ends with QEMU_EOF, so we need at least 3 bytes to be
140 * able to test in the middle */
144 /* We test with size - 2. We can't test size - 1 due to EOF tricks */
145 obj_copy(obj
, obj_clone
);
146 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, size
- 2));
148 /* Test with size/2, first half of real state */
149 obj_copy(obj
, obj_clone
);
150 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, size
/2));
152 /* Test with size/2, second half of real state */
153 obj_copy(obj
, obj_clone
);
154 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
+ (size
/2), size
/2));
157 obj_copy(obj
, obj_clone
);
158 return load_vmstate_one(desc
, obj
, version
, wire
, size
);
161 /* Test struct that we are going to use for our tests */
163 typedef struct TestSimple
{
170 int16_t i16_1
, i16_2
;
171 int32_t i32_1
, i32_2
;
172 int64_t i64_1
, i64_2
;
175 /* Object instantiation, we are going to use it in more than one test */
177 TestSimple obj_simple
= {
194 /* Description of the values. If you add a primitive type
195 you are expected to add a test here */
197 static const VMStateDescription vmstate_simple_primitive
= {
198 .name
= "simple/primitive",
200 .minimum_version_id
= 1,
201 .fields
= (VMStateField
[]) {
202 VMSTATE_BOOL(b_1
, TestSimple
),
203 VMSTATE_BOOL(b_2
, TestSimple
),
204 VMSTATE_UINT8(u8_1
, TestSimple
),
205 VMSTATE_UINT16(u16_1
, TestSimple
),
206 VMSTATE_UINT32(u32_1
, TestSimple
),
207 VMSTATE_UINT64(u64_1
, TestSimple
),
208 VMSTATE_INT8(i8_1
, TestSimple
),
209 VMSTATE_INT8(i8_2
, TestSimple
),
210 VMSTATE_INT16(i16_1
, TestSimple
),
211 VMSTATE_INT16(i16_2
, TestSimple
),
212 VMSTATE_INT32(i32_1
, TestSimple
),
213 VMSTATE_INT32(i32_2
, TestSimple
),
214 VMSTATE_INT64(i64_1
, TestSimple
),
215 VMSTATE_INT64(i64_2
, TestSimple
),
216 VMSTATE_END_OF_LIST()
220 /* It describes what goes through the wire. Our tests are basically:
223 - save a struct a vmstate to a file
224 - read that file back (binary read, no vmstate)
225 - compare it with what we expect to be on the wire
227 - save to the file what we expect to be on the wire
228 - read struct back with vmstate in a different
229 - compare back with the original struct
232 uint8_t wire_simple_primitive
[] = {
236 /* u16_1 */ 0x02, 0x00,
237 /* u32_1 */ 0x00, 0x01, 0x11, 0x70,
238 /* u64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
241 /* i16_1 */ 0x02, 0x00,
242 /* i16_2 */ 0xfe, 0x0,
243 /* i32_1 */ 0x00, 0x01, 0x11, 0x70,
244 /* i32_2 */ 0xff, 0xfe, 0xee, 0x90,
245 /* i64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
246 /* i64_2 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x0b, 0x84,
247 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
250 static void obj_simple_copy(void *target
, void *source
)
252 memcpy(target
, source
, sizeof(TestSimple
));
255 static void test_simple_primitive(void)
257 TestSimple obj
, obj_clone
;
259 memset(&obj
, 0, sizeof(obj
));
260 save_vmstate(&vmstate_simple_primitive
, &obj_simple
);
262 compare_vmstate(wire_simple_primitive
, sizeof(wire_simple_primitive
));
264 SUCCESS(load_vmstate(&vmstate_simple_primitive
, &obj
, &obj_clone
,
265 obj_simple_copy
, 1, wire_simple_primitive
,
266 sizeof(wire_simple_primitive
)));
268 #define FIELD_EQUAL(name) g_assert_cmpint(obj.name, ==, obj_simple.name)
286 typedef struct TestSimpleArray
{
290 /* Object instantiation, we are going to use it in more than one test */
292 TestSimpleArray obj_simple_arr
= {
293 .u16_1
= { 0x42, 0x43, 0x44 },
296 /* Description of the values. If you add a primitive type
297 you are expected to add a test here */
299 static const VMStateDescription vmstate_simple_arr
= {
300 .name
= "simple/array",
302 .minimum_version_id
= 1,
303 .fields
= (VMStateField
[]) {
304 VMSTATE_UINT16_ARRAY(u16_1
, TestSimpleArray
, 3),
305 VMSTATE_END_OF_LIST()
309 uint8_t wire_simple_arr
[] = {
310 /* u16_1 */ 0x00, 0x42,
311 /* u16_1 */ 0x00, 0x43,
312 /* u16_1 */ 0x00, 0x44,
313 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
316 static void obj_simple_arr_copy(void *target
, void *source
)
318 memcpy(target
, source
, sizeof(TestSimpleArray
));
321 static void test_simple_array(void)
323 TestSimpleArray obj
, obj_clone
;
325 memset(&obj
, 0, sizeof(obj
));
326 save_vmstate(&vmstate_simple_arr
, &obj_simple_arr
);
328 compare_vmstate(wire_simple_arr
, sizeof(wire_simple_arr
));
330 SUCCESS(load_vmstate(&vmstate_simple_arr
, &obj
, &obj_clone
,
331 obj_simple_arr_copy
, 1, wire_simple_arr
,
332 sizeof(wire_simple_arr
)));
335 typedef struct TestStruct
{
341 static const VMStateDescription vmstate_versioned
= {
342 .name
= "test/versioned",
344 .minimum_version_id
= 1,
345 .fields
= (VMStateField
[]) {
346 VMSTATE_UINT32(a
, TestStruct
),
347 VMSTATE_UINT32_V(b
, TestStruct
, 2), /* Versioned field in the middle, so
348 * we catch bugs more easily.
350 VMSTATE_UINT32(c
, TestStruct
),
351 VMSTATE_UINT64(d
, TestStruct
),
352 VMSTATE_UINT32_V(e
, TestStruct
, 2),
353 VMSTATE_UINT64_V(f
, TestStruct
, 2),
354 VMSTATE_END_OF_LIST()
358 static void test_load_v1(void)
363 0, 0, 0, 0, 0, 0, 0, 40, /* d */
364 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
366 save_buffer(buf
, sizeof(buf
));
368 QEMUFile
*loading
= open_test_file(false);
369 TestStruct obj
= { .b
= 200, .e
= 500, .f
= 600 };
370 vmstate_load_state(loading
, &vmstate_versioned
, &obj
, 1);
371 g_assert(!qemu_file_get_error(loading
));
372 g_assert_cmpint(obj
.a
, ==, 10);
373 g_assert_cmpint(obj
.b
, ==, 200);
374 g_assert_cmpint(obj
.c
, ==, 30);
375 g_assert_cmpint(obj
.d
, ==, 40);
376 g_assert_cmpint(obj
.e
, ==, 500);
377 g_assert_cmpint(obj
.f
, ==, 600);
378 qemu_fclose(loading
);
381 static void test_load_v2(void)
387 0, 0, 0, 0, 0, 0, 0, 40, /* d */
389 0, 0, 0, 0, 0, 0, 0, 60, /* f */
390 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
392 save_buffer(buf
, sizeof(buf
));
394 QEMUFile
*loading
= open_test_file(false);
396 vmstate_load_state(loading
, &vmstate_versioned
, &obj
, 2);
397 g_assert_cmpint(obj
.a
, ==, 10);
398 g_assert_cmpint(obj
.b
, ==, 20);
399 g_assert_cmpint(obj
.c
, ==, 30);
400 g_assert_cmpint(obj
.d
, ==, 40);
401 g_assert_cmpint(obj
.e
, ==, 50);
402 g_assert_cmpint(obj
.f
, ==, 60);
403 qemu_fclose(loading
);
406 static bool test_skip(void *opaque
, int version_id
)
408 TestStruct
*t
= (TestStruct
*)opaque
;
412 static const VMStateDescription vmstate_skipping
= {
415 .minimum_version_id
= 1,
416 .fields
= (VMStateField
[]) {
417 VMSTATE_UINT32(a
, TestStruct
),
418 VMSTATE_UINT32(b
, TestStruct
),
419 VMSTATE_UINT32_TEST(c
, TestStruct
, test_skip
),
420 VMSTATE_UINT64(d
, TestStruct
),
421 VMSTATE_UINT32_TEST(e
, TestStruct
, test_skip
),
422 VMSTATE_UINT64_V(f
, TestStruct
, 2),
423 VMSTATE_END_OF_LIST()
428 static void test_save_noskip(void)
430 QEMUFile
*fsave
= open_test_file(true);
431 TestStruct obj
= { .a
= 1, .b
= 2, .c
= 3, .d
= 4, .e
= 5, .f
= 6,
433 int ret
= vmstate_save_state(fsave
, &vmstate_skipping
, &obj
, NULL
);
435 g_assert(!qemu_file_get_error(fsave
));
437 uint8_t expected
[] = {
441 0, 0, 0, 0, 0, 0, 0, 4, /* d */
443 0, 0, 0, 0, 0, 0, 0, 6, /* f */
447 compare_vmstate(expected
, sizeof(expected
));
450 static void test_save_skip(void)
452 QEMUFile
*fsave
= open_test_file(true);
453 TestStruct obj
= { .a
= 1, .b
= 2, .c
= 3, .d
= 4, .e
= 5, .f
= 6,
455 int ret
= vmstate_save_state(fsave
, &vmstate_skipping
, &obj
, NULL
);
457 g_assert(!qemu_file_get_error(fsave
));
459 uint8_t expected
[] = {
462 0, 0, 0, 0, 0, 0, 0, 4, /* d */
463 0, 0, 0, 0, 0, 0, 0, 6, /* f */
467 compare_vmstate(expected
, sizeof(expected
));
470 static void test_load_noskip(void)
476 0, 0, 0, 0, 0, 0, 0, 40, /* d */
478 0, 0, 0, 0, 0, 0, 0, 60, /* f */
479 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
481 save_buffer(buf
, sizeof(buf
));
483 QEMUFile
*loading
= open_test_file(false);
484 TestStruct obj
= { .skip_c_e
= false };
485 vmstate_load_state(loading
, &vmstate_skipping
, &obj
, 2);
486 g_assert(!qemu_file_get_error(loading
));
487 g_assert_cmpint(obj
.a
, ==, 10);
488 g_assert_cmpint(obj
.b
, ==, 20);
489 g_assert_cmpint(obj
.c
, ==, 30);
490 g_assert_cmpint(obj
.d
, ==, 40);
491 g_assert_cmpint(obj
.e
, ==, 50);
492 g_assert_cmpint(obj
.f
, ==, 60);
493 qemu_fclose(loading
);
496 static void test_load_skip(void)
501 0, 0, 0, 0, 0, 0, 0, 40, /* d */
502 0, 0, 0, 0, 0, 0, 0, 60, /* f */
503 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
505 save_buffer(buf
, sizeof(buf
));
507 QEMUFile
*loading
= open_test_file(false);
508 TestStruct obj
= { .skip_c_e
= true, .c
= 300, .e
= 500 };
509 vmstate_load_state(loading
, &vmstate_skipping
, &obj
, 2);
510 g_assert(!qemu_file_get_error(loading
));
511 g_assert_cmpint(obj
.a
, ==, 10);
512 g_assert_cmpint(obj
.b
, ==, 20);
513 g_assert_cmpint(obj
.c
, ==, 300);
514 g_assert_cmpint(obj
.d
, ==, 40);
515 g_assert_cmpint(obj
.e
, ==, 500);
516 g_assert_cmpint(obj
.f
, ==, 60);
517 qemu_fclose(loading
);
524 const VMStateDescription vmsd_tst
= {
527 .minimum_version_id
= 1,
528 .fields
= (VMStateField
[]) {
529 VMSTATE_INT32(i
, TestStructTriv
),
530 VMSTATE_END_OF_LIST()
534 /* test array migration */
539 TestStructTriv
*ar
[AR_SIZE
];
540 } TestArrayOfPtrToStuct
;
542 const VMStateDescription vmsd_arps
= {
545 .minimum_version_id
= 1,
546 .fields
= (VMStateField
[]) {
547 VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(ar
, TestArrayOfPtrToStuct
,
548 AR_SIZE
, 0, vmsd_tst
, TestStructTriv
),
549 VMSTATE_END_OF_LIST()
553 static uint8_t wire_arr_ptr_no0
[] = {
554 0x00, 0x00, 0x00, 0x00,
555 0x00, 0x00, 0x00, 0x01,
556 0x00, 0x00, 0x00, 0x02,
557 0x00, 0x00, 0x00, 0x03,
561 static void test_arr_ptr_str_no0_save(void)
563 TestStructTriv ar
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
564 TestArrayOfPtrToStuct sample
= {.ar
= {&ar
[0], &ar
[1], &ar
[2], &ar
[3]} };
566 save_vmstate(&vmsd_arps
, &sample
);
567 compare_vmstate(wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
));
570 static void test_arr_ptr_str_no0_load(void)
572 TestStructTriv ar_gt
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
573 TestStructTriv ar
[AR_SIZE
] = {};
574 TestArrayOfPtrToStuct obj
= {.ar
= {&ar
[0], &ar
[1], &ar
[2], &ar
[3]} };
577 save_buffer(wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
));
578 SUCCESS(load_vmstate_one(&vmsd_arps
, &obj
, 1,
579 wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
)));
580 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
581 /* compare the target array ar with the ground truth array ar_gt */
582 g_assert_cmpint(ar_gt
[idx
].i
, ==, ar
[idx
].i
);
586 static uint8_t wire_arr_ptr_0
[] = {
587 0x00, 0x00, 0x00, 0x00,
589 0x00, 0x00, 0x00, 0x02,
590 0x00, 0x00, 0x00, 0x03,
594 static void test_arr_ptr_str_0_save(void)
596 TestStructTriv ar
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
597 TestArrayOfPtrToStuct sample
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
599 save_vmstate(&vmsd_arps
, &sample
);
600 compare_vmstate(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
603 static void test_arr_ptr_str_0_load(void)
605 TestStructTriv ar_gt
[AR_SIZE
] = {{.i
= 0}, {.i
= 0}, {.i
= 2}, {.i
= 3} };
606 TestStructTriv ar
[AR_SIZE
] = {};
607 TestArrayOfPtrToStuct obj
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
610 save_buffer(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
611 SUCCESS(load_vmstate_one(&vmsd_arps
, &obj
, 1,
612 wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
)));
613 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
614 /* compare the target array ar with the ground truth array ar_gt */
615 g_assert_cmpint(ar_gt
[idx
].i
, ==, ar
[idx
].i
);
617 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
619 g_assert_cmpint((uintptr_t)(obj
.ar
[idx
]), ==, 0);
621 g_assert_cmpint((uintptr_t)(obj
.ar
[idx
]), !=, 0);
626 typedef struct TestArrayOfPtrToInt
{
627 int32_t *ar
[AR_SIZE
];
628 } TestArrayOfPtrToInt
;
630 const VMStateDescription vmsd_arpp
= {
633 .minimum_version_id
= 1,
634 .fields
= (VMStateField
[]) {
635 VMSTATE_ARRAY_OF_POINTER(ar
, TestArrayOfPtrToInt
,
636 AR_SIZE
, 0, vmstate_info_int32
, int32_t*),
637 VMSTATE_END_OF_LIST()
641 static void test_arr_ptr_prim_0_save(void)
643 int32_t ar
[AR_SIZE
] = {0 , 1, 2, 3};
644 TestArrayOfPtrToInt sample
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
646 save_vmstate(&vmsd_arpp
, &sample
);
647 compare_vmstate(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
650 static void test_arr_ptr_prim_0_load(void)
652 int32_t ar_gt
[AR_SIZE
] = {0, 1, 2, 3};
653 int32_t ar
[AR_SIZE
] = {3 , 42, 1, 0};
654 TestArrayOfPtrToInt obj
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
657 save_buffer(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
658 SUCCESS(load_vmstate_one(&vmsd_arpp
, &obj
, 1,
659 wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
)));
660 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
661 /* compare the target array ar with the ground truth array ar_gt */
663 g_assert_cmpint(42, ==, ar
[idx
]);
665 g_assert_cmpint(ar_gt
[idx
], ==, ar
[idx
]);
670 /* test QTAILQ migration */
671 typedef struct TestQtailqElement TestQtailqElement
;
673 struct TestQtailqElement
{
676 QTAILQ_ENTRY(TestQtailqElement
) next
;
679 typedef struct TestQtailq
{
681 QTAILQ_HEAD(, TestQtailqElement
) q
;
685 static const VMStateDescription vmstate_q_element
= {
686 .name
= "test/queue-element",
688 .minimum_version_id
= 1,
689 .fields
= (VMStateField
[]) {
690 VMSTATE_BOOL(b
, TestQtailqElement
),
691 VMSTATE_UINT8(u8
, TestQtailqElement
),
692 VMSTATE_END_OF_LIST()
696 static const VMStateDescription vmstate_q
= {
697 .name
= "test/queue",
699 .minimum_version_id
= 1,
700 .fields
= (VMStateField
[]) {
701 VMSTATE_INT16(i16
, TestQtailq
),
702 VMSTATE_QTAILQ_V(q
, TestQtailq
, 1, vmstate_q_element
, TestQtailqElement
,
704 VMSTATE_INT32(i32
, TestQtailq
),
705 VMSTATE_END_OF_LIST()
711 /* start of element 0 of q */ 0x01,
714 /* start of element 1 of q */ 0x01,
718 /* i32 */ 0x00, 0x01, 0x11, 0x70,
719 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
722 static void test_save_q(void)
729 TestQtailqElement obj_qe1
= {
734 TestQtailqElement obj_qe2
= {
739 QTAILQ_INIT(&obj_q
.q
);
740 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe1
, next
);
741 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe2
, next
);
743 save_vmstate(&vmstate_q
, &obj_q
);
744 compare_vmstate(wire_q
, sizeof(wire_q
));
747 static void test_load_q(void)
754 TestQtailqElement obj_qe1
= {
759 TestQtailqElement obj_qe2
= {
764 QTAILQ_INIT(&obj_q
.q
);
765 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe1
, next
);
766 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe2
, next
);
768 QEMUFile
*fsave
= open_test_file(true);
770 qemu_put_buffer(fsave
, wire_q
, sizeof(wire_q
));
771 g_assert(!qemu_file_get_error(fsave
));
774 QEMUFile
*fload
= open_test_file(false);
778 vmstate_load_state(fload
, &vmstate_q
, &tgt
, 1);
779 char eof
= qemu_get_byte(fload
);
780 g_assert(!qemu_file_get_error(fload
));
781 g_assert_cmpint(tgt
.i16
, ==, obj_q
.i16
);
782 g_assert_cmpint(tgt
.i32
, ==, obj_q
.i32
);
783 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
785 TestQtailqElement
*qele_from
= QTAILQ_FIRST(&obj_q
.q
);
786 TestQtailqElement
*qlast_from
= QTAILQ_LAST(&obj_q
.q
);
787 TestQtailqElement
*qele_to
= QTAILQ_FIRST(&tgt
.q
);
788 TestQtailqElement
*qlast_to
= QTAILQ_LAST(&tgt
.q
);
791 g_assert_cmpint(qele_to
->b
, ==, qele_from
->b
);
792 g_assert_cmpint(qele_to
->u8
, ==, qele_from
->u8
);
793 if ((qele_from
== qlast_from
) || (qele_to
== qlast_to
)) {
796 qele_from
= QTAILQ_NEXT(qele_from
, next
);
797 qele_to
= QTAILQ_NEXT(qele_to
, next
);
800 g_assert_cmpint((uintptr_t) qele_from
, ==, (uintptr_t) qlast_from
);
801 g_assert_cmpint((uintptr_t) qele_to
, ==, (uintptr_t) qlast_to
);
804 TestQtailqElement
*qele
;
805 while (!QTAILQ_EMPTY(&tgt
.q
)) {
806 qele
= QTAILQ_LAST(&tgt
.q
);
807 QTAILQ_REMOVE(&tgt
.q
, qele
, next
);
815 typedef struct TestGTreeInterval
{
820 #define VMSTATE_INTERVAL \
822 .name = "interval", \
824 .minimum_version_id = 1, \
825 .fields = (VMStateField[]) { \
826 VMSTATE_UINT64(low, TestGTreeInterval), \
827 VMSTATE_UINT64(high, TestGTreeInterval), \
828 VMSTATE_END_OF_LIST() \
832 /* mapping (value) */
833 typedef struct TestGTreeMapping
{
838 #define VMSTATE_MAPPING \
842 .minimum_version_id = 1, \
843 .fields = (VMStateField[]) { \
844 VMSTATE_UINT64(phys_addr, TestGTreeMapping), \
845 VMSTATE_UINT32(flags, TestGTreeMapping), \
846 VMSTATE_END_OF_LIST() \
850 static const VMStateDescription vmstate_interval_mapping
[2] = {
851 VMSTATE_MAPPING
, /* value */
852 VMSTATE_INTERVAL
/* key */
855 typedef struct TestGTreeDomain
{
860 typedef struct TestGTreeIOMMU
{
865 /* Interval comparison function */
866 static gint
interval_cmp(gconstpointer a
, gconstpointer b
, gpointer user_data
)
868 TestGTreeInterval
*inta
= (TestGTreeInterval
*)a
;
869 TestGTreeInterval
*intb
= (TestGTreeInterval
*)b
;
871 if (inta
->high
< intb
->low
) {
873 } else if (intb
->high
< inta
->low
) {
880 /* ID comparison function */
881 static gint
int_cmp(gconstpointer a
, gconstpointer b
, gpointer user_data
)
883 guint ua
= GPOINTER_TO_UINT(a
);
884 guint ub
= GPOINTER_TO_UINT(b
);
885 return (ua
> ub
) - (ua
< ub
);
888 static void destroy_domain(gpointer data
)
890 TestGTreeDomain
*domain
= (TestGTreeDomain
*)data
;
892 g_tree_destroy(domain
->mappings
);
896 static int domain_preload(void *opaque
)
898 TestGTreeDomain
*domain
= opaque
;
900 domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
,
901 NULL
, g_free
, g_free
);
905 static int iommu_preload(void *opaque
)
907 TestGTreeIOMMU
*iommu
= opaque
;
909 iommu
->domains
= g_tree_new_full((GCompareDataFunc
)int_cmp
,
910 NULL
, NULL
, destroy_domain
);
914 static const VMStateDescription vmstate_domain
= {
917 .minimum_version_id
= 1,
918 .pre_load
= domain_preload
,
919 .fields
= (VMStateField
[]) {
920 VMSTATE_INT32(id
, TestGTreeDomain
),
921 VMSTATE_GTREE_V(mappings
, TestGTreeDomain
, 1,
922 vmstate_interval_mapping
,
923 TestGTreeInterval
, TestGTreeMapping
),
924 VMSTATE_END_OF_LIST()
928 /* test QLIST Migration */
930 typedef struct TestQListElement
{
932 QLIST_ENTRY(TestQListElement
) next
;
935 typedef struct TestQListContainer
{
937 QLIST_HEAD(, TestQListElement
) list
;
938 } TestQListContainer
;
940 static const VMStateDescription vmstate_qlist_element
= {
941 .name
= "test/queue list",
943 .minimum_version_id
= 1,
944 .fields
= (VMStateField
[]) {
945 VMSTATE_UINT32(id
, TestQListElement
),
946 VMSTATE_END_OF_LIST()
950 static const VMStateDescription vmstate_iommu
= {
953 .minimum_version_id
= 1,
954 .pre_load
= iommu_preload
,
955 .fields
= (VMStateField
[]) {
956 VMSTATE_INT32(id
, TestGTreeIOMMU
),
957 VMSTATE_GTREE_DIRECT_KEY_V(domains
, TestGTreeIOMMU
, 1,
958 &vmstate_domain
, TestGTreeDomain
),
959 VMSTATE_END_OF_LIST()
963 static const VMStateDescription vmstate_container
= {
964 .name
= "test/container/qlist",
966 .minimum_version_id
= 1,
967 .fields
= (VMStateField
[]) {
968 VMSTATE_UINT32(id
, TestQListContainer
),
969 VMSTATE_QLIST_V(list
, TestQListContainer
, 1, vmstate_qlist_element
,
970 TestQListElement
, next
),
971 VMSTATE_END_OF_LIST()
975 uint8_t first_domain_dump
[] = {
978 0x00, 0x0, 0x0, 0x2, /* 2 mappings */
979 0x1, /* start of a */
981 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
982 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
984 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00,
985 0x00, 0x00, 0x00, 0x01,
986 0x1, /* start of b */
988 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
989 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF,
991 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
992 0x00, 0x00, 0x00, 0x02,
993 0x0, /* end of gtree */
994 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
997 static TestGTreeDomain
*create_first_domain(void)
999 TestGTreeDomain
*domain
;
1000 TestGTreeMapping
*map_a
, *map_b
;
1001 TestGTreeInterval
*a
, *b
;
1003 domain
= g_malloc0(sizeof(TestGTreeDomain
));
1006 a
= g_malloc0(sizeof(TestGTreeInterval
));
1010 b
= g_malloc0(sizeof(TestGTreeInterval
));
1014 map_a
= g_malloc0(sizeof(TestGTreeMapping
));
1015 map_a
->phys_addr
= 0xa000;
1018 map_b
= g_malloc0(sizeof(TestGTreeMapping
));
1019 map_b
->phys_addr
= 0xe0000;
1022 domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
, NULL
,
1023 (GDestroyNotify
)g_free
,
1024 (GDestroyNotify
)g_free
);
1025 g_tree_insert(domain
->mappings
, a
, map_a
);
1026 g_tree_insert(domain
->mappings
, b
, map_b
);
1030 static void test_gtree_save_domain(void)
1032 TestGTreeDomain
*first_domain
= create_first_domain();
1034 save_vmstate(&vmstate_domain
, first_domain
);
1035 compare_vmstate(first_domain_dump
, sizeof(first_domain_dump
));
1036 destroy_domain(first_domain
);
1039 struct match_node_data
{
1045 struct tree_cmp_data
{
1048 GTraverseFunc match_node
;
1051 static gboolean
match_interval_mapping_node(gpointer key
,
1052 gpointer value
, gpointer data
)
1054 TestGTreeMapping
*map_a
, *map_b
;
1055 TestGTreeInterval
*a
, *b
;
1056 struct match_node_data
*d
= (struct match_node_data
*)data
;
1057 a
= (TestGTreeInterval
*)key
;
1058 b
= (TestGTreeInterval
*)d
->key
;
1060 map_a
= (TestGTreeMapping
*)value
;
1061 map_b
= (TestGTreeMapping
*)d
->value
;
1063 assert(a
->low
== b
->low
);
1064 assert(a
->high
== b
->high
);
1065 assert(map_a
->phys_addr
== map_b
->phys_addr
);
1066 assert(map_a
->flags
== map_b
->flags
);
1067 g_tree_remove(d
->tree
, key
);
1071 static gboolean
diff_tree(gpointer key
, gpointer value
, gpointer data
)
1073 struct tree_cmp_data
*tp
= (struct tree_cmp_data
*)data
;
1074 struct match_node_data d
= {tp
->tree2
, key
, value
};
1076 g_tree_foreach(tp
->tree2
, tp
->match_node
, &d
);
1077 g_tree_remove(tp
->tree1
, key
);
1081 static void compare_trees(GTree
*tree1
, GTree
*tree2
,
1082 GTraverseFunc function
)
1084 struct tree_cmp_data tp
= {tree1
, tree2
, function
};
1086 g_tree_foreach(tree1
, diff_tree
, &tp
);
1087 assert(g_tree_nnodes(tree1
) == 0);
1088 assert(g_tree_nnodes(tree2
) == 0);
1091 static void diff_domain(TestGTreeDomain
*d1
, TestGTreeDomain
*d2
)
1093 assert(d1
->id
== d2
->id
);
1094 compare_trees(d1
->mappings
, d2
->mappings
, match_interval_mapping_node
);
1097 static gboolean
match_domain_node(gpointer key
, gpointer value
, gpointer data
)
1100 TestGTreeDomain
*d1
, *d2
;
1101 struct match_node_data
*d
= (struct match_node_data
*)data
;
1103 id1
= (uint64_t)(uintptr_t)key
;
1104 id2
= (uint64_t)(uintptr_t)d
->key
;
1105 d1
= (TestGTreeDomain
*)value
;
1106 d2
= (TestGTreeDomain
*)d
->value
;
1108 diff_domain(d1
, d2
);
1109 g_tree_remove(d
->tree
, key
);
1113 static void diff_iommu(TestGTreeIOMMU
*iommu1
, TestGTreeIOMMU
*iommu2
)
1115 assert(iommu1
->id
== iommu2
->id
);
1116 compare_trees(iommu1
->domains
, iommu2
->domains
, match_domain_node
);
1119 static void test_gtree_load_domain(void)
1121 TestGTreeDomain
*dest_domain
= g_malloc0(sizeof(TestGTreeDomain
));
1122 TestGTreeDomain
*orig_domain
= create_first_domain();
1123 QEMUFile
*fload
, *fsave
;
1126 fsave
= open_test_file(true);
1127 qemu_put_buffer(fsave
, first_domain_dump
, sizeof(first_domain_dump
));
1128 g_assert(!qemu_file_get_error(fsave
));
1131 fload
= open_test_file(false);
1133 vmstate_load_state(fload
, &vmstate_domain
, dest_domain
, 1);
1134 eof
= qemu_get_byte(fload
);
1135 g_assert(!qemu_file_get_error(fload
));
1136 g_assert_cmpint(orig_domain
->id
, ==, dest_domain
->id
);
1137 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
1139 diff_domain(orig_domain
, dest_domain
);
1140 destroy_domain(orig_domain
);
1141 destroy_domain(dest_domain
);
1145 uint8_t iommu_dump
[] = {
1147 0x00, 0x0, 0x0, 0x7,
1148 0x00, 0x0, 0x0, 0x2, /* 2 domains */
1149 0x1,/* start of domain 5 */
1150 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x5, /* key = 5 */
1151 0x00, 0x0, 0x0, 0x5, /* domain1 id */
1152 0x00, 0x0, 0x0, 0x1, /* 1 mapping */
1153 0x1, /* start of mappings */
1155 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1156 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF,
1158 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
1159 0x00, 0x0, 0x0, 0x3,
1160 0x0, /* end of domain1 mappings*/
1161 0x1,/* start of domain 6 */
1162 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x6, /* key = 6 */
1163 0x00, 0x0, 0x0, 0x6, /* domain6 id */
1164 0x00, 0x0, 0x0, 0x2, /* 2 mappings */
1165 0x1, /* start of a */
1167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
1170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00,
1171 0x00, 0x00, 0x00, 0x01,
1172 0x1, /* start of b */
1174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
1175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF,
1177 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
1178 0x00, 0x00, 0x00, 0x02,
1179 0x0, /* end of domain6 mappings*/
1180 0x0, /* end of domains */
1181 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
1184 static TestGTreeIOMMU
*create_iommu(void)
1186 TestGTreeIOMMU
*iommu
= g_malloc0(sizeof(TestGTreeIOMMU
));
1187 TestGTreeDomain
*first_domain
= create_first_domain();
1188 TestGTreeDomain
*second_domain
;
1189 TestGTreeMapping
*map_c
;
1190 TestGTreeInterval
*c
;
1193 iommu
->domains
= g_tree_new_full((GCompareDataFunc
)int_cmp
, NULL
,
1197 second_domain
= g_malloc0(sizeof(TestGTreeDomain
));
1198 second_domain
->id
= 5;
1199 second_domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
,
1201 (GDestroyNotify
)g_free
,
1202 (GDestroyNotify
)g_free
);
1204 g_tree_insert(iommu
->domains
, GUINT_TO_POINTER(6), first_domain
);
1205 g_tree_insert(iommu
->domains
, (gpointer
)0x0000000000000005, second_domain
);
1207 c
= g_malloc0(sizeof(TestGTreeInterval
));
1209 c
->high
= 0x1FFFFFF;
1211 map_c
= g_malloc0(sizeof(TestGTreeMapping
));
1212 map_c
->phys_addr
= 0xF000000;
1215 g_tree_insert(second_domain
->mappings
, c
, map_c
);
1219 static void destroy_iommu(TestGTreeIOMMU
*iommu
)
1221 g_tree_destroy(iommu
->domains
);
1225 static void test_gtree_save_iommu(void)
1227 TestGTreeIOMMU
*iommu
= create_iommu();
1229 save_vmstate(&vmstate_iommu
, iommu
);
1230 compare_vmstate(iommu_dump
, sizeof(iommu_dump
));
1231 destroy_iommu(iommu
);
1234 static void test_gtree_load_iommu(void)
1236 TestGTreeIOMMU
*dest_iommu
= g_malloc0(sizeof(TestGTreeIOMMU
));
1237 TestGTreeIOMMU
*orig_iommu
= create_iommu();
1238 QEMUFile
*fsave
, *fload
;
1241 fsave
= open_test_file(true);
1242 qemu_put_buffer(fsave
, iommu_dump
, sizeof(iommu_dump
));
1243 g_assert(!qemu_file_get_error(fsave
));
1246 fload
= open_test_file(false);
1247 vmstate_load_state(fload
, &vmstate_iommu
, dest_iommu
, 1);
1248 eof
= qemu_get_byte(fload
);
1249 g_assert(!qemu_file_get_error(fload
));
1250 g_assert_cmpint(orig_iommu
->id
, ==, dest_iommu
->id
);
1251 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
1253 diff_iommu(orig_iommu
, dest_iommu
);
1254 destroy_iommu(orig_iommu
);
1255 destroy_iommu(dest_iommu
);
1259 static uint8_t qlist_dump
[] = {
1260 0x00, 0x00, 0x00, 0x01, /* container id */
1261 0x1, /* start of a */
1262 0x00, 0x00, 0x00, 0x0a,
1263 0x1, /* start of b */
1264 0x00, 0x00, 0x0b, 0x00,
1265 0x1, /* start of c */
1266 0x00, 0x0c, 0x00, 0x00,
1267 0x1, /* start of d */
1268 0x0d, 0x00, 0x00, 0x00,
1269 0x0, /* end of list */
1270 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
1273 static TestQListContainer
*alloc_container(void)
1275 TestQListElement
*a
= g_malloc(sizeof(TestQListElement
));
1276 TestQListElement
*b
= g_malloc(sizeof(TestQListElement
));
1277 TestQListElement
*c
= g_malloc(sizeof(TestQListElement
));
1278 TestQListElement
*d
= g_malloc(sizeof(TestQListElement
));
1279 TestQListContainer
*container
= g_malloc(sizeof(TestQListContainer
));
1287 QLIST_INIT(&container
->list
);
1288 QLIST_INSERT_HEAD(&container
->list
, d
, next
);
1289 QLIST_INSERT_HEAD(&container
->list
, c
, next
);
1290 QLIST_INSERT_HEAD(&container
->list
, b
, next
);
1291 QLIST_INSERT_HEAD(&container
->list
, a
, next
);
1295 static void free_container(TestQListContainer
*container
)
1297 TestQListElement
*iter
, *tmp
;
1299 QLIST_FOREACH_SAFE(iter
, &container
->list
, next
, tmp
) {
1300 QLIST_REMOVE(iter
, next
);
1306 static void compare_containers(TestQListContainer
*c1
, TestQListContainer
*c2
)
1308 TestQListElement
*first_item_c1
, *first_item_c2
;
1310 while (!QLIST_EMPTY(&c1
->list
)) {
1311 first_item_c1
= QLIST_FIRST(&c1
->list
);
1312 first_item_c2
= QLIST_FIRST(&c2
->list
);
1313 assert(first_item_c2
);
1314 assert(first_item_c1
->id
== first_item_c2
->id
);
1315 QLIST_REMOVE(first_item_c1
, next
);
1316 QLIST_REMOVE(first_item_c2
, next
);
1317 g_free(first_item_c1
);
1318 g_free(first_item_c2
);
1320 assert(QLIST_EMPTY(&c2
->list
));
1324 * Check the prev & next fields are correct by doing list
1325 * manipulations on the container. We will do that for both
1326 * the source and the destination containers
1328 static void manipulate_container(TestQListContainer
*c
)
1330 TestQListElement
*prev
= NULL
, *iter
= QLIST_FIRST(&c
->list
);
1331 TestQListElement
*elem
;
1333 elem
= g_malloc(sizeof(TestQListElement
));
1335 QLIST_INSERT_AFTER(iter
, elem
, next
);
1337 elem
= g_malloc(sizeof(TestQListElement
));
1339 QLIST_INSERT_HEAD(&c
->list
, elem
, next
);
1343 iter
= QLIST_NEXT(iter
, next
);
1346 elem
= g_malloc(sizeof(TestQListElement
));
1348 QLIST_INSERT_BEFORE(prev
, elem
, next
);
1350 elem
= g_malloc(sizeof(TestQListElement
));
1352 QLIST_INSERT_AFTER(prev
, elem
, next
);
1354 QLIST_REMOVE(prev
, next
);
1358 static void test_save_qlist(void)
1360 TestQListContainer
*container
= alloc_container();
1362 save_vmstate(&vmstate_container
, container
);
1363 compare_vmstate(qlist_dump
, sizeof(qlist_dump
));
1364 free_container(container
);
1367 static void test_load_qlist(void)
1369 QEMUFile
*fsave
, *fload
;
1370 TestQListContainer
*orig_container
= alloc_container();
1371 TestQListContainer
*dest_container
= g_malloc0(sizeof(TestQListContainer
));
1374 QLIST_INIT(&dest_container
->list
);
1376 fsave
= open_test_file(true);
1377 qemu_put_buffer(fsave
, qlist_dump
, sizeof(qlist_dump
));
1378 g_assert(!qemu_file_get_error(fsave
));
1381 fload
= open_test_file(false);
1382 vmstate_load_state(fload
, &vmstate_container
, dest_container
, 1);
1383 eof
= qemu_get_byte(fload
);
1384 g_assert(!qemu_file_get_error(fload
));
1385 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
1386 manipulate_container(orig_container
);
1387 manipulate_container(dest_container
);
1388 compare_containers(orig_container
, dest_container
);
1389 free_container(orig_container
);
1390 free_container(dest_container
);
1394 typedef struct TmpTestStruct
{
1399 static int tmp_child_pre_save(void *opaque
)
1401 struct TmpTestStruct
*tts
= opaque
;
1403 tts
->diff
= tts
->parent
->b
- tts
->parent
->a
;
1408 static int tmp_child_post_load(void *opaque
, int version_id
)
1410 struct TmpTestStruct
*tts
= opaque
;
1412 tts
->parent
->b
= tts
->parent
->a
+ tts
->diff
;
1417 static const VMStateDescription vmstate_tmp_back_to_parent
= {
1418 .name
= "test/tmp_child_parent",
1419 .fields
= (VMStateField
[]) {
1420 VMSTATE_UINT64(f
, TestStruct
),
1421 VMSTATE_END_OF_LIST()
1425 static const VMStateDescription vmstate_tmp_child
= {
1426 .name
= "test/tmp_child",
1427 .pre_save
= tmp_child_pre_save
,
1428 .post_load
= tmp_child_post_load
,
1429 .fields
= (VMStateField
[]) {
1430 VMSTATE_INT64(diff
, TmpTestStruct
),
1431 VMSTATE_STRUCT_POINTER(parent
, TmpTestStruct
,
1432 vmstate_tmp_back_to_parent
, TestStruct
),
1433 VMSTATE_END_OF_LIST()
1437 static const VMStateDescription vmstate_with_tmp
= {
1438 .name
= "test/with_tmp",
1440 .fields
= (VMStateField
[]) {
1441 VMSTATE_UINT32(a
, TestStruct
),
1442 VMSTATE_UINT64(d
, TestStruct
),
1443 VMSTATE_WITH_TMP(TestStruct
, TmpTestStruct
, vmstate_tmp_child
),
1444 VMSTATE_END_OF_LIST()
1448 static void obj_tmp_copy(void *target
, void *source
)
1450 memcpy(target
, source
, sizeof(TestStruct
));
1453 static void test_tmp_struct(void)
1455 TestStruct obj
, obj_clone
;
1457 uint8_t const wire_with_tmp
[] = {
1458 /* u32 a */ 0x00, 0x00, 0x00, 0x02,
1459 /* u64 d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1460 /* diff */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
1461 /* u64 f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
1462 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
1465 memset(&obj
, 0, sizeof(obj
));
1470 save_vmstate(&vmstate_with_tmp
, &obj
);
1472 compare_vmstate(wire_with_tmp
, sizeof(wire_with_tmp
));
1474 memset(&obj
, 0, sizeof(obj
));
1475 SUCCESS(load_vmstate(&vmstate_with_tmp
, &obj
, &obj_clone
,
1476 obj_tmp_copy
, 1, wire_with_tmp
,
1477 sizeof(wire_with_tmp
)));
1478 g_assert_cmpint(obj
.a
, ==, 2); /* From top level vmsd */
1479 g_assert_cmpint(obj
.b
, ==, 4); /* from the post_load */
1480 g_assert_cmpint(obj
.d
, ==, 1); /* From top level vmsd */
1481 g_assert_cmpint(obj
.f
, ==, 8); /* From the child->parent */
1484 int main(int argc
, char **argv
)
1486 g_autofree
char *temp_file
= g_strdup_printf("%s/vmst.test.XXXXXX",
1488 temp_fd
= mkstemp(temp_file
);
1490 module_call_init(MODULE_INIT_QOM
);
1492 g_setenv("QTEST_SILENT_ERRORS", "1", 1);
1494 g_test_init(&argc
, &argv
, NULL
);
1495 g_test_add_func("/vmstate/simple/primitive", test_simple_primitive
);
1496 g_test_add_func("/vmstate/simple/array", test_simple_array
);
1497 g_test_add_func("/vmstate/versioned/load/v1", test_load_v1
);
1498 g_test_add_func("/vmstate/versioned/load/v2", test_load_v2
);
1499 g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip
);
1500 g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip
);
1501 g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip
);
1502 g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip
);
1503 g_test_add_func("/vmstate/array/ptr/str/no0/save",
1504 test_arr_ptr_str_no0_save
);
1505 g_test_add_func("/vmstate/array/ptr/str/no0/load",
1506 test_arr_ptr_str_no0_load
);
1507 g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save
);
1508 g_test_add_func("/vmstate/array/ptr/str/0/load",
1509 test_arr_ptr_str_0_load
);
1510 g_test_add_func("/vmstate/array/ptr/prim/0/save",
1511 test_arr_ptr_prim_0_save
);
1512 g_test_add_func("/vmstate/array/ptr/prim/0/load",
1513 test_arr_ptr_prim_0_load
);
1514 g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q
);
1515 g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q
);
1516 g_test_add_func("/vmstate/gtree/save/savedomain", test_gtree_save_domain
);
1517 g_test_add_func("/vmstate/gtree/load/loaddomain", test_gtree_load_domain
);
1518 g_test_add_func("/vmstate/gtree/save/saveiommu", test_gtree_save_iommu
);
1519 g_test_add_func("/vmstate/gtree/load/loadiommu", test_gtree_load_iommu
);
1520 g_test_add_func("/vmstate/qlist/save/saveqlist", test_save_qlist
);
1521 g_test_add_func("/vmstate/qlist/load/loadqlist", test_load_qlist
);
1522 g_test_add_func("/vmstate/tmp_struct", test_tmp_struct
);