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