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_ARRAY")] 110 #[macro_export] 111 macro_rules! vmstate_array { 112 ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr, $info:expr, $size:expr) => {{ 113 $crate::bindings::VMStateField { 114 name: ::core::concat!(::core::stringify!($field_name), 0) 115 .as_bytes() 116 .as_ptr() as *const ::std::os::raw::c_char, 117 err_hint: ::core::ptr::null(), 118 offset: $crate::offset_of!($struct_name, $field_name), 119 size: $size, 120 start: 0, 121 num: $length as _, 122 num_offset: 0, 123 size_offset: 0, 124 info: unsafe { $info }, 125 flags: VMStateFlags::VMS_ARRAY, 126 vmsd: ::core::ptr::null(), 127 version_id: $version_id, 128 struct_version_id: 0, 129 field_exists: None, 130 } 131 }}; 132 } 133 134 #[doc(alias = "VMSTATE_UINT32_ARRAY_V")] 135 #[macro_export] 136 macro_rules! vmstate_uint32_array_v { 137 ($field_name:ident, $struct_name:ty, $length:expr, $version_id:expr) => {{ 138 $crate::vmstate_array!( 139 $field_name, 140 $struct_name, 141 $length, 142 $version_id, 143 ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32), 144 ::core::mem::size_of::<u32>() 145 ) 146 }}; 147 } 148 149 #[doc(alias = "VMSTATE_UINT32_ARRAY")] 150 #[macro_export] 151 macro_rules! vmstate_uint32_array { 152 ($field_name:ident, $struct_name:ty, $length:expr) => {{ 153 $crate::vmstate_uint32_array_v!($field_name, $struct_name, $length, 0) 154 }}; 155 } 156 157 #[doc(alias = "VMSTATE_STRUCT_POINTER_V")] 158 #[macro_export] 159 macro_rules! vmstate_struct_pointer_v { 160 ($field_name:ident, $struct_name:ty, $version_id:expr, $vmsd:expr, $type:ty) => {{ 161 $crate::bindings::VMStateField { 162 name: ::core::concat!(::core::stringify!($field_name), 0) 163 .as_bytes() 164 .as_ptr() as *const ::std::os::raw::c_char, 165 err_hint: ::core::ptr::null(), 166 offset: $crate::offset_of!($struct_name, $field_name), 167 size: ::core::mem::size_of::<*const $type>(), 168 start: 0, 169 num: 0, 170 num_offset: 0, 171 size_offset: 0, 172 info: ::core::ptr::null(), 173 flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0), 174 vmsd: unsafe { $vmsd }, 175 version_id: $version_id, 176 struct_version_id: 0, 177 field_exists: None, 178 } 179 }}; 180 } 181 182 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER")] 183 #[macro_export] 184 macro_rules! vmstate_array_of_pointer { 185 ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $info:expr, $type:ty) => {{ 186 $crate::bindings::VMStateField { 187 name: ::core::concat!(::core::stringify!($field_name), 0) 188 .as_bytes() 189 .as_ptr() as *const ::std::os::raw::c_char, 190 version_id: $version_id, 191 num: $num as _, 192 info: unsafe { $info }, 193 size: ::core::mem::size_of::<*const $type>(), 194 flags: VMStateFlags(VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0), 195 offset: $crate::offset_of!($struct_name, $field_name), 196 err_hint: ::core::ptr::null(), 197 start: 0, 198 num_offset: 0, 199 size_offset: 0, 200 vmsd: ::core::ptr::null(), 201 struct_version_id: 0, 202 field_exists: None, 203 } 204 }}; 205 } 206 207 #[doc(alias = "VMSTATE_ARRAY_OF_POINTER_TO_STRUCT")] 208 #[macro_export] 209 macro_rules! vmstate_array_of_pointer_to_struct { 210 ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr, $vmsd:expr, $type:ty) => {{ 211 $crate::bindings::VMStateField { 212 name: ::core::concat!(::core::stringify!($field_name), 0) 213 .as_bytes() 214 .as_ptr() as *const ::std::os::raw::c_char, 215 version_id: $version_id, 216 num: $num as _, 217 vmsd: unsafe { $vmsd }, 218 size: ::core::mem::size_of::<*const $type>(), 219 flags: VMStateFlags( 220 VMStateFlags::VMS_ARRAY.0 221 | VMStateFlags::VMS_STRUCT.0 222 | VMStateFlags::VMS_ARRAY_OF_POINTER.0, 223 ), 224 offset: $crate::offset_of!($struct_name, $field_name), 225 err_hint: ::core::ptr::null(), 226 start: 0, 227 num_offset: 0, 228 size_offset: 0, 229 vmsd: ::core::ptr::null(), 230 struct_version_id: 0, 231 field_exists: None, 232 } 233 }}; 234 } 235 236 #[doc(alias = "VMSTATE_CLOCK_V")] 237 #[macro_export] 238 macro_rules! vmstate_clock_v { 239 ($field_name:ident, $struct_name:ty, $version_id:expr) => {{ 240 $crate::vmstate_struct_pointer_v!( 241 $field_name, 242 $struct_name, 243 $version_id, 244 ::core::ptr::addr_of!($crate::bindings::vmstate_clock), 245 $crate::bindings::Clock 246 ) 247 }}; 248 } 249 250 #[doc(alias = "VMSTATE_CLOCK")] 251 #[macro_export] 252 macro_rules! vmstate_clock { 253 ($field_name:ident, $struct_name:ty) => {{ 254 $crate::vmstate_clock_v!($field_name, $struct_name, 0) 255 }}; 256 } 257 258 #[doc(alias = "VMSTATE_ARRAY_CLOCK_V")] 259 #[macro_export] 260 macro_rules! vmstate_array_clock_v { 261 ($field_name:ident, $struct_name:ty, $num:expr, $version_id:expr) => {{ 262 $crate::vmstate_array_of_pointer_to_struct!( 263 $field_name, 264 $struct_name, 265 $num, 266 $version_id, 267 ::core::ptr::addr_of!($crate::bindings::vmstate_clock), 268 $crate::bindings::Clock 269 ) 270 }}; 271 } 272 273 #[doc(alias = "VMSTATE_ARRAY_CLOCK")] 274 #[macro_export] 275 macro_rules! vmstate_array_clock { 276 ($field_name:ident, $struct_name:ty, $num:expr) => {{ 277 $crate::vmstate_array_clock_v!($field_name, $struct_name, $name, 0) 278 }}; 279 } 280 281 /// Helper macro to declare a list of 282 /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return 283 /// a pointer to the array of values it created. 284 #[macro_export] 285 macro_rules! vmstate_fields { 286 ($($field:expr),*$(,)*) => {{ 287 static _FIELDS: &[$crate::bindings::VMStateField] = &[ 288 $($field),*, 289 $crate::bindings::VMStateField { 290 name: ::core::ptr::null(), 291 err_hint: ::core::ptr::null(), 292 offset: 0, 293 size: 0, 294 start: 0, 295 num: 0, 296 num_offset: 0, 297 size_offset: 0, 298 info: ::core::ptr::null(), 299 flags: VMStateFlags::VMS_END, 300 vmsd: ::core::ptr::null(), 301 version_id: 0, 302 struct_version_id: 0, 303 field_exists: None, 304 } 305 ]; 306 _FIELDS.as_ptr() 307 }} 308 } 309 310 /// A transparent wrapper type for the `subsections` field of 311 /// [`VMStateDescription`]. 312 /// 313 /// This is necessary to be able to declare subsection descriptions as statics, 314 /// because the only way to implement `Sync` for a foreign type (and `*const` 315 /// pointers are foreign types in Rust) is to create a wrapper struct and 316 /// `unsafe impl Sync` for it. 317 /// 318 /// This struct is used in the 319 /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation. 320 #[repr(transparent)] 321 pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]); 322 323 unsafe impl Sync for VMStateSubsectionsWrapper {} 324 325 /// Helper macro to declare a list of subsections ([`VMStateDescription`]) 326 /// into a static and return a pointer to the array of pointers it created. 327 #[macro_export] 328 macro_rules! vmstate_subsections { 329 ($($subsection:expr),*$(,)*) => {{ 330 static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[ 331 $({ 332 static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection; 333 ::core::ptr::addr_of!(_SUBSECTION) 334 }),*, 335 ::core::ptr::null() 336 ]); 337 _SUBSECTIONS.0.as_ptr() 338 }} 339 } 340