aboutsummaryrefslogtreecommitdiff
path: root/rust/qemu-api/src
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2025-01-17 10:12:52 -0500
committerStefan Hajnoczi <stefanha@redhat.com>2025-01-17 10:12:52 -0500
commit09360a048bd7a133e47cb8dea617d44540bdebbd (patch)
tree2b4868526830031398f0f8077c8bfc86854cf5c5 /rust/qemu-api/src
parent4d5d933bbc7cc52f6cc6b9021f91fa06266222d5 (diff)
parent99a637a86f55c8486b06c698656befdf012eec4d (diff)
downloadqemu-09360a048bd7a133e47cb8dea617d44540bdebbd.zip
qemu-09360a048bd7a133e47cb8dea617d44540bdebbd.tar.gz
qemu-09360a048bd7a133e47cb8dea617d44540bdebbd.tar.bz2
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* rust: miscellaneous changes * target/i386: small code generation improvements * target/i386: various cleanups and fixes * cpu: remove env->nr_cores # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmeBoIgUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroOD2gf+NK7U1EhNIrsbBsbtu2i7+tnbRKIB # MTu+Mxb2wz4C7//pxq+vva4bgT3iOuL9RF19PRe/63CMD65xMiwyyNrEWX2HbRIJ # 5dytLLLdef3yMhHh2x1uZfm54g12Ppvn9kulMCbPawrlqWgg1sZbkUBrRtFzS45c # NeYjGWWSpBDe7LtsrgSRYLPnz6wWEiy3tDpu2VoDtjrE86UVDXwyzpbtBk9Y8jPi # CKdvLyQeO9xDE5OoXMjJMlJeQq3D9iwYEprXUqy+RUZtpW7YmqMCf2JQ4dAjVCad # 07v/kITF4brGCVnzDcDA6W7LqHpBu1w+Hn23yLw3HEDDBt11o9JjQCl9qA== # =xIQ4 # -----END PGP SIGNATURE----- # gpg: Signature made Fri 10 Jan 2025 17:34:48 EST # 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: (38 commits) i386/cpu: Set and track CPUID_EXT3_CMP_LEG in env->features[FEAT_8000_0001_ECX] i386/cpu: Set up CPUID_HT in x86_cpu_expand_features() instead of cpu_x86_cpuid() cpu: Remove nr_cores from struct CPUState i386/cpu: Hoist check of CPUID_EXT3_TOPOEXT against threads_per_core i386/cpu: Track a X86CPUTopoInfo directly in CPUX86State i386/topology: Introduce helpers for various topology info of different level i386/topology: Update the comment of x86_apicid_from_topo_ids() i386/cpu: Drop cores_per_pkg in cpu_x86_cpuid() i386/cpu: Drop the variable smp_cores and smp_threads in x86_cpu_pre_plug() i386/cpu: Extract a common fucntion to setup value of MSR_CORE_THREAD_COUNT target/i386/kvm: Replace ARRAY_SIZE(msr_handlers) with KVM_MSR_FILTER_MAX_RANGES target/i386/kvm: Clean up error handling in kvm_arch_init() target/i386/kvm: Return -1 when kvm_msr_energy_thread_init() fails target/i386/kvm: Clean up return values of MSR filter related functions target/i386/confidential-guest: Fix comment of x86_confidential_guest_kvm_type() target/i386/kvm: Drop workaround for KVM_X86_DISABLE_EXITS_HTL typo target/i386/kvm: Only save/load kvmclock MSRs when kvmclock enabled target/i386/kvm: Remove local MSR_KVM_WALL_CLOCK and MSR_KVM_SYSTEM_TIME definitions target/i386/kvm: Add feature bit definitions for KVM CPUID i386/cpu: Mark avx10_version filtered when prefix is NULL ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'rust/qemu-api/src')
-rw-r--r--rust/qemu-api/src/assertions.rs90
-rw-r--r--rust/qemu-api/src/irq.rs3
-rw-r--r--rust/qemu-api/src/lib.rs1
-rw-r--r--rust/qemu-api/src/prelude.rs2
-rw-r--r--rust/qemu-api/src/qom.rs85
-rw-r--r--rust/qemu-api/src/sysbus.rs23
6 files changed, 183 insertions, 21 deletions
diff --git a/rust/qemu-api/src/assertions.rs b/rust/qemu-api/src/assertions.rs
new file mode 100644
index 0000000..6e42046
--- /dev/null
+++ b/rust/qemu-api/src/assertions.rs
@@ -0,0 +1,90 @@
+// Copyright 2024, Red Hat Inc.
+// Author(s): Paolo Bonzini <pbonzini@redhat.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//! This module provides macros to check the equality of types and
+//! the type of `struct` fields. This can be useful to ensure that
+//! types match the expectations of C code.
+
+// Based on https://stackoverflow.com/questions/64251852/x/70978292#70978292
+// (stackoverflow answers are released under MIT license).
+
+#[doc(hidden)]
+pub trait EqType {
+ type Itself;
+}
+
+impl<T> EqType for T {
+ type Itself = T;
+}
+
+/// Assert that two types are the same.
+///
+/// # Examples
+///
+/// ```
+/// # use qemu_api::assert_same_type;
+/// # use std::ops::Deref;
+/// assert_same_type!(u32, u32);
+/// assert_same_type!(<Box<u32> as Deref>::Target, u32);
+/// ```
+///
+/// Different types will cause a compile failure
+///
+/// ```compile_fail
+/// # use qemu_api::assert_same_type;
+/// assert_same_type!(&Box<u32>, &u32);
+/// ```
+#[macro_export]
+macro_rules! assert_same_type {
+ ($t1:ty, $t2:ty) => {
+ const _: () = {
+ #[allow(unused)]
+ fn assert_same_type(v: $t1) {
+ fn types_must_be_equal<T, U>(_: T)
+ where
+ T: $crate::assertions::EqType<Itself = U>,
+ {
+ }
+ types_must_be_equal::<_, $t2>(v);
+ }
+ };
+ };
+}
+
+/// Assert that a field of a struct has the given type.
+///
+/// # Examples
+///
+/// ```
+/// # use qemu_api::assert_field_type;
+/// pub struct A {
+/// field1: u32,
+/// }
+///
+/// assert_field_type!(A, field1, u32);
+/// ```
+///
+/// Different types will cause a compile failure
+///
+/// ```compile_fail
+/// # use qemu_api::assert_field_type;
+/// # pub struct A { field1: u32 }
+/// assert_field_type!(A, field1, i32);
+/// ```
+#[macro_export]
+macro_rules! assert_field_type {
+ ($t:ty, $i:tt, $ti:ty) => {
+ const _: () = {
+ #[allow(unused)]
+ fn assert_field_type(v: $t) {
+ fn types_must_be_equal<T, U>(_: T)
+ where
+ T: $crate::assertions::EqType<Itself = U>,
+ {
+ }
+ types_must_be_equal::<_, $ti>(v.$i);
+ }
+ };
+ };
+}
diff --git a/rust/qemu-api/src/irq.rs b/rust/qemu-api/src/irq.rs
index 6258141..378e520 100644
--- a/rust/qemu-api/src/irq.rs
+++ b/rust/qemu-api/src/irq.rs
@@ -24,8 +24,7 @@ use crate::{
///
/// 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
-/// [`SysBusDevice::init_irq`](crate::sysbus::SysBusDevice::init_irq), and
+/// a function such as [`SysBusDeviceMethods::init_irq`], and
/// initially leaves the pointer to a NULL value, representing an unconnected
/// interrupt. To connect it, whoever creates the device fills the pointer with
/// the sink's `IRQState *`, for example using `sysbus_connect_irq`. Because
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index 4b43e02..83c6a98 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -12,6 +12,7 @@ pub mod bindings;
#[rustfmt::skip]
pub mod prelude;
+pub mod assertions;
pub mod bitops;
pub mod c_str;
pub mod callbacks;
diff --git a/rust/qemu-api/src/prelude.rs b/rust/qemu-api/src/prelude.rs
index 6f32dee..4ea70b9 100644
--- a/rust/qemu-api/src/prelude.rs
+++ b/rust/qemu-api/src/prelude.rs
@@ -16,3 +16,5 @@ pub use crate::qom::ObjectMethods;
pub use crate::qom::ObjectType;
pub use crate::qom_isa;
+
+pub use crate::sysbus::SysBusDeviceMethods;
diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs
index 7d5fbef..97901fb 100644
--- a/rust/qemu-api/src/qom.rs
+++ b/rust/qemu-api/src/qom.rs
@@ -55,6 +55,7 @@
use std::{
ffi::CStr,
+ fmt,
ops::{Deref, DerefMut},
os::raw::c_void,
};
@@ -105,6 +106,52 @@ macro_rules! qom_isa {
};
}
+/// This is the same as [`ManuallyDrop<T>`](std::mem::ManuallyDrop), though
+/// it hides the standard methods of `ManuallyDrop`.
+///
+/// The first field of an `ObjectType` must be of type `ParentField<T>`.
+/// (Technically, this is only necessary if there is at least one Rust
+/// superclass in the hierarchy). This is to ensure that the parent field is
+/// dropped after the subclass; this drop order is enforced by the C
+/// `object_deinit` function.
+///
+/// # Examples
+///
+/// ```ignore
+/// #[repr(C)]
+/// #[derive(qemu_api_macros::Object)]
+/// pub struct MyDevice {
+/// parent: ParentField<DeviceState>,
+/// ...
+/// }
+/// ```
+#[derive(Debug)]
+#[repr(transparent)]
+pub struct ParentField<T: ObjectType>(std::mem::ManuallyDrop<T>);
+
+impl<T: ObjectType> Deref for ParentField<T> {
+ type Target = T;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<T: ObjectType> DerefMut for ParentField<T> {
+ #[inline(always)]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+impl<T: fmt::Display + ObjectType> fmt::Display for ParentField<T> {
+ #[inline(always)]
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ self.0.fmt(f)
+ }
+}
+
unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) {
// SAFETY: obj is an instance of T, since rust_instance_init<T>
// is called from QOM core as the instance_init function
@@ -116,11 +163,7 @@ unsafe extern "C" fn rust_instance_post_init<T: ObjectImpl>(obj: *mut Object) {
// SAFETY: obj is an instance of T, since rust_instance_post_init<T>
// is called from QOM core as the instance_post_init function
// for class T
- //
- // FIXME: it's not really guaranteed that there are no backpointers to
- // obj; it's quite possible that they have been created by instance_init().
- // The receiver should be &self, not &mut self.
- T::INSTANCE_POST_INIT.unwrap()(unsafe { &mut *obj.cast::<T>() })
+ T::INSTANCE_POST_INIT.unwrap()(unsafe { &*obj.cast::<T>() })
}
unsafe extern "C" fn rust_class_init<T: ObjectType + ClassInitImpl<T::Class>>(
@@ -133,6 +176,16 @@ unsafe extern "C" fn rust_class_init<T: ObjectType + ClassInitImpl<T::Class>>(
T::class_init(unsafe { &mut *klass.cast::<T::Class>() })
}
+unsafe extern "C" fn drop_object<T: ObjectImpl>(obj: *mut 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
+ // superclass field separately after this function returns, `T` must
+ // implement the unsafe trait ObjectType; the safety rules for the
+ // trait mandate that the parent field is manually dropped.
+ unsafe { std::ptr::drop_in_place(obj.cast::<T>()) }
+}
+
/// Trait exposed by all structs corresponding to QOM objects.
///
/// # Safety
@@ -151,11 +204,16 @@ unsafe extern "C" fn rust_class_init<T: ObjectType + ClassInitImpl<T::Class>>(
///
/// - the struct must be `#[repr(C)]`;
///
-/// - the first field of the struct must be of the instance struct corresponding
-/// to the superclass, which is `ObjectImpl::ParentType`
+/// - the first field of the struct must be of type
+/// [`ParentField<T>`](ParentField), where `T` is the parent type
+/// [`ObjectImpl::ParentType`]
+///
+/// - the first field of the `Class` must be of the class struct corresponding
+/// to the superclass, which is `ObjectImpl::ParentType::Class`. `ParentField`
+/// is not needed here.
///
-/// - likewise, the first field of the `Class` must be of the class struct
-/// corresponding to the superclass, which is `ObjectImpl::ParentType::Class`.
+/// In both cases, having a separate class type is not necessary if the subclass
+/// does not add any field.
pub unsafe trait ObjectType: Sized {
/// The QOM class object corresponding to this struct. This is used
/// to automatically generate a `class_init` method.
@@ -384,13 +442,12 @@ impl<T: ObjectType> ObjectCastMut for &mut T {}
/// Trait a type must implement to be registered with QEMU.
pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> {
- /// The parent of the type. This should match the first field of
- /// the struct that implements `ObjectImpl`:
+ /// The parent of the type. This should match the first field of the
+ /// struct that implements `ObjectImpl`, minus the `ParentField<_>` wrapper.
type ParentType: ObjectType;
/// Whether the object can be instantiated
const ABSTRACT: bool = false;
- const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
/// Function that is called to initialize an object. The parent class will
/// have already been initialized so the type is only responsible for
@@ -402,7 +459,7 @@ pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> {
/// Function that is called to finish initialization of an object, once
/// `INSTANCE_INIT` functions have been called.
- const INSTANCE_POST_INIT: Option<fn(&mut Self)> = None;
+ const INSTANCE_POST_INIT: Option<fn(&Self)> = None;
/// Called on descendent classes after all parent class initialization
/// has occurred, but before the class itself is initialized. This
@@ -426,7 +483,7 @@ pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> {
None => None,
Some(_) => Some(rust_instance_post_init::<Self>),
},
- instance_finalize: Self::INSTANCE_FINALIZE,
+ instance_finalize: Some(drop_object::<Self>),
abstract_: Self::ABSTRACT,
class_size: core::mem::size_of::<Self::Class>(),
class_init: Some(rust_class_init::<Self>),
diff --git a/rust/qemu-api/src/sysbus.rs b/rust/qemu-api/src/sysbus.rs
index 8193734..e6762b5 100644
--- a/rust/qemu-api/src/sysbus.rs
+++ b/rust/qemu-api/src/sysbus.rs
@@ -32,20 +32,33 @@ where
}
}
-impl SysBusDevice {
- /// Return `self` cast to a mutable pointer, for use in calls to C code.
- const fn as_mut_ptr(&self) -> *mut SysBusDevice {
- addr_of!(*self) as *mut _
+/// Trait for methods of [`SysBusDevice`] and its subclasses.
+pub trait SysBusDeviceMethods: ObjectDeref
+where
+ Self::Target: IsA<SysBusDevice>,
+{
+ /// Expose a memory region to the board so that it can give it an address
+ /// in guest memory. Note that the ordering of calls to `init_mmio` is
+ /// important, since whoever creates the sysbus device will refer to the
+ /// region with a number that corresponds to the order of calls to
+ /// `init_mmio`.
+ fn init_mmio(&self, iomem: &bindings::MemoryRegion) {
+ assert!(bql_locked());
+ unsafe {
+ bindings::sysbus_init_mmio(self.as_mut_ptr(), addr_of!(*iomem) as *mut _);
+ }
}
/// Expose an interrupt source outside the device as a qdev GPIO output.
/// Note that the ordering of calls to `init_irq` is important, since
/// whoever creates the sysbus device will refer to the interrupts with
/// a number that corresponds to the order of calls to `init_irq`.
- pub fn init_irq(&self, irq: &InterruptSource) {
+ fn init_irq(&self, irq: &InterruptSource) {
assert!(bql_locked());
unsafe {
bindings::sysbus_init_irq(self.as_mut_ptr(), irq.as_ptr());
}
}
}
+
+impl<R: ObjectDeref> SysBusDeviceMethods for R where R::Target: IsA<SysBusDevice> {}