xref: /qemu/rust/qemu-api/tests/vmstate_tests.rs (revision 1998502196ad81fde58a48aac2256731bf6d0022)
1 // Copyright (C) 2025 Intel Corporation.
2 // Author(s): Zhao Liu <zhai1.liu@intel.com>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 
5 use std::{ffi::CStr, mem::size_of, slice};
6 
7 use qemu_api::{
8     bindings::{vmstate_info_int8, vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags},
9     c_str,
10     vmstate::{VMStateDescription, VMStateField},
11     vmstate_fields, vmstate_of, vmstate_unused,
12     zeroable::Zeroable,
13 };
14 
15 const FOO_ARRAY_MAX: usize = 3;
16 
17 // =========================== Test VMSTATE_FOOA ===========================
18 // Test the use cases of the vmstate macro, corresponding to the following C
19 // macro variants:
20 //   * VMSTATE_FOOA:
21 //     - VMSTATE_U16
22 //     - VMSTATE_UNUSED
23 //     - VMSTATE_VARRAY_UINT16_UNSAFE
24 //     - VMSTATE_VARRAY_MULTIPLY
25 #[repr(C)]
26 #[derive(qemu_api_macros::offsets)]
27 struct FooA {
28     arr: [u8; FOO_ARRAY_MAX],
29     num: u16,
30     arr_mul: [i8; FOO_ARRAY_MAX],
31     num_mul: u32,
32     elem: i8,
33 }
34 
35 static VMSTATE_FOOA: VMStateDescription = VMStateDescription {
36     name: c_str!("foo_a").as_ptr(),
37     version_id: 1,
38     minimum_version_id: 1,
39     fields: vmstate_fields! {
40         vmstate_of!(FooA, elem),
41         vmstate_unused!(size_of::<i64>()),
42         vmstate_of!(FooA, arr[0 .. num]).with_version_id(0),
43         vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]),
44     },
45     ..Zeroable::ZERO
46 };
47 
48 #[test]
49 fn test_vmstate_uint16() {
50     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
51 
52     // 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE_UINT16)
53     assert_eq!(
54         unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
55         b"elem\0"
56     );
57     assert_eq!(foo_fields[0].offset, 16);
58     assert_eq!(foo_fields[0].num_offset, 0);
59     assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int8 });
60     assert_eq!(foo_fields[0].version_id, 0);
61     assert_eq!(foo_fields[0].size, 1);
62     assert_eq!(foo_fields[0].num, 0);
63     assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
64     assert!(foo_fields[0].vmsd.is_null());
65     assert!(foo_fields[0].field_exists.is_none());
66 }
67 
68 #[test]
69 fn test_vmstate_unused() {
70     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
71 
72     // 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTATE_UNUSED)
73     assert_eq!(
74         unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
75         b"unused\0"
76     );
77     assert_eq!(foo_fields[1].offset, 0);
78     assert_eq!(foo_fields[1].num_offset, 0);
79     assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_unused_buffer });
80     assert_eq!(foo_fields[1].version_id, 0);
81     assert_eq!(foo_fields[1].size, 8);
82     assert_eq!(foo_fields[1].num, 0);
83     assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_BUFFER);
84     assert!(foo_fields[1].vmsd.is_null());
85     assert!(foo_fields[1].field_exists.is_none());
86 }
87 
88 #[test]
89 fn test_vmstate_varray_uint16_unsafe() {
90     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
91 
92     // 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to
93     // VMSTATE_VARRAY_UINT16_UNSAFE)
94     assert_eq!(
95         unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
96         b"arr\0"
97     );
98     assert_eq!(foo_fields[2].offset, 0);
99     assert_eq!(foo_fields[2].num_offset, 4);
100     assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
101     assert_eq!(foo_fields[2].version_id, 0);
102     assert_eq!(foo_fields[2].size, 1);
103     assert_eq!(foo_fields[2].num, 0);
104     assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY_UINT16);
105     assert!(foo_fields[2].vmsd.is_null());
106     assert!(foo_fields[2].field_exists.is_none());
107 }
108 
109 #[test]
110 fn test_vmstate_varray_multiply() {
111     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
112 
113     // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to
114     // VMSTATE_VARRAY_MULTIPLY)
115     assert_eq!(
116         unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
117         b"arr_mul\0"
118     );
119     assert_eq!(foo_fields[3].offset, 6);
120     assert_eq!(foo_fields[3].num_offset, 12);
121     assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_int8 });
122     assert_eq!(foo_fields[3].version_id, 0);
123     assert_eq!(foo_fields[3].size, 1);
124     assert_eq!(foo_fields[3].num, 16);
125     assert_eq!(
126         foo_fields[3].flags.0,
127         VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
128     );
129     assert!(foo_fields[3].vmsd.is_null());
130     assert!(foo_fields[3].field_exists.is_none());
131 
132     // The last VMStateField in VMSTATE_FOOA.
133     assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
134 }
135