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 //! Some macros are direct equivalents to the C macros declared in 8 //! `include/migration/vmstate.h` while 9 //! [`vmstate_subsections`](crate::vmstate_subsections) and 10 //! [`vmstate_fields`](crate::vmstate_fields) are meant to be used when 11 //! declaring a device model state struct. 12 13 pub use crate::bindings::VMStateDescription; 14 15 #[doc(alias = "VMSTATE_UNUSED_BUFFER")] 16 #[macro_export] 17 macro_rules! vmstate_unused_buffer { 18 ($field_exists_fn:expr, $version_id:expr, $size:expr) => {{ 19 $crate::bindings::VMStateField { 20 name: c_str!("unused").as_ptr(), 21 err_hint: ::core::ptr::null(), 22 offset: 0, 23 size: $size, 24 start: 0, 25 num: 0, 26 num_offset: 0, 27 size_offset: 0, 28 info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) }, 29 flags: VMStateFlags::VMS_BUFFER, 30 vmsd: ::core::ptr::null(), 31 version_id: $version_id, 32 struct_version_id: 0, 33 field_exists: $field_exists_fn, 34 } 35 }}; 36 } 37 38 #[doc(alias = "VMSTATE_UNUSED_V")] 39 #[macro_export] 40 macro_rules! vmstate_unused_v { 41 ($version_id:expr, $size:expr) => {{ 42 $crate::vmstate_unused_buffer!(None, $version_id, $size) 43 }}; 44 } 45 46 #[doc(alias = "VMSTATE_UNUSED")] 47 #[macro_export] 48 macro_rules! vmstate_unused { 49 ($size:expr) => {{ 50 $crate::vmstate_unused_v!(0, $size) 51 }}; 52 } 53 54 #[doc(alias = "VMSTATE_SINGLE_TEST")] 55 #[macro_export] 56 macro_rules! vmstate_single_test { 57 ($field_name:ident, $struct_name:ty, $field_exists_fn:expr, $version_id:expr, $info:expr, $size:expr) => {{ 58 $crate::bindings::VMStateField { 59 name: ::core::concat!(::core::stringify!($field_name), 0) 60 .as_bytes() 61 .as_ptr() as *const ::std::os::raw::c_char, 62 err_hint: ::core::ptr::null(), 63 offset: $crate::offset_of!($struct_name, $field_name), 64 size: $size, 65 start: 0, 66 num: 0, 67 num_offset: 0, 68 size_offset: 0, 69 info: unsafe { $info }, 70 flags: VMStateFlags::VMS_SINGLE, 71 vmsd: ::core::ptr::null(), 72 version_id: $version_id, 73 struct_version_id: 0, 74 field_exists: $field_exists_fn, 75 } 76 }}; 77 } 78 79 #[doc(alias = "VMSTATE_SINGLE")] 80 #[macro_export] 81 macro_rules! vmstate_single { 82 ($field_name:ident, $struct_name:ty, $version_id:expr, $info:expr, $size:expr) => {{ 83 $crate::vmstate_single_test!($field_name, $struct_name, None, $version_id, $info, $size) 84 }}; 85 } 86 87 #[doc(alias = "VMSTATE_UINT32_V")] 88 #[macro_export] 89 macro_rules! vmstate_uint32_v { 90 ($field_name:ident, $struct_name:ty, $version_id:expr) => {{ 91 $crate::vmstate_single!( 92 $field_name, 93 $struct_name, 94 $version_id, 95 ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32), 96 ::core::mem::size_of::<u32>() 97 ) 98 }}; 99 } 100 101 #[doc(alias = "VMSTATE_UINT32")] 102 #[macro_export] 103 macro_rules! vmstate_uint32 { 104 ($field_name:ident, $struct_name:ty) => {{ 105 $crate::vmstate_uint32_v!($field_name, $struct_name, 0) 106 }}; 107 } 108 109 #[doc(alias = "VMSTATE_INT32_V")] 110 #[macro_export] 111 macro_rules! vmstate_int32_v { 112 ($field_name:ident, $struct_name:ty, $version_id:expr) => {{ 113 $crate::vmstate_single!( 114 $field_name, 115 $struct_name, 116 $version_id, 117 ::core::ptr::addr_of!($crate::bindings::vmstate_info_int32), 118 ::core::mem::size_of::<i32>() 119 ) 120 }}; 121 } 122 123 #[doc(alias = "VMSTATE_INT32")] 124 #[macro_export] 125 macro_rules! vmstate_int32 { 126 ($field_name:ident, $struct_name:ty) => {{ 127 $crate::vmstate_int32_v!($field_name, $struct_name, 0) 128 }}; 129 } 130 131 #[doc(alias = "VMSTATE_ARRAY")] 132 #[macro_export] 133 macro_rules! vmstate_array { 134 ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr, $info:expr, $size:expr) => {{ 135 $crate::bindings::VMStateField { 136 name: ::core::concat!(::core::stringify!($field_name), 0) 137 .as_bytes() 138 .as_ptr() as *const ::std::os::raw::c_char, 139 err_hint: ::core::ptr::null(), 140 offset: $crate::offset_of!($struct_name, $field_name), 141 size: $size, 142 start: 0, 143 num: $length as _, 144 num_offset: 0, 145 size_offset: 0, 146 info: unsafe { $info }, 147 flags: VMStateFlags::VMS_ARRAY, 148 vmsd: ::core::ptr::null(), 149 version_id: $version_id, 150 struct_version_id: 0, 151 field_exists: None, 152 } 153 }}; 154 } 155 156 #[doc(alias = "VMSTATE_UINT32_ARRAY_V")] 157 #[macro_export] 158 macro_rules! vmstate_uint32_array_v { 159 ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr) => {{ 160 $crate::vmstate_array!( 161 $field_name, 162 $struct_name, 163 $length, 164 $version_id, 165 ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32), 166 ::core::mem::size_of::<u32>() 167 ) 168 }}; 169 } 170 171 #[doc(alias = "VMSTATE_UINT32_ARRAY")] 172 #[macro_export] 173 macro_rules! vmstate_uint32_array { 174 ($field_name:ident, $struct_name:ty, $length:expr) => {{ 175 $crate::vmstate_uint32_array_v!($field_name, $struct_name, $length, 0) 176 }}; 177 } 178 179 #[doc(alias = "VMSTATE_STRUCT_POINTER_V")] 180 #[macro_export] 181 macro_rules! vmstate_struct_pointer_v { 182 ($field_name:ident, $struct_name:ty, $version_id:expr, $vmsd:expr, $type:ty) => {{ 183 $crate::bindings::VMStateField { 184 name: ::core::concat!(::core::stringify!($field_name), 0) 185 .as_bytes() 186 .as_ptr() as *const ::std::os::raw::c_char, 187 err_hint: ::core::ptr::null(), 188 offset: $crate::offset_of!($struct_name, $field_name), 189 size: ::core::mem::size_of::<*const $type>(), 190 start: 0, 191 num: 0, 192 num_offset: 0, 193 size_offset: 0, 194 info: ::core::ptr::null(), 195 flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0), 196 vmsd: unsafe { $vmsd }, 197 version_id: $version_id, 198 struct_version_id: 0, 199 field_exists: None, 200 } 201 }}; 202 } 203 204 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER")] 205 #[macro_export] 206 macro_rules! vmstate_array_of_pointer { 207 ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $info:expr, $type:ty) => {{ 208 $crate::bindings::VMStateField { 209 name: ::core::concat!(::core::stringify!($field_name), 0) 210 .as_bytes() 211 .as_ptr() as *const ::std::os::raw::c_char, 212 version_id: $version_id, 213 num: $num as _, 214 info: unsafe { $info }, 215 size: ::core::mem::size_of::<*const $type>(), 216 flags: VMStateFlags(VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0), 217 offset: $crate::offset_of!($struct_name, $field_name), 218 err_hint: ::core::ptr::null(), 219 start: 0, 220 num_offset: 0, 221 size_offset: 0, 222 vmsd: ::core::ptr::null(), 223 struct_version_id: 0, 224 field_exists: None, 225 } 226 }}; 227 } 228 229 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER_TO_STRUCT")] 230 #[macro_export] 231 macro_rules! vmstate_array_of_pointer_to_struct { 232 ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $vmsd:expr, $type:ty) => {{ 233 $crate::bindings::VMStateField { 234 name: ::core::concat!(::core::stringify!($field_name), 0) 235 .as_bytes() 236 .as_ptr() as *const ::std::os::raw::c_char, 237 version_id: $version_id, 238 num: $num as _, 239 vmsd: unsafe { $vmsd }, 240 size: ::core::mem::size_of::<*const $type>(), 241 flags: VMStateFlags( 242 VMStateFlags::VMS_ARRAY.0 243 | VMStateFlags::VMS_STRUCT.0 244 | VMStateFlags::VMS_ARRAY_OF_POINTER.0, 245 ), 246 offset: $crate::offset_of!($struct_name, $field_name), 247 err_hint: ::core::ptr::null(), 248 start: 0, 249 num_offset: 0, 250 size_offset: 0, 251 vmsd: ::core::ptr::null(), 252 struct_version_id: 0, 253 field_exists: None, 254 } 255 }}; 256 } 257 258 #[doc(alias = "VMSTATE_CLOCK_V")] 259 #[macro_export] 260 macro_rules! vmstate_clock_v { 261 ($field_name:ident, $struct_name:ty, $version_id:expr) => {{ 262 $crate::vmstate_struct_pointer_v!( 263 $field_name, 264 $struct_name, 265 $version_id, 266 ::core::ptr::addr_of!($crate::bindings::vmstate_clock), 267 $crate::bindings::Clock 268 ) 269 }}; 270 } 271 272 #[doc(alias = "VMSTATE_CLOCK")] 273 #[macro_export] 274 macro_rules! vmstate_clock { 275 ($field_name:ident, $struct_name:ty) => {{ 276 $crate::vmstate_clock_v!($field_name, $struct_name, 0) 277 }}; 278 } 279 280 #[doc(alias = "VMSTATE_ARRAY_CLOCK_V")] 281 #[macro_export] 282 macro_rules! vmstate_array_clock_v { 283 ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr) => {{ 284 $crate::vmstate_array_of_pointer_to_struct!( 285 $field_name, 286 $struct_name, 287 $num, 288 $version_id, 289 ::core::ptr::addr_of!($crate::bindings::vmstate_clock), 290 $crate::bindings::Clock 291 ) 292 }}; 293 } 294 295 #[doc(alias = "VMSTATE_ARRAY_CLOCK")] 296 #[macro_export] 297 macro_rules! vmstate_array_clock { 298 ($field_name:ident, $struct_name:ty, $num:expr) => {{ 299 $crate::vmstate_array_clock_v!($field_name, $struct_name, $name, 0) 300 }}; 301 } 302 303 /// Helper macro to declare a list of 304 /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return 305 /// a pointer to the array of values it created. 306 #[macro_export] 307 macro_rules! vmstate_fields { 308 ($($field:expr),*$(,)*) => {{ 309 static _FIELDS: &[$crate::bindings::VMStateField] = &[ 310 $($field),*, 311 $crate::bindings::VMStateField { 312 name: ::core::ptr::null(), 313 err_hint: ::core::ptr::null(), 314 offset: 0, 315 size: 0, 316 start: 0, 317 num: 0, 318 num_offset: 0, 319 size_offset: 0, 320 info: ::core::ptr::null(), 321 flags: VMStateFlags::VMS_END, 322 vmsd: ::core::ptr::null(), 323 version_id: 0, 324 struct_version_id: 0, 325 field_exists: None, 326 } 327 ]; 328 _FIELDS.as_ptr() 329 }} 330 } 331 332 /// A transparent wrapper type for the `subsections` field of 333 /// [`VMStateDescription`]. 334 /// 335 /// This is necessary to be able to declare subsection descriptions as statics, 336 /// because the only way to implement `Sync` for a foreign type (and `*const` 337 /// pointers are foreign types in Rust) is to create a wrapper struct and 338 /// `unsafe impl Sync` for it. 339 /// 340 /// This struct is used in the 341 /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation. 342 #[repr(transparent)] 343 pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]); 344 345 unsafe impl Sync for VMStateSubsectionsWrapper {} 346 347 /// Helper macro to declare a list of subsections ([`VMStateDescription`]) 348 /// into a static and return a pointer to the array of pointers it created. 349 #[macro_export] 350 macro_rules! vmstate_subsections { 351 ($($subsection:expr),*$(,)*) => {{ 352 static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[ 353 $({ 354 static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection; 355 ::core::ptr::addr_of!(_SUBSECTION) 356 }),*, 357 ::core::ptr::null() 358 ]); 359 _SUBSECTIONS.0.as_ptr() 360 }} 361 } 362