// Copyright 2024, Linaro Limited // Author(s): Manos Pitsidianakis // SPDX-License-Identifier: GPL-2.0-or-later //! Helper macros to declare migration state for device models. //! //! This module includes four families of macros: //! //! * [`vmstate_unused!`](crate::vmstate_unused) and //! [`vmstate_of!`](crate::vmstate_of), which are used to express the //! migration format for a struct. This is based on the [`VMState`] trait, //! which is defined by all migratable types. //! //! * [`impl_vmstate_forward`](crate::impl_vmstate_forward), //! [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), and //! [`impl_vmstate_struct`](crate::impl_vmstate_struct), which help with the //! definition of the [`VMState`] trait (respectively for transparent structs, //! nested structs and `bilge`-defined types) //! //! * helper macros to declare a device model state struct, in particular //! [`vmstate_subsections`](crate::vmstate_subsections) and //! [`vmstate_fields`](crate::vmstate_fields). //! //! * direct equivalents to the C macros declared in //! `include/migration/vmstate.h`. These are not type-safe and only provide //! functionality that is missing from `vmstate_of!`. pub use std::convert::Infallible; use std::{ error::Error, ffi::{c_int, c_void, CStr}, fmt, io, marker::PhantomData, mem, ptr::{addr_of, NonNull}, }; use common::{ callbacks::FnCall, errno::{into_neg_errno, Errno}, Zeroable, }; use crate::bindings::{self, VMStateFlags}; pub use crate::bindings::{MigrationPriority, VMStateField}; /// This macro is used to call a function with a generic argument bound /// to the type of a field. The function must take a /// [`PhantomData`]`` argument; `T` is the type of /// field `$field` in the `$typ` type. /// /// # Examples /// /// ``` /// # use migration::call_func_with_field; /// # use core::marker::PhantomData; /// const fn size_of_field(_: PhantomData) -> usize { /// std::mem::size_of::() /// } /// /// struct Foo { /// x: u16, /// }; /// // calls size_of_field::() /// assert_eq!(call_func_with_field!(size_of_field, Foo, x), 2); /// ``` #[macro_export] macro_rules! call_func_with_field { // Based on the answer by user steffahn (Frank Steffahn) at // https://users.rust-lang.org/t/inferring-type-of-field/122857 // and used under MIT license ($func:expr, $typ:ty, $($field:tt).+) => { $func(loop { #![allow(unreachable_code)] const fn phantom__(_: &T) -> ::core::marker::PhantomData { ::core::marker::PhantomData } // Unreachable code is exempt from checks on uninitialized values. // Use that trick to infer the type of this PhantomData. break ::core::marker::PhantomData; break phantom__(&{ let value__: $typ; value__.$($field).+ }); }) }; } /// A trait for types that can be included in a device's migration stream. It /// provides the base contents of a `VMStateField` (minus the name and offset). /// /// # Safety /// /// The contents of this trait go straight into structs that are parsed by C /// code and used to introspect into other structs. Generally, you don't need /// to implement it except via macros that do it for you, such as /// `impl_vmstate_bitsized!`. pub unsafe trait VMState { /// The base contents of a `VMStateField` (minus the name and offset) for /// the type that is implementing the trait. const BASE: VMStateField; /// A flag that is added to another field's `VMStateField` to specify the /// length's type in a variable-sized array. If this is not a supported /// type for the length (i.e. if it is not `u8`, `u16`, `u32`), using it /// in a call to [`vmstate_of!`](crate::vmstate_of) will cause a /// compile-time error. const VARRAY_FLAG: VMStateFlags = { panic!("invalid type for variable-sized array"); }; } /// Internal utility function to retrieve a type's `VMStateField`; /// used by [`vmstate_of!`](crate::vmstate_of). pub const fn vmstate_base(_: PhantomData) -> VMStateField { T::BASE } /// Internal utility function to retrieve a type's `VMStateFlags` when it /// is used as the element count of a `VMSTATE_VARRAY`; used by /// [`vmstate_of!`](crate::vmstate_of). pub const fn vmstate_varray_flag(_: PhantomData) -> VMStateFlags { T::VARRAY_FLAG } /// Return the `VMStateField` for a field of a struct. The field must be /// visible in the current scope. /// /// Only a limited set of types is supported out of the box: /// * scalar types (integer and `bool`) /// * the C struct `QEMUTimer` /// * a transparent wrapper for any of the above (`Cell`, `UnsafeCell`, /// [`BqlCell`], [`BqlRefCell`]) /// * a raw pointer to any of the above /// * a `NonNull` pointer, a `Box` or an [`Owned`] for any of the above /// * an array of any of the above /// /// In order to support other types, the trait `VMState` must be implemented /// for them. The macros [`impl_vmstate_forward`](crate::impl_vmstate_forward), /// [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), and /// [`impl_vmstate_struct`](crate::impl_vmstate_struct) help with this. /// /// [`BqlCell`]: ../../bql/cell/struct.BqlCell.html /// [`BqlRefCell`]: ../../bql/cell/struct.BqlRefCell.html /// [`Owned`]: ../../qom/qom/struct.Owned.html #[macro_export] macro_rules! vmstate_of { ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(, $test_fn:expr)? $(,)?) => { $crate::bindings::VMStateField { name: ::core::concat!(::core::stringify!($field_name), "\0") .as_bytes() .as_ptr() as *const ::std::os::raw::c_char, offset: ::std::mem::offset_of!($struct_name, $field_name), $(num_offset: ::std::mem::offset_of!($struct_name, $num),)? $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)? // The calls to `call_func_with_field!` are the magic that // computes most of the VMStateField from the type of the field. ..$crate::call_func_with_field!( $crate::vmstate::vmstate_base, $struct_name, $field_name )$(.with_varray_flag($crate::call_func_with_field!( $crate::vmstate::vmstate_varray_flag, $struct_name, $num)) $(.with_varray_multiply($factor))?)? } }; } pub trait VMStateFlagsExt { const VMS_VARRAY_FLAGS: VMStateFlags; } impl VMStateFlagsExt for VMStateFlags { const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags( VMStateFlags::VMS_VARRAY_INT32.0 | VMStateFlags::VMS_VARRAY_UINT8.0 | VMStateFlags::VMS_VARRAY_UINT16.0 | VMStateFlags::VMS_VARRAY_UINT32.0, ); } // Add a couple builder-style methods to VMStateField, allowing // easy derivation of VMStateField constants from other types. impl VMStateField { #[must_use] pub const fn with_version_id(mut self, version_id: i32) -> Self { assert!(version_id >= 0); self.version_id = version_id; self } #[must_use] pub const fn with_array_flag(mut self, num: usize) -> Self { assert!(num <= 0x7FFF_FFFFusize); assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) == 0); assert!((self.flags.0 & VMStateFlags::VMS_VARRAY_FLAGS.0) == 0); if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 { self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0); self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0); // VMS_ARRAY_OF_POINTER flag stores the size of pointer. // FIXME: *const, *mut, NonNull and Box<> have the same size as usize. // Resize if more smart pointers are supported. self.size = std::mem::size_of::(); } self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0); self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0); self.num = num as i32; self } #[must_use] pub const fn with_pointer_flag(mut self) -> Self { assert!((self.flags.0 & VMStateFlags::VMS_POINTER.0) == 0); self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_POINTER.0); self } #[must_use] pub const fn with_varray_flag_unchecked(mut self, flag: VMStateFlags) -> Self { self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0); self.flags = VMStateFlags(self.flags.0 | flag.0); self.num = 0; // varray uses num_offset instead of num. self } #[must_use] #[allow(unused_mut)] pub const fn with_varray_flag(mut self, flag: VMStateFlags) -> Self { assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0); self.with_varray_flag_unchecked(flag) } #[must_use] pub const fn with_varray_multiply(mut self, num: u32) -> Self { assert!(num <= 0x7FFF_FFFFu32); self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0); self.num = num as i32; self } } /// This macro can be used (by just passing it a type) to forward the `VMState` /// trait to the first field of a tuple. This is a workaround for lack of /// support of nested [`offset_of`](core::mem::offset_of) until Rust 1.82.0. /// /// # Examples /// /// ``` /// # use migration::impl_vmstate_forward; /// pub struct Fifo([u8; 16]); /// impl_vmstate_forward!(Fifo); /// ``` #[macro_export] macro_rules! impl_vmstate_forward { // This is similar to impl_vmstate_transparent below, but it // uses the same trick as vmstate_of! to obtain the type of // the first field of the tuple ($tuple:ty) => { unsafe impl $crate::vmstate::VMState for $tuple { const BASE: $crate::bindings::VMStateField = $crate::call_func_with_field!($crate::vmstate::vmstate_base, $tuple, 0); } }; } // Transparent wrappers: just use the internal type #[macro_export] macro_rules! impl_vmstate_transparent { ($type:ty where $base:tt: VMState $($where:tt)*) => { unsafe impl<$base> $crate::vmstate::VMState for $type where $base: $crate::vmstate::VMState $($where)* { const BASE: $crate::vmstate::VMStateField = $crate::vmstate::VMStateField { size: mem::size_of::<$type>(), ..<$base as $crate::vmstate::VMState>::BASE }; const VARRAY_FLAG: $crate::bindings::VMStateFlags = <$base as $crate::vmstate::VMState>::VARRAY_FLAG; } }; } impl_vmstate_transparent!(std::cell::Cell where T: VMState); impl_vmstate_transparent!(std::cell::UnsafeCell where T: VMState); impl_vmstate_transparent!(std::pin::Pin where T: VMState); impl_vmstate_transparent!(common::Opaque where T: VMState); #[macro_export] macro_rules! impl_vmstate_bitsized { ($type:ty) => { unsafe impl $crate::vmstate::VMState for $type { const BASE: $crate::bindings::VMStateField = <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt as ::bilge::prelude::Number>::UnderlyingType as $crate::vmstate::VMState>::BASE; const VARRAY_FLAG: $crate::bindings::VMStateFlags = <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt as ::bilge::prelude::Number>::UnderlyingType as $crate::vmstate::VMState>::VARRAY_FLAG; } }; } // Scalar types using predefined VMStateInfos macro_rules! impl_vmstate_scalar { ($info:ident, $type:ty$(, $varray_flag:ident)?) => { unsafe impl $crate::vmstate::VMState for $type { const BASE: $crate::vmstate::VMStateField = $crate::vmstate::VMStateField { info: addr_of!(bindings::$info), size: mem::size_of::<$type>(), flags: $crate::vmstate::VMStateFlags::VMS_SINGLE, ..::common::zeroable::Zeroable::ZERO }; $(const VARRAY_FLAG: VMStateFlags = VMStateFlags::$varray_flag;)? } }; } impl_vmstate_scalar!(vmstate_info_bool, bool); impl_vmstate_scalar!(vmstate_info_int8, i8); impl_vmstate_scalar!(vmstate_info_int16, i16); impl_vmstate_scalar!(vmstate_info_int32, i32); impl_vmstate_scalar!(vmstate_info_int64, i64); impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY_UINT8); impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY_UINT16); impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY_UINT32); impl_vmstate_scalar!(vmstate_info_uint64, u64); impl_vmstate_scalar!(vmstate_info_timer, util::timer::Timer); #[macro_export] macro_rules! impl_vmstate_c_struct { ($type:ty, $vmsd:expr) => { unsafe impl $crate::vmstate::VMState for $type { const BASE: $crate::bindings::VMStateField = $crate::bindings::VMStateField { vmsd: ::std::ptr::addr_of!($vmsd), size: ::std::mem::size_of::<$type>(), flags: $crate::bindings::VMStateFlags::VMS_STRUCT, ..::common::zeroable::Zeroable::ZERO }; } }; } // Pointer types using the underlying type's VMState plus VMS_POINTER // Note that references are not supported, though references to cells // could be allowed. #[macro_export] macro_rules! impl_vmstate_pointer { ($type:ty where $base:tt: VMState $($where:tt)*) => { unsafe impl<$base> $crate::vmstate::VMState for $type where $base: $crate::vmstate::VMState $($where)* { const BASE: $crate::vmstate::VMStateField = <$base as $crate::vmstate::VMState>::BASE.with_pointer_flag(); } }; } impl_vmstate_pointer!(*const T where T: VMState); impl_vmstate_pointer!(*mut T where T: VMState); impl_vmstate_pointer!(NonNull where T: VMState); // Unlike C pointers, Box is always non-null therefore there is no need // to specify VMS_ALLOC. impl_vmstate_pointer!(Box where T: VMState); // Arrays using the underlying type's VMState plus // VMS_ARRAY/VMS_ARRAY_OF_POINTER unsafe impl VMState for [T; N] { const BASE: VMStateField = ::BASE.with_array_flag(N); } #[doc(alias = "VMSTATE_UNUSED")] #[macro_export] macro_rules! vmstate_unused { ($size:expr) => {{ $crate::bindings::VMStateField { name: c"unused".as_ptr(), size: $size, info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) }, flags: $crate::bindings::VMStateFlags::VMS_BUFFER, ..::common::Zeroable::ZERO } }}; } pub extern "C" fn rust_vms_test_field_exists FnCall<(&'a T, u8), bool>>( opaque: *mut c_void, version_id: c_int, ) -> bool { // SAFETY: the function is used in T's implementation of VMState let owner: &T = unsafe { &*(opaque.cast::()) }; let version: u8 = version_id.try_into().unwrap(); F::call((owner, version)) } pub type VMSFieldExistCb = unsafe extern "C" fn( opaque: *mut std::os::raw::c_void, version_id: std::os::raw::c_int, ) -> bool; #[macro_export] macro_rules! vmstate_exist_fn { ($struct_name:ty, $test_fn:expr) => {{ const fn test_cb_builder__ ::common::FnCall<(&'a T, u8), bool>>( _phantom: ::core::marker::PhantomData, ) -> $crate::vmstate::VMSFieldExistCb { const { assert!(F::IS_SOME) }; $crate::vmstate::rust_vms_test_field_exists:: } const fn phantom__(_: &T) -> ::core::marker::PhantomData { ::core::marker::PhantomData } Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn))) }}; } /// Helper macro to declare a list of /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return /// a pointer to the array of values it created. #[macro_export] macro_rules! vmstate_fields { ($($field:expr),*$(,)*) => {{ static _FIELDS: &[$crate::bindings::VMStateField] = &[ $($field),*, $crate::bindings::VMStateField { flags: $crate::bindings::VMStateFlags::VMS_END, ..::common::zeroable::Zeroable::ZERO } ]; _FIELDS.as_ptr() }} } #[doc(alias = "VMSTATE_VALIDATE")] #[macro_export] macro_rules! vmstate_validate { ($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => { $crate::bindings::VMStateField { name: ::std::ffi::CStr::as_ptr($test_name), field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn), flags: $crate::bindings::VMStateFlags( $crate::bindings::VMStateFlags::VMS_MUST_EXIST.0 | $crate::bindings::VMStateFlags::VMS_ARRAY.0, ), num: 0, // 0 elements: no data, only run test_fn callback ..::common::zeroable::Zeroable::ZERO } }; } /// Helper macro to allow using a struct in [`vmstate_of!`] /// /// # Safety /// /// The [`VMStateDescription`] constant `$vmsd` must be an accurate /// description of the struct. #[macro_export] macro_rules! impl_vmstate_struct { ($type:ty, $vmsd:expr) => { unsafe impl $crate::vmstate::VMState for $type { const BASE: $crate::bindings::VMStateField = { static VMSD: &$crate::bindings::VMStateDescription = $vmsd.as_ref(); $crate::bindings::VMStateField { vmsd: ::core::ptr::addr_of!(*VMSD), size: ::core::mem::size_of::<$type>(), flags: $crate::bindings::VMStateFlags::VMS_STRUCT, ..common::Zeroable::ZERO } }; } }; } /// A transparent wrapper type for the `subsections` field of /// [`VMStateDescription`]. /// /// This is necessary to be able to declare subsection descriptions as statics, /// because the only way to implement `Sync` for a foreign type (and `*const` /// pointers are foreign types in Rust) is to create a wrapper struct and /// `unsafe impl Sync` for it. /// /// This struct is used in the /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation. #[repr(transparent)] pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]); unsafe impl Sync for VMStateSubsectionsWrapper {} /// Helper macro to declare a list of subsections ([`VMStateDescription`]) /// into a static and return a pointer to the array of pointers it created. #[macro_export] macro_rules! vmstate_subsections { ($($subsection:expr),*$(,)*) => {{ static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[ $({ static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection.get(); ::core::ptr::addr_of!(_SUBSECTION) }),*, ::core::ptr::null() ]); &_SUBSECTIONS }} } pub struct VMStateDescription(bindings::VMStateDescription, PhantomData); // SAFETY: When a *const T is passed to the callbacks, the call itself // is done in a thread-safe manner. The invocation is okay as long as // T itself is `Sync`. unsafe impl Sync for VMStateDescription {} #[derive(Clone)] pub struct VMStateDescriptionBuilder(bindings::VMStateDescription, PhantomData); #[derive(Debug)] pub struct InvalidError; impl Error for InvalidError {} impl std::fmt::Display for InvalidError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "invalid migration data") } } impl From for Errno { fn from(_value: InvalidError) -> Errno { io::ErrorKind::InvalidInput.into() } } unsafe extern "C" fn vmstate_no_version_cb< T, F: for<'a> FnCall<(&'a T,), Result<(), impl Into>>, >( opaque: *mut c_void, ) -> c_int { // SAFETY: the function is used in T's implementation of VMState let result = F::call((unsafe { &*(opaque.cast::()) },)); into_neg_errno(result) } unsafe extern "C" fn vmstate_post_load_cb< T, F: for<'a> FnCall<(&'a T, u8), Result<(), impl Into>>, >( opaque: *mut c_void, version_id: c_int, ) -> c_int { // SAFETY: the function is used in T's implementation of VMState let owner: &T = unsafe { &*(opaque.cast::()) }; let version: u8 = version_id.try_into().unwrap(); let result = F::call((owner, version)); into_neg_errno(result) } unsafe extern "C" fn vmstate_needed_cb FnCall<(&'a T,), bool>>( opaque: *mut c_void, ) -> bool { // SAFETY: the function is used in T's implementation of VMState F::call((unsafe { &*(opaque.cast::()) },)) } unsafe extern "C" fn vmstate_dev_unplug_pending_cb FnCall<(&'a T,), bool>>( opaque: *mut c_void, ) -> bool { // SAFETY: the function is used in T's implementation of VMState F::call((unsafe { &*(opaque.cast::()) },)) } impl VMStateDescriptionBuilder { #[must_use] pub const fn name(mut self, name_str: &CStr) -> Self { self.0.name = ::std::ffi::CStr::as_ptr(name_str); self } #[must_use] pub const fn unmigratable(mut self) -> Self { self.0.unmigratable = true; self } #[must_use] pub const fn early_setup(mut self) -> Self { self.0.early_setup = true; self } #[must_use] pub const fn version_id(mut self, version: u8) -> Self { self.0.version_id = version as c_int; self } #[must_use] pub const fn minimum_version_id(mut self, min_version: u8) -> Self { self.0.minimum_version_id = min_version as c_int; self } #[must_use] pub const fn priority(mut self, priority: MigrationPriority) -> Self { self.0.priority = priority; self } #[must_use] pub const fn pre_load FnCall<(&'a T,), Result<(), impl Into>>>( mut self, _f: &F, ) -> Self { self.0.pre_load = if F::IS_SOME { Some(vmstate_no_version_cb::) } else { None }; self } #[must_use] pub const fn post_load FnCall<(&'a T, u8), Result<(), impl Into>>>( mut self, _f: &F, ) -> Self { self.0.post_load = if F::IS_SOME { Some(vmstate_post_load_cb::) } else { None }; self } #[must_use] pub const fn pre_save FnCall<(&'a T,), Result<(), impl Into>>>( mut self, _f: &F, ) -> Self { self.0.pre_save = if F::IS_SOME { Some(vmstate_no_version_cb::) } else { None }; self } #[must_use] pub const fn post_save FnCall<(&'a T,), Result<(), impl Into>>>( mut self, _f: &F, ) -> Self { self.0.post_save = if F::IS_SOME { Some(vmstate_no_version_cb::) } else { None }; self } #[must_use] pub const fn needed FnCall<(&'a T,), bool>>(mut self, _f: &F) -> Self { self.0.needed = if F::IS_SOME { Some(vmstate_needed_cb::) } else { None }; self } #[must_use] pub const fn unplug_pending FnCall<(&'a T,), bool>>(mut self, _f: &F) -> Self { self.0.dev_unplug_pending = if F::IS_SOME { Some(vmstate_dev_unplug_pending_cb::) } else { None }; self } #[must_use] pub const fn fields(mut self, fields: *const VMStateField) -> Self { self.0.fields = fields; self } #[must_use] pub const fn subsections(mut self, subs: &'static VMStateSubsectionsWrapper) -> Self { self.0.subsections = subs.0.as_ptr(); self } #[must_use] pub const fn build(self) -> VMStateDescription { VMStateDescription::(self.0, PhantomData) } #[must_use] pub const fn new() -> Self { Self(bindings::VMStateDescription::ZERO, PhantomData) } } impl Default for VMStateDescriptionBuilder { fn default() -> Self { Self::new() } } impl VMStateDescription { pub const fn get(&self) -> bindings::VMStateDescription { self.0 } pub const fn as_ref(&self) -> &bindings::VMStateDescription { &self.0 } }