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