From patchwork Fri Feb 7 10:16:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13964728 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4C0A5C02196 for ; Fri, 7 Feb 2025 10:18:19 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tgLPx-0007QD-3H; Fri, 07 Feb 2025 05:17:01 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLPb-0007KI-G1 for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:16:45 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLPZ-0003lK-At for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:16:39 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738923395; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ynfSiKySz1E493NM3nAmhgtxqEj3XUDWlZBIVMVVqV8=; b=T1rmDmxXu3QJUSRHn00L6Gh8PTL+Vy3QanInr6Y08UVjRae/gb0GkTXgvAYSHoh2irpqAo h//6ixDNnwqtknkFmOdWptXLGjvald5edpL3KAtdQU2KcUpJWXw09N/J+I6dzD20Uqc8oD 3kjk38FWM7rv1yam34bWv0D5bskpQXI= Received: from mail-ej1-f72.google.com (mail-ej1-f72.google.com [209.85.218.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-659-ysoVjjfvNCilfwI5r_FSfg-1; Fri, 07 Feb 2025 05:16:33 -0500 X-MC-Unique: ysoVjjfvNCilfwI5r_FSfg-1 X-Mimecast-MFC-AGG-ID: ysoVjjfvNCilfwI5r_FSfg Received: by mail-ej1-f72.google.com with SMTP id a640c23a62f3a-ab7044083e5so221841466b.2 for ; Fri, 07 Feb 2025 02:16:33 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738923390; x=1739528190; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ynfSiKySz1E493NM3nAmhgtxqEj3XUDWlZBIVMVVqV8=; b=NMQ117j4FnTPVgM8kno8BkFQVzw3HqorwOtXcKk7W5HXWKzOHS+ass7PLSHouEP7/q RB3jMKYWzrxjBA1iJL3+MSIhh46lXtQtYiXbnvSFagXs4DWdG22Gy7aEGdrLODZ9r8NJ H7OBsIOTOCH/IMC0B+4gWoxCVmS5G/2uBFqWm3Z3Kugj0xUOJuhtfFFbBAmcntp32Fzs EN3NtKqGU/7mEVMdXt2NMfI07V4b+fUenLdPk1HW+gJdCxLkZJXrARUGRVhH6eBirTcY ZWCev3JusmFOItTXYvPlZwVos6MlwAxhAS4a2ATJnlGYn0P9esmRi4Kt+SZMqvrTvZYd PpDQ== X-Gm-Message-State: AOJu0Yzk/8P5m2iHJyFOu2mq8bQvCuJqOpQuGFH1h/Zr/fCk/YQm3O3s MvGOmIwtUwxMMWjYjRHRjjRpewP8NFjAQM2vyap94j25E1WfLeSflwcPxFK7hGECc2B0GLNHdu/ 28RDgcIt0mZjZ+xpd88KfsVwJZ3xSW2G9JGHykVu+folh2rb+zTWiuFh4u+t/Oq0MJBvlM9MxGp SEjKQ4QiO0jElZYCwKf97xgxxUvEQgY1hKxjwCEYg= X-Gm-Gg: ASbGncvykBq6TaHlWyEuDvsW9FEw7uhp0dAqhgfIxByS8/NDbaO5Y0hpcVbTBAmafJp hcmOUjX9sn0eOqMqAJba1PovuFl7h0dXEwVAow10zHF+NzSuFUNJ536a97dH3kqv1001MePEHgE 2npkGjZ1Eo+7dSyYWRqxDQPzLhIKMJ3krynIUAe3vpbp1UT9BsH9t07shi/2yDjVPPlFaNR3ujw wrT1CG/I2QkPSMKaxhvGX6BxjYtqdX5HXwNBb6pvCWP5yvyPa7u8cBub850QWFncH/0dxD0SUhF YISzoQ== X-Received: by 2002:a17:907:72d4:b0:ab7:5f0e:87e9 with SMTP id a640c23a62f3a-ab789c709d0mr241699166b.55.1738923390190; Fri, 07 Feb 2025 02:16:30 -0800 (PST) X-Google-Smtp-Source: AGHT+IHtNVzUSMaVefP8pN97PYvnHBMVz7li2Kz2Y5myFpgrULJWY3/oHyeUKMhZENZnChv/evvjtw== X-Received: by 2002:a17:907:72d4:b0:ab7:5f0e:87e9 with SMTP id a640c23a62f3a-ab789c709d0mr241693666b.55.1738923389586; Fri, 07 Feb 2025 02:16:29 -0800 (PST) Received: from [192.168.10.3] ([151.62.97.55]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5de3e49c372sm1343232a12.3.2025.02.07.02.16.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 02:16:27 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, zhao1.liu@intel.com Subject: [PATCH 01/12] rust: qom: add reference counting functionality Date: Fri, 7 Feb 2025 11:16:12 +0100 Message-ID: <20250207101623.2443552-2-pbonzini@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250207101623.2443552-1-pbonzini@redhat.com> References: <20250207101623.2443552-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add a smart pointer that allows to add and remove references from QOM objects. It's important to note that while all QOM objects have a reference count, in practice not all of them have their lifetime guarded by it. Embedded objects, specifically, are confined to the lifetime of the owner. When writing Rust bindings this is important, because embedded objects are *never* used through the "Owned<>" smart pointer that is introduced here. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/qemu-api/src/qom.rs | 158 ++++++++++++++++++++++++++++++++++- rust/qemu-api/src/vmstate.rs | 6 +- rust/qemu-api/tests/tests.rs | 10 +++ 3 files changed, 172 insertions(+), 2 deletions(-) diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index f50ee371aac..4a2e84c9aed 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -56,6 +56,7 @@ use std::{ ffi::CStr, fmt, + mem::ManuallyDrop, ops::{Deref, DerefMut}, os::raw::c_void, ptr::NonNull, @@ -63,7 +64,13 @@ pub use bindings::{Object, ObjectClass}; -use crate::bindings::{self, object_dynamic_cast, object_get_class, object_get_typename, TypeInfo}; +use crate::{ + bindings::{ + self, object_dynamic_cast, object_get_class, object_get_typename, object_ref, object_unref, + TypeInfo, + }, + cell::bql_locked, +}; /// Marker trait: `Self` can be statically upcasted to `P` (i.e. `P` is a direct /// or indirect parent of `Self`). @@ -610,6 +617,148 @@ unsafe impl ObjectType for Object { unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_OBJECT) }; } +/// A reference-counted pointer to a QOM object. +/// +/// `Owned` wraps `T` with automatic reference counting. It increases the +/// reference count when created via [`Owned::from`] or cloned, and decreases +/// it when dropped. This ensures that the reference count remains elevated +/// as long as any `Owned` references to it exist. +/// +/// `Owned` can be used for two reasons: +/// * because the lifetime of the QOM object is unknown and someone else could +/// take a reference (similar to `Arc`, for example): in this case, the +/// object can escape and outlive the Rust struct that contains the `Owned` +/// field; +/// +/// * to ensure that the object stays alive until after `Drop::drop` is called +/// on the Rust struct: in this case, the object will always die together with +/// the Rust struct that contains the `Owned` field. +/// +/// Child properties are an example of the second case: in C, an object that +/// is created with `object_initialize_child` will die *before* +/// `instance_finalize` is called, whereas Rust expects the struct to have valid +/// contents when `Drop::drop` is called. Therefore Rust structs that have +/// child properties need to keep a reference to the child object. Right now +/// this can be done with `Owned`; in the future one might have a separate +/// `Child<'parent, T>` smart pointer that keeps a reference to a `T`, like +/// `Owned`, but does not allow cloning. +/// +/// Note that dropping an `Owned` requires the big QEMU lock to be taken. +#[repr(transparent)] +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Owned(NonNull); + +// The following rationale for safety is taken from Linux's kernel::sync::Arc. + +// SAFETY: It is safe to send `Owned` to another thread when the underlying +// `T` is `Sync` because it effectively means sharing `&T` (which is safe +// because `T` is `Sync`); additionally, it needs `T` to be `Send` because any +// thread that has an `Owned` may ultimately access `T` using a +// mutable reference when the reference count reaches zero and `T` is dropped. +unsafe impl Send for Owned {} + +// SAFETY: It is safe to send `&Owned` to another thread when the underlying +// `T` is `Sync` because it effectively means sharing `&T` (which is safe +// because `T` is `Sync`); additionally, it needs `T` to be `Send` because any +// thread that has a `&Owned` may clone it and get an `Owned` on that +// thread, so the thread may ultimately access `T` using a mutable reference +// when the reference count reaches zero and `T` is dropped. +unsafe impl Sync for Owned {} + +impl Owned { + /// Convert a raw C pointer into an owned reference to the QOM + /// object it points to. The object's reference count will be + /// decreased when the `Owned` is dropped. + /// + /// # Panics + /// + /// Panics if `ptr` is NULL. + /// + /// # Safety + /// + /// The caller must indeed own a reference to the QOM object. + /// The object must not be embedded in another unless the outer + /// object is guaranteed to have a longer lifetime. + /// + /// A raw pointer obtained via [`Owned::into_raw()`] can always be passed + /// back to `from_raw()` (assuming the original `Owned` was valid!), + /// since the owned reference remains there between the calls to + /// `into_raw()` and `from_raw()`. + pub unsafe fn from_raw(ptr: *const T) -> Self { + // SAFETY NOTE: while NonNull requires a mutable pointer, only + // Deref is implemented so the pointer passed to from_raw + // remains const + Owned(NonNull::new(ptr as *mut T).unwrap()) + } + + /// Obtain a raw C pointer from a reference. `src` is consumed + /// and the reference is leaked. + #[allow(clippy::missing_const_for_fn)] + pub fn into_raw(src: Owned) -> *mut T { + let src = ManuallyDrop::new(src); + src.0.as_ptr() + } + + /// Increase the reference count of a QOM object and return + /// a new owned reference to it. + /// + /// # Safety + /// + /// The object must not be embedded in another, unless the outer + /// object is guaranteed to have a longer lifetime. + pub unsafe fn from(obj: &T) -> Self { + unsafe { + object_ref(obj.as_object_mut_ptr().cast::()); + + // SAFETY NOTE: while NonNull requires a mutable pointer, only + // Deref is implemented so the reference passed to from_raw + // remains shared + Owned(NonNull::new_unchecked(obj.as_mut_ptr())) + } + } +} + +impl Clone for Owned { + fn clone(&self) -> Self { + // SAFETY: creation method is unsafe; whoever calls it has + // responsibility that the pointer is valid, and remains valid + // throughout the lifetime of the `Owned` and its clones. + unsafe { Owned::from(self.deref()) } + } +} + +impl Deref for Owned { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: creation method is unsafe; whoever calls it has + // responsibility that the pointer is valid, and remains valid + // throughout the lifetime of the `Owned` and its clones. + // With that guarantee, reference counting ensures that + // the object remains alive. + unsafe { &*self.0.as_ptr() } + } +} +impl ObjectDeref for Owned {} + +impl Drop for Owned { + fn drop(&mut self) { + assert!(bql_locked()); + // SAFETY: creation method is unsafe, and whoever calls it has + // responsibility that the pointer is valid, and remains valid + // throughout the lifetime of the `Owned` and its clones. + unsafe { + object_unref(self.as_object_mut_ptr().cast::()); + } + } +} + +impl> fmt::Debug for Owned { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.deref().debug_fmt(f) + } +} + /// Trait for methods exposed by the Object class. The methods can be /// called on all objects that have the trait `IsA`. /// @@ -641,6 +790,13 @@ fn get_class(&self) -> &'static ::Class { klass } + + /// Convenience function for implementing the Debug trait + fn debug_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple(&self.typename()) + .field(&(self as *const Self)) + .finish() + } } impl ObjectMethods for R where R::Target: IsA {} diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs index 6ac432cf52f..11d21b8791c 100644 --- a/rust/qemu-api/src/vmstate.rs +++ b/rust/qemu-api/src/vmstate.rs @@ -29,6 +29,8 @@ pub use crate::bindings::{VMStateDescription, VMStateField}; use crate::{ bindings::{self, VMStateFlags}, + prelude::*, + qom::Owned, zeroable::Zeroable, }; @@ -191,7 +193,8 @@ pub const fn vmstate_varray_flag(_: PhantomData) -> VMStateFlags /// * a transparent wrapper for any of the above (`Cell`, `UnsafeCell`, /// [`BqlCell`](crate::cell::BqlCell), [`BqlRefCell`](crate::cell::BqlRefCell) /// * a raw pointer to any of the above -/// * a `NonNull` pointer or a `Box` for any of the above +/// * a `NonNull` pointer, a `Box` or an [`Owned`](crate::qom::Owned) for any of +/// the above /// * an array of any of the above /// /// In order to support other types, the trait `VMState` must be implemented @@ -398,6 +401,7 @@ unsafe impl<$base> VMState for $type where $base: VMState $($where)* { // Unlike C pointers, Box is always non-null therefore there is no need // to specify VMS_ALLOC. impl_vmstate_pointer!(Box where T: VMState); +impl_vmstate_pointer!(Owned where T: VMState + ObjectType); // Arrays using the underlying type's VMState plus // VMS_ARRAY/VMS_ARRAY_OF_POINTER diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs index 5c3e75ed3d5..69ddac7f1c5 100644 --- a/rust/qemu-api/tests/tests.rs +++ b/rust/qemu-api/tests/tests.rs @@ -138,6 +138,16 @@ fn test_object_new() { } } +#[test] +#[allow(clippy::redundant_clone)] +/// Create, clone and then drop an instance. +fn test_clone() { + init_qom(); + let p = DummyState::new(); + assert_eq!(p.clone().typename(), "dummy"); + drop(p); +} + #[test] /// Try invoking a method on an object. fn test_typename() { From patchwork Fri Feb 7 10:16:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13964727 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3EBB1C0219D for ; Fri, 7 Feb 2025 10:17:35 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tgLPz-0007Sw-TM; Fri, 07 Feb 2025 05:17:04 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLPg-0007L0-7X for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:16:46 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLPe-0003wV-Cu for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:16:43 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738923400; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ybz9Kd3KNqxlJqHHjf3WKawSVTyUpJp4hK0ydPUn82E=; b=aAVAsvf7XEzv33Ivwus3IfJnIKhSXri22AG34P39jWFfp1+uHtSkTV4zzagiBSp7VuaNiZ 0mtljpS1mDKk+zMChIu2OilvYxfiajzlp3QcrFhRMtC4hZunr8phkeR+ZiM7geXJmzLC+S gvK1dkranVi3M4sZt05WwsMM0DYMToY= Received: from mail-ej1-f72.google.com (mail-ej1-f72.google.com [209.85.218.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-77-sT0hVOuIPy2K6LAdmlnUFg-1; Fri, 07 Feb 2025 05:16:39 -0500 X-MC-Unique: sT0hVOuIPy2K6LAdmlnUFg-1 X-Mimecast-MFC-AGG-ID: sT0hVOuIPy2K6LAdmlnUFg Received: by mail-ej1-f72.google.com with SMTP id a640c23a62f3a-ab7907bb87eso39168266b.3 for ; Fri, 07 Feb 2025 02:16:39 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738923396; x=1739528196; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ybz9Kd3KNqxlJqHHjf3WKawSVTyUpJp4hK0ydPUn82E=; b=p4rh1cItBy67oiheJQnatSaK6n08wmmCx2oeAlNrFespY30V7Uw/knvDYfTyiSIAmf cWYBJG3KXn+BaQHLAAj9/nyPSo3C+N4Gdvk2IJsuwDmLO7pB9MSMDHkTZPL80oftMpDu 8XwU5T0kx+TjQuMhwlU+QMw7snEh8CnMtmcqcpIPVF67nDmruCdT2D1gdIxgmuasHKnL qvVsZqnBklD8g9iE1Umgy2Dzu4Bx9mWU24eISP2aYQXhgzSh+XliEpjkBeZT3/dKPBrh 5ZQQYlAICv5r+8f5tZi5N1PqWVOK4CnAXo9L3IJM/oE+U4NH2DpGqskETdcg0mmGn2Xy f2/w== X-Gm-Message-State: AOJu0YwKyWw+a7Dwo2iOHyoUQqKiup2GjkiSrQ4MPcQ8Z2u8jnzsBqTr ezjEk3FtiKan6FfB+xfgLjjabyVZk0Dn5IpdPOemhicQ57b+dQQ8bevrOsYps+Y5XgYRWjxYkWv ZUKQP/C0vUdhk/nu1k18MTOUIxIN9NGvBnFzJpWmemZf8bpWqMFpw3yM4rx4I+JjJYno45MXArr 7HUEFvozEGCo/lFJhJgf7kh2cSVvZvCq73TEaSzmw= X-Gm-Gg: ASbGnctnQY6zNGsGwtC7ch9rMxB5Yj2lN/UqiVs3h2WR2IcurZUEh/wQnV1LuTFwNRD quaW8xDvaBu8FxIq4qlFosNZhh0mBS81gx4HQJ8/ZTWBQglUZl5vughLBvspNX7IMqikhU7FLKB kPGcP9u1GgV1a73IAYrSfXH9Jaxq7mZY4WW5ZdSETxUPozlJyGUSHrr1cpiPhD+uItSxcDw+qMM JfZW/m7t8241lWIqEdeT11hqw1nzeuZM4YY0qSf4Nq5BL3p07S/uHy/uZ36Wg5sq03v0+BUDmev w9elaw== X-Received: by 2002:a17:906:f585:b0:ab6:b848:2ab with SMTP id a640c23a62f3a-ab789b344a7mr278032666b.16.1738923396276; Fri, 07 Feb 2025 02:16:36 -0800 (PST) X-Google-Smtp-Source: AGHT+IFRMwDZp5GoGPo4LhchJ2F/GIOnN4dlM12Yx76gbWciYm/C8FDZEwHLD7KfPm0N5vouH7BKcw== X-Received: by 2002:a17:906:f585:b0:ab6:b848:2ab with SMTP id a640c23a62f3a-ab789b344a7mr278026966b.16.1738923395815; Fri, 07 Feb 2025 02:16:35 -0800 (PST) Received: from [192.168.10.3] ([151.62.97.55]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ab773339986sm238685766b.156.2025.02.07.02.16.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 02:16:30 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, zhao1.liu@intel.com Subject: [PATCH 02/12] rust: qom: add object creation functionality Date: Fri, 7 Feb 2025 11:16:13 +0100 Message-ID: <20250207101623.2443552-3-pbonzini@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250207101623.2443552-1-pbonzini@redhat.com> References: <20250207101623.2443552-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org The basic object lifecycle test can now be implemented using safe code! Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/hw/char/pl011/src/device.rs | 23 +++++++++++++---------- rust/qemu-api/src/prelude.rs | 1 + rust/qemu-api/src/qom.rs | 23 +++++++++++++++++++++-- rust/qemu-api/tests/tests.rs | 30 +++++++++++------------------- 4 files changed, 46 insertions(+), 31 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 8050ede9c85..f5db114b0c7 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -10,11 +10,11 @@ use qemu_api::{ bindings::{ - error_fatal, hwaddr, memory_region_init_io, qdev_init_clock_in, qdev_new, - qdev_prop_set_chr, qemu_chr_fe_accept_input, qemu_chr_fe_ioctl, qemu_chr_fe_set_handlers, - qemu_chr_fe_write_all, qemu_irq, sysbus_connect_irq, sysbus_mmio_map, - sysbus_realize_and_unref, CharBackend, Chardev, Clock, ClockEvent, MemoryRegion, - QEMUChrEvent, CHR_IOCTL_SERIAL_SET_BREAK, + error_fatal, hwaddr, memory_region_init_io, qdev_init_clock_in, qdev_prop_set_chr, + qemu_chr_fe_accept_input, qemu_chr_fe_ioctl, qemu_chr_fe_set_handlers, + qemu_chr_fe_write_all, qemu_irq, sysbus_connect_irq, sysbus_mmio_map, sysbus_realize, + CharBackend, Chardev, Clock, ClockEvent, MemoryRegion, QEMUChrEvent, + CHR_IOCTL_SERIAL_SET_BREAK, }, c_str, impl_vmstate_forward, irq::InterruptSource, @@ -705,15 +705,18 @@ pub fn post_load(&self, _version_id: u32) -> Result<(), ()> { irq: qemu_irq, chr: *mut Chardev, ) -> *mut DeviceState { + let pl011 = PL011State::new(); unsafe { - let dev: *mut DeviceState = qdev_new(PL011State::TYPE_NAME.as_ptr()); - let sysbus: *mut SysBusDevice = dev.cast::(); - + let dev = pl011.as_mut_ptr::(); qdev_prop_set_chr(dev, c_str!("chardev").as_ptr(), chr); - sysbus_realize_and_unref(sysbus, addr_of_mut!(error_fatal)); + + let sysbus = pl011.as_mut_ptr::(); + sysbus_realize(sysbus, addr_of_mut!(error_fatal)); sysbus_mmio_map(sysbus, 0, addr); sysbus_connect_irq(sysbus, 0, irq); - dev + + // return the pointer, which is kept alive by the QOM tree; drop owned ref + pl011.as_mut_ptr() } } diff --git a/rust/qemu-api/src/prelude.rs b/rust/qemu-api/src/prelude.rs index 2dc86e19b29..3df6a5c21ec 100644 --- a/rust/qemu-api/src/prelude.rs +++ b/rust/qemu-api/src/prelude.rs @@ -12,6 +12,7 @@ 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; pub use crate::qom::ObjectType; diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index 4a2e84c9aed..fad4759d7a6 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -66,8 +66,8 @@ use crate::{ bindings::{ - self, object_dynamic_cast, object_get_class, object_get_typename, object_ref, object_unref, - TypeInfo, + self, object_dynamic_cast, object_get_class, object_get_typename, object_new, object_ref, + object_unref, TypeInfo, }, cell::bql_locked, }; @@ -759,6 +759,24 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } +/// Trait for class methods exposed by the Object class. The methods can be +/// called on all objects that have the trait `IsA`. +/// +/// The trait should only be used through the blanket implementation, +/// which guarantees safety via `IsA` +pub trait ObjectClassMethods: IsA { + /// Return a new reference counted instance of this class + fn new() -> Owned { + assert!(bql_locked()); + // 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::()) + } + } +} + /// Trait for methods exposed by the Object class. The methods can be /// called on all objects that have the trait `IsA`. /// @@ -799,4 +817,5 @@ fn debug_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } +impl ObjectClassMethods for T where T: IsA {} impl ObjectMethods for R where R::Target: IsA {} diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs index 69ddac7f1c5..9986925d71f 100644 --- a/rust/qemu-api/tests/tests.rs +++ b/rust/qemu-api/tests/tests.rs @@ -3,8 +3,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later use std::{ - ffi::CStr, - os::raw::c_void, + ffi::{c_void, CStr}, ptr::{addr_of, addr_of_mut}, }; @@ -132,10 +131,8 @@ fn init_qom() { /// Create and immediately drop an instance. fn test_object_new() { init_qom(); - unsafe { - object_unref(object_new(DummyState::TYPE_NAME.as_ptr()).cast()); - object_unref(object_new(DummyChildState::TYPE_NAME.as_ptr()).cast()); - } + drop(DummyState::new()); + drop(DummyChildState::new()); } #[test] @@ -152,12 +149,8 @@ fn test_clone() { /// Try invoking a method on an object. fn test_typename() { init_qom(); - let p: *mut DummyState = unsafe { object_new(DummyState::TYPE_NAME.as_ptr()).cast() }; - let p_ref: &DummyState = unsafe { &*p }; - assert_eq!(p_ref.typename(), "dummy"); - unsafe { - object_unref(p_ref.as_object_mut_ptr().cast::()); - } + let p = DummyState::new(); + assert_eq!(p.typename(), "dummy"); } // a note on all "cast" tests: usually, especially for downcasts the desired @@ -172,24 +165,23 @@ fn test_typename() { /// Test casts on shared references. fn test_cast() { init_qom(); - let p: *mut DummyState = unsafe { object_new(DummyState::TYPE_NAME.as_ptr()).cast() }; + let p = DummyState::new(); + let p_ptr: *mut DummyState = unsafe { p.as_mut_ptr() }; + let p_ref: &mut DummyState = unsafe { &mut *p_ptr }; - let p_ref: &DummyState = unsafe { &*p }; let obj_ref: &Object = p_ref.upcast(); - assert_eq!(addr_of!(*obj_ref), p.cast()); + assert_eq!(addr_of!(*obj_ref), p_ptr.cast()); let sbd_ref: Option<&SysBusDevice> = obj_ref.dynamic_cast(); assert!(sbd_ref.is_none()); let dev_ref: Option<&DeviceState> = obj_ref.downcast(); - assert_eq!(addr_of!(*dev_ref.unwrap()), p.cast()); + assert_eq!(addr_of!(*dev_ref.unwrap()), p_ptr.cast()); // SAFETY: the cast is wrong, but the value is only used for comparison unsafe { let sbd_ref: &SysBusDevice = obj_ref.unsafe_cast(); - assert_eq!(addr_of!(*sbd_ref), p.cast()); - - object_unref(p_ref.as_object_mut_ptr().cast::()); + assert_eq!(addr_of!(*sbd_ref), p_ptr.cast()); } } From patchwork Fri Feb 7 10:16:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13964726 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D6CF5C0219B for ; Fri, 7 Feb 2025 10:17:32 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tgLQ1-0007TB-1r; Fri, 07 Feb 2025 05:17:05 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLPk-0007Lm-HU for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:16:53 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLPi-000432-RC for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:16:48 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738923405; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ejM9LdULLid2GnKlRXBOXJbddnv2FpH9YLwLU6Alx7U=; b=FMdhJVpqP2Nt1LFQRyOyWkk/z4YZBVCA10zQV80uMRGGAh0H1G+Okfj41e1b+DPFPWAC73 M7076ikbMXv7jgmfhNHE7homMtr3IIMb4CzYp7i9wMWImbZofBocPicQlk+k+3xeNJLvdc ZYkaxBQTlLPh8k6h0e6+ThEMHlfxrPw= Received: from mail-ej1-f71.google.com (mail-ej1-f71.google.com [209.85.218.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-417-n-B2sFemNlSJqUQxXMqJRQ-1; Fri, 07 Feb 2025 05:16:44 -0500 X-MC-Unique: n-B2sFemNlSJqUQxXMqJRQ-1 X-Mimecast-MFC-AGG-ID: n-B2sFemNlSJqUQxXMqJRQ Received: by mail-ej1-f71.google.com with SMTP id a640c23a62f3a-ab397fff5a3so213356566b.1 for ; Fri, 07 Feb 2025 02:16:44 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738923401; x=1739528201; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ejM9LdULLid2GnKlRXBOXJbddnv2FpH9YLwLU6Alx7U=; b=Kig8VCHtPqT7qGF8fhPIcDnqmUfZJs1q3xz610oLcVghD9UBF7Bec6t68zM2chp47a TDvmNHazgj/AFls7QUwpCIgk3a8K1e+XRPbK0k4AnPf/3dpSilEgo2tqnNqsgXhBAAgQ 2pw3xWsXe0oviFdVrgJ0pHVDQc/+QfmMa+cfPUICNdYMVxtvCf+fyQ5jhpXvjb8USvb1 vsTfU2kGmWcdrxgO07YWwLVP58n4QqilQG2EPW2h9NWkgRF/jAlmO2dXb8n7RF+/6C+B 8pC8yjGnfuYctQZCd9+O+9ceAqrJyZslGCTHYeeV6hpPSZKM7LwvRgujN6Cq6JKRLb3p f4aw== X-Gm-Message-State: AOJu0YylYvh7Ggmb6TS2rTpLIF5u+t+4x21O5xxBwsFYUQFD0DYArJA9 ulCPsh9gKdOusuI6jDgjo5A+/0hd1g8K27/vG2bBq8WsyWFT+gyWhZSO0XGGQWHDlsm5Ww7+x3J aSsB7gYjN8aL8IvRzjf8YLj+V6S8OPE2b+QhwhQHMkIpTX00A3J6Okohh9E+vlHElOOnPeo6Jnf 8wvu8ylmxoggBW6AZwvdasXeAKzkSHvcc8rsKqO9g= X-Gm-Gg: ASbGncsIOfy/FTS1uMxkaIWE2Q4dvLdlFonJQNaNLZ7Lw9EwipMmJskhnRUVTjgKZnl WbtyNxgkTmFZG/cm/N/2V5iV6oeInEbBws59+pcz4wCTTV7p4NNJcFXuJ2mRf7/xo+JuNb+bMFi 192TwPSr8PmYhAg/ZEgl7OSR9jHqMmhqX3TtDYLY4+nLicD2YLVT6NS5pF19DFXhMKzNYnVZm1B A68REQs6y6bGiSBNepbMwncCRacxQHvgdhNYKR0x1j4Ik8hzyaF18RiEwUSJB+LD1IugzfA4BX0 9Bw47w== X-Received: by 2002:a17:907:9484:b0:ab2:f6e5:3f1 with SMTP id a640c23a62f3a-ab789ace50cmr220063666b.8.1738923401347; Fri, 07 Feb 2025 02:16:41 -0800 (PST) X-Google-Smtp-Source: AGHT+IFYFvkx7kxL5wQX/I6eTUg9VtwNiAsz7cQrnkIWtbX2vjwB7yapZwzOC5xnpFw7o24m1v/ngw== X-Received: by 2002:a17:907:9484:b0:ab2:f6e5:3f1 with SMTP id a640c23a62f3a-ab789ace50cmr220060566b.8.1738923400879; Fri, 07 Feb 2025 02:16:40 -0800 (PST) Received: from [192.168.10.3] ([151.62.97.55]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ab772f49361sm240505766b.33.2025.02.07.02.16.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 02:16:36 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, zhao1.liu@intel.com Subject: [PATCH 03/12] rust: callbacks: allow passing optional callbacks as () Date: Fri, 7 Feb 2025 11:16:14 +0100 Message-ID: <20250207101623.2443552-4-pbonzini@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250207101623.2443552-1-pbonzini@redhat.com> References: <20250207101623.2443552-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org In some cases, callbacks are optional. Using "Some(function)" and "None" does not work well, because when someone writes "None" the compiler does not know what to use for "F" in "Option". Therefore, adopt () to mean a "null" callback. It is possible to enforce that a callback is valid by adding a "let _: () = F::ASSERT_IS_SOME" before the invocation of F::call. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/qemu-api/src/callbacks.rs | 97 ++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/rust/qemu-api/src/callbacks.rs b/rust/qemu-api/src/callbacks.rs index 314f9dce962..9642a16eb89 100644 --- a/rust/qemu-api/src/callbacks.rs +++ b/rust/qemu-api/src/callbacks.rs @@ -79,6 +79,31 @@ /// call_it(&move |_| String::from(x), "hello workd"); /// ``` /// +/// `()` can be used to indicate "no function": +/// +/// ``` +/// # use qemu_api::callbacks::FnCall; +/// fn optional FnCall<(&'a str,), String>>(_f: &F, s: &str) -> Option { +/// if F::IS_SOME { +/// Some(F::call((s,))) +/// } else { +/// None +/// } +/// } +/// +/// assert!(optional(&(), "hello world").is_none()); +/// ``` +/// +/// Invoking `F::call` will then be a run-time error. +/// +/// ```should_panic +/// # use qemu_api::callbacks::FnCall; +/// # fn call_it FnCall<(&'a str,), String>>(_f: &F, s: &str) -> String { +/// # F::call((s,)) +/// # } +/// let s: String = call_it(&(), "hello world"); // panics +/// ``` +/// /// # Safety /// /// Because `Self` is a zero-sized type, all instances of the type are @@ -93,10 +118,70 @@ pub unsafe trait FnCall: 'static + Sync + Sized { /// Rust 1.79.0+. const ASSERT_ZERO_SIZED: () = { assert!(mem::size_of::() == 0) }; + /// Referring to this constant asserts that the `Self` type is an actual + /// function type, which can be used to catch incorrect use of `()` + /// at compile time. + /// + /// # Examples + /// + /// ```compile_fail + /// # use qemu_api::callbacks::FnCall; + /// fn call_it FnCall<(&'a str,), String>>(_f: &F, s: &str) -> String { + /// let _: () = F::ASSERT_IS_SOME; + /// F::call((s,)) + /// } + /// + /// let s: String = call_it((), "hello world"); // does not compile + /// ``` + /// + /// Note that this can be more simply `const { assert!(F::IS_SOME) }` in + /// Rust 1.79.0 or newer. + const ASSERT_IS_SOME: () = { assert!(Self::IS_SOME) }; + + /// `true` if `Self` is an actual function type and not `()`. + /// + /// # Examples + /// + /// You can use `IS_SOME` to catch this at compile time: + /// + /// ```compile_fail + /// # use qemu_api::callbacks::FnCall; + /// fn call_it FnCall<(&'a str,), String>>(_f: &F, s: &str) -> String { + /// const { assert!(F::IS_SOME) } + /// F::call((s,)) + /// } + /// + /// let s: String = call_it((), "hello world"); // does not compile + /// ``` + const IS_SOME: bool; + + /// `false` if `Self` is an actual function type, `true` if it is `()`. + fn is_none() -> bool { + !Self::IS_SOME + } + + /// `true` if `Self` is an actual function type, `false` if it is `()`. + fn is_some() -> bool { + Self::IS_SOME + } + /// Call the function with the arguments in args. fn call(a: Args) -> R; } +/// `()` acts as a "null" callback. Using `()` and `function` is nicer +/// than `None` and `Some(function)`, because the compiler is unable to +/// infer the type of just `None`. Therefore, the trait itself acts as the +/// option type, with functions [`FnCall::is_some`] and [`FnCall::is_none`]. +unsafe impl FnCall for () { + const IS_SOME: bool = false; + + /// Call the function with the arguments in args. + fn call(_a: Args) -> R { + panic!("callback not specified") + } +} + macro_rules! impl_call { ($($args:ident,)* ) => ( // SAFETY: because each function is treated as a separate type, @@ -106,6 +191,8 @@ unsafe impl FnCall<($($args,)*), R> for F where F: 'static + Sync + Sized + Fn($($args, )*) -> R, { + const IS_SOME: bool = true; + #[inline(always)] fn call(a: ($($args,)*)) -> R { let _: () = Self::ASSERT_ZERO_SIZED; @@ -141,4 +228,14 @@ fn do_test_call<'a, F: FnCall<(&'a str,), String>>(_f: &F) -> String { fn test_call() { assert_eq!(do_test_call(&str::to_owned), "hello world") } + + // The `_f` parameter is unused but it helps the compiler infer `F`. + fn do_test_is_some<'a, F: FnCall<(&'a str,), String>>(_f: &F) { + assert!(F::is_some()); + } + + #[test] + fn test_is_some() { + do_test_is_some(&str::to_owned); + } } From patchwork Fri Feb 7 10:16:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13964729 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0C342C0219B for ; Fri, 7 Feb 2025 10:18:24 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tgLQN-0007lM-Cs; Fri, 07 Feb 2025 05:17:27 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLPp-0007Nd-3R for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:16:55 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLPn-0004GU-2a for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:16:52 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738923410; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qPLe8n7w4lU+JK6BULn/ii43xbBtY2BZigYuJPo3FFQ=; b=iII3ZBDf2LGLyi/VU3r2enK8wQP/OsOVRmFXIKO9uatgQ49YHI5Kr2YBP/ZRIVhJugIq1n DcIhr6V850c7cyKRUR49mgyE8ww4fPJ6Zh1fxLD3e063w7xGzxyatxGN4U/1PAWLyNYfCk V3lxMHi0BHRaFqv38kyQV+Vnclj9nDA= Received: from mail-ed1-f70.google.com (mail-ed1-f70.google.com [209.85.208.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-246-RAEH24RFN4CgJKh44eEXqA-1; Fri, 07 Feb 2025 05:16:49 -0500 X-MC-Unique: RAEH24RFN4CgJKh44eEXqA-1 X-Mimecast-MFC-AGG-ID: RAEH24RFN4CgJKh44eEXqA Received: by mail-ed1-f70.google.com with SMTP id 4fb4d7f45d1cf-5dc5beb5eb0so1501294a12.1 for ; Fri, 07 Feb 2025 02:16:48 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738923407; x=1739528207; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=qPLe8n7w4lU+JK6BULn/ii43xbBtY2BZigYuJPo3FFQ=; b=SxQdV+qcXeMXZZjE9q4r5rOtAL5US+HjThVYNS2jlkRmRB02IoDdWMliDMlE03pCNA Ea01XNBK8a7UtQyf992SmQ1ye3EQLqoWhI8JLG4deCV14qBfwvk1OINgkNfF+0IkdOcs Qgi2J7JN6Ny8gCrcEJU5Fgnjhyu5qkQxrTYYg09VannzKRQF2DlAjC++26D6KoGJ4kyD CGebmAmQNaNrp6pOhAMxOViiBJCL87ZVx1qUaPFx+0VHfnmBSq7m31StVUc4v7fTHaXp oz0sOrEHCioHIhe9maXqfV+z9nJ8mvNDkgBnSzqk/CD1uv6qL0os6vjQts3L5FkEmcoi N7kA== X-Gm-Message-State: AOJu0YzYQ93FJPfEQc5EU0G9aOzCi6FvjVAIQz6XHiNV6rJIirR0WLxF pzEBYfUeJzIFILXJfzwQdKDI0Q55+juNfXeYlS6YnSrYe3YVZSLXQZbjfyVLyfqNnePiC5ATvfE nTVKufV7X46j/tPb3rihp2TN+w6i4ZEQ9VAh+Q1PdmfWdqHDFJgvpy6AhoVxzF9t+Y4rq5rlbV/ g0NM73GXv3trldXYGkX7j809cClhI4GQ9PMtUJjNM= X-Gm-Gg: ASbGncuDuETHADvOIvtYr2mUQp4ijcGpITT0Ez1PKogWehGJbKhnj0wUG0CN53gWjUy 9q+ZfB1pNCg2JAhlWDBFyAqIM3+r04vcPzBaNgE2qSV+nXLFuZB804hrkoO7Dux4cutTAH4oJN+ ue9wGYNT3DpUJGIH3hIKxlS+NphNPwtdP/bBJDIU/hBh6sNwJtxQqu/XkR6pgjRnvoEiFwJrG1Y C5l3IwRBjQYyt8uk3gRGtaPvFLPulDKJhMUPWl9Lzz+UQ220KlKFzkRhvI5e5nW9fY8a34HRZ6S rzBkpw== X-Received: by 2002:a05:6402:4588:b0:5db:e91a:6baf with SMTP id 4fb4d7f45d1cf-5de45015f49mr7206872a12.14.1738923406475; Fri, 07 Feb 2025 02:16:46 -0800 (PST) X-Google-Smtp-Source: AGHT+IHyLaRlLhMDi0sic2b81oIjyoDiKQ8HxFyoPHsUiHz/TTRI0oQR/+PmMjzhrWK8g7PQ3Zf3VQ== X-Received: by 2002:a05:6402:4588:b0:5db:e91a:6baf with SMTP id 4fb4d7f45d1cf-5de45015f49mr7206826a12.14.1738923405955; Fri, 07 Feb 2025 02:16:45 -0800 (PST) Received: from [192.168.10.3] ([151.62.97.55]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5dcf6c9f904sm2276175a12.58.2025.02.07.02.16.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 02:16:42 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, zhao1.liu@intel.com Subject: [PATCH 04/12] rust: qdev: add clock creation Date: Fri, 7 Feb 2025 11:16:15 +0100 Message-ID: <20250207101623.2443552-5-pbonzini@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250207101623.2443552-1-pbonzini@redhat.com> References: <20250207101623.2443552-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Add a Rust version of qdev_init_clock_in, which can be used in instance_init. There are a couple differences with the C version: - in Rust the object keeps its own reference to the clock (in addition to the one embedded in the NamedClockList), and the reference is dropped automatically by instance_finalize(); this is encoded in the signature of DeviceClassMethods::init_clock_in, which makes the lifetime of the clock independent of that of the object it holds. This goes unnoticed in the C version and is due to the existence of aliases. - also, anything that happens during instance_init uses the pinned_init framework to operate on a partially initialized object, and is done through class methods (i.e. through DeviceClassMethods rather than DeviceMethods) because the device does not exist yet. Therefore, Rust code *must* create clocks from instance_init, which is stricter than C. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/hw/char/pl011/src/device.rs | 43 +++++------- rust/qemu-api/src/prelude.rs | 2 + rust/qemu-api/src/qdev.rs | 109 ++++++++++++++++++++++++++++++- rust/qemu-api/src/vmstate.rs | 4 +- 4 files changed, 127 insertions(+), 31 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index f5db114b0c7..37936a328b8 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -10,17 +10,16 @@ use qemu_api::{ bindings::{ - error_fatal, hwaddr, memory_region_init_io, qdev_init_clock_in, qdev_prop_set_chr, - qemu_chr_fe_accept_input, qemu_chr_fe_ioctl, qemu_chr_fe_set_handlers, - qemu_chr_fe_write_all, qemu_irq, sysbus_connect_irq, sysbus_mmio_map, sysbus_realize, - CharBackend, Chardev, Clock, ClockEvent, MemoryRegion, QEMUChrEvent, - CHR_IOCTL_SERIAL_SET_BREAK, + error_fatal, hwaddr, memory_region_init_io, qdev_prop_set_chr, qemu_chr_fe_accept_input, + qemu_chr_fe_ioctl, qemu_chr_fe_set_handlers, qemu_chr_fe_write_all, qemu_irq, + sysbus_connect_irq, sysbus_mmio_map, sysbus_realize, CharBackend, Chardev, MemoryRegion, + QEMUChrEvent, CHR_IOCTL_SERIAL_SET_BREAK, }, c_str, impl_vmstate_forward, irq::InterruptSource, prelude::*, - qdev::{DeviceImpl, DeviceState, Property}, - qom::{ClassInitImpl, ObjectImpl, ParentField}, + qdev::{Clock, ClockEvent, DeviceImpl, DeviceState, Property}, + qom::{ClassInitImpl, ObjectImpl, Owned, ParentField}, sysbus::{SysBusDevice, SysBusDeviceClass}, vmstate::VMStateDescription, }; @@ -131,7 +130,7 @@ pub struct PL011State { #[doc(alias = "irq")] pub interrupts: [InterruptSource; IRQMASK.len()], #[doc(alias = "clk")] - pub clock: NonNull, + pub clock: Owned, #[doc(alias = "migrate_clk")] pub migrate_clock: bool, } @@ -485,8 +484,6 @@ impl PL011State { /// location/instance. All its fields are expected to hold unitialized /// values with the sole exception of `parent_obj`. unsafe fn init(&mut self) { - const CLK_NAME: &CStr = c_str!("clk"); - // SAFETY: // // self and self.iomem are guaranteed to be valid at this point since callers @@ -506,22 +503,16 @@ unsafe fn init(&mut self) { // SAFETY: // - // self.clock is not initialized at this point; but since `NonNull<_>` is Copy, - // we can overwrite the undefined value without side effects. This is - // safe since all PL011State instances are created by QOM code which - // calls this function to initialize the fields; therefore no code is - // able to access an invalid self.clock value. - unsafe { - let dev: &mut DeviceState = self.upcast_mut(); - self.clock = NonNull::new(qdev_init_clock_in( - dev, - CLK_NAME.as_ptr(), - None, /* pl011_clock_update */ - addr_of_mut!(*self).cast::(), - ClockEvent::ClockUpdate.0, - )) - .unwrap(); - } + // self.clock is not initialized at this point; but since `Owned<_>` is + // not Drop, we can overwrite the undefined value without side effects; + // it's not sound but, because for all PL011State instances are created + // by QOM code which calls this function to initialize the fields, at + // leastno code is able to access an invalid self.clock value. + self.clock = self.init_clock_in("clk", &Self::clock_update, ClockEvent::ClockUpdate); + } + + const fn clock_update(&self, _event: ClockEvent) { + /* pl011_trace_baudrate_change(s); */ } fn post_init(&self) { diff --git a/rust/qemu-api/src/prelude.rs b/rust/qemu-api/src/prelude.rs index 3df6a5c21ec..87e3ce90f26 100644 --- a/rust/qemu-api/src/prelude.rs +++ b/rust/qemu-api/src/prelude.rs @@ -7,6 +7,8 @@ pub use crate::cell::BqlCell; pub use crate::cell::BqlRefCell; +pub use crate::qdev::DeviceMethods; + pub use crate::qom::IsA; pub use crate::qom::Object; pub use crate::qom::ObjectCast; diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs index f4c75c752f1..8f6744c5e26 100644 --- a/rust/qemu-api/src/qdev.rs +++ b/rust/qemu-api/src/qdev.rs @@ -4,14 +4,20 @@ //! Bindings to create devices and access device functionality from Rust. -use std::{ffi::CStr, ptr::NonNull}; +use std::{ + ffi::{CStr, CString}, + os::raw::c_void, + ptr::NonNull, +}; -pub use bindings::{DeviceClass, DeviceState, Property}; +pub use bindings::{Clock, ClockEvent, DeviceClass, DeviceState, Property}; use crate::{ bindings::{self, Error}, + callbacks::FnCall, + cell::bql_locked, prelude::*, - qom::{ClassInitImpl, ObjectClass}, + qom::{ClassInitImpl, ObjectClass, Owned}, vmstate::VMStateDescription, }; @@ -143,3 +149,100 @@ unsafe impl ObjectType for DeviceState { unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_DEVICE) }; } qom_isa!(DeviceState: Object); + +/// Trait for methods exposed by the [`DeviceState`] class. The methods can be +/// called on all objects that have the trait `IsA`. +/// +/// The trait should only be used through the blanket implementation, +/// which guarantees safety via `IsA`. +pub trait DeviceMethods: ObjectDeref +where + Self::Target: IsA, +{ + /// Add an input clock named `name`. Invoke the callback with + /// `self` as the first parameter for the events that are requested. + /// + /// The resulting clock is added as a child of `self`, but it also + /// stays alive until after `Drop::drop` is called because C code + /// keeps an extra reference to it until `device_finalize()` calls + /// `qdev_finalize_clocklist()`. Therefore (unlike most cases in + /// which Rust code has a reference to a child object) it would be + /// possible for this function to return a `&Clock` too. + #[inline] + fn init_clock_in FnCall<(&'a Self::Target, ClockEvent)>>( + &self, + name: &str, + _cb: &F, + events: ClockEvent, + ) -> Owned { + fn do_init_clock_in( + dev: *mut DeviceState, + name: &str, + cb: Option, + events: ClockEvent, + ) -> Owned { + assert!(bql_locked()); + + // SAFETY: the clock is heap allocated, but qdev_init_clock_in() + // does not gift the reference to its caller; so use Owned::from to + // add one. The callback is disabled automatically when the clock + // is unparented, which happens before the device is finalized. + unsafe { + let cstr = CString::new(name).unwrap(); + let clk = bindings::qdev_init_clock_in( + dev, + cstr.as_ptr(), + cb, + dev.cast::(), + events.0, + ); + + Owned::from(&*clk) + } + } + + let cb: Option = if F::is_some() { + unsafe extern "C" fn rust_clock_cb FnCall<(&'a T, ClockEvent)>>( + opaque: *mut c_void, + event: ClockEvent, + ) { + // SAFETY: the opaque is "this", which is indeed a pointer to T + F::call((unsafe { &*(opaque.cast::()) }, event)) + } + Some(rust_clock_cb::) + } else { + None + }; + + // SAFETY: self can be cast to DeviceState because its type has an + // IsA bound. + do_init_clock_in(unsafe { self.as_mut_ptr() }, name, cb, events) + } + + /// Add an output clock named `name`. + /// + /// The resulting clock is added as a child of `self`, but it also + /// stays alive until after `Drop::drop` is called because C code + /// keeps an extra reference to it until `device_finalize()` calls + /// `qdev_finalize_clocklist()`. Therefore (unlike most cases in + /// which Rust code has a reference to a child object) it would be + /// possible for this function to return a `&Clock` too. + #[inline] + fn init_clock_out(&self, name: &str) -> Owned { + unsafe { + let cstr = CString::new(name).unwrap(); + let clk = bindings::qdev_init_clock_out(self.as_mut_ptr(), cstr.as_ptr()); + + Owned::from(&*clk) + } + } +} + +impl DeviceMethods for R where R::Target: IsA {} + +unsafe impl ObjectType for Clock { + type Class = ObjectClass; + const TYPE_NAME: &'static CStr = + unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_CLOCK) }; +} +qom_isa!(Clock: Object); diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs index 11d21b8791c..164effc6553 100644 --- a/rust/qemu-api/src/vmstate.rs +++ b/rust/qemu-api/src/vmstate.rs @@ -470,11 +470,11 @@ macro_rules! vmstate_clock { $crate::assert_field_type!( $struct_name, $field_name, - core::ptr::NonNull<$crate::bindings::Clock> + $crate::qom::Owned<$crate::bindings::Clock> ); $crate::offset_of!($struct_name, $field_name) }, - size: ::core::mem::size_of::<*const $crate::bindings::Clock>(), + size: ::core::mem::size_of::<*const $crate::qdev::Clock>(), flags: VMStateFlags(VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0), vmsd: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_clock) }, ..$crate::zeroable::Zeroable::ZERO From patchwork Fri Feb 7 10:16:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13964731 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5FABFC0219B for ; Fri, 7 Feb 2025 10:18:31 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tgLQ4-0007Ur-2q; Fri, 07 Feb 2025 05:17:09 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLPv-0007Pf-HF for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:16:59 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLPu-0004Hc-2F for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:16:59 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738923417; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=e8ugkz2MCTVi9k0wZ/H/gZ6hjpuLYxOLaMc5B1rAzi0=; b=cmqBMnWSdKLdmKXESraUkoraBDV7jfv/Ytal+oJlgfV/kg6Hv3lxQ1b566xC8p3zMaNFT1 wKo8+H48h1yKI6A3hmYBVVaxSErreHWM6Shur5VNNj99iDgDntg+YdZjhSk4ZGEyi5vWxx Krxm9hZ2H1HnD1pq2Ut/Px6pPWcMk0g= Received: from mail-ej1-f70.google.com (mail-ej1-f70.google.com [209.85.218.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-642-GS6K0KNGMhC6aO2VD5gKSw-1; Fri, 07 Feb 2025 05:16:56 -0500 X-MC-Unique: GS6K0KNGMhC6aO2VD5gKSw-1 X-Mimecast-MFC-AGG-ID: GS6K0KNGMhC6aO2VD5gKSw Received: by mail-ej1-f70.google.com with SMTP id a640c23a62f3a-ab2e44dc9b8so312064666b.1 for ; Fri, 07 Feb 2025 02:16:56 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738923413; x=1739528213; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=e8ugkz2MCTVi9k0wZ/H/gZ6hjpuLYxOLaMc5B1rAzi0=; b=Xd3Y1l4/offFQ7GIkhQ8aj7yoPLWaVlyHVPOHplYAYf+6y7vMvFUH4nzOTLpPV8d1X lDkpI5P1JZJUGtSjSZ0gp5plBkYv4QJczfSy96LxtvS7v6oHuDiMwMXVce4XL3usaNaG i5r4eVDsCttLsbuuct+vE0Eb1x16iBkzdxtqW+8se/XZZ/rkmUsNXrGubpKJ2IY1GaSe DkCvTulU2NoWUvmFSHdW3T7LvtoAo7OwBhA1wC8KSmMg83JOCEUx7O8EjG6LVWK+hXwc 6ImLMCcx/wPBUn+cDmBcY5JHdkPyuEpZWmjCi3X7HWXz8WJZa8mrfGFaPzSt7DVpMC1w afFg== X-Gm-Message-State: AOJu0Yyc6SUyTiS0CFh19sd/9PMd41H9he/hHp6/LQplP50HIViZGlgh x6ZQ6bJ7ViN598afQzHAUpulfNcMDm08eoeCI1ndrwLBzYvQ7Wx0vWf32D2gUtbyFhwdyS/C43G engWCQ5vCU6FY/SlWKlEx36BsewyRgFjH/uhVvaxQW+vtGSUxIkygKQnmDu+OrzaDl8k0t4NKez QLlp3Mk6WnJjdcgTqUlTXJjWkasGsItH+NVIseRmY= X-Gm-Gg: ASbGncu6A1S97fP1nC0ULYuUYmIP6hF8inAE54RXf0eDdUnMxfcoi3DWCf+x9PTJr0Q WBpbXAoC+Kqs/39314QFytPvWWD5hRYyOFW7phSU69cykrS614GrgNQ65AzlPAKkMSvsDqu7ZLM jJQrNOyYS8wtKAsumhzCjTjJ+36EuD+J/4Za1wJD46m1bBzfiqwV5id8UPiTpRQ280QVQhwAc7x ublC/JkQNRdl3qS7PX8GOWo4/cGYBcdWa2aQGwmwwqWhaiGcjf+vskjXF0WyoB68+aE7HEZLzn8 GmSj6w== X-Received: by 2002:a17:907:7e8c:b0:ab6:f782:3ee2 with SMTP id a640c23a62f3a-ab76e896c1cmr679681466b.9.1738923412914; Fri, 07 Feb 2025 02:16:52 -0800 (PST) X-Google-Smtp-Source: AGHT+IFM3lk2ydc7epwpkztg3w/h+v1br1TpLcOGK5HJ3x0fJvwRo4UJf6MhFQZ1H9LxVlL2Y6xFHw== X-Received: by 2002:a17:907:7e8c:b0:ab6:f782:3ee2 with SMTP id a640c23a62f3a-ab76e896c1cmr679677266b.9.1738923412411; Fri, 07 Feb 2025 02:16:52 -0800 (PST) Received: from [192.168.10.3] ([151.62.97.55]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ab7732e7232sm241982766b.97.2025.02.07.02.16.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 02:16:46 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, zhao1.liu@intel.com Subject: [PATCH 05/12] rust: qom: allow initializing interface vtables Date: Fri, 7 Feb 2025 11:16:16 +0100 Message-ID: <20250207101623.2443552-6-pbonzini@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250207101623.2443552-1-pbonzini@redhat.com> References: <20250207101623.2443552-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Unlike regular classes, interface vtables can only be obtained via object_class_dynamic_cast. Provide a wrapper that allows accessing the vtable and pass it to a ClassInitImpl implementation, for example ClassInitImpl. Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/qemu-api/src/prelude.rs | 1 + rust/qemu-api/src/qom.rs | 45 ++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/rust/qemu-api/src/prelude.rs b/rust/qemu-api/src/prelude.rs index 87e3ce90f26..254edb476dd 100644 --- a/rust/qemu-api/src/prelude.rs +++ b/rust/qemu-api/src/prelude.rs @@ -9,6 +9,7 @@ pub use crate::qdev::DeviceMethods; +pub use crate::qom::InterfaceType; pub use crate::qom::IsA; pub use crate::qom::Object; pub use crate::qom::ObjectCast; diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index fad4759d7a6..fa69ae4c702 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -66,8 +66,8 @@ use crate::{ bindings::{ - self, object_dynamic_cast, object_get_class, object_get_typename, object_new, object_ref, - object_unref, TypeInfo, + self, object_class_dynamic_cast, object_dynamic_cast, object_get_class, + object_get_typename, object_new, object_ref, object_unref, TypeInfo, }, cell::bql_locked, }; @@ -263,6 +263,47 @@ unsafe fn as_object_mut_ptr(&self) -> *mut Object { } } +/// Trait exposed by all structs corresponding to QOM interfaces. +/// Unlike `ObjectType`, it is implemented on the class type (which provides +/// the vtable for the interfaces). +/// +/// # Safety +/// +/// `TYPE` must match the contents of the `TypeInfo` as found in the C code; +/// right now, interfaces can only be declared in C. +pub unsafe trait InterfaceType: Sized { + /// The name of the type, which can be passed to + /// `object_class_dynamic_cast()` to obtain the pointer to the vtable + /// for this interface. + const TYPE_NAME: &'static CStr; + + /// Initialize the vtable for the interface; the generic argument `T` is the + /// type being initialized, while the generic argument `U` is the type that + /// lists the interface in its `TypeInfo`. + /// + /// # Panics + /// + /// Panic if the incoming argument if `T` does not implement the interface. + fn interface_init< + T: ObjectType + ClassInitImpl + ClassInitImpl, + U: ObjectType, + >( + klass: &mut U::Class, + ) { + unsafe { + // SAFETY: upcasting to ObjectClass is always valid, and the + // return type is either NULL or the argument itself + let result: *mut Self = object_class_dynamic_cast( + (klass as *mut U::Class).cast(), + Self::TYPE_NAME.as_ptr(), + ) + .cast(); + + >::class_init(result.as_mut().unwrap()) + } + } +} + /// This trait provides safe casting operations for QOM objects to raw pointers, /// to be used for example for FFI. The trait can be applied to any kind of /// reference or smart pointers, and enforces correctness through the [`IsA`] From patchwork Fri Feb 7 10:16:17 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13964743 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C588FC02196 for ; Fri, 7 Feb 2025 10:20:50 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tgLTL-0007Dp-1M; Fri, 07 Feb 2025 05:20:31 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLTF-0007Ch-UO for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:20:29 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLTE-0006BQ-Dz for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:20:25 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738923622; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VfV5omvEttMhI3EQX/PeOloTPWUmqnbr5osfkTzsZPA=; b=STT82YIEWCFI24ogiz6CdCWBaMsqfyKTfu2ZZOARMt+WXBRDsuXLBSSBIfBMHIlbtY8LzS lQ6vgtEkXzJ8kY8LUbGpZNScv7ANycBUeUIdYfzPBs2AiyACuB3utj5slPl/CPgfEcssVx AaCq39PTKDFBBCWiuqXQwvqqxAM3858= Received: from mail-ej1-f69.google.com (mail-ej1-f69.google.com [209.85.218.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-319-bcE6NB4PMlqnPF1niivVjg-1; Fri, 07 Feb 2025 05:17:00 -0500 X-MC-Unique: bcE6NB4PMlqnPF1niivVjg-1 X-Mimecast-MFC-AGG-ID: bcE6NB4PMlqnPF1niivVjg Received: by mail-ej1-f69.google.com with SMTP id a640c23a62f3a-aa66f6ce6bfso201060666b.2 for ; Fri, 07 Feb 2025 02:17:00 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738923418; x=1739528218; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=VfV5omvEttMhI3EQX/PeOloTPWUmqnbr5osfkTzsZPA=; b=JnL7NPX/e3ZXcvS5nWix0txoSYd8bSmyP2xMWDDzVqtjsZ2ol9uw0SSLkQ6j657mC1 h4wLHrLvCde5ZMXi/HboP2A3z/AgXTU/KvzAwybSsTSFlZxhi0Q9UAdxJdLPk6OTpD3o 9CKQI790CCXLXGtqXK6z7X3BBJP8/txW4cU9cPzf0nurX41UjMajLNzFBd5/0yJXEirE SZH8rGNpQkPGkD+1g4YpGfFcA84+nhn9PB460mo1iChRjEDh6oYksCywpiorRRfv2Z0w u2iXdXjHdqatLmGi8rcsNFCmEeMm6m7GbM0nHi+6E6KV8JLvmVU3mJpMQeMfI2E1Q67F PorQ== X-Gm-Message-State: AOJu0YyuKarkoHtEYdN1FaJG3OXpb6/nueJQsjzty+Yv5qVBoRlQzF3t 8M1HBYG/fvKt5waq7atNtjeVZ3KAytSH+7jr7s1sPTJ0kNIELsLnY188UK02qgDoyVH+ydW0iJm M+Vik1WzIpTwT1vLnbeLVqCoJatuWA2y/d7zvEfhY/dGEEwJhkCFAz62xydENVV29KAckLHGwhP yWBnttmxL7nHXIwWojgYWaxuUpcCjF2NO5DXKBIjs= X-Gm-Gg: ASbGncvFcAyXcc/xC2WtKgwVr3dWqj1pvSDKRUItpTNJGOMGRBC8gGv7+XGG4WmRX/j KFSZaX4mfbfeBRZNBTd3ruxOuujU6SRtGSw3iv2Ha1qxiwkx59qXOSp2z7h4uSyviGE/MgWbBDh Itm13rE2cCt7kKbfAIXoPA7VveHsXT2O+6CFQpjt4aMe/ib00ofvPSheiWBnhIGW32OrbG8XrpT Q60JXgzb39ft0hdFbfgbJDX2FGK8ccSeWKWixyADUTtS3dzBNUiKMsiiWtf0aXpl6bztdFdXYzD ZYKSxQ== X-Received: by 2002:a17:907:6eac:b0:ab2:d721:ed92 with SMTP id a640c23a62f3a-ab789bfc571mr233637066b.45.1738923418155; Fri, 07 Feb 2025 02:16:58 -0800 (PST) X-Google-Smtp-Source: AGHT+IENxl2fGDbpXRhUB0cRg1D0aYQkWxbK9bKR2Fu7DI9m+bd5p0vWIL9kMuJAABQEtkcAZ6lzbw== X-Received: by 2002:a17:907:6eac:b0:ab2:d721:ed92 with SMTP id a640c23a62f3a-ab789bfc571mr233632566b.45.1738923417520; Fri, 07 Feb 2025 02:16:57 -0800 (PST) Received: from [192.168.10.3] ([151.62.97.55]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ab772f83e30sm240714566b.38.2025.02.07.02.16.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 02:16:54 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, zhao1.liu@intel.com Subject: [PATCH 06/12] rust: qdev: make ObjectImpl a supertrait of DeviceImpl Date: Fri, 7 Feb 2025 11:16:17 +0100 Message-ID: <20250207101623.2443552-7-pbonzini@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250207101623.2443552-1-pbonzini@redhat.com> References: <20250207101623.2443552-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org In practice it has to be implemented always in order to access an implementation of ClassInitImpl. Make the relationship explicit in the code. Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/qemu-api/src/qdev.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs index 8f6744c5e26..cb6f12e726c 100644 --- a/rust/qemu-api/src/qdev.rs +++ b/rust/qemu-api/src/qdev.rs @@ -17,12 +17,12 @@ callbacks::FnCall, cell::bql_locked, prelude::*, - qom::{ClassInitImpl, ObjectClass, Owned}, + qom::{ClassInitImpl, ObjectClass, ObjectImpl, Owned}, vmstate::VMStateDescription, }; /// Trait providing the contents of [`DeviceClass`]. -pub trait DeviceImpl { +pub trait DeviceImpl: ObjectImpl { /// _Realization_ is the second stage of device creation. It contains /// all operations that depend on device properties and can fail (note: /// this is not yet supported for Rust devices). From patchwork Fri Feb 7 10:16:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13964733 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 85ED1C02196 for ; Fri, 7 Feb 2025 10:18:37 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tgLQS-00085x-K1; Fri, 07 Feb 2025 05:17:32 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLQA-0007cD-OY for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:17:19 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLQ7-0004JP-9r for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:17:13 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738923430; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uES4HqqtaqOqQfE1eDVbpmrfNp7K4yqKrpgY/1SVq6M=; b=MVfwFLJ+opy4yyOosnBaDVM3guywh7iQ9BhGg+Np27IlzCYF+2OFTlDJ4sXAwmyaUFcipd gOdvF7fzP0wjwZt7HRROCJTlOk0o5FlIxk9dnvGcnFOUMxHtnQwnceCDmtNHWBiLhw1H1a i/zjnUJsfFrvGkZPw1EaghFF4VJABmo= Received: from mail-ej1-f69.google.com (mail-ej1-f69.google.com [209.85.218.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-205-LbFYS8CPMR-gC_TJmAF7hA-1; Fri, 07 Feb 2025 05:17:07 -0500 X-MC-Unique: LbFYS8CPMR-gC_TJmAF7hA-1 X-Mimecast-MFC-AGG-ID: LbFYS8CPMR-gC_TJmAF7hA Received: by mail-ej1-f69.google.com with SMTP id a640c23a62f3a-ab6c52ca20aso236465466b.3 for ; Fri, 07 Feb 2025 02:17:07 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738923423; x=1739528223; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=uES4HqqtaqOqQfE1eDVbpmrfNp7K4yqKrpgY/1SVq6M=; b=pUoBWjpsdyDv+fWjuSfEQ7LKjRb5Abs4ocFGGLJ49BjgbiSz8TmppHclfx+oU+6IS3 XPpuJM9TYIP8ss1xhcPOhOZoRX9eWqQVSsw/cuH6G/dKe0sK4VXymwkVNyYiE99Rt4vZ Brrc5xcOFI3KBJeVrZVjDHueABKE+KPCPrlgRlXczv4wblKFAT3GqXexMLCxG6sBaeT/ hpwO4J+Kb0sSgzTlB9VLjtgeJdjFY4mh+hyusYv69PLEcSOJAPd2Q1qvT8mRnE3S2SCI o4HJR1S16jUX9KdNjXRHCzwyqdH65aZHtxLTf/c7mSFRPAv8OYc0A0tIaoyiDt7nQW9u vVJA== X-Gm-Message-State: AOJu0Yxt3Gj1MdKOwjqwTrWgIGxgfhPqxAp+ZeV9s2qy1sexb0jxOdPe AhKB7WnlHHPJ3Y/r8AoWaffx2JqXHkisOZr2iZy76nv9RvtYWB9iIB0VceBTqHlhsY/hPiSk6Ig eVSojPSyyvhZ3VKTm7EeSNHrGX5e54xDsIKjBmbCVL+jAPA3kMmO2XGpVDz7TFUhMjpZo0PvUCx YEmB0Y9/hOcYy1pVuC/AxjP7aRIlyQ2TWIJ4Y7Bb8= X-Gm-Gg: ASbGncuUlNjVsA0E+fMvqSVY21xAvxqhbB1kix3tSMJPsPUcgBtXpXZRrAZhIYStPwc gtiSsE+he40jnlarpKaAi2lYFNF+tI4BaX5iy1Z57QiFmF/RfGsI/3Q0e/W108FCc7ejeXQUFo/ 0bA4ekhDZFCMn1zoh372aqMrZYPC4zA+8LK6gYkSeDEpxiLuxEmGZQYKnk9R2tuYlK7Ql2JFPeq kMgWWb+SYRz4Sv+bWgUGG1elXCndUr+lzwoh7BtJu96snfuk62KGClB3WE6umAyKkc+Sr0aEhew 4HNH0A== X-Received: by 2002:a17:907:1c9c:b0:aab:ee4a:6788 with SMTP id a640c23a62f3a-ab789c52c06mr265615266b.57.1738923422911; Fri, 07 Feb 2025 02:17:02 -0800 (PST) X-Google-Smtp-Source: AGHT+IFO1fspAubICNGVr5jbIr6183o8CuCT9k/HZqztef1KcklMNYJUU3W4/K74J0ggeoj8UGHV0g== X-Received: by 2002:a17:907:1c9c:b0:aab:ee4a:6788 with SMTP id a640c23a62f3a-ab789c52c06mr265609966b.57.1738923422303; Fri, 07 Feb 2025 02:17:02 -0800 (PST) Received: from [192.168.10.3] ([151.62.97.55]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ab772fd6933sm239441866b.78.2025.02.07.02.16.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 02:16:59 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, zhao1.liu@intel.com Subject: [PATCH 07/12] rust: qdev: switch from legacy reset to Resettable Date: Fri, 7 Feb 2025 11:16:18 +0100 Message-ID: <20250207101623.2443552-8-pbonzini@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250207101623.2443552-1-pbonzini@redhat.com> References: <20250207101623.2443552-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- meson.build | 1 + rust/hw/char/pl011/src/device.rs | 10 ++- rust/qemu-api/src/qdev.rs | 111 ++++++++++++++++++++++++------- rust/qemu-api/tests/tests.rs | 5 +- 4 files changed, 99 insertions(+), 28 deletions(-) diff --git a/meson.build b/meson.build index 131b2225ab6..32abefb7c48 100644 --- a/meson.build +++ b/meson.build @@ -4072,6 +4072,7 @@ if have_rust 'MigrationPriority', 'QEMUChrEvent', 'QEMUClockType', + 'ResetType', 'device_endian', 'module_init_type', ] diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 37936a328b8..1d0390b4fbe 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -18,7 +18,7 @@ c_str, impl_vmstate_forward, irq::InterruptSource, prelude::*, - qdev::{Clock, ClockEvent, DeviceImpl, DeviceState, Property}, + qdev::{Clock, ClockEvent, DeviceImpl, DeviceState, Property, ResetType, ResettablePhasesImpl}, qom::{ClassInitImpl, ObjectImpl, Owned, ParentField}, sysbus::{SysBusDevice, SysBusDeviceClass}, vmstate::VMStateDescription, @@ -171,7 +171,10 @@ fn vmsd() -> Option<&'static VMStateDescription> { Some(&device_class::VMSTATE_PL011) } const REALIZE: Option = Some(Self::realize); - const RESET: Option = Some(Self::reset); +} + +impl ResettablePhasesImpl for PL011State { + const HOLD: Option = Some(Self::reset_hold); } impl PL011Registers { @@ -622,7 +625,7 @@ pub fn realize(&self) { } } - pub fn reset(&self) { + pub fn reset_hold(&self, _type: ResetType) { self.regs.borrow_mut().reset(); } @@ -737,3 +740,4 @@ impl ObjectImpl for PL011Luminary { } impl DeviceImpl for PL011Luminary {} +impl ResettablePhasesImpl for PL011Luminary {} diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs index cb6f12e726c..2ec1ecc8489 100644 --- a/rust/qemu-api/src/qdev.rs +++ b/rust/qemu-api/src/qdev.rs @@ -10,10 +10,10 @@ ptr::NonNull, }; -pub use bindings::{Clock, ClockEvent, DeviceClass, DeviceState, Property}; +pub use bindings::{Clock, ClockEvent, DeviceClass, DeviceState, Property, ResetType}; use crate::{ - bindings::{self, Error}, + bindings::{self, Error, ResettableClass}, callbacks::FnCall, cell::bql_locked, prelude::*, @@ -21,8 +21,70 @@ vmstate::VMStateDescription, }; +/// Trait providing the contents of the `ResettablePhases` struct, +/// which is part of the QOM `Resettable` interface. +pub trait ResettablePhasesImpl { + /// If not None, this is called when the object enters reset. It + /// can reset local state of the object, but it must not do anything that + /// has a side-effect on other objects, such as raising or lowering an + /// [`InterruptSource`](crate::irq::InterruptSource), or reading or + /// writing guest memory. It takes the reset's type as argument. + const ENTER: Option = None; + + /// If not None, this is called when the object for entry into reset, once + /// every object in the system which is being reset has had its + /// `ResettablePhasesImpl::ENTER` method called. At this point devices + /// can do actions that affect other objects. + /// + /// If in doubt, implement this method. + const HOLD: Option = None; + + /// If not None, this phase is called when the object leaves the reset + /// state. Actions affecting other objects are permitted. + const EXIT: Option = None; +} + +/// # Safety +/// +/// 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_resettable_enter_fn( + obj: *mut Object, + typ: ResetType, +) { + let state = NonNull::new(obj).unwrap().cast::(); + T::ENTER.unwrap()(unsafe { state.as_ref() }, typ); +} + +/// # Safety +/// +/// 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_resettable_hold_fn( + obj: *mut Object, + typ: ResetType, +) { + let state = NonNull::new(obj).unwrap().cast::(); + T::HOLD.unwrap()(unsafe { state.as_ref() }, typ); +} + +/// # Safety +/// +/// 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_resettable_exit_fn( + obj: *mut Object, + typ: ResetType, +) { + let state = NonNull::new(obj).unwrap().cast::(); + T::EXIT.unwrap()(unsafe { state.as_ref() }, typ); +} + /// Trait providing the contents of [`DeviceClass`]. -pub trait DeviceImpl: ObjectImpl { +pub trait DeviceImpl: ObjectImpl + ResettablePhasesImpl { /// _Realization_ is the second stage of device creation. It contains /// all operations that depend on device properties and can fail (note: /// this is not yet supported for Rust devices). @@ -31,13 +93,6 @@ pub trait DeviceImpl: ObjectImpl { /// with the function pointed to by `REALIZE`. const REALIZE: Option = None; - /// If not `None`, the parent class's `reset` method is overridden - /// with the function pointed to by `RESET`. - /// - /// Rust does not yet support the three-phase reset protocol; this is - /// usually okay for leaf classes. - const RESET: Option = None; - /// An array providing the properties that the user can set on the /// device. Not a `const` because referencing statics in constants /// is unstable until Rust 1.83.0. @@ -65,29 +120,36 @@ fn vmsd() -> Option<&'static VMStateDescription> { T::REALIZE.unwrap()(unsafe { state.as_ref() }); } -/// # Safety -/// -/// 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_reset_fn(dev: *mut DeviceState) { - let mut state = NonNull::new(dev).unwrap().cast::(); - T::RESET.unwrap()(unsafe { state.as_mut() }); +unsafe impl InterfaceType for ResettableClass { + const TYPE_NAME: &'static CStr = + unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_RESETTABLE_INTERFACE) }; +} + +impl ClassInitImpl for T +where + T: ResettablePhasesImpl, +{ + fn class_init(rc: &mut ResettableClass) { + if ::ENTER.is_some() { + rc.phases.enter = Some(rust_resettable_enter_fn::); + } + if ::HOLD.is_some() { + rc.phases.hold = Some(rust_resettable_hold_fn::); + } + if ::EXIT.is_some() { + rc.phases.exit = Some(rust_resettable_exit_fn::); + } + } } impl ClassInitImpl for T where - T: ClassInitImpl + DeviceImpl, + T: ClassInitImpl + ClassInitImpl + DeviceImpl, { fn class_init(dc: &mut DeviceClass) { if ::REALIZE.is_some() { dc.realize = Some(rust_realize_fn::); } - if ::RESET.is_some() { - unsafe { - bindings::device_class_set_legacy_reset(dc, Some(rust_reset_fn::)); - } - } if let Some(vmsd) = ::vmsd() { dc.vmsd = vmsd; } @@ -98,6 +160,7 @@ fn class_init(dc: &mut DeviceClass) { } } + ResettableClass::interface_init::(dc); >::class_init(&mut dc.parent_class); } } diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs index 9986925d71f..ccf915d64f3 100644 --- a/rust/qemu-api/tests/tests.rs +++ b/rust/qemu-api/tests/tests.rs @@ -13,7 +13,7 @@ cell::{self, BqlCell}, declare_properties, define_property, prelude::*, - qdev::{DeviceClass, DeviceImpl, DeviceState, Property}, + qdev::{DeviceClass, DeviceImpl, DeviceState, Property, ResettablePhasesImpl}, qom::{ClassInitImpl, ObjectImpl, ParentField}, vmstate::VMStateDescription, zeroable::Zeroable, @@ -61,6 +61,8 @@ impl ObjectImpl for DummyState { const ABSTRACT: bool = false; } +impl ResettablePhasesImpl for DummyState {} + impl DeviceImpl for DummyState { fn properties() -> &'static [Property] { &DUMMY_PROPERTIES @@ -101,6 +103,7 @@ impl ObjectImpl for DummyChildState { const ABSTRACT: bool = false; } +impl ResettablePhasesImpl for DummyChildState {} impl DeviceImpl for DummyChildState {} impl ClassInitImpl for DummyChildState { From patchwork Fri Feb 7 10:16:19 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13964735 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 2AD6CC0219C for ; Fri, 7 Feb 2025 10:19:01 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tgLQO-0007oR-59; Fri, 07 Feb 2025 05:17:28 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLQD-0007cf-Qd for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:17:20 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLQB-0004KF-Ho for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:17:17 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738923434; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TjaNShE0GYpF6KF1Wxl7XEXpF6pZfvD+oUSQf7rKQdY=; b=jV2Tz9IVGiFGbqScoqWtZHj99lxSG8oONKRbmS6LPf7HeegVccgkH8xBoDKQpBn/lLNJWA jGE4LnO7oqbTYFAKDJmpNGN50huXwXcOEJeOS7k/ABsGN3S8SfOWNumwL37PcYIuNrPRNW hU/Mj6kqPIYOrASoY593ct6yNyyk0RA= Received: from mail-ed1-f69.google.com (mail-ed1-f69.google.com [209.85.208.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-102-RSPkADiuN06ZnFi50KAnhw-1; Fri, 07 Feb 2025 05:17:13 -0500 X-MC-Unique: RSPkADiuN06ZnFi50KAnhw-1 X-Mimecast-MFC-AGG-ID: RSPkADiuN06ZnFi50KAnhw Received: by mail-ed1-f69.google.com with SMTP id 4fb4d7f45d1cf-5da0b47115aso1969815a12.1 for ; Fri, 07 Feb 2025 02:17:13 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738923430; x=1739528230; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=TjaNShE0GYpF6KF1Wxl7XEXpF6pZfvD+oUSQf7rKQdY=; b=JSGVGz3v/XKZueiStPoTDW1Xy14eI5kImQmc8NEBr5uMw4Zco5twqchM0Rgd7pCk1j 0hLb+y9cJPG3TA3e2u7ah6SdaOhAT5lmt1A9acOIcHpEjhsSP4EMlxETXp4WzT7Dsti8 PQrI4/vuHbQE3tdQBQ7mpxRsjDA+rNooGd8kFF1siKQxSej/Va7Umpqe08C0RUpgynVv 2YLnNjWR8a+Ur6XhHtaeIPsKnzcjlFwbpq77MsNBK8Azs4GLxha9zTc1fWk77Y9MZvUH etay6TJz0T7SDyW5tCtf71xVUAD33RxAlS4DKf8fGUhVw1TzgnWSfVfPioRV2nAMYhEu zBTw== X-Gm-Message-State: AOJu0Yz9DDdF/U04rNDouozl3JsJ3RBge8c9PdGKufmUSxjiIyT3gBQl +aQyujJ3cWqmJU8QioR9Cj7mfOp2rG8vs6ClZnsAZxZKHC8+PcKpesZ0wDmh7jicCetQLGG1nfA FCRtYMMvdSDy0dRB1JosZwVsq5On0qM/yUfSZ8QctfbTpdlqJvZLhe3cMKYzWFa8NpA0xzjkH1q 385IVwnZywQ3/pvtOCDiQ2KwgtBmFlESXH6D1GKyY= X-Gm-Gg: ASbGncsPqVoxVa02yy9s2pbcPq5+Jic4z1eHv1wTGPkXExFP5uqZGrMQEnrEV1abUyh glhqqgeLhuU4cXzTeBgr1xfassHlO9s+j3Bo1UHOzYbs/1p7YZBMRMlKhErnakLPOmZuoOJq2WQ 9SlvNAlHYHzhd5ntY4exR8DGfSmMmNhavVLOYAmLoa/QSD3aGRJyGXlX/zVl6CRuIfNOBco36JP lYtD9ArqTI67r2Mrz2dAQtvMdB5w+IgdhFznkcbMrZq6c5txWkgrIPXRjEhp2bifcgziTE7psei lhPDnQ== X-Received: by 2002:a05:6402:2106:b0:5dc:8fb1:d44d with SMTP id 4fb4d7f45d1cf-5de450e21aamr2777324a12.31.1738923430081; Fri, 07 Feb 2025 02:17:10 -0800 (PST) X-Google-Smtp-Source: AGHT+IEYp/qCQKGqc9ALJGnFfpCzNDn5MW+i6Srj0+xOB+dOTx67uTb5tDI5ArxPFQFyZaPjizB/GA== X-Received: by 2002:a05:6402:2106:b0:5dc:8fb1:d44d with SMTP id 4fb4d7f45d1cf-5de450e21aamr2777286a12.31.1738923429553; Fri, 07 Feb 2025 02:17:09 -0800 (PST) Received: from [192.168.10.3] ([151.62.97.55]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5dcf1b739f8sm2283300a12.6.2025.02.07.02.17.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 02:17:03 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, zhao1.liu@intel.com Subject: [PATCH 08/12] rust: bindings: add Send and Sync markers for types that have bindings Date: Fri, 7 Feb 2025 11:16:19 +0100 Message-ID: <20250207101623.2443552-9-pbonzini@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250207101623.2443552-1-pbonzini@redhat.com> References: <20250207101623.2443552-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This is needed for the MemoryRegionOps to be declared as static; Rust requires static elements to be Sync. Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/qemu-api/src/bindings.rs | 46 +++++++++++++++++++++++++++++++++++ rust/qemu-api/src/irq.rs | 3 +++ 2 files changed, 49 insertions(+) diff --git a/rust/qemu-api/src/bindings.rs b/rust/qemu-api/src/bindings.rs index 8a9b821bb91..b71220113ef 100644 --- a/rust/qemu-api/src/bindings.rs +++ b/rust/qemu-api/src/bindings.rs @@ -21,9 +21,55 @@ #[cfg(not(MESON))] 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 {} + +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 {} + +// SAFETY: these are constants and vtables; the Send and Sync requirements +// are deferred to the unsafe callbacks that they contain +unsafe impl Send for MemoryRegionOps {} +unsafe impl Sync for MemoryRegionOps {} + unsafe impl Send for Property {} unsafe impl Sync for Property {} + +unsafe impl Send for TypeInfo {} unsafe impl Sync for TypeInfo {} + +unsafe impl Send for VMStateDescription {} unsafe impl Sync for VMStateDescription {} + +unsafe impl Send for VMStateField {} unsafe impl Sync for VMStateField {} + +unsafe impl Send for VMStateInfo {} unsafe impl Sync for VMStateInfo {} diff --git a/rust/qemu-api/src/irq.rs b/rust/qemu-api/src/irq.rs index 378e5202951..638545c3a64 100644 --- a/rust/qemu-api/src/irq.rs +++ b/rust/qemu-api/src/irq.rs @@ -43,6 +43,9 @@ pub struct InterruptSource _marker: PhantomData, } +// SAFETY: the implementation asserts via `BqlCell` that the BQL is taken +unsafe impl Sync for InterruptSource where c_int: From {} + impl InterruptSource { /// Send a low (`false`) value to the interrupt sink. pub fn lower(&self) { From patchwork Fri Feb 7 10:16:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13964730 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D0267C0219B for ; Fri, 7 Feb 2025 10:18:27 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tgLQR-00080r-7T; Fri, 07 Feb 2025 05:17:31 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLQJ-0007eU-Gf for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:17:24 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLQH-0004L7-3M for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:17:23 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738923440; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3cSSTTdboz+apeIJ4mIzJ7cmm1cZOm2bARcfKVsvDi0=; b=fLUusjt1rNC4vhVOmGdC9Fxo17ArH2D4t+dhQwW2WKBCVRivQiBAKC8vDZzdG9xseb2Apu nQ6YJUzyYN4hjfxUZD4YpBy4mGuCyEhdhh8tlaPxOeY4Eh3huUJLR733AVFVJ75No6gAIY pN+XA19VXPzD1gPj8LaeUUV3phfVqCw= Received: from mail-ej1-f70.google.com (mail-ej1-f70.google.com [209.85.218.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-523-SX9Hzgg2OZavnhyWPEb8mw-1; Fri, 07 Feb 2025 05:17:19 -0500 X-MC-Unique: SX9Hzgg2OZavnhyWPEb8mw-1 X-Mimecast-MFC-AGG-ID: SX9Hzgg2OZavnhyWPEb8mw Received: by mail-ej1-f70.google.com with SMTP id a640c23a62f3a-ab69e4c2563so247128066b.1 for ; Fri, 07 Feb 2025 02:17:18 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738923436; x=1739528236; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=3cSSTTdboz+apeIJ4mIzJ7cmm1cZOm2bARcfKVsvDi0=; b=Wpxde/paBuZNkA/IpXgIRGJlFgBqHBSJPtTtv5EuuJMPAyrPZuloVcYzA2OVLGJndM ITg4uJHFssFHYitilOd4TrmNq8Y/KeWuIuu4ZlBGS/xoiykkoFezmH74B/tbOZ5Sr2wf ck44ghEA0WlziJtdUPCebL+654TkAWb58TK3l9QKlovoEcRs0wceHzk7T3FJPoqVv4hC b1aENOKQ1JcDXu/rAur7FSLkGZ2UXsR2aAT0T7R7TfA8QDL8He8b5e9d0bcsWU6q6KnT BhFAvIoHMRk12fszbCCrd0e5Fegkx0dD7462dMhOtvpTG5dTpauZtG5FXbmk/bqLWaM9 cI4g== X-Gm-Message-State: AOJu0Yz+wIXGKSSLNqrXT6b/hnHH0IdU4mpjHOCUpMutJBxtxAK7zeFh W1Voku73zojlJHUm+huPQZGb2SxNWXuJpb4rsdDfwPkrPnN0ybyDUyoiPZGRdrHxSPwHtSgXfK4 D67bAp2p3zbPn5at5DS0ZMO9qVItNZM/R7kk5dUzd7jgpWidPJSJnHHzAUlJb1jBvxtD+vnU4SA +CeDV1MbeZPBuKwRJcV5fjz1hwo/YOEIWhI0za+DM= X-Gm-Gg: ASbGncvOsX7cUbPy1E9UkF6dseq6auSo7ZcFbVLtZlICuj40a+eraubJ9S4E9sie5x4 uoA+jCGYFAG+2RkID0NCRlI8tzr6w1sqJ15bUFQYpJ14vfoAHJ6TyE+GxCBmMEIHcyn1qh+igee WRkXNxOBtk54Xuw6oCqO+7a2WRE4JjHMVK04nljqIRryYRj2XaazVLZpcuqH17p8peiEs2UfPDC 3gTmgQ6mO8gAMisq3Zi7z9XNvdZL6+mAS2dlH242eJNC2+dJCYlV5K2CLKAU4KR0YQWyDsygSkJ LHWTgA== X-Received: by 2002:a17:906:9c94:b0:ab6:d6c3:f1e4 with SMTP id a640c23a62f3a-ab789c1d1c9mr198405066b.38.1738923435702; Fri, 07 Feb 2025 02:17:15 -0800 (PST) X-Google-Smtp-Source: AGHT+IEcRIx1tLxmMnWDIZ3rmy67uIFpCRxbXNj7iOv9GsmGkAPUINLJx1k+nK7pFjbd3/hB8Tm8QQ== X-Received: by 2002:a17:906:9c94:b0:ab6:d6c3:f1e4 with SMTP id a640c23a62f3a-ab789c1d1c9mr198400866b.38.1738923434902; Fri, 07 Feb 2025 02:17:14 -0800 (PST) Received: from [192.168.10.3] ([151.62.97.55]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ab772f843f4sm245053066b.68.2025.02.07.02.17.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 02:17:11 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, zhao1.liu@intel.com Subject: [PATCH 09/12] rust: bindings for MemoryRegionOps Date: Fri, 7 Feb 2025 11:16:20 +0100 Message-ID: <20250207101623.2443552-10-pbonzini@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250207101623.2443552-1-pbonzini@redhat.com> References: <20250207101623.2443552-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/hw/char/pl011/src/device.rs | 51 +++---- rust/hw/char/pl011/src/lib.rs | 1 - rust/hw/char/pl011/src/memory_ops.rs | 34 ----- rust/qemu-api/meson.build | 1 + rust/qemu-api/src/lib.rs | 1 + rust/qemu-api/src/memory.rs | 191 +++++++++++++++++++++++++++ rust/qemu-api/src/sysbus.rs | 7 +- rust/qemu-api/src/zeroable.rs | 1 + 8 files changed, 226 insertions(+), 61 deletions(-) delete mode 100644 rust/hw/char/pl011/src/memory_ops.rs create mode 100644 rust/qemu-api/src/memory.rs diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 1d0390b4fbe..5e4e75133c8 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -10,13 +10,14 @@ use qemu_api::{ bindings::{ - error_fatal, hwaddr, memory_region_init_io, qdev_prop_set_chr, qemu_chr_fe_accept_input, - qemu_chr_fe_ioctl, qemu_chr_fe_set_handlers, qemu_chr_fe_write_all, qemu_irq, - sysbus_connect_irq, sysbus_mmio_map, sysbus_realize, CharBackend, Chardev, MemoryRegion, - QEMUChrEvent, CHR_IOCTL_SERIAL_SET_BREAK, + error_fatal, qdev_prop_set_chr, qemu_chr_fe_accept_input, qemu_chr_fe_ioctl, + qemu_chr_fe_set_handlers, qemu_chr_fe_write_all, qemu_irq, sysbus_connect_irq, + sysbus_mmio_map, sysbus_realize, CharBackend, Chardev, QEMUChrEvent, + CHR_IOCTL_SERIAL_SET_BREAK, }, c_str, impl_vmstate_forward, irq::InterruptSource, + memory::{hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder}, prelude::*, qdev::{Clock, ClockEvent, DeviceImpl, DeviceState, Property, ResetType, ResettablePhasesImpl}, qom::{ClassInitImpl, ObjectImpl, Owned, ParentField}, @@ -26,7 +27,6 @@ use crate::{ device_class, - memory_ops::PL011_OPS, registers::{self, Interrupt}, RegisterOffset, }; @@ -487,20 +487,24 @@ impl PL011State { /// location/instance. All its fields are expected to hold unitialized /// values with the sole exception of `parent_obj`. unsafe fn init(&mut self) { + static PL011_OPS: MemoryRegionOps = MemoryRegionOpsBuilder::::new() + .read(&PL011State::read) + .write(&PL011State::write) + .native_endian() + .impl_sizes(4, 4) + .build(); + // SAFETY: // // self and self.iomem are guaranteed to be valid at this point since callers // must make sure the `self` reference is valid. - unsafe { - memory_region_init_io( - addr_of_mut!(self.iomem), - addr_of_mut!(*self).cast::(), - &PL011_OPS, - addr_of_mut!(*self).cast::(), - Self::TYPE_NAME.as_ptr(), - 0x1000, - ); - } + MemoryRegion::init_io( + unsafe { &mut *addr_of_mut!(self.iomem) }, + addr_of_mut!(*self), + &PL011_OPS, + "pl011", + 0x1000, + ); self.regs = Default::default(); @@ -525,7 +529,7 @@ fn post_init(&self) { } } - pub fn read(&mut self, offset: hwaddr, _size: u32) -> u64 { + pub fn read(&self, offset: hwaddr, _size: u32) -> u64 { match RegisterOffset::try_from(offset) { Err(v) if (0x3f8..0x400).contains(&(v >> 2)) => { let device_id = self.get_class().device_id; @@ -540,7 +544,7 @@ pub fn read(&mut self, offset: hwaddr, _size: u32) -> u64 { if update_irq { self.update(); unsafe { - qemu_chr_fe_accept_input(&mut self.char_backend); + qemu_chr_fe_accept_input(addr_of!(self.char_backend) as *mut _); } } result.into() @@ -548,7 +552,7 @@ pub fn read(&mut self, offset: hwaddr, _size: u32) -> u64 { } } - pub fn write(&mut self, offset: hwaddr, value: u64) { + pub fn write(&self, offset: hwaddr, value: u64, _size: u32) { let mut update_irq = false; if let Ok(field) = RegisterOffset::try_from(offset) { // qemu_chr_fe_write_all() calls into the can_receive @@ -561,14 +565,15 @@ pub fn write(&mut self, offset: hwaddr, value: u64) { // XXX this blocks entire thread. Rewrite to use // qemu_chr_fe_write and background I/O callbacks unsafe { - qemu_chr_fe_write_all(&mut self.char_backend, &ch, 1); + qemu_chr_fe_write_all(addr_of!(self.char_backend) as *mut _, &ch, 1); } } - update_irq = self - .regs - .borrow_mut() - .write(field, value as u32, &mut self.char_backend); + update_irq = self.regs.borrow_mut().write( + field, + value as u32, + addr_of!(self.char_backend) as *mut _, + ); } else { eprintln!("write bad offset {offset} value {value}"); } diff --git a/rust/hw/char/pl011/src/lib.rs b/rust/hw/char/pl011/src/lib.rs index e704daf6e3e..88452dc888c 100644 --- a/rust/hw/char/pl011/src/lib.rs +++ b/rust/hw/char/pl011/src/lib.rs @@ -27,7 +27,6 @@ mod device; mod device_class; -mod memory_ops; pub use device::pl011_create; diff --git a/rust/hw/char/pl011/src/memory_ops.rs b/rust/hw/char/pl011/src/memory_ops.rs deleted file mode 100644 index 432d3263898..00000000000 --- a/rust/hw/char/pl011/src/memory_ops.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2024, Linaro Limited -// Author(s): Manos Pitsidianakis -// SPDX-License-Identifier: GPL-2.0-or-later - -use core::ptr::NonNull; -use std::os::raw::{c_uint, c_void}; - -use qemu_api::{bindings::*, zeroable::Zeroable}; - -use crate::device::PL011State; - -pub static PL011_OPS: MemoryRegionOps = MemoryRegionOps { - read: Some(pl011_read), - write: Some(pl011_write), - read_with_attrs: None, - write_with_attrs: None, - endianness: device_endian::DEVICE_NATIVE_ENDIAN, - valid: Zeroable::ZERO, - impl_: MemoryRegionOps__bindgen_ty_2 { - min_access_size: 4, - max_access_size: 4, - ..Zeroable::ZERO - }, -}; - -unsafe extern "C" fn pl011_read(opaque: *mut c_void, addr: hwaddr, size: c_uint) -> u64 { - let mut state = NonNull::new(opaque).unwrap().cast::(); - unsafe { state.as_mut() }.read(addr, size) -} - -unsafe extern "C" fn pl011_write(opaque: *mut c_void, addr: hwaddr, data: u64, _size: c_uint) { - let mut state = NonNull::new(opaque).unwrap().cast::(); - unsafe { state.as_mut() }.write(addr, data); -} diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build index 60944a657de..80eafc7f6bd 100644 --- a/rust/qemu-api/meson.build +++ b/rust/qemu-api/meson.build @@ -22,6 +22,7 @@ _qemu_api_rs = static_library( 'src/cell.rs', 'src/c_str.rs', 'src/irq.rs', + 'src/memory.rs', 'src/module.rs', 'src/offset_of.rs', 'src/prelude.rs', diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs index 83c6a987c05..8cc095b13f6 100644 --- a/rust/qemu-api/src/lib.rs +++ b/rust/qemu-api/src/lib.rs @@ -18,6 +18,7 @@ pub mod callbacks; pub mod cell; pub mod irq; +pub mod memory; pub mod module; pub mod offset_of; pub mod qdev; diff --git a/rust/qemu-api/src/memory.rs b/rust/qemu-api/src/memory.rs new file mode 100644 index 00000000000..963d689c27d --- /dev/null +++ b/rust/qemu-api/src/memory.rs @@ -0,0 +1,191 @@ +// Copyright 2024 Red Hat, Inc. +// Author(s): Paolo Bonzini +// SPDX-License-Identifier: GPL-2.0-or-later + +//! Bindings for `MemoryRegion` and `MemoryRegionOps` + +use std::{ + ffi::{CStr, CString}, + marker::{PhantomData, PhantomPinned}, + os::raw::{c_uint, c_void}, + ptr::addr_of, +}; + +pub use bindings::hwaddr; + +use crate::{ + bindings::{self, device_endian, memory_region_init_io}, + callbacks::FnCall, + prelude::*, + zeroable::Zeroable, +}; + +pub struct MemoryRegionOps( + bindings::MemoryRegionOps, + // Note: quite often you'll see PhantomData mentioned when discussing + // covariance and contravariance; you don't need any of those to understand + // this usage of PhantomData. Quite simply, MemoryRegionOps *logically* + // holds callbacks that take an argument of type &T, except the type is erased + // before the callback is stored in the bindings::MemoryRegionOps field. + // The argument of PhantomData is a function pointer in order to represent + // that relationship; while that will also provide desirable and safe variance + // for T, variance is not the point but just a consequence. + PhantomData, +); + +// SAFETY: When a *const T is passed to the callbacks, the call itself +// is done in a thread-safe manner. The invocation is okay as long as +// T itself is `Sync`. +unsafe impl Sync for MemoryRegionOps {} + +#[derive(Clone)] +pub struct MemoryRegionOpsBuilder(bindings::MemoryRegionOps, PhantomData); + +unsafe extern "C" fn memory_region_ops_read_cb FnCall<(&'a T, hwaddr, u32), u64>>( + opaque: *mut c_void, + addr: hwaddr, + size: c_uint, +) -> u64 { + F::call((unsafe { &*(opaque.cast::()) }, addr, size)) +} + +unsafe extern "C" fn memory_region_ops_write_cb FnCall<(&'a T, hwaddr, u64, u32)>>( + opaque: *mut c_void, + addr: hwaddr, + data: u64, + size: c_uint, +) { + F::call((unsafe { &*(opaque.cast::()) }, addr, data, size)) +} + +impl MemoryRegionOpsBuilder { + #[must_use] + pub const fn read FnCall<(&'a T, hwaddr, u32), u64>>(mut self, _f: &F) -> Self { + self.0.read = Some(memory_region_ops_read_cb::); + self + } + + #[must_use] + pub const fn write FnCall<(&'a T, hwaddr, u64, u32)>>(mut self, _f: &F) -> Self { + self.0.write = Some(memory_region_ops_write_cb::); + self + } + + #[must_use] + pub const fn big_endian(mut self) -> Self { + self.0.endianness = device_endian::DEVICE_BIG_ENDIAN; + self + } + + #[must_use] + pub const fn little_endian(mut self) -> Self { + self.0.endianness = device_endian::DEVICE_LITTLE_ENDIAN; + self + } + + #[must_use] + pub const fn native_endian(mut self) -> Self { + self.0.endianness = device_endian::DEVICE_NATIVE_ENDIAN; + self + } + + #[must_use] + pub const fn valid_sizes(mut self, min: u32, max: u32) -> Self { + self.0.valid.min_access_size = min; + self.0.valid.max_access_size = max; + self + } + + #[must_use] + pub const fn valid_unaligned(mut self) -> Self { + self.0.valid.unaligned = true; + self + } + + #[must_use] + pub const fn impl_sizes(mut self, min: u32, max: u32) -> Self { + self.0.impl_.min_access_size = min; + self.0.impl_.max_access_size = max; + self + } + + #[must_use] + pub const fn impl_unaligned(mut self) -> Self { + self.0.impl_.unaligned = true; + self + } + + #[must_use] + pub const fn build(self) -> MemoryRegionOps { + MemoryRegionOps::(self.0, PhantomData) + } + + #[must_use] + pub const fn new() -> Self { + Self(bindings::MemoryRegionOps::ZERO, PhantomData) + } +} + +impl Default for MemoryRegionOpsBuilder { + fn default() -> Self { + Self::new() + } +} + +/// 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, +} + +impl MemoryRegion { + // inline to ensure that it is not included in tests, which only + // link to hwcore and qom. FIXME: inlining is actually the opposite + // of what we want, since this is the type-erased version of the + // init_io function below. Look into splitting the qemu_api crate. + #[inline(always)] + unsafe fn do_init_io( + slot: *mut bindings::MemoryRegion, + owner: *mut Object, + ops: &'static bindings::MemoryRegionOps, + name: &'static str, + size: u64, + ) { + unsafe { + let cstr = CString::new(name).unwrap(); + memory_region_init_io( + slot, + owner.cast::(), + ops, + owner.cast::(), + cstr.as_ptr(), + size, + ); + } + } + + pub fn init_io>( + &mut self, + owner: *mut T, + ops: &'static MemoryRegionOps, + name: &'static str, + size: u64, + ) { + unsafe { + Self::do_init_io(&mut self.inner, owner.cast::(), &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 { + type Class = bindings::MemoryRegionClass; + const TYPE_NAME: &'static CStr = + unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_MEMORY_REGION) }; +} +qom_isa!(MemoryRegion: Object); diff --git a/rust/qemu-api/src/sysbus.rs b/rust/qemu-api/src/sysbus.rs index e6762b5c145..c27dbf79e43 100644 --- a/rust/qemu-api/src/sysbus.rs +++ b/rust/qemu-api/src/sysbus.rs @@ -2,7 +2,7 @@ // Author(s): Paolo Bonzini // SPDX-License-Identifier: GPL-2.0-or-later -use std::{ffi::CStr, ptr::addr_of}; +use std::ffi::CStr; pub use bindings::{SysBusDevice, SysBusDeviceClass}; @@ -10,6 +10,7 @@ bindings, cell::bql_locked, irq::InterruptSource, + memory::MemoryRegion, prelude::*, qdev::{DeviceClass, DeviceState}, qom::ClassInitImpl, @@ -42,10 +43,10 @@ pub trait SysBusDeviceMethods: ObjectDeref /// 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) { + fn init_mmio(&self, iomem: &MemoryRegion) { assert!(bql_locked()); unsafe { - bindings::sysbus_init_mmio(self.as_mut_ptr(), addr_of!(*iomem) as *mut _); + bindings::sysbus_init_mmio(self.as_mut_ptr(), iomem.as_mut_ptr()); } } diff --git a/rust/qemu-api/src/zeroable.rs b/rust/qemu-api/src/zeroable.rs index 7b04947cb6c..75742b50d4e 100644 --- a/rust/qemu-api/src/zeroable.rs +++ b/rust/qemu-api/src/zeroable.rs @@ -100,3 +100,4 @@ fn default() -> Self { impl_zeroable!(crate::bindings::VMStateDescription); impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_1); impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_2); +impl_zeroable!(crate::bindings::MemoryRegionOps); From patchwork Fri Feb 7 10:16:21 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13964736 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id AD683C0219B for ; Fri, 7 Feb 2025 10:19:05 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tgLQO-0007ob-8k; Fri, 07 Feb 2025 05:17:28 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLQM-0007hg-HW for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:17:26 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLQL-0004Lq-04 for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:17:26 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738923444; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2zMrreiA6fXml/tyoB0xwdzip2po3nTWUJjLq04bCbM=; b=IvYEJZ72oWYtUSSx4XRXvato5E8FkAOh96jAoKZb7d+ZOdUznF8/CddXVMiQj5sVSnYbPC UARdTWNaLhv41T/B/QiP6OvWNLZatNJ2kwnStVeSZLq6+qvYAmNAATHw0lrUWsNn2cCSde OQhpb9IL9tAKlBiO5EV2Ghh5T9OyKNI= Received: from mail-ej1-f72.google.com (mail-ej1-f72.google.com [209.85.218.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-625-CJXagb1hP5CU44sSqsF9Hg-1; Fri, 07 Feb 2025 05:17:23 -0500 X-MC-Unique: CJXagb1hP5CU44sSqsF9Hg-1 X-Mimecast-MFC-AGG-ID: CJXagb1hP5CU44sSqsF9Hg Received: by mail-ej1-f72.google.com with SMTP id a640c23a62f3a-ab2e44dc9b8so312118166b.1 for ; Fri, 07 Feb 2025 02:17:22 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738923441; x=1739528241; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=2zMrreiA6fXml/tyoB0xwdzip2po3nTWUJjLq04bCbM=; b=Sqg9O7QTEVy0KLeXvq9hnUp1aWim+m657Y1Qgy/lTwbedKf/yRu2zpCs7v83uLtOVU /64Wo2qhXajVS8fcrPZkq59wdlkmFt+knwPrjKfnTQt9+4eqF0sGPJTOpWwaT1H1jtw+ T9Lze1LdvXfDuqT9rOCLZfe5krkzbsBjew6c8sI5uSECvKusHWrUG5uHRDoP5jHyMLGA 7V0IjiHDBJeYBlg4I+sygZKNrqVNsRf/8oI4jR/qS3al21KXSGLybdiVAp0ULvclpCiS wR5d1BKR1PGtVur+iVeT+R1HPpenIvRl9659Qkd7XHxhtSRgUR/iN9pcoEy1RfMxGLeS PfpA== X-Gm-Message-State: AOJu0YwZbbr0bJCD9HyG6HfjR81Der2Yx1GcilQ6TKuGf2XjH8shWvKI xR4vpqs3Xab0bljUx4nCIHx8YOw9an5NWORcmPtnyVb5dIaKDPlP/7xonAwse2opsp1ol3Na7vb WBNpdaCkYfKg6Tu+M72iIB6dM62O+8MlcdoWaRQL+f8yqodPPbmYCVN3gIMAdiyoMioRN6rZ1iL RNVW57BeFJk+BoWg+Yci4VTNMevZvPZigi7MboOrY= X-Gm-Gg: ASbGncuOyMFRK+lTUtViR5rmU8v1R0gqwPlUw5++k7o+5PBdqr6Jb9yZ1BZxccsecrd Yd/CkMGAzp3y4us49E7jzRIGHAtwm5so2c9pbMVmNiTEHFZxH9AOalhDi6ceAAGHHeyBvW3HNpy 6X8yGqhvM2VgP6E1UIiUjwiWCsdGZcb4fP4We/Wb8k8IjwnOnUxFm4j0vNBaAgHDpIOqarKe5hg EUOwuIqrykjj7B5LTn+PpQZ2mPbOrixcDiq+n7+hFR0T2lLFVCQsvSIFBzht9kjE7OcN5DVlF5E YZfD2A== X-Received: by 2002:a17:907:6d0e:b0:ab6:cdc2:3417 with SMTP id a640c23a62f3a-ab76e8cef13mr685456966b.15.1738923441006; Fri, 07 Feb 2025 02:17:21 -0800 (PST) X-Google-Smtp-Source: AGHT+IE6CjID0RSFN1ybO48T/D2riX1cvSrYvRckWhyBsi/kD+UvPszJG/T/VWvUl46MIRHbYT/twA== X-Received: by 2002:a17:907:6d0e:b0:ab6:cdc2:3417 with SMTP id a640c23a62f3a-ab76e8cef13mr685452266b.15.1738923440500; Fri, 07 Feb 2025 02:17:20 -0800 (PST) Received: from [192.168.10.3] ([151.62.97.55]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ab78405313dsm146061166b.55.2025.02.07.02.17.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 02:17:16 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, zhao1.liu@intel.com Subject: [PATCH 10/12] rust: irq: define ObjectType for IRQState Date: Fri, 7 Feb 2025 11:16:21 +0100 Message-ID: <20250207101623.2443552-11-pbonzini@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250207101623.2443552-1-pbonzini@redhat.com> References: <20250207101623.2443552-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This is a small preparation in order to use an Owned for the argument to sysbus_connect_irq. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/qemu-api/src/irq.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/rust/qemu-api/src/irq.rs b/rust/qemu-api/src/irq.rs index 638545c3a64..835b027d5e5 100644 --- a/rust/qemu-api/src/irq.rs +++ b/rust/qemu-api/src/irq.rs @@ -5,11 +5,12 @@ //! Bindings for interrupt sources use core::ptr; -use std::{marker::PhantomData, os::raw::c_int}; +use std::{ffi::CStr, marker::PhantomData, os::raw::c_int}; use crate::{ - bindings::{qemu_set_irq, IRQState}, + bindings::{self, qemu_set_irq}, prelude::*, + qom::ObjectClass, }; /// Interrupt sources are used by devices to pass changes to a value (typically @@ -21,7 +22,8 @@ /// 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 @@ -91,3 +93,10 @@ fn default() -> Self { } } } + +unsafe impl ObjectType for IRQState { + type Class = ObjectClass; + const TYPE_NAME: &'static CStr = + unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_IRQ) }; +} +qom_isa!(IRQState: Object); From patchwork Fri Feb 7 10:16:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13964734 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id AA44DC02196 for ; Fri, 7 Feb 2025 10:18:59 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tgLQS-000865-MM; Fri, 07 Feb 2025 05:17:32 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLQQ-00080E-Op for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:17:30 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLQP-0004MU-13 for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:17:30 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738923448; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=aKHP+M1YbRMZ4IFrh+t3bRBHjugSohWNkvOiKtYRuX0=; b=UaAUiSWpIRWZf17yN1D7gFgshzvAzkdivKrC0jOuk86Nmrz+9ebyS9NVeOo8MdrAevQNFG Ea4JW2pQVbZJH594U6yjlhpypLnHRq42UfIYVtDUg0bMyZVZeFE06yl7EpHY0Ky9qWl1aT t09HE7NLjUv/Ioet7W7Z+Tix+0E61V0= Received: from mail-ej1-f69.google.com (mail-ej1-f69.google.com [209.85.218.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-93-Cm-MlBMpNX-bD5gx_R60VQ-1; Fri, 07 Feb 2025 05:17:27 -0500 X-MC-Unique: Cm-MlBMpNX-bD5gx_R60VQ-1 X-Mimecast-MFC-AGG-ID: Cm-MlBMpNX-bD5gx_R60VQ Received: by mail-ej1-f69.google.com with SMTP id a640c23a62f3a-aa67f03ca86so137824466b.2 for ; Fri, 07 Feb 2025 02:17:27 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738923444; x=1739528244; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=aKHP+M1YbRMZ4IFrh+t3bRBHjugSohWNkvOiKtYRuX0=; b=GMSUq9/aZbZldIDUT6+UNv5zdJI+rV5FrUvKJX4PWsjSvB75D0cg9nknnrryIyQKUc x91CNASTtLIRcVFyJQX9rryTs2/TwYfC5GeWOOrfX+deI7TvYFXdfZy3gCFfXF+d3JLC GDKtT3hH0DsjW6ODHkAciGi6ojeSqbO4ighqxwxEaH0ORNI2eCgd1iUMiylk9M3XHcGW ppq1MbU5pfKj3SKJnX3S25iTdBHh8UQfCoEhAariNGjmpaD6oG0oKDzNn+fC9J2UFcLv Hy+Yzrt3Vw8vGLwE2WxuyPfpG96zUEnIf3I9xvcygccSFwTbocjp7zIlUEupzaGRzrhQ AKtA== X-Gm-Message-State: AOJu0YxvfL0F0OO1tMsEsCrC4TMUzRG4F4TWSsp17jTYeg70MBTCUWU1 9dDv+SrbnfWNtNLHJnxY4OrZxma9EDGzuDvkJxh6fINDgkIpVwh/i0sVc1eT8L25BFi52Cta8ut 0c47bH0+EpE2mBuCs1lqTz3Q5290nA5DytkL7XEhFBJzHeDhs2Yx+tsEHtcKkLwOKi6htaYkM5e ix2w5VMdFAOKRjEwJSooXcqvHwanpM8S2cfgAFU6E= X-Gm-Gg: ASbGncsKvPO49whNTx2/NcagMpXq2DmY+YKqHVJ8uM+i9+OtJ9FtEj/YiLdroln/cTh M6Dc+17lkdfhJ1ybJAQ4ZkgNS8e1LVkVL7ZJXeXwJVgQ0SMqpmpmHW2rhPQA2KrYmBItnbzgyui 1ien0+Zod3fckFBfvAF66oR014ThHAW4RtJJRIbyBvUEEvn92XfBtLddkw24BzpPg9evjHwg9Gi fzEH4i120UyEOBfWDg088pwAw2UlI0GxBx/25ztp89WxpJXNXqv3IgOFwlNSJ/kfQdbrxKnzbga ExQpUg== X-Received: by 2002:a05:6402:2392:b0:5de:4a8b:4c9c with SMTP id 4fb4d7f45d1cf-5de4a8b4fc4mr3255591a12.32.1738923444191; Fri, 07 Feb 2025 02:17:24 -0800 (PST) X-Google-Smtp-Source: AGHT+IFfsoSU1JKMR6X86QsmGLSD3TaYkv4VQukNlw/UjcAmcXXn4FgyZ4tohgtK6GEsxcTAsO+s9g== X-Received: by 2002:a05:6402:2392:b0:5de:4a8b:4c9c with SMTP id 4fb4d7f45d1cf-5de4a8b4fc4mr3255525a12.32.1738923443524; Fri, 07 Feb 2025 02:17:23 -0800 (PST) Received: from [192.168.10.3] ([151.62.97.55]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5dcf1b85a4dsm2272828a12.47.2025.02.07.02.17.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 02:17:21 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, zhao1.liu@intel.com Subject: [PATCH 11/12] rust: chardev, qdev: add bindings to qdev_prop_set_chr Date: Fri, 7 Feb 2025 11:16:22 +0100 Message-ID: <20250207101623.2443552-12-pbonzini@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250207101623.2443552-1-pbonzini@redhat.com> References: <20250207101623.2443552-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Because the argument to the function is an Owned, this also adds an ObjectType implementation to Chardev. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/hw/char/pl011/src/device.rs | 1 + rust/qemu-api/meson.build | 1 + rust/qemu-api/src/chardev.rs | 19 +++++++++++++++++++ rust/qemu-api/src/lib.rs | 1 + rust/qemu-api/src/qdev.rs | 9 +++++++++ 5 files changed, 31 insertions(+) create mode 100644 rust/qemu-api/src/chardev.rs diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 5e4e75133c8..22f3ca3b4e8 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -15,6 +15,7 @@ sysbus_mmio_map, sysbus_realize, CharBackend, Chardev, QEMUChrEvent, CHR_IOCTL_SERIAL_SET_BREAK, }, + chardev::Chardev, c_str, impl_vmstate_forward, irq::InterruptSource, memory::{hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder}, diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build index 80eafc7f6bd..45e30324b29 100644 --- a/rust/qemu-api/meson.build +++ b/rust/qemu-api/meson.build @@ -20,6 +20,7 @@ _qemu_api_rs = static_library( 'src/bitops.rs', 'src/callbacks.rs', 'src/cell.rs', + 'src/chardev.rs', 'src/c_str.rs', 'src/irq.rs', 'src/memory.rs', diff --git a/rust/qemu-api/src/chardev.rs b/rust/qemu-api/src/chardev.rs new file mode 100644 index 00000000000..74cfb634e5f --- /dev/null +++ b/rust/qemu-api/src/chardev.rs @@ -0,0 +1,19 @@ +// Copyright 2024 Red Hat, Inc. +// Author(s): Paolo Bonzini +// SPDX-License-Identifier: GPL-2.0-or-later + +//! Bindings for character devices + +use std::ffi::CStr; + +use crate::{bindings, prelude::*}; + +pub type Chardev = bindings::Chardev; +pub type ChardevClass = bindings::ChardevClass; + +unsafe impl ObjectType for Chardev { + type Class = ChardevClass; + const TYPE_NAME: &'static CStr = + unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_CHARDEV) }; +} +qom_isa!(Chardev: Object); diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs index 8cc095b13f6..1d7112445e2 100644 --- a/rust/qemu-api/src/lib.rs +++ b/rust/qemu-api/src/lib.rs @@ -17,6 +17,7 @@ pub mod c_str; pub mod callbacks; pub mod cell; +pub mod chardev; pub mod irq; pub mod memory; pub mod module; diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs index 2ec1ecc8489..0041c66ed0c 100644 --- a/rust/qemu-api/src/qdev.rs +++ b/rust/qemu-api/src/qdev.rs @@ -16,6 +16,7 @@ bindings::{self, Error, ResettableClass}, callbacks::FnCall, cell::bql_locked, + chardev::Chardev, prelude::*, qom::{ClassInitImpl, ObjectClass, ObjectImpl, Owned}, vmstate::VMStateDescription, @@ -299,6 +300,14 @@ fn init_clock_out(&self, name: &str) -> Owned { Owned::from(&*clk) } } + + fn prop_set_chr(&self, propname: &str, chr: &Owned) { + assert!(bql_locked()); + let c_propname = CString::new(propname).unwrap(); + unsafe { + bindings::qdev_prop_set_chr(self.as_mut_ptr(), c_propname.as_ptr(), chr.as_mut_ptr()); + } + } } impl DeviceMethods for R where R::Target: IsA {} From patchwork Fri Feb 7 10:16:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 13964732 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 8CDEEC0219B for ; Fri, 7 Feb 2025 10:18:37 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tgLQh-0008LK-W9; Fri, 07 Feb 2025 05:17:48 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLQV-00089n-Ac for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:17:35 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tgLQT-0004Nq-9w for qemu-devel@nongnu.org; Fri, 07 Feb 2025 05:17:34 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1738923452; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=oC4sSczyHUPcW1OOZ38NHr8TjI3/9SwgCw7OQNwY7a8=; b=dkdr8XWp5T2b/AMVWspnyvaQ9qcwp/GzK8vTXnPH+/Tkd1VLAn1yiIV4VBuE3WqvEp2422 GBw6QuBEEUcHkpqznN7RwSInb30mz6VFuSa4HCjNh+rMNVc/KQZaoN+3VoNVntlY83Xcli KFi3MXSmGEC/kW4O1LJGsztWOY65bnc= Received: from mail-ej1-f70.google.com (mail-ej1-f70.google.com [209.85.218.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-214-HLDGdtmWO6WdQakRnONK8Q-1; Fri, 07 Feb 2025 05:17:31 -0500 X-MC-Unique: HLDGdtmWO6WdQakRnONK8Q-1 X-Mimecast-MFC-AGG-ID: HLDGdtmWO6WdQakRnONK8Q Received: by mail-ej1-f70.google.com with SMTP id a640c23a62f3a-ab7912ce928so24637266b.0 for ; Fri, 07 Feb 2025 02:17:31 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738923449; x=1739528249; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=oC4sSczyHUPcW1OOZ38NHr8TjI3/9SwgCw7OQNwY7a8=; b=MVavbQDi66lxcjcciR3rXxJJYvhZjLXYhpVtbafXmG+JLFBqxrdLq1oWKzMg0e4Y+U wa8vWWItVjLyBHA4Xz3xpvKe9LH4QsbCb1Hl4Jhj1qLy5/fuTY5Qi9gFjjfLOCxBOBoz UNbnVwjeIBMl7U5zQJ8h5kWrQBavcRow21kfmyxkWoFNu4Nb/ArugrawBmrWku4K4xaB zgwmCytjn/AXhaZDeSvfP8fNar4bLzYgXRev4a0W3ZdHWv+JKNXJOtASI3GmKrxL0BC+ p6V2Q/85KwtGxDStqV5AGcRjugp+Di6D9xTRya5G8BuqxE0X/0/gOnvXykRHL2txmQcD oXMw== X-Gm-Message-State: AOJu0YzuXHpa/wE+y2Gh3ulE0/mIKBRLHiwWiQZlirOYGD+95vfTT1mO mffduzdrQFsooZnC+bOidBgpdTYgEhf6ePR5Af252ZtbtOP7RKIVgHa2VvpnsrQagGyQAfxjZOi QuMo6Hi8RBO0cdpaNwdzokB7WzwCnZKmNsvIhalJgM4HyWxMK0VvRz93uRbNCM8MajIWOxrJkTR IipTJB99zvmQ3jMqHwvRI7ixgV5fHavp8rf8K4vlc= X-Gm-Gg: ASbGncuO2LFVv1auo/Pr+Mg+cuVpv6Ai8ZNIBsipTo/jfoJd4OdWym5rYqWIJUBx7TP w6o+/HA13jTriOSzr9wsmpAt9/JRphwZ4wOFANnVPu+jGLWRq7M7EDeIEhidYkOUtdoQVB828Qv aakX91tDChAo9ckJwCC5DTL9TvhBafPTxkr10kLLTpAOYPyDf0ELuZBYf+hDmp4zY2R8i2GzZ6a uWBf1msGpdU0jZ5LSey+P//KCW5VdR6SGKu5OBUmUoNUopyePLseZjqMmN3HSvpE1m72mzmfTcU dZm7GQ== X-Received: by 2002:a17:907:d08d:b0:ab7:6d49:2c03 with SMTP id a640c23a62f3a-ab789c60410mr215138466b.19.1738923449222; Fri, 07 Feb 2025 02:17:29 -0800 (PST) X-Google-Smtp-Source: AGHT+IFe0xsu8AxCXKMVsluGB+rII8w3U/NIqVdeJNW6ztpaWVv5HgBhXR4pXND5uDrb6wiZzetH/g== X-Received: by 2002:a17:907:d08d:b0:ab7:6d49:2c03 with SMTP id a640c23a62f3a-ab789c60410mr215134966b.19.1738923448776; Fri, 07 Feb 2025 02:17:28 -0800 (PST) Received: from [192.168.10.3] ([151.62.97.55]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ab7732e6192sm238995966b.121.2025.02.07.02.17.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Feb 2025 02:17:25 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, zhao1.liu@intel.com Subject: [PATCH 12/12] rust: pl011: convert pl011_create to safe Rust Date: Fri, 7 Feb 2025 11:16:23 +0100 Message-ID: <20250207101623.2443552-13-pbonzini@redhat.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250207101623.2443552-1-pbonzini@redhat.com> References: <20250207101623.2443552-1-pbonzini@redhat.com> MIME-Version: 1.0 Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Not a major change but, as a small but significant step in creating qdev bindings, show how pl011_create can be written without "unsafe" calls (apart from converting pointers to references). This also provides a starting point for creating Error** bindings. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/hw/char/pl011/src/device.rs | 39 ++++++++++++++++---------------- rust/qemu-api/src/sysbus.rs | 34 +++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 22f3ca3b4e8..7e936b50eb0 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -10,14 +10,12 @@ use qemu_api::{ bindings::{ - error_fatal, qdev_prop_set_chr, qemu_chr_fe_accept_input, qemu_chr_fe_ioctl, - qemu_chr_fe_set_handlers, qemu_chr_fe_write_all, qemu_irq, sysbus_connect_irq, - sysbus_mmio_map, sysbus_realize, CharBackend, Chardev, QEMUChrEvent, - CHR_IOCTL_SERIAL_SET_BREAK, + qemu_chr_fe_accept_input, qemu_chr_fe_ioctl, qemu_chr_fe_set_handlers, + qemu_chr_fe_write_all, CharBackend, QEMUChrEvent, CHR_IOCTL_SERIAL_SET_BREAK, }, chardev::Chardev, - c_str, impl_vmstate_forward, - irq::InterruptSource, + impl_vmstate_forward, + irq::{IRQState, InterruptSource}, memory::{hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder}, prelude::*, qdev::{Clock, ClockEvent, DeviceImpl, DeviceState, Property, ResetType, ResettablePhasesImpl}, @@ -698,26 +696,27 @@ pub fn post_load(&self, _version_id: u32) -> Result<(), ()> { /// # Safety /// -/// We expect the FFI user of this function to pass a valid pointer for `chr`. +/// We expect the FFI user of this function to pass a valid pointer for `chr` +/// and `irq`. #[no_mangle] pub unsafe extern "C" fn pl011_create( addr: u64, - irq: qemu_irq, + irq: *mut IRQState, chr: *mut Chardev, ) -> *mut DeviceState { - let pl011 = PL011State::new(); - unsafe { - let dev = pl011.as_mut_ptr::(); - qdev_prop_set_chr(dev, c_str!("chardev").as_ptr(), chr); + // SAFETY: The callers promise that they have owned references. + // They do not gift them to pl011_create, so use `Owned::from`. + let irq = unsafe { Owned::::from(&*irq) }; + let chr = unsafe { Owned::::from(&*chr) }; - let sysbus = pl011.as_mut_ptr::(); - sysbus_realize(sysbus, addr_of_mut!(error_fatal)); - sysbus_mmio_map(sysbus, 0, addr); - sysbus_connect_irq(sysbus, 0, irq); - - // return the pointer, which is kept alive by the QOM tree; drop owned ref - pl011.as_mut_ptr() - } + let dev = PL011State::new(); + dev.prop_set_chr("chardev", &chr); + dev.realize(); + dev.mmio_map(0, addr); + dev.connect_irq(0, &irq); + // SAFETY: return the pointer, which has to be mutable and is kept alive + // by the QOM tree; drop owned ref + unsafe { dev.as_mut_ptr() } } #[repr(C)] diff --git a/rust/qemu-api/src/sysbus.rs b/rust/qemu-api/src/sysbus.rs index c27dbf79e43..1f071706ce8 100644 --- a/rust/qemu-api/src/sysbus.rs +++ b/rust/qemu-api/src/sysbus.rs @@ -2,18 +2,18 @@ // Author(s): Paolo Bonzini // SPDX-License-Identifier: GPL-2.0-or-later -use std::ffi::CStr; +use std::{ffi::CStr, ptr::addr_of_mut}; pub use bindings::{SysBusDevice, SysBusDeviceClass}; use crate::{ bindings, cell::bql_locked, - irq::InterruptSource, + irq::{IRQState, InterruptSource}, memory::MemoryRegion, prelude::*, qdev::{DeviceClass, DeviceState}, - qom::ClassInitImpl, + qom::{ClassInitImpl, Owned}, }; unsafe impl ObjectType for SysBusDevice { @@ -60,6 +60,34 @@ fn init_irq(&self, irq: &InterruptSource) { bindings::sysbus_init_irq(self.as_mut_ptr(), irq.as_ptr()); } } + + // TODO: do we want a type like GuestAddress here? + fn mmio_map(&self, id: u32, addr: u64) { + assert!(bql_locked()); + let id: i32 = id.try_into().unwrap(); + unsafe { + bindings::sysbus_mmio_map(self.as_mut_ptr(), id, addr); + } + } + + // Owned<> is used here because sysbus_connect_irq (via + // object_property_set_link) adds a reference to the IRQState, + // which can prolong its life + fn connect_irq(&self, id: u32, irq: &Owned) { + assert!(bql_locked()); + let id: i32 = id.try_into().unwrap(); + unsafe { + bindings::sysbus_connect_irq(self.as_mut_ptr(), id, irq.as_mut_ptr()); + } + } + + fn realize(&self) { + // TODO: return an Error + assert!(bql_locked()); + unsafe { + bindings::sysbus_realize(self.as_mut_ptr(), addr_of_mut!(bindings::error_fatal)); + } + } } impl SysBusDeviceMethods for R where R::Target: IsA {}