xref: /qemu/rust/qemu-api/src/vmstate.rs (revision 716d89f9cc14faf784d83c945c40b7e8256ae525)
1 // Copyright 2024, Linaro Limited
2 // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 
5 //! Helper macros to declare migration state for device models.
6 //!
7 //! Some macros are direct equivalents to the C macros declared in
8 //! `include/migration/vmstate.h` while
9 //! [`vmstate_subsections`](crate::vmstate_subsections) and
10 //! [`vmstate_fields`](crate::vmstate_fields) are meant to be used when
11 //! declaring a device model state struct.
12 
13 pub use crate::bindings::VMStateDescription;
14 
15 #[doc(alias = "VMSTATE_UNUSED_BUFFER")]
16 #[macro_export]
17 macro_rules! vmstate_unused_buffer {
18     ($field_exists_fn:expr, $version_id:expr, $size:expr) => {{
19         $crate::bindings::VMStateField {
20             name: c_str!("unused").as_ptr(),
21             err_hint: ::core::ptr::null(),
22             offset: 0,
23             size: $size,
24             start: 0,
25             num: 0,
26             num_offset: 0,
27             size_offset: 0,
28             info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) },
29             flags: VMStateFlags::VMS_BUFFER,
30             vmsd: ::core::ptr::null(),
31             version_id: $version_id,
32             struct_version_id: 0,
33             field_exists: $field_exists_fn,
34         }
35     }};
36 }
37 
38 #[doc(alias = "VMSTATE_UNUSED_V")]
39 #[macro_export]
40 macro_rules! vmstate_unused_v {
41     ($version_id:expr, $size:expr) => {{
42         $crate::vmstate_unused_buffer!(None, $version_id, $size)
43     }};
44 }
45 
46 #[doc(alias = "VMSTATE_UNUSED")]
47 #[macro_export]
48 macro_rules! vmstate_unused {
49     ($size:expr) => {{
50         $crate::vmstate_unused_v!(0, $size)
51     }};
52 }
53 
54 #[doc(alias = "VMSTATE_SINGLE_TEST")]
55 #[macro_export]
56 macro_rules! vmstate_single_test {
57     ($field_name:ident, $struct_name:ty, $field_exists_fn:expr, $version_id:expr, $info:expr, $size:expr) => {{
58         $crate::bindings::VMStateField {
59             name: ::core::concat!(::core::stringify!($field_name), 0)
60                 .as_bytes()
61                 .as_ptr() as *const ::std::os::raw::c_char,
62             err_hint: ::core::ptr::null(),
63             offset: $crate::offset_of!($struct_name, $field_name),
64             size: $size,
65             start: 0,
66             num: 0,
67             num_offset: 0,
68             size_offset: 0,
69             info: unsafe { $info },
70             flags: VMStateFlags::VMS_SINGLE,
71             vmsd: ::core::ptr::null(),
72             version_id: $version_id,
73             struct_version_id: 0,
74             field_exists: $field_exists_fn,
75         }
76     }};
77 }
78 
79 #[doc(alias = "VMSTATE_SINGLE")]
80 #[macro_export]
81 macro_rules! vmstate_single {
82     ($field_name:ident, $struct_name:ty, $version_id:expr, $info:expr, $size:expr) => {{
83         $crate::vmstate_single_test!($field_name, $struct_name, None, $version_id, $info, $size)
84     }};
85 }
86 
87 #[doc(alias = "VMSTATE_UINT32_V")]
88 #[macro_export]
89 macro_rules! vmstate_uint32_v {
90     ($field_name:ident, $struct_name:ty, $version_id:expr) => {{
91         $crate::vmstate_single!(
92             $field_name,
93             $struct_name,
94             $version_id,
95             ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32),
96             ::core::mem::size_of::<u32>()
97         )
98     }};
99 }
100 
101 #[doc(alias = "VMSTATE_UINT32")]
102 #[macro_export]
103 macro_rules! vmstate_uint32 {
104     ($field_name:ident, $struct_name:ty) => {{
105         $crate::vmstate_uint32_v!($field_name, $struct_name, 0)
106     }};
107 }
108 
109 #[doc(alias = "VMSTATE_INT32_V")]
110 #[macro_export]
111 macro_rules! vmstate_int32_v {
112     ($field_name:ident, $struct_name:ty, $version_id:expr) => {{
113         $crate::vmstate_single!(
114             $field_name,
115             $struct_name,
116             $version_id,
117             ::core::ptr::addr_of!($crate::bindings::vmstate_info_int32),
118             ::core::mem::size_of::<i32>()
119         )
120     }};
121 }
122 
123 #[doc(alias = "VMSTATE_INT32")]
124 #[macro_export]
125 macro_rules! vmstate_int32 {
126     ($field_name:ident, $struct_name:ty) => {{
127         $crate::vmstate_int32_v!($field_name, $struct_name, 0)
128     }};
129 }
130 
131 #[doc(alias = "VMSTATE_ARRAY")]
132 #[macro_export]
133 macro_rules! vmstate_array {
134     ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr, $info:expr, $size:expr) => {{
135         $crate::bindings::VMStateField {
136             name: ::core::concat!(::core::stringify!($field_name), 0)
137                 .as_bytes()
138                 .as_ptr() as *const ::std::os::raw::c_char,
139             err_hint: ::core::ptr::null(),
140             offset: $crate::offset_of!($struct_name, $field_name),
141             size: $size,
142             start: 0,
143             num: $length as _,
144             num_offset: 0,
145             size_offset: 0,
146             info: unsafe { $info },
147             flags: VMStateFlags::VMS_ARRAY,
148             vmsd: ::core::ptr::null(),
149             version_id: $version_id,
150             struct_version_id: 0,
151             field_exists: None,
152         }
153     }};
154 }
155 
156 #[doc(alias = "VMSTATE_UINT32_ARRAY_V")]
157 #[macro_export]
158 macro_rules! vmstate_uint32_array_v {
159     ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr) => {{
160         $crate::vmstate_array!(
161             $field_name,
162             $struct_name,
163             $length,
164             $version_id,
165             ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32),
166             ::core::mem::size_of::<u32>()
167         )
168     }};
169 }
170 
171 #[doc(alias = "VMSTATE_UINT32_ARRAY")]
172 #[macro_export]
173 macro_rules! vmstate_uint32_array {
174     ($field_name:ident, $struct_name:ty, $length:expr) => {{
175         $crate::vmstate_uint32_array_v!($field_name, $struct_name, $length, 0)
176     }};
177 }
178 
179 #[doc(alias = "VMSTATE_STRUCT_POINTER_V")]
180 #[macro_export]
181 macro_rules! vmstate_struct_pointer_v {
182     ($field_name:ident, $struct_name:ty, $version_id:expr, $vmsd:expr, $type:ty) => {{
183         $crate::bindings::VMStateField {
184             name: ::core::concat!(::core::stringify!($field_name), 0)
185                 .as_bytes()
186                 .as_ptr() as *const ::std::os::raw::c_char,
187             err_hint: ::core::ptr::null(),
188             offset: $crate::offset_of!($struct_name, $field_name),
189             size: ::core::mem::size_of::<*const $type>(),
190             start: 0,
191             num: 0,
192             num_offset: 0,
193             size_offset: 0,
194             info: ::core::ptr::null(),
195             flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0),
196             vmsd: unsafe { $vmsd },
197             version_id: $version_id,
198             struct_version_id: 0,
199             field_exists: None,
200         }
201     }};
202 }
203 
204 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER")]
205 #[macro_export]
206 macro_rules! vmstate_array_of_pointer {
207     ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $info:expr, $type:ty) => {{
208         $crate::bindings::VMStateField {
209             name: ::core::concat!(::core::stringify!($field_name), 0)
210                 .as_bytes()
211                 .as_ptr() as *const ::std::os::raw::c_char,
212             version_id: $version_id,
213             num: $num as _,
214             info: unsafe { $info },
215             size: ::core::mem::size_of::<*const $type>(),
216             flags: VMStateFlags(VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0),
217             offset: $crate::offset_of!($struct_name, $field_name),
218             err_hint: ::core::ptr::null(),
219             start: 0,
220             num_offset: 0,
221             size_offset: 0,
222             vmsd: ::core::ptr::null(),
223             struct_version_id: 0,
224             field_exists: None,
225         }
226     }};
227 }
228 
229 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER_TO_STRUCT")]
230 #[macro_export]
231 macro_rules! vmstate_array_of_pointer_to_struct {
232     ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $vmsd:expr, $type:ty) => {{
233         $crate::bindings::VMStateField {
234             name: ::core::concat!(::core::stringify!($field_name), 0)
235                 .as_bytes()
236                 .as_ptr() as *const ::std::os::raw::c_char,
237             version_id: $version_id,
238             num: $num as _,
239             vmsd: unsafe { $vmsd },
240             size: ::core::mem::size_of::<*const $type>(),
241             flags: VMStateFlags(
242                 VMStateFlags::VMS_ARRAY.0
243                     | VMStateFlags::VMS_STRUCT.0
244                     | VMStateFlags::VMS_ARRAY_OF_POINTER.0,
245             ),
246             offset: $crate::offset_of!($struct_name, $field_name),
247             err_hint: ::core::ptr::null(),
248             start: 0,
249             num_offset: 0,
250             size_offset: 0,
251             vmsd: ::core::ptr::null(),
252             struct_version_id: 0,
253             field_exists: None,
254         }
255     }};
256 }
257 
258 #[doc(alias = "VMSTATE_CLOCK_V")]
259 #[macro_export]
260 macro_rules! vmstate_clock_v {
261     ($field_name:ident, $struct_name:ty, $version_id:expr) => {{
262         $crate::vmstate_struct_pointer_v!(
263             $field_name,
264             $struct_name,
265             $version_id,
266             ::core::ptr::addr_of!($crate::bindings::vmstate_clock),
267             $crate::bindings::Clock
268         )
269     }};
270 }
271 
272 #[doc(alias = "VMSTATE_CLOCK")]
273 #[macro_export]
274 macro_rules! vmstate_clock {
275     ($field_name:ident, $struct_name:ty) => {{
276         $crate::vmstate_clock_v!($field_name, $struct_name, 0)
277     }};
278 }
279 
280 #[doc(alias = "VMSTATE_ARRAY_CLOCK_V")]
281 #[macro_export]
282 macro_rules! vmstate_array_clock_v {
283     ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr) => {{
284         $crate::vmstate_array_of_pointer_to_struct!(
285             $field_name,
286             $struct_name,
287             $num,
288             $version_id,
289             ::core::ptr::addr_of!($crate::bindings::vmstate_clock),
290             $crate::bindings::Clock
291         )
292     }};
293 }
294 
295 #[doc(alias = "VMSTATE_ARRAY_CLOCK")]
296 #[macro_export]
297 macro_rules! vmstate_array_clock {
298     ($field_name:ident, $struct_name:ty, $num:expr) => {{
299         $crate::vmstate_array_clock_v!($field_name, $struct_name, $name, 0)
300     }};
301 }
302 
303 /// Helper macro to declare a list of
304 /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return
305 /// a pointer to the array of values it created.
306 #[macro_export]
307 macro_rules! vmstate_fields {
308     ($($field:expr),*$(,)*) => {{
309         static _FIELDS: &[$crate::bindings::VMStateField] = &[
310             $($field),*,
311             $crate::bindings::VMStateField {
312                 name: ::core::ptr::null(),
313                 err_hint: ::core::ptr::null(),
314                 offset: 0,
315                 size: 0,
316                 start: 0,
317                 num: 0,
318                 num_offset: 0,
319                 size_offset: 0,
320                 info: ::core::ptr::null(),
321                 flags: VMStateFlags::VMS_END,
322                 vmsd: ::core::ptr::null(),
323                 version_id: 0,
324                 struct_version_id: 0,
325                 field_exists: None,
326             }
327         ];
328         _FIELDS.as_ptr()
329     }}
330 }
331 
332 /// A transparent wrapper type for the `subsections` field of
333 /// [`VMStateDescription`].
334 ///
335 /// This is necessary to be able to declare subsection descriptions as statics,
336 /// because the only way to implement `Sync` for a foreign type (and `*const`
337 /// pointers are foreign types in Rust) is to create a wrapper struct and
338 /// `unsafe impl Sync` for it.
339 ///
340 /// This struct is used in the
341 /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation.
342 #[repr(transparent)]
343 pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]);
344 
345 unsafe impl Sync for VMStateSubsectionsWrapper {}
346 
347 /// Helper macro to declare a list of subsections ([`VMStateDescription`])
348 /// into a static and return a pointer to the array of pointers it created.
349 #[macro_export]
350 macro_rules! vmstate_subsections {
351     ($($subsection:expr),*$(,)*) => {{
352         static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[
353             $({
354                 static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection;
355                 ::core::ptr::addr_of!(_SUBSECTION)
356             }),*,
357             ::core::ptr::null()
358         ]);
359         _SUBSECTIONS.0.as_ptr()
360     }}
361 }
362