xref: /openbmc/qemu/rust/migration/src/vmstate.rs (revision 917ac07f9aef579b9538a81d45f45850aba42906)
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 four 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 migratable types.
13 //!
14 //! * [`impl_vmstate_forward`](crate::impl_vmstate_forward),
15 //!   [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), and
16 //!   [`impl_vmstate_struct`](crate::impl_vmstate_struct), which help with the
17 //!   definition of the [`VMState`] trait (respectively for transparent structs,
18 //!   nested structs and `bilge`-defined types)
19 //!
20 //! * helper macros to declare a device model state struct, in particular
21 //!   [`vmstate_subsections`](crate::vmstate_subsections) and
22 //!   [`vmstate_fields`](crate::vmstate_fields).
23 //!
24 //! * direct equivalents to the C macros declared in
25 //!   `include/migration/vmstate.h`. These are not type-safe and only provide
26 //!   functionality that is missing from `vmstate_of!`.
27 
28 pub use std::convert::Infallible;
29 use std::{
30     error::Error,
31     ffi::{c_int, c_void, CStr},
32     fmt, io,
33     marker::PhantomData,
34     mem,
35     ptr::{addr_of, NonNull},
36 };
37 
38 use common::{
39     callbacks::FnCall,
40     errno::{into_neg_errno, Errno},
41     Zeroable,
42 };
43 
44 use crate::bindings::{self, VMStateFlags};
45 pub use crate::bindings::{MigrationPriority, VMStateField};
46 
47 /// This macro is used to call a function with a generic argument bound
48 /// to the type of a field.  The function must take a
49 /// [`PhantomData`]`<T>` argument; `T` is the type of
50 /// field `$field` in the `$typ` type.
51 ///
52 /// # Examples
53 ///
54 /// ```
55 /// # use migration::call_func_with_field;
56 /// # use core::marker::PhantomData;
57 /// const fn size_of_field<T>(_: PhantomData<T>) -> usize {
58 ///     std::mem::size_of::<T>()
59 /// }
60 ///
61 /// struct Foo {
62 ///     x: u16,
63 /// };
64 /// // calls size_of_field::<u16>()
65 /// assert_eq!(call_func_with_field!(size_of_field, Foo, x), 2);
66 /// ```
67 #[macro_export]
68 macro_rules! call_func_with_field {
69     // Based on the answer by user steffahn (Frank Steffahn) at
70     // https://users.rust-lang.org/t/inferring-type-of-field/122857
71     // and used under MIT license
72     ($func:expr, $typ:ty, $($field:tt).+) => {
73         $func(loop {
74             #![allow(unreachable_code)]
75             #![allow(unused_variables)]
76             const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> { ::core::marker::PhantomData }
77             // Unreachable code is exempt from checks on uninitialized values.
78             // Use that trick to infer the type of this PhantomData.
79             break ::core::marker::PhantomData;
80             break phantom__(&{ let value__: $typ; value__.$($field).+ });
81         })
82     };
83 }
84 
85 /// A trait for types that can be included in a device's migration stream.  It
86 /// provides the base contents of a `VMStateField` (minus the name and offset).
87 ///
88 /// # Safety
89 ///
90 /// The contents of this trait go straight into structs that are parsed by C
91 /// code and used to introspect into other structs.  Generally, you don't need
92 /// to implement it except via macros that do it for you, such as
93 /// `impl_vmstate_bitsized!`.
94 pub unsafe trait VMState {
95     /// The base contents of a `VMStateField` (minus the name and offset) for
96     /// the type that is implementing the trait.
97     const BASE: VMStateField;
98 
99     /// A flag that is added to another field's `VMStateField` to specify the
100     /// length's type in a variable-sized array.  If this is not a supported
101     /// type for the length (i.e. if it is not `u8`, `u16`, `u32`), using it
102     /// in a call to [`vmstate_of!`](crate::vmstate_of) will cause a
103     /// compile-time error.
104     const VARRAY_FLAG: VMStateFlags = {
105         panic!("invalid type for variable-sized array");
106     };
107 }
108 
109 /// Internal utility function to retrieve a type's `VMStateField`;
110 /// used by [`vmstate_of!`](crate::vmstate_of).
111 pub const fn vmstate_base<T: VMState>(_: PhantomData<T>) -> VMStateField {
112     T::BASE
113 }
114 
115 /// Internal utility function to retrieve a type's `VMStateFlags` when it
116 /// is used as the element count of a `VMSTATE_VARRAY`; used by
117 /// [`vmstate_of!`](crate::vmstate_of).
118 pub const fn vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags {
119     T::VARRAY_FLAG
120 }
121 
122 /// Return the `VMStateField` for a field of a struct.  The field must be
123 /// visible in the current scope.
124 ///
125 /// Only a limited set of types is supported out of the box:
126 /// * scalar types (integer and `bool`)
127 /// * the C struct `QEMUTimer`
128 /// * a transparent wrapper for any of the above (`Cell`, `UnsafeCell`,
129 ///   [`BqlCell`], [`BqlRefCell`])
130 /// * a raw pointer to any of the above
131 /// * a `NonNull` pointer, a `Box` or an [`Owned`] for any of the above
132 /// * an array of any of the above
133 ///
134 /// In order to support other types, the trait `VMState` must be implemented
135 /// for them.  The macros [`impl_vmstate_forward`](crate::impl_vmstate_forward),
136 /// [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), and
137 /// [`impl_vmstate_struct`](crate::impl_vmstate_struct) help with this.
138 ///
139 /// [`BqlCell`]: ../../bql/cell/struct.BqlCell.html
140 /// [`BqlRefCell`]: ../../bql/cell/struct.BqlRefCell.html
141 /// [`Owned`]: ../../qom/qom/struct.Owned.html
142 #[macro_export]
143 macro_rules! vmstate_of {
144     ($struct_name:ty, $($field_name:ident).+ $([0 .. $($num:ident).+ $(* $factor:expr)?])? $(, $test_fn:expr)? $(,)?) => {
145         $crate::bindings::VMStateField {
146             name: ::core::concat!(::core::stringify!($($field_name).+), "\0")
147                 .as_bytes()
148                 .as_ptr().cast::<::std::os::raw::c_char>(),
149             offset: ::std::mem::offset_of!($struct_name, $($field_name).+),
150             $(num_offset: ::std::mem::offset_of!($struct_name, $($num).+),)?
151             $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)?
152             // The calls to `call_func_with_field!` are the magic that
153             // computes most of the VMStateField from the type of the field.
154             ..$crate::call_func_with_field!(
155                 $crate::vmstate::vmstate_base,
156                 $struct_name,
157                 $($field_name).+
158             )$(.with_varray_flag($crate::call_func_with_field!(
159                     $crate::vmstate::vmstate_varray_flag,
160                     $struct_name,
161                     $($num).+))
162                $(.with_varray_multiply($factor))?)?
163         }
164     };
165 }
166 
167 pub trait VMStateFlagsExt {
168     const VMS_VARRAY_FLAGS: VMStateFlags;
169 }
170 
171 impl VMStateFlagsExt for VMStateFlags {
172     const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags(
173         VMStateFlags::VMS_VARRAY_INT32.0
174             | VMStateFlags::VMS_VARRAY_UINT8.0
175             | VMStateFlags::VMS_VARRAY_UINT16.0
176             | VMStateFlags::VMS_VARRAY_UINT32.0,
177     );
178 }
179 
180 // Add a couple builder-style methods to VMStateField, allowing
181 // easy derivation of VMStateField constants from other types.
182 impl VMStateField {
183     #[must_use]
184     pub const fn with_version_id(mut self, version_id: i32) -> Self {
185         assert!(version_id >= 0);
186         self.version_id = version_id;
187         self
188     }
189 
190     #[must_use]
191     pub const fn with_array_flag(mut self, num: usize) -> Self {
192         assert!(num <= 0x7FFF_FFFFusize);
193         assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) == 0);
194         assert!((self.flags.0 & VMStateFlags::VMS_VARRAY_FLAGS.0) == 0);
195         if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 {
196             self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0);
197             self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0);
198             // VMS_ARRAY_OF_POINTER flag stores the size of pointer.
199             // FIXME: *const, *mut, NonNull and Box<> have the same size as usize.
200             //        Resize if more smart pointers are supported.
201             self.size = std::mem::size_of::<usize>();
202         }
203         self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0);
204         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0);
205         self.num = num as i32;
206         self
207     }
208 
209     #[must_use]
210     pub const fn with_pointer_flag(mut self) -> Self {
211         assert!((self.flags.0 & VMStateFlags::VMS_POINTER.0) == 0);
212         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_POINTER.0);
213         self
214     }
215 
216     #[must_use]
217     pub const fn with_varray_flag_unchecked(mut self, flag: VMStateFlags) -> Self {
218         self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0);
219         self.flags = VMStateFlags(self.flags.0 | flag.0);
220         self.num = 0; // varray uses num_offset instead of num.
221         self
222     }
223 
224     #[must_use]
225     #[allow(unused_mut)]
226     pub const fn with_varray_flag(mut self, flag: VMStateFlags) -> Self {
227         assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0);
228         self.with_varray_flag_unchecked(flag)
229     }
230 
231     #[must_use]
232     pub const fn with_varray_multiply(mut self, num: u32) -> Self {
233         assert!(num <= 0x7FFF_FFFFu32);
234         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0);
235         self.num = num as i32;
236         self
237     }
238 }
239 
240 /// This macro can be used (by just passing it a type) to forward the `VMState`
241 /// trait to the first field of a tuple.  This is a workaround for lack of
242 /// support of nested [`offset_of`](core::mem::offset_of) until Rust 1.82.0.
243 ///
244 /// # Examples
245 ///
246 /// ```
247 /// # use migration::impl_vmstate_forward;
248 /// pub struct Fifo([u8; 16]);
249 /// impl_vmstate_forward!(Fifo);
250 /// ```
251 #[macro_export]
252 macro_rules! impl_vmstate_forward {
253     // This is similar to impl_vmstate_transparent below, but it
254     // uses the same trick as vmstate_of! to obtain the type of
255     // the first field of the tuple
256     ($tuple:ty) => {
257         unsafe impl $crate::vmstate::VMState for $tuple {
258             const BASE: $crate::bindings::VMStateField =
259                 $crate::call_func_with_field!($crate::vmstate::vmstate_base, $tuple, 0);
260         }
261     };
262 }
263 
264 // Transparent wrappers: just use the internal type
265 
266 #[macro_export]
267 macro_rules! impl_vmstate_transparent {
268     ($type:ty where $base:tt: VMState $($where:tt)*) => {
269         unsafe impl<$base> $crate::vmstate::VMState for $type where $base: $crate::vmstate::VMState $($where)* {
270             const BASE: $crate::vmstate::VMStateField = $crate::vmstate::VMStateField {
271                 size: ::core::mem::size_of::<$type>(),
272                 ..<$base as $crate::vmstate::VMState>::BASE
273             };
274             const VARRAY_FLAG: $crate::bindings::VMStateFlags = <$base as $crate::vmstate::VMState>::VARRAY_FLAG;
275         }
276     };
277 }
278 
279 impl_vmstate_transparent!(bql::BqlCell<T> where T: VMState);
280 impl_vmstate_transparent!(bql::BqlRefCell<T> where T: VMState);
281 impl_vmstate_transparent!(std::cell::Cell<T> where T: VMState);
282 impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState);
283 impl_vmstate_transparent!(std::pin::Pin<T> where T: VMState);
284 impl_vmstate_transparent!(common::Opaque<T> where T: VMState);
285 impl_vmstate_transparent!(std::mem::ManuallyDrop<T> where T: VMState);
286 
287 #[macro_export]
288 macro_rules! impl_vmstate_bitsized {
289     ($type:ty) => {
290         unsafe impl $crate::vmstate::VMState for $type {
291             const BASE: $crate::bindings::VMStateField =
292                                         <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
293                                           as ::bilge::prelude::Number>::UnderlyingType
294                                          as $crate::vmstate::VMState>::BASE;
295             const VARRAY_FLAG: $crate::bindings::VMStateFlags =
296                                         <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
297                                           as ::bilge::prelude::Number>::UnderlyingType
298                                          as $crate::vmstate::VMState>::VARRAY_FLAG;
299         }
300 
301         impl $crate::migratable::ToMigrationState for $type {
302             type Migrated = <<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
303                                           as ::bilge::prelude::Number>::UnderlyingType;
304 
305             fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), $crate::InvalidError> {
306                 *target = Self::Migrated::from(*self);
307                 Ok(())
308             }
309 
310             fn restore_migrated_state_mut(
311                 &mut self,
312                 source: Self::Migrated,
313                 version_id: u8,
314             ) -> Result<(), $crate::InvalidError> {
315                 *self = Self::from(source);
316                 Ok(())
317             }
318         }
319     };
320 }
321 
322 // Scalar types using predefined VMStateInfos
323 
324 macro_rules! impl_vmstate_scalar {
325     ($info:ident, $type:ty$(, $varray_flag:ident)?) => {
326         unsafe impl $crate::vmstate::VMState for $type {
327             const BASE: $crate::vmstate::VMStateField = $crate::vmstate::VMStateField {
328                 info: addr_of!(bindings::$info),
329                 size: mem::size_of::<$type>(),
330                 flags: $crate::vmstate::VMStateFlags::VMS_SINGLE,
331                 ..::common::zeroable::Zeroable::ZERO
332             };
333             $(const VARRAY_FLAG: VMStateFlags = VMStateFlags::$varray_flag;)?
334         }
335     };
336 }
337 
338 impl_vmstate_scalar!(vmstate_info_bool, bool);
339 impl_vmstate_scalar!(vmstate_info_int8, i8);
340 impl_vmstate_scalar!(vmstate_info_int16, i16);
341 impl_vmstate_scalar!(vmstate_info_int32, i32);
342 impl_vmstate_scalar!(vmstate_info_int64, i64);
343 impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY_UINT8);
344 impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY_UINT16);
345 impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY_UINT32);
346 impl_vmstate_scalar!(vmstate_info_uint64, u64);
347 impl_vmstate_scalar!(vmstate_info_timer, util::timer::Timer);
348 
349 #[macro_export]
350 macro_rules! impl_vmstate_c_struct {
351     ($type:ty, $vmsd:expr) => {
352         unsafe impl $crate::vmstate::VMState for $type {
353             const BASE: $crate::bindings::VMStateField = $crate::bindings::VMStateField {
354                 vmsd: ::std::ptr::addr_of!($vmsd),
355                 size: ::std::mem::size_of::<$type>(),
356                 flags: $crate::bindings::VMStateFlags::VMS_STRUCT,
357                 ..::common::zeroable::Zeroable::ZERO
358             };
359         }
360     };
361 }
362 
363 // Pointer types using the underlying type's VMState plus VMS_POINTER
364 // Note that references are not supported, though references to cells
365 // could be allowed.
366 
367 #[macro_export]
368 macro_rules! impl_vmstate_pointer {
369     ($type:ty where $base:tt: VMState $($where:tt)*) => {
370         unsafe impl<$base> $crate::vmstate::VMState for $type where $base: $crate::vmstate::VMState $($where)* {
371             const BASE: $crate::vmstate::VMStateField = <$base as $crate::vmstate::VMState>::BASE.with_pointer_flag();
372         }
373     };
374 }
375 
376 impl_vmstate_pointer!(*const T where T: VMState);
377 impl_vmstate_pointer!(*mut T where T: VMState);
378 impl_vmstate_pointer!(NonNull<T> where T: VMState);
379 
380 // Unlike C pointers, Box is always non-null therefore there is no need
381 // to specify VMS_ALLOC.
382 impl_vmstate_pointer!(Box<T> where T: VMState);
383 
384 // Arrays using the underlying type's VMState plus
385 // VMS_ARRAY/VMS_ARRAY_OF_POINTER
386 
387 unsafe impl<T: VMState, const N: usize> VMState for [T; N] {
388     const BASE: VMStateField = <T as VMState>::BASE.with_array_flag(N);
389 }
390 
391 #[doc(alias = "VMSTATE_UNUSED")]
392 #[macro_export]
393 macro_rules! vmstate_unused {
394     ($size:expr) => {{
395         $crate::bindings::VMStateField {
396             name: c"unused".as_ptr(),
397             size: $size,
398             info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) },
399             flags: $crate::bindings::VMStateFlags::VMS_BUFFER,
400             ..::common::Zeroable::ZERO
401         }
402     }};
403 }
404 
405 pub extern "C" fn rust_vms_test_field_exists<T, F: for<'a> FnCall<(&'a T, u8), bool>>(
406     opaque: *mut c_void,
407     version_id: c_int,
408 ) -> bool {
409     // SAFETY: the function is used in T's implementation of VMState
410     let owner: &T = unsafe { &*(opaque.cast::<T>()) };
411     let version: u8 = version_id.try_into().unwrap();
412     F::call((owner, version))
413 }
414 
415 pub type VMSFieldExistCb = unsafe extern "C" fn(
416     opaque: *mut std::os::raw::c_void,
417     version_id: std::os::raw::c_int,
418 ) -> bool;
419 
420 #[macro_export]
421 macro_rules! vmstate_exist_fn {
422     ($struct_name:ty, $test_fn:expr) => {{
423         const fn test_cb_builder__<T, F: for<'a> ::common::FnCall<(&'a T, u8), bool>>(
424             _phantom: ::core::marker::PhantomData<F>,
425         ) -> $crate::vmstate::VMSFieldExistCb {
426             const { assert!(F::IS_SOME) };
427             $crate::vmstate::rust_vms_test_field_exists::<T, F>
428         }
429 
430         const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> {
431             ::core::marker::PhantomData
432         }
433         Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn)))
434     }};
435 }
436 
437 /// Add a terminator to the fields in the arguments, and return
438 /// a reference to the resulting array of values.
439 #[macro_export]
440 macro_rules! vmstate_fields_ref {
441     ($($field:expr),*$(,)*) => {
442         &[
443             $($field),*,
444             $crate::bindings::VMStateField {
445                 flags: $crate::bindings::VMStateFlags::VMS_END,
446                 ..::common::zeroable::Zeroable::ZERO
447             }
448         ]
449     }
450 }
451 
452 /// Helper macro to declare a list of
453 /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return
454 /// a pointer to the array of values it created.
455 #[macro_export]
456 macro_rules! vmstate_fields {
457     ($($field:expr),*$(,)*) => {{
458         static _FIELDS: &[$crate::bindings::VMStateField] = $crate::vmstate_fields_ref!(
459             $($field),*,
460         );
461         _FIELDS
462     }}
463 }
464 
465 #[doc(alias = "VMSTATE_VALIDATE")]
466 #[macro_export]
467 macro_rules! vmstate_validate {
468     ($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => {
469         $crate::bindings::VMStateField {
470             name: ::std::ffi::CStr::as_ptr($test_name),
471             field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),
472             flags: $crate::bindings::VMStateFlags(
473                 $crate::bindings::VMStateFlags::VMS_MUST_EXIST.0
474                     | $crate::bindings::VMStateFlags::VMS_ARRAY.0,
475             ),
476             num: 0, // 0 elements: no data, only run test_fn callback
477             ..::common::zeroable::Zeroable::ZERO
478         }
479     };
480 }
481 
482 /// Helper macro to allow using a struct in [`vmstate_of!`]
483 ///
484 /// # Safety
485 ///
486 /// The [`VMStateDescription`] constant `$vmsd` must be an accurate
487 /// description of the struct.
488 #[macro_export]
489 macro_rules! impl_vmstate_struct {
490     ($type:ty, $vmsd:expr) => {
491         unsafe impl $crate::vmstate::VMState for $type {
492             const BASE: $crate::bindings::VMStateField = {
493                 static VMSD: &$crate::bindings::VMStateDescription = $vmsd.as_ref();
494 
495                 $crate::bindings::VMStateField {
496                     vmsd: ::core::ptr::addr_of!(*VMSD),
497                     size: ::core::mem::size_of::<$type>(),
498                     flags: $crate::bindings::VMStateFlags::VMS_STRUCT,
499                     ..common::Zeroable::ZERO
500                 }
501             };
502         }
503     };
504 }
505 
506 /// The type returned by [`vmstate_subsections!`](crate::vmstate_subsections).
507 pub type VMStateSubsections = &'static [Option<&'static crate::bindings::VMStateDescription>];
508 
509 /// Helper macro to declare a list of subsections ([`VMStateDescription`])
510 /// into a static and return a pointer to the array of pointers it created.
511 #[macro_export]
512 macro_rules! vmstate_subsections {
513     ($($subsection:expr),*$(,)*) => {{
514         static _SUBSECTIONS: $crate::vmstate::VMStateSubsections = &[
515             $({
516                 static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection.get();
517                 Some(&_SUBSECTION)
518             }),*,
519             None,
520         ];
521         &_SUBSECTIONS
522     }}
523 }
524 
525 pub struct VMStateDescription<T>(bindings::VMStateDescription, PhantomData<fn(&T)>);
526 
527 // SAFETY: When a *const T is passed to the callbacks, the call itself
528 // is done in a thread-safe manner.  The invocation is okay as long as
529 // T itself is `Sync`.
530 unsafe impl<T: Sync> Sync for VMStateDescription<T> {}
531 
532 #[derive(Clone)]
533 pub struct VMStateDescriptionBuilder<T>(bindings::VMStateDescription, PhantomData<fn(&T)>);
534 
535 #[derive(Debug)]
536 pub struct InvalidError;
537 
538 impl Error for InvalidError {}
539 
540 impl std::fmt::Display for InvalidError {
541     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542         write!(f, "invalid migration data")
543     }
544 }
545 
546 impl From<InvalidError> for Errno {
547     fn from(_value: InvalidError) -> Errno {
548         io::ErrorKind::InvalidInput.into()
549     }
550 }
551 
552 unsafe extern "C" fn vmstate_no_version_cb<
553     T,
554     F: for<'a> FnCall<(&'a T,), Result<(), impl Into<Errno>>>,
555 >(
556     opaque: *mut c_void,
557 ) -> c_int {
558     // SAFETY: the function is used in T's implementation of VMState
559     let result = F::call((unsafe { &*(opaque.cast::<T>()) },));
560     into_neg_errno(result)
561 }
562 
563 unsafe extern "C" fn vmstate_post_load_cb<
564     T,
565     F: for<'a> FnCall<(&'a T, u8), Result<(), impl Into<Errno>>>,
566 >(
567     opaque: *mut c_void,
568     version_id: c_int,
569 ) -> c_int {
570     // SAFETY: the function is used in T's implementation of VMState
571     let owner: &T = unsafe { &*(opaque.cast::<T>()) };
572     let version: u8 = version_id.try_into().unwrap();
573     let result = F::call((owner, version));
574     into_neg_errno(result)
575 }
576 
577 unsafe extern "C" fn vmstate_needed_cb<T, F: for<'a> FnCall<(&'a T,), bool>>(
578     opaque: *mut c_void,
579 ) -> bool {
580     // SAFETY: the function is used in T's implementation of VMState
581     F::call((unsafe { &*(opaque.cast::<T>()) },))
582 }
583 
584 unsafe extern "C" fn vmstate_dev_unplug_pending_cb<T, F: for<'a> FnCall<(&'a T,), bool>>(
585     opaque: *mut c_void,
586 ) -> bool {
587     // SAFETY: the function is used in T's implementation of VMState
588     F::call((unsafe { &*(opaque.cast::<T>()) },))
589 }
590 
591 impl<T> VMStateDescriptionBuilder<T> {
592     #[must_use]
593     pub const fn name(mut self, name_str: &CStr) -> Self {
594         self.0.name = ::std::ffi::CStr::as_ptr(name_str);
595         self
596     }
597 
598     #[must_use]
599     pub const fn unmigratable(mut self) -> Self {
600         self.0.unmigratable = true;
601         self
602     }
603 
604     #[must_use]
605     pub const fn early_setup(mut self) -> Self {
606         self.0.early_setup = true;
607         self
608     }
609 
610     #[must_use]
611     pub const fn version_id(mut self, version: u8) -> Self {
612         self.0.version_id = version as c_int;
613         self
614     }
615 
616     #[must_use]
617     pub const fn minimum_version_id(mut self, min_version: u8) -> Self {
618         self.0.minimum_version_id = min_version as c_int;
619         self
620     }
621 
622     #[must_use]
623     pub const fn priority(mut self, priority: MigrationPriority) -> Self {
624         self.0.priority = priority;
625         self
626     }
627 
628     #[must_use]
629     pub const fn pre_load<F: for<'a> FnCall<(&'a T,), Result<(), impl Into<Errno>>>>(
630         mut self,
631         _f: &F,
632     ) -> Self {
633         self.0.pre_load = if F::IS_SOME {
634             Some(vmstate_no_version_cb::<T, F>)
635         } else {
636             None
637         };
638         self
639     }
640 
641     #[must_use]
642     pub const fn post_load<F: for<'a> FnCall<(&'a T, u8), Result<(), impl Into<Errno>>>>(
643         mut self,
644         _f: &F,
645     ) -> Self {
646         self.0.post_load = if F::IS_SOME {
647             Some(vmstate_post_load_cb::<T, F>)
648         } else {
649             None
650         };
651         self
652     }
653 
654     #[must_use]
655     pub const fn pre_save<F: for<'a> FnCall<(&'a T,), Result<(), impl Into<Errno>>>>(
656         mut self,
657         _f: &F,
658     ) -> Self {
659         self.0.pre_save = if F::IS_SOME {
660             Some(vmstate_no_version_cb::<T, F>)
661         } else {
662             None
663         };
664         self
665     }
666 
667     #[must_use]
668     pub const fn post_save<F: for<'a> FnCall<(&'a T,), Result<(), impl Into<Errno>>>>(
669         mut self,
670         _f: &F,
671     ) -> Self {
672         self.0.post_save = if F::IS_SOME {
673             Some(vmstate_no_version_cb::<T, F>)
674         } else {
675             None
676         };
677         self
678     }
679 
680     #[must_use]
681     pub const fn needed<F: for<'a> FnCall<(&'a T,), bool>>(mut self, _f: &F) -> Self {
682         self.0.needed = if F::IS_SOME {
683             Some(vmstate_needed_cb::<T, F>)
684         } else {
685             None
686         };
687         self
688     }
689 
690     #[must_use]
691     pub const fn unplug_pending<F: for<'a> FnCall<(&'a T,), bool>>(mut self, _f: &F) -> Self {
692         self.0.dev_unplug_pending = if F::IS_SOME {
693             Some(vmstate_dev_unplug_pending_cb::<T, F>)
694         } else {
695             None
696         };
697         self
698     }
699 
700     #[must_use]
701     pub const fn fields(mut self, fields: &'static [VMStateField]) -> Self {
702         if fields[fields.len() - 1].flags.0 != VMStateFlags::VMS_END.0 {
703             panic!("fields are not terminated, use vmstate_fields!");
704         }
705         self.0.fields = fields.as_ptr();
706         self
707     }
708 
709     #[must_use]
710     pub const fn subsections(mut self, subs: &'static VMStateSubsections) -> Self {
711         if subs[subs.len() - 1].is_some() {
712             panic!("subsections are not terminated, use vmstate_subsections!");
713         }
714         let subs: *const Option<&bindings::VMStateDescription> = subs.as_ptr();
715         self.0.subsections = subs.cast::<*const bindings::VMStateDescription>();
716         self
717     }
718 
719     #[must_use]
720     pub const fn build(self) -> VMStateDescription<T> {
721         VMStateDescription::<T>(self.0, PhantomData)
722     }
723 
724     #[must_use]
725     pub const fn new() -> Self {
726         Self(bindings::VMStateDescription::ZERO, PhantomData)
727     }
728 }
729 
730 impl<T> Default for VMStateDescriptionBuilder<T> {
731     fn default() -> Self {
732         Self::new()
733     }
734 }
735 
736 impl<T> VMStateDescription<T> {
737     pub const fn get(&self) -> bindings::VMStateDescription {
738         self.0
739     }
740 
741     pub const fn as_ref(&self) -> &bindings::VMStateDescription {
742         &self.0
743     }
744 }
745