xref: /qemu/rust/qemu-api/src/qom.rs (revision f75fb90ff2af75cd4405fe4c6ba0c0c38a120590)
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 //! Definitions required by QEMU when registering a device.
6 
7 use std::{ffi::CStr, os::raw::c_void};
8 
9 use crate::bindings::{Object, ObjectClass, TypeInfo};
10 
11 /// Trait a type must implement to be registered with QEMU.
12 pub trait ObjectImpl: ClassInitImpl + Sized {
13     type Class;
14     const TYPE_NAME: &'static CStr;
15     const PARENT_TYPE_NAME: Option<&'static CStr>;
16     const ABSTRACT: bool = false;
17     const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
18     const INSTANCE_POST_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
19     const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
20 
21     const TYPE_INFO: TypeInfo = TypeInfo {
22         name: Self::TYPE_NAME.as_ptr(),
23         parent: if let Some(pname) = Self::PARENT_TYPE_NAME {
24             pname.as_ptr()
25         } else {
26             core::ptr::null_mut()
27         },
28         instance_size: core::mem::size_of::<Self>(),
29         instance_align: core::mem::align_of::<Self>(),
30         instance_init: Self::INSTANCE_INIT,
31         instance_post_init: Self::INSTANCE_POST_INIT,
32         instance_finalize: Self::INSTANCE_FINALIZE,
33         abstract_: Self::ABSTRACT,
34         class_size: core::mem::size_of::<Self::Class>(),
35         class_init: <Self as ClassInitImpl>::CLASS_INIT,
36         class_base_init: <Self as ClassInitImpl>::CLASS_BASE_INIT,
37         class_data: core::ptr::null_mut(),
38         interfaces: core::ptr::null_mut(),
39     };
40 }
41 
42 /// Trait used to fill in a class struct.
43 ///
44 /// Each QOM class that has virtual methods describes them in a
45 /// _class struct_.  Class structs include a parent field corresponding
46 /// to the vtable of the parent class, all the way up to [`ObjectClass`].
47 /// Each QOM type has one such class struct.
48 ///
49 /// The Rust implementation of methods will usually come from a trait
50 /// like [`ObjectImpl`] or [`DeviceImpl`](crate::device_class::DeviceImpl).
51 pub trait ClassInitImpl {
52     /// Function that is called after all parent class initialization
53     /// has occurred.  On entry, the virtual method pointers are set to
54     /// the default values coming from the parent classes; the function
55     /// can change them to override virtual methods of a parent class.
56     const CLASS_INIT: Option<unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void)>;
57 
58     /// Called on descendent classes after all parent class initialization
59     /// has occurred, but before the class itself is initialized.  This
60     /// is only useful if a class is not a leaf, and can be used to undo
61     /// the effects of copying the contents of the parent's class struct
62     /// to the descendants.
63     const CLASS_BASE_INIT: Option<
64         unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void),
65     >;
66 }
67 
68 #[macro_export]
69 macro_rules! module_init {
70     ($type:ident => $body:block) => {
71         const _: () = {
72             #[used]
73             #[cfg_attr(
74                 not(any(target_vendor = "apple", target_os = "windows")),
75                 link_section = ".init_array"
76             )]
77             #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")]
78             #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
79             pub static LOAD_MODULE: extern "C" fn() = {
80                 extern "C" fn init_fn() {
81                     $body
82                 }
83 
84                 extern "C" fn ctor_fn() {
85                     unsafe {
86                         $crate::bindings::register_module_init(
87                             Some(init_fn),
88                             $crate::bindings::module_init_type::$type,
89                         );
90                     }
91                 }
92 
93                 ctor_fn
94             };
95         };
96     };
97 
98     // shortcut because it's quite common that $body needs unsafe {}
99     ($type:ident => unsafe $body:block) => {
100         $crate::module_init! {
101             $type => { unsafe { $body } }
102         }
103     };
104 }
105