xref: /qemu/rust/qemu-api/src/vmstate.rs (revision 2537f8309885013c4b04ae7b2888591ba0cb6ca7)
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