diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2024-12-21 08:06:50 -0500 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2024-12-21 08:06:50 -0500 |
commit | e3a207722b783675b362db4ae22a449f42a26b24 (patch) | |
tree | 02593a73b81cc459bd7e645e688c1296b47cb741 /rust/qemu-api/src | |
parent | 9863d46a5a25bfff7d2195ad5e3127ab3bae0a2b (diff) | |
parent | bf9987c06eb8274c2503174b944b8fbe94cc24d7 (diff) | |
download | qemu-e3a207722b783675b362db4ae22a449f42a26b24.zip qemu-e3a207722b783675b362db4ae22a449f42a26b24.tar.gz qemu-e3a207722b783675b362db4ae22a449f42a26b24.tar.bz2 |
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* qdev: second part of Property cleanups
* rust: second part of QOM rework
* rust: callbacks wrapper
* rust: pl011 bugfixes
* kvm: cleanup errors in kvm_convert_memory()
# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmdkaEkUHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroN0/wgAgIJg8BrlRKfmiz14NZfph8/jarSj
# TOWYVxL2v4q98KBuL5pta2ucObgzwqyqSyc02S2DGSOIMQCIiBB5MaCk1iMjx+BO
# pmVU8gNlD8faO8SSmnnr+jDQt+G+bQ/nRgQJOAReF8oVw3O2aC/FaVKpitMzWtvv
# PLnJWdrqqpGq14OzX8iNCzSujxppAuyjrhT4lNlekzDoDfdTez72r+rXkvg4GzZL
# QC3xLYg/LrT8Rs+zgOhm/AaIyS4bOyMlkU9Du1rQ6Tyne45ey2FCwKVzBKrJdGcw
# sVbzEclxseLenoTbZqYK6JTzLdDoThVUbY2JwoCGUaIm+74P4NjEsUsTVg==
# =TuQM
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 19 Dec 2024 13:39:05 EST
# 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: (42 commits)
rust: pl011: simplify handling of the FIFO enabled bit in LCR
rust: pl011: fix migration stream
rust: pl011: extend registers to 32 bits
rust: pl011: fix break errors and definition of Data struct
rust: pl011: always use reset() method on registers
rust: pl011: match break logic of C version
rust: pl011: fix declaration of LineControl bits
target/i386: Reset TSCs of parked vCPUs too on VM reset
kvm: consistently return 0/-errno from kvm_convert_memory
rust: qemu-api: add a module to wrap functions and zero-sized closures
rust: qom: add initial subset of methods on Object
rust: qom: add casting functionality
rust: tests: allow writing more than one test
bql: add a "mock" BQL for Rust unit tests
rust: re-export C types from qemu-api submodules
rust: rename qemu-api modules to follow C code a bit more
rust: qom: add possibility of overriding unparent
rust: qom: put class_init together from multiple ClassInitImpl<>
Constify all opaque Property pointers
hw/core/qdev-properties: Constify Property argument to PropertyInfo.print
...
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'rust/qemu-api/src')
-rw-r--r-- | rust/qemu-api/src/callbacks.rs | 144 | ||||
-rw-r--r-- | rust/qemu-api/src/cell.rs | 26 | ||||
-rw-r--r-- | rust/qemu-api/src/definitions.rs | 168 | ||||
-rw-r--r-- | rust/qemu-api/src/lib.rs | 6 | ||||
-rw-r--r-- | rust/qemu-api/src/module.rs | 43 | ||||
-rw-r--r-- | rust/qemu-api/src/prelude.rs | 10 | ||||
-rw-r--r-- | rust/qemu-api/src/qdev.rs (renamed from rust/qemu-api/src/device_class.rs) | 67 | ||||
-rw-r--r-- | rust/qemu-api/src/qom.rs | 584 | ||||
-rw-r--r-- | rust/qemu-api/src/sysbus.rs | 20 | ||||
-rw-r--r-- | rust/qemu-api/src/vmstate.rs | 31 |
10 files changed, 861 insertions, 238 deletions
diff --git a/rust/qemu-api/src/callbacks.rs b/rust/qemu-api/src/callbacks.rs new file mode 100644 index 0000000..314f9dc --- /dev/null +++ b/rust/qemu-api/src/callbacks.rs @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: MIT + +//! Utility functions to deal with callbacks from C to Rust. + +use std::{mem, ptr::NonNull}; + +/// Trait for functions (types implementing [`Fn`]) that can be used as +/// callbacks. These include both zero-capture closures and function pointers. +/// +/// In Rust, calling a function through the `Fn` trait normally requires a +/// `self` parameter, even though for zero-sized functions (including function +/// pointers) the type itself contains all necessary information to call the +/// function. This trait provides a `call` function that doesn't require `self`, +/// allowing zero-sized functions to be called using only their type. +/// +/// This enables zero-sized functions to be passed entirely through generic +/// parameters and resolved at compile-time. A typical use is a function +/// receiving an unused parameter of generic type `F` and calling it via +/// `F::call` or passing it to another function via `func::<F>`. +/// +/// QEMU uses this trick to create wrappers to C callbacks. The wrappers +/// are needed to convert an opaque `*mut c_void` into a Rust reference, +/// but they only have a single opaque that they can use. The `FnCall` +/// trait makes it possible to use that opaque for `self` or any other +/// reference: +/// +/// ```ignore +/// // The compiler creates a new `rust_bh_cb` wrapper for each function +/// // passed to `qemu_bh_schedule_oneshot` below. +/// unsafe extern "C" fn rust_bh_cb<T, F: for<'a> FnCall<(&'a T,)>>( +/// opaque: *mut c_void, +/// ) { +/// // SAFETY: the opaque was passed as a reference to `T`. +/// F::call((unsafe { &*(opaque.cast::<T>()) }, )) +/// } +/// +/// // The `_f` parameter is unused but it helps the compiler build the appropriate `F`. +/// // Using a reference allows usage in const context. +/// fn qemu_bh_schedule_oneshot<T, F: for<'a> FnCall<(&'a T,)>>(_f: &F, opaque: &T) { +/// let cb: unsafe extern "C" fn(*mut c_void) = rust_bh_cb::<T, F>; +/// unsafe { +/// bindings::qemu_bh_schedule_oneshot(cb, opaque as *const T as *const c_void as *mut c_void) +/// } +/// } +/// ``` +/// +/// Each wrapper is a separate instance of `rust_bh_cb` and is therefore +/// compiled to a separate function ("monomorphization"). If you wanted +/// to pass `self` as the opaque value, the generic parameters would be +/// `rust_bh_cb::<Self, F>`. +/// +/// `Args` is a tuple type whose types are the arguments of the function, +/// while `R` is the returned type. +/// +/// # Examples +/// +/// ``` +/// # use qemu_api::callbacks::FnCall; +/// fn call_it<F: for<'a> FnCall<(&'a str,), String>>(_f: &F, s: &str) -> String { +/// F::call((s,)) +/// } +/// +/// let s: String = call_it(&str::to_owned, "hello world"); +/// assert_eq!(s, "hello world"); +/// ``` +/// +/// Note that the compiler will produce a different version of `call_it` for +/// each function that is passed to it. Therefore the argument is not really +/// used, except to decide what is `F` and what `F::call` does. +/// +/// Attempting to pass a non-zero-sized closure causes a compile-time failure: +/// +/// ```compile_fail +/// # use qemu_api::callbacks::FnCall; +/// # fn call_it<'a, F: FnCall<(&'a str,), String>>(_f: &F, s: &'a str) -> String { +/// # F::call((s,)) +/// # } +/// let x: &'static str = "goodbye world"; +/// call_it(&move |_| String::from(x), "hello workd"); +/// ``` +/// +/// # Safety +/// +/// Because `Self` is a zero-sized type, all instances of the type are +/// equivalent. However, in addition to this, `Self` must have no invariants +/// that could be violated by creating a reference to it. +/// +/// This is always true for zero-capture closures and function pointers, as long +/// as the code is able to name the function in the first place. +pub unsafe trait FnCall<Args, R = ()>: 'static + Sync + Sized { + /// Referring to this internal constant asserts that the `Self` type is + /// zero-sized. Can be replaced by an inline const expression in + /// Rust 1.79.0+. + const ASSERT_ZERO_SIZED: () = { assert!(mem::size_of::<Self>() == 0) }; + + /// Call the function with the arguments in args. + fn call(a: Args) -> R; +} + +macro_rules! impl_call { + ($($args:ident,)* ) => ( + // SAFETY: because each function is treated as a separate type, + // accessing `FnCall` is only possible in code that would be + // allowed to call the function. + unsafe impl<F, $($args,)* R> FnCall<($($args,)*), R> for F + where + F: 'static + Sync + Sized + Fn($($args, )*) -> R, + { + #[inline(always)] + fn call(a: ($($args,)*)) -> R { + let _: () = Self::ASSERT_ZERO_SIZED; + + // SAFETY: the safety of this method is the condition for implementing + // `FnCall`. As to the `NonNull` idiom to create a zero-sized type, + // see https://github.com/rust-lang/libs-team/issues/292. + let f: &'static F = unsafe { &*NonNull::<Self>::dangling().as_ptr() }; + let ($($args,)*) = a; + f($($args,)*) + } + } + ) +} + +impl_call!(_1, _2, _3, _4, _5,); +impl_call!(_1, _2, _3, _4,); +impl_call!(_1, _2, _3,); +impl_call!(_1, _2,); +impl_call!(_1,); +impl_call!(); + +#[cfg(test)] +mod tests { + use super::*; + + // The `_f` parameter is unused but it helps the compiler infer `F`. + fn do_test_call<'a, F: FnCall<(&'a str,), String>>(_f: &F) -> String { + F::call(("hello world",)) + } + + #[test] + fn test_call() { + assert_eq!(do_test_call(&str::to_owned), "hello world") + } +} diff --git a/rust/qemu-api/src/cell.rs b/rust/qemu-api/src/cell.rs index 28349de..eae4e2c 100644 --- a/rust/qemu-api/src/cell.rs +++ b/rust/qemu-api/src/cell.rs @@ -124,9 +124,18 @@ use std::{ use crate::bindings; -// TODO: When building doctests do not include the actual BQL, because cargo -// does not know how to link them to libqemuutil. This can be fixed by -// running rustdoc from "meson test" instead of relying on cargo. +/// An internal function that is used by doctests. +pub fn bql_start_test() { + if cfg!(MESON) { + // SAFETY: integration tests are run with --test-threads=1, while + // unit tests and doctests are not multithreaded and do not have + // any BQL-protected data. Just set bql_locked to true. + unsafe { + bindings::rust_bql_mock_lock(); + } + } +} + pub fn bql_locked() -> bool { // SAFETY: the function does nothing but return a thread-local bool !cfg!(MESON) || unsafe { bindings::bql_locked() } @@ -220,6 +229,7 @@ impl<T> BqlCell<T> { /// /// ``` /// use qemu_api::cell::BqlCell; + /// # qemu_api::cell::bql_start_test(); /// /// let c = BqlCell::new(5); /// ``` @@ -236,6 +246,7 @@ impl<T> BqlCell<T> { /// /// ``` /// use qemu_api::cell::BqlCell; + /// # qemu_api::cell::bql_start_test(); /// /// let c = BqlCell::new(5); /// @@ -253,6 +264,7 @@ impl<T> BqlCell<T> { /// /// ``` /// use qemu_api::cell::BqlCell; + /// # qemu_api::cell::bql_start_test(); /// /// let cell = BqlCell::new(5); /// assert_eq!(cell.get(), 5); @@ -274,6 +286,7 @@ impl<T> BqlCell<T> { /// /// ``` /// use qemu_api::cell::BqlCell; + /// # qemu_api::cell::bql_start_test(); /// /// let c = BqlCell::new(5); /// let five = c.into_inner(); @@ -293,6 +306,7 @@ impl<T: Copy> BqlCell<T> { /// /// ``` /// use qemu_api::cell::BqlCell; + /// # qemu_api::cell::bql_start_test(); /// /// let c = BqlCell::new(5); /// @@ -315,6 +329,7 @@ impl<T> BqlCell<T> { /// /// ``` /// use qemu_api::cell::BqlCell; + /// # qemu_api::cell::bql_start_test(); /// /// let c = BqlCell::new(5); /// @@ -333,6 +348,7 @@ impl<T: Default> BqlCell<T> { /// /// ``` /// use qemu_api::cell::BqlCell; + /// # qemu_api::cell::bql_start_test(); /// /// let c = BqlCell::new(5); /// let five = c.take(); @@ -461,6 +477,7 @@ impl<T> BqlRefCell<T> { /// /// ``` /// use qemu_api::cell::BqlRefCell; + /// # qemu_api::cell::bql_start_test(); /// /// let c = BqlRefCell::new(5); /// @@ -472,6 +489,7 @@ impl<T> BqlRefCell<T> { /// /// ```should_panic /// use qemu_api::cell::BqlRefCell; + /// # qemu_api::cell::bql_start_test(); /// /// let c = BqlRefCell::new(5); /// @@ -513,6 +531,7 @@ impl<T> BqlRefCell<T> { /// /// ``` /// use qemu_api::cell::BqlRefCell; + /// # qemu_api::cell::bql_start_test(); /// /// let c = BqlRefCell::new("hello".to_owned()); /// @@ -525,6 +544,7 @@ impl<T> BqlRefCell<T> { /// /// ```should_panic /// use qemu_api::cell::BqlRefCell; + /// # qemu_api::cell::bql_start_test(); /// /// let c = BqlRefCell::new(5); /// let m = c.borrow(); diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs deleted file mode 100644 index df91a2e..0000000 --- a/rust/qemu-api/src/definitions.rs +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2024, Linaro Limited -// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org> -// SPDX-License-Identifier: GPL-2.0-or-later - -//! Definitions required by QEMU when registering a device. - -use std::{ffi::CStr, os::raw::c_void}; - -use crate::bindings::{Object, ObjectClass, TypeInfo}; - -unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) { - // SAFETY: obj is an instance of T, since rust_instance_init<T> - // is called from QOM core as the instance_init function - // for class T - unsafe { T::INSTANCE_INIT.unwrap()(&mut *obj.cast::<T>()) } -} - -unsafe extern "C" fn rust_instance_post_init<T: ObjectImpl>(obj: *mut Object) { - // SAFETY: obj is an instance of T, since rust_instance_post_init<T> - // is called from QOM core as the instance_post_init function - // for class T - // - // FIXME: it's not really guaranteed that there are no backpointers to - // obj; it's quite possible that they have been created by instance_init(). - // The receiver should be &self, not &mut self. - T::INSTANCE_POST_INIT.unwrap()(unsafe { &mut *obj.cast::<T>() }) -} - -/// Trait exposed by all structs corresponding to QOM objects. -/// -/// # Safety -/// -/// For classes declared in C: -/// -/// - `Class` and `TYPE` must match the data in the `TypeInfo`; -/// -/// - the first field of the struct must be of the instance type corresponding -/// to the superclass, as declared in the `TypeInfo` -/// -/// - likewise, the first field of the `Class` struct must be of the class type -/// corresponding to the superclass -/// -/// For classes declared in Rust and implementing [`ObjectImpl`]: -/// -/// - the struct must be `#[repr(C)]`; -/// -/// - the first field of the struct must be of the instance struct corresponding -/// to the superclass, which is `ObjectImpl::ParentType` -/// -/// - likewise, the first field of the `Class` must be of the class struct -/// corresponding to the superclass, which is `ObjectImpl::ParentType::Class`. -pub unsafe trait ObjectType: Sized { - /// The QOM class object corresponding to this struct. Not used yet. - type Class; - - /// The name of the type, which can be passed to `object_new()` to - /// generate an instance of this type. - const TYPE_NAME: &'static CStr; -} - -/// Trait a type must implement to be registered with QEMU. -pub trait ObjectImpl: ObjectType + ClassInitImpl { - /// The parent of the type. This should match the first field of - /// the struct that implements `ObjectImpl`: - type ParentType: ObjectType; - - /// Whether the object can be instantiated - const ABSTRACT: bool = false; - const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)> = None; - - /// Function that is called to initialize an object. The parent class will - /// have already been initialized so the type is only responsible for - /// initializing its own members. - /// - /// FIXME: The argument is not really a valid reference. `&mut - /// MaybeUninit<Self>` would be a better description. - const INSTANCE_INIT: Option<unsafe fn(&mut Self)> = None; - - /// Function that is called to finish initialization of an object, once - /// `INSTANCE_INIT` functions have been called. - const INSTANCE_POST_INIT: Option<fn(&mut Self)> = None; - - const TYPE_INFO: TypeInfo = TypeInfo { - name: Self::TYPE_NAME.as_ptr(), - parent: Self::ParentType::TYPE_NAME.as_ptr(), - instance_size: core::mem::size_of::<Self>(), - instance_align: core::mem::align_of::<Self>(), - instance_init: match Self::INSTANCE_INIT { - None => None, - Some(_) => Some(rust_instance_init::<Self>), - }, - instance_post_init: match Self::INSTANCE_POST_INIT { - None => None, - Some(_) => Some(rust_instance_post_init::<Self>), - }, - instance_finalize: Self::INSTANCE_FINALIZE, - abstract_: Self::ABSTRACT, - class_size: core::mem::size_of::<Self::Class>(), - class_init: <Self as ClassInitImpl>::CLASS_INIT, - class_base_init: <Self as ClassInitImpl>::CLASS_BASE_INIT, - class_data: core::ptr::null_mut(), - interfaces: core::ptr::null_mut(), - }; -} - -/// Trait used to fill in a class struct. -/// -/// Each QOM class that has virtual methods describes them in a -/// _class struct_. Class structs include a parent field corresponding -/// to the vtable of the parent class, all the way up to [`ObjectClass`]. -/// Each QOM type has one such class struct. -/// -/// The Rust implementation of methods will usually come from a trait -/// like [`ObjectImpl`] or [`DeviceImpl`](crate::device_class::DeviceImpl). -pub trait ClassInitImpl { - /// Function that is called after all parent class initialization - /// has occurred. On entry, the virtual method pointers are set to - /// the default values coming from the parent classes; the function - /// can change them to override virtual methods of a parent class. - const CLASS_INIT: Option<unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void)>; - - /// Called on descendent classes after all parent class initialization - /// has occurred, but before the class itself is initialized. This - /// is only useful if a class is not a leaf, and can be used to undo - /// the effects of copying the contents of the parent's class struct - /// to the descendants. - const CLASS_BASE_INIT: Option< - unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void), - >; -} - -#[macro_export] -macro_rules! module_init { - ($type:ident => $body:block) => { - const _: () = { - #[used] - #[cfg_attr( - not(any(target_vendor = "apple", target_os = "windows")), - link_section = ".init_array" - )] - #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")] - #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")] - pub static LOAD_MODULE: extern "C" fn() = { - extern "C" fn init_fn() { - $body - } - - extern "C" fn ctor_fn() { - unsafe { - $crate::bindings::register_module_init( - Some(init_fn), - $crate::bindings::module_init_type::$type, - ); - } - } - - ctor_fn - }; - }; - }; - - // shortcut because it's quite common that $body needs unsafe {} - ($type:ident => unsafe $body:block) => { - $crate::module_init! { - $type => { unsafe { $body } } - } - }; -} diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs index 9e007e1..4b43e02 100644 --- a/rust/qemu-api/src/lib.rs +++ b/rust/qemu-api/src/lib.rs @@ -14,11 +14,13 @@ pub mod prelude; pub mod bitops; pub mod c_str; +pub mod callbacks; pub mod cell; -pub mod definitions; -pub mod device_class; pub mod irq; +pub mod module; pub mod offset_of; +pub mod qdev; +pub mod qom; pub mod sysbus; pub mod vmstate; pub mod zeroable; diff --git a/rust/qemu-api/src/module.rs b/rust/qemu-api/src/module.rs new file mode 100644 index 0000000..fa5cea3 --- /dev/null +++ b/rust/qemu-api/src/module.rs @@ -0,0 +1,43 @@ +// Copyright 2024, Linaro Limited +// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org> +// SPDX-License-Identifier: GPL-2.0-or-later + +//! Macro to register blocks of code that run as QEMU starts up. + +#[macro_export] +macro_rules! module_init { + ($type:ident => $body:block) => { + const _: () = { + #[used] + #[cfg_attr( + not(any(target_vendor = "apple", target_os = "windows")), + link_section = ".init_array" + )] + #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")] + #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")] + pub static LOAD_MODULE: extern "C" fn() = { + extern "C" fn init_fn() { + $body + } + + extern "C" fn ctor_fn() { + unsafe { + $crate::bindings::register_module_init( + Some(init_fn), + $crate::bindings::module_init_type::$type, + ); + } + } + + ctor_fn + }; + }; + }; + + // shortcut because it's quite common that $body needs unsafe {} + ($type:ident => unsafe $body:block) => { + $crate::module_init! { + $type => { unsafe { $body } } + } + }; +} diff --git a/rust/qemu-api/src/prelude.rs b/rust/qemu-api/src/prelude.rs index 1b8677b..6f32dee 100644 --- a/rust/qemu-api/src/prelude.rs +++ b/rust/qemu-api/src/prelude.rs @@ -7,4 +7,12 @@ pub use crate::bitops::IntegerExt; pub use crate::cell::BqlCell; pub use crate::cell::BqlRefCell; -pub use crate::definitions::ObjectType; +pub use crate::qom::IsA; +pub use crate::qom::Object; +pub use crate::qom::ObjectCast; +pub use crate::qom::ObjectCastMut; +pub use crate::qom::ObjectDeref; +pub use crate::qom::ObjectMethods; +pub use crate::qom::ObjectType; + +pub use crate::qom_isa; diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/qdev.rs index 03d03fe..686054e 100644 --- a/rust/qemu-api/src/device_class.rs +++ b/rust/qemu-api/src/qdev.rs @@ -2,12 +2,17 @@ // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org> // SPDX-License-Identifier: GPL-2.0-or-later -use std::{ffi::CStr, os::raw::c_void}; +//! Bindings to create devices and access device functionality from Rust. + +use std::ffi::CStr; + +pub use bindings::{DeviceClass, DeviceState, Property}; use crate::{ - bindings::{self, DeviceClass, DeviceState, Error, ObjectClass, Property, VMStateDescription}, + bindings::{self, Error}, prelude::*, - zeroable::Zeroable, + qom::{ClassInitImpl, ObjectClass}, + vmstate::VMStateDescription, }; /// Trait providing the contents of [`DeviceClass`]. @@ -31,7 +36,7 @@ pub trait DeviceImpl { /// device. Not a `const` because referencing statics in constants /// is unstable until Rust 1.83.0. fn properties() -> &'static [Property] { - &[Zeroable::ZERO; 1] + &[] } /// A `VMStateDescription` providing the migration format for the device @@ -45,7 +50,7 @@ pub trait DeviceImpl { /// # Safety /// /// This function is only called through the QOM machinery and -/// the `impl_device_class!` macro. +/// used by the `ClassInitImpl<DeviceClass>` trait. /// We expect the FFI user of this function to pass a valid pointer that /// can be downcasted to type `T`. We also expect the device is /// readable/writeable from one thread at any time. @@ -66,43 +71,31 @@ unsafe extern "C" fn rust_reset_fn<T: DeviceImpl>(dev: *mut DeviceState) { T::RESET.unwrap()(unsafe { &mut *state }); } -/// # Safety -/// -/// We expect the FFI user of this function to pass a valid pointer that -/// can be downcasted to type `DeviceClass`, because `T` implements -/// `DeviceImpl`. -pub unsafe extern "C" fn rust_device_class_init<T: DeviceImpl>( - klass: *mut ObjectClass, - _: *mut c_void, -) { - let mut dc = ::core::ptr::NonNull::new(klass.cast::<DeviceClass>()).unwrap(); - unsafe { - let dc = dc.as_mut(); +impl<T> ClassInitImpl<DeviceClass> for T +where + T: ClassInitImpl<ObjectClass> + DeviceImpl, +{ + fn class_init(dc: &mut DeviceClass) { if <T as DeviceImpl>::REALIZE.is_some() { dc.realize = Some(rust_realize_fn::<T>); } if <T as DeviceImpl>::RESET.is_some() { - bindings::device_class_set_legacy_reset(dc, Some(rust_reset_fn::<T>)); + unsafe { + bindings::device_class_set_legacy_reset(dc, Some(rust_reset_fn::<T>)); + } } if let Some(vmsd) = <T as DeviceImpl>::vmsd() { dc.vmsd = vmsd; } - bindings::device_class_set_props(dc, <T as DeviceImpl>::properties().as_ptr()); - } -} - -#[macro_export] -macro_rules! impl_device_class { - ($type:ty) => { - impl $crate::definitions::ClassInitImpl for $type { - const CLASS_INIT: Option< - unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut ::std::os::raw::c_void), - > = Some($crate::device_class::rust_device_class_init::<$type>); - const CLASS_BASE_INIT: Option< - unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut ::std::os::raw::c_void), - > = None; + let prop = <T as DeviceImpl>::properties(); + if !prop.is_empty() { + unsafe { + bindings::device_class_set_props_n(dc, prop.as_ptr(), prop.len()); + } } - }; + + <T as ClassInitImpl<ObjectClass>>::class_init(&mut dc.parent_class); + } } #[macro_export] @@ -134,7 +127,7 @@ macro_rules! define_property { macro_rules! declare_properties { ($ident:ident, $($prop:expr),*$(,)*) => { pub static $ident: [$crate::bindings::Property; { - let mut len = 1; + let mut len = 0; $({ _ = stringify!($prop); len += 1; @@ -142,13 +135,13 @@ macro_rules! declare_properties { len }] = [ $($prop),*, - $crate::zeroable::Zeroable::ZERO, ]; }; } -unsafe impl ObjectType for bindings::DeviceState { - type Class = bindings::DeviceClass; +unsafe impl ObjectType for DeviceState { + type Class = DeviceClass; const TYPE_NAME: &'static CStr = unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_DEVICE) }; } +qom_isa!(DeviceState: Object); diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs new file mode 100644 index 0000000..7d5fbef --- /dev/null +++ b/rust/qemu-api/src/qom.rs @@ -0,0 +1,584 @@ +// Copyright 2024, Linaro Limited +// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org> +// SPDX-License-Identifier: GPL-2.0-or-later + +//! Bindings to access QOM functionality from Rust. +//! +//! The QEMU Object Model (QOM) provides inheritance and dynamic typing for QEMU +//! devices. This module makes QOM's features available in Rust through three +//! main mechanisms: +//! +//! * Automatic creation and registration of `TypeInfo` for classes that are +//! written in Rust, as well as mapping between Rust traits and QOM vtables. +//! +//! * Type-safe casting between parent and child classes, through the [`IsA`] +//! trait and methods such as [`upcast`](ObjectCast::upcast) and +//! [`downcast`](ObjectCast::downcast). +//! +//! * Automatic delegation of parent class methods to child classes. When a +//! trait uses [`IsA`] as a bound, its contents become available to all child +//! classes through blanket implementations. This works both for class methods +//! and for instance methods accessed through references or smart pointers. +//! +//! # Structure of a class +//! +//! A leaf class only needs a struct holding instance state. The struct must +//! implement the [`ObjectType`] and [`IsA`] traits, as well as any `*Impl` +//! traits that exist for its superclasses. +//! +//! If a class has subclasses, it will also provide a struct for instance data, +//! with the same characteristics as for concrete classes, but it also needs +//! additional components to support virtual methods: +//! +//! * a struct for class data, for example `DeviceClass`. This corresponds to +//! the C "class struct" and holds the vtable that is used by instances of the +//! class and its subclasses. It must start with its parent's class struct. +//! +//! * a trait for virtual method implementations, for example `DeviceImpl`. +//! Child classes implement this trait to provide their own behavior for +//! virtual methods. The trait's methods take `&self` to access instance data. +//! +//! * an implementation of [`ClassInitImpl`], for example +//! `ClassInitImpl<DeviceClass>`. This fills the vtable in the class struct; +//! the source for this is the `*Impl` trait; the associated consts and +//! functions if needed are wrapped to map C types into Rust types. +//! +//! * a trait for instance methods, for example `DeviceMethods`. This trait is +//! automatically implemented for any reference or smart pointer to a device +//! instance. It calls into the vtable provides access across all subclasses +//! to methods defined for the class. +//! +//! * optionally, a trait for class methods, for example `DeviceClassMethods`. +//! This provides access to class-wide functionality that doesn't depend on +//! instance data. Like instance methods, these are automatically inherited by +//! child classes. + +use std::{ + ffi::CStr, + ops::{Deref, DerefMut}, + os::raw::c_void, +}; + +pub use bindings::{Object, ObjectClass}; + +use crate::bindings::{self, object_dynamic_cast, object_get_class, object_get_typename, TypeInfo}; + +/// Marker trait: `Self` can be statically upcasted to `P` (i.e. `P` is a direct +/// or indirect parent of `Self`). +/// +/// # Safety +/// +/// The struct `Self` must be `#[repr(C)]` and must begin, directly or +/// indirectly, with a field of type `P`. This ensures that invalid casts, +/// which rely on `IsA<>` for static checking, are rejected at compile time. +pub unsafe trait IsA<P: ObjectType>: ObjectType {} + +// SAFETY: it is always safe to cast to your own type +unsafe impl<T: ObjectType> IsA<T> for T {} + +/// Macro to mark superclasses of QOM classes. This enables type-safe +/// up- and downcasting. +/// +/// # Safety +/// +/// This macro is a thin wrapper around the [`IsA`] trait and performs +/// no checking whatsoever of what is declared. It is the caller's +/// responsibility to have $struct begin, directly or indirectly, with +/// a field of type `$parent`. +#[macro_export] +macro_rules! qom_isa { + ($struct:ty : $($parent:ty),* ) => { + $( + // SAFETY: it is the caller responsibility to have $parent as the + // first field + unsafe impl $crate::qom::IsA<$parent> for $struct {} + + impl AsRef<$parent> for $struct { + fn as_ref(&self) -> &$parent { + // SAFETY: follows the same rules as for IsA<U>, which is + // declared above. + let ptr: *const Self = self; + unsafe { &*ptr.cast::<$parent>() } + } + } + )* + }; +} + +unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) { + // SAFETY: obj is an instance of T, since rust_instance_init<T> + // is called from QOM core as the instance_init function + // for class T + unsafe { T::INSTANCE_INIT.unwrap()(&mut *obj.cast::<T>()) } +} + +unsafe extern "C" fn rust_instance_post_init<T: ObjectImpl>(obj: *mut Object) { + // SAFETY: obj is an instance of T, since rust_instance_post_init<T> + // is called from QOM core as the instance_post_init function + // for class T + // + // FIXME: it's not really guaranteed that there are no backpointers to + // obj; it's quite possible that they have been created by instance_init(). + // The receiver should be &self, not &mut self. + T::INSTANCE_POST_INIT.unwrap()(unsafe { &mut *obj.cast::<T>() }) +} + +unsafe extern "C" fn rust_class_init<T: ObjectType + ClassInitImpl<T::Class>>( + klass: *mut ObjectClass, + _data: *mut c_void, +) { + // SAFETY: klass is a T::Class, since rust_class_init<T> + // is called from QOM core as the class_init function + // for class T + T::class_init(unsafe { &mut *klass.cast::<T::Class>() }) +} + +/// Trait exposed by all structs corresponding to QOM objects. +/// +/// # Safety +/// +/// For classes declared in C: +/// +/// - `Class` and `TYPE` must match the data in the `TypeInfo`; +/// +/// - the first field of the struct must be of the instance type corresponding +/// to the superclass, as declared in the `TypeInfo` +/// +/// - likewise, the first field of the `Class` struct must be of the class type +/// corresponding to the superclass +/// +/// For classes declared in Rust and implementing [`ObjectImpl`]: +/// +/// - the struct must be `#[repr(C)]`; +/// +/// - the first field of the struct must be of the instance struct corresponding +/// to the superclass, which is `ObjectImpl::ParentType` +/// +/// - likewise, the first field of the `Class` must be of the class struct +/// corresponding to the superclass, which is `ObjectImpl::ParentType::Class`. +pub unsafe trait ObjectType: Sized { + /// The QOM class object corresponding to this struct. This is used + /// to automatically generate a `class_init` method. + type Class; + + /// The name of the type, which can be passed to `object_new()` to + /// generate an instance of this type. + const TYPE_NAME: &'static CStr; + + /// Return the receiver as an Object. This is always safe, even + /// if this type represents an interface. + fn as_object(&self) -> &Object { + unsafe { &*self.as_object_ptr() } + } + + /// Return the receiver as a const raw pointer to Object. + /// This is preferrable to `as_object_mut_ptr()` if a C + /// function only needs a `const Object *`. + fn as_object_ptr(&self) -> *const Object { + self.as_ptr().cast() + } + + /// Return the receiver as a mutable raw pointer to Object. + /// + /// # Safety + /// + /// This cast is always safe, but because the result is mutable + /// and the incoming reference is not, this should only be used + /// for calls to C functions, and only if needed. + unsafe fn as_object_mut_ptr(&self) -> *mut Object { + self.as_object_ptr() as *mut _ + } +} + +/// This trait provides safe casting operations for QOM objects to raw pointers, +/// to be used for example for FFI. The trait can be applied to any kind of +/// reference or smart pointers, and enforces correctness through the [`IsA`] +/// trait. +pub trait ObjectDeref: Deref +where + Self::Target: ObjectType, +{ + /// Convert to a const Rust pointer, to be used for example for FFI. + /// The target pointer type must be the type of `self` or a superclass + fn as_ptr<U: ObjectType>(&self) -> *const U + where + Self::Target: IsA<U>, + { + let ptr: *const Self::Target = self.deref(); + ptr.cast::<U>() + } + + /// Convert to a mutable Rust pointer, to be used for example for FFI. + /// The target pointer type must be the type of `self` or a superclass. + /// Used to implement interior mutability for objects. + /// + /// # Safety + /// + /// This method is unsafe because it overrides const-ness of `&self`. + /// Bindings to C APIs will use it a lot, but otherwise it should not + /// be necessary. + unsafe fn as_mut_ptr<U: ObjectType>(&self) -> *mut U + where + Self::Target: IsA<U>, + { + #[allow(clippy::as_ptr_cast_mut)] + { + self.as_ptr::<U>() as *mut _ + } + } +} + +/// Trait that adds extra functionality for `&T` where `T` is a QOM +/// object type. Allows conversion to/from C objects in generic code. +pub trait ObjectCast: ObjectDeref + Copy +where + Self::Target: ObjectType, +{ + /// Safely convert from a derived type to one of its parent types. + /// + /// This is always safe; the [`IsA`] trait provides static verification + /// trait that `Self` dereferences to `U` or a child of `U`. + fn upcast<'a, U: ObjectType>(self) -> &'a U + where + Self::Target: IsA<U>, + Self: 'a, + { + // SAFETY: soundness is declared via IsA<U>, which is an unsafe trait + unsafe { self.unsafe_cast::<U>() } + } + + /// Attempt to convert to a derived type. + /// + /// Returns `None` if the object is not actually of type `U`. This is + /// verified at runtime by checking the object's type information. + fn downcast<'a, U: IsA<Self::Target>>(self) -> Option<&'a U> + where + Self: 'a, + { + self.dynamic_cast::<U>() + } + + /// Attempt to convert between any two types in the QOM hierarchy. + /// + /// Returns `None` if the object is not actually of type `U`. This is + /// verified at runtime by checking the object's type information. + fn dynamic_cast<'a, U: ObjectType>(self) -> Option<&'a U> + where + Self: 'a, + { + unsafe { + // SAFETY: upcasting to Object is always valid, and the + // return type is either NULL or the argument itself + let result: *const U = + object_dynamic_cast(self.as_object_mut_ptr(), U::TYPE_NAME.as_ptr()).cast(); + + result.as_ref() + } + } + + /// Convert to any QOM type without verification. + /// + /// # Safety + /// + /// What safety? You need to know yourself that the cast is correct; only + /// use when performance is paramount. It is still better than a raw + /// pointer `cast()`, which does not even check that you remain in the + /// realm of QOM `ObjectType`s. + /// + /// `unsafe_cast::<Object>()` is always safe. + unsafe fn unsafe_cast<'a, U: ObjectType>(self) -> &'a U + where + Self: 'a, + { + unsafe { &*(self.as_ptr::<Self::Target>().cast::<U>()) } + } +} + +impl<T: ObjectType> ObjectDeref for &T {} +impl<T: ObjectType> ObjectCast for &T {} + +/// Trait for mutable type casting operations in the QOM hierarchy. +/// +/// This trait provides the mutable counterparts to [`ObjectCast`]'s conversion +/// functions. Unlike `ObjectCast`, this trait returns `Result` for fallible +/// conversions to preserve the original smart pointer if the cast fails. This +/// is necessary because mutable references cannot be copied, so a failed cast +/// must return ownership of the original reference. For example: +/// +/// ```ignore +/// let mut dev = get_device(); +/// // If this fails, we need the original `dev` back to try something else +/// match dev.dynamic_cast_mut::<FooDevice>() { +/// Ok(foodev) => /* use foodev */, +/// Err(dev) => /* still have ownership of dev */ +/// } +/// ``` +pub trait ObjectCastMut: Sized + ObjectDeref + DerefMut +where + Self::Target: ObjectType, +{ + /// Safely convert from a derived type to one of its parent types. + /// + /// This is always safe; the [`IsA`] trait provides static verification + /// that `Self` dereferences to `U` or a child of `U`. + fn upcast_mut<'a, U: ObjectType>(self) -> &'a mut U + where + Self::Target: IsA<U>, + Self: 'a, + { + // SAFETY: soundness is declared via IsA<U>, which is an unsafe trait + unsafe { self.unsafe_cast_mut::<U>() } + } + + /// Attempt to convert to a derived type. + /// + /// Returns `Ok(..)` if the object is of type `U`, or `Err(self)` if the + /// object if the conversion failed. This is verified at runtime by + /// checking the object's type information. + fn downcast_mut<'a, U: IsA<Self::Target>>(self) -> Result<&'a mut U, Self> + where + Self: 'a, + { + self.dynamic_cast_mut::<U>() + } + + /// Attempt to convert between any two types in the QOM hierarchy. + /// + /// Returns `Ok(..)` if the object is of type `U`, or `Err(self)` if the + /// object if the conversion failed. This is verified at runtime by + /// checking the object's type information. + fn dynamic_cast_mut<'a, U: ObjectType>(self) -> Result<&'a mut U, Self> + where + Self: 'a, + { + unsafe { + // SAFETY: upcasting to Object is always valid, and the + // return type is either NULL or the argument itself + let result: *mut U = + object_dynamic_cast(self.as_object_mut_ptr(), U::TYPE_NAME.as_ptr()).cast(); + + result.as_mut().ok_or(self) + } + } + + /// Convert to any QOM type without verification. + /// + /// # Safety + /// + /// What safety? You need to know yourself that the cast is correct; only + /// use when performance is paramount. It is still better than a raw + /// pointer `cast()`, which does not even check that you remain in the + /// realm of QOM `ObjectType`s. + /// + /// `unsafe_cast::<Object>()` is always safe. + unsafe fn unsafe_cast_mut<'a, U: ObjectType>(self) -> &'a mut U + where + Self: 'a, + { + unsafe { &mut *self.as_mut_ptr::<Self::Target>().cast::<U>() } + } +} + +impl<T: ObjectType> ObjectDeref for &mut T {} +impl<T: ObjectType> ObjectCastMut for &mut T {} + +/// Trait a type must implement to be registered with QEMU. +pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> { + /// The parent of the type. This should match the first field of + /// the struct that implements `ObjectImpl`: + type ParentType: ObjectType; + + /// Whether the object can be instantiated + const ABSTRACT: bool = false; + const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)> = None; + + /// Function that is called to initialize an object. The parent class will + /// have already been initialized so the type is only responsible for + /// initializing its own members. + /// + /// FIXME: The argument is not really a valid reference. `&mut + /// MaybeUninit<Self>` would be a better description. + const INSTANCE_INIT: Option<unsafe fn(&mut Self)> = None; + + /// Function that is called to finish initialization of an object, once + /// `INSTANCE_INIT` functions have been called. + const INSTANCE_POST_INIT: Option<fn(&mut Self)> = None; + + /// Called on descendent classes after all parent class initialization + /// has occurred, but before the class itself is initialized. This + /// is only useful if a class is not a leaf, and can be used to undo + /// the effects of copying the contents of the parent's class struct + /// to the descendants. + const CLASS_BASE_INIT: Option< + unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void), + > = None; + + const TYPE_INFO: TypeInfo = TypeInfo { + name: Self::TYPE_NAME.as_ptr(), + parent: Self::ParentType::TYPE_NAME.as_ptr(), + instance_size: core::mem::size_of::<Self>(), + instance_align: core::mem::align_of::<Self>(), + instance_init: match Self::INSTANCE_INIT { + None => None, + Some(_) => Some(rust_instance_init::<Self>), + }, + instance_post_init: match Self::INSTANCE_POST_INIT { + None => None, + Some(_) => Some(rust_instance_post_init::<Self>), + }, + instance_finalize: Self::INSTANCE_FINALIZE, + abstract_: Self::ABSTRACT, + class_size: core::mem::size_of::<Self::Class>(), + class_init: Some(rust_class_init::<Self>), + class_base_init: Self::CLASS_BASE_INIT, + class_data: core::ptr::null_mut(), + interfaces: core::ptr::null_mut(), + }; + + // methods on ObjectClass + const UNPARENT: Option<fn(&Self)> = None; +} + +/// Internal trait used to automatically fill in a class struct. +/// +/// Each QOM class that has virtual methods describes them in a +/// _class struct_. Class structs include a parent field corresponding +/// to the vtable of the parent class, all the way up to [`ObjectClass`]. +/// Each QOM type has one such class struct; this trait takes care of +/// initializing the `T` part of the class struct, for the type that +/// implements the trait. +/// +/// Each struct will implement this trait with `T` equal to each +/// superclass. For example, a device should implement at least +/// `ClassInitImpl<`[`DeviceClass`](crate::qdev::DeviceClass)`>` and +/// `ClassInitImpl<`[`ObjectClass`]`>`. Such implementations are made +/// in one of two ways. +/// +/// For most superclasses, `ClassInitImpl` is provided by the `qemu-api` +/// crate itself. The Rust implementation of methods will come from a +/// trait like [`ObjectImpl`] or [`DeviceImpl`](crate::qdev::DeviceImpl), +/// and `ClassInitImpl` is provided by blanket implementations that +/// operate on all implementors of the `*Impl`* trait. For example: +/// +/// ```ignore +/// impl<T> ClassInitImpl<DeviceClass> for T +/// where +/// T: ClassInitImpl<ObjectClass> + DeviceImpl, +/// ``` +/// +/// The bound on `ClassInitImpl<ObjectClass>` is needed so that, +/// after initializing the `DeviceClass` part of the class struct, +/// the parent [`ObjectClass`] is initialized as well. +/// +/// The other case is when manual implementation of the trait is needed. +/// This covers the following cases: +/// +/// * if a class implements a QOM interface, the Rust code _has_ to define its +/// own class struct `FooClass` and implement `ClassInitImpl<FooClass>`. +/// `ClassInitImpl<FooClass>`'s `class_init` method will then forward to +/// multiple other `class_init`s, for the interfaces as well as the +/// superclass. (Note that there is no Rust example yet for using interfaces). +/// +/// * for classes implemented outside the ``qemu-api`` crate, it's not possible +/// to add blanket implementations like the above one, due to orphan rules. In +/// that case, the easiest solution is to implement +/// `ClassInitImpl<YourSuperclass>` for each subclass and not have a +/// `YourSuperclassImpl` trait at all. +/// +/// ```ignore +/// impl ClassInitImpl<YourSuperclass> for YourSubclass { +/// fn class_init(klass: &mut YourSuperclass) { +/// klass.some_method = Some(Self::some_method); +/// <Self as ClassInitImpl<SysBusDeviceClass>>::class_init(&mut klass.parent_class); +/// } +/// } +/// ``` +/// +/// While this method incurs a small amount of code duplication, +/// it is generally limited to the recursive call on the last line. +/// This is because classes defined in Rust do not need the same +/// glue code that is needed when the classes are defined in C code. +/// You may consider using a macro if you have many subclasses. +pub trait ClassInitImpl<T> { + /// Initialize `klass` to point to the virtual method implementations + /// for `Self`. On entry, the virtual method pointers are set to + /// the default values coming from the parent classes; the function + /// can change them to override virtual methods of a parent class. + /// + /// The virtual method implementations usually come from another + /// trait, for example [`DeviceImpl`](crate::qdev::DeviceImpl) + /// when `T` is [`DeviceClass`](crate::qdev::DeviceClass). + /// + /// On entry, `klass`'s parent class is initialized, while the other fields + /// are all zero; it is therefore assumed that all fields in `T` can be + /// zeroed, otherwise it would not be possible to provide the class as a + /// `&mut T`. TODO: add a bound of [`Zeroable`](crate::zeroable::Zeroable) + /// to T; this is more easily done once Zeroable does not require a manual + /// implementation (Rust 1.75.0). + fn class_init(klass: &mut T); +} + +/// # Safety +/// +/// We expect the FFI user of this function to pass a valid pointer that +/// can be downcasted to type `T`. We also expect the device is +/// readable/writeable from one thread at any time. +unsafe extern "C" fn rust_unparent_fn<T: ObjectImpl>(dev: *mut Object) { + unsafe { + assert!(!dev.is_null()); + let state = core::ptr::NonNull::new_unchecked(dev.cast::<T>()); + T::UNPARENT.unwrap()(state.as_ref()); + } +} + +impl<T> ClassInitImpl<ObjectClass> for T +where + T: ObjectImpl, +{ + fn class_init(oc: &mut ObjectClass) { + if <T as ObjectImpl>::UNPARENT.is_some() { + oc.unparent = Some(rust_unparent_fn::<T>); + } + } +} + +unsafe impl ObjectType for Object { + type Class = ObjectClass; + const TYPE_NAME: &'static CStr = + unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_OBJECT) }; +} + +/// Trait for methods exposed by the Object class. The methods can be +/// called on all objects that have the trait `IsA<Object>`. +/// +/// The trait should only be used through the blanket implementation, +/// which guarantees safety via `IsA` +pub trait ObjectMethods: ObjectDeref +where + Self::Target: IsA<Object>, +{ + /// Return the name of the type of `self` + fn typename(&self) -> std::borrow::Cow<'_, str> { + let obj = self.upcast::<Object>(); + // SAFETY: safety of this is the requirement for implementing IsA + // The result of the C API has static lifetime + unsafe { + let p = object_get_typename(obj.as_mut_ptr()); + CStr::from_ptr(p).to_string_lossy() + } + } + + fn get_class(&self) -> &'static <Self::Target as ObjectType>::Class { + let obj = self.upcast::<Object>(); + + // SAFETY: all objects can call object_get_class; the actual class + // type is guaranteed by the implementation of `ObjectType` and + // `ObjectImpl`. + let klass: &'static <Self::Target as ObjectType>::Class = + unsafe { &*object_get_class(obj.as_mut_ptr()).cast() }; + + klass + } +} + +impl<R: ObjectDeref> ObjectMethods for R where R::Target: IsA<Object> {} diff --git a/rust/qemu-api/src/sysbus.rs b/rust/qemu-api/src/sysbus.rs index 5ee0685..8193734 100644 --- a/rust/qemu-api/src/sysbus.rs +++ b/rust/qemu-api/src/sysbus.rs @@ -6,13 +6,31 @@ use std::{ffi::CStr, ptr::addr_of}; pub use bindings::{SysBusDevice, SysBusDeviceClass}; -use crate::{bindings, cell::bql_locked, irq::InterruptSource, prelude::*}; +use crate::{ + bindings, + cell::bql_locked, + irq::InterruptSource, + prelude::*, + qdev::{DeviceClass, DeviceState}, + qom::ClassInitImpl, +}; unsafe impl ObjectType for SysBusDevice { type Class = SysBusDeviceClass; const TYPE_NAME: &'static CStr = unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_SYS_BUS_DEVICE) }; } +qom_isa!(SysBusDevice: DeviceState, Object); + +// TODO: add SysBusDeviceImpl +impl<T> ClassInitImpl<SysBusDeviceClass> for T +where + T: ClassInitImpl<DeviceClass>, +{ + fn class_init(sdc: &mut SysBusDeviceClass) { + <T as ClassInitImpl<DeviceClass>>::class_init(&mut sdc.parent_class); + } +} impl SysBusDevice { /// Return `self` cast to a mutable pointer, for use in calls to C code. diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs index bedcf1e..63c897a 100644 --- a/rust/qemu-api/src/vmstate.rs +++ b/rust/qemu-api/src/vmstate.rs @@ -10,6 +10,8 @@ //! [`vmstate_fields`](crate::vmstate_fields) are meant to be used when //! declaring a device model state struct. +pub use crate::bindings::VMStateDescription; + #[doc(alias = "VMSTATE_UNUSED_BUFFER")] #[macro_export] macro_rules! vmstate_unused_buffer { @@ -104,28 +106,6 @@ macro_rules! vmstate_uint32 { }}; } -#[doc(alias = "VMSTATE_INT32_V")] -#[macro_export] -macro_rules! vmstate_int32_v { - ($field_name:ident, $struct_name:ty, $version_id:expr) => {{ - $crate::vmstate_single!( - $field_name, - $struct_name, - $version_id, - ::core::ptr::addr_of!($crate::bindings::vmstate_info_int32), - ::core::mem::size_of::<i32>() - ) - }}; -} - -#[doc(alias = "VMSTATE_INT32")] -#[macro_export] -macro_rules! vmstate_int32 { - ($field_name:ident, $struct_name:ty) => {{ - $crate::vmstate_int32_v!($field_name, $struct_name, 0) - }}; -} - #[doc(alias = "VMSTATE_ARRAY")] #[macro_export] macro_rules! vmstate_array { @@ -328,7 +308,7 @@ macro_rules! vmstate_fields { } /// A transparent wrapper type for the `subsections` field of -/// [`VMStateDescription`](crate::bindings::VMStateDescription). +/// [`VMStateDescription`]. /// /// This is necessary to be able to declare subsection descriptions as statics, /// because the only way to implement `Sync` for a foreign type (and `*const` @@ -342,9 +322,8 @@ pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMSta unsafe impl Sync for VMStateSubsectionsWrapper {} -/// Helper macro to declare a list of subsections -/// ([`VMStateDescription`](`crate::bindings::VMStateDescription`)) into a -/// static and return a pointer to the array of pointers it created. +/// Helper macro to declare a list of subsections ([`VMStateDescription`]) +/// into a static and return a pointer to the array of pointers it created. #[macro_export] macro_rules! vmstate_subsections { ($($subsection:expr),*$(,)*) => {{ |