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