xref: /qemu/rust/qemu-api/src/qdev.rs (revision b134a09ffab3b918979007cf40f603e5b54ed597)
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::{
8e4fb0be1SPaolo Bonzini     ffi::{c_int, c_void, CStr, CString},
9201ef001SPaolo Bonzini     ptr::NonNull,
10201ef001SPaolo Bonzini };
11ce4a144cSPaolo Bonzini 
12fc22d650SPaolo Bonzini pub use bindings::{ClockEvent, DeviceClass, Property, ResetType};
13716d89f9SPaolo Bonzini 
148c80c472SPaolo Bonzini use crate::{
159a96d410SZhao Liu     bindings::{self, qdev_init_gpio_in, qdev_init_gpio_out, Error, ResettableClass},
16201ef001SPaolo Bonzini     callbacks::FnCall,
17fc22d650SPaolo Bonzini     cell::{bql_locked, Opaque},
18a22bd55fSPaolo Bonzini     chardev::Chardev,
199a96d410SZhao Liu     irq::InterruptSource,
207bd8e3efSPaolo Bonzini     prelude::*,
21d556226dSPaolo Bonzini     qom::{ObjectClass, ObjectImpl, Owned},
22716d89f9SPaolo Bonzini     vmstate::VMStateDescription,
238c80c472SPaolo Bonzini };
248c80c472SPaolo Bonzini 
25fc22d650SPaolo Bonzini /// A safe wrapper around [`bindings::Clock`].
26fc22d650SPaolo Bonzini #[repr(transparent)]
27fc22d650SPaolo Bonzini #[derive(Debug, qemu_api_macros::Wrapper)]
28fc22d650SPaolo Bonzini pub struct Clock(Opaque<bindings::Clock>);
29fc22d650SPaolo Bonzini 
30fc22d650SPaolo Bonzini unsafe impl Send for Clock {}
31fc22d650SPaolo Bonzini unsafe impl Sync for Clock {}
32fc22d650SPaolo Bonzini 
33fc22d650SPaolo Bonzini /// A safe wrapper around [`bindings::DeviceState`].
34fc22d650SPaolo Bonzini #[repr(transparent)]
35fc22d650SPaolo Bonzini #[derive(Debug, qemu_api_macros::Wrapper)]
36fc22d650SPaolo Bonzini pub struct DeviceState(Opaque<bindings::DeviceState>);
37fc22d650SPaolo Bonzini 
38fc22d650SPaolo Bonzini unsafe impl Send for DeviceState {}
39fc22d650SPaolo Bonzini unsafe impl Sync for DeviceState {}
40fc22d650SPaolo Bonzini 
415472a38cSPaolo Bonzini /// Trait providing the contents of the `ResettablePhases` struct,
425472a38cSPaolo Bonzini /// which is part of the QOM `Resettable` interface.
435472a38cSPaolo Bonzini pub trait ResettablePhasesImpl {
445472a38cSPaolo Bonzini     /// If not None, this is called when the object enters reset. It
455472a38cSPaolo Bonzini     /// can reset local state of the object, but it must not do anything that
465472a38cSPaolo Bonzini     /// has a side-effect on other objects, such as raising or lowering an
479a96d410SZhao Liu     /// [`InterruptSource`], or reading or writing guest memory. It takes the
489a96d410SZhao Liu     /// reset's type as argument.
495472a38cSPaolo Bonzini     const ENTER: Option<fn(&Self, ResetType)> = None;
505472a38cSPaolo Bonzini 
515472a38cSPaolo Bonzini     /// If not None, this is called when the object for entry into reset, once
525472a38cSPaolo Bonzini     /// every object in the system which is being reset has had its
535472a38cSPaolo Bonzini     /// `ResettablePhasesImpl::ENTER` method called. At this point devices
545472a38cSPaolo Bonzini     /// can do actions that affect other objects.
555472a38cSPaolo Bonzini     ///
565472a38cSPaolo Bonzini     /// If in doubt, implement this method.
575472a38cSPaolo Bonzini     const HOLD: Option<fn(&Self, ResetType)> = None;
585472a38cSPaolo Bonzini 
595472a38cSPaolo Bonzini     /// If not None, this phase is called when the object leaves the reset
605472a38cSPaolo Bonzini     /// state. Actions affecting other objects are permitted.
615472a38cSPaolo Bonzini     const EXIT: Option<fn(&Self, ResetType)> = None;
625472a38cSPaolo Bonzini }
635472a38cSPaolo Bonzini 
645472a38cSPaolo Bonzini /// # Safety
655472a38cSPaolo Bonzini ///
665472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
675472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
685472a38cSPaolo Bonzini /// readable/writeable from one thread at any time.
rust_resettable_enter_fn<T: ResettablePhasesImpl>( obj: *mut bindings::Object, typ: ResetType, )695472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>(
707fb4a99dSPaolo Bonzini     obj: *mut bindings::Object,
715472a38cSPaolo Bonzini     typ: ResetType,
725472a38cSPaolo Bonzini ) {
735472a38cSPaolo Bonzini     let state = NonNull::new(obj).unwrap().cast::<T>();
745472a38cSPaolo Bonzini     T::ENTER.unwrap()(unsafe { state.as_ref() }, typ);
755472a38cSPaolo Bonzini }
765472a38cSPaolo Bonzini 
775472a38cSPaolo Bonzini /// # Safety
785472a38cSPaolo Bonzini ///
795472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
805472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
815472a38cSPaolo Bonzini /// readable/writeable from one thread at any time.
rust_resettable_hold_fn<T: ResettablePhasesImpl>( obj: *mut bindings::Object, typ: ResetType, )825472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>(
837fb4a99dSPaolo Bonzini     obj: *mut bindings::Object,
845472a38cSPaolo Bonzini     typ: ResetType,
855472a38cSPaolo Bonzini ) {
865472a38cSPaolo Bonzini     let state = NonNull::new(obj).unwrap().cast::<T>();
875472a38cSPaolo Bonzini     T::HOLD.unwrap()(unsafe { state.as_ref() }, typ);
885472a38cSPaolo Bonzini }
895472a38cSPaolo Bonzini 
905472a38cSPaolo Bonzini /// # Safety
915472a38cSPaolo Bonzini ///
925472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
935472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
945472a38cSPaolo Bonzini /// readable/writeable from one thread at any time.
rust_resettable_exit_fn<T: ResettablePhasesImpl>( obj: *mut bindings::Object, typ: ResetType, )955472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>(
967fb4a99dSPaolo Bonzini     obj: *mut bindings::Object,
975472a38cSPaolo Bonzini     typ: ResetType,
985472a38cSPaolo Bonzini ) {
995472a38cSPaolo Bonzini     let state = NonNull::new(obj).unwrap().cast::<T>();
1005472a38cSPaolo Bonzini     T::EXIT.unwrap()(unsafe { state.as_ref() }, typ);
1015472a38cSPaolo Bonzini }
1025472a38cSPaolo Bonzini 
1038c80c472SPaolo Bonzini /// Trait providing the contents of [`DeviceClass`].
104ac5699c5SPaolo Bonzini pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl + IsA<DeviceState> {
1058c80c472SPaolo Bonzini     /// _Realization_ is the second stage of device creation. It contains
1068c80c472SPaolo Bonzini     /// all operations that depend on device properties and can fail (note:
1078c80c472SPaolo Bonzini     /// this is not yet supported for Rust devices).
1088c80c472SPaolo Bonzini     ///
1098c80c472SPaolo Bonzini     /// If not `None`, the parent class's `realize` method is overridden
1108c80c472SPaolo Bonzini     /// with the function pointed to by `REALIZE`.
1110f9eb0ffSZhao Liu     const REALIZE: Option<fn(&Self)> = None;
1128c80c472SPaolo Bonzini 
1138c80c472SPaolo Bonzini     /// An array providing the properties that the user can set on the
1148c80c472SPaolo Bonzini     /// device.  Not a `const` because referencing statics in constants
1158c80c472SPaolo Bonzini     /// is unstable until Rust 1.83.0.
properties() -> &'static [Property]1168c80c472SPaolo Bonzini     fn properties() -> &'static [Property] {
1175f997648SRichard Henderson         &[]
1188c80c472SPaolo Bonzini     }
1198c80c472SPaolo Bonzini 
1208c80c472SPaolo Bonzini     /// A `VMStateDescription` providing the migration format for the device
1218c80c472SPaolo Bonzini     /// Not a `const` because referencing statics in constants is unstable
1228c80c472SPaolo Bonzini     /// until Rust 1.83.0.
vmsd() -> Option<&'static VMStateDescription>1238c80c472SPaolo Bonzini     fn vmsd() -> Option<&'static VMStateDescription> {
1248c80c472SPaolo Bonzini         None
1258c80c472SPaolo Bonzini     }
1268c80c472SPaolo Bonzini }
1278c80c472SPaolo Bonzini 
1288c80c472SPaolo Bonzini /// # Safety
1298c80c472SPaolo Bonzini ///
130f75fb90fSPaolo Bonzini /// This function is only called through the QOM machinery and
131d556226dSPaolo Bonzini /// used by `DeviceClass::class_init`.
132f75fb90fSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
133f75fb90fSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
134f75fb90fSPaolo Bonzini /// readable/writeable from one thread at any time.
rust_realize_fn<T: DeviceImpl>( dev: *mut bindings::DeviceState, _errp: *mut *mut Error, )135fc22d650SPaolo Bonzini unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>(
136fc22d650SPaolo Bonzini     dev: *mut bindings::DeviceState,
137fc22d650SPaolo Bonzini     _errp: *mut *mut Error,
138fc22d650SPaolo Bonzini ) {
1397d052039SPaolo Bonzini     let state = NonNull::new(dev).unwrap().cast::<T>();
1407d052039SPaolo Bonzini     T::REALIZE.unwrap()(unsafe { state.as_ref() });
141f75fb90fSPaolo Bonzini }
142f75fb90fSPaolo Bonzini 
1435472a38cSPaolo Bonzini unsafe impl InterfaceType for ResettableClass {
1445472a38cSPaolo Bonzini     const TYPE_NAME: &'static CStr =
1455472a38cSPaolo Bonzini         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_RESETTABLE_INTERFACE) };
1465472a38cSPaolo Bonzini }
1475472a38cSPaolo Bonzini 
148d556226dSPaolo Bonzini impl ResettableClass {
149d556226dSPaolo Bonzini     /// Fill in the virtual methods of `ResettableClass` based on the
150d556226dSPaolo Bonzini     /// definitions in the `ResettablePhasesImpl` trait.
class_init<T: ResettablePhasesImpl>(&mut self)151d556226dSPaolo Bonzini     pub fn class_init<T: ResettablePhasesImpl>(&mut self) {
1525472a38cSPaolo Bonzini         if <T as ResettablePhasesImpl>::ENTER.is_some() {
153d556226dSPaolo Bonzini             self.phases.enter = Some(rust_resettable_enter_fn::<T>);
1545472a38cSPaolo Bonzini         }
1555472a38cSPaolo Bonzini         if <T as ResettablePhasesImpl>::HOLD.is_some() {
156d556226dSPaolo Bonzini             self.phases.hold = Some(rust_resettable_hold_fn::<T>);
1575472a38cSPaolo Bonzini         }
1585472a38cSPaolo Bonzini         if <T as ResettablePhasesImpl>::EXIT.is_some() {
159d556226dSPaolo Bonzini             self.phases.exit = Some(rust_resettable_exit_fn::<T>);
1605472a38cSPaolo Bonzini         }
1615472a38cSPaolo Bonzini     }
162f75fb90fSPaolo Bonzini }
163f75fb90fSPaolo Bonzini 
164d556226dSPaolo Bonzini impl DeviceClass {
165d556226dSPaolo Bonzini     /// Fill in the virtual methods of `DeviceClass` based on the definitions in
166d556226dSPaolo Bonzini     /// the `DeviceImpl` trait.
class_init<T: DeviceImpl>(&mut self)167d556226dSPaolo Bonzini     pub fn class_init<T: DeviceImpl>(&mut self) {
168f75fb90fSPaolo Bonzini         if <T as DeviceImpl>::REALIZE.is_some() {
169d556226dSPaolo Bonzini             self.realize = Some(rust_realize_fn::<T>);
1708c80c472SPaolo Bonzini         }
1718c80c472SPaolo Bonzini         if let Some(vmsd) = <T as DeviceImpl>::vmsd() {
172d556226dSPaolo Bonzini             self.vmsd = vmsd;
1738c80c472SPaolo Bonzini         }
1745f997648SRichard Henderson         let prop = <T as DeviceImpl>::properties();
1755f997648SRichard Henderson         if !prop.is_empty() {
1766dd818fbSPaolo Bonzini             unsafe {
177d556226dSPaolo Bonzini                 bindings::device_class_set_props_n(self, prop.as_ptr(), prop.len());
1785f997648SRichard Henderson             }
1798c80c472SPaolo Bonzini         }
180cb36da9bSPaolo Bonzini 
181d556226dSPaolo Bonzini         ResettableClass::cast::<DeviceState>(self).class_init::<T>();
182d556226dSPaolo Bonzini         self.parent_class.class_init::<T>();
1838c80c472SPaolo Bonzini     }
1845a5110d2SManos Pitsidianakis }
1855a5110d2SManos Pitsidianakis 
1865a5110d2SManos Pitsidianakis #[macro_export]
1875a5110d2SManos Pitsidianakis macro_rules! define_property {
1887f2d4181SZhao Liu     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, bit = $bitnr:expr, default = $defval:expr$(,)*) => {
1897f2d4181SZhao Liu         $crate::bindings::Property {
1907f2d4181SZhao Liu             // use associated function syntax for type checking
1917f2d4181SZhao Liu             name: ::std::ffi::CStr::as_ptr($name),
1927f2d4181SZhao Liu             info: $prop,
193*b134a09fSPaolo Bonzini             offset: ::std::mem::offset_of!($state, $field) as isize,
1947f2d4181SZhao Liu             bitnr: $bitnr,
1957f2d4181SZhao Liu             set_default: true,
1967f2d4181SZhao Liu             defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
1977f2d4181SZhao Liu             ..$crate::zeroable::Zeroable::ZERO
1987f2d4181SZhao Liu         }
1997f2d4181SZhao Liu     };
200a3057c52SJunjie Mao     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, default = $defval:expr$(,)*) => {
2015a5110d2SManos Pitsidianakis         $crate::bindings::Property {
20203a573b9SPaolo Bonzini             // use associated function syntax for type checking
2039f7d4520SPaolo Bonzini             name: ::std::ffi::CStr::as_ptr($name),
2045a5110d2SManos Pitsidianakis             info: $prop,
205*b134a09fSPaolo Bonzini             offset: ::std::mem::offset_of!($state, $field) as isize,
2065a5110d2SManos Pitsidianakis             set_default: true,
20703a573b9SPaolo Bonzini             defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
2086e50bde1SPaolo Bonzini             ..$crate::zeroable::Zeroable::ZERO
2095a5110d2SManos Pitsidianakis         }
2105a5110d2SManos Pitsidianakis     };
211a3057c52SJunjie Mao     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty$(,)*) => {
2125a5110d2SManos Pitsidianakis         $crate::bindings::Property {
21303a573b9SPaolo Bonzini             // use associated function syntax for type checking
2149f7d4520SPaolo Bonzini             name: ::std::ffi::CStr::as_ptr($name),
2155a5110d2SManos Pitsidianakis             info: $prop,
216*b134a09fSPaolo Bonzini             offset: ::std::mem::offset_of!($state, $field) as isize,
2175a5110d2SManos Pitsidianakis             set_default: false,
2186e50bde1SPaolo Bonzini             ..$crate::zeroable::Zeroable::ZERO
2195a5110d2SManos Pitsidianakis         }
2205a5110d2SManos Pitsidianakis     };
2215a5110d2SManos Pitsidianakis }
2225a5110d2SManos Pitsidianakis 
2235a5110d2SManos Pitsidianakis #[macro_export]
2245a5110d2SManos Pitsidianakis macro_rules! declare_properties {
2255a5110d2SManos Pitsidianakis     ($ident:ident, $($prop:expr),*$(,)*) => {
226c92c447fSPaolo Bonzini         pub static $ident: [$crate::bindings::Property; {
2275f997648SRichard Henderson             let mut len = 0;
2285a5110d2SManos Pitsidianakis             $({
2295a5110d2SManos Pitsidianakis                 _ = stringify!($prop);
2305a5110d2SManos Pitsidianakis                 len += 1;
2315a5110d2SManos Pitsidianakis             })*
2325a5110d2SManos Pitsidianakis             len
233c92c447fSPaolo Bonzini         }] = [
2345a5110d2SManos Pitsidianakis             $($prop),*,
235c92c447fSPaolo Bonzini         ];
2365a5110d2SManos Pitsidianakis     };
2375a5110d2SManos Pitsidianakis }
238ce4a144cSPaolo Bonzini 
2396dd818fbSPaolo Bonzini unsafe impl ObjectType for DeviceState {
2406dd818fbSPaolo Bonzini     type Class = DeviceClass;
2417bd8e3efSPaolo Bonzini     const TYPE_NAME: &'static CStr =
242ce4a144cSPaolo Bonzini         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_DEVICE) };
2437bd8e3efSPaolo Bonzini }
244f50cd85cSPaolo Bonzini qom_isa!(DeviceState: Object);
245201ef001SPaolo Bonzini 
246201ef001SPaolo Bonzini /// Trait for methods exposed by the [`DeviceState`] class.  The methods can be
247201ef001SPaolo Bonzini /// called on all objects that have the trait `IsA<DeviceState>`.
248201ef001SPaolo Bonzini ///
249201ef001SPaolo Bonzini /// The trait should only be used through the blanket implementation,
250201ef001SPaolo Bonzini /// which guarantees safety via `IsA`.
251201ef001SPaolo Bonzini pub trait DeviceMethods: ObjectDeref
252201ef001SPaolo Bonzini where
253201ef001SPaolo Bonzini     Self::Target: IsA<DeviceState>,
254201ef001SPaolo Bonzini {
255201ef001SPaolo Bonzini     /// Add an input clock named `name`.  Invoke the callback with
256201ef001SPaolo Bonzini     /// `self` as the first parameter for the events that are requested.
257201ef001SPaolo Bonzini     ///
258201ef001SPaolo Bonzini     /// The resulting clock is added as a child of `self`, but it also
259201ef001SPaolo Bonzini     /// stays alive until after `Drop::drop` is called because C code
260201ef001SPaolo Bonzini     /// keeps an extra reference to it until `device_finalize()` calls
261201ef001SPaolo Bonzini     /// `qdev_finalize_clocklist()`.  Therefore (unlike most cases in
262201ef001SPaolo Bonzini     /// which Rust code has a reference to a child object) it would be
263201ef001SPaolo Bonzini     /// possible for this function to return a `&Clock` too.
264201ef001SPaolo Bonzini     #[inline]
init_clock_in<F: for<'a> FnCall<(&'a Self::Target, ClockEvent)>>( &self, name: &str, _cb: &F, events: ClockEvent, ) -> Owned<Clock>265201ef001SPaolo Bonzini     fn init_clock_in<F: for<'a> FnCall<(&'a Self::Target, ClockEvent)>>(
266201ef001SPaolo Bonzini         &self,
267201ef001SPaolo Bonzini         name: &str,
268201ef001SPaolo Bonzini         _cb: &F,
269201ef001SPaolo Bonzini         events: ClockEvent,
270201ef001SPaolo Bonzini     ) -> Owned<Clock> {
271201ef001SPaolo Bonzini         fn do_init_clock_in(
272fc22d650SPaolo Bonzini             dev: &DeviceState,
273201ef001SPaolo Bonzini             name: &str,
274201ef001SPaolo Bonzini             cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)>,
275201ef001SPaolo Bonzini             events: ClockEvent,
276201ef001SPaolo Bonzini         ) -> Owned<Clock> {
277201ef001SPaolo Bonzini             assert!(bql_locked());
278201ef001SPaolo Bonzini 
279201ef001SPaolo Bonzini             // SAFETY: the clock is heap allocated, but qdev_init_clock_in()
280201ef001SPaolo Bonzini             // does not gift the reference to its caller; so use Owned::from to
281201ef001SPaolo Bonzini             // add one.  The callback is disabled automatically when the clock
282201ef001SPaolo Bonzini             // is unparented, which happens before the device is finalized.
283201ef001SPaolo Bonzini             unsafe {
284201ef001SPaolo Bonzini                 let cstr = CString::new(name).unwrap();
285201ef001SPaolo Bonzini                 let clk = bindings::qdev_init_clock_in(
286fc22d650SPaolo Bonzini                     dev.as_mut_ptr(),
287201ef001SPaolo Bonzini                     cstr.as_ptr(),
288201ef001SPaolo Bonzini                     cb,
289fc22d650SPaolo Bonzini                     dev.as_void_ptr(),
290201ef001SPaolo Bonzini                     events.0,
291201ef001SPaolo Bonzini                 );
292201ef001SPaolo Bonzini 
293fc22d650SPaolo Bonzini                 let clk: &Clock = Clock::from_raw(clk);
294fc22d650SPaolo Bonzini                 Owned::from(clk)
295201ef001SPaolo Bonzini             }
296201ef001SPaolo Bonzini         }
297201ef001SPaolo Bonzini 
298201ef001SPaolo Bonzini         let cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)> = if F::is_some() {
299201ef001SPaolo Bonzini             unsafe extern "C" fn rust_clock_cb<T, F: for<'a> FnCall<(&'a T, ClockEvent)>>(
300201ef001SPaolo Bonzini                 opaque: *mut c_void,
301201ef001SPaolo Bonzini                 event: ClockEvent,
302201ef001SPaolo Bonzini             ) {
303201ef001SPaolo Bonzini                 // SAFETY: the opaque is "this", which is indeed a pointer to T
304201ef001SPaolo Bonzini                 F::call((unsafe { &*(opaque.cast::<T>()) }, event))
305201ef001SPaolo Bonzini             }
306201ef001SPaolo Bonzini             Some(rust_clock_cb::<Self::Target, F>)
307201ef001SPaolo Bonzini         } else {
308201ef001SPaolo Bonzini             None
309201ef001SPaolo Bonzini         };
310201ef001SPaolo Bonzini 
311fc22d650SPaolo Bonzini         do_init_clock_in(self.upcast(), name, cb, events)
312201ef001SPaolo Bonzini     }
313201ef001SPaolo Bonzini 
314201ef001SPaolo Bonzini     /// Add an output clock named `name`.
315201ef001SPaolo Bonzini     ///
316201ef001SPaolo Bonzini     /// The resulting clock is added as a child of `self`, but it also
317201ef001SPaolo Bonzini     /// stays alive until after `Drop::drop` is called because C code
318201ef001SPaolo Bonzini     /// keeps an extra reference to it until `device_finalize()` calls
319201ef001SPaolo Bonzini     /// `qdev_finalize_clocklist()`.  Therefore (unlike most cases in
320201ef001SPaolo Bonzini     /// which Rust code has a reference to a child object) it would be
321201ef001SPaolo Bonzini     /// possible for this function to return a `&Clock` too.
322201ef001SPaolo Bonzini     #[inline]
init_clock_out(&self, name: &str) -> Owned<Clock>323201ef001SPaolo Bonzini     fn init_clock_out(&self, name: &str) -> Owned<Clock> {
324201ef001SPaolo Bonzini         unsafe {
325201ef001SPaolo Bonzini             let cstr = CString::new(name).unwrap();
326fc22d650SPaolo Bonzini             let clk = bindings::qdev_init_clock_out(self.upcast().as_mut_ptr(), cstr.as_ptr());
327201ef001SPaolo Bonzini 
328fc22d650SPaolo Bonzini             let clk: &Clock = Clock::from_raw(clk);
329fc22d650SPaolo Bonzini             Owned::from(clk)
330201ef001SPaolo Bonzini         }
331201ef001SPaolo Bonzini     }
332a22bd55fSPaolo Bonzini 
prop_set_chr(&self, propname: &str, chr: &Owned<Chardev>)333a22bd55fSPaolo Bonzini     fn prop_set_chr(&self, propname: &str, chr: &Owned<Chardev>) {
334a22bd55fSPaolo Bonzini         assert!(bql_locked());
335a22bd55fSPaolo Bonzini         let c_propname = CString::new(propname).unwrap();
33648627510SPaolo Bonzini         let chr: &Chardev = chr;
337a22bd55fSPaolo Bonzini         unsafe {
338fc22d650SPaolo Bonzini             bindings::qdev_prop_set_chr(
339fc22d650SPaolo Bonzini                 self.upcast().as_mut_ptr(),
340fc22d650SPaolo Bonzini                 c_propname.as_ptr(),
341fc22d650SPaolo Bonzini                 chr.as_mut_ptr(),
342fc22d650SPaolo Bonzini             );
343a22bd55fSPaolo Bonzini         }
344a22bd55fSPaolo Bonzini     }
3459a96d410SZhao Liu 
init_gpio_in<F: for<'a> FnCall<(&'a Self::Target, u32, u32)>>( &self, num_lines: u32, _cb: F, )3469a96d410SZhao Liu     fn init_gpio_in<F: for<'a> FnCall<(&'a Self::Target, u32, u32)>>(
3479a96d410SZhao Liu         &self,
3489a96d410SZhao Liu         num_lines: u32,
3499a96d410SZhao Liu         _cb: F,
3509a96d410SZhao Liu     ) {
351fc22d650SPaolo Bonzini         fn do_init_gpio_in(
352fc22d650SPaolo Bonzini             dev: &DeviceState,
353fc22d650SPaolo Bonzini             num_lines: u32,
354fc22d650SPaolo Bonzini             gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int),
355fc22d650SPaolo Bonzini         ) {
356fc22d650SPaolo Bonzini             unsafe {
357fc22d650SPaolo Bonzini                 qdev_init_gpio_in(dev.as_mut_ptr(), Some(gpio_in_cb), num_lines as c_int);
358fc22d650SPaolo Bonzini             }
359fc22d650SPaolo Bonzini         }
3609a96d410SZhao Liu 
361fc22d650SPaolo Bonzini         let _: () = F::ASSERT_IS_SOME;
3629a96d410SZhao Liu         unsafe extern "C" fn rust_irq_handler<T, F: for<'a> FnCall<(&'a T, u32, u32)>>(
3639a96d410SZhao Liu             opaque: *mut c_void,
3649a96d410SZhao Liu             line: c_int,
3659a96d410SZhao Liu             level: c_int,
3669a96d410SZhao Liu         ) {
3679a96d410SZhao Liu             // SAFETY: the opaque was passed as a reference to `T`
3689a96d410SZhao Liu             F::call((unsafe { &*(opaque.cast::<T>()) }, line as u32, level as u32))
3699a96d410SZhao Liu         }
3709a96d410SZhao Liu 
3719a96d410SZhao Liu         let gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int) =
3729a96d410SZhao Liu             rust_irq_handler::<Self::Target, F>;
3739a96d410SZhao Liu 
374fc22d650SPaolo Bonzini         do_init_gpio_in(self.upcast(), num_lines, gpio_in_cb);
3759a96d410SZhao Liu     }
3769a96d410SZhao Liu 
init_gpio_out(&self, pins: &[InterruptSource])3779a96d410SZhao Liu     fn init_gpio_out(&self, pins: &[InterruptSource]) {
3789a96d410SZhao Liu         unsafe {
3799a96d410SZhao Liu             qdev_init_gpio_out(
380fc22d650SPaolo Bonzini                 self.upcast().as_mut_ptr(),
3819a96d410SZhao Liu                 InterruptSource::slice_as_ptr(pins),
3829a96d410SZhao Liu                 pins.len() as c_int,
3839a96d410SZhao Liu             );
3849a96d410SZhao Liu         }
3859a96d410SZhao Liu     }
386201ef001SPaolo Bonzini }
387201ef001SPaolo Bonzini 
388201ef001SPaolo Bonzini impl<R: ObjectDeref> DeviceMethods for R where R::Target: IsA<DeviceState> {}
389201ef001SPaolo Bonzini 
390201ef001SPaolo Bonzini unsafe impl ObjectType for Clock {
391201ef001SPaolo Bonzini     type Class = ObjectClass;
392201ef001SPaolo Bonzini     const TYPE_NAME: &'static CStr =
393201ef001SPaolo Bonzini         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_CLOCK) };
394201ef001SPaolo Bonzini }
395201ef001SPaolo Bonzini qom_isa!(Clock: Object);
396