xref: /qemu/rust/qemu-api/src/qdev.rs (revision b134a09ffab3b918979007cf40f603e5b54ed597)
1 // Copyright 2024, Linaro Limited
2 // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 
5 //! Bindings to create devices and access device functionality from Rust.
6 
7 use std::{
8     ffi::{c_int, c_void, CStr, CString},
9     ptr::NonNull,
10 };
11 
12 pub use bindings::{ClockEvent, DeviceClass, Property, ResetType};
13 
14 use crate::{
15     bindings::{self, qdev_init_gpio_in, qdev_init_gpio_out, Error, ResettableClass},
16     callbacks::FnCall,
17     cell::{bql_locked, Opaque},
18     chardev::Chardev,
19     irq::InterruptSource,
20     prelude::*,
21     qom::{ObjectClass, ObjectImpl, Owned},
22     vmstate::VMStateDescription,
23 };
24 
25 /// A safe wrapper around [`bindings::Clock`].
26 #[repr(transparent)]
27 #[derive(Debug, qemu_api_macros::Wrapper)]
28 pub struct Clock(Opaque<bindings::Clock>);
29 
30 unsafe impl Send for Clock {}
31 unsafe impl Sync for Clock {}
32 
33 /// A safe wrapper around [`bindings::DeviceState`].
34 #[repr(transparent)]
35 #[derive(Debug, qemu_api_macros::Wrapper)]
36 pub struct DeviceState(Opaque<bindings::DeviceState>);
37 
38 unsafe impl Send for DeviceState {}
39 unsafe impl Sync for DeviceState {}
40 
41 /// Trait providing the contents of the `ResettablePhases` struct,
42 /// which is part of the QOM `Resettable` interface.
43 pub trait ResettablePhasesImpl {
44     /// If not None, this is called when the object enters reset. It
45     /// can reset local state of the object, but it must not do anything that
46     /// has a side-effect on other objects, such as raising or lowering an
47     /// [`InterruptSource`], or reading or writing guest memory. It takes the
48     /// reset's type as argument.
49     const ENTER: Option<fn(&Self, ResetType)> = None;
50 
51     /// If not None, this is called when the object for entry into reset, once
52     /// every object in the system which is being reset has had its
53     /// `ResettablePhasesImpl::ENTER` method called. At this point devices
54     /// can do actions that affect other objects.
55     ///
56     /// If in doubt, implement this method.
57     const HOLD: Option<fn(&Self, ResetType)> = None;
58 
59     /// If not None, this phase is called when the object leaves the reset
60     /// state. Actions affecting other objects are permitted.
61     const EXIT: Option<fn(&Self, ResetType)> = None;
62 }
63 
64 /// # Safety
65 ///
66 /// We expect the FFI user of this function to pass a valid pointer that
67 /// can be downcasted to type `T`. We also expect the device is
68 /// readable/writeable from one thread at any time.
rust_resettable_enter_fn<T: ResettablePhasesImpl>( obj: *mut bindings::Object, typ: ResetType, )69 unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>(
70     obj: *mut bindings::Object,
71     typ: ResetType,
72 ) {
73     let state = NonNull::new(obj).unwrap().cast::<T>();
74     T::ENTER.unwrap()(unsafe { state.as_ref() }, typ);
75 }
76 
77 /// # Safety
78 ///
79 /// We expect the FFI user of this function to pass a valid pointer that
80 /// can be downcasted to type `T`. We also expect the device is
81 /// readable/writeable from one thread at any time.
rust_resettable_hold_fn<T: ResettablePhasesImpl>( obj: *mut bindings::Object, typ: ResetType, )82 unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>(
83     obj: *mut bindings::Object,
84     typ: ResetType,
85 ) {
86     let state = NonNull::new(obj).unwrap().cast::<T>();
87     T::HOLD.unwrap()(unsafe { state.as_ref() }, typ);
88 }
89 
90 /// # Safety
91 ///
92 /// We expect the FFI user of this function to pass a valid pointer that
93 /// can be downcasted to type `T`. We also expect the device is
94 /// readable/writeable from one thread at any time.
rust_resettable_exit_fn<T: ResettablePhasesImpl>( obj: *mut bindings::Object, typ: ResetType, )95 unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>(
96     obj: *mut bindings::Object,
97     typ: ResetType,
98 ) {
99     let state = NonNull::new(obj).unwrap().cast::<T>();
100     T::EXIT.unwrap()(unsafe { state.as_ref() }, typ);
101 }
102 
103 /// Trait providing the contents of [`DeviceClass`].
104 pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl + IsA<DeviceState> {
105     /// _Realization_ is the second stage of device creation. It contains
106     /// all operations that depend on device properties and can fail (note:
107     /// this is not yet supported for Rust devices).
108     ///
109     /// If not `None`, the parent class's `realize` method is overridden
110     /// with the function pointed to by `REALIZE`.
111     const REALIZE: Option<fn(&Self)> = None;
112 
113     /// An array providing the properties that the user can set on the
114     /// device.  Not a `const` because referencing statics in constants
115     /// is unstable until Rust 1.83.0.
properties() -> &'static [Property]116     fn properties() -> &'static [Property] {
117         &[]
118     }
119 
120     /// A `VMStateDescription` providing the migration format for the device
121     /// Not a `const` because referencing statics in constants is unstable
122     /// until Rust 1.83.0.
vmsd() -> Option<&'static VMStateDescription>123     fn vmsd() -> Option<&'static VMStateDescription> {
124         None
125     }
126 }
127 
128 /// # Safety
129 ///
130 /// This function is only called through the QOM machinery and
131 /// used by `DeviceClass::class_init`.
132 /// We expect the FFI user of this function to pass a valid pointer that
133 /// can be downcasted to type `T`. We also expect the device is
134 /// readable/writeable from one thread at any time.
rust_realize_fn<T: DeviceImpl>( dev: *mut bindings::DeviceState, _errp: *mut *mut Error, )135 unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>(
136     dev: *mut bindings::DeviceState,
137     _errp: *mut *mut Error,
138 ) {
139     let state = NonNull::new(dev).unwrap().cast::<T>();
140     T::REALIZE.unwrap()(unsafe { state.as_ref() });
141 }
142 
143 unsafe impl InterfaceType for ResettableClass {
144     const TYPE_NAME: &'static CStr =
145         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_RESETTABLE_INTERFACE) };
146 }
147 
148 impl ResettableClass {
149     /// Fill in the virtual methods of `ResettableClass` based on the
150     /// definitions in the `ResettablePhasesImpl` trait.
class_init<T: ResettablePhasesImpl>(&mut self)151     pub fn class_init<T: ResettablePhasesImpl>(&mut self) {
152         if <T as ResettablePhasesImpl>::ENTER.is_some() {
153             self.phases.enter = Some(rust_resettable_enter_fn::<T>);
154         }
155         if <T as ResettablePhasesImpl>::HOLD.is_some() {
156             self.phases.hold = Some(rust_resettable_hold_fn::<T>);
157         }
158         if <T as ResettablePhasesImpl>::EXIT.is_some() {
159             self.phases.exit = Some(rust_resettable_exit_fn::<T>);
160         }
161     }
162 }
163 
164 impl DeviceClass {
165     /// Fill in the virtual methods of `DeviceClass` based on the definitions in
166     /// the `DeviceImpl` trait.
class_init<T: DeviceImpl>(&mut self)167     pub fn class_init<T: DeviceImpl>(&mut self) {
168         if <T as DeviceImpl>::REALIZE.is_some() {
169             self.realize = Some(rust_realize_fn::<T>);
170         }
171         if let Some(vmsd) = <T as DeviceImpl>::vmsd() {
172             self.vmsd = vmsd;
173         }
174         let prop = <T as DeviceImpl>::properties();
175         if !prop.is_empty() {
176             unsafe {
177                 bindings::device_class_set_props_n(self, prop.as_ptr(), prop.len());
178             }
179         }
180 
181         ResettableClass::cast::<DeviceState>(self).class_init::<T>();
182         self.parent_class.class_init::<T>();
183     }
184 }
185 
186 #[macro_export]
187 macro_rules! define_property {
188     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, bit = $bitnr:expr, default = $defval:expr$(,)*) => {
189         $crate::bindings::Property {
190             // use associated function syntax for type checking
191             name: ::std::ffi::CStr::as_ptr($name),
192             info: $prop,
193             offset: ::std::mem::offset_of!($state, $field) as isize,
194             bitnr: $bitnr,
195             set_default: true,
196             defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
197             ..$crate::zeroable::Zeroable::ZERO
198         }
199     };
200     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, default = $defval:expr$(,)*) => {
201         $crate::bindings::Property {
202             // use associated function syntax for type checking
203             name: ::std::ffi::CStr::as_ptr($name),
204             info: $prop,
205             offset: ::std::mem::offset_of!($state, $field) as isize,
206             set_default: true,
207             defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
208             ..$crate::zeroable::Zeroable::ZERO
209         }
210     };
211     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty$(,)*) => {
212         $crate::bindings::Property {
213             // use associated function syntax for type checking
214             name: ::std::ffi::CStr::as_ptr($name),
215             info: $prop,
216             offset: ::std::mem::offset_of!($state, $field) as isize,
217             set_default: false,
218             ..$crate::zeroable::Zeroable::ZERO
219         }
220     };
221 }
222 
223 #[macro_export]
224 macro_rules! declare_properties {
225     ($ident:ident, $($prop:expr),*$(,)*) => {
226         pub static $ident: [$crate::bindings::Property; {
227             let mut len = 0;
228             $({
229                 _ = stringify!($prop);
230                 len += 1;
231             })*
232             len
233         }] = [
234             $($prop),*,
235         ];
236     };
237 }
238 
239 unsafe impl ObjectType for DeviceState {
240     type Class = DeviceClass;
241     const TYPE_NAME: &'static CStr =
242         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_DEVICE) };
243 }
244 qom_isa!(DeviceState: Object);
245 
246 /// Trait for methods exposed by the [`DeviceState`] class.  The methods can be
247 /// called on all objects that have the trait `IsA<DeviceState>`.
248 ///
249 /// The trait should only be used through the blanket implementation,
250 /// which guarantees safety via `IsA`.
251 pub trait DeviceMethods: ObjectDeref
252 where
253     Self::Target: IsA<DeviceState>,
254 {
255     /// Add an input clock named `name`.  Invoke the callback with
256     /// `self` as the first parameter for the events that are requested.
257     ///
258     /// The resulting clock is added as a child of `self`, but it also
259     /// stays alive until after `Drop::drop` is called because C code
260     /// keeps an extra reference to it until `device_finalize()` calls
261     /// `qdev_finalize_clocklist()`.  Therefore (unlike most cases in
262     /// which Rust code has a reference to a child object) it would be
263     /// possible for this function to return a `&Clock` too.
264     #[inline]
init_clock_in<F: for<'a> FnCall<(&'a Self::Target, ClockEvent)>>( &self, name: &str, _cb: &F, events: ClockEvent, ) -> Owned<Clock>265     fn init_clock_in<F: for<'a> FnCall<(&'a Self::Target, ClockEvent)>>(
266         &self,
267         name: &str,
268         _cb: &F,
269         events: ClockEvent,
270     ) -> Owned<Clock> {
271         fn do_init_clock_in(
272             dev: &DeviceState,
273             name: &str,
274             cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)>,
275             events: ClockEvent,
276         ) -> Owned<Clock> {
277             assert!(bql_locked());
278 
279             // SAFETY: the clock is heap allocated, but qdev_init_clock_in()
280             // does not gift the reference to its caller; so use Owned::from to
281             // add one.  The callback is disabled automatically when the clock
282             // is unparented, which happens before the device is finalized.
283             unsafe {
284                 let cstr = CString::new(name).unwrap();
285                 let clk = bindings::qdev_init_clock_in(
286                     dev.as_mut_ptr(),
287                     cstr.as_ptr(),
288                     cb,
289                     dev.as_void_ptr(),
290                     events.0,
291                 );
292 
293                 let clk: &Clock = Clock::from_raw(clk);
294                 Owned::from(clk)
295             }
296         }
297 
298         let cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)> = if F::is_some() {
299             unsafe extern "C" fn rust_clock_cb<T, F: for<'a> FnCall<(&'a T, ClockEvent)>>(
300                 opaque: *mut c_void,
301                 event: ClockEvent,
302             ) {
303                 // SAFETY: the opaque is "this", which is indeed a pointer to T
304                 F::call((unsafe { &*(opaque.cast::<T>()) }, event))
305             }
306             Some(rust_clock_cb::<Self::Target, F>)
307         } else {
308             None
309         };
310 
311         do_init_clock_in(self.upcast(), name, cb, events)
312     }
313 
314     /// Add an output clock named `name`.
315     ///
316     /// The resulting clock is added as a child of `self`, but it also
317     /// stays alive until after `Drop::drop` is called because C code
318     /// keeps an extra reference to it until `device_finalize()` calls
319     /// `qdev_finalize_clocklist()`.  Therefore (unlike most cases in
320     /// which Rust code has a reference to a child object) it would be
321     /// possible for this function to return a `&Clock` too.
322     #[inline]
init_clock_out(&self, name: &str) -> Owned<Clock>323     fn init_clock_out(&self, name: &str) -> Owned<Clock> {
324         unsafe {
325             let cstr = CString::new(name).unwrap();
326             let clk = bindings::qdev_init_clock_out(self.upcast().as_mut_ptr(), cstr.as_ptr());
327 
328             let clk: &Clock = Clock::from_raw(clk);
329             Owned::from(clk)
330         }
331     }
332 
prop_set_chr(&self, propname: &str, chr: &Owned<Chardev>)333     fn prop_set_chr(&self, propname: &str, chr: &Owned<Chardev>) {
334         assert!(bql_locked());
335         let c_propname = CString::new(propname).unwrap();
336         let chr: &Chardev = chr;
337         unsafe {
338             bindings::qdev_prop_set_chr(
339                 self.upcast().as_mut_ptr(),
340                 c_propname.as_ptr(),
341                 chr.as_mut_ptr(),
342             );
343         }
344     }
345 
init_gpio_in<F: for<'a> FnCall<(&'a Self::Target, u32, u32)>>( &self, num_lines: u32, _cb: F, )346     fn init_gpio_in<F: for<'a> FnCall<(&'a Self::Target, u32, u32)>>(
347         &self,
348         num_lines: u32,
349         _cb: F,
350     ) {
351         fn do_init_gpio_in(
352             dev: &DeviceState,
353             num_lines: u32,
354             gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int),
355         ) {
356             unsafe {
357                 qdev_init_gpio_in(dev.as_mut_ptr(), Some(gpio_in_cb), num_lines as c_int);
358             }
359         }
360 
361         let _: () = F::ASSERT_IS_SOME;
362         unsafe extern "C" fn rust_irq_handler<T, F: for<'a> FnCall<(&'a T, u32, u32)>>(
363             opaque: *mut c_void,
364             line: c_int,
365             level: c_int,
366         ) {
367             // SAFETY: the opaque was passed as a reference to `T`
368             F::call((unsafe { &*(opaque.cast::<T>()) }, line as u32, level as u32))
369         }
370 
371         let gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int) =
372             rust_irq_handler::<Self::Target, F>;
373 
374         do_init_gpio_in(self.upcast(), num_lines, gpio_in_cb);
375     }
376 
init_gpio_out(&self, pins: &[InterruptSource])377     fn init_gpio_out(&self, pins: &[InterruptSource]) {
378         unsafe {
379             qdev_init_gpio_out(
380                 self.upcast().as_mut_ptr(),
381                 InterruptSource::slice_as_ptr(pins),
382                 pins.len() as c_int,
383             );
384         }
385     }
386 }
387 
388 impl<R: ObjectDeref> DeviceMethods for R where R::Target: IsA<DeviceState> {}
389 
390 unsafe impl ObjectType for Clock {
391     type Class = ObjectClass;
392     const TYPE_NAME: &'static CStr =
393         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_CLOCK) };
394 }
395 qom_isa!(Clock: Object);
396