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; 23 24 pub use crate::bindings::{VMStateDescription, VMStateField}; 25 26 /// This macro is used to call a function with a generic argument bound 27 /// to the type of a field. The function must take a 28 /// [`PhantomData`]`<T>` argument; `T` is the type of 29 /// field `$field` in the `$typ` type. 30 /// 31 /// # Examples 32 /// 33 /// ``` 34 /// # use qemu_api::call_func_with_field; 35 /// # use core::marker::PhantomData; 36 /// const fn size_of_field<T>(_: PhantomData<T>) -> usize { 37 /// std::mem::size_of::<T>() 38 /// } 39 /// 40 /// struct Foo { 41 /// x: u16, 42 /// }; 43 /// // calls size_of_field::<u16>() 44 /// assert_eq!(call_func_with_field!(size_of_field, Foo, x), 2); 45 /// ``` 46 #[macro_export] 47 macro_rules! call_func_with_field { 48 // Based on the answer by user steffahn (Frank Steffahn) at 49 // https://users.rust-lang.org/t/inferring-type-of-field/122857 50 // and used under MIT license 51 ($func:expr, $typ:ty, $($field:tt).+) => { 52 $func(loop { 53 #![allow(unreachable_code)] 54 const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> { ::core::marker::PhantomData } 55 // Unreachable code is exempt from checks on uninitialized values. 56 // Use that trick to infer the type of this PhantomData. 57 break ::core::marker::PhantomData; 58 break phantom__(&{ let value__: $typ; value__.$($field).+ }); 59 }) 60 }; 61 } 62 63 /// A trait for types that can be included in a device's migration stream. It 64 /// provides the base contents of a `VMStateField` (minus the name and offset). 65 /// 66 /// # Safety 67 /// 68 /// The contents of this trait go straight into structs that are parsed by C 69 /// code and used to introspect into other structs. Be careful. 70 pub unsafe trait VMState { 71 /// The base contents of a `VMStateField` (minus the name and offset) for 72 /// the type that is implementing the trait. 73 const BASE: VMStateField; 74 } 75 76 /// Internal utility function to retrieve a type's `VMStateField`; 77 /// used by [`vmstate_of!`](crate::vmstate_of). 78 pub const fn vmstate_base<T: VMState>(_: PhantomData<T>) -> VMStateField { 79 T::BASE 80 } 81 82 /// Return the `VMStateField` for a field of a struct. The field must be 83 /// visible in the current scope. 84 /// 85 /// In order to support other types, the trait `VMState` must be implemented 86 /// for them. 87 #[macro_export] 88 macro_rules! vmstate_of { 89 ($struct_name:ty, $field_name:ident $(,)?) => { 90 $crate::bindings::VMStateField { 91 name: ::core::concat!(::core::stringify!($field_name), "\0") 92 .as_bytes() 93 .as_ptr() as *const ::std::os::raw::c_char, 94 offset: $crate::offset_of!($struct_name, $field_name), 95 // Compute most of the VMStateField from the type of the field. 96 ..$crate::call_func_with_field!( 97 $crate::vmstate::vmstate_base, 98 $struct_name, 99 $field_name 100 ) 101 } 102 }; 103 } 104 105 // Add a couple builder-style methods to VMStateField, allowing 106 // easy derivation of VMStateField constants from other types. 107 impl VMStateField { 108 #[must_use] 109 pub const fn with_version_id(mut self, version_id: i32) -> Self { 110 assert!(version_id >= 0); 111 self.version_id = version_id; 112 self 113 } 114 } 115 116 #[doc(alias = "VMSTATE_UNUSED_BUFFER")] 117 #[macro_export] 118 macro_rules! vmstate_unused_buffer { 119 ($field_exists_fn:expr, $version_id:expr, $size:expr) => {{ 120 $crate::bindings::VMStateField { 121 name: c_str!("unused").as_ptr(), 122 err_hint: ::core::ptr::null(), 123 offset: 0, 124 size: $size, 125 start: 0, 126 num: 0, 127 num_offset: 0, 128 size_offset: 0, 129 info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) }, 130 flags: VMStateFlags::VMS_BUFFER, 131 vmsd: ::core::ptr::null(), 132 version_id: $version_id, 133 struct_version_id: 0, 134 field_exists: $field_exists_fn, 135 } 136 }}; 137 } 138 139 #[doc(alias = "VMSTATE_UNUSED_V")] 140 #[macro_export] 141 macro_rules! vmstate_unused_v { 142 ($version_id:expr, $size:expr) => {{ 143 $crate::vmstate_unused_buffer!(None, $version_id, $size) 144 }}; 145 } 146 147 #[doc(alias = "VMSTATE_UNUSED")] 148 #[macro_export] 149 macro_rules! vmstate_unused { 150 ($size:expr) => {{ 151 $crate::vmstate_unused_v!(0, $size) 152 }}; 153 } 154 155 #[doc(alias = "VMSTATE_SINGLE_TEST")] 156 #[macro_export] 157 macro_rules! vmstate_single_test { 158 ($field_name:ident, $struct_name:ty, $field_exists_fn:expr, $version_id:expr, $info:expr, $size:expr) => {{ 159 $crate::bindings::VMStateField { 160 name: ::core::concat!(::core::stringify!($field_name), 0) 161 .as_bytes() 162 .as_ptr() as *const ::std::os::raw::c_char, 163 err_hint: ::core::ptr::null(), 164 offset: $crate::offset_of!($struct_name, $field_name), 165 size: $size, 166 start: 0, 167 num: 0, 168 num_offset: 0, 169 size_offset: 0, 170 info: unsafe { $info }, 171 flags: VMStateFlags::VMS_SINGLE, 172 vmsd: ::core::ptr::null(), 173 version_id: $version_id, 174 struct_version_id: 0, 175 field_exists: $field_exists_fn, 176 } 177 }}; 178 } 179 180 #[doc(alias = "VMSTATE_SINGLE")] 181 #[macro_export] 182 macro_rules! vmstate_single { 183 ($field_name:ident, $struct_name:ty, $version_id:expr, $info:expr, $size:expr) => {{ 184 $crate::vmstate_single_test!($field_name, $struct_name, None, $version_id, $info, $size) 185 }}; 186 } 187 188 #[doc(alias = "VMSTATE_UINT32_V")] 189 #[macro_export] 190 macro_rules! vmstate_uint32_v { 191 ($field_name:ident, $struct_name:ty, $version_id:expr) => {{ 192 $crate::vmstate_single!( 193 $field_name, 194 $struct_name, 195 $version_id, 196 ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32), 197 ::core::mem::size_of::<u32>() 198 ) 199 }}; 200 } 201 202 #[doc(alias = "VMSTATE_UINT32")] 203 #[macro_export] 204 macro_rules! vmstate_uint32 { 205 ($field_name:ident, $struct_name:ty) => {{ 206 $crate::vmstate_uint32_v!($field_name, $struct_name, 0) 207 }}; 208 } 209 210 #[doc(alias = "VMSTATE_ARRAY")] 211 #[macro_export] 212 macro_rules! vmstate_array { 213 ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr, $info:expr, $size:expr) => {{ 214 $crate::bindings::VMStateField { 215 name: ::core::concat!(::core::stringify!($field_name), 0) 216 .as_bytes() 217 .as_ptr() as *const ::std::os::raw::c_char, 218 err_hint: ::core::ptr::null(), 219 offset: $crate::offset_of!($struct_name, $field_name), 220 size: $size, 221 start: 0, 222 num: $length as _, 223 num_offset: 0, 224 size_offset: 0, 225 info: unsafe { $info }, 226 flags: VMStateFlags::VMS_ARRAY, 227 vmsd: ::core::ptr::null(), 228 version_id: $version_id, 229 struct_version_id: 0, 230 field_exists: None, 231 } 232 }}; 233 } 234 235 #[doc(alias = "VMSTATE_UINT32_ARRAY_V")] 236 #[macro_export] 237 macro_rules! vmstate_uint32_array_v { 238 ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr) => {{ 239 $crate::vmstate_array!( 240 $field_name, 241 $struct_name, 242 $length, 243 $version_id, 244 ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32), 245 ::core::mem::size_of::<u32>() 246 ) 247 }}; 248 } 249 250 #[doc(alias = "VMSTATE_UINT32_ARRAY")] 251 #[macro_export] 252 macro_rules! vmstate_uint32_array { 253 ($field_name:ident, $struct_name:ty, $length:expr) => {{ 254 $crate::vmstate_uint32_array_v!($field_name, $struct_name, $length, 0) 255 }}; 256 } 257 258 #[doc(alias = "VMSTATE_STRUCT_POINTER_V")] 259 #[macro_export] 260 macro_rules! vmstate_struct_pointer_v { 261 ($field_name:ident, $struct_name:ty, $version_id:expr, $vmsd:expr, $type:ty) => {{ 262 $crate::bindings::VMStateField { 263 name: ::core::concat!(::core::stringify!($field_name), 0) 264 .as_bytes() 265 .as_ptr() as *const ::std::os::raw::c_char, 266 err_hint: ::core::ptr::null(), 267 offset: $crate::offset_of!($struct_name, $field_name), 268 size: ::core::mem::size_of::<*const $type>(), 269 start: 0, 270 num: 0, 271 num_offset: 0, 272 size_offset: 0, 273 info: ::core::ptr::null(), 274 flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0), 275 vmsd: unsafe { $vmsd }, 276 version_id: $version_id, 277 struct_version_id: 0, 278 field_exists: None, 279 } 280 }}; 281 } 282 283 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER")] 284 #[macro_export] 285 macro_rules! vmstate_array_of_pointer { 286 ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $info:expr, $type:ty) => {{ 287 $crate::bindings::VMStateField { 288 name: ::core::concat!(::core::stringify!($field_name), 0) 289 .as_bytes() 290 .as_ptr() as *const ::std::os::raw::c_char, 291 version_id: $version_id, 292 num: $num as _, 293 info: unsafe { $info }, 294 size: ::core::mem::size_of::<*const $type>(), 295 flags: VMStateFlags(VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0), 296 offset: $crate::offset_of!($struct_name, $field_name), 297 err_hint: ::core::ptr::null(), 298 start: 0, 299 num_offset: 0, 300 size_offset: 0, 301 vmsd: ::core::ptr::null(), 302 struct_version_id: 0, 303 field_exists: None, 304 } 305 }}; 306 } 307 308 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER_TO_STRUCT")] 309 #[macro_export] 310 macro_rules! vmstate_array_of_pointer_to_struct { 311 ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $vmsd:expr, $type:ty) => {{ 312 $crate::bindings::VMStateField { 313 name: ::core::concat!(::core::stringify!($field_name), 0) 314 .as_bytes() 315 .as_ptr() as *const ::std::os::raw::c_char, 316 version_id: $version_id, 317 num: $num as _, 318 vmsd: unsafe { $vmsd }, 319 size: ::core::mem::size_of::<*const $type>(), 320 flags: VMStateFlags( 321 VMStateFlags::VMS_ARRAY.0 322 | VMStateFlags::VMS_STRUCT.0 323 | VMStateFlags::VMS_ARRAY_OF_POINTER.0, 324 ), 325 offset: $crate::offset_of!($struct_name, $field_name), 326 err_hint: ::core::ptr::null(), 327 start: 0, 328 num_offset: 0, 329 size_offset: 0, 330 vmsd: ::core::ptr::null(), 331 struct_version_id: 0, 332 field_exists: None, 333 } 334 }}; 335 } 336 337 #[doc(alias = "VMSTATE_CLOCK_V")] 338 #[macro_export] 339 macro_rules! vmstate_clock_v { 340 ($field_name:ident, $struct_name:ty, $version_id:expr) => {{ 341 $crate::vmstate_struct_pointer_v!( 342 $field_name, 343 $struct_name, 344 $version_id, 345 ::core::ptr::addr_of!($crate::bindings::vmstate_clock), 346 $crate::bindings::Clock 347 ) 348 }}; 349 } 350 351 #[doc(alias = "VMSTATE_CLOCK")] 352 #[macro_export] 353 macro_rules! vmstate_clock { 354 ($field_name:ident, $struct_name:ty) => {{ 355 $crate::vmstate_clock_v!($field_name, $struct_name, 0) 356 }}; 357 } 358 359 #[doc(alias = "VMSTATE_ARRAY_CLOCK_V")] 360 #[macro_export] 361 macro_rules! vmstate_array_clock_v { 362 ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr) => {{ 363 $crate::vmstate_array_of_pointer_to_struct!( 364 $field_name, 365 $struct_name, 366 $num, 367 $version_id, 368 ::core::ptr::addr_of!($crate::bindings::vmstate_clock), 369 $crate::bindings::Clock 370 ) 371 }}; 372 } 373 374 #[doc(alias = "VMSTATE_ARRAY_CLOCK")] 375 #[macro_export] 376 macro_rules! vmstate_array_clock { 377 ($field_name:ident, $struct_name:ty, $num:expr) => {{ 378 $crate::vmstate_array_clock_v!($field_name, $struct_name, $name, 0) 379 }}; 380 } 381 382 /// Helper macro to declare a list of 383 /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return 384 /// a pointer to the array of values it created. 385 #[macro_export] 386 macro_rules! vmstate_fields { 387 ($($field:expr),*$(,)*) => {{ 388 static _FIELDS: &[$crate::bindings::VMStateField] = &[ 389 $($field),*, 390 $crate::bindings::VMStateField { 391 name: ::core::ptr::null(), 392 err_hint: ::core::ptr::null(), 393 offset: 0, 394 size: 0, 395 start: 0, 396 num: 0, 397 num_offset: 0, 398 size_offset: 0, 399 info: ::core::ptr::null(), 400 flags: VMStateFlags::VMS_END, 401 vmsd: ::core::ptr::null(), 402 version_id: 0, 403 struct_version_id: 0, 404 field_exists: None, 405 } 406 ]; 407 _FIELDS.as_ptr() 408 }} 409 } 410 411 /// A transparent wrapper type for the `subsections` field of 412 /// [`VMStateDescription`]. 413 /// 414 /// This is necessary to be able to declare subsection descriptions as statics, 415 /// because the only way to implement `Sync` for a foreign type (and `*const` 416 /// pointers are foreign types in Rust) is to create a wrapper struct and 417 /// `unsafe impl Sync` for it. 418 /// 419 /// This struct is used in the 420 /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation. 421 #[repr(transparent)] 422 pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]); 423 424 unsafe impl Sync for VMStateSubsectionsWrapper {} 425 426 /// Helper macro to declare a list of subsections ([`VMStateDescription`]) 427 /// into a static and return a pointer to the array of pointers it created. 428 #[macro_export] 429 macro_rules! vmstate_subsections { 430 ($($subsection:expr),*$(,)*) => {{ 431 static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[ 432 $({ 433 static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection; 434 ::core::ptr::addr_of!(_SUBSECTION) 435 }),*, 436 ::core::ptr::null() 437 ]); 438 _SUBSECTIONS.0.as_ptr() 439 }} 440 } 441