mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 04:13:53 -06:00
rust: vmstate: implement VMState for scalar types
Scalar types are those that have their own VMStateInfo. This poses a problem in that references to VMStateInfo can only be included in associated consts starting with Rust 1.83.0, when the const_refs_static was stabilized. Removing the requirement is done by placing a limited list of VMStateInfos in an enum, and going from enum to &VMStateInfo only when building the VMStateField. The same thing cannot be done with VMS_STRUCT because the set of VMStateDescriptions extends to structs defined by the devices. Therefore, structs and cells cannot yet use vmstate_of!. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
2537f83098
commit
f2cb78bdbe
1 changed files with 126 additions and 2 deletions
|
@ -22,7 +22,10 @@
|
|||
use core::{marker::PhantomData, mem, ptr::NonNull};
|
||||
|
||||
pub use crate::bindings::{VMStateDescription, VMStateField};
|
||||
use crate::bindings::VMStateFlags;
|
||||
use crate::{
|
||||
bindings::{self, VMStateFlags},
|
||||
zeroable::Zeroable,
|
||||
};
|
||||
|
||||
/// This macro is used to call a function with a generic argument bound
|
||||
/// to the type of a field. The function must take a
|
||||
|
@ -61,6 +64,70 @@ macro_rules! call_func_with_field {
|
|||
};
|
||||
}
|
||||
|
||||
/// Workaround for lack of `const_refs_static`: references to global variables
|
||||
/// can be included in a `static`, but not in a `const`; unfortunately, this
|
||||
/// is exactly what would go in the `VMStateField`'s `info` member.
|
||||
///
|
||||
/// This enum contains the contents of the `VMStateField`'s `info` member,
|
||||
/// but as an `enum` instead of a pointer.
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum VMStateFieldType {
|
||||
null,
|
||||
vmstate_info_bool,
|
||||
vmstate_info_int8,
|
||||
vmstate_info_int16,
|
||||
vmstate_info_int32,
|
||||
vmstate_info_int64,
|
||||
vmstate_info_uint8,
|
||||
vmstate_info_uint16,
|
||||
vmstate_info_uint32,
|
||||
vmstate_info_uint64,
|
||||
vmstate_info_timer,
|
||||
}
|
||||
|
||||
/// Workaround for lack of `const_refs_static`. Converts a `VMStateFieldType`
|
||||
/// to a `*const VMStateInfo`, for inclusion in a `VMStateField`.
|
||||
#[macro_export]
|
||||
macro_rules! info_enum_to_ref {
|
||||
($e:expr) => {
|
||||
unsafe {
|
||||
match $e {
|
||||
$crate::vmstate::VMStateFieldType::null => ::core::ptr::null(),
|
||||
$crate::vmstate::VMStateFieldType::vmstate_info_bool => {
|
||||
::core::ptr::addr_of!($crate::bindings::vmstate_info_bool)
|
||||
}
|
||||
$crate::vmstate::VMStateFieldType::vmstate_info_int8 => {
|
||||
::core::ptr::addr_of!($crate::bindings::vmstate_info_int8)
|
||||
}
|
||||
$crate::vmstate::VMStateFieldType::vmstate_info_int16 => {
|
||||
::core::ptr::addr_of!($crate::bindings::vmstate_info_int16)
|
||||
}
|
||||
$crate::vmstate::VMStateFieldType::vmstate_info_int32 => {
|
||||
::core::ptr::addr_of!($crate::bindings::vmstate_info_int32)
|
||||
}
|
||||
$crate::vmstate::VMStateFieldType::vmstate_info_int64 => {
|
||||
::core::ptr::addr_of!($crate::bindings::vmstate_info_int64)
|
||||
}
|
||||
$crate::vmstate::VMStateFieldType::vmstate_info_uint8 => {
|
||||
::core::ptr::addr_of!($crate::bindings::vmstate_info_uint8)
|
||||
}
|
||||
$crate::vmstate::VMStateFieldType::vmstate_info_uint16 => {
|
||||
::core::ptr::addr_of!($crate::bindings::vmstate_info_uint16)
|
||||
}
|
||||
$crate::vmstate::VMStateFieldType::vmstate_info_uint32 => {
|
||||
::core::ptr::addr_of!($crate::bindings::vmstate_info_uint32)
|
||||
}
|
||||
$crate::vmstate::VMStateFieldType::vmstate_info_uint64 => {
|
||||
::core::ptr::addr_of!($crate::bindings::vmstate_info_uint64)
|
||||
}
|
||||
$crate::vmstate::VMStateFieldType::vmstate_info_timer => {
|
||||
::core::ptr::addr_of!($crate::bindings::vmstate_info_timer)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// A trait for types that can be included in a device's migration stream. It
|
||||
/// provides the base contents of a `VMStateField` (minus the name and offset).
|
||||
///
|
||||
|
@ -69,6 +136,12 @@ macro_rules! call_func_with_field {
|
|||
/// The contents of this trait go straight into structs that are parsed by C
|
||||
/// code and used to introspect into other structs. Be careful.
|
||||
pub unsafe trait VMState {
|
||||
/// The `info` member of a `VMStateField` is a pointer and as such cannot
|
||||
/// yet be included in the [`BASE`](VMState::BASE) associated constant;
|
||||
/// this is only allowed by Rust 1.83.0 and newer. For now, include the
|
||||
/// member as an enum which is stored in a separate constant.
|
||||
const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::null;
|
||||
|
||||
/// The base contents of a `VMStateField` (minus the name and offset) for
|
||||
/// the type that is implementing the trait.
|
||||
const BASE: VMStateField;
|
||||
|
@ -83,6 +156,12 @@ pub unsafe trait VMState {
|
|||
};
|
||||
}
|
||||
|
||||
/// Internal utility function to retrieve a type's `VMStateFieldType`;
|
||||
/// used by [`vmstate_of!`](crate::vmstate_of).
|
||||
pub const fn vmstate_scalar_type<T: VMState>(_: PhantomData<T>) -> VMStateFieldType {
|
||||
T::SCALAR_TYPE
|
||||
}
|
||||
|
||||
/// Internal utility function to retrieve a type's `VMStateField`;
|
||||
/// used by [`vmstate_of!`](crate::vmstate_of).
|
||||
pub const fn vmstate_base<T: VMState>(_: PhantomData<T>) -> VMStateField {
|
||||
|
@ -99,6 +178,15 @@ pub const fn vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags
|
|||
/// Return the `VMStateField` for a field of a struct. The field must be
|
||||
/// visible in the current scope.
|
||||
///
|
||||
/// Only a limited set of types is supported out of the box:
|
||||
/// * scalar types (integer and `bool`)
|
||||
/// * the C struct `QEMUTimer`
|
||||
/// * a transparent wrapper for any of the above (`Cell`, `UnsafeCell`,
|
||||
/// [`BqlCell`](crate::cell::BqlCell), [`BqlRefCell`](crate::cell::BqlRefCell)
|
||||
/// * a raw pointer to any of the above
|
||||
/// * a `NonNull` pointer or a `Box` for any of the above
|
||||
/// * an array of any of the above
|
||||
///
|
||||
/// In order to support other types, the trait `VMState` must be implemented
|
||||
/// for them.
|
||||
#[macro_export]
|
||||
|
@ -109,8 +197,14 @@ macro_rules! vmstate_of {
|
|||
.as_bytes()
|
||||
.as_ptr() as *const ::std::os::raw::c_char,
|
||||
offset: $crate::offset_of!($struct_name, $field_name),
|
||||
// Compute most of the VMStateField from the type of the field.
|
||||
$(.num_offset: $crate::offset_of!($struct_name, $num),)?
|
||||
// The calls to `call_func_with_field!` are the magic that
|
||||
// computes most of the VMStateField from the type of the field.
|
||||
info: $crate::info_enum_to_ref!($crate::call_func_with_field!(
|
||||
$crate::vmstate::vmstate_scalar_type,
|
||||
$struct_name,
|
||||
$field_name
|
||||
)),
|
||||
..$crate::call_func_with_field!(
|
||||
$crate::vmstate::vmstate_base,
|
||||
$struct_name,
|
||||
|
@ -187,6 +281,7 @@ impl VMStateField {
|
|||
macro_rules! impl_vmstate_transparent {
|
||||
($type:ty where $base:tt: VMState $($where:tt)*) => {
|
||||
unsafe impl<$base> VMState for $type where $base: VMState $($where)* {
|
||||
const SCALAR_TYPE: VMStateFieldType = <$base as VMState>::SCALAR_TYPE;
|
||||
const BASE: VMStateField = VMStateField {
|
||||
size: mem::size_of::<$type>(),
|
||||
..<$base as VMState>::BASE
|
||||
|
@ -201,6 +296,33 @@ impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState);
|
|||
impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState);
|
||||
impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState);
|
||||
|
||||
// Scalar types using predefined VMStateInfos
|
||||
|
||||
macro_rules! impl_vmstate_scalar {
|
||||
($info:ident, $type:ty$(, $varray_flag:ident)?) => {
|
||||
unsafe impl VMState for $type {
|
||||
const SCALAR_TYPE: VMStateFieldType = VMStateFieldType::$info;
|
||||
const BASE: VMStateField = VMStateField {
|
||||
size: mem::size_of::<$type>(),
|
||||
flags: VMStateFlags::VMS_SINGLE,
|
||||
..Zeroable::ZERO
|
||||
};
|
||||
$(const VARRAY_FLAG: VMStateFlags = VMStateFlags::$varray_flag;)?
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_vmstate_scalar!(vmstate_info_bool, bool);
|
||||
impl_vmstate_scalar!(vmstate_info_int8, i8);
|
||||
impl_vmstate_scalar!(vmstate_info_int16, i16);
|
||||
impl_vmstate_scalar!(vmstate_info_int32, i32);
|
||||
impl_vmstate_scalar!(vmstate_info_int64, i64);
|
||||
impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY_UINT8);
|
||||
impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY_UINT16);
|
||||
impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY_UINT32);
|
||||
impl_vmstate_scalar!(vmstate_info_uint64, u64);
|
||||
impl_vmstate_scalar!(vmstate_info_timer, bindings::QEMUTimer);
|
||||
|
||||
// Pointer types using the underlying type's VMState plus VMS_POINTER
|
||||
// Note that references are not supported, though references to cells
|
||||
// could be allowed.
|
||||
|
@ -208,6 +330,7 @@ impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState);
|
|||
macro_rules! impl_vmstate_pointer {
|
||||
($type:ty where $base:tt: VMState $($where:tt)*) => {
|
||||
unsafe impl<$base> VMState for $type where $base: VMState $($where)* {
|
||||
const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE;
|
||||
const BASE: VMStateField = <$base as VMState>::BASE.with_pointer_flag();
|
||||
}
|
||||
};
|
||||
|
@ -225,6 +348,7 @@ impl_vmstate_pointer!(Box<T> where T: VMState);
|
|||
// VMS_ARRAY/VMS_ARRAY_OF_POINTER
|
||||
|
||||
unsafe impl<T: VMState, const N: usize> VMState for [T; N] {
|
||||
const SCALAR_TYPE: VMStateFieldType = <T as VMState>::SCALAR_TYPE;
|
||||
const BASE: VMStateField = <T as VMState>::BASE.with_array_flag(N);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue