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