1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "qemu/osdep.h"
26
27#include "qemu-common.h"
28#include "migration/migration.h"
29#include "migration/vmstate.h"
30#include "qemu/coroutine.h"
31#include "io/channel-file.h"
32
33static char temp_file[] = "/tmp/vmst.test.XXXXXX";
34static int temp_fd;
35
36
37
38static QEMUFile *open_test_file(bool write)
39{
40 int fd = dup(temp_fd);
41 QIOChannel *ioc;
42 QEMUFile *f;
43
44 lseek(fd, 0, SEEK_SET);
45 if (write) {
46 g_assert_cmpint(ftruncate(fd, 0), ==, 0);
47 }
48 ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
49 if (write) {
50 f = qemu_fopen_channel_output(ioc);
51 } else {
52 f = qemu_fopen_channel_input(ioc);
53 }
54 object_unref(OBJECT(ioc));
55 return f;
56}
57
58#define SUCCESS(val) \
59 g_assert_cmpint((val), ==, 0)
60
61#define FAILURE(val) \
62 g_assert_cmpint((val), !=, 0)
63
64static void save_vmstate(const VMStateDescription *desc, void *obj)
65{
66 QEMUFile *f = open_test_file(true);
67
68
69 vmstate_save_state(f, desc, obj, NULL);
70 qemu_put_byte(f, QEMU_VM_EOF);
71 g_assert(!qemu_file_get_error(f));
72 qemu_fclose(f);
73}
74
75static void save_buffer(const uint8_t *buf, size_t buf_size)
76{
77 QEMUFile *fsave = open_test_file(true);
78 qemu_put_buffer(fsave, buf, buf_size);
79 qemu_fclose(fsave);
80}
81
82static void compare_vmstate(const uint8_t *wire, size_t size)
83{
84 QEMUFile *f = open_test_file(false);
85 uint8_t result[size];
86
87
88
89 g_assert_cmpint(qemu_get_buffer(f, result, sizeof(result)), ==,
90 sizeof(result));
91 g_assert(!qemu_file_get_error(f));
92
93
94
95 SUCCESS(memcmp(result, wire, sizeof(result)));
96
97
98 qemu_get_byte(f);
99 g_assert_cmpint(qemu_file_get_error(f), ==, -EIO);
100
101 qemu_fclose(f);
102}
103
104static int load_vmstate_one(const VMStateDescription *desc, void *obj,
105 int version, const uint8_t *wire, size_t size)
106{
107 QEMUFile *f;
108 int ret;
109
110 f = open_test_file(true);
111 qemu_put_buffer(f, wire, size);
112 qemu_fclose(f);
113
114 f = open_test_file(false);
115 ret = vmstate_load_state(f, desc, obj, version);
116 if (ret) {
117 g_assert(qemu_file_get_error(f));
118 } else{
119 g_assert(!qemu_file_get_error(f));
120 }
121 qemu_fclose(f);
122 return ret;
123}
124
125
126static int load_vmstate(const VMStateDescription *desc,
127 void *obj, void *obj_clone,
128 void (*obj_copy)(void *, void*),
129 int version, const uint8_t *wire, size_t size)
130{
131
132 obj_copy(obj_clone, obj);
133 FAILURE(load_vmstate_one(desc, obj, version, wire, 0));
134
135
136
137
138 if (size > 3) {
139
140
141 obj_copy(obj, obj_clone);
142 FAILURE(load_vmstate_one(desc, obj, version, wire, size - 2));
143
144
145 obj_copy(obj, obj_clone);
146 FAILURE(load_vmstate_one(desc, obj, version, wire, size/2));
147
148
149 obj_copy(obj, obj_clone);
150 FAILURE(load_vmstate_one(desc, obj, version, wire + (size/2), size/2));
151
152 }
153 obj_copy(obj, obj_clone);
154 return load_vmstate_one(desc, obj, version, wire, size);
155}
156
157
158
159typedef struct TestSimple {
160 bool b_1, b_2;
161 uint8_t u8_1;
162 uint16_t u16_1;
163 uint32_t u32_1;
164 uint64_t u64_1;
165 int8_t i8_1, i8_2;
166 int16_t i16_1, i16_2;
167 int32_t i32_1, i32_2;
168 int64_t i64_1, i64_2;
169} TestSimple;
170
171
172
173TestSimple obj_simple = {
174 .b_1 = true,
175 .b_2 = false,
176 .u8_1 = 130,
177 .u16_1 = 512,
178 .u32_1 = 70000,
179 .u64_1 = 12121212,
180 .i8_1 = 65,
181 .i8_2 = -65,
182 .i16_1 = 512,
183 .i16_2 = -512,
184 .i32_1 = 70000,
185 .i32_2 = -70000,
186 .i64_1 = 12121212,
187 .i64_2 = -12121212,
188};
189
190
191
192
193static const VMStateDescription vmstate_simple_primitive = {
194 .name = "simple/primitive",
195 .version_id = 1,
196 .minimum_version_id = 1,
197 .fields = (VMStateField[]) {
198 VMSTATE_BOOL(b_1, TestSimple),
199 VMSTATE_BOOL(b_2, TestSimple),
200 VMSTATE_UINT8(u8_1, TestSimple),
201 VMSTATE_UINT16(u16_1, TestSimple),
202 VMSTATE_UINT32(u32_1, TestSimple),
203 VMSTATE_UINT64(u64_1, TestSimple),
204 VMSTATE_INT8(i8_1, TestSimple),
205 VMSTATE_INT8(i8_2, TestSimple),
206 VMSTATE_INT16(i16_1, TestSimple),
207 VMSTATE_INT16(i16_2, TestSimple),
208 VMSTATE_INT32(i32_1, TestSimple),
209 VMSTATE_INT32(i32_2, TestSimple),
210 VMSTATE_INT64(i64_1, TestSimple),
211 VMSTATE_INT64(i64_2, TestSimple),
212 VMSTATE_END_OF_LIST()
213 }
214};
215
216
217
218
219
220
221
222
223
224
225
226
227
228uint8_t wire_simple_primitive[] = {
229 0x01,
230 0x00,
231 0x82,
232 0x02, 0x00,
233 0x00, 0x01, 0x11, 0x70,
234 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
235 0x41,
236 0xbf,
237 0x02, 0x00,
238 0xfe, 0x0,
239 0x00, 0x01, 0x11, 0x70,
240 0xff, 0xfe, 0xee, 0x90,
241 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
242 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x0b, 0x84,
243 QEMU_VM_EOF,
244};
245
246static void obj_simple_copy(void *target, void *source)
247{
248 memcpy(target, source, sizeof(TestSimple));
249}
250
251static void test_simple_primitive(void)
252{
253 TestSimple obj, obj_clone;
254
255 memset(&obj, 0, sizeof(obj));
256 save_vmstate(&vmstate_simple_primitive, &obj_simple);
257
258 compare_vmstate(wire_simple_primitive, sizeof(wire_simple_primitive));
259
260 SUCCESS(load_vmstate(&vmstate_simple_primitive, &obj, &obj_clone,
261 obj_simple_copy, 1, wire_simple_primitive,
262 sizeof(wire_simple_primitive)));
263
264#define FIELD_EQUAL(name) g_assert_cmpint(obj.name, ==, obj_simple.name)
265
266 FIELD_EQUAL(b_1);
267 FIELD_EQUAL(b_2);
268 FIELD_EQUAL(u8_1);
269 FIELD_EQUAL(u16_1);
270 FIELD_EQUAL(u32_1);
271 FIELD_EQUAL(u64_1);
272 FIELD_EQUAL(i8_1);
273 FIELD_EQUAL(i8_2);
274 FIELD_EQUAL(i16_1);
275 FIELD_EQUAL(i16_2);
276 FIELD_EQUAL(i32_1);
277 FIELD_EQUAL(i32_2);
278 FIELD_EQUAL(i64_1);
279 FIELD_EQUAL(i64_2);
280}
281
282typedef struct TestStruct {
283 uint32_t a, b, c, e;
284 uint64_t d, f;
285 bool skip_c_e;
286} TestStruct;
287
288static const VMStateDescription vmstate_versioned = {
289 .name = "test/versioned",
290 .version_id = 2,
291 .minimum_version_id = 1,
292 .fields = (VMStateField[]) {
293 VMSTATE_UINT32(a, TestStruct),
294 VMSTATE_UINT32_V(b, TestStruct, 2),
295
296
297 VMSTATE_UINT32(c, TestStruct),
298 VMSTATE_UINT64(d, TestStruct),
299 VMSTATE_UINT32_V(e, TestStruct, 2),
300 VMSTATE_UINT64_V(f, TestStruct, 2),
301 VMSTATE_END_OF_LIST()
302 }
303};
304
305static void test_load_v1(void)
306{
307 uint8_t buf[] = {
308 0, 0, 0, 10,
309 0, 0, 0, 30,
310 0, 0, 0, 0, 0, 0, 0, 40,
311 QEMU_VM_EOF,
312 };
313 save_buffer(buf, sizeof(buf));
314
315 QEMUFile *loading = open_test_file(false);
316 TestStruct obj = { .b = 200, .e = 500, .f = 600 };
317 vmstate_load_state(loading, &vmstate_versioned, &obj, 1);
318 g_assert(!qemu_file_get_error(loading));
319 g_assert_cmpint(obj.a, ==, 10);
320 g_assert_cmpint(obj.b, ==, 200);
321 g_assert_cmpint(obj.c, ==, 30);
322 g_assert_cmpint(obj.d, ==, 40);
323 g_assert_cmpint(obj.e, ==, 500);
324 g_assert_cmpint(obj.f, ==, 600);
325 qemu_fclose(loading);
326}
327
328static void test_load_v2(void)
329{
330 uint8_t buf[] = {
331 0, 0, 0, 10,
332 0, 0, 0, 20,
333 0, 0, 0, 30,
334 0, 0, 0, 0, 0, 0, 0, 40,
335 0, 0, 0, 50,
336 0, 0, 0, 0, 0, 0, 0, 60,
337 QEMU_VM_EOF,
338 };
339 save_buffer(buf, sizeof(buf));
340
341 QEMUFile *loading = open_test_file(false);
342 TestStruct obj;
343 vmstate_load_state(loading, &vmstate_versioned, &obj, 2);
344 g_assert_cmpint(obj.a, ==, 10);
345 g_assert_cmpint(obj.b, ==, 20);
346 g_assert_cmpint(obj.c, ==, 30);
347 g_assert_cmpint(obj.d, ==, 40);
348 g_assert_cmpint(obj.e, ==, 50);
349 g_assert_cmpint(obj.f, ==, 60);
350 qemu_fclose(loading);
351}
352
353static bool test_skip(void *opaque, int version_id)
354{
355 TestStruct *t = (TestStruct *)opaque;
356 return !t->skip_c_e;
357}
358
359static const VMStateDescription vmstate_skipping = {
360 .name = "test/skip",
361 .version_id = 2,
362 .minimum_version_id = 1,
363 .fields = (VMStateField[]) {
364 VMSTATE_UINT32(a, TestStruct),
365 VMSTATE_UINT32(b, TestStruct),
366 VMSTATE_UINT32_TEST(c, TestStruct, test_skip),
367 VMSTATE_UINT64(d, TestStruct),
368 VMSTATE_UINT32_TEST(e, TestStruct, test_skip),
369 VMSTATE_UINT64_V(f, TestStruct, 2),
370 VMSTATE_END_OF_LIST()
371 }
372};
373
374
375static void test_save_noskip(void)
376{
377 QEMUFile *fsave = open_test_file(true);
378 TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
379 .skip_c_e = false };
380 vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL);
381 g_assert(!qemu_file_get_error(fsave));
382
383 uint8_t expected[] = {
384 0, 0, 0, 1,
385 0, 0, 0, 2,
386 0, 0, 0, 3,
387 0, 0, 0, 0, 0, 0, 0, 4,
388 0, 0, 0, 5,
389 0, 0, 0, 0, 0, 0, 0, 6,
390 };
391
392 qemu_fclose(fsave);
393 compare_vmstate(expected, sizeof(expected));
394}
395
396static void test_save_skip(void)
397{
398 QEMUFile *fsave = open_test_file(true);
399 TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
400 .skip_c_e = true };
401 vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL);
402 g_assert(!qemu_file_get_error(fsave));
403
404 uint8_t expected[] = {
405 0, 0, 0, 1,
406 0, 0, 0, 2,
407 0, 0, 0, 0, 0, 0, 0, 4,
408 0, 0, 0, 0, 0, 0, 0, 6,
409 };
410
411 qemu_fclose(fsave);
412 compare_vmstate(expected, sizeof(expected));
413}
414
415static void test_load_noskip(void)
416{
417 uint8_t buf[] = {
418 0, 0, 0, 10,
419 0, 0, 0, 20,
420 0, 0, 0, 30,
421 0, 0, 0, 0, 0, 0, 0, 40,
422 0, 0, 0, 50,
423 0, 0, 0, 0, 0, 0, 0, 60,
424 QEMU_VM_EOF,
425 };
426 save_buffer(buf, sizeof(buf));
427
428 QEMUFile *loading = open_test_file(false);
429 TestStruct obj = { .skip_c_e = false };
430 vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
431 g_assert(!qemu_file_get_error(loading));
432 g_assert_cmpint(obj.a, ==, 10);
433 g_assert_cmpint(obj.b, ==, 20);
434 g_assert_cmpint(obj.c, ==, 30);
435 g_assert_cmpint(obj.d, ==, 40);
436 g_assert_cmpint(obj.e, ==, 50);
437 g_assert_cmpint(obj.f, ==, 60);
438 qemu_fclose(loading);
439}
440
441static void test_load_skip(void)
442{
443 uint8_t buf[] = {
444 0, 0, 0, 10,
445 0, 0, 0, 20,
446 0, 0, 0, 0, 0, 0, 0, 40,
447 0, 0, 0, 0, 0, 0, 0, 60,
448 QEMU_VM_EOF,
449 };
450 save_buffer(buf, sizeof(buf));
451
452 QEMUFile *loading = open_test_file(false);
453 TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
454 vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
455 g_assert(!qemu_file_get_error(loading));
456 g_assert_cmpint(obj.a, ==, 10);
457 g_assert_cmpint(obj.b, ==, 20);
458 g_assert_cmpint(obj.c, ==, 300);
459 g_assert_cmpint(obj.d, ==, 40);
460 g_assert_cmpint(obj.e, ==, 500);
461 g_assert_cmpint(obj.f, ==, 60);
462 qemu_fclose(loading);
463}
464
465typedef struct {
466 int32_t i;
467} TestStructTriv;
468
469const VMStateDescription vmsd_tst = {
470 .name = "test/tst",
471 .version_id = 1,
472 .minimum_version_id = 1,
473 .fields = (VMStateField[]) {
474 VMSTATE_INT32(i, TestStructTriv),
475 VMSTATE_END_OF_LIST()
476 }
477};
478
479
480
481#define AR_SIZE 4
482
483typedef struct {
484 TestStructTriv *ar[AR_SIZE];
485} TestArrayOfPtrToStuct;
486
487const VMStateDescription vmsd_arps = {
488 .name = "test/arps",
489 .version_id = 1,
490 .minimum_version_id = 1,
491 .fields = (VMStateField[]) {
492 VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(ar, TestArrayOfPtrToStuct,
493 AR_SIZE, 0, vmsd_tst, TestStructTriv),
494 VMSTATE_END_OF_LIST()
495 }
496};
497
498static uint8_t wire_arr_ptr_no0[] = {
499 0x00, 0x00, 0x00, 0x00,
500 0x00, 0x00, 0x00, 0x01,
501 0x00, 0x00, 0x00, 0x02,
502 0x00, 0x00, 0x00, 0x03,
503 QEMU_VM_EOF
504};
505
506static void test_arr_ptr_str_no0_save(void)
507{
508 TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
509 TestArrayOfPtrToStuct sample = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} };
510
511 save_vmstate(&vmsd_arps, &sample);
512 compare_vmstate(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0));
513}
514
515static void test_arr_ptr_str_no0_load(void)
516{
517 TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
518 TestStructTriv ar[AR_SIZE] = {};
519 TestArrayOfPtrToStuct obj = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} };
520 int idx;
521
522 save_buffer(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0));
523 SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1,
524 wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0)));
525 for (idx = 0; idx < AR_SIZE; ++idx) {
526
527 g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i);
528 }
529}
530
531static uint8_t wire_arr_ptr_0[] = {
532 0x00, 0x00, 0x00, 0x00,
533 VMS_NULLPTR_MARKER,
534 0x00, 0x00, 0x00, 0x02,
535 0x00, 0x00, 0x00, 0x03,
536 QEMU_VM_EOF
537};
538
539static void test_arr_ptr_str_0_save(void)
540{
541 TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
542 TestArrayOfPtrToStuct sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
543
544 save_vmstate(&vmsd_arps, &sample);
545 compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
546}
547
548static void test_arr_ptr_str_0_load(void)
549{
550 TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 0}, {.i = 2}, {.i = 3} };
551 TestStructTriv ar[AR_SIZE] = {};
552 TestArrayOfPtrToStuct obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
553 int idx;
554
555 save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
556 SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1,
557 wire_arr_ptr_0, sizeof(wire_arr_ptr_0)));
558 for (idx = 0; idx < AR_SIZE; ++idx) {
559
560 g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i);
561 }
562 for (idx = 0; idx < AR_SIZE; ++idx) {
563 if (idx == 1) {
564 g_assert_cmpint((uintptr_t)(obj.ar[idx]), ==, 0);
565 } else {
566 g_assert_cmpint((uintptr_t)(obj.ar[idx]), !=, 0);
567 }
568 }
569}
570
571typedef struct TestArrayOfPtrToInt {
572 int32_t *ar[AR_SIZE];
573} TestArrayOfPtrToInt;
574
575const VMStateDescription vmsd_arpp = {
576 .name = "test/arps",
577 .version_id = 1,
578 .minimum_version_id = 1,
579 .fields = (VMStateField[]) {
580 VMSTATE_ARRAY_OF_POINTER(ar, TestArrayOfPtrToInt,
581 AR_SIZE, 0, vmstate_info_int32, int32_t*),
582 VMSTATE_END_OF_LIST()
583 }
584};
585
586static void test_arr_ptr_prim_0_save(void)
587{
588 int32_t ar[AR_SIZE] = {0 , 1, 2, 3};
589 TestArrayOfPtrToInt sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
590
591 save_vmstate(&vmsd_arpp, &sample);
592 compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
593}
594
595static void test_arr_ptr_prim_0_load(void)
596{
597 int32_t ar_gt[AR_SIZE] = {0, 1, 2, 3};
598 int32_t ar[AR_SIZE] = {3 , 42, 1, 0};
599 TestArrayOfPtrToInt obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
600 int idx;
601
602 save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
603 SUCCESS(load_vmstate_one(&vmsd_arpp, &obj, 1,
604 wire_arr_ptr_0, sizeof(wire_arr_ptr_0)));
605 for (idx = 0; idx < AR_SIZE; ++idx) {
606
607 if (idx == 1) {
608 g_assert_cmpint(42, ==, ar[idx]);
609 } else {
610 g_assert_cmpint(ar_gt[idx], ==, ar[idx]);
611 }
612 }
613}
614
615
616typedef struct TestQtailqElement TestQtailqElement;
617
618struct TestQtailqElement {
619 bool b;
620 uint8_t u8;
621 QTAILQ_ENTRY(TestQtailqElement) next;
622};
623
624typedef struct TestQtailq {
625 int16_t i16;
626 QTAILQ_HEAD(TestQtailqHead, TestQtailqElement) q;
627 int32_t i32;
628} TestQtailq;
629
630static const VMStateDescription vmstate_q_element = {
631 .name = "test/queue-element",
632 .version_id = 1,
633 .minimum_version_id = 1,
634 .fields = (VMStateField[]) {
635 VMSTATE_BOOL(b, TestQtailqElement),
636 VMSTATE_UINT8(u8, TestQtailqElement),
637 VMSTATE_END_OF_LIST()
638 },
639};
640
641static const VMStateDescription vmstate_q = {
642 .name = "test/queue",
643 .version_id = 1,
644 .minimum_version_id = 1,
645 .fields = (VMStateField[]) {
646 VMSTATE_INT16(i16, TestQtailq),
647 VMSTATE_QTAILQ_V(q, TestQtailq, 1, vmstate_q_element, TestQtailqElement,
648 next),
649 VMSTATE_INT32(i32, TestQtailq),
650 VMSTATE_END_OF_LIST()
651 }
652};
653
654uint8_t wire_q[] = {
655 0xfe, 0x0,
656 0x01,
657 0x01,
658 0x82,
659 0x01,
660 0x00,
661 0x41,
662 0x00,
663 0x00, 0x01, 0x11, 0x70,
664 QEMU_VM_EOF,
665};
666
667static void test_save_q(void)
668{
669 TestQtailq obj_q = {
670 .i16 = -512,
671 .i32 = 70000,
672 };
673
674 TestQtailqElement obj_qe1 = {
675 .b = true,
676 .u8 = 130,
677 };
678
679 TestQtailqElement obj_qe2 = {
680 .b = false,
681 .u8 = 65,
682 };
683
684 QTAILQ_INIT(&obj_q.q);
685 QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next);
686 QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next);
687
688 save_vmstate(&vmstate_q, &obj_q);
689 compare_vmstate(wire_q, sizeof(wire_q));
690}
691
692static void test_load_q(void)
693{
694 TestQtailq obj_q = {
695 .i16 = -512,
696 .i32 = 70000,
697 };
698
699 TestQtailqElement obj_qe1 = {
700 .b = true,
701 .u8 = 130,
702 };
703
704 TestQtailqElement obj_qe2 = {
705 .b = false,
706 .u8 = 65,
707 };
708
709 QTAILQ_INIT(&obj_q.q);
710 QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next);
711 QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next);
712
713 QEMUFile *fsave = open_test_file(true);
714
715 qemu_put_buffer(fsave, wire_q, sizeof(wire_q));
716 g_assert(!qemu_file_get_error(fsave));
717 qemu_fclose(fsave);
718
719 QEMUFile *fload = open_test_file(false);
720 TestQtailq tgt;
721
722 QTAILQ_INIT(&tgt.q);
723 vmstate_load_state(fload, &vmstate_q, &tgt, 1);
724 char eof = qemu_get_byte(fload);
725 g_assert(!qemu_file_get_error(fload));
726 g_assert_cmpint(tgt.i16, ==, obj_q.i16);
727 g_assert_cmpint(tgt.i32, ==, obj_q.i32);
728 g_assert_cmpint(eof, ==, QEMU_VM_EOF);
729
730 TestQtailqElement *qele_from = QTAILQ_FIRST(&obj_q.q);
731 TestQtailqElement *qlast_from = QTAILQ_LAST(&obj_q.q, TestQtailqHead);
732 TestQtailqElement *qele_to = QTAILQ_FIRST(&tgt.q);
733 TestQtailqElement *qlast_to = QTAILQ_LAST(&tgt.q, TestQtailqHead);
734
735 while (1) {
736 g_assert_cmpint(qele_to->b, ==, qele_from->b);
737 g_assert_cmpint(qele_to->u8, ==, qele_from->u8);
738 if ((qele_from == qlast_from) || (qele_to == qlast_to)) {
739 break;
740 }
741 qele_from = QTAILQ_NEXT(qele_from, next);
742 qele_to = QTAILQ_NEXT(qele_to, next);
743 }
744
745 g_assert_cmpint((uintptr_t) qele_from, ==, (uintptr_t) qlast_from);
746 g_assert_cmpint((uintptr_t) qele_to, ==, (uintptr_t) qlast_to);
747
748
749 TestQtailqElement *qele;
750 while (!QTAILQ_EMPTY(&tgt.q)) {
751 qele = QTAILQ_LAST(&tgt.q, TestQtailqHead);
752 QTAILQ_REMOVE(&tgt.q, qele, next);
753 free(qele);
754 qele = NULL;
755 }
756 qemu_fclose(fload);
757}
758
759typedef struct TmpTestStruct {
760 TestStruct *parent;
761 int64_t diff;
762} TmpTestStruct;
763
764static void tmp_child_pre_save(void *opaque)
765{
766 struct TmpTestStruct *tts = opaque;
767
768 tts->diff = tts->parent->b - tts->parent->a;
769}
770
771static int tmp_child_post_load(void *opaque, int version_id)
772{
773 struct TmpTestStruct *tts = opaque;
774
775 tts->parent->b = tts->parent->a + tts->diff;
776
777 return 0;
778}
779
780static const VMStateDescription vmstate_tmp_back_to_parent = {
781 .name = "test/tmp_child_parent",
782 .fields = (VMStateField[]) {
783 VMSTATE_UINT64(f, TestStruct),
784 VMSTATE_END_OF_LIST()
785 }
786};
787
788static const VMStateDescription vmstate_tmp_child = {
789 .name = "test/tmp_child",
790 .pre_save = tmp_child_pre_save,
791 .post_load = tmp_child_post_load,
792 .fields = (VMStateField[]) {
793 VMSTATE_INT64(diff, TmpTestStruct),
794 VMSTATE_STRUCT_POINTER(parent, TmpTestStruct,
795 vmstate_tmp_back_to_parent, TestStruct),
796 VMSTATE_END_OF_LIST()
797 }
798};
799
800static const VMStateDescription vmstate_with_tmp = {
801 .name = "test/with_tmp",
802 .version_id = 1,
803 .fields = (VMStateField[]) {
804 VMSTATE_UINT32(a, TestStruct),
805 VMSTATE_UINT64(d, TestStruct),
806 VMSTATE_WITH_TMP(TestStruct, TmpTestStruct, vmstate_tmp_child),
807 VMSTATE_END_OF_LIST()
808 }
809};
810
811static void obj_tmp_copy(void *target, void *source)
812{
813 memcpy(target, source, sizeof(TestStruct));
814}
815
816static void test_tmp_struct(void)
817{
818 TestStruct obj, obj_clone;
819
820 uint8_t const wire_with_tmp[] = {
821 0x00, 0x00, 0x00, 0x02,
822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
825 QEMU_VM_EOF,
826 };
827
828 memset(&obj, 0, sizeof(obj));
829 obj.a = 2;
830 obj.b = 4;
831 obj.d = 1;
832 obj.f = 8;
833 save_vmstate(&vmstate_with_tmp, &obj);
834
835 compare_vmstate(wire_with_tmp, sizeof(wire_with_tmp));
836
837 memset(&obj, 0, sizeof(obj));
838 SUCCESS(load_vmstate(&vmstate_with_tmp, &obj, &obj_clone,
839 obj_tmp_copy, 1, wire_with_tmp,
840 sizeof(wire_with_tmp)));
841 g_assert_cmpint(obj.a, ==, 2);
842 g_assert_cmpint(obj.b, ==, 4);
843 g_assert_cmpint(obj.d, ==, 1);
844 g_assert_cmpint(obj.f, ==, 8);
845}
846
847int main(int argc, char **argv)
848{
849 temp_fd = mkstemp(temp_file);
850
851 module_call_init(MODULE_INIT_QOM);
852
853 g_test_init(&argc, &argv, NULL);
854 g_test_add_func("/vmstate/simple/primitive", test_simple_primitive);
855 g_test_add_func("/vmstate/versioned/load/v1", test_load_v1);
856 g_test_add_func("/vmstate/versioned/load/v2", test_load_v2);
857 g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip);
858 g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip);
859 g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip);
860 g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip);
861 g_test_add_func("/vmstate/array/ptr/str/no0/save",
862 test_arr_ptr_str_no0_save);
863 g_test_add_func("/vmstate/array/ptr/str/no0/load",
864 test_arr_ptr_str_no0_load);
865 g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save);
866 g_test_add_func("/vmstate/array/ptr/str/0/load",
867 test_arr_ptr_str_0_load);
868 g_test_add_func("/vmstate/array/ptr/prim/0/save",
869 test_arr_ptr_prim_0_save);
870 g_test_add_func("/vmstate/array/ptr/prim/0/load",
871 test_arr_ptr_prim_0_load);
872 g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q);
873 g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q);
874 g_test_add_func("/vmstate/tmp_struct", test_tmp_struct);
875 g_test_run();
876
877 close(temp_fd);
878 unlink(temp_file);
879
880 return 0;
881}
882