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