aboutsummaryrefslogtreecommitdiff
path: root/rust/qemu-api/src
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2025-05-05 11:26:47 -0400
committerStefan Hajnoczi <stefanha@redhat.com>2025-05-05 11:26:47 -0400
commitdc1ed8f256c446cbf33e090f0e214d0311a771a7 (patch)
treee693365000225a671eccf7fad90b2b04d7a6f348 /rust/qemu-api/src
parentb6f568262b48ca0cb3dc018909908017551b5679 (diff)
parent03f50d7ee756eecbd4481c3008b5e01e999729c7 (diff)
downloadqemu-dc1ed8f256c446cbf33e090f0e214d0311a771a7.zip
qemu-dc1ed8f256c446cbf33e090f0e214d0311a771a7.tar.gz
qemu-dc1ed8f256c446cbf33e090f0e214d0311a771a7.tar.bz2
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* rust: support migration of HPET device * target/i386/hvf: fix compilation errors * target/i386/tcg: fix some interrupt shadow cases * hw/char/serial: remove unused prog_if compat property * rust: centralize config in workspace root * monitor: fix race on exiting QEMU # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmgVQzkUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroOR8Af/Tke7kRZQyvoKURaKpVOBgP91fTQu # IKwmX1OYe9JMPBwZV5g/++2HSaAddDzkFq90gmgTY+hpvRE3kDWOA86QtDRP4LKa # Oq3yW48yrFiRZBAxERgRxRCsEvzlPC3cAEqCQd4fTL+cW6NVorbj4x/tQcALb47V # cgXXVp59TW4lJk7nJUjd0mCFK1qEoIbZuuBgMn32K+fpBV/UghcoImT2giMeM24Y # WW3olrLA9UN2fh5da7923WUvA9mSjnE0Yfdk6eKC3nCzlgMKktofwKHilm0tA6xA # 7sJbwYTDSB9QxgnNw3WvAFAOMapJmedaSNorZdmcxCss7ed0s8hV8am9vQ== # =LFS/ # -----END PGP SIGNATURE----- # gpg: Signature made Fri 02 May 2025 18:12:09 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: monitor: don't wake up qmp_dispatcher_co coroutine upon cleanup rust: centralize config in workspace root hw/char/serial: Remove unused prog_if compat property target/i386: do not block singlestep for STI target/i386: do not trigger IRQ shadow for LSS target/i386/hvf: fix a compilation error target/i386/emulate: remove rflags leftovers rust/hpet: Support migration rust/timer: Define NANOSECONDS_PER_SECOND binding as u64 rust/vmstate_test: Test varray with num field wrapped in BqlCell rust: assertions: Support index field wrapped in BqlCell vmstate: support varray for vmstate_clock! rust/vmstate: Add support for field_exists checks Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'rust/qemu-api/src')
-rw-r--r--rust/qemu-api/src/assertions.rs25
-rw-r--r--rust/qemu-api/src/timer.rs2
-rw-r--r--rust/qemu-api/src/vmstate.rs83
3 files changed, 58 insertions, 52 deletions
diff --git a/rust/qemu-api/src/assertions.rs b/rust/qemu-api/src/assertions.rs
index eb12e94..a2d38c8 100644
--- a/rust/qemu-api/src/assertions.rs
+++ b/rust/qemu-api/src/assertions.rs
@@ -78,33 +78,26 @@ macro_rules! assert_same_type {
/// ```
#[macro_export]
macro_rules! assert_field_type {
- ($t:ty, $i:tt, $ti:ty) => {
+ (@internal $param_name:ident, $ti:ty, $t:ty, $($field:tt)*) => {
const _: () = {
#[allow(unused)]
- fn assert_field_type(v: $t) {
- fn types_must_be_equal<T, U>(_: T)
+ fn assert_field_type($param_name: &$t) {
+ fn types_must_be_equal<T, U>(_: &T)
where
T: $crate::assertions::EqType<Itself = U>,
{
}
- types_must_be_equal::<_, $ti>(v.$i);
+ types_must_be_equal::<_, $ti>(&$($field)*);
}
};
};
+ ($t:ty, $i:tt, $ti:ty) => {
+ $crate::assert_field_type!(@internal v, $ti, $t, v.$i);
+ };
+
($t:ty, $i:tt, $ti:ty, num = $num:ident) => {
- const _: () = {
- #[allow(unused)]
- fn assert_field_type(v: $t) {
- fn types_must_be_equal<T, U>(_: T)
- where
- T: $crate::assertions::EqType<Itself = U>,
- {
- }
- let index: usize = v.$num.try_into().unwrap();
- types_must_be_equal::<_, &$ti>(&v.$i[index]);
- }
- };
+ $crate::assert_field_type!(@internal v, $ti, $t, v.$i[0]);
};
}
diff --git a/rust/qemu-api/src/timer.rs b/rust/qemu-api/src/timer.rs
index f0b04ef..e769f8b 100644
--- a/rust/qemu-api/src/timer.rs
+++ b/rust/qemu-api/src/timer.rs
@@ -121,3 +121,5 @@ impl ClockType {
pub const CLOCK_VIRTUAL: ClockType = ClockType {
id: QEMUClockType::QEMU_CLOCK_VIRTUAL,
};
+
+pub const NANOSECONDS_PER_SECOND: u64 = 1000000000;
diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs
index 1b2b12e..9ae97c3 100644
--- a/rust/qemu-api/src/vmstate.rs
+++ b/rust/qemu-api/src/vmstate.rs
@@ -200,13 +200,14 @@ pub const fn vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags
/// and [`impl_vmstate_forward!`](crate::impl_vmstate_forward) help with this.
#[macro_export]
macro_rules! vmstate_of {
- ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(,)?) => {
+ ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(, $test_fn:expr)? $(,)?) => {
$crate::bindings::VMStateField {
name: ::core::concat!(::core::stringify!($field_name), "\0")
.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),)?
+ $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)?
// 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!(
@@ -435,6 +436,38 @@ macro_rules! vmstate_unused {
}};
}
+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 {
+ // SAFETY: the opaque was passed as a reference to `T`.
+ let owner: &T = unsafe { &*(opaque.cast::<T>()) };
+ let version: u8 = version_id.try_into().unwrap();
+ 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;
+
+#[macro_export]
+macro_rules! vmstate_exist_fn {
+ ($struct_name:ty, $test_fn:expr) => {{
+ 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)))
+ }};
+}
+
// FIXME: including the `vmsd` field in a `const` is not possible without
// the const_refs_static feature (stabilized in Rust 1.83.0). Without it,
// it is not possible to use VMS_STRUCT in a transparent manner using
@@ -445,7 +478,7 @@ macro_rules! vmstate_unused {
#[doc(alias = "VMSTATE_STRUCT")]
#[macro_export]
macro_rules! vmstate_struct {
- ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(,)?) => {
+ ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(, $test_fn:expr)? $(,)?) => {
$crate::bindings::VMStateField {
name: ::core::concat!(::core::stringify!($field_name), "\0")
.as_bytes()
@@ -458,6 +491,7 @@ macro_rules! vmstate_struct {
size: ::core::mem::size_of::<$type>(),
flags: $crate::bindings::VMStateFlags::VMS_STRUCT,
vmsd: $vmsd,
+ $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)?
..$crate::zeroable::Zeroable::ZERO
} $(.with_varray_flag_unchecked(
$crate::call_func_with_field!(
@@ -473,7 +507,7 @@ macro_rules! vmstate_struct {
#[doc(alias = "VMSTATE_CLOCK")]
#[macro_export]
macro_rules! vmstate_clock {
- ($struct_name:ty, $field_name:ident) => {{
+ ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?) => {{
$crate::bindings::VMStateField {
name: ::core::concat!(::core::stringify!($field_name), "\0")
.as_bytes()
@@ -482,7 +516,7 @@ macro_rules! vmstate_clock {
$crate::assert_field_type!(
$struct_name,
$field_name,
- $crate::qom::Owned<$crate::qdev::Clock>
+ $crate::qom::Owned<$crate::qdev::Clock> $(, num = $num)?
);
$crate::offset_of!($struct_name, $field_name)
},
@@ -493,7 +527,14 @@ macro_rules! vmstate_clock {
),
vmsd: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_clock) },
..$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))?)?
}};
}
@@ -514,43 +555,13 @@ 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)))
- },
+ field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),
flags: $crate::bindings::VMStateFlags(
$crate::bindings::VMStateFlags::VMS_MUST_EXIST.0
| $crate::bindings::VMStateFlags::VMS_ARRAY.0,