12668b4bfSEduardo Habkost /* 22668b4bfSEduardo Habkost * Test code for VMState 32668b4bfSEduardo Habkost * 42668b4bfSEduardo Habkost * Copyright (c) 2013 Red Hat Inc. 52668b4bfSEduardo Habkost * 62668b4bfSEduardo Habkost * Permission is hereby granted, free of charge, to any person obtaining a copy 72668b4bfSEduardo Habkost * of this software and associated documentation files (the "Software"), to deal 82668b4bfSEduardo Habkost * in the Software without restriction, including without limitation the rights 92668b4bfSEduardo Habkost * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 102668b4bfSEduardo Habkost * copies of the Software, and to permit persons to whom the Software is 112668b4bfSEduardo Habkost * furnished to do so, subject to the following conditions: 122668b4bfSEduardo Habkost * 132668b4bfSEduardo Habkost * The above copyright notice and this permission notice shall be included in 142668b4bfSEduardo Habkost * all copies or substantial portions of the Software. 152668b4bfSEduardo Habkost * 162668b4bfSEduardo Habkost * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 172668b4bfSEduardo Habkost * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 182668b4bfSEduardo Habkost * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 192668b4bfSEduardo Habkost * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 202668b4bfSEduardo Habkost * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 212668b4bfSEduardo Habkost * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 222668b4bfSEduardo Habkost * THE SOFTWARE. 232668b4bfSEduardo Habkost */ 242668b4bfSEduardo Habkost 25681c28a3SPeter Maydell #include "qemu/osdep.h" 262668b4bfSEduardo Habkost 272668b4bfSEduardo Habkost #include "qemu-common.h" 282668b4bfSEduardo Habkost #include "migration/migration.h" 292668b4bfSEduardo Habkost #include "migration/vmstate.h" 3008a0aee1SJuan Quintela #include "migration/qemu-file-types.h" 3108a0aee1SJuan Quintela #include "../migration/qemu-file.h" 3240014d81SJuan Quintela #include "../migration/qemu-file-channel.h" 33*c3d2e2e7SJuan Quintela #include "../migration/savevm.h" 3410817bf0SDaniel P. Berrange #include "qemu/coroutine.h" 358925839fSDaniel P. Berrange #include "io/channel-file.h" 362668b4bfSEduardo Habkost 37748bfb4eSStefan Weil static char temp_file[] = "/tmp/vmst.test.XXXXXX"; 38748bfb4eSStefan Weil static int temp_fd; 392668b4bfSEduardo Habkost 409935bacaSDr. David Alan Gilbert 412668b4bfSEduardo Habkost /* Duplicate temp_fd and seek to the beginning of the file */ 42c6f6646cSJuan Quintela static QEMUFile *open_test_file(bool write) 432668b4bfSEduardo Habkost { 442668b4bfSEduardo Habkost int fd = dup(temp_fd); 458925839fSDaniel P. Berrange QIOChannel *ioc; 464ae3c0e2SMarc-André Lureau QEMUFile *f; 474ae3c0e2SMarc-André Lureau 482668b4bfSEduardo Habkost lseek(fd, 0, SEEK_SET); 49c6f6646cSJuan Quintela if (write) { 502668b4bfSEduardo Habkost g_assert_cmpint(ftruncate(fd, 0), ==, 0); 512668b4bfSEduardo Habkost } 528925839fSDaniel P. Berrange ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd)); 538925839fSDaniel P. Berrange if (write) { 544ae3c0e2SMarc-André Lureau f = qemu_fopen_channel_output(ioc); 558925839fSDaniel P. Berrange } else { 564ae3c0e2SMarc-André Lureau f = qemu_fopen_channel_input(ioc); 578925839fSDaniel P. Berrange } 584ae3c0e2SMarc-André Lureau object_unref(OBJECT(ioc)); 594ae3c0e2SMarc-André Lureau return f; 602668b4bfSEduardo Habkost } 612668b4bfSEduardo Habkost 624ea7df4eSJuan Quintela #define SUCCESS(val) \ 634ea7df4eSJuan Quintela g_assert_cmpint((val), ==, 0) 644ea7df4eSJuan Quintela 654ea7df4eSJuan Quintela #define FAILURE(val) \ 664ea7df4eSJuan Quintela g_assert_cmpint((val), !=, 0) 674ea7df4eSJuan Quintela 684ea7df4eSJuan Quintela static void save_vmstate(const VMStateDescription *desc, void *obj) 694ea7df4eSJuan Quintela { 704ea7df4eSJuan Quintela QEMUFile *f = open_test_file(true); 714ea7df4eSJuan Quintela 724ea7df4eSJuan Quintela /* Save file with vmstate */ 738118f095SAlexander Graf vmstate_save_state(f, desc, obj, NULL); 744ea7df4eSJuan Quintela qemu_put_byte(f, QEMU_VM_EOF); 754ea7df4eSJuan Quintela g_assert(!qemu_file_get_error(f)); 764ea7df4eSJuan Quintela qemu_fclose(f); 774ea7df4eSJuan Quintela } 784ea7df4eSJuan Quintela 796d57b4c0SHalil Pasic static void save_buffer(const uint8_t *buf, size_t buf_size) 806d57b4c0SHalil Pasic { 816d57b4c0SHalil Pasic QEMUFile *fsave = open_test_file(true); 826d57b4c0SHalil Pasic qemu_put_buffer(fsave, buf, buf_size); 836d57b4c0SHalil Pasic qemu_fclose(fsave); 846d57b4c0SHalil Pasic } 856d57b4c0SHalil Pasic 865c379d90SDr. David Alan Gilbert static void compare_vmstate(const uint8_t *wire, size_t size) 874ea7df4eSJuan Quintela { 884ea7df4eSJuan Quintela QEMUFile *f = open_test_file(false); 894ea7df4eSJuan Quintela uint8_t result[size]; 904ea7df4eSJuan Quintela 914ea7df4eSJuan Quintela /* read back as binary */ 924ea7df4eSJuan Quintela 934ea7df4eSJuan Quintela g_assert_cmpint(qemu_get_buffer(f, result, sizeof(result)), ==, 944ea7df4eSJuan Quintela sizeof(result)); 954ea7df4eSJuan Quintela g_assert(!qemu_file_get_error(f)); 964ea7df4eSJuan Quintela 974ea7df4eSJuan Quintela /* Compare that what is on the file is the same that what we 984ea7df4eSJuan Quintela expected to be there */ 994ea7df4eSJuan Quintela SUCCESS(memcmp(result, wire, sizeof(result))); 1004ea7df4eSJuan Quintela 1014ea7df4eSJuan Quintela /* Must reach EOF */ 1024ea7df4eSJuan Quintela qemu_get_byte(f); 1034ea7df4eSJuan Quintela g_assert_cmpint(qemu_file_get_error(f), ==, -EIO); 1044ea7df4eSJuan Quintela 1054ea7df4eSJuan Quintela qemu_fclose(f); 1064ea7df4eSJuan Quintela } 1074ea7df4eSJuan Quintela 1084ea7df4eSJuan Quintela static int load_vmstate_one(const VMStateDescription *desc, void *obj, 1095c379d90SDr. David Alan Gilbert int version, const uint8_t *wire, size_t size) 1104ea7df4eSJuan Quintela { 1114ea7df4eSJuan Quintela QEMUFile *f; 1124ea7df4eSJuan Quintela int ret; 1134ea7df4eSJuan Quintela 1144ea7df4eSJuan Quintela f = open_test_file(true); 1154ea7df4eSJuan Quintela qemu_put_buffer(f, wire, size); 1164ea7df4eSJuan Quintela qemu_fclose(f); 1174ea7df4eSJuan Quintela 1184ea7df4eSJuan Quintela f = open_test_file(false); 1194ea7df4eSJuan Quintela ret = vmstate_load_state(f, desc, obj, version); 1204ea7df4eSJuan Quintela if (ret) { 1214ea7df4eSJuan Quintela g_assert(qemu_file_get_error(f)); 1224ea7df4eSJuan Quintela } else{ 1234ea7df4eSJuan Quintela g_assert(!qemu_file_get_error(f)); 1244ea7df4eSJuan Quintela } 1254ea7df4eSJuan Quintela qemu_fclose(f); 1264ea7df4eSJuan Quintela return ret; 1274ea7df4eSJuan Quintela } 1284ea7df4eSJuan Quintela 1294ea7df4eSJuan Quintela 1304ea7df4eSJuan Quintela static int load_vmstate(const VMStateDescription *desc, 1314ea7df4eSJuan Quintela void *obj, void *obj_clone, 1324ea7df4eSJuan Quintela void (*obj_copy)(void *, void*), 1335c379d90SDr. David Alan Gilbert int version, const uint8_t *wire, size_t size) 1344ea7df4eSJuan Quintela { 1354ea7df4eSJuan Quintela /* We test with zero size */ 1364ea7df4eSJuan Quintela obj_copy(obj_clone, obj); 1374ea7df4eSJuan Quintela FAILURE(load_vmstate_one(desc, obj, version, wire, 0)); 1384ea7df4eSJuan Quintela 1394ea7df4eSJuan Quintela /* Stream ends with QEMU_EOF, so we need at least 3 bytes to be 1404ea7df4eSJuan Quintela * able to test in the middle */ 1414ea7df4eSJuan Quintela 1424ea7df4eSJuan Quintela if (size > 3) { 1434ea7df4eSJuan Quintela 1444ea7df4eSJuan Quintela /* We test with size - 2. We can't test size - 1 due to EOF tricks */ 1454ea7df4eSJuan Quintela obj_copy(obj, obj_clone); 1464ea7df4eSJuan Quintela FAILURE(load_vmstate_one(desc, obj, version, wire, size - 2)); 1474ea7df4eSJuan Quintela 1484ea7df4eSJuan Quintela /* Test with size/2, first half of real state */ 1494ea7df4eSJuan Quintela obj_copy(obj, obj_clone); 1504ea7df4eSJuan Quintela FAILURE(load_vmstate_one(desc, obj, version, wire, size/2)); 1514ea7df4eSJuan Quintela 1524ea7df4eSJuan Quintela /* Test with size/2, second half of real state */ 1534ea7df4eSJuan Quintela obj_copy(obj, obj_clone); 1544ea7df4eSJuan Quintela FAILURE(load_vmstate_one(desc, obj, version, wire + (size/2), size/2)); 1554ea7df4eSJuan Quintela 1564ea7df4eSJuan Quintela } 1574ea7df4eSJuan Quintela obj_copy(obj, obj_clone); 1584ea7df4eSJuan Quintela return load_vmstate_one(desc, obj, version, wire, size); 1594ea7df4eSJuan Quintela } 1604ea7df4eSJuan Quintela 1614ea7df4eSJuan Quintela /* Test struct that we are going to use for our tests */ 1624ea7df4eSJuan Quintela 1634ea7df4eSJuan Quintela typedef struct TestSimple { 1644ea7df4eSJuan Quintela bool b_1, b_2; 1654ea7df4eSJuan Quintela uint8_t u8_1; 1664ea7df4eSJuan Quintela uint16_t u16_1; 1674ea7df4eSJuan Quintela uint32_t u32_1; 1684ea7df4eSJuan Quintela uint64_t u64_1; 1694ea7df4eSJuan Quintela int8_t i8_1, i8_2; 1704ea7df4eSJuan Quintela int16_t i16_1, i16_2; 1714ea7df4eSJuan Quintela int32_t i32_1, i32_2; 1724ea7df4eSJuan Quintela int64_t i64_1, i64_2; 1734ea7df4eSJuan Quintela } TestSimple; 1744ea7df4eSJuan Quintela 1754ea7df4eSJuan Quintela /* Object instantiation, we are going to use it in more than one test */ 1764ea7df4eSJuan Quintela 1774ea7df4eSJuan Quintela TestSimple obj_simple = { 1784ea7df4eSJuan Quintela .b_1 = true, 1794ea7df4eSJuan Quintela .b_2 = false, 1804ea7df4eSJuan Quintela .u8_1 = 130, 1814ea7df4eSJuan Quintela .u16_1 = 512, 1824ea7df4eSJuan Quintela .u32_1 = 70000, 1834ea7df4eSJuan Quintela .u64_1 = 12121212, 1844ea7df4eSJuan Quintela .i8_1 = 65, 1854ea7df4eSJuan Quintela .i8_2 = -65, 1864ea7df4eSJuan Quintela .i16_1 = 512, 1874ea7df4eSJuan Quintela .i16_2 = -512, 1884ea7df4eSJuan Quintela .i32_1 = 70000, 1894ea7df4eSJuan Quintela .i32_2 = -70000, 1904ea7df4eSJuan Quintela .i64_1 = 12121212, 1914ea7df4eSJuan Quintela .i64_2 = -12121212, 1924ea7df4eSJuan Quintela }; 1934ea7df4eSJuan Quintela 1944ea7df4eSJuan Quintela /* Description of the values. If you add a primitive type 1954ea7df4eSJuan Quintela you are expected to add a test here */ 1964ea7df4eSJuan Quintela 1974ea7df4eSJuan Quintela static const VMStateDescription vmstate_simple_primitive = { 1984ea7df4eSJuan Quintela .name = "simple/primitive", 1994ea7df4eSJuan Quintela .version_id = 1, 2004ea7df4eSJuan Quintela .minimum_version_id = 1, 2014ea7df4eSJuan Quintela .fields = (VMStateField[]) { 2024ea7df4eSJuan Quintela VMSTATE_BOOL(b_1, TestSimple), 2034ea7df4eSJuan Quintela VMSTATE_BOOL(b_2, TestSimple), 2044ea7df4eSJuan Quintela VMSTATE_UINT8(u8_1, TestSimple), 2054ea7df4eSJuan Quintela VMSTATE_UINT16(u16_1, TestSimple), 2064ea7df4eSJuan Quintela VMSTATE_UINT32(u32_1, TestSimple), 2074ea7df4eSJuan Quintela VMSTATE_UINT64(u64_1, TestSimple), 2084ea7df4eSJuan Quintela VMSTATE_INT8(i8_1, TestSimple), 2094ea7df4eSJuan Quintela VMSTATE_INT8(i8_2, TestSimple), 2104ea7df4eSJuan Quintela VMSTATE_INT16(i16_1, TestSimple), 2114ea7df4eSJuan Quintela VMSTATE_INT16(i16_2, TestSimple), 2124ea7df4eSJuan Quintela VMSTATE_INT32(i32_1, TestSimple), 2134ea7df4eSJuan Quintela VMSTATE_INT32(i32_2, TestSimple), 2144ea7df4eSJuan Quintela VMSTATE_INT64(i64_1, TestSimple), 2154ea7df4eSJuan Quintela VMSTATE_INT64(i64_2, TestSimple), 2164ea7df4eSJuan Quintela VMSTATE_END_OF_LIST() 2174ea7df4eSJuan Quintela } 2184ea7df4eSJuan Quintela }; 2194ea7df4eSJuan Quintela 2204ea7df4eSJuan Quintela /* It describes what goes through the wire. Our tests are basically: 2214ea7df4eSJuan Quintela 2224ea7df4eSJuan Quintela * save test 2234ea7df4eSJuan Quintela - save a struct a vmstate to a file 2244ea7df4eSJuan Quintela - read that file back (binary read, no vmstate) 2254ea7df4eSJuan Quintela - compare it with what we expect to be on the wire 2264ea7df4eSJuan Quintela * load test 2274ea7df4eSJuan Quintela - save to the file what we expect to be on the wire 2284ea7df4eSJuan Quintela - read struct back with vmstate in a different 2294ea7df4eSJuan Quintela - compare back with the original struct 2304ea7df4eSJuan Quintela */ 2314ea7df4eSJuan Quintela 2324ea7df4eSJuan Quintela uint8_t wire_simple_primitive[] = { 2334ea7df4eSJuan Quintela /* b_1 */ 0x01, 2344ea7df4eSJuan Quintela /* b_2 */ 0x00, 2354ea7df4eSJuan Quintela /* u8_1 */ 0x82, 2364ea7df4eSJuan Quintela /* u16_1 */ 0x02, 0x00, 2374ea7df4eSJuan Quintela /* u32_1 */ 0x00, 0x01, 0x11, 0x70, 2384ea7df4eSJuan Quintela /* u64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c, 2394ea7df4eSJuan Quintela /* i8_1 */ 0x41, 2404ea7df4eSJuan Quintela /* i8_2 */ 0xbf, 2414ea7df4eSJuan Quintela /* i16_1 */ 0x02, 0x00, 2424ea7df4eSJuan Quintela /* i16_2 */ 0xfe, 0x0, 2434ea7df4eSJuan Quintela /* i32_1 */ 0x00, 0x01, 0x11, 0x70, 2444ea7df4eSJuan Quintela /* i32_2 */ 0xff, 0xfe, 0xee, 0x90, 2454ea7df4eSJuan Quintela /* i64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c, 2464ea7df4eSJuan Quintela /* i64_2 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x0b, 0x84, 2474ea7df4eSJuan Quintela QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 2484ea7df4eSJuan Quintela }; 2494ea7df4eSJuan Quintela 2504ea7df4eSJuan Quintela static void obj_simple_copy(void *target, void *source) 2514ea7df4eSJuan Quintela { 2524ea7df4eSJuan Quintela memcpy(target, source, sizeof(TestSimple)); 2534ea7df4eSJuan Quintela } 2544ea7df4eSJuan Quintela 2554ea7df4eSJuan Quintela static void test_simple_primitive(void) 2564ea7df4eSJuan Quintela { 2574ea7df4eSJuan Quintela TestSimple obj, obj_clone; 2584ea7df4eSJuan Quintela 2594ea7df4eSJuan Quintela memset(&obj, 0, sizeof(obj)); 2604ea7df4eSJuan Quintela save_vmstate(&vmstate_simple_primitive, &obj_simple); 2614ea7df4eSJuan Quintela 2624ea7df4eSJuan Quintela compare_vmstate(wire_simple_primitive, sizeof(wire_simple_primitive)); 2634ea7df4eSJuan Quintela 2644ea7df4eSJuan Quintela SUCCESS(load_vmstate(&vmstate_simple_primitive, &obj, &obj_clone, 2654ea7df4eSJuan Quintela obj_simple_copy, 1, wire_simple_primitive, 2664ea7df4eSJuan Quintela sizeof(wire_simple_primitive))); 2674ea7df4eSJuan Quintela 2684ea7df4eSJuan Quintela #define FIELD_EQUAL(name) g_assert_cmpint(obj.name, ==, obj_simple.name) 2694ea7df4eSJuan Quintela 2704ea7df4eSJuan Quintela FIELD_EQUAL(b_1); 2714ea7df4eSJuan Quintela FIELD_EQUAL(b_2); 2724ea7df4eSJuan Quintela FIELD_EQUAL(u8_1); 2734ea7df4eSJuan Quintela FIELD_EQUAL(u16_1); 2744ea7df4eSJuan Quintela FIELD_EQUAL(u32_1); 2754ea7df4eSJuan Quintela FIELD_EQUAL(u64_1); 2764ea7df4eSJuan Quintela FIELD_EQUAL(i8_1); 2774ea7df4eSJuan Quintela FIELD_EQUAL(i8_2); 2784ea7df4eSJuan Quintela FIELD_EQUAL(i16_1); 2794ea7df4eSJuan Quintela FIELD_EQUAL(i16_2); 2804ea7df4eSJuan Quintela FIELD_EQUAL(i32_1); 2814ea7df4eSJuan Quintela FIELD_EQUAL(i32_2); 2824ea7df4eSJuan Quintela FIELD_EQUAL(i64_1); 2834ea7df4eSJuan Quintela FIELD_EQUAL(i64_2); 2844ea7df4eSJuan Quintela } 2854ea7df4eSJuan Quintela 2864ea7df4eSJuan Quintela typedef struct TestStruct { 2872668b4bfSEduardo Habkost uint32_t a, b, c, e; 2882668b4bfSEduardo Habkost uint64_t d, f; 2892668b4bfSEduardo Habkost bool skip_c_e; 2902668b4bfSEduardo Habkost } TestStruct; 2912668b4bfSEduardo Habkost 2922668b4bfSEduardo Habkost static const VMStateDescription vmstate_versioned = { 2934ea7df4eSJuan Quintela .name = "test/versioned", 2942668b4bfSEduardo Habkost .version_id = 2, 2952668b4bfSEduardo Habkost .minimum_version_id = 1, 2962668b4bfSEduardo Habkost .fields = (VMStateField[]) { 2972668b4bfSEduardo Habkost VMSTATE_UINT32(a, TestStruct), 2982668b4bfSEduardo Habkost VMSTATE_UINT32_V(b, TestStruct, 2), /* Versioned field in the middle, so 2992668b4bfSEduardo Habkost * we catch bugs more easily. 3002668b4bfSEduardo Habkost */ 3012668b4bfSEduardo Habkost VMSTATE_UINT32(c, TestStruct), 3022668b4bfSEduardo Habkost VMSTATE_UINT64(d, TestStruct), 3032668b4bfSEduardo Habkost VMSTATE_UINT32_V(e, TestStruct, 2), 3042668b4bfSEduardo Habkost VMSTATE_UINT64_V(f, TestStruct, 2), 3052668b4bfSEduardo Habkost VMSTATE_END_OF_LIST() 3062668b4bfSEduardo Habkost } 3072668b4bfSEduardo Habkost }; 3082668b4bfSEduardo Habkost 3092668b4bfSEduardo Habkost static void test_load_v1(void) 3102668b4bfSEduardo Habkost { 3112668b4bfSEduardo Habkost uint8_t buf[] = { 3122668b4bfSEduardo Habkost 0, 0, 0, 10, /* a */ 3132668b4bfSEduardo Habkost 0, 0, 0, 30, /* c */ 3142668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 40, /* d */ 3152668b4bfSEduardo Habkost QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 3162668b4bfSEduardo Habkost }; 3176d57b4c0SHalil Pasic save_buffer(buf, sizeof(buf)); 3182668b4bfSEduardo Habkost 319c6f6646cSJuan Quintela QEMUFile *loading = open_test_file(false); 3202668b4bfSEduardo Habkost TestStruct obj = { .b = 200, .e = 500, .f = 600 }; 3212668b4bfSEduardo Habkost vmstate_load_state(loading, &vmstate_versioned, &obj, 1); 3222668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(loading)); 3232668b4bfSEduardo Habkost g_assert_cmpint(obj.a, ==, 10); 3242668b4bfSEduardo Habkost g_assert_cmpint(obj.b, ==, 200); 3252668b4bfSEduardo Habkost g_assert_cmpint(obj.c, ==, 30); 3262668b4bfSEduardo Habkost g_assert_cmpint(obj.d, ==, 40); 3272668b4bfSEduardo Habkost g_assert_cmpint(obj.e, ==, 500); 3282668b4bfSEduardo Habkost g_assert_cmpint(obj.f, ==, 600); 3292668b4bfSEduardo Habkost qemu_fclose(loading); 3302668b4bfSEduardo Habkost } 3312668b4bfSEduardo Habkost 3322668b4bfSEduardo Habkost static void test_load_v2(void) 3332668b4bfSEduardo Habkost { 3342668b4bfSEduardo Habkost uint8_t buf[] = { 3352668b4bfSEduardo Habkost 0, 0, 0, 10, /* a */ 3362668b4bfSEduardo Habkost 0, 0, 0, 20, /* b */ 3372668b4bfSEduardo Habkost 0, 0, 0, 30, /* c */ 3382668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 40, /* d */ 3392668b4bfSEduardo Habkost 0, 0, 0, 50, /* e */ 3402668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 60, /* f */ 3412668b4bfSEduardo Habkost QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 3422668b4bfSEduardo Habkost }; 3436d57b4c0SHalil Pasic save_buffer(buf, sizeof(buf)); 3442668b4bfSEduardo Habkost 345c6f6646cSJuan Quintela QEMUFile *loading = open_test_file(false); 3462668b4bfSEduardo Habkost TestStruct obj; 3472668b4bfSEduardo Habkost vmstate_load_state(loading, &vmstate_versioned, &obj, 2); 3482668b4bfSEduardo Habkost g_assert_cmpint(obj.a, ==, 10); 3492668b4bfSEduardo Habkost g_assert_cmpint(obj.b, ==, 20); 3502668b4bfSEduardo Habkost g_assert_cmpint(obj.c, ==, 30); 3512668b4bfSEduardo Habkost g_assert_cmpint(obj.d, ==, 40); 3522668b4bfSEduardo Habkost g_assert_cmpint(obj.e, ==, 50); 3532668b4bfSEduardo Habkost g_assert_cmpint(obj.f, ==, 60); 3542668b4bfSEduardo Habkost qemu_fclose(loading); 3552668b4bfSEduardo Habkost } 3562668b4bfSEduardo Habkost 3572668b4bfSEduardo Habkost static bool test_skip(void *opaque, int version_id) 3582668b4bfSEduardo Habkost { 3592668b4bfSEduardo Habkost TestStruct *t = (TestStruct *)opaque; 3602668b4bfSEduardo Habkost return !t->skip_c_e; 3612668b4bfSEduardo Habkost } 3622668b4bfSEduardo Habkost 3632668b4bfSEduardo Habkost static const VMStateDescription vmstate_skipping = { 3644ea7df4eSJuan Quintela .name = "test/skip", 3652668b4bfSEduardo Habkost .version_id = 2, 3662668b4bfSEduardo Habkost .minimum_version_id = 1, 3672668b4bfSEduardo Habkost .fields = (VMStateField[]) { 3682668b4bfSEduardo Habkost VMSTATE_UINT32(a, TestStruct), 3692668b4bfSEduardo Habkost VMSTATE_UINT32(b, TestStruct), 3702668b4bfSEduardo Habkost VMSTATE_UINT32_TEST(c, TestStruct, test_skip), 3712668b4bfSEduardo Habkost VMSTATE_UINT64(d, TestStruct), 3722668b4bfSEduardo Habkost VMSTATE_UINT32_TEST(e, TestStruct, test_skip), 3732668b4bfSEduardo Habkost VMSTATE_UINT64_V(f, TestStruct, 2), 3742668b4bfSEduardo Habkost VMSTATE_END_OF_LIST() 3752668b4bfSEduardo Habkost } 3762668b4bfSEduardo Habkost }; 3772668b4bfSEduardo Habkost 3782668b4bfSEduardo Habkost 3792668b4bfSEduardo Habkost static void test_save_noskip(void) 3802668b4bfSEduardo Habkost { 381a8ec4437SDaniel P. Berrange QEMUFile *fsave = open_test_file(true); 3822668b4bfSEduardo Habkost TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, 3832668b4bfSEduardo Habkost .skip_c_e = false }; 3848118f095SAlexander Graf vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL); 3852668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(fsave)); 3862668b4bfSEduardo Habkost 3872668b4bfSEduardo Habkost uint8_t expected[] = { 3882668b4bfSEduardo Habkost 0, 0, 0, 1, /* a */ 3892668b4bfSEduardo Habkost 0, 0, 0, 2, /* b */ 3902668b4bfSEduardo Habkost 0, 0, 0, 3, /* c */ 3912668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 4, /* d */ 3922668b4bfSEduardo Habkost 0, 0, 0, 5, /* e */ 3932668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 6, /* f */ 3942668b4bfSEduardo Habkost }; 395a8ec4437SDaniel P. Berrange 3969935bacaSDr. David Alan Gilbert qemu_fclose(fsave); 397a8ec4437SDaniel P. Berrange compare_vmstate(expected, sizeof(expected)); 3982668b4bfSEduardo Habkost } 3992668b4bfSEduardo Habkost 4002668b4bfSEduardo Habkost static void test_save_skip(void) 4012668b4bfSEduardo Habkost { 402a8ec4437SDaniel P. Berrange QEMUFile *fsave = open_test_file(true); 4032668b4bfSEduardo Habkost TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, 4042668b4bfSEduardo Habkost .skip_c_e = true }; 4058118f095SAlexander Graf vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL); 4062668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(fsave)); 4072668b4bfSEduardo Habkost 4082668b4bfSEduardo Habkost uint8_t expected[] = { 4092668b4bfSEduardo Habkost 0, 0, 0, 1, /* a */ 4102668b4bfSEduardo Habkost 0, 0, 0, 2, /* b */ 4112668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 4, /* d */ 4122668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 6, /* f */ 4132668b4bfSEduardo Habkost }; 4142668b4bfSEduardo Habkost 4159935bacaSDr. David Alan Gilbert qemu_fclose(fsave); 416a8ec4437SDaniel P. Berrange compare_vmstate(expected, sizeof(expected)); 4172668b4bfSEduardo Habkost } 4182668b4bfSEduardo Habkost 4192668b4bfSEduardo Habkost static void test_load_noskip(void) 4202668b4bfSEduardo Habkost { 4212668b4bfSEduardo Habkost uint8_t buf[] = { 4222668b4bfSEduardo Habkost 0, 0, 0, 10, /* a */ 4232668b4bfSEduardo Habkost 0, 0, 0, 20, /* b */ 4242668b4bfSEduardo Habkost 0, 0, 0, 30, /* c */ 4252668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 40, /* d */ 4262668b4bfSEduardo Habkost 0, 0, 0, 50, /* e */ 4272668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 60, /* f */ 4282668b4bfSEduardo Habkost QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 4292668b4bfSEduardo Habkost }; 4306d57b4c0SHalil Pasic save_buffer(buf, sizeof(buf)); 4312668b4bfSEduardo Habkost 432a8ec4437SDaniel P. Berrange QEMUFile *loading = open_test_file(false); 4332668b4bfSEduardo Habkost TestStruct obj = { .skip_c_e = false }; 4342668b4bfSEduardo Habkost vmstate_load_state(loading, &vmstate_skipping, &obj, 2); 4352668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(loading)); 4362668b4bfSEduardo Habkost g_assert_cmpint(obj.a, ==, 10); 4372668b4bfSEduardo Habkost g_assert_cmpint(obj.b, ==, 20); 4382668b4bfSEduardo Habkost g_assert_cmpint(obj.c, ==, 30); 4392668b4bfSEduardo Habkost g_assert_cmpint(obj.d, ==, 40); 4402668b4bfSEduardo Habkost g_assert_cmpint(obj.e, ==, 50); 4412668b4bfSEduardo Habkost g_assert_cmpint(obj.f, ==, 60); 4422668b4bfSEduardo Habkost qemu_fclose(loading); 4432668b4bfSEduardo Habkost } 4442668b4bfSEduardo Habkost 4452668b4bfSEduardo Habkost static void test_load_skip(void) 4462668b4bfSEduardo Habkost { 4472668b4bfSEduardo Habkost uint8_t buf[] = { 4482668b4bfSEduardo Habkost 0, 0, 0, 10, /* a */ 4492668b4bfSEduardo Habkost 0, 0, 0, 20, /* b */ 4502668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 40, /* d */ 4512668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 60, /* f */ 4522668b4bfSEduardo Habkost QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 4532668b4bfSEduardo Habkost }; 4546d57b4c0SHalil Pasic save_buffer(buf, sizeof(buf)); 4552668b4bfSEduardo Habkost 456a8ec4437SDaniel P. Berrange QEMUFile *loading = open_test_file(false); 4572668b4bfSEduardo Habkost TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 }; 4582668b4bfSEduardo Habkost vmstate_load_state(loading, &vmstate_skipping, &obj, 2); 4592668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(loading)); 4602668b4bfSEduardo Habkost g_assert_cmpint(obj.a, ==, 10); 4612668b4bfSEduardo Habkost g_assert_cmpint(obj.b, ==, 20); 4622668b4bfSEduardo Habkost g_assert_cmpint(obj.c, ==, 300); 4632668b4bfSEduardo Habkost g_assert_cmpint(obj.d, ==, 40); 4642668b4bfSEduardo Habkost g_assert_cmpint(obj.e, ==, 500); 4652668b4bfSEduardo Habkost g_assert_cmpint(obj.f, ==, 60); 4662668b4bfSEduardo Habkost qemu_fclose(loading); 4672668b4bfSEduardo Habkost } 4682668b4bfSEduardo Habkost 4698cc49f03SHalil Pasic typedef struct { 4708cc49f03SHalil Pasic int32_t i; 4718cc49f03SHalil Pasic } TestStructTriv; 4728cc49f03SHalil Pasic 4738cc49f03SHalil Pasic const VMStateDescription vmsd_tst = { 4748cc49f03SHalil Pasic .name = "test/tst", 4758cc49f03SHalil Pasic .version_id = 1, 4768cc49f03SHalil Pasic .minimum_version_id = 1, 4778cc49f03SHalil Pasic .fields = (VMStateField[]) { 4788cc49f03SHalil Pasic VMSTATE_INT32(i, TestStructTriv), 4798cc49f03SHalil Pasic VMSTATE_END_OF_LIST() 4808cc49f03SHalil Pasic } 4818cc49f03SHalil Pasic }; 4828cc49f03SHalil Pasic 483cc958831SHalil Pasic /* test array migration */ 484cc958831SHalil Pasic 4858cc49f03SHalil Pasic #define AR_SIZE 4 4868cc49f03SHalil Pasic 4878cc49f03SHalil Pasic typedef struct { 4888cc49f03SHalil Pasic TestStructTriv *ar[AR_SIZE]; 4898cc49f03SHalil Pasic } TestArrayOfPtrToStuct; 4908cc49f03SHalil Pasic 4918cc49f03SHalil Pasic const VMStateDescription vmsd_arps = { 4928cc49f03SHalil Pasic .name = "test/arps", 4938cc49f03SHalil Pasic .version_id = 1, 4948cc49f03SHalil Pasic .minimum_version_id = 1, 4958cc49f03SHalil Pasic .fields = (VMStateField[]) { 4968cc49f03SHalil Pasic VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(ar, TestArrayOfPtrToStuct, 4978cc49f03SHalil Pasic AR_SIZE, 0, vmsd_tst, TestStructTriv), 4988cc49f03SHalil Pasic VMSTATE_END_OF_LIST() 4998cc49f03SHalil Pasic } 5008cc49f03SHalil Pasic }; 501cc958831SHalil Pasic 502cc958831SHalil Pasic static uint8_t wire_arr_ptr_no0[] = { 5038cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x00, 5048cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x01, 5058cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x02, 5068cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x03, 5078cc49f03SHalil Pasic QEMU_VM_EOF 5088cc49f03SHalil Pasic }; 5098cc49f03SHalil Pasic 510cc958831SHalil Pasic static void test_arr_ptr_str_no0_save(void) 511cc958831SHalil Pasic { 512cc958831SHalil Pasic TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} }; 513cc958831SHalil Pasic TestArrayOfPtrToStuct sample = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} }; 514cc958831SHalil Pasic 5158cc49f03SHalil Pasic save_vmstate(&vmsd_arps, &sample); 516cc958831SHalil Pasic compare_vmstate(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0)); 5178cc49f03SHalil Pasic } 5188cc49f03SHalil Pasic 5198cc49f03SHalil Pasic static void test_arr_ptr_str_no0_load(void) 5208cc49f03SHalil Pasic { 5218cc49f03SHalil Pasic TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} }; 5228cc49f03SHalil Pasic TestStructTriv ar[AR_SIZE] = {}; 5238cc49f03SHalil Pasic TestArrayOfPtrToStuct obj = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} }; 5248cc49f03SHalil Pasic int idx; 525cc958831SHalil Pasic 526cc958831SHalil Pasic save_buffer(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0)); 527cc958831SHalil Pasic SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1, 528cc958831SHalil Pasic wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0))); 529cc958831SHalil Pasic for (idx = 0; idx < AR_SIZE; ++idx) { 530cc958831SHalil Pasic /* compare the target array ar with the ground truth array ar_gt */ 531cc958831SHalil Pasic g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i); 532cc958831SHalil Pasic } 533cc958831SHalil Pasic } 534cc958831SHalil Pasic 535cc958831SHalil Pasic static uint8_t wire_arr_ptr_0[] = { 5368cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x00, 537cc958831SHalil Pasic VMS_NULLPTR_MARKER, 5388cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x02, 5398cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x03, 5408cc49f03SHalil Pasic QEMU_VM_EOF 5418cc49f03SHalil Pasic }; 5428cc49f03SHalil Pasic 543cc958831SHalil Pasic static void test_arr_ptr_str_0_save(void) 544cc958831SHalil Pasic { 545cc958831SHalil Pasic TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} }; 546cc958831SHalil Pasic TestArrayOfPtrToStuct sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} }; 547cc958831SHalil Pasic 548cc958831SHalil Pasic save_vmstate(&vmsd_arps, &sample); 549cc958831SHalil Pasic compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0)); 550cc958831SHalil Pasic } 551cc958831SHalil Pasic 552cc958831SHalil Pasic static void test_arr_ptr_str_0_load(void) 553cc958831SHalil Pasic { 554cc958831SHalil Pasic TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 0}, {.i = 2}, {.i = 3} }; 555cc958831SHalil Pasic TestStructTriv ar[AR_SIZE] = {}; 556cc958831SHalil Pasic TestArrayOfPtrToStuct obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} }; 557cc958831SHalil Pasic int idx; 558cc958831SHalil Pasic 559cc958831SHalil Pasic save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0)); 5608cc49f03SHalil Pasic SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1, 561cc958831SHalil Pasic wire_arr_ptr_0, sizeof(wire_arr_ptr_0))); 5628cc49f03SHalil Pasic for (idx = 0; idx < AR_SIZE; ++idx) { 5638cc49f03SHalil Pasic /* compare the target array ar with the ground truth array ar_gt */ 5648cc49f03SHalil Pasic g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i); 5658cc49f03SHalil Pasic } 566cc958831SHalil Pasic for (idx = 0; idx < AR_SIZE; ++idx) { 567cc958831SHalil Pasic if (idx == 1) { 568cc958831SHalil Pasic g_assert_cmpint((uintptr_t)(obj.ar[idx]), ==, 0); 569cc958831SHalil Pasic } else { 570cc958831SHalil Pasic g_assert_cmpint((uintptr_t)(obj.ar[idx]), !=, 0); 571cc958831SHalil Pasic } 572cc958831SHalil Pasic } 5738cc49f03SHalil Pasic } 5748cc49f03SHalil Pasic 57543333099SHalil Pasic typedef struct TestArrayOfPtrToInt { 57643333099SHalil Pasic int32_t *ar[AR_SIZE]; 57743333099SHalil Pasic } TestArrayOfPtrToInt; 57843333099SHalil Pasic 57943333099SHalil Pasic const VMStateDescription vmsd_arpp = { 58043333099SHalil Pasic .name = "test/arps", 58143333099SHalil Pasic .version_id = 1, 58243333099SHalil Pasic .minimum_version_id = 1, 58343333099SHalil Pasic .fields = (VMStateField[]) { 58443333099SHalil Pasic VMSTATE_ARRAY_OF_POINTER(ar, TestArrayOfPtrToInt, 58543333099SHalil Pasic AR_SIZE, 0, vmstate_info_int32, int32_t*), 58643333099SHalil Pasic VMSTATE_END_OF_LIST() 58743333099SHalil Pasic } 58843333099SHalil Pasic }; 58943333099SHalil Pasic 59043333099SHalil Pasic static void test_arr_ptr_prim_0_save(void) 59143333099SHalil Pasic { 59243333099SHalil Pasic int32_t ar[AR_SIZE] = {0 , 1, 2, 3}; 59343333099SHalil Pasic TestArrayOfPtrToInt sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} }; 59443333099SHalil Pasic 59543333099SHalil Pasic save_vmstate(&vmsd_arpp, &sample); 59643333099SHalil Pasic compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0)); 59743333099SHalil Pasic } 59843333099SHalil Pasic 59943333099SHalil Pasic static void test_arr_ptr_prim_0_load(void) 60043333099SHalil Pasic { 60143333099SHalil Pasic int32_t ar_gt[AR_SIZE] = {0, 1, 2, 3}; 60243333099SHalil Pasic int32_t ar[AR_SIZE] = {3 , 42, 1, 0}; 60343333099SHalil Pasic TestArrayOfPtrToInt obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} }; 60443333099SHalil Pasic int idx; 60543333099SHalil Pasic 60643333099SHalil Pasic save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0)); 60743333099SHalil Pasic SUCCESS(load_vmstate_one(&vmsd_arpp, &obj, 1, 60843333099SHalil Pasic wire_arr_ptr_0, sizeof(wire_arr_ptr_0))); 60943333099SHalil Pasic for (idx = 0; idx < AR_SIZE; ++idx) { 61043333099SHalil Pasic /* compare the target array ar with the ground truth array ar_gt */ 61143333099SHalil Pasic if (idx == 1) { 61243333099SHalil Pasic g_assert_cmpint(42, ==, ar[idx]); 61343333099SHalil Pasic } else { 61443333099SHalil Pasic g_assert_cmpint(ar_gt[idx], ==, ar[idx]); 61543333099SHalil Pasic } 61643333099SHalil Pasic } 61743333099SHalil Pasic } 61843333099SHalil Pasic 6197e99f22cSJianjun Duan /* test QTAILQ migration */ 6207e99f22cSJianjun Duan typedef struct TestQtailqElement TestQtailqElement; 6217e99f22cSJianjun Duan 6227e99f22cSJianjun Duan struct TestQtailqElement { 6237e99f22cSJianjun Duan bool b; 6247e99f22cSJianjun Duan uint8_t u8; 6257e99f22cSJianjun Duan QTAILQ_ENTRY(TestQtailqElement) next; 6267e99f22cSJianjun Duan }; 6277e99f22cSJianjun Duan 6287e99f22cSJianjun Duan typedef struct TestQtailq { 6297e99f22cSJianjun Duan int16_t i16; 6307e99f22cSJianjun Duan QTAILQ_HEAD(TestQtailqHead, TestQtailqElement) q; 6317e99f22cSJianjun Duan int32_t i32; 6327e99f22cSJianjun Duan } TestQtailq; 6337e99f22cSJianjun Duan 6347e99f22cSJianjun Duan static const VMStateDescription vmstate_q_element = { 6357e99f22cSJianjun Duan .name = "test/queue-element", 6367e99f22cSJianjun Duan .version_id = 1, 6377e99f22cSJianjun Duan .minimum_version_id = 1, 6387e99f22cSJianjun Duan .fields = (VMStateField[]) { 6397e99f22cSJianjun Duan VMSTATE_BOOL(b, TestQtailqElement), 6407e99f22cSJianjun Duan VMSTATE_UINT8(u8, TestQtailqElement), 6417e99f22cSJianjun Duan VMSTATE_END_OF_LIST() 6427e99f22cSJianjun Duan }, 6437e99f22cSJianjun Duan }; 6447e99f22cSJianjun Duan 6457e99f22cSJianjun Duan static const VMStateDescription vmstate_q = { 6467e99f22cSJianjun Duan .name = "test/queue", 6477e99f22cSJianjun Duan .version_id = 1, 6487e99f22cSJianjun Duan .minimum_version_id = 1, 6497e99f22cSJianjun Duan .fields = (VMStateField[]) { 6507e99f22cSJianjun Duan VMSTATE_INT16(i16, TestQtailq), 6517e99f22cSJianjun Duan VMSTATE_QTAILQ_V(q, TestQtailq, 1, vmstate_q_element, TestQtailqElement, 6527e99f22cSJianjun Duan next), 6537e99f22cSJianjun Duan VMSTATE_INT32(i32, TestQtailq), 6547e99f22cSJianjun Duan VMSTATE_END_OF_LIST() 6557e99f22cSJianjun Duan } 6567e99f22cSJianjun Duan }; 6577e99f22cSJianjun Duan 6587e99f22cSJianjun Duan uint8_t wire_q[] = { 6597e99f22cSJianjun Duan /* i16 */ 0xfe, 0x0, 6607e99f22cSJianjun Duan /* start of element 0 of q */ 0x01, 6617e99f22cSJianjun Duan /* .b */ 0x01, 6627e99f22cSJianjun Duan /* .u8 */ 0x82, 6637e99f22cSJianjun Duan /* start of element 1 of q */ 0x01, 6647e99f22cSJianjun Duan /* b */ 0x00, 6657e99f22cSJianjun Duan /* u8 */ 0x41, 6667e99f22cSJianjun Duan /* end of q */ 0x00, 6677e99f22cSJianjun Duan /* i32 */ 0x00, 0x01, 0x11, 0x70, 6687e99f22cSJianjun Duan QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 6697e99f22cSJianjun Duan }; 6707e99f22cSJianjun Duan 6717e99f22cSJianjun Duan static void test_save_q(void) 6727e99f22cSJianjun Duan { 6737e99f22cSJianjun Duan TestQtailq obj_q = { 6747e99f22cSJianjun Duan .i16 = -512, 6757e99f22cSJianjun Duan .i32 = 70000, 6767e99f22cSJianjun Duan }; 6777e99f22cSJianjun Duan 6787e99f22cSJianjun Duan TestQtailqElement obj_qe1 = { 6797e99f22cSJianjun Duan .b = true, 6807e99f22cSJianjun Duan .u8 = 130, 6817e99f22cSJianjun Duan }; 6827e99f22cSJianjun Duan 6837e99f22cSJianjun Duan TestQtailqElement obj_qe2 = { 6847e99f22cSJianjun Duan .b = false, 6857e99f22cSJianjun Duan .u8 = 65, 6867e99f22cSJianjun Duan }; 6877e99f22cSJianjun Duan 6887e99f22cSJianjun Duan QTAILQ_INIT(&obj_q.q); 6897e99f22cSJianjun Duan QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next); 6907e99f22cSJianjun Duan QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next); 6917e99f22cSJianjun Duan 6927e99f22cSJianjun Duan save_vmstate(&vmstate_q, &obj_q); 6937e99f22cSJianjun Duan compare_vmstate(wire_q, sizeof(wire_q)); 6947e99f22cSJianjun Duan } 6957e99f22cSJianjun Duan 6967e99f22cSJianjun Duan static void test_load_q(void) 6977e99f22cSJianjun Duan { 6987e99f22cSJianjun Duan TestQtailq obj_q = { 6997e99f22cSJianjun Duan .i16 = -512, 7007e99f22cSJianjun Duan .i32 = 70000, 7017e99f22cSJianjun Duan }; 7027e99f22cSJianjun Duan 7037e99f22cSJianjun Duan TestQtailqElement obj_qe1 = { 7047e99f22cSJianjun Duan .b = true, 7057e99f22cSJianjun Duan .u8 = 130, 7067e99f22cSJianjun Duan }; 7077e99f22cSJianjun Duan 7087e99f22cSJianjun Duan TestQtailqElement obj_qe2 = { 7097e99f22cSJianjun Duan .b = false, 7107e99f22cSJianjun Duan .u8 = 65, 7117e99f22cSJianjun Duan }; 7127e99f22cSJianjun Duan 7137e99f22cSJianjun Duan QTAILQ_INIT(&obj_q.q); 7147e99f22cSJianjun Duan QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next); 7157e99f22cSJianjun Duan QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next); 7167e99f22cSJianjun Duan 7177e99f22cSJianjun Duan QEMUFile *fsave = open_test_file(true); 7187e99f22cSJianjun Duan 7197e99f22cSJianjun Duan qemu_put_buffer(fsave, wire_q, sizeof(wire_q)); 7207e99f22cSJianjun Duan g_assert(!qemu_file_get_error(fsave)); 7217e99f22cSJianjun Duan qemu_fclose(fsave); 7227e99f22cSJianjun Duan 7237e99f22cSJianjun Duan QEMUFile *fload = open_test_file(false); 7247e99f22cSJianjun Duan TestQtailq tgt; 7257e99f22cSJianjun Duan 7267e99f22cSJianjun Duan QTAILQ_INIT(&tgt.q); 7277e99f22cSJianjun Duan vmstate_load_state(fload, &vmstate_q, &tgt, 1); 7287e99f22cSJianjun Duan char eof = qemu_get_byte(fload); 7297e99f22cSJianjun Duan g_assert(!qemu_file_get_error(fload)); 7307e99f22cSJianjun Duan g_assert_cmpint(tgt.i16, ==, obj_q.i16); 7317e99f22cSJianjun Duan g_assert_cmpint(tgt.i32, ==, obj_q.i32); 7327e99f22cSJianjun Duan g_assert_cmpint(eof, ==, QEMU_VM_EOF); 7337e99f22cSJianjun Duan 7347e99f22cSJianjun Duan TestQtailqElement *qele_from = QTAILQ_FIRST(&obj_q.q); 7357e99f22cSJianjun Duan TestQtailqElement *qlast_from = QTAILQ_LAST(&obj_q.q, TestQtailqHead); 7367e99f22cSJianjun Duan TestQtailqElement *qele_to = QTAILQ_FIRST(&tgt.q); 7377e99f22cSJianjun Duan TestQtailqElement *qlast_to = QTAILQ_LAST(&tgt.q, TestQtailqHead); 7387e99f22cSJianjun Duan 7397e99f22cSJianjun Duan while (1) { 7407e99f22cSJianjun Duan g_assert_cmpint(qele_to->b, ==, qele_from->b); 7417e99f22cSJianjun Duan g_assert_cmpint(qele_to->u8, ==, qele_from->u8); 7427e99f22cSJianjun Duan if ((qele_from == qlast_from) || (qele_to == qlast_to)) { 7437e99f22cSJianjun Duan break; 7447e99f22cSJianjun Duan } 7457e99f22cSJianjun Duan qele_from = QTAILQ_NEXT(qele_from, next); 7467e99f22cSJianjun Duan qele_to = QTAILQ_NEXT(qele_to, next); 7477e99f22cSJianjun Duan } 7487e99f22cSJianjun Duan 7497e99f22cSJianjun Duan g_assert_cmpint((uintptr_t) qele_from, ==, (uintptr_t) qlast_from); 7507e99f22cSJianjun Duan g_assert_cmpint((uintptr_t) qele_to, ==, (uintptr_t) qlast_to); 7517e99f22cSJianjun Duan 7527e99f22cSJianjun Duan /* clean up */ 7537e99f22cSJianjun Duan TestQtailqElement *qele; 7547e99f22cSJianjun Duan while (!QTAILQ_EMPTY(&tgt.q)) { 7557e99f22cSJianjun Duan qele = QTAILQ_LAST(&tgt.q, TestQtailqHead); 7567e99f22cSJianjun Duan QTAILQ_REMOVE(&tgt.q, qele, next); 7577e99f22cSJianjun Duan free(qele); 7587e99f22cSJianjun Duan qele = NULL; 7597e99f22cSJianjun Duan } 7607e99f22cSJianjun Duan qemu_fclose(fload); 7617e99f22cSJianjun Duan } 7627e99f22cSJianjun Duan 7635c379d90SDr. David Alan Gilbert typedef struct TmpTestStruct { 7645c379d90SDr. David Alan Gilbert TestStruct *parent; 7655c379d90SDr. David Alan Gilbert int64_t diff; 7665c379d90SDr. David Alan Gilbert } TmpTestStruct; 7675c379d90SDr. David Alan Gilbert 7685c379d90SDr. David Alan Gilbert static void tmp_child_pre_save(void *opaque) 7695c379d90SDr. David Alan Gilbert { 7705c379d90SDr. David Alan Gilbert struct TmpTestStruct *tts = opaque; 7715c379d90SDr. David Alan Gilbert 7725c379d90SDr. David Alan Gilbert tts->diff = tts->parent->b - tts->parent->a; 7735c379d90SDr. David Alan Gilbert } 7745c379d90SDr. David Alan Gilbert 7755c379d90SDr. David Alan Gilbert static int tmp_child_post_load(void *opaque, int version_id) 7765c379d90SDr. David Alan Gilbert { 7775c379d90SDr. David Alan Gilbert struct TmpTestStruct *tts = opaque; 7785c379d90SDr. David Alan Gilbert 7795c379d90SDr. David Alan Gilbert tts->parent->b = tts->parent->a + tts->diff; 7805c379d90SDr. David Alan Gilbert 7815c379d90SDr. David Alan Gilbert return 0; 7825c379d90SDr. David Alan Gilbert } 7835c379d90SDr. David Alan Gilbert 7845c379d90SDr. David Alan Gilbert static const VMStateDescription vmstate_tmp_back_to_parent = { 7855c379d90SDr. David Alan Gilbert .name = "test/tmp_child_parent", 7865c379d90SDr. David Alan Gilbert .fields = (VMStateField[]) { 7875c379d90SDr. David Alan Gilbert VMSTATE_UINT64(f, TestStruct), 7885c379d90SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 7895c379d90SDr. David Alan Gilbert } 7905c379d90SDr. David Alan Gilbert }; 7915c379d90SDr. David Alan Gilbert 7925c379d90SDr. David Alan Gilbert static const VMStateDescription vmstate_tmp_child = { 7935c379d90SDr. David Alan Gilbert .name = "test/tmp_child", 7945c379d90SDr. David Alan Gilbert .pre_save = tmp_child_pre_save, 7955c379d90SDr. David Alan Gilbert .post_load = tmp_child_post_load, 7965c379d90SDr. David Alan Gilbert .fields = (VMStateField[]) { 7975c379d90SDr. David Alan Gilbert VMSTATE_INT64(diff, TmpTestStruct), 7985c379d90SDr. David Alan Gilbert VMSTATE_STRUCT_POINTER(parent, TmpTestStruct, 7995c379d90SDr. David Alan Gilbert vmstate_tmp_back_to_parent, TestStruct), 8005c379d90SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 8015c379d90SDr. David Alan Gilbert } 8025c379d90SDr. David Alan Gilbert }; 8035c379d90SDr. David Alan Gilbert 8045c379d90SDr. David Alan Gilbert static const VMStateDescription vmstate_with_tmp = { 8055c379d90SDr. David Alan Gilbert .name = "test/with_tmp", 8065c379d90SDr. David Alan Gilbert .version_id = 1, 8075c379d90SDr. David Alan Gilbert .fields = (VMStateField[]) { 8085c379d90SDr. David Alan Gilbert VMSTATE_UINT32(a, TestStruct), 8095c379d90SDr. David Alan Gilbert VMSTATE_UINT64(d, TestStruct), 8105c379d90SDr. David Alan Gilbert VMSTATE_WITH_TMP(TestStruct, TmpTestStruct, vmstate_tmp_child), 8115c379d90SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 8125c379d90SDr. David Alan Gilbert } 8135c379d90SDr. David Alan Gilbert }; 8145c379d90SDr. David Alan Gilbert 8155c379d90SDr. David Alan Gilbert static void obj_tmp_copy(void *target, void *source) 8165c379d90SDr. David Alan Gilbert { 8175c379d90SDr. David Alan Gilbert memcpy(target, source, sizeof(TestStruct)); 8185c379d90SDr. David Alan Gilbert } 8195c379d90SDr. David Alan Gilbert 8205c379d90SDr. David Alan Gilbert static void test_tmp_struct(void) 8215c379d90SDr. David Alan Gilbert { 8225c379d90SDr. David Alan Gilbert TestStruct obj, obj_clone; 8235c379d90SDr. David Alan Gilbert 8245c379d90SDr. David Alan Gilbert uint8_t const wire_with_tmp[] = { 8255c379d90SDr. David Alan Gilbert /* u32 a */ 0x00, 0x00, 0x00, 0x02, 8265c379d90SDr. David Alan Gilbert /* u64 d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 8275c379d90SDr. David Alan Gilbert /* diff */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 8285c379d90SDr. David Alan Gilbert /* u64 f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 8295c379d90SDr. David Alan Gilbert QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 8305c379d90SDr. David Alan Gilbert }; 8315c379d90SDr. David Alan Gilbert 8325c379d90SDr. David Alan Gilbert memset(&obj, 0, sizeof(obj)); 8335c379d90SDr. David Alan Gilbert obj.a = 2; 8345c379d90SDr. David Alan Gilbert obj.b = 4; 8355c379d90SDr. David Alan Gilbert obj.d = 1; 8365c379d90SDr. David Alan Gilbert obj.f = 8; 8375c379d90SDr. David Alan Gilbert save_vmstate(&vmstate_with_tmp, &obj); 8385c379d90SDr. David Alan Gilbert 8395c379d90SDr. David Alan Gilbert compare_vmstate(wire_with_tmp, sizeof(wire_with_tmp)); 8405c379d90SDr. David Alan Gilbert 8415c379d90SDr. David Alan Gilbert memset(&obj, 0, sizeof(obj)); 8425c379d90SDr. David Alan Gilbert SUCCESS(load_vmstate(&vmstate_with_tmp, &obj, &obj_clone, 8435c379d90SDr. David Alan Gilbert obj_tmp_copy, 1, wire_with_tmp, 8445c379d90SDr. David Alan Gilbert sizeof(wire_with_tmp))); 8455c379d90SDr. David Alan Gilbert g_assert_cmpint(obj.a, ==, 2); /* From top level vmsd */ 8465c379d90SDr. David Alan Gilbert g_assert_cmpint(obj.b, ==, 4); /* from the post_load */ 8475c379d90SDr. David Alan Gilbert g_assert_cmpint(obj.d, ==, 1); /* From top level vmsd */ 8485c379d90SDr. David Alan Gilbert g_assert_cmpint(obj.f, ==, 8); /* From the child->parent */ 8495c379d90SDr. David Alan Gilbert } 8505c379d90SDr. David Alan Gilbert 8512668b4bfSEduardo Habkost int main(int argc, char **argv) 8522668b4bfSEduardo Habkost { 8532668b4bfSEduardo Habkost temp_fd = mkstemp(temp_file); 8542668b4bfSEduardo Habkost 8558925839fSDaniel P. Berrange module_call_init(MODULE_INIT_QOM); 8568925839fSDaniel P. Berrange 8572668b4bfSEduardo Habkost g_test_init(&argc, &argv, NULL); 8584ea7df4eSJuan Quintela g_test_add_func("/vmstate/simple/primitive", test_simple_primitive); 8592668b4bfSEduardo Habkost g_test_add_func("/vmstate/versioned/load/v1", test_load_v1); 8602668b4bfSEduardo Habkost g_test_add_func("/vmstate/versioned/load/v2", test_load_v2); 8612668b4bfSEduardo Habkost g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip); 8622668b4bfSEduardo Habkost g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip); 8632668b4bfSEduardo Habkost g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip); 8642668b4bfSEduardo Habkost g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip); 8658cc49f03SHalil Pasic g_test_add_func("/vmstate/array/ptr/str/no0/save", 8668cc49f03SHalil Pasic test_arr_ptr_str_no0_save); 8678cc49f03SHalil Pasic g_test_add_func("/vmstate/array/ptr/str/no0/load", 8688cc49f03SHalil Pasic test_arr_ptr_str_no0_load); 869cc958831SHalil Pasic g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save); 870cc958831SHalil Pasic g_test_add_func("/vmstate/array/ptr/str/0/load", 871cc958831SHalil Pasic test_arr_ptr_str_0_load); 87243333099SHalil Pasic g_test_add_func("/vmstate/array/ptr/prim/0/save", 87343333099SHalil Pasic test_arr_ptr_prim_0_save); 87443333099SHalil Pasic g_test_add_func("/vmstate/array/ptr/prim/0/load", 87543333099SHalil Pasic test_arr_ptr_prim_0_load); 8767e99f22cSJianjun Duan g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q); 8777e99f22cSJianjun Duan g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q); 8785c379d90SDr. David Alan Gilbert g_test_add_func("/vmstate/tmp_struct", test_tmp_struct); 8792668b4bfSEduardo Habkost g_test_run(); 8802668b4bfSEduardo Habkost 8812668b4bfSEduardo Habkost close(temp_fd); 8822668b4bfSEduardo Habkost unlink(temp_file); 8832668b4bfSEduardo Habkost 8842668b4bfSEduardo Habkost return 0; 8852668b4bfSEduardo Habkost } 886