xref: /qemu/rust/qemu-api/src/vmstate.rs (revision f2cb78bdbe5f9ff61366beb216971a8502456c3a)
10a65e412SManos Pitsidianakis // Copyright 2024, Linaro Limited
20a65e412SManos Pitsidianakis // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
30a65e412SManos Pitsidianakis // SPDX-License-Identifier: GPL-2.0-or-later
40a65e412SManos Pitsidianakis 
50a65e412SManos Pitsidianakis //! Helper macros to declare migration state for device models.
60a65e412SManos Pitsidianakis //!
70d43ddaeSPaolo Bonzini //! This module includes three families of macros:
80d43ddaeSPaolo Bonzini //!
90d43ddaeSPaolo Bonzini //! * [`vmstate_unused!`](crate::vmstate_unused) and
100d43ddaeSPaolo Bonzini //!   [`vmstate_of!`](crate::vmstate_of), which are used to express the
110d43ddaeSPaolo Bonzini //!   migration format for a struct.  This is based on the [`VMState`] trait,
120d43ddaeSPaolo Bonzini //!   which is defined by all migrateable types.
130d43ddaeSPaolo Bonzini //!
140d43ddaeSPaolo Bonzini //! * helper macros to declare a device model state struct, in particular
150a65e412SManos Pitsidianakis //!   [`vmstate_subsections`](crate::vmstate_subsections) and
160d43ddaeSPaolo Bonzini //!   [`vmstate_fields`](crate::vmstate_fields).
170d43ddaeSPaolo Bonzini //!
180d43ddaeSPaolo Bonzini //! * direct equivalents to the C macros declared in
190d43ddaeSPaolo Bonzini //!   `include/migration/vmstate.h`. These are not type-safe and should not be
200d43ddaeSPaolo Bonzini //!   used if the equivalent functionality is available with `vmstate_of!`.
210a65e412SManos Pitsidianakis 
2280aa3045SPaolo Bonzini use core::{marker::PhantomData, mem, ptr::NonNull};
230d43ddaeSPaolo Bonzini 
240d43ddaeSPaolo Bonzini pub use crate::bindings::{VMStateDescription, VMStateField};
25*f2cb78bdSPaolo Bonzini use crate::{
26*f2cb78bdSPaolo Bonzini     bindings::{self, VMStateFlags},
27*f2cb78bdSPaolo Bonzini     zeroable::Zeroable,
28*f2cb78bdSPaolo Bonzini };
290d43ddaeSPaolo Bonzini 
300d43ddaeSPaolo Bonzini /// This macro is used to call a function with a generic argument bound
310d43ddaeSPaolo Bonzini /// to the type of a field.  The function must take a
320d43ddaeSPaolo Bonzini /// [`PhantomData`]`<T>` argument; `T` is the type of
330d43ddaeSPaolo Bonzini /// field `$field` in the `$typ` type.
340d43ddaeSPaolo Bonzini ///
350d43ddaeSPaolo Bonzini /// # Examples
360d43ddaeSPaolo Bonzini ///
370d43ddaeSPaolo Bonzini /// ```
380d43ddaeSPaolo Bonzini /// # use qemu_api::call_func_with_field;
390d43ddaeSPaolo Bonzini /// # use core::marker::PhantomData;
400d43ddaeSPaolo Bonzini /// const fn size_of_field<T>(_: PhantomData<T>) -> usize {
410d43ddaeSPaolo Bonzini ///     std::mem::size_of::<T>()
420d43ddaeSPaolo Bonzini /// }
430d43ddaeSPaolo Bonzini ///
440d43ddaeSPaolo Bonzini /// struct Foo {
450d43ddaeSPaolo Bonzini ///     x: u16,
460d43ddaeSPaolo Bonzini /// };
470d43ddaeSPaolo Bonzini /// // calls size_of_field::<u16>()
480d43ddaeSPaolo Bonzini /// assert_eq!(call_func_with_field!(size_of_field, Foo, x), 2);
490d43ddaeSPaolo Bonzini /// ```
500d43ddaeSPaolo Bonzini #[macro_export]
510d43ddaeSPaolo Bonzini macro_rules! call_func_with_field {
520d43ddaeSPaolo Bonzini     // Based on the answer by user steffahn (Frank Steffahn) at
530d43ddaeSPaolo Bonzini     // https://users.rust-lang.org/t/inferring-type-of-field/122857
540d43ddaeSPaolo Bonzini     // and used under MIT license
550d43ddaeSPaolo Bonzini     ($func:expr, $typ:ty, $($field:tt).+) => {
560d43ddaeSPaolo Bonzini         $func(loop {
570d43ddaeSPaolo Bonzini             #![allow(unreachable_code)]
580d43ddaeSPaolo Bonzini             const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> { ::core::marker::PhantomData }
590d43ddaeSPaolo Bonzini             // Unreachable code is exempt from checks on uninitialized values.
600d43ddaeSPaolo Bonzini             // Use that trick to infer the type of this PhantomData.
610d43ddaeSPaolo Bonzini             break ::core::marker::PhantomData;
620d43ddaeSPaolo Bonzini             break phantom__(&{ let value__: $typ; value__.$($field).+ });
630d43ddaeSPaolo Bonzini         })
640d43ddaeSPaolo Bonzini     };
650d43ddaeSPaolo Bonzini }
660d43ddaeSPaolo Bonzini 
67*f2cb78bdSPaolo Bonzini /// Workaround for lack of `const_refs_static`: references to global variables
68*f2cb78bdSPaolo Bonzini /// can be included in a `static`, but not in a `const`; unfortunately, this
69*f2cb78bdSPaolo Bonzini /// is exactly what would go in the `VMStateField`'s `info` member.
70*f2cb78bdSPaolo Bonzini ///
71*f2cb78bdSPaolo Bonzini /// This enum contains the contents of the `VMStateField`'s `info` member,
72*f2cb78bdSPaolo Bonzini /// but as an `enum` instead of a pointer.
73*f2cb78bdSPaolo Bonzini #[allow(non_camel_case_types)]
74*f2cb78bdSPaolo Bonzini pub enum VMStateFieldType {
75*f2cb78bdSPaolo Bonzini     null,
76*f2cb78bdSPaolo Bonzini     vmstate_info_bool,
77*f2cb78bdSPaolo Bonzini     vmstate_info_int8,
78*f2cb78bdSPaolo Bonzini     vmstate_info_int16,
79*f2cb78bdSPaolo Bonzini     vmstate_info_int32,
80*f2cb78bdSPaolo Bonzini     vmstate_info_int64,
81*f2cb78bdSPaolo Bonzini     vmstate_info_uint8,
82*f2cb78bdSPaolo Bonzini     vmstate_info_uint16,
83*f2cb78bdSPaolo Bonzini     vmstate_info_uint32,
84*f2cb78bdSPaolo Bonzini     vmstate_info_uint64,
85*f2cb78bdSPaolo Bonzini     vmstate_info_timer,
86*f2cb78bdSPaolo Bonzini }
87*f2cb78bdSPaolo Bonzini 
88*f2cb78bdSPaolo Bonzini /// Workaround for lack of `const_refs_static`.  Converts a `VMStateFieldType`
89*f2cb78bdSPaolo Bonzini /// to a `*const VMStateInfo`, for inclusion in a `VMStateField`.
90*f2cb78bdSPaolo Bonzini #[macro_export]
91*f2cb78bdSPaolo Bonzini macro_rules! info_enum_to_ref {
92*f2cb78bdSPaolo Bonzini     ($e:expr) => {
93*f2cb78bdSPaolo Bonzini         unsafe {
94*f2cb78bdSPaolo Bonzini             match $e {
95*f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::null => ::core::ptr::null(),
96*f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_bool => {
97*f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_bool)
98*f2cb78bdSPaolo Bonzini                 }
99*f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_int8 => {
100*f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int8)
101*f2cb78bdSPaolo Bonzini                 }
102*f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_int16 => {
103*f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int16)
104*f2cb78bdSPaolo Bonzini                 }
105*f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_int32 => {
106*f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int32)
107*f2cb78bdSPaolo Bonzini                 }
108*f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_int64 => {
109*f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int64)
110*f2cb78bdSPaolo Bonzini                 }
111*f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_uint8 => {
112*f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint8)
113*f2cb78bdSPaolo Bonzini                 }
114*f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_uint16 => {
115*f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint16)
116*f2cb78bdSPaolo Bonzini                 }
117*f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_uint32 => {
118*f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32)
119*f2cb78bdSPaolo Bonzini                 }
120*f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_uint64 => {
121*f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint64)
122*f2cb78bdSPaolo Bonzini                 }
123*f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_timer => {
124*f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_timer)
125*f2cb78bdSPaolo Bonzini                 }
126*f2cb78bdSPaolo Bonzini             }
127*f2cb78bdSPaolo Bonzini         }
128*f2cb78bdSPaolo Bonzini     };
129*f2cb78bdSPaolo Bonzini }
130*f2cb78bdSPaolo Bonzini 
1310d43ddaeSPaolo Bonzini /// A trait for types that can be included in a device's migration stream.  It
1320d43ddaeSPaolo Bonzini /// provides the base contents of a `VMStateField` (minus the name and offset).
1330d43ddaeSPaolo Bonzini ///
1340d43ddaeSPaolo Bonzini /// # Safety
1350d43ddaeSPaolo Bonzini ///
1360d43ddaeSPaolo Bonzini /// The contents of this trait go straight into structs that are parsed by C
1370d43ddaeSPaolo Bonzini /// code and used to introspect into other structs.  Be careful.
1380d43ddaeSPaolo Bonzini pub unsafe trait VMState {
139*f2cb78bdSPaolo Bonzini     /// The `info` member of a `VMStateField` is a pointer and as such cannot
140*f2cb78bdSPaolo Bonzini     /// yet be included in the [`BASE`](VMState::BASE) associated constant;
141*f2cb78bdSPaolo Bonzini     /// this is only allowed by Rust 1.83.0 and newer.  For now, include the
142*f2cb78bdSPaolo Bonzini     /// member as an enum which is stored in a separate constant.
143*f2cb78bdSPaolo Bonzini     const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::null;
144*f2cb78bdSPaolo Bonzini 
1450d43ddaeSPaolo Bonzini     /// The base contents of a `VMStateField` (minus the name and offset) for
1460d43ddaeSPaolo Bonzini     /// the type that is implementing the trait.
1470d43ddaeSPaolo Bonzini     const BASE: VMStateField;
1485b024b4eSPaolo Bonzini 
1495b024b4eSPaolo Bonzini     /// A flag that is added to another field's `VMStateField` to specify the
1505b024b4eSPaolo Bonzini     /// length's type in a variable-sized array.  If this is not a supported
1515b024b4eSPaolo Bonzini     /// type for the length (i.e. if it is not `u8`, `u16`, `u32`), using it
1525b024b4eSPaolo Bonzini     /// in a call to [`vmstate_of!`](crate::vmstate_of) will cause a
1535b024b4eSPaolo Bonzini     /// compile-time error.
1545b024b4eSPaolo Bonzini     const VARRAY_FLAG: VMStateFlags = {
1555b024b4eSPaolo Bonzini         panic!("invalid type for variable-sized array");
1565b024b4eSPaolo Bonzini     };
1570d43ddaeSPaolo Bonzini }
1580d43ddaeSPaolo Bonzini 
159*f2cb78bdSPaolo Bonzini /// Internal utility function to retrieve a type's `VMStateFieldType`;
160*f2cb78bdSPaolo Bonzini /// used by [`vmstate_of!`](crate::vmstate_of).
161*f2cb78bdSPaolo Bonzini pub const fn vmstate_scalar_type<T: VMState>(_: PhantomData<T>) -> VMStateFieldType {
162*f2cb78bdSPaolo Bonzini     T::SCALAR_TYPE
163*f2cb78bdSPaolo Bonzini }
164*f2cb78bdSPaolo Bonzini 
1650d43ddaeSPaolo Bonzini /// Internal utility function to retrieve a type's `VMStateField`;
1660d43ddaeSPaolo Bonzini /// used by [`vmstate_of!`](crate::vmstate_of).
1670d43ddaeSPaolo Bonzini pub const fn vmstate_base<T: VMState>(_: PhantomData<T>) -> VMStateField {
1680d43ddaeSPaolo Bonzini     T::BASE
1690d43ddaeSPaolo Bonzini }
1700d43ddaeSPaolo Bonzini 
1715b024b4eSPaolo Bonzini /// Internal utility function to retrieve a type's `VMStateFlags` when it
1725b024b4eSPaolo Bonzini /// is used as the element count of a `VMSTATE_VARRAY`; used by
1735b024b4eSPaolo Bonzini /// [`vmstate_of!`](crate::vmstate_of).
1745b024b4eSPaolo Bonzini pub const fn vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags {
1755b024b4eSPaolo Bonzini     T::VARRAY_FLAG
1765b024b4eSPaolo Bonzini }
1775b024b4eSPaolo Bonzini 
1780d43ddaeSPaolo Bonzini /// Return the `VMStateField` for a field of a struct.  The field must be
1790d43ddaeSPaolo Bonzini /// visible in the current scope.
1800d43ddaeSPaolo Bonzini ///
181*f2cb78bdSPaolo Bonzini /// Only a limited set of types is supported out of the box:
182*f2cb78bdSPaolo Bonzini /// * scalar types (integer and `bool`)
183*f2cb78bdSPaolo Bonzini /// * the C struct `QEMUTimer`
184*f2cb78bdSPaolo Bonzini /// * a transparent wrapper for any of the above (`Cell`, `UnsafeCell`,
185*f2cb78bdSPaolo Bonzini ///   [`BqlCell`](crate::cell::BqlCell), [`BqlRefCell`](crate::cell::BqlRefCell)
186*f2cb78bdSPaolo Bonzini /// * a raw pointer to any of the above
187*f2cb78bdSPaolo Bonzini /// * a `NonNull` pointer or a `Box` for any of the above
188*f2cb78bdSPaolo Bonzini /// * an array of any of the above
189*f2cb78bdSPaolo Bonzini ///
1900d43ddaeSPaolo Bonzini /// In order to support other types, the trait `VMState` must be implemented
1910d43ddaeSPaolo Bonzini /// for them.
1920d43ddaeSPaolo Bonzini #[macro_export]
1930d43ddaeSPaolo Bonzini macro_rules! vmstate_of {
1945b024b4eSPaolo Bonzini     ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(,)?) => {
1950d43ddaeSPaolo Bonzini         $crate::bindings::VMStateField {
1960d43ddaeSPaolo Bonzini             name: ::core::concat!(::core::stringify!($field_name), "\0")
1970d43ddaeSPaolo Bonzini                 .as_bytes()
1980d43ddaeSPaolo Bonzini                 .as_ptr() as *const ::std::os::raw::c_char,
1990d43ddaeSPaolo Bonzini             offset: $crate::offset_of!($struct_name, $field_name),
2005b024b4eSPaolo Bonzini             $(.num_offset: $crate::offset_of!($struct_name, $num),)?
201*f2cb78bdSPaolo Bonzini             // The calls to `call_func_with_field!` are the magic that
202*f2cb78bdSPaolo Bonzini             // computes most of the VMStateField from the type of the field.
203*f2cb78bdSPaolo Bonzini             info: $crate::info_enum_to_ref!($crate::call_func_with_field!(
204*f2cb78bdSPaolo Bonzini                 $crate::vmstate::vmstate_scalar_type,
205*f2cb78bdSPaolo Bonzini                 $struct_name,
206*f2cb78bdSPaolo Bonzini                 $field_name
207*f2cb78bdSPaolo Bonzini             )),
2080d43ddaeSPaolo Bonzini             ..$crate::call_func_with_field!(
2090d43ddaeSPaolo Bonzini                 $crate::vmstate::vmstate_base,
2100d43ddaeSPaolo Bonzini                 $struct_name,
2110d43ddaeSPaolo Bonzini                 $field_name
2125b024b4eSPaolo Bonzini             )$(.with_varray_flag($crate::call_func_with_field!(
2135b024b4eSPaolo Bonzini                     $crate::vmstate::vmstate_varray_flag,
2145b024b4eSPaolo Bonzini                     $struct_name,
2155b024b4eSPaolo Bonzini                     $num))
2165b024b4eSPaolo Bonzini                $(.with_varray_multiply($factor))?)?
2170d43ddaeSPaolo Bonzini         }
2180d43ddaeSPaolo Bonzini     };
2190d43ddaeSPaolo Bonzini }
2200d43ddaeSPaolo Bonzini 
22180aa3045SPaolo Bonzini impl VMStateFlags {
22280aa3045SPaolo Bonzini     const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags(
22380aa3045SPaolo Bonzini         VMStateFlags::VMS_VARRAY_INT32.0
22480aa3045SPaolo Bonzini             | VMStateFlags::VMS_VARRAY_UINT8.0
22580aa3045SPaolo Bonzini             | VMStateFlags::VMS_VARRAY_UINT16.0
22680aa3045SPaolo Bonzini             | VMStateFlags::VMS_VARRAY_UINT32.0,
22780aa3045SPaolo Bonzini     );
22880aa3045SPaolo Bonzini }
22980aa3045SPaolo Bonzini 
2300d43ddaeSPaolo Bonzini // Add a couple builder-style methods to VMStateField, allowing
2310d43ddaeSPaolo Bonzini // easy derivation of VMStateField constants from other types.
2320d43ddaeSPaolo Bonzini impl VMStateField {
2330d43ddaeSPaolo Bonzini     #[must_use]
2340d43ddaeSPaolo Bonzini     pub const fn with_version_id(mut self, version_id: i32) -> Self {
2350d43ddaeSPaolo Bonzini         assert!(version_id >= 0);
2360d43ddaeSPaolo Bonzini         self.version_id = version_id;
2370d43ddaeSPaolo Bonzini         self
2380d43ddaeSPaolo Bonzini     }
23980aa3045SPaolo Bonzini 
24080aa3045SPaolo Bonzini     #[must_use]
24180aa3045SPaolo Bonzini     pub const fn with_array_flag(mut self, num: usize) -> Self {
24280aa3045SPaolo Bonzini         assert!(num <= 0x7FFF_FFFFusize);
24380aa3045SPaolo Bonzini         assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) == 0);
24480aa3045SPaolo Bonzini         assert!((self.flags.0 & VMStateFlags::VMS_VARRAY_FLAGS.0) == 0);
24580aa3045SPaolo Bonzini         if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 {
24680aa3045SPaolo Bonzini             self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0);
24780aa3045SPaolo Bonzini             self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0);
24880aa3045SPaolo Bonzini         }
24980aa3045SPaolo Bonzini         self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0);
25080aa3045SPaolo Bonzini         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0);
25180aa3045SPaolo Bonzini         self.num = num as i32;
25280aa3045SPaolo Bonzini         self
25380aa3045SPaolo Bonzini     }
25480aa3045SPaolo Bonzini 
25580aa3045SPaolo Bonzini     #[must_use]
25680aa3045SPaolo Bonzini     pub const fn with_pointer_flag(mut self) -> Self {
25780aa3045SPaolo Bonzini         assert!((self.flags.0 & VMStateFlags::VMS_POINTER.0) == 0);
25880aa3045SPaolo Bonzini         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_POINTER.0);
25980aa3045SPaolo Bonzini         self
26080aa3045SPaolo Bonzini     }
2615b024b4eSPaolo Bonzini 
2625b024b4eSPaolo Bonzini     #[must_use]
2635b024b4eSPaolo Bonzini     pub const fn with_varray_flag<T: VMState>(mut self, flag: VMStateFlags) -> VMStateField {
2645b024b4eSPaolo Bonzini         assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0);
2655b024b4eSPaolo Bonzini         self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0);
2665b024b4eSPaolo Bonzini         self.flags = VMStateFlags(self.flags.0 | flag.0);
2675b024b4eSPaolo Bonzini         self
2685b024b4eSPaolo Bonzini     }
2695b024b4eSPaolo Bonzini 
2705b024b4eSPaolo Bonzini     #[must_use]
2715b024b4eSPaolo Bonzini     pub const fn with_varray_multiply(mut self, num: u32) -> VMStateField {
2725b024b4eSPaolo Bonzini         assert!(num <= 0x7FFF_FFFFu32);
2735b024b4eSPaolo Bonzini         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0);
2745b024b4eSPaolo Bonzini         self.num = num as i32;
2755b024b4eSPaolo Bonzini         self
2765b024b4eSPaolo Bonzini     }
27780aa3045SPaolo Bonzini }
27880aa3045SPaolo Bonzini 
27980aa3045SPaolo Bonzini // Transparent wrappers: just use the internal type
28080aa3045SPaolo Bonzini 
28180aa3045SPaolo Bonzini macro_rules! impl_vmstate_transparent {
28280aa3045SPaolo Bonzini     ($type:ty where $base:tt: VMState $($where:tt)*) => {
28380aa3045SPaolo Bonzini         unsafe impl<$base> VMState for $type where $base: VMState $($where)* {
284*f2cb78bdSPaolo Bonzini             const SCALAR_TYPE: VMStateFieldType = <$base as VMState>::SCALAR_TYPE;
28580aa3045SPaolo Bonzini             const BASE: VMStateField = VMStateField {
28680aa3045SPaolo Bonzini                 size: mem::size_of::<$type>(),
28780aa3045SPaolo Bonzini                 ..<$base as VMState>::BASE
28880aa3045SPaolo Bonzini             };
2895b024b4eSPaolo Bonzini             const VARRAY_FLAG: VMStateFlags = <$base as VMState>::VARRAY_FLAG;
29080aa3045SPaolo Bonzini         }
29180aa3045SPaolo Bonzini     };
29280aa3045SPaolo Bonzini }
29380aa3045SPaolo Bonzini 
29480aa3045SPaolo Bonzini impl_vmstate_transparent!(std::cell::Cell<T> where T: VMState);
29580aa3045SPaolo Bonzini impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState);
29680aa3045SPaolo Bonzini impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState);
29780aa3045SPaolo Bonzini impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState);
29880aa3045SPaolo Bonzini 
299*f2cb78bdSPaolo Bonzini // Scalar types using predefined VMStateInfos
300*f2cb78bdSPaolo Bonzini 
301*f2cb78bdSPaolo Bonzini macro_rules! impl_vmstate_scalar {
302*f2cb78bdSPaolo Bonzini     ($info:ident, $type:ty$(, $varray_flag:ident)?) => {
303*f2cb78bdSPaolo Bonzini         unsafe impl VMState for $type {
304*f2cb78bdSPaolo Bonzini             const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::$info;
305*f2cb78bdSPaolo Bonzini             const BASE: VMStateField = VMStateField {
306*f2cb78bdSPaolo Bonzini                 size: mem::size_of::<$type>(),
307*f2cb78bdSPaolo Bonzini                 flags: VMStateFlags::VMS_SINGLE,
308*f2cb78bdSPaolo Bonzini                 ..Zeroable::ZERO
309*f2cb78bdSPaolo Bonzini             };
310*f2cb78bdSPaolo Bonzini             $(const VARRAY_FLAG: VMStateFlags = VMStateFlags::$varray_flag;)?
311*f2cb78bdSPaolo Bonzini         }
312*f2cb78bdSPaolo Bonzini     };
313*f2cb78bdSPaolo Bonzini }
314*f2cb78bdSPaolo Bonzini 
315*f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_bool, bool);
316*f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_int8, i8);
317*f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_int16, i16);
318*f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_int32, i32);
319*f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_int64, i64);
320*f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY_UINT8);
321*f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY_UINT16);
322*f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY_UINT32);
323*f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_uint64, u64);
324*f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_timer, bindings::QEMUTimer);
325*f2cb78bdSPaolo Bonzini 
32680aa3045SPaolo Bonzini // Pointer types using the underlying type's VMState plus VMS_POINTER
32780aa3045SPaolo Bonzini // Note that references are not supported, though references to cells
32880aa3045SPaolo Bonzini // could be allowed.
32980aa3045SPaolo Bonzini 
33080aa3045SPaolo Bonzini macro_rules! impl_vmstate_pointer {
33180aa3045SPaolo Bonzini     ($type:ty where $base:tt: VMState $($where:tt)*) => {
33280aa3045SPaolo Bonzini         unsafe impl<$base> VMState for $type where $base: VMState $($where)* {
333*f2cb78bdSPaolo Bonzini             const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE;
33480aa3045SPaolo Bonzini             const BASE: VMStateField = <$base as VMState>::BASE.with_pointer_flag();
33580aa3045SPaolo Bonzini         }
33680aa3045SPaolo Bonzini     };
33780aa3045SPaolo Bonzini }
33880aa3045SPaolo Bonzini 
33980aa3045SPaolo Bonzini impl_vmstate_pointer!(*const T where T: VMState);
34080aa3045SPaolo Bonzini impl_vmstate_pointer!(*mut T where T: VMState);
34180aa3045SPaolo Bonzini impl_vmstate_pointer!(NonNull<T> where T: VMState);
34280aa3045SPaolo Bonzini 
34380aa3045SPaolo Bonzini // Unlike C pointers, Box is always non-null therefore there is no need
34480aa3045SPaolo Bonzini // to specify VMS_ALLOC.
34580aa3045SPaolo Bonzini impl_vmstate_pointer!(Box<T> where T: VMState);
34680aa3045SPaolo Bonzini 
34780aa3045SPaolo Bonzini // Arrays using the underlying type's VMState plus
34880aa3045SPaolo Bonzini // VMS_ARRAY/VMS_ARRAY_OF_POINTER
34980aa3045SPaolo Bonzini 
35080aa3045SPaolo Bonzini unsafe impl<T: VMState, const N: usize> VMState for [T; N] {
351*f2cb78bdSPaolo Bonzini     const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE;
35280aa3045SPaolo Bonzini     const BASE: VMStateField = <T as VMState>::BASE.with_array_flag(N);
3530d43ddaeSPaolo Bonzini }
354716d89f9SPaolo Bonzini 
3550a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_UNUSED_BUFFER")]
3560a65e412SManos Pitsidianakis #[macro_export]
3570a65e412SManos Pitsidianakis macro_rules! vmstate_unused_buffer {
3580a65e412SManos Pitsidianakis     ($field_exists_fn:expr, $version_id:expr, $size:expr) => {{
3590a65e412SManos Pitsidianakis         $crate::bindings::VMStateField {
360718e255fSPaolo Bonzini             name: c_str!("unused").as_ptr(),
3610a65e412SManos Pitsidianakis             err_hint: ::core::ptr::null(),
3620a65e412SManos Pitsidianakis             offset: 0,
3630a65e412SManos Pitsidianakis             size: $size,
3640a65e412SManos Pitsidianakis             start: 0,
3650a65e412SManos Pitsidianakis             num: 0,
3660a65e412SManos Pitsidianakis             num_offset: 0,
3670a65e412SManos Pitsidianakis             size_offset: 0,
3680a65e412SManos Pitsidianakis             info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) },
3690a65e412SManos Pitsidianakis             flags: VMStateFlags::VMS_BUFFER,
3700a65e412SManos Pitsidianakis             vmsd: ::core::ptr::null(),
3710a65e412SManos Pitsidianakis             version_id: $version_id,
3720a65e412SManos Pitsidianakis             struct_version_id: 0,
3730a65e412SManos Pitsidianakis             field_exists: $field_exists_fn,
3740a65e412SManos Pitsidianakis         }
3750a65e412SManos Pitsidianakis     }};
3760a65e412SManos Pitsidianakis }
3770a65e412SManos Pitsidianakis 
3780a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_UNUSED_V")]
3790a65e412SManos Pitsidianakis #[macro_export]
3800a65e412SManos Pitsidianakis macro_rules! vmstate_unused_v {
3810a65e412SManos Pitsidianakis     ($version_id:expr, $size:expr) => {{
3820a65e412SManos Pitsidianakis         $crate::vmstate_unused_buffer!(None, $version_id, $size)
3830a65e412SManos Pitsidianakis     }};
3840a65e412SManos Pitsidianakis }
3850a65e412SManos Pitsidianakis 
3860a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_UNUSED")]
3870a65e412SManos Pitsidianakis #[macro_export]
3880a65e412SManos Pitsidianakis macro_rules! vmstate_unused {
3890a65e412SManos Pitsidianakis     ($size:expr) => {{
3900a65e412SManos Pitsidianakis         $crate::vmstate_unused_v!(0, $size)
3910a65e412SManos Pitsidianakis     }};
3920a65e412SManos Pitsidianakis }
3930a65e412SManos Pitsidianakis 
3940a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_SINGLE_TEST")]
3950a65e412SManos Pitsidianakis #[macro_export]
3960a65e412SManos Pitsidianakis macro_rules! vmstate_single_test {
3970a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty, $field_exists_fn:expr, $version_id:expr, $info:expr, $size:expr) => {{
3980a65e412SManos Pitsidianakis         $crate::bindings::VMStateField {
3990a65e412SManos Pitsidianakis             name: ::core::concat!(::core::stringify!($field_name), 0)
4000a65e412SManos Pitsidianakis                 .as_bytes()
4019f7d4520SPaolo Bonzini                 .as_ptr() as *const ::std::os::raw::c_char,
4020a65e412SManos Pitsidianakis             err_hint: ::core::ptr::null(),
403f3518400SJunjie Mao             offset: $crate::offset_of!($struct_name, $field_name),
4040a65e412SManos Pitsidianakis             size: $size,
4050a65e412SManos Pitsidianakis             start: 0,
4060a65e412SManos Pitsidianakis             num: 0,
4070a65e412SManos Pitsidianakis             num_offset: 0,
4080a65e412SManos Pitsidianakis             size_offset: 0,
4090a65e412SManos Pitsidianakis             info: unsafe { $info },
4100a65e412SManos Pitsidianakis             flags: VMStateFlags::VMS_SINGLE,
4110a65e412SManos Pitsidianakis             vmsd: ::core::ptr::null(),
4120a65e412SManos Pitsidianakis             version_id: $version_id,
4130a65e412SManos Pitsidianakis             struct_version_id: 0,
4140a65e412SManos Pitsidianakis             field_exists: $field_exists_fn,
4150a65e412SManos Pitsidianakis         }
4160a65e412SManos Pitsidianakis     }};
4170a65e412SManos Pitsidianakis }
4180a65e412SManos Pitsidianakis 
4190a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_SINGLE")]
4200a65e412SManos Pitsidianakis #[macro_export]
4210a65e412SManos Pitsidianakis macro_rules! vmstate_single {
4220a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty, $version_id:expr, $info:expr, $size:expr) => {{
4230a65e412SManos Pitsidianakis         $crate::vmstate_single_test!($field_name, $struct_name, None, $version_id, $info, $size)
4240a65e412SManos Pitsidianakis     }};
4250a65e412SManos Pitsidianakis }
4260a65e412SManos Pitsidianakis 
4270a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_UINT32_V")]
4280a65e412SManos Pitsidianakis #[macro_export]
4290a65e412SManos Pitsidianakis macro_rules! vmstate_uint32_v {
4300a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty, $version_id:expr) => {{
4310a65e412SManos Pitsidianakis         $crate::vmstate_single!(
4320a65e412SManos Pitsidianakis             $field_name,
4330a65e412SManos Pitsidianakis             $struct_name,
4340a65e412SManos Pitsidianakis             $version_id,
4350a65e412SManos Pitsidianakis             ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32),
4360a65e412SManos Pitsidianakis             ::core::mem::size_of::<u32>()
4370a65e412SManos Pitsidianakis         )
4380a65e412SManos Pitsidianakis     }};
4390a65e412SManos Pitsidianakis }
4400a65e412SManos Pitsidianakis 
4410a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_UINT32")]
4420a65e412SManos Pitsidianakis #[macro_export]
4430a65e412SManos Pitsidianakis macro_rules! vmstate_uint32 {
4440a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty) => {{
4450a65e412SManos Pitsidianakis         $crate::vmstate_uint32_v!($field_name, $struct_name, 0)
4460a65e412SManos Pitsidianakis     }};
4470a65e412SManos Pitsidianakis }
4480a65e412SManos Pitsidianakis 
4490a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_ARRAY")]
4500a65e412SManos Pitsidianakis #[macro_export]
4510a65e412SManos Pitsidianakis macro_rules! vmstate_array {
4520a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr, $info:expr, $size:expr) => {{
4530a65e412SManos Pitsidianakis         $crate::bindings::VMStateField {
4540a65e412SManos Pitsidianakis             name: ::core::concat!(::core::stringify!($field_name), 0)
4550a65e412SManos Pitsidianakis                 .as_bytes()
4569f7d4520SPaolo Bonzini                 .as_ptr() as *const ::std::os::raw::c_char,
4570a65e412SManos Pitsidianakis             err_hint: ::core::ptr::null(),
458f3518400SJunjie Mao             offset: $crate::offset_of!($struct_name, $field_name),
4590a65e412SManos Pitsidianakis             size: $size,
4600a65e412SManos Pitsidianakis             start: 0,
4610a65e412SManos Pitsidianakis             num: $length as _,
4620a65e412SManos Pitsidianakis             num_offset: 0,
4630a65e412SManos Pitsidianakis             size_offset: 0,
4640a65e412SManos Pitsidianakis             info: unsafe { $info },
4650a65e412SManos Pitsidianakis             flags: VMStateFlags::VMS_ARRAY,
4660a65e412SManos Pitsidianakis             vmsd: ::core::ptr::null(),
4670a65e412SManos Pitsidianakis             version_id: $version_id,
4680a65e412SManos Pitsidianakis             struct_version_id: 0,
4690a65e412SManos Pitsidianakis             field_exists: None,
4700a65e412SManos Pitsidianakis         }
4710a65e412SManos Pitsidianakis     }};
4720a65e412SManos Pitsidianakis }
4730a65e412SManos Pitsidianakis 
4740a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_UINT32_ARRAY_V")]
4750a65e412SManos Pitsidianakis #[macro_export]
4760a65e412SManos Pitsidianakis macro_rules! vmstate_uint32_array_v {
4770a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr) => {{
4780a65e412SManos Pitsidianakis         $crate::vmstate_array!(
4790a65e412SManos Pitsidianakis             $field_name,
4800a65e412SManos Pitsidianakis             $struct_name,
4810a65e412SManos Pitsidianakis             $length,
4820a65e412SManos Pitsidianakis             $version_id,
4830a65e412SManos Pitsidianakis             ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32),
4840a65e412SManos Pitsidianakis             ::core::mem::size_of::<u32>()
4850a65e412SManos Pitsidianakis         )
4860a65e412SManos Pitsidianakis     }};
4870a65e412SManos Pitsidianakis }
4880a65e412SManos Pitsidianakis 
4890a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_UINT32_ARRAY")]
4900a65e412SManos Pitsidianakis #[macro_export]
4910a65e412SManos Pitsidianakis macro_rules! vmstate_uint32_array {
4920a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty, $length:expr) => {{
4930a65e412SManos Pitsidianakis         $crate::vmstate_uint32_array_v!($field_name, $struct_name, $length, 0)
4940a65e412SManos Pitsidianakis     }};
4950a65e412SManos Pitsidianakis }
4960a65e412SManos Pitsidianakis 
4970a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_STRUCT_POINTER_V")]
4980a65e412SManos Pitsidianakis #[macro_export]
4990a65e412SManos Pitsidianakis macro_rules! vmstate_struct_pointer_v {
5000a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty, $version_id:expr, $vmsd:expr, $type:ty) => {{
5010a65e412SManos Pitsidianakis         $crate::bindings::VMStateField {
5020a65e412SManos Pitsidianakis             name: ::core::concat!(::core::stringify!($field_name), 0)
5030a65e412SManos Pitsidianakis                 .as_bytes()
5049f7d4520SPaolo Bonzini                 .as_ptr() as *const ::std::os::raw::c_char,
5050a65e412SManos Pitsidianakis             err_hint: ::core::ptr::null(),
506f3518400SJunjie Mao             offset: $crate::offset_of!($struct_name, $field_name),
5070a65e412SManos Pitsidianakis             size: ::core::mem::size_of::<*const $type>(),
5080a65e412SManos Pitsidianakis             start: 0,
5090a65e412SManos Pitsidianakis             num: 0,
5100a65e412SManos Pitsidianakis             num_offset: 0,
5110a65e412SManos Pitsidianakis             size_offset: 0,
5120a65e412SManos Pitsidianakis             info: ::core::ptr::null(),
5130a65e412SManos Pitsidianakis             flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0),
5140a65e412SManos Pitsidianakis             vmsd: unsafe { $vmsd },
5150a65e412SManos Pitsidianakis             version_id: $version_id,
5160a65e412SManos Pitsidianakis             struct_version_id: 0,
5170a65e412SManos Pitsidianakis             field_exists: None,
5180a65e412SManos Pitsidianakis         }
5190a65e412SManos Pitsidianakis     }};
5200a65e412SManos Pitsidianakis }
5210a65e412SManos Pitsidianakis 
5220a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_ARRAY_OF_POINTER")]
5230a65e412SManos Pitsidianakis #[macro_export]
5240a65e412SManos Pitsidianakis macro_rules! vmstate_array_of_pointer {
5250a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $info:expr, $type:ty) => {{
5260a65e412SManos Pitsidianakis         $crate::bindings::VMStateField {
5270a65e412SManos Pitsidianakis             name: ::core::concat!(::core::stringify!($field_name), 0)
5280a65e412SManos Pitsidianakis                 .as_bytes()
5299f7d4520SPaolo Bonzini                 .as_ptr() as *const ::std::os::raw::c_char,
5300a65e412SManos Pitsidianakis             version_id: $version_id,
5310a65e412SManos Pitsidianakis             num: $num as _,
5320a65e412SManos Pitsidianakis             info: unsafe { $info },
5330a65e412SManos Pitsidianakis             size: ::core::mem::size_of::<*const $type>(),
5340a65e412SManos Pitsidianakis             flags: VMStateFlags(VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0),
535f3518400SJunjie Mao             offset: $crate::offset_of!($struct_name, $field_name),
5360a65e412SManos Pitsidianakis             err_hint: ::core::ptr::null(),
5370a65e412SManos Pitsidianakis             start: 0,
5380a65e412SManos Pitsidianakis             num_offset: 0,
5390a65e412SManos Pitsidianakis             size_offset: 0,
5400a65e412SManos Pitsidianakis             vmsd: ::core::ptr::null(),
5410a65e412SManos Pitsidianakis             struct_version_id: 0,
5420a65e412SManos Pitsidianakis             field_exists: None,
5430a65e412SManos Pitsidianakis         }
5440a65e412SManos Pitsidianakis     }};
5450a65e412SManos Pitsidianakis }
5460a65e412SManos Pitsidianakis 
5470a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_ARRAY_OF_POINTER_TO_STRUCT")]
5480a65e412SManos Pitsidianakis #[macro_export]
5490a65e412SManos Pitsidianakis macro_rules! vmstate_array_of_pointer_to_struct {
5500a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $vmsd:expr, $type:ty) => {{
5510a65e412SManos Pitsidianakis         $crate::bindings::VMStateField {
5520a65e412SManos Pitsidianakis             name: ::core::concat!(::core::stringify!($field_name), 0)
5530a65e412SManos Pitsidianakis                 .as_bytes()
5549f7d4520SPaolo Bonzini                 .as_ptr() as *const ::std::os::raw::c_char,
5550a65e412SManos Pitsidianakis             version_id: $version_id,
5560a65e412SManos Pitsidianakis             num: $num as _,
5570a65e412SManos Pitsidianakis             vmsd: unsafe { $vmsd },
5580a65e412SManos Pitsidianakis             size: ::core::mem::size_of::<*const $type>(),
5590a65e412SManos Pitsidianakis             flags: VMStateFlags(
5600a65e412SManos Pitsidianakis                 VMStateFlags::VMS_ARRAY.0
5610a65e412SManos Pitsidianakis                     | VMStateFlags::VMS_STRUCT.0
5620a65e412SManos Pitsidianakis                     | VMStateFlags::VMS_ARRAY_OF_POINTER.0,
5630a65e412SManos Pitsidianakis             ),
564f3518400SJunjie Mao             offset: $crate::offset_of!($struct_name, $field_name),
5650a65e412SManos Pitsidianakis             err_hint: ::core::ptr::null(),
5660a65e412SManos Pitsidianakis             start: 0,
5670a65e412SManos Pitsidianakis             num_offset: 0,
5680a65e412SManos Pitsidianakis             size_offset: 0,
5690a65e412SManos Pitsidianakis             vmsd: ::core::ptr::null(),
5700a65e412SManos Pitsidianakis             struct_version_id: 0,
5710a65e412SManos Pitsidianakis             field_exists: None,
5720a65e412SManos Pitsidianakis         }
5730a65e412SManos Pitsidianakis     }};
5740a65e412SManos Pitsidianakis }
5750a65e412SManos Pitsidianakis 
5760a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_CLOCK_V")]
5770a65e412SManos Pitsidianakis #[macro_export]
5780a65e412SManos Pitsidianakis macro_rules! vmstate_clock_v {
5790a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty, $version_id:expr) => {{
5800a65e412SManos Pitsidianakis         $crate::vmstate_struct_pointer_v!(
5810a65e412SManos Pitsidianakis             $field_name,
5820a65e412SManos Pitsidianakis             $struct_name,
5830a65e412SManos Pitsidianakis             $version_id,
5840a65e412SManos Pitsidianakis             ::core::ptr::addr_of!($crate::bindings::vmstate_clock),
5850a65e412SManos Pitsidianakis             $crate::bindings::Clock
5860a65e412SManos Pitsidianakis         )
5870a65e412SManos Pitsidianakis     }};
5880a65e412SManos Pitsidianakis }
5890a65e412SManos Pitsidianakis 
5900a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_CLOCK")]
5910a65e412SManos Pitsidianakis #[macro_export]
5920a65e412SManos Pitsidianakis macro_rules! vmstate_clock {
5930a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty) => {{
5940a65e412SManos Pitsidianakis         $crate::vmstate_clock_v!($field_name, $struct_name, 0)
5950a65e412SManos Pitsidianakis     }};
5960a65e412SManos Pitsidianakis }
5970a65e412SManos Pitsidianakis 
5980a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_ARRAY_CLOCK_V")]
5990a65e412SManos Pitsidianakis #[macro_export]
6000a65e412SManos Pitsidianakis macro_rules! vmstate_array_clock_v {
6010a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr) => {{
6020a65e412SManos Pitsidianakis         $crate::vmstate_array_of_pointer_to_struct!(
6030a65e412SManos Pitsidianakis             $field_name,
6040a65e412SManos Pitsidianakis             $struct_name,
6050a65e412SManos Pitsidianakis             $num,
6060a65e412SManos Pitsidianakis             $version_id,
6070a65e412SManos Pitsidianakis             ::core::ptr::addr_of!($crate::bindings::vmstate_clock),
6080a65e412SManos Pitsidianakis             $crate::bindings::Clock
6090a65e412SManos Pitsidianakis         )
6100a65e412SManos Pitsidianakis     }};
6110a65e412SManos Pitsidianakis }
6120a65e412SManos Pitsidianakis 
6130a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_ARRAY_CLOCK")]
6140a65e412SManos Pitsidianakis #[macro_export]
6150a65e412SManos Pitsidianakis macro_rules! vmstate_array_clock {
6160a65e412SManos Pitsidianakis     ($field_name:ident, $struct_name:ty, $num:expr) => {{
6170a65e412SManos Pitsidianakis         $crate::vmstate_array_clock_v!($field_name, $struct_name, $name, 0)
6180a65e412SManos Pitsidianakis     }};
6190a65e412SManos Pitsidianakis }
6200a65e412SManos Pitsidianakis 
6210a65e412SManos Pitsidianakis /// Helper macro to declare a list of
6220a65e412SManos Pitsidianakis /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return
6230a65e412SManos Pitsidianakis /// a pointer to the array of values it created.
6240a65e412SManos Pitsidianakis #[macro_export]
6250a65e412SManos Pitsidianakis macro_rules! vmstate_fields {
6260a65e412SManos Pitsidianakis     ($($field:expr),*$(,)*) => {{
6270a65e412SManos Pitsidianakis         static _FIELDS: &[$crate::bindings::VMStateField] = &[
6280a65e412SManos Pitsidianakis             $($field),*,
6290a65e412SManos Pitsidianakis             $crate::bindings::VMStateField {
6302537f830SPaolo Bonzini                 flags: $crate::bindings::VMStateFlags::VMS_END,
6312537f830SPaolo Bonzini                 ..$crate::zeroable::Zeroable::ZERO
6320a65e412SManos Pitsidianakis             }
6330a65e412SManos Pitsidianakis         ];
6340a65e412SManos Pitsidianakis         _FIELDS.as_ptr()
6350a65e412SManos Pitsidianakis     }}
6360a65e412SManos Pitsidianakis }
6370a65e412SManos Pitsidianakis 
6380a65e412SManos Pitsidianakis /// A transparent wrapper type for the `subsections` field of
639716d89f9SPaolo Bonzini /// [`VMStateDescription`].
6400a65e412SManos Pitsidianakis ///
6410a65e412SManos Pitsidianakis /// This is necessary to be able to declare subsection descriptions as statics,
6420a65e412SManos Pitsidianakis /// because the only way to implement `Sync` for a foreign type (and `*const`
6430a65e412SManos Pitsidianakis /// pointers are foreign types in Rust) is to create a wrapper struct and
6440a65e412SManos Pitsidianakis /// `unsafe impl Sync` for it.
6450a65e412SManos Pitsidianakis ///
6460a65e412SManos Pitsidianakis /// This struct is used in the
6470a65e412SManos Pitsidianakis /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation.
6480a65e412SManos Pitsidianakis #[repr(transparent)]
6490a65e412SManos Pitsidianakis pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]);
6500a65e412SManos Pitsidianakis 
6510a65e412SManos Pitsidianakis unsafe impl Sync for VMStateSubsectionsWrapper {}
6520a65e412SManos Pitsidianakis 
653716d89f9SPaolo Bonzini /// Helper macro to declare a list of subsections ([`VMStateDescription`])
654716d89f9SPaolo Bonzini /// into a static and return a pointer to the array of pointers it created.
6550a65e412SManos Pitsidianakis #[macro_export]
6560a65e412SManos Pitsidianakis macro_rules! vmstate_subsections {
6570a65e412SManos Pitsidianakis     ($($subsection:expr),*$(,)*) => {{
6580a65e412SManos Pitsidianakis         static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[
6590a65e412SManos Pitsidianakis             $({
6600a65e412SManos Pitsidianakis                 static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection;
6610a65e412SManos Pitsidianakis                 ::core::ptr::addr_of!(_SUBSECTION)
6620a65e412SManos Pitsidianakis             }),*,
6630a65e412SManos Pitsidianakis             ::core::ptr::null()
6640a65e412SManos Pitsidianakis         ]);
6650a65e412SManos Pitsidianakis         _SUBSECTIONS.0.as_ptr()
6660a65e412SManos Pitsidianakis     }}
6670a65e412SManos Pitsidianakis }
668