xref: /qemu/rust/qemu-api/src/vmstate.rs (revision 9a2ba4882d320a650b4f98f92b49bb45956d227e)
1 // Copyright 2024, Linaro Limited
2 // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 
5 //! Helper macros to declare migration state for device models.
6 //!
7 //! This module includes four families of macros:
8 //!
9 //! * [`vmstate_unused!`](crate::vmstate_unused) and
10 //!   [`vmstate_of!`](crate::vmstate_of), which are used to express the
11 //!   migration format for a struct.  This is based on the [`VMState`] trait,
12 //!   which is defined by all migrateable types.
13 //!
14 //! * [`impl_vmstate_forward`](crate::impl_vmstate_forward) and
15 //!   [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), which help with
16 //!   the definition of the [`VMState`] trait (respectively for transparent
17 //!   structs and for `bilge`-defined types)
18 //!
19 //! * helper macros to declare a device model state struct, in particular
20 //!   [`vmstate_subsections`](crate::vmstate_subsections) and
21 //!   [`vmstate_fields`](crate::vmstate_fields).
22 //!
23 //! * direct equivalents to the C macros declared in
24 //!   `include/migration/vmstate.h`. These are not type-safe and should not be
25 //!   used if the equivalent functionality is available with `vmstate_of!`.
26 
27 use core::{marker::PhantomData, mem, ptr::NonNull};
28 
29 pub use crate::bindings::{VMStateDescription, VMStateField};
30 use crate::{
31     bindings::{self, VMStateFlags},
32     zeroable::Zeroable,
33 };
34 
35 /// This macro is used to call a function with a generic argument bound
36 /// to the type of a field.  The function must take a
37 /// [`PhantomData`]`<T>` argument; `T` is the type of
38 /// field `$field` in the `$typ` type.
39 ///
40 /// # Examples
41 ///
42 /// ```
43 /// # use qemu_api::call_func_with_field;
44 /// # use core::marker::PhantomData;
45 /// const fn size_of_field<T>(_: PhantomData<T>) -> usize {
46 ///     std::mem::size_of::<T>()
47 /// }
48 ///
49 /// struct Foo {
50 ///     x: u16,
51 /// };
52 /// // calls size_of_field::<u16>()
53 /// assert_eq!(call_func_with_field!(size_of_field, Foo, x), 2);
54 /// ```
55 #[macro_export]
56 macro_rules! call_func_with_field {
57     // Based on the answer by user steffahn (Frank Steffahn) at
58     // https://users.rust-lang.org/t/inferring-type-of-field/122857
59     // and used under MIT license
60     ($func:expr, $typ:ty, $($field:tt).+) => {
61         $func(loop {
62             #![allow(unreachable_code)]
63             const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> { ::core::marker::PhantomData }
64             // Unreachable code is exempt from checks on uninitialized values.
65             // Use that trick to infer the type of this PhantomData.
66             break ::core::marker::PhantomData;
67             break phantom__(&{ let value__: $typ; value__.$($field).+ });
68         })
69     };
70 }
71 
72 /// Workaround for lack of `const_refs_static`: references to global variables
73 /// can be included in a `static`, but not in a `const`; unfortunately, this
74 /// is exactly what would go in the `VMStateField`'s `info` member.
75 ///
76 /// This enum contains the contents of the `VMStateField`'s `info` member,
77 /// but as an `enum` instead of a pointer.
78 #[allow(non_camel_case_types)]
79 pub enum VMStateFieldType {
80     null,
81     vmstate_info_bool,
82     vmstate_info_int8,
83     vmstate_info_int16,
84     vmstate_info_int32,
85     vmstate_info_int64,
86     vmstate_info_uint8,
87     vmstate_info_uint16,
88     vmstate_info_uint32,
89     vmstate_info_uint64,
90     vmstate_info_timer,
91 }
92 
93 /// Workaround for lack of `const_refs_static`.  Converts a `VMStateFieldType`
94 /// to a `*const VMStateInfo`, for inclusion in a `VMStateField`.
95 #[macro_export]
96 macro_rules! info_enum_to_ref {
97     ($e:expr) => {
98         unsafe {
99             match $e {
100                 $crate::vmstate::VMStateFieldType::null => ::core::ptr::null(),
101                 $crate::vmstate::VMStateFieldType::vmstate_info_bool => {
102                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_bool)
103                 }
104                 $crate::vmstate::VMStateFieldType::vmstate_info_int8 => {
105                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int8)
106                 }
107                 $crate::vmstate::VMStateFieldType::vmstate_info_int16 => {
108                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int16)
109                 }
110                 $crate::vmstate::VMStateFieldType::vmstate_info_int32 => {
111                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int32)
112                 }
113                 $crate::vmstate::VMStateFieldType::vmstate_info_int64 => {
114                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int64)
115                 }
116                 $crate::vmstate::VMStateFieldType::vmstate_info_uint8 => {
117                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint8)
118                 }
119                 $crate::vmstate::VMStateFieldType::vmstate_info_uint16 => {
120                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint16)
121                 }
122                 $crate::vmstate::VMStateFieldType::vmstate_info_uint32 => {
123                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32)
124                 }
125                 $crate::vmstate::VMStateFieldType::vmstate_info_uint64 => {
126                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint64)
127                 }
128                 $crate::vmstate::VMStateFieldType::vmstate_info_timer => {
129                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_timer)
130                 }
131             }
132         }
133     };
134 }
135 
136 /// A trait for types that can be included in a device's migration stream.  It
137 /// provides the base contents of a `VMStateField` (minus the name and offset).
138 ///
139 /// # Safety
140 ///
141 /// The contents of this trait go straight into structs that are parsed by C
142 /// code and used to introspect into other structs.  Generally, you don't need
143 /// to implement it except via macros that do it for you, such as
144 /// `impl_vmstate_bitsized!`.
145 pub unsafe trait VMState {
146     /// The `info` member of a `VMStateField` is a pointer and as such cannot
147     /// yet be included in the [`BASE`](VMState::BASE) associated constant;
148     /// this is only allowed by Rust 1.83.0 and newer.  For now, include the
149     /// member as an enum which is stored in a separate constant.
150     const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::null;
151 
152     /// The base contents of a `VMStateField` (minus the name and offset) for
153     /// the type that is implementing the trait.
154     const BASE: VMStateField;
155 
156     /// A flag that is added to another field's `VMStateField` to specify the
157     /// length's type in a variable-sized array.  If this is not a supported
158     /// type for the length (i.e. if it is not `u8`, `u16`, `u32`), using it
159     /// in a call to [`vmstate_of!`](crate::vmstate_of) will cause a
160     /// compile-time error.
161     const VARRAY_FLAG: VMStateFlags = {
162         panic!("invalid type for variable-sized array");
163     };
164 }
165 
166 /// Internal utility function to retrieve a type's `VMStateFieldType`;
167 /// used by [`vmstate_of!`](crate::vmstate_of).
168 pub const fn vmstate_scalar_type<T: VMState>(_: PhantomData<T>) -> VMStateFieldType {
169     T::SCALAR_TYPE
170 }
171 
172 /// Internal utility function to retrieve a type's `VMStateField`;
173 /// used by [`vmstate_of!`](crate::vmstate_of).
174 pub const fn vmstate_base<T: VMState>(_: PhantomData<T>) -> VMStateField {
175     T::BASE
176 }
177 
178 /// Internal utility function to retrieve a type's `VMStateFlags` when it
179 /// is used as the element count of a `VMSTATE_VARRAY`; used by
180 /// [`vmstate_of!`](crate::vmstate_of).
181 pub const fn vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags {
182     T::VARRAY_FLAG
183 }
184 
185 /// Return the `VMStateField` for a field of a struct.  The field must be
186 /// visible in the current scope.
187 ///
188 /// Only a limited set of types is supported out of the box:
189 /// * scalar types (integer and `bool`)
190 /// * the C struct `QEMUTimer`
191 /// * a transparent wrapper for any of the above (`Cell`, `UnsafeCell`,
192 ///   [`BqlCell`](crate::cell::BqlCell), [`BqlRefCell`](crate::cell::BqlRefCell)
193 /// * a raw pointer to any of the above
194 /// * a `NonNull` pointer or a `Box` for any of the above
195 /// * an array of any of the above
196 ///
197 /// In order to support other types, the trait `VMState` must be implemented
198 /// for them.  The macros
199 /// [`impl_vmstate_bitsized!`](crate::impl_vmstate_bitsized)
200 /// and [`impl_vmstate_forward!`](crate::impl_vmstate_forward) help with this.
201 #[macro_export]
202 macro_rules! vmstate_of {
203     ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(,)?) => {
204         $crate::bindings::VMStateField {
205             name: ::core::concat!(::core::stringify!($field_name), "\0")
206                 .as_bytes()
207                 .as_ptr() as *const ::std::os::raw::c_char,
208             offset: $crate::offset_of!($struct_name, $field_name),
209             $(.num_offset: $crate::offset_of!($struct_name, $num),)?
210             // The calls to `call_func_with_field!` are the magic that
211             // computes most of the VMStateField from the type of the field.
212             info: $crate::info_enum_to_ref!($crate::call_func_with_field!(
213                 $crate::vmstate::vmstate_scalar_type,
214                 $struct_name,
215                 $field_name
216             )),
217             ..$crate::call_func_with_field!(
218                 $crate::vmstate::vmstate_base,
219                 $struct_name,
220                 $field_name
221             )$(.with_varray_flag($crate::call_func_with_field!(
222                     $crate::vmstate::vmstate_varray_flag,
223                     $struct_name,
224                     $num))
225                $(.with_varray_multiply($factor))?)?
226         }
227     };
228 }
229 
230 impl VMStateFlags {
231     const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags(
232         VMStateFlags::VMS_VARRAY_INT32.0
233             | VMStateFlags::VMS_VARRAY_UINT8.0
234             | VMStateFlags::VMS_VARRAY_UINT16.0
235             | VMStateFlags::VMS_VARRAY_UINT32.0,
236     );
237 }
238 
239 // Add a couple builder-style methods to VMStateField, allowing
240 // easy derivation of VMStateField constants from other types.
241 impl VMStateField {
242     #[must_use]
243     pub const fn with_version_id(mut self, version_id: i32) -> Self {
244         assert!(version_id >= 0);
245         self.version_id = version_id;
246         self
247     }
248 
249     #[must_use]
250     pub const fn with_array_flag(mut self, num: usize) -> Self {
251         assert!(num <= 0x7FFF_FFFFusize);
252         assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) == 0);
253         assert!((self.flags.0 & VMStateFlags::VMS_VARRAY_FLAGS.0) == 0);
254         if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 {
255             self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0);
256             self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0);
257         }
258         self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0);
259         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0);
260         self.num = num as i32;
261         self
262     }
263 
264     #[must_use]
265     pub const fn with_pointer_flag(mut self) -> Self {
266         assert!((self.flags.0 & VMStateFlags::VMS_POINTER.0) == 0);
267         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_POINTER.0);
268         self
269     }
270 
271     #[must_use]
272     pub const fn with_varray_flag<T: VMState>(mut self, flag: VMStateFlags) -> VMStateField {
273         assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0);
274         self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0);
275         self.flags = VMStateFlags(self.flags.0 | flag.0);
276         self
277     }
278 
279     #[must_use]
280     pub const fn with_varray_multiply(mut self, num: u32) -> VMStateField {
281         assert!(num <= 0x7FFF_FFFFu32);
282         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0);
283         self.num = num as i32;
284         self
285     }
286 }
287 
288 /// This macro can be used (by just passing it a type) to forward the `VMState`
289 /// trait to the first field of a tuple.  This is a workaround for lack of
290 /// support of nested [`offset_of`](core::mem::offset_of) until Rust 1.82.0.
291 ///
292 /// # Examples
293 ///
294 /// ```
295 /// # use qemu_api::vmstate::impl_vmstate_forward;
296 /// pub struct Fifo([u8; 16]);
297 /// impl_vmstate_forward!(Fifo);
298 /// ```
299 #[macro_export]
300 macro_rules! impl_vmstate_forward {
301     // This is similar to impl_vmstate_transparent below, but it
302     // uses the same trick as vmstate_of! to obtain the type of
303     // the first field of the tuple
304     ($tuple:ty) => {
305         unsafe impl $crate::vmstate::VMState for $tuple {
306             const SCALAR_TYPE: $crate::vmstate::VMStateFieldType =
307                 $crate::call_func_with_field!($crate::vmstate::vmstate_scalar_type, $tuple, 0);
308             const BASE: $crate::bindings::VMStateField =
309                 $crate::call_func_with_field!($crate::vmstate::vmstate_base, $tuple, 0);
310         }
311     };
312 }
313 
314 // Transparent wrappers: just use the internal type
315 
316 macro_rules! impl_vmstate_transparent {
317     ($type:ty where $base:tt: VMState $($where:tt)*) => {
318         unsafe impl<$base> VMState for $type where $base: VMState $($where)* {
319             const SCALAR_TYPE: VMStateFieldType = <$base as VMState>::SCALAR_TYPE;
320             const BASE: VMStateField = VMStateField {
321                 size: mem::size_of::<$type>(),
322                 ..<$base as VMState>::BASE
323             };
324             const VARRAY_FLAG: VMStateFlags = <$base as VMState>::VARRAY_FLAG;
325         }
326     };
327 }
328 
329 impl_vmstate_transparent!(std::cell::Cell<T> where T: VMState);
330 impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState);
331 impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState);
332 impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState);
333 
334 #[macro_export]
335 macro_rules! impl_vmstate_bitsized {
336     ($type:ty) => {
337         unsafe impl $crate::vmstate::VMState for $type {
338             const SCALAR_TYPE: $crate::vmstate::VMStateFieldType =
339                                         <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
340                                           as ::bilge::prelude::Number>::UnderlyingType
341                                          as $crate::vmstate::VMState>::SCALAR_TYPE;
342             const BASE: $crate::bindings::VMStateField =
343                                         <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
344                                           as ::bilge::prelude::Number>::UnderlyingType
345                                          as $crate::vmstate::VMState>::BASE;
346             const VARRAY_FLAG: $crate::bindings::VMStateFlags =
347                                         <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
348                                           as ::bilge::prelude::Number>::UnderlyingType
349                                          as $crate::vmstate::VMState>::VARRAY_FLAG;
350         }
351     };
352 }
353 
354 // Scalar types using predefined VMStateInfos
355 
356 macro_rules! impl_vmstate_scalar {
357     ($info:ident, $type:ty$(, $varray_flag:ident)?) => {
358         unsafe impl VMState for $type {
359             const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::$info;
360             const BASE: VMStateField = VMStateField {
361                 size: mem::size_of::<$type>(),
362                 flags: VMStateFlags::VMS_SINGLE,
363                 ..Zeroable::ZERO
364             };
365             $(const VARRAY_FLAG: VMStateFlags = VMStateFlags::$varray_flag;)?
366         }
367     };
368 }
369 
370 impl_vmstate_scalar!(vmstate_info_bool, bool);
371 impl_vmstate_scalar!(vmstate_info_int8, i8);
372 impl_vmstate_scalar!(vmstate_info_int16, i16);
373 impl_vmstate_scalar!(vmstate_info_int32, i32);
374 impl_vmstate_scalar!(vmstate_info_int64, i64);
375 impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY_UINT8);
376 impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY_UINT16);
377 impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY_UINT32);
378 impl_vmstate_scalar!(vmstate_info_uint64, u64);
379 impl_vmstate_scalar!(vmstate_info_timer, bindings::QEMUTimer);
380 
381 // Pointer types using the underlying type's VMState plus VMS_POINTER
382 // Note that references are not supported, though references to cells
383 // could be allowed.
384 
385 macro_rules! impl_vmstate_pointer {
386     ($type:ty where $base:tt: VMState $($where:tt)*) => {
387         unsafe impl<$base> VMState for $type where $base: VMState $($where)* {
388             const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE;
389             const BASE: VMStateField = <$base as VMState>::BASE.with_pointer_flag();
390         }
391     };
392 }
393 
394 impl_vmstate_pointer!(*const T where T: VMState);
395 impl_vmstate_pointer!(*mut T where T: VMState);
396 impl_vmstate_pointer!(NonNull<T> where T: VMState);
397 
398 // Unlike C pointers, Box is always non-null therefore there is no need
399 // to specify VMS_ALLOC.
400 impl_vmstate_pointer!(Box<T> where T: VMState);
401 
402 // Arrays using the underlying type's VMState plus
403 // VMS_ARRAY/VMS_ARRAY_OF_POINTER
404 
405 unsafe impl<T: VMState, const N: usize> VMState for [T; N] {
406     const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE;
407     const BASE: VMStateField = <T as VMState>::BASE.with_array_flag(N);
408 }
409 
410 #[doc(alias = "VMSTATE_UNUSED_BUFFER")]
411 #[macro_export]
412 macro_rules! vmstate_unused_buffer {
413     ($field_exists_fn:expr, $version_id:expr, $size:expr) => {{
414         $crate::bindings::VMStateField {
415             name: c_str!("unused").as_ptr(),
416             err_hint: ::core::ptr::null(),
417             offset: 0,
418             size: $size,
419             start: 0,
420             num: 0,
421             num_offset: 0,
422             size_offset: 0,
423             info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) },
424             flags: VMStateFlags::VMS_BUFFER,
425             vmsd: ::core::ptr::null(),
426             version_id: $version_id,
427             struct_version_id: 0,
428             field_exists: $field_exists_fn,
429         }
430     }};
431 }
432 
433 #[doc(alias = "VMSTATE_UNUSED_V")]
434 #[macro_export]
435 macro_rules! vmstate_unused_v {
436     ($version_id:expr, $size:expr) => {{
437         $crate::vmstate_unused_buffer!(None, $version_id, $size)
438     }};
439 }
440 
441 #[doc(alias = "VMSTATE_UNUSED")]
442 #[macro_export]
443 macro_rules! vmstate_unused {
444     ($size:expr) => {{
445         $crate::vmstate_unused_v!(0, $size)
446     }};
447 }
448 
449 #[doc(alias = "VMSTATE_SINGLE_TEST")]
450 #[macro_export]
451 macro_rules! vmstate_single_test {
452     ($field_name:ident, $struct_name:ty, $field_exists_fn:expr, $version_id:expr, $info:expr, $size:expr) => {{
453         $crate::bindings::VMStateField {
454             name: ::core::concat!(::core::stringify!($field_name), 0)
455                 .as_bytes()
456                 .as_ptr() as *const ::std::os::raw::c_char,
457             err_hint: ::core::ptr::null(),
458             offset: $crate::offset_of!($struct_name, $field_name),
459             size: $size,
460             start: 0,
461             num: 0,
462             num_offset: 0,
463             size_offset: 0,
464             info: unsafe { $info },
465             flags: VMStateFlags::VMS_SINGLE,
466             vmsd: ::core::ptr::null(),
467             version_id: $version_id,
468             struct_version_id: 0,
469             field_exists: $field_exists_fn,
470         }
471     }};
472 }
473 
474 #[doc(alias = "VMSTATE_SINGLE")]
475 #[macro_export]
476 macro_rules! vmstate_single {
477     ($field_name:ident, $struct_name:ty, $version_id:expr, $info:expr, $size:expr) => {{
478         $crate::vmstate_single_test!($field_name, $struct_name, None, $version_id, $info, $size)
479     }};
480 }
481 
482 #[doc(alias = "VMSTATE_UINT32_V")]
483 #[macro_export]
484 macro_rules! vmstate_uint32_v {
485     ($field_name:ident, $struct_name:ty, $version_id:expr) => {{
486         $crate::vmstate_single!(
487             $field_name,
488             $struct_name,
489             $version_id,
490             ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32),
491             ::core::mem::size_of::<u32>()
492         )
493     }};
494 }
495 
496 #[doc(alias = "VMSTATE_UINT32")]
497 #[macro_export]
498 macro_rules! vmstate_uint32 {
499     ($field_name:ident, $struct_name:ty) => {{
500         $crate::vmstate_uint32_v!($field_name, $struct_name, 0)
501     }};
502 }
503 
504 #[doc(alias = "VMSTATE_ARRAY")]
505 #[macro_export]
506 macro_rules! vmstate_array {
507     ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr, $info:expr, $size:expr) => {{
508         $crate::bindings::VMStateField {
509             name: ::core::concat!(::core::stringify!($field_name), 0)
510                 .as_bytes()
511                 .as_ptr() as *const ::std::os::raw::c_char,
512             err_hint: ::core::ptr::null(),
513             offset: $crate::offset_of!($struct_name, $field_name),
514             size: $size,
515             start: 0,
516             num: $length as _,
517             num_offset: 0,
518             size_offset: 0,
519             info: unsafe { $info },
520             flags: VMStateFlags::VMS_ARRAY,
521             vmsd: ::core::ptr::null(),
522             version_id: $version_id,
523             struct_version_id: 0,
524             field_exists: None,
525         }
526     }};
527 }
528 
529 #[doc(alias = "VMSTATE_UINT32_ARRAY_V")]
530 #[macro_export]
531 macro_rules! vmstate_uint32_array_v {
532     ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr) => {{
533         $crate::vmstate_array!(
534             $field_name,
535             $struct_name,
536             $length,
537             $version_id,
538             ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32),
539             ::core::mem::size_of::<u32>()
540         )
541     }};
542 }
543 
544 #[doc(alias = "VMSTATE_UINT32_ARRAY")]
545 #[macro_export]
546 macro_rules! vmstate_uint32_array {
547     ($field_name:ident, $struct_name:ty, $length:expr) => {{
548         $crate::vmstate_uint32_array_v!($field_name, $struct_name, $length, 0)
549     }};
550 }
551 
552 #[doc(alias = "VMSTATE_STRUCT_POINTER_V")]
553 #[macro_export]
554 macro_rules! vmstate_struct_pointer_v {
555     ($field_name:ident, $struct_name:ty, $version_id:expr, $vmsd:expr, $type:ty) => {{
556         $crate::bindings::VMStateField {
557             name: ::core::concat!(::core::stringify!($field_name), 0)
558                 .as_bytes()
559                 .as_ptr() as *const ::std::os::raw::c_char,
560             err_hint: ::core::ptr::null(),
561             offset: $crate::offset_of!($struct_name, $field_name),
562             size: ::core::mem::size_of::<*const $type>(),
563             start: 0,
564             num: 0,
565             num_offset: 0,
566             size_offset: 0,
567             info: ::core::ptr::null(),
568             flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0),
569             vmsd: unsafe { $vmsd },
570             version_id: $version_id,
571             struct_version_id: 0,
572             field_exists: None,
573         }
574     }};
575 }
576 
577 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER")]
578 #[macro_export]
579 macro_rules! vmstate_array_of_pointer {
580     ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $info:expr, $type:ty) => {{
581         $crate::bindings::VMStateField {
582             name: ::core::concat!(::core::stringify!($field_name), 0)
583                 .as_bytes()
584                 .as_ptr() as *const ::std::os::raw::c_char,
585             version_id: $version_id,
586             num: $num as _,
587             info: unsafe { $info },
588             size: ::core::mem::size_of::<*const $type>(),
589             flags: VMStateFlags(VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0),
590             offset: $crate::offset_of!($struct_name, $field_name),
591             err_hint: ::core::ptr::null(),
592             start: 0,
593             num_offset: 0,
594             size_offset: 0,
595             vmsd: ::core::ptr::null(),
596             struct_version_id: 0,
597             field_exists: None,
598         }
599     }};
600 }
601 
602 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER_TO_STRUCT")]
603 #[macro_export]
604 macro_rules! vmstate_array_of_pointer_to_struct {
605     ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $vmsd:expr, $type:ty) => {{
606         $crate::bindings::VMStateField {
607             name: ::core::concat!(::core::stringify!($field_name), 0)
608                 .as_bytes()
609                 .as_ptr() as *const ::std::os::raw::c_char,
610             version_id: $version_id,
611             num: $num as _,
612             vmsd: unsafe { $vmsd },
613             size: ::core::mem::size_of::<*const $type>(),
614             flags: VMStateFlags(
615                 VMStateFlags::VMS_ARRAY.0
616                     | VMStateFlags::VMS_STRUCT.0
617                     | VMStateFlags::VMS_ARRAY_OF_POINTER.0,
618             ),
619             offset: $crate::offset_of!($struct_name, $field_name),
620             err_hint: ::core::ptr::null(),
621             start: 0,
622             num_offset: 0,
623             size_offset: 0,
624             vmsd: ::core::ptr::null(),
625             struct_version_id: 0,
626             field_exists: None,
627         }
628     }};
629 }
630 
631 // FIXME: including the `vmsd` field in a `const` is not possible without
632 // the const_refs_static feature (stabilized in Rust 1.83.0).  Without it,
633 // it is not possible to use VMS_STRUCT in a transparent manner using
634 // `vmstate_of!`.  While VMSTATE_CLOCK can at least try to be type-safe,
635 // VMSTATE_STRUCT includes $type only for documentation purposes; it
636 // is checked against $field_name and $struct_name, but not against $vmsd
637 // which is what really would matter.
638 #[doc(alias = "VMSTATE_STRUCT")]
639 #[macro_export]
640 macro_rules! vmstate_struct {
641     ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(,)?) => {
642         $crate::bindings::VMStateField {
643             name: ::core::concat!(::core::stringify!($field_name), "\0")
644                 .as_bytes()
645                 .as_ptr() as *const ::std::os::raw::c_char,
646             $(.num_offset: $crate::offset_of!($struct_name, $num),)?
647             offset: {
648                 $crate::assert_field_type!($struct_name, $field_name, $type);
649                 $crate::offset_of!($struct_name, $field_name)
650             },
651             size: ::core::mem::size_of::<$type>(),
652             flags: $crate::bindings::VMStateFlags::VMS_STRUCT,
653             vmsd: unsafe { $vmsd },
654             ..$crate::zeroable::Zeroable::ZERO $(
655                 .with_varray_flag($crate::call_func_with_field!(
656                     $crate::vmstate::vmstate_varray_flag,
657                     $struct_name,
658                     $num))
659                $(.with_varray_multiply($factor))?)?
660         }
661     };
662 }
663 
664 #[doc(alias = "VMSTATE_CLOCK_V")]
665 #[macro_export]
666 macro_rules! vmstate_clock_v {
667     ($field_name:ident, $struct_name:ty, $version_id:expr) => {{
668         $crate::vmstate_struct_pointer_v!(
669             $field_name,
670             $struct_name,
671             $version_id,
672             ::core::ptr::addr_of!($crate::bindings::vmstate_clock),
673             $crate::bindings::Clock
674         )
675     }};
676 }
677 
678 #[doc(alias = "VMSTATE_CLOCK")]
679 #[macro_export]
680 macro_rules! vmstate_clock {
681     ($field_name:ident, $struct_name:ty) => {{
682         $crate::vmstate_clock_v!($field_name, $struct_name, 0)
683     }};
684 }
685 
686 #[doc(alias = "VMSTATE_ARRAY_CLOCK_V")]
687 #[macro_export]
688 macro_rules! vmstate_array_clock_v {
689     ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr) => {{
690         $crate::vmstate_array_of_pointer_to_struct!(
691             $field_name,
692             $struct_name,
693             $num,
694             $version_id,
695             ::core::ptr::addr_of!($crate::bindings::vmstate_clock),
696             $crate::bindings::Clock
697         )
698     }};
699 }
700 
701 #[doc(alias = "VMSTATE_ARRAY_CLOCK")]
702 #[macro_export]
703 macro_rules! vmstate_array_clock {
704     ($field_name:ident, $struct_name:ty, $num:expr) => {{
705         $crate::vmstate_array_clock_v!($field_name, $struct_name, $name, 0)
706     }};
707 }
708 
709 /// Helper macro to declare a list of
710 /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return
711 /// a pointer to the array of values it created.
712 #[macro_export]
713 macro_rules! vmstate_fields {
714     ($($field:expr),*$(,)*) => {{
715         static _FIELDS: &[$crate::bindings::VMStateField] = &[
716             $($field),*,
717             $crate::bindings::VMStateField {
718                 flags: $crate::bindings::VMStateFlags::VMS_END,
719                 ..$crate::zeroable::Zeroable::ZERO
720             }
721         ];
722         _FIELDS.as_ptr()
723     }}
724 }
725 
726 /// A transparent wrapper type for the `subsections` field of
727 /// [`VMStateDescription`].
728 ///
729 /// This is necessary to be able to declare subsection descriptions as statics,
730 /// because the only way to implement `Sync` for a foreign type (and `*const`
731 /// pointers are foreign types in Rust) is to create a wrapper struct and
732 /// `unsafe impl Sync` for it.
733 ///
734 /// This struct is used in the
735 /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation.
736 #[repr(transparent)]
737 pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]);
738 
739 unsafe impl Sync for VMStateSubsectionsWrapper {}
740 
741 /// Helper macro to declare a list of subsections ([`VMStateDescription`])
742 /// into a static and return a pointer to the array of pointers it created.
743 #[macro_export]
744 macro_rules! vmstate_subsections {
745     ($($subsection:expr),*$(,)*) => {{
746         static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[
747             $({
748                 static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection;
749                 ::core::ptr::addr_of!(_SUBSECTION)
750             }),*,
751             ::core::ptr::null()
752         ]);
753         _SUBSECTIONS.0.as_ptr()
754     }}
755 }
756