aboutsummaryrefslogtreecommitdiff
path: root/rust/qemu-api/src/vmstate.rs
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2025-03-23 11:04:40 -0400
committerStefan Hajnoczi <stefanha@redhat.com>2025-03-23 11:04:40 -0400
commit71119ed3651622e1c531d1294839e9f3341adaf5 (patch)
tree1b5c3e5bc5fed3cb0ed38382a19553f14f578b4a /rust/qemu-api/src/vmstate.rs
parentcea9dfbc48607340a617be5372088d81fa79f41c (diff)
parent64acc23c9793e86f2811345f3c122bf3ece8088b (diff)
downloadqemu-71119ed3651622e1c531d1294839e9f3341adaf5.zip
qemu-71119ed3651622e1c531d1294839e9f3341adaf5.tar.gz
qemu-71119ed3651622e1c531d1294839e9f3341adaf5.tar.bz2
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* exec/cpu-all: remove BSWAP_NEEDED * pl011: pad C PL011State struct to same size as Rust struct * rust: hpet: fix type of "timers" property * rust: hpet: fix functional tests (and really everything that uses it) * rust: Kconfig: Factor out whether devices are Rust or C * rust: vmstate: Fixes and tests # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmfdsUsUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroOGpwf/Qk4bAcLX7A1/nOmYT+DtWzZ9V/VS # hSOe6BruzW8rzwMyn/d7oR+aUpk3sL+v2iPBWqoZ/wh0w8kcABcUfWsqqGI8ln/K # pnTdiC+hra5z0AFH1tmjjtOI50WDOeSjh5SFvoPJtGzhEbo89QvsUWgy98HiHOMm # YFPDuhg3Pfd1XDcdoaa85sOHO1vDsj45fCEJhx6Ktib4vOlEm2I4Z9YR/JxNMT33 # vy/y09HG4cpc6bWKLPL3nqR9RchUSI+YRDZ8rlaXUowiZzH2K/wi0qJOsvG6oJF5 # awni0YWuwyFi16jmUub8NFnWk6NKjbACqw74AwoVPbNbDoCrrogXzIF2Lw== # =NzCN # -----END PGP SIGNATURE----- # gpg: Signature made Fri 21 Mar 2025 14:34:51 EDT # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (24 commits) rust: hpet: fix decoding of timer registers rust/vmstate: Include complete crate path of VMStateFlags in vmstate_clock rust/vmstate: Add unit test for vmstate_validate rust/vmstate: Add unit test for pointer case rust/vmstate: Add unit test for vmstate_{of|struct} macro rust/vmstate: Add unit test for vmstate_of macro rust/vmstate: Support vmstate_validate rust/vmstate: Re-implement VMState trait for timer binding rust/vmstate: Relax array check when build varray in vmstate_struct rust/vmstate: Fix unnecessary VMState bound of with_varray_flag() rust/vmstate: Fix "cannot infer type" error in vmstate_struct rust/vmstate: Fix type check for varray in vmstate_struct rust/vmstate: Fix size field of VMStateField with VMS_ARRAY_OF_POINTER flag rust/vmstate: Fix num field when varray flags are set rust/vmstate: Fix num_offset in vmstate macros rust/vmstate: Remove unnecessary unsafe exec/cpu-all: remove BSWAP_NEEDED load_aout: replace bswap_needed with big_endian rust: pl011: Check size of state struct at compile time hw/char/pl011: Pad PL011State struct to same size as Rust impl ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'rust/qemu-api/src/vmstate.rs')
-rw-r--r--rust/qemu-api/src/vmstate.rs100
1 files changed, 81 insertions, 19 deletions
diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs
index f0510ae..1b2b12e 100644
--- a/rust/qemu-api/src/vmstate.rs
+++ b/rust/qemu-api/src/vmstate.rs
@@ -25,13 +25,11 @@
//! functionality that is missing from `vmstate_of!`.
use core::{marker::PhantomData, mem, ptr::NonNull};
+use std::os::raw::{c_int, c_void};
pub use crate::bindings::{VMStateDescription, VMStateField};
use crate::{
- bindings::{self, VMStateFlags},
- prelude::*,
- qom::Owned,
- zeroable::Zeroable,
+ bindings::VMStateFlags, callbacks::FnCall, prelude::*, qom::Owned, zeroable::Zeroable,
};
/// This macro is used to call a function with a generic argument bound
@@ -208,7 +206,7 @@ macro_rules! vmstate_of {
.as_bytes()
.as_ptr() as *const ::std::os::raw::c_char,
offset: $crate::offset_of!($struct_name, $field_name),
- $(.num_offset: $crate::offset_of!($struct_name, $num),)?
+ $(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!(
@@ -256,6 +254,10 @@ impl VMStateField {
if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 {
self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0);
+ // VMS_ARRAY_OF_POINTER flag stores the size of pointer.
+ // FIXME: *const, *mut, NonNull and Box<> have the same size as usize.
+ // Resize if more smart pointers are supported.
+ self.size = std::mem::size_of::<usize>();
}
self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0);
@@ -271,14 +273,21 @@ impl VMStateField {
}
#[must_use]
- pub const fn with_varray_flag<T: VMState>(mut self, flag: VMStateFlags) -> VMStateField {
- assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0);
+ pub const fn with_varray_flag_unchecked(mut self, flag: VMStateFlags) -> VMStateField {
self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0);
self.flags = VMStateFlags(self.flags.0 | flag.0);
+ self.num = 0; // varray uses num_offset instead of num.
self
}
#[must_use]
+ #[allow(unused_mut)]
+ pub const fn with_varray_flag(mut self, flag: VMStateFlags) -> VMStateField {
+ assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0);
+ self.with_varray_flag_unchecked(flag)
+ }
+
+ #[must_use]
pub const fn with_varray_multiply(mut self, num: u32) -> VMStateField {
assert!(num <= 0x7FFF_FFFFu32);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0);
@@ -333,6 +342,7 @@ impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState);
impl_vmstate_transparent!(std::pin::Pin<T> where T: VMState);
impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState);
impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState);
+impl_vmstate_transparent!(crate::cell::Opaque<T> where T: VMState);
#[macro_export]
macro_rules! impl_vmstate_bitsized {
@@ -379,7 +389,7 @@ 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);
+impl_vmstate_scalar!(vmstate_info_timer, crate::timer::Timer);
// Pointer types using the underlying type's VMState plus VMS_POINTER
// Note that references are not supported, though references to cells
@@ -440,21 +450,23 @@ macro_rules! vmstate_struct {
name: ::core::concat!(::core::stringify!($field_name), "\0")
.as_bytes()
.as_ptr() as *const ::std::os::raw::c_char,
- $(.num_offset: $crate::offset_of!($struct_name, $num),)?
+ $(num_offset: $crate::offset_of!($struct_name, $num),)?
offset: {
- $crate::assert_field_type!($struct_name, $field_name, $type);
+ $crate::assert_field_type!($struct_name, $field_name, $type $(, num = $num)?);
$crate::offset_of!($struct_name, $field_name)
},
size: ::core::mem::size_of::<$type>(),
flags: $crate::bindings::VMStateFlags::VMS_STRUCT,
- vmsd: unsafe { $vmsd },
- ..$crate::zeroable::Zeroable::ZERO $(
- .with_varray_flag($crate::call_func_with_field!(
- $crate::vmstate::vmstate_varray_flag,
- $struct_name,
- $num))
- $(.with_varray_multiply($factor))?)?
- }
+ vmsd: $vmsd,
+ ..$crate::zeroable::Zeroable::ZERO
+ } $(.with_varray_flag_unchecked(
+ $crate::call_func_with_field!(
+ $crate::vmstate::vmstate_varray_flag,
+ $struct_name,
+ $num
+ )
+ )
+ $(.with_varray_multiply($factor))?)?
};
}
@@ -475,7 +487,10 @@ macro_rules! vmstate_clock {
$crate::offset_of!($struct_name, $field_name)
},
size: ::core::mem::size_of::<*const $crate::qdev::Clock>(),
- flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0),
+ flags: $crate::bindings::VMStateFlags(
+ $crate::bindings::VMStateFlags::VMS_STRUCT.0
+ | $crate::bindings::VMStateFlags::VMS_POINTER.0,
+ ),
vmsd: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_clock) },
..$crate::zeroable::Zeroable::ZERO
}
@@ -499,6 +514,53 @@ macro_rules! vmstate_fields {
}}
}
+pub extern "C" fn rust_vms_test_field_exists<T, F: for<'a> FnCall<(&'a T, u8), bool>>(
+ opaque: *mut c_void,
+ version_id: c_int,
+) -> bool {
+ let owner: &T = unsafe { &*(opaque.cast::<T>()) };
+ let version: u8 = version_id.try_into().unwrap();
+ // SAFETY: the opaque was passed as a reference to `T`.
+ F::call((owner, version))
+}
+
+pub type VMSFieldExistCb = unsafe extern "C" fn(
+ opaque: *mut std::os::raw::c_void,
+ version_id: std::os::raw::c_int,
+) -> bool;
+
+#[doc(alias = "VMSTATE_VALIDATE")]
+#[macro_export]
+macro_rules! vmstate_validate {
+ ($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => {
+ $crate::bindings::VMStateField {
+ name: ::std::ffi::CStr::as_ptr($test_name),
+ field_exists: {
+ const fn test_cb_builder__<
+ T,
+ F: for<'a> $crate::callbacks::FnCall<(&'a T, u8), bool>,
+ >(
+ _phantom: ::core::marker::PhantomData<F>,
+ ) -> $crate::vmstate::VMSFieldExistCb {
+ let _: () = F::ASSERT_IS_SOME;
+ $crate::vmstate::rust_vms_test_field_exists::<T, F>
+ }
+
+ const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> {
+ ::core::marker::PhantomData
+ }
+ Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn)))
+ },
+ flags: $crate::bindings::VMStateFlags(
+ $crate::bindings::VMStateFlags::VMS_MUST_EXIST.0
+ | $crate::bindings::VMStateFlags::VMS_ARRAY.0,
+ ),
+ num: 0, // 0 elements: no data, only run test_fn callback
+ ..$crate::zeroable::Zeroable::ZERO
+ }
+ };
+}
+
/// A transparent wrapper type for the `subsections` field of
/// [`VMStateDescription`].
///