diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2025-03-10 13:40:05 +0800 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2025-03-10 13:40:05 +0800 |
commit | 1843a0c01d06049f517fea7e155e5236e7287276 (patch) | |
tree | 2f520c4c409e5c24f377af7372e92678d57482fc /rust/qemu-api | |
parent | d9a4282c4b690e45d25c2b933f318bb41eeb271d (diff) | |
parent | 816945364f698ae750aa665fce3d121c98e37a6f (diff) | |
download | qemu-1843a0c01d06049f517fea7e155e5236e7287276.zip qemu-1843a0c01d06049f517fea7e155e5236e7287276.tar.gz qemu-1843a0c01d06049f517fea7e155e5236e7287276.tar.bz2 |
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* scripts: dump stdin on meson-buildoptions error
* rust: introduce qemu_api::cell::Opaque<>
* rust: express pinning requirements for timers
* rust: hpet: decode HPET registers into enums
* rust: cell: add full example of declaring a SysBusDevice
* rust: qom: remove operations on &mut
# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmfNbXwUHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroNjpwf+ODnG0XzHt7LSag695zs5fVLK353m
# vLAHJ0bsmHoR4V+jEc+eaY7esDx5TLB9SRX/NvDsumJ9xnGYxXVn8Ti5GNHpa/xd
# qSReB6X3E8fqG5e3AffUJGJnxrD8dHJ733RsyJBZqJc9sWkUnSiEBb5lGu7br6oC
# fFyfiGweYboQ4AsiQUDtEN+tQsTWNkdThYEzq+dpnZrDJHNnw5e/rRwmqCUnEsLU
# PfwhrOGJ3OkIUtdgHStuNfiN9sqjXV5DXmZVa9L2We8FEQdkhBzg3TC0ez0gFG/1
# W0P6JwfWk9Z+y/ERxkaycSXmabM0zUiFF1UJNgKEXp5iuPnRFC82OtRSUg==
# =de1b
# -----END PGP SIGNATURE-----
# gpg: Signature made Sun 09 Mar 2025 18:29:16 HKT
# gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg: issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1
# Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83
* tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (25 commits)
rust: pl011: Allow NULL chardev argument to pl011_create()
meson.build: default to -gsplit-dwarf for debug info
rust: qom: remove operations on &mut
rust: cell: add full example of declaring a SysBusDevice
rust: hpet: decode HPET registers into enums
rust: pl011: pass around registers::Data
rust: pl011: switch to safe chardev operation
rust: pl011: clean up visibilities of callbacks
rust: pl011: move register definitions out of lib.rs
rust: chardev: provide basic bindings to character devices
rust: bindings: remove more unnecessary Send/Sync impls
rust: chardev: wrap Chardev with Opaque<>
rust: memory: wrap MemoryRegion with Opaque<>
rust: sysbus: wrap SysBusDevice with Opaque<>
rust: hpet: do not access fields of SysBusDevice
rust: qdev: wrap Clock and DeviceState with Opaque<>
rust: qom: wrap Object with Opaque<>
rust: irq: wrap IRQState with Opaque<>
rust: timer: wrap QEMUTimer with Opaque<> and express pinning requirements
rust: hpet: embed Timer without the Option and Box indirection
...
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'rust/qemu-api')
-rw-r--r-- | rust/qemu-api/meson.build | 24 | ||||
-rw-r--r-- | rust/qemu-api/src/bindings.rs | 26 | ||||
-rw-r--r-- | rust/qemu-api/src/cell.rs | 277 | ||||
-rw-r--r-- | rust/qemu-api/src/chardev.rs | 248 | ||||
-rw-r--r-- | rust/qemu-api/src/irq.rs | 15 | ||||
-rw-r--r-- | rust/qemu-api/src/memory.rs | 32 | ||||
-rw-r--r-- | rust/qemu-api/src/prelude.rs | 1 | ||||
-rw-r--r-- | rust/qemu-api/src/qdev.rs | 75 | ||||
-rw-r--r-- | rust/qemu-api/src/qom.rs | 118 | ||||
-rw-r--r-- | rust/qemu-api/src/sysbus.rs | 40 | ||||
-rw-r--r-- | rust/qemu-api/src/timer.rs | 47 | ||||
-rw-r--r-- | rust/qemu-api/src/vmstate.rs | 3 | ||||
-rw-r--r-- | rust/qemu-api/src/zeroable.rs | 1 | ||||
-rw-r--r-- | rust/qemu-api/tests/tests.rs | 34 |
14 files changed, 708 insertions, 233 deletions
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build index bcf1cf7..a3f226c 100644 --- a/rust/qemu-api/meson.build +++ b/rust/qemu-api/meson.build @@ -42,22 +42,31 @@ _qemu_api_rs = static_library( override_options: ['rust_std=2021', 'build.rust_std=2021'], rust_abi: 'rust', rust_args: _qemu_api_cfg, - dependencies: libc_dep, + dependencies: [libc_dep, qemu_api_macros], ) rust.test('rust-qemu-api-tests', _qemu_api_rs, suite: ['unit', 'rust']) -qemu_api = declare_dependency( - link_with: _qemu_api_rs, - dependencies: qemu_api_macros, -) +qemu_api = declare_dependency(link_with: _qemu_api_rs) # Rust executables do not support objects, so add an intermediate step. rust_qemu_api_objs = static_library( 'rust_qemu_api_objs', objects: [libqom.extract_all_objects(recursive: false), - libhwcore.extract_all_objects(recursive: false)]) + libhwcore.extract_all_objects(recursive: false), + libchardev.extract_all_objects(recursive: false), + libcrypto.extract_all_objects(recursive: false), + libauthz.extract_all_objects(recursive: false), + libio.extract_all_objects(recursive: false)]) +rust_qemu_api_deps = declare_dependency( + dependencies: [ + qom_ss.dependencies(), + chardev_ss.dependencies(), + crypto_ss.dependencies(), + authz_ss.dependencies(), + io_ss.dependencies()], + link_whole: [rust_qemu_api_objs, libqemuutil]) test('rust-qemu-api-integration', executable( @@ -66,8 +75,7 @@ test('rust-qemu-api-integration', override_options: ['rust_std=2021', 'build.rust_std=2021'], rust_args: ['--test'], install: false, - dependencies: [qemu_api, qemu_api_macros], - link_whole: [rust_qemu_api_objs, libqemuutil]), + dependencies: [qemu_api, qemu_api_macros, rust_qemu_api_deps]), args: [ '--test', '--test-threads', '1', '--format', 'pretty', diff --git a/rust/qemu-api/src/bindings.rs b/rust/qemu-api/src/bindings.rs index d286863..3c1d297 100644 --- a/rust/qemu-api/src/bindings.rs +++ b/rust/qemu-api/src/bindings.rs @@ -25,33 +25,11 @@ include!(concat!(env!("OUT_DIR"), "/bindings.inc.rs")); // SAFETY: these are implemented in C; the bindings need to assert that the // BQL is taken, either directly or via `BqlCell` and `BqlRefCell`. -unsafe impl Send for BusState {} -unsafe impl Sync for BusState {} - +// When bindings for character devices are introduced, this can be +// moved to the Opaque<> wrapper in src/chardev.rs. unsafe impl Send for CharBackend {} unsafe impl Sync for CharBackend {} -unsafe impl Send for Chardev {} -unsafe impl Sync for Chardev {} - -unsafe impl Send for Clock {} -unsafe impl Sync for Clock {} - -unsafe impl Send for DeviceState {} -unsafe impl Sync for DeviceState {} - -unsafe impl Send for MemoryRegion {} -unsafe impl Sync for MemoryRegion {} - -unsafe impl Send for ObjectClass {} -unsafe impl Sync for ObjectClass {} - -unsafe impl Send for Object {} -unsafe impl Sync for Object {} - -unsafe impl Send for SysBusDevice {} -unsafe impl Sync for SysBusDevice {} - // SAFETY: this is a pure data struct unsafe impl Send for CoalescedMemoryRange {} unsafe impl Sync for CoalescedMemoryRange {} diff --git a/rust/qemu-api/src/cell.rs b/rust/qemu-api/src/cell.rs index eae4e2c..ab0785a 100644 --- a/rust/qemu-api/src/cell.rs +++ b/rust/qemu-api/src/cell.rs @@ -27,7 +27,7 @@ // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -//! BQL-protected mutable containers. +//! QEMU-specific mutable containers //! //! Rust memory safety is based on this rule: Given an object `T`, it is only //! possible to have one of the following: @@ -43,8 +43,10 @@ //! usually have their pointer shared with the "outside world very early in //! their lifetime", for example when they create their //! [`MemoryRegion`s](crate::bindings::MemoryRegion). Therefore, individual -//! parts of a device must be made mutable in a controlled manner through the -//! use of cell types. +//! parts of a device must be made mutable in a controlled manner; this module +//! provides the tools to do so. +//! +//! ## Cell types //! //! [`BqlCell<T>`] and [`BqlRefCell<T>`] allow doing this via the Big QEMU Lock. //! While they are essentially the same single-threaded primitives that are @@ -71,7 +73,35 @@ //! QEMU device implementations is usually incorrect and can lead to //! thread-safety issues. //! -//! ## `BqlCell<T>` +//! ### Example +//! +//! ``` +//! # use qemu_api::prelude::*; +//! # use qemu_api::{c_str, cell::BqlRefCell, irq::InterruptSource, irq::IRQState}; +//! # use qemu_api::{sysbus::SysBusDevice, qom::Owned, qom::ParentField}; +//! # const N_GPIOS: usize = 8; +//! # struct PL061Registers { /* ... */ } +//! # unsafe impl ObjectType for PL061State { +//! # type Class = <SysBusDevice as ObjectType>::Class; +//! # const TYPE_NAME: &'static std::ffi::CStr = c_str!("pl061"); +//! # } +//! struct PL061State { +//! parent_obj: ParentField<SysBusDevice>, +//! +//! // Configuration is read-only after initialization +//! pullups: u32, +//! pulldowns: u32, +//! +//! // Single values shared with C code use BqlCell, in this case via InterruptSource +//! out: [InterruptSource; N_GPIOS], +//! interrupt: InterruptSource, +//! +//! // Larger state accessed by device methods uses BqlRefCell or Mutex +//! registers: BqlRefCell<PL061Registers>, +//! } +//! ``` +//! +//! ### `BqlCell<T>` //! //! [`BqlCell<T>`] implements interior mutability by moving values in and out of //! the cell. That is, an `&mut T` to the inner value can never be obtained as @@ -91,7 +121,7 @@ //! - [`set`](BqlCell::set): this method replaces the interior value, //! dropping the replaced value. //! -//! ## `BqlRefCell<T>` +//! ### `BqlRefCell<T>` //! //! [`BqlRefCell<T>`] uses Rust's lifetimes to implement "dynamic borrowing", a //! process whereby one can claim temporary, exclusive, mutable access to the @@ -111,13 +141,82 @@ //! Multiple immutable borrows are allowed via [`borrow`](BqlRefCell::borrow), //! or a single mutable borrow via [`borrow_mut`](BqlRefCell::borrow_mut). The //! thread will panic if these rules are violated or if the BQL is not held. +//! +//! ## Opaque wrappers +//! +//! The cell types from the previous section are useful at the boundaries +//! of code that requires interior mutability. When writing glue code that +//! interacts directly with C structs, however, it is useful to operate +//! at a lower level. +//! +//! C functions often violate Rust's fundamental assumptions about memory +//! safety by modifying memory even if it is shared. Furthermore, C structs +//! often start their life uninitialized and may be populated lazily. +//! +//! For this reason, this module provides the [`Opaque<T>`] type to opt out +//! of Rust's usual guarantees about the wrapped type. Access to the wrapped +//! value is always through raw pointers, obtained via methods like +//! [`as_mut_ptr()`](Opaque::as_mut_ptr) and [`as_ptr()`](Opaque::as_ptr). These +//! pointers can then be passed to C functions or dereferenced; both actions +//! require `unsafe` blocks, making it clear where safety guarantees must be +//! manually verified. For example +//! +//! ```ignore +//! unsafe { +//! let state = Opaque::<MyStruct>::uninit(); +//! qemu_struct_init(state.as_mut_ptr()); +//! } +//! ``` +//! +//! [`Opaque<T>`] will usually be wrapped one level further, so that +//! bridge methods can be added to the wrapper: +//! +//! ```ignore +//! pub struct MyStruct(Opaque<bindings::MyStruct>); +//! +//! impl MyStruct { +//! fn new() -> Pin<Box<MyStruct>> { +//! let result = Box::pin(unsafe { Opaque::uninit() }); +//! unsafe { qemu_struct_init(result.as_mut_ptr()) }; +//! result +//! } +//! } +//! ``` +//! +//! This pattern of wrapping bindgen-generated types in [`Opaque<T>`] provides +//! several advantages: +//! +//! * The choice of traits to be implemented is not limited by the +//! bindgen-generated code. For example, [`Drop`] can be added without +//! disabling [`Copy`] on the underlying bindgen type +//! +//! * [`Send`] and [`Sync`] implementations can be controlled by the wrapper +//! type rather than being automatically derived from the C struct's layout +//! +//! * Methods can be implemented in a separate crate from the bindgen-generated +//! bindings +//! +//! * [`Debug`](std::fmt::Debug) and [`Display`](std::fmt::Display) +//! implementations can be customized to be more readable than the raw C +//! struct representation +//! +//! The [`Opaque<T>`] type does not include BQL validation; it is possible to +//! assert in the code that the right lock is taken, to use it together +//! with a custom lock guard type, or to let C code take the lock, as +//! appropriate. It is also possible to use it with non-thread-safe +//! types, since by default (unlike [`BqlCell`] and [`BqlRefCell`] +//! it is neither `Sync` nor `Send`. +//! +//! While [`Opaque<T>`] is necessary for C interop, it should be used sparingly +//! and only at FFI boundaries. For QEMU-specific types that need interior +//! mutability, prefer [`BqlCell`] or [`BqlRefCell`]. use std::{ cell::{Cell, UnsafeCell}, cmp::Ordering, fmt, - marker::PhantomData, - mem, + marker::{PhantomData, PhantomPinned}, + mem::{self, MaybeUninit}, ops::{Deref, DerefMut}, ptr::NonNull, }; @@ -840,3 +939,167 @@ impl<T: fmt::Display> fmt::Display for BqlRefMut<'_, T> { (**self).fmt(f) } } + +/// Stores an opaque value that is shared with C code. +/// +/// Often, C structs can changed when calling a C function even if they are +/// behind a shared Rust reference, or they can be initialized lazily and have +/// invalid bit patterns (e.g. `3` for a [`bool`]). This goes against Rust's +/// strict aliasing rules, which normally prevent mutation through shared +/// references. +/// +/// Wrapping the struct with `Opaque<T>` ensures that the Rust compiler does not +/// assume the usual constraints that Rust structs require, and allows using +/// shared references on the Rust side. +/// +/// `Opaque<T>` is `#[repr(transparent)]`, so that it matches the memory layout +/// of `T`. +#[repr(transparent)] +pub struct Opaque<T> { + value: UnsafeCell<MaybeUninit<T>>, + // PhantomPinned also allows multiple references to the `Opaque<T>`, i.e. + // one `&mut Opaque<T>` can coexist with a `&mut T` or any number of `&T`; + // see https://docs.rs/pinned-aliasable/latest/pinned_aliasable/. + _pin: PhantomPinned, +} + +impl<T> Opaque<T> { + /// Creates a new shared reference from a C pointer + /// + /// # Safety + /// + /// The pointer must be valid, though it need not point to a valid value. + pub unsafe fn from_raw<'a>(ptr: *mut T) -> &'a Self { + let ptr = NonNull::new(ptr).unwrap().cast::<Self>(); + // SAFETY: Self is a transparent wrapper over T + unsafe { ptr.as_ref() } + } + + /// Creates a new opaque object with uninitialized contents. + /// + /// # Safety + /// + /// Ultimately the pointer to the returned value will be dereferenced + /// in another `unsafe` block, for example when passing it to a C function, + /// but the functions containing the dereference are usually safe. The + /// value returned from `uninit()` must be initialized and pinned before + /// calling them. + #[allow(clippy::missing_const_for_fn)] + pub unsafe fn uninit() -> Self { + Self { + value: UnsafeCell::new(MaybeUninit::uninit()), + _pin: PhantomPinned, + } + } + + /// Creates a new opaque object with zeroed contents. + /// + /// # Safety + /// + /// Ultimately the pointer to the returned value will be dereferenced + /// in another `unsafe` block, for example when passing it to a C function, + /// but the functions containing the dereference are usually safe. The + /// value returned from `uninit()` must be pinned (and possibly initialized) + /// before calling them. + #[allow(clippy::missing_const_for_fn)] + pub unsafe fn zeroed() -> Self { + Self { + value: UnsafeCell::new(MaybeUninit::zeroed()), + _pin: PhantomPinned, + } + } + + /// Returns a raw mutable pointer to the opaque data. + pub const fn as_mut_ptr(&self) -> *mut T { + UnsafeCell::get(&self.value).cast() + } + + /// Returns a raw pointer to the opaque data. + pub const fn as_ptr(&self) -> *const T { + self.as_mut_ptr() as *const _ + } + + /// Returns a raw pointer to the opaque data that can be passed to a + /// C function as `void *`. + pub const fn as_void_ptr(&self) -> *mut std::ffi::c_void { + UnsafeCell::get(&self.value).cast() + } + + /// Converts a raw pointer to the wrapped type. + pub const fn raw_get(slot: *mut Self) -> *mut T { + // Compare with Linux's raw_get method, which goes through an UnsafeCell + // because it takes a *const Self instead. + slot.cast() + } +} + +impl<T> fmt::Debug for Opaque<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut name: String = "Opaque<".to_string(); + name += std::any::type_name::<T>(); + name += ">"; + f.debug_tuple(&name).field(&self.as_ptr()).finish() + } +} + +impl<T: Default> Opaque<T> { + /// Creates a new opaque object with default contents. + /// + /// # Safety + /// + /// Ultimately the pointer to the returned value will be dereferenced + /// in another `unsafe` block, for example when passing it to a C function, + /// but the functions containing the dereference are usually safe. The + /// value returned from `uninit()` must be pinned before calling them. + pub unsafe fn new() -> Self { + Self { + value: UnsafeCell::new(MaybeUninit::new(T::default())), + _pin: PhantomPinned, + } + } +} + +/// Annotates [`Self`] as a transparent wrapper for another type. +/// +/// Usually defined via the [`qemu_api_macros::Wrapper`] derive macro. +/// +/// # Examples +/// +/// ``` +/// # use std::mem::ManuallyDrop; +/// # use qemu_api::cell::Wrapper; +/// #[repr(transparent)] +/// pub struct Example { +/// inner: ManuallyDrop<String>, +/// } +/// +/// unsafe impl Wrapper for Example { +/// type Wrapped = String; +/// } +/// ``` +/// +/// # Safety +/// +/// `Self` must be a `#[repr(transparent)]` wrapper for the `Wrapped` type, +/// whether directly or indirectly. +/// +/// # Methods +/// +/// By convention, types that implement Wrapper also implement the following +/// methods: +/// +/// ```ignore +/// pub const unsafe fn from_raw<'a>(value: *mut Self::Wrapped) -> &'a Self; +/// pub const unsafe fn as_mut_ptr(&self) -> *mut Self::Wrapped; +/// pub const unsafe fn as_ptr(&self) -> *const Self::Wrapped; +/// pub const unsafe fn raw_get(slot: *mut Self) -> *const Self::Wrapped; +/// ``` +/// +/// They are not defined here to allow them to be `const`. +pub unsafe trait Wrapper { + type Wrapped; +} + +unsafe impl<T> Wrapper for Opaque<T> { + type Wrapped = T; +} diff --git a/rust/qemu-api/src/chardev.rs b/rust/qemu-api/src/chardev.rs index 74cfb63..11e6c45 100644 --- a/rust/qemu-api/src/chardev.rs +++ b/rust/qemu-api/src/chardev.rs @@ -3,13 +3,255 @@ // SPDX-License-Identifier: GPL-2.0-or-later //! Bindings for character devices +//! +//! Character devices in QEMU can run under the big QEMU lock or in a separate +//! `GMainContext`. Here we only support the former, because the bindings +//! enforce that the BQL is taken whenever the functions in [`CharBackend`] are +//! called. -use std::ffi::CStr; +use std::{ + ffi::CStr, + fmt::{self, Debug}, + io::{self, ErrorKind, Write}, + marker::PhantomPinned, + os::raw::{c_int, c_void}, + ptr::addr_of_mut, + slice, +}; -use crate::{bindings, prelude::*}; +use crate::{ + bindings, + callbacks::FnCall, + cell::{BqlRefMut, Opaque}, + prelude::*, +}; + +/// A safe wrapper around [`bindings::Chardev`]. +#[repr(transparent)] +#[derive(qemu_api_macros::Wrapper)] +pub struct Chardev(Opaque<bindings::Chardev>); -pub type Chardev = bindings::Chardev; pub type ChardevClass = bindings::ChardevClass; +pub type Event = bindings::QEMUChrEvent; + +/// A safe wrapper around [`bindings::CharBackend`], denoting the character +/// back-end that is used for example by a device. Compared to the +/// underlying C struct it adds BQL protection, and is marked as pinned +/// because the QOM object ([`bindings::Chardev`]) contains a pointer to +/// the `CharBackend`. +pub struct CharBackend { + inner: BqlRefCell<bindings::CharBackend>, + _pin: PhantomPinned, +} + +impl Write for BqlRefMut<'_, bindings::CharBackend> { + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + let chr: &mut bindings::CharBackend = self; + + let len = buf.len().try_into().unwrap(); + let r = unsafe { bindings::qemu_chr_fe_write(addr_of_mut!(*chr), buf.as_ptr(), len) }; + errno::into_io_result(r).map(|cnt| cnt as usize) + } + + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + let chr: &mut bindings::CharBackend = self; + + let len = buf.len().try_into().unwrap(); + let r = unsafe { bindings::qemu_chr_fe_write_all(addr_of_mut!(*chr), buf.as_ptr(), len) }; + errno::into_io_result(r).and_then(|cnt| { + if cnt as usize == buf.len() { + Ok(()) + } else { + Err(ErrorKind::WriteZero.into()) + } + }) + } +} + +impl Debug for CharBackend { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // SAFETY: accessed just to print the values + let chr = self.inner.as_ptr(); + Debug::fmt(unsafe { &*chr }, f) + } +} + +// FIXME: use something like PinnedDrop from the pinned_init crate +impl Drop for CharBackend { + fn drop(&mut self) { + self.disable_handlers(); + } +} + +impl CharBackend { + /// Enable the front-end's character device handlers, if there is an + /// associated `Chardev`. + pub fn enable_handlers< + 'chardev, + 'owner: 'chardev, + T, + CanReceiveFn: for<'a> FnCall<(&'a T,), u32>, + ReceiveFn: for<'a, 'b> FnCall<(&'a T, &'b [u8])>, + EventFn: for<'a> FnCall<(&'a T, Event)>, + >( + // When "self" is dropped, the handlers are automatically disabled. + // However, this is not necessarily true if the owner is dropped. + // So require the owner to outlive the character device. + &'chardev self, + owner: &'owner T, + _can_receive: CanReceiveFn, + _receive: ReceiveFn, + _event: EventFn, + ) { + unsafe extern "C" fn rust_can_receive_cb<T, F: for<'a> FnCall<(&'a T,), u32>>( + opaque: *mut c_void, + ) -> c_int { + // SAFETY: the values are safe according to the contract of + // enable_handlers() and qemu_chr_fe_set_handlers() + let owner: &T = unsafe { &*(opaque.cast::<T>()) }; + let r = F::call((owner,)); + r.try_into().unwrap() + } + + unsafe extern "C" fn rust_receive_cb<T, F: for<'a, 'b> FnCall<(&'a T, &'b [u8])>>( + opaque: *mut c_void, + buf: *const u8, + size: c_int, + ) { + // SAFETY: the values are safe according to the contract of + // enable_handlers() and qemu_chr_fe_set_handlers() + let owner: &T = unsafe { &*(opaque.cast::<T>()) }; + let buf = unsafe { slice::from_raw_parts(buf, size.try_into().unwrap()) }; + F::call((owner, buf)) + } + + unsafe extern "C" fn rust_event_cb<T, F: for<'a> FnCall<(&'a T, Event)>>( + opaque: *mut c_void, + event: Event, + ) { + // SAFETY: the values are safe according to the contract of + // enable_handlers() and qemu_chr_fe_set_handlers() + let owner: &T = unsafe { &*(opaque.cast::<T>()) }; + F::call((owner, event)) + } + + let _: () = CanReceiveFn::ASSERT_IS_SOME; + let receive_cb: Option<unsafe extern "C" fn(*mut c_void, *const u8, c_int)> = + if ReceiveFn::is_some() { + Some(rust_receive_cb::<T, ReceiveFn>) + } else { + None + }; + let event_cb: Option<unsafe extern "C" fn(*mut c_void, Event)> = if EventFn::is_some() { + Some(rust_event_cb::<T, EventFn>) + } else { + None + }; + + let mut chr = self.inner.borrow_mut(); + // SAFETY: the borrow promises that the BQL is taken + unsafe { + bindings::qemu_chr_fe_set_handlers( + addr_of_mut!(*chr), + Some(rust_can_receive_cb::<T, CanReceiveFn>), + receive_cb, + event_cb, + None, + (owner as *const T as *mut T).cast::<c_void>(), + core::ptr::null_mut(), + true, + ); + } + } + + /// Disable the front-end's character device handlers. + pub fn disable_handlers(&self) { + let mut chr = self.inner.borrow_mut(); + // SAFETY: the borrow promises that the BQL is taken + unsafe { + bindings::qemu_chr_fe_set_handlers( + addr_of_mut!(*chr), + None, + None, + None, + None, + core::ptr::null_mut(), + core::ptr::null_mut(), + true, + ); + } + } + + /// Notify that the frontend is ready to receive data. + pub fn accept_input(&self) { + let mut chr = self.inner.borrow_mut(); + // SAFETY: the borrow promises that the BQL is taken + unsafe { bindings::qemu_chr_fe_accept_input(addr_of_mut!(*chr)) } + } + + /// Temporarily borrow the character device, allowing it to be used + /// as an implementor of `Write`. Note that it is not valid to drop + /// the big QEMU lock while the character device is borrowed, as + /// that might cause C code to write to the character device. + pub fn borrow_mut(&self) -> impl Write + '_ { + self.inner.borrow_mut() + } + + /// Send a continuous stream of zero bits on the line if `enabled` is + /// true, or a short stream if `enabled` is false. + pub fn send_break(&self, long: bool) -> io::Result<()> { + let mut chr = self.inner.borrow_mut(); + let mut duration: c_int = long.into(); + // SAFETY: the borrow promises that the BQL is taken + let r = unsafe { + bindings::qemu_chr_fe_ioctl( + addr_of_mut!(*chr), + bindings::CHR_IOCTL_SERIAL_SET_BREAK as i32, + addr_of_mut!(duration).cast::<c_void>(), + ) + }; + + errno::into_io_result(r).map(|_| ()) + } + + /// Write data to a character backend from the front end. This function + /// will send data from the front end to the back end. Unlike + /// `write`, this function will block if the back end cannot + /// consume all of the data attempted to be written. + /// + /// Returns the number of bytes consumed (0 if no associated Chardev) or an + /// error. + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { + let len = buf.len().try_into().unwrap(); + // SAFETY: qemu_chr_fe_write is thread-safe + let r = unsafe { bindings::qemu_chr_fe_write(self.inner.as_ptr(), buf.as_ptr(), len) }; + errno::into_io_result(r).map(|cnt| cnt as usize) + } + + /// Write data to a character backend from the front end. This function + /// will send data from the front end to the back end. Unlike + /// `write`, this function will block if the back end cannot + /// consume all of the data attempted to be written. + /// + /// Returns the number of bytes consumed (0 if no associated Chardev) or an + /// error. + pub fn write_all(&self, buf: &[u8]) -> io::Result<()> { + let len = buf.len().try_into().unwrap(); + // SAFETY: qemu_chr_fe_write_all is thread-safe + let r = unsafe { bindings::qemu_chr_fe_write_all(self.inner.as_ptr(), buf.as_ptr(), len) }; + errno::into_io_result(r).and_then(|cnt| { + if cnt as usize == buf.len() { + Ok(()) + } else { + Err(ErrorKind::WriteZero.into()) + } + }) + } +} unsafe impl ObjectType for Chardev { type Class = ChardevClass; diff --git a/rust/qemu-api/src/irq.rs b/rust/qemu-api/src/irq.rs index 34c1926..1222d4f 100644 --- a/rust/qemu-api/src/irq.rs +++ b/rust/qemu-api/src/irq.rs @@ -8,10 +8,16 @@ use std::{ffi::CStr, marker::PhantomData, os::raw::c_int, ptr}; use crate::{ bindings::{self, qemu_set_irq}, + cell::Opaque, prelude::*, qom::ObjectClass, }; +/// An opaque wrapper around [`bindings::IRQState`]. +#[repr(transparent)] +#[derive(Debug, qemu_api_macros::Wrapper)] +pub struct IRQState(Opaque<bindings::IRQState>); + /// Interrupt sources are used by devices to pass changes to a value (typically /// a boolean). The interrupt sink is usually an interrupt controller or /// GPIO controller. @@ -21,8 +27,7 @@ use crate::{ /// method sends a `true` value to the sink. If the guest has to see a /// different polarity, that change is performed by the board between the /// device and the interrupt controller. -pub type IRQState = bindings::IRQState; - +/// /// Interrupts are implemented as a pointer to the interrupt "sink", which has /// type [`IRQState`]. A device exposes its source as a QOM link property using /// a function such as [`SysBusDeviceMethods::init_irq`], and @@ -40,7 +45,7 @@ pub struct InterruptSource<T = bool> where c_int: From<T>, { - cell: BqlCell<*mut IRQState>, + cell: BqlCell<*mut bindings::IRQState>, _marker: PhantomData<T>, } @@ -79,11 +84,11 @@ where } } - pub(crate) const fn as_ptr(&self) -> *mut *mut IRQState { + pub(crate) const fn as_ptr(&self) -> *mut *mut bindings::IRQState { self.cell.as_ptr() } - pub(crate) const fn slice_as_ptr(slice: &[Self]) -> *mut *mut IRQState { + pub(crate) const fn slice_as_ptr(slice: &[Self]) -> *mut *mut bindings::IRQState { assert!(!slice.is_empty()); slice[0].as_ptr() } diff --git a/rust/qemu-api/src/memory.rs b/rust/qemu-api/src/memory.rs index 682951a..fdb1ea1 100644 --- a/rust/qemu-api/src/memory.rs +++ b/rust/qemu-api/src/memory.rs @@ -6,9 +6,8 @@ use std::{ ffi::{CStr, CString}, - marker::{PhantomData, PhantomPinned}, + marker::PhantomData, os::raw::{c_uint, c_void}, - ptr::addr_of, }; pub use bindings::{hwaddr, MemTxAttrs}; @@ -16,6 +15,7 @@ pub use bindings::{hwaddr, MemTxAttrs}; use crate::{ bindings::{self, device_endian, memory_region_init_io}, callbacks::FnCall, + cell::Opaque, prelude::*, zeroable::Zeroable, }; @@ -132,13 +132,13 @@ impl<T> Default for MemoryRegionOpsBuilder<T> { } } -/// A safe wrapper around [`bindings::MemoryRegion`]. Compared to the -/// underlying C struct it is marked as pinned because the QOM tree -/// contains a pointer to it. -pub struct MemoryRegion { - inner: bindings::MemoryRegion, - _pin: PhantomPinned, -} +/// A safe wrapper around [`bindings::MemoryRegion`]. +#[repr(transparent)] +#[derive(qemu_api_macros::Wrapper)] +pub struct MemoryRegion(Opaque<bindings::MemoryRegion>); + +unsafe impl Send for MemoryRegion {} +unsafe impl Sync for MemoryRegion {} impl MemoryRegion { // inline to ensure that it is not included in tests, which only @@ -157,7 +157,7 @@ impl MemoryRegion { let cstr = CString::new(name).unwrap(); memory_region_init_io( slot, - owner.cast::<Object>(), + owner.cast::<bindings::Object>(), ops, owner.cast::<c_void>(), cstr.as_ptr(), @@ -174,13 +174,15 @@ impl MemoryRegion { size: u64, ) { unsafe { - Self::do_init_io(&mut self.inner, owner.cast::<Object>(), &ops.0, name, size); + Self::do_init_io( + self.0.as_mut_ptr(), + owner.cast::<Object>(), + &ops.0, + name, + size, + ); } } - - pub(crate) const fn as_mut_ptr(&self) -> *mut bindings::MemoryRegion { - addr_of!(self.inner) as *mut _ - } } unsafe impl ObjectType for MemoryRegion { diff --git a/rust/qemu-api/src/prelude.rs b/rust/qemu-api/src/prelude.rs index 634acf3..43bfcd5 100644 --- a/rust/qemu-api/src/prelude.rs +++ b/rust/qemu-api/src/prelude.rs @@ -17,7 +17,6 @@ pub use crate::qom::InterfaceType; pub use crate::qom::IsA; pub use crate::qom::Object; pub use crate::qom::ObjectCast; -pub use crate::qom::ObjectCastMut; pub use crate::qom::ObjectDeref; pub use crate::qom::ObjectClassMethods; pub use crate::qom::ObjectMethods; diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs index c136457..18b4a9b 100644 --- a/rust/qemu-api/src/qdev.rs +++ b/rust/qemu-api/src/qdev.rs @@ -10,12 +10,12 @@ use std::{ ptr::NonNull, }; -pub use bindings::{Clock, ClockEvent, DeviceClass, DeviceState, Property, ResetType}; +pub use bindings::{ClockEvent, DeviceClass, Property, ResetType}; use crate::{ bindings::{self, qdev_init_gpio_in, qdev_init_gpio_out, Error, ResettableClass}, callbacks::FnCall, - cell::bql_locked, + cell::{bql_locked, Opaque}, chardev::Chardev, irq::InterruptSource, prelude::*, @@ -23,6 +23,22 @@ use crate::{ vmstate::VMStateDescription, }; +/// A safe wrapper around [`bindings::Clock`]. +#[repr(transparent)] +#[derive(Debug, qemu_api_macros::Wrapper)] +pub struct Clock(Opaque<bindings::Clock>); + +unsafe impl Send for Clock {} +unsafe impl Sync for Clock {} + +/// A safe wrapper around [`bindings::DeviceState`]. +#[repr(transparent)] +#[derive(Debug, qemu_api_macros::Wrapper)] +pub struct DeviceState(Opaque<bindings::DeviceState>); + +unsafe impl Send for DeviceState {} +unsafe impl Sync for DeviceState {} + /// Trait providing the contents of the `ResettablePhases` struct, /// which is part of the QOM `Resettable` interface. pub trait ResettablePhasesImpl { @@ -52,7 +68,7 @@ pub trait ResettablePhasesImpl { /// can be downcasted to type `T`. We also expect the device is /// readable/writeable from one thread at any time. unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>( - obj: *mut Object, + obj: *mut bindings::Object, typ: ResetType, ) { let state = NonNull::new(obj).unwrap().cast::<T>(); @@ -65,7 +81,7 @@ unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>( /// can be downcasted to type `T`. We also expect the device is /// readable/writeable from one thread at any time. unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>( - obj: *mut Object, + obj: *mut bindings::Object, typ: ResetType, ) { let state = NonNull::new(obj).unwrap().cast::<T>(); @@ -78,7 +94,7 @@ unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>( /// can be downcasted to type `T`. We also expect the device is /// readable/writeable from one thread at any time. unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>( - obj: *mut Object, + obj: *mut bindings::Object, typ: ResetType, ) { let state = NonNull::new(obj).unwrap().cast::<T>(); @@ -117,7 +133,10 @@ pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl + IsA<DeviceState> { /// We expect the FFI user of this function to pass a valid pointer that /// can be downcasted to type `T`. We also expect the device is /// readable/writeable from one thread at any time. -unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>(dev: *mut DeviceState, _errp: *mut *mut Error) { +unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>( + dev: *mut bindings::DeviceState, + _errp: *mut *mut Error, +) { let state = NonNull::new(dev).unwrap().cast::<T>(); T::REALIZE.unwrap()(unsafe { state.as_ref() }); } @@ -251,7 +270,7 @@ where events: ClockEvent, ) -> Owned<Clock> { fn do_init_clock_in( - dev: *mut DeviceState, + dev: &DeviceState, name: &str, cb: Option<unsafe extern "C" fn(*mut c_void, ClockEvent)>, events: ClockEvent, @@ -265,14 +284,15 @@ where unsafe { let cstr = CString::new(name).unwrap(); let clk = bindings::qdev_init_clock_in( - dev, + dev.as_mut_ptr(), cstr.as_ptr(), cb, - dev.cast::<c_void>(), + dev.as_void_ptr(), events.0, ); - Owned::from(&*clk) + let clk: &Clock = Clock::from_raw(clk); + Owned::from(clk) } } @@ -289,7 +309,7 @@ where None }; - do_init_clock_in(self.as_mut_ptr(), name, cb, events) + do_init_clock_in(self.upcast(), name, cb, events) } /// Add an output clock named `name`. @@ -304,17 +324,23 @@ where fn init_clock_out(&self, name: &str) -> Owned<Clock> { unsafe { let cstr = CString::new(name).unwrap(); - let clk = bindings::qdev_init_clock_out(self.as_mut_ptr(), cstr.as_ptr()); + let clk = bindings::qdev_init_clock_out(self.upcast().as_mut_ptr(), cstr.as_ptr()); - Owned::from(&*clk) + let clk: &Clock = Clock::from_raw(clk); + Owned::from(clk) } } fn prop_set_chr(&self, propname: &str, chr: &Owned<Chardev>) { assert!(bql_locked()); let c_propname = CString::new(propname).unwrap(); + let chr: &Chardev = chr; unsafe { - bindings::qdev_prop_set_chr(self.as_mut_ptr(), c_propname.as_ptr(), chr.as_mut_ptr()); + bindings::qdev_prop_set_chr( + self.upcast().as_mut_ptr(), + c_propname.as_ptr(), + chr.as_mut_ptr(), + ); } } @@ -323,8 +349,17 @@ where num_lines: u32, _cb: F, ) { - let _: () = F::ASSERT_IS_SOME; + fn do_init_gpio_in( + dev: &DeviceState, + num_lines: u32, + gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int), + ) { + unsafe { + qdev_init_gpio_in(dev.as_mut_ptr(), Some(gpio_in_cb), num_lines as c_int); + } + } + let _: () = F::ASSERT_IS_SOME; unsafe extern "C" fn rust_irq_handler<T, F: for<'a> FnCall<(&'a T, u32, u32)>>( opaque: *mut c_void, line: c_int, @@ -337,19 +372,13 @@ where let gpio_in_cb: unsafe extern "C" fn(*mut c_void, c_int, c_int) = rust_irq_handler::<Self::Target, F>; - unsafe { - qdev_init_gpio_in( - self.as_mut_ptr::<DeviceState>(), - Some(gpio_in_cb), - num_lines as c_int, - ); - } + do_init_gpio_in(self.upcast(), num_lines, gpio_in_cb); } fn init_gpio_out(&self, pins: &[InterruptSource]) { unsafe { qdev_init_gpio_out( - self.as_mut_ptr::<DeviceState>(), + self.upcast().as_mut_ptr(), InterruptSource::slice_as_ptr(pins), pins.len() as c_int, ); diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index 5488643..34d7bc0 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -101,16 +101,24 @@ use std::{ ptr::NonNull, }; -pub use bindings::{Object, ObjectClass}; +pub use bindings::ObjectClass; use crate::{ bindings::{ self, object_class_dynamic_cast, object_dynamic_cast, object_get_class, object_get_typename, object_new, object_ref, object_unref, TypeInfo, }, - cell::bql_locked, + cell::{bql_locked, Opaque}, }; +/// A safe wrapper around [`bindings::Object`]. +#[repr(transparent)] +#[derive(Debug, qemu_api_macros::Wrapper)] +pub struct Object(Opaque<bindings::Object>); + +unsafe impl Send for Object {} +unsafe impl Sync for Object {} + /// Marker trait: `Self` can be statically upcasted to `P` (i.e. `P` is a direct /// or indirect parent of `Self`). /// @@ -199,7 +207,7 @@ impl<T: fmt::Display + ObjectType> fmt::Display for ParentField<T> { } } -unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) { +unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut bindings::Object) { let mut state = NonNull::new(obj).unwrap().cast::<T>(); // SAFETY: obj is an instance of T, since rust_instance_init<T> // is called from QOM core as the instance_init function @@ -209,7 +217,7 @@ unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) { } } -unsafe extern "C" fn rust_instance_post_init<T: ObjectImpl>(obj: *mut Object) { +unsafe extern "C" fn rust_instance_post_init<T: ObjectImpl>(obj: *mut bindings::Object) { let state = NonNull::new(obj).unwrap().cast::<T>(); // SAFETY: obj is an instance of T, since rust_instance_post_init<T> // is called from QOM core as the instance_post_init function @@ -230,7 +238,7 @@ unsafe extern "C" fn rust_class_init<T: ObjectType + ObjectImpl>( <T as ObjectImpl>::CLASS_INIT(unsafe { klass.as_mut() }) } -unsafe extern "C" fn drop_object<T: ObjectImpl>(obj: *mut Object) { +unsafe extern "C" fn drop_object<T: ObjectImpl>(obj: *mut bindings::Object) { // SAFETY: obj is an instance of T, since drop_object<T> is called // from the QOM core function object_deinit() as the instance_finalize // function for class T. Note that while object_deinit() will drop the @@ -280,14 +288,14 @@ pub unsafe trait ObjectType: Sized { /// Return the receiver as an Object. This is always safe, even /// if this type represents an interface. fn as_object(&self) -> &Object { - unsafe { &*self.as_object_ptr() } + unsafe { &*self.as_ptr().cast() } } /// Return the receiver as a const raw pointer to Object. /// This is preferrable to `as_object_mut_ptr()` if a C /// function only needs a `const Object *`. - fn as_object_ptr(&self) -> *const Object { - self.as_ptr().cast() + fn as_object_ptr(&self) -> *const bindings::Object { + self.as_object().as_ptr() } /// Return the receiver as a mutable raw pointer to Object. @@ -297,8 +305,8 @@ pub unsafe trait ObjectType: Sized { /// This cast is always safe, but because the result is mutable /// and the incoming reference is not, this should only be used /// for calls to C functions, and only if needed. - unsafe fn as_object_mut_ptr(&self) -> *mut Object { - self.as_object_ptr() as *mut _ + unsafe fn as_object_mut_ptr(&self) -> *mut bindings::Object { + self.as_object().as_mut_ptr() } } @@ -455,90 +463,7 @@ where impl<T: ObjectType> ObjectDeref for &T {} impl<T: ObjectType> ObjectCast for &T {} -/// Trait for mutable type casting operations in the QOM hierarchy. -/// -/// This trait provides the mutable counterparts to [`ObjectCast`]'s conversion -/// functions. Unlike `ObjectCast`, this trait returns `Result` for fallible -/// conversions to preserve the original smart pointer if the cast fails. This -/// is necessary because mutable references cannot be copied, so a failed cast -/// must return ownership of the original reference. For example: -/// -/// ```ignore -/// let mut dev = get_device(); -/// // If this fails, we need the original `dev` back to try something else -/// match dev.dynamic_cast_mut::<FooDevice>() { -/// Ok(foodev) => /* use foodev */, -/// Err(dev) => /* still have ownership of dev */ -/// } -/// ``` -pub trait ObjectCastMut: Sized + ObjectDeref + DerefMut -where - Self::Target: ObjectType, -{ - /// Safely convert from a derived type to one of its parent types. - /// - /// This is always safe; the [`IsA`] trait provides static verification - /// that `Self` dereferences to `U` or a child of `U`. - fn upcast_mut<'a, U: ObjectType>(self) -> &'a mut U - where - Self::Target: IsA<U>, - Self: 'a, - { - // SAFETY: soundness is declared via IsA<U>, which is an unsafe trait - unsafe { self.unsafe_cast_mut::<U>() } - } - - /// Attempt to convert to a derived type. - /// - /// Returns `Ok(..)` if the object is of type `U`, or `Err(self)` if the - /// object if the conversion failed. This is verified at runtime by - /// checking the object's type information. - fn downcast_mut<'a, U: IsA<Self::Target>>(self) -> Result<&'a mut U, Self> - where - Self: 'a, - { - self.dynamic_cast_mut::<U>() - } - - /// Attempt to convert between any two types in the QOM hierarchy. - /// - /// Returns `Ok(..)` if the object is of type `U`, or `Err(self)` if the - /// object if the conversion failed. This is verified at runtime by - /// checking the object's type information. - fn dynamic_cast_mut<'a, U: ObjectType>(self) -> Result<&'a mut U, Self> - where - Self: 'a, - { - unsafe { - // SAFETY: upcasting to Object is always valid, and the - // return type is either NULL or the argument itself - let result: *mut U = - object_dynamic_cast(self.as_object_mut_ptr(), U::TYPE_NAME.as_ptr()).cast(); - - result.as_mut().ok_or(self) - } - } - - /// Convert to any QOM type without verification. - /// - /// # Safety - /// - /// What safety? You need to know yourself that the cast is correct; only - /// use when performance is paramount. It is still better than a raw - /// pointer `cast()`, which does not even check that you remain in the - /// realm of QOM `ObjectType`s. - /// - /// `unsafe_cast::<Object>()` is always safe. - unsafe fn unsafe_cast_mut<'a, U: ObjectType>(self) -> &'a mut U - where - Self: 'a, - { - unsafe { &mut *self.as_mut_ptr::<Self::Target>().cast::<U>() } - } -} - impl<T: ObjectType> ObjectDeref for &mut T {} -impl<T: ObjectType> ObjectCastMut for &mut T {} /// Trait a type must implement to be registered with QEMU. pub trait ObjectImpl: ObjectType + IsA<Object> { @@ -621,7 +546,7 @@ pub trait ObjectImpl: ObjectType + IsA<Object> { /// We expect the FFI user of this function to pass a valid pointer that /// can be downcasted to type `T`. We also expect the device is /// readable/writeable from one thread at any time. -unsafe extern "C" fn rust_unparent_fn<T: ObjectImpl>(dev: *mut Object) { +unsafe extern "C" fn rust_unparent_fn<T: ObjectImpl>(dev: *mut bindings::Object) { let state = NonNull::new(dev).unwrap().cast::<T>(); T::UNPARENT.unwrap()(unsafe { state.as_ref() }); } @@ -796,8 +721,9 @@ pub trait ObjectClassMethods: IsA<Object> { // SAFETY: the object created by object_new is allocated on // the heap and has a reference count of 1 unsafe { - let obj = &*object_new(Self::TYPE_NAME.as_ptr()); - Owned::from_raw(obj.unsafe_cast::<Self>()) + let raw_obj = object_new(Self::TYPE_NAME.as_ptr()); + let obj = Object::from_raw(raw_obj).unsafe_cast::<Self>(); + Owned::from_raw(obj) } } } diff --git a/rust/qemu-api/src/sysbus.rs b/rust/qemu-api/src/sysbus.rs index 04821a2..e92502a 100644 --- a/rust/qemu-api/src/sysbus.rs +++ b/rust/qemu-api/src/sysbus.rs @@ -6,11 +6,11 @@ use std::{ffi::CStr, ptr::addr_of_mut}; -pub use bindings::{SysBusDevice, SysBusDeviceClass}; +pub use bindings::SysBusDeviceClass; use crate::{ bindings, - cell::bql_locked, + cell::{bql_locked, Opaque}, irq::{IRQState, InterruptSource}, memory::MemoryRegion, prelude::*, @@ -18,6 +18,14 @@ use crate::{ qom::Owned, }; +/// A safe wrapper around [`bindings::SysBusDevice`]. +#[repr(transparent)] +#[derive(Debug, qemu_api_macros::Wrapper)] +pub struct SysBusDevice(Opaque<bindings::SysBusDevice>); + +unsafe impl Send for SysBusDevice {} +unsafe impl Sync for SysBusDevice {} + unsafe impl ObjectType for SysBusDevice { type Class = SysBusDeviceClass; const TYPE_NAME: &'static CStr = @@ -49,7 +57,7 @@ where fn init_mmio(&self, iomem: &MemoryRegion) { assert!(bql_locked()); unsafe { - bindings::sysbus_init_mmio(self.as_mut_ptr(), iomem.as_mut_ptr()); + bindings::sysbus_init_mmio(self.upcast().as_mut_ptr(), iomem.as_mut_ptr()); } } @@ -60,7 +68,21 @@ where fn init_irq(&self, irq: &InterruptSource) { assert!(bql_locked()); unsafe { - bindings::sysbus_init_irq(self.as_mut_ptr(), irq.as_ptr()); + bindings::sysbus_init_irq(self.upcast().as_mut_ptr(), irq.as_ptr()); + } + } + + // TODO: do we want a type like GuestAddress here? + fn mmio_addr(&self, id: u32) -> Option<u64> { + assert!(bql_locked()); + // SAFETY: the BQL ensures that no one else writes to sbd.mmio[], and + // the SysBusDevice must be initialized to get an IsA<SysBusDevice>. + let sbd = unsafe { *self.upcast().as_ptr() }; + let id: usize = id.try_into().unwrap(); + if sbd.mmio[id].memory.is_null() { + None + } else { + Some(sbd.mmio[id].addr) } } @@ -69,7 +91,7 @@ where assert!(bql_locked()); let id: i32 = id.try_into().unwrap(); unsafe { - bindings::sysbus_mmio_map(self.as_mut_ptr(), id, addr); + bindings::sysbus_mmio_map(self.upcast().as_mut_ptr(), id, addr); } } @@ -79,8 +101,9 @@ where fn connect_irq(&self, id: u32, irq: &Owned<IRQState>) { assert!(bql_locked()); let id: i32 = id.try_into().unwrap(); + let irq: &IRQState = irq; unsafe { - bindings::sysbus_connect_irq(self.as_mut_ptr(), id, irq.as_mut_ptr()); + bindings::sysbus_connect_irq(self.upcast().as_mut_ptr(), id, irq.as_mut_ptr()); } } @@ -88,7 +111,10 @@ where // TODO: return an Error assert!(bql_locked()); unsafe { - bindings::sysbus_realize(self.as_mut_ptr(), addr_of_mut!(bindings::error_fatal)); + bindings::sysbus_realize( + self.upcast().as_mut_ptr(), + addr_of_mut!(bindings::error_fatal), + ); } } } diff --git a/rust/qemu-api/src/timer.rs b/rust/qemu-api/src/timer.rs index a593538..f0b04ef 100644 --- a/rust/qemu-api/src/timer.rs +++ b/rust/qemu-api/src/timer.rs @@ -2,31 +2,51 @@ // Author(s): Zhao Liu <zhai1.liu@intel.com> // SPDX-License-Identifier: GPL-2.0-or-later -use std::os::raw::{c_int, c_void}; +use std::{ + os::raw::{c_int, c_void}, + pin::Pin, +}; use crate::{ bindings::{self, qemu_clock_get_ns, timer_del, timer_init_full, timer_mod, QEMUClockType}, callbacks::FnCall, + cell::Opaque, }; -pub type Timer = bindings::QEMUTimer; -pub type TimerListGroup = bindings::QEMUTimerListGroup; +/// A safe wrapper around [`bindings::QEMUTimer`]. +#[repr(transparent)] +#[derive(Debug, qemu_api_macros::Wrapper)] +pub struct Timer(Opaque<bindings::QEMUTimer>); + +unsafe impl Send for Timer {} +unsafe impl Sync for Timer {} + +#[repr(transparent)] +#[derive(qemu_api_macros::Wrapper)] +pub struct TimerListGroup(Opaque<bindings::QEMUTimerListGroup>); + +unsafe impl Send for TimerListGroup {} +unsafe impl Sync for TimerListGroup {} impl Timer { pub const MS: u32 = bindings::SCALE_MS; pub const US: u32 = bindings::SCALE_US; pub const NS: u32 = bindings::SCALE_NS; - pub fn new() -> Self { - Default::default() - } - - const fn as_mut_ptr(&self) -> *mut Self { - self as *const Timer as *mut _ + /// Create a `Timer` struct without initializing it. + /// + /// # Safety + /// + /// The timer must be initialized before it is armed with + /// [`modify`](Self::modify). + pub unsafe fn new() -> Self { + // SAFETY: requirements relayed to callers of Timer::new + Self(unsafe { Opaque::zeroed() }) } + /// Create a new timer with the given attributes. pub fn init_full<'timer, 'opaque: 'timer, T, F>( - &'timer mut self, + self: Pin<&'timer mut Self>, timer_list_group: Option<&TimerListGroup>, clk_type: ClockType, scale: u32, @@ -51,7 +71,7 @@ impl Timer { // SAFETY: the opaque outlives the timer unsafe { timer_init_full( - self, + self.as_mut_ptr(), if let Some(g) = timer_list_group { g as *const TimerListGroup as *mut _ } else { @@ -67,14 +87,19 @@ impl Timer { } pub fn modify(&self, expire_time: u64) { + // SAFETY: the only way to obtain a Timer safely is via methods that + // take a Pin<&mut Self>, therefore the timer is pinned unsafe { timer_mod(self.as_mut_ptr(), expire_time as i64) } } pub fn delete(&self) { + // SAFETY: the only way to obtain a Timer safely is via methods that + // take a Pin<&mut Self>, therefore the timer is pinned unsafe { timer_del(self.as_mut_ptr()) } } } +// FIXME: use something like PinnedDrop from the pinned_init crate impl Drop for Timer { fn drop(&mut self) { self.delete() diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs index 24a4dc8..f0510ae 100644 --- a/rust/qemu-api/src/vmstate.rs +++ b/rust/qemu-api/src/vmstate.rs @@ -330,6 +330,7 @@ macro_rules! impl_vmstate_transparent { impl_vmstate_transparent!(std::cell::Cell<T> where T: VMState); impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState); +impl_vmstate_transparent!(std::pin::Pin<T> where T: VMState); impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState); impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState); @@ -469,7 +470,7 @@ macro_rules! vmstate_clock { $crate::assert_field_type!( $struct_name, $field_name, - $crate::qom::Owned<$crate::bindings::Clock> + $crate::qom::Owned<$crate::qdev::Clock> ); $crate::offset_of!($struct_name, $field_name) }, diff --git a/rust/qemu-api/src/zeroable.rs b/rust/qemu-api/src/zeroable.rs index 47b6977..a3415a2 100644 --- a/rust/qemu-api/src/zeroable.rs +++ b/rust/qemu-api/src/zeroable.rs @@ -106,3 +106,4 @@ impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_1); impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_2); impl_zeroable!(crate::bindings::MemoryRegionOps); impl_zeroable!(crate::bindings::MemTxAttrs); +impl_zeroable!(crate::bindings::CharBackend); diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs index e398578..269122e 100644 --- a/rust/qemu-api/tests/tests.rs +++ b/rust/qemu-api/tests/tests.rs @@ -2,13 +2,10 @@ // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org> // SPDX-License-Identifier: GPL-2.0-or-later -use std::{ - ffi::{c_void, CStr}, - ptr::{addr_of, addr_of_mut}, -}; +use std::{ffi::CStr, ptr::addr_of}; use qemu_api::{ - bindings::{module_call_init, module_init_type, object_new, object_unref, qdev_prop_bool}, + bindings::{module_call_init, module_init_type, qdev_prop_bool}, c_str, cell::{self, BqlCell}, declare_properties, define_property, @@ -182,30 +179,3 @@ fn test_cast() { assert_eq!(addr_of!(*sbd_ref), p_ptr.cast()); } } - -#[test] -#[allow(clippy::shadow_unrelated)] -/// Test casts on mutable references. -fn test_cast_mut() { - init_qom(); - let p: *mut DummyState = unsafe { object_new(DummyState::TYPE_NAME.as_ptr()).cast() }; - - let p_ref: &mut DummyState = unsafe { &mut *p }; - let obj_ref: &mut Object = p_ref.upcast_mut(); - assert_eq!(addr_of_mut!(*obj_ref), p.cast()); - - let sbd_ref: Result<&mut SysBusDevice, &mut Object> = obj_ref.dynamic_cast_mut(); - let obj_ref = sbd_ref.unwrap_err(); - - let dev_ref: Result<&mut DeviceState, &mut Object> = obj_ref.downcast_mut(); - let dev_ref = dev_ref.unwrap(); - assert_eq!(addr_of_mut!(*dev_ref), p.cast()); - - // SAFETY: the cast is wrong, but the value is only used for comparison - unsafe { - let sbd_ref: &mut SysBusDevice = obj_ref.unsafe_cast_mut(); - assert_eq!(addr_of_mut!(*sbd_ref), p.cast()); - - object_unref(p_ref.as_object_mut_ptr().cast::<c_void>()); - } -} |