xref: /qemu/rust/qemu-api/src/vmstate.rs (revision 98721058d6d50ef218e0c26e4f67c8ef96965859)
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 //!
700f89716SPaolo Bonzini //! This module includes four 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,
12*aef5ac86SZhao Liu //!   which is defined by all migratable types.
130d43ddaeSPaolo Bonzini //!
1400f89716SPaolo Bonzini //! * [`impl_vmstate_forward`](crate::impl_vmstate_forward) and
1500f89716SPaolo Bonzini //!   [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), which help with
1600f89716SPaolo Bonzini //!   the definition of the [`VMState`] trait (respectively for transparent
1700f89716SPaolo Bonzini //!   structs and for `bilge`-defined types)
1800f89716SPaolo Bonzini //!
190d43ddaeSPaolo Bonzini //! * helper macros to declare a device model state struct, in particular
200a65e412SManos Pitsidianakis //!   [`vmstate_subsections`](crate::vmstate_subsections) and
210d43ddaeSPaolo Bonzini //!   [`vmstate_fields`](crate::vmstate_fields).
220d43ddaeSPaolo Bonzini //!
230d43ddaeSPaolo Bonzini //! * direct equivalents to the C macros declared in
249d489949SPaolo Bonzini //!   `include/migration/vmstate.h`. These are not type-safe and only provide
259d489949SPaolo Bonzini //!   functionality that is missing from `vmstate_of!`.
260a65e412SManos Pitsidianakis 
2780aa3045SPaolo Bonzini use core::{marker::PhantomData, mem, ptr::NonNull};
28e4fb0be1SPaolo Bonzini use std::ffi::{c_int, c_void};
290d43ddaeSPaolo Bonzini 
300d43ddaeSPaolo Bonzini pub use crate::bindings::{VMStateDescription, VMStateField};
31b1310037SZhao Liu use crate::{
32b1310037SZhao Liu     bindings::VMStateFlags, callbacks::FnCall, prelude::*, qom::Owned, zeroable::Zeroable,
33b1310037SZhao Liu };
340d43ddaeSPaolo Bonzini 
350d43ddaeSPaolo Bonzini /// This macro is used to call a function with a generic argument bound
360d43ddaeSPaolo Bonzini /// to the type of a field.  The function must take a
370d43ddaeSPaolo Bonzini /// [`PhantomData`]`<T>` argument; `T` is the type of
380d43ddaeSPaolo Bonzini /// field `$field` in the `$typ` type.
390d43ddaeSPaolo Bonzini ///
400d43ddaeSPaolo Bonzini /// # Examples
410d43ddaeSPaolo Bonzini ///
420d43ddaeSPaolo Bonzini /// ```
430d43ddaeSPaolo Bonzini /// # use qemu_api::call_func_with_field;
440d43ddaeSPaolo Bonzini /// # use core::marker::PhantomData;
450d43ddaeSPaolo Bonzini /// const fn size_of_field<T>(_: PhantomData<T>) -> usize {
460d43ddaeSPaolo Bonzini ///     std::mem::size_of::<T>()
470d43ddaeSPaolo Bonzini /// }
480d43ddaeSPaolo Bonzini ///
490d43ddaeSPaolo Bonzini /// struct Foo {
500d43ddaeSPaolo Bonzini ///     x: u16,
510d43ddaeSPaolo Bonzini /// };
520d43ddaeSPaolo Bonzini /// // calls size_of_field::<u16>()
530d43ddaeSPaolo Bonzini /// assert_eq!(call_func_with_field!(size_of_field, Foo, x), 2);
540d43ddaeSPaolo Bonzini /// ```
550d43ddaeSPaolo Bonzini #[macro_export]
560d43ddaeSPaolo Bonzini macro_rules! call_func_with_field {
570d43ddaeSPaolo Bonzini     // Based on the answer by user steffahn (Frank Steffahn) at
580d43ddaeSPaolo Bonzini     // https://users.rust-lang.org/t/inferring-type-of-field/122857
590d43ddaeSPaolo Bonzini     // and used under MIT license
600d43ddaeSPaolo Bonzini     ($func:expr, $typ:ty, $($field:tt).+) => {
610d43ddaeSPaolo Bonzini         $func(loop {
620d43ddaeSPaolo Bonzini             #![allow(unreachable_code)]
630d43ddaeSPaolo Bonzini             const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> { ::core::marker::PhantomData }
640d43ddaeSPaolo Bonzini             // Unreachable code is exempt from checks on uninitialized values.
650d43ddaeSPaolo Bonzini             // Use that trick to infer the type of this PhantomData.
660d43ddaeSPaolo Bonzini             break ::core::marker::PhantomData;
670d43ddaeSPaolo Bonzini             break phantom__(&{ let value__: $typ; value__.$($field).+ });
680d43ddaeSPaolo Bonzini         })
690d43ddaeSPaolo Bonzini     };
700d43ddaeSPaolo Bonzini }
710d43ddaeSPaolo Bonzini 
72f2cb78bdSPaolo Bonzini /// Workaround for lack of `const_refs_static`: references to global variables
73f2cb78bdSPaolo Bonzini /// can be included in a `static`, but not in a `const`; unfortunately, this
74f2cb78bdSPaolo Bonzini /// is exactly what would go in the `VMStateField`'s `info` member.
75f2cb78bdSPaolo Bonzini ///
76f2cb78bdSPaolo Bonzini /// This enum contains the contents of the `VMStateField`'s `info` member,
77f2cb78bdSPaolo Bonzini /// but as an `enum` instead of a pointer.
78f2cb78bdSPaolo Bonzini #[allow(non_camel_case_types)]
79f2cb78bdSPaolo Bonzini pub enum VMStateFieldType {
80f2cb78bdSPaolo Bonzini     null,
81f2cb78bdSPaolo Bonzini     vmstate_info_bool,
82f2cb78bdSPaolo Bonzini     vmstate_info_int8,
83f2cb78bdSPaolo Bonzini     vmstate_info_int16,
84f2cb78bdSPaolo Bonzini     vmstate_info_int32,
85f2cb78bdSPaolo Bonzini     vmstate_info_int64,
86f2cb78bdSPaolo Bonzini     vmstate_info_uint8,
87f2cb78bdSPaolo Bonzini     vmstate_info_uint16,
88f2cb78bdSPaolo Bonzini     vmstate_info_uint32,
89f2cb78bdSPaolo Bonzini     vmstate_info_uint64,
90f2cb78bdSPaolo Bonzini     vmstate_info_timer,
91f2cb78bdSPaolo Bonzini }
92f2cb78bdSPaolo Bonzini 
93f2cb78bdSPaolo Bonzini /// Workaround for lack of `const_refs_static`.  Converts a `VMStateFieldType`
94f2cb78bdSPaolo Bonzini /// to a `*const VMStateInfo`, for inclusion in a `VMStateField`.
95f2cb78bdSPaolo Bonzini #[macro_export]
96f2cb78bdSPaolo Bonzini macro_rules! info_enum_to_ref {
97f2cb78bdSPaolo Bonzini     ($e:expr) => {
98f2cb78bdSPaolo Bonzini         unsafe {
99f2cb78bdSPaolo Bonzini             match $e {
100f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::null => ::core::ptr::null(),
101f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_bool => {
102f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_bool)
103f2cb78bdSPaolo Bonzini                 }
104f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_int8 => {
105f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int8)
106f2cb78bdSPaolo Bonzini                 }
107f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_int16 => {
108f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int16)
109f2cb78bdSPaolo Bonzini                 }
110f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_int32 => {
111f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int32)
112f2cb78bdSPaolo Bonzini                 }
113f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_int64 => {
114f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int64)
115f2cb78bdSPaolo Bonzini                 }
116f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_uint8 => {
117f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint8)
118f2cb78bdSPaolo Bonzini                 }
119f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_uint16 => {
120f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint16)
121f2cb78bdSPaolo Bonzini                 }
122f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_uint32 => {
123f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32)
124f2cb78bdSPaolo Bonzini                 }
125f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_uint64 => {
126f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint64)
127f2cb78bdSPaolo Bonzini                 }
128f2cb78bdSPaolo Bonzini                 $crate::vmstate::VMStateFieldType::vmstate_info_timer => {
129f2cb78bdSPaolo Bonzini                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_timer)
130f2cb78bdSPaolo Bonzini                 }
131f2cb78bdSPaolo Bonzini             }
132f2cb78bdSPaolo Bonzini         }
133f2cb78bdSPaolo Bonzini     };
134f2cb78bdSPaolo Bonzini }
135f2cb78bdSPaolo Bonzini 
1360d43ddaeSPaolo Bonzini /// A trait for types that can be included in a device's migration stream.  It
1370d43ddaeSPaolo Bonzini /// provides the base contents of a `VMStateField` (minus the name and offset).
1380d43ddaeSPaolo Bonzini ///
1390d43ddaeSPaolo Bonzini /// # Safety
1400d43ddaeSPaolo Bonzini ///
1410d43ddaeSPaolo Bonzini /// The contents of this trait go straight into structs that are parsed by C
14200f89716SPaolo Bonzini /// code and used to introspect into other structs.  Generally, you don't need
14300f89716SPaolo Bonzini /// to implement it except via macros that do it for you, such as
14400f89716SPaolo Bonzini /// `impl_vmstate_bitsized!`.
1450d43ddaeSPaolo Bonzini pub unsafe trait VMState {
146f2cb78bdSPaolo Bonzini     /// The `info` member of a `VMStateField` is a pointer and as such cannot
147f2cb78bdSPaolo Bonzini     /// yet be included in the [`BASE`](VMState::BASE) associated constant;
148f2cb78bdSPaolo Bonzini     /// this is only allowed by Rust 1.83.0 and newer.  For now, include the
149f2cb78bdSPaolo Bonzini     /// member as an enum which is stored in a separate constant.
150f2cb78bdSPaolo Bonzini     const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::null;
151f2cb78bdSPaolo Bonzini 
1520d43ddaeSPaolo Bonzini     /// The base contents of a `VMStateField` (minus the name and offset) for
1530d43ddaeSPaolo Bonzini     /// the type that is implementing the trait.
1540d43ddaeSPaolo Bonzini     const BASE: VMStateField;
1555b024b4eSPaolo Bonzini 
1565b024b4eSPaolo Bonzini     /// A flag that is added to another field's `VMStateField` to specify the
1575b024b4eSPaolo Bonzini     /// length's type in a variable-sized array.  If this is not a supported
1585b024b4eSPaolo Bonzini     /// type for the length (i.e. if it is not `u8`, `u16`, `u32`), using it
1595b024b4eSPaolo Bonzini     /// in a call to [`vmstate_of!`](crate::vmstate_of) will cause a
1605b024b4eSPaolo Bonzini     /// compile-time error.
1615b024b4eSPaolo Bonzini     const VARRAY_FLAG: VMStateFlags = {
1625b024b4eSPaolo Bonzini         panic!("invalid type for variable-sized array");
1635b024b4eSPaolo Bonzini     };
1640d43ddaeSPaolo Bonzini }
1650d43ddaeSPaolo Bonzini 
166f2cb78bdSPaolo Bonzini /// Internal utility function to retrieve a type's `VMStateFieldType`;
167f2cb78bdSPaolo Bonzini /// used by [`vmstate_of!`](crate::vmstate_of).
vmstate_scalar_type<T: VMState>(_: PhantomData<T>) -> VMStateFieldType168f2cb78bdSPaolo Bonzini pub const fn vmstate_scalar_type<T: VMState>(_: PhantomData<T>) -> VMStateFieldType {
169f2cb78bdSPaolo Bonzini     T::SCALAR_TYPE
170f2cb78bdSPaolo Bonzini }
171f2cb78bdSPaolo Bonzini 
1720d43ddaeSPaolo Bonzini /// Internal utility function to retrieve a type's `VMStateField`;
1730d43ddaeSPaolo Bonzini /// used by [`vmstate_of!`](crate::vmstate_of).
vmstate_base<T: VMState>(_: PhantomData<T>) -> VMStateField1740d43ddaeSPaolo Bonzini pub const fn vmstate_base<T: VMState>(_: PhantomData<T>) -> VMStateField {
1750d43ddaeSPaolo Bonzini     T::BASE
1760d43ddaeSPaolo Bonzini }
1770d43ddaeSPaolo Bonzini 
1785b024b4eSPaolo Bonzini /// Internal utility function to retrieve a type's `VMStateFlags` when it
1795b024b4eSPaolo Bonzini /// is used as the element count of a `VMSTATE_VARRAY`; used by
1805b024b4eSPaolo Bonzini /// [`vmstate_of!`](crate::vmstate_of).
vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags1815b024b4eSPaolo Bonzini pub const fn vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags {
1825b024b4eSPaolo Bonzini     T::VARRAY_FLAG
1835b024b4eSPaolo Bonzini }
1845b024b4eSPaolo Bonzini 
1850d43ddaeSPaolo Bonzini /// Return the `VMStateField` for a field of a struct.  The field must be
1860d43ddaeSPaolo Bonzini /// visible in the current scope.
1870d43ddaeSPaolo Bonzini ///
188f2cb78bdSPaolo Bonzini /// Only a limited set of types is supported out of the box:
189f2cb78bdSPaolo Bonzini /// * scalar types (integer and `bool`)
190f2cb78bdSPaolo Bonzini /// * the C struct `QEMUTimer`
191f2cb78bdSPaolo Bonzini /// * a transparent wrapper for any of the above (`Cell`, `UnsafeCell`,
192ee7d3aecSPaolo Bonzini ///   [`BqlCell`], [`BqlRefCell`]
193f2cb78bdSPaolo Bonzini /// * a raw pointer to any of the above
194ee7d3aecSPaolo Bonzini /// * a `NonNull` pointer, a `Box` or an [`Owned`] for any of the above
195f2cb78bdSPaolo Bonzini /// * an array of any of the above
196f2cb78bdSPaolo Bonzini ///
1970d43ddaeSPaolo Bonzini /// In order to support other types, the trait `VMState` must be implemented
19800f89716SPaolo Bonzini /// for them.  The macros
19900f89716SPaolo Bonzini /// [`impl_vmstate_bitsized!`](crate::impl_vmstate_bitsized)
20000f89716SPaolo Bonzini /// and [`impl_vmstate_forward!`](crate::impl_vmstate_forward) help with this.
2010d43ddaeSPaolo Bonzini #[macro_export]
2020d43ddaeSPaolo Bonzini macro_rules! vmstate_of {
2036f8e6aedSZhao Liu     ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(, $test_fn:expr)? $(,)?) => {
2040d43ddaeSPaolo Bonzini         $crate::bindings::VMStateField {
2050d43ddaeSPaolo Bonzini             name: ::core::concat!(::core::stringify!($field_name), "\0")
2060d43ddaeSPaolo Bonzini                 .as_bytes()
2070d43ddaeSPaolo Bonzini                 .as_ptr() as *const ::std::os::raw::c_char,
208b134a09fSPaolo Bonzini             offset: ::std::mem::offset_of!($struct_name, $field_name),
209b134a09fSPaolo Bonzini             $(num_offset: ::std::mem::offset_of!($struct_name, $num),)?
2106f8e6aedSZhao Liu             $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)?
211f2cb78bdSPaolo Bonzini             // The calls to `call_func_with_field!` are the magic that
212f2cb78bdSPaolo Bonzini             // computes most of the VMStateField from the type of the field.
213f2cb78bdSPaolo Bonzini             info: $crate::info_enum_to_ref!($crate::call_func_with_field!(
214f2cb78bdSPaolo Bonzini                 $crate::vmstate::vmstate_scalar_type,
215f2cb78bdSPaolo Bonzini                 $struct_name,
216f2cb78bdSPaolo Bonzini                 $field_name
217f2cb78bdSPaolo Bonzini             )),
2180d43ddaeSPaolo Bonzini             ..$crate::call_func_with_field!(
2190d43ddaeSPaolo Bonzini                 $crate::vmstate::vmstate_base,
2200d43ddaeSPaolo Bonzini                 $struct_name,
2210d43ddaeSPaolo Bonzini                 $field_name
2225b024b4eSPaolo Bonzini             )$(.with_varray_flag($crate::call_func_with_field!(
2235b024b4eSPaolo Bonzini                     $crate::vmstate::vmstate_varray_flag,
2245b024b4eSPaolo Bonzini                     $struct_name,
2255b024b4eSPaolo Bonzini                     $num))
2265b024b4eSPaolo Bonzini                $(.with_varray_multiply($factor))?)?
2270d43ddaeSPaolo Bonzini         }
2280d43ddaeSPaolo Bonzini     };
2290d43ddaeSPaolo Bonzini }
2300d43ddaeSPaolo Bonzini 
23180aa3045SPaolo Bonzini impl VMStateFlags {
23280aa3045SPaolo Bonzini     const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags(
23380aa3045SPaolo Bonzini         VMStateFlags::VMS_VARRAY_INT32.0
23480aa3045SPaolo Bonzini             | VMStateFlags::VMS_VARRAY_UINT8.0
23580aa3045SPaolo Bonzini             | VMStateFlags::VMS_VARRAY_UINT16.0
23680aa3045SPaolo Bonzini             | VMStateFlags::VMS_VARRAY_UINT32.0,
23780aa3045SPaolo Bonzini     );
23880aa3045SPaolo Bonzini }
23980aa3045SPaolo Bonzini 
2400d43ddaeSPaolo Bonzini // Add a couple builder-style methods to VMStateField, allowing
2410d43ddaeSPaolo Bonzini // easy derivation of VMStateField constants from other types.
2420d43ddaeSPaolo Bonzini impl VMStateField {
2430d43ddaeSPaolo Bonzini     #[must_use]
with_version_id(mut self, version_id: i32) -> Self2440d43ddaeSPaolo Bonzini     pub const fn with_version_id(mut self, version_id: i32) -> Self {
2450d43ddaeSPaolo Bonzini         assert!(version_id >= 0);
2460d43ddaeSPaolo Bonzini         self.version_id = version_id;
2470d43ddaeSPaolo Bonzini         self
2480d43ddaeSPaolo Bonzini     }
24980aa3045SPaolo Bonzini 
25080aa3045SPaolo Bonzini     #[must_use]
with_array_flag(mut self, num: usize) -> Self25180aa3045SPaolo Bonzini     pub const fn with_array_flag(mut self, num: usize) -> Self {
25280aa3045SPaolo Bonzini         assert!(num <= 0x7FFF_FFFFusize);
25380aa3045SPaolo Bonzini         assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) == 0);
25480aa3045SPaolo Bonzini         assert!((self.flags.0 & VMStateFlags::VMS_VARRAY_FLAGS.0) == 0);
25580aa3045SPaolo Bonzini         if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 {
25680aa3045SPaolo Bonzini             self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0);
25780aa3045SPaolo Bonzini             self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0);
25820797069SZhao Liu             // VMS_ARRAY_OF_POINTER flag stores the size of pointer.
25920797069SZhao Liu             // FIXME: *const, *mut, NonNull and Box<> have the same size as usize.
26020797069SZhao Liu             //        Resize if more smart pointers are supported.
26120797069SZhao Liu             self.size = std::mem::size_of::<usize>();
26280aa3045SPaolo Bonzini         }
26380aa3045SPaolo Bonzini         self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0);
26480aa3045SPaolo Bonzini         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0);
26580aa3045SPaolo Bonzini         self.num = num as i32;
26680aa3045SPaolo Bonzini         self
26780aa3045SPaolo Bonzini     }
26880aa3045SPaolo Bonzini 
26980aa3045SPaolo Bonzini     #[must_use]
with_pointer_flag(mut self) -> Self27080aa3045SPaolo Bonzini     pub const fn with_pointer_flag(mut self) -> Self {
27180aa3045SPaolo Bonzini         assert!((self.flags.0 & VMStateFlags::VMS_POINTER.0) == 0);
27280aa3045SPaolo Bonzini         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_POINTER.0);
27380aa3045SPaolo Bonzini         self
27480aa3045SPaolo Bonzini     }
2755b024b4eSPaolo Bonzini 
2765b024b4eSPaolo Bonzini     #[must_use]
with_varray_flag_unchecked(mut self, flag: VMStateFlags) -> VMStateField2775006e39cSZhao Liu     pub const fn with_varray_flag_unchecked(mut self, flag: VMStateFlags) -> VMStateField {
2785b024b4eSPaolo Bonzini         self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0);
2795b024b4eSPaolo Bonzini         self.flags = VMStateFlags(self.flags.0 | flag.0);
280c3d80af5SZhao Liu         self.num = 0; // varray uses num_offset instead of num.
2815b024b4eSPaolo Bonzini         self
2825b024b4eSPaolo Bonzini     }
2835b024b4eSPaolo Bonzini 
2845b024b4eSPaolo Bonzini     #[must_use]
2855006e39cSZhao Liu     #[allow(unused_mut)]
with_varray_flag(mut self, flag: VMStateFlags) -> VMStateField2865006e39cSZhao Liu     pub const fn with_varray_flag(mut self, flag: VMStateFlags) -> VMStateField {
2875006e39cSZhao Liu         assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0);
2885006e39cSZhao Liu         self.with_varray_flag_unchecked(flag)
2895006e39cSZhao Liu     }
2905006e39cSZhao Liu 
2915006e39cSZhao Liu     #[must_use]
with_varray_multiply(mut self, num: u32) -> VMStateField2925b024b4eSPaolo Bonzini     pub const fn with_varray_multiply(mut self, num: u32) -> VMStateField {
2935b024b4eSPaolo Bonzini         assert!(num <= 0x7FFF_FFFFu32);
2945b024b4eSPaolo Bonzini         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0);
2955b024b4eSPaolo Bonzini         self.num = num as i32;
2965b024b4eSPaolo Bonzini         self
2975b024b4eSPaolo Bonzini     }
29880aa3045SPaolo Bonzini }
29980aa3045SPaolo Bonzini 
30000f89716SPaolo Bonzini /// This macro can be used (by just passing it a type) to forward the `VMState`
30100f89716SPaolo Bonzini /// trait to the first field of a tuple.  This is a workaround for lack of
30200f89716SPaolo Bonzini /// support of nested [`offset_of`](core::mem::offset_of) until Rust 1.82.0.
30300f89716SPaolo Bonzini ///
30400f89716SPaolo Bonzini /// # Examples
30500f89716SPaolo Bonzini ///
30600f89716SPaolo Bonzini /// ```
30716534af5SPaolo Bonzini /// # use qemu_api::impl_vmstate_forward;
30800f89716SPaolo Bonzini /// pub struct Fifo([u8; 16]);
30900f89716SPaolo Bonzini /// impl_vmstate_forward!(Fifo);
31000f89716SPaolo Bonzini /// ```
31100f89716SPaolo Bonzini #[macro_export]
31200f89716SPaolo Bonzini macro_rules! impl_vmstate_forward {
31300f89716SPaolo Bonzini     // This is similar to impl_vmstate_transparent below, but it
31400f89716SPaolo Bonzini     // uses the same trick as vmstate_of! to obtain the type of
31500f89716SPaolo Bonzini     // the first field of the tuple
31600f89716SPaolo Bonzini     ($tuple:ty) => {
31700f89716SPaolo Bonzini         unsafe impl $crate::vmstate::VMState for $tuple {
31800f89716SPaolo Bonzini             const SCALAR_TYPE: $crate::vmstate::VMStateFieldType =
31900f89716SPaolo Bonzini                 $crate::call_func_with_field!($crate::vmstate::vmstate_scalar_type, $tuple, 0);
32000f89716SPaolo Bonzini             const BASE: $crate::bindings::VMStateField =
32100f89716SPaolo Bonzini                 $crate::call_func_with_field!($crate::vmstate::vmstate_base, $tuple, 0);
32200f89716SPaolo Bonzini         }
32300f89716SPaolo Bonzini     };
32400f89716SPaolo Bonzini }
32500f89716SPaolo Bonzini 
32680aa3045SPaolo Bonzini // Transparent wrappers: just use the internal type
32780aa3045SPaolo Bonzini 
32880aa3045SPaolo Bonzini macro_rules! impl_vmstate_transparent {
32980aa3045SPaolo Bonzini     ($type:ty where $base:tt: VMState $($where:tt)*) => {
33080aa3045SPaolo Bonzini         unsafe impl<$base> VMState for $type where $base: VMState $($where)* {
331f2cb78bdSPaolo Bonzini             const SCALAR_TYPE: VMStateFieldType = <$base as VMState>::SCALAR_TYPE;
33280aa3045SPaolo Bonzini             const BASE: VMStateField = VMStateField {
33380aa3045SPaolo Bonzini                 size: mem::size_of::<$type>(),
33480aa3045SPaolo Bonzini                 ..<$base as VMState>::BASE
33580aa3045SPaolo Bonzini             };
3365b024b4eSPaolo Bonzini             const VARRAY_FLAG: VMStateFlags = <$base as VMState>::VARRAY_FLAG;
33780aa3045SPaolo Bonzini         }
33880aa3045SPaolo Bonzini     };
33980aa3045SPaolo Bonzini }
34080aa3045SPaolo Bonzini 
34180aa3045SPaolo Bonzini impl_vmstate_transparent!(std::cell::Cell<T> where T: VMState);
34280aa3045SPaolo Bonzini impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState);
343d7f5ae8bSPaolo Bonzini impl_vmstate_transparent!(std::pin::Pin<T> where T: VMState);
34480aa3045SPaolo Bonzini impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState);
34580aa3045SPaolo Bonzini impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState);
3463baf82e0SZhao Liu impl_vmstate_transparent!(crate::cell::Opaque<T> where T: VMState);
34780aa3045SPaolo Bonzini 
34800f89716SPaolo Bonzini #[macro_export]
34900f89716SPaolo Bonzini macro_rules! impl_vmstate_bitsized {
35000f89716SPaolo Bonzini     ($type:ty) => {
35100f89716SPaolo Bonzini         unsafe impl $crate::vmstate::VMState for $type {
35200f89716SPaolo Bonzini             const SCALAR_TYPE: $crate::vmstate::VMStateFieldType =
35300f89716SPaolo Bonzini                                         <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
35400f89716SPaolo Bonzini                                           as ::bilge::prelude::Number>::UnderlyingType
35500f89716SPaolo Bonzini                                          as $crate::vmstate::VMState>::SCALAR_TYPE;
35600f89716SPaolo Bonzini             const BASE: $crate::bindings::VMStateField =
35700f89716SPaolo Bonzini                                         <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
35800f89716SPaolo Bonzini                                           as ::bilge::prelude::Number>::UnderlyingType
35900f89716SPaolo Bonzini                                          as $crate::vmstate::VMState>::BASE;
36000f89716SPaolo Bonzini             const VARRAY_FLAG: $crate::bindings::VMStateFlags =
36100f89716SPaolo Bonzini                                         <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
36200f89716SPaolo Bonzini                                           as ::bilge::prelude::Number>::UnderlyingType
36300f89716SPaolo Bonzini                                          as $crate::vmstate::VMState>::VARRAY_FLAG;
36400f89716SPaolo Bonzini         }
36500f89716SPaolo Bonzini     };
36600f89716SPaolo Bonzini }
36700f89716SPaolo Bonzini 
368f2cb78bdSPaolo Bonzini // Scalar types using predefined VMStateInfos
369f2cb78bdSPaolo Bonzini 
370f2cb78bdSPaolo Bonzini macro_rules! impl_vmstate_scalar {
371f2cb78bdSPaolo Bonzini     ($info:ident, $type:ty$(, $varray_flag:ident)?) => {
372f2cb78bdSPaolo Bonzini         unsafe impl VMState for $type {
373f2cb78bdSPaolo Bonzini             const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::$info;
374f2cb78bdSPaolo Bonzini             const BASE: VMStateField = VMStateField {
375f2cb78bdSPaolo Bonzini                 size: mem::size_of::<$type>(),
376f2cb78bdSPaolo Bonzini                 flags: VMStateFlags::VMS_SINGLE,
377f2cb78bdSPaolo Bonzini                 ..Zeroable::ZERO
378f2cb78bdSPaolo Bonzini             };
379f2cb78bdSPaolo Bonzini             $(const VARRAY_FLAG: VMStateFlags = VMStateFlags::$varray_flag;)?
380f2cb78bdSPaolo Bonzini         }
381f2cb78bdSPaolo Bonzini     };
382f2cb78bdSPaolo Bonzini }
383f2cb78bdSPaolo Bonzini 
384f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_bool, bool);
385f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_int8, i8);
386f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_int16, i16);
387f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_int32, i32);
388f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_int64, i64);
389f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY_UINT8);
390f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY_UINT16);
391f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY_UINT32);
392f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_uint64, u64);
3933baf82e0SZhao Liu impl_vmstate_scalar!(vmstate_info_timer, crate::timer::Timer);
394f2cb78bdSPaolo Bonzini 
39580aa3045SPaolo Bonzini // Pointer types using the underlying type's VMState plus VMS_POINTER
39680aa3045SPaolo Bonzini // Note that references are not supported, though references to cells
39780aa3045SPaolo Bonzini // could be allowed.
39880aa3045SPaolo Bonzini 
39980aa3045SPaolo Bonzini macro_rules! impl_vmstate_pointer {
40080aa3045SPaolo Bonzini     ($type:ty where $base:tt: VMState $($where:tt)*) => {
40180aa3045SPaolo Bonzini         unsafe impl<$base> VMState for $type where $base: VMState $($where)* {
402f2cb78bdSPaolo Bonzini             const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE;
40380aa3045SPaolo Bonzini             const BASE: VMStateField = <$base as VMState>::BASE.with_pointer_flag();
40480aa3045SPaolo Bonzini         }
40580aa3045SPaolo Bonzini     };
40680aa3045SPaolo Bonzini }
40780aa3045SPaolo Bonzini 
40880aa3045SPaolo Bonzini impl_vmstate_pointer!(*const T where T: VMState);
40980aa3045SPaolo Bonzini impl_vmstate_pointer!(*mut T where T: VMState);
41080aa3045SPaolo Bonzini impl_vmstate_pointer!(NonNull<T> where T: VMState);
41180aa3045SPaolo Bonzini 
41280aa3045SPaolo Bonzini // Unlike C pointers, Box is always non-null therefore there is no need
41380aa3045SPaolo Bonzini // to specify VMS_ALLOC.
41480aa3045SPaolo Bonzini impl_vmstate_pointer!(Box<T> where T: VMState);
4150fcccf3fSPaolo Bonzini impl_vmstate_pointer!(Owned<T> where T: VMState + ObjectType);
41680aa3045SPaolo Bonzini 
41780aa3045SPaolo Bonzini // Arrays using the underlying type's VMState plus
41880aa3045SPaolo Bonzini // VMS_ARRAY/VMS_ARRAY_OF_POINTER
41980aa3045SPaolo Bonzini 
42080aa3045SPaolo Bonzini unsafe impl<T: VMState, const N: usize> VMState for [T; N] {
421f2cb78bdSPaolo Bonzini     const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE;
42280aa3045SPaolo Bonzini     const BASE: VMStateField = <T as VMState>::BASE.with_array_flag(N);
4230d43ddaeSPaolo Bonzini }
424716d89f9SPaolo Bonzini 
4250a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_UNUSED")]
4260a65e412SManos Pitsidianakis #[macro_export]
4270a65e412SManos Pitsidianakis macro_rules! vmstate_unused {
4280a65e412SManos Pitsidianakis     ($size:expr) => {{
4290a65e412SManos Pitsidianakis         $crate::bindings::VMStateField {
430f117857bSPaolo Bonzini             name: c"unused".as_ptr(),
4310a65e412SManos Pitsidianakis             size: $size,
4329d489949SPaolo Bonzini             info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) },
4339d489949SPaolo Bonzini             flags: $crate::bindings::VMStateFlags::VMS_BUFFER,
4349d489949SPaolo Bonzini             ..$crate::zeroable::Zeroable::ZERO
4350a65e412SManos Pitsidianakis         }
4360a65e412SManos Pitsidianakis     }};
4370a65e412SManos Pitsidianakis }
4380a65e412SManos Pitsidianakis 
rust_vms_test_field_exists<T, F: for<'a> FnCall<(&'a T, u8), bool>>( opaque: *mut c_void, version_id: c_int, ) -> bool4396f8e6aedSZhao Liu pub extern "C" fn rust_vms_test_field_exists<T, F: for<'a> FnCall<(&'a T, u8), bool>>(
4406f8e6aedSZhao Liu     opaque: *mut c_void,
4416f8e6aedSZhao Liu     version_id: c_int,
4426f8e6aedSZhao Liu ) -> bool {
4436f8e6aedSZhao Liu     // SAFETY: the opaque was passed as a reference to `T`.
4446f8e6aedSZhao Liu     let owner: &T = unsafe { &*(opaque.cast::<T>()) };
4456f8e6aedSZhao Liu     let version: u8 = version_id.try_into().unwrap();
4466f8e6aedSZhao Liu     F::call((owner, version))
4476f8e6aedSZhao Liu }
4486f8e6aedSZhao Liu 
4496f8e6aedSZhao Liu pub type VMSFieldExistCb = unsafe extern "C" fn(
4506f8e6aedSZhao Liu     opaque: *mut std::os::raw::c_void,
4516f8e6aedSZhao Liu     version_id: std::os::raw::c_int,
4526f8e6aedSZhao Liu ) -> bool;
4536f8e6aedSZhao Liu 
4546f8e6aedSZhao Liu #[macro_export]
4556f8e6aedSZhao Liu macro_rules! vmstate_exist_fn {
4566f8e6aedSZhao Liu     ($struct_name:ty, $test_fn:expr) => {{
4576f8e6aedSZhao Liu         const fn test_cb_builder__<T, F: for<'a> $crate::callbacks::FnCall<(&'a T, u8), bool>>(
4586f8e6aedSZhao Liu             _phantom: ::core::marker::PhantomData<F>,
4596f8e6aedSZhao Liu         ) -> $crate::vmstate::VMSFieldExistCb {
4606f8e6aedSZhao Liu             let _: () = F::ASSERT_IS_SOME;
4616f8e6aedSZhao Liu             $crate::vmstate::rust_vms_test_field_exists::<T, F>
4626f8e6aedSZhao Liu         }
4636f8e6aedSZhao Liu 
4646f8e6aedSZhao Liu         const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> {
4656f8e6aedSZhao Liu             ::core::marker::PhantomData
4666f8e6aedSZhao Liu         }
4676f8e6aedSZhao Liu         Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn)))
4686f8e6aedSZhao Liu     }};
4696f8e6aedSZhao Liu }
4706f8e6aedSZhao Liu 
4719a2ba488SPaolo Bonzini // FIXME: including the `vmsd` field in a `const` is not possible without
4729a2ba488SPaolo Bonzini // the const_refs_static feature (stabilized in Rust 1.83.0).  Without it,
4739a2ba488SPaolo Bonzini // it is not possible to use VMS_STRUCT in a transparent manner using
4749a2ba488SPaolo Bonzini // `vmstate_of!`.  While VMSTATE_CLOCK can at least try to be type-safe,
4759a2ba488SPaolo Bonzini // VMSTATE_STRUCT includes $type only for documentation purposes; it
4769a2ba488SPaolo Bonzini // is checked against $field_name and $struct_name, but not against $vmsd
4779a2ba488SPaolo Bonzini // which is what really would matter.
4789a2ba488SPaolo Bonzini #[doc(alias = "VMSTATE_STRUCT")]
4799a2ba488SPaolo Bonzini #[macro_export]
4809a2ba488SPaolo Bonzini macro_rules! vmstate_struct {
4816f8e6aedSZhao Liu     ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(, $test_fn:expr)? $(,)?) => {
4829a2ba488SPaolo Bonzini         $crate::bindings::VMStateField {
4839a2ba488SPaolo Bonzini             name: ::core::concat!(::core::stringify!($field_name), "\0")
4849a2ba488SPaolo Bonzini                 .as_bytes()
4859a2ba488SPaolo Bonzini                 .as_ptr() as *const ::std::os::raw::c_char,
486b134a09fSPaolo Bonzini             $(num_offset: ::std::mem::offset_of!($struct_name, $num),)?
4879a2ba488SPaolo Bonzini             offset: {
48861825825SZhao Liu                 $crate::assert_field_type!($struct_name, $field_name, $type $(, num = $num)?);
489b134a09fSPaolo Bonzini                 ::std::mem::offset_of!($struct_name, $field_name)
4909a2ba488SPaolo Bonzini             },
4919a2ba488SPaolo Bonzini             size: ::core::mem::size_of::<$type>(),
4929a2ba488SPaolo Bonzini             flags: $crate::bindings::VMStateFlags::VMS_STRUCT,
493ea8a7cebSZhao Liu             vmsd: $vmsd,
4946f8e6aedSZhao Liu             $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)?
49542c814b1SZhao Liu             ..$crate::zeroable::Zeroable::ZERO
4965006e39cSZhao Liu          } $(.with_varray_flag_unchecked(
49742c814b1SZhao Liu                   $crate::call_func_with_field!(
4989a2ba488SPaolo Bonzini                       $crate::vmstate::vmstate_varray_flag,
4999a2ba488SPaolo Bonzini                       $struct_name,
50042c814b1SZhao Liu                       $num
50142c814b1SZhao Liu                   )
50242c814b1SZhao Liu               )
5039a2ba488SPaolo Bonzini            $(.with_varray_multiply($factor))?)?
5049a2ba488SPaolo Bonzini     };
5059a2ba488SPaolo Bonzini }
5069a2ba488SPaolo Bonzini 
5070a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_CLOCK")]
5080a65e412SManos Pitsidianakis #[macro_export]
5090a65e412SManos Pitsidianakis macro_rules! vmstate_clock {
510756ea88fSPaolo Bonzini     ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?) => {{
5119d489949SPaolo Bonzini         $crate::bindings::VMStateField {
5129d489949SPaolo Bonzini             name: ::core::concat!(::core::stringify!($field_name), "\0")
5139d489949SPaolo Bonzini                 .as_bytes()
5149d489949SPaolo Bonzini                 .as_ptr() as *const ::std::os::raw::c_char,
5159d489949SPaolo Bonzini             offset: {
5169d489949SPaolo Bonzini                 $crate::assert_field_type!(
5170a65e412SManos Pitsidianakis                     $struct_name,
5189d489949SPaolo Bonzini                     $field_name,
519756ea88fSPaolo Bonzini                     $crate::qom::Owned<$crate::qdev::Clock> $(, num = $num)?
5209d489949SPaolo Bonzini                 );
521b134a09fSPaolo Bonzini                 ::std::mem::offset_of!($struct_name, $field_name)
5229d489949SPaolo Bonzini             },
523201ef001SPaolo Bonzini             size: ::core::mem::size_of::<*const $crate::qdev::Clock>(),
524f7b87e46SZhao Liu             flags: $crate::bindings::VMStateFlags(
525f7b87e46SZhao Liu                 $crate::bindings::VMStateFlags::VMS_STRUCT.0
526f7b87e46SZhao Liu                     | $crate::bindings::VMStateFlags::VMS_POINTER.0,
527f7b87e46SZhao Liu             ),
5289d489949SPaolo Bonzini             vmsd: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_clock) },
5299d489949SPaolo Bonzini             ..$crate::zeroable::Zeroable::ZERO
530756ea88fSPaolo Bonzini          } $(.with_varray_flag_unchecked(
531756ea88fSPaolo Bonzini                   $crate::call_func_with_field!(
532756ea88fSPaolo Bonzini                       $crate::vmstate::vmstate_varray_flag,
533756ea88fSPaolo Bonzini                       $struct_name,
534756ea88fSPaolo Bonzini                       $num
535756ea88fSPaolo Bonzini                   )
536756ea88fSPaolo Bonzini               )
537756ea88fSPaolo Bonzini            $(.with_varray_multiply($factor))?)?
5380a65e412SManos Pitsidianakis     }};
5390a65e412SManos Pitsidianakis }
5400a65e412SManos Pitsidianakis 
5410a65e412SManos Pitsidianakis /// Helper macro to declare a list of
5420a65e412SManos Pitsidianakis /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return
5430a65e412SManos Pitsidianakis /// a pointer to the array of values it created.
5440a65e412SManos Pitsidianakis #[macro_export]
5450a65e412SManos Pitsidianakis macro_rules! vmstate_fields {
5460a65e412SManos Pitsidianakis     ($($field:expr),*$(,)*) => {{
5470a65e412SManos Pitsidianakis         static _FIELDS: &[$crate::bindings::VMStateField] = &[
5480a65e412SManos Pitsidianakis             $($field),*,
5490a65e412SManos Pitsidianakis             $crate::bindings::VMStateField {
5502537f830SPaolo Bonzini                 flags: $crate::bindings::VMStateFlags::VMS_END,
5512537f830SPaolo Bonzini                 ..$crate::zeroable::Zeroable::ZERO
5520a65e412SManos Pitsidianakis             }
5530a65e412SManos Pitsidianakis         ];
5540a65e412SManos Pitsidianakis         _FIELDS.as_ptr()
5550a65e412SManos Pitsidianakis     }}
5560a65e412SManos Pitsidianakis }
5570a65e412SManos Pitsidianakis 
558b1310037SZhao Liu #[doc(alias = "VMSTATE_VALIDATE")]
559b1310037SZhao Liu #[macro_export]
560b1310037SZhao Liu macro_rules! vmstate_validate {
561b1310037SZhao Liu     ($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => {
562b1310037SZhao Liu         $crate::bindings::VMStateField {
563b1310037SZhao Liu             name: ::std::ffi::CStr::as_ptr($test_name),
5646f8e6aedSZhao Liu             field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),
565b1310037SZhao Liu             flags: $crate::bindings::VMStateFlags(
566b1310037SZhao Liu                 $crate::bindings::VMStateFlags::VMS_MUST_EXIST.0
567b1310037SZhao Liu                     | $crate::bindings::VMStateFlags::VMS_ARRAY.0,
568b1310037SZhao Liu             ),
569b1310037SZhao Liu             num: 0, // 0 elements: no data, only run test_fn callback
570b1310037SZhao Liu             ..$crate::zeroable::Zeroable::ZERO
571b1310037SZhao Liu         }
572b1310037SZhao Liu     };
573b1310037SZhao Liu }
574b1310037SZhao Liu 
5750a65e412SManos Pitsidianakis /// A transparent wrapper type for the `subsections` field of
576716d89f9SPaolo Bonzini /// [`VMStateDescription`].
5770a65e412SManos Pitsidianakis ///
5780a65e412SManos Pitsidianakis /// This is necessary to be able to declare subsection descriptions as statics,
5790a65e412SManos Pitsidianakis /// because the only way to implement `Sync` for a foreign type (and `*const`
5800a65e412SManos Pitsidianakis /// pointers are foreign types in Rust) is to create a wrapper struct and
5810a65e412SManos Pitsidianakis /// `unsafe impl Sync` for it.
5820a65e412SManos Pitsidianakis ///
5830a65e412SManos Pitsidianakis /// This struct is used in the
5840a65e412SManos Pitsidianakis /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation.
5850a65e412SManos Pitsidianakis #[repr(transparent)]
5860a65e412SManos Pitsidianakis pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]);
5870a65e412SManos Pitsidianakis 
5880a65e412SManos Pitsidianakis unsafe impl Sync for VMStateSubsectionsWrapper {}
5890a65e412SManos Pitsidianakis 
590716d89f9SPaolo Bonzini /// Helper macro to declare a list of subsections ([`VMStateDescription`])
591716d89f9SPaolo Bonzini /// into a static and return a pointer to the array of pointers it created.
5920a65e412SManos Pitsidianakis #[macro_export]
5930a65e412SManos Pitsidianakis macro_rules! vmstate_subsections {
5940a65e412SManos Pitsidianakis     ($($subsection:expr),*$(,)*) => {{
5950a65e412SManos Pitsidianakis         static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[
5960a65e412SManos Pitsidianakis             $({
5970a65e412SManos Pitsidianakis                 static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection;
5980a65e412SManos Pitsidianakis                 ::core::ptr::addr_of!(_SUBSECTION)
5990a65e412SManos Pitsidianakis             }),*,
6000a65e412SManos Pitsidianakis             ::core::ptr::null()
6010a65e412SManos Pitsidianakis         ]);
6020a65e412SManos Pitsidianakis         _SUBSECTIONS.0.as_ptr()
6030a65e412SManos Pitsidianakis     }}
6040a65e412SManos Pitsidianakis }
605