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). 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`], [`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] 244 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] 251 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] 270 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] 277 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)] 286 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] 292 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 439 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