forked from qemu/qemu
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rust: add crate to expose bindings and interfaces
Add rust/qemu-api, which exposes rust-bindgen generated FFI bindings and provides some declaration macros for symbols visible to the rest of QEMU. Co-authored-by: Junjie Mao <[email protected]> Co-authored-by: Paolo Bonzini <[email protected]> Signed-off-by: Junjie Mao <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]> Signed-off-by: Manos Pitsidianakis <[email protected]> Link: https://lore.kernel.org/r/0fb23fbe211761b263aacec03deaf85c0cc39995.1727961605.git.manos.pitsidianakis@linaro.org Signed-off-by: Paolo Bonzini <[email protected]>
- Loading branch information
1 parent
dc43b18
commit 5a5110d
Showing
13 changed files
with
541 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3291,6 +3291,12 @@ F: hw/core/register.c | |
F: include/hw/register.h | ||
F: include/hw/registerfields.h | ||
|
||
Rust | ||
M: Manos Pitsidianakis <[email protected]> | ||
S: Maintained | ||
F: rust/qemu-api | ||
F: rust/rustfmt.toml | ||
|
||
SLIRP | ||
M: Samuel Thibault <[email protected]> | ||
S: Maintained | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
subdir('qemu-api') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Ignore generated bindings file overrides. | ||
src/bindings.rs |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
[package] | ||
name = "qemu_api" | ||
version = "0.1.0" | ||
edition = "2021" | ||
authors = ["Manos Pitsidianakis <[email protected]>"] | ||
license = "GPL-2.0-or-later" | ||
readme = "README.md" | ||
homepage = "https://www.qemu.org" | ||
description = "Rust bindings for QEMU" | ||
repository = "https://gitlab.com/qemu-project/qemu/" | ||
resolver = "2" | ||
publish = false | ||
keywords = [] | ||
categories = [] | ||
|
||
[dependencies] | ||
|
||
[features] | ||
default = [] | ||
allocator = [] | ||
|
||
# Do not include in any global workspace | ||
[workspace] | ||
|
||
[lints.rust] | ||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(MESON)', 'cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)'] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# QEMU bindings and API wrappers | ||
|
||
This library exports helper Rust types, Rust macros and C FFI bindings for internal QEMU APIs. | ||
|
||
The C bindings can be generated with `bindgen`, using this build target: | ||
|
||
```console | ||
$ ninja bindings.rs | ||
``` | ||
|
||
## Generate Rust documentation | ||
|
||
To generate docs for this crate, including private items: | ||
|
||
```sh | ||
cargo doc --no-deps --document-private-items | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Copyright 2024, Linaro Limited | ||
// Author(s): Manos Pitsidianakis <[email protected]> | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
use std::path::Path; | ||
|
||
fn main() { | ||
if !Path::new("src/bindings.rs").exists() { | ||
panic!( | ||
"No generated C bindings found! Either build them manually with bindgen or with meson \ | ||
(`ninja bindings.rs`) and copy them to src/bindings.rs, or build through meson." | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
_qemu_api_rs = static_library( | ||
'qemu_api', | ||
structured_sources( | ||
[ | ||
'src/lib.rs', | ||
'src/definitions.rs', | ||
'src/device_class.rs', | ||
], | ||
{'.' : bindings_rs}, | ||
), | ||
override_options: ['rust_std=2021', 'build.rust_std=2021'], | ||
rust_abi: 'rust', | ||
rust_args: rustc_args + [ | ||
'--cfg', 'MESON', | ||
# '--cfg', 'feature="allocator"', | ||
], | ||
) | ||
|
||
qemu_api = declare_dependency( | ||
link_with: _qemu_api_rs, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// Copyright 2024, Linaro Limited | ||
// Author(s): Manos Pitsidianakis <[email protected]> | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
//! Definitions required by QEMU when registering a device. | ||
use ::core::ffi::{c_void, CStr}; | ||
|
||
use crate::bindings::{Object, ObjectClass, TypeInfo}; | ||
|
||
/// Trait a type must implement to be registered with QEMU. | ||
pub trait ObjectImpl { | ||
type Class; | ||
const TYPE_INFO: TypeInfo; | ||
const TYPE_NAME: &'static CStr; | ||
const PARENT_TYPE_NAME: Option<&'static CStr>; | ||
const ABSTRACT: bool; | ||
const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)>; | ||
const INSTANCE_POST_INIT: Option<unsafe extern "C" fn(obj: *mut Object)>; | ||
const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)>; | ||
} | ||
|
||
pub trait Class { | ||
const CLASS_INIT: Option<unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void)>; | ||
const CLASS_BASE_INIT: Option< | ||
unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void), | ||
>; | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! module_init { | ||
($func:expr, $type:expr) => { | ||
#[used] | ||
#[cfg_attr(target_os = "linux", link_section = ".ctors")] | ||
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")] | ||
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")] | ||
pub static LOAD_MODULE: extern "C" fn() = { | ||
extern "C" fn __load() { | ||
unsafe { | ||
$crate::bindings::register_module_init(Some($func), $type); | ||
} | ||
} | ||
|
||
__load | ||
}; | ||
}; | ||
(qom: $func:ident => $body:block) => { | ||
// NOTE: To have custom identifiers for the ctor func we need to either supply | ||
// them directly as a macro argument or create them with a proc macro. | ||
#[used] | ||
#[cfg_attr(target_os = "linux", link_section = ".ctors")] | ||
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")] | ||
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")] | ||
pub static LOAD_MODULE: extern "C" fn() = { | ||
extern "C" fn __load() { | ||
#[no_mangle] | ||
unsafe extern "C" fn $func() { | ||
$body | ||
} | ||
|
||
unsafe { | ||
$crate::bindings::register_module_init( | ||
Some($func), | ||
$crate::bindings::module_init_type::MODULE_INIT_QOM, | ||
); | ||
} | ||
} | ||
|
||
__load | ||
}; | ||
}; | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! type_info { | ||
($t:ty) => { | ||
$crate::bindings::TypeInfo { | ||
name: <$t as $crate::definitions::ObjectImpl>::TYPE_NAME.as_ptr(), | ||
parent: if let Some(pname) = <$t as $crate::definitions::ObjectImpl>::PARENT_TYPE_NAME { | ||
pname.as_ptr() | ||
} else { | ||
::core::ptr::null_mut() | ||
}, | ||
instance_size: ::core::mem::size_of::<$t>() as $crate::bindings::size_t, | ||
instance_align: ::core::mem::align_of::<$t>() as $crate::bindings::size_t, | ||
instance_init: <$t as $crate::definitions::ObjectImpl>::INSTANCE_INIT, | ||
instance_post_init: <$t as $crate::definitions::ObjectImpl>::INSTANCE_POST_INIT, | ||
instance_finalize: <$t as $crate::definitions::ObjectImpl>::INSTANCE_FINALIZE, | ||
abstract_: <$t as $crate::definitions::ObjectImpl>::ABSTRACT, | ||
class_size: ::core::mem::size_of::<<$t as $crate::definitions::ObjectImpl>::Class>() as $crate::bindings::size_t, | ||
class_init: <<$t as $crate::definitions::ObjectImpl>::Class as $crate::definitions::Class>::CLASS_INIT, | ||
class_base_init: <<$t as $crate::definitions::ObjectImpl>::Class as $crate::definitions::Class>::CLASS_BASE_INIT, | ||
class_data: ::core::ptr::null_mut(), | ||
interfaces: ::core::ptr::null_mut(), | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// Copyright 2024, Linaro Limited | ||
// Author(s): Manos Pitsidianakis <[email protected]> | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
use std::sync::OnceLock; | ||
|
||
use crate::bindings::Property; | ||
|
||
#[macro_export] | ||
macro_rules! device_class_init { | ||
($func:ident, props => $props:ident, realize_fn => $realize_fn:expr, legacy_reset_fn => $legacy_reset_fn:expr, vmsd => $vmsd:ident$(,)*) => { | ||
#[no_mangle] | ||
pub unsafe extern "C" fn $func( | ||
klass: *mut $crate::bindings::ObjectClass, | ||
_: *mut ::core::ffi::c_void, | ||
) { | ||
let mut dc = | ||
::core::ptr::NonNull::new(klass.cast::<$crate::bindings::DeviceClass>()).unwrap(); | ||
dc.as_mut().realize = $realize_fn; | ||
dc.as_mut().vmsd = &$vmsd; | ||
$crate::bindings::device_class_set_legacy_reset(dc.as_mut(), $legacy_reset_fn); | ||
$crate::bindings::device_class_set_props(dc.as_mut(), $props.as_mut_ptr()); | ||
} | ||
}; | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! define_property { | ||
($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr, default = $defval:expr$(,)*) => { | ||
$crate::bindings::Property { | ||
name: { | ||
#[used] | ||
static _TEMP: &::core::ffi::CStr = $name; | ||
_TEMP.as_ptr() | ||
}, | ||
info: $prop, | ||
offset: ::core::mem::offset_of!($state, $field) | ||
.try_into() | ||
.expect("Could not fit offset value to type"), | ||
bitnr: 0, | ||
bitmask: 0, | ||
set_default: true, | ||
defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval.into() }, | ||
arrayoffset: 0, | ||
arrayinfo: ::core::ptr::null(), | ||
arrayfieldsize: 0, | ||
link_type: ::core::ptr::null(), | ||
} | ||
}; | ||
($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr$(,)*) => { | ||
$crate::bindings::Property { | ||
name: { | ||
#[used] | ||
static _TEMP: &::core::ffi::CStr = $name; | ||
_TEMP.as_ptr() | ||
}, | ||
info: $prop, | ||
offset: ::core::mem::offset_of!($state, $field) | ||
.try_into() | ||
.expect("Could not fit offset value to type"), | ||
bitnr: 0, | ||
bitmask: 0, | ||
set_default: false, | ||
defval: $crate::bindings::Property__bindgen_ty_1 { i: 0 }, | ||
arrayoffset: 0, | ||
arrayinfo: ::core::ptr::null(), | ||
arrayfieldsize: 0, | ||
link_type: ::core::ptr::null(), | ||
} | ||
}; | ||
} | ||
|
||
#[repr(C)] | ||
pub struct Properties<const N: usize>(pub OnceLock<[Property; N]>, pub fn() -> [Property; N]); | ||
|
||
impl<const N: usize> Properties<N> { | ||
pub fn as_mut_ptr(&mut self) -> *mut Property { | ||
_ = self.0.get_or_init(self.1); | ||
self.0.get_mut().unwrap().as_mut_ptr() | ||
} | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! declare_properties { | ||
($ident:ident, $($prop:expr),*$(,)*) => { | ||
|
||
const fn _calc_prop_len() -> usize { | ||
let mut len = 1; | ||
$({ | ||
_ = stringify!($prop); | ||
len += 1; | ||
})* | ||
len | ||
} | ||
const PROP_LEN: usize = _calc_prop_len(); | ||
|
||
fn _make_properties() -> [$crate::bindings::Property; PROP_LEN] { | ||
[ | ||
$($prop),*, | ||
unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() }, | ||
] | ||
} | ||
|
||
#[no_mangle] | ||
pub static mut $ident: $crate::device_class::Properties<PROP_LEN> = $crate::device_class::Properties(::std::sync::OnceLock::new(), _make_properties); | ||
}; | ||
} | ||
|
||
#[macro_export] | ||
macro_rules! vm_state_description { | ||
($(#[$outer:meta])* | ||
$name:ident, | ||
$(name: $vname:expr,)* | ||
$(unmigratable: $um_val:expr,)* | ||
) => { | ||
#[used] | ||
$(#[$outer])* | ||
pub static $name: $crate::bindings::VMStateDescription = $crate::bindings::VMStateDescription { | ||
$(name: { | ||
#[used] | ||
static VMSTATE_NAME: &::core::ffi::CStr = $vname; | ||
$vname.as_ptr() | ||
},)* | ||
unmigratable: true, | ||
..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::VMStateDescription>::zeroed().assume_init() } | ||
}; | ||
} | ||
} |
Oops, something went wrong.