xref: /qemu/rust/qemu-api/src/qdev.rs (revision 5472a38cb9e10bda897fc29d4841c00476f22585)
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 
54aed0296SPaolo Bonzini //! Bindings to create devices and access device functionality from Rust.
64aed0296SPaolo Bonzini 
7201ef001SPaolo Bonzini use std::{
8201ef001SPaolo Bonzini     ffi::{CStr, CString},
9201ef001SPaolo Bonzini     os::raw::c_void,
10201ef001SPaolo Bonzini     ptr::NonNull,
11201ef001SPaolo Bonzini };
12ce4a144cSPaolo Bonzini 
13*5472a38cSPaolo Bonzini pub use bindings::{Clock, ClockEvent, DeviceClass, DeviceState, Property, ResetType};
14716d89f9SPaolo Bonzini 
158c80c472SPaolo Bonzini use crate::{
16*5472a38cSPaolo Bonzini     bindings::{self, Error, ResettableClass},
17201ef001SPaolo Bonzini     callbacks::FnCall,
18201ef001SPaolo Bonzini     cell::bql_locked,
197bd8e3efSPaolo Bonzini     prelude::*,
2068da5402SPaolo Bonzini     qom::{ClassInitImpl, ObjectClass, ObjectImpl, Owned},
21716d89f9SPaolo Bonzini     vmstate::VMStateDescription,
228c80c472SPaolo Bonzini };
238c80c472SPaolo Bonzini 
24*5472a38cSPaolo Bonzini /// Trait providing the contents of the `ResettablePhases` struct,
25*5472a38cSPaolo Bonzini /// which is part of the QOM `Resettable` interface.
26*5472a38cSPaolo Bonzini pub trait ResettablePhasesImpl {
27*5472a38cSPaolo Bonzini     /// If not None, this is called when the object enters reset. It
28*5472a38cSPaolo Bonzini     /// can reset local state of the object, but it must not do anything that
29*5472a38cSPaolo Bonzini     /// has a side-effect on other objects, such as raising or lowering an
30*5472a38cSPaolo Bonzini     /// [`InterruptSource`](crate::irq::InterruptSource), or reading or
31*5472a38cSPaolo Bonzini     /// writing guest memory. It takes the reset's type as argument.
32*5472a38cSPaolo Bonzini     const ENTER: Option<fn(&Self, ResetType)> = None;
33*5472a38cSPaolo Bonzini 
34*5472a38cSPaolo Bonzini     /// If not None, this is called when the object for entry into reset, once
35*5472a38cSPaolo Bonzini     /// every object in the system which is being reset has had its
36*5472a38cSPaolo Bonzini     /// `ResettablePhasesImpl::ENTER` method called. At this point devices
37*5472a38cSPaolo Bonzini     /// can do actions that affect other objects.
38*5472a38cSPaolo Bonzini     ///
39*5472a38cSPaolo Bonzini     /// If in doubt, implement this method.
40*5472a38cSPaolo Bonzini     const HOLD: Option<fn(&Self, ResetType)> = None;
41*5472a38cSPaolo Bonzini 
42*5472a38cSPaolo Bonzini     /// If not None, this phase is called when the object leaves the reset
43*5472a38cSPaolo Bonzini     /// state. Actions affecting other objects are permitted.
44*5472a38cSPaolo Bonzini     const EXIT: Option<fn(&Self, ResetType)> = None;
45*5472a38cSPaolo Bonzini }
46*5472a38cSPaolo Bonzini 
47*5472a38cSPaolo Bonzini /// # Safety
48*5472a38cSPaolo Bonzini ///
49*5472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
50*5472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
51*5472a38cSPaolo Bonzini /// readable/writeable from one thread at any time.
52*5472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>(
53*5472a38cSPaolo Bonzini     obj: *mut Object,
54*5472a38cSPaolo Bonzini     typ: ResetType,
55*5472a38cSPaolo Bonzini ) {
56*5472a38cSPaolo Bonzini     let state = NonNull::new(obj).unwrap().cast::<T>();
57*5472a38cSPaolo Bonzini     T::ENTER.unwrap()(unsafe { state.as_ref() }, typ);
58*5472a38cSPaolo Bonzini }
59*5472a38cSPaolo Bonzini 
60*5472a38cSPaolo Bonzini /// # Safety
61*5472a38cSPaolo Bonzini ///
62*5472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
63*5472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
64*5472a38cSPaolo Bonzini /// readable/writeable from one thread at any time.
65*5472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>(
66*5472a38cSPaolo Bonzini     obj: *mut Object,
67*5472a38cSPaolo Bonzini     typ: ResetType,
68*5472a38cSPaolo Bonzini ) {
69*5472a38cSPaolo Bonzini     let state = NonNull::new(obj).unwrap().cast::<T>();
70*5472a38cSPaolo Bonzini     T::HOLD.unwrap()(unsafe { state.as_ref() }, typ);
71*5472a38cSPaolo Bonzini }
72*5472a38cSPaolo Bonzini 
73*5472a38cSPaolo Bonzini /// # Safety
74*5472a38cSPaolo Bonzini ///
75*5472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
76*5472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
77*5472a38cSPaolo Bonzini /// readable/writeable from one thread at any time.
78*5472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>(
79*5472a38cSPaolo Bonzini     obj: *mut Object,
80*5472a38cSPaolo Bonzini     typ: ResetType,
81*5472a38cSPaolo Bonzini ) {
82*5472a38cSPaolo Bonzini     let state = NonNull::new(obj).unwrap().cast::<T>();
83*5472a38cSPaolo Bonzini     T::EXIT.unwrap()(unsafe { state.as_ref() }, typ);
84*5472a38cSPaolo Bonzini }
85*5472a38cSPaolo Bonzini 
868c80c472SPaolo Bonzini /// Trait providing the contents of [`DeviceClass`].
87*5472a38cSPaolo Bonzini pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl {
888c80c472SPaolo Bonzini     /// _Realization_ is the second stage of device creation. It contains
898c80c472SPaolo Bonzini     /// all operations that depend on device properties and can fail (note:
908c80c472SPaolo Bonzini     /// this is not yet supported for Rust devices).
918c80c472SPaolo Bonzini     ///
928c80c472SPaolo Bonzini     /// If not `None`, the parent class's `realize` method is overridden
938c80c472SPaolo Bonzini     /// with the function pointed to by `REALIZE`.
940f9eb0ffSZhao Liu     const REALIZE: Option<fn(&Self)> = None;
958c80c472SPaolo Bonzini 
968c80c472SPaolo Bonzini     /// An array providing the properties that the user can set on the
978c80c472SPaolo Bonzini     /// device.  Not a `const` because referencing statics in constants
988c80c472SPaolo Bonzini     /// is unstable until Rust 1.83.0.
998c80c472SPaolo Bonzini     fn properties() -> &'static [Property] {
1005f997648SRichard Henderson         &[]
1018c80c472SPaolo Bonzini     }
1028c80c472SPaolo Bonzini 
1038c80c472SPaolo Bonzini     /// A `VMStateDescription` providing the migration format for the device
1048c80c472SPaolo Bonzini     /// Not a `const` because referencing statics in constants is unstable
1058c80c472SPaolo Bonzini     /// until Rust 1.83.0.
1068c80c472SPaolo Bonzini     fn vmsd() -> Option<&'static VMStateDescription> {
1078c80c472SPaolo Bonzini         None
1088c80c472SPaolo Bonzini     }
1098c80c472SPaolo Bonzini }
1108c80c472SPaolo Bonzini 
1118c80c472SPaolo Bonzini /// # Safety
1128c80c472SPaolo Bonzini ///
113f75fb90fSPaolo Bonzini /// This function is only called through the QOM machinery and
1146dd818fbSPaolo Bonzini /// used by the `ClassInitImpl<DeviceClass>` trait.
115f75fb90fSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
116f75fb90fSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
117f75fb90fSPaolo Bonzini /// readable/writeable from one thread at any time.
118f75fb90fSPaolo Bonzini unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>(dev: *mut DeviceState, _errp: *mut *mut Error) {
1197d052039SPaolo Bonzini     let state = NonNull::new(dev).unwrap().cast::<T>();
1207d052039SPaolo Bonzini     T::REALIZE.unwrap()(unsafe { state.as_ref() });
121f75fb90fSPaolo Bonzini }
122f75fb90fSPaolo Bonzini 
123*5472a38cSPaolo Bonzini unsafe impl InterfaceType for ResettableClass {
124*5472a38cSPaolo Bonzini     const TYPE_NAME: &'static CStr =
125*5472a38cSPaolo Bonzini         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_RESETTABLE_INTERFACE) };
126*5472a38cSPaolo Bonzini }
127*5472a38cSPaolo Bonzini 
128*5472a38cSPaolo Bonzini impl<T> ClassInitImpl<ResettableClass> for T
129*5472a38cSPaolo Bonzini where
130*5472a38cSPaolo Bonzini     T: ResettablePhasesImpl,
131*5472a38cSPaolo Bonzini {
132*5472a38cSPaolo Bonzini     fn class_init(rc: &mut ResettableClass) {
133*5472a38cSPaolo Bonzini         if <T as ResettablePhasesImpl>::ENTER.is_some() {
134*5472a38cSPaolo Bonzini             rc.phases.enter = Some(rust_resettable_enter_fn::<T>);
135*5472a38cSPaolo Bonzini         }
136*5472a38cSPaolo Bonzini         if <T as ResettablePhasesImpl>::HOLD.is_some() {
137*5472a38cSPaolo Bonzini             rc.phases.hold = Some(rust_resettable_hold_fn::<T>);
138*5472a38cSPaolo Bonzini         }
139*5472a38cSPaolo Bonzini         if <T as ResettablePhasesImpl>::EXIT.is_some() {
140*5472a38cSPaolo Bonzini             rc.phases.exit = Some(rust_resettable_exit_fn::<T>);
141*5472a38cSPaolo Bonzini         }
142*5472a38cSPaolo Bonzini     }
143f75fb90fSPaolo Bonzini }
144f75fb90fSPaolo Bonzini 
1456dd818fbSPaolo Bonzini impl<T> ClassInitImpl<DeviceClass> for T
1466dd818fbSPaolo Bonzini where
147*5472a38cSPaolo Bonzini     T: ClassInitImpl<ObjectClass> + ClassInitImpl<ResettableClass> + DeviceImpl,
1486dd818fbSPaolo Bonzini {
1496dd818fbSPaolo Bonzini     fn class_init(dc: &mut DeviceClass) {
150f75fb90fSPaolo Bonzini         if <T as DeviceImpl>::REALIZE.is_some() {
151f75fb90fSPaolo Bonzini             dc.realize = Some(rust_realize_fn::<T>);
1528c80c472SPaolo Bonzini         }
1538c80c472SPaolo Bonzini         if let Some(vmsd) = <T as DeviceImpl>::vmsd() {
1548c80c472SPaolo Bonzini             dc.vmsd = vmsd;
1558c80c472SPaolo Bonzini         }
1565f997648SRichard Henderson         let prop = <T as DeviceImpl>::properties();
1575f997648SRichard Henderson         if !prop.is_empty() {
1586dd818fbSPaolo Bonzini             unsafe {
1595f997648SRichard Henderson                 bindings::device_class_set_props_n(dc, prop.as_ptr(), prop.len());
1605f997648SRichard Henderson             }
1618c80c472SPaolo Bonzini         }
162cb36da9bSPaolo Bonzini 
163*5472a38cSPaolo Bonzini         ResettableClass::interface_init::<T, DeviceState>(dc);
164cb36da9bSPaolo Bonzini         <T as ClassInitImpl<ObjectClass>>::class_init(&mut dc.parent_class);
1658c80c472SPaolo Bonzini     }
1665a5110d2SManos Pitsidianakis }
1675a5110d2SManos Pitsidianakis 
1685a5110d2SManos Pitsidianakis #[macro_export]
1695a5110d2SManos Pitsidianakis macro_rules! define_property {
170a3057c52SJunjie Mao     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, default = $defval:expr$(,)*) => {
1715a5110d2SManos Pitsidianakis         $crate::bindings::Property {
17203a573b9SPaolo Bonzini             // use associated function syntax for type checking
1739f7d4520SPaolo Bonzini             name: ::std::ffi::CStr::as_ptr($name),
1745a5110d2SManos Pitsidianakis             info: $prop,
175f3518400SJunjie Mao             offset: $crate::offset_of!($state, $field) as isize,
1765a5110d2SManos Pitsidianakis             set_default: true,
17703a573b9SPaolo Bonzini             defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
1786e50bde1SPaolo Bonzini             ..$crate::zeroable::Zeroable::ZERO
1795a5110d2SManos Pitsidianakis         }
1805a5110d2SManos Pitsidianakis     };
181a3057c52SJunjie Mao     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty$(,)*) => {
1825a5110d2SManos Pitsidianakis         $crate::bindings::Property {
18303a573b9SPaolo Bonzini             // use associated function syntax for type checking
1849f7d4520SPaolo Bonzini             name: ::std::ffi::CStr::as_ptr($name),
1855a5110d2SManos Pitsidianakis             info: $prop,
186f3518400SJunjie Mao             offset: $crate::offset_of!($state, $field) as isize,
1875a5110d2SManos Pitsidianakis             set_default: false,
1886e50bde1SPaolo Bonzini             ..$crate::zeroable::Zeroable::ZERO
1895a5110d2SManos Pitsidianakis         }
1905a5110d2SManos Pitsidianakis     };
1915a5110d2SManos Pitsidianakis }
1925a5110d2SManos Pitsidianakis 
1935a5110d2SManos Pitsidianakis #[macro_export]
1945a5110d2SManos Pitsidianakis macro_rules! declare_properties {
1955a5110d2SManos Pitsidianakis     ($ident:ident, $($prop:expr),*$(,)*) => {
196c92c447fSPaolo Bonzini         pub static $ident: [$crate::bindings::Property; {
1975f997648SRichard Henderson             let mut len = 0;
1985a5110d2SManos Pitsidianakis             $({
1995a5110d2SManos Pitsidianakis                 _ = stringify!($prop);
2005a5110d2SManos Pitsidianakis                 len += 1;
2015a5110d2SManos Pitsidianakis             })*
2025a5110d2SManos Pitsidianakis             len
203c92c447fSPaolo Bonzini         }] = [
2045a5110d2SManos Pitsidianakis             $($prop),*,
205c92c447fSPaolo Bonzini         ];
2065a5110d2SManos Pitsidianakis     };
2075a5110d2SManos Pitsidianakis }
208ce4a144cSPaolo Bonzini 
2096dd818fbSPaolo Bonzini unsafe impl ObjectType for DeviceState {
2106dd818fbSPaolo Bonzini     type Class = DeviceClass;
2117bd8e3efSPaolo Bonzini     const TYPE_NAME: &'static CStr =
212ce4a144cSPaolo Bonzini         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_DEVICE) };
2137bd8e3efSPaolo Bonzini }
214f50cd85cSPaolo Bonzini qom_isa!(DeviceState: Object);
215201ef001SPaolo Bonzini 
216201ef001SPaolo Bonzini /// Trait for methods exposed by the [`DeviceState`] class.  The methods can be
217201ef001SPaolo Bonzini /// called on all objects that have the trait `IsA<DeviceState>`.
218201ef001SPaolo Bonzini ///
219201ef001SPaolo Bonzini /// The trait should only be used through the blanket implementation,
220201ef001SPaolo Bonzini /// which guarantees safety via `IsA`.
221201ef001SPaolo Bonzini pub trait DeviceMethods: ObjectDeref
222201ef001SPaolo Bonzini where
223201ef001SPaolo Bonzini     Self::Target: IsA<DeviceState>,
224201ef001SPaolo Bonzini {
225201ef001SPaolo Bonzini     /// Add an input clock named `name`.  Invoke the callback with
226201ef001SPaolo Bonzini     /// `self` as the first parameter for the events that are requested.
227201ef001SPaolo Bonzini     ///
228201ef001SPaolo Bonzini     /// The resulting clock is added as a child of `self`, but it also
229201ef001SPaolo Bonzini     /// stays alive until after `Drop::drop` is called because C code
230201ef001SPaolo Bonzini     /// keeps an extra reference to it until `device_finalize()` calls
231201ef001SPaolo Bonzini     /// `qdev_finalize_clocklist()`.  Therefore (unlike most cases in
232201ef001SPaolo Bonzini     /// which Rust code has a reference to a child object) it would be
233201ef001SPaolo Bonzini     /// possible for this function to return a `&Clock` too.
234201ef001SPaolo Bonzini     #[inline]
235201ef001SPaolo Bonzini     fn init_clock_in<F: for<'a> FnCall<(&'a Self::Target, ClockEvent)>>(
236201ef001SPaolo Bonzini         &self,
237201ef001SPaolo Bonzini         name: &str,
238201ef001SPaolo Bonzini         _cb: &F,
239201ef001SPaolo Bonzini         events: ClockEvent,
240201ef001SPaolo Bonzini     ) -> Owned<Clock> {
241201ef001SPaolo Bonzini         fn do_init_clock_in(
242201ef001SPaolo Bonzini             dev: *mut DeviceState,
243201ef001SPaolo Bonzini             name: &str,
244201ef001SPaolo Bonzini             cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)>,
245201ef001SPaolo Bonzini             events: ClockEvent,
246201ef001SPaolo Bonzini         ) -> Owned<Clock> {
247201ef001SPaolo Bonzini             assert!(bql_locked());
248201ef001SPaolo Bonzini 
249201ef001SPaolo Bonzini             // SAFETY: the clock is heap allocated, but qdev_init_clock_in()
250201ef001SPaolo Bonzini             // does not gift the reference to its caller; so use Owned::from to
251201ef001SPaolo Bonzini             // add one.  The callback is disabled automatically when the clock
252201ef001SPaolo Bonzini             // is unparented, which happens before the device is finalized.
253201ef001SPaolo Bonzini             unsafe {
254201ef001SPaolo Bonzini                 let cstr = CString::new(name).unwrap();
255201ef001SPaolo Bonzini                 let clk = bindings::qdev_init_clock_in(
256201ef001SPaolo Bonzini                     dev,
257201ef001SPaolo Bonzini                     cstr.as_ptr(),
258201ef001SPaolo Bonzini                     cb,
259201ef001SPaolo Bonzini                     dev.cast::<c_void>(),
260201ef001SPaolo Bonzini                     events.0,
261201ef001SPaolo Bonzini                 );
262201ef001SPaolo Bonzini 
263201ef001SPaolo Bonzini                 Owned::from(&*clk)
264201ef001SPaolo Bonzini             }
265201ef001SPaolo Bonzini         }
266201ef001SPaolo Bonzini 
267201ef001SPaolo Bonzini         let cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)> = if F::is_some() {
268201ef001SPaolo Bonzini             unsafe extern "C" fn rust_clock_cb<T, F: for<'a> FnCall<(&'a T, ClockEvent)>>(
269201ef001SPaolo Bonzini                 opaque: *mut c_void,
270201ef001SPaolo Bonzini                 event: ClockEvent,
271201ef001SPaolo Bonzini             ) {
272201ef001SPaolo Bonzini                 // SAFETY: the opaque is "this", which is indeed a pointer to T
273201ef001SPaolo Bonzini                 F::call((unsafe { &*(opaque.cast::<T>()) }, event))
274201ef001SPaolo Bonzini             }
275201ef001SPaolo Bonzini             Some(rust_clock_cb::<Self::Target, F>)
276201ef001SPaolo Bonzini         } else {
277201ef001SPaolo Bonzini             None
278201ef001SPaolo Bonzini         };
279201ef001SPaolo Bonzini 
280201ef001SPaolo Bonzini         do_init_clock_in(self.as_mut_ptr(), name, cb, events)
281201ef001SPaolo Bonzini     }
282201ef001SPaolo Bonzini 
283201ef001SPaolo Bonzini     /// Add an output clock named `name`.
284201ef001SPaolo Bonzini     ///
285201ef001SPaolo Bonzini     /// The resulting clock is added as a child of `self`, but it also
286201ef001SPaolo Bonzini     /// stays alive until after `Drop::drop` is called because C code
287201ef001SPaolo Bonzini     /// keeps an extra reference to it until `device_finalize()` calls
288201ef001SPaolo Bonzini     /// `qdev_finalize_clocklist()`.  Therefore (unlike most cases in
289201ef001SPaolo Bonzini     /// which Rust code has a reference to a child object) it would be
290201ef001SPaolo Bonzini     /// possible for this function to return a `&Clock` too.
291201ef001SPaolo Bonzini     #[inline]
292201ef001SPaolo Bonzini     fn init_clock_out(&self, name: &str) -> Owned<Clock> {
293201ef001SPaolo Bonzini         unsafe {
294201ef001SPaolo Bonzini             let cstr = CString::new(name).unwrap();
295201ef001SPaolo Bonzini             let clk = bindings::qdev_init_clock_out(self.as_mut_ptr(), cstr.as_ptr());
296201ef001SPaolo Bonzini 
297201ef001SPaolo Bonzini             Owned::from(&*clk)
298201ef001SPaolo Bonzini         }
299201ef001SPaolo Bonzini     }
300201ef001SPaolo Bonzini }
301201ef001SPaolo Bonzini 
302201ef001SPaolo Bonzini impl<R: ObjectDeref> DeviceMethods for R where R::Target: IsA<DeviceState> {}
303201ef001SPaolo Bonzini 
304201ef001SPaolo Bonzini unsafe impl ObjectType for Clock {
305201ef001SPaolo Bonzini     type Class = ObjectClass;
306201ef001SPaolo Bonzini     const TYPE_NAME: &'static CStr =
307201ef001SPaolo Bonzini         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_CLOCK) };
308201ef001SPaolo Bonzini }
309201ef001SPaolo Bonzini qom_isa!(Clock: Object);
310