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/savevm.h"
32 #include "qemu/module.h"
33 #include "io/channel-file.h"
38 /* Duplicate temp_fd and seek to the beginning of the file */
39 static QEMUFile
*open_test_file(bool write
)
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_file_new_output(ioc
);
55 f
= qemu_file_new_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);
89 g_autofree
uint8_t *result
= g_malloc(size
);
91 /* read back as binary */
93 g_assert_cmpint(qemu_get_buffer(f
, result
, size
), ==, size
);
94 g_assert(!qemu_file_get_error(f
));
96 /* Compare that what is on the file is the same that what we
97 expected to be there */
98 SUCCESS(memcmp(result
, wire
, size
));
102 g_assert_cmpint(qemu_file_get_error(f
), ==, -EIO
);
107 static int load_vmstate_one(const VMStateDescription
*desc
, void *obj
,
108 int version
, const uint8_t *wire
, size_t size
)
113 f
= open_test_file(true);
114 qemu_put_buffer(f
, wire
, size
);
117 f
= open_test_file(false);
118 ret
= vmstate_load_state(f
, desc
, obj
, version
);
120 g_assert(qemu_file_get_error(f
));
122 g_assert(!qemu_file_get_error(f
));
129 static int load_vmstate(const VMStateDescription
*desc
,
130 void *obj
, void *obj_clone
,
131 void (*obj_copy
)(void *, void*),
132 int version
, const uint8_t *wire
, size_t size
)
134 /* We test with zero size */
135 obj_copy(obj_clone
, obj
);
136 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, 0));
138 /* Stream ends with QEMU_EOF, so we need at least 3 bytes to be
139 * able to test in the middle */
143 /* We test with size - 2. We can't test size - 1 due to EOF tricks */
144 obj_copy(obj
, obj_clone
);
145 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, size
- 2));
147 /* Test with size/2, first half of real state */
148 obj_copy(obj
, obj_clone
);
149 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, size
/2));
151 /* Test with size/2, second half of real state */
152 obj_copy(obj
, obj_clone
);
153 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
+ (size
/2), size
/2));
156 obj_copy(obj
, obj_clone
);
157 return load_vmstate_one(desc
, obj
, version
, wire
, size
);
160 /* Test struct that we are going to use for our tests */
162 typedef struct TestSimple
{
169 int16_t i16_1
, i16_2
;
170 int32_t i32_1
, i32_2
;
171 int64_t i64_1
, i64_2
;
174 /* Object instantiation, we are going to use it in more than one test */
176 TestSimple obj_simple
= {
193 /* Description of the values. If you add a primitive type
194 you are expected to add a test here */
196 static const VMStateDescription vmstate_simple_primitive
= {
197 .name
= "simple/primitive",
199 .minimum_version_id
= 1,
200 .fields
= (VMStateField
[]) {
201 VMSTATE_BOOL(b_1
, TestSimple
),
202 VMSTATE_BOOL(b_2
, TestSimple
),
203 VMSTATE_UINT8(u8_1
, TestSimple
),
204 VMSTATE_UINT16(u16_1
, TestSimple
),
205 VMSTATE_UINT32(u32_1
, TestSimple
),
206 VMSTATE_UINT64(u64_1
, TestSimple
),
207 VMSTATE_INT8(i8_1
, TestSimple
),
208 VMSTATE_INT8(i8_2
, TestSimple
),
209 VMSTATE_INT16(i16_1
, TestSimple
),
210 VMSTATE_INT16(i16_2
, TestSimple
),
211 VMSTATE_INT32(i32_1
, TestSimple
),
212 VMSTATE_INT32(i32_2
, TestSimple
),
213 VMSTATE_INT64(i64_1
, TestSimple
),
214 VMSTATE_INT64(i64_2
, TestSimple
),
215 VMSTATE_END_OF_LIST()
219 /* It describes what goes through the wire. Our tests are basically:
222 - save a struct a vmstate to a file
223 - read that file back (binary read, no vmstate)
224 - compare it with what we expect to be on the wire
226 - save to the file what we expect to be on the wire
227 - read struct back with vmstate in a different
228 - compare back with the original struct
231 uint8_t wire_simple_primitive
[] = {
235 /* u16_1 */ 0x02, 0x00,
236 /* u32_1 */ 0x00, 0x01, 0x11, 0x70,
237 /* u64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
240 /* i16_1 */ 0x02, 0x00,
241 /* i16_2 */ 0xfe, 0x0,
242 /* i32_1 */ 0x00, 0x01, 0x11, 0x70,
243 /* i32_2 */ 0xff, 0xfe, 0xee, 0x90,
244 /* i64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
245 /* i64_2 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x0b, 0x84,
246 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
249 static void obj_simple_copy(void *target
, void *source
)
251 memcpy(target
, source
, sizeof(TestSimple
));
254 static void test_simple_primitive(void)
256 TestSimple obj
, obj_clone
;
258 memset(&obj
, 0, sizeof(obj
));
259 save_vmstate(&vmstate_simple_primitive
, &obj_simple
);
261 compare_vmstate(wire_simple_primitive
, sizeof(wire_simple_primitive
));
263 SUCCESS(load_vmstate(&vmstate_simple_primitive
, &obj
, &obj_clone
,
264 obj_simple_copy
, 1, wire_simple_primitive
,
265 sizeof(wire_simple_primitive
)));
267 #define FIELD_EQUAL(name) g_assert_cmpint(obj.name, ==, obj_simple.name)
285 typedef struct TestSimpleArray
{
289 /* Object instantiation, we are going to use it in more than one test */
291 TestSimpleArray obj_simple_arr
= {
292 .u16_1
= { 0x42, 0x43, 0x44 },
295 /* Description of the values. If you add a primitive type
296 you are expected to add a test here */
298 static const VMStateDescription vmstate_simple_arr
= {
299 .name
= "simple/array",
301 .minimum_version_id
= 1,
302 .fields
= (VMStateField
[]) {
303 VMSTATE_UINT16_ARRAY(u16_1
, TestSimpleArray
, 3),
304 VMSTATE_END_OF_LIST()
308 uint8_t wire_simple_arr
[] = {
309 /* u16_1 */ 0x00, 0x42,
310 /* u16_1 */ 0x00, 0x43,
311 /* u16_1 */ 0x00, 0x44,
312 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
315 static void obj_simple_arr_copy(void *target
, void *source
)
317 memcpy(target
, source
, sizeof(TestSimpleArray
));
320 static void test_simple_array(void)
322 TestSimpleArray obj
, obj_clone
;
324 memset(&obj
, 0, sizeof(obj
));
325 save_vmstate(&vmstate_simple_arr
, &obj_simple_arr
);
327 compare_vmstate(wire_simple_arr
, sizeof(wire_simple_arr
));
329 SUCCESS(load_vmstate(&vmstate_simple_arr
, &obj
, &obj_clone
,
330 obj_simple_arr_copy
, 1, wire_simple_arr
,
331 sizeof(wire_simple_arr
)));
334 typedef struct TestStruct
{
340 static const VMStateDescription vmstate_versioned
= {
341 .name
= "test/versioned",
343 .minimum_version_id
= 1,
344 .fields
= (VMStateField
[]) {
345 VMSTATE_UINT32(a
, TestStruct
),
346 VMSTATE_UINT32_V(b
, TestStruct
, 2), /* Versioned field in the middle, so
347 * we catch bugs more easily.
349 VMSTATE_UINT32(c
, TestStruct
),
350 VMSTATE_UINT64(d
, TestStruct
),
351 VMSTATE_UINT32_V(e
, TestStruct
, 2),
352 VMSTATE_UINT64_V(f
, TestStruct
, 2),
353 VMSTATE_END_OF_LIST()
357 static void test_load_v1(void)
362 0, 0, 0, 0, 0, 0, 0, 40, /* d */
363 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
365 save_buffer(buf
, sizeof(buf
));
367 QEMUFile
*loading
= open_test_file(false);
368 TestStruct obj
= { .b
= 200, .e
= 500, .f
= 600 };
369 vmstate_load_state(loading
, &vmstate_versioned
, &obj
, 1);
370 g_assert(!qemu_file_get_error(loading
));
371 g_assert_cmpint(obj
.a
, ==, 10);
372 g_assert_cmpint(obj
.b
, ==, 200);
373 g_assert_cmpint(obj
.c
, ==, 30);
374 g_assert_cmpint(obj
.d
, ==, 40);
375 g_assert_cmpint(obj
.e
, ==, 500);
376 g_assert_cmpint(obj
.f
, ==, 600);
377 qemu_fclose(loading
);
380 static void test_load_v2(void)
386 0, 0, 0, 0, 0, 0, 0, 40, /* d */
388 0, 0, 0, 0, 0, 0, 0, 60, /* f */
389 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
391 save_buffer(buf
, sizeof(buf
));
393 QEMUFile
*loading
= open_test_file(false);
395 vmstate_load_state(loading
, &vmstate_versioned
, &obj
, 2);
396 g_assert_cmpint(obj
.a
, ==, 10);
397 g_assert_cmpint(obj
.b
, ==, 20);
398 g_assert_cmpint(obj
.c
, ==, 30);
399 g_assert_cmpint(obj
.d
, ==, 40);
400 g_assert_cmpint(obj
.e
, ==, 50);
401 g_assert_cmpint(obj
.f
, ==, 60);
402 qemu_fclose(loading
);
405 static bool test_skip(void *opaque
, int version_id
)
407 TestStruct
*t
= (TestStruct
*)opaque
;
411 static const VMStateDescription vmstate_skipping
= {
414 .minimum_version_id
= 1,
415 .fields
= (VMStateField
[]) {
416 VMSTATE_UINT32(a
, TestStruct
),
417 VMSTATE_UINT32(b
, TestStruct
),
418 VMSTATE_UINT32_TEST(c
, TestStruct
, test_skip
),
419 VMSTATE_UINT64(d
, TestStruct
),
420 VMSTATE_UINT32_TEST(e
, TestStruct
, test_skip
),
421 VMSTATE_UINT64_V(f
, TestStruct
, 2),
422 VMSTATE_END_OF_LIST()
427 static void test_save_noskip(void)
429 QEMUFile
*fsave
= open_test_file(true);
430 TestStruct obj
= { .a
= 1, .b
= 2, .c
= 3, .d
= 4, .e
= 5, .f
= 6,
432 int ret
= vmstate_save_state(fsave
, &vmstate_skipping
, &obj
, NULL
);
434 g_assert(!qemu_file_get_error(fsave
));
436 uint8_t expected
[] = {
440 0, 0, 0, 0, 0, 0, 0, 4, /* d */
442 0, 0, 0, 0, 0, 0, 0, 6, /* f */
446 compare_vmstate(expected
, sizeof(expected
));
449 static void test_save_skip(void)
451 QEMUFile
*fsave
= open_test_file(true);
452 TestStruct obj
= { .a
= 1, .b
= 2, .c
= 3, .d
= 4, .e
= 5, .f
= 6,
454 int ret
= vmstate_save_state(fsave
, &vmstate_skipping
, &obj
, NULL
);
456 g_assert(!qemu_file_get_error(fsave
));
458 uint8_t expected
[] = {
461 0, 0, 0, 0, 0, 0, 0, 4, /* d */
462 0, 0, 0, 0, 0, 0, 0, 6, /* f */
466 compare_vmstate(expected
, sizeof(expected
));
469 static void test_load_noskip(void)
475 0, 0, 0, 0, 0, 0, 0, 40, /* d */
477 0, 0, 0, 0, 0, 0, 0, 60, /* f */
478 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
480 save_buffer(buf
, sizeof(buf
));
482 QEMUFile
*loading
= open_test_file(false);
483 TestStruct obj
= { .skip_c_e
= false };
484 vmstate_load_state(loading
, &vmstate_skipping
, &obj
, 2);
485 g_assert(!qemu_file_get_error(loading
));
486 g_assert_cmpint(obj
.a
, ==, 10);
487 g_assert_cmpint(obj
.b
, ==, 20);
488 g_assert_cmpint(obj
.c
, ==, 30);
489 g_assert_cmpint(obj
.d
, ==, 40);
490 g_assert_cmpint(obj
.e
, ==, 50);
491 g_assert_cmpint(obj
.f
, ==, 60);
492 qemu_fclose(loading
);
495 static void test_load_skip(void)
500 0, 0, 0, 0, 0, 0, 0, 40, /* d */
501 0, 0, 0, 0, 0, 0, 0, 60, /* f */
502 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
504 save_buffer(buf
, sizeof(buf
));
506 QEMUFile
*loading
= open_test_file(false);
507 TestStruct obj
= { .skip_c_e
= true, .c
= 300, .e
= 500 };
508 vmstate_load_state(loading
, &vmstate_skipping
, &obj
, 2);
509 g_assert(!qemu_file_get_error(loading
));
510 g_assert_cmpint(obj
.a
, ==, 10);
511 g_assert_cmpint(obj
.b
, ==, 20);
512 g_assert_cmpint(obj
.c
, ==, 300);
513 g_assert_cmpint(obj
.d
, ==, 40);
514 g_assert_cmpint(obj
.e
, ==, 500);
515 g_assert_cmpint(obj
.f
, ==, 60);
516 qemu_fclose(loading
);
523 const VMStateDescription vmsd_tst
= {
526 .minimum_version_id
= 1,
527 .fields
= (VMStateField
[]) {
528 VMSTATE_INT32(i
, TestStructTriv
),
529 VMSTATE_END_OF_LIST()
533 /* test array migration */
538 TestStructTriv
*ar
[AR_SIZE
];
539 } TestArrayOfPtrToStuct
;
541 const VMStateDescription vmsd_arps
= {
544 .minimum_version_id
= 1,
545 .fields
= (VMStateField
[]) {
546 VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(ar
, TestArrayOfPtrToStuct
,
547 AR_SIZE
, 0, vmsd_tst
, TestStructTriv
),
548 VMSTATE_END_OF_LIST()
552 static uint8_t wire_arr_ptr_no0
[] = {
553 0x00, 0x00, 0x00, 0x00,
554 0x00, 0x00, 0x00, 0x01,
555 0x00, 0x00, 0x00, 0x02,
556 0x00, 0x00, 0x00, 0x03,
560 static void test_arr_ptr_str_no0_save(void)
562 TestStructTriv ar
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
563 TestArrayOfPtrToStuct sample
= {.ar
= {&ar
[0], &ar
[1], &ar
[2], &ar
[3]} };
565 save_vmstate(&vmsd_arps
, &sample
);
566 compare_vmstate(wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
));
569 static void test_arr_ptr_str_no0_load(void)
571 TestStructTriv ar_gt
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
572 TestStructTriv ar
[AR_SIZE
] = {};
573 TestArrayOfPtrToStuct obj
= {.ar
= {&ar
[0], &ar
[1], &ar
[2], &ar
[3]} };
576 save_buffer(wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
));
577 SUCCESS(load_vmstate_one(&vmsd_arps
, &obj
, 1,
578 wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
)));
579 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
580 /* compare the target array ar with the ground truth array ar_gt */
581 g_assert_cmpint(ar_gt
[idx
].i
, ==, ar
[idx
].i
);
585 static uint8_t wire_arr_ptr_0
[] = {
586 0x00, 0x00, 0x00, 0x00,
588 0x00, 0x00, 0x00, 0x02,
589 0x00, 0x00, 0x00, 0x03,
593 static void test_arr_ptr_str_0_save(void)
595 TestStructTriv ar
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
596 TestArrayOfPtrToStuct sample
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
598 save_vmstate(&vmsd_arps
, &sample
);
599 compare_vmstate(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
602 static void test_arr_ptr_str_0_load(void)
604 TestStructTriv ar_gt
[AR_SIZE
] = {{.i
= 0}, {.i
= 0}, {.i
= 2}, {.i
= 3} };
605 TestStructTriv ar
[AR_SIZE
] = {};
606 TestArrayOfPtrToStuct obj
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
609 save_buffer(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
610 SUCCESS(load_vmstate_one(&vmsd_arps
, &obj
, 1,
611 wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
)));
612 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
613 /* compare the target array ar with the ground truth array ar_gt */
614 g_assert_cmpint(ar_gt
[idx
].i
, ==, ar
[idx
].i
);
616 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
618 g_assert_cmpint((uintptr_t)(obj
.ar
[idx
]), ==, 0);
620 g_assert_cmpint((uintptr_t)(obj
.ar
[idx
]), !=, 0);
625 typedef struct TestArrayOfPtrToInt
{
626 int32_t *ar
[AR_SIZE
];
627 } TestArrayOfPtrToInt
;
629 const VMStateDescription vmsd_arpp
= {
632 .minimum_version_id
= 1,
633 .fields
= (VMStateField
[]) {
634 VMSTATE_ARRAY_OF_POINTER(ar
, TestArrayOfPtrToInt
,
635 AR_SIZE
, 0, vmstate_info_int32
, int32_t*),
636 VMSTATE_END_OF_LIST()
640 static void test_arr_ptr_prim_0_save(void)
642 int32_t ar
[AR_SIZE
] = {0 , 1, 2, 3};
643 TestArrayOfPtrToInt sample
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
645 save_vmstate(&vmsd_arpp
, &sample
);
646 compare_vmstate(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
649 static void test_arr_ptr_prim_0_load(void)
651 int32_t ar_gt
[AR_SIZE
] = {0, 1, 2, 3};
652 int32_t ar
[AR_SIZE
] = {3 , 42, 1, 0};
653 TestArrayOfPtrToInt obj
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
656 save_buffer(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
657 SUCCESS(load_vmstate_one(&vmsd_arpp
, &obj
, 1,
658 wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
)));
659 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
660 /* compare the target array ar with the ground truth array ar_gt */
662 g_assert_cmpint(42, ==, ar
[idx
]);
664 g_assert_cmpint(ar_gt
[idx
], ==, ar
[idx
]);
669 /* test QTAILQ migration */
670 typedef struct TestQtailqElement TestQtailqElement
;
672 struct TestQtailqElement
{
675 QTAILQ_ENTRY(TestQtailqElement
) next
;
678 typedef struct TestQtailq
{
680 QTAILQ_HEAD(, TestQtailqElement
) q
;
684 static const VMStateDescription vmstate_q_element
= {
685 .name
= "test/queue-element",
687 .minimum_version_id
= 1,
688 .fields
= (VMStateField
[]) {
689 VMSTATE_BOOL(b
, TestQtailqElement
),
690 VMSTATE_UINT8(u8
, TestQtailqElement
),
691 VMSTATE_END_OF_LIST()
695 static const VMStateDescription vmstate_q
= {
696 .name
= "test/queue",
698 .minimum_version_id
= 1,
699 .fields
= (VMStateField
[]) {
700 VMSTATE_INT16(i16
, TestQtailq
),
701 VMSTATE_QTAILQ_V(q
, TestQtailq
, 1, vmstate_q_element
, TestQtailqElement
,
703 VMSTATE_INT32(i32
, TestQtailq
),
704 VMSTATE_END_OF_LIST()
710 /* start of element 0 of q */ 0x01,
713 /* start of element 1 of q */ 0x01,
717 /* i32 */ 0x00, 0x01, 0x11, 0x70,
718 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
721 static void test_save_q(void)
728 TestQtailqElement obj_qe1
= {
733 TestQtailqElement obj_qe2
= {
738 QTAILQ_INIT(&obj_q
.q
);
739 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe1
, next
);
740 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe2
, next
);
742 save_vmstate(&vmstate_q
, &obj_q
);
743 compare_vmstate(wire_q
, sizeof(wire_q
));
746 static void test_load_q(void)
753 TestQtailqElement obj_qe1
= {
758 TestQtailqElement obj_qe2
= {
763 QTAILQ_INIT(&obj_q
.q
);
764 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe1
, next
);
765 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe2
, next
);
767 QEMUFile
*fsave
= open_test_file(true);
769 qemu_put_buffer(fsave
, wire_q
, sizeof(wire_q
));
770 g_assert(!qemu_file_get_error(fsave
));
773 QEMUFile
*fload
= open_test_file(false);
777 vmstate_load_state(fload
, &vmstate_q
, &tgt
, 1);
778 char eof
= qemu_get_byte(fload
);
779 g_assert(!qemu_file_get_error(fload
));
780 g_assert_cmpint(tgt
.i16
, ==, obj_q
.i16
);
781 g_assert_cmpint(tgt
.i32
, ==, obj_q
.i32
);
782 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
784 TestQtailqElement
*qele_from
= QTAILQ_FIRST(&obj_q
.q
);
785 TestQtailqElement
*qlast_from
= QTAILQ_LAST(&obj_q
.q
);
786 TestQtailqElement
*qele_to
= QTAILQ_FIRST(&tgt
.q
);
787 TestQtailqElement
*qlast_to
= QTAILQ_LAST(&tgt
.q
);
790 g_assert_cmpint(qele_to
->b
, ==, qele_from
->b
);
791 g_assert_cmpint(qele_to
->u8
, ==, qele_from
->u8
);
792 if ((qele_from
== qlast_from
) || (qele_to
== qlast_to
)) {
795 qele_from
= QTAILQ_NEXT(qele_from
, next
);
796 qele_to
= QTAILQ_NEXT(qele_to
, next
);
799 g_assert_cmpint((uintptr_t) qele_from
, ==, (uintptr_t) qlast_from
);
800 g_assert_cmpint((uintptr_t) qele_to
, ==, (uintptr_t) qlast_to
);
803 TestQtailqElement
*qele
;
804 while (!QTAILQ_EMPTY(&tgt
.q
)) {
805 qele
= QTAILQ_LAST(&tgt
.q
);
806 QTAILQ_REMOVE(&tgt
.q
, qele
, next
);
814 typedef struct TestGTreeInterval
{
819 #define VMSTATE_INTERVAL \
821 .name = "interval", \
823 .minimum_version_id = 1, \
824 .fields = (VMStateField[]) { \
825 VMSTATE_UINT64(low, TestGTreeInterval), \
826 VMSTATE_UINT64(high, TestGTreeInterval), \
827 VMSTATE_END_OF_LIST() \
831 /* mapping (value) */
832 typedef struct TestGTreeMapping
{
837 #define VMSTATE_MAPPING \
841 .minimum_version_id = 1, \
842 .fields = (VMStateField[]) { \
843 VMSTATE_UINT64(phys_addr, TestGTreeMapping), \
844 VMSTATE_UINT32(flags, TestGTreeMapping), \
845 VMSTATE_END_OF_LIST() \
849 static const VMStateDescription vmstate_interval_mapping
[2] = {
850 VMSTATE_MAPPING
, /* value */
851 VMSTATE_INTERVAL
/* key */
854 typedef struct TestGTreeDomain
{
859 typedef struct TestGTreeIOMMU
{
864 /* Interval comparison function */
865 static gint
interval_cmp(gconstpointer a
, gconstpointer b
, gpointer user_data
)
867 TestGTreeInterval
*inta
= (TestGTreeInterval
*)a
;
868 TestGTreeInterval
*intb
= (TestGTreeInterval
*)b
;
870 if (inta
->high
< intb
->low
) {
872 } else if (intb
->high
< inta
->low
) {
879 /* ID comparison function */
880 static gint
int_cmp(gconstpointer a
, gconstpointer b
, gpointer user_data
)
882 guint ua
= GPOINTER_TO_UINT(a
);
883 guint ub
= GPOINTER_TO_UINT(b
);
884 return (ua
> ub
) - (ua
< ub
);
887 static void destroy_domain(gpointer data
)
889 TestGTreeDomain
*domain
= (TestGTreeDomain
*)data
;
891 g_tree_destroy(domain
->mappings
);
895 static int domain_preload(void *opaque
)
897 TestGTreeDomain
*domain
= opaque
;
899 domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
,
900 NULL
, g_free
, g_free
);
904 static int iommu_preload(void *opaque
)
906 TestGTreeIOMMU
*iommu
= opaque
;
908 iommu
->domains
= g_tree_new_full((GCompareDataFunc
)int_cmp
,
909 NULL
, NULL
, destroy_domain
);
913 static const VMStateDescription vmstate_domain
= {
916 .minimum_version_id
= 1,
917 .pre_load
= domain_preload
,
918 .fields
= (VMStateField
[]) {
919 VMSTATE_INT32(id
, TestGTreeDomain
),
920 VMSTATE_GTREE_V(mappings
, TestGTreeDomain
, 1,
921 vmstate_interval_mapping
,
922 TestGTreeInterval
, TestGTreeMapping
),
923 VMSTATE_END_OF_LIST()
927 /* test QLIST Migration */
929 typedef struct TestQListElement
{
931 QLIST_ENTRY(TestQListElement
) next
;
934 typedef struct TestQListContainer
{
936 QLIST_HEAD(, TestQListElement
) list
;
937 } TestQListContainer
;
939 static const VMStateDescription vmstate_qlist_element
= {
940 .name
= "test/queue list",
942 .minimum_version_id
= 1,
943 .fields
= (VMStateField
[]) {
944 VMSTATE_UINT32(id
, TestQListElement
),
945 VMSTATE_END_OF_LIST()
949 static const VMStateDescription vmstate_iommu
= {
952 .minimum_version_id
= 1,
953 .pre_load
= iommu_preload
,
954 .fields
= (VMStateField
[]) {
955 VMSTATE_INT32(id
, TestGTreeIOMMU
),
956 VMSTATE_GTREE_DIRECT_KEY_V(domains
, TestGTreeIOMMU
, 1,
957 &vmstate_domain
, TestGTreeDomain
),
958 VMSTATE_END_OF_LIST()
962 static const VMStateDescription vmstate_container
= {
963 .name
= "test/container/qlist",
965 .minimum_version_id
= 1,
966 .fields
= (VMStateField
[]) {
967 VMSTATE_UINT32(id
, TestQListContainer
),
968 VMSTATE_QLIST_V(list
, TestQListContainer
, 1, vmstate_qlist_element
,
969 TestQListElement
, next
),
970 VMSTATE_END_OF_LIST()
974 uint8_t first_domain_dump
[] = {
977 0x00, 0x0, 0x0, 0x2, /* 2 mappings */
978 0x1, /* start of a */
980 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
981 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
983 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00,
984 0x00, 0x00, 0x00, 0x01,
985 0x1, /* start of b */
987 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
988 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF,
990 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
991 0x00, 0x00, 0x00, 0x02,
992 0x0, /* end of gtree */
993 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
996 static TestGTreeDomain
*create_first_domain(void)
998 TestGTreeDomain
*domain
;
999 TestGTreeMapping
*map_a
, *map_b
;
1000 TestGTreeInterval
*a
, *b
;
1002 domain
= g_new0(TestGTreeDomain
, 1);
1005 a
= g_new0(TestGTreeInterval
, 1);
1009 b
= g_new0(TestGTreeInterval
, 1);
1013 map_a
= g_new0(TestGTreeMapping
, 1);
1014 map_a
->phys_addr
= 0xa000;
1017 map_b
= g_new0(TestGTreeMapping
, 1);
1018 map_b
->phys_addr
= 0xe0000;
1021 domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
, NULL
,
1022 (GDestroyNotify
)g_free
,
1023 (GDestroyNotify
)g_free
);
1024 g_tree_insert(domain
->mappings
, a
, map_a
);
1025 g_tree_insert(domain
->mappings
, b
, map_b
);
1029 static void test_gtree_save_domain(void)
1031 TestGTreeDomain
*first_domain
= create_first_domain();
1033 save_vmstate(&vmstate_domain
, first_domain
);
1034 compare_vmstate(first_domain_dump
, sizeof(first_domain_dump
));
1035 destroy_domain(first_domain
);
1038 struct match_node_data
{
1044 struct tree_cmp_data
{
1047 GTraverseFunc match_node
;
1050 static gboolean
match_interval_mapping_node(gpointer key
,
1051 gpointer value
, gpointer data
)
1053 TestGTreeMapping
*map_a
, *map_b
;
1054 TestGTreeInterval
*a
, *b
;
1055 struct match_node_data
*d
= (struct match_node_data
*)data
;
1056 a
= (TestGTreeInterval
*)key
;
1057 b
= (TestGTreeInterval
*)d
->key
;
1059 map_a
= (TestGTreeMapping
*)value
;
1060 map_b
= (TestGTreeMapping
*)d
->value
;
1062 assert(a
->low
== b
->low
);
1063 assert(a
->high
== b
->high
);
1064 assert(map_a
->phys_addr
== map_b
->phys_addr
);
1065 assert(map_a
->flags
== map_b
->flags
);
1066 g_tree_remove(d
->tree
, key
);
1070 static gboolean
diff_tree(gpointer key
, gpointer value
, gpointer data
)
1072 struct tree_cmp_data
*tp
= (struct tree_cmp_data
*)data
;
1073 struct match_node_data d
= {tp
->tree2
, key
, value
};
1075 g_tree_foreach(tp
->tree2
, tp
->match_node
, &d
);
1079 static void compare_trees(GTree
*tree1
, GTree
*tree2
,
1080 GTraverseFunc function
)
1082 struct tree_cmp_data tp
= {tree1
, tree2
, function
};
1084 assert(g_tree_nnodes(tree1
) == g_tree_nnodes(tree2
));
1085 g_tree_foreach(tree1
, diff_tree
, &tp
);
1086 g_tree_destroy(g_tree_ref(tree1
));
1089 static void diff_domain(TestGTreeDomain
*d1
, TestGTreeDomain
*d2
)
1091 assert(d1
->id
== d2
->id
);
1092 compare_trees(d1
->mappings
, d2
->mappings
, match_interval_mapping_node
);
1095 static gboolean
match_domain_node(gpointer key
, gpointer value
, gpointer data
)
1098 TestGTreeDomain
*d1
, *d2
;
1099 struct match_node_data
*d
= (struct match_node_data
*)data
;
1101 id1
= (uint64_t)(uintptr_t)key
;
1102 id2
= (uint64_t)(uintptr_t)d
->key
;
1103 d1
= (TestGTreeDomain
*)value
;
1104 d2
= (TestGTreeDomain
*)d
->value
;
1106 diff_domain(d1
, d2
);
1107 g_tree_remove(d
->tree
, key
);
1111 static void diff_iommu(TestGTreeIOMMU
*iommu1
, TestGTreeIOMMU
*iommu2
)
1113 assert(iommu1
->id
== iommu2
->id
);
1114 compare_trees(iommu1
->domains
, iommu2
->domains
, match_domain_node
);
1117 static void test_gtree_load_domain(void)
1119 TestGTreeDomain
*dest_domain
= g_new0(TestGTreeDomain
, 1);
1120 TestGTreeDomain
*orig_domain
= create_first_domain();
1121 QEMUFile
*fload
, *fsave
;
1124 fsave
= open_test_file(true);
1125 qemu_put_buffer(fsave
, first_domain_dump
, sizeof(first_domain_dump
));
1126 g_assert(!qemu_file_get_error(fsave
));
1129 fload
= open_test_file(false);
1131 vmstate_load_state(fload
, &vmstate_domain
, dest_domain
, 1);
1132 eof
= qemu_get_byte(fload
);
1133 g_assert(!qemu_file_get_error(fload
));
1134 g_assert_cmpint(orig_domain
->id
, ==, dest_domain
->id
);
1135 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
1137 diff_domain(orig_domain
, dest_domain
);
1138 destroy_domain(orig_domain
);
1139 destroy_domain(dest_domain
);
1143 uint8_t iommu_dump
[] = {
1145 0x00, 0x0, 0x0, 0x7,
1146 0x00, 0x0, 0x0, 0x2, /* 2 domains */
1147 0x1,/* start of domain 5 */
1148 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x5, /* key = 5 */
1149 0x00, 0x0, 0x0, 0x5, /* domain1 id */
1150 0x00, 0x0, 0x0, 0x1, /* 1 mapping */
1151 0x1, /* start of mappings */
1153 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1154 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF,
1156 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
1157 0x00, 0x0, 0x0, 0x3,
1158 0x0, /* end of domain1 mappings*/
1159 0x1,/* start of domain 6 */
1160 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x6, /* key = 6 */
1161 0x00, 0x0, 0x0, 0x6, /* domain6 id */
1162 0x00, 0x0, 0x0, 0x2, /* 2 mappings */
1163 0x1, /* start of a */
1165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
1168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00,
1169 0x00, 0x00, 0x00, 0x01,
1170 0x1, /* start of b */
1172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
1173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF,
1175 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
1176 0x00, 0x00, 0x00, 0x02,
1177 0x0, /* end of domain6 mappings*/
1178 0x0, /* end of domains */
1179 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
1182 static TestGTreeIOMMU
*create_iommu(void)
1184 TestGTreeIOMMU
*iommu
= g_new0(TestGTreeIOMMU
, 1);
1185 TestGTreeDomain
*first_domain
= create_first_domain();
1186 TestGTreeDomain
*second_domain
;
1187 TestGTreeMapping
*map_c
;
1188 TestGTreeInterval
*c
;
1191 iommu
->domains
= g_tree_new_full((GCompareDataFunc
)int_cmp
, NULL
,
1195 second_domain
= g_new0(TestGTreeDomain
, 1);
1196 second_domain
->id
= 5;
1197 second_domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
,
1199 (GDestroyNotify
)g_free
,
1200 (GDestroyNotify
)g_free
);
1202 g_tree_insert(iommu
->domains
, GUINT_TO_POINTER(6), first_domain
);
1203 g_tree_insert(iommu
->domains
, (gpointer
)0x0000000000000005, second_domain
);
1205 c
= g_new0(TestGTreeInterval
, 1);
1207 c
->high
= 0x1FFFFFF;
1209 map_c
= g_new0(TestGTreeMapping
, 1);
1210 map_c
->phys_addr
= 0xF000000;
1213 g_tree_insert(second_domain
->mappings
, c
, map_c
);
1217 static void destroy_iommu(TestGTreeIOMMU
*iommu
)
1219 g_tree_destroy(iommu
->domains
);
1223 static void test_gtree_save_iommu(void)
1225 TestGTreeIOMMU
*iommu
= create_iommu();
1227 save_vmstate(&vmstate_iommu
, iommu
);
1228 compare_vmstate(iommu_dump
, sizeof(iommu_dump
));
1229 destroy_iommu(iommu
);
1232 static void test_gtree_load_iommu(void)
1234 TestGTreeIOMMU
*dest_iommu
= g_new0(TestGTreeIOMMU
, 1);
1235 TestGTreeIOMMU
*orig_iommu
= create_iommu();
1236 QEMUFile
*fsave
, *fload
;
1239 fsave
= open_test_file(true);
1240 qemu_put_buffer(fsave
, iommu_dump
, sizeof(iommu_dump
));
1241 g_assert(!qemu_file_get_error(fsave
));
1244 fload
= open_test_file(false);
1245 vmstate_load_state(fload
, &vmstate_iommu
, dest_iommu
, 1);
1246 eof
= qemu_get_byte(fload
);
1247 g_assert(!qemu_file_get_error(fload
));
1248 g_assert_cmpint(orig_iommu
->id
, ==, dest_iommu
->id
);
1249 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
1251 diff_iommu(orig_iommu
, dest_iommu
);
1252 destroy_iommu(orig_iommu
);
1253 destroy_iommu(dest_iommu
);
1257 static uint8_t qlist_dump
[] = {
1258 0x00, 0x00, 0x00, 0x01, /* container id */
1259 0x1, /* start of a */
1260 0x00, 0x00, 0x00, 0x0a,
1261 0x1, /* start of b */
1262 0x00, 0x00, 0x0b, 0x00,
1263 0x1, /* start of c */
1264 0x00, 0x0c, 0x00, 0x00,
1265 0x1, /* start of d */
1266 0x0d, 0x00, 0x00, 0x00,
1267 0x0, /* end of list */
1268 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
1271 static TestQListContainer
*alloc_container(void)
1273 TestQListElement
*a
= g_new(TestQListElement
, 1);
1274 TestQListElement
*b
= g_new(TestQListElement
, 1);
1275 TestQListElement
*c
= g_new(TestQListElement
, 1);
1276 TestQListElement
*d
= g_new(TestQListElement
, 1);
1277 TestQListContainer
*container
= g_new(TestQListContainer
, 1);
1285 QLIST_INIT(&container
->list
);
1286 QLIST_INSERT_HEAD(&container
->list
, d
, next
);
1287 QLIST_INSERT_HEAD(&container
->list
, c
, next
);
1288 QLIST_INSERT_HEAD(&container
->list
, b
, next
);
1289 QLIST_INSERT_HEAD(&container
->list
, a
, next
);
1293 static void free_container(TestQListContainer
*container
)
1295 TestQListElement
*iter
, *tmp
;
1297 QLIST_FOREACH_SAFE(iter
, &container
->list
, next
, tmp
) {
1298 QLIST_REMOVE(iter
, next
);
1304 static void compare_containers(TestQListContainer
*c1
, TestQListContainer
*c2
)
1306 TestQListElement
*first_item_c1
, *first_item_c2
;
1308 while (!QLIST_EMPTY(&c1
->list
)) {
1309 first_item_c1
= QLIST_FIRST(&c1
->list
);
1310 first_item_c2
= QLIST_FIRST(&c2
->list
);
1311 assert(first_item_c2
);
1312 assert(first_item_c1
->id
== first_item_c2
->id
);
1313 QLIST_REMOVE(first_item_c1
, next
);
1314 QLIST_REMOVE(first_item_c2
, next
);
1315 g_free(first_item_c1
);
1316 g_free(first_item_c2
);
1318 assert(QLIST_EMPTY(&c2
->list
));
1322 * Check the prev & next fields are correct by doing list
1323 * manipulations on the container. We will do that for both
1324 * the source and the destination containers
1326 static void manipulate_container(TestQListContainer
*c
)
1328 TestQListElement
*prev
= NULL
, *iter
= QLIST_FIRST(&c
->list
);
1329 TestQListElement
*elem
;
1331 elem
= g_new(TestQListElement
, 1);
1333 QLIST_INSERT_AFTER(iter
, elem
, next
);
1335 elem
= g_new(TestQListElement
, 1);
1337 QLIST_INSERT_HEAD(&c
->list
, elem
, next
);
1341 iter
= QLIST_NEXT(iter
, next
);
1344 elem
= g_new(TestQListElement
, 1);
1346 QLIST_INSERT_BEFORE(prev
, elem
, next
);
1348 elem
= g_new(TestQListElement
, 1);
1350 QLIST_INSERT_AFTER(prev
, elem
, next
);
1352 QLIST_REMOVE(prev
, next
);
1356 static void test_save_qlist(void)
1358 TestQListContainer
*container
= alloc_container();
1360 save_vmstate(&vmstate_container
, container
);
1361 compare_vmstate(qlist_dump
, sizeof(qlist_dump
));
1362 free_container(container
);
1365 static void test_load_qlist(void)
1367 QEMUFile
*fsave
, *fload
;
1368 TestQListContainer
*orig_container
= alloc_container();
1369 TestQListContainer
*dest_container
= g_new0(TestQListContainer
, 1);
1372 QLIST_INIT(&dest_container
->list
);
1374 fsave
= open_test_file(true);
1375 qemu_put_buffer(fsave
, qlist_dump
, sizeof(qlist_dump
));
1376 g_assert(!qemu_file_get_error(fsave
));
1379 fload
= open_test_file(false);
1380 vmstate_load_state(fload
, &vmstate_container
, dest_container
, 1);
1381 eof
= qemu_get_byte(fload
);
1382 g_assert(!qemu_file_get_error(fload
));
1383 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
1384 manipulate_container(orig_container
);
1385 manipulate_container(dest_container
);
1386 compare_containers(orig_container
, dest_container
);
1387 free_container(orig_container
);
1388 free_container(dest_container
);
1392 typedef struct TmpTestStruct
{
1397 static int tmp_child_pre_save(void *opaque
)
1399 struct TmpTestStruct
*tts
= opaque
;
1401 tts
->diff
= tts
->parent
->b
- tts
->parent
->a
;
1406 static int tmp_child_post_load(void *opaque
, int version_id
)
1408 struct TmpTestStruct
*tts
= opaque
;
1410 tts
->parent
->b
= tts
->parent
->a
+ tts
->diff
;
1415 static const VMStateDescription vmstate_tmp_back_to_parent
= {
1416 .name
= "test/tmp_child_parent",
1417 .fields
= (VMStateField
[]) {
1418 VMSTATE_UINT64(f
, TestStruct
),
1419 VMSTATE_END_OF_LIST()
1423 static const VMStateDescription vmstate_tmp_child
= {
1424 .name
= "test/tmp_child",
1425 .pre_save
= tmp_child_pre_save
,
1426 .post_load
= tmp_child_post_load
,
1427 .fields
= (VMStateField
[]) {
1428 VMSTATE_INT64(diff
, TmpTestStruct
),
1429 VMSTATE_STRUCT_POINTER(parent
, TmpTestStruct
,
1430 vmstate_tmp_back_to_parent
, TestStruct
),
1431 VMSTATE_END_OF_LIST()
1435 static const VMStateDescription vmstate_with_tmp
= {
1436 .name
= "test/with_tmp",
1438 .fields
= (VMStateField
[]) {
1439 VMSTATE_UINT32(a
, TestStruct
),
1440 VMSTATE_UINT64(d
, TestStruct
),
1441 VMSTATE_WITH_TMP(TestStruct
, TmpTestStruct
, vmstate_tmp_child
),
1442 VMSTATE_END_OF_LIST()
1446 static void obj_tmp_copy(void *target
, void *source
)
1448 memcpy(target
, source
, sizeof(TestStruct
));
1451 static void test_tmp_struct(void)
1453 TestStruct obj
, obj_clone
;
1455 uint8_t const wire_with_tmp
[] = {
1456 /* u32 a */ 0x00, 0x00, 0x00, 0x02,
1457 /* u64 d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1458 /* diff */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
1459 /* u64 f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
1460 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
1463 memset(&obj
, 0, sizeof(obj
));
1468 save_vmstate(&vmstate_with_tmp
, &obj
);
1470 compare_vmstate(wire_with_tmp
, sizeof(wire_with_tmp
));
1472 memset(&obj
, 0, sizeof(obj
));
1473 SUCCESS(load_vmstate(&vmstate_with_tmp
, &obj
, &obj_clone
,
1474 obj_tmp_copy
, 1, wire_with_tmp
,
1475 sizeof(wire_with_tmp
)));
1476 g_assert_cmpint(obj
.a
, ==, 2); /* From top level vmsd */
1477 g_assert_cmpint(obj
.b
, ==, 4); /* from the post_load */
1478 g_assert_cmpint(obj
.d
, ==, 1); /* From top level vmsd */
1479 g_assert_cmpint(obj
.f
, ==, 8); /* From the child->parent */
1482 int main(int argc
, char **argv
)
1484 g_autofree
char *temp_file
= g_strdup_printf("%s/vmst.test.XXXXXX",
1486 temp_fd
= mkstemp(temp_file
);
1487 g_assert(temp_fd
>= 0);
1489 module_call_init(MODULE_INIT_QOM
);
1491 g_setenv("QTEST_SILENT_ERRORS", "1", 1);
1493 g_test_init(&argc
, &argv
, NULL
);
1494 g_test_add_func("/vmstate/simple/primitive", test_simple_primitive
);
1495 g_test_add_func("/vmstate/simple/array", test_simple_array
);
1496 g_test_add_func("/vmstate/versioned/load/v1", test_load_v1
);
1497 g_test_add_func("/vmstate/versioned/load/v2", test_load_v2
);
1498 g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip
);
1499 g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip
);
1500 g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip
);
1501 g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip
);
1502 g_test_add_func("/vmstate/array/ptr/str/no0/save",
1503 test_arr_ptr_str_no0_save
);
1504 g_test_add_func("/vmstate/array/ptr/str/no0/load",
1505 test_arr_ptr_str_no0_load
);
1506 g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save
);
1507 g_test_add_func("/vmstate/array/ptr/str/0/load",
1508 test_arr_ptr_str_0_load
);
1509 g_test_add_func("/vmstate/array/ptr/prim/0/save",
1510 test_arr_ptr_prim_0_save
);
1511 g_test_add_func("/vmstate/array/ptr/prim/0/load",
1512 test_arr_ptr_prim_0_load
);
1513 g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q
);
1514 g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q
);
1515 g_test_add_func("/vmstate/gtree/save/savedomain", test_gtree_save_domain
);
1516 g_test_add_func("/vmstate/gtree/load/loaddomain", test_gtree_load_domain
);
1517 g_test_add_func("/vmstate/gtree/save/saveiommu", test_gtree_save_iommu
);
1518 g_test_add_func("/vmstate/gtree/load/loadiommu", test_gtree_load_iommu
);
1519 g_test_add_func("/vmstate/qlist/save/saveqlist", test_save_qlist
);
1520 g_test_add_func("/vmstate/qlist/load/loadqlist", test_load_qlist
);
1521 g_test_add_func("/vmstate/tmp_struct", test_tmp_struct
);