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