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