xref: /openbmc/qemu/rust/qemu-api/src/vmstate.rs (revision 0d43ddae35a29d1822ec3f35a31bfe7c91618ef4)
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 //! This module includes three families of macros:
8 //!
9 //! * [`vmstate_unused!`](crate::vmstate_unused) and
10 //!   [`vmstate_of!`](crate::vmstate_of), which are used to express the
11 //!   migration format for a struct.  This is based on the [`VMState`] trait,
12 //!   which is defined by all migrateable types.
13 //!
14 //! * helper macros to declare a device model state struct, in particular
15 //!   [`vmstate_subsections`](crate::vmstate_subsections) and
16 //!   [`vmstate_fields`](crate::vmstate_fields).
17 //!
18 //! * direct equivalents to the C macros declared in
19 //!   `include/migration/vmstate.h`. These are not type-safe and should not be
20 //!   used if the equivalent functionality is available with `vmstate_of!`.
21 
22 use core::marker::PhantomData;
23 
24 pub use crate::bindings::{VMStateDescription, VMStateField};
25 
26 /// This macro is used to call a function with a generic argument bound
27 /// to the type of a field.  The function must take a
28 /// [`PhantomData`]`<T>` argument; `T` is the type of
29 /// field `$field` in the `$typ` type.
30 ///
31 /// # Examples
32 ///
33 /// ```
34 /// # use qemu_api::call_func_with_field;
35 /// # use core::marker::PhantomData;
36 /// const fn size_of_field<T>(_: PhantomData<T>) -> usize {
37 ///     std::mem::size_of::<T>()
38 /// }
39 ///
40 /// struct Foo {
41 ///     x: u16,
42 /// };
43 /// // calls size_of_field::<u16>()
44 /// assert_eq!(call_func_with_field!(size_of_field, Foo, x), 2);
45 /// ```
46 #[macro_export]
47 macro_rules! call_func_with_field {
48     // Based on the answer by user steffahn (Frank Steffahn) at
49     // https://users.rust-lang.org/t/inferring-type-of-field/122857
50     // and used under MIT license
51     ($func:expr, $typ:ty, $($field:tt).+) => {
52         $func(loop {
53             #![allow(unreachable_code)]
54             const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> { ::core::marker::PhantomData }
55             // Unreachable code is exempt from checks on uninitialized values.
56             // Use that trick to infer the type of this PhantomData.
57             break ::core::marker::PhantomData;
58             break phantom__(&{ let value__: $typ; value__.$($field).+ });
59         })
60     };
61 }
62 
63 /// A trait for types that can be included in a device's migration stream.  It
64 /// provides the base contents of a `VMStateField` (minus the name and offset).
65 ///
66 /// # Safety
67 ///
68 /// The contents of this trait go straight into structs that are parsed by C
69 /// code and used to introspect into other structs.  Be careful.
70 pub unsafe trait VMState {
71     /// The base contents of a `VMStateField` (minus the name and offset) for
72     /// the type that is implementing the trait.
73     const BASE: VMStateField;
74 }
75 
76 /// Internal utility function to retrieve a type's `VMStateField`;
77 /// used by [`vmstate_of!`](crate::vmstate_of).
78 pub const fn vmstate_base<T: VMState>(_: PhantomData<T>) -> VMStateField {
79     T::BASE
80 }
81 
82 /// Return the `VMStateField` for a field of a struct.  The field must be
83 /// visible in the current scope.
84 ///
85 /// In order to support other types, the trait `VMState` must be implemented
86 /// for them.
87 #[macro_export]
88 macro_rules! vmstate_of {
89     ($struct_name:ty, $field_name:ident $(,)?) => {
90         $crate::bindings::VMStateField {
91             name: ::core::concat!(::core::stringify!($field_name), "\0")
92                 .as_bytes()
93                 .as_ptr() as *const ::std::os::raw::c_char,
94             offset: $crate::offset_of!($struct_name, $field_name),
95             // Compute most of the VMStateField from the type of the field.
96             ..$crate::call_func_with_field!(
97                 $crate::vmstate::vmstate_base,
98                 $struct_name,
99                 $field_name
100             )
101         }
102     };
103 }
104 
105 // Add a couple builder-style methods to VMStateField, allowing
106 // easy derivation of VMStateField constants from other types.
107 impl VMStateField {
108     #[must_use]
109     pub const fn with_version_id(mut self, version_id: i32) -> Self {
110         assert!(version_id >= 0);
111         self.version_id = version_id;
112         self
113     }
114 }
115 
116 #[doc(alias = "VMSTATE_UNUSED_BUFFER")]
117 #[macro_export]
118 macro_rules! vmstate_unused_buffer {
119     ($field_exists_fn:expr, $version_id:expr, $size:expr) => {{
120         $crate::bindings::VMStateField {
121             name: c_str!("unused").as_ptr(),
122             err_hint: ::core::ptr::null(),
123             offset: 0,
124             size: $size,
125             start: 0,
126             num: 0,
127             num_offset: 0,
128             size_offset: 0,
129             info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) },
130             flags: VMStateFlags::VMS_BUFFER,
131             vmsd: ::core::ptr::null(),
132             version_id: $version_id,
133             struct_version_id: 0,
134             field_exists: $field_exists_fn,
135         }
136     }};
137 }
138 
139 #[doc(alias = "VMSTATE_UNUSED_V")]
140 #[macro_export]
141 macro_rules! vmstate_unused_v {
142     ($version_id:expr, $size:expr) => {{
143         $crate::vmstate_unused_buffer!(None, $version_id, $size)
144     }};
145 }
146 
147 #[doc(alias = "VMSTATE_UNUSED")]
148 #[macro_export]
149 macro_rules! vmstate_unused {
150     ($size:expr) => {{
151         $crate::vmstate_unused_v!(0, $size)
152     }};
153 }
154 
155 #[doc(alias = "VMSTATE_SINGLE_TEST")]
156 #[macro_export]
157 macro_rules! vmstate_single_test {
158     ($field_name:ident, $struct_name:ty, $field_exists_fn:expr, $version_id:expr, $info:expr, $size:expr) => {{
159         $crate::bindings::VMStateField {
160             name: ::core::concat!(::core::stringify!($field_name), 0)
161                 .as_bytes()
162                 .as_ptr() as *const ::std::os::raw::c_char,
163             err_hint: ::core::ptr::null(),
164             offset: $crate::offset_of!($struct_name, $field_name),
165             size: $size,
166             start: 0,
167             num: 0,
168             num_offset: 0,
169             size_offset: 0,
170             info: unsafe { $info },
171             flags: VMStateFlags::VMS_SINGLE,
172             vmsd: ::core::ptr::null(),
173             version_id: $version_id,
174             struct_version_id: 0,
175             field_exists: $field_exists_fn,
176         }
177     }};
178 }
179 
180 #[doc(alias = "VMSTATE_SINGLE")]
181 #[macro_export]
182 macro_rules! vmstate_single {
183     ($field_name:ident, $struct_name:ty, $version_id:expr, $info:expr, $size:expr) => {{
184         $crate::vmstate_single_test!($field_name, $struct_name, None, $version_id, $info, $size)
185     }};
186 }
187 
188 #[doc(alias = "VMSTATE_UINT32_V")]
189 #[macro_export]
190 macro_rules! vmstate_uint32_v {
191     ($field_name:ident, $struct_name:ty, $version_id:expr) => {{
192         $crate::vmstate_single!(
193             $field_name,
194             $struct_name,
195             $version_id,
196             ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32),
197             ::core::mem::size_of::<u32>()
198         )
199     }};
200 }
201 
202 #[doc(alias = "VMSTATE_UINT32")]
203 #[macro_export]
204 macro_rules! vmstate_uint32 {
205     ($field_name:ident, $struct_name:ty) => {{
206         $crate::vmstate_uint32_v!($field_name, $struct_name, 0)
207     }};
208 }
209 
210 #[doc(alias = "VMSTATE_ARRAY")]
211 #[macro_export]
212 macro_rules! vmstate_array {
213     ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr, $info:expr, $size:expr) => {{
214         $crate::bindings::VMStateField {
215             name: ::core::concat!(::core::stringify!($field_name), 0)
216                 .as_bytes()
217                 .as_ptr() as *const ::std::os::raw::c_char,
218             err_hint: ::core::ptr::null(),
219             offset: $crate::offset_of!($struct_name, $field_name),
220             size: $size,
221             start: 0,
222             num: $length as _,
223             num_offset: 0,
224             size_offset: 0,
225             info: unsafe { $info },
226             flags: VMStateFlags::VMS_ARRAY,
227             vmsd: ::core::ptr::null(),
228             version_id: $version_id,
229             struct_version_id: 0,
230             field_exists: None,
231         }
232     }};
233 }
234 
235 #[doc(alias = "VMSTATE_UINT32_ARRAY_V")]
236 #[macro_export]
237 macro_rules! vmstate_uint32_array_v {
238     ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr) => {{
239         $crate::vmstate_array!(
240             $field_name,
241             $struct_name,
242             $length,
243             $version_id,
244             ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32),
245             ::core::mem::size_of::<u32>()
246         )
247     }};
248 }
249 
250 #[doc(alias = "VMSTATE_UINT32_ARRAY")]
251 #[macro_export]
252 macro_rules! vmstate_uint32_array {
253     ($field_name:ident, $struct_name:ty, $length:expr) => {{
254         $crate::vmstate_uint32_array_v!($field_name, $struct_name, $length, 0)
255     }};
256 }
257 
258 #[doc(alias = "VMSTATE_STRUCT_POINTER_V")]
259 #[macro_export]
260 macro_rules! vmstate_struct_pointer_v {
261     ($field_name:ident, $struct_name:ty, $version_id:expr, $vmsd:expr, $type:ty) => {{
262         $crate::bindings::VMStateField {
263             name: ::core::concat!(::core::stringify!($field_name), 0)
264                 .as_bytes()
265                 .as_ptr() as *const ::std::os::raw::c_char,
266             err_hint: ::core::ptr::null(),
267             offset: $crate::offset_of!($struct_name, $field_name),
268             size: ::core::mem::size_of::<*const $type>(),
269             start: 0,
270             num: 0,
271             num_offset: 0,
272             size_offset: 0,
273             info: ::core::ptr::null(),
274             flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0),
275             vmsd: unsafe { $vmsd },
276             version_id: $version_id,
277             struct_version_id: 0,
278             field_exists: None,
279         }
280     }};
281 }
282 
283 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER")]
284 #[macro_export]
285 macro_rules! vmstate_array_of_pointer {
286     ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $info:expr, $type:ty) => {{
287         $crate::bindings::VMStateField {
288             name: ::core::concat!(::core::stringify!($field_name), 0)
289                 .as_bytes()
290                 .as_ptr() as *const ::std::os::raw::c_char,
291             version_id: $version_id,
292             num: $num as _,
293             info: unsafe { $info },
294             size: ::core::mem::size_of::<*const $type>(),
295             flags: VMStateFlags(VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0),
296             offset: $crate::offset_of!($struct_name, $field_name),
297             err_hint: ::core::ptr::null(),
298             start: 0,
299             num_offset: 0,
300             size_offset: 0,
301             vmsd: ::core::ptr::null(),
302             struct_version_id: 0,
303             field_exists: None,
304         }
305     }};
306 }
307 
308 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER_TO_STRUCT")]
309 #[macro_export]
310 macro_rules! vmstate_array_of_pointer_to_struct {
311     ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $vmsd:expr, $type:ty) => {{
312         $crate::bindings::VMStateField {
313             name: ::core::concat!(::core::stringify!($field_name), 0)
314                 .as_bytes()
315                 .as_ptr() as *const ::std::os::raw::c_char,
316             version_id: $version_id,
317             num: $num as _,
318             vmsd: unsafe { $vmsd },
319             size: ::core::mem::size_of::<*const $type>(),
320             flags: VMStateFlags(
321                 VMStateFlags::VMS_ARRAY.0
322                     | VMStateFlags::VMS_STRUCT.0
323                     | VMStateFlags::VMS_ARRAY_OF_POINTER.0,
324             ),
325             offset: $crate::offset_of!($struct_name, $field_name),
326             err_hint: ::core::ptr::null(),
327             start: 0,
328             num_offset: 0,
329             size_offset: 0,
330             vmsd: ::core::ptr::null(),
331             struct_version_id: 0,
332             field_exists: None,
333         }
334     }};
335 }
336 
337 #[doc(alias = "VMSTATE_CLOCK_V")]
338 #[macro_export]
339 macro_rules! vmstate_clock_v {
340     ($field_name:ident, $struct_name:ty, $version_id:expr) => {{
341         $crate::vmstate_struct_pointer_v!(
342             $field_name,
343             $struct_name,
344             $version_id,
345             ::core::ptr::addr_of!($crate::bindings::vmstate_clock),
346             $crate::bindings::Clock
347         )
348     }};
349 }
350 
351 #[doc(alias = "VMSTATE_CLOCK")]
352 #[macro_export]
353 macro_rules! vmstate_clock {
354     ($field_name:ident, $struct_name:ty) => {{
355         $crate::vmstate_clock_v!($field_name, $struct_name, 0)
356     }};
357 }
358 
359 #[doc(alias = "VMSTATE_ARRAY_CLOCK_V")]
360 #[macro_export]
361 macro_rules! vmstate_array_clock_v {
362     ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr) => {{
363         $crate::vmstate_array_of_pointer_to_struct!(
364             $field_name,
365             $struct_name,
366             $num,
367             $version_id,
368             ::core::ptr::addr_of!($crate::bindings::vmstate_clock),
369             $crate::bindings::Clock
370         )
371     }};
372 }
373 
374 #[doc(alias = "VMSTATE_ARRAY_CLOCK")]
375 #[macro_export]
376 macro_rules! vmstate_array_clock {
377     ($field_name:ident, $struct_name:ty, $num:expr) => {{
378         $crate::vmstate_array_clock_v!($field_name, $struct_name, $name, 0)
379     }};
380 }
381 
382 /// Helper macro to declare a list of
383 /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return
384 /// a pointer to the array of values it created.
385 #[macro_export]
386 macro_rules! vmstate_fields {
387     ($($field:expr),*$(,)*) => {{
388         static _FIELDS: &[$crate::bindings::VMStateField] = &[
389             $($field),*,
390             $crate::bindings::VMStateField {
391                 name: ::core::ptr::null(),
392                 err_hint: ::core::ptr::null(),
393                 offset: 0,
394                 size: 0,
395                 start: 0,
396                 num: 0,
397                 num_offset: 0,
398                 size_offset: 0,
399                 info: ::core::ptr::null(),
400                 flags: VMStateFlags::VMS_END,
401                 vmsd: ::core::ptr::null(),
402                 version_id: 0,
403                 struct_version_id: 0,
404                 field_exists: None,
405             }
406         ];
407         _FIELDS.as_ptr()
408     }}
409 }
410 
411 /// A transparent wrapper type for the `subsections` field of
412 /// [`VMStateDescription`].
413 ///
414 /// This is necessary to be able to declare subsection descriptions as statics,
415 /// because the only way to implement `Sync` for a foreign type (and `*const`
416 /// pointers are foreign types in Rust) is to create a wrapper struct and
417 /// `unsafe impl Sync` for it.
418 ///
419 /// This struct is used in the
420 /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation.
421 #[repr(transparent)]
422 pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]);
423 
424 unsafe impl Sync for VMStateSubsectionsWrapper {}
425 
426 /// Helper macro to declare a list of subsections ([`VMStateDescription`])
427 /// into a static and return a pointer to the array of pointers it created.
428 #[macro_export]
429 macro_rules! vmstate_subsections {
430     ($($subsection:expr),*$(,)*) => {{
431         static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[
432             $({
433                 static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection;
434                 ::core::ptr::addr_of!(_SUBSECTION)
435             }),*,
436             ::core::ptr::null()
437         ]);
438         _SUBSECTIONS.0.as_ptr()
439     }}
440 }
441