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 int temp_fd; 382668b4bfSEduardo Habkost 399935bacaSDr. David Alan Gilbert 402668b4bfSEduardo Habkost /* Duplicate temp_fd and seek to the beginning of the file */ 41c6f6646cSJuan Quintela static QEMUFile *open_test_file(bool write) 422668b4bfSEduardo Habkost { 431c861885SPeter Maydell int fd; 448925839fSDaniel P. Berrange QIOChannel *ioc; 454ae3c0e2SMarc-André Lureau QEMUFile *f; 464ae3c0e2SMarc-André Lureau 471c861885SPeter Maydell fd = dup(temp_fd); 481c861885SPeter Maydell g_assert(fd >= 0); 492668b4bfSEduardo Habkost lseek(fd, 0, SEEK_SET); 50c6f6646cSJuan Quintela if (write) { 512668b4bfSEduardo Habkost g_assert_cmpint(ftruncate(fd, 0), ==, 0); 522668b4bfSEduardo Habkost } 538925839fSDaniel P. Berrange ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd)); 548925839fSDaniel P. Berrange if (write) { 554ae3c0e2SMarc-André Lureau f = qemu_fopen_channel_output(ioc); 568925839fSDaniel P. Berrange } else { 574ae3c0e2SMarc-André Lureau f = qemu_fopen_channel_input(ioc); 588925839fSDaniel P. Berrange } 594ae3c0e2SMarc-André Lureau object_unref(OBJECT(ioc)); 604ae3c0e2SMarc-André Lureau return f; 612668b4bfSEduardo Habkost } 622668b4bfSEduardo Habkost 634ea7df4eSJuan Quintela #define SUCCESS(val) \ 644ea7df4eSJuan Quintela g_assert_cmpint((val), ==, 0) 654ea7df4eSJuan Quintela 664ea7df4eSJuan Quintela #define FAILURE(val) \ 674ea7df4eSJuan Quintela g_assert_cmpint((val), !=, 0) 684ea7df4eSJuan Quintela 694ea7df4eSJuan Quintela static void save_vmstate(const VMStateDescription *desc, void *obj) 704ea7df4eSJuan Quintela { 714ea7df4eSJuan Quintela QEMUFile *f = open_test_file(true); 724ea7df4eSJuan Quintela 734ea7df4eSJuan Quintela /* Save file with vmstate */ 742f168d07SDr. David Alan Gilbert int ret = vmstate_save_state(f, desc, obj, NULL); 752f168d07SDr. David Alan Gilbert g_assert(!ret); 764ea7df4eSJuan Quintela qemu_put_byte(f, QEMU_VM_EOF); 774ea7df4eSJuan Quintela g_assert(!qemu_file_get_error(f)); 784ea7df4eSJuan Quintela qemu_fclose(f); 794ea7df4eSJuan Quintela } 804ea7df4eSJuan Quintela 816d57b4c0SHalil Pasic static void save_buffer(const uint8_t *buf, size_t buf_size) 826d57b4c0SHalil Pasic { 836d57b4c0SHalil Pasic QEMUFile *fsave = open_test_file(true); 846d57b4c0SHalil Pasic qemu_put_buffer(fsave, buf, buf_size); 856d57b4c0SHalil Pasic qemu_fclose(fsave); 866d57b4c0SHalil Pasic } 876d57b4c0SHalil Pasic 885c379d90SDr. David Alan Gilbert static void compare_vmstate(const uint8_t *wire, size_t size) 894ea7df4eSJuan Quintela { 904ea7df4eSJuan Quintela QEMUFile *f = open_test_file(false); 914ea7df4eSJuan Quintela uint8_t result[size]; 924ea7df4eSJuan Quintela 934ea7df4eSJuan Quintela /* read back as binary */ 944ea7df4eSJuan Quintela 954ea7df4eSJuan Quintela g_assert_cmpint(qemu_get_buffer(f, result, sizeof(result)), ==, 964ea7df4eSJuan Quintela sizeof(result)); 974ea7df4eSJuan Quintela g_assert(!qemu_file_get_error(f)); 984ea7df4eSJuan Quintela 994ea7df4eSJuan Quintela /* Compare that what is on the file is the same that what we 1004ea7df4eSJuan Quintela expected to be there */ 1014ea7df4eSJuan Quintela SUCCESS(memcmp(result, wire, sizeof(result))); 1024ea7df4eSJuan Quintela 1034ea7df4eSJuan Quintela /* Must reach EOF */ 1044ea7df4eSJuan Quintela qemu_get_byte(f); 1054ea7df4eSJuan Quintela g_assert_cmpint(qemu_file_get_error(f), ==, -EIO); 1064ea7df4eSJuan Quintela 1074ea7df4eSJuan Quintela qemu_fclose(f); 1084ea7df4eSJuan Quintela } 1094ea7df4eSJuan Quintela 1104ea7df4eSJuan Quintela static int load_vmstate_one(const VMStateDescription *desc, void *obj, 1115c379d90SDr. David Alan Gilbert int version, const uint8_t *wire, size_t size) 1124ea7df4eSJuan Quintela { 1134ea7df4eSJuan Quintela QEMUFile *f; 1144ea7df4eSJuan Quintela int ret; 1154ea7df4eSJuan Quintela 1164ea7df4eSJuan Quintela f = open_test_file(true); 1174ea7df4eSJuan Quintela qemu_put_buffer(f, wire, size); 1184ea7df4eSJuan Quintela qemu_fclose(f); 1194ea7df4eSJuan Quintela 1204ea7df4eSJuan Quintela f = open_test_file(false); 1214ea7df4eSJuan Quintela ret = vmstate_load_state(f, desc, obj, version); 1224ea7df4eSJuan Quintela if (ret) { 1234ea7df4eSJuan Quintela g_assert(qemu_file_get_error(f)); 1244ea7df4eSJuan Quintela } else{ 1254ea7df4eSJuan Quintela g_assert(!qemu_file_get_error(f)); 1264ea7df4eSJuan Quintela } 1274ea7df4eSJuan Quintela qemu_fclose(f); 1284ea7df4eSJuan Quintela return ret; 1294ea7df4eSJuan Quintela } 1304ea7df4eSJuan Quintela 1314ea7df4eSJuan Quintela 1324ea7df4eSJuan Quintela static int load_vmstate(const VMStateDescription *desc, 1334ea7df4eSJuan Quintela void *obj, void *obj_clone, 1344ea7df4eSJuan Quintela void (*obj_copy)(void *, void*), 1355c379d90SDr. David Alan Gilbert int version, const uint8_t *wire, size_t size) 1364ea7df4eSJuan Quintela { 1374ea7df4eSJuan Quintela /* We test with zero size */ 1384ea7df4eSJuan Quintela obj_copy(obj_clone, obj); 1394ea7df4eSJuan Quintela FAILURE(load_vmstate_one(desc, obj, version, wire, 0)); 1404ea7df4eSJuan Quintela 1414ea7df4eSJuan Quintela /* Stream ends with QEMU_EOF, so we need at least 3 bytes to be 1424ea7df4eSJuan Quintela * able to test in the middle */ 1434ea7df4eSJuan Quintela 1444ea7df4eSJuan Quintela if (size > 3) { 1454ea7df4eSJuan Quintela 1464ea7df4eSJuan Quintela /* We test with size - 2. We can't test size - 1 due to EOF tricks */ 1474ea7df4eSJuan Quintela obj_copy(obj, obj_clone); 1484ea7df4eSJuan Quintela FAILURE(load_vmstate_one(desc, obj, version, wire, size - 2)); 1494ea7df4eSJuan Quintela 1504ea7df4eSJuan Quintela /* Test with size/2, first half of real state */ 1514ea7df4eSJuan Quintela obj_copy(obj, obj_clone); 1524ea7df4eSJuan Quintela FAILURE(load_vmstate_one(desc, obj, version, wire, size/2)); 1534ea7df4eSJuan Quintela 1544ea7df4eSJuan Quintela /* Test with size/2, second half of real state */ 1554ea7df4eSJuan Quintela obj_copy(obj, obj_clone); 1564ea7df4eSJuan Quintela FAILURE(load_vmstate_one(desc, obj, version, wire + (size/2), size/2)); 1574ea7df4eSJuan Quintela 1584ea7df4eSJuan Quintela } 1594ea7df4eSJuan Quintela obj_copy(obj, obj_clone); 1604ea7df4eSJuan Quintela return load_vmstate_one(desc, obj, version, wire, size); 1614ea7df4eSJuan Quintela } 1624ea7df4eSJuan Quintela 1634ea7df4eSJuan Quintela /* Test struct that we are going to use for our tests */ 1644ea7df4eSJuan Quintela 1654ea7df4eSJuan Quintela typedef struct TestSimple { 1664ea7df4eSJuan Quintela bool b_1, b_2; 1674ea7df4eSJuan Quintela uint8_t u8_1; 1684ea7df4eSJuan Quintela uint16_t u16_1; 1694ea7df4eSJuan Quintela uint32_t u32_1; 1704ea7df4eSJuan Quintela uint64_t u64_1; 1714ea7df4eSJuan Quintela int8_t i8_1, i8_2; 1724ea7df4eSJuan Quintela int16_t i16_1, i16_2; 1734ea7df4eSJuan Quintela int32_t i32_1, i32_2; 1744ea7df4eSJuan Quintela int64_t i64_1, i64_2; 1754ea7df4eSJuan Quintela } TestSimple; 1764ea7df4eSJuan Quintela 1774ea7df4eSJuan Quintela /* Object instantiation, we are going to use it in more than one test */ 1784ea7df4eSJuan Quintela 1794ea7df4eSJuan Quintela TestSimple obj_simple = { 1804ea7df4eSJuan Quintela .b_1 = true, 1814ea7df4eSJuan Quintela .b_2 = false, 1824ea7df4eSJuan Quintela .u8_1 = 130, 1834ea7df4eSJuan Quintela .u16_1 = 512, 1844ea7df4eSJuan Quintela .u32_1 = 70000, 1854ea7df4eSJuan Quintela .u64_1 = 12121212, 1864ea7df4eSJuan Quintela .i8_1 = 65, 1874ea7df4eSJuan Quintela .i8_2 = -65, 1884ea7df4eSJuan Quintela .i16_1 = 512, 1894ea7df4eSJuan Quintela .i16_2 = -512, 1904ea7df4eSJuan Quintela .i32_1 = 70000, 1914ea7df4eSJuan Quintela .i32_2 = -70000, 1924ea7df4eSJuan Quintela .i64_1 = 12121212, 1934ea7df4eSJuan Quintela .i64_2 = -12121212, 1944ea7df4eSJuan Quintela }; 1954ea7df4eSJuan Quintela 1964ea7df4eSJuan Quintela /* Description of the values. If you add a primitive type 1974ea7df4eSJuan Quintela you are expected to add a test here */ 1984ea7df4eSJuan Quintela 1994ea7df4eSJuan Quintela static const VMStateDescription vmstate_simple_primitive = { 2004ea7df4eSJuan Quintela .name = "simple/primitive", 2014ea7df4eSJuan Quintela .version_id = 1, 2024ea7df4eSJuan Quintela .minimum_version_id = 1, 2034ea7df4eSJuan Quintela .fields = (VMStateField[]) { 2044ea7df4eSJuan Quintela VMSTATE_BOOL(b_1, TestSimple), 2054ea7df4eSJuan Quintela VMSTATE_BOOL(b_2, TestSimple), 2064ea7df4eSJuan Quintela VMSTATE_UINT8(u8_1, TestSimple), 2074ea7df4eSJuan Quintela VMSTATE_UINT16(u16_1, TestSimple), 2084ea7df4eSJuan Quintela VMSTATE_UINT32(u32_1, TestSimple), 2094ea7df4eSJuan Quintela VMSTATE_UINT64(u64_1, TestSimple), 2104ea7df4eSJuan Quintela VMSTATE_INT8(i8_1, TestSimple), 2114ea7df4eSJuan Quintela VMSTATE_INT8(i8_2, TestSimple), 2124ea7df4eSJuan Quintela VMSTATE_INT16(i16_1, TestSimple), 2134ea7df4eSJuan Quintela VMSTATE_INT16(i16_2, TestSimple), 2144ea7df4eSJuan Quintela VMSTATE_INT32(i32_1, TestSimple), 2154ea7df4eSJuan Quintela VMSTATE_INT32(i32_2, TestSimple), 2164ea7df4eSJuan Quintela VMSTATE_INT64(i64_1, TestSimple), 2174ea7df4eSJuan Quintela VMSTATE_INT64(i64_2, TestSimple), 2184ea7df4eSJuan Quintela VMSTATE_END_OF_LIST() 2194ea7df4eSJuan Quintela } 2204ea7df4eSJuan Quintela }; 2214ea7df4eSJuan Quintela 2224ea7df4eSJuan Quintela /* It describes what goes through the wire. Our tests are basically: 2234ea7df4eSJuan Quintela 2244ea7df4eSJuan Quintela * save test 2254ea7df4eSJuan Quintela - save a struct a vmstate to a file 2264ea7df4eSJuan Quintela - read that file back (binary read, no vmstate) 2274ea7df4eSJuan Quintela - compare it with what we expect to be on the wire 2284ea7df4eSJuan Quintela * load test 2294ea7df4eSJuan Quintela - save to the file what we expect to be on the wire 2304ea7df4eSJuan Quintela - read struct back with vmstate in a different 2314ea7df4eSJuan Quintela - compare back with the original struct 2324ea7df4eSJuan Quintela */ 2334ea7df4eSJuan Quintela 2344ea7df4eSJuan Quintela uint8_t wire_simple_primitive[] = { 2354ea7df4eSJuan Quintela /* b_1 */ 0x01, 2364ea7df4eSJuan Quintela /* b_2 */ 0x00, 2374ea7df4eSJuan Quintela /* u8_1 */ 0x82, 2384ea7df4eSJuan Quintela /* u16_1 */ 0x02, 0x00, 2394ea7df4eSJuan Quintela /* u32_1 */ 0x00, 0x01, 0x11, 0x70, 2404ea7df4eSJuan Quintela /* u64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c, 2414ea7df4eSJuan Quintela /* i8_1 */ 0x41, 2424ea7df4eSJuan Quintela /* i8_2 */ 0xbf, 2434ea7df4eSJuan Quintela /* i16_1 */ 0x02, 0x00, 2444ea7df4eSJuan Quintela /* i16_2 */ 0xfe, 0x0, 2454ea7df4eSJuan Quintela /* i32_1 */ 0x00, 0x01, 0x11, 0x70, 2464ea7df4eSJuan Quintela /* i32_2 */ 0xff, 0xfe, 0xee, 0x90, 2474ea7df4eSJuan Quintela /* i64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c, 2484ea7df4eSJuan Quintela /* i64_2 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x0b, 0x84, 2494ea7df4eSJuan Quintela QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 2504ea7df4eSJuan Quintela }; 2514ea7df4eSJuan Quintela 2524ea7df4eSJuan Quintela static void obj_simple_copy(void *target, void *source) 2534ea7df4eSJuan Quintela { 2544ea7df4eSJuan Quintela memcpy(target, source, sizeof(TestSimple)); 2554ea7df4eSJuan Quintela } 2564ea7df4eSJuan Quintela 2574ea7df4eSJuan Quintela static void test_simple_primitive(void) 2584ea7df4eSJuan Quintela { 2594ea7df4eSJuan Quintela TestSimple obj, obj_clone; 2604ea7df4eSJuan Quintela 2614ea7df4eSJuan Quintela memset(&obj, 0, sizeof(obj)); 2624ea7df4eSJuan Quintela save_vmstate(&vmstate_simple_primitive, &obj_simple); 2634ea7df4eSJuan Quintela 2644ea7df4eSJuan Quintela compare_vmstate(wire_simple_primitive, sizeof(wire_simple_primitive)); 2654ea7df4eSJuan Quintela 2664ea7df4eSJuan Quintela SUCCESS(load_vmstate(&vmstate_simple_primitive, &obj, &obj_clone, 2674ea7df4eSJuan Quintela obj_simple_copy, 1, wire_simple_primitive, 2684ea7df4eSJuan Quintela sizeof(wire_simple_primitive))); 2694ea7df4eSJuan Quintela 2704ea7df4eSJuan Quintela #define FIELD_EQUAL(name) g_assert_cmpint(obj.name, ==, obj_simple.name) 2714ea7df4eSJuan Quintela 2724ea7df4eSJuan Quintela FIELD_EQUAL(b_1); 2734ea7df4eSJuan Quintela FIELD_EQUAL(b_2); 2744ea7df4eSJuan Quintela FIELD_EQUAL(u8_1); 2754ea7df4eSJuan Quintela FIELD_EQUAL(u16_1); 2764ea7df4eSJuan Quintela FIELD_EQUAL(u32_1); 2774ea7df4eSJuan Quintela FIELD_EQUAL(u64_1); 2784ea7df4eSJuan Quintela FIELD_EQUAL(i8_1); 2794ea7df4eSJuan Quintela FIELD_EQUAL(i8_2); 2804ea7df4eSJuan Quintela FIELD_EQUAL(i16_1); 2814ea7df4eSJuan Quintela FIELD_EQUAL(i16_2); 2824ea7df4eSJuan Quintela FIELD_EQUAL(i32_1); 2834ea7df4eSJuan Quintela FIELD_EQUAL(i32_2); 2844ea7df4eSJuan Quintela FIELD_EQUAL(i64_1); 2854ea7df4eSJuan Quintela FIELD_EQUAL(i64_2); 2864ea7df4eSJuan Quintela } 2874ea7df4eSJuan Quintela 288b95d6588SMarc-André Lureau typedef struct TestSimpleArray { 289b95d6588SMarc-André Lureau uint16_t u16_1[3]; 290b95d6588SMarc-André Lureau } TestSimpleArray; 291b95d6588SMarc-André Lureau 292b95d6588SMarc-André Lureau /* Object instantiation, we are going to use it in more than one test */ 293b95d6588SMarc-André Lureau 294b95d6588SMarc-André Lureau TestSimpleArray obj_simple_arr = { 295b95d6588SMarc-André Lureau .u16_1 = { 0x42, 0x43, 0x44 }, 296b95d6588SMarc-André Lureau }; 297b95d6588SMarc-André Lureau 298b95d6588SMarc-André Lureau /* Description of the values. If you add a primitive type 299b95d6588SMarc-André Lureau you are expected to add a test here */ 300b95d6588SMarc-André Lureau 301b95d6588SMarc-André Lureau static const VMStateDescription vmstate_simple_arr = { 302b95d6588SMarc-André Lureau .name = "simple/array", 303b95d6588SMarc-André Lureau .version_id = 1, 304b95d6588SMarc-André Lureau .minimum_version_id = 1, 305b95d6588SMarc-André Lureau .fields = (VMStateField[]) { 306b95d6588SMarc-André Lureau VMSTATE_UINT16_ARRAY(u16_1, TestSimpleArray, 3), 307b95d6588SMarc-André Lureau VMSTATE_END_OF_LIST() 308b95d6588SMarc-André Lureau } 309b95d6588SMarc-André Lureau }; 310b95d6588SMarc-André Lureau 311b95d6588SMarc-André Lureau uint8_t wire_simple_arr[] = { 312b95d6588SMarc-André Lureau /* u16_1 */ 0x00, 0x42, 313b95d6588SMarc-André Lureau /* u16_1 */ 0x00, 0x43, 314b95d6588SMarc-André Lureau /* u16_1 */ 0x00, 0x44, 315b95d6588SMarc-André Lureau QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 316b95d6588SMarc-André Lureau }; 317b95d6588SMarc-André Lureau 318b95d6588SMarc-André Lureau static void obj_simple_arr_copy(void *target, void *source) 319b95d6588SMarc-André Lureau { 320b95d6588SMarc-André Lureau memcpy(target, source, sizeof(TestSimpleArray)); 321b95d6588SMarc-André Lureau } 322b95d6588SMarc-André Lureau 323b95d6588SMarc-André Lureau static void test_simple_array(void) 324b95d6588SMarc-André Lureau { 325b95d6588SMarc-André Lureau TestSimpleArray obj, obj_clone; 326b95d6588SMarc-André Lureau 327b95d6588SMarc-André Lureau memset(&obj, 0, sizeof(obj)); 328b95d6588SMarc-André Lureau save_vmstate(&vmstate_simple_arr, &obj_simple_arr); 329b95d6588SMarc-André Lureau 330b95d6588SMarc-André Lureau compare_vmstate(wire_simple_arr, sizeof(wire_simple_arr)); 331b95d6588SMarc-André Lureau 332b95d6588SMarc-André Lureau SUCCESS(load_vmstate(&vmstate_simple_arr, &obj, &obj_clone, 333b95d6588SMarc-André Lureau obj_simple_arr_copy, 1, wire_simple_arr, 334b95d6588SMarc-André Lureau sizeof(wire_simple_arr))); 335b95d6588SMarc-André Lureau } 336b95d6588SMarc-André Lureau 3374ea7df4eSJuan Quintela typedef struct TestStruct { 3382668b4bfSEduardo Habkost uint32_t a, b, c, e; 3392668b4bfSEduardo Habkost uint64_t d, f; 3402668b4bfSEduardo Habkost bool skip_c_e; 3412668b4bfSEduardo Habkost } TestStruct; 3422668b4bfSEduardo Habkost 3432668b4bfSEduardo Habkost static const VMStateDescription vmstate_versioned = { 3444ea7df4eSJuan Quintela .name = "test/versioned", 3452668b4bfSEduardo Habkost .version_id = 2, 3462668b4bfSEduardo Habkost .minimum_version_id = 1, 3472668b4bfSEduardo Habkost .fields = (VMStateField[]) { 3482668b4bfSEduardo Habkost VMSTATE_UINT32(a, TestStruct), 3492668b4bfSEduardo Habkost VMSTATE_UINT32_V(b, TestStruct, 2), /* Versioned field in the middle, so 3502668b4bfSEduardo Habkost * we catch bugs more easily. 3512668b4bfSEduardo Habkost */ 3522668b4bfSEduardo Habkost VMSTATE_UINT32(c, TestStruct), 3532668b4bfSEduardo Habkost VMSTATE_UINT64(d, TestStruct), 3542668b4bfSEduardo Habkost VMSTATE_UINT32_V(e, TestStruct, 2), 3552668b4bfSEduardo Habkost VMSTATE_UINT64_V(f, TestStruct, 2), 3562668b4bfSEduardo Habkost VMSTATE_END_OF_LIST() 3572668b4bfSEduardo Habkost } 3582668b4bfSEduardo Habkost }; 3592668b4bfSEduardo Habkost 3602668b4bfSEduardo Habkost static void test_load_v1(void) 3612668b4bfSEduardo Habkost { 3622668b4bfSEduardo Habkost uint8_t buf[] = { 3632668b4bfSEduardo Habkost 0, 0, 0, 10, /* a */ 3642668b4bfSEduardo Habkost 0, 0, 0, 30, /* c */ 3652668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 40, /* d */ 3662668b4bfSEduardo Habkost QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 3672668b4bfSEduardo Habkost }; 3686d57b4c0SHalil Pasic save_buffer(buf, sizeof(buf)); 3692668b4bfSEduardo Habkost 370c6f6646cSJuan Quintela QEMUFile *loading = open_test_file(false); 3712668b4bfSEduardo Habkost TestStruct obj = { .b = 200, .e = 500, .f = 600 }; 3722668b4bfSEduardo Habkost vmstate_load_state(loading, &vmstate_versioned, &obj, 1); 3732668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(loading)); 3742668b4bfSEduardo Habkost g_assert_cmpint(obj.a, ==, 10); 3752668b4bfSEduardo Habkost g_assert_cmpint(obj.b, ==, 200); 3762668b4bfSEduardo Habkost g_assert_cmpint(obj.c, ==, 30); 3772668b4bfSEduardo Habkost g_assert_cmpint(obj.d, ==, 40); 3782668b4bfSEduardo Habkost g_assert_cmpint(obj.e, ==, 500); 3792668b4bfSEduardo Habkost g_assert_cmpint(obj.f, ==, 600); 3802668b4bfSEduardo Habkost qemu_fclose(loading); 3812668b4bfSEduardo Habkost } 3822668b4bfSEduardo Habkost 3832668b4bfSEduardo Habkost static void test_load_v2(void) 3842668b4bfSEduardo Habkost { 3852668b4bfSEduardo Habkost uint8_t buf[] = { 3862668b4bfSEduardo Habkost 0, 0, 0, 10, /* a */ 3872668b4bfSEduardo Habkost 0, 0, 0, 20, /* b */ 3882668b4bfSEduardo Habkost 0, 0, 0, 30, /* c */ 3892668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 40, /* d */ 3902668b4bfSEduardo Habkost 0, 0, 0, 50, /* e */ 3912668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 60, /* f */ 3922668b4bfSEduardo Habkost QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 3932668b4bfSEduardo Habkost }; 3946d57b4c0SHalil Pasic save_buffer(buf, sizeof(buf)); 3952668b4bfSEduardo Habkost 396c6f6646cSJuan Quintela QEMUFile *loading = open_test_file(false); 3972668b4bfSEduardo Habkost TestStruct obj; 3982668b4bfSEduardo Habkost vmstate_load_state(loading, &vmstate_versioned, &obj, 2); 3992668b4bfSEduardo Habkost g_assert_cmpint(obj.a, ==, 10); 4002668b4bfSEduardo Habkost g_assert_cmpint(obj.b, ==, 20); 4012668b4bfSEduardo Habkost g_assert_cmpint(obj.c, ==, 30); 4022668b4bfSEduardo Habkost g_assert_cmpint(obj.d, ==, 40); 4032668b4bfSEduardo Habkost g_assert_cmpint(obj.e, ==, 50); 4042668b4bfSEduardo Habkost g_assert_cmpint(obj.f, ==, 60); 4052668b4bfSEduardo Habkost qemu_fclose(loading); 4062668b4bfSEduardo Habkost } 4072668b4bfSEduardo Habkost 4082668b4bfSEduardo Habkost static bool test_skip(void *opaque, int version_id) 4092668b4bfSEduardo Habkost { 4102668b4bfSEduardo Habkost TestStruct *t = (TestStruct *)opaque; 4112668b4bfSEduardo Habkost return !t->skip_c_e; 4122668b4bfSEduardo Habkost } 4132668b4bfSEduardo Habkost 4142668b4bfSEduardo Habkost static const VMStateDescription vmstate_skipping = { 4154ea7df4eSJuan Quintela .name = "test/skip", 4162668b4bfSEduardo Habkost .version_id = 2, 4172668b4bfSEduardo Habkost .minimum_version_id = 1, 4182668b4bfSEduardo Habkost .fields = (VMStateField[]) { 4192668b4bfSEduardo Habkost VMSTATE_UINT32(a, TestStruct), 4202668b4bfSEduardo Habkost VMSTATE_UINT32(b, TestStruct), 4212668b4bfSEduardo Habkost VMSTATE_UINT32_TEST(c, TestStruct, test_skip), 4222668b4bfSEduardo Habkost VMSTATE_UINT64(d, TestStruct), 4232668b4bfSEduardo Habkost VMSTATE_UINT32_TEST(e, TestStruct, test_skip), 4242668b4bfSEduardo Habkost VMSTATE_UINT64_V(f, TestStruct, 2), 4252668b4bfSEduardo Habkost VMSTATE_END_OF_LIST() 4262668b4bfSEduardo Habkost } 4272668b4bfSEduardo Habkost }; 4282668b4bfSEduardo Habkost 4292668b4bfSEduardo Habkost 4302668b4bfSEduardo Habkost static void test_save_noskip(void) 4312668b4bfSEduardo Habkost { 432a8ec4437SDaniel P. Berrange QEMUFile *fsave = open_test_file(true); 4332668b4bfSEduardo Habkost TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, 4342668b4bfSEduardo Habkost .skip_c_e = false }; 4352f168d07SDr. David Alan Gilbert int ret = vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL); 4362f168d07SDr. David Alan Gilbert g_assert(!ret); 4372668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(fsave)); 4382668b4bfSEduardo Habkost 4392668b4bfSEduardo Habkost uint8_t expected[] = { 4402668b4bfSEduardo Habkost 0, 0, 0, 1, /* a */ 4412668b4bfSEduardo Habkost 0, 0, 0, 2, /* b */ 4422668b4bfSEduardo Habkost 0, 0, 0, 3, /* c */ 4432668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 4, /* d */ 4442668b4bfSEduardo Habkost 0, 0, 0, 5, /* e */ 4452668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 6, /* f */ 4462668b4bfSEduardo Habkost }; 447a8ec4437SDaniel P. Berrange 4489935bacaSDr. David Alan Gilbert qemu_fclose(fsave); 449a8ec4437SDaniel P. Berrange compare_vmstate(expected, sizeof(expected)); 4502668b4bfSEduardo Habkost } 4512668b4bfSEduardo Habkost 4522668b4bfSEduardo Habkost static void test_save_skip(void) 4532668b4bfSEduardo Habkost { 454a8ec4437SDaniel P. Berrange QEMUFile *fsave = open_test_file(true); 4552668b4bfSEduardo Habkost TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, 4562668b4bfSEduardo Habkost .skip_c_e = true }; 4572f168d07SDr. David Alan Gilbert int ret = vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL); 4582f168d07SDr. David Alan Gilbert g_assert(!ret); 4592668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(fsave)); 4602668b4bfSEduardo Habkost 4612668b4bfSEduardo Habkost uint8_t expected[] = { 4622668b4bfSEduardo Habkost 0, 0, 0, 1, /* a */ 4632668b4bfSEduardo Habkost 0, 0, 0, 2, /* b */ 4642668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 4, /* d */ 4652668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 6, /* f */ 4662668b4bfSEduardo Habkost }; 4672668b4bfSEduardo Habkost 4689935bacaSDr. David Alan Gilbert qemu_fclose(fsave); 469a8ec4437SDaniel P. Berrange compare_vmstate(expected, sizeof(expected)); 4702668b4bfSEduardo Habkost } 4712668b4bfSEduardo Habkost 4722668b4bfSEduardo Habkost static void test_load_noskip(void) 4732668b4bfSEduardo Habkost { 4742668b4bfSEduardo Habkost uint8_t buf[] = { 4752668b4bfSEduardo Habkost 0, 0, 0, 10, /* a */ 4762668b4bfSEduardo Habkost 0, 0, 0, 20, /* b */ 4772668b4bfSEduardo Habkost 0, 0, 0, 30, /* c */ 4782668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 40, /* d */ 4792668b4bfSEduardo Habkost 0, 0, 0, 50, /* e */ 4802668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 60, /* f */ 4812668b4bfSEduardo Habkost QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 4822668b4bfSEduardo Habkost }; 4836d57b4c0SHalil Pasic save_buffer(buf, sizeof(buf)); 4842668b4bfSEduardo Habkost 485a8ec4437SDaniel P. Berrange QEMUFile *loading = open_test_file(false); 4862668b4bfSEduardo Habkost TestStruct obj = { .skip_c_e = false }; 4872668b4bfSEduardo Habkost vmstate_load_state(loading, &vmstate_skipping, &obj, 2); 4882668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(loading)); 4892668b4bfSEduardo Habkost g_assert_cmpint(obj.a, ==, 10); 4902668b4bfSEduardo Habkost g_assert_cmpint(obj.b, ==, 20); 4912668b4bfSEduardo Habkost g_assert_cmpint(obj.c, ==, 30); 4922668b4bfSEduardo Habkost g_assert_cmpint(obj.d, ==, 40); 4932668b4bfSEduardo Habkost g_assert_cmpint(obj.e, ==, 50); 4942668b4bfSEduardo Habkost g_assert_cmpint(obj.f, ==, 60); 4952668b4bfSEduardo Habkost qemu_fclose(loading); 4962668b4bfSEduardo Habkost } 4972668b4bfSEduardo Habkost 4982668b4bfSEduardo Habkost static void test_load_skip(void) 4992668b4bfSEduardo Habkost { 5002668b4bfSEduardo Habkost uint8_t buf[] = { 5012668b4bfSEduardo Habkost 0, 0, 0, 10, /* a */ 5022668b4bfSEduardo Habkost 0, 0, 0, 20, /* b */ 5032668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 40, /* d */ 5042668b4bfSEduardo Habkost 0, 0, 0, 0, 0, 0, 0, 60, /* f */ 5052668b4bfSEduardo Habkost QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 5062668b4bfSEduardo Habkost }; 5076d57b4c0SHalil Pasic save_buffer(buf, sizeof(buf)); 5082668b4bfSEduardo Habkost 509a8ec4437SDaniel P. Berrange QEMUFile *loading = open_test_file(false); 5102668b4bfSEduardo Habkost TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 }; 5112668b4bfSEduardo Habkost vmstate_load_state(loading, &vmstate_skipping, &obj, 2); 5122668b4bfSEduardo Habkost g_assert(!qemu_file_get_error(loading)); 5132668b4bfSEduardo Habkost g_assert_cmpint(obj.a, ==, 10); 5142668b4bfSEduardo Habkost g_assert_cmpint(obj.b, ==, 20); 5152668b4bfSEduardo Habkost g_assert_cmpint(obj.c, ==, 300); 5162668b4bfSEduardo Habkost g_assert_cmpint(obj.d, ==, 40); 5172668b4bfSEduardo Habkost g_assert_cmpint(obj.e, ==, 500); 5182668b4bfSEduardo Habkost g_assert_cmpint(obj.f, ==, 60); 5192668b4bfSEduardo Habkost qemu_fclose(loading); 5202668b4bfSEduardo Habkost } 5212668b4bfSEduardo Habkost 5228cc49f03SHalil Pasic typedef struct { 5238cc49f03SHalil Pasic int32_t i; 5248cc49f03SHalil Pasic } TestStructTriv; 5258cc49f03SHalil Pasic 5268cc49f03SHalil Pasic const VMStateDescription vmsd_tst = { 5278cc49f03SHalil Pasic .name = "test/tst", 5288cc49f03SHalil Pasic .version_id = 1, 5298cc49f03SHalil Pasic .minimum_version_id = 1, 5308cc49f03SHalil Pasic .fields = (VMStateField[]) { 5318cc49f03SHalil Pasic VMSTATE_INT32(i, TestStructTriv), 5328cc49f03SHalil Pasic VMSTATE_END_OF_LIST() 5338cc49f03SHalil Pasic } 5348cc49f03SHalil Pasic }; 5358cc49f03SHalil Pasic 536cc958831SHalil Pasic /* test array migration */ 537cc958831SHalil Pasic 5388cc49f03SHalil Pasic #define AR_SIZE 4 5398cc49f03SHalil Pasic 5408cc49f03SHalil Pasic typedef struct { 5418cc49f03SHalil Pasic TestStructTriv *ar[AR_SIZE]; 5428cc49f03SHalil Pasic } TestArrayOfPtrToStuct; 5438cc49f03SHalil Pasic 5448cc49f03SHalil Pasic const VMStateDescription vmsd_arps = { 5458cc49f03SHalil Pasic .name = "test/arps", 5468cc49f03SHalil Pasic .version_id = 1, 5478cc49f03SHalil Pasic .minimum_version_id = 1, 5488cc49f03SHalil Pasic .fields = (VMStateField[]) { 5498cc49f03SHalil Pasic VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(ar, TestArrayOfPtrToStuct, 5508cc49f03SHalil Pasic AR_SIZE, 0, vmsd_tst, TestStructTriv), 5518cc49f03SHalil Pasic VMSTATE_END_OF_LIST() 5528cc49f03SHalil Pasic } 5538cc49f03SHalil Pasic }; 554cc958831SHalil Pasic 555cc958831SHalil Pasic static uint8_t wire_arr_ptr_no0[] = { 5568cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x00, 5578cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x01, 5588cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x02, 5598cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x03, 5608cc49f03SHalil Pasic QEMU_VM_EOF 5618cc49f03SHalil Pasic }; 5628cc49f03SHalil Pasic 563cc958831SHalil Pasic static void test_arr_ptr_str_no0_save(void) 564cc958831SHalil Pasic { 565cc958831SHalil Pasic TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} }; 566cc958831SHalil Pasic TestArrayOfPtrToStuct sample = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} }; 567cc958831SHalil Pasic 5688cc49f03SHalil Pasic save_vmstate(&vmsd_arps, &sample); 569cc958831SHalil Pasic compare_vmstate(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0)); 5708cc49f03SHalil Pasic } 5718cc49f03SHalil Pasic 5728cc49f03SHalil Pasic static void test_arr_ptr_str_no0_load(void) 5738cc49f03SHalil Pasic { 5748cc49f03SHalil Pasic TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} }; 5758cc49f03SHalil Pasic TestStructTriv ar[AR_SIZE] = {}; 5768cc49f03SHalil Pasic TestArrayOfPtrToStuct obj = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} }; 5778cc49f03SHalil Pasic int idx; 578cc958831SHalil Pasic 579cc958831SHalil Pasic save_buffer(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0)); 580cc958831SHalil Pasic SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1, 581cc958831SHalil Pasic wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0))); 582cc958831SHalil Pasic for (idx = 0; idx < AR_SIZE; ++idx) { 583cc958831SHalil Pasic /* compare the target array ar with the ground truth array ar_gt */ 584cc958831SHalil Pasic g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i); 585cc958831SHalil Pasic } 586cc958831SHalil Pasic } 587cc958831SHalil Pasic 588cc958831SHalil Pasic static uint8_t wire_arr_ptr_0[] = { 5898cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x00, 590cc958831SHalil Pasic VMS_NULLPTR_MARKER, 5918cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x02, 5928cc49f03SHalil Pasic 0x00, 0x00, 0x00, 0x03, 5938cc49f03SHalil Pasic QEMU_VM_EOF 5948cc49f03SHalil Pasic }; 5958cc49f03SHalil Pasic 596cc958831SHalil Pasic static void test_arr_ptr_str_0_save(void) 597cc958831SHalil Pasic { 598cc958831SHalil Pasic TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} }; 599cc958831SHalil Pasic TestArrayOfPtrToStuct sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} }; 600cc958831SHalil Pasic 601cc958831SHalil Pasic save_vmstate(&vmsd_arps, &sample); 602cc958831SHalil Pasic compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0)); 603cc958831SHalil Pasic } 604cc958831SHalil Pasic 605cc958831SHalil Pasic static void test_arr_ptr_str_0_load(void) 606cc958831SHalil Pasic { 607cc958831SHalil Pasic TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 0}, {.i = 2}, {.i = 3} }; 608cc958831SHalil Pasic TestStructTriv ar[AR_SIZE] = {}; 609cc958831SHalil Pasic TestArrayOfPtrToStuct obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} }; 610cc958831SHalil Pasic int idx; 611cc958831SHalil Pasic 612cc958831SHalil Pasic save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0)); 6138cc49f03SHalil Pasic SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1, 614cc958831SHalil Pasic wire_arr_ptr_0, sizeof(wire_arr_ptr_0))); 6158cc49f03SHalil Pasic for (idx = 0; idx < AR_SIZE; ++idx) { 6168cc49f03SHalil Pasic /* compare the target array ar with the ground truth array ar_gt */ 6178cc49f03SHalil Pasic g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i); 6188cc49f03SHalil Pasic } 619cc958831SHalil Pasic for (idx = 0; idx < AR_SIZE; ++idx) { 620cc958831SHalil Pasic if (idx == 1) { 621cc958831SHalil Pasic g_assert_cmpint((uintptr_t)(obj.ar[idx]), ==, 0); 622cc958831SHalil Pasic } else { 623cc958831SHalil Pasic g_assert_cmpint((uintptr_t)(obj.ar[idx]), !=, 0); 624cc958831SHalil Pasic } 625cc958831SHalil Pasic } 6268cc49f03SHalil Pasic } 6278cc49f03SHalil Pasic 62843333099SHalil Pasic typedef struct TestArrayOfPtrToInt { 62943333099SHalil Pasic int32_t *ar[AR_SIZE]; 63043333099SHalil Pasic } TestArrayOfPtrToInt; 63143333099SHalil Pasic 63243333099SHalil Pasic const VMStateDescription vmsd_arpp = { 63343333099SHalil Pasic .name = "test/arps", 63443333099SHalil Pasic .version_id = 1, 63543333099SHalil Pasic .minimum_version_id = 1, 63643333099SHalil Pasic .fields = (VMStateField[]) { 63743333099SHalil Pasic VMSTATE_ARRAY_OF_POINTER(ar, TestArrayOfPtrToInt, 63843333099SHalil Pasic AR_SIZE, 0, vmstate_info_int32, int32_t*), 63943333099SHalil Pasic VMSTATE_END_OF_LIST() 64043333099SHalil Pasic } 64143333099SHalil Pasic }; 64243333099SHalil Pasic 64343333099SHalil Pasic static void test_arr_ptr_prim_0_save(void) 64443333099SHalil Pasic { 64543333099SHalil Pasic int32_t ar[AR_SIZE] = {0 , 1, 2, 3}; 64643333099SHalil Pasic TestArrayOfPtrToInt sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} }; 64743333099SHalil Pasic 64843333099SHalil Pasic save_vmstate(&vmsd_arpp, &sample); 64943333099SHalil Pasic compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0)); 65043333099SHalil Pasic } 65143333099SHalil Pasic 65243333099SHalil Pasic static void test_arr_ptr_prim_0_load(void) 65343333099SHalil Pasic { 65443333099SHalil Pasic int32_t ar_gt[AR_SIZE] = {0, 1, 2, 3}; 65543333099SHalil Pasic int32_t ar[AR_SIZE] = {3 , 42, 1, 0}; 65643333099SHalil Pasic TestArrayOfPtrToInt obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} }; 65743333099SHalil Pasic int idx; 65843333099SHalil Pasic 65943333099SHalil Pasic save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0)); 66043333099SHalil Pasic SUCCESS(load_vmstate_one(&vmsd_arpp, &obj, 1, 66143333099SHalil Pasic wire_arr_ptr_0, sizeof(wire_arr_ptr_0))); 66243333099SHalil Pasic for (idx = 0; idx < AR_SIZE; ++idx) { 66343333099SHalil Pasic /* compare the target array ar with the ground truth array ar_gt */ 66443333099SHalil Pasic if (idx == 1) { 66543333099SHalil Pasic g_assert_cmpint(42, ==, ar[idx]); 66643333099SHalil Pasic } else { 66743333099SHalil Pasic g_assert_cmpint(ar_gt[idx], ==, ar[idx]); 66843333099SHalil Pasic } 66943333099SHalil Pasic } 67043333099SHalil Pasic } 67143333099SHalil Pasic 6727e99f22cSJianjun Duan /* test QTAILQ migration */ 6737e99f22cSJianjun Duan typedef struct TestQtailqElement TestQtailqElement; 6747e99f22cSJianjun Duan 6757e99f22cSJianjun Duan struct TestQtailqElement { 6767e99f22cSJianjun Duan bool b; 6777e99f22cSJianjun Duan uint8_t u8; 6787e99f22cSJianjun Duan QTAILQ_ENTRY(TestQtailqElement) next; 6797e99f22cSJianjun Duan }; 6807e99f22cSJianjun Duan 6817e99f22cSJianjun Duan typedef struct TestQtailq { 6827e99f22cSJianjun Duan int16_t i16; 683eae3eb3eSPaolo Bonzini QTAILQ_HEAD(, TestQtailqElement) q; 6847e99f22cSJianjun Duan int32_t i32; 6857e99f22cSJianjun Duan } TestQtailq; 6867e99f22cSJianjun Duan 6877e99f22cSJianjun Duan static const VMStateDescription vmstate_q_element = { 6887e99f22cSJianjun Duan .name = "test/queue-element", 6897e99f22cSJianjun Duan .version_id = 1, 6907e99f22cSJianjun Duan .minimum_version_id = 1, 6917e99f22cSJianjun Duan .fields = (VMStateField[]) { 6927e99f22cSJianjun Duan VMSTATE_BOOL(b, TestQtailqElement), 6937e99f22cSJianjun Duan VMSTATE_UINT8(u8, TestQtailqElement), 6947e99f22cSJianjun Duan VMSTATE_END_OF_LIST() 6957e99f22cSJianjun Duan }, 6967e99f22cSJianjun Duan }; 6977e99f22cSJianjun Duan 6987e99f22cSJianjun Duan static const VMStateDescription vmstate_q = { 6997e99f22cSJianjun Duan .name = "test/queue", 7007e99f22cSJianjun Duan .version_id = 1, 7017e99f22cSJianjun Duan .minimum_version_id = 1, 7027e99f22cSJianjun Duan .fields = (VMStateField[]) { 7037e99f22cSJianjun Duan VMSTATE_INT16(i16, TestQtailq), 7047e99f22cSJianjun Duan VMSTATE_QTAILQ_V(q, TestQtailq, 1, vmstate_q_element, TestQtailqElement, 7057e99f22cSJianjun Duan next), 7067e99f22cSJianjun Duan VMSTATE_INT32(i32, TestQtailq), 7077e99f22cSJianjun Duan VMSTATE_END_OF_LIST() 7087e99f22cSJianjun Duan } 7097e99f22cSJianjun Duan }; 7107e99f22cSJianjun Duan 7117e99f22cSJianjun Duan uint8_t wire_q[] = { 7127e99f22cSJianjun Duan /* i16 */ 0xfe, 0x0, 7137e99f22cSJianjun Duan /* start of element 0 of q */ 0x01, 7147e99f22cSJianjun Duan /* .b */ 0x01, 7157e99f22cSJianjun Duan /* .u8 */ 0x82, 7167e99f22cSJianjun Duan /* start of element 1 of q */ 0x01, 7177e99f22cSJianjun Duan /* b */ 0x00, 7187e99f22cSJianjun Duan /* u8 */ 0x41, 7197e99f22cSJianjun Duan /* end of q */ 0x00, 7207e99f22cSJianjun Duan /* i32 */ 0x00, 0x01, 0x11, 0x70, 7217e99f22cSJianjun Duan QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 7227e99f22cSJianjun Duan }; 7237e99f22cSJianjun Duan 7247e99f22cSJianjun Duan static void test_save_q(void) 7257e99f22cSJianjun Duan { 7267e99f22cSJianjun Duan TestQtailq obj_q = { 7277e99f22cSJianjun Duan .i16 = -512, 7287e99f22cSJianjun Duan .i32 = 70000, 7297e99f22cSJianjun Duan }; 7307e99f22cSJianjun Duan 7317e99f22cSJianjun Duan TestQtailqElement obj_qe1 = { 7327e99f22cSJianjun Duan .b = true, 7337e99f22cSJianjun Duan .u8 = 130, 7347e99f22cSJianjun Duan }; 7357e99f22cSJianjun Duan 7367e99f22cSJianjun Duan TestQtailqElement obj_qe2 = { 7377e99f22cSJianjun Duan .b = false, 7387e99f22cSJianjun Duan .u8 = 65, 7397e99f22cSJianjun Duan }; 7407e99f22cSJianjun Duan 7417e99f22cSJianjun Duan QTAILQ_INIT(&obj_q.q); 7427e99f22cSJianjun Duan QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next); 7437e99f22cSJianjun Duan QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next); 7447e99f22cSJianjun Duan 7457e99f22cSJianjun Duan save_vmstate(&vmstate_q, &obj_q); 7467e99f22cSJianjun Duan compare_vmstate(wire_q, sizeof(wire_q)); 7477e99f22cSJianjun Duan } 7487e99f22cSJianjun Duan 7497e99f22cSJianjun Duan static void test_load_q(void) 7507e99f22cSJianjun Duan { 7517e99f22cSJianjun Duan TestQtailq obj_q = { 7527e99f22cSJianjun Duan .i16 = -512, 7537e99f22cSJianjun Duan .i32 = 70000, 7547e99f22cSJianjun Duan }; 7557e99f22cSJianjun Duan 7567e99f22cSJianjun Duan TestQtailqElement obj_qe1 = { 7577e99f22cSJianjun Duan .b = true, 7587e99f22cSJianjun Duan .u8 = 130, 7597e99f22cSJianjun Duan }; 7607e99f22cSJianjun Duan 7617e99f22cSJianjun Duan TestQtailqElement obj_qe2 = { 7627e99f22cSJianjun Duan .b = false, 7637e99f22cSJianjun Duan .u8 = 65, 7647e99f22cSJianjun Duan }; 7657e99f22cSJianjun Duan 7667e99f22cSJianjun Duan QTAILQ_INIT(&obj_q.q); 7677e99f22cSJianjun Duan QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next); 7687e99f22cSJianjun Duan QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next); 7697e99f22cSJianjun Duan 7707e99f22cSJianjun Duan QEMUFile *fsave = open_test_file(true); 7717e99f22cSJianjun Duan 7727e99f22cSJianjun Duan qemu_put_buffer(fsave, wire_q, sizeof(wire_q)); 7737e99f22cSJianjun Duan g_assert(!qemu_file_get_error(fsave)); 7747e99f22cSJianjun Duan qemu_fclose(fsave); 7757e99f22cSJianjun Duan 7767e99f22cSJianjun Duan QEMUFile *fload = open_test_file(false); 7777e99f22cSJianjun Duan TestQtailq tgt; 7787e99f22cSJianjun Duan 7797e99f22cSJianjun Duan QTAILQ_INIT(&tgt.q); 7807e99f22cSJianjun Duan vmstate_load_state(fload, &vmstate_q, &tgt, 1); 7817e99f22cSJianjun Duan char eof = qemu_get_byte(fload); 7827e99f22cSJianjun Duan g_assert(!qemu_file_get_error(fload)); 7837e99f22cSJianjun Duan g_assert_cmpint(tgt.i16, ==, obj_q.i16); 7847e99f22cSJianjun Duan g_assert_cmpint(tgt.i32, ==, obj_q.i32); 7857e99f22cSJianjun Duan g_assert_cmpint(eof, ==, QEMU_VM_EOF); 7867e99f22cSJianjun Duan 7877e99f22cSJianjun Duan TestQtailqElement *qele_from = QTAILQ_FIRST(&obj_q.q); 788eae3eb3eSPaolo Bonzini TestQtailqElement *qlast_from = QTAILQ_LAST(&obj_q.q); 7897e99f22cSJianjun Duan TestQtailqElement *qele_to = QTAILQ_FIRST(&tgt.q); 790eae3eb3eSPaolo Bonzini TestQtailqElement *qlast_to = QTAILQ_LAST(&tgt.q); 7917e99f22cSJianjun Duan 7927e99f22cSJianjun Duan while (1) { 7937e99f22cSJianjun Duan g_assert_cmpint(qele_to->b, ==, qele_from->b); 7947e99f22cSJianjun Duan g_assert_cmpint(qele_to->u8, ==, qele_from->u8); 7957e99f22cSJianjun Duan if ((qele_from == qlast_from) || (qele_to == qlast_to)) { 7967e99f22cSJianjun Duan break; 7977e99f22cSJianjun Duan } 7987e99f22cSJianjun Duan qele_from = QTAILQ_NEXT(qele_from, next); 7997e99f22cSJianjun Duan qele_to = QTAILQ_NEXT(qele_to, next); 8007e99f22cSJianjun Duan } 8017e99f22cSJianjun Duan 8027e99f22cSJianjun Duan g_assert_cmpint((uintptr_t) qele_from, ==, (uintptr_t) qlast_from); 8037e99f22cSJianjun Duan g_assert_cmpint((uintptr_t) qele_to, ==, (uintptr_t) qlast_to); 8047e99f22cSJianjun Duan 8057e99f22cSJianjun Duan /* clean up */ 8067e99f22cSJianjun Duan TestQtailqElement *qele; 8077e99f22cSJianjun Duan while (!QTAILQ_EMPTY(&tgt.q)) { 808eae3eb3eSPaolo Bonzini qele = QTAILQ_LAST(&tgt.q); 8097e99f22cSJianjun Duan QTAILQ_REMOVE(&tgt.q, qele, next); 8107e99f22cSJianjun Duan free(qele); 8117e99f22cSJianjun Duan qele = NULL; 8127e99f22cSJianjun Duan } 8137e99f22cSJianjun Duan qemu_fclose(fload); 8147e99f22cSJianjun Duan } 8157e99f22cSJianjun Duan 8169a85e4b8SEric Auger /* interval (key) */ 8179a85e4b8SEric Auger typedef struct TestGTreeInterval { 8189a85e4b8SEric Auger uint64_t low; 8199a85e4b8SEric Auger uint64_t high; 8209a85e4b8SEric Auger } TestGTreeInterval; 8219a85e4b8SEric Auger 8229a85e4b8SEric Auger #define VMSTATE_INTERVAL \ 8239a85e4b8SEric Auger { \ 8249a85e4b8SEric Auger .name = "interval", \ 8259a85e4b8SEric Auger .version_id = 1, \ 8269a85e4b8SEric Auger .minimum_version_id = 1, \ 8279a85e4b8SEric Auger .fields = (VMStateField[]) { \ 8289a85e4b8SEric Auger VMSTATE_UINT64(low, TestGTreeInterval), \ 8299a85e4b8SEric Auger VMSTATE_UINT64(high, TestGTreeInterval), \ 8309a85e4b8SEric Auger VMSTATE_END_OF_LIST() \ 8319a85e4b8SEric Auger } \ 8329a85e4b8SEric Auger } 8339a85e4b8SEric Auger 8349a85e4b8SEric Auger /* mapping (value) */ 8359a85e4b8SEric Auger typedef struct TestGTreeMapping { 8369a85e4b8SEric Auger uint64_t phys_addr; 8379a85e4b8SEric Auger uint32_t flags; 8389a85e4b8SEric Auger } TestGTreeMapping; 8399a85e4b8SEric Auger 8409a85e4b8SEric Auger #define VMSTATE_MAPPING \ 8419a85e4b8SEric Auger { \ 8429a85e4b8SEric Auger .name = "mapping", \ 8439a85e4b8SEric Auger .version_id = 1, \ 8449a85e4b8SEric Auger .minimum_version_id = 1, \ 8459a85e4b8SEric Auger .fields = (VMStateField[]) { \ 8469a85e4b8SEric Auger VMSTATE_UINT64(phys_addr, TestGTreeMapping), \ 8479a85e4b8SEric Auger VMSTATE_UINT32(flags, TestGTreeMapping), \ 8489a85e4b8SEric Auger VMSTATE_END_OF_LIST() \ 8499a85e4b8SEric Auger }, \ 8509a85e4b8SEric Auger } 8519a85e4b8SEric Auger 8529a85e4b8SEric Auger static const VMStateDescription vmstate_interval_mapping[2] = { 8539a85e4b8SEric Auger VMSTATE_MAPPING, /* value */ 8549a85e4b8SEric Auger VMSTATE_INTERVAL /* key */ 8559a85e4b8SEric Auger }; 8569a85e4b8SEric Auger 8579a85e4b8SEric Auger typedef struct TestGTreeDomain { 8589a85e4b8SEric Auger int32_t id; 8599a85e4b8SEric Auger GTree *mappings; 8609a85e4b8SEric Auger } TestGTreeDomain; 8619a85e4b8SEric Auger 8629a85e4b8SEric Auger typedef struct TestGTreeIOMMU { 8639a85e4b8SEric Auger int32_t id; 8649a85e4b8SEric Auger GTree *domains; 8659a85e4b8SEric Auger } TestGTreeIOMMU; 8669a85e4b8SEric Auger 8679a85e4b8SEric Auger /* Interval comparison function */ 8689a85e4b8SEric Auger static gint interval_cmp(gconstpointer a, gconstpointer b, gpointer user_data) 8699a85e4b8SEric Auger { 8709a85e4b8SEric Auger TestGTreeInterval *inta = (TestGTreeInterval *)a; 8719a85e4b8SEric Auger TestGTreeInterval *intb = (TestGTreeInterval *)b; 8729a85e4b8SEric Auger 8739a85e4b8SEric Auger if (inta->high < intb->low) { 8749a85e4b8SEric Auger return -1; 8759a85e4b8SEric Auger } else if (intb->high < inta->low) { 8769a85e4b8SEric Auger return 1; 8779a85e4b8SEric Auger } else { 8789a85e4b8SEric Auger return 0; 8799a85e4b8SEric Auger } 8809a85e4b8SEric Auger } 8819a85e4b8SEric Auger 8829a85e4b8SEric Auger /* ID comparison function */ 8839a85e4b8SEric Auger static gint int_cmp(gconstpointer a, gconstpointer b, gpointer user_data) 8849a85e4b8SEric Auger { 88585c93c57SYonggang Luo guint ua = GPOINTER_TO_UINT(a); 88685c93c57SYonggang Luo guint ub = GPOINTER_TO_UINT(b); 8879a85e4b8SEric Auger return (ua > ub) - (ua < ub); 8889a85e4b8SEric Auger } 8899a85e4b8SEric Auger 8909a85e4b8SEric Auger static void destroy_domain(gpointer data) 8919a85e4b8SEric Auger { 8929a85e4b8SEric Auger TestGTreeDomain *domain = (TestGTreeDomain *)data; 8939a85e4b8SEric Auger 8949a85e4b8SEric Auger g_tree_destroy(domain->mappings); 8959a85e4b8SEric Auger g_free(domain); 8969a85e4b8SEric Auger } 8979a85e4b8SEric Auger 8989a85e4b8SEric Auger static int domain_preload(void *opaque) 8999a85e4b8SEric Auger { 9009a85e4b8SEric Auger TestGTreeDomain *domain = opaque; 9019a85e4b8SEric Auger 9029a85e4b8SEric Auger domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp, 9039a85e4b8SEric Auger NULL, g_free, g_free); 9049a85e4b8SEric Auger return 0; 9059a85e4b8SEric Auger } 9069a85e4b8SEric Auger 9079a85e4b8SEric Auger static int iommu_preload(void *opaque) 9089a85e4b8SEric Auger { 9099a85e4b8SEric Auger TestGTreeIOMMU *iommu = opaque; 9109a85e4b8SEric Auger 9119a85e4b8SEric Auger iommu->domains = g_tree_new_full((GCompareDataFunc)int_cmp, 9129a85e4b8SEric Auger NULL, NULL, destroy_domain); 9139a85e4b8SEric Auger return 0; 9149a85e4b8SEric Auger } 9159a85e4b8SEric Auger 9169a85e4b8SEric Auger static const VMStateDescription vmstate_domain = { 9179a85e4b8SEric Auger .name = "domain", 9189a85e4b8SEric Auger .version_id = 1, 9199a85e4b8SEric Auger .minimum_version_id = 1, 9209a85e4b8SEric Auger .pre_load = domain_preload, 9219a85e4b8SEric Auger .fields = (VMStateField[]) { 9229a85e4b8SEric Auger VMSTATE_INT32(id, TestGTreeDomain), 9239a85e4b8SEric Auger VMSTATE_GTREE_V(mappings, TestGTreeDomain, 1, 9249a85e4b8SEric Auger vmstate_interval_mapping, 9259a85e4b8SEric Auger TestGTreeInterval, TestGTreeMapping), 9269a85e4b8SEric Auger VMSTATE_END_OF_LIST() 9279a85e4b8SEric Auger } 9289a85e4b8SEric Auger }; 9299a85e4b8SEric Auger 9304746dbf8SEric Auger /* test QLIST Migration */ 9314746dbf8SEric Auger 9324746dbf8SEric Auger typedef struct TestQListElement { 9334746dbf8SEric Auger uint32_t id; 9344746dbf8SEric Auger QLIST_ENTRY(TestQListElement) next; 9354746dbf8SEric Auger } TestQListElement; 9364746dbf8SEric Auger 9374746dbf8SEric Auger typedef struct TestQListContainer { 9384746dbf8SEric Auger uint32_t id; 9394746dbf8SEric Auger QLIST_HEAD(, TestQListElement) list; 9404746dbf8SEric Auger } TestQListContainer; 9414746dbf8SEric Auger 9424746dbf8SEric Auger static const VMStateDescription vmstate_qlist_element = { 9434746dbf8SEric Auger .name = "test/queue list", 9444746dbf8SEric Auger .version_id = 1, 9454746dbf8SEric Auger .minimum_version_id = 1, 9464746dbf8SEric Auger .fields = (VMStateField[]) { 9474746dbf8SEric Auger VMSTATE_UINT32(id, TestQListElement), 9484746dbf8SEric Auger VMSTATE_END_OF_LIST() 9494746dbf8SEric Auger } 9504746dbf8SEric Auger }; 9514746dbf8SEric Auger 9529a85e4b8SEric Auger static const VMStateDescription vmstate_iommu = { 9539a85e4b8SEric Auger .name = "iommu", 9549a85e4b8SEric Auger .version_id = 1, 9559a85e4b8SEric Auger .minimum_version_id = 1, 9569a85e4b8SEric Auger .pre_load = iommu_preload, 9579a85e4b8SEric Auger .fields = (VMStateField[]) { 9589a85e4b8SEric Auger VMSTATE_INT32(id, TestGTreeIOMMU), 9599a85e4b8SEric Auger VMSTATE_GTREE_DIRECT_KEY_V(domains, TestGTreeIOMMU, 1, 9609a85e4b8SEric Auger &vmstate_domain, TestGTreeDomain), 9619a85e4b8SEric Auger VMSTATE_END_OF_LIST() 9629a85e4b8SEric Auger } 9639a85e4b8SEric Auger }; 9649a85e4b8SEric Auger 9654746dbf8SEric Auger static const VMStateDescription vmstate_container = { 9664746dbf8SEric Auger .name = "test/container/qlist", 9674746dbf8SEric Auger .version_id = 1, 9684746dbf8SEric Auger .minimum_version_id = 1, 9694746dbf8SEric Auger .fields = (VMStateField[]) { 9704746dbf8SEric Auger VMSTATE_UINT32(id, TestQListContainer), 9714746dbf8SEric Auger VMSTATE_QLIST_V(list, TestQListContainer, 1, vmstate_qlist_element, 9724746dbf8SEric Auger TestQListElement, next), 9734746dbf8SEric Auger VMSTATE_END_OF_LIST() 9744746dbf8SEric Auger } 9754746dbf8SEric Auger }; 9764746dbf8SEric Auger 9779a85e4b8SEric Auger uint8_t first_domain_dump[] = { 9789a85e4b8SEric Auger /* id */ 9799a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x6, 9809a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x2, /* 2 mappings */ 9819a85e4b8SEric Auger 0x1, /* start of a */ 9829a85e4b8SEric Auger /* a */ 9839a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 9849a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 9859a85e4b8SEric Auger /* map_a */ 9869a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 9879a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x01, 9889a85e4b8SEric Auger 0x1, /* start of b */ 9899a85e4b8SEric Auger /* b */ 9909a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 9919a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF, 9929a85e4b8SEric Auger /* map_b */ 9939a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 9949a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x02, 9959a85e4b8SEric Auger 0x0, /* end of gtree */ 9969a85e4b8SEric Auger QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 9979a85e4b8SEric Auger }; 9989a85e4b8SEric Auger 9999a85e4b8SEric Auger static TestGTreeDomain *create_first_domain(void) 10009a85e4b8SEric Auger { 10019a85e4b8SEric Auger TestGTreeDomain *domain; 10029a85e4b8SEric Auger TestGTreeMapping *map_a, *map_b; 10039a85e4b8SEric Auger TestGTreeInterval *a, *b; 10049a85e4b8SEric Auger 1005*b21e2380SMarkus Armbruster domain = g_new0(TestGTreeDomain, 1); 10069a85e4b8SEric Auger domain->id = 6; 10079a85e4b8SEric Auger 1008*b21e2380SMarkus Armbruster a = g_new0(TestGTreeInterval, 1); 10099a85e4b8SEric Auger a->low = 0x1000; 10109a85e4b8SEric Auger a->high = 0x1FFF; 10119a85e4b8SEric Auger 1012*b21e2380SMarkus Armbruster b = g_new0(TestGTreeInterval, 1); 10139a85e4b8SEric Auger b->low = 0x4000; 10149a85e4b8SEric Auger b->high = 0x4FFF; 10159a85e4b8SEric Auger 1016*b21e2380SMarkus Armbruster map_a = g_new0(TestGTreeMapping, 1); 10179a85e4b8SEric Auger map_a->phys_addr = 0xa000; 10189a85e4b8SEric Auger map_a->flags = 1; 10199a85e4b8SEric Auger 1020*b21e2380SMarkus Armbruster map_b = g_new0(TestGTreeMapping, 1); 10219a85e4b8SEric Auger map_b->phys_addr = 0xe0000; 10229a85e4b8SEric Auger map_b->flags = 2; 10239a85e4b8SEric Auger 10249a85e4b8SEric Auger domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp, NULL, 10259a85e4b8SEric Auger (GDestroyNotify)g_free, 10269a85e4b8SEric Auger (GDestroyNotify)g_free); 10279a85e4b8SEric Auger g_tree_insert(domain->mappings, a, map_a); 10289a85e4b8SEric Auger g_tree_insert(domain->mappings, b, map_b); 10299a85e4b8SEric Auger return domain; 10309a85e4b8SEric Auger } 10319a85e4b8SEric Auger 10329a85e4b8SEric Auger static void test_gtree_save_domain(void) 10339a85e4b8SEric Auger { 10349a85e4b8SEric Auger TestGTreeDomain *first_domain = create_first_domain(); 10359a85e4b8SEric Auger 10369a85e4b8SEric Auger save_vmstate(&vmstate_domain, first_domain); 10379a85e4b8SEric Auger compare_vmstate(first_domain_dump, sizeof(first_domain_dump)); 10389a85e4b8SEric Auger destroy_domain(first_domain); 10399a85e4b8SEric Auger } 10409a85e4b8SEric Auger 10419a85e4b8SEric Auger struct match_node_data { 10429a85e4b8SEric Auger GTree *tree; 10439a85e4b8SEric Auger gpointer key; 10449a85e4b8SEric Auger gpointer value; 10459a85e4b8SEric Auger }; 10469a85e4b8SEric Auger 10479a85e4b8SEric Auger struct tree_cmp_data { 10489a85e4b8SEric Auger GTree *tree1; 10499a85e4b8SEric Auger GTree *tree2; 10509a85e4b8SEric Auger GTraverseFunc match_node; 10519a85e4b8SEric Auger }; 10529a85e4b8SEric Auger 10539a85e4b8SEric Auger static gboolean match_interval_mapping_node(gpointer key, 10549a85e4b8SEric Auger gpointer value, gpointer data) 10559a85e4b8SEric Auger { 10569a85e4b8SEric Auger TestGTreeMapping *map_a, *map_b; 10579a85e4b8SEric Auger TestGTreeInterval *a, *b; 10589a85e4b8SEric Auger struct match_node_data *d = (struct match_node_data *)data; 10599a85e4b8SEric Auger a = (TestGTreeInterval *)key; 10609a85e4b8SEric Auger b = (TestGTreeInterval *)d->key; 10619a85e4b8SEric Auger 10629a85e4b8SEric Auger map_a = (TestGTreeMapping *)value; 10639a85e4b8SEric Auger map_b = (TestGTreeMapping *)d->value; 10649a85e4b8SEric Auger 10659a85e4b8SEric Auger assert(a->low == b->low); 10669a85e4b8SEric Auger assert(a->high == b->high); 10679a85e4b8SEric Auger assert(map_a->phys_addr == map_b->phys_addr); 10689a85e4b8SEric Auger assert(map_a->flags == map_b->flags); 10699a85e4b8SEric Auger g_tree_remove(d->tree, key); 10709a85e4b8SEric Auger return true; 10719a85e4b8SEric Auger } 10729a85e4b8SEric Auger 10739a85e4b8SEric Auger static gboolean diff_tree(gpointer key, gpointer value, gpointer data) 10749a85e4b8SEric Auger { 10759a85e4b8SEric Auger struct tree_cmp_data *tp = (struct tree_cmp_data *)data; 10769a85e4b8SEric Auger struct match_node_data d = {tp->tree2, key, value}; 10779a85e4b8SEric Auger 10789a85e4b8SEric Auger g_tree_foreach(tp->tree2, tp->match_node, &d); 10799a85e4b8SEric Auger g_tree_remove(tp->tree1, key); 10809a85e4b8SEric Auger return false; 10819a85e4b8SEric Auger } 10829a85e4b8SEric Auger 10839a85e4b8SEric Auger static void compare_trees(GTree *tree1, GTree *tree2, 10849a85e4b8SEric Auger GTraverseFunc function) 10859a85e4b8SEric Auger { 10869a85e4b8SEric Auger struct tree_cmp_data tp = {tree1, tree2, function}; 10879a85e4b8SEric Auger 10889a85e4b8SEric Auger g_tree_foreach(tree1, diff_tree, &tp); 10899a85e4b8SEric Auger assert(g_tree_nnodes(tree1) == 0); 10909a85e4b8SEric Auger assert(g_tree_nnodes(tree2) == 0); 10919a85e4b8SEric Auger } 10929a85e4b8SEric Auger 10939a85e4b8SEric Auger static void diff_domain(TestGTreeDomain *d1, TestGTreeDomain *d2) 10949a85e4b8SEric Auger { 10959a85e4b8SEric Auger assert(d1->id == d2->id); 10969a85e4b8SEric Auger compare_trees(d1->mappings, d2->mappings, match_interval_mapping_node); 10979a85e4b8SEric Auger } 10989a85e4b8SEric Auger 10999a85e4b8SEric Auger static gboolean match_domain_node(gpointer key, gpointer value, gpointer data) 11009a85e4b8SEric Auger { 11019a85e4b8SEric Auger uint64_t id1, id2; 11029a85e4b8SEric Auger TestGTreeDomain *d1, *d2; 11039a85e4b8SEric Auger struct match_node_data *d = (struct match_node_data *)data; 11049a85e4b8SEric Auger 11059a85e4b8SEric Auger id1 = (uint64_t)(uintptr_t)key; 11069a85e4b8SEric Auger id2 = (uint64_t)(uintptr_t)d->key; 11079a85e4b8SEric Auger d1 = (TestGTreeDomain *)value; 11089a85e4b8SEric Auger d2 = (TestGTreeDomain *)d->value; 11099a85e4b8SEric Auger assert(id1 == id2); 11109a85e4b8SEric Auger diff_domain(d1, d2); 11119a85e4b8SEric Auger g_tree_remove(d->tree, key); 11129a85e4b8SEric Auger return true; 11139a85e4b8SEric Auger } 11149a85e4b8SEric Auger 11159a85e4b8SEric Auger static void diff_iommu(TestGTreeIOMMU *iommu1, TestGTreeIOMMU *iommu2) 11169a85e4b8SEric Auger { 11179a85e4b8SEric Auger assert(iommu1->id == iommu2->id); 11189a85e4b8SEric Auger compare_trees(iommu1->domains, iommu2->domains, match_domain_node); 11199a85e4b8SEric Auger } 11209a85e4b8SEric Auger 11219a85e4b8SEric Auger static void test_gtree_load_domain(void) 11229a85e4b8SEric Auger { 1123*b21e2380SMarkus Armbruster TestGTreeDomain *dest_domain = g_new0(TestGTreeDomain, 1); 11249a85e4b8SEric Auger TestGTreeDomain *orig_domain = create_first_domain(); 11259a85e4b8SEric Auger QEMUFile *fload, *fsave; 11269a85e4b8SEric Auger char eof; 11279a85e4b8SEric Auger 11289a85e4b8SEric Auger fsave = open_test_file(true); 11299a85e4b8SEric Auger qemu_put_buffer(fsave, first_domain_dump, sizeof(first_domain_dump)); 11309a85e4b8SEric Auger g_assert(!qemu_file_get_error(fsave)); 11319a85e4b8SEric Auger qemu_fclose(fsave); 11329a85e4b8SEric Auger 11339a85e4b8SEric Auger fload = open_test_file(false); 11349a85e4b8SEric Auger 11359a85e4b8SEric Auger vmstate_load_state(fload, &vmstate_domain, dest_domain, 1); 11369a85e4b8SEric Auger eof = qemu_get_byte(fload); 11379a85e4b8SEric Auger g_assert(!qemu_file_get_error(fload)); 11389a85e4b8SEric Auger g_assert_cmpint(orig_domain->id, ==, dest_domain->id); 11399a85e4b8SEric Auger g_assert_cmpint(eof, ==, QEMU_VM_EOF); 11409a85e4b8SEric Auger 11419a85e4b8SEric Auger diff_domain(orig_domain, dest_domain); 11429a85e4b8SEric Auger destroy_domain(orig_domain); 11439a85e4b8SEric Auger destroy_domain(dest_domain); 11449a85e4b8SEric Auger qemu_fclose(fload); 11459a85e4b8SEric Auger } 11469a85e4b8SEric Auger 11479a85e4b8SEric Auger uint8_t iommu_dump[] = { 11489a85e4b8SEric Auger /* iommu id */ 11499a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x7, 11509a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x2, /* 2 domains */ 11519a85e4b8SEric Auger 0x1,/* start of domain 5 */ 11529a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x5, /* key = 5 */ 11539a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x5, /* domain1 id */ 11549a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x1, /* 1 mapping */ 11559a85e4b8SEric Auger 0x1, /* start of mappings */ 11569a85e4b8SEric Auger /* c */ 11579a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 11589a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 11599a85e4b8SEric Auger /* map_c */ 11609a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 11619a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x3, 11629a85e4b8SEric Auger 0x0, /* end of domain1 mappings*/ 11639a85e4b8SEric Auger 0x1,/* start of domain 6 */ 11649a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x0, 0x6, /* key = 6 */ 11659a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x6, /* domain6 id */ 11669a85e4b8SEric Auger 0x00, 0x0, 0x0, 0x2, /* 2 mappings */ 11679a85e4b8SEric Auger 0x1, /* start of a */ 11689a85e4b8SEric Auger /* a */ 11699a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 11709a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 11719a85e4b8SEric Auger /* map_a */ 11729a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 11739a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x01, 11749a85e4b8SEric Auger 0x1, /* start of b */ 11759a85e4b8SEric Auger /* b */ 11769a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 11779a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0xFF, 11789a85e4b8SEric Auger /* map_b */ 11799a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 11809a85e4b8SEric Auger 0x00, 0x00, 0x00, 0x02, 11819a85e4b8SEric Auger 0x0, /* end of domain6 mappings*/ 11829a85e4b8SEric Auger 0x0, /* end of domains */ 11839a85e4b8SEric Auger QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 11849a85e4b8SEric Auger }; 11859a85e4b8SEric Auger 11869a85e4b8SEric Auger static TestGTreeIOMMU *create_iommu(void) 11879a85e4b8SEric Auger { 1188*b21e2380SMarkus Armbruster TestGTreeIOMMU *iommu = g_new0(TestGTreeIOMMU, 1); 11899a85e4b8SEric Auger TestGTreeDomain *first_domain = create_first_domain(); 11909a85e4b8SEric Auger TestGTreeDomain *second_domain; 11919a85e4b8SEric Auger TestGTreeMapping *map_c; 11929a85e4b8SEric Auger TestGTreeInterval *c; 11939a85e4b8SEric Auger 11949a85e4b8SEric Auger iommu->id = 7; 11959a85e4b8SEric Auger iommu->domains = g_tree_new_full((GCompareDataFunc)int_cmp, NULL, 11969a85e4b8SEric Auger NULL, 11979a85e4b8SEric Auger destroy_domain); 11989a85e4b8SEric Auger 1199*b21e2380SMarkus Armbruster second_domain = g_new0(TestGTreeDomain, 1); 12009a85e4b8SEric Auger second_domain->id = 5; 12019a85e4b8SEric Auger second_domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp, 12029a85e4b8SEric Auger NULL, 12039a85e4b8SEric Auger (GDestroyNotify)g_free, 12049a85e4b8SEric Auger (GDestroyNotify)g_free); 12059a85e4b8SEric Auger 12069a85e4b8SEric Auger g_tree_insert(iommu->domains, GUINT_TO_POINTER(6), first_domain); 12079a85e4b8SEric Auger g_tree_insert(iommu->domains, (gpointer)0x0000000000000005, second_domain); 12089a85e4b8SEric Auger 1209*b21e2380SMarkus Armbruster c = g_new0(TestGTreeInterval, 1); 12109a85e4b8SEric Auger c->low = 0x1000000; 12119a85e4b8SEric Auger c->high = 0x1FFFFFF; 12129a85e4b8SEric Auger 1213*b21e2380SMarkus Armbruster map_c = g_new0(TestGTreeMapping, 1); 12149a85e4b8SEric Auger map_c->phys_addr = 0xF000000; 12159a85e4b8SEric Auger map_c->flags = 0x3; 12169a85e4b8SEric Auger 12179a85e4b8SEric Auger g_tree_insert(second_domain->mappings, c, map_c); 12189a85e4b8SEric Auger return iommu; 12199a85e4b8SEric Auger } 12209a85e4b8SEric Auger 12219a85e4b8SEric Auger static void destroy_iommu(TestGTreeIOMMU *iommu) 12229a85e4b8SEric Auger { 12239a85e4b8SEric Auger g_tree_destroy(iommu->domains); 12249a85e4b8SEric Auger g_free(iommu); 12259a85e4b8SEric Auger } 12269a85e4b8SEric Auger 12279a85e4b8SEric Auger static void test_gtree_save_iommu(void) 12289a85e4b8SEric Auger { 12299a85e4b8SEric Auger TestGTreeIOMMU *iommu = create_iommu(); 12309a85e4b8SEric Auger 12319a85e4b8SEric Auger save_vmstate(&vmstate_iommu, iommu); 12329a85e4b8SEric Auger compare_vmstate(iommu_dump, sizeof(iommu_dump)); 12339a85e4b8SEric Auger destroy_iommu(iommu); 12349a85e4b8SEric Auger } 12359a85e4b8SEric Auger 12369a85e4b8SEric Auger static void test_gtree_load_iommu(void) 12379a85e4b8SEric Auger { 1238*b21e2380SMarkus Armbruster TestGTreeIOMMU *dest_iommu = g_new0(TestGTreeIOMMU, 1); 12399a85e4b8SEric Auger TestGTreeIOMMU *orig_iommu = create_iommu(); 12409a85e4b8SEric Auger QEMUFile *fsave, *fload; 12419a85e4b8SEric Auger char eof; 12429a85e4b8SEric Auger 12439a85e4b8SEric Auger fsave = open_test_file(true); 12449a85e4b8SEric Auger qemu_put_buffer(fsave, iommu_dump, sizeof(iommu_dump)); 12459a85e4b8SEric Auger g_assert(!qemu_file_get_error(fsave)); 12469a85e4b8SEric Auger qemu_fclose(fsave); 12479a85e4b8SEric Auger 12489a85e4b8SEric Auger fload = open_test_file(false); 12499a85e4b8SEric Auger vmstate_load_state(fload, &vmstate_iommu, dest_iommu, 1); 12509a85e4b8SEric Auger eof = qemu_get_byte(fload); 1251a6fbd637SChen Qun g_assert(!qemu_file_get_error(fload)); 12529a85e4b8SEric Auger g_assert_cmpint(orig_iommu->id, ==, dest_iommu->id); 12539a85e4b8SEric Auger g_assert_cmpint(eof, ==, QEMU_VM_EOF); 12549a85e4b8SEric Auger 12559a85e4b8SEric Auger diff_iommu(orig_iommu, dest_iommu); 12569a85e4b8SEric Auger destroy_iommu(orig_iommu); 12579a85e4b8SEric Auger destroy_iommu(dest_iommu); 12589a85e4b8SEric Auger qemu_fclose(fload); 12599a85e4b8SEric Auger } 12609a85e4b8SEric Auger 12614746dbf8SEric Auger static uint8_t qlist_dump[] = { 12624746dbf8SEric Auger 0x00, 0x00, 0x00, 0x01, /* container id */ 12634746dbf8SEric Auger 0x1, /* start of a */ 12644746dbf8SEric Auger 0x00, 0x00, 0x00, 0x0a, 12654746dbf8SEric Auger 0x1, /* start of b */ 12664746dbf8SEric Auger 0x00, 0x00, 0x0b, 0x00, 12674746dbf8SEric Auger 0x1, /* start of c */ 12684746dbf8SEric Auger 0x00, 0x0c, 0x00, 0x00, 12694746dbf8SEric Auger 0x1, /* start of d */ 12704746dbf8SEric Auger 0x0d, 0x00, 0x00, 0x00, 12714746dbf8SEric Auger 0x0, /* end of list */ 12724746dbf8SEric Auger QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 12734746dbf8SEric Auger }; 12744746dbf8SEric Auger 12754746dbf8SEric Auger static TestQListContainer *alloc_container(void) 12764746dbf8SEric Auger { 1277*b21e2380SMarkus Armbruster TestQListElement *a = g_new(TestQListElement, 1); 1278*b21e2380SMarkus Armbruster TestQListElement *b = g_new(TestQListElement, 1); 1279*b21e2380SMarkus Armbruster TestQListElement *c = g_new(TestQListElement, 1); 1280*b21e2380SMarkus Armbruster TestQListElement *d = g_new(TestQListElement, 1); 1281*b21e2380SMarkus Armbruster TestQListContainer *container = g_new(TestQListContainer, 1); 12824746dbf8SEric Auger 12834746dbf8SEric Auger a->id = 0x0a; 12844746dbf8SEric Auger b->id = 0x0b00; 12854746dbf8SEric Auger c->id = 0xc0000; 12864746dbf8SEric Auger d->id = 0xd000000; 12874746dbf8SEric Auger container->id = 1; 12884746dbf8SEric Auger 12894746dbf8SEric Auger QLIST_INIT(&container->list); 12904746dbf8SEric Auger QLIST_INSERT_HEAD(&container->list, d, next); 12914746dbf8SEric Auger QLIST_INSERT_HEAD(&container->list, c, next); 12924746dbf8SEric Auger QLIST_INSERT_HEAD(&container->list, b, next); 12934746dbf8SEric Auger QLIST_INSERT_HEAD(&container->list, a, next); 12944746dbf8SEric Auger return container; 12954746dbf8SEric Auger } 12964746dbf8SEric Auger 12974746dbf8SEric Auger static void free_container(TestQListContainer *container) 12984746dbf8SEric Auger { 12994746dbf8SEric Auger TestQListElement *iter, *tmp; 13004746dbf8SEric Auger 13014746dbf8SEric Auger QLIST_FOREACH_SAFE(iter, &container->list, next, tmp) { 13024746dbf8SEric Auger QLIST_REMOVE(iter, next); 13034746dbf8SEric Auger g_free(iter); 13044746dbf8SEric Auger } 13054746dbf8SEric Auger g_free(container); 13064746dbf8SEric Auger } 13074746dbf8SEric Auger 13084746dbf8SEric Auger static void compare_containers(TestQListContainer *c1, TestQListContainer *c2) 13094746dbf8SEric Auger { 13104746dbf8SEric Auger TestQListElement *first_item_c1, *first_item_c2; 13114746dbf8SEric Auger 13124746dbf8SEric Auger while (!QLIST_EMPTY(&c1->list)) { 13134746dbf8SEric Auger first_item_c1 = QLIST_FIRST(&c1->list); 13144746dbf8SEric Auger first_item_c2 = QLIST_FIRST(&c2->list); 13154746dbf8SEric Auger assert(first_item_c2); 13164746dbf8SEric Auger assert(first_item_c1->id == first_item_c2->id); 13174746dbf8SEric Auger QLIST_REMOVE(first_item_c1, next); 13184746dbf8SEric Auger QLIST_REMOVE(first_item_c2, next); 13194746dbf8SEric Auger g_free(first_item_c1); 13204746dbf8SEric Auger g_free(first_item_c2); 13214746dbf8SEric Auger } 13224746dbf8SEric Auger assert(QLIST_EMPTY(&c2->list)); 13234746dbf8SEric Auger } 13244746dbf8SEric Auger 13254746dbf8SEric Auger /* 13264746dbf8SEric Auger * Check the prev & next fields are correct by doing list 13274746dbf8SEric Auger * manipulations on the container. We will do that for both 13284746dbf8SEric Auger * the source and the destination containers 13294746dbf8SEric Auger */ 13304746dbf8SEric Auger static void manipulate_container(TestQListContainer *c) 13314746dbf8SEric Auger { 13324746dbf8SEric Auger TestQListElement *prev = NULL, *iter = QLIST_FIRST(&c->list); 13334746dbf8SEric Auger TestQListElement *elem; 13344746dbf8SEric Auger 1335*b21e2380SMarkus Armbruster elem = g_new(TestQListElement, 1); 13364746dbf8SEric Auger elem->id = 0x12; 13374746dbf8SEric Auger QLIST_INSERT_AFTER(iter, elem, next); 13384746dbf8SEric Auger 1339*b21e2380SMarkus Armbruster elem = g_new(TestQListElement, 1); 13404746dbf8SEric Auger elem->id = 0x13; 13414746dbf8SEric Auger QLIST_INSERT_HEAD(&c->list, elem, next); 13424746dbf8SEric Auger 13434746dbf8SEric Auger while (iter) { 13444746dbf8SEric Auger prev = iter; 13454746dbf8SEric Auger iter = QLIST_NEXT(iter, next); 13464746dbf8SEric Auger } 13474746dbf8SEric Auger 1348*b21e2380SMarkus Armbruster elem = g_new(TestQListElement, 1); 13494746dbf8SEric Auger elem->id = 0x14; 13504746dbf8SEric Auger QLIST_INSERT_BEFORE(prev, elem, next); 13514746dbf8SEric Auger 1352*b21e2380SMarkus Armbruster elem = g_new(TestQListElement, 1); 13534746dbf8SEric Auger elem->id = 0x15; 13544746dbf8SEric Auger QLIST_INSERT_AFTER(prev, elem, next); 13554746dbf8SEric Auger 13564746dbf8SEric Auger QLIST_REMOVE(prev, next); 13574746dbf8SEric Auger g_free(prev); 13584746dbf8SEric Auger } 13594746dbf8SEric Auger 13604746dbf8SEric Auger static void test_save_qlist(void) 13614746dbf8SEric Auger { 13624746dbf8SEric Auger TestQListContainer *container = alloc_container(); 13634746dbf8SEric Auger 13644746dbf8SEric Auger save_vmstate(&vmstate_container, container); 13654746dbf8SEric Auger compare_vmstate(qlist_dump, sizeof(qlist_dump)); 13664746dbf8SEric Auger free_container(container); 13674746dbf8SEric Auger } 13684746dbf8SEric Auger 13694746dbf8SEric Auger static void test_load_qlist(void) 13704746dbf8SEric Auger { 13714746dbf8SEric Auger QEMUFile *fsave, *fload; 13724746dbf8SEric Auger TestQListContainer *orig_container = alloc_container(); 1373*b21e2380SMarkus Armbruster TestQListContainer *dest_container = g_new0(TestQListContainer, 1); 13744746dbf8SEric Auger char eof; 13754746dbf8SEric Auger 13764746dbf8SEric Auger QLIST_INIT(&dest_container->list); 13774746dbf8SEric Auger 13784746dbf8SEric Auger fsave = open_test_file(true); 13794746dbf8SEric Auger qemu_put_buffer(fsave, qlist_dump, sizeof(qlist_dump)); 13804746dbf8SEric Auger g_assert(!qemu_file_get_error(fsave)); 13814746dbf8SEric Auger qemu_fclose(fsave); 13824746dbf8SEric Auger 13834746dbf8SEric Auger fload = open_test_file(false); 13844746dbf8SEric Auger vmstate_load_state(fload, &vmstate_container, dest_container, 1); 13854746dbf8SEric Auger eof = qemu_get_byte(fload); 13864746dbf8SEric Auger g_assert(!qemu_file_get_error(fload)); 13874746dbf8SEric Auger g_assert_cmpint(eof, ==, QEMU_VM_EOF); 13884746dbf8SEric Auger manipulate_container(orig_container); 13894746dbf8SEric Auger manipulate_container(dest_container); 13904746dbf8SEric Auger compare_containers(orig_container, dest_container); 13914746dbf8SEric Auger free_container(orig_container); 13924746dbf8SEric Auger free_container(dest_container); 1393a6fbd637SChen Qun qemu_fclose(fload); 13944746dbf8SEric Auger } 13954746dbf8SEric Auger 13965c379d90SDr. David Alan Gilbert typedef struct TmpTestStruct { 13975c379d90SDr. David Alan Gilbert TestStruct *parent; 13985c379d90SDr. David Alan Gilbert int64_t diff; 13995c379d90SDr. David Alan Gilbert } TmpTestStruct; 14005c379d90SDr. David Alan Gilbert 140144b1ff31SDr. David Alan Gilbert static int tmp_child_pre_save(void *opaque) 14025c379d90SDr. David Alan Gilbert { 14035c379d90SDr. David Alan Gilbert struct TmpTestStruct *tts = opaque; 14045c379d90SDr. David Alan Gilbert 14055c379d90SDr. David Alan Gilbert tts->diff = tts->parent->b - tts->parent->a; 140644b1ff31SDr. David Alan Gilbert 140744b1ff31SDr. David Alan Gilbert return 0; 14085c379d90SDr. David Alan Gilbert } 14095c379d90SDr. David Alan Gilbert 14105c379d90SDr. David Alan Gilbert static int tmp_child_post_load(void *opaque, int version_id) 14115c379d90SDr. David Alan Gilbert { 14125c379d90SDr. David Alan Gilbert struct TmpTestStruct *tts = opaque; 14135c379d90SDr. David Alan Gilbert 14145c379d90SDr. David Alan Gilbert tts->parent->b = tts->parent->a + tts->diff; 14155c379d90SDr. David Alan Gilbert 14165c379d90SDr. David Alan Gilbert return 0; 14175c379d90SDr. David Alan Gilbert } 14185c379d90SDr. David Alan Gilbert 14195c379d90SDr. David Alan Gilbert static const VMStateDescription vmstate_tmp_back_to_parent = { 14205c379d90SDr. David Alan Gilbert .name = "test/tmp_child_parent", 14215c379d90SDr. David Alan Gilbert .fields = (VMStateField[]) { 14225c379d90SDr. David Alan Gilbert VMSTATE_UINT64(f, TestStruct), 14235c379d90SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 14245c379d90SDr. David Alan Gilbert } 14255c379d90SDr. David Alan Gilbert }; 14265c379d90SDr. David Alan Gilbert 14275c379d90SDr. David Alan Gilbert static const VMStateDescription vmstate_tmp_child = { 14285c379d90SDr. David Alan Gilbert .name = "test/tmp_child", 14295c379d90SDr. David Alan Gilbert .pre_save = tmp_child_pre_save, 14305c379d90SDr. David Alan Gilbert .post_load = tmp_child_post_load, 14315c379d90SDr. David Alan Gilbert .fields = (VMStateField[]) { 14325c379d90SDr. David Alan Gilbert VMSTATE_INT64(diff, TmpTestStruct), 14335c379d90SDr. David Alan Gilbert VMSTATE_STRUCT_POINTER(parent, TmpTestStruct, 14345c379d90SDr. David Alan Gilbert vmstate_tmp_back_to_parent, TestStruct), 14355c379d90SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 14365c379d90SDr. David Alan Gilbert } 14375c379d90SDr. David Alan Gilbert }; 14385c379d90SDr. David Alan Gilbert 14395c379d90SDr. David Alan Gilbert static const VMStateDescription vmstate_with_tmp = { 14405c379d90SDr. David Alan Gilbert .name = "test/with_tmp", 14415c379d90SDr. David Alan Gilbert .version_id = 1, 14425c379d90SDr. David Alan Gilbert .fields = (VMStateField[]) { 14435c379d90SDr. David Alan Gilbert VMSTATE_UINT32(a, TestStruct), 14445c379d90SDr. David Alan Gilbert VMSTATE_UINT64(d, TestStruct), 14455c379d90SDr. David Alan Gilbert VMSTATE_WITH_TMP(TestStruct, TmpTestStruct, vmstate_tmp_child), 14465c379d90SDr. David Alan Gilbert VMSTATE_END_OF_LIST() 14475c379d90SDr. David Alan Gilbert } 14485c379d90SDr. David Alan Gilbert }; 14495c379d90SDr. David Alan Gilbert 14505c379d90SDr. David Alan Gilbert static void obj_tmp_copy(void *target, void *source) 14515c379d90SDr. David Alan Gilbert { 14525c379d90SDr. David Alan Gilbert memcpy(target, source, sizeof(TestStruct)); 14535c379d90SDr. David Alan Gilbert } 14545c379d90SDr. David Alan Gilbert 14555c379d90SDr. David Alan Gilbert static void test_tmp_struct(void) 14565c379d90SDr. David Alan Gilbert { 14575c379d90SDr. David Alan Gilbert TestStruct obj, obj_clone; 14585c379d90SDr. David Alan Gilbert 14595c379d90SDr. David Alan Gilbert uint8_t const wire_with_tmp[] = { 14605c379d90SDr. David Alan Gilbert /* u32 a */ 0x00, 0x00, 0x00, 0x02, 14615c379d90SDr. David Alan Gilbert /* u64 d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 14625c379d90SDr. David Alan Gilbert /* diff */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 14635c379d90SDr. David Alan Gilbert /* u64 f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 14645c379d90SDr. David Alan Gilbert QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ 14655c379d90SDr. David Alan Gilbert }; 14665c379d90SDr. David Alan Gilbert 14675c379d90SDr. David Alan Gilbert memset(&obj, 0, sizeof(obj)); 14685c379d90SDr. David Alan Gilbert obj.a = 2; 14695c379d90SDr. David Alan Gilbert obj.b = 4; 14705c379d90SDr. David Alan Gilbert obj.d = 1; 14715c379d90SDr. David Alan Gilbert obj.f = 8; 14725c379d90SDr. David Alan Gilbert save_vmstate(&vmstate_with_tmp, &obj); 14735c379d90SDr. David Alan Gilbert 14745c379d90SDr. David Alan Gilbert compare_vmstate(wire_with_tmp, sizeof(wire_with_tmp)); 14755c379d90SDr. David Alan Gilbert 14765c379d90SDr. David Alan Gilbert memset(&obj, 0, sizeof(obj)); 14775c379d90SDr. David Alan Gilbert SUCCESS(load_vmstate(&vmstate_with_tmp, &obj, &obj_clone, 14785c379d90SDr. David Alan Gilbert obj_tmp_copy, 1, wire_with_tmp, 14795c379d90SDr. David Alan Gilbert sizeof(wire_with_tmp))); 14805c379d90SDr. David Alan Gilbert g_assert_cmpint(obj.a, ==, 2); /* From top level vmsd */ 14815c379d90SDr. David Alan Gilbert g_assert_cmpint(obj.b, ==, 4); /* from the post_load */ 14825c379d90SDr. David Alan Gilbert g_assert_cmpint(obj.d, ==, 1); /* From top level vmsd */ 14835c379d90SDr. David Alan Gilbert g_assert_cmpint(obj.f, ==, 8); /* From the child->parent */ 14845c379d90SDr. David Alan Gilbert } 14855c379d90SDr. David Alan Gilbert 14862668b4bfSEduardo Habkost int main(int argc, char **argv) 14872668b4bfSEduardo Habkost { 148896c64746SYonggang Luo g_autofree char *temp_file = g_strdup_printf("%s/vmst.test.XXXXXX", 148996c64746SYonggang Luo g_get_tmp_dir()); 14902668b4bfSEduardo Habkost temp_fd = mkstemp(temp_file); 14911c861885SPeter Maydell g_assert(temp_fd >= 0); 14922668b4bfSEduardo Habkost 14938925839fSDaniel P. Berrange module_call_init(MODULE_INIT_QOM); 14948925839fSDaniel P. Berrange 1495e468ffdcSMarc-André Lureau g_setenv("QTEST_SILENT_ERRORS", "1", 1); 1496977a7204SDaniel P. Berrangé 14972668b4bfSEduardo Habkost g_test_init(&argc, &argv, NULL); 14984ea7df4eSJuan Quintela g_test_add_func("/vmstate/simple/primitive", test_simple_primitive); 1499b95d6588SMarc-André Lureau g_test_add_func("/vmstate/simple/array", test_simple_array); 15002668b4bfSEduardo Habkost g_test_add_func("/vmstate/versioned/load/v1", test_load_v1); 15012668b4bfSEduardo Habkost g_test_add_func("/vmstate/versioned/load/v2", test_load_v2); 15022668b4bfSEduardo Habkost g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip); 15032668b4bfSEduardo Habkost g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip); 15042668b4bfSEduardo Habkost g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip); 15052668b4bfSEduardo Habkost g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip); 15068cc49f03SHalil Pasic g_test_add_func("/vmstate/array/ptr/str/no0/save", 15078cc49f03SHalil Pasic test_arr_ptr_str_no0_save); 15088cc49f03SHalil Pasic g_test_add_func("/vmstate/array/ptr/str/no0/load", 15098cc49f03SHalil Pasic test_arr_ptr_str_no0_load); 1510cc958831SHalil Pasic g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save); 1511cc958831SHalil Pasic g_test_add_func("/vmstate/array/ptr/str/0/load", 1512cc958831SHalil Pasic test_arr_ptr_str_0_load); 151343333099SHalil Pasic g_test_add_func("/vmstate/array/ptr/prim/0/save", 151443333099SHalil Pasic test_arr_ptr_prim_0_save); 151543333099SHalil Pasic g_test_add_func("/vmstate/array/ptr/prim/0/load", 151643333099SHalil Pasic test_arr_ptr_prim_0_load); 15177e99f22cSJianjun Duan g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q); 15187e99f22cSJianjun Duan g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q); 15199a85e4b8SEric Auger g_test_add_func("/vmstate/gtree/save/savedomain", test_gtree_save_domain); 15209a85e4b8SEric Auger g_test_add_func("/vmstate/gtree/load/loaddomain", test_gtree_load_domain); 15219a85e4b8SEric Auger g_test_add_func("/vmstate/gtree/save/saveiommu", test_gtree_save_iommu); 15229a85e4b8SEric Auger g_test_add_func("/vmstate/gtree/load/loadiommu", test_gtree_load_iommu); 15234746dbf8SEric Auger g_test_add_func("/vmstate/qlist/save/saveqlist", test_save_qlist); 15244746dbf8SEric Auger g_test_add_func("/vmstate/qlist/load/loadqlist", test_load_qlist); 15255c379d90SDr. David Alan Gilbert g_test_add_func("/vmstate/tmp_struct", test_tmp_struct); 15262668b4bfSEduardo Habkost g_test_run(); 15272668b4bfSEduardo Habkost 15282668b4bfSEduardo Habkost close(temp_fd); 15292668b4bfSEduardo Habkost unlink(temp_file); 15302668b4bfSEduardo Habkost 15312668b4bfSEduardo Habkost return 0; 15322668b4bfSEduardo Habkost } 1533