10a65e412SManos Pitsidianakis // Copyright 2024, Linaro Limited 20a65e412SManos Pitsidianakis // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org> 30a65e412SManos Pitsidianakis // SPDX-License-Identifier: GPL-2.0-or-later 40a65e412SManos Pitsidianakis 50a65e412SManos Pitsidianakis //! Helper macros to declare migration state for device models. 60a65e412SManos Pitsidianakis //! 700f89716SPaolo Bonzini //! This module includes four families of macros: 80d43ddaeSPaolo Bonzini //! 90d43ddaeSPaolo Bonzini //! * [`vmstate_unused!`](crate::vmstate_unused) and 100d43ddaeSPaolo Bonzini //! [`vmstate_of!`](crate::vmstate_of), which are used to express the 110d43ddaeSPaolo Bonzini //! migration format for a struct. This is based on the [`VMState`] trait, 12*aef5ac86SZhao Liu //! which is defined by all migratable types. 130d43ddaeSPaolo Bonzini //! 1400f89716SPaolo Bonzini //! * [`impl_vmstate_forward`](crate::impl_vmstate_forward) and 1500f89716SPaolo Bonzini //! [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), which help with 1600f89716SPaolo Bonzini //! the definition of the [`VMState`] trait (respectively for transparent 1700f89716SPaolo Bonzini //! structs and for `bilge`-defined types) 1800f89716SPaolo Bonzini //! 190d43ddaeSPaolo Bonzini //! * helper macros to declare a device model state struct, in particular 200a65e412SManos Pitsidianakis //! [`vmstate_subsections`](crate::vmstate_subsections) and 210d43ddaeSPaolo Bonzini //! [`vmstate_fields`](crate::vmstate_fields). 220d43ddaeSPaolo Bonzini //! 230d43ddaeSPaolo Bonzini //! * direct equivalents to the C macros declared in 249d489949SPaolo Bonzini //! `include/migration/vmstate.h`. These are not type-safe and only provide 259d489949SPaolo Bonzini //! functionality that is missing from `vmstate_of!`. 260a65e412SManos Pitsidianakis 2780aa3045SPaolo Bonzini use core::{marker::PhantomData, mem, ptr::NonNull}; 28e4fb0be1SPaolo Bonzini use std::ffi::{c_int, c_void}; 290d43ddaeSPaolo Bonzini 300d43ddaeSPaolo Bonzini pub use crate::bindings::{VMStateDescription, VMStateField}; 31b1310037SZhao Liu use crate::{ 32b1310037SZhao Liu bindings::VMStateFlags, callbacks::FnCall, prelude::*, qom::Owned, zeroable::Zeroable, 33b1310037SZhao Liu }; 340d43ddaeSPaolo Bonzini 350d43ddaeSPaolo Bonzini /// This macro is used to call a function with a generic argument bound 360d43ddaeSPaolo Bonzini /// to the type of a field. The function must take a 370d43ddaeSPaolo Bonzini /// [`PhantomData`]`<T>` argument; `T` is the type of 380d43ddaeSPaolo Bonzini /// field `$field` in the `$typ` type. 390d43ddaeSPaolo Bonzini /// 400d43ddaeSPaolo Bonzini /// # Examples 410d43ddaeSPaolo Bonzini /// 420d43ddaeSPaolo Bonzini /// ``` 430d43ddaeSPaolo Bonzini /// # use qemu_api::call_func_with_field; 440d43ddaeSPaolo Bonzini /// # use core::marker::PhantomData; 450d43ddaeSPaolo Bonzini /// const fn size_of_field<T>(_: PhantomData<T>) -> usize { 460d43ddaeSPaolo Bonzini /// std::mem::size_of::<T>() 470d43ddaeSPaolo Bonzini /// } 480d43ddaeSPaolo Bonzini /// 490d43ddaeSPaolo Bonzini /// struct Foo { 500d43ddaeSPaolo Bonzini /// x: u16, 510d43ddaeSPaolo Bonzini /// }; 520d43ddaeSPaolo Bonzini /// // calls size_of_field::<u16>() 530d43ddaeSPaolo Bonzini /// assert_eq!(call_func_with_field!(size_of_field, Foo, x), 2); 540d43ddaeSPaolo Bonzini /// ``` 550d43ddaeSPaolo Bonzini #[macro_export] 560d43ddaeSPaolo Bonzini macro_rules! call_func_with_field { 570d43ddaeSPaolo Bonzini // Based on the answer by user steffahn (Frank Steffahn) at 580d43ddaeSPaolo Bonzini // https://users.rust-lang.org/t/inferring-type-of-field/122857 590d43ddaeSPaolo Bonzini // and used under MIT license 600d43ddaeSPaolo Bonzini ($func:expr, $typ:ty, $($field:tt).+) => { 610d43ddaeSPaolo Bonzini $func(loop { 620d43ddaeSPaolo Bonzini #![allow(unreachable_code)] 630d43ddaeSPaolo Bonzini const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> { ::core::marker::PhantomData } 640d43ddaeSPaolo Bonzini // Unreachable code is exempt from checks on uninitialized values. 650d43ddaeSPaolo Bonzini // Use that trick to infer the type of this PhantomData. 660d43ddaeSPaolo Bonzini break ::core::marker::PhantomData; 670d43ddaeSPaolo Bonzini break phantom__(&{ let value__: $typ; value__.$($field).+ }); 680d43ddaeSPaolo Bonzini }) 690d43ddaeSPaolo Bonzini }; 700d43ddaeSPaolo Bonzini } 710d43ddaeSPaolo Bonzini 72f2cb78bdSPaolo Bonzini /// Workaround for lack of `const_refs_static`: references to global variables 73f2cb78bdSPaolo Bonzini /// can be included in a `static`, but not in a `const`; unfortunately, this 74f2cb78bdSPaolo Bonzini /// is exactly what would go in the `VMStateField`'s `info` member. 75f2cb78bdSPaolo Bonzini /// 76f2cb78bdSPaolo Bonzini /// This enum contains the contents of the `VMStateField`'s `info` member, 77f2cb78bdSPaolo Bonzini /// but as an `enum` instead of a pointer. 78f2cb78bdSPaolo Bonzini #[allow(non_camel_case_types)] 79f2cb78bdSPaolo Bonzini pub enum VMStateFieldType { 80f2cb78bdSPaolo Bonzini null, 81f2cb78bdSPaolo Bonzini vmstate_info_bool, 82f2cb78bdSPaolo Bonzini vmstate_info_int8, 83f2cb78bdSPaolo Bonzini vmstate_info_int16, 84f2cb78bdSPaolo Bonzini vmstate_info_int32, 85f2cb78bdSPaolo Bonzini vmstate_info_int64, 86f2cb78bdSPaolo Bonzini vmstate_info_uint8, 87f2cb78bdSPaolo Bonzini vmstate_info_uint16, 88f2cb78bdSPaolo Bonzini vmstate_info_uint32, 89f2cb78bdSPaolo Bonzini vmstate_info_uint64, 90f2cb78bdSPaolo Bonzini vmstate_info_timer, 91f2cb78bdSPaolo Bonzini } 92f2cb78bdSPaolo Bonzini 93f2cb78bdSPaolo Bonzini /// Workaround for lack of `const_refs_static`. Converts a `VMStateFieldType` 94f2cb78bdSPaolo Bonzini /// to a `*const VMStateInfo`, for inclusion in a `VMStateField`. 95f2cb78bdSPaolo Bonzini #[macro_export] 96f2cb78bdSPaolo Bonzini macro_rules! info_enum_to_ref { 97f2cb78bdSPaolo Bonzini ($e:expr) => { 98f2cb78bdSPaolo Bonzini unsafe { 99f2cb78bdSPaolo Bonzini match $e { 100f2cb78bdSPaolo Bonzini $crate::vmstate::VMStateFieldType::null => ::core::ptr::null(), 101f2cb78bdSPaolo Bonzini $crate::vmstate::VMStateFieldType::vmstate_info_bool => { 102f2cb78bdSPaolo Bonzini ::core::ptr::addr_of!($crate::bindings::vmstate_info_bool) 103f2cb78bdSPaolo Bonzini } 104f2cb78bdSPaolo Bonzini $crate::vmstate::VMStateFieldType::vmstate_info_int8 => { 105f2cb78bdSPaolo Bonzini ::core::ptr::addr_of!($crate::bindings::vmstate_info_int8) 106f2cb78bdSPaolo Bonzini } 107f2cb78bdSPaolo Bonzini $crate::vmstate::VMStateFieldType::vmstate_info_int16 => { 108f2cb78bdSPaolo Bonzini ::core::ptr::addr_of!($crate::bindings::vmstate_info_int16) 109f2cb78bdSPaolo Bonzini } 110f2cb78bdSPaolo Bonzini $crate::vmstate::VMStateFieldType::vmstate_info_int32 => { 111f2cb78bdSPaolo Bonzini ::core::ptr::addr_of!($crate::bindings::vmstate_info_int32) 112f2cb78bdSPaolo Bonzini } 113f2cb78bdSPaolo Bonzini $crate::vmstate::VMStateFieldType::vmstate_info_int64 => { 114f2cb78bdSPaolo Bonzini ::core::ptr::addr_of!($crate::bindings::vmstate_info_int64) 115f2cb78bdSPaolo Bonzini } 116f2cb78bdSPaolo Bonzini $crate::vmstate::VMStateFieldType::vmstate_info_uint8 => { 117f2cb78bdSPaolo Bonzini ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint8) 118f2cb78bdSPaolo Bonzini } 119f2cb78bdSPaolo Bonzini $crate::vmstate::VMStateFieldType::vmstate_info_uint16 => { 120f2cb78bdSPaolo Bonzini ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint16) 121f2cb78bdSPaolo Bonzini } 122f2cb78bdSPaolo Bonzini $crate::vmstate::VMStateFieldType::vmstate_info_uint32 => { 123f2cb78bdSPaolo Bonzini ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32) 124f2cb78bdSPaolo Bonzini } 125f2cb78bdSPaolo Bonzini $crate::vmstate::VMStateFieldType::vmstate_info_uint64 => { 126f2cb78bdSPaolo Bonzini ::core::ptr::addr_of!($crate::bindings::vmstate_info_uint64) 127f2cb78bdSPaolo Bonzini } 128f2cb78bdSPaolo Bonzini $crate::vmstate::VMStateFieldType::vmstate_info_timer => { 129f2cb78bdSPaolo Bonzini ::core::ptr::addr_of!($crate::bindings::vmstate_info_timer) 130f2cb78bdSPaolo Bonzini } 131f2cb78bdSPaolo Bonzini } 132f2cb78bdSPaolo Bonzini } 133f2cb78bdSPaolo Bonzini }; 134f2cb78bdSPaolo Bonzini } 135f2cb78bdSPaolo Bonzini 1360d43ddaeSPaolo Bonzini /// A trait for types that can be included in a device's migration stream. It 1370d43ddaeSPaolo Bonzini /// provides the base contents of a `VMStateField` (minus the name and offset). 1380d43ddaeSPaolo Bonzini /// 1390d43ddaeSPaolo Bonzini /// # Safety 1400d43ddaeSPaolo Bonzini /// 1410d43ddaeSPaolo Bonzini /// The contents of this trait go straight into structs that are parsed by C 14200f89716SPaolo Bonzini /// code and used to introspect into other structs. Generally, you don't need 14300f89716SPaolo Bonzini /// to implement it except via macros that do it for you, such as 14400f89716SPaolo Bonzini /// `impl_vmstate_bitsized!`. 1450d43ddaeSPaolo Bonzini pub unsafe trait VMState { 146f2cb78bdSPaolo Bonzini /// The `info` member of a `VMStateField` is a pointer and as such cannot 147f2cb78bdSPaolo Bonzini /// yet be included in the [`BASE`](VMState::BASE) associated constant; 148f2cb78bdSPaolo Bonzini /// this is only allowed by Rust 1.83.0 and newer. For now, include the 149f2cb78bdSPaolo Bonzini /// member as an enum which is stored in a separate constant. 150f2cb78bdSPaolo Bonzini const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::null; 151f2cb78bdSPaolo Bonzini 1520d43ddaeSPaolo Bonzini /// The base contents of a `VMStateField` (minus the name and offset) for 1530d43ddaeSPaolo Bonzini /// the type that is implementing the trait. 1540d43ddaeSPaolo Bonzini const BASE: VMStateField; 1555b024b4eSPaolo Bonzini 1565b024b4eSPaolo Bonzini /// A flag that is added to another field's `VMStateField` to specify the 1575b024b4eSPaolo Bonzini /// length's type in a variable-sized array. If this is not a supported 1585b024b4eSPaolo Bonzini /// type for the length (i.e. if it is not `u8`, `u16`, `u32`), using it 1595b024b4eSPaolo Bonzini /// in a call to [`vmstate_of!`](crate::vmstate_of) will cause a 1605b024b4eSPaolo Bonzini /// compile-time error. 1615b024b4eSPaolo Bonzini const VARRAY_FLAG: VMStateFlags = { 1625b024b4eSPaolo Bonzini panic!("invalid type for variable-sized array"); 1635b024b4eSPaolo Bonzini }; 1640d43ddaeSPaolo Bonzini } 1650d43ddaeSPaolo Bonzini 166f2cb78bdSPaolo Bonzini /// Internal utility function to retrieve a type's `VMStateFieldType`; 167f2cb78bdSPaolo Bonzini /// used by [`vmstate_of!`](crate::vmstate_of). 168f2cb78bdSPaolo Bonzini pub const fn vmstate_scalar_type<T: VMState>(_: PhantomData<T>) -> VMStateFieldType { 169f2cb78bdSPaolo Bonzini T::SCALAR_TYPE 170f2cb78bdSPaolo Bonzini } 171f2cb78bdSPaolo Bonzini 1720d43ddaeSPaolo Bonzini /// Internal utility function to retrieve a type's `VMStateField`; 1730d43ddaeSPaolo Bonzini /// used by [`vmstate_of!`](crate::vmstate_of). 1740d43ddaeSPaolo Bonzini pub const fn vmstate_base<T: VMState>(_: PhantomData<T>) -> VMStateField { 1750d43ddaeSPaolo Bonzini T::BASE 1760d43ddaeSPaolo Bonzini } 1770d43ddaeSPaolo Bonzini 1785b024b4eSPaolo Bonzini /// Internal utility function to retrieve a type's `VMStateFlags` when it 1795b024b4eSPaolo Bonzini /// is used as the element count of a `VMSTATE_VARRAY`; used by 1805b024b4eSPaolo Bonzini /// [`vmstate_of!`](crate::vmstate_of). 1815b024b4eSPaolo Bonzini pub const fn vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags { 1825b024b4eSPaolo Bonzini T::VARRAY_FLAG 1835b024b4eSPaolo Bonzini } 1845b024b4eSPaolo Bonzini 1850d43ddaeSPaolo Bonzini /// Return the `VMStateField` for a field of a struct. The field must be 1860d43ddaeSPaolo Bonzini /// visible in the current scope. 1870d43ddaeSPaolo Bonzini /// 188f2cb78bdSPaolo Bonzini /// Only a limited set of types is supported out of the box: 189f2cb78bdSPaolo Bonzini /// * scalar types (integer and `bool`) 190f2cb78bdSPaolo Bonzini /// * the C struct `QEMUTimer` 191f2cb78bdSPaolo Bonzini /// * a transparent wrapper for any of the above (`Cell`, `UnsafeCell`, 192ee7d3aecSPaolo Bonzini /// [`BqlCell`], [`BqlRefCell`] 193f2cb78bdSPaolo Bonzini /// * a raw pointer to any of the above 194ee7d3aecSPaolo Bonzini /// * a `NonNull` pointer, a `Box` or an [`Owned`] for any of the above 195f2cb78bdSPaolo Bonzini /// * an array of any of the above 196f2cb78bdSPaolo Bonzini /// 1970d43ddaeSPaolo Bonzini /// In order to support other types, the trait `VMState` must be implemented 19800f89716SPaolo Bonzini /// for them. The macros 19900f89716SPaolo Bonzini /// [`impl_vmstate_bitsized!`](crate::impl_vmstate_bitsized) 20000f89716SPaolo Bonzini /// and [`impl_vmstate_forward!`](crate::impl_vmstate_forward) help with this. 2010d43ddaeSPaolo Bonzini #[macro_export] 2020d43ddaeSPaolo Bonzini macro_rules! vmstate_of { 2036f8e6aedSZhao Liu ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(, $test_fn:expr)? $(,)?) => { 2040d43ddaeSPaolo Bonzini $crate::bindings::VMStateField { 2050d43ddaeSPaolo Bonzini name: ::core::concat!(::core::stringify!($field_name), "\0") 2060d43ddaeSPaolo Bonzini .as_bytes() 2070d43ddaeSPaolo Bonzini .as_ptr() as *const ::std::os::raw::c_char, 208b134a09fSPaolo Bonzini offset: ::std::mem::offset_of!($struct_name, $field_name), 209b134a09fSPaolo Bonzini $(num_offset: ::std::mem::offset_of!($struct_name, $num),)? 2106f8e6aedSZhao Liu $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)? 211f2cb78bdSPaolo Bonzini // The calls to `call_func_with_field!` are the magic that 212f2cb78bdSPaolo Bonzini // computes most of the VMStateField from the type of the field. 213f2cb78bdSPaolo Bonzini info: $crate::info_enum_to_ref!($crate::call_func_with_field!( 214f2cb78bdSPaolo Bonzini $crate::vmstate::vmstate_scalar_type, 215f2cb78bdSPaolo Bonzini $struct_name, 216f2cb78bdSPaolo Bonzini $field_name 217f2cb78bdSPaolo Bonzini )), 2180d43ddaeSPaolo Bonzini ..$crate::call_func_with_field!( 2190d43ddaeSPaolo Bonzini $crate::vmstate::vmstate_base, 2200d43ddaeSPaolo Bonzini $struct_name, 2210d43ddaeSPaolo Bonzini $field_name 2225b024b4eSPaolo Bonzini )$(.with_varray_flag($crate::call_func_with_field!( 2235b024b4eSPaolo Bonzini $crate::vmstate::vmstate_varray_flag, 2245b024b4eSPaolo Bonzini $struct_name, 2255b024b4eSPaolo Bonzini $num)) 2265b024b4eSPaolo Bonzini $(.with_varray_multiply($factor))?)? 2270d43ddaeSPaolo Bonzini } 2280d43ddaeSPaolo Bonzini }; 2290d43ddaeSPaolo Bonzini } 2300d43ddaeSPaolo Bonzini 23180aa3045SPaolo Bonzini impl VMStateFlags { 23280aa3045SPaolo Bonzini const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags( 23380aa3045SPaolo Bonzini VMStateFlags::VMS_VARRAY_INT32.0 23480aa3045SPaolo Bonzini | VMStateFlags::VMS_VARRAY_UINT8.0 23580aa3045SPaolo Bonzini | VMStateFlags::VMS_VARRAY_UINT16.0 23680aa3045SPaolo Bonzini | VMStateFlags::VMS_VARRAY_UINT32.0, 23780aa3045SPaolo Bonzini ); 23880aa3045SPaolo Bonzini } 23980aa3045SPaolo Bonzini 2400d43ddaeSPaolo Bonzini // Add a couple builder-style methods to VMStateField, allowing 2410d43ddaeSPaolo Bonzini // easy derivation of VMStateField constants from other types. 2420d43ddaeSPaolo Bonzini impl VMStateField { 2430d43ddaeSPaolo Bonzini #[must_use] 2440d43ddaeSPaolo Bonzini pub const fn with_version_id(mut self, version_id: i32) -> Self { 2450d43ddaeSPaolo Bonzini assert!(version_id >= 0); 2460d43ddaeSPaolo Bonzini self.version_id = version_id; 2470d43ddaeSPaolo Bonzini self 2480d43ddaeSPaolo Bonzini } 24980aa3045SPaolo Bonzini 25080aa3045SPaolo Bonzini #[must_use] 25180aa3045SPaolo Bonzini pub const fn with_array_flag(mut self, num: usize) -> Self { 25280aa3045SPaolo Bonzini assert!(num <= 0x7FFF_FFFFusize); 25380aa3045SPaolo Bonzini assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) == 0); 25480aa3045SPaolo Bonzini assert!((self.flags.0 & VMStateFlags::VMS_VARRAY_FLAGS.0) == 0); 25580aa3045SPaolo Bonzini if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 { 25680aa3045SPaolo Bonzini self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0); 25780aa3045SPaolo Bonzini self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0); 25820797069SZhao Liu // VMS_ARRAY_OF_POINTER flag stores the size of pointer. 25920797069SZhao Liu // FIXME: *const, *mut, NonNull and Box<> have the same size as usize. 26020797069SZhao Liu // Resize if more smart pointers are supported. 26120797069SZhao Liu self.size = std::mem::size_of::<usize>(); 26280aa3045SPaolo Bonzini } 26380aa3045SPaolo Bonzini self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0); 26480aa3045SPaolo Bonzini self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0); 26580aa3045SPaolo Bonzini self.num = num as i32; 26680aa3045SPaolo Bonzini self 26780aa3045SPaolo Bonzini } 26880aa3045SPaolo Bonzini 26980aa3045SPaolo Bonzini #[must_use] 27080aa3045SPaolo Bonzini pub const fn with_pointer_flag(mut self) -> Self { 27180aa3045SPaolo Bonzini assert!((self.flags.0 & VMStateFlags::VMS_POINTER.0) == 0); 27280aa3045SPaolo Bonzini self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_POINTER.0); 27380aa3045SPaolo Bonzini self 27480aa3045SPaolo Bonzini } 2755b024b4eSPaolo Bonzini 2765b024b4eSPaolo Bonzini #[must_use] 2775006e39cSZhao Liu pub const fn with_varray_flag_unchecked(mut self, flag: VMStateFlags) -> VMStateField { 2785b024b4eSPaolo Bonzini self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0); 2795b024b4eSPaolo Bonzini self.flags = VMStateFlags(self.flags.0 | flag.0); 280c3d80af5SZhao Liu self.num = 0; // varray uses num_offset instead of num. 2815b024b4eSPaolo Bonzini self 2825b024b4eSPaolo Bonzini } 2835b024b4eSPaolo Bonzini 2845b024b4eSPaolo Bonzini #[must_use] 2855006e39cSZhao Liu #[allow(unused_mut)] 2865006e39cSZhao Liu pub const fn with_varray_flag(mut self, flag: VMStateFlags) -> VMStateField { 2875006e39cSZhao Liu assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0); 2885006e39cSZhao Liu self.with_varray_flag_unchecked(flag) 2895006e39cSZhao Liu } 2905006e39cSZhao Liu 2915006e39cSZhao Liu #[must_use] 2925b024b4eSPaolo Bonzini pub const fn with_varray_multiply(mut self, num: u32) -> VMStateField { 2935b024b4eSPaolo Bonzini assert!(num <= 0x7FFF_FFFFu32); 2945b024b4eSPaolo Bonzini self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0); 2955b024b4eSPaolo Bonzini self.num = num as i32; 2965b024b4eSPaolo Bonzini self 2975b024b4eSPaolo Bonzini } 29880aa3045SPaolo Bonzini } 29980aa3045SPaolo Bonzini 30000f89716SPaolo Bonzini /// This macro can be used (by just passing it a type) to forward the `VMState` 30100f89716SPaolo Bonzini /// trait to the first field of a tuple. This is a workaround for lack of 30200f89716SPaolo Bonzini /// support of nested [`offset_of`](core::mem::offset_of) until Rust 1.82.0. 30300f89716SPaolo Bonzini /// 30400f89716SPaolo Bonzini /// # Examples 30500f89716SPaolo Bonzini /// 30600f89716SPaolo Bonzini /// ``` 30716534af5SPaolo Bonzini /// # use qemu_api::impl_vmstate_forward; 30800f89716SPaolo Bonzini /// pub struct Fifo([u8; 16]); 30900f89716SPaolo Bonzini /// impl_vmstate_forward!(Fifo); 31000f89716SPaolo Bonzini /// ``` 31100f89716SPaolo Bonzini #[macro_export] 31200f89716SPaolo Bonzini macro_rules! impl_vmstate_forward { 31300f89716SPaolo Bonzini // This is similar to impl_vmstate_transparent below, but it 31400f89716SPaolo Bonzini // uses the same trick as vmstate_of! to obtain the type of 31500f89716SPaolo Bonzini // the first field of the tuple 31600f89716SPaolo Bonzini ($tuple:ty) => { 31700f89716SPaolo Bonzini unsafe impl $crate::vmstate::VMState for $tuple { 31800f89716SPaolo Bonzini const SCALAR_TYPE: $crate::vmstate::VMStateFieldType = 31900f89716SPaolo Bonzini $crate::call_func_with_field!($crate::vmstate::vmstate_scalar_type, $tuple, 0); 32000f89716SPaolo Bonzini const BASE: $crate::bindings::VMStateField = 32100f89716SPaolo Bonzini $crate::call_func_with_field!($crate::vmstate::vmstate_base, $tuple, 0); 32200f89716SPaolo Bonzini } 32300f89716SPaolo Bonzini }; 32400f89716SPaolo Bonzini } 32500f89716SPaolo Bonzini 32680aa3045SPaolo Bonzini // Transparent wrappers: just use the internal type 32780aa3045SPaolo Bonzini 32880aa3045SPaolo Bonzini macro_rules! impl_vmstate_transparent { 32980aa3045SPaolo Bonzini ($type:ty where $base:tt: VMState $($where:tt)*) => { 33080aa3045SPaolo Bonzini unsafe impl<$base> VMState for $type where $base: VMState $($where)* { 331f2cb78bdSPaolo Bonzini const SCALAR_TYPE: VMStateFieldType = <$base as VMState>::SCALAR_TYPE; 33280aa3045SPaolo Bonzini const BASE: VMStateField = VMStateField { 33380aa3045SPaolo Bonzini size: mem::size_of::<$type>(), 33480aa3045SPaolo Bonzini ..<$base as VMState>::BASE 33580aa3045SPaolo Bonzini }; 3365b024b4eSPaolo Bonzini const VARRAY_FLAG: VMStateFlags = <$base as VMState>::VARRAY_FLAG; 33780aa3045SPaolo Bonzini } 33880aa3045SPaolo Bonzini }; 33980aa3045SPaolo Bonzini } 34080aa3045SPaolo Bonzini 34180aa3045SPaolo Bonzini impl_vmstate_transparent!(std::cell::Cell<T> where T: VMState); 34280aa3045SPaolo Bonzini impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState); 343d7f5ae8bSPaolo Bonzini impl_vmstate_transparent!(std::pin::Pin<T> where T: VMState); 34480aa3045SPaolo Bonzini impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState); 34580aa3045SPaolo Bonzini impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState); 3463baf82e0SZhao Liu impl_vmstate_transparent!(crate::cell::Opaque<T> where T: VMState); 34780aa3045SPaolo Bonzini 34800f89716SPaolo Bonzini #[macro_export] 34900f89716SPaolo Bonzini macro_rules! impl_vmstate_bitsized { 35000f89716SPaolo Bonzini ($type:ty) => { 35100f89716SPaolo Bonzini unsafe impl $crate::vmstate::VMState for $type { 35200f89716SPaolo Bonzini const SCALAR_TYPE: $crate::vmstate::VMStateFieldType = 35300f89716SPaolo Bonzini <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt 35400f89716SPaolo Bonzini as ::bilge::prelude::Number>::UnderlyingType 35500f89716SPaolo Bonzini as $crate::vmstate::VMState>::SCALAR_TYPE; 35600f89716SPaolo Bonzini const BASE: $crate::bindings::VMStateField = 35700f89716SPaolo Bonzini <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt 35800f89716SPaolo Bonzini as ::bilge::prelude::Number>::UnderlyingType 35900f89716SPaolo Bonzini as $crate::vmstate::VMState>::BASE; 36000f89716SPaolo Bonzini const VARRAY_FLAG: $crate::bindings::VMStateFlags = 36100f89716SPaolo Bonzini <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt 36200f89716SPaolo Bonzini as ::bilge::prelude::Number>::UnderlyingType 36300f89716SPaolo Bonzini as $crate::vmstate::VMState>::VARRAY_FLAG; 36400f89716SPaolo Bonzini } 36500f89716SPaolo Bonzini }; 36600f89716SPaolo Bonzini } 36700f89716SPaolo Bonzini 368f2cb78bdSPaolo Bonzini // Scalar types using predefined VMStateInfos 369f2cb78bdSPaolo Bonzini 370f2cb78bdSPaolo Bonzini macro_rules! impl_vmstate_scalar { 371f2cb78bdSPaolo Bonzini ($info:ident, $type:ty$(, $varray_flag:ident)?) => { 372f2cb78bdSPaolo Bonzini unsafe impl VMState for $type { 373f2cb78bdSPaolo Bonzini const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::$info; 374f2cb78bdSPaolo Bonzini const BASE: VMStateField = VMStateField { 375f2cb78bdSPaolo Bonzini size: mem::size_of::<$type>(), 376f2cb78bdSPaolo Bonzini flags: VMStateFlags::VMS_SINGLE, 377f2cb78bdSPaolo Bonzini ..Zeroable::ZERO 378f2cb78bdSPaolo Bonzini }; 379f2cb78bdSPaolo Bonzini $(const VARRAY_FLAG: VMStateFlags = VMStateFlags::$varray_flag;)? 380f2cb78bdSPaolo Bonzini } 381f2cb78bdSPaolo Bonzini }; 382f2cb78bdSPaolo Bonzini } 383f2cb78bdSPaolo Bonzini 384f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_bool, bool); 385f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_int8, i8); 386f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_int16, i16); 387f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_int32, i32); 388f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_int64, i64); 389f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY_UINT8); 390f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY_UINT16); 391f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY_UINT32); 392f2cb78bdSPaolo Bonzini impl_vmstate_scalar!(vmstate_info_uint64, u64); 3933baf82e0SZhao Liu impl_vmstate_scalar!(vmstate_info_timer, crate::timer::Timer); 394f2cb78bdSPaolo Bonzini 39580aa3045SPaolo Bonzini // Pointer types using the underlying type's VMState plus VMS_POINTER 39680aa3045SPaolo Bonzini // Note that references are not supported, though references to cells 39780aa3045SPaolo Bonzini // could be allowed. 39880aa3045SPaolo Bonzini 39980aa3045SPaolo Bonzini macro_rules! impl_vmstate_pointer { 40080aa3045SPaolo Bonzini ($type:ty where $base:tt: VMState $($where:tt)*) => { 40180aa3045SPaolo Bonzini unsafe impl<$base> VMState for $type where $base: VMState $($where)* { 402f2cb78bdSPaolo Bonzini const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE; 40380aa3045SPaolo Bonzini const BASE: VMStateField = <$base as VMState>::BASE.with_pointer_flag(); 40480aa3045SPaolo Bonzini } 40580aa3045SPaolo Bonzini }; 40680aa3045SPaolo Bonzini } 40780aa3045SPaolo Bonzini 40880aa3045SPaolo Bonzini impl_vmstate_pointer!(*const T where T: VMState); 40980aa3045SPaolo Bonzini impl_vmstate_pointer!(*mut T where T: VMState); 41080aa3045SPaolo Bonzini impl_vmstate_pointer!(NonNull<T> where T: VMState); 41180aa3045SPaolo Bonzini 41280aa3045SPaolo Bonzini // Unlike C pointers, Box is always non-null therefore there is no need 41380aa3045SPaolo Bonzini // to specify VMS_ALLOC. 41480aa3045SPaolo Bonzini impl_vmstate_pointer!(Box<T> where T: VMState); 4150fcccf3fSPaolo Bonzini impl_vmstate_pointer!(Owned<T> where T: VMState + ObjectType); 41680aa3045SPaolo Bonzini 41780aa3045SPaolo Bonzini // Arrays using the underlying type's VMState plus 41880aa3045SPaolo Bonzini // VMS_ARRAY/VMS_ARRAY_OF_POINTER 41980aa3045SPaolo Bonzini 42080aa3045SPaolo Bonzini unsafe impl<T: VMState, const N: usize> VMState for [T; N] { 421f2cb78bdSPaolo Bonzini const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE; 42280aa3045SPaolo Bonzini const BASE: VMStateField = <T as VMState>::BASE.with_array_flag(N); 4230d43ddaeSPaolo Bonzini } 424716d89f9SPaolo Bonzini 4250a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_UNUSED")] 4260a65e412SManos Pitsidianakis #[macro_export] 4270a65e412SManos Pitsidianakis macro_rules! vmstate_unused { 4280a65e412SManos Pitsidianakis ($size:expr) => {{ 4290a65e412SManos Pitsidianakis $crate::bindings::VMStateField { 430f117857bSPaolo Bonzini name: c"unused".as_ptr(), 4310a65e412SManos Pitsidianakis size: $size, 4329d489949SPaolo Bonzini info: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_info_unused_buffer) }, 4339d489949SPaolo Bonzini flags: $crate::bindings::VMStateFlags::VMS_BUFFER, 4349d489949SPaolo Bonzini ..$crate::zeroable::Zeroable::ZERO 4350a65e412SManos Pitsidianakis } 4360a65e412SManos Pitsidianakis }}; 4370a65e412SManos Pitsidianakis } 4380a65e412SManos Pitsidianakis 4396f8e6aedSZhao Liu pub extern "C" fn rust_vms_test_field_exists<T, F: for<'a> FnCall<(&'a T, u8), bool>>( 4406f8e6aedSZhao Liu opaque: *mut c_void, 4416f8e6aedSZhao Liu version_id: c_int, 4426f8e6aedSZhao Liu ) -> bool { 4436f8e6aedSZhao Liu // SAFETY: the opaque was passed as a reference to `T`. 4446f8e6aedSZhao Liu let owner: &T = unsafe { &*(opaque.cast::<T>()) }; 4456f8e6aedSZhao Liu let version: u8 = version_id.try_into().unwrap(); 4466f8e6aedSZhao Liu F::call((owner, version)) 4476f8e6aedSZhao Liu } 4486f8e6aedSZhao Liu 4496f8e6aedSZhao Liu pub type VMSFieldExistCb = unsafe extern "C" fn( 4506f8e6aedSZhao Liu opaque: *mut std::os::raw::c_void, 4516f8e6aedSZhao Liu version_id: std::os::raw::c_int, 4526f8e6aedSZhao Liu ) -> bool; 4536f8e6aedSZhao Liu 4546f8e6aedSZhao Liu #[macro_export] 4556f8e6aedSZhao Liu macro_rules! vmstate_exist_fn { 4566f8e6aedSZhao Liu ($struct_name:ty, $test_fn:expr) => {{ 4576f8e6aedSZhao Liu const fn test_cb_builder__<T, F: for<'a> $crate::callbacks::FnCall<(&'a T, u8), bool>>( 4586f8e6aedSZhao Liu _phantom: ::core::marker::PhantomData<F>, 4596f8e6aedSZhao Liu ) -> $crate::vmstate::VMSFieldExistCb { 4606f8e6aedSZhao Liu let _: () = F::ASSERT_IS_SOME; 4616f8e6aedSZhao Liu $crate::vmstate::rust_vms_test_field_exists::<T, F> 4626f8e6aedSZhao Liu } 4636f8e6aedSZhao Liu 4646f8e6aedSZhao Liu const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> { 4656f8e6aedSZhao Liu ::core::marker::PhantomData 4666f8e6aedSZhao Liu } 4676f8e6aedSZhao Liu Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn))) 4686f8e6aedSZhao Liu }}; 4696f8e6aedSZhao Liu } 4706f8e6aedSZhao Liu 4719a2ba488SPaolo Bonzini // FIXME: including the `vmsd` field in a `const` is not possible without 4729a2ba488SPaolo Bonzini // the const_refs_static feature (stabilized in Rust 1.83.0). Without it, 4739a2ba488SPaolo Bonzini // it is not possible to use VMS_STRUCT in a transparent manner using 4749a2ba488SPaolo Bonzini // `vmstate_of!`. While VMSTATE_CLOCK can at least try to be type-safe, 4759a2ba488SPaolo Bonzini // VMSTATE_STRUCT includes $type only for documentation purposes; it 4769a2ba488SPaolo Bonzini // is checked against $field_name and $struct_name, but not against $vmsd 4779a2ba488SPaolo Bonzini // which is what really would matter. 4789a2ba488SPaolo Bonzini #[doc(alias = "VMSTATE_STRUCT")] 4799a2ba488SPaolo Bonzini #[macro_export] 4809a2ba488SPaolo Bonzini macro_rules! vmstate_struct { 4816f8e6aedSZhao Liu ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(, $test_fn:expr)? $(,)?) => { 4829a2ba488SPaolo Bonzini $crate::bindings::VMStateField { 4839a2ba488SPaolo Bonzini name: ::core::concat!(::core::stringify!($field_name), "\0") 4849a2ba488SPaolo Bonzini .as_bytes() 4859a2ba488SPaolo Bonzini .as_ptr() as *const ::std::os::raw::c_char, 486b134a09fSPaolo Bonzini $(num_offset: ::std::mem::offset_of!($struct_name, $num),)? 4879a2ba488SPaolo Bonzini offset: { 48861825825SZhao Liu $crate::assert_field_type!($struct_name, $field_name, $type $(, num = $num)?); 489b134a09fSPaolo Bonzini ::std::mem::offset_of!($struct_name, $field_name) 4909a2ba488SPaolo Bonzini }, 4919a2ba488SPaolo Bonzini size: ::core::mem::size_of::<$type>(), 4929a2ba488SPaolo Bonzini flags: $crate::bindings::VMStateFlags::VMS_STRUCT, 493ea8a7cebSZhao Liu vmsd: $vmsd, 4946f8e6aedSZhao Liu $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)? 49542c814b1SZhao Liu ..$crate::zeroable::Zeroable::ZERO 4965006e39cSZhao Liu } $(.with_varray_flag_unchecked( 49742c814b1SZhao Liu $crate::call_func_with_field!( 4989a2ba488SPaolo Bonzini $crate::vmstate::vmstate_varray_flag, 4999a2ba488SPaolo Bonzini $struct_name, 50042c814b1SZhao Liu $num 50142c814b1SZhao Liu ) 50242c814b1SZhao Liu ) 5039a2ba488SPaolo Bonzini $(.with_varray_multiply($factor))?)? 5049a2ba488SPaolo Bonzini }; 5059a2ba488SPaolo Bonzini } 5069a2ba488SPaolo Bonzini 5070a65e412SManos Pitsidianakis #[doc(alias = "VMSTATE_CLOCK")] 5080a65e412SManos Pitsidianakis #[macro_export] 5090a65e412SManos Pitsidianakis macro_rules! vmstate_clock { 510756ea88fSPaolo Bonzini ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?) => {{ 5119d489949SPaolo Bonzini $crate::bindings::VMStateField { 5129d489949SPaolo Bonzini name: ::core::concat!(::core::stringify!($field_name), "\0") 5139d489949SPaolo Bonzini .as_bytes() 5149d489949SPaolo Bonzini .as_ptr() as *const ::std::os::raw::c_char, 5159d489949SPaolo Bonzini offset: { 5169d489949SPaolo Bonzini $crate::assert_field_type!( 5170a65e412SManos Pitsidianakis $struct_name, 5189d489949SPaolo Bonzini $field_name, 519756ea88fSPaolo Bonzini $crate::qom::Owned<$crate::qdev::Clock> $(, num = $num)? 5209d489949SPaolo Bonzini ); 521b134a09fSPaolo Bonzini ::std::mem::offset_of!($struct_name, $field_name) 5229d489949SPaolo Bonzini }, 523201ef001SPaolo Bonzini size: ::core::mem::size_of::<*const $crate::qdev::Clock>(), 524f7b87e46SZhao Liu flags: $crate::bindings::VMStateFlags( 525f7b87e46SZhao Liu $crate::bindings::VMStateFlags::VMS_STRUCT.0 526f7b87e46SZhao Liu | $crate::bindings::VMStateFlags::VMS_POINTER.0, 527f7b87e46SZhao Liu ), 5289d489949SPaolo Bonzini vmsd: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_clock) }, 5299d489949SPaolo Bonzini ..$crate::zeroable::Zeroable::ZERO 530756ea88fSPaolo Bonzini } $(.with_varray_flag_unchecked( 531756ea88fSPaolo Bonzini $crate::call_func_with_field!( 532756ea88fSPaolo Bonzini $crate::vmstate::vmstate_varray_flag, 533756ea88fSPaolo Bonzini $struct_name, 534756ea88fSPaolo Bonzini $num 535756ea88fSPaolo Bonzini ) 536756ea88fSPaolo Bonzini ) 537756ea88fSPaolo Bonzini $(.with_varray_multiply($factor))?)? 5380a65e412SManos Pitsidianakis }}; 5390a65e412SManos Pitsidianakis } 5400a65e412SManos Pitsidianakis 5410a65e412SManos Pitsidianakis /// Helper macro to declare a list of 5420a65e412SManos Pitsidianakis /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return 5430a65e412SManos Pitsidianakis /// a pointer to the array of values it created. 5440a65e412SManos Pitsidianakis #[macro_export] 5450a65e412SManos Pitsidianakis macro_rules! vmstate_fields { 5460a65e412SManos Pitsidianakis ($($field:expr),*$(,)*) => {{ 5470a65e412SManos Pitsidianakis static _FIELDS: &[$crate::bindings::VMStateField] = &[ 5480a65e412SManos Pitsidianakis $($field),*, 5490a65e412SManos Pitsidianakis $crate::bindings::VMStateField { 5502537f830SPaolo Bonzini flags: $crate::bindings::VMStateFlags::VMS_END, 5512537f830SPaolo Bonzini ..$crate::zeroable::Zeroable::ZERO 5520a65e412SManos Pitsidianakis } 5530a65e412SManos Pitsidianakis ]; 5540a65e412SManos Pitsidianakis _FIELDS.as_ptr() 5550a65e412SManos Pitsidianakis }} 5560a65e412SManos Pitsidianakis } 5570a65e412SManos Pitsidianakis 558b1310037SZhao Liu #[doc(alias = "VMSTATE_VALIDATE")] 559b1310037SZhao Liu #[macro_export] 560b1310037SZhao Liu macro_rules! vmstate_validate { 561b1310037SZhao Liu ($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => { 562b1310037SZhao Liu $crate::bindings::VMStateField { 563b1310037SZhao Liu name: ::std::ffi::CStr::as_ptr($test_name), 5646f8e6aedSZhao Liu field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn), 565b1310037SZhao Liu flags: $crate::bindings::VMStateFlags( 566b1310037SZhao Liu $crate::bindings::VMStateFlags::VMS_MUST_EXIST.0 567b1310037SZhao Liu | $crate::bindings::VMStateFlags::VMS_ARRAY.0, 568b1310037SZhao Liu ), 569b1310037SZhao Liu num: 0, // 0 elements: no data, only run test_fn callback 570b1310037SZhao Liu ..$crate::zeroable::Zeroable::ZERO 571b1310037SZhao Liu } 572b1310037SZhao Liu }; 573b1310037SZhao Liu } 574b1310037SZhao Liu 5750a65e412SManos Pitsidianakis /// A transparent wrapper type for the `subsections` field of 576716d89f9SPaolo Bonzini /// [`VMStateDescription`]. 5770a65e412SManos Pitsidianakis /// 5780a65e412SManos Pitsidianakis /// This is necessary to be able to declare subsection descriptions as statics, 5790a65e412SManos Pitsidianakis /// because the only way to implement `Sync` for a foreign type (and `*const` 5800a65e412SManos Pitsidianakis /// pointers are foreign types in Rust) is to create a wrapper struct and 5810a65e412SManos Pitsidianakis /// `unsafe impl Sync` for it. 5820a65e412SManos Pitsidianakis /// 5830a65e412SManos Pitsidianakis /// This struct is used in the 5840a65e412SManos Pitsidianakis /// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation. 5850a65e412SManos Pitsidianakis #[repr(transparent)] 5860a65e412SManos Pitsidianakis pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]); 5870a65e412SManos Pitsidianakis 5880a65e412SManos Pitsidianakis unsafe impl Sync for VMStateSubsectionsWrapper {} 5890a65e412SManos Pitsidianakis 590716d89f9SPaolo Bonzini /// Helper macro to declare a list of subsections ([`VMStateDescription`]) 591716d89f9SPaolo Bonzini /// into a static and return a pointer to the array of pointers it created. 5920a65e412SManos Pitsidianakis #[macro_export] 5930a65e412SManos Pitsidianakis macro_rules! vmstate_subsections { 5940a65e412SManos Pitsidianakis ($($subsection:expr),*$(,)*) => {{ 5950a65e412SManos Pitsidianakis static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[ 5960a65e412SManos Pitsidianakis $({ 5970a65e412SManos Pitsidianakis static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection; 5980a65e412SManos Pitsidianakis ::core::ptr::addr_of!(_SUBSECTION) 5990a65e412SManos Pitsidianakis }),*, 6000a65e412SManos Pitsidianakis ::core::ptr::null() 6010a65e412SManos Pitsidianakis ]); 6020a65e412SManos Pitsidianakis _SUBSECTIONS.0.as_ptr() 6030a65e412SManos Pitsidianakis }} 6040a65e412SManos Pitsidianakis } 605