[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 11/26] rust: qdev: move device_class_init! body to generic functi
From: |
Paolo Bonzini |
Subject: |
[PATCH 11/26] rust: qdev: move device_class_init! body to generic function, ClassInitImpl implementation to macro |
Date: |
Mon, 9 Dec 2024 13:37:02 +0100 |
Use a trait to access the former parameters to device_class_init!.
This allows hiding the details of the class_init implementation behind
a generic function and makes higher-level functionality available from
qemu_api.
The implementation of ClassInitImpl is then the same for all devices and
is easily macroized. Later on, we can remove the need to implement
ClassInitImpl by hand for all device types, and stop making
rust_device_class_init<>() public.
While at it, document the members of DeviceImpl.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/hw/char/pl011/src/device.rs | 34 +++++-----
rust/hw/char/pl011/src/device_class.rs | 8 ---
rust/qemu-api/src/device_class.rs | 87 +++++++++++++++++++++-----
rust/qemu-api/tests/tests.rs | 30 ++++-----
4 files changed, 103 insertions(+), 56 deletions(-)
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index 2384d4bcb95..28b1924337d 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -12,11 +12,13 @@
bindings::{self, *},
c_str,
definitions::ObjectImpl,
- device_class::TYPE_SYS_BUS_DEVICE,
+ device_class::{DeviceImpl, TYPE_SYS_BUS_DEVICE},
+ impl_device_class,
irq::InterruptSource,
};
use crate::{
+ device_class,
memory_ops::PL011_OPS,
registers::{self, Interrupt},
RegisterOffset,
@@ -116,14 +118,20 @@ pub struct PL011Class {
_inner: [u8; 0],
}
-impl qemu_api::definitions::ClassInitImpl for PL011State {
- const CLASS_INIT: Option<unsafe extern "C" fn(klass: *mut ObjectClass,
data: *mut c_void)> =
- Some(crate::device_class::pl011_class_init);
- const CLASS_BASE_INIT: Option<
- unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void),
- > = None;
+impl DeviceImpl for PL011State {
+ fn properties() -> &'static [Property] {
+ &device_class::PL011_PROPERTIES
+ }
+ fn vmsd() -> Option<&'static VMStateDescription> {
+ Some(&device_class::VMSTATE_PL011)
+ }
+ const REALIZE: Option<unsafe extern "C" fn(*mut DeviceState, *mut *mut
Error)> =
+ Some(device_class::pl011_realize);
+ const RESET: Option<unsafe extern "C" fn(*mut DeviceState)> =
Some(device_class::pl011_reset);
}
+impl_device_class!(PL011State);
+
impl PL011State {
/// Initializes a pre-allocated, unitialized instance of `PL011State`.
///
@@ -649,17 +657,13 @@ pub struct PL011LuminaryClass {
}
}
-impl qemu_api::definitions::ClassInitImpl for PL011Luminary {
- const CLASS_INIT: Option<unsafe extern "C" fn(klass: *mut ObjectClass,
data: *mut c_void)> =
- None;
- const CLASS_BASE_INIT: Option<
- unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void),
- > = None;
-}
-
impl ObjectImpl for PL011Luminary {
type Class = PL011LuminaryClass;
const TYPE_NAME: &'static CStr = crate::TYPE_PL011_LUMINARY;
const PARENT_TYPE_NAME: Option<&'static CStr> = Some(crate::TYPE_PL011);
const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> =
Some(pl011_luminary_init);
}
+
+impl DeviceImpl for PL011Luminary {}
+
+impl_device_class!(PL011Luminary);
diff --git a/rust/hw/char/pl011/src/device_class.rs
b/rust/hw/char/pl011/src/device_class.rs
index a707fde1384..c61b6bb0258 100644
--- a/rust/hw/char/pl011/src/device_class.rs
+++ b/rust/hw/char/pl011/src/device_class.rs
@@ -93,14 +93,6 @@ extern "C" fn pl011_post_load(opaque: *mut c_void,
version_id: c_int) -> c_int {
),
}
-qemu_api::device_class_init! {
- pl011_class_init,
- props => PL011_PROPERTIES,
- realize_fn => Some(pl011_realize),
- legacy_reset_fn => Some(pl011_reset),
- vmsd => VMSTATE_PL011,
-}
-
/// # Safety
///
/// We expect the FFI user of this function to pass a valid pointer, that has
diff --git a/rust/qemu-api/src/device_class.rs
b/rust/qemu-api/src/device_class.rs
index 922bbce1bb8..f683f94f2a5 100644
--- a/rust/qemu-api/src/device_class.rs
+++ b/rust/qemu-api/src/device_class.rs
@@ -2,25 +2,80 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later
-use std::ffi::CStr;
+use std::{ffi::CStr, os::raw::c_void};
-use crate::bindings;
+use crate::{
+ bindings::{self, DeviceClass, DeviceState, Error, ObjectClass, Property,
VMStateDescription},
+ zeroable::Zeroable,
+};
+
+/// Trait providing the contents of [`DeviceClass`].
+pub trait DeviceImpl {
+ /// _Realization_ is the second stage of device creation. It contains
+ /// all operations that depend on device properties and can fail (note:
+ /// this is not yet supported for Rust devices).
+ ///
+ /// If not `None`, the parent class's `realize` method is overridden
+ /// with the function pointed to by `REALIZE`.
+ const REALIZE: Option<unsafe extern "C" fn(*mut DeviceState, *mut *mut
Error)> = None;
+
+ /// If not `None`, the parent class's `reset` method is overridden
+ /// with the function pointed to by `RESET`.
+ ///
+ /// Rust does not yet support the three-phase reset protocol; this is
+ /// usually okay for leaf classes.
+ const RESET: Option<unsafe extern "C" fn(dev: *mut DeviceState)> = None;
+
+ /// An array providing the properties that the user can set on the
+ /// 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
+ /// Not a `const` because referencing statics in constants is unstable
+ /// until Rust 1.83.0.
+ fn vmsd() -> Option<&'static VMStateDescription> {
+ None
+ }
+}
+
+/// # 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();
+ if let Some(realize_fn) = <T as DeviceImpl>::REALIZE {
+ dc.realize = Some(realize_fn);
+ }
+ if let Some(reset_fn) = <T as DeviceImpl>::RESET {
+ bindings::device_class_set_legacy_reset(dc, Some(reset_fn));
+ }
+ 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! device_class_init {
- ($func:ident, props => $props:ident, realize_fn => $realize_fn:expr,
legacy_reset_fn => $legacy_reset_fn:expr, vmsd => $vmsd:ident$(,)*) => {
- pub unsafe extern "C" fn $func(
- klass: *mut $crate::bindings::ObjectClass,
- _: *mut ::std::os::raw::c_void,
- ) {
- let mut dc =
-
::core::ptr::NonNull::new(klass.cast::<$crate::bindings::DeviceClass>()).unwrap();
- unsafe {
- dc.as_mut().realize = $realize_fn;
- dc.as_mut().vmsd = &$vmsd;
- $crate::bindings::device_class_set_legacy_reset(dc.as_mut(),
$legacy_reset_fn);
- $crate::bindings::device_class_set_props(dc.as_mut(),
$props.as_ptr());
- }
+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;
}
};
}
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
index fd0c979121c..b8b12a40422 100644
--- a/rust/qemu-api/tests/tests.rs
+++ b/rust/qemu-api/tests/tests.rs
@@ -2,13 +2,14 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later
-use std::{ffi::CStr, os::raw::c_void};
+use std::ffi::CStr;
use qemu_api::{
bindings::*,
c_str, declare_properties, define_property,
- definitions::{ClassInitImpl, ObjectImpl},
- device_class, device_class_init,
+ definitions::ObjectImpl,
+ device_class::{self, DeviceImpl},
+ impl_device_class,
zeroable::Zeroable,
};
@@ -45,28 +46,23 @@ pub struct DummyClass {
),
}
- device_class_init! {
- dummy_class_init,
- props => DUMMY_PROPERTIES,
- realize_fn => None,
- legacy_reset_fn => None,
- vmsd => VMSTATE,
- }
-
impl ObjectImpl for DummyState {
type Class = DummyClass;
const TYPE_NAME: &'static CStr = c_str!("dummy");
const PARENT_TYPE_NAME: Option<&'static CStr> =
Some(device_class::TYPE_DEVICE);
}
- impl ClassInitImpl for DummyState {
- const CLASS_INIT: Option<unsafe extern "C" fn(klass: *mut ObjectClass,
data: *mut c_void)> =
- Some(dummy_class_init);
- const CLASS_BASE_INIT: Option<
- unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void),
- > = None;
+ impl DeviceImpl for DummyState {
+ fn properties() -> &'static [Property] {
+ &DUMMY_PROPERTIES
+ }
+ fn vmsd() -> Option<&'static VMStateDescription> {
+ Some(&VMSTATE)
+ }
}
+ impl_device_class!(DummyState);
+
unsafe {
module_call_init(module_init_type::MODULE_INIT_QOM);
object_unref(object_new(DummyState::TYPE_NAME.as_ptr()).cast());
--
2.47.1
- Re: [PATCH 06/26] rust: add a bit operation module, (continued)
- [PATCH 05/26] rust: add bindings for interrupt sources, Paolo Bonzini, 2024/12/09
- [PATCH 08/26] rust: qom: rename Class trait to ClassInitImpl, Paolo Bonzini, 2024/12/09
- [PATCH 10/26] rust: qom: move ClassInitImpl to the instance side, Paolo Bonzini, 2024/12/09
- [PATCH 09/26] rust: qom: convert type_info! macro to an associated const, Paolo Bonzini, 2024/12/09
- [PATCH 11/26] rust: qdev: move device_class_init! body to generic function, ClassInitImpl implementation to macro,
Paolo Bonzini <=
- [PATCH 13/26] rust: qom: automatically use Drop trait to implement instance_finalize, Paolo Bonzini, 2024/12/09
- [PATCH 16/26] rust: qom: change the parent type to an associated type, Paolo Bonzini, 2024/12/09
- [PATCH 17/26] rust: qom: put class_init together from multiple ClassInitImpl<>, Paolo Bonzini, 2024/12/09
- [PATCH 20/26] rust: re-export C types from qemu-api submodules, Paolo Bonzini, 2024/12/09