xref: /qemu/rust/qemu-api/src/qdev.rs (revision 7f2d4181a3efc3c1fd9de4bdca81317a1116239a)
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 
135472a38cSPaolo Bonzini pub use bindings::{Clock, ClockEvent, DeviceClass, DeviceState, Property, ResetType};
14716d89f9SPaolo Bonzini 
158c80c472SPaolo Bonzini use crate::{
165472a38cSPaolo Bonzini     bindings::{self, Error, ResettableClass},
17201ef001SPaolo Bonzini     callbacks::FnCall,
18201ef001SPaolo Bonzini     cell::bql_locked,
19a22bd55fSPaolo Bonzini     chardev::Chardev,
207bd8e3efSPaolo Bonzini     prelude::*,
2168da5402SPaolo Bonzini     qom::{ClassInitImpl, ObjectClass, ObjectImpl, Owned},
22716d89f9SPaolo Bonzini     vmstate::VMStateDescription,
238c80c472SPaolo Bonzini };
248c80c472SPaolo Bonzini 
255472a38cSPaolo Bonzini /// Trait providing the contents of the `ResettablePhases` struct,
265472a38cSPaolo Bonzini /// which is part of the QOM `Resettable` interface.
275472a38cSPaolo Bonzini pub trait ResettablePhasesImpl {
285472a38cSPaolo Bonzini     /// If not None, this is called when the object enters reset. It
295472a38cSPaolo Bonzini     /// can reset local state of the object, but it must not do anything that
305472a38cSPaolo Bonzini     /// has a side-effect on other objects, such as raising or lowering an
315472a38cSPaolo Bonzini     /// [`InterruptSource`](crate::irq::InterruptSource), or reading or
325472a38cSPaolo Bonzini     /// writing guest memory. It takes the reset's type as argument.
335472a38cSPaolo Bonzini     const ENTER: Option<fn(&Self, ResetType)> = None;
345472a38cSPaolo Bonzini 
355472a38cSPaolo Bonzini     /// If not None, this is called when the object for entry into reset, once
365472a38cSPaolo Bonzini     /// every object in the system which is being reset has had its
375472a38cSPaolo Bonzini     /// `ResettablePhasesImpl::ENTER` method called. At this point devices
385472a38cSPaolo Bonzini     /// can do actions that affect other objects.
395472a38cSPaolo Bonzini     ///
405472a38cSPaolo Bonzini     /// If in doubt, implement this method.
415472a38cSPaolo Bonzini     const HOLD: Option<fn(&Self, ResetType)> = None;
425472a38cSPaolo Bonzini 
435472a38cSPaolo Bonzini     /// If not None, this phase is called when the object leaves the reset
445472a38cSPaolo Bonzini     /// state. Actions affecting other objects are permitted.
455472a38cSPaolo Bonzini     const EXIT: Option<fn(&Self, ResetType)> = None;
465472a38cSPaolo Bonzini }
475472a38cSPaolo Bonzini 
485472a38cSPaolo Bonzini /// # Safety
495472a38cSPaolo Bonzini ///
505472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
515472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
525472a38cSPaolo Bonzini /// readable/writeable from one thread at any time.
535472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>(
545472a38cSPaolo Bonzini     obj: *mut Object,
555472a38cSPaolo Bonzini     typ: ResetType,
565472a38cSPaolo Bonzini ) {
575472a38cSPaolo Bonzini     let state = NonNull::new(obj).unwrap().cast::<T>();
585472a38cSPaolo Bonzini     T::ENTER.unwrap()(unsafe { state.as_ref() }, typ);
595472a38cSPaolo Bonzini }
605472a38cSPaolo Bonzini 
615472a38cSPaolo Bonzini /// # Safety
625472a38cSPaolo Bonzini ///
635472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
645472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
655472a38cSPaolo Bonzini /// readable/writeable from one thread at any time.
665472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>(
675472a38cSPaolo Bonzini     obj: *mut Object,
685472a38cSPaolo Bonzini     typ: ResetType,
695472a38cSPaolo Bonzini ) {
705472a38cSPaolo Bonzini     let state = NonNull::new(obj).unwrap().cast::<T>();
715472a38cSPaolo Bonzini     T::HOLD.unwrap()(unsafe { state.as_ref() }, typ);
725472a38cSPaolo Bonzini }
735472a38cSPaolo Bonzini 
745472a38cSPaolo Bonzini /// # Safety
755472a38cSPaolo Bonzini ///
765472a38cSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
775472a38cSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
785472a38cSPaolo Bonzini /// readable/writeable from one thread at any time.
795472a38cSPaolo Bonzini unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>(
805472a38cSPaolo Bonzini     obj: *mut Object,
815472a38cSPaolo Bonzini     typ: ResetType,
825472a38cSPaolo Bonzini ) {
835472a38cSPaolo Bonzini     let state = NonNull::new(obj).unwrap().cast::<T>();
845472a38cSPaolo Bonzini     T::EXIT.unwrap()(unsafe { state.as_ref() }, typ);
855472a38cSPaolo Bonzini }
865472a38cSPaolo Bonzini 
878c80c472SPaolo Bonzini /// Trait providing the contents of [`DeviceClass`].
885472a38cSPaolo Bonzini pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl {
898c80c472SPaolo Bonzini     /// _Realization_ is the second stage of device creation. It contains
908c80c472SPaolo Bonzini     /// all operations that depend on device properties and can fail (note:
918c80c472SPaolo Bonzini     /// this is not yet supported for Rust devices).
928c80c472SPaolo Bonzini     ///
938c80c472SPaolo Bonzini     /// If not `None`, the parent class's `realize` method is overridden
948c80c472SPaolo Bonzini     /// with the function pointed to by `REALIZE`.
950f9eb0ffSZhao Liu     const REALIZE: Option<fn(&Self)> = None;
968c80c472SPaolo Bonzini 
978c80c472SPaolo Bonzini     /// An array providing the properties that the user can set on the
988c80c472SPaolo Bonzini     /// device.  Not a `const` because referencing statics in constants
998c80c472SPaolo Bonzini     /// is unstable until Rust 1.83.0.
1008c80c472SPaolo Bonzini     fn properties() -> &'static [Property] {
1015f997648SRichard Henderson         &[]
1028c80c472SPaolo Bonzini     }
1038c80c472SPaolo Bonzini 
1048c80c472SPaolo Bonzini     /// A `VMStateDescription` providing the migration format for the device
1058c80c472SPaolo Bonzini     /// Not a `const` because referencing statics in constants is unstable
1068c80c472SPaolo Bonzini     /// until Rust 1.83.0.
1078c80c472SPaolo Bonzini     fn vmsd() -> Option<&'static VMStateDescription> {
1088c80c472SPaolo Bonzini         None
1098c80c472SPaolo Bonzini     }
1108c80c472SPaolo Bonzini }
1118c80c472SPaolo Bonzini 
1128c80c472SPaolo Bonzini /// # Safety
1138c80c472SPaolo Bonzini ///
114f75fb90fSPaolo Bonzini /// This function is only called through the QOM machinery and
1156dd818fbSPaolo Bonzini /// used by the `ClassInitImpl<DeviceClass>` trait.
116f75fb90fSPaolo Bonzini /// We expect the FFI user of this function to pass a valid pointer that
117f75fb90fSPaolo Bonzini /// can be downcasted to type `T`. We also expect the device is
118f75fb90fSPaolo Bonzini /// readable/writeable from one thread at any time.
119f75fb90fSPaolo Bonzini unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>(dev: *mut DeviceState, _errp: *mut *mut Error) {
1207d052039SPaolo Bonzini     let state = NonNull::new(dev).unwrap().cast::<T>();
1217d052039SPaolo Bonzini     T::REALIZE.unwrap()(unsafe { state.as_ref() });
122f75fb90fSPaolo Bonzini }
123f75fb90fSPaolo Bonzini 
1245472a38cSPaolo Bonzini unsafe impl InterfaceType for ResettableClass {
1255472a38cSPaolo Bonzini     const TYPE_NAME: &'static CStr =
1265472a38cSPaolo Bonzini         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_RESETTABLE_INTERFACE) };
1275472a38cSPaolo Bonzini }
1285472a38cSPaolo Bonzini 
1295472a38cSPaolo Bonzini impl<T> ClassInitImpl<ResettableClass> for T
1305472a38cSPaolo Bonzini where
1315472a38cSPaolo Bonzini     T: ResettablePhasesImpl,
1325472a38cSPaolo Bonzini {
1335472a38cSPaolo Bonzini     fn class_init(rc: &mut ResettableClass) {
1345472a38cSPaolo Bonzini         if <T as ResettablePhasesImpl>::ENTER.is_some() {
1355472a38cSPaolo Bonzini             rc.phases.enter = Some(rust_resettable_enter_fn::<T>);
1365472a38cSPaolo Bonzini         }
1375472a38cSPaolo Bonzini         if <T as ResettablePhasesImpl>::HOLD.is_some() {
1385472a38cSPaolo Bonzini             rc.phases.hold = Some(rust_resettable_hold_fn::<T>);
1395472a38cSPaolo Bonzini         }
1405472a38cSPaolo Bonzini         if <T as ResettablePhasesImpl>::EXIT.is_some() {
1415472a38cSPaolo Bonzini             rc.phases.exit = Some(rust_resettable_exit_fn::<T>);
1425472a38cSPaolo Bonzini         }
1435472a38cSPaolo Bonzini     }
144f75fb90fSPaolo Bonzini }
145f75fb90fSPaolo Bonzini 
1466dd818fbSPaolo Bonzini impl<T> ClassInitImpl<DeviceClass> for T
1476dd818fbSPaolo Bonzini where
1485472a38cSPaolo Bonzini     T: ClassInitImpl<ObjectClass> + ClassInitImpl<ResettableClass> + DeviceImpl,
1496dd818fbSPaolo Bonzini {
1506dd818fbSPaolo Bonzini     fn class_init(dc: &mut DeviceClass) {
151f75fb90fSPaolo Bonzini         if <T as DeviceImpl>::REALIZE.is_some() {
152f75fb90fSPaolo Bonzini             dc.realize = Some(rust_realize_fn::<T>);
1538c80c472SPaolo Bonzini         }
1548c80c472SPaolo Bonzini         if let Some(vmsd) = <T as DeviceImpl>::vmsd() {
1558c80c472SPaolo Bonzini             dc.vmsd = vmsd;
1568c80c472SPaolo Bonzini         }
1575f997648SRichard Henderson         let prop = <T as DeviceImpl>::properties();
1585f997648SRichard Henderson         if !prop.is_empty() {
1596dd818fbSPaolo Bonzini             unsafe {
1605f997648SRichard Henderson                 bindings::device_class_set_props_n(dc, prop.as_ptr(), prop.len());
1615f997648SRichard Henderson             }
1628c80c472SPaolo Bonzini         }
163cb36da9bSPaolo Bonzini 
1645472a38cSPaolo Bonzini         ResettableClass::interface_init::<T, DeviceState>(dc);
165cb36da9bSPaolo Bonzini         <T as ClassInitImpl<ObjectClass>>::class_init(&mut dc.parent_class);
1668c80c472SPaolo Bonzini     }
1675a5110d2SManos Pitsidianakis }
1685a5110d2SManos Pitsidianakis 
1695a5110d2SManos Pitsidianakis #[macro_export]
1705a5110d2SManos Pitsidianakis macro_rules! define_property {
171*7f2d4181SZhao Liu     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, bit = $bitnr:expr, default = $defval:expr$(,)*) => {
172*7f2d4181SZhao Liu         $crate::bindings::Property {
173*7f2d4181SZhao Liu             // use associated function syntax for type checking
174*7f2d4181SZhao Liu             name: ::std::ffi::CStr::as_ptr($name),
175*7f2d4181SZhao Liu             info: $prop,
176*7f2d4181SZhao Liu             offset: $crate::offset_of!($state, $field) as isize,
177*7f2d4181SZhao Liu             bitnr: $bitnr,
178*7f2d4181SZhao Liu             set_default: true,
179*7f2d4181SZhao Liu             defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
180*7f2d4181SZhao Liu             ..$crate::zeroable::Zeroable::ZERO
181*7f2d4181SZhao Liu         }
182*7f2d4181SZhao Liu     };
183a3057c52SJunjie Mao     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, default = $defval:expr$(,)*) => {
1845a5110d2SManos Pitsidianakis         $crate::bindings::Property {
18503a573b9SPaolo Bonzini             // use associated function syntax for type checking
1869f7d4520SPaolo Bonzini             name: ::std::ffi::CStr::as_ptr($name),
1875a5110d2SManos Pitsidianakis             info: $prop,
188f3518400SJunjie Mao             offset: $crate::offset_of!($state, $field) as isize,
1895a5110d2SManos Pitsidianakis             set_default: true,
19003a573b9SPaolo Bonzini             defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
1916e50bde1SPaolo Bonzini             ..$crate::zeroable::Zeroable::ZERO
1925a5110d2SManos Pitsidianakis         }
1935a5110d2SManos Pitsidianakis     };
194a3057c52SJunjie Mao     ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty$(,)*) => {
1955a5110d2SManos Pitsidianakis         $crate::bindings::Property {
19603a573b9SPaolo Bonzini             // use associated function syntax for type checking
1979f7d4520SPaolo Bonzini             name: ::std::ffi::CStr::as_ptr($name),
1985a5110d2SManos Pitsidianakis             info: $prop,
199f3518400SJunjie Mao             offset: $crate::offset_of!($state, $field) as isize,
2005a5110d2SManos Pitsidianakis             set_default: false,
2016e50bde1SPaolo Bonzini             ..$crate::zeroable::Zeroable::ZERO
2025a5110d2SManos Pitsidianakis         }
2035a5110d2SManos Pitsidianakis     };
2045a5110d2SManos Pitsidianakis }
2055a5110d2SManos Pitsidianakis 
2065a5110d2SManos Pitsidianakis #[macro_export]
2075a5110d2SManos Pitsidianakis macro_rules! declare_properties {
2085a5110d2SManos Pitsidianakis     ($ident:ident, $($prop:expr),*$(,)*) => {
209c92c447fSPaolo Bonzini         pub static $ident: [$crate::bindings::Property; {
2105f997648SRichard Henderson             let mut len = 0;
2115a5110d2SManos Pitsidianakis             $({
2125a5110d2SManos Pitsidianakis                 _ = stringify!($prop);
2135a5110d2SManos Pitsidianakis                 len += 1;
2145a5110d2SManos Pitsidianakis             })*
2155a5110d2SManos Pitsidianakis             len
216c92c447fSPaolo Bonzini         }] = [
2175a5110d2SManos Pitsidianakis             $($prop),*,
218c92c447fSPaolo Bonzini         ];
2195a5110d2SManos Pitsidianakis     };
2205a5110d2SManos Pitsidianakis }
221ce4a144cSPaolo Bonzini 
2226dd818fbSPaolo Bonzini unsafe impl ObjectType for DeviceState {
2236dd818fbSPaolo Bonzini     type Class = DeviceClass;
2247bd8e3efSPaolo Bonzini     const TYPE_NAME: &'static CStr =
225ce4a144cSPaolo Bonzini         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_DEVICE) };
2267bd8e3efSPaolo Bonzini }
227f50cd85cSPaolo Bonzini qom_isa!(DeviceState: Object);
228201ef001SPaolo Bonzini 
229201ef001SPaolo Bonzini /// Trait for methods exposed by the [`DeviceState`] class.  The methods can be
230201ef001SPaolo Bonzini /// called on all objects that have the trait `IsA<DeviceState>`.
231201ef001SPaolo Bonzini ///
232201ef001SPaolo Bonzini /// The trait should only be used through the blanket implementation,
233201ef001SPaolo Bonzini /// which guarantees safety via `IsA`.
234201ef001SPaolo Bonzini pub trait DeviceMethods: ObjectDeref
235201ef001SPaolo Bonzini where
236201ef001SPaolo Bonzini     Self::Target: IsA<DeviceState>,
237201ef001SPaolo Bonzini {
238201ef001SPaolo Bonzini     /// Add an input clock named `name`.  Invoke the callback with
239201ef001SPaolo Bonzini     /// `self` as the first parameter for the events that are requested.
240201ef001SPaolo Bonzini     ///
241201ef001SPaolo Bonzini     /// The resulting clock is added as a child of `self`, but it also
242201ef001SPaolo Bonzini     /// stays alive until after `Drop::drop` is called because C code
243201ef001SPaolo Bonzini     /// keeps an extra reference to it until `device_finalize()` calls
244201ef001SPaolo Bonzini     /// `qdev_finalize_clocklist()`.  Therefore (unlike most cases in
245201ef001SPaolo Bonzini     /// which Rust code has a reference to a child object) it would be
246201ef001SPaolo Bonzini     /// possible for this function to return a `&Clock` too.
247201ef001SPaolo Bonzini     #[inline]
248201ef001SPaolo Bonzini     fn init_clock_in<F: for<'a> FnCall<(&'a Self::Target, ClockEvent)>>(
249201ef001SPaolo Bonzini         &self,
250201ef001SPaolo Bonzini         name: &str,
251201ef001SPaolo Bonzini         _cb: &F,
252201ef001SPaolo Bonzini         events: ClockEvent,
253201ef001SPaolo Bonzini     ) -> Owned<Clock> {
254201ef001SPaolo Bonzini         fn do_init_clock_in(
255201ef001SPaolo Bonzini             dev: *mut DeviceState,
256201ef001SPaolo Bonzini             name: &str,
257201ef001SPaolo Bonzini             cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)>,
258201ef001SPaolo Bonzini             events: ClockEvent,
259201ef001SPaolo Bonzini         ) -> Owned<Clock> {
260201ef001SPaolo Bonzini             assert!(bql_locked());
261201ef001SPaolo Bonzini 
262201ef001SPaolo Bonzini             // SAFETY: the clock is heap allocated, but qdev_init_clock_in()
263201ef001SPaolo Bonzini             // does not gift the reference to its caller; so use Owned::from to
264201ef001SPaolo Bonzini             // add one.  The callback is disabled automatically when the clock
265201ef001SPaolo Bonzini             // is unparented, which happens before the device is finalized.
266201ef001SPaolo Bonzini             unsafe {
267201ef001SPaolo Bonzini                 let cstr = CString::new(name).unwrap();
268201ef001SPaolo Bonzini                 let clk = bindings::qdev_init_clock_in(
269201ef001SPaolo Bonzini                     dev,
270201ef001SPaolo Bonzini                     cstr.as_ptr(),
271201ef001SPaolo Bonzini                     cb,
272201ef001SPaolo Bonzini                     dev.cast::<c_void>(),
273201ef001SPaolo Bonzini                     events.0,
274201ef001SPaolo Bonzini                 );
275201ef001SPaolo Bonzini 
276201ef001SPaolo Bonzini                 Owned::from(&*clk)
277201ef001SPaolo Bonzini             }
278201ef001SPaolo Bonzini         }
279201ef001SPaolo Bonzini 
280201ef001SPaolo Bonzini         let cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)> = if F::is_some() {
281201ef001SPaolo Bonzini             unsafe extern "C" fn rust_clock_cb<T, F: for<'a> FnCall<(&'a T, ClockEvent)>>(
282201ef001SPaolo Bonzini                 opaque: *mut c_void,
283201ef001SPaolo Bonzini                 event: ClockEvent,
284201ef001SPaolo Bonzini             ) {
285201ef001SPaolo Bonzini                 // SAFETY: the opaque is "this", which is indeed a pointer to T
286201ef001SPaolo Bonzini                 F::call((unsafe { &*(opaque.cast::<T>()) }, event))
287201ef001SPaolo Bonzini             }
288201ef001SPaolo Bonzini             Some(rust_clock_cb::<Self::Target, F>)
289201ef001SPaolo Bonzini         } else {
290201ef001SPaolo Bonzini             None
291201ef001SPaolo Bonzini         };
292201ef001SPaolo Bonzini 
293201ef001SPaolo Bonzini         do_init_clock_in(self.as_mut_ptr(), name, cb, events)
294201ef001SPaolo Bonzini     }
295201ef001SPaolo Bonzini 
296201ef001SPaolo Bonzini     /// Add an output clock named `name`.
297201ef001SPaolo Bonzini     ///
298201ef001SPaolo Bonzini     /// The resulting clock is added as a child of `self`, but it also
299201ef001SPaolo Bonzini     /// stays alive until after `Drop::drop` is called because C code
300201ef001SPaolo Bonzini     /// keeps an extra reference to it until `device_finalize()` calls
301201ef001SPaolo Bonzini     /// `qdev_finalize_clocklist()`.  Therefore (unlike most cases in
302201ef001SPaolo Bonzini     /// which Rust code has a reference to a child object) it would be
303201ef001SPaolo Bonzini     /// possible for this function to return a `&Clock` too.
304201ef001SPaolo Bonzini     #[inline]
305201ef001SPaolo Bonzini     fn init_clock_out(&self, name: &str) -> Owned<Clock> {
306201ef001SPaolo Bonzini         unsafe {
307201ef001SPaolo Bonzini             let cstr = CString::new(name).unwrap();
308201ef001SPaolo Bonzini             let clk = bindings::qdev_init_clock_out(self.as_mut_ptr(), cstr.as_ptr());
309201ef001SPaolo Bonzini 
310201ef001SPaolo Bonzini             Owned::from(&*clk)
311201ef001SPaolo Bonzini         }
312201ef001SPaolo Bonzini     }
313a22bd55fSPaolo Bonzini 
314a22bd55fSPaolo Bonzini     fn prop_set_chr(&self, propname: &str, chr: &Owned<Chardev>) {
315a22bd55fSPaolo Bonzini         assert!(bql_locked());
316a22bd55fSPaolo Bonzini         let c_propname = CString::new(propname).unwrap();
317a22bd55fSPaolo Bonzini         unsafe {
318a22bd55fSPaolo Bonzini             bindings::qdev_prop_set_chr(self.as_mut_ptr(), c_propname.as_ptr(), chr.as_mut_ptr());
319a22bd55fSPaolo Bonzini         }
320a22bd55fSPaolo Bonzini     }
321201ef001SPaolo Bonzini }
322201ef001SPaolo Bonzini 
323201ef001SPaolo Bonzini impl<R: ObjectDeref> DeviceMethods for R where R::Target: IsA<DeviceState> {}
324201ef001SPaolo Bonzini 
325201ef001SPaolo Bonzini unsafe impl ObjectType for Clock {
326201ef001SPaolo Bonzini     type Class = ObjectClass;
327201ef001SPaolo Bonzini     const TYPE_NAME: &'static CStr =
328201ef001SPaolo Bonzini         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_CLOCK) };
329201ef001SPaolo Bonzini }
330201ef001SPaolo Bonzini qom_isa!(Clock: Object);
331