xref: /qemu/rust/qemu-api/src/vmstate.rs (revision b4b0880c3aae98e5c08d4d785b0fe16f0b780081)
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 only provide
25 //!   functionality that is missing from `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     prelude::*,
33     qom::Owned,
34     zeroable::Zeroable,
35 };
36 
37 /// This macro is used to call a function with a generic argument bound
38 /// to the type of a field.  The function must take a
39 /// [`PhantomData`]`<T>` argument; `T` is the type of
40 /// field `$field` in the `$typ` type.
41 ///
42 /// # Examples
43 ///
44 /// ```
45 /// # use qemu_api::call_func_with_field;
46 /// # use core::marker::PhantomData;
47 /// const fn size_of_field<T>(_: PhantomData<T>) -> usize {
48 ///     std::mem::size_of::<T>()
49 /// }
50 ///
51 /// struct Foo {
52 ///     x: u16,
53 /// };
54 /// // calls size_of_field::<u16>()
55 /// assert_eq!(call_func_with_field!(size_of_field, Foo, x), 2);
56 /// ```
57 #[macro_export]
58 macro_rules! call_func_with_field {
59     // Based on the answer by user steffahn (Frank Steffahn) at
60     // https://users.rust-lang.org/t/inferring-type-of-field/122857
61     // and used under MIT license
62     ($func:expr, $typ:ty, $($field:tt).+) => {
63         $func(loop {
64             #![allow(unreachable_code)]
65             const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> { ::core::marker::PhantomData }
66             // Unreachable code is exempt from checks on uninitialized values.
67             // Use that trick to infer the type of this PhantomData.
68             break ::core::marker::PhantomData;
69             break phantom__(&{ let value__: $typ; value__.$($field).+ });
70         })
71     };
72 }
73 
74 /// Workaround for lack of `const_refs_static`: references to global variables
75 /// can be included in a `static`, but not in a `const`; unfortunately, this
76 /// is exactly what would go in the `VMStateField`'s `info` member.
77 ///
78 /// This enum contains the contents of the `VMStateField`'s `info` member,
79 /// but as an `enum` instead of a pointer.
80 #[allow(non_camel_case_types)]
81 pub enum VMStateFieldType {
82     null,
83     vmstate_info_bool,
84     vmstate_info_int8,
85     vmstate_info_int16,
86     vmstate_info_int32,
87     vmstate_info_int64,
88     vmstate_info_uint8,
89     vmstate_info_uint16,
90     vmstate_info_uint32,
91     vmstate_info_uint64,
92     vmstate_info_timer,
93 }
94 
95 /// Workaround for lack of `const_refs_static`.  Converts a `VMStateFieldType`
96 /// to a `*const VMStateInfo`, for inclusion in a `VMStateField`.
97 #[macro_export]
98 macro_rules! info_enum_to_ref {
99     ($e:expr) => {
100         unsafe {
101             match $e {
102                 $crate::vmstate::VMStateFieldType::null => ::core::ptr::null(),
103                 $crate::vmstate::VMStateFieldType::vmstate_info_bool => {
104                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_bool)
105                 }
106                 $crate::vmstate::VMStateFieldType::vmstate_info_int8 => {
107                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int8)
108                 }
109                 $crate::vmstate::VMStateFieldType::vmstate_info_int16 => {
110                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int16)
111                 }
112                 $crate::vmstate::VMStateFieldType::vmstate_info_int32 => {
113                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int32)
114                 }
115                 $crate::vmstate::VMStateFieldType::vmstate_info_int64 => {
116                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_int64)
117                 }
118                 $crate::vmstate::VMStateFieldType::vmstate_info_uint8 => {
119                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint8)
120                 }
121                 $crate::vmstate::VMStateFieldType::vmstate_info_uint16 => {
122                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint16)
123                 }
124                 $crate::vmstate::VMStateFieldType::vmstate_info_uint32 => {
125                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32)
126                 }
127                 $crate::vmstate::VMStateFieldType::vmstate_info_uint64 => {
128                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint64)
129                 }
130                 $crate::vmstate::VMStateFieldType::vmstate_info_timer => {
131                     ::core::ptr::addr_of!($crate::bindings::vmstate_info_timer)
132                 }
133             }
134         }
135     };
136 }
137 
138 /// A trait for types that can be included in a device's migration stream.  It
139 /// provides the base contents of a `VMStateField` (minus the name and offset).
140 ///
141 /// # Safety
142 ///
143 /// The contents of this trait go straight into structs that are parsed by C
144 /// code and used to introspect into other structs.  Generally, you don't need
145 /// to implement it except via macros that do it for you, such as
146 /// `impl_vmstate_bitsized!`.
147 pub unsafe trait VMState {
148     /// The `info` member of a `VMStateField` is a pointer and as such cannot
149     /// yet be included in the [`BASE`](VMState::BASE) associated constant;
150     /// this is only allowed by Rust 1.83.0 and newer.  For now, include the
151     /// member as an enum which is stored in a separate constant.
152     const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::null;
153 
154     /// The base contents of a `VMStateField` (minus the name and offset) for
155     /// the type that is implementing the trait.
156     const BASE: VMStateField;
157 
158     /// A flag that is added to another field's `VMStateField` to specify the
159     /// length's type in a variable-sized array.  If this is not a supported
160     /// type for the length (i.e. if it is not `u8`, `u16`, `u32`), using it
161     /// in a call to [`vmstate_of!`](crate::vmstate_of) will cause a
162     /// compile-time error.
163     const VARRAY_FLAG: VMStateFlags = {
164         panic!("invalid type for variable-sized array");
165     };
166 }
167 
168 /// Internal utility function to retrieve a type's `VMStateFieldType`;
169 /// used by [`vmstate_of!`](crate::vmstate_of).
170 pub const fn vmstate_scalar_type<T: VMState>(_: PhantomData<T>) -> VMStateFieldType {
171     T::SCALAR_TYPE
172 }
173 
174 /// Internal utility function to retrieve a type's `VMStateField`;
175 /// used by [`vmstate_of!`](crate::vmstate_of).
176 pub const fn vmstate_base<T: VMState>(_: PhantomData<T>) -> VMStateField {
177     T::BASE
178 }
179 
180 /// Internal utility function to retrieve a type's `VMStateFlags` when it
181 /// is used as the element count of a `VMSTATE_VARRAY`; used by
182 /// [`vmstate_of!`](crate::vmstate_of).
183 pub const fn vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags {
184     T::VARRAY_FLAG
185 }
186 
187 /// Return the `VMStateField` for a field of a struct.  The field must be
188 /// visible in the current scope.
189 ///
190 /// Only a limited set of types is supported out of the box:
191 /// * scalar types (integer and `bool`)
192 /// * the C struct `QEMUTimer`
193 /// * a transparent wrapper for any of the above (`Cell`, `UnsafeCell`,
194 ///   [`BqlCell`], [`BqlRefCell`]
195 /// * a raw pointer to any of the above
196 /// * a `NonNull` pointer, a `Box` or an [`Owned`] for any of the above
197 /// * an array of any of the above
198 ///
199 /// In order to support other types, the trait `VMState` must be implemented
200 /// for them.  The macros
201 /// [`impl_vmstate_bitsized!`](crate::impl_vmstate_bitsized)
202 /// and [`impl_vmstate_forward!`](crate::impl_vmstate_forward) help with this.
203 #[macro_export]
204 macro_rules! vmstate_of {
205     ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(,)?) => {
206         $crate::bindings::VMStateField {
207             name: ::core::concat!(::core::stringify!($field_name), "\0")
208                 .as_bytes()
209                 .as_ptr() as *const ::std::os::raw::c_char,
210             offset: $crate::offset_of!($struct_name, $field_name),
211             $(.num_offset: $crate::offset_of!($struct_name, $num),)?
212             // The calls to `call_func_with_field!` are the magic that
213             // computes most of the VMStateField from the type of the field.
214             info: $crate::info_enum_to_ref!($crate::call_func_with_field!(
215                 $crate::vmstate::vmstate_scalar_type,
216                 $struct_name,
217                 $field_name
218             )),
219             ..$crate::call_func_with_field!(
220                 $crate::vmstate::vmstate_base,
221                 $struct_name,
222                 $field_name
223             )$(.with_varray_flag($crate::call_func_with_field!(
224                     $crate::vmstate::vmstate_varray_flag,
225                     $struct_name,
226                     $num))
227                $(.with_varray_multiply($factor))?)?
228         }
229     };
230 }
231 
232 impl VMStateFlags {
233     const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags(
234         VMStateFlags::VMS_VARRAY_INT32.0
235             | VMStateFlags::VMS_VARRAY_UINT8.0
236             | VMStateFlags::VMS_VARRAY_UINT16.0
237             | VMStateFlags::VMS_VARRAY_UINT32.0,
238     );
239 }
240 
241 // Add a couple builder-style methods to VMStateField, allowing
242 // easy derivation of VMStateField constants from other types.
243 impl VMStateField {
244     #[must_use]
245     pub const fn with_version_id(mut self, version_id: i32) -> Self {
246         assert!(version_id >= 0);
247         self.version_id = version_id;
248         self
249     }
250 
251     #[must_use]
252     pub const fn with_array_flag(mut self, num: usize) -> Self {
253         assert!(num <= 0x7FFF_FFFFusize);
254         assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) == 0);
255         assert!((self.flags.0 & VMStateFlags::VMS_VARRAY_FLAGS.0) == 0);
256         if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 {
257             self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0);
258             self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0);
259         }
260         self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0);
261         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0);
262         self.num = num as i32;
263         self
264     }
265 
266     #[must_use]
267     pub const fn with_pointer_flag(mut self) -> Self {
268         assert!((self.flags.0 & VMStateFlags::VMS_POINTER.0) == 0);
269         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_POINTER.0);
270         self
271     }
272 
273     #[must_use]
274     pub const fn with_varray_flag<T: VMState>(mut self, flag: VMStateFlags) -> VMStateField {
275         assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0);
276         self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0);
277         self.flags = VMStateFlags(self.flags.0 | flag.0);
278         self
279     }
280 
281     #[must_use]
282     pub const fn with_varray_multiply(mut self, num: u32) -> VMStateField {
283         assert!(num <= 0x7FFF_FFFFu32);
284         self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0);
285         self.num = num as i32;
286         self
287     }
288 }
289 
290 /// This macro can be used (by just passing it a type) to forward the `VMState`
291 /// trait to the first field of a tuple.  This is a workaround for lack of
292 /// support of nested [`offset_of`](core::mem::offset_of) until Rust 1.82.0.
293 ///
294 /// # Examples
295 ///
296 /// ```
297 /// # use qemu_api::impl_vmstate_forward;
298 /// pub struct Fifo([u8; 16]);
299 /// impl_vmstate_forward!(Fifo);
300 /// ```
301 #[macro_export]
302 macro_rules! impl_vmstate_forward {
303     // This is similar to impl_vmstate_transparent below, but it
304     // uses the same trick as vmstate_of! to obtain the type of
305     // the first field of the tuple
306     ($tuple:ty) => {
307         unsafe impl $crate::vmstate::VMState for $tuple {
308             const SCALAR_TYPE: $crate::vmstate::VMStateFieldType =
309                 $crate::call_func_with_field!($crate::vmstate::vmstate_scalar_type, $tuple, 0);
310             const BASE: $crate::bindings::VMStateField =
311                 $crate::call_func_with_field!($crate::vmstate::vmstate_base, $tuple, 0);
312         }
313     };
314 }
315 
316 // Transparent wrappers: just use the internal type
317 
318 macro_rules! impl_vmstate_transparent {
319     ($type:ty where $base:tt: VMState $($where:tt)*) => {
320         unsafe impl<$base> VMState for $type where $base: VMState $($where)* {
321             const SCALAR_TYPE: VMStateFieldType = <$base as VMState>::SCALAR_TYPE;
322             const BASE: VMStateField = VMStateField {
323                 size: mem::size_of::<$type>(),
324                 ..<$base as VMState>::BASE
325             };
326             const VARRAY_FLAG: VMStateFlags = <$base as VMState>::VARRAY_FLAG;
327         }
328     };
329 }
330 
331 impl_vmstate_transparent!(std::cell::Cell<T> where T: VMState);
332 impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState);
333 impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState);
334 impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState);
335 
336 #[macro_export]
337 macro_rules! impl_vmstate_bitsized {
338     ($type:ty) => {
339         unsafe impl $crate::vmstate::VMState for $type {
340             const SCALAR_TYPE: $crate::vmstate::VMStateFieldType =
341                                         <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
342                                           as ::bilge::prelude::Number>::UnderlyingType
343                                          as $crate::vmstate::VMState>::SCALAR_TYPE;
344             const BASE: $crate::bindings::VMStateField =
345                                         <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
346                                           as ::bilge::prelude::Number>::UnderlyingType
347                                          as $crate::vmstate::VMState>::BASE;
348             const VARRAY_FLAG: $crate::bindings::VMStateFlags =
349                                         <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
350                                           as ::bilge::prelude::Number>::UnderlyingType
351                                          as $crate::vmstate::VMState>::VARRAY_FLAG;
352         }
353     };
354 }
355 
356 // Scalar types using predefined VMStateInfos
357 
358 macro_rules! impl_vmstate_scalar {
359     ($info:ident, $type:ty$(, $varray_flag:ident)?) => {
360         unsafe impl VMState for $type {
361             const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::$info;
362             const BASE: VMStateField = VMStateField {
363                 size: mem::size_of::<$type>(),
364                 flags: VMStateFlags::VMS_SINGLE,
365                 ..Zeroable::ZERO
366             };
367             $(const VARRAY_FLAG: VMStateFlags = VMStateFlags::$varray_flag;)?
368         }
369     };
370 }
371 
372 impl_vmstate_scalar!(vmstate_info_bool, bool);
373 impl_vmstate_scalar!(vmstate_info_int8, i8);
374 impl_vmstate_scalar!(vmstate_info_int16, i16);
375 impl_vmstate_scalar!(vmstate_info_int32, i32);
376 impl_vmstate_scalar!(vmstate_info_int64, i64);
377 impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY_UINT8);
378 impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY_UINT16);
379 impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY_UINT32);
380 impl_vmstate_scalar!(vmstate_info_uint64, u64);
381 impl_vmstate_scalar!(vmstate_info_timer, bindings::QEMUTimer);
382 
383 // Pointer types using the underlying type's VMState plus VMS_POINTER
384 // Note that references are not supported, though references to cells
385 // could be allowed.
386 
387 macro_rules! impl_vmstate_pointer {
388     ($type:ty where $base:tt: VMState $($where:tt)*) => {
389         unsafe impl<$base> VMState for $type where $base: VMState $($where)* {
390             const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE;
391             const BASE: VMStateField = <$base as VMState>::BASE.with_pointer_flag();
392         }
393     };
394 }
395 
396 impl_vmstate_pointer!(*const T where T: VMState);
397 impl_vmstate_pointer!(*mut T where T: VMState);
398 impl_vmstate_pointer!(NonNull<T> where T: VMState);
399 
400 // Unlike C pointers, Box is always non-null therefore there is no need
401 // to specify VMS_ALLOC.
402 impl_vmstate_pointer!(Box<T> where T: VMState);
403 impl_vmstate_pointer!(Owned<T> where T: VMState + ObjectType);
404 
405 // Arrays using the underlying type's VMState plus
406 // VMS_ARRAY/VMS_ARRAY_OF_POINTER
407 
408 unsafe impl<T: VMState, const N: usize> VMState for [T; N] {
409     const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE;
410     const BASE: VMStateField = <T as VMState>::BASE.with_array_flag(N);
411 }
412 
413 #[doc(alias = "VMSTATE_UNUSED")]
414 #[macro_export]
415 macro_rules! vmstate_unused {
416     ($size:expr) => {{
417         $crate::bindings::VMStateField {
418             name: $crate::c_str!("unused").as_ptr(),
419             size: $size,
420             info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) },
421             flags: $crate::bindings::VMStateFlags::VMS_BUFFER,
422             ..$crate::zeroable::Zeroable::ZERO
423         }
424     }};
425 }
426 
427 // FIXME: including the `vmsd` field in a `const` is not possible without
428 // the const_refs_static feature (stabilized in Rust 1.83.0).  Without it,
429 // it is not possible to use VMS_STRUCT in a transparent manner using
430 // `vmstate_of!`.  While VMSTATE_CLOCK can at least try to be type-safe,
431 // VMSTATE_STRUCT includes $type only for documentation purposes; it
432 // is checked against $field_name and $struct_name, but not against $vmsd
433 // which is what really would matter.
434 #[doc(alias = "VMSTATE_STRUCT")]
435 #[macro_export]
436 macro_rules! vmstate_struct {
437     ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(,)?) => {
438         $crate::bindings::VMStateField {
439             name: ::core::concat!(::core::stringify!($field_name), "\0")
440                 .as_bytes()
441                 .as_ptr() as *const ::std::os::raw::c_char,
442             $(.num_offset: $crate::offset_of!($struct_name, $num),)?
443             offset: {
444                 $crate::assert_field_type!($struct_name, $field_name, $type);
445                 $crate::offset_of!($struct_name, $field_name)
446             },
447             size: ::core::mem::size_of::<$type>(),
448             flags: $crate::bindings::VMStateFlags::VMS_STRUCT,
449             vmsd: unsafe { $vmsd },
450             ..$crate::zeroable::Zeroable::ZERO $(
451                 .with_varray_flag($crate::call_func_with_field!(
452                     $crate::vmstate::vmstate_varray_flag,
453                     $struct_name,
454                     $num))
455                $(.with_varray_multiply($factor))?)?
456         }
457     };
458 }
459 
460 #[doc(alias = "VMSTATE_CLOCK")]
461 #[macro_export]
462 macro_rules! vmstate_clock {
463     ($struct_name:ty, $field_name:ident) => {{
464         $crate::bindings::VMStateField {
465             name: ::core::concat!(::core::stringify!($field_name), "\0")
466                 .as_bytes()
467                 .as_ptr() as *const ::std::os::raw::c_char,
468             offset: {
469                 $crate::assert_field_type!(
470                     $struct_name,
471                     $field_name,
472                     $crate::qom::Owned<$crate::bindings::Clock>
473                 );
474                 $crate::offset_of!($struct_name, $field_name)
475             },
476             size: ::core::mem::size_of::<*const $crate::qdev::Clock>(),
477             flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0),
478             vmsd: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_clock) },
479             ..$crate::zeroable::Zeroable::ZERO
480         }
481     }};
482 }
483 
484 /// Helper macro to declare a list of
485 /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return
486 /// a pointer to the array of values it created.
487 #[macro_export]
488 macro_rules! vmstate_fields {
489     ($($field:expr),*$(,)*) => {{
490         static _FIELDS: &[$crate::bindings::VMStateField] = &[
491             $($field),*,
492             $crate::bindings::VMStateField {
493                 flags: $crate::bindings::VMStateFlags::VMS_END,
494                 ..$crate::zeroable::Zeroable::ZERO
495             }
496         ];
497         _FIELDS.as_ptr()
498     }}
499 }
500 
501 /// A transparent wrapper type for the `subsections` field of
502 /// [`VMStateDescription`].
503 ///
504 /// This is necessary to be able to declare subsection descriptions as statics,
505 /// because the only way to implement `Sync` for a foreign type (and `*const`
506 /// pointers are foreign types in Rust) is to create a wrapper struct and
507 /// `unsafe impl Sync` for it.
508 ///
509 /// This struct is used in the
510 /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation.
511 #[repr(transparent)]
512 pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]);
513 
514 unsafe impl Sync for VMStateSubsectionsWrapper {}
515 
516 /// Helper macro to declare a list of subsections ([`VMStateDescription`])
517 /// into a static and return a pointer to the array of pointers it created.
518 #[macro_export]
519 macro_rules! vmstate_subsections {
520     ($($subsection:expr),*$(,)*) => {{
521         static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[
522             $({
523                 static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection;
524                 ::core::ptr::addr_of!(_SUBSECTION)
525             }),*,
526             ::core::ptr::null()
527         ]);
528         _SUBSECTIONS.0.as_ptr()
529     }}
530 }
531