15a5110d2SManos Pitsidianakis // Copyright 2024, Linaro Limited 25a5110d2SManos Pitsidianakis // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org> 35a5110d2SManos Pitsidianakis // SPDX-License-Identifier: GPL-2.0-or-later 45a5110d2SManos Pitsidianakis 54aed0296SPaolo Bonzini //! Bindings to create devices and access device functionality from Rust. 64aed0296SPaolo Bonzini 7201ef001SPaolo Bonzini use std::{ 8201ef001SPaolo Bonzini ffi::{CStr, CString}, 9201ef001SPaolo Bonzini os::raw::c_void, 10201ef001SPaolo Bonzini ptr::NonNull, 11201ef001SPaolo Bonzini }; 12ce4a144cSPaolo Bonzini 13*5472a38cSPaolo Bonzini pub use bindings::{Clock, ClockEvent, DeviceClass, DeviceState, Property, ResetType}; 14716d89f9SPaolo Bonzini 158c80c472SPaolo Bonzini use crate::{ 16*5472a38cSPaolo Bonzini bindings::{self, Error, ResettableClass}, 17201ef001SPaolo Bonzini callbacks::FnCall, 18201ef001SPaolo Bonzini cell::bql_locked, 197bd8e3efSPaolo Bonzini prelude::*, 2068da5402SPaolo Bonzini qom::{ClassInitImpl, ObjectClass, ObjectImpl, Owned}, 21716d89f9SPaolo Bonzini vmstate::VMStateDescription, 228c80c472SPaolo Bonzini }; 238c80c472SPaolo Bonzini 24*5472a38cSPaolo Bonzini /// Trait providing the contents of the `ResettablePhases` struct, 25*5472a38cSPaolo Bonzini /// which is part of the QOM `Resettable` interface. 26*5472a38cSPaolo Bonzini pub trait ResettablePhasesImpl { 27*5472a38cSPaolo Bonzini /// If not None, this is called when the object enters reset. It 28*5472a38cSPaolo Bonzini /// can reset local state of the object, but it must not do anything that 29*5472a38cSPaolo Bonzini /// has a side-effect on other objects, such as raising or lowering an 30*5472a38cSPaolo Bonzini /// [`InterruptSource`](crate::irq::InterruptSource), or reading or 31*5472a38cSPaolo Bonzini /// writing guest memory. It takes the reset's type as argument. 32*5472a38cSPaolo Bonzini const ENTER: Option<fn(&Self, ResetType)> = None; 33*5472a38cSPaolo Bonzini 34*5472a38cSPaolo Bonzini /// If not None, this is called when the object for entry into reset, once 35*5472a38cSPaolo Bonzini /// every object in the system which is being reset has had its 36*5472a38cSPaolo Bonzini /// `ResettablePhasesImpl::ENTER` method called. At this point devices 37*5472a38cSPaolo Bonzini /// can do actions that affect other objects. 38*5472a38cSPaolo Bonzini /// 39*5472a38cSPaolo Bonzini /// If in doubt, implement this method. 40*5472a38cSPaolo Bonzini const HOLD: Option<fn(&Self, ResetType)> = None; 41*5472a38cSPaolo Bonzini 42*5472a38cSPaolo Bonzini /// If not None, this phase is called when the object leaves the reset 43*5472a38cSPaolo Bonzini /// state. Actions affecting other objects are permitted. 44*5472a38cSPaolo Bonzini const EXIT: Option<fn(&Self, ResetType)> = None; 45*5472a38cSPaolo Bonzini } 46*5472a38cSPaolo Bonzini 47*5472a38cSPaolo Bonzini /// # Safety 48*5472a38cSPaolo Bonzini /// 49*5472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that 50*5472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is 51*5472a38cSPaolo Bonzini /// readable/writeable from one thread at any time. 52*5472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>( 53*5472a38cSPaolo Bonzini obj: *mut Object, 54*5472a38cSPaolo Bonzini typ: ResetType, 55*5472a38cSPaolo Bonzini ) { 56*5472a38cSPaolo Bonzini let state = NonNull::new(obj).unwrap().cast::<T>(); 57*5472a38cSPaolo Bonzini T::ENTER.unwrap()(unsafe { state.as_ref() }, typ); 58*5472a38cSPaolo Bonzini } 59*5472a38cSPaolo Bonzini 60*5472a38cSPaolo Bonzini /// # Safety 61*5472a38cSPaolo Bonzini /// 62*5472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that 63*5472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is 64*5472a38cSPaolo Bonzini /// readable/writeable from one thread at any time. 65*5472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>( 66*5472a38cSPaolo Bonzini obj: *mut Object, 67*5472a38cSPaolo Bonzini typ: ResetType, 68*5472a38cSPaolo Bonzini ) { 69*5472a38cSPaolo Bonzini let state = NonNull::new(obj).unwrap().cast::<T>(); 70*5472a38cSPaolo Bonzini T::HOLD.unwrap()(unsafe { state.as_ref() }, typ); 71*5472a38cSPaolo Bonzini } 72*5472a38cSPaolo Bonzini 73*5472a38cSPaolo Bonzini /// # Safety 74*5472a38cSPaolo Bonzini /// 75*5472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that 76*5472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is 77*5472a38cSPaolo Bonzini /// readable/writeable from one thread at any time. 78*5472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>( 79*5472a38cSPaolo Bonzini obj: *mut Object, 80*5472a38cSPaolo Bonzini typ: ResetType, 81*5472a38cSPaolo Bonzini ) { 82*5472a38cSPaolo Bonzini let state = NonNull::new(obj).unwrap().cast::<T>(); 83*5472a38cSPaolo Bonzini T::EXIT.unwrap()(unsafe { state.as_ref() }, typ); 84*5472a38cSPaolo Bonzini } 85*5472a38cSPaolo Bonzini 868c80c472SPaolo Bonzini /// Trait providing the contents of [`DeviceClass`]. 87*5472a38cSPaolo Bonzini pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl { 888c80c472SPaolo Bonzini /// _Realization_ is the second stage of device creation. It contains 898c80c472SPaolo Bonzini /// all operations that depend on device properties and can fail (note: 908c80c472SPaolo Bonzini /// this is not yet supported for Rust devices). 918c80c472SPaolo Bonzini /// 928c80c472SPaolo Bonzini /// If not `None`, the parent class's `realize` method is overridden 938c80c472SPaolo Bonzini /// with the function pointed to by `REALIZE`. 940f9eb0ffSZhao Liu const REALIZE: Option<fn(&Self)> = None; 958c80c472SPaolo Bonzini 968c80c472SPaolo Bonzini /// An array providing the properties that the user can set on the 978c80c472SPaolo Bonzini /// device. Not a `const` because referencing statics in constants 988c80c472SPaolo Bonzini /// is unstable until Rust 1.83.0. 998c80c472SPaolo Bonzini fn properties() -> &'static [Property] { 1005f997648SRichard Henderson &[] 1018c80c472SPaolo Bonzini } 1028c80c472SPaolo Bonzini 1038c80c472SPaolo Bonzini /// A `VMStateDescription` providing the migration format for the device 1048c80c472SPaolo Bonzini /// Not a `const` because referencing statics in constants is unstable 1058c80c472SPaolo Bonzini /// until Rust 1.83.0. 1068c80c472SPaolo Bonzini fn vmsd() -> Option<&'static VMStateDescription> { 1078c80c472SPaolo Bonzini None 1088c80c472SPaolo Bonzini } 1098c80c472SPaolo Bonzini } 1108c80c472SPaolo Bonzini 1118c80c472SPaolo Bonzini /// # Safety 1128c80c472SPaolo Bonzini /// 113f75fb90fSPaolo Bonzini /// This function is only called through the QOM machinery and 1146dd818fbSPaolo Bonzini /// used by the `ClassInitImpl<DeviceClass>` trait. 115f75fb90fSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that 116f75fb90fSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is 117f75fb90fSPaolo Bonzini /// readable/writeable from one thread at any time. 118f75fb90fSPaolo Bonzini unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>(dev: *mut DeviceState, _errp: *mut *mut Error) { 1197d052039SPaolo Bonzini let state = NonNull::new(dev).unwrap().cast::<T>(); 1207d052039SPaolo Bonzini T::REALIZE.unwrap()(unsafe { state.as_ref() }); 121f75fb90fSPaolo Bonzini } 122f75fb90fSPaolo Bonzini 123*5472a38cSPaolo Bonzini unsafe impl InterfaceType for ResettableClass { 124*5472a38cSPaolo Bonzini const TYPE_NAME: &'static CStr = 125*5472a38cSPaolo Bonzini unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_RESETTABLE_INTERFACE) }; 126*5472a38cSPaolo Bonzini } 127*5472a38cSPaolo Bonzini 128*5472a38cSPaolo Bonzini impl<T> ClassInitImpl<ResettableClass> for T 129*5472a38cSPaolo Bonzini where 130*5472a38cSPaolo Bonzini T: ResettablePhasesImpl, 131*5472a38cSPaolo Bonzini { 132*5472a38cSPaolo Bonzini fn class_init(rc: &mut ResettableClass) { 133*5472a38cSPaolo Bonzini if <T as ResettablePhasesImpl>::ENTER.is_some() { 134*5472a38cSPaolo Bonzini rc.phases.enter = Some(rust_resettable_enter_fn::<T>); 135*5472a38cSPaolo Bonzini } 136*5472a38cSPaolo Bonzini if <T as ResettablePhasesImpl>::HOLD.is_some() { 137*5472a38cSPaolo Bonzini rc.phases.hold = Some(rust_resettable_hold_fn::<T>); 138*5472a38cSPaolo Bonzini } 139*5472a38cSPaolo Bonzini if <T as ResettablePhasesImpl>::EXIT.is_some() { 140*5472a38cSPaolo Bonzini rc.phases.exit = Some(rust_resettable_exit_fn::<T>); 141*5472a38cSPaolo Bonzini } 142*5472a38cSPaolo Bonzini } 143f75fb90fSPaolo Bonzini } 144f75fb90fSPaolo Bonzini 1456dd818fbSPaolo Bonzini impl<T> ClassInitImpl<DeviceClass> for T 1466dd818fbSPaolo Bonzini where 147*5472a38cSPaolo Bonzini T: ClassInitImpl<ObjectClass> + ClassInitImpl<ResettableClass> + DeviceImpl, 1486dd818fbSPaolo Bonzini { 1496dd818fbSPaolo Bonzini fn class_init(dc: &mut DeviceClass) { 150f75fb90fSPaolo Bonzini if <T as DeviceImpl>::REALIZE.is_some() { 151f75fb90fSPaolo Bonzini dc.realize = Some(rust_realize_fn::<T>); 1528c80c472SPaolo Bonzini } 1538c80c472SPaolo Bonzini if let Some(vmsd) = <T as DeviceImpl>::vmsd() { 1548c80c472SPaolo Bonzini dc.vmsd = vmsd; 1558c80c472SPaolo Bonzini } 1565f997648SRichard Henderson let prop = <T as DeviceImpl>::properties(); 1575f997648SRichard Henderson if !prop.is_empty() { 1586dd818fbSPaolo Bonzini unsafe { 1595f997648SRichard Henderson bindings::device_class_set_props_n(dc, prop.as_ptr(), prop.len()); 1605f997648SRichard Henderson } 1618c80c472SPaolo Bonzini } 162cb36da9bSPaolo Bonzini 163*5472a38cSPaolo Bonzini ResettableClass::interface_init::<T, DeviceState>(dc); 164cb36da9bSPaolo Bonzini <T as ClassInitImpl<ObjectClass>>::class_init(&mut dc.parent_class); 1658c80c472SPaolo Bonzini } 1665a5110d2SManos Pitsidianakis } 1675a5110d2SManos Pitsidianakis 1685a5110d2SManos Pitsidianakis #[macro_export] 1695a5110d2SManos Pitsidianakis macro_rules! define_property { 170a3057c52SJunjie Mao ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, default = $defval:expr$(,)*) => { 1715a5110d2SManos Pitsidianakis $crate::bindings::Property { 17203a573b9SPaolo Bonzini // use associated function syntax for type checking 1739f7d4520SPaolo Bonzini name: ::std::ffi::CStr::as_ptr($name), 1745a5110d2SManos Pitsidianakis info: $prop, 175f3518400SJunjie Mao offset: $crate::offset_of!($state, $field) as isize, 1765a5110d2SManos Pitsidianakis set_default: true, 17703a573b9SPaolo Bonzini defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 }, 1786e50bde1SPaolo Bonzini ..$crate::zeroable::Zeroable::ZERO 1795a5110d2SManos Pitsidianakis } 1805a5110d2SManos Pitsidianakis }; 181a3057c52SJunjie Mao ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty$(,)*) => { 1825a5110d2SManos Pitsidianakis $crate::bindings::Property { 18303a573b9SPaolo Bonzini // use associated function syntax for type checking 1849f7d4520SPaolo Bonzini name: ::std::ffi::CStr::as_ptr($name), 1855a5110d2SManos Pitsidianakis info: $prop, 186f3518400SJunjie Mao offset: $crate::offset_of!($state, $field) as isize, 1875a5110d2SManos Pitsidianakis set_default: false, 1886e50bde1SPaolo Bonzini ..$crate::zeroable::Zeroable::ZERO 1895a5110d2SManos Pitsidianakis } 1905a5110d2SManos Pitsidianakis }; 1915a5110d2SManos Pitsidianakis } 1925a5110d2SManos Pitsidianakis 1935a5110d2SManos Pitsidianakis #[macro_export] 1945a5110d2SManos Pitsidianakis macro_rules! declare_properties { 1955a5110d2SManos Pitsidianakis ($ident:ident, $($prop:expr),*$(,)*) => { 196c92c447fSPaolo Bonzini pub static $ident: [$crate::bindings::Property; { 1975f997648SRichard Henderson let mut len = 0; 1985a5110d2SManos Pitsidianakis $({ 1995a5110d2SManos Pitsidianakis _ = stringify!($prop); 2005a5110d2SManos Pitsidianakis len += 1; 2015a5110d2SManos Pitsidianakis })* 2025a5110d2SManos Pitsidianakis len 203c92c447fSPaolo Bonzini }] = [ 2045a5110d2SManos Pitsidianakis $($prop),*, 205c92c447fSPaolo Bonzini ]; 2065a5110d2SManos Pitsidianakis }; 2075a5110d2SManos Pitsidianakis } 208ce4a144cSPaolo Bonzini 2096dd818fbSPaolo Bonzini unsafe impl ObjectType for DeviceState { 2106dd818fbSPaolo Bonzini type Class = DeviceClass; 2117bd8e3efSPaolo Bonzini const TYPE_NAME: &'static CStr = 212ce4a144cSPaolo Bonzini unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_DEVICE) }; 2137bd8e3efSPaolo Bonzini } 214f50cd85cSPaolo Bonzini qom_isa!(DeviceState: Object); 215201ef001SPaolo Bonzini 216201ef001SPaolo Bonzini /// Trait for methods exposed by the [`DeviceState`] class. The methods can be 217201ef001SPaolo Bonzini /// called on all objects that have the trait `IsA<DeviceState>`. 218201ef001SPaolo Bonzini /// 219201ef001SPaolo Bonzini /// The trait should only be used through the blanket implementation, 220201ef001SPaolo Bonzini /// which guarantees safety via `IsA`. 221201ef001SPaolo Bonzini pub trait DeviceMethods: ObjectDeref 222201ef001SPaolo Bonzini where 223201ef001SPaolo Bonzini Self::Target: IsA<DeviceState>, 224201ef001SPaolo Bonzini { 225201ef001SPaolo Bonzini /// Add an input clock named `name`. Invoke the callback with 226201ef001SPaolo Bonzini /// `self` as the first parameter for the events that are requested. 227201ef001SPaolo Bonzini /// 228201ef001SPaolo Bonzini /// The resulting clock is added as a child of `self`, but it also 229201ef001SPaolo Bonzini /// stays alive until after `Drop::drop` is called because C code 230201ef001SPaolo Bonzini /// keeps an extra reference to it until `device_finalize()` calls 231201ef001SPaolo Bonzini /// `qdev_finalize_clocklist()`. Therefore (unlike most cases in 232201ef001SPaolo Bonzini /// which Rust code has a reference to a child object) it would be 233201ef001SPaolo Bonzini /// possible for this function to return a `&Clock` too. 234201ef001SPaolo Bonzini #[inline] 235201ef001SPaolo Bonzini fn init_clock_in<F: for<'a> FnCall<(&'a Self::Target, ClockEvent)>>( 236201ef001SPaolo Bonzini &self, 237201ef001SPaolo Bonzini name: &str, 238201ef001SPaolo Bonzini _cb: &F, 239201ef001SPaolo Bonzini events: ClockEvent, 240201ef001SPaolo Bonzini ) -> Owned<Clock> { 241201ef001SPaolo Bonzini fn do_init_clock_in( 242201ef001SPaolo Bonzini dev: *mut DeviceState, 243201ef001SPaolo Bonzini name: &str, 244201ef001SPaolo Bonzini cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)>, 245201ef001SPaolo Bonzini events: ClockEvent, 246201ef001SPaolo Bonzini ) -> Owned<Clock> { 247201ef001SPaolo Bonzini assert!(bql_locked()); 248201ef001SPaolo Bonzini 249201ef001SPaolo Bonzini // SAFETY: the clock is heap allocated, but qdev_init_clock_in() 250201ef001SPaolo Bonzini // does not gift the reference to its caller; so use Owned::from to 251201ef001SPaolo Bonzini // add one. The callback is disabled automatically when the clock 252201ef001SPaolo Bonzini // is unparented, which happens before the device is finalized. 253201ef001SPaolo Bonzini unsafe { 254201ef001SPaolo Bonzini let cstr = CString::new(name).unwrap(); 255201ef001SPaolo Bonzini let clk = bindings::qdev_init_clock_in( 256201ef001SPaolo Bonzini dev, 257201ef001SPaolo Bonzini cstr.as_ptr(), 258201ef001SPaolo Bonzini cb, 259201ef001SPaolo Bonzini dev.cast::<c_void>(), 260201ef001SPaolo Bonzini events.0, 261201ef001SPaolo Bonzini ); 262201ef001SPaolo Bonzini 263201ef001SPaolo Bonzini Owned::from(&*clk) 264201ef001SPaolo Bonzini } 265201ef001SPaolo Bonzini } 266201ef001SPaolo Bonzini 267201ef001SPaolo Bonzini let cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)> = if F::is_some() { 268201ef001SPaolo Bonzini unsafe extern "C" fn rust_clock_cb<T, F: for<'a> FnCall<(&'a T, ClockEvent)>>( 269201ef001SPaolo Bonzini opaque: *mut c_void, 270201ef001SPaolo Bonzini event: ClockEvent, 271201ef001SPaolo Bonzini ) { 272201ef001SPaolo Bonzini // SAFETY: the opaque is "this", which is indeed a pointer to T 273201ef001SPaolo Bonzini F::call((unsafe { &*(opaque.cast::<T>()) }, event)) 274201ef001SPaolo Bonzini } 275201ef001SPaolo Bonzini Some(rust_clock_cb::<Self::Target, F>) 276201ef001SPaolo Bonzini } else { 277201ef001SPaolo Bonzini None 278201ef001SPaolo Bonzini }; 279201ef001SPaolo Bonzini 280201ef001SPaolo Bonzini do_init_clock_in(self.as_mut_ptr(), name, cb, events) 281201ef001SPaolo Bonzini } 282201ef001SPaolo Bonzini 283201ef001SPaolo Bonzini /// Add an output clock named `name`. 284201ef001SPaolo Bonzini /// 285201ef001SPaolo Bonzini /// The resulting clock is added as a child of `self`, but it also 286201ef001SPaolo Bonzini /// stays alive until after `Drop::drop` is called because C code 287201ef001SPaolo Bonzini /// keeps an extra reference to it until `device_finalize()` calls 288201ef001SPaolo Bonzini /// `qdev_finalize_clocklist()`. Therefore (unlike most cases in 289201ef001SPaolo Bonzini /// which Rust code has a reference to a child object) it would be 290201ef001SPaolo Bonzini /// possible for this function to return a `&Clock` too. 291201ef001SPaolo Bonzini #[inline] 292201ef001SPaolo Bonzini fn init_clock_out(&self, name: &str) -> Owned<Clock> { 293201ef001SPaolo Bonzini unsafe { 294201ef001SPaolo Bonzini let cstr = CString::new(name).unwrap(); 295201ef001SPaolo Bonzini let clk = bindings::qdev_init_clock_out(self.as_mut_ptr(), cstr.as_ptr()); 296201ef001SPaolo Bonzini 297201ef001SPaolo Bonzini Owned::from(&*clk) 298201ef001SPaolo Bonzini } 299201ef001SPaolo Bonzini } 300201ef001SPaolo Bonzini } 301201ef001SPaolo Bonzini 302201ef001SPaolo Bonzini impl<R: ObjectDeref> DeviceMethods for R where R::Target: IsA<DeviceState> {} 303201ef001SPaolo Bonzini 304201ef001SPaolo Bonzini unsafe impl ObjectType for Clock { 305201ef001SPaolo Bonzini type Class = ObjectClass; 306201ef001SPaolo Bonzini const TYPE_NAME: &'static CStr = 307201ef001SPaolo Bonzini unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_CLOCK) }; 308201ef001SPaolo Bonzini } 309201ef001SPaolo Bonzini qom_isa!(Clock: Object); 310