From nobody Wed Dec 17 06:17:35 2025 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BBDA6C8E1 for ; Mon, 17 Jun 2024 20:30:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718656228; cv=none; b=MXw1rNkNRNwNg67MrcFCzCXLt/NTCFPIcQ5LIezpxXznqlOXG/QLTdu/eNc6OCVfuVYqnz+i9Sjz1rktw5BM4KH7Aiwg40m5kRmT+Q0Cz2/m1hF3j++rRca7S8P1fL6bXKqqk1Vbi4Qgp73HOzDfufyV2T+pojE9SMfZtpWGdxk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718656228; c=relaxed/simple; bh=A8M6FF7htEPo5boFGolkHiGeAc6qKIiKNMl16i3X2mY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=X0f3+tnFYXPUs42Y0BiOV2+XLtrBhU42snjGcz2x3SIfrV6Gjj3BJGKUteTE5X45t/rpB0E9MtowGOB8LyhRhZ4mF7WAvuWF4jrcrIp898t7gMZRKzgtfIBrrEes2Z55waLlDPDeHk91atHS7W5WgCFBnpcHQ5YE7N6+Be3TmSc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=GQV4JxS2; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="GQV4JxS2" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1718656224; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xI+z2ALaUfW3Qgvh6spulMhk7FV84f8kGNKB6ILw4nc=; b=GQV4JxS2ybAXnS9rL8ekpcU4u5ieYquJIJXuMLEo9BrRVc6DikDD87yYUF/cg5qOdwvJuE fbmYqQvAdQdJ8wvPUtL1pX+BV8bHnZSJsG51NHtOdxA37X+zKvPQQGMNuFZG5joc52tkom 2aktG4t6wmGpGukoiUAvooFhSfsL+4o= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-264-YPBhcbmxMo2dex7bHl_JmA-1; Mon, 17 Jun 2024 16:30:23 -0400 X-MC-Unique: YPBhcbmxMo2dex7bHl_JmA-1 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-4246e5fd996so3196505e9.0 for ; Mon, 17 Jun 2024 13:30:23 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718656222; x=1719261022; 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=xI+z2ALaUfW3Qgvh6spulMhk7FV84f8kGNKB6ILw4nc=; b=VzMCxkuFFvllsr53HpItyXpaf/p1CvChhFNb8WRfG5FtIy8ZpqNfvEXMfkjVd3bmpT zErmKNiaBEyY6h9lyv5GvwSo/XTtSvUBzm+T6Fh6a/LhOV8M/RvFDhl9G7VNn3X4us/5 aEVGE9uPO6wgyeDa6ZMqEJ4iliGDvk5PMFNq+qNyNj64Kz5rr7ZMmBMfo7mNEjvPxMQG DrZEE20RELaLj/+dDONCDSdJwRITxyK/hZ7j6JJUTcxUNGr4HT089BssszIIj7OSg7Ho lxaUbXzeJhMSgi3i00w2cI885ZeHRxoKHOxDbWT22D2dckbC9PNgpR/owkenC/0WzkzV Rmmg== X-Forwarded-Encrypted: i=1; AJvYcCUgeK6+UJrdpQkm2VvsugBXX3WODZrgsBVvsiluXjZMrXDNXsn5hakUbHt4AS3rVNLttE828zTrtXSeMvxFgDarv0E09HW775qaKGXN X-Gm-Message-State: AOJu0YztvEYtB/yLfF//A73gFhHY32dcMKRosEqHLUu+VkKXHX+3mZOU vAge8ZpYM7ALaKDMqmSwGuplgzIaenEX+80LoxwF1wfmvL78HIvxZDRP9KckQT2LD/+u+XhC1rR utqmzP0MWkxfUsEXRdDAGkAECffQl2HskUPJszFLG4MO9nTC/DccNQxJvCq/59Q== X-Received: by 2002:a05:600c:1d82:b0:420:ffe3:8536 with SMTP id 5b1f17b1804b1-42304854ecdmr88725985e9.37.1718656222031; Mon, 17 Jun 2024 13:30:22 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHmp0ZVVmRphzqmYQn2Ly27dG0tqw083L13j4r8JcE0pxXR+Ka+RQpWXbiA8+YnOYH4G8hKeg== X-Received: by 2002:a05:600c:1d82:b0:420:ffe3:8536 with SMTP id 5b1f17b1804b1-42304854ecdmr88725825e9.37.1718656221727; Mon, 17 Jun 2024 13:30:21 -0700 (PDT) Received: from cassiopeiae.. ([2a02:810d:4b3f:ee94:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-422a1e68d04sm185142205e9.36.2024.06.17.13.30.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jun 2024 13:30:20 -0700 (PDT) From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, mcgrof@kernel.org, russ.weight@linux.dev, ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, airlied@gmail.com, fujita.tomonori@gmail.com, pstanner@redhat.com, ajanulgu@redhat.com, lyude@redhat.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH v3 1/2] rust: add abstraction for struct device Date: Mon, 17 Jun 2024 22:29:40 +0200 Message-ID: <20240617203010.101452-2-dakr@redhat.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240617203010.101452-1-dakr@redhat.com> References: <20240617203010.101452-1-dakr@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Add an (always) reference-counted abstraction for a generic C `struct device`. This abstraction encapsulates existing `struct device` instances and manages its reference count. Subsystems may use this abstraction as a base to abstract subsystem specific device instances based on a generic `struct device`, such as `struct pci_dev`. Co-developed-by: Wedson Almeida Filho Signed-off-by: Wedson Almeida Filho Signed-off-by: Danilo Krummrich Acked-by: Greg Kroah-Hartman --- rust/helpers.c | 1 + rust/kernel/device.rs | 102 ++++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 3 files changed, 104 insertions(+) create mode 100644 rust/kernel/device.rs diff --git a/rust/helpers.c b/rust/helpers.c index 2c37a0f5d7a8..0e02b2c64c72 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs new file mode 100644 index 000000000000..e445e87fb7d7 --- /dev/null +++ b/rust/kernel/device.rs @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Generic devices that are part of the kernel's driver model. +//! +//! C header: [`include/linux/device.h`](srctree/include/linux/device.h) + +use crate::{ + bindings, + types::{ARef, Opaque}, +}; +use core::ptr; + +/// A reference-counted device. +/// +/// This structure represents the Rust abstraction for a C `struct device`= . This implementation +/// abstracts the usage of an already existing C `struct device` within Ru= st code that we get +/// passed from the C side. +/// +/// An instance of this abstraction can be obtained temporarily or permane= nt. +/// +/// A temporary one is bound to the lifetime of the C `struct device` poin= ter used for creation. +/// A permanent instance is always reference-counted and hence not restric= ted by any lifetime +/// boundaries. +/// +/// For subsystems it is recommended to create a permanent instance to wra= p into a subsystem +/// specific device structure (e.g. `pci::Device`). This is useful for pas= sing it to drivers in +/// `T::probe()`, such that a driver can store the `ARef` (equival= ent to storing a +/// `struct device` pointer in a C driver) for arbitrary purposes, e.g. al= locating DMA coherent +/// memory. +/// +/// # Invariants +/// +/// The pointer stored in `Self` is non-null and valid for the lifetime of= the `ARef` instance. In +/// particular, the `ARef` instance owns an increment on the underlying ob= ject=E2=80=99s reference count. +/// +/// `bindings::device::release` is valid to be called from any thread, hen= ce `ARef` can be +/// dropped from any thread. +#[repr(transparent)] +pub struct Device(Opaque); + +impl Device { + /// Creates a new reference-counted abstraction instance of an existin= g `struct device` pointer. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid, non-null, and has a non-z= ero reference count, + /// i.e. it must be ensured that the reference count of the C `struct = device` `ptr` points to + /// can't drop to zero, for the duration of this function call. + /// + /// It must also be ensured that `bindings::device::release` can be ca= lled from any thread. + /// While not officially documented, this should be the case for any `= struct device`. + pub unsafe fn from_raw(ptr: *mut bindings::device) -> ARef { + // SAFETY: By the safety requirements, ptr is valid. + // Initially increase the reference count by one to compensate for= the final decrement once + // this newly created `ARef` instance is dropped. + unsafe { bindings::get_device(ptr) }; + + // CAST: `Self` is a `repr(transparent)` wrapper around `bindings:= :device`. + let ptr =3D ptr.cast::(); + + // SAFETY: By the safety requirements, ptr is valid. + unsafe { ARef::from_raw(ptr::NonNull::new_unchecked(ptr)) } + } + + /// Obtain the raw `struct device *`. + pub(crate) fn as_raw(&self) -> *mut bindings::device { + self.0.get() + } + + /// Convert a raw C `struct device` pointer to a `&'a Device`. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is valid, non-null, and has a non-z= ero reference count, + /// i.e. it must be ensured that the reference count of the C `struct = device` `ptr` points to + /// can't drop to zero, for the duration of this function call and the= entire duration when the + /// returned reference exists. + pub unsafe fn as_ref<'a>(ptr: *mut bindings::device) -> &'a Self { + // SAFETY: Guaranteed by the safety requirements of the function. + unsafe { &*ptr.cast() } + } +} + +// SAFETY: Instances of `Device` are always reference-counted. +unsafe impl crate::types::AlwaysRefCounted for Device { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference guarantees that the= refcount is non-zero. + unsafe { bindings::get_device(self.as_raw()) }; + } + + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is = non-zero. + unsafe { bindings::put_device(obj.cast().as_ptr()) } + } +} + +// SAFETY: As by the type invariant `Device` can be sent to any thread. +unsafe impl Send for Device {} + +// SAFETY: `Device` can be shared among threads because all immutable meth= ods are protected by the +// synchronization in `struct device`. +unsafe impl Sync for Device {} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index fbd91a48ff8b..dd1207f1a873 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -28,6 +28,7 @@ =20 pub mod alloc; mod build_assert; +pub mod device; pub mod error; pub mod init; pub mod ioctl; --=20 2.45.1 From nobody Wed Dec 17 06:17:35 2025 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 86B991990DA for ; Mon, 17 Jun 2024 20:30:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718656231; cv=none; b=uO2x391tx2In7OvFidxOcE3sxL2Lyb/aLEU03RtEo9jWd8Mtlboc0CHdzkLA5LoQEQINtZWVMR+sY1Yj350EfhbPsXOvtOzSXU+lg+0D7frinlmhlDAHuFTm8qbYV7I6423UnFPAZtW3BIApyXmeKs+VVy0blL4za+4Yu9q/KZk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718656231; c=relaxed/simple; bh=B1mlD2gcDZn3WcFLN8earxzL3eEqpyTKvhmSVNGtGhM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Y09aNZR5LJepYH+LBZIal67Ss7y5zksFtEaUz2fmw5JNCnnbaVGWmbT/A2XkrOxYQtsMeMs+8RdaFI8+0XyDgNvRTOurJ8bb2nJ8FdcE77g5SEWOQOy9xOqQ9iiZhSD0QKvQJY52/oQZ8pJeGkk6yV0zhvpzLhmYt2bDaMxKCc0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=h4G9U5bL; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="h4G9U5bL" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1718656228; 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=PgQhmsr/qwpQV0Je5+W+RhOcNOfhN6QQb+s3cR1jcGU=; b=h4G9U5bLgEOPde+48arDL1SSpYzm+lRDif04NuvO4gAWvoGdUpwwQ8U5thEw/yhVi+OJGE CXISisVCkFWQfY5xk7AvjtSz80sJHuEukdCpyJ2yIOjJuZfgVcXJAFOae4cNwfS1rcTkUI OGAkbVpiUNaUbNwSv7YX1hF9YX0uJCc= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-77-wdIQcScfOMeP9u7ir-l4vw-1; Mon, 17 Jun 2024 16:30:27 -0400 X-MC-Unique: wdIQcScfOMeP9u7ir-l4vw-1 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-4217a6a00d8so31218755e9.0 for ; Mon, 17 Jun 2024 13:30:26 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718656226; x=1719261026; 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=PgQhmsr/qwpQV0Je5+W+RhOcNOfhN6QQb+s3cR1jcGU=; b=G243U+ZS6xlCCZLVyOqQ8PaxZ+go/UBdYJ8UtFSYEgLpCpoeMCKxtsietOdWrFj7m+ 045IwFRIfDjelVoUVhb0n5kN+3K8dZiIqtF2YfNrmn+93Rmc/el8OcIQ1EdO/LL4rqUV K08G4X/Kz/7wDNoTsmtU/uQN+qvOi2VEpjPETvcNzScUgf+lARPySudPqZAKRljIh+DR CzZTdGxLcnf7n4Xn0SculiqyaDPM8a+c0s7JICOXEzYhDCLfx2uxnpGn2ZPRkl48aMXP khlkB/dWL8D7yWvF8cKL69UyBZ7UW0FrccG0ZlXOLzPLCjug4TErStzOwYcfR0HPxSF2 rNrw== X-Forwarded-Encrypted: i=1; AJvYcCUZT9SolSRcuFZ088iJqfM5waZRXOXIttkMFQIkaflS/vGf8k+bRDKfZVaf0OCW6cs+qB5JuqAvqBM3borz2nfcfRHe1OM7+YPskxiI X-Gm-Message-State: AOJu0Yx6nJVEStOvodoQUSUG9RyHRiGitAK1dbEMS0BDPNGH5nKsK0Am 7xUTTuzegX5sjDztdxzyjnPyqx8Ofiv7RrI8XO2XCyJ9KwB1UIQlWBVwjFbG9Ljp9AG+fIJImnV BmrpP2BteD0HK6QcbZ+h9HWVhmPmhAjYN9MYrlO0T4NsGiigLx1jTH+xhHBaE6Q== X-Received: by 2002:a05:600c:2d8c:b0:422:140:f440 with SMTP id 5b1f17b1804b1-4230484adc9mr86367965e9.36.1718656225971; Mon, 17 Jun 2024 13:30:25 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGFEnB6x2MMZffzzdSjL8T8/a13bSO8sq6uqSY99yH4rtqsHFx2SMJS7ed+5la0ootKESeSwQ== X-Received: by 2002:a05:600c:2d8c:b0:422:140:f440 with SMTP id 5b1f17b1804b1-4230484adc9mr86367725e9.36.1718656225662; Mon, 17 Jun 2024 13:30:25 -0700 (PDT) Received: from cassiopeiae.. ([2a02:810d:4b3f:ee94:642:1aff:fe31:a19f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-422f6127c6fsm168658825e9.24.2024.06.17.13.30.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Jun 2024 13:30:25 -0700 (PDT) From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, mcgrof@kernel.org, russ.weight@linux.dev, ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, airlied@gmail.com, fujita.tomonori@gmail.com, pstanner@redhat.com, ajanulgu@redhat.com, lyude@redhat.com Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH v3 2/2] rust: add firmware abstractions Date: Mon, 17 Jun 2024 22:29:41 +0200 Message-ID: <20240617203010.101452-3-dakr@redhat.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20240617203010.101452-1-dakr@redhat.com> References: <20240617203010.101452-1-dakr@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add an abstraction around the kernels firmware API to request firmware images. The abstraction provides functions to access the firmware's size and backing buffer. The firmware is released once the abstraction instance is dropped. Signed-off-by: Danilo Krummrich --- drivers/base/firmware_loader/Kconfig | 7 ++ rust/bindings/bindings_helper.h | 1 + rust/kernel/firmware.rs | 98 ++++++++++++++++++++++++++++ rust/kernel/lib.rs | 2 + 4 files changed, 108 insertions(+) create mode 100644 rust/kernel/firmware.rs diff --git a/drivers/base/firmware_loader/Kconfig b/drivers/base/firmware_l= oader/Kconfig index 5ca00e02fe82..a03701674265 100644 --- a/drivers/base/firmware_loader/Kconfig +++ b/drivers/base/firmware_loader/Kconfig @@ -37,6 +37,13 @@ config FW_LOADER_DEBUG SHA256 checksums to the kernel log for each firmware file that is loaded. =20 +config RUST_FW_LOADER_ABSTRACTIONS + bool "Rust Firmware Loader abstractions" + depends on RUST + depends on FW_LOADER=3Dy + help + This enables the Rust abstractions for the firmware loader API. + if FW_LOADER =20 config FW_LOADER_PAGED_BUF diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index ddb5644d4fd9..18a3f05115cb 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs new file mode 100644 index 000000000000..05a4f84cfd42 --- /dev/null +++ b/rust/kernel/firmware.rs @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Firmware abstraction +//! +//! C header: [`include/linux/firmware.h`](srctree/include/linux/firmware.= h") + +use crate::{bindings, device::Device, error::Error, error::Result, str::CS= tr}; +use core::ptr::NonNull; + +// One of the following: `bindings::request_firmware`, `bindings::firmware= _request_nowarn`, +// `firmware_request_platform`, `bindings::request_firmware_direct` +type FwFunc =3D + unsafe extern "C" fn(*mut *const bindings::firmware, *const i8, *mut b= indings::device) -> i32; + +/// Abstraction around a C `struct firmware`. +/// +/// This is a simple abstraction around the C firmware API. Just like with= the C API, firmware can +/// be requested. Once requested the abstraction provides direct access to= the firmware buffer as +/// `&[u8]`. The firmware is released once [`Firmware`] is dropped. +/// +/// # Invariants +/// +/// The pointer is valid, and has ownership over the instance of `struct f= irmware`. +/// +/// # Examples +/// +/// ``` +/// # use kernel::{c_str, device::Device, firmware::Firmware}; +/// +/// # // SAFETY: *NOT* safe, just for the example to get an `ARef`= instance +/// # let dev =3D unsafe { Device::from_raw(core::ptr::null_mut()) }; +/// +/// let fw =3D Firmware::request(c_str!("path/to/firmware.bin"), &dev).unw= rap(); +/// let blob =3D fw.data(); +/// ``` +pub struct Firmware(NonNull); + +impl Firmware { + fn request_internal(name: &CStr, dev: &Device, func: FwFunc) -> Result= { + let mut fw: *mut bindings::firmware =3D core::ptr::null_mut(); + let pfw: *mut *mut bindings::firmware =3D &mut fw; + + // SAFETY: `pfw` is a valid pointer to a NULL initialized `binding= s::firmware` pointer. + // `name` and `dev` are valid as by their type invariants. + let ret =3D unsafe { func(pfw as _, name.as_char_ptr(), dev.as_raw= ()) }; + if ret !=3D 0 { + return Err(Error::from_errno(ret)); + } + + // SAFETY: `func` not bailing out with a non-zero error code, guar= antees that `fw` is a + // valid pointer to `bindings::firmware`. + Ok(Firmware(unsafe { NonNull::new_unchecked(fw) })) + } + + /// Send a firmware request and wait for it. See also `bindings::reque= st_firmware`. + pub fn request(name: &CStr, dev: &Device) -> Result { + Self::request_internal(name, dev, bindings::request_firmware) + } + + /// Send a request for an optional firmware module. See also + /// `bindings::firmware_request_nowarn`. + pub fn request_nowarn(name: &CStr, dev: &Device) -> Result { + Self::request_internal(name, dev, bindings::firmware_request_nowar= n) + } + + fn as_raw(&self) -> *mut bindings::firmware { + self.0.as_ptr() + } + + /// Returns the size of the requested firmware in bytes. + pub fn size(&self) -> usize { + // SAFETY: Safe by the type invariant. + unsafe { (*self.as_raw()).size } + } + + /// Returns the requested firmware as `&[u8]`. + pub fn data(&self) -> &[u8] { + // SAFETY: Safe by the type invariant. Additionally, `bindings::fi= rmware` guarantees, if + // successfully requested, that `bindings::firmware::data` has a s= ize of + // `bindings::firmware::size` bytes. + unsafe { core::slice::from_raw_parts((*self.as_raw()).data, self.s= ize()) } + } +} + +impl Drop for Firmware { + fn drop(&mut self) { + // SAFETY: Safe by the type invariant. + unsafe { bindings::release_firmware(self.as_raw()) }; + } +} + +// SAFETY: `Firmware` only holds a pointer to a C `struct firmware`, which= is safe to be used from +// any thread. +unsafe impl Send for Firmware {} + +// SAFETY: `Firmware` only holds a pointer to a C `struct firmware`, refer= ences to which are safe to +// be used from any thread. +unsafe impl Sync for Firmware {} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index dd1207f1a873..7707cb013ce9 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -30,6 +30,8 @@ mod build_assert; pub mod device; pub mod error; +#[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)] +pub mod firmware; pub mod init; pub mod ioctl; #[cfg(CONFIG_KUNIT)] --=20 2.45.1