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 276666c96aSJuan Quintela #include "../migration/migration.h" 282668b4bfSEduardo Habkost #include "migration/vmstate.h" 2908a0aee1SJuan Quintela #include "migration/qemu-file-types.h" 3008a0aee1SJuan Quintela #include "../migration/qemu-file.h" 3140014d81SJuan Quintela #include "../migration/qemu-file-channel.h" 32c3d2e2e7SJuan Quintela #include "../migration/savevm.h" 3310817bf0SDaniel P. Berrange #include "qemu/coroutine.h" 340b8fa32fSMarkus Armbruster #include "qemu/module.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 */ 732f168d07SDr. David Alan Gilbert int ret = vmstate_save_state(f, desc, obj, NULL); 742f168d07SDr. David Alan Gilbert g_assert(!ret); 754ea7df4eSJuan Quintela qemu_put_byte(f, QEMU_VM_EOF); 764ea7df4eSJuan Quintela g_assert(!qemu_file_get_error(f)); 774ea7df4eSJuan Quintela qemu_fclose(f); 784ea7df4eSJuan Quintela } 794ea7df4eSJuan Quintela 806d57b4c0SHalil Pasic static void save_buffer(const uint8_t *buf, size_t buf_size) 816d57b4c0SHalil Pasic { 826d57b4c0SHalil Pasic QEMUFile *fsave = open_test_file(true); 836d57b4c0SHalil Pasic qemu_put_buffer(fsave, buf, buf_size); 846d57b4c0SHalil Pasic qemu_fclose(fsave); 856d57b4c0SHalil Pasic } 866d57b4c0SHalil Pasic 875c379d90SDr. David Alan Gilbert static void compare_vmstate(const uint8_t *wire, size_t size) 884ea7df4eSJuan Quintela { 894ea7df4eSJuan Quintela QEMUFile *f = open_test_file(false); 904ea7df4eSJuan Quintela uint8_t result[size]; 914ea7df4eSJuan Quintela 924ea7df4eSJuan Quintela /* read back as binary */ 934ea7df4eSJuan Quintela 944ea7df4eSJuan Quintela g_assert_cmpint(qemu_get_buffer(f, result, sizeof(result)), ==, 954ea7df4eSJuan Quintela sizeof(result)); 964ea7df4eSJuan Quintela g_assert(!qemu_file_get_error(f)); 974ea7df4eSJuan Quintela 984ea7df4eSJuan Quintela /* Compare that what is on the file is the same that what we 994ea7df4eSJuan Quintela expected to be there */ 1004ea7df4eSJuan Quintela SUCCESS(memcmp(result, wire, sizeof(result))); 1014ea7df4eSJuan Quintela 1024ea7df4eSJuan Quintela /* Must reach EOF */ 1034ea7df4eSJuan Quintela qemu_get_byte(f); 1044ea7df4eSJuan Quintela g_assert_cmpint(qemu_file_get_error(f), ==, -EIO); 1054ea7df4eSJuan Quintela 1064ea7df4eSJuan Quintela qemu_fclose(f); 1074ea7df4eSJuan Quintela } 1084ea7df4eSJuan Quintela 1094ea7df4eSJuan Quintela static int load_vmstate_one(const VMStateDescription *desc, void *obj, 1105c379d90SDr. David Alan Gilbert int version, const uint8_t *wire, size_t size) 1114ea7df4eSJuan Quintela { 1124ea7df4eSJuan Quintela QEMUFile *f; 1134ea7df4eSJuan Quintela int ret; 1144ea7df4eSJuan Quintela 1154ea7df4eSJuan Quintela f = open_test_file(true); 1164ea7df4eSJuan Quintela qemu_put_buffer(f, wire, size); 1174ea7df4eSJuan Quintela qemu_fclose(f); 1184ea7df4eSJuan Quintela 1194ea7df4eSJuan Quintela f = open_test_file(false); 1204ea7df4eSJuan Quintela ret = vmstate_load_state(f, desc, obj, version); 1214ea7df4eSJuan Quintela if (ret) { 1224ea7df4eSJuan Quintela g_assert(qemu_file_get_error(f)); 1234ea7df4eSJuan Quintela } else{ 1244ea7df4eSJuan Quintela g_assert(!qemu_file_get_error(f)); 1254ea7df4eSJuan Quintela } 1264ea7df4eSJuan Quintela qemu_fclose(f); 1274ea7df4eSJuan Quintela return ret; 1284ea7df4eSJuan Quintela } 1294ea7df4eSJuan Quintela 1304ea7df4eSJuan Quintela 1314ea7df4eSJuan Quintela static int load_vmstate(const VMStateDescription *desc, 1324ea7df4eSJuan Quintela void *obj, void *obj_clone, 1334ea7df4eSJuan Quintela void (*obj_copy)(void *, void*), 1345c379d90SDr. David Alan Gilbert int version, const uint8_t *wire, size_t size) 1354ea7df4eSJuan Quintela { 1364ea7df4eSJuan Quintela /* We test with zero size */ 1374ea7df4eSJuan Quintela obj_copy(obj_clone, obj); 1384ea7df4eSJuan Quintela FAILURE(load_vmstate_one(desc, obj, version, wire, 0)); 1394ea7df4eSJuan Quintela 1404ea7df4eSJuan Quintela /* Stream ends with QEMU_EOF, so we need at least 3 bytes to be 1414ea7df4eSJuan Quintela * able to test in the middle */ 1424ea7df4eSJuan Quintela 1434ea7df4eSJuan Quintela if (size > 3) { 1444ea7df4eSJuan Quintela 1454ea7df4eSJuan Quintela /* We test with size - 2. We can't test size - 1 due to EOF tricks */ 1464ea7df4eSJuan Quintela obj_copy(obj, obj_clone); 1474ea7df4eSJuan Quintela FAILURE(load_vmstate_one(desc, obj, version, wire, size - 2)); 1484ea7df4eSJuan Quintela 1494ea7df4eSJuan Quintela /* Test with size/2, first half of real state */ 1504ea7df4eSJuan Quintela obj_copy(obj, obj_clone); 1514ea7df4eSJuan Quintela FAILURE(load_vmstate_one(desc, obj, version, wire, size/2)); 1524ea7df4eSJuan Quintela 1534ea7df4eSJuan Quintela /* Test with size/2, second half of real state */ 1544ea7df4eSJuan Quintela obj_copy(obj, obj_clone); 1554ea7df4eSJuan Quintela FAILURE(load_vmstate_one(desc, obj, version, wire + (size/2), size/2)); 1564ea7df4eSJuan Quintela 1574ea7df4eSJuan Quintela } 1584ea7df4eSJuan Quintela obj_copy(obj, obj_clone); 1594ea7df4eSJuan Quintela return load_vmstate_one(desc, obj, version, wire, size); 1604ea7df4eSJuan Quintela } 1614ea7df4eSJuan Quintela 1624ea7df4eSJuan Quintela /* Test struct that we are going to use for our tests */ 1634ea7df4eSJuan Quintela 1644ea7df4eSJuan Quintela typedef struct TestSimple { 1654ea7df4eSJuan Quintela bool b_1, b_2; 1664ea7df4eSJuan Quintela uint8_t u8_1; 1674ea7df4eSJuan Quintela uint16_t u16_1; 1684ea7df4eSJuan Quintela uint32_t u32_1; 1694ea7df4eSJuan Quintela uint64_t u64_1; 1704ea7df4eSJuan Quintela int8_t i8_1, i8_2; 1714ea7df4eSJuan Quintela int16_t i16_1, i16_2; 1724ea7df4eSJuan Quintela int32_t i32_1, i32_2; 1734ea7df4eSJuan Quintela int64_t i64_1, i64_2; 1744ea7df4eSJuan Quintela } TestSimple; 1754ea7df4eSJuan Quintela 1764ea7df4eSJuan Quintela /* Object instantiation, we are going to use it in more than one test */ 1774ea7df4eSJuan Quintela 1784ea7df4eSJuan Quintela TestSimple obj_simple = { 1794ea7df4eSJuan Quintela .b_1 = true, 1804ea7df4eSJuan Quintela .b_2 = false, 1814ea7df4eSJuan Quintela .u8_1 = 130, 1824ea7df4eSJuan Quintela .u16_1 = 512, 1834ea7df4eSJuan Quintela .u32_1 = 70000, 1844ea7df4eSJuan Quintela .u64_1 = 12121212, 1854ea7df4eSJuan Quintela .i8_1 = 65, 1864ea7df4eSJuan Quintela .i8_2 = -65, 1874ea7df4eSJuan Quintela .i16_1 = 512, 1884ea7df4eSJuan Quintela .i16_2 = -512, 1894ea7df4eSJuan Quintela .i32_1 = 70000, 1904ea7df4eSJuan Quintela .i32_2 = -70000, 1914ea7df4eSJuan Quintela .i64_1 = 12121212, 1924ea7df4eSJuan Quintela .i64_2 = -12121212, 1934ea7df4eSJuan Quintela }; 1944ea7df4eSJuan Quintela 1954ea7df4eSJuan Quintela /* Description of the values. If you add a primitive type 1964ea7df4eSJuan Quintela you are expected to add a test here */ 1974ea7df4eSJuan Quintela 1984ea7df4eSJuan Quintela static const VMStateDescription vmstate_simple_primitive = { 1994ea7df4eSJuan Quintela .name = "simple/primitive", 2004ea7df4eSJuan Quintela .version_id = 1, 2014ea7df4eSJuan Quintela .minimum_version_id = 1, 2024ea7df4eSJuan Quintela .fields = (VMStateField[]) { 2034ea7df4eSJuan Quintela VMSTATE_BOOL(b_1, TestSimple), 2044ea7df4eSJuan Quintela VMSTATE_BOOL(b_2, TestSimple), 2054ea7df4eSJuan Quintela VMSTATE_UINT8(u8_1, TestSimple), 2064ea7df4eSJuan Quintela VMSTATE_UINT16(u16_1, TestSimple), 2074ea7df4eSJuan Quintela VMSTATE_UINT32(u32_1, TestSimple), 2084ea7df4eSJuan Quintela VMSTATE_UINT64(u64_1, TestSimple), 2094ea7df4eSJuan Quintela VMSTATE_INT8(i8_1, TestSimple), 2104ea7df4eSJuan Quintela VMSTATE_INT8(i8_2, TestSimple), 2114ea7df4eSJuan Quintela VMSTATE_INT16(i16_1, TestSimple), 2124ea7df4eSJuan Quintela VMSTATE_INT16(i16_2, TestSimple), 2134ea7df4eSJuan Quintela VMSTATE_INT32(i32_1, TestSimple), 2144ea7df4eSJuan Quintela VMSTATE_INT32(i32_2, TestSimple), 2154ea7df4eSJuan Quintela VMSTATE_INT64(i64_1, TestSimple), 2164ea7df4eSJuan Quintela VMSTATE_INT64(i64_2, TestSimple), 2174ea7df4eSJuan Quintela VMSTATE_END_OF_LIST() 2184ea7df4eSJuan Quintela } 2194ea7df4eSJuan Quintela }; 2204ea7df4eSJuan Quintela 2214ea7df4eSJuan Quintela /* It describes what goes through the wire. Our tests are basically: 2224ea7df4eSJuan Quintela 2234ea7df4eSJuan Quintela * save test 2244ea7df4eSJuan Quintela - save a struct a vmstate to a file 2254ea7df4eSJuan Quintela - read that file back (binary read, no vmstate) 2264ea7df4eSJuan Quintela - compare it with what we expect to be on the wire 2274ea7df4eSJuan Quintela * load test 2284ea7df4eSJuan Quintela - save to the file what we expect to be on the wire 2294ea7df4eSJuan Quintela - read struct back with vmstate in a different 2304ea7df4eSJuan Quintela - compare back with the original struct 2314ea7df4eSJuan Quintela */ 2324ea7df4eSJuan Quintela 2334ea7df4eSJuan Quintela uint8_t wire_simple_primitive[] = { 2344ea7df4eSJuan Quintela /* b_1 */ 0x01, 2354ea7df4eSJuan Quintela /* b_2 */ 0x00, 2364ea7df4eSJuan Quintela /* u8_1 */ 0x82, 2374ea7df4eSJuan Quintela /* u16_1 */ 0x02, 0x00, 2384ea7df4eSJuan Quintela /* u32_1 */ 0x00, 0x01, 0x11, 0x70, 2394ea7df4eSJuan Quintela /* u64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c, 2404ea7df4eSJuan Quintela /* i8_1 */ 0x41, 2414ea7df4eSJuan Quintela /* i8_2 */ 0xbf, 2424ea7df4eSJuan Quintela /* i16_1 */ 0x02, 0x00, 2434ea7df4eSJuan Quintela /* i16_2 */ 0xfe, 0x0, 2444ea7df4eSJuan Quintela /* i32_1 */ 0x00, 0x01, 0x11, 0x70, 2454ea7df4eSJuan Quintela /* i32_2 */ 0xff, 0xfe, 0xee, 0x90, 2464ea7df4eSJuan Quintela /* i64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c, 2474ea7df4eSJuan Quintela /* i64_2 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x0b, 0x84, 2484ea7df4eSJuan Quintela QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 2494ea7df4eSJuan Quintela }; 2504ea7df4eSJuan Quintela 2514ea7df4eSJuan Quintela static void obj_simple_copy(void *target, void *source) 2524ea7df4eSJuan Quintela { 2534ea7df4eSJuan Quintela memcpy(target, source, sizeof(TestSimple)); 2544ea7df4eSJuan Quintela } 2554ea7df4eSJuan Quintela 2564ea7df4eSJuan Quintela static void test_simple_primitive(void) 2574ea7df4eSJuan Quintela { 2584ea7df4eSJuan Quintela TestSimple obj, obj_clone; 2594ea7df4eSJuan Quintela 2604ea7df4eSJuan Quintela memset(&obj, 0, sizeof(obj)); 2614ea7df4eSJuan Quintela save_vmstate(&vmstate_simple_primitive, &obj_simple); 2624ea7df4eSJuan Quintela 2634ea7df4eSJuan Quintela compare_vmstate(wire_simple_primitive, sizeof(wire_simple_primitive)); 2644ea7df4eSJuan Quintela 2654ea7df4eSJuan Quintela SUCCESS(load_vmstate(&vmstate_simple_primitive, &obj, &obj_clone, 2664ea7df4eSJuan Quintela obj_simple_copy, 1, wire_simple_primitive, 2674ea7df4eSJuan Quintela sizeof(wire_simple_primitive))); 2684ea7df4eSJuan Quintela 2694ea7df4eSJuan Quintela #define FIELD_EQUAL(name) g_assert_cmpint(obj.name, ==, obj_simple.name) 2704ea7df4eSJuan Quintela 2714ea7df4eSJuan Quintela FIELD_EQUAL(b_1); 2724ea7df4eSJuan Quintela FIELD_EQUAL(b_2); 2734ea7df4eSJuan Quintela FIELD_EQUAL(u8_1); 2744ea7df4eSJuan Quintela FIELD_EQUAL(u16_1); 2754ea7df4eSJuan Quintela FIELD_EQUAL(u32_1); 2764ea7df4eSJuan Quintela FIELD_EQUAL(u64_1); 2774ea7df4eSJuan Quintela FIELD_EQUAL(i8_1); 2784ea7df4eSJuan Quintela FIELD_EQUAL(i8_2); 2794ea7df4eSJuan Quintela FIELD_EQUAL(i16_1); 2804ea7df4eSJuan Quintela FIELD_EQUAL(i16_2); 2814ea7df4eSJuan Quintela FIELD_EQUAL(i32_1); 2824ea7df4eSJuan Quintela FIELD_EQUAL(i32_2); 2834ea7df4eSJuan Quintela FIELD_EQUAL(i64_1); 2844ea7df4eSJuan Quintela FIELD_EQUAL(i64_2); 2854ea7df4eSJuan Quintela } 2864ea7df4eSJuan Quintela 287b95d6588SMarc-André Lureau typedef struct TestSimpleArray { 288b95d6588SMarc-André Lureau uint16_t u16_1[3]; 289b95d6588SMarc-André Lureau } TestSimpleArray; 290b95d6588SMarc-André Lureau 291b95d6588SMarc-André Lureau /* Object instantiation, we are going to use it in more than one test */ 292b95d6588SMarc-André Lureau 293b95d6588SMarc-André Lureau TestSimpleArray obj_simple_arr = { 294b95d6588SMarc-André Lureau .u16_1 = { 0x42, 0x43, 0x44 }, 295b95d6588SMarc-André Lureau }; 296b95d6588SMarc-André Lureau 297b95d6588SMarc-André Lureau /* Description of the values. If you add a primitive type 298b95d6588SMarc-André Lureau you are expected to add a test here */ 299b95d6588SMarc-André Lureau 300b95d6588SMarc-André Lureau static const VMStateDescription vmstate_simple_arr = { 301b95d6588SMarc-André Lureau .name = "simple/array", 302b95d6588SMarc-André Lureau .version_id = 1, 303b95d6588SMarc-André Lureau .minimum_version_id = 1, 304b95d6588SMarc-André Lureau .fields = (VMStateField[]) { 305b95d6588SMarc-André Lureau VMSTATE_UINT16_ARRAY(u16_1, TestSimpleArray, 3), 306b95d6588SMarc-André Lureau VMSTATE_END_OF_LIST() 307b95d6588SMarc-André Lureau } 308b95d6588SMarc-André Lureau }; 309b95d6588SMarc-André Lureau 310b95d6588SMarc-André Lureau uint8_t wire_simple_arr[] = { 311b95d6588SMarc-André Lureau /* u16_1 */ 0x00, 0x42, 312b95d6588SMarc-André Lureau /* u16_1 */ 0x00, 0x43, 313b95d6588SMarc-André Lureau /* u16_1 */ 0x00, 0x44, 314b95d6588SMarc-André Lureau QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 315b95d6588SMarc-André Lureau }; 316b95d6588SMarc-André Lureau 317b95d6588SMarc-André Lureau static void obj_simple_arr_copy(void *target, void *source) 318b95d6588SMarc-André Lureau { 319b95d6588SMarc-André Lureau memcpy(target, source, sizeof(TestSimpleArray)); 320b95d6588SMarc-André Lureau } 321b95d6588SMarc-André Lureau 322b95d6588SMarc-André Lureau static void test_simple_array(void) 323b95d6588SMarc-André Lureau { 324b95d6588SMarc-André Lureau TestSimpleArray obj, obj_clone; 325b95d6588SMarc-André Lureau 326b95d6588SMarc-André Lureau memset(&obj, 0, sizeof(obj)); 327b95d6588SMarc-André Lureau save_vmstate(&vmstate_simple_arr, &obj_simple_arr); 328b95d6588SMarc-André Lureau 329b95d6588SMarc-André Lureau compare_vmstate(wire_simple_arr, sizeof(wire_simple_arr)); 330b95d6588SMarc-André Lureau 331b95d6588SMarc-André Lureau SUCCESS(load_vmstate(&vmstate_simple_arr, &obj, &obj_clone, 332b95d6588SMarc-André Lureau obj_simple_arr_copy, 1, wire_simple_arr, 333b95d6588SMarc-André Lureau sizeof(wire_simple_arr))); 334b95d6588SMarc-André Lureau } 335b95d6588SMarc-André Lureau 3364ea7df4eSJuan Quintela typedef struct TestStruct { 3372668b4bfSEduardo Habkost uint32_t a, b, c, e; 3382668b4bfSEduardo Habkost uint64_t d, f; 3392668b4bfSEduardo Habkost bool skip_c_e; 3402668b4bfSEduardo Habkost } TestStruct; 3412668b4bfSEduardo Habkost 3422668b4bfSEduardo Habkost static const VMStateDescription vmstate_versioned = { 3434ea7df4eSJuan Quintela .name = "test/versioned", 3442668b4bfSEduardo Habkost .version_id = 2, 3452668b4bfSEduardo Habkost .minimum_version_id = 1, 3462668b4bfSEduardo Habkost .fields = (VMStateField[]) { 3472668b4bfSEduardo Habkost VMSTATE_UINT32(a, TestStruct), 3482668b4bfSEduardo Habkost VMSTATE_UINT32_V(b, TestStruct, 2), /* Versioned field in the middle, so 3492668b4bfSEduardo Habkost * we catch bugs more easily. 3502668b4bfSEduardo Habkost */ 3512668b4bfSEduardo Habkost VMSTATE_UINT32(c, TestStruct), 3522668b4bfSEduardo Habkost VMSTATE_UINT64(d, TestStruct), 3532668b4bfSEduardo Habkost VMSTATE_UINT32_V(e, TestStruct, 2), 3542668b4bfSEduardo Habkost VMSTATE_UINT64_V(f, TestStruct, 2), 3552668b4bfSEduardo Habkost VMSTATE_END_OF_LIST() 3562668b4bfSEduardo Habkost } 3572668b4bfSEduardo Habkost }; 3582668b4bfSEduardo Habkost 3592668b4bfSEduardo Habkost static void test_load_v1(void) 3602668b4bfSEduardo Habkost { 3612668b4bfSEduardo Habkost uint8_t buf[] = { 3622668b4bfSEduardo Habkost 0, 0, 0, 10, /* a */ 3632668b4bfSEduardo Habkost 0, 0, 0, 30, /* c */ 3642668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 40, /* d */ 3652668b4bfSEduardo Habkost QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 3662668b4bfSEduardo Habkost }; 3676d57b4c0SHalil Pasic save_buffer(buf, sizeof(buf)); 3682668b4bfSEduardo Habkost 369c6f6646cSJuan Quintela QEMUFile *loading = open_test_file(false); 3702668b4bfSEduardo Habkost TestStruct obj = { .b = 200, .e = 500, .f = 600 }; 3712668b4bfSEduardo Habkost vmstate_load_state(loading, &vmstate_versioned, &obj, 1); 3722668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(loading)); 3732668b4bfSEduardo Habkost g_assert_cmpint(obj.a, ==, 10); 3742668b4bfSEduardo Habkost g_assert_cmpint(obj.b, ==, 200); 3752668b4bfSEduardo Habkost g_assert_cmpint(obj.c, ==, 30); 3762668b4bfSEduardo Habkost g_assert_cmpint(obj.d, ==, 40); 3772668b4bfSEduardo Habkost g_assert_cmpint(obj.e, ==, 500); 3782668b4bfSEduardo Habkost g_assert_cmpint(obj.f, ==, 600); 3792668b4bfSEduardo Habkost qemu_fclose(loading); 3802668b4bfSEduardo Habkost } 3812668b4bfSEduardo Habkost 3822668b4bfSEduardo Habkost static void test_load_v2(void) 3832668b4bfSEduardo Habkost { 3842668b4bfSEduardo Habkost uint8_t buf[] = { 3852668b4bfSEduardo Habkost 0, 0, 0, 10, /* a */ 3862668b4bfSEduardo Habkost 0, 0, 0, 20, /* b */ 3872668b4bfSEduardo Habkost 0, 0, 0, 30, /* c */ 3882668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 40, /* d */ 3892668b4bfSEduardo Habkost 0, 0, 0, 50, /* e */ 3902668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 60, /* f */ 3912668b4bfSEduardo Habkost QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 3922668b4bfSEduardo Habkost }; 3936d57b4c0SHalil Pasic save_buffer(buf, sizeof(buf)); 3942668b4bfSEduardo Habkost 395c6f6646cSJuan Quintela QEMUFile *loading = open_test_file(false); 3962668b4bfSEduardo Habkost TestStruct obj; 3972668b4bfSEduardo Habkost vmstate_load_state(loading, &vmstate_versioned, &obj, 2); 3982668b4bfSEduardo Habkost g_assert_cmpint(obj.a, ==, 10); 3992668b4bfSEduardo Habkost g_assert_cmpint(obj.b, ==, 20); 4002668b4bfSEduardo Habkost g_assert_cmpint(obj.c, ==, 30); 4012668b4bfSEduardo Habkost g_assert_cmpint(obj.d, ==, 40); 4022668b4bfSEduardo Habkost g_assert_cmpint(obj.e, ==, 50); 4032668b4bfSEduardo Habkost g_assert_cmpint(obj.f, ==, 60); 4042668b4bfSEduardo Habkost qemu_fclose(loading); 4052668b4bfSEduardo Habkost } 4062668b4bfSEduardo Habkost 4072668b4bfSEduardo Habkost static bool test_skip(void *opaque, int version_id) 4082668b4bfSEduardo Habkost { 4092668b4bfSEduardo Habkost TestStruct *t = (TestStruct *)opaque; 4102668b4bfSEduardo Habkost return !t->skip_c_e; 4112668b4bfSEduardo Habkost } 4122668b4bfSEduardo Habkost 4132668b4bfSEduardo Habkost static const VMStateDescription vmstate_skipping = { 4144ea7df4eSJuan Quintela .name = "test/skip", 4152668b4bfSEduardo Habkost .version_id = 2, 4162668b4bfSEduardo Habkost .minimum_version_id = 1, 4172668b4bfSEduardo Habkost .fields = (VMStateField[]) { 4182668b4bfSEduardo Habkost VMSTATE_UINT32(a, TestStruct), 4192668b4bfSEduardo Habkost VMSTATE_UINT32(b, TestStruct), 4202668b4bfSEduardo Habkost VMSTATE_UINT32_TEST(c, TestStruct, test_skip), 4212668b4bfSEduardo Habkost VMSTATE_UINT64(d, TestStruct), 4222668b4bfSEduardo Habkost VMSTATE_UINT32_TEST(e, TestStruct, test_skip), 4232668b4bfSEduardo Habkost VMSTATE_UINT64_V(f, TestStruct, 2), 4242668b4bfSEduardo Habkost VMSTATE_END_OF_LIST() 4252668b4bfSEduardo Habkost } 4262668b4bfSEduardo Habkost }; 4272668b4bfSEduardo Habkost 4282668b4bfSEduardo Habkost 4292668b4bfSEduardo Habkost static void test_save_noskip(void) 4302668b4bfSEduardo Habkost { 431a8ec4437SDaniel P. Berrange QEMUFile *fsave = open_test_file(true); 4322668b4bfSEduardo Habkost TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, 4332668b4bfSEduardo Habkost .skip_c_e = false }; 4342f168d07SDr. David Alan Gilbert int ret = vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL); 4352f168d07SDr. David Alan Gilbert g_assert(!ret); 4362668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(fsave)); 4372668b4bfSEduardo Habkost 4382668b4bfSEduardo Habkost uint8_t expected[] = { 4392668b4bfSEduardo Habkost 0, 0, 0, 1, /* a */ 4402668b4bfSEduardo Habkost 0, 0, 0, 2, /* b */ 4412668b4bfSEduardo Habkost 0, 0, 0, 3, /* c */ 4422668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 4, /* d */ 4432668b4bfSEduardo Habkost 0, 0, 0, 5, /* e */ 4442668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 6, /* f */ 4452668b4bfSEduardo Habkost }; 446a8ec4437SDaniel P. Berrange 4479935bacaSDr. David Alan Gilbert qemu_fclose(fsave); 448a8ec4437SDaniel P. Berrange compare_vmstate(expected, sizeof(expected)); 4492668b4bfSEduardo Habkost } 4502668b4bfSEduardo Habkost 4512668b4bfSEduardo Habkost static void test_save_skip(void) 4522668b4bfSEduardo Habkost { 453a8ec4437SDaniel P. Berrange QEMUFile *fsave = open_test_file(true); 4542668b4bfSEduardo Habkost TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, 4552668b4bfSEduardo Habkost .skip_c_e = true }; 4562f168d07SDr. David Alan Gilbert int ret = vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL); 4572f168d07SDr. David Alan Gilbert g_assert(!ret); 4582668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(fsave)); 4592668b4bfSEduardo Habkost 4602668b4bfSEduardo Habkost uint8_t expected[] = { 4612668b4bfSEduardo Habkost 0, 0, 0, 1, /* a */ 4622668b4bfSEduardo Habkost 0, 0, 0, 2, /* b */ 4632668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 4, /* d */ 4642668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 6, /* f */ 4652668b4bfSEduardo Habkost }; 4662668b4bfSEduardo Habkost 4679935bacaSDr. David Alan Gilbert qemu_fclose(fsave); 468a8ec4437SDaniel P. Berrange compare_vmstate(expected, sizeof(expected)); 4692668b4bfSEduardo Habkost } 4702668b4bfSEduardo Habkost 4712668b4bfSEduardo Habkost static void test_load_noskip(void) 4722668b4bfSEduardo Habkost { 4732668b4bfSEduardo Habkost uint8_t buf[] = { 4742668b4bfSEduardo Habkost 0, 0, 0, 10, /* a */ 4752668b4bfSEduardo Habkost 0, 0, 0, 20, /* b */ 4762668b4bfSEduardo Habkost 0, 0, 0, 30, /* c */ 4772668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 40, /* d */ 4782668b4bfSEduardo Habkost 0, 0, 0, 50, /* e */ 4792668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 60, /* f */ 4802668b4bfSEduardo Habkost QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 4812668b4bfSEduardo Habkost }; 4826d57b4c0SHalil Pasic save_buffer(buf, sizeof(buf)); 4832668b4bfSEduardo Habkost 484a8ec4437SDaniel P. Berrange QEMUFile *loading = open_test_file(false); 4852668b4bfSEduardo Habkost TestStruct obj = { .skip_c_e = false }; 4862668b4bfSEduardo Habkost vmstate_load_state(loading, &vmstate_skipping, &obj, 2); 4872668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(loading)); 4882668b4bfSEduardo Habkost g_assert_cmpint(obj.a, ==, 10); 4892668b4bfSEduardo Habkost g_assert_cmpint(obj.b, ==, 20); 4902668b4bfSEduardo Habkost g_assert_cmpint(obj.c, ==, 30); 4912668b4bfSEduardo Habkost g_assert_cmpint(obj.d, ==, 40); 4922668b4bfSEduardo Habkost g_assert_cmpint(obj.e, ==, 50); 4932668b4bfSEduardo Habkost g_assert_cmpint(obj.f, ==, 60); 4942668b4bfSEduardo Habkost qemu_fclose(loading); 4952668b4bfSEduardo Habkost } 4962668b4bfSEduardo Habkost 4972668b4bfSEduardo Habkost static void test_load_skip(void) 4982668b4bfSEduardo Habkost { 4992668b4bfSEduardo Habkost uint8_t buf[] = { 5002668b4bfSEduardo Habkost 0, 0, 0, 10, /* a */ 5012668b4bfSEduardo Habkost 0, 0, 0, 20, /* b */ 5022668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 40, /* d */ 5032668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 60, /* f */ 5042668b4bfSEduardo Habkost QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 5052668b4bfSEduardo Habkost }; 5066d57b4c0SHalil Pasic save_buffer(buf, sizeof(buf)); 5072668b4bfSEduardo Habkost 508a8ec4437SDaniel P. Berrange QEMUFile *loading = open_test_file(false); 5092668b4bfSEduardo Habkost TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 }; 5102668b4bfSEduardo Habkost vmstate_load_state(loading, &vmstate_skipping, &obj, 2); 5112668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(loading)); 5122668b4bfSEduardo Habkost g_assert_cmpint(obj.a, ==, 10); 5132668b4bfSEduardo Habkost g_assert_cmpint(obj.b, ==, 20); 5142668b4bfSEduardo Habkost g_assert_cmpint(obj.c, ==, 300); 5152668b4bfSEduardo Habkost g_assert_cmpint(obj.d, ==, 40); 5162668b4bfSEduardo Habkost g_assert_cmpint(obj.e, ==, 500); 5172668b4bfSEduardo Habkost g_assert_cmpint(obj.f, ==, 60); 5182668b4bfSEduardo Habkost qemu_fclose(loading); 5192668b4bfSEduardo Habkost } 5202668b4bfSEduardo Habkost 5218cc49f03SHalil Pasic typedef struct { 5228cc49f03SHalil Pasic int32_t i; 5238cc49f03SHalil Pasic } TestStructTriv; 5248cc49f03SHalil Pasic 5258cc49f03SHalil Pasic const VMStateDescription vmsd_tst = { 5268cc49f03SHalil Pasic .name = "test/tst", 5278cc49f03SHalil Pasic .version_id = 1, 5288cc49f03SHalil Pasic .minimum_version_id = 1, 5298cc49f03SHalil Pasic .fields = (VMStateField[]) { 5308cc49f03SHalil Pasic VMSTATE_INT32(i, TestStructTriv), 5318cc49f03SHalil Pasic VMSTATE_END_OF_LIST() 5328cc49f03SHalil Pasic } 5338cc49f03SHalil Pasic }; 5348cc49f03SHalil Pasic 535cc958831SHalil Pasic /* test array migration */ 536cc958831SHalil Pasic 5378cc49f03SHalil Pasic #define AR_SIZE 4 5388cc49f03SHalil Pasic 5398cc49f03SHalil Pasic typedef struct { 5408cc49f03SHalil Pasic TestStructTriv *ar[AR_SIZE]; 5418cc49f03SHalil Pasic } TestArrayOfPtrToStuct; 5428cc49f03SHalil Pasic 5438cc49f03SHalil Pasic const VMStateDescription vmsd_arps = { 5448cc49f03SHalil Pasic .name = "test/arps", 5458cc49f03SHalil Pasic .version_id = 1, 5468cc49f03SHalil Pasic .minimum_version_id = 1, 5478cc49f03SHalil Pasic .fields = (VMStateField[]) { 5488cc49f03SHalil Pasic VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(ar, TestArrayOfPtrToStuct, 5498cc49f03SHalil Pasic AR_SIZE, 0, vmsd_tst, TestStructTriv), 5508cc49f03SHalil Pasic VMSTATE_END_OF_LIST() 5518cc49f03SHalil Pasic } 5528cc49f03SHalil Pasic }; 553cc958831SHalil Pasic 554cc958831SHalil Pasic static uint8_t wire_arr_ptr_no0[] = { 5558cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x00, 5568cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x01, 5578cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x02, 5588cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x03, 5598cc49f03SHalil Pasic QEMU_VM_EOF 5608cc49f03SHalil Pasic }; 5618cc49f03SHalil Pasic 562cc958831SHalil Pasic static void test_arr_ptr_str_no0_save(void) 563cc958831SHalil Pasic { 564cc958831SHalil Pasic TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} }; 565cc958831SHalil Pasic TestArrayOfPtrToStuct sample = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} }; 566cc958831SHalil Pasic 5678cc49f03SHalil Pasic save_vmstate(&vmsd_arps, &sample); 568cc958831SHalil Pasic compare_vmstate(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0)); 5698cc49f03SHalil Pasic } 5708cc49f03SHalil Pasic 5718cc49f03SHalil Pasic static void test_arr_ptr_str_no0_load(void) 5728cc49f03SHalil Pasic { 5738cc49f03SHalil Pasic TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} }; 5748cc49f03SHalil Pasic TestStructTriv ar[AR_SIZE] = {}; 5758cc49f03SHalil Pasic TestArrayOfPtrToStuct obj = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} }; 5768cc49f03SHalil Pasic int idx; 577cc958831SHalil Pasic 578cc958831SHalil Pasic save_buffer(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0)); 579cc958831SHalil Pasic SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1, 580cc958831SHalil Pasic wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0))); 581cc958831SHalil Pasic for (idx = 0; idx < AR_SIZE; ++idx) { 582cc958831SHalil Pasic /* compare the target array ar with the ground truth array ar_gt */ 583cc958831SHalil Pasic g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i); 584cc958831SHalil Pasic } 585cc958831SHalil Pasic } 586cc958831SHalil Pasic 587cc958831SHalil Pasic static uint8_t wire_arr_ptr_0[] = { 5888cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x00, 589cc958831SHalil Pasic VMS_NULLPTR_MARKER, 5908cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x02, 5918cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x03, 5928cc49f03SHalil Pasic QEMU_VM_EOF 5938cc49f03SHalil Pasic }; 5948cc49f03SHalil Pasic 595cc958831SHalil Pasic static void test_arr_ptr_str_0_save(void) 596cc958831SHalil Pasic { 597cc958831SHalil Pasic TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} }; 598cc958831SHalil Pasic TestArrayOfPtrToStuct sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} }; 599cc958831SHalil Pasic 600cc958831SHalil Pasic save_vmstate(&vmsd_arps, &sample); 601cc958831SHalil Pasic compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0)); 602cc958831SHalil Pasic } 603cc958831SHalil Pasic 604cc958831SHalil Pasic static void test_arr_ptr_str_0_load(void) 605cc958831SHalil Pasic { 606cc958831SHalil Pasic TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 0}, {.i = 2}, {.i = 3} }; 607cc958831SHalil Pasic TestStructTriv ar[AR_SIZE] = {}; 608cc958831SHalil Pasic TestArrayOfPtrToStuct obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} }; 609cc958831SHalil Pasic int idx; 610cc958831SHalil Pasic 611cc958831SHalil Pasic save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0)); 6128cc49f03SHalil Pasic SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1, 613cc958831SHalil Pasic wire_arr_ptr_0, sizeof(wire_arr_ptr_0))); 6148cc49f03SHalil Pasic for (idx = 0; idx < AR_SIZE; ++idx) { 6158cc49f03SHalil Pasic /* compare the target array ar with the ground truth array ar_gt */ 6168cc49f03SHalil Pasic g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i); 6178cc49f03SHalil Pasic } 618cc958831SHalil Pasic for (idx = 0; idx < AR_SIZE; ++idx) { 619cc958831SHalil Pasic if (idx == 1) { 620cc958831SHalil Pasic g_assert_cmpint((uintptr_t)(obj.ar[idx]), ==, 0); 621cc958831SHalil Pasic } else { 622cc958831SHalil Pasic g_assert_cmpint((uintptr_t)(obj.ar[idx]), !=, 0); 623cc958831SHalil Pasic } 624cc958831SHalil Pasic } 6258cc49f03SHalil Pasic } 6268cc49f03SHalil Pasic 62743333099SHalil Pasic typedef struct TestArrayOfPtrToInt { 62843333099SHalil Pasic int32_t *ar[AR_SIZE]; 62943333099SHalil Pasic } TestArrayOfPtrToInt; 63043333099SHalil Pasic 63143333099SHalil Pasic const VMStateDescription vmsd_arpp = { 63243333099SHalil Pasic .name = "test/arps", 63343333099SHalil Pasic .version_id = 1, 63443333099SHalil Pasic .minimum_version_id = 1, 63543333099SHalil Pasic .fields = (VMStateField[]) { 63643333099SHalil Pasic VMSTATE_ARRAY_OF_POINTER(ar, TestArrayOfPtrToInt, 63743333099SHalil Pasic AR_SIZE, 0, vmstate_info_int32, int32_t*), 63843333099SHalil Pasic VMSTATE_END_OF_LIST() 63943333099SHalil Pasic } 64043333099SHalil Pasic }; 64143333099SHalil Pasic 64243333099SHalil Pasic static void test_arr_ptr_prim_0_save(void) 64343333099SHalil Pasic { 64443333099SHalil Pasic int32_t ar[AR_SIZE] = {0 , 1, 2, 3}; 64543333099SHalil Pasic TestArrayOfPtrToInt sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} }; 64643333099SHalil Pasic 64743333099SHalil Pasic save_vmstate(&vmsd_arpp, &sample); 64843333099SHalil Pasic compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0)); 64943333099SHalil Pasic } 65043333099SHalil Pasic 65143333099SHalil Pasic static void test_arr_ptr_prim_0_load(void) 65243333099SHalil Pasic { 65343333099SHalil Pasic int32_t ar_gt[AR_SIZE] = {0, 1, 2, 3}; 65443333099SHalil Pasic int32_t ar[AR_SIZE] = {3 , 42, 1, 0}; 65543333099SHalil Pasic TestArrayOfPtrToInt obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} }; 65643333099SHalil Pasic int idx; 65743333099SHalil Pasic 65843333099SHalil Pasic save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0)); 65943333099SHalil Pasic SUCCESS(load_vmstate_one(&vmsd_arpp, &obj, 1, 66043333099SHalil Pasic wire_arr_ptr_0, sizeof(wire_arr_ptr_0))); 66143333099SHalil Pasic for (idx = 0; idx < AR_SIZE; ++idx) { 66243333099SHalil Pasic /* compare the target array ar with the ground truth array ar_gt */ 66343333099SHalil Pasic if (idx == 1) { 66443333099SHalil Pasic g_assert_cmpint(42, ==, ar[idx]); 66543333099SHalil Pasic } else { 66643333099SHalil Pasic g_assert_cmpint(ar_gt[idx], ==, ar[idx]); 66743333099SHalil Pasic } 66843333099SHalil Pasic } 66943333099SHalil Pasic } 67043333099SHalil Pasic 6717e99f22cSJianjun Duan /* test QTAILQ migration */ 6727e99f22cSJianjun Duan typedef struct TestQtailqElement TestQtailqElement; 6737e99f22cSJianjun Duan 6747e99f22cSJianjun Duan struct TestQtailqElement { 6757e99f22cSJianjun Duan bool b; 6767e99f22cSJianjun Duan uint8_t u8; 6777e99f22cSJianjun Duan QTAILQ_ENTRY(TestQtailqElement) next; 6787e99f22cSJianjun Duan }; 6797e99f22cSJianjun Duan 6807e99f22cSJianjun Duan typedef struct TestQtailq { 6817e99f22cSJianjun Duan int16_t i16; 682eae3eb3eSPaolo Bonzini QTAILQ_HEAD(, TestQtailqElement) q; 6837e99f22cSJianjun Duan int32_t i32; 6847e99f22cSJianjun Duan } TestQtailq; 6857e99f22cSJianjun Duan 6867e99f22cSJianjun Duan static const VMStateDescription vmstate_q_element = { 6877e99f22cSJianjun Duan .name = "test/queue-element", 6887e99f22cSJianjun Duan .version_id = 1, 6897e99f22cSJianjun Duan .minimum_version_id = 1, 6907e99f22cSJianjun Duan .fields = (VMStateField[]) { 6917e99f22cSJianjun Duan VMSTATE_BOOL(b, TestQtailqElement), 6927e99f22cSJianjun Duan VMSTATE_UINT8(u8, TestQtailqElement), 6937e99f22cSJianjun Duan VMSTATE_END_OF_LIST() 6947e99f22cSJianjun Duan }, 6957e99f22cSJianjun Duan }; 6967e99f22cSJianjun Duan 6977e99f22cSJianjun Duan static const VMStateDescription vmstate_q = { 6987e99f22cSJianjun Duan .name = "test/queue", 6997e99f22cSJianjun Duan .version_id = 1, 7007e99f22cSJianjun Duan .minimum_version_id = 1, 7017e99f22cSJianjun Duan .fields = (VMStateField[]) { 7027e99f22cSJianjun Duan VMSTATE_INT16(i16, TestQtailq), 7037e99f22cSJianjun Duan VMSTATE_QTAILQ_V(q, TestQtailq, 1, vmstate_q_element, TestQtailqElement, 7047e99f22cSJianjun Duan next), 7057e99f22cSJianjun Duan VMSTATE_INT32(i32, TestQtailq), 7067e99f22cSJianjun Duan VMSTATE_END_OF_LIST() 7077e99f22cSJianjun Duan } 7087e99f22cSJianjun Duan }; 7097e99f22cSJianjun Duan 7107e99f22cSJianjun Duan uint8_t wire_q[] = { 7117e99f22cSJianjun Duan /* i16 */ 0xfe, 0x0, 7127e99f22cSJianjun Duan /* start of element 0 of q */ 0x01, 7137e99f22cSJianjun Duan /* .b */ 0x01, 7147e99f22cSJianjun Duan /* .u8 */ 0x82, 7157e99f22cSJianjun Duan /* start of element 1 of q */ 0x01, 7167e99f22cSJianjun Duan /* b */ 0x00, 7177e99f22cSJianjun Duan /* u8 */ 0x41, 7187e99f22cSJianjun Duan /* end of q */ 0x00, 7197e99f22cSJianjun Duan /* i32 */ 0x00, 0x01, 0x11, 0x70, 7207e99f22cSJianjun Duan QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 7217e99f22cSJianjun Duan }; 7227e99f22cSJianjun Duan 7237e99f22cSJianjun Duan static void test_save_q(void) 7247e99f22cSJianjun Duan { 7257e99f22cSJianjun Duan TestQtailq obj_q = { 7267e99f22cSJianjun Duan .i16 = -512, 7277e99f22cSJianjun Duan .i32 = 70000, 7287e99f22cSJianjun Duan }; 7297e99f22cSJianjun Duan 7307e99f22cSJianjun Duan TestQtailqElement obj_qe1 = { 7317e99f22cSJianjun Duan .b = true, 7327e99f22cSJianjun Duan .u8 = 130, 7337e99f22cSJianjun Duan }; 7347e99f22cSJianjun Duan 7357e99f22cSJianjun Duan TestQtailqElement obj_qe2 = { 7367e99f22cSJianjun Duan .b = false, 7377e99f22cSJianjun Duan .u8 = 65, 7387e99f22cSJianjun Duan }; 7397e99f22cSJianjun Duan 7407e99f22cSJianjun Duan QTAILQ_INIT(&obj_q.q); 7417e99f22cSJianjun Duan QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next); 7427e99f22cSJianjun Duan QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next); 7437e99f22cSJianjun Duan 7447e99f22cSJianjun Duan save_vmstate(&vmstate_q, &obj_q); 7457e99f22cSJianjun Duan compare_vmstate(wire_q, sizeof(wire_q)); 7467e99f22cSJianjun Duan } 7477e99f22cSJianjun Duan 7487e99f22cSJianjun Duan static void test_load_q(void) 7497e99f22cSJianjun Duan { 7507e99f22cSJianjun Duan TestQtailq obj_q = { 7517e99f22cSJianjun Duan .i16 = -512, 7527e99f22cSJianjun Duan .i32 = 70000, 7537e99f22cSJianjun Duan }; 7547e99f22cSJianjun Duan 7557e99f22cSJianjun Duan TestQtailqElement obj_qe1 = { 7567e99f22cSJianjun Duan .b = true, 7577e99f22cSJianjun Duan .u8 = 130, 7587e99f22cSJianjun Duan }; 7597e99f22cSJianjun Duan 7607e99f22cSJianjun Duan TestQtailqElement obj_qe2 = { 7617e99f22cSJianjun Duan .b = false, 7627e99f22cSJianjun Duan .u8 = 65, 7637e99f22cSJianjun Duan }; 7647e99f22cSJianjun Duan 7657e99f22cSJianjun Duan QTAILQ_INIT(&obj_q.q); 7667e99f22cSJianjun Duan QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next); 7677e99f22cSJianjun Duan QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next); 7687e99f22cSJianjun Duan 7697e99f22cSJianjun Duan QEMUFile *fsave = open_test_file(true); 7707e99f22cSJianjun Duan 7717e99f22cSJianjun Duan qemu_put_buffer(fsave, wire_q, sizeof(wire_q)); 7727e99f22cSJianjun Duan g_assert(!qemu_file_get_error(fsave)); 7737e99f22cSJianjun Duan qemu_fclose(fsave); 7747e99f22cSJianjun Duan 7757e99f22cSJianjun Duan QEMUFile *fload = open_test_file(false); 7767e99f22cSJianjun Duan TestQtailq tgt; 7777e99f22cSJianjun Duan 7787e99f22cSJianjun Duan QTAILQ_INIT(&tgt.q); 7797e99f22cSJianjun Duan vmstate_load_state(fload, &vmstate_q, &tgt, 1); 7807e99f22cSJianjun Duan char eof = qemu_get_byte(fload); 7817e99f22cSJianjun Duan g_assert(!qemu_file_get_error(fload)); 7827e99f22cSJianjun Duan g_assert_cmpint(tgt.i16, ==, obj_q.i16); 7837e99f22cSJianjun Duan g_assert_cmpint(tgt.i32, ==, obj_q.i32); 7847e99f22cSJianjun Duan g_assert_cmpint(eof, ==, QEMU_VM_EOF); 7857e99f22cSJianjun Duan 7867e99f22cSJianjun Duan TestQtailqElement *qele_from = QTAILQ_FIRST(&obj_q.q); 787eae3eb3eSPaolo Bonzini TestQtailqElement *qlast_from = QTAILQ_LAST(&obj_q.q); 7887e99f22cSJianjun Duan TestQtailqElement *qele_to = QTAILQ_FIRST(&tgt.q); 789eae3eb3eSPaolo Bonzini TestQtailqElement *qlast_to = QTAILQ_LAST(&tgt.q); 7907e99f22cSJianjun Duan 7917e99f22cSJianjun Duan while (1) { 7927e99f22cSJianjun Duan g_assert_cmpint(qele_to->b, ==, qele_from->b); 7937e99f22cSJianjun Duan g_assert_cmpint(qele_to->u8, ==, qele_from->u8); 7947e99f22cSJianjun Duan if ((qele_from == qlast_from) || (qele_to == qlast_to)) { 7957e99f22cSJianjun Duan break; 7967e99f22cSJianjun Duan } 7977e99f22cSJianjun Duan qele_from = QTAILQ_NEXT(qele_from, next); 7987e99f22cSJianjun Duan qele_to = QTAILQ_NEXT(qele_to, next); 7997e99f22cSJianjun Duan } 8007e99f22cSJianjun Duan 8017e99f22cSJianjun Duan g_assert_cmpint((uintptr_t) qele_from, ==, (uintptr_t) qlast_from); 8027e99f22cSJianjun Duan g_assert_cmpint((uintptr_t) qele_to, ==, (uintptr_t) qlast_to); 8037e99f22cSJianjun Duan 8047e99f22cSJianjun Duan /* clean up */ 8057e99f22cSJianjun Duan TestQtailqElement *qele; 8067e99f22cSJianjun Duan while (!QTAILQ_EMPTY(&tgt.q)) { 807eae3eb3eSPaolo Bonzini qele = QTAILQ_LAST(&tgt.q); 8087e99f22cSJianjun Duan QTAILQ_REMOVE(&tgt.q, qele, next); 8097e99f22cSJianjun Duan free(qele); 8107e99f22cSJianjun Duan qele = NULL; 8117e99f22cSJianjun Duan } 8127e99f22cSJianjun Duan qemu_fclose(fload); 8137e99f22cSJianjun Duan } 8147e99f22cSJianjun Duan 815*9a85e4b8SEric Auger /* interval (key) */ 816*9a85e4b8SEric Auger typedef struct TestGTreeInterval { 817*9a85e4b8SEric Auger uint64_t low; 818*9a85e4b8SEric Auger uint64_t high; 819*9a85e4b8SEric Auger } TestGTreeInterval; 820*9a85e4b8SEric Auger 821*9a85e4b8SEric Auger #define VMSTATE_INTERVAL \ 822*9a85e4b8SEric Auger { \ 823*9a85e4b8SEric Auger .name = "interval", \ 824*9a85e4b8SEric Auger .version_id = 1, \ 825*9a85e4b8SEric Auger .minimum_version_id = 1, \ 826*9a85e4b8SEric Auger .fields = (VMStateField[]) { \ 827*9a85e4b8SEric Auger VMSTATE_UINT64(low, TestGTreeInterval), \ 828*9a85e4b8SEric Auger VMSTATE_UINT64(high, TestGTreeInterval), \ 829*9a85e4b8SEric Auger VMSTATE_END_OF_LIST() \ 830*9a85e4b8SEric Auger } \ 831*9a85e4b8SEric Auger } 832*9a85e4b8SEric Auger 833*9a85e4b8SEric Auger /* mapping (value) */ 834*9a85e4b8SEric Auger typedef struct TestGTreeMapping { 835*9a85e4b8SEric Auger uint64_t phys_addr; 836*9a85e4b8SEric Auger uint32_t flags; 837*9a85e4b8SEric Auger } TestGTreeMapping; 838*9a85e4b8SEric Auger 839*9a85e4b8SEric Auger #define VMSTATE_MAPPING \ 840*9a85e4b8SEric Auger { \ 841*9a85e4b8SEric Auger .name = "mapping", \ 842*9a85e4b8SEric Auger .version_id = 1, \ 843*9a85e4b8SEric Auger .minimum_version_id = 1, \ 844*9a85e4b8SEric Auger .fields = (VMStateField[]) { \ 845*9a85e4b8SEric Auger VMSTATE_UINT64(phys_addr, TestGTreeMapping), \ 846*9a85e4b8SEric Auger VMSTATE_UINT32(flags, TestGTreeMapping), \ 847*9a85e4b8SEric Auger VMSTATE_END_OF_LIST() \ 848*9a85e4b8SEric Auger }, \ 849*9a85e4b8SEric Auger } 850*9a85e4b8SEric Auger 851*9a85e4b8SEric Auger static const VMStateDescription vmstate_interval_mapping[2] = { 852*9a85e4b8SEric Auger VMSTATE_MAPPING, /* value */ 853*9a85e4b8SEric Auger VMSTATE_INTERVAL /* key */ 854*9a85e4b8SEric Auger }; 855*9a85e4b8SEric Auger 856*9a85e4b8SEric Auger typedef struct TestGTreeDomain { 857*9a85e4b8SEric Auger int32_t id; 858*9a85e4b8SEric Auger GTree *mappings; 859*9a85e4b8SEric Auger } TestGTreeDomain; 860*9a85e4b8SEric Auger 861*9a85e4b8SEric Auger typedef struct TestGTreeIOMMU { 862*9a85e4b8SEric Auger int32_t id; 863*9a85e4b8SEric Auger GTree *domains; 864*9a85e4b8SEric Auger } TestGTreeIOMMU; 865*9a85e4b8SEric Auger 866*9a85e4b8SEric Auger /* Interval comparison function */ 867*9a85e4b8SEric Auger static gint interval_cmp(gconstpointer a, gconstpointer b, gpointer user_data) 868*9a85e4b8SEric Auger { 869*9a85e4b8SEric Auger TestGTreeInterval *inta = (TestGTreeInterval *)a; 870*9a85e4b8SEric Auger TestGTreeInterval *intb = (TestGTreeInterval *)b; 871*9a85e4b8SEric Auger 872*9a85e4b8SEric Auger if (inta->high < intb->low) { 873*9a85e4b8SEric Auger return -1; 874*9a85e4b8SEric Auger } else if (intb->high < inta->low) { 875*9a85e4b8SEric Auger return 1; 876*9a85e4b8SEric Auger } else { 877*9a85e4b8SEric Auger return 0; 878*9a85e4b8SEric Auger } 879*9a85e4b8SEric Auger } 880*9a85e4b8SEric Auger 881*9a85e4b8SEric Auger /* ID comparison function */ 882*9a85e4b8SEric Auger static gint int_cmp(gconstpointer a, gconstpointer b, gpointer user_data) 883*9a85e4b8SEric Auger { 884*9a85e4b8SEric Auger uint ua = GPOINTER_TO_UINT(a); 885*9a85e4b8SEric Auger uint ub = GPOINTER_TO_UINT(b); 886*9a85e4b8SEric Auger return (ua > ub) - (ua < ub); 887*9a85e4b8SEric Auger } 888*9a85e4b8SEric Auger 889*9a85e4b8SEric Auger static void destroy_domain(gpointer data) 890*9a85e4b8SEric Auger { 891*9a85e4b8SEric Auger TestGTreeDomain *domain = (TestGTreeDomain *)data; 892*9a85e4b8SEric Auger 893*9a85e4b8SEric Auger g_tree_destroy(domain->mappings); 894*9a85e4b8SEric Auger g_free(domain); 895*9a85e4b8SEric Auger } 896*9a85e4b8SEric Auger 897*9a85e4b8SEric Auger static int domain_preload(void *opaque) 898*9a85e4b8SEric Auger { 899*9a85e4b8SEric Auger TestGTreeDomain *domain = opaque; 900*9a85e4b8SEric Auger 901*9a85e4b8SEric Auger domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp, 902*9a85e4b8SEric Auger NULL, g_free, g_free); 903*9a85e4b8SEric Auger return 0; 904*9a85e4b8SEric Auger } 905*9a85e4b8SEric Auger 906*9a85e4b8SEric Auger static int iommu_preload(void *opaque) 907*9a85e4b8SEric Auger { 908*9a85e4b8SEric Auger TestGTreeIOMMU *iommu = opaque; 909*9a85e4b8SEric Auger 910*9a85e4b8SEric Auger iommu->domains = g_tree_new_full((GCompareDataFunc)int_cmp, 911*9a85e4b8SEric Auger NULL, NULL, destroy_domain); 912*9a85e4b8SEric Auger return 0; 913*9a85e4b8SEric Auger } 914*9a85e4b8SEric Auger 915*9a85e4b8SEric Auger static const VMStateDescription vmstate_domain = { 916*9a85e4b8SEric Auger .name = "domain", 917*9a85e4b8SEric Auger .version_id = 1, 918*9a85e4b8SEric Auger .minimum_version_id = 1, 919*9a85e4b8SEric Auger .pre_load = domain_preload, 920*9a85e4b8SEric Auger .fields = (VMStateField[]) { 921*9a85e4b8SEric Auger VMSTATE_INT32(id, TestGTreeDomain), 922*9a85e4b8SEric Auger VMSTATE_GTREE_V(mappings, TestGTreeDomain, 1, 923*9a85e4b8SEric Auger vmstate_interval_mapping, 924*9a85e4b8SEric Auger TestGTreeInterval, TestGTreeMapping), 925*9a85e4b8SEric Auger VMSTATE_END_OF_LIST() 926*9a85e4b8SEric Auger } 927*9a85e4b8SEric Auger }; 928*9a85e4b8SEric Auger 929*9a85e4b8SEric Auger static const VMStateDescription vmstate_iommu = { 930*9a85e4b8SEric Auger .name = "iommu", 931*9a85e4b8SEric Auger .version_id = 1, 932*9a85e4b8SEric Auger .minimum_version_id = 1, 933*9a85e4b8SEric Auger .pre_load = iommu_preload, 934*9a85e4b8SEric Auger .fields = (VMStateField[]) { 935*9a85e4b8SEric Auger VMSTATE_INT32(id, TestGTreeIOMMU), 936*9a85e4b8SEric Auger VMSTATE_GTREE_DIRECT_KEY_V(domains, TestGTreeIOMMU, 1, 937*9a85e4b8SEric Auger &vmstate_domain, TestGTreeDomain), 938*9a85e4b8SEric Auger VMSTATE_END_OF_LIST() 939*9a85e4b8SEric Auger } 940*9a85e4b8SEric Auger }; 941*9a85e4b8SEric Auger 942*9a85e4b8SEric Auger uint8_t first_domain_dump[] = { 943*9a85e4b8SEric Auger /* id */ 944*9a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x6, 945*9a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x2, /* 2 mappings */ 946*9a85e4b8SEric Auger 0x1, /* start of a */ 947*9a85e4b8SEric Auger /* a */ 948*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 949*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 950*9a85e4b8SEric Auger /* map_a */ 951*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 952*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x01, 953*9a85e4b8SEric Auger 0x1, /* start of b */ 954*9a85e4b8SEric Auger /* b */ 955*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 956*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF, 957*9a85e4b8SEric Auger /* map_b */ 958*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 959*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x02, 960*9a85e4b8SEric Auger 0x0, /* end of gtree */ 961*9a85e4b8SEric Auger QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 962*9a85e4b8SEric Auger }; 963*9a85e4b8SEric Auger 964*9a85e4b8SEric Auger static TestGTreeDomain *create_first_domain(void) 965*9a85e4b8SEric Auger { 966*9a85e4b8SEric Auger TestGTreeDomain *domain; 967*9a85e4b8SEric Auger TestGTreeMapping *map_a, *map_b; 968*9a85e4b8SEric Auger TestGTreeInterval *a, *b; 969*9a85e4b8SEric Auger 970*9a85e4b8SEric Auger domain = g_malloc0(sizeof(TestGTreeDomain)); 971*9a85e4b8SEric Auger domain->id = 6; 972*9a85e4b8SEric Auger 973*9a85e4b8SEric Auger a = g_malloc0(sizeof(TestGTreeInterval)); 974*9a85e4b8SEric Auger a->low = 0x1000; 975*9a85e4b8SEric Auger a->high = 0x1FFF; 976*9a85e4b8SEric Auger 977*9a85e4b8SEric Auger b = g_malloc0(sizeof(TestGTreeInterval)); 978*9a85e4b8SEric Auger b->low = 0x4000; 979*9a85e4b8SEric Auger b->high = 0x4FFF; 980*9a85e4b8SEric Auger 981*9a85e4b8SEric Auger map_a = g_malloc0(sizeof(TestGTreeMapping)); 982*9a85e4b8SEric Auger map_a->phys_addr = 0xa000; 983*9a85e4b8SEric Auger map_a->flags = 1; 984*9a85e4b8SEric Auger 985*9a85e4b8SEric Auger map_b = g_malloc0(sizeof(TestGTreeMapping)); 986*9a85e4b8SEric Auger map_b->phys_addr = 0xe0000; 987*9a85e4b8SEric Auger map_b->flags = 2; 988*9a85e4b8SEric Auger 989*9a85e4b8SEric Auger domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp, NULL, 990*9a85e4b8SEric Auger (GDestroyNotify)g_free, 991*9a85e4b8SEric Auger (GDestroyNotify)g_free); 992*9a85e4b8SEric Auger g_tree_insert(domain->mappings, a, map_a); 993*9a85e4b8SEric Auger g_tree_insert(domain->mappings, b, map_b); 994*9a85e4b8SEric Auger return domain; 995*9a85e4b8SEric Auger } 996*9a85e4b8SEric Auger 997*9a85e4b8SEric Auger static void test_gtree_save_domain(void) 998*9a85e4b8SEric Auger { 999*9a85e4b8SEric Auger TestGTreeDomain *first_domain = create_first_domain(); 1000*9a85e4b8SEric Auger 1001*9a85e4b8SEric Auger save_vmstate(&vmstate_domain, first_domain); 1002*9a85e4b8SEric Auger compare_vmstate(first_domain_dump, sizeof(first_domain_dump)); 1003*9a85e4b8SEric Auger destroy_domain(first_domain); 1004*9a85e4b8SEric Auger } 1005*9a85e4b8SEric Auger 1006*9a85e4b8SEric Auger struct match_node_data { 1007*9a85e4b8SEric Auger GTree *tree; 1008*9a85e4b8SEric Auger gpointer key; 1009*9a85e4b8SEric Auger gpointer value; 1010*9a85e4b8SEric Auger }; 1011*9a85e4b8SEric Auger 1012*9a85e4b8SEric Auger struct tree_cmp_data { 1013*9a85e4b8SEric Auger GTree *tree1; 1014*9a85e4b8SEric Auger GTree *tree2; 1015*9a85e4b8SEric Auger GTraverseFunc match_node; 1016*9a85e4b8SEric Auger }; 1017*9a85e4b8SEric Auger 1018*9a85e4b8SEric Auger static gboolean match_interval_mapping_node(gpointer key, 1019*9a85e4b8SEric Auger gpointer value, gpointer data) 1020*9a85e4b8SEric Auger { 1021*9a85e4b8SEric Auger TestGTreeMapping *map_a, *map_b; 1022*9a85e4b8SEric Auger TestGTreeInterval *a, *b; 1023*9a85e4b8SEric Auger struct match_node_data *d = (struct match_node_data *)data; 1024*9a85e4b8SEric Auger char *str = g_strdup_printf("dest"); 1025*9a85e4b8SEric Auger 1026*9a85e4b8SEric Auger g_free(str); 1027*9a85e4b8SEric Auger a = (TestGTreeInterval *)key; 1028*9a85e4b8SEric Auger b = (TestGTreeInterval *)d->key; 1029*9a85e4b8SEric Auger 1030*9a85e4b8SEric Auger map_a = (TestGTreeMapping *)value; 1031*9a85e4b8SEric Auger map_b = (TestGTreeMapping *)d->value; 1032*9a85e4b8SEric Auger 1033*9a85e4b8SEric Auger assert(a->low == b->low); 1034*9a85e4b8SEric Auger assert(a->high == b->high); 1035*9a85e4b8SEric Auger assert(map_a->phys_addr == map_b->phys_addr); 1036*9a85e4b8SEric Auger assert(map_a->flags == map_b->flags); 1037*9a85e4b8SEric Auger g_tree_remove(d->tree, key); 1038*9a85e4b8SEric Auger return true; 1039*9a85e4b8SEric Auger } 1040*9a85e4b8SEric Auger 1041*9a85e4b8SEric Auger static gboolean diff_tree(gpointer key, gpointer value, gpointer data) 1042*9a85e4b8SEric Auger { 1043*9a85e4b8SEric Auger struct tree_cmp_data *tp = (struct tree_cmp_data *)data; 1044*9a85e4b8SEric Auger struct match_node_data d = {tp->tree2, key, value}; 1045*9a85e4b8SEric Auger 1046*9a85e4b8SEric Auger g_tree_foreach(tp->tree2, tp->match_node, &d); 1047*9a85e4b8SEric Auger g_tree_remove(tp->tree1, key); 1048*9a85e4b8SEric Auger return false; 1049*9a85e4b8SEric Auger } 1050*9a85e4b8SEric Auger 1051*9a85e4b8SEric Auger static void compare_trees(GTree *tree1, GTree *tree2, 1052*9a85e4b8SEric Auger GTraverseFunc function) 1053*9a85e4b8SEric Auger { 1054*9a85e4b8SEric Auger struct tree_cmp_data tp = {tree1, tree2, function}; 1055*9a85e4b8SEric Auger 1056*9a85e4b8SEric Auger g_tree_foreach(tree1, diff_tree, &tp); 1057*9a85e4b8SEric Auger assert(g_tree_nnodes(tree1) == 0); 1058*9a85e4b8SEric Auger assert(g_tree_nnodes(tree2) == 0); 1059*9a85e4b8SEric Auger } 1060*9a85e4b8SEric Auger 1061*9a85e4b8SEric Auger static void diff_domain(TestGTreeDomain *d1, TestGTreeDomain *d2) 1062*9a85e4b8SEric Auger { 1063*9a85e4b8SEric Auger assert(d1->id == d2->id); 1064*9a85e4b8SEric Auger compare_trees(d1->mappings, d2->mappings, match_interval_mapping_node); 1065*9a85e4b8SEric Auger } 1066*9a85e4b8SEric Auger 1067*9a85e4b8SEric Auger static gboolean match_domain_node(gpointer key, gpointer value, gpointer data) 1068*9a85e4b8SEric Auger { 1069*9a85e4b8SEric Auger uint64_t id1, id2; 1070*9a85e4b8SEric Auger TestGTreeDomain *d1, *d2; 1071*9a85e4b8SEric Auger struct match_node_data *d = (struct match_node_data *)data; 1072*9a85e4b8SEric Auger 1073*9a85e4b8SEric Auger id1 = (uint64_t)(uintptr_t)key; 1074*9a85e4b8SEric Auger id2 = (uint64_t)(uintptr_t)d->key; 1075*9a85e4b8SEric Auger d1 = (TestGTreeDomain *)value; 1076*9a85e4b8SEric Auger d2 = (TestGTreeDomain *)d->value; 1077*9a85e4b8SEric Auger assert(id1 == id2); 1078*9a85e4b8SEric Auger diff_domain(d1, d2); 1079*9a85e4b8SEric Auger g_tree_remove(d->tree, key); 1080*9a85e4b8SEric Auger return true; 1081*9a85e4b8SEric Auger } 1082*9a85e4b8SEric Auger 1083*9a85e4b8SEric Auger static void diff_iommu(TestGTreeIOMMU *iommu1, TestGTreeIOMMU *iommu2) 1084*9a85e4b8SEric Auger { 1085*9a85e4b8SEric Auger assert(iommu1->id == iommu2->id); 1086*9a85e4b8SEric Auger compare_trees(iommu1->domains, iommu2->domains, match_domain_node); 1087*9a85e4b8SEric Auger } 1088*9a85e4b8SEric Auger 1089*9a85e4b8SEric Auger static void test_gtree_load_domain(void) 1090*9a85e4b8SEric Auger { 1091*9a85e4b8SEric Auger TestGTreeDomain *dest_domain = g_malloc0(sizeof(TestGTreeDomain)); 1092*9a85e4b8SEric Auger TestGTreeDomain *orig_domain = create_first_domain(); 1093*9a85e4b8SEric Auger QEMUFile *fload, *fsave; 1094*9a85e4b8SEric Auger char eof; 1095*9a85e4b8SEric Auger 1096*9a85e4b8SEric Auger fsave = open_test_file(true); 1097*9a85e4b8SEric Auger qemu_put_buffer(fsave, first_domain_dump, sizeof(first_domain_dump)); 1098*9a85e4b8SEric Auger g_assert(!qemu_file_get_error(fsave)); 1099*9a85e4b8SEric Auger qemu_fclose(fsave); 1100*9a85e4b8SEric Auger 1101*9a85e4b8SEric Auger fload = open_test_file(false); 1102*9a85e4b8SEric Auger 1103*9a85e4b8SEric Auger vmstate_load_state(fload, &vmstate_domain, dest_domain, 1); 1104*9a85e4b8SEric Auger eof = qemu_get_byte(fload); 1105*9a85e4b8SEric Auger g_assert(!qemu_file_get_error(fload)); 1106*9a85e4b8SEric Auger g_assert_cmpint(orig_domain->id, ==, dest_domain->id); 1107*9a85e4b8SEric Auger g_assert_cmpint(eof, ==, QEMU_VM_EOF); 1108*9a85e4b8SEric Auger 1109*9a85e4b8SEric Auger diff_domain(orig_domain, dest_domain); 1110*9a85e4b8SEric Auger destroy_domain(orig_domain); 1111*9a85e4b8SEric Auger destroy_domain(dest_domain); 1112*9a85e4b8SEric Auger qemu_fclose(fload); 1113*9a85e4b8SEric Auger } 1114*9a85e4b8SEric Auger 1115*9a85e4b8SEric Auger uint8_t iommu_dump[] = { 1116*9a85e4b8SEric Auger /* iommu id */ 1117*9a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x7, 1118*9a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x2, /* 2 domains */ 1119*9a85e4b8SEric Auger 0x1,/* start of domain 5 */ 1120*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x5, /* key = 5 */ 1121*9a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x5, /* domain1 id */ 1122*9a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x1, /* 1 mapping */ 1123*9a85e4b8SEric Auger 0x1, /* start of mappings */ 1124*9a85e4b8SEric Auger /* c */ 1125*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 1126*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 1127*9a85e4b8SEric Auger /* map_c */ 1128*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 1129*9a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x3, 1130*9a85e4b8SEric Auger 0x0, /* end of domain1 mappings*/ 1131*9a85e4b8SEric Auger 0x1,/* start of domain 6 */ 1132*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x6, /* key = 6 */ 1133*9a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x6, /* domain6 id */ 1134*9a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x2, /* 2 mappings */ 1135*9a85e4b8SEric Auger 0x1, /* start of a */ 1136*9a85e4b8SEric Auger /* a */ 1137*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 1138*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 1139*9a85e4b8SEric Auger /* map_a */ 1140*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 1141*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x01, 1142*9a85e4b8SEric Auger 0x1, /* start of b */ 1143*9a85e4b8SEric Auger /* b */ 1144*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 1145*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF, 1146*9a85e4b8SEric Auger /* map_b */ 1147*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 1148*9a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x02, 1149*9a85e4b8SEric Auger 0x0, /* end of domain6 mappings*/ 1150*9a85e4b8SEric Auger 0x0, /* end of domains */ 1151*9a85e4b8SEric Auger QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 1152*9a85e4b8SEric Auger }; 1153*9a85e4b8SEric Auger 1154*9a85e4b8SEric Auger static TestGTreeIOMMU *create_iommu(void) 1155*9a85e4b8SEric Auger { 1156*9a85e4b8SEric Auger TestGTreeIOMMU *iommu = g_malloc0(sizeof(TestGTreeIOMMU)); 1157*9a85e4b8SEric Auger TestGTreeDomain *first_domain = create_first_domain(); 1158*9a85e4b8SEric Auger TestGTreeDomain *second_domain; 1159*9a85e4b8SEric Auger TestGTreeMapping *map_c; 1160*9a85e4b8SEric Auger TestGTreeInterval *c; 1161*9a85e4b8SEric Auger 1162*9a85e4b8SEric Auger iommu->id = 7; 1163*9a85e4b8SEric Auger iommu->domains = g_tree_new_full((GCompareDataFunc)int_cmp, NULL, 1164*9a85e4b8SEric Auger NULL, 1165*9a85e4b8SEric Auger destroy_domain); 1166*9a85e4b8SEric Auger 1167*9a85e4b8SEric Auger second_domain = g_malloc0(sizeof(TestGTreeDomain)); 1168*9a85e4b8SEric Auger second_domain->id = 5; 1169*9a85e4b8SEric Auger second_domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp, 1170*9a85e4b8SEric Auger NULL, 1171*9a85e4b8SEric Auger (GDestroyNotify)g_free, 1172*9a85e4b8SEric Auger (GDestroyNotify)g_free); 1173*9a85e4b8SEric Auger 1174*9a85e4b8SEric Auger g_tree_insert(iommu->domains, GUINT_TO_POINTER(6), first_domain); 1175*9a85e4b8SEric Auger g_tree_insert(iommu->domains, (gpointer)0x0000000000000005, second_domain); 1176*9a85e4b8SEric Auger 1177*9a85e4b8SEric Auger c = g_malloc0(sizeof(TestGTreeInterval)); 1178*9a85e4b8SEric Auger c->low = 0x1000000; 1179*9a85e4b8SEric Auger c->high = 0x1FFFFFF; 1180*9a85e4b8SEric Auger 1181*9a85e4b8SEric Auger map_c = g_malloc0(sizeof(TestGTreeMapping)); 1182*9a85e4b8SEric Auger map_c->phys_addr = 0xF000000; 1183*9a85e4b8SEric Auger map_c->flags = 0x3; 1184*9a85e4b8SEric Auger 1185*9a85e4b8SEric Auger g_tree_insert(second_domain->mappings, c, map_c); 1186*9a85e4b8SEric Auger return iommu; 1187*9a85e4b8SEric Auger } 1188*9a85e4b8SEric Auger 1189*9a85e4b8SEric Auger static void destroy_iommu(TestGTreeIOMMU *iommu) 1190*9a85e4b8SEric Auger { 1191*9a85e4b8SEric Auger g_tree_destroy(iommu->domains); 1192*9a85e4b8SEric Auger g_free(iommu); 1193*9a85e4b8SEric Auger } 1194*9a85e4b8SEric Auger 1195*9a85e4b8SEric Auger static void test_gtree_save_iommu(void) 1196*9a85e4b8SEric Auger { 1197*9a85e4b8SEric Auger TestGTreeIOMMU *iommu = create_iommu(); 1198*9a85e4b8SEric Auger 1199*9a85e4b8SEric Auger save_vmstate(&vmstate_iommu, iommu); 1200*9a85e4b8SEric Auger compare_vmstate(iommu_dump, sizeof(iommu_dump)); 1201*9a85e4b8SEric Auger destroy_iommu(iommu); 1202*9a85e4b8SEric Auger } 1203*9a85e4b8SEric Auger 1204*9a85e4b8SEric Auger static void test_gtree_load_iommu(void) 1205*9a85e4b8SEric Auger { 1206*9a85e4b8SEric Auger TestGTreeIOMMU *dest_iommu = g_malloc0(sizeof(TestGTreeIOMMU)); 1207*9a85e4b8SEric Auger TestGTreeIOMMU *orig_iommu = create_iommu(); 1208*9a85e4b8SEric Auger QEMUFile *fsave, *fload; 1209*9a85e4b8SEric Auger char eof; 1210*9a85e4b8SEric Auger int ret; 1211*9a85e4b8SEric Auger 1212*9a85e4b8SEric Auger fsave = open_test_file(true); 1213*9a85e4b8SEric Auger qemu_put_buffer(fsave, iommu_dump, sizeof(iommu_dump)); 1214*9a85e4b8SEric Auger g_assert(!qemu_file_get_error(fsave)); 1215*9a85e4b8SEric Auger qemu_fclose(fsave); 1216*9a85e4b8SEric Auger 1217*9a85e4b8SEric Auger fload = open_test_file(false); 1218*9a85e4b8SEric Auger vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1); 1219*9a85e4b8SEric Auger ret = qemu_file_get_error(fload); 1220*9a85e4b8SEric Auger eof = qemu_get_byte(fload); 1221*9a85e4b8SEric Auger ret = qemu_file_get_error(fload); 1222*9a85e4b8SEric Auger g_assert(!ret); 1223*9a85e4b8SEric Auger g_assert_cmpint(orig_iommu->id, ==, dest_iommu->id); 1224*9a85e4b8SEric Auger g_assert_cmpint(eof, ==, QEMU_VM_EOF); 1225*9a85e4b8SEric Auger 1226*9a85e4b8SEric Auger diff_iommu(orig_iommu, dest_iommu); 1227*9a85e4b8SEric Auger destroy_iommu(orig_iommu); 1228*9a85e4b8SEric Auger destroy_iommu(dest_iommu); 1229*9a85e4b8SEric Auger qemu_fclose(fload); 1230*9a85e4b8SEric Auger } 1231*9a85e4b8SEric Auger 12325c379d90SDr. David Alan Gilbert typedef struct TmpTestStruct { 12335c379d90SDr. David Alan Gilbert TestStruct *parent; 12345c379d90SDr. David Alan Gilbert int64_t diff; 12355c379d90SDr. David Alan Gilbert } TmpTestStruct; 12365c379d90SDr. David Alan Gilbert 123744b1ff31SDr. David Alan Gilbert static int tmp_child_pre_save(void *opaque) 12385c379d90SDr. David Alan Gilbert { 12395c379d90SDr. David Alan Gilbert struct TmpTestStruct *tts = opaque; 12405c379d90SDr. David Alan Gilbert 12415c379d90SDr. David Alan Gilbert tts->diff = tts->parent->b - tts->parent->a; 124244b1ff31SDr. David Alan Gilbert 124344b1ff31SDr. David Alan Gilbert return 0; 12445c379d90SDr. David Alan Gilbert } 12455c379d90SDr. David Alan Gilbert 12465c379d90SDr. David Alan Gilbert static int tmp_child_post_load(void *opaque, int version_id) 12475c379d90SDr. David Alan Gilbert { 12485c379d90SDr. David Alan Gilbert struct TmpTestStruct *tts = opaque; 12495c379d90SDr. David Alan Gilbert 12505c379d90SDr. David Alan Gilbert tts->parent->b = tts->parent->a + tts->diff; 12515c379d90SDr. David Alan Gilbert 12525c379d90SDr. David Alan Gilbert return 0; 12535c379d90SDr. David Alan Gilbert } 12545c379d90SDr. David Alan Gilbert 12555c379d90SDr. David Alan Gilbert static const VMStateDescription vmstate_tmp_back_to_parent = { 12565c379d90SDr. David Alan Gilbert .name = "test/tmp_child_parent", 12575c379d90SDr. David Alan Gilbert .fields = (VMStateField[]) { 12585c379d90SDr. David Alan Gilbert VMSTATE_UINT64(f, TestStruct), 12595c379d90SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 12605c379d90SDr. David Alan Gilbert } 12615c379d90SDr. David Alan Gilbert }; 12625c379d90SDr. David Alan Gilbert 12635c379d90SDr. David Alan Gilbert static const VMStateDescription vmstate_tmp_child = { 12645c379d90SDr. David Alan Gilbert .name = "test/tmp_child", 12655c379d90SDr. David Alan Gilbert .pre_save = tmp_child_pre_save, 12665c379d90SDr. David Alan Gilbert .post_load = tmp_child_post_load, 12675c379d90SDr. David Alan Gilbert .fields = (VMStateField[]) { 12685c379d90SDr. David Alan Gilbert VMSTATE_INT64(diff, TmpTestStruct), 12695c379d90SDr. David Alan Gilbert VMSTATE_STRUCT_POINTER(parent, TmpTestStruct, 12705c379d90SDr. David Alan Gilbert vmstate_tmp_back_to_parent, TestStruct), 12715c379d90SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 12725c379d90SDr. David Alan Gilbert } 12735c379d90SDr. David Alan Gilbert }; 12745c379d90SDr. David Alan Gilbert 12755c379d90SDr. David Alan Gilbert static const VMStateDescription vmstate_with_tmp = { 12765c379d90SDr. David Alan Gilbert .name = "test/with_tmp", 12775c379d90SDr. David Alan Gilbert .version_id = 1, 12785c379d90SDr. David Alan Gilbert .fields = (VMStateField[]) { 12795c379d90SDr. David Alan Gilbert VMSTATE_UINT32(a, TestStruct), 12805c379d90SDr. David Alan Gilbert VMSTATE_UINT64(d, TestStruct), 12815c379d90SDr. David Alan Gilbert VMSTATE_WITH_TMP(TestStruct, TmpTestStruct, vmstate_tmp_child), 12825c379d90SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 12835c379d90SDr. David Alan Gilbert } 12845c379d90SDr. David Alan Gilbert }; 12855c379d90SDr. David Alan Gilbert 12865c379d90SDr. David Alan Gilbert static void obj_tmp_copy(void *target, void *source) 12875c379d90SDr. David Alan Gilbert { 12885c379d90SDr. David Alan Gilbert memcpy(target, source, sizeof(TestStruct)); 12895c379d90SDr. David Alan Gilbert } 12905c379d90SDr. David Alan Gilbert 12915c379d90SDr. David Alan Gilbert static void test_tmp_struct(void) 12925c379d90SDr. David Alan Gilbert { 12935c379d90SDr. David Alan Gilbert TestStruct obj, obj_clone; 12945c379d90SDr. David Alan Gilbert 12955c379d90SDr. David Alan Gilbert uint8_t const wire_with_tmp[] = { 12965c379d90SDr. David Alan Gilbert /* u32 a */ 0x00, 0x00, 0x00, 0x02, 12975c379d90SDr. David Alan Gilbert /* u64 d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 12985c379d90SDr. David Alan Gilbert /* diff */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 12995c379d90SDr. David Alan Gilbert /* u64 f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 13005c379d90SDr. David Alan Gilbert QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 13015c379d90SDr. David Alan Gilbert }; 13025c379d90SDr. David Alan Gilbert 13035c379d90SDr. David Alan Gilbert memset(&obj, 0, sizeof(obj)); 13045c379d90SDr. David Alan Gilbert obj.a = 2; 13055c379d90SDr. David Alan Gilbert obj.b = 4; 13065c379d90SDr. David Alan Gilbert obj.d = 1; 13075c379d90SDr. David Alan Gilbert obj.f = 8; 13085c379d90SDr. David Alan Gilbert save_vmstate(&vmstate_with_tmp, &obj); 13095c379d90SDr. David Alan Gilbert 13105c379d90SDr. David Alan Gilbert compare_vmstate(wire_with_tmp, sizeof(wire_with_tmp)); 13115c379d90SDr. David Alan Gilbert 13125c379d90SDr. David Alan Gilbert memset(&obj, 0, sizeof(obj)); 13135c379d90SDr. David Alan Gilbert SUCCESS(load_vmstate(&vmstate_with_tmp, &obj, &obj_clone, 13145c379d90SDr. David Alan Gilbert obj_tmp_copy, 1, wire_with_tmp, 13155c379d90SDr. David Alan Gilbert sizeof(wire_with_tmp))); 13165c379d90SDr. David Alan Gilbert g_assert_cmpint(obj.a, ==, 2); /* From top level vmsd */ 13175c379d90SDr. David Alan Gilbert g_assert_cmpint(obj.b, ==, 4); /* from the post_load */ 13185c379d90SDr. David Alan Gilbert g_assert_cmpint(obj.d, ==, 1); /* From top level vmsd */ 13195c379d90SDr. David Alan Gilbert g_assert_cmpint(obj.f, ==, 8); /* From the child->parent */ 13205c379d90SDr. David Alan Gilbert } 13215c379d90SDr. David Alan Gilbert 13222668b4bfSEduardo Habkost int main(int argc, char **argv) 13232668b4bfSEduardo Habkost { 13242668b4bfSEduardo Habkost temp_fd = mkstemp(temp_file); 13252668b4bfSEduardo Habkost 13268925839fSDaniel P. Berrange module_call_init(MODULE_INIT_QOM); 13278925839fSDaniel P. Berrange 1328977a7204SDaniel P. Berrangé setenv("QTEST_SILENT_ERRORS", "1", 1); 1329977a7204SDaniel P. Berrangé 13302668b4bfSEduardo Habkost g_test_init(&argc, &argv, NULL); 13314ea7df4eSJuan Quintela g_test_add_func("/vmstate/simple/primitive", test_simple_primitive); 1332b95d6588SMarc-André Lureau g_test_add_func("/vmstate/simple/array", test_simple_array); 13332668b4bfSEduardo Habkost g_test_add_func("/vmstate/versioned/load/v1", test_load_v1); 13342668b4bfSEduardo Habkost g_test_add_func("/vmstate/versioned/load/v2", test_load_v2); 13352668b4bfSEduardo Habkost g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip); 13362668b4bfSEduardo Habkost g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip); 13372668b4bfSEduardo Habkost g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip); 13382668b4bfSEduardo Habkost g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip); 13398cc49f03SHalil Pasic g_test_add_func("/vmstate/array/ptr/str/no0/save", 13408cc49f03SHalil Pasic test_arr_ptr_str_no0_save); 13418cc49f03SHalil Pasic g_test_add_func("/vmstate/array/ptr/str/no0/load", 13428cc49f03SHalil Pasic test_arr_ptr_str_no0_load); 1343cc958831SHalil Pasic g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save); 1344cc958831SHalil Pasic g_test_add_func("/vmstate/array/ptr/str/0/load", 1345cc958831SHalil Pasic test_arr_ptr_str_0_load); 134643333099SHalil Pasic g_test_add_func("/vmstate/array/ptr/prim/0/save", 134743333099SHalil Pasic test_arr_ptr_prim_0_save); 134843333099SHalil Pasic g_test_add_func("/vmstate/array/ptr/prim/0/load", 134943333099SHalil Pasic test_arr_ptr_prim_0_load); 13507e99f22cSJianjun Duan g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q); 13517e99f22cSJianjun Duan g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q); 1352*9a85e4b8SEric Auger g_test_add_func("/vmstate/gtree/save/savedomain", test_gtree_save_domain); 1353*9a85e4b8SEric Auger g_test_add_func("/vmstate/gtree/load/loaddomain", test_gtree_load_domain); 1354*9a85e4b8SEric Auger g_test_add_func("/vmstate/gtree/save/saveiommu", test_gtree_save_iommu); 1355*9a85e4b8SEric Auger g_test_add_func("/vmstate/gtree/load/loadiommu", test_gtree_load_iommu); 13565c379d90SDr. David Alan Gilbert g_test_add_func("/vmstate/tmp_struct", test_tmp_struct); 13572668b4bfSEduardo Habkost g_test_run(); 13582668b4bfSEduardo Habkost 13592668b4bfSEduardo Habkost close(temp_fd); 13602668b4bfSEduardo Habkost unlink(temp_file); 13612668b4bfSEduardo Habkost 13622668b4bfSEduardo Habkost return 0; 13632668b4bfSEduardo Habkost } 1364