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::{CStr, CString}, 9 os::raw::c_void, 10 ptr::NonNull, 11 }; 12 13 pub use bindings::{Clock, ClockEvent, DeviceClass, DeviceState, Property, ResetType}; 14 15 use crate::{ 16 bindings::{self, Error, ResettableClass}, 17 callbacks::FnCall, 18 cell::bql_locked, 19 prelude::*, 20 qom::{ClassInitImpl, ObjectClass, ObjectImpl, Owned}, 21 vmstate::VMStateDescription, 22 }; 23 24 /// Trait providing the contents of the `ResettablePhases` struct, 25 /// which is part of the QOM `Resettable` interface. 26 pub trait ResettablePhasesImpl { 27 /// If not None, this is called when the object enters reset. It 28 /// can reset local state of the object, but it must not do anything that 29 /// has a side-effect on other objects, such as raising or lowering an 30 /// [`InterruptSource`](crate::irq::InterruptSource), or reading or 31 /// writing guest memory. It takes the reset's type as argument. 32 const ENTER: Option<fn(&Self, ResetType)> = None; 33 34 /// If not None, this is called when the object for entry into reset, once 35 /// every object in the system which is being reset has had its 36 /// `ResettablePhasesImpl::ENTER` method called. At this point devices 37 /// can do actions that affect other objects. 38 /// 39 /// If in doubt, implement this method. 40 const HOLD: Option<fn(&Self, ResetType)> = None; 41 42 /// If not None, this phase is called when the object leaves the reset 43 /// state. Actions affecting other objects are permitted. 44 const EXIT: Option<fn(&Self, ResetType)> = None; 45 } 46 47 /// # Safety 48 /// 49 /// We expect the FFI user of this function to pass a valid pointer that 50 /// can be downcasted to type `T`. We also expect the device is 51 /// readable/writeable from one thread at any time. 52 unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>( 53 obj: *mut Object, 54 typ: ResetType, 55 ) { 56 let state = NonNull::new(obj).unwrap().cast::<T>(); 57 T::ENTER.unwrap()(unsafe { state.as_ref() }, typ); 58 } 59 60 /// # Safety 61 /// 62 /// We expect the FFI user of this function to pass a valid pointer that 63 /// can be downcasted to type `T`. We also expect the device is 64 /// readable/writeable from one thread at any time. 65 unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>( 66 obj: *mut Object, 67 typ: ResetType, 68 ) { 69 let state = NonNull::new(obj).unwrap().cast::<T>(); 70 T::HOLD.unwrap()(unsafe { state.as_ref() }, typ); 71 } 72 73 /// # Safety 74 /// 75 /// We expect the FFI user of this function to pass a valid pointer that 76 /// can be downcasted to type `T`. We also expect the device is 77 /// readable/writeable from one thread at any time. 78 unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>( 79 obj: *mut Object, 80 typ: ResetType, 81 ) { 82 let state = NonNull::new(obj).unwrap().cast::<T>(); 83 T::EXIT.unwrap()(unsafe { state.as_ref() }, typ); 84 } 85 86 /// Trait providing the contents of [`DeviceClass`]. 87 pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl { 88 /// _Realization_ is the second stage of device creation. It contains 89 /// all operations that depend on device properties and can fail (note: 90 /// this is not yet supported for Rust devices). 91 /// 92 /// If not `None`, the parent class's `realize` method is overridden 93 /// with the function pointed to by `REALIZE`. 94 const REALIZE: Option<fn(&Self)> = None; 95 96 /// An array providing the properties that the user can set on the 97 /// device. Not a `const` because referencing statics in constants 98 /// is unstable until Rust 1.83.0. 99 fn properties() -> &'static [Property] { 100 &[] 101 } 102 103 /// A `VMStateDescription` providing the migration format for the device 104 /// Not a `const` because referencing statics in constants is unstable 105 /// until Rust 1.83.0. 106 fn vmsd() -> Option<&'static VMStateDescription> { 107 None 108 } 109 } 110 111 /// # Safety 112 /// 113 /// This function is only called through the QOM machinery and 114 /// used by the `ClassInitImpl<DeviceClass>` trait. 115 /// We expect the FFI user of this function to pass a valid pointer that 116 /// can be downcasted to type `T`. We also expect the device is 117 /// readable/writeable from one thread at any time. 118 unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>(dev: *mut DeviceState, _errp: *mut *mut Error) { 119 let state = NonNull::new(dev).unwrap().cast::<T>(); 120 T::REALIZE.unwrap()(unsafe { state.as_ref() }); 121 } 122 123 unsafe impl InterfaceType for ResettableClass { 124 const TYPE_NAME: &'static CStr = 125 unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_RESETTABLE_INTERFACE) }; 126 } 127 128 impl<T> ClassInitImpl<ResettableClass> for T 129 where 130 T: ResettablePhasesImpl, 131 { 132 fn class_init(rc: &mut ResettableClass) { 133 if <T as ResettablePhasesImpl>::ENTER.is_some() { 134 rc.phases.enter = Some(rust_resettable_enter_fn::<T>); 135 } 136 if <T as ResettablePhasesImpl>::HOLD.is_some() { 137 rc.phases.hold = Some(rust_resettable_hold_fn::<T>); 138 } 139 if <T as ResettablePhasesImpl>::EXIT.is_some() { 140 rc.phases.exit = Some(rust_resettable_exit_fn::<T>); 141 } 142 } 143 } 144 145 impl<T> ClassInitImpl<DeviceClass> for T 146 where 147 T: ClassInitImpl<ObjectClass> + ClassInitImpl<ResettableClass> + DeviceImpl, 148 { 149 fn class_init(dc: &mut DeviceClass) { 150 if <T as DeviceImpl>::REALIZE.is_some() { 151 dc.realize = Some(rust_realize_fn::<T>); 152 } 153 if let Some(vmsd) = <T as DeviceImpl>::vmsd() { 154 dc.vmsd = vmsd; 155 } 156 let prop = <T as DeviceImpl>::properties(); 157 if !prop.is_empty() { 158 unsafe { 159 bindings::device_class_set_props_n(dc, prop.as_ptr(), prop.len()); 160 } 161 } 162 163 ResettableClass::interface_init::<T, DeviceState>(dc); 164 <T as ClassInitImpl<ObjectClass>>::class_init(&mut dc.parent_class); 165 } 166 } 167 168 #[macro_export] 169 macro_rules! define_property { 170 ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, default = $defval:expr$(,)*) => { 171 $crate::bindings::Property { 172 // use associated function syntax for type checking 173 name: ::std::ffi::CStr::as_ptr($name), 174 info: $prop, 175 offset: $crate::offset_of!($state, $field) as isize, 176 set_default: true, 177 defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 }, 178 ..$crate::zeroable::Zeroable::ZERO 179 } 180 }; 181 ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty$(,)*) => { 182 $crate::bindings::Property { 183 // use associated function syntax for type checking 184 name: ::std::ffi::CStr::as_ptr($name), 185 info: $prop, 186 offset: $crate::offset_of!($state, $field) as isize, 187 set_default: false, 188 ..$crate::zeroable::Zeroable::ZERO 189 } 190 }; 191 } 192 193 #[macro_export] 194 macro_rules! declare_properties { 195 ($ident:ident, $($prop:expr),*$(,)*) => { 196 pub static $ident: [$crate::bindings::Property; { 197 let mut len = 0; 198 $({ 199 _ = stringify!($prop); 200 len += 1; 201 })* 202 len 203 }] = [ 204 $($prop),*, 205 ]; 206 }; 207 } 208 209 unsafe impl ObjectType for DeviceState { 210 type Class = DeviceClass; 211 const TYPE_NAME: &'static CStr = 212 unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_DEVICE) }; 213 } 214 qom_isa!(DeviceState: Object); 215 216 /// Trait for methods exposed by the [`DeviceState`] class. The methods can be 217 /// called on all objects that have the trait `IsA<DeviceState>`. 218 /// 219 /// The trait should only be used through the blanket implementation, 220 /// which guarantees safety via `IsA`. 221 pub trait DeviceMethods: ObjectDeref 222 where 223 Self::Target: IsA<DeviceState>, 224 { 225 /// Add an input clock named `name`. Invoke the callback with 226 /// `self` as the first parameter for the events that are requested. 227 /// 228 /// The resulting clock is added as a child of `self`, but it also 229 /// stays alive until after `Drop::drop` is called because C code 230 /// keeps an extra reference to it until `device_finalize()` calls 231 /// `qdev_finalize_clocklist()`. Therefore (unlike most cases in 232 /// which Rust code has a reference to a child object) it would be 233 /// possible for this function to return a `&Clock` too. 234 #[inline] 235 fn init_clock_in<F: for<'a> FnCall<(&'a Self::Target, ClockEvent)>>( 236 &self, 237 name: &str, 238 _cb: &F, 239 events: ClockEvent, 240 ) -> Owned<Clock> { 241 fn do_init_clock_in( 242 dev: *mut DeviceState, 243 name: &str, 244 cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)>, 245 events: ClockEvent, 246 ) -> Owned<Clock> { 247 assert!(bql_locked()); 248 249 // SAFETY: the clock is heap allocated, but qdev_init_clock_in() 250 // does not gift the reference to its caller; so use Owned::from to 251 // add one. The callback is disabled automatically when the clock 252 // is unparented, which happens before the device is finalized. 253 unsafe { 254 let cstr = CString::new(name).unwrap(); 255 let clk = bindings::qdev_init_clock_in( 256 dev, 257 cstr.as_ptr(), 258 cb, 259 dev.cast::<c_void>(), 260 events.0, 261 ); 262 263 Owned::from(&*clk) 264 } 265 } 266 267 let cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)> = if F::is_some() { 268 unsafe extern "C" fn rust_clock_cb<T, F: for<'a> FnCall<(&'a T, ClockEvent)>>( 269 opaque: *mut c_void, 270 event: ClockEvent, 271 ) { 272 // SAFETY: the opaque is "this", which is indeed a pointer to T 273 F::call((unsafe { &*(opaque.cast::<T>()) }, event)) 274 } 275 Some(rust_clock_cb::<Self::Target, F>) 276 } else { 277 None 278 }; 279 280 do_init_clock_in(self.as_mut_ptr(), name, cb, events) 281 } 282 283 /// Add an output clock named `name`. 284 /// 285 /// The resulting clock is added as a child of `self`, but it also 286 /// stays alive until after `Drop::drop` is called because C code 287 /// keeps an extra reference to it until `device_finalize()` calls 288 /// `qdev_finalize_clocklist()`. Therefore (unlike most cases in 289 /// which Rust code has a reference to a child object) it would be 290 /// possible for this function to return a `&Clock` too. 291 #[inline] 292 fn init_clock_out(&self, name: &str) -> Owned<Clock> { 293 unsafe { 294 let cstr = CString::new(name).unwrap(); 295 let clk = bindings::qdev_init_clock_out(self.as_mut_ptr(), cstr.as_ptr()); 296 297 Owned::from(&*clk) 298 } 299 } 300 } 301 302 impl<R: ObjectDeref> DeviceMethods for R where R::Target: IsA<DeviceState> {} 303 304 unsafe impl ObjectType for Clock { 305 type Class = ObjectClass; 306 const TYPE_NAME: &'static CStr = 307 unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_CLOCK) }; 308 } 309 qom_isa!(Clock: Object); 310