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 should not be 25 //! used if the equivalent functionality is available with `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 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`](crate::cell::BqlCell), [`BqlRefCell`](crate::cell::BqlRefCell) 193 /// * a raw pointer to any of the above 194 /// * a `NonNull` pointer or a `Box` 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)?])? $(,)?) => { 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: $crate::offset_of!($struct_name, $field_name), 209 $(.num_offset: $crate::offset_of!($struct_name, $num),)? 210 // The calls to `call_func_with_field!` are the magic that 211 // computes most of the VMStateField from the type of the field. 212 info: $crate::info_enum_to_ref!($crate::call_func_with_field!( 213 $crate::vmstate::vmstate_scalar_type, 214 $struct_name, 215 $field_name 216 )), 217 ..$crate::call_func_with_field!( 218 $crate::vmstate::vmstate_base, 219 $struct_name, 220 $field_name 221 )$(.with_varray_flag($crate::call_func_with_field!( 222 $crate::vmstate::vmstate_varray_flag, 223 $struct_name, 224 $num)) 225 $(.with_varray_multiply($factor))?)? 226 } 227 }; 228 } 229 230 impl VMStateFlags { 231 const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags( 232 VMStateFlags::VMS_VARRAY_INT32.0 233 | VMStateFlags::VMS_VARRAY_UINT8.0 234 | VMStateFlags::VMS_VARRAY_UINT16.0 235 | VMStateFlags::VMS_VARRAY_UINT32.0, 236 ); 237 } 238 239 // Add a couple builder-style methods to VMStateField, allowing 240 // easy derivation of VMStateField constants from other types. 241 impl VMStateField { 242 #[must_use] 243 pub const fn with_version_id(mut self, version_id: i32) -> Self { 244 assert!(version_id >= 0); 245 self.version_id = version_id; 246 self 247 } 248 249 #[must_use] 250 pub const fn with_array_flag(mut self, num: usize) -> Self { 251 assert!(num <= 0x7FFF_FFFFusize); 252 assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) == 0); 253 assert!((self.flags.0 & VMStateFlags::VMS_VARRAY_FLAGS.0) == 0); 254 if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 { 255 self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0); 256 self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0); 257 } 258 self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0); 259 self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0); 260 self.num = num as i32; 261 self 262 } 263 264 #[must_use] 265 pub const fn with_pointer_flag(mut self) -> Self { 266 assert!((self.flags.0 & VMStateFlags::VMS_POINTER.0) == 0); 267 self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_POINTER.0); 268 self 269 } 270 271 #[must_use] 272 pub const fn with_varray_flag<T: VMState>(mut self, flag: VMStateFlags) -> VMStateField { 273 assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0); 274 self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0); 275 self.flags = VMStateFlags(self.flags.0 | flag.0); 276 self 277 } 278 279 #[must_use] 280 pub const fn with_varray_multiply(mut self, num: u32) -> VMStateField { 281 assert!(num <= 0x7FFF_FFFFu32); 282 self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0); 283 self.num = num as i32; 284 self 285 } 286 } 287 288 /// This macro can be used (by just passing it a type) to forward the `VMState` 289 /// trait to the first field of a tuple. This is a workaround for lack of 290 /// support of nested [`offset_of`](core::mem::offset_of) until Rust 1.82.0. 291 /// 292 /// # Examples 293 /// 294 /// ``` 295 /// # use qemu_api::vmstate::impl_vmstate_forward; 296 /// pub struct Fifo([u8; 16]); 297 /// impl_vmstate_forward!(Fifo); 298 /// ``` 299 #[macro_export] 300 macro_rules! impl_vmstate_forward { 301 // This is similar to impl_vmstate_transparent below, but it 302 // uses the same trick as vmstate_of! to obtain the type of 303 // the first field of the tuple 304 ($tuple:ty) => { 305 unsafe impl $crate::vmstate::VMState for $tuple { 306 const SCALAR_TYPE: $crate::vmstate::VMStateFieldType = 307 $crate::call_func_with_field!($crate::vmstate::vmstate_scalar_type, $tuple, 0); 308 const BASE: $crate::bindings::VMStateField = 309 $crate::call_func_with_field!($crate::vmstate::vmstate_base, $tuple, 0); 310 } 311 }; 312 } 313 314 // Transparent wrappers: just use the internal type 315 316 macro_rules! impl_vmstate_transparent { 317 ($type:ty where $base:tt: VMState $($where:tt)*) => { 318 unsafe impl<$base> VMState for $type where $base: VMState $($where)* { 319 const SCALAR_TYPE: VMStateFieldType = <$base as VMState>::SCALAR_TYPE; 320 const BASE: VMStateField = VMStateField { 321 size: mem::size_of::<$type>(), 322 ..<$base as VMState>::BASE 323 }; 324 const VARRAY_FLAG: VMStateFlags = <$base as VMState>::VARRAY_FLAG; 325 } 326 }; 327 } 328 329 impl_vmstate_transparent!(std::cell::Cell<T> where T: VMState); 330 impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState); 331 impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState); 332 impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState); 333 334 #[macro_export] 335 macro_rules! impl_vmstate_bitsized { 336 ($type:ty) => { 337 unsafe impl $crate::vmstate::VMState for $type { 338 const SCALAR_TYPE: $crate::vmstate::VMStateFieldType = 339 <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt 340 as ::bilge::prelude::Number>::UnderlyingType 341 as $crate::vmstate::VMState>::SCALAR_TYPE; 342 const BASE: $crate::bindings::VMStateField = 343 <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt 344 as ::bilge::prelude::Number>::UnderlyingType 345 as $crate::vmstate::VMState>::BASE; 346 const VARRAY_FLAG: $crate::bindings::VMStateFlags = 347 <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt 348 as ::bilge::prelude::Number>::UnderlyingType 349 as $crate::vmstate::VMState>::VARRAY_FLAG; 350 } 351 }; 352 } 353 354 // Scalar types using predefined VMStateInfos 355 356 macro_rules! impl_vmstate_scalar { 357 ($info:ident, $type:ty$(, $varray_flag:ident)?) => { 358 unsafe impl VMState for $type { 359 const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::$info; 360 const BASE: VMStateField = VMStateField { 361 size: mem::size_of::<$type>(), 362 flags: VMStateFlags::VMS_SINGLE, 363 ..Zeroable::ZERO 364 }; 365 $(const VARRAY_FLAG: VMStateFlags = VMStateFlags::$varray_flag;)? 366 } 367 }; 368 } 369 370 impl_vmstate_scalar!(vmstate_info_bool, bool); 371 impl_vmstate_scalar!(vmstate_info_int8, i8); 372 impl_vmstate_scalar!(vmstate_info_int16, i16); 373 impl_vmstate_scalar!(vmstate_info_int32, i32); 374 impl_vmstate_scalar!(vmstate_info_int64, i64); 375 impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY_UINT8); 376 impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY_UINT16); 377 impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY_UINT32); 378 impl_vmstate_scalar!(vmstate_info_uint64, u64); 379 impl_vmstate_scalar!(vmstate_info_timer, bindings::QEMUTimer); 380 381 // Pointer types using the underlying type's VMState plus VMS_POINTER 382 // Note that references are not supported, though references to cells 383 // could be allowed. 384 385 macro_rules! impl_vmstate_pointer { 386 ($type:ty where $base:tt: VMState $($where:tt)*) => { 387 unsafe impl<$base> VMState for $type where $base: VMState $($where)* { 388 const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE; 389 const BASE: VMStateField = <$base as VMState>::BASE.with_pointer_flag(); 390 } 391 }; 392 } 393 394 impl_vmstate_pointer!(*const T where T: VMState); 395 impl_vmstate_pointer!(*mut T where T: VMState); 396 impl_vmstate_pointer!(NonNull<T> where T: VMState); 397 398 // Unlike C pointers, Box is always non-null therefore there is no need 399 // to specify VMS_ALLOC. 400 impl_vmstate_pointer!(Box<T> where T: VMState); 401 402 // Arrays using the underlying type's VMState plus 403 // VMS_ARRAY/VMS_ARRAY_OF_POINTER 404 405 unsafe impl<T: VMState, const N: usize> VMState for [T; N] { 406 const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE; 407 const BASE: VMStateField = <T as VMState>::BASE.with_array_flag(N); 408 } 409 410 #[doc(alias = "VMSTATE_UNUSED_BUFFER")] 411 #[macro_export] 412 macro_rules! vmstate_unused_buffer { 413 ($field_exists_fn:expr, $version_id:expr, $size:expr) => {{ 414 $crate::bindings::VMStateField { 415 name: c_str!("unused").as_ptr(), 416 err_hint: ::core::ptr::null(), 417 offset: 0, 418 size: $size, 419 start: 0, 420 num: 0, 421 num_offset: 0, 422 size_offset: 0, 423 info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) }, 424 flags: VMStateFlags::VMS_BUFFER, 425 vmsd: ::core::ptr::null(), 426 version_id: $version_id, 427 struct_version_id: 0, 428 field_exists: $field_exists_fn, 429 } 430 }}; 431 } 432 433 #[doc(alias = "VMSTATE_UNUSED_V")] 434 #[macro_export] 435 macro_rules! vmstate_unused_v { 436 ($version_id:expr, $size:expr) => {{ 437 $crate::vmstate_unused_buffer!(None, $version_id, $size) 438 }}; 439 } 440 441 #[doc(alias = "VMSTATE_UNUSED")] 442 #[macro_export] 443 macro_rules! vmstate_unused { 444 ($size:expr) => {{ 445 $crate::vmstate_unused_v!(0, $size) 446 }}; 447 } 448 449 #[doc(alias = "VMSTATE_SINGLE_TEST")] 450 #[macro_export] 451 macro_rules! vmstate_single_test { 452 ($field_name:ident, $struct_name:ty, $field_exists_fn: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: 0, 462 num_offset: 0, 463 size_offset: 0, 464 info: unsafe { $info }, 465 flags: VMStateFlags::VMS_SINGLE, 466 vmsd: ::core::ptr::null(), 467 version_id: $version_id, 468 struct_version_id: 0, 469 field_exists: $field_exists_fn, 470 } 471 }}; 472 } 473 474 #[doc(alias = "VMSTATE_SINGLE")] 475 #[macro_export] 476 macro_rules! vmstate_single { 477 ($field_name:ident, $struct_name:ty, $version_id:expr, $info:expr, $size:expr) => {{ 478 $crate::vmstate_single_test!($field_name, $struct_name, None, $version_id, $info, $size) 479 }}; 480 } 481 482 #[doc(alias = "VMSTATE_UINT32_V")] 483 #[macro_export] 484 macro_rules! vmstate_uint32_v { 485 ($field_name:ident, $struct_name:ty, $version_id:expr) => {{ 486 $crate::vmstate_single!( 487 $field_name, 488 $struct_name, 489 $version_id, 490 ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32), 491 ::core::mem::size_of::<u32>() 492 ) 493 }}; 494 } 495 496 #[doc(alias = "VMSTATE_UINT32")] 497 #[macro_export] 498 macro_rules! vmstate_uint32 { 499 ($field_name:ident, $struct_name:ty) => {{ 500 $crate::vmstate_uint32_v!($field_name, $struct_name, 0) 501 }}; 502 } 503 504 #[doc(alias = "VMSTATE_ARRAY")] 505 #[macro_export] 506 macro_rules! vmstate_array { 507 ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr, $info:expr, $size:expr) => {{ 508 $crate::bindings::VMStateField { 509 name: ::core::concat!(::core::stringify!($field_name), 0) 510 .as_bytes() 511 .as_ptr() as *const ::std::os::raw::c_char, 512 err_hint: ::core::ptr::null(), 513 offset: $crate::offset_of!($struct_name, $field_name), 514 size: $size, 515 start: 0, 516 num: $length as _, 517 num_offset: 0, 518 size_offset: 0, 519 info: unsafe { $info }, 520 flags: VMStateFlags::VMS_ARRAY, 521 vmsd: ::core::ptr::null(), 522 version_id: $version_id, 523 struct_version_id: 0, 524 field_exists: None, 525 } 526 }}; 527 } 528 529 #[doc(alias = "VMSTATE_UINT32_ARRAY_V")] 530 #[macro_export] 531 macro_rules! vmstate_uint32_array_v { 532 ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr) => {{ 533 $crate::vmstate_array!( 534 $field_name, 535 $struct_name, 536 $length, 537 $version_id, 538 ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32), 539 ::core::mem::size_of::<u32>() 540 ) 541 }}; 542 } 543 544 #[doc(alias = "VMSTATE_UINT32_ARRAY")] 545 #[macro_export] 546 macro_rules! vmstate_uint32_array { 547 ($field_name:ident, $struct_name:ty, $length:expr) => {{ 548 $crate::vmstate_uint32_array_v!($field_name, $struct_name, $length, 0) 549 }}; 550 } 551 552 #[doc(alias = "VMSTATE_STRUCT_POINTER_V")] 553 #[macro_export] 554 macro_rules! vmstate_struct_pointer_v { 555 ($field_name:ident, $struct_name:ty, $version_id:expr, $vmsd:expr, $type:ty) => {{ 556 $crate::bindings::VMStateField { 557 name: ::core::concat!(::core::stringify!($field_name), 0) 558 .as_bytes() 559 .as_ptr() as *const ::std::os::raw::c_char, 560 err_hint: ::core::ptr::null(), 561 offset: $crate::offset_of!($struct_name, $field_name), 562 size: ::core::mem::size_of::<*const $type>(), 563 start: 0, 564 num: 0, 565 num_offset: 0, 566 size_offset: 0, 567 info: ::core::ptr::null(), 568 flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0), 569 vmsd: unsafe { $vmsd }, 570 version_id: $version_id, 571 struct_version_id: 0, 572 field_exists: None, 573 } 574 }}; 575 } 576 577 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER")] 578 #[macro_export] 579 macro_rules! vmstate_array_of_pointer { 580 ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $info:expr, $type:ty) => {{ 581 $crate::bindings::VMStateField { 582 name: ::core::concat!(::core::stringify!($field_name), 0) 583 .as_bytes() 584 .as_ptr() as *const ::std::os::raw::c_char, 585 version_id: $version_id, 586 num: $num as _, 587 info: unsafe { $info }, 588 size: ::core::mem::size_of::<*const $type>(), 589 flags: VMStateFlags(VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0), 590 offset: $crate::offset_of!($struct_name, $field_name), 591 err_hint: ::core::ptr::null(), 592 start: 0, 593 num_offset: 0, 594 size_offset: 0, 595 vmsd: ::core::ptr::null(), 596 struct_version_id: 0, 597 field_exists: None, 598 } 599 }}; 600 } 601 602 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER_TO_STRUCT")] 603 #[macro_export] 604 macro_rules! vmstate_array_of_pointer_to_struct { 605 ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $vmsd:expr, $type:ty) => {{ 606 $crate::bindings::VMStateField { 607 name: ::core::concat!(::core::stringify!($field_name), 0) 608 .as_bytes() 609 .as_ptr() as *const ::std::os::raw::c_char, 610 version_id: $version_id, 611 num: $num as _, 612 vmsd: unsafe { $vmsd }, 613 size: ::core::mem::size_of::<*const $type>(), 614 flags: VMStateFlags( 615 VMStateFlags::VMS_ARRAY.0 616 | VMStateFlags::VMS_STRUCT.0 617 | VMStateFlags::VMS_ARRAY_OF_POINTER.0, 618 ), 619 offset: $crate::offset_of!($struct_name, $field_name), 620 err_hint: ::core::ptr::null(), 621 start: 0, 622 num_offset: 0, 623 size_offset: 0, 624 vmsd: ::core::ptr::null(), 625 struct_version_id: 0, 626 field_exists: None, 627 } 628 }}; 629 } 630 631 // FIXME: including the `vmsd` field in a `const` is not possible without 632 // the const_refs_static feature (stabilized in Rust 1.83.0). Without it, 633 // it is not possible to use VMS_STRUCT in a transparent manner using 634 // `vmstate_of!`. While VMSTATE_CLOCK can at least try to be type-safe, 635 // VMSTATE_STRUCT includes $type only for documentation purposes; it 636 // is checked against $field_name and $struct_name, but not against $vmsd 637 // which is what really would matter. 638 #[doc(alias = "VMSTATE_STRUCT")] 639 #[macro_export] 640 macro_rules! vmstate_struct { 641 ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(,)?) => { 642 $crate::bindings::VMStateField { 643 name: ::core::concat!(::core::stringify!($field_name), "\0") 644 .as_bytes() 645 .as_ptr() as *const ::std::os::raw::c_char, 646 $(.num_offset: $crate::offset_of!($struct_name, $num),)? 647 offset: { 648 $crate::assert_field_type!($struct_name, $field_name, $type); 649 $crate::offset_of!($struct_name, $field_name) 650 }, 651 size: ::core::mem::size_of::<$type>(), 652 flags: $crate::bindings::VMStateFlags::VMS_STRUCT, 653 vmsd: unsafe { $vmsd }, 654 ..$crate::zeroable::Zeroable::ZERO $( 655 .with_varray_flag($crate::call_func_with_field!( 656 $crate::vmstate::vmstate_varray_flag, 657 $struct_name, 658 $num)) 659 $(.with_varray_multiply($factor))?)? 660 } 661 }; 662 } 663 664 #[doc(alias = "VMSTATE_CLOCK_V")] 665 #[macro_export] 666 macro_rules! vmstate_clock_v { 667 ($field_name:ident, $struct_name:ty, $version_id:expr) => {{ 668 $crate::vmstate_struct_pointer_v!( 669 $field_name, 670 $struct_name, 671 $version_id, 672 ::core::ptr::addr_of!($crate::bindings::vmstate_clock), 673 $crate::bindings::Clock 674 ) 675 }}; 676 } 677 678 #[doc(alias = "VMSTATE_CLOCK")] 679 #[macro_export] 680 macro_rules! vmstate_clock { 681 ($field_name:ident, $struct_name:ty) => {{ 682 $crate::vmstate_clock_v!($field_name, $struct_name, 0) 683 }}; 684 } 685 686 #[doc(alias = "VMSTATE_ARRAY_CLOCK_V")] 687 #[macro_export] 688 macro_rules! vmstate_array_clock_v { 689 ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr) => {{ 690 $crate::vmstate_array_of_pointer_to_struct!( 691 $field_name, 692 $struct_name, 693 $num, 694 $version_id, 695 ::core::ptr::addr_of!($crate::bindings::vmstate_clock), 696 $crate::bindings::Clock 697 ) 698 }}; 699 } 700 701 #[doc(alias = "VMSTATE_ARRAY_CLOCK")] 702 #[macro_export] 703 macro_rules! vmstate_array_clock { 704 ($field_name:ident, $struct_name:ty, $num:expr) => {{ 705 $crate::vmstate_array_clock_v!($field_name, $struct_name, $name, 0) 706 }}; 707 } 708 709 /// Helper macro to declare a list of 710 /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return 711 /// a pointer to the array of values it created. 712 #[macro_export] 713 macro_rules! vmstate_fields { 714 ($($field:expr),*$(,)*) => {{ 715 static _FIELDS: &[$crate::bindings::VMStateField] = &[ 716 $($field),*, 717 $crate::bindings::VMStateField { 718 flags: $crate::bindings::VMStateFlags::VMS_END, 719 ..$crate::zeroable::Zeroable::ZERO 720 } 721 ]; 722 _FIELDS.as_ptr() 723 }} 724 } 725 726 /// A transparent wrapper type for the `subsections` field of 727 /// [`VMStateDescription`]. 728 /// 729 /// This is necessary to be able to declare subsection descriptions as statics, 730 /// because the only way to implement `Sync` for a foreign type (and `*const` 731 /// pointers are foreign types in Rust) is to create a wrapper struct and 732 /// `unsafe impl Sync` for it. 733 /// 734 /// This struct is used in the 735 /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation. 736 #[repr(transparent)] 737 pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]); 738 739 unsafe impl Sync for VMStateSubsectionsWrapper {} 740 741 /// Helper macro to declare a list of subsections ([`VMStateDescription`]) 742 /// into a static and return a pointer to the array of pointers it created. 743 #[macro_export] 744 macro_rules! vmstate_subsections { 745 ($($subsection:expr),*$(,)*) => {{ 746 static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[ 747 $({ 748 static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection; 749 ::core::ptr::addr_of!(_SUBSECTION) 750 }),*, 751 ::core::ptr::null() 752 ]); 753 _SUBSECTIONS.0.as_ptr() 754 }} 755 } 756