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. 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. 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. 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. 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. 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. 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. 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. 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: $crate::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: $crate::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: $crate::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] 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] 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 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 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 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