xref: /qemu/rust/qemu-api/tests/vmstate_tests.rs (revision 57c327f3a044ebd6da9efda07e4d264996688110)
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::{
9         vmstate_info_bool, vmstate_info_int64, vmstate_info_int8, vmstate_info_uint64,
10         vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags,
11     },
12     c_str,
13     cell::BqlCell,
14     vmstate::{VMStateDescription, VMStateField},
15     vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused,
16     zeroable::Zeroable,
17 };
18 
19 const FOO_ARRAY_MAX: usize = 3;
20 
21 // =========================== Test VMSTATE_FOOA ===========================
22 // Test the use cases of the vmstate macro, corresponding to the following C
23 // macro variants:
24 //   * VMSTATE_FOOA:
25 //     - VMSTATE_U16
26 //     - VMSTATE_UNUSED
27 //     - VMSTATE_VARRAY_UINT16_UNSAFE
28 //     - VMSTATE_VARRAY_MULTIPLY
29 #[repr(C)]
30 #[derive(qemu_api_macros::offsets)]
31 struct FooA {
32     arr: [u8; FOO_ARRAY_MAX],
33     num: u16,
34     arr_mul: [i8; FOO_ARRAY_MAX],
35     num_mul: u32,
36     elem: i8,
37 }
38 
39 static VMSTATE_FOOA: VMStateDescription = VMStateDescription {
40     name: c_str!("foo_a").as_ptr(),
41     version_id: 1,
42     minimum_version_id: 1,
43     fields: vmstate_fields! {
44         vmstate_of!(FooA, elem),
45         vmstate_unused!(size_of::<i64>()),
46         vmstate_of!(FooA, arr[0 .. num]).with_version_id(0),
47         vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]),
48     },
49     ..Zeroable::ZERO
50 };
51 
52 #[test]
53 fn test_vmstate_uint16() {
54     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
55 
56     // 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE_UINT16)
57     assert_eq!(
58         unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
59         b"elem\0"
60     );
61     assert_eq!(foo_fields[0].offset, 16);
62     assert_eq!(foo_fields[0].num_offset, 0);
63     assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int8 });
64     assert_eq!(foo_fields[0].version_id, 0);
65     assert_eq!(foo_fields[0].size, 1);
66     assert_eq!(foo_fields[0].num, 0);
67     assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
68     assert!(foo_fields[0].vmsd.is_null());
69     assert!(foo_fields[0].field_exists.is_none());
70 }
71 
72 #[test]
73 fn test_vmstate_unused() {
74     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
75 
76     // 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTATE_UNUSED)
77     assert_eq!(
78         unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
79         b"unused\0"
80     );
81     assert_eq!(foo_fields[1].offset, 0);
82     assert_eq!(foo_fields[1].num_offset, 0);
83     assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_unused_buffer });
84     assert_eq!(foo_fields[1].version_id, 0);
85     assert_eq!(foo_fields[1].size, 8);
86     assert_eq!(foo_fields[1].num, 0);
87     assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_BUFFER);
88     assert!(foo_fields[1].vmsd.is_null());
89     assert!(foo_fields[1].field_exists.is_none());
90 }
91 
92 #[test]
93 fn test_vmstate_varray_uint16_unsafe() {
94     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
95 
96     // 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to
97     // VMSTATE_VARRAY_UINT16_UNSAFE)
98     assert_eq!(
99         unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
100         b"arr\0"
101     );
102     assert_eq!(foo_fields[2].offset, 0);
103     assert_eq!(foo_fields[2].num_offset, 4);
104     assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
105     assert_eq!(foo_fields[2].version_id, 0);
106     assert_eq!(foo_fields[2].size, 1);
107     assert_eq!(foo_fields[2].num, 0);
108     assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY_UINT16);
109     assert!(foo_fields[2].vmsd.is_null());
110     assert!(foo_fields[2].field_exists.is_none());
111 }
112 
113 #[test]
114 fn test_vmstate_varray_multiply() {
115     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
116 
117     // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to
118     // VMSTATE_VARRAY_MULTIPLY)
119     assert_eq!(
120         unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
121         b"arr_mul\0"
122     );
123     assert_eq!(foo_fields[3].offset, 6);
124     assert_eq!(foo_fields[3].num_offset, 12);
125     assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_int8 });
126     assert_eq!(foo_fields[3].version_id, 0);
127     assert_eq!(foo_fields[3].size, 1);
128     assert_eq!(foo_fields[3].num, 16);
129     assert_eq!(
130         foo_fields[3].flags.0,
131         VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
132     );
133     assert!(foo_fields[3].vmsd.is_null());
134     assert!(foo_fields[3].field_exists.is_none());
135 
136     // The last VMStateField in VMSTATE_FOOA.
137     assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
138 }
139 
140 // =========================== Test VMSTATE_FOOB ===========================
141 // Test the use cases of the vmstate macro, corresponding to the following C
142 // macro variants:
143 //   * VMSTATE_FOOB:
144 //     - VMSTATE_BOOL_V
145 //     - VMSTATE_U64
146 //     - VMSTATE_STRUCT_VARRAY_UINT8
147 //     - (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32
148 //     - VMSTATE_ARRAY
149 #[repr(C)]
150 #[derive(qemu_api_macros::offsets)]
151 struct FooB {
152     arr_a: [FooA; FOO_ARRAY_MAX],
153     num_a: u8,
154     arr_a_mul: [FooA; FOO_ARRAY_MAX],
155     num_a_mul: u32,
156     wrap: BqlCell<u64>,
157     val: bool,
158     // FIXME: Use Timer array. Now we can't since it's hard to link savevm.c to test.
159     arr_i64: [i64; FOO_ARRAY_MAX],
160 }
161 
162 static VMSTATE_FOOB: VMStateDescription = VMStateDescription {
163     name: c_str!("foo_b").as_ptr(),
164     version_id: 2,
165     minimum_version_id: 1,
166     fields: vmstate_fields! {
167         vmstate_of!(FooB, val).with_version_id(2),
168         vmstate_of!(FooB, wrap),
169         vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).with_version_id(1),
170         vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE_FOOA, FooA).with_version_id(2),
171         vmstate_of!(FooB, arr_i64),
172     },
173     ..Zeroable::ZERO
174 };
175 
176 #[test]
177 fn test_vmstate_bool_v() {
178     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
179 
180     // 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_BOOL_V)
181     assert_eq!(
182         unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
183         b"val\0"
184     );
185     assert_eq!(foo_fields[0].offset, 136);
186     assert_eq!(foo_fields[0].num_offset, 0);
187     assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_bool });
188     assert_eq!(foo_fields[0].version_id, 2);
189     assert_eq!(foo_fields[0].size, 1);
190     assert_eq!(foo_fields[0].num, 0);
191     assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
192     assert!(foo_fields[0].vmsd.is_null());
193     assert!(foo_fields[0].field_exists.is_none());
194 }
195 
196 #[test]
197 fn test_vmstate_uint64() {
198     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
199 
200     // 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE_U64)
201     assert_eq!(
202         unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
203         b"wrap\0"
204     );
205     assert_eq!(foo_fields[1].offset, 128);
206     assert_eq!(foo_fields[1].num_offset, 0);
207     assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_uint64 });
208     assert_eq!(foo_fields[1].version_id, 0);
209     assert_eq!(foo_fields[1].size, 8);
210     assert_eq!(foo_fields[1].num, 0);
211     assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_SINGLE);
212     assert!(foo_fields[1].vmsd.is_null());
213     assert!(foo_fields[1].field_exists.is_none());
214 }
215 
216 #[test]
217 fn test_vmstate_struct_varray_uint8() {
218     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
219 
220     // 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to
221     // VMSTATE_STRUCT_VARRAY_UINT8)
222     assert_eq!(
223         unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
224         b"arr_a\0"
225     );
226     assert_eq!(foo_fields[2].offset, 0);
227     assert_eq!(foo_fields[2].num_offset, 60);
228     assert!(foo_fields[2].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
229     assert_eq!(foo_fields[2].version_id, 1);
230     assert_eq!(foo_fields[2].size, 20);
231     assert_eq!(foo_fields[2].num, 0);
232     assert_eq!(
233         foo_fields[2].flags.0,
234         VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY_UINT8.0
235     );
236     assert_eq!(foo_fields[2].vmsd, &VMSTATE_FOOA);
237     assert!(foo_fields[2].field_exists.is_none());
238 }
239 
240 #[test]
241 fn test_vmstate_struct_varray_uint32_multiply() {
242     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
243 
244     // 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to
245     // (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32)
246     assert_eq!(
247         unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
248         b"arr_a_mul\0"
249     );
250     assert_eq!(foo_fields[3].offset, 64);
251     assert_eq!(foo_fields[3].num_offset, 124);
252     assert!(foo_fields[3].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
253     assert_eq!(foo_fields[3].version_id, 2);
254     assert_eq!(foo_fields[3].size, 20);
255     assert_eq!(foo_fields[3].num, 32);
256     assert_eq!(
257         foo_fields[3].flags.0,
258         VMStateFlags::VMS_STRUCT.0
259             | VMStateFlags::VMS_VARRAY_UINT32.0
260             | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
261     );
262     assert_eq!(foo_fields[3].vmsd, &VMSTATE_FOOA);
263     assert!(foo_fields[3].field_exists.is_none());
264 }
265 
266 #[test]
267 fn test_vmstate_macro_array() {
268     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) };
269 
270     // 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to
271     // VMSTATE_ARRAY)
272     assert_eq!(
273         unsafe { CStr::from_ptr(foo_fields[4].name) }.to_bytes_with_nul(),
274         b"arr_i64\0"
275     );
276     assert_eq!(foo_fields[4].offset, 144);
277     assert_eq!(foo_fields[4].num_offset, 0);
278     assert_eq!(foo_fields[4].info, unsafe { &vmstate_info_int64 });
279     assert_eq!(foo_fields[4].version_id, 0);
280     assert_eq!(foo_fields[4].size, 8);
281     assert_eq!(foo_fields[4].num, FOO_ARRAY_MAX as i32);
282     assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_ARRAY);
283     assert!(foo_fields[4].vmsd.is_null());
284     assert!(foo_fields[4].field_exists.is_none());
285 
286     // The last VMStateField in VMSTATE_FOOB.
287     assert_eq!(foo_fields[5].flags, VMStateFlags::VMS_END);
288 }
289