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 migratable 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 use std::ffi::{c_int, c_void};
29
30 pub use crate::bindings::{VMStateDescription, VMStateField};
31 use crate::{
32 bindings::VMStateFlags, callbacks::FnCall, prelude::*, qom::Owned, 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).
vmstate_scalar_type<T: VMState>(_: PhantomData<T>) -> VMStateFieldType168 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).
vmstate_base<T: VMState>(_: PhantomData<T>) -> VMStateField174 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).
vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags181 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`], [`BqlRefCell`]
193 /// * a raw pointer to any of the above
194 /// * a `NonNull` pointer, a `Box` or an [`Owned`] 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)?])? $(, $test_fn: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: ::std::mem::offset_of!($struct_name, $field_name),
209 $(num_offset: ::std::mem::offset_of!($struct_name, $num),)?
210 $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)?
211 // The calls to `call_func_with_field!` are the magic that
212 // computes most of the VMStateField from the type of the field.
213 info: $crate::info_enum_to_ref!($crate::call_func_with_field!(
214 $crate::vmstate::vmstate_scalar_type,
215 $struct_name,
216 $field_name
217 )),
218 ..$crate::call_func_with_field!(
219 $crate::vmstate::vmstate_base,
220 $struct_name,
221 $field_name
222 )$(.with_varray_flag($crate::call_func_with_field!(
223 $crate::vmstate::vmstate_varray_flag,
224 $struct_name,
225 $num))
226 $(.with_varray_multiply($factor))?)?
227 }
228 };
229 }
230
231 impl VMStateFlags {
232 const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags(
233 VMStateFlags::VMS_VARRAY_INT32.0
234 | VMStateFlags::VMS_VARRAY_UINT8.0
235 | VMStateFlags::VMS_VARRAY_UINT16.0
236 | VMStateFlags::VMS_VARRAY_UINT32.0,
237 );
238 }
239
240 // Add a couple builder-style methods to VMStateField, allowing
241 // easy derivation of VMStateField constants from other types.
242 impl VMStateField {
243 #[must_use]
with_version_id(mut self, version_id: i32) -> Self244 pub const fn with_version_id(mut self, version_id: i32) -> Self {
245 assert!(version_id >= 0);
246 self.version_id = version_id;
247 self
248 }
249
250 #[must_use]
with_array_flag(mut self, num: usize) -> Self251 pub const fn with_array_flag(mut self, num: usize) -> Self {
252 assert!(num <= 0x7FFF_FFFFusize);
253 assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) == 0);
254 assert!((self.flags.0 & VMStateFlags::VMS_VARRAY_FLAGS.0) == 0);
255 if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 {
256 self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0);
257 self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0);
258 // VMS_ARRAY_OF_POINTER flag stores the size of pointer.
259 // FIXME: *const, *mut, NonNull and Box<> have the same size as usize.
260 // Resize if more smart pointers are supported.
261 self.size = std::mem::size_of::<usize>();
262 }
263 self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0);
264 self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0);
265 self.num = num as i32;
266 self
267 }
268
269 #[must_use]
with_pointer_flag(mut self) -> Self270 pub const fn with_pointer_flag(mut self) -> Self {
271 assert!((self.flags.0 & VMStateFlags::VMS_POINTER.0) == 0);
272 self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_POINTER.0);
273 self
274 }
275
276 #[must_use]
with_varray_flag_unchecked(mut self, flag: VMStateFlags) -> VMStateField277 pub const fn with_varray_flag_unchecked(mut self, flag: VMStateFlags) -> VMStateField {
278 self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0);
279 self.flags = VMStateFlags(self.flags.0 | flag.0);
280 self.num = 0; // varray uses num_offset instead of num.
281 self
282 }
283
284 #[must_use]
285 #[allow(unused_mut)]
with_varray_flag(mut self, flag: VMStateFlags) -> VMStateField286 pub const fn with_varray_flag(mut self, flag: VMStateFlags) -> VMStateField {
287 assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0);
288 self.with_varray_flag_unchecked(flag)
289 }
290
291 #[must_use]
with_varray_multiply(mut self, num: u32) -> VMStateField292 pub const fn with_varray_multiply(mut self, num: u32) -> VMStateField {
293 assert!(num <= 0x7FFF_FFFFu32);
294 self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0);
295 self.num = num as i32;
296 self
297 }
298 }
299
300 /// This macro can be used (by just passing it a type) to forward the `VMState`
301 /// trait to the first field of a tuple. This is a workaround for lack of
302 /// support of nested [`offset_of`](core::mem::offset_of) until Rust 1.82.0.
303 ///
304 /// # Examples
305 ///
306 /// ```
307 /// # use qemu_api::impl_vmstate_forward;
308 /// pub struct Fifo([u8; 16]);
309 /// impl_vmstate_forward!(Fifo);
310 /// ```
311 #[macro_export]
312 macro_rules! impl_vmstate_forward {
313 // This is similar to impl_vmstate_transparent below, but it
314 // uses the same trick as vmstate_of! to obtain the type of
315 // the first field of the tuple
316 ($tuple:ty) => {
317 unsafe impl $crate::vmstate::VMState for $tuple {
318 const SCALAR_TYPE: $crate::vmstate::VMStateFieldType =
319 $crate::call_func_with_field!($crate::vmstate::vmstate_scalar_type, $tuple, 0);
320 const BASE: $crate::bindings::VMStateField =
321 $crate::call_func_with_field!($crate::vmstate::vmstate_base, $tuple, 0);
322 }
323 };
324 }
325
326 // Transparent wrappers: just use the internal type
327
328 macro_rules! impl_vmstate_transparent {
329 ($type:ty where $base:tt: VMState $($where:tt)*) => {
330 unsafe impl<$base> VMState for $type where $base: VMState $($where)* {
331 const SCALAR_TYPE: VMStateFieldType = <$base as VMState>::SCALAR_TYPE;
332 const BASE: VMStateField = VMStateField {
333 size: mem::size_of::<$type>(),
334 ..<$base as VMState>::BASE
335 };
336 const VARRAY_FLAG: VMStateFlags = <$base as VMState>::VARRAY_FLAG;
337 }
338 };
339 }
340
341 impl_vmstate_transparent!(std::cell::Cell<T> where T: VMState);
342 impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState);
343 impl_vmstate_transparent!(std::pin::Pin<T> where T: VMState);
344 impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState);
345 impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState);
346 impl_vmstate_transparent!(crate::cell::Opaque<T> where T: VMState);
347
348 #[macro_export]
349 macro_rules! impl_vmstate_bitsized {
350 ($type:ty) => {
351 unsafe impl $crate::vmstate::VMState for $type {
352 const SCALAR_TYPE: $crate::vmstate::VMStateFieldType =
353 <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
354 as ::bilge::prelude::Number>::UnderlyingType
355 as $crate::vmstate::VMState>::SCALAR_TYPE;
356 const BASE: $crate::bindings::VMStateField =
357 <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
358 as ::bilge::prelude::Number>::UnderlyingType
359 as $crate::vmstate::VMState>::BASE;
360 const VARRAY_FLAG: $crate::bindings::VMStateFlags =
361 <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
362 as ::bilge::prelude::Number>::UnderlyingType
363 as $crate::vmstate::VMState>::VARRAY_FLAG;
364 }
365 };
366 }
367
368 // Scalar types using predefined VMStateInfos
369
370 macro_rules! impl_vmstate_scalar {
371 ($info:ident, $type:ty$(, $varray_flag:ident)?) => {
372 unsafe impl VMState for $type {
373 const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::$info;
374 const BASE: VMStateField = VMStateField {
375 size: mem::size_of::<$type>(),
376 flags: VMStateFlags::VMS_SINGLE,
377 ..Zeroable::ZERO
378 };
379 $(const VARRAY_FLAG: VMStateFlags = VMStateFlags::$varray_flag;)?
380 }
381 };
382 }
383
384 impl_vmstate_scalar!(vmstate_info_bool, bool);
385 impl_vmstate_scalar!(vmstate_info_int8, i8);
386 impl_vmstate_scalar!(vmstate_info_int16, i16);
387 impl_vmstate_scalar!(vmstate_info_int32, i32);
388 impl_vmstate_scalar!(vmstate_info_int64, i64);
389 impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY_UINT8);
390 impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY_UINT16);
391 impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY_UINT32);
392 impl_vmstate_scalar!(vmstate_info_uint64, u64);
393 impl_vmstate_scalar!(vmstate_info_timer, crate::timer::Timer);
394
395 // Pointer types using the underlying type's VMState plus VMS_POINTER
396 // Note that references are not supported, though references to cells
397 // could be allowed.
398
399 macro_rules! impl_vmstate_pointer {
400 ($type:ty where $base:tt: VMState $($where:tt)*) => {
401 unsafe impl<$base> VMState for $type where $base: VMState $($where)* {
402 const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE;
403 const BASE: VMStateField = <$base as VMState>::BASE.with_pointer_flag();
404 }
405 };
406 }
407
408 impl_vmstate_pointer!(*const T where T: VMState);
409 impl_vmstate_pointer!(*mut T where T: VMState);
410 impl_vmstate_pointer!(NonNull<T> where T: VMState);
411
412 // Unlike C pointers, Box is always non-null therefore there is no need
413 // to specify VMS_ALLOC.
414 impl_vmstate_pointer!(Box<T> where T: VMState);
415 impl_vmstate_pointer!(Owned<T> where T: VMState + ObjectType);
416
417 // Arrays using the underlying type's VMState plus
418 // VMS_ARRAY/VMS_ARRAY_OF_POINTER
419
420 unsafe impl<T: VMState, const N: usize> VMState for [T; N] {
421 const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE;
422 const BASE: VMStateField = <T as VMState>::BASE.with_array_flag(N);
423 }
424
425 #[doc(alias = "VMSTATE_UNUSED")]
426 #[macro_export]
427 macro_rules! vmstate_unused {
428 ($size:expr) => {{
429 $crate::bindings::VMStateField {
430 name: c"unused".as_ptr(),
431 size: $size,
432 info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) },
433 flags: $crate::bindings::VMStateFlags::VMS_BUFFER,
434 ..$crate::zeroable::Zeroable::ZERO
435 }
436 }};
437 }
438
rust_vms_test_field_exists<T, F: for<'a> FnCall<(&'a T, u8), bool>>( opaque: *mut c_void, version_id: c_int, ) -> bool439 pub extern "C" fn rust_vms_test_field_exists<T, F: for<'a> FnCall<(&'a T, u8), bool>>(
440 opaque: *mut c_void,
441 version_id: c_int,
442 ) -> bool {
443 // SAFETY: the opaque was passed as a reference to `T`.
444 let owner: &T = unsafe { &*(opaque.cast::<T>()) };
445 let version: u8 = version_id.try_into().unwrap();
446 F::call((owner, version))
447 }
448
449 pub type VMSFieldExistCb = unsafe extern "C" fn(
450 opaque: *mut std::os::raw::c_void,
451 version_id: std::os::raw::c_int,
452 ) -> bool;
453
454 #[macro_export]
455 macro_rules! vmstate_exist_fn {
456 ($struct_name:ty, $test_fn:expr) => {{
457 const fn test_cb_builder__<T, F: for<'a> $crate::callbacks::FnCall<(&'a T, u8), bool>>(
458 _phantom: ::core::marker::PhantomData<F>,
459 ) -> $crate::vmstate::VMSFieldExistCb {
460 let _: () = F::ASSERT_IS_SOME;
461 $crate::vmstate::rust_vms_test_field_exists::<T, F>
462 }
463
464 const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> {
465 ::core::marker::PhantomData
466 }
467 Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn)))
468 }};
469 }
470
471 // FIXME: including the `vmsd` field in a `const` is not possible without
472 // the const_refs_static feature (stabilized in Rust 1.83.0). Without it,
473 // it is not possible to use VMS_STRUCT in a transparent manner using
474 // `vmstate_of!`. While VMSTATE_CLOCK can at least try to be type-safe,
475 // VMSTATE_STRUCT includes $type only for documentation purposes; it
476 // is checked against $field_name and $struct_name, but not against $vmsd
477 // which is what really would matter.
478 #[doc(alias = "VMSTATE_STRUCT")]
479 #[macro_export]
480 macro_rules! vmstate_struct {
481 ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(, $test_fn:expr)? $(,)?) => {
482 $crate::bindings::VMStateField {
483 name: ::core::concat!(::core::stringify!($field_name), "\0")
484 .as_bytes()
485 .as_ptr() as *const ::std::os::raw::c_char,
486 $(num_offset: ::std::mem::offset_of!($struct_name, $num),)?
487 offset: {
488 $crate::assert_field_type!($struct_name, $field_name, $type $(, num = $num)?);
489 ::std::mem::offset_of!($struct_name, $field_name)
490 },
491 size: ::core::mem::size_of::<$type>(),
492 flags: $crate::bindings::VMStateFlags::VMS_STRUCT,
493 vmsd: $vmsd,
494 $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)?
495 ..$crate::zeroable::Zeroable::ZERO
496 } $(.with_varray_flag_unchecked(
497 $crate::call_func_with_field!(
498 $crate::vmstate::vmstate_varray_flag,
499 $struct_name,
500 $num
501 )
502 )
503 $(.with_varray_multiply($factor))?)?
504 };
505 }
506
507 #[doc(alias = "VMSTATE_CLOCK")]
508 #[macro_export]
509 macro_rules! vmstate_clock {
510 ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?) => {{
511 $crate::bindings::VMStateField {
512 name: ::core::concat!(::core::stringify!($field_name), "\0")
513 .as_bytes()
514 .as_ptr() as *const ::std::os::raw::c_char,
515 offset: {
516 $crate::assert_field_type!(
517 $struct_name,
518 $field_name,
519 $crate::qom::Owned<$crate::qdev::Clock> $(, num = $num)?
520 );
521 ::std::mem::offset_of!($struct_name, $field_name)
522 },
523 size: ::core::mem::size_of::<*const $crate::qdev::Clock>(),
524 flags: $crate::bindings::VMStateFlags(
525 $crate::bindings::VMStateFlags::VMS_STRUCT.0
526 | $crate::bindings::VMStateFlags::VMS_POINTER.0,
527 ),
528 vmsd: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_clock) },
529 ..$crate::zeroable::Zeroable::ZERO
530 } $(.with_varray_flag_unchecked(
531 $crate::call_func_with_field!(
532 $crate::vmstate::vmstate_varray_flag,
533 $struct_name,
534 $num
535 )
536 )
537 $(.with_varray_multiply($factor))?)?
538 }};
539 }
540
541 /// Helper macro to declare a list of
542 /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return
543 /// a pointer to the array of values it created.
544 #[macro_export]
545 macro_rules! vmstate_fields {
546 ($($field:expr),*$(,)*) => {{
547 static _FIELDS: &[$crate::bindings::VMStateField] = &[
548 $($field),*,
549 $crate::bindings::VMStateField {
550 flags: $crate::bindings::VMStateFlags::VMS_END,
551 ..$crate::zeroable::Zeroable::ZERO
552 }
553 ];
554 _FIELDS.as_ptr()
555 }}
556 }
557
558 #[doc(alias = "VMSTATE_VALIDATE")]
559 #[macro_export]
560 macro_rules! vmstate_validate {
561 ($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => {
562 $crate::bindings::VMStateField {
563 name: ::std::ffi::CStr::as_ptr($test_name),
564 field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),
565 flags: $crate::bindings::VMStateFlags(
566 $crate::bindings::VMStateFlags::VMS_MUST_EXIST.0
567 | $crate::bindings::VMStateFlags::VMS_ARRAY.0,
568 ),
569 num: 0, // 0 elements: no data, only run test_fn callback
570 ..$crate::zeroable::Zeroable::ZERO
571 }
572 };
573 }
574
575 /// A transparent wrapper type for the `subsections` field of
576 /// [`VMStateDescription`].
577 ///
578 /// This is necessary to be able to declare subsection descriptions as statics,
579 /// because the only way to implement `Sync` for a foreign type (and `*const`
580 /// pointers are foreign types in Rust) is to create a wrapper struct and
581 /// `unsafe impl Sync` for it.
582 ///
583 /// This struct is used in the
584 /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation.
585 #[repr(transparent)]
586 pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]);
587
588 unsafe impl Sync for VMStateSubsectionsWrapper {}
589
590 /// Helper macro to declare a list of subsections ([`VMStateDescription`])
591 /// into a static and return a pointer to the array of pointers it created.
592 #[macro_export]
593 macro_rules! vmstate_subsections {
594 ($($subsection:expr),*$(,)*) => {{
595 static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[
596 $({
597 static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection;
598 ::core::ptr::addr_of!(_SUBSECTION)
599 }),*,
600 ::core::ptr::null()
601 ]);
602 _SUBSECTIONS.0.as_ptr()
603 }}
604 }
605