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/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"
37 /* Duplicate temp_fd and seek to the beginning of the file */
38 static QEMUFile
*open_test_file(bool write
)
46 lseek(fd
, 0, SEEK_SET
);
48 g_assert_cmpint(ftruncate(fd
, 0), ==, 0);
50 ioc
= QIO_CHANNEL(qio_channel_file_new_fd(fd
));
52 f
= qemu_file_new_output(ioc
);
54 f
= qemu_file_new_input(ioc
);
56 object_unref(OBJECT(ioc
));
60 #define SUCCESS(val) \
61 g_assert_cmpint((val), ==, 0)
63 #define FAILURE(val) \
64 g_assert_cmpint((val), !=, 0)
66 static void save_vmstate(const VMStateDescription
*desc
, void *obj
)
68 QEMUFile
*f
= open_test_file(true);
70 /* Save file with vmstate */
71 int ret
= vmstate_save_state(f
, desc
, obj
, NULL
);
73 qemu_put_byte(f
, QEMU_VM_EOF
);
74 g_assert(!qemu_file_get_error(f
));
78 static void save_buffer(const uint8_t *buf
, size_t buf_size
)
80 QEMUFile
*fsave
= open_test_file(true);
81 qemu_put_buffer(fsave
, buf
, buf_size
);
85 static void compare_vmstate(const uint8_t *wire
, size_t size
)
87 QEMUFile
*f
= open_test_file(false);
88 g_autofree
uint8_t *result
= g_malloc(size
);
90 /* read back as binary */
92 g_assert_cmpint(qemu_get_buffer(f
, result
, size
), ==, size
);
93 g_assert(!qemu_file_get_error(f
));
95 /* Compare that what is on the file is the same that what we
96 expected to be there */
97 SUCCESS(memcmp(result
, wire
, size
));
101 g_assert_cmpint(qemu_file_get_error(f
), ==, -EIO
);
106 static int load_vmstate_one(const VMStateDescription
*desc
, void *obj
,
107 int version
, const uint8_t *wire
, size_t size
)
112 f
= open_test_file(true);
113 qemu_put_buffer(f
, wire
, size
);
116 f
= open_test_file(false);
117 ret
= vmstate_load_state(f
, desc
, obj
, version
);
119 g_assert(qemu_file_get_error(f
));
121 g_assert(!qemu_file_get_error(f
));
128 static int load_vmstate(const VMStateDescription
*desc
,
129 void *obj
, void *obj_clone
,
130 void (*obj_copy
)(void *, void*),
131 int version
, const uint8_t *wire
, size_t size
)
133 /* We test with zero size */
134 obj_copy(obj_clone
, obj
);
135 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, 0));
137 /* Stream ends with QEMU_EOF, so we need at least 3 bytes to be
138 * able to test in the middle */
142 /* We test with size - 2. We can't test size - 1 due to EOF tricks */
143 obj_copy(obj
, obj_clone
);
144 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, size
- 2));
146 /* Test with size/2, first half of real state */
147 obj_copy(obj
, obj_clone
);
148 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, size
/2));
150 /* Test with size/2, second half of real state */
151 obj_copy(obj
, obj_clone
);
152 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
+ (size
/2), size
/2));
155 obj_copy(obj
, obj_clone
);
156 return load_vmstate_one(desc
, obj
, version
, wire
, size
);
159 /* Test struct that we are going to use for our tests */
161 typedef struct TestSimple
{
168 int16_t i16_1
, i16_2
;
169 int32_t i32_1
, i32_2
;
170 int64_t i64_1
, i64_2
;
173 /* Object instantiation, we are going to use it in more than one test */
175 TestSimple obj_simple
= {
192 /* Description of the values. If you add a primitive type
193 you are expected to add a test here */
195 static const VMStateDescription vmstate_simple_primitive
= {
196 .name
= "simple/primitive",
198 .minimum_version_id
= 1,
199 .fields
= (const VMStateField
[]) {
200 VMSTATE_BOOL(b_1
, TestSimple
),
201 VMSTATE_BOOL(b_2
, TestSimple
),
202 VMSTATE_UINT8(u8_1
, TestSimple
),
203 VMSTATE_UINT16(u16_1
, TestSimple
),
204 VMSTATE_UINT32(u32_1
, TestSimple
),
205 VMSTATE_UINT64(u64_1
, TestSimple
),
206 VMSTATE_INT8(i8_1
, TestSimple
),
207 VMSTATE_INT8(i8_2
, TestSimple
),
208 VMSTATE_INT16(i16_1
, TestSimple
),
209 VMSTATE_INT16(i16_2
, TestSimple
),
210 VMSTATE_INT32(i32_1
, TestSimple
),
211 VMSTATE_INT32(i32_2
, TestSimple
),
212 VMSTATE_INT64(i64_1
, TestSimple
),
213 VMSTATE_INT64(i64_2
, TestSimple
),
214 VMSTATE_END_OF_LIST()
218 /* It describes what goes through the wire. Our tests are basically:
221 - save a struct a vmstate to a file
222 - read that file back (binary read, no vmstate)
223 - compare it with what we expect to be on the wire
225 - save to the file what we expect to be on the wire
226 - read struct back with vmstate in a different
227 - compare back with the original struct
230 uint8_t wire_simple_primitive
[] = {
234 /* u16_1 */ 0x02, 0x00,
235 /* u32_1 */ 0x00, 0x01, 0x11, 0x70,
236 /* u64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
239 /* i16_1 */ 0x02, 0x00,
240 /* i16_2 */ 0xfe, 0x0,
241 /* i32_1 */ 0x00, 0x01, 0x11, 0x70,
242 /* i32_2 */ 0xff, 0xfe, 0xee, 0x90,
243 /* i64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
244 /* i64_2 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x0b, 0x84,
245 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
248 static void obj_simple_copy(void *target
, void *source
)
250 memcpy(target
, source
, sizeof(TestSimple
));
253 static void test_simple_primitive(void)
255 TestSimple obj
, obj_clone
;
257 memset(&obj
, 0, sizeof(obj
));
258 save_vmstate(&vmstate_simple_primitive
, &obj_simple
);
260 compare_vmstate(wire_simple_primitive
, sizeof(wire_simple_primitive
));
262 SUCCESS(load_vmstate(&vmstate_simple_primitive
, &obj
, &obj_clone
,
263 obj_simple_copy
, 1, wire_simple_primitive
,
264 sizeof(wire_simple_primitive
)));
266 #define FIELD_EQUAL(name) g_assert_cmpint(obj.name, ==, obj_simple.name)
284 typedef struct TestSimpleArray
{
288 /* Object instantiation, we are going to use it in more than one test */
290 TestSimpleArray obj_simple_arr
= {
291 .u16_1
= { 0x42, 0x43, 0x44 },
294 /* Description of the values. If you add a primitive type
295 you are expected to add a test here */
297 static const VMStateDescription vmstate_simple_arr
= {
298 .name
= "simple/array",
300 .minimum_version_id
= 1,
301 .fields
= (const VMStateField
[]) {
302 VMSTATE_UINT16_ARRAY(u16_1
, TestSimpleArray
, 3),
303 VMSTATE_END_OF_LIST()
307 uint8_t wire_simple_arr
[] = {
308 /* u16_1 */ 0x00, 0x42,
309 /* u16_1 */ 0x00, 0x43,
310 /* u16_1 */ 0x00, 0x44,
311 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
314 static void obj_simple_arr_copy(void *target
, void *source
)
316 memcpy(target
, source
, sizeof(TestSimpleArray
));
319 static void test_simple_array(void)
321 TestSimpleArray obj
, obj_clone
;
323 memset(&obj
, 0, sizeof(obj
));
324 save_vmstate(&vmstate_simple_arr
, &obj_simple_arr
);
326 compare_vmstate(wire_simple_arr
, sizeof(wire_simple_arr
));
328 SUCCESS(load_vmstate(&vmstate_simple_arr
, &obj
, &obj_clone
,
329 obj_simple_arr_copy
, 1, wire_simple_arr
,
330 sizeof(wire_simple_arr
)));
333 typedef struct TestStruct
{
339 static const VMStateDescription vmstate_versioned
= {
340 .name
= "test/versioned",
342 .minimum_version_id
= 1,
343 .fields
= (const VMStateField
[]) {
344 VMSTATE_UINT32(a
, TestStruct
),
345 VMSTATE_UINT32_V(b
, TestStruct
, 2), /* Versioned field in the middle, so
346 * we catch bugs more easily.
348 VMSTATE_UINT32(c
, TestStruct
),
349 VMSTATE_UINT64(d
, TestStruct
),
350 VMSTATE_UINT32_V(e
, TestStruct
, 2),
351 VMSTATE_UINT64_V(f
, TestStruct
, 2),
352 VMSTATE_END_OF_LIST()
356 static void test_load_v1(void)
361 0, 0, 0, 0, 0, 0, 0, 40, /* d */
362 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
364 save_buffer(buf
, sizeof(buf
));
366 QEMUFile
*loading
= open_test_file(false);
367 TestStruct obj
= { .b
= 200, .e
= 500, .f
= 600 };
368 vmstate_load_state(loading
, &vmstate_versioned
, &obj
, 1);
369 g_assert(!qemu_file_get_error(loading
));
370 g_assert_cmpint(obj
.a
, ==, 10);
371 g_assert_cmpint(obj
.b
, ==, 200);
372 g_assert_cmpint(obj
.c
, ==, 30);
373 g_assert_cmpint(obj
.d
, ==, 40);
374 g_assert_cmpint(obj
.e
, ==, 500);
375 g_assert_cmpint(obj
.f
, ==, 600);
376 qemu_fclose(loading
);
379 static void test_load_v2(void)
385 0, 0, 0, 0, 0, 0, 0, 40, /* d */
387 0, 0, 0, 0, 0, 0, 0, 60, /* f */
388 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
390 save_buffer(buf
, sizeof(buf
));
392 QEMUFile
*loading
= open_test_file(false);
394 vmstate_load_state(loading
, &vmstate_versioned
, &obj
, 2);
395 g_assert_cmpint(obj
.a
, ==, 10);
396 g_assert_cmpint(obj
.b
, ==, 20);
397 g_assert_cmpint(obj
.c
, ==, 30);
398 g_assert_cmpint(obj
.d
, ==, 40);
399 g_assert_cmpint(obj
.e
, ==, 50);
400 g_assert_cmpint(obj
.f
, ==, 60);
401 qemu_fclose(loading
);
404 static bool test_skip(void *opaque
, int version_id
)
406 TestStruct
*t
= (TestStruct
*)opaque
;
410 static const VMStateDescription vmstate_skipping
= {
413 .minimum_version_id
= 1,
414 .fields
= (const VMStateField
[]) {
415 VMSTATE_UINT32(a
, TestStruct
),
416 VMSTATE_UINT32(b
, TestStruct
),
417 VMSTATE_UINT32_TEST(c
, TestStruct
, test_skip
),
418 VMSTATE_UINT64(d
, TestStruct
),
419 VMSTATE_UINT32_TEST(e
, TestStruct
, test_skip
),
420 VMSTATE_UINT64_V(f
, TestStruct
, 2),
421 VMSTATE_END_OF_LIST()
426 static void test_save_noskip(void)
428 QEMUFile
*fsave
= open_test_file(true);
429 TestStruct obj
= { .a
= 1, .b
= 2, .c
= 3, .d
= 4, .e
= 5, .f
= 6,
431 int ret
= vmstate_save_state(fsave
, &vmstate_skipping
, &obj
, NULL
);
433 g_assert(!qemu_file_get_error(fsave
));
435 uint8_t expected
[] = {
439 0, 0, 0, 0, 0, 0, 0, 4, /* d */
441 0, 0, 0, 0, 0, 0, 0, 6, /* f */
445 compare_vmstate(expected
, sizeof(expected
));
448 static void test_save_skip(void)
450 QEMUFile
*fsave
= open_test_file(true);
451 TestStruct obj
= { .a
= 1, .b
= 2, .c
= 3, .d
= 4, .e
= 5, .f
= 6,
453 int ret
= vmstate_save_state(fsave
, &vmstate_skipping
, &obj
, NULL
);
455 g_assert(!qemu_file_get_error(fsave
));
457 uint8_t expected
[] = {
460 0, 0, 0, 0, 0, 0, 0, 4, /* d */
461 0, 0, 0, 0, 0, 0, 0, 6, /* f */
465 compare_vmstate(expected
, sizeof(expected
));
468 static void test_load_noskip(void)
474 0, 0, 0, 0, 0, 0, 0, 40, /* d */
476 0, 0, 0, 0, 0, 0, 0, 60, /* f */
477 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
479 save_buffer(buf
, sizeof(buf
));
481 QEMUFile
*loading
= open_test_file(false);
482 TestStruct obj
= { .skip_c_e
= false };
483 vmstate_load_state(loading
, &vmstate_skipping
, &obj
, 2);
484 g_assert(!qemu_file_get_error(loading
));
485 g_assert_cmpint(obj
.a
, ==, 10);
486 g_assert_cmpint(obj
.b
, ==, 20);
487 g_assert_cmpint(obj
.c
, ==, 30);
488 g_assert_cmpint(obj
.d
, ==, 40);
489 g_assert_cmpint(obj
.e
, ==, 50);
490 g_assert_cmpint(obj
.f
, ==, 60);
491 qemu_fclose(loading
);
494 static void test_load_skip(void)
499 0, 0, 0, 0, 0, 0, 0, 40, /* d */
500 0, 0, 0, 0, 0, 0, 0, 60, /* f */
501 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
503 save_buffer(buf
, sizeof(buf
));
505 QEMUFile
*loading
= open_test_file(false);
506 TestStruct obj
= { .skip_c_e
= true, .c
= 300, .e
= 500 };
507 vmstate_load_state(loading
, &vmstate_skipping
, &obj
, 2);
508 g_assert(!qemu_file_get_error(loading
));
509 g_assert_cmpint(obj
.a
, ==, 10);
510 g_assert_cmpint(obj
.b
, ==, 20);
511 g_assert_cmpint(obj
.c
, ==, 300);
512 g_assert_cmpint(obj
.d
, ==, 40);
513 g_assert_cmpint(obj
.e
, ==, 500);
514 g_assert_cmpint(obj
.f
, ==, 60);
515 qemu_fclose(loading
);
522 const VMStateDescription vmsd_tst
= {
525 .minimum_version_id
= 1,
526 .fields
= (const VMStateField
[]) {
527 VMSTATE_INT32(i
, TestStructTriv
),
528 VMSTATE_END_OF_LIST()
532 /* test array migration */
537 TestStructTriv
*ar
[AR_SIZE
];
538 } TestArrayOfPtrToStuct
;
540 const VMStateDescription vmsd_arps
= {
543 .minimum_version_id
= 1,
544 .fields
= (const VMStateField
[]) {
545 VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(ar
, TestArrayOfPtrToStuct
,
546 AR_SIZE
, 0, vmsd_tst
, TestStructTriv
),
547 VMSTATE_END_OF_LIST()
551 static uint8_t wire_arr_ptr_no0
[] = {
552 0x00, 0x00, 0x00, 0x00,
553 0x00, 0x00, 0x00, 0x01,
554 0x00, 0x00, 0x00, 0x02,
555 0x00, 0x00, 0x00, 0x03,
559 static void test_arr_ptr_str_no0_save(void)
561 TestStructTriv ar
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
562 TestArrayOfPtrToStuct sample
= {.ar
= {&ar
[0], &ar
[1], &ar
[2], &ar
[3]} };
564 save_vmstate(&vmsd_arps
, &sample
);
565 compare_vmstate(wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
));
568 static void test_arr_ptr_str_no0_load(void)
570 TestStructTriv ar_gt
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
571 TestStructTriv ar
[AR_SIZE
] = {};
572 TestArrayOfPtrToStuct obj
= {.ar
= {&ar
[0], &ar
[1], &ar
[2], &ar
[3]} };
575 save_buffer(wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
));
576 SUCCESS(load_vmstate_one(&vmsd_arps
, &obj
, 1,
577 wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
)));
578 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
579 /* compare the target array ar with the ground truth array ar_gt */
580 g_assert_cmpint(ar_gt
[idx
].i
, ==, ar
[idx
].i
);
584 static uint8_t wire_arr_ptr_0
[] = {
585 0x00, 0x00, 0x00, 0x00,
587 0x00, 0x00, 0x00, 0x02,
588 0x00, 0x00, 0x00, 0x03,
592 static void test_arr_ptr_str_0_save(void)
594 TestStructTriv ar
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
595 TestArrayOfPtrToStuct sample
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
597 save_vmstate(&vmsd_arps
, &sample
);
598 compare_vmstate(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
601 static void test_arr_ptr_str_0_load(void)
603 TestStructTriv ar_gt
[AR_SIZE
] = {{.i
= 0}, {.i
= 0}, {.i
= 2}, {.i
= 3} };
604 TestStructTriv ar
[AR_SIZE
] = {};
605 TestArrayOfPtrToStuct obj
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
608 save_buffer(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
609 SUCCESS(load_vmstate_one(&vmsd_arps
, &obj
, 1,
610 wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
)));
611 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
612 /* compare the target array ar with the ground truth array ar_gt */
613 g_assert_cmpint(ar_gt
[idx
].i
, ==, ar
[idx
].i
);
615 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
617 g_assert_cmpint((uintptr_t)(obj
.ar
[idx
]), ==, 0);
619 g_assert_cmpint((uintptr_t)(obj
.ar
[idx
]), !=, 0);
624 typedef struct TestArrayOfPtrToInt
{
625 int32_t *ar
[AR_SIZE
];
626 } TestArrayOfPtrToInt
;
628 const VMStateDescription vmsd_arpp
= {
631 .minimum_version_id
= 1,
632 .fields
= (const VMStateField
[]) {
633 VMSTATE_ARRAY_OF_POINTER(ar
, TestArrayOfPtrToInt
,
634 AR_SIZE
, 0, vmstate_info_int32
, int32_t*),
635 VMSTATE_END_OF_LIST()
639 static void test_arr_ptr_prim_0_save(void)
641 int32_t ar
[AR_SIZE
] = {0 , 1, 2, 3};
642 TestArrayOfPtrToInt sample
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
644 save_vmstate(&vmsd_arpp
, &sample
);
645 compare_vmstate(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
648 static void test_arr_ptr_prim_0_load(void)
650 int32_t ar_gt
[AR_SIZE
] = {0, 1, 2, 3};
651 int32_t ar
[AR_SIZE
] = {3 , 42, 1, 0};
652 TestArrayOfPtrToInt obj
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
655 save_buffer(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
656 SUCCESS(load_vmstate_one(&vmsd_arpp
, &obj
, 1,
657 wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
)));
658 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
659 /* compare the target array ar with the ground truth array ar_gt */
661 g_assert_cmpint(42, ==, ar
[idx
]);
663 g_assert_cmpint(ar_gt
[idx
], ==, ar
[idx
]);
668 /* test QTAILQ migration */
669 typedef struct TestQtailqElement TestQtailqElement
;
671 struct TestQtailqElement
{
674 QTAILQ_ENTRY(TestQtailqElement
) next
;
677 typedef struct TestQtailq
{
679 QTAILQ_HEAD(, TestQtailqElement
) q
;
683 static const VMStateDescription vmstate_q_element
= {
684 .name
= "test/queue-element",
686 .minimum_version_id
= 1,
687 .fields
= (const VMStateField
[]) {
688 VMSTATE_BOOL(b
, TestQtailqElement
),
689 VMSTATE_UINT8(u8
, TestQtailqElement
),
690 VMSTATE_END_OF_LIST()
694 static const VMStateDescription vmstate_q
= {
695 .name
= "test/queue",
697 .minimum_version_id
= 1,
698 .fields
= (const VMStateField
[]) {
699 VMSTATE_INT16(i16
, TestQtailq
),
700 VMSTATE_QTAILQ_V(q
, TestQtailq
, 1, vmstate_q_element
, TestQtailqElement
,
702 VMSTATE_INT32(i32
, TestQtailq
),
703 VMSTATE_END_OF_LIST()
709 /* start of element 0 of q */ 0x01,
712 /* start of element 1 of q */ 0x01,
716 /* i32 */ 0x00, 0x01, 0x11, 0x70,
717 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
720 static void test_save_q(void)
727 TestQtailqElement obj_qe1
= {
732 TestQtailqElement obj_qe2
= {
737 QTAILQ_INIT(&obj_q
.q
);
738 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe1
, next
);
739 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe2
, next
);
741 save_vmstate(&vmstate_q
, &obj_q
);
742 compare_vmstate(wire_q
, sizeof(wire_q
));
745 static void test_load_q(void)
752 TestQtailqElement obj_qe1
= {
757 TestQtailqElement obj_qe2
= {
762 QTAILQ_INIT(&obj_q
.q
);
763 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe1
, next
);
764 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe2
, next
);
766 QEMUFile
*fsave
= open_test_file(true);
768 qemu_put_buffer(fsave
, wire_q
, sizeof(wire_q
));
769 g_assert(!qemu_file_get_error(fsave
));
772 QEMUFile
*fload
= open_test_file(false);
776 vmstate_load_state(fload
, &vmstate_q
, &tgt
, 1);
777 char eof
= qemu_get_byte(fload
);
778 g_assert(!qemu_file_get_error(fload
));
779 g_assert_cmpint(tgt
.i16
, ==, obj_q
.i16
);
780 g_assert_cmpint(tgt
.i32
, ==, obj_q
.i32
);
781 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
783 TestQtailqElement
*qele_from
= QTAILQ_FIRST(&obj_q
.q
);
784 TestQtailqElement
*qlast_from
= QTAILQ_LAST(&obj_q
.q
);
785 TestQtailqElement
*qele_to
= QTAILQ_FIRST(&tgt
.q
);
786 TestQtailqElement
*qlast_to
= QTAILQ_LAST(&tgt
.q
);
789 g_assert_cmpint(qele_to
->b
, ==, qele_from
->b
);
790 g_assert_cmpint(qele_to
->u8
, ==, qele_from
->u8
);
791 if ((qele_from
== qlast_from
) || (qele_to
== qlast_to
)) {
794 qele_from
= QTAILQ_NEXT(qele_from
, next
);
795 qele_to
= QTAILQ_NEXT(qele_to
, next
);
798 g_assert_cmpint((uintptr_t) qele_from
, ==, (uintptr_t) qlast_from
);
799 g_assert_cmpint((uintptr_t) qele_to
, ==, (uintptr_t) qlast_to
);
802 TestQtailqElement
*qele
;
803 while (!QTAILQ_EMPTY(&tgt
.q
)) {
804 qele
= QTAILQ_LAST(&tgt
.q
);
805 QTAILQ_REMOVE(&tgt
.q
, qele
, next
);
813 typedef struct TestGTreeInterval
{
818 #define VMSTATE_INTERVAL \
820 .name = "interval", \
822 .minimum_version_id = 1, \
823 .fields = (const VMStateField[]) { \
824 VMSTATE_UINT64(low, TestGTreeInterval), \
825 VMSTATE_UINT64(high, TestGTreeInterval), \
826 VMSTATE_END_OF_LIST() \
830 /* mapping (value) */
831 typedef struct TestGTreeMapping
{
836 #define VMSTATE_MAPPING \
840 .minimum_version_id = 1, \
841 .fields = (const VMStateField[]) { \
842 VMSTATE_UINT64(phys_addr, TestGTreeMapping), \
843 VMSTATE_UINT32(flags, TestGTreeMapping), \
844 VMSTATE_END_OF_LIST() \
848 static const VMStateDescription vmstate_interval_mapping
[2] = {
849 VMSTATE_MAPPING
, /* value */
850 VMSTATE_INTERVAL
/* key */
853 typedef struct TestGTreeDomain
{
858 typedef struct TestGTreeIOMMU
{
863 /* Interval comparison function */
864 static gint
interval_cmp(gconstpointer a
, gconstpointer b
, gpointer user_data
)
866 TestGTreeInterval
*inta
= (TestGTreeInterval
*)a
;
867 TestGTreeInterval
*intb
= (TestGTreeInterval
*)b
;
869 if (inta
->high
< intb
->low
) {
871 } else if (intb
->high
< inta
->low
) {
878 /* ID comparison function */
879 static gint
int_cmp(gconstpointer a
, gconstpointer b
, gpointer user_data
)
881 guint ua
= GPOINTER_TO_UINT(a
);
882 guint ub
= GPOINTER_TO_UINT(b
);
883 return (ua
> ub
) - (ua
< ub
);
886 static void destroy_domain(gpointer data
)
888 TestGTreeDomain
*domain
= (TestGTreeDomain
*)data
;
890 g_tree_destroy(domain
->mappings
);
894 static int domain_preload(void *opaque
)
896 TestGTreeDomain
*domain
= opaque
;
898 domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
,
899 NULL
, g_free
, g_free
);
903 static int iommu_preload(void *opaque
)
905 TestGTreeIOMMU
*iommu
= opaque
;
907 iommu
->domains
= g_tree_new_full((GCompareDataFunc
)int_cmp
,
908 NULL
, NULL
, destroy_domain
);
912 static const VMStateDescription vmstate_domain
= {
915 .minimum_version_id
= 1,
916 .pre_load
= domain_preload
,
917 .fields
= (const VMStateField
[]) {
918 VMSTATE_INT32(id
, TestGTreeDomain
),
919 VMSTATE_GTREE_V(mappings
, TestGTreeDomain
, 1,
920 vmstate_interval_mapping
,
921 TestGTreeInterval
, TestGTreeMapping
),
922 VMSTATE_END_OF_LIST()
926 /* test QLIST Migration */
928 typedef struct TestQListElement
{
930 QLIST_ENTRY(TestQListElement
) next
;
933 typedef struct TestQListContainer
{
935 QLIST_HEAD(, TestQListElement
) list
;
936 } TestQListContainer
;
938 static const VMStateDescription vmstate_qlist_element
= {
939 .name
= "test/queue list",
941 .minimum_version_id
= 1,
942 .fields
= (const VMStateField
[]) {
943 VMSTATE_UINT32(id
, TestQListElement
),
944 VMSTATE_END_OF_LIST()
948 static const VMStateDescription vmstate_iommu
= {
951 .minimum_version_id
= 1,
952 .pre_load
= iommu_preload
,
953 .fields
= (const VMStateField
[]) {
954 VMSTATE_INT32(id
, TestGTreeIOMMU
),
955 VMSTATE_GTREE_DIRECT_KEY_V(domains
, TestGTreeIOMMU
, 1,
956 &vmstate_domain
, TestGTreeDomain
),
957 VMSTATE_END_OF_LIST()
961 static const VMStateDescription vmstate_container
= {
962 .name
= "test/container/qlist",
964 .minimum_version_id
= 1,
965 .fields
= (const VMStateField
[]) {
966 VMSTATE_UINT32(id
, TestQListContainer
),
967 VMSTATE_QLIST_V(list
, TestQListContainer
, 1, vmstate_qlist_element
,
968 TestQListElement
, next
),
969 VMSTATE_END_OF_LIST()
973 uint8_t first_domain_dump
[] = {
976 0x00, 0x0, 0x0, 0x2, /* 2 mappings */
977 0x1, /* start of a */
979 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
980 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
982 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00,
983 0x00, 0x00, 0x00, 0x01,
984 0x1, /* start of b */
986 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
987 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF,
989 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
990 0x00, 0x00, 0x00, 0x02,
991 0x0, /* end of gtree */
992 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
995 static TestGTreeDomain
*create_first_domain(void)
997 TestGTreeDomain
*domain
;
998 TestGTreeMapping
*map_a
, *map_b
;
999 TestGTreeInterval
*a
, *b
;
1001 domain
= g_new0(TestGTreeDomain
, 1);
1004 a
= g_new0(TestGTreeInterval
, 1);
1008 b
= g_new0(TestGTreeInterval
, 1);
1012 map_a
= g_new0(TestGTreeMapping
, 1);
1013 map_a
->phys_addr
= 0xa000;
1016 map_b
= g_new0(TestGTreeMapping
, 1);
1017 map_b
->phys_addr
= 0xe0000;
1020 domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
, NULL
,
1021 (GDestroyNotify
)g_free
,
1022 (GDestroyNotify
)g_free
);
1023 g_tree_insert(domain
->mappings
, a
, map_a
);
1024 g_tree_insert(domain
->mappings
, b
, map_b
);
1028 static void test_gtree_save_domain(void)
1030 TestGTreeDomain
*first_domain
= create_first_domain();
1032 save_vmstate(&vmstate_domain
, first_domain
);
1033 compare_vmstate(first_domain_dump
, sizeof(first_domain_dump
));
1034 destroy_domain(first_domain
);
1037 struct match_node_data
{
1043 struct tree_cmp_data
{
1046 GTraverseFunc match_node
;
1049 static gboolean
match_interval_mapping_node(gpointer key
,
1050 gpointer value
, gpointer data
)
1052 TestGTreeMapping
*map_a
, *map_b
;
1053 TestGTreeInterval
*a
, *b
;
1054 struct match_node_data
*d
= (struct match_node_data
*)data
;
1055 a
= (TestGTreeInterval
*)key
;
1056 b
= (TestGTreeInterval
*)d
->key
;
1058 map_a
= (TestGTreeMapping
*)value
;
1059 map_b
= (TestGTreeMapping
*)d
->value
;
1061 assert(a
->low
== b
->low
);
1062 assert(a
->high
== b
->high
);
1063 assert(map_a
->phys_addr
== map_b
->phys_addr
);
1064 assert(map_a
->flags
== map_b
->flags
);
1065 g_tree_remove(d
->tree
, key
);
1069 static gboolean
diff_tree(gpointer key
, gpointer value
, gpointer data
)
1071 struct tree_cmp_data
*tp
= (struct tree_cmp_data
*)data
;
1072 struct match_node_data d
= {tp
->tree2
, key
, value
};
1074 g_tree_foreach(tp
->tree2
, tp
->match_node
, &d
);
1078 static void compare_trees(GTree
*tree1
, GTree
*tree2
,
1079 GTraverseFunc function
)
1081 struct tree_cmp_data tp
= {tree1
, tree2
, function
};
1083 assert(g_tree_nnodes(tree1
) == g_tree_nnodes(tree2
));
1084 g_tree_foreach(tree1
, diff_tree
, &tp
);
1085 g_tree_destroy(g_tree_ref(tree1
));
1088 static void diff_domain(TestGTreeDomain
*d1
, TestGTreeDomain
*d2
)
1090 assert(d1
->id
== d2
->id
);
1091 compare_trees(d1
->mappings
, d2
->mappings
, match_interval_mapping_node
);
1094 static gboolean
match_domain_node(gpointer key
, gpointer value
, gpointer data
)
1097 TestGTreeDomain
*d1
, *d2
;
1098 struct match_node_data
*d
= (struct match_node_data
*)data
;
1100 id1
= (uint64_t)(uintptr_t)key
;
1101 id2
= (uint64_t)(uintptr_t)d
->key
;
1102 d1
= (TestGTreeDomain
*)value
;
1103 d2
= (TestGTreeDomain
*)d
->value
;
1105 diff_domain(d1
, d2
);
1106 g_tree_remove(d
->tree
, key
);
1110 static void diff_iommu(TestGTreeIOMMU
*iommu1
, TestGTreeIOMMU
*iommu2
)
1112 assert(iommu1
->id
== iommu2
->id
);
1113 compare_trees(iommu1
->domains
, iommu2
->domains
, match_domain_node
);
1116 static void test_gtree_load_domain(void)
1118 TestGTreeDomain
*dest_domain
= g_new0(TestGTreeDomain
, 1);
1119 TestGTreeDomain
*orig_domain
= create_first_domain();
1120 QEMUFile
*fload
, *fsave
;
1123 fsave
= open_test_file(true);
1124 qemu_put_buffer(fsave
, first_domain_dump
, sizeof(first_domain_dump
));
1125 g_assert(!qemu_file_get_error(fsave
));
1128 fload
= open_test_file(false);
1130 vmstate_load_state(fload
, &vmstate_domain
, dest_domain
, 1);
1131 eof
= qemu_get_byte(fload
);
1132 g_assert(!qemu_file_get_error(fload
));
1133 g_assert_cmpint(orig_domain
->id
, ==, dest_domain
->id
);
1134 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
1136 diff_domain(orig_domain
, dest_domain
);
1137 destroy_domain(orig_domain
);
1138 destroy_domain(dest_domain
);
1142 uint8_t iommu_dump
[] = {
1144 0x00, 0x0, 0x0, 0x7,
1145 0x00, 0x0, 0x0, 0x2, /* 2 domains */
1146 0x1,/* start of domain 5 */
1147 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x5, /* key = 5 */
1148 0x00, 0x0, 0x0, 0x5, /* domain1 id */
1149 0x00, 0x0, 0x0, 0x1, /* 1 mapping */
1150 0x1, /* start of mappings */
1152 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1153 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF,
1155 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
1156 0x00, 0x0, 0x0, 0x3,
1157 0x0, /* end of domain1 mappings*/
1158 0x1,/* start of domain 6 */
1159 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x6, /* key = 6 */
1160 0x00, 0x0, 0x0, 0x6, /* domain6 id */
1161 0x00, 0x0, 0x0, 0x2, /* 2 mappings */
1162 0x1, /* start of a */
1164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
1167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00,
1168 0x00, 0x00, 0x00, 0x01,
1169 0x1, /* start of b */
1171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
1172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF,
1174 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
1175 0x00, 0x00, 0x00, 0x02,
1176 0x0, /* end of domain6 mappings*/
1177 0x0, /* end of domains */
1178 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
1181 static TestGTreeIOMMU
*create_iommu(void)
1183 TestGTreeIOMMU
*iommu
= g_new0(TestGTreeIOMMU
, 1);
1184 TestGTreeDomain
*first_domain
= create_first_domain();
1185 TestGTreeDomain
*second_domain
;
1186 TestGTreeMapping
*map_c
;
1187 TestGTreeInterval
*c
;
1190 iommu
->domains
= g_tree_new_full((GCompareDataFunc
)int_cmp
, NULL
,
1194 second_domain
= g_new0(TestGTreeDomain
, 1);
1195 second_domain
->id
= 5;
1196 second_domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
,
1198 (GDestroyNotify
)g_free
,
1199 (GDestroyNotify
)g_free
);
1201 g_tree_insert(iommu
->domains
, GUINT_TO_POINTER(6), first_domain
);
1202 g_tree_insert(iommu
->domains
, (gpointer
)0x0000000000000005, second_domain
);
1204 c
= g_new0(TestGTreeInterval
, 1);
1206 c
->high
= 0x1FFFFFF;
1208 map_c
= g_new0(TestGTreeMapping
, 1);
1209 map_c
->phys_addr
= 0xF000000;
1212 g_tree_insert(second_domain
->mappings
, c
, map_c
);
1216 static void destroy_iommu(TestGTreeIOMMU
*iommu
)
1218 g_tree_destroy(iommu
->domains
);
1222 static void test_gtree_save_iommu(void)
1224 TestGTreeIOMMU
*iommu
= create_iommu();
1226 save_vmstate(&vmstate_iommu
, iommu
);
1227 compare_vmstate(iommu_dump
, sizeof(iommu_dump
));
1228 destroy_iommu(iommu
);
1231 static void test_gtree_load_iommu(void)
1233 TestGTreeIOMMU
*dest_iommu
= g_new0(TestGTreeIOMMU
, 1);
1234 TestGTreeIOMMU
*orig_iommu
= create_iommu();
1235 QEMUFile
*fsave
, *fload
;
1238 fsave
= open_test_file(true);
1239 qemu_put_buffer(fsave
, iommu_dump
, sizeof(iommu_dump
));
1240 g_assert(!qemu_file_get_error(fsave
));
1243 fload
= open_test_file(false);
1244 vmstate_load_state(fload
, &vmstate_iommu
, dest_iommu
, 1);
1245 eof
= qemu_get_byte(fload
);
1246 g_assert(!qemu_file_get_error(fload
));
1247 g_assert_cmpint(orig_iommu
->id
, ==, dest_iommu
->id
);
1248 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
1250 diff_iommu(orig_iommu
, dest_iommu
);
1251 destroy_iommu(orig_iommu
);
1252 destroy_iommu(dest_iommu
);
1256 static uint8_t qlist_dump
[] = {
1257 0x00, 0x00, 0x00, 0x01, /* container id */
1258 0x1, /* start of a */
1259 0x00, 0x00, 0x00, 0x0a,
1260 0x1, /* start of b */
1261 0x00, 0x00, 0x0b, 0x00,
1262 0x1, /* start of c */
1263 0x00, 0x0c, 0x00, 0x00,
1264 0x1, /* start of d */
1265 0x0d, 0x00, 0x00, 0x00,
1266 0x0, /* end of list */
1267 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
1270 static TestQListContainer
*alloc_container(void)
1272 TestQListElement
*a
= g_new(TestQListElement
, 1);
1273 TestQListElement
*b
= g_new(TestQListElement
, 1);
1274 TestQListElement
*c
= g_new(TestQListElement
, 1);
1275 TestQListElement
*d
= g_new(TestQListElement
, 1);
1276 TestQListContainer
*container
= g_new(TestQListContainer
, 1);
1284 QLIST_INIT(&container
->list
);
1285 QLIST_INSERT_HEAD(&container
->list
, d
, next
);
1286 QLIST_INSERT_HEAD(&container
->list
, c
, next
);
1287 QLIST_INSERT_HEAD(&container
->list
, b
, next
);
1288 QLIST_INSERT_HEAD(&container
->list
, a
, next
);
1292 static void free_container(TestQListContainer
*container
)
1294 TestQListElement
*iter
, *tmp
;
1296 QLIST_FOREACH_SAFE(iter
, &container
->list
, next
, tmp
) {
1297 QLIST_REMOVE(iter
, next
);
1303 static void compare_containers(TestQListContainer
*c1
, TestQListContainer
*c2
)
1305 TestQListElement
*first_item_c1
, *first_item_c2
;
1307 while (!QLIST_EMPTY(&c1
->list
)) {
1308 first_item_c1
= QLIST_FIRST(&c1
->list
);
1309 first_item_c2
= QLIST_FIRST(&c2
->list
);
1310 assert(first_item_c2
);
1311 assert(first_item_c1
->id
== first_item_c2
->id
);
1312 QLIST_REMOVE(first_item_c1
, next
);
1313 QLIST_REMOVE(first_item_c2
, next
);
1314 g_free(first_item_c1
);
1315 g_free(first_item_c2
);
1317 assert(QLIST_EMPTY(&c2
->list
));
1321 * Check the prev & next fields are correct by doing list
1322 * manipulations on the container. We will do that for both
1323 * the source and the destination containers
1325 static void manipulate_container(TestQListContainer
*c
)
1327 TestQListElement
*prev
= NULL
, *iter
= QLIST_FIRST(&c
->list
);
1328 TestQListElement
*elem
;
1330 elem
= g_new(TestQListElement
, 1);
1332 QLIST_INSERT_AFTER(iter
, elem
, next
);
1334 elem
= g_new(TestQListElement
, 1);
1336 QLIST_INSERT_HEAD(&c
->list
, elem
, next
);
1340 iter
= QLIST_NEXT(iter
, next
);
1343 elem
= g_new(TestQListElement
, 1);
1345 QLIST_INSERT_BEFORE(prev
, elem
, next
);
1347 elem
= g_new(TestQListElement
, 1);
1349 QLIST_INSERT_AFTER(prev
, elem
, next
);
1351 QLIST_REMOVE(prev
, next
);
1355 static void test_save_qlist(void)
1357 TestQListContainer
*container
= alloc_container();
1359 save_vmstate(&vmstate_container
, container
);
1360 compare_vmstate(qlist_dump
, sizeof(qlist_dump
));
1361 free_container(container
);
1364 static void test_load_qlist(void)
1366 QEMUFile
*fsave
, *fload
;
1367 TestQListContainer
*orig_container
= alloc_container();
1368 TestQListContainer
*dest_container
= g_new0(TestQListContainer
, 1);
1371 QLIST_INIT(&dest_container
->list
);
1373 fsave
= open_test_file(true);
1374 qemu_put_buffer(fsave
, qlist_dump
, sizeof(qlist_dump
));
1375 g_assert(!qemu_file_get_error(fsave
));
1378 fload
= open_test_file(false);
1379 vmstate_load_state(fload
, &vmstate_container
, dest_container
, 1);
1380 eof
= qemu_get_byte(fload
);
1381 g_assert(!qemu_file_get_error(fload
));
1382 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
1383 manipulate_container(orig_container
);
1384 manipulate_container(dest_container
);
1385 compare_containers(orig_container
, dest_container
);
1386 free_container(orig_container
);
1387 free_container(dest_container
);
1391 typedef struct TmpTestStruct
{
1396 static int tmp_child_pre_save(void *opaque
)
1398 struct TmpTestStruct
*tts
= opaque
;
1400 tts
->diff
= tts
->parent
->b
- tts
->parent
->a
;
1405 static int tmp_child_post_load(void *opaque
, int version_id
)
1407 struct TmpTestStruct
*tts
= opaque
;
1409 tts
->parent
->b
= tts
->parent
->a
+ tts
->diff
;
1414 static const VMStateDescription vmstate_tmp_back_to_parent
= {
1415 .name
= "test/tmp_child_parent",
1416 .fields
= (const VMStateField
[]) {
1417 VMSTATE_UINT64(f
, TestStruct
),
1418 VMSTATE_END_OF_LIST()
1422 static const VMStateDescription vmstate_tmp_child
= {
1423 .name
= "test/tmp_child",
1424 .pre_save
= tmp_child_pre_save
,
1425 .post_load
= tmp_child_post_load
,
1426 .fields
= (const VMStateField
[]) {
1427 VMSTATE_INT64(diff
, TmpTestStruct
),
1428 VMSTATE_STRUCT_POINTER(parent
, TmpTestStruct
,
1429 vmstate_tmp_back_to_parent
, TestStruct
),
1430 VMSTATE_END_OF_LIST()
1434 static const VMStateDescription vmstate_with_tmp
= {
1435 .name
= "test/with_tmp",
1437 .fields
= (const VMStateField
[]) {
1438 VMSTATE_UINT32(a
, TestStruct
),
1439 VMSTATE_UINT64(d
, TestStruct
),
1440 VMSTATE_WITH_TMP(TestStruct
, TmpTestStruct
, vmstate_tmp_child
),
1441 VMSTATE_END_OF_LIST()
1445 static void obj_tmp_copy(void *target
, void *source
)
1447 memcpy(target
, source
, sizeof(TestStruct
));
1450 static void test_tmp_struct(void)
1452 TestStruct obj
, obj_clone
;
1454 uint8_t const wire_with_tmp
[] = {
1455 /* u32 a */ 0x00, 0x00, 0x00, 0x02,
1456 /* u64 d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1457 /* diff */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
1458 /* u64 f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
1459 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
1462 memset(&obj
, 0, sizeof(obj
));
1467 save_vmstate(&vmstate_with_tmp
, &obj
);
1469 compare_vmstate(wire_with_tmp
, sizeof(wire_with_tmp
));
1471 memset(&obj
, 0, sizeof(obj
));
1472 SUCCESS(load_vmstate(&vmstate_with_tmp
, &obj
, &obj_clone
,
1473 obj_tmp_copy
, 1, wire_with_tmp
,
1474 sizeof(wire_with_tmp
)));
1475 g_assert_cmpint(obj
.a
, ==, 2); /* From top level vmsd */
1476 g_assert_cmpint(obj
.b
, ==, 4); /* from the post_load */
1477 g_assert_cmpint(obj
.d
, ==, 1); /* From top level vmsd */
1478 g_assert_cmpint(obj
.f
, ==, 8); /* From the child->parent */
1481 int main(int argc
, char **argv
)
1483 g_autofree
char *temp_file
= g_strdup_printf("%s/vmst.test.XXXXXX",
1485 temp_fd
= mkstemp(temp_file
);
1486 g_assert(temp_fd
>= 0);
1488 module_call_init(MODULE_INIT_QOM
);
1490 g_setenv("QTEST_SILENT_ERRORS", "1", 1);
1492 g_test_init(&argc
, &argv
, NULL
);
1493 g_test_add_func("/vmstate/simple/primitive", test_simple_primitive
);
1494 g_test_add_func("/vmstate/simple/array", test_simple_array
);
1495 g_test_add_func("/vmstate/versioned/load/v1", test_load_v1
);
1496 g_test_add_func("/vmstate/versioned/load/v2", test_load_v2
);
1497 g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip
);
1498 g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip
);
1499 g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip
);
1500 g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip
);
1501 g_test_add_func("/vmstate/array/ptr/str/no0/save",
1502 test_arr_ptr_str_no0_save
);
1503 g_test_add_func("/vmstate/array/ptr/str/no0/load",
1504 test_arr_ptr_str_no0_load
);
1505 g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save
);
1506 g_test_add_func("/vmstate/array/ptr/str/0/load",
1507 test_arr_ptr_str_0_load
);
1508 g_test_add_func("/vmstate/array/ptr/prim/0/save",
1509 test_arr_ptr_prim_0_save
);
1510 g_test_add_func("/vmstate/array/ptr/prim/0/load",
1511 test_arr_ptr_prim_0_load
);
1512 g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q
);
1513 g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q
);
1514 g_test_add_func("/vmstate/gtree/save/savedomain", test_gtree_save_domain
);
1515 g_test_add_func("/vmstate/gtree/load/loaddomain", test_gtree_load_domain
);
1516 g_test_add_func("/vmstate/gtree/save/saveiommu", test_gtree_save_iommu
);
1517 g_test_add_func("/vmstate/gtree/load/loadiommu", test_gtree_load_iommu
);
1518 g_test_add_func("/vmstate/qlist/save/saveqlist", test_save_qlist
);
1519 g_test_add_func("/vmstate/qlist/load/loadqlist", test_load_qlist
);
1520 g_test_add_func("/vmstate/tmp_struct", test_tmp_struct
);