xref: /qemu/rust/qemu-api/src/qdev.rs (revision 8c80c472da6342c5924bc4ea7e87c77ca61477b8)
15a5110d2SManos Pitsidianakis // Copyright 2024, Linaro Limited
25a5110d2SManos Pitsidianakis // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
35a5110d2SManos Pitsidianakis // SPDX-License-Identifier: GPL-2.0-or-later
45a5110d2SManos Pitsidianakis 
5*8c80c472SPaolo Bonzini use std::{ffi::CStr, os::raw::c_void};
6ce4a144cSPaolo Bonzini 
7*8c80c472SPaolo Bonzini use crate::{
8*8c80c472SPaolo Bonzini     bindings::{self, DeviceClass, DeviceState, Error, ObjectClass, Property, VMStateDescription},
9*8c80c472SPaolo Bonzini     zeroable::Zeroable,
10*8c80c472SPaolo Bonzini };
11*8c80c472SPaolo Bonzini 
12*8c80c472SPaolo Bonzini /// Trait providing the contents of [`DeviceClass`].
13*8c80c472SPaolo Bonzini pub trait DeviceImpl {
14*8c80c472SPaolo Bonzini     /// _Realization_ is the second stage of device creation. It contains
15*8c80c472SPaolo Bonzini     /// all operations that depend on device properties and can fail (note:
16*8c80c472SPaolo Bonzini     /// this is not yet supported for Rust devices).
17*8c80c472SPaolo Bonzini     ///
18*8c80c472SPaolo Bonzini     /// If not `None`, the parent class's `realize` method is overridden
19*8c80c472SPaolo Bonzini     /// with the function pointed to by `REALIZE`.
20*8c80c472SPaolo Bonzini     const REALIZE: Option<unsafe extern "C" fn(*mut DeviceState, *mut *mut Error)> = None;
21*8c80c472SPaolo Bonzini 
22*8c80c472SPaolo Bonzini     /// If not `None`, the parent class's `reset` method is overridden
23*8c80c472SPaolo Bonzini     /// with the function pointed to by `RESET`.
24*8c80c472SPaolo Bonzini     ///
25*8c80c472SPaolo Bonzini     /// Rust does not yet support the three-phase reset protocol; this is
26*8c80c472SPaolo Bonzini     /// usually okay for leaf classes.
27*8c80c472SPaolo Bonzini     const RESET: Option<unsafe extern "C" fn(dev: *mut DeviceState)> = None;
28*8c80c472SPaolo Bonzini 
29*8c80c472SPaolo Bonzini     /// An array providing the properties that the user can set on the
30*8c80c472SPaolo Bonzini     /// device.  Not a `const` because referencing statics in constants
31*8c80c472SPaolo Bonzini     /// is unstable until Rust 1.83.0.
32*8c80c472SPaolo Bonzini     fn properties() -> &'static [Property] {
33*8c80c472SPaolo Bonzini         &[Zeroable::ZERO; 1]
34*8c80c472SPaolo Bonzini     }
35*8c80c472SPaolo Bonzini 
36*8c80c472SPaolo Bonzini     /// A `VMStateDescription` providing the migration format for the device
37*8c80c472SPaolo Bonzini     /// Not a `const` because referencing statics in constants is unstable
38*8c80c472SPaolo Bonzini     /// until Rust 1.83.0.
39*8c80c472SPaolo Bonzini     fn vmsd() -> Option<&'static VMStateDescription> {
40*8c80c472SPaolo Bonzini         None
41*8c80c472SPaolo Bonzini     }
42*8c80c472SPaolo Bonzini }
43*8c80c472SPaolo Bonzini 
44*8c80c472SPaolo Bonzini /// # Safety
45*8c80c472SPaolo Bonzini ///
46*8c80c472SPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
47*8c80c472SPaolo Bonzini /// can be downcasted to type `DeviceClass`, because `T` implements
48*8c80c472SPaolo Bonzini /// `DeviceImpl`.
49*8c80c472SPaolo Bonzini pub unsafe extern "C" fn rust_device_class_init<T: DeviceImpl>(
50*8c80c472SPaolo Bonzini     klass: *mut ObjectClass,
51*8c80c472SPaolo Bonzini     _: *mut c_void,
52*8c80c472SPaolo Bonzini ) {
53*8c80c472SPaolo Bonzini     let mut dc = ::core::ptr::NonNull::new(klass.cast::<DeviceClass>()).unwrap();
54*8c80c472SPaolo Bonzini     unsafe {
55*8c80c472SPaolo Bonzini         let dc = dc.as_mut();
56*8c80c472SPaolo Bonzini         if let Some(realize_fn) = <T as DeviceImpl>::REALIZE {
57*8c80c472SPaolo Bonzini             dc.realize = Some(realize_fn);
58*8c80c472SPaolo Bonzini         }
59*8c80c472SPaolo Bonzini         if let Some(reset_fn) = <T as DeviceImpl>::RESET {
60*8c80c472SPaolo Bonzini             bindings::device_class_set_legacy_reset(dc, Some(reset_fn));
61*8c80c472SPaolo Bonzini         }
62*8c80c472SPaolo Bonzini         if let Some(vmsd) = <T as DeviceImpl>::vmsd() {
63*8c80c472SPaolo Bonzini             dc.vmsd = vmsd;
64*8c80c472SPaolo Bonzini         }
65*8c80c472SPaolo Bonzini         bindings::device_class_set_props(dc, <T as DeviceImpl>::properties().as_ptr());
66*8c80c472SPaolo Bonzini     }
67*8c80c472SPaolo Bonzini }
68ce4a144cSPaolo Bonzini 
695a5110d2SManos Pitsidianakis #[macro_export]
70*8c80c472SPaolo Bonzini macro_rules! impl_device_class {
71*8c80c472SPaolo Bonzini     ($type:ty) => {
72*8c80c472SPaolo Bonzini         impl $crate::definitions::ClassInitImpl for $type {
73*8c80c472SPaolo Bonzini             const CLASS_INIT: Option<
74*8c80c472SPaolo Bonzini                 unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut ::std::os::raw::c_void),
75*8c80c472SPaolo Bonzini             > = Some($crate::device_class::rust_device_class_init::<$type>);
76*8c80c472SPaolo Bonzini             const CLASS_BASE_INIT: Option<
77*8c80c472SPaolo Bonzini                 unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut ::std::os::raw::c_void),
78*8c80c472SPaolo Bonzini             > = None;
797b72c7ddSPaolo Bonzini         }
805a5110d2SManos Pitsidianakis     };
815a5110d2SManos Pitsidianakis }
825a5110d2SManos Pitsidianakis 
835a5110d2SManos Pitsidianakis #[macro_export]
845a5110d2SManos Pitsidianakis macro_rules! define_property {
85a3057c52SJunjie Mao     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, default = $defval:expr$(,)*) => {
865a5110d2SManos Pitsidianakis         $crate::bindings::Property {
8703a573b9SPaolo Bonzini             // use associated function syntax for type checking
889f7d4520SPaolo Bonzini             name: ::std::ffi::CStr::as_ptr($name),
895a5110d2SManos Pitsidianakis             info: $prop,
90f3518400SJunjie Mao             offset: $crate::offset_of!($state, $field) as isize,
915a5110d2SManos Pitsidianakis             set_default: true,
9203a573b9SPaolo Bonzini             defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
936e50bde1SPaolo Bonzini             ..$crate::zeroable::Zeroable::ZERO
945a5110d2SManos Pitsidianakis         }
955a5110d2SManos Pitsidianakis     };
96a3057c52SJunjie Mao     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty$(,)*) => {
975a5110d2SManos Pitsidianakis         $crate::bindings::Property {
9803a573b9SPaolo Bonzini             // use associated function syntax for type checking
999f7d4520SPaolo Bonzini             name: ::std::ffi::CStr::as_ptr($name),
1005a5110d2SManos Pitsidianakis             info: $prop,
101f3518400SJunjie Mao             offset: $crate::offset_of!($state, $field) as isize,
1025a5110d2SManos Pitsidianakis             set_default: false,
1036e50bde1SPaolo Bonzini             ..$crate::zeroable::Zeroable::ZERO
1045a5110d2SManos Pitsidianakis         }
1055a5110d2SManos Pitsidianakis     };
1065a5110d2SManos Pitsidianakis }
1075a5110d2SManos Pitsidianakis 
1085a5110d2SManos Pitsidianakis #[macro_export]
1095a5110d2SManos Pitsidianakis macro_rules! declare_properties {
1105a5110d2SManos Pitsidianakis     ($ident:ident, $($prop:expr),*$(,)*) => {
111c92c447fSPaolo Bonzini         pub static $ident: [$crate::bindings::Property; {
1125a5110d2SManos Pitsidianakis             let mut len = 1;
1135a5110d2SManos Pitsidianakis             $({
1145a5110d2SManos Pitsidianakis                 _ = stringify!($prop);
1155a5110d2SManos Pitsidianakis                 len += 1;
1165a5110d2SManos Pitsidianakis             })*
1175a5110d2SManos Pitsidianakis             len
118c92c447fSPaolo Bonzini         }] = [
1195a5110d2SManos Pitsidianakis             $($prop),*,
1206e50bde1SPaolo Bonzini             $crate::zeroable::Zeroable::ZERO,
121c92c447fSPaolo Bonzini         ];
1225a5110d2SManos Pitsidianakis     };
1235a5110d2SManos Pitsidianakis }
124ce4a144cSPaolo Bonzini 
125ce4a144cSPaolo Bonzini // workaround until we can use --generate-cstr in bindgen.
126ce4a144cSPaolo Bonzini pub const TYPE_DEVICE: &CStr =
127ce4a144cSPaolo Bonzini     unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_DEVICE) };
128ce4a144cSPaolo Bonzini pub const TYPE_SYS_BUS_DEVICE: &CStr =
129ce4a144cSPaolo Bonzini     unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_SYS_BUS_DEVICE) };
130