@@ -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);
@@ -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
@@ -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;
}
};
}
@@ -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());