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"
37 static char temp_file
[] = "/tmp/vmst.test.XXXXXX";
41 /* Duplicate temp_fd and seek to the beginning of the file */
42 static QEMUFile
*open_test_file(bool write
)
44 int fd
= dup(temp_fd
);
48 lseek(fd
, 0, SEEK_SET
);
50 g_assert_cmpint(ftruncate(fd
, 0), ==, 0);
52 ioc
= QIO_CHANNEL(qio_channel_file_new_fd(fd
));
54 f
= qemu_fopen_channel_output(ioc
);
56 f
= qemu_fopen_channel_input(ioc
);
58 object_unref(OBJECT(ioc
));
62 #define SUCCESS(val) \
63 g_assert_cmpint((val), ==, 0)
65 #define FAILURE(val) \
66 g_assert_cmpint((val), !=, 0)
68 static void save_vmstate(const VMStateDescription
*desc
, void *obj
)
70 QEMUFile
*f
= open_test_file(true);
72 /* Save file with vmstate */
73 int ret
= vmstate_save_state(f
, desc
, obj
, NULL
);
75 qemu_put_byte(f
, QEMU_VM_EOF
);
76 g_assert(!qemu_file_get_error(f
));
80 static void save_buffer(const uint8_t *buf
, size_t buf_size
)
82 QEMUFile
*fsave
= open_test_file(true);
83 qemu_put_buffer(fsave
, buf
, buf_size
);
87 static void compare_vmstate(const uint8_t *wire
, size_t size
)
89 QEMUFile
*f
= open_test_file(false);
92 /* read back as binary */
94 g_assert_cmpint(qemu_get_buffer(f
, result
, sizeof(result
)), ==,
96 g_assert(!qemu_file_get_error(f
));
98 /* Compare that what is on the file is the same that what we
99 expected to be there */
100 SUCCESS(memcmp(result
, wire
, sizeof(result
)));
104 g_assert_cmpint(qemu_file_get_error(f
), ==, -EIO
);
109 static int load_vmstate_one(const VMStateDescription
*desc
, void *obj
,
110 int version
, const uint8_t *wire
, size_t size
)
115 f
= open_test_file(true);
116 qemu_put_buffer(f
, wire
, size
);
119 f
= open_test_file(false);
120 ret
= vmstate_load_state(f
, desc
, obj
, version
);
122 g_assert(qemu_file_get_error(f
));
124 g_assert(!qemu_file_get_error(f
));
131 static int load_vmstate(const VMStateDescription
*desc
,
132 void *obj
, void *obj_clone
,
133 void (*obj_copy
)(void *, void*),
134 int version
, const uint8_t *wire
, size_t size
)
136 /* We test with zero size */
137 obj_copy(obj_clone
, obj
);
138 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, 0));
140 /* Stream ends with QEMU_EOF, so we need at least 3 bytes to be
141 * able to test in the middle */
145 /* We test with size - 2. We can't test size - 1 due to EOF tricks */
146 obj_copy(obj
, obj_clone
);
147 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, size
- 2));
149 /* Test with size/2, first half of real state */
150 obj_copy(obj
, obj_clone
);
151 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
, size
/2));
153 /* Test with size/2, second half of real state */
154 obj_copy(obj
, obj_clone
);
155 FAILURE(load_vmstate_one(desc
, obj
, version
, wire
+ (size
/2), size
/2));
158 obj_copy(obj
, obj_clone
);
159 return load_vmstate_one(desc
, obj
, version
, wire
, size
);
162 /* Test struct that we are going to use for our tests */
164 typedef struct TestSimple
{
171 int16_t i16_1
, i16_2
;
172 int32_t i32_1
, i32_2
;
173 int64_t i64_1
, i64_2
;
176 /* Object instantiation, we are going to use it in more than one test */
178 TestSimple obj_simple
= {
195 /* Description of the values. If you add a primitive type
196 you are expected to add a test here */
198 static const VMStateDescription vmstate_simple_primitive
= {
199 .name
= "simple/primitive",
201 .minimum_version_id
= 1,
202 .fields
= (VMStateField
[]) {
203 VMSTATE_BOOL(b_1
, TestSimple
),
204 VMSTATE_BOOL(b_2
, TestSimple
),
205 VMSTATE_UINT8(u8_1
, TestSimple
),
206 VMSTATE_UINT16(u16_1
, TestSimple
),
207 VMSTATE_UINT32(u32_1
, TestSimple
),
208 VMSTATE_UINT64(u64_1
, TestSimple
),
209 VMSTATE_INT8(i8_1
, TestSimple
),
210 VMSTATE_INT8(i8_2
, TestSimple
),
211 VMSTATE_INT16(i16_1
, TestSimple
),
212 VMSTATE_INT16(i16_2
, TestSimple
),
213 VMSTATE_INT32(i32_1
, TestSimple
),
214 VMSTATE_INT32(i32_2
, TestSimple
),
215 VMSTATE_INT64(i64_1
, TestSimple
),
216 VMSTATE_INT64(i64_2
, TestSimple
),
217 VMSTATE_END_OF_LIST()
221 /* It describes what goes through the wire. Our tests are basically:
224 - save a struct a vmstate to a file
225 - read that file back (binary read, no vmstate)
226 - compare it with what we expect to be on the wire
228 - save to the file what we expect to be on the wire
229 - read struct back with vmstate in a different
230 - compare back with the original struct
233 uint8_t wire_simple_primitive
[] = {
237 /* u16_1 */ 0x02, 0x00,
238 /* u32_1 */ 0x00, 0x01, 0x11, 0x70,
239 /* u64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
242 /* i16_1 */ 0x02, 0x00,
243 /* i16_2 */ 0xfe, 0x0,
244 /* i32_1 */ 0x00, 0x01, 0x11, 0x70,
245 /* i32_2 */ 0xff, 0xfe, 0xee, 0x90,
246 /* i64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
247 /* i64_2 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x0b, 0x84,
248 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
251 static void obj_simple_copy(void *target
, void *source
)
253 memcpy(target
, source
, sizeof(TestSimple
));
256 static void test_simple_primitive(void)
258 TestSimple obj
, obj_clone
;
260 memset(&obj
, 0, sizeof(obj
));
261 save_vmstate(&vmstate_simple_primitive
, &obj_simple
);
263 compare_vmstate(wire_simple_primitive
, sizeof(wire_simple_primitive
));
265 SUCCESS(load_vmstate(&vmstate_simple_primitive
, &obj
, &obj_clone
,
266 obj_simple_copy
, 1, wire_simple_primitive
,
267 sizeof(wire_simple_primitive
)));
269 #define FIELD_EQUAL(name) g_assert_cmpint(obj.name, ==, obj_simple.name)
287 typedef struct TestSimpleArray
{
291 /* Object instantiation, we are going to use it in more than one test */
293 TestSimpleArray obj_simple_arr
= {
294 .u16_1
= { 0x42, 0x43, 0x44 },
297 /* Description of the values. If you add a primitive type
298 you are expected to add a test here */
300 static const VMStateDescription vmstate_simple_arr
= {
301 .name
= "simple/array",
303 .minimum_version_id
= 1,
304 .fields
= (VMStateField
[]) {
305 VMSTATE_UINT16_ARRAY(u16_1
, TestSimpleArray
, 3),
306 VMSTATE_END_OF_LIST()
310 uint8_t wire_simple_arr
[] = {
311 /* u16_1 */ 0x00, 0x42,
312 /* u16_1 */ 0x00, 0x43,
313 /* u16_1 */ 0x00, 0x44,
314 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
317 static void obj_simple_arr_copy(void *target
, void *source
)
319 memcpy(target
, source
, sizeof(TestSimpleArray
));
322 static void test_simple_array(void)
324 TestSimpleArray obj
, obj_clone
;
326 memset(&obj
, 0, sizeof(obj
));
327 save_vmstate(&vmstate_simple_arr
, &obj_simple_arr
);
329 compare_vmstate(wire_simple_arr
, sizeof(wire_simple_arr
));
331 SUCCESS(load_vmstate(&vmstate_simple_arr
, &obj
, &obj_clone
,
332 obj_simple_arr_copy
, 1, wire_simple_arr
,
333 sizeof(wire_simple_arr
)));
336 typedef struct TestStruct
{
342 static const VMStateDescription vmstate_versioned
= {
343 .name
= "test/versioned",
345 .minimum_version_id
= 1,
346 .fields
= (VMStateField
[]) {
347 VMSTATE_UINT32(a
, TestStruct
),
348 VMSTATE_UINT32_V(b
, TestStruct
, 2), /* Versioned field in the middle, so
349 * we catch bugs more easily.
351 VMSTATE_UINT32(c
, TestStruct
),
352 VMSTATE_UINT64(d
, TestStruct
),
353 VMSTATE_UINT32_V(e
, TestStruct
, 2),
354 VMSTATE_UINT64_V(f
, TestStruct
, 2),
355 VMSTATE_END_OF_LIST()
359 static void test_load_v1(void)
364 0, 0, 0, 0, 0, 0, 0, 40, /* d */
365 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
367 save_buffer(buf
, sizeof(buf
));
369 QEMUFile
*loading
= open_test_file(false);
370 TestStruct obj
= { .b
= 200, .e
= 500, .f
= 600 };
371 vmstate_load_state(loading
, &vmstate_versioned
, &obj
, 1);
372 g_assert(!qemu_file_get_error(loading
));
373 g_assert_cmpint(obj
.a
, ==, 10);
374 g_assert_cmpint(obj
.b
, ==, 200);
375 g_assert_cmpint(obj
.c
, ==, 30);
376 g_assert_cmpint(obj
.d
, ==, 40);
377 g_assert_cmpint(obj
.e
, ==, 500);
378 g_assert_cmpint(obj
.f
, ==, 600);
379 qemu_fclose(loading
);
382 static void test_load_v2(void)
388 0, 0, 0, 0, 0, 0, 0, 40, /* d */
390 0, 0, 0, 0, 0, 0, 0, 60, /* f */
391 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
393 save_buffer(buf
, sizeof(buf
));
395 QEMUFile
*loading
= open_test_file(false);
397 vmstate_load_state(loading
, &vmstate_versioned
, &obj
, 2);
398 g_assert_cmpint(obj
.a
, ==, 10);
399 g_assert_cmpint(obj
.b
, ==, 20);
400 g_assert_cmpint(obj
.c
, ==, 30);
401 g_assert_cmpint(obj
.d
, ==, 40);
402 g_assert_cmpint(obj
.e
, ==, 50);
403 g_assert_cmpint(obj
.f
, ==, 60);
404 qemu_fclose(loading
);
407 static bool test_skip(void *opaque
, int version_id
)
409 TestStruct
*t
= (TestStruct
*)opaque
;
413 static const VMStateDescription vmstate_skipping
= {
416 .minimum_version_id
= 1,
417 .fields
= (VMStateField
[]) {
418 VMSTATE_UINT32(a
, TestStruct
),
419 VMSTATE_UINT32(b
, TestStruct
),
420 VMSTATE_UINT32_TEST(c
, TestStruct
, test_skip
),
421 VMSTATE_UINT64(d
, TestStruct
),
422 VMSTATE_UINT32_TEST(e
, TestStruct
, test_skip
),
423 VMSTATE_UINT64_V(f
, TestStruct
, 2),
424 VMSTATE_END_OF_LIST()
429 static void test_save_noskip(void)
431 QEMUFile
*fsave
= open_test_file(true);
432 TestStruct obj
= { .a
= 1, .b
= 2, .c
= 3, .d
= 4, .e
= 5, .f
= 6,
434 int ret
= vmstate_save_state(fsave
, &vmstate_skipping
, &obj
, NULL
);
436 g_assert(!qemu_file_get_error(fsave
));
438 uint8_t expected
[] = {
442 0, 0, 0, 0, 0, 0, 0, 4, /* d */
444 0, 0, 0, 0, 0, 0, 0, 6, /* f */
448 compare_vmstate(expected
, sizeof(expected
));
451 static void test_save_skip(void)
453 QEMUFile
*fsave
= open_test_file(true);
454 TestStruct obj
= { .a
= 1, .b
= 2, .c
= 3, .d
= 4, .e
= 5, .f
= 6,
456 int ret
= vmstate_save_state(fsave
, &vmstate_skipping
, &obj
, NULL
);
458 g_assert(!qemu_file_get_error(fsave
));
460 uint8_t expected
[] = {
463 0, 0, 0, 0, 0, 0, 0, 4, /* d */
464 0, 0, 0, 0, 0, 0, 0, 6, /* f */
468 compare_vmstate(expected
, sizeof(expected
));
471 static void test_load_noskip(void)
477 0, 0, 0, 0, 0, 0, 0, 40, /* d */
479 0, 0, 0, 0, 0, 0, 0, 60, /* f */
480 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
482 save_buffer(buf
, sizeof(buf
));
484 QEMUFile
*loading
= open_test_file(false);
485 TestStruct obj
= { .skip_c_e
= false };
486 vmstate_load_state(loading
, &vmstate_skipping
, &obj
, 2);
487 g_assert(!qemu_file_get_error(loading
));
488 g_assert_cmpint(obj
.a
, ==, 10);
489 g_assert_cmpint(obj
.b
, ==, 20);
490 g_assert_cmpint(obj
.c
, ==, 30);
491 g_assert_cmpint(obj
.d
, ==, 40);
492 g_assert_cmpint(obj
.e
, ==, 50);
493 g_assert_cmpint(obj
.f
, ==, 60);
494 qemu_fclose(loading
);
497 static void test_load_skip(void)
502 0, 0, 0, 0, 0, 0, 0, 40, /* d */
503 0, 0, 0, 0, 0, 0, 0, 60, /* f */
504 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
506 save_buffer(buf
, sizeof(buf
));
508 QEMUFile
*loading
= open_test_file(false);
509 TestStruct obj
= { .skip_c_e
= true, .c
= 300, .e
= 500 };
510 vmstate_load_state(loading
, &vmstate_skipping
, &obj
, 2);
511 g_assert(!qemu_file_get_error(loading
));
512 g_assert_cmpint(obj
.a
, ==, 10);
513 g_assert_cmpint(obj
.b
, ==, 20);
514 g_assert_cmpint(obj
.c
, ==, 300);
515 g_assert_cmpint(obj
.d
, ==, 40);
516 g_assert_cmpint(obj
.e
, ==, 500);
517 g_assert_cmpint(obj
.f
, ==, 60);
518 qemu_fclose(loading
);
525 const VMStateDescription vmsd_tst
= {
528 .minimum_version_id
= 1,
529 .fields
= (VMStateField
[]) {
530 VMSTATE_INT32(i
, TestStructTriv
),
531 VMSTATE_END_OF_LIST()
535 /* test array migration */
540 TestStructTriv
*ar
[AR_SIZE
];
541 } TestArrayOfPtrToStuct
;
543 const VMStateDescription vmsd_arps
= {
546 .minimum_version_id
= 1,
547 .fields
= (VMStateField
[]) {
548 VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(ar
, TestArrayOfPtrToStuct
,
549 AR_SIZE
, 0, vmsd_tst
, TestStructTriv
),
550 VMSTATE_END_OF_LIST()
554 static uint8_t wire_arr_ptr_no0
[] = {
555 0x00, 0x00, 0x00, 0x00,
556 0x00, 0x00, 0x00, 0x01,
557 0x00, 0x00, 0x00, 0x02,
558 0x00, 0x00, 0x00, 0x03,
562 static void test_arr_ptr_str_no0_save(void)
564 TestStructTriv ar
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
565 TestArrayOfPtrToStuct sample
= {.ar
= {&ar
[0], &ar
[1], &ar
[2], &ar
[3]} };
567 save_vmstate(&vmsd_arps
, &sample
);
568 compare_vmstate(wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
));
571 static void test_arr_ptr_str_no0_load(void)
573 TestStructTriv ar_gt
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
574 TestStructTriv ar
[AR_SIZE
] = {};
575 TestArrayOfPtrToStuct obj
= {.ar
= {&ar
[0], &ar
[1], &ar
[2], &ar
[3]} };
578 save_buffer(wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
));
579 SUCCESS(load_vmstate_one(&vmsd_arps
, &obj
, 1,
580 wire_arr_ptr_no0
, sizeof(wire_arr_ptr_no0
)));
581 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
582 /* compare the target array ar with the ground truth array ar_gt */
583 g_assert_cmpint(ar_gt
[idx
].i
, ==, ar
[idx
].i
);
587 static uint8_t wire_arr_ptr_0
[] = {
588 0x00, 0x00, 0x00, 0x00,
590 0x00, 0x00, 0x00, 0x02,
591 0x00, 0x00, 0x00, 0x03,
595 static void test_arr_ptr_str_0_save(void)
597 TestStructTriv ar
[AR_SIZE
] = {{.i
= 0}, {.i
= 1}, {.i
= 2}, {.i
= 3} };
598 TestArrayOfPtrToStuct sample
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
600 save_vmstate(&vmsd_arps
, &sample
);
601 compare_vmstate(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
604 static void test_arr_ptr_str_0_load(void)
606 TestStructTriv ar_gt
[AR_SIZE
] = {{.i
= 0}, {.i
= 0}, {.i
= 2}, {.i
= 3} };
607 TestStructTriv ar
[AR_SIZE
] = {};
608 TestArrayOfPtrToStuct obj
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
611 save_buffer(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
612 SUCCESS(load_vmstate_one(&vmsd_arps
, &obj
, 1,
613 wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
)));
614 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
615 /* compare the target array ar with the ground truth array ar_gt */
616 g_assert_cmpint(ar_gt
[idx
].i
, ==, ar
[idx
].i
);
618 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
620 g_assert_cmpint((uintptr_t)(obj
.ar
[idx
]), ==, 0);
622 g_assert_cmpint((uintptr_t)(obj
.ar
[idx
]), !=, 0);
627 typedef struct TestArrayOfPtrToInt
{
628 int32_t *ar
[AR_SIZE
];
629 } TestArrayOfPtrToInt
;
631 const VMStateDescription vmsd_arpp
= {
634 .minimum_version_id
= 1,
635 .fields
= (VMStateField
[]) {
636 VMSTATE_ARRAY_OF_POINTER(ar
, TestArrayOfPtrToInt
,
637 AR_SIZE
, 0, vmstate_info_int32
, int32_t*),
638 VMSTATE_END_OF_LIST()
642 static void test_arr_ptr_prim_0_save(void)
644 int32_t ar
[AR_SIZE
] = {0 , 1, 2, 3};
645 TestArrayOfPtrToInt sample
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
647 save_vmstate(&vmsd_arpp
, &sample
);
648 compare_vmstate(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
651 static void test_arr_ptr_prim_0_load(void)
653 int32_t ar_gt
[AR_SIZE
] = {0, 1, 2, 3};
654 int32_t ar
[AR_SIZE
] = {3 , 42, 1, 0};
655 TestArrayOfPtrToInt obj
= {.ar
= {&ar
[0], NULL
, &ar
[2], &ar
[3]} };
658 save_buffer(wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
));
659 SUCCESS(load_vmstate_one(&vmsd_arpp
, &obj
, 1,
660 wire_arr_ptr_0
, sizeof(wire_arr_ptr_0
)));
661 for (idx
= 0; idx
< AR_SIZE
; ++idx
) {
662 /* compare the target array ar with the ground truth array ar_gt */
664 g_assert_cmpint(42, ==, ar
[idx
]);
666 g_assert_cmpint(ar_gt
[idx
], ==, ar
[idx
]);
671 /* test QTAILQ migration */
672 typedef struct TestQtailqElement TestQtailqElement
;
674 struct TestQtailqElement
{
677 QTAILQ_ENTRY(TestQtailqElement
) next
;
680 typedef struct TestQtailq
{
682 QTAILQ_HEAD(, TestQtailqElement
) q
;
686 static const VMStateDescription vmstate_q_element
= {
687 .name
= "test/queue-element",
689 .minimum_version_id
= 1,
690 .fields
= (VMStateField
[]) {
691 VMSTATE_BOOL(b
, TestQtailqElement
),
692 VMSTATE_UINT8(u8
, TestQtailqElement
),
693 VMSTATE_END_OF_LIST()
697 static const VMStateDescription vmstate_q
= {
698 .name
= "test/queue",
700 .minimum_version_id
= 1,
701 .fields
= (VMStateField
[]) {
702 VMSTATE_INT16(i16
, TestQtailq
),
703 VMSTATE_QTAILQ_V(q
, TestQtailq
, 1, vmstate_q_element
, TestQtailqElement
,
705 VMSTATE_INT32(i32
, TestQtailq
),
706 VMSTATE_END_OF_LIST()
712 /* start of element 0 of q */ 0x01,
715 /* start of element 1 of q */ 0x01,
719 /* i32 */ 0x00, 0x01, 0x11, 0x70,
720 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
723 static void test_save_q(void)
730 TestQtailqElement obj_qe1
= {
735 TestQtailqElement obj_qe2
= {
740 QTAILQ_INIT(&obj_q
.q
);
741 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe1
, next
);
742 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe2
, next
);
744 save_vmstate(&vmstate_q
, &obj_q
);
745 compare_vmstate(wire_q
, sizeof(wire_q
));
748 static void test_load_q(void)
755 TestQtailqElement obj_qe1
= {
760 TestQtailqElement obj_qe2
= {
765 QTAILQ_INIT(&obj_q
.q
);
766 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe1
, next
);
767 QTAILQ_INSERT_TAIL(&obj_q
.q
, &obj_qe2
, next
);
769 QEMUFile
*fsave
= open_test_file(true);
771 qemu_put_buffer(fsave
, wire_q
, sizeof(wire_q
));
772 g_assert(!qemu_file_get_error(fsave
));
775 QEMUFile
*fload
= open_test_file(false);
779 vmstate_load_state(fload
, &vmstate_q
, &tgt
, 1);
780 char eof
= qemu_get_byte(fload
);
781 g_assert(!qemu_file_get_error(fload
));
782 g_assert_cmpint(tgt
.i16
, ==, obj_q
.i16
);
783 g_assert_cmpint(tgt
.i32
, ==, obj_q
.i32
);
784 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
786 TestQtailqElement
*qele_from
= QTAILQ_FIRST(&obj_q
.q
);
787 TestQtailqElement
*qlast_from
= QTAILQ_LAST(&obj_q
.q
);
788 TestQtailqElement
*qele_to
= QTAILQ_FIRST(&tgt
.q
);
789 TestQtailqElement
*qlast_to
= QTAILQ_LAST(&tgt
.q
);
792 g_assert_cmpint(qele_to
->b
, ==, qele_from
->b
);
793 g_assert_cmpint(qele_to
->u8
, ==, qele_from
->u8
);
794 if ((qele_from
== qlast_from
) || (qele_to
== qlast_to
)) {
797 qele_from
= QTAILQ_NEXT(qele_from
, next
);
798 qele_to
= QTAILQ_NEXT(qele_to
, next
);
801 g_assert_cmpint((uintptr_t) qele_from
, ==, (uintptr_t) qlast_from
);
802 g_assert_cmpint((uintptr_t) qele_to
, ==, (uintptr_t) qlast_to
);
805 TestQtailqElement
*qele
;
806 while (!QTAILQ_EMPTY(&tgt
.q
)) {
807 qele
= QTAILQ_LAST(&tgt
.q
);
808 QTAILQ_REMOVE(&tgt
.q
, qele
, next
);
816 typedef struct TestGTreeInterval
{
821 #define VMSTATE_INTERVAL \
823 .name = "interval", \
825 .minimum_version_id = 1, \
826 .fields = (VMStateField[]) { \
827 VMSTATE_UINT64(low, TestGTreeInterval), \
828 VMSTATE_UINT64(high, TestGTreeInterval), \
829 VMSTATE_END_OF_LIST() \
833 /* mapping (value) */
834 typedef struct TestGTreeMapping
{
839 #define VMSTATE_MAPPING \
843 .minimum_version_id = 1, \
844 .fields = (VMStateField[]) { \
845 VMSTATE_UINT64(phys_addr, TestGTreeMapping), \
846 VMSTATE_UINT32(flags, TestGTreeMapping), \
847 VMSTATE_END_OF_LIST() \
851 static const VMStateDescription vmstate_interval_mapping
[2] = {
852 VMSTATE_MAPPING
, /* value */
853 VMSTATE_INTERVAL
/* key */
856 typedef struct TestGTreeDomain
{
861 typedef struct TestGTreeIOMMU
{
866 /* Interval comparison function */
867 static gint
interval_cmp(gconstpointer a
, gconstpointer b
, gpointer user_data
)
869 TestGTreeInterval
*inta
= (TestGTreeInterval
*)a
;
870 TestGTreeInterval
*intb
= (TestGTreeInterval
*)b
;
872 if (inta
->high
< intb
->low
) {
874 } else if (intb
->high
< inta
->low
) {
881 /* ID comparison function */
882 static gint
int_cmp(gconstpointer a
, gconstpointer b
, gpointer user_data
)
884 uint ua
= GPOINTER_TO_UINT(a
);
885 uint ub
= GPOINTER_TO_UINT(b
);
886 return (ua
> ub
) - (ua
< ub
);
889 static void destroy_domain(gpointer data
)
891 TestGTreeDomain
*domain
= (TestGTreeDomain
*)data
;
893 g_tree_destroy(domain
->mappings
);
897 static int domain_preload(void *opaque
)
899 TestGTreeDomain
*domain
= opaque
;
901 domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
,
902 NULL
, g_free
, g_free
);
906 static int iommu_preload(void *opaque
)
908 TestGTreeIOMMU
*iommu
= opaque
;
910 iommu
->domains
= g_tree_new_full((GCompareDataFunc
)int_cmp
,
911 NULL
, NULL
, destroy_domain
);
915 static const VMStateDescription vmstate_domain
= {
918 .minimum_version_id
= 1,
919 .pre_load
= domain_preload
,
920 .fields
= (VMStateField
[]) {
921 VMSTATE_INT32(id
, TestGTreeDomain
),
922 VMSTATE_GTREE_V(mappings
, TestGTreeDomain
, 1,
923 vmstate_interval_mapping
,
924 TestGTreeInterval
, TestGTreeMapping
),
925 VMSTATE_END_OF_LIST()
929 /* test QLIST Migration */
931 typedef struct TestQListElement
{
933 QLIST_ENTRY(TestQListElement
) next
;
936 typedef struct TestQListContainer
{
938 QLIST_HEAD(, TestQListElement
) list
;
939 } TestQListContainer
;
941 static const VMStateDescription vmstate_qlist_element
= {
942 .name
= "test/queue list",
944 .minimum_version_id
= 1,
945 .fields
= (VMStateField
[]) {
946 VMSTATE_UINT32(id
, TestQListElement
),
947 VMSTATE_END_OF_LIST()
951 static const VMStateDescription vmstate_iommu
= {
954 .minimum_version_id
= 1,
955 .pre_load
= iommu_preload
,
956 .fields
= (VMStateField
[]) {
957 VMSTATE_INT32(id
, TestGTreeIOMMU
),
958 VMSTATE_GTREE_DIRECT_KEY_V(domains
, TestGTreeIOMMU
, 1,
959 &vmstate_domain
, TestGTreeDomain
),
960 VMSTATE_END_OF_LIST()
964 static const VMStateDescription vmstate_container
= {
965 .name
= "test/container/qlist",
967 .minimum_version_id
= 1,
968 .fields
= (VMStateField
[]) {
969 VMSTATE_UINT32(id
, TestQListContainer
),
970 VMSTATE_QLIST_V(list
, TestQListContainer
, 1, vmstate_qlist_element
,
971 TestQListElement
, next
),
972 VMSTATE_END_OF_LIST()
976 uint8_t first_domain_dump
[] = {
979 0x00, 0x0, 0x0, 0x2, /* 2 mappings */
980 0x1, /* start of a */
982 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
983 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
985 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00,
986 0x00, 0x00, 0x00, 0x01,
987 0x1, /* start of b */
989 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
990 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF,
992 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
993 0x00, 0x00, 0x00, 0x02,
994 0x0, /* end of gtree */
995 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
998 static TestGTreeDomain
*create_first_domain(void)
1000 TestGTreeDomain
*domain
;
1001 TestGTreeMapping
*map_a
, *map_b
;
1002 TestGTreeInterval
*a
, *b
;
1004 domain
= g_malloc0(sizeof(TestGTreeDomain
));
1007 a
= g_malloc0(sizeof(TestGTreeInterval
));
1011 b
= g_malloc0(sizeof(TestGTreeInterval
));
1015 map_a
= g_malloc0(sizeof(TestGTreeMapping
));
1016 map_a
->phys_addr
= 0xa000;
1019 map_b
= g_malloc0(sizeof(TestGTreeMapping
));
1020 map_b
->phys_addr
= 0xe0000;
1023 domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
, NULL
,
1024 (GDestroyNotify
)g_free
,
1025 (GDestroyNotify
)g_free
);
1026 g_tree_insert(domain
->mappings
, a
, map_a
);
1027 g_tree_insert(domain
->mappings
, b
, map_b
);
1031 static void test_gtree_save_domain(void)
1033 TestGTreeDomain
*first_domain
= create_first_domain();
1035 save_vmstate(&vmstate_domain
, first_domain
);
1036 compare_vmstate(first_domain_dump
, sizeof(first_domain_dump
));
1037 destroy_domain(first_domain
);
1040 struct match_node_data
{
1046 struct tree_cmp_data
{
1049 GTraverseFunc match_node
;
1052 static gboolean
match_interval_mapping_node(gpointer key
,
1053 gpointer value
, gpointer data
)
1055 TestGTreeMapping
*map_a
, *map_b
;
1056 TestGTreeInterval
*a
, *b
;
1057 struct match_node_data
*d
= (struct match_node_data
*)data
;
1058 char *str
= g_strdup_printf("dest");
1061 a
= (TestGTreeInterval
*)key
;
1062 b
= (TestGTreeInterval
*)d
->key
;
1064 map_a
= (TestGTreeMapping
*)value
;
1065 map_b
= (TestGTreeMapping
*)d
->value
;
1067 assert(a
->low
== b
->low
);
1068 assert(a
->high
== b
->high
);
1069 assert(map_a
->phys_addr
== map_b
->phys_addr
);
1070 assert(map_a
->flags
== map_b
->flags
);
1071 g_tree_remove(d
->tree
, key
);
1075 static gboolean
diff_tree(gpointer key
, gpointer value
, gpointer data
)
1077 struct tree_cmp_data
*tp
= (struct tree_cmp_data
*)data
;
1078 struct match_node_data d
= {tp
->tree2
, key
, value
};
1080 g_tree_foreach(tp
->tree2
, tp
->match_node
, &d
);
1081 g_tree_remove(tp
->tree1
, key
);
1085 static void compare_trees(GTree
*tree1
, GTree
*tree2
,
1086 GTraverseFunc function
)
1088 struct tree_cmp_data tp
= {tree1
, tree2
, function
};
1090 g_tree_foreach(tree1
, diff_tree
, &tp
);
1091 assert(g_tree_nnodes(tree1
) == 0);
1092 assert(g_tree_nnodes(tree2
) == 0);
1095 static void diff_domain(TestGTreeDomain
*d1
, TestGTreeDomain
*d2
)
1097 assert(d1
->id
== d2
->id
);
1098 compare_trees(d1
->mappings
, d2
->mappings
, match_interval_mapping_node
);
1101 static gboolean
match_domain_node(gpointer key
, gpointer value
, gpointer data
)
1104 TestGTreeDomain
*d1
, *d2
;
1105 struct match_node_data
*d
= (struct match_node_data
*)data
;
1107 id1
= (uint64_t)(uintptr_t)key
;
1108 id2
= (uint64_t)(uintptr_t)d
->key
;
1109 d1
= (TestGTreeDomain
*)value
;
1110 d2
= (TestGTreeDomain
*)d
->value
;
1112 diff_domain(d1
, d2
);
1113 g_tree_remove(d
->tree
, key
);
1117 static void diff_iommu(TestGTreeIOMMU
*iommu1
, TestGTreeIOMMU
*iommu2
)
1119 assert(iommu1
->id
== iommu2
->id
);
1120 compare_trees(iommu1
->domains
, iommu2
->domains
, match_domain_node
);
1123 static void test_gtree_load_domain(void)
1125 TestGTreeDomain
*dest_domain
= g_malloc0(sizeof(TestGTreeDomain
));
1126 TestGTreeDomain
*orig_domain
= create_first_domain();
1127 QEMUFile
*fload
, *fsave
;
1130 fsave
= open_test_file(true);
1131 qemu_put_buffer(fsave
, first_domain_dump
, sizeof(first_domain_dump
));
1132 g_assert(!qemu_file_get_error(fsave
));
1135 fload
= open_test_file(false);
1137 vmstate_load_state(fload
, &vmstate_domain
, dest_domain
, 1);
1138 eof
= qemu_get_byte(fload
);
1139 g_assert(!qemu_file_get_error(fload
));
1140 g_assert_cmpint(orig_domain
->id
, ==, dest_domain
->id
);
1141 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
1143 diff_domain(orig_domain
, dest_domain
);
1144 destroy_domain(orig_domain
);
1145 destroy_domain(dest_domain
);
1149 uint8_t iommu_dump
[] = {
1151 0x00, 0x0, 0x0, 0x7,
1152 0x00, 0x0, 0x0, 0x2, /* 2 domains */
1153 0x1,/* start of domain 5 */
1154 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x5, /* key = 5 */
1155 0x00, 0x0, 0x0, 0x5, /* domain1 id */
1156 0x00, 0x0, 0x0, 0x1, /* 1 mapping */
1157 0x1, /* start of mappings */
1159 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1160 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF,
1162 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
1163 0x00, 0x0, 0x0, 0x3,
1164 0x0, /* end of domain1 mappings*/
1165 0x1,/* start of domain 6 */
1166 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x6, /* key = 6 */
1167 0x00, 0x0, 0x0, 0x6, /* domain6 id */
1168 0x00, 0x0, 0x0, 0x2, /* 2 mappings */
1169 0x1, /* start of a */
1171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
1174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00,
1175 0x00, 0x00, 0x00, 0x01,
1176 0x1, /* start of b */
1178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
1179 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF,
1181 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
1182 0x00, 0x00, 0x00, 0x02,
1183 0x0, /* end of domain6 mappings*/
1184 0x0, /* end of domains */
1185 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
1188 static TestGTreeIOMMU
*create_iommu(void)
1190 TestGTreeIOMMU
*iommu
= g_malloc0(sizeof(TestGTreeIOMMU
));
1191 TestGTreeDomain
*first_domain
= create_first_domain();
1192 TestGTreeDomain
*second_domain
;
1193 TestGTreeMapping
*map_c
;
1194 TestGTreeInterval
*c
;
1197 iommu
->domains
= g_tree_new_full((GCompareDataFunc
)int_cmp
, NULL
,
1201 second_domain
= g_malloc0(sizeof(TestGTreeDomain
));
1202 second_domain
->id
= 5;
1203 second_domain
->mappings
= g_tree_new_full((GCompareDataFunc
)interval_cmp
,
1205 (GDestroyNotify
)g_free
,
1206 (GDestroyNotify
)g_free
);
1208 g_tree_insert(iommu
->domains
, GUINT_TO_POINTER(6), first_domain
);
1209 g_tree_insert(iommu
->domains
, (gpointer
)0x0000000000000005, second_domain
);
1211 c
= g_malloc0(sizeof(TestGTreeInterval
));
1213 c
->high
= 0x1FFFFFF;
1215 map_c
= g_malloc0(sizeof(TestGTreeMapping
));
1216 map_c
->phys_addr
= 0xF000000;
1219 g_tree_insert(second_domain
->mappings
, c
, map_c
);
1223 static void destroy_iommu(TestGTreeIOMMU
*iommu
)
1225 g_tree_destroy(iommu
->domains
);
1229 static void test_gtree_save_iommu(void)
1231 TestGTreeIOMMU
*iommu
= create_iommu();
1233 save_vmstate(&vmstate_iommu
, iommu
);
1234 compare_vmstate(iommu_dump
, sizeof(iommu_dump
));
1235 destroy_iommu(iommu
);
1238 static void test_gtree_load_iommu(void)
1240 TestGTreeIOMMU
*dest_iommu
= g_malloc0(sizeof(TestGTreeIOMMU
));
1241 TestGTreeIOMMU
*orig_iommu
= create_iommu();
1242 QEMUFile
*fsave
, *fload
;
1246 fsave
= open_test_file(true);
1247 qemu_put_buffer(fsave
, iommu_dump
, sizeof(iommu_dump
));
1248 g_assert(!qemu_file_get_error(fsave
));
1251 fload
= open_test_file(false);
1252 vmstate_load_state(fload
, &vmstate_iommu
, dest_iommu
, 1);
1253 ret
= qemu_file_get_error(fload
);
1254 eof
= qemu_get_byte(fload
);
1255 ret
= qemu_file_get_error(fload
);
1257 g_assert_cmpint(orig_iommu
->id
, ==, dest_iommu
->id
);
1258 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
1260 diff_iommu(orig_iommu
, dest_iommu
);
1261 destroy_iommu(orig_iommu
);
1262 destroy_iommu(dest_iommu
);
1266 static uint8_t qlist_dump
[] = {
1267 0x00, 0x00, 0x00, 0x01, /* container id */
1268 0x1, /* start of a */
1269 0x00, 0x00, 0x00, 0x0a,
1270 0x1, /* start of b */
1271 0x00, 0x00, 0x0b, 0x00,
1272 0x1, /* start of c */
1273 0x00, 0x0c, 0x00, 0x00,
1274 0x1, /* start of d */
1275 0x0d, 0x00, 0x00, 0x00,
1276 0x0, /* end of list */
1277 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
1280 static TestQListContainer
*alloc_container(void)
1282 TestQListElement
*a
= g_malloc(sizeof(TestQListElement
));
1283 TestQListElement
*b
= g_malloc(sizeof(TestQListElement
));
1284 TestQListElement
*c
= g_malloc(sizeof(TestQListElement
));
1285 TestQListElement
*d
= g_malloc(sizeof(TestQListElement
));
1286 TestQListContainer
*container
= g_malloc(sizeof(TestQListContainer
));
1294 QLIST_INIT(&container
->list
);
1295 QLIST_INSERT_HEAD(&container
->list
, d
, next
);
1296 QLIST_INSERT_HEAD(&container
->list
, c
, next
);
1297 QLIST_INSERT_HEAD(&container
->list
, b
, next
);
1298 QLIST_INSERT_HEAD(&container
->list
, a
, next
);
1302 static void free_container(TestQListContainer
*container
)
1304 TestQListElement
*iter
, *tmp
;
1306 QLIST_FOREACH_SAFE(iter
, &container
->list
, next
, tmp
) {
1307 QLIST_REMOVE(iter
, next
);
1313 static void compare_containers(TestQListContainer
*c1
, TestQListContainer
*c2
)
1315 TestQListElement
*first_item_c1
, *first_item_c2
;
1317 while (!QLIST_EMPTY(&c1
->list
)) {
1318 first_item_c1
= QLIST_FIRST(&c1
->list
);
1319 first_item_c2
= QLIST_FIRST(&c2
->list
);
1320 assert(first_item_c2
);
1321 assert(first_item_c1
->id
== first_item_c2
->id
);
1322 QLIST_REMOVE(first_item_c1
, next
);
1323 QLIST_REMOVE(first_item_c2
, next
);
1324 g_free(first_item_c1
);
1325 g_free(first_item_c2
);
1327 assert(QLIST_EMPTY(&c2
->list
));
1331 * Check the prev & next fields are correct by doing list
1332 * manipulations on the container. We will do that for both
1333 * the source and the destination containers
1335 static void manipulate_container(TestQListContainer
*c
)
1337 TestQListElement
*prev
= NULL
, *iter
= QLIST_FIRST(&c
->list
);
1338 TestQListElement
*elem
;
1340 elem
= g_malloc(sizeof(TestQListElement
));
1342 QLIST_INSERT_AFTER(iter
, elem
, next
);
1344 elem
= g_malloc(sizeof(TestQListElement
));
1346 QLIST_INSERT_HEAD(&c
->list
, elem
, next
);
1350 iter
= QLIST_NEXT(iter
, next
);
1353 elem
= g_malloc(sizeof(TestQListElement
));
1355 QLIST_INSERT_BEFORE(prev
, elem
, next
);
1357 elem
= g_malloc(sizeof(TestQListElement
));
1359 QLIST_INSERT_AFTER(prev
, elem
, next
);
1361 QLIST_REMOVE(prev
, next
);
1365 static void test_save_qlist(void)
1367 TestQListContainer
*container
= alloc_container();
1369 save_vmstate(&vmstate_container
, container
);
1370 compare_vmstate(qlist_dump
, sizeof(qlist_dump
));
1371 free_container(container
);
1374 static void test_load_qlist(void)
1376 QEMUFile
*fsave
, *fload
;
1377 TestQListContainer
*orig_container
= alloc_container();
1378 TestQListContainer
*dest_container
= g_malloc0(sizeof(TestQListContainer
));
1381 QLIST_INIT(&dest_container
->list
);
1383 fsave
= open_test_file(true);
1384 qemu_put_buffer(fsave
, qlist_dump
, sizeof(qlist_dump
));
1385 g_assert(!qemu_file_get_error(fsave
));
1388 fload
= open_test_file(false);
1389 vmstate_load_state(fload
, &vmstate_container
, dest_container
, 1);
1390 eof
= qemu_get_byte(fload
);
1391 g_assert(!qemu_file_get_error(fload
));
1392 g_assert_cmpint(eof
, ==, QEMU_VM_EOF
);
1393 manipulate_container(orig_container
);
1394 manipulate_container(dest_container
);
1395 compare_containers(orig_container
, dest_container
);
1396 free_container(orig_container
);
1397 free_container(dest_container
);
1400 typedef struct TmpTestStruct
{
1405 static int tmp_child_pre_save(void *opaque
)
1407 struct TmpTestStruct
*tts
= opaque
;
1409 tts
->diff
= tts
->parent
->b
- tts
->parent
->a
;
1414 static int tmp_child_post_load(void *opaque
, int version_id
)
1416 struct TmpTestStruct
*tts
= opaque
;
1418 tts
->parent
->b
= tts
->parent
->a
+ tts
->diff
;
1423 static const VMStateDescription vmstate_tmp_back_to_parent
= {
1424 .name
= "test/tmp_child_parent",
1425 .fields
= (VMStateField
[]) {
1426 VMSTATE_UINT64(f
, TestStruct
),
1427 VMSTATE_END_OF_LIST()
1431 static const VMStateDescription vmstate_tmp_child
= {
1432 .name
= "test/tmp_child",
1433 .pre_save
= tmp_child_pre_save
,
1434 .post_load
= tmp_child_post_load
,
1435 .fields
= (VMStateField
[]) {
1436 VMSTATE_INT64(diff
, TmpTestStruct
),
1437 VMSTATE_STRUCT_POINTER(parent
, TmpTestStruct
,
1438 vmstate_tmp_back_to_parent
, TestStruct
),
1439 VMSTATE_END_OF_LIST()
1443 static const VMStateDescription vmstate_with_tmp
= {
1444 .name
= "test/with_tmp",
1446 .fields
= (VMStateField
[]) {
1447 VMSTATE_UINT32(a
, TestStruct
),
1448 VMSTATE_UINT64(d
, TestStruct
),
1449 VMSTATE_WITH_TMP(TestStruct
, TmpTestStruct
, vmstate_tmp_child
),
1450 VMSTATE_END_OF_LIST()
1454 static void obj_tmp_copy(void *target
, void *source
)
1456 memcpy(target
, source
, sizeof(TestStruct
));
1459 static void test_tmp_struct(void)
1461 TestStruct obj
, obj_clone
;
1463 uint8_t const wire_with_tmp
[] = {
1464 /* u32 a */ 0x00, 0x00, 0x00, 0x02,
1465 /* u64 d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
1466 /* diff */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
1467 /* u64 f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
1468 QEMU_VM_EOF
, /* just to ensure we won't get EOF reported prematurely */
1471 memset(&obj
, 0, sizeof(obj
));
1476 save_vmstate(&vmstate_with_tmp
, &obj
);
1478 compare_vmstate(wire_with_tmp
, sizeof(wire_with_tmp
));
1480 memset(&obj
, 0, sizeof(obj
));
1481 SUCCESS(load_vmstate(&vmstate_with_tmp
, &obj
, &obj_clone
,
1482 obj_tmp_copy
, 1, wire_with_tmp
,
1483 sizeof(wire_with_tmp
)));
1484 g_assert_cmpint(obj
.a
, ==, 2); /* From top level vmsd */
1485 g_assert_cmpint(obj
.b
, ==, 4); /* from the post_load */
1486 g_assert_cmpint(obj
.d
, ==, 1); /* From top level vmsd */
1487 g_assert_cmpint(obj
.f
, ==, 8); /* From the child->parent */
1490 int main(int argc
, char **argv
)
1492 temp_fd
= mkstemp(temp_file
);
1494 module_call_init(MODULE_INIT_QOM
);
1496 g_setenv("QTEST_SILENT_ERRORS", "1", 1);
1498 g_test_init(&argc
, &argv
, NULL
);
1499 g_test_add_func("/vmstate/simple/primitive", test_simple_primitive
);
1500 g_test_add_func("/vmstate/simple/array", test_simple_array
);
1501 g_test_add_func("/vmstate/versioned/load/v1", test_load_v1
);
1502 g_test_add_func("/vmstate/versioned/load/v2", test_load_v2
);
1503 g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip
);
1504 g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip
);
1505 g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip
);
1506 g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip
);
1507 g_test_add_func("/vmstate/array/ptr/str/no0/save",
1508 test_arr_ptr_str_no0_save
);
1509 g_test_add_func("/vmstate/array/ptr/str/no0/load",
1510 test_arr_ptr_str_no0_load
);
1511 g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save
);
1512 g_test_add_func("/vmstate/array/ptr/str/0/load",
1513 test_arr_ptr_str_0_load
);
1514 g_test_add_func("/vmstate/array/ptr/prim/0/save",
1515 test_arr_ptr_prim_0_save
);
1516 g_test_add_func("/vmstate/array/ptr/prim/0/load",
1517 test_arr_ptr_prim_0_load
);
1518 g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q
);
1519 g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q
);
1520 g_test_add_func("/vmstate/gtree/save/savedomain", test_gtree_save_domain
);
1521 g_test_add_func("/vmstate/gtree/load/loaddomain", test_gtree_load_domain
);
1522 g_test_add_func("/vmstate/gtree/save/saveiommu", test_gtree_save_iommu
);
1523 g_test_add_func("/vmstate/gtree/load/loadiommu", test_gtree_load_iommu
);
1524 g_test_add_func("/vmstate/qlist/save/saveqlist", test_save_qlist
);
1525 g_test_add_func("/vmstate/qlist/load/loadqlist", test_load_qlist
);
1526 g_test_add_func("/vmstate/tmp_struct", test_tmp_struct
);