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