lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250417082906.dfiproihig7egkp2@vireshk-i7>
Date: Thu, 17 Apr 2025 13:59:06 +0530
From: Viresh Kumar <viresh.kumar@...aro.org>
To: Danilo Krummrich <dakr@...nel.org>
Cc: "Rafael J. Wysocki" <rafael@...nel.org>,
	Miguel Ojeda <miguel.ojeda.sandonis@...il.com>,
	Danilo Krummrich <dakr@...hat.com>, Miguel Ojeda <ojeda@...nel.org>,
	Alex Gaynor <alex.gaynor@...il.com>,
	Boqun Feng <boqun.feng@...il.com>, Gary Guo <gary@...yguo.net>,
	Björn Roy Baron <bjorn3_gh@...tonmail.com>,
	Benno Lossin <benno.lossin@...ton.me>,
	Andreas Hindborg <a.hindborg@...nel.org>,
	Alice Ryhl <aliceryhl@...gle.com>, Trevor Gross <tmgross@...ch.edu>,
	linux-pm@...r.kernel.org,
	Vincent Guittot <vincent.guittot@...aro.org>,
	Stephen Boyd <sboyd@...nel.org>, Nishanth Menon <nm@...com>,
	rust-for-linux@...r.kernel.org,
	Manos Pitsidianakis <manos.pitsidianakis@...aro.org>,
	Alex Bennée <alex.bennee@...aro.org>,
	Joakim Bech <joakim.bech@...aro.org>, Rob Herring <robh@...nel.org>,
	Yury Norov <yury.norov@...il.com>, Burak Emir <bqe@...gle.com>,
	Rasmus Villemoes <linux@...musvillemoes.dk>,
	Russell King <linux@...linux.org.uk>, linux-clk@...r.kernel.org,
	Michael Turquette <mturquette@...libre.com>,
	linux-kernel@...r.kernel.org
Subject: Re: [PATCH V10 13/15] rust: cpufreq: Extend abstractions for driver
 registration

On 16-04-25, 12:59, Danilo Krummrich wrote:
> Anyways, that doesn't help for now. Unfortunately, I think you actually need to
> dynamically allocate it. There's no need to revert everything though. You can
> just allocate a new KBox from VTABLE, i.e.
> 
> 	let vtable = KBox::new(Self::VTABLE, GFP_KERNEL)?;

Thanks. Here is the diff for this patch:

diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
index e8f4e18002c9..8cb62641c64b 100644
--- a/rust/kernel/cpufreq.rs
+++ b/rust/kernel/cpufreq.rs
@@ -9,7 +9,6 @@
 //! Reference: <https://docs.kernel.org/admin-guide/pm/cpufreq.html>
 
 use crate::{
-    alloc::AllocError,
     clk::{Clk, Hertz},
     cpumask,
     device::Device,
@@ -22,16 +21,17 @@
 };
 
 use core::{
+    cell::UnsafeCell,
     marker::PhantomData,
     mem::MaybeUninit,
     ops::{Deref, DerefMut},
     pin::Pin,
-    ptr::{self, NonNull},
+    ptr,
 };
 
 use macros::vtable;
 
-// Maximum length of CPU frequency driver's name.
+/// Maximum length of CPU frequency driver's name.
 const CPUFREQ_NAME_LEN: usize = bindings::CPUFREQ_NAME_LEN as usize;
 
 /// Default transition latency value in nanoseconds.
@@ -872,7 +872,7 @@ fn register_em(_policy: &mut Policy) {
 ///         data.generic_verify()
 ///     }
 ///
-///     fn target_index(policy: &mut cpufreq::Policy, index: u32) -> Result<()> {
+///     fn target_index(policy: &mut cpufreq::Policy, index: cpufreq::TableIndex) -> Result<()> {
 ///         // Update CPU frequency
 ///         Ok(())
 ///     }
@@ -887,15 +887,15 @@ fn register_em(_policy: &mut Policy) {
 /// }
 /// ```
 #[repr(transparent)]
-pub struct Registration<T: Driver>(NonNull<bindings::cpufreq_driver>, PhantomData<T>);
+pub struct Registration<T: Driver>(KBox<UnsafeCell<bindings::cpufreq_driver>>, PhantomData<T>);
 
-// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads
-// or CPUs, so it is safe to share it.
+/// SAFETY: `Registration` doesn't offer any methods or access to fields when shared between threads
+/// or CPUs, so it is safe to share it.
 unsafe impl<T: Driver> Sync for Registration<T> {}
 
 #[allow(clippy::non_send_fields_in_send_ty)]
-// SAFETY: Registration with and unregistration from the cpufreq subsystem can happen from any
-// thread.
+/// SAFETY: Registration with and unregistration from the cpufreq subsystem can happen from any
+/// thread.
 unsafe impl<T: Driver> Send for Registration<T> {}
 
 impl<T: Driver> Registration<T> {
@@ -1020,16 +1020,14 @@ impl<T: Driver> Registration<T> {
 
     /// Registers a CPU frequency driver with the cpufreq core.
     pub fn new() -> Result<Self> {
-        let drv: *const bindings::cpufreq_driver = &Self::VTABLE;
-        let drv = drv.cast_mut();
+        // We can't use `&Self::VTABLE` directly because the cpufreq core modifies some fields in
+        // the C `struct cpufreq_driver`, which requires a mutable reference.
+        let mut drv = KBox::new(UnsafeCell::new(Self::VTABLE), GFP_KERNEL)?;
 
-        // SAFETY: It is safe to register the driver with the cpufreq core in the kernel C code.
-        to_result(unsafe { bindings::cpufreq_register_driver(drv) })?;
+        // SAFETY: `drv` is guaranteed to be valid for the lifetime of `Registration`.
+        to_result(unsafe { bindings::cpufreq_register_driver(drv.get_mut()) })?;
 
-        Ok(Self(
-            NonNull::new(drv.cast()).ok_or(AllocError)?,
-            PhantomData,
-        ))
+        Ok(Self(drv, PhantomData))
     }
 
     /// Same as [`Registration::new`], but does not return a [`Registration`] instance.
@@ -1037,16 +1035,15 @@ pub fn new() -> Result<Self> {
     /// Instead the [`Registration`] is owned by [`Devres`] and will be revoked / dropped, once the
     /// device is detached.
     pub fn new_foreign_owned(dev: &Device) -> Result<()> {
-        Devres::new_foreign_owned(dev, Self::new()?, GFP_KERNEL)?;
-        Ok(())
+        Devres::new_foreign_owned(dev, Self::new()?, GFP_KERNEL)
     }
 }
 
-// CPU frequency driver callbacks.
+/// CPU frequency driver callbacks.
 impl<T: Driver> Registration<T> {
-    // Driver's `init` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `init` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn init_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int {
         from_result(|| {
             // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
@@ -1059,9 +1056,9 @@ extern "C" fn init_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::
         })
     }
 
-    // Driver's `exit` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `exit` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn exit_callback(ptr: *mut bindings::cpufreq_policy) {
         // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
         // lifetime of `policy`.
@@ -1071,9 +1068,9 @@ extern "C" fn exit_callback(ptr: *mut bindings::cpufreq_policy) {
         let _ = T::exit(policy, data);
     }
 
-    // Driver's `online` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `online` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn online_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int {
         from_result(|| {
             // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
@@ -1083,9 +1080,9 @@ extern "C" fn online_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi
         })
     }
 
-    // Driver's `offline` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `offline` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn offline_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int {
         from_result(|| {
             // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
@@ -1095,9 +1092,9 @@ extern "C" fn offline_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ff
         })
     }
 
-    // Driver's `suspend` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `suspend` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn suspend_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int {
         from_result(|| {
             // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
@@ -1107,9 +1104,9 @@ extern "C" fn suspend_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ff
         })
     }
 
-    // Driver's `resume` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `resume` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn resume_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int {
         from_result(|| {
             // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
@@ -1119,9 +1116,9 @@ extern "C" fn resume_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi
         })
     }
 
-    // Driver's `ready` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `ready` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn ready_callback(ptr: *mut bindings::cpufreq_policy) {
         // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
         // lifetime of `policy`.
@@ -1129,9 +1126,9 @@ extern "C" fn ready_callback(ptr: *mut bindings::cpufreq_policy) {
         T::ready(policy);
     }
 
-    // Driver's `verify` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `verify` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn verify_callback(ptr: *mut bindings::cpufreq_policy_data) -> kernel::ffi::c_int {
         from_result(|| {
             // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
@@ -1141,9 +1138,9 @@ extern "C" fn verify_callback(ptr: *mut bindings::cpufreq_policy_data) -> kernel
         })
     }
 
-    // Driver's `setpolicy` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `setpolicy` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn setpolicy_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int {
         from_result(|| {
             // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
@@ -1153,9 +1150,9 @@ extern "C" fn setpolicy_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::
         })
     }
 
-    // Driver's `target` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `target` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn target_callback(
         ptr: *mut bindings::cpufreq_policy,
         target_freq: u32,
@@ -1169,9 +1166,9 @@ extern "C" fn target_callback(
         })
     }
 
-    // Driver's `target_index` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `target_index` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn target_index_callback(
         ptr: *mut bindings::cpufreq_policy,
         index: u32,
@@ -1180,13 +1177,18 @@ extern "C" fn target_index_callback(
             // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
             // lifetime of `policy`.
             let policy = unsafe { Policy::from_raw_mut(ptr) };
+
+            // SAFETY: The C code guarantees that `index` corresponds to a valid entry in the
+            // frequency table.
+            let index = unsafe { TableIndex::new(index as usize) };
+
             T::target_index(policy, index).map(|()| 0)
         })
     }
 
-    // Driver's `fast_switch` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `fast_switch` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn fast_switch_callback(
         ptr: *mut bindings::cpufreq_policy,
         target_freq: u32,
@@ -1197,7 +1199,7 @@ extern "C" fn fast_switch_callback(
         T::fast_switch(policy, target_freq)
     }
 
-    // Driver's `adjust_perf` callback.
+    /// Driver's `adjust_perf` callback.
     extern "C" fn adjust_perf_callback(
         cpu: u32,
         min_perf: usize,
@@ -1209,9 +1211,9 @@ extern "C" fn adjust_perf_callback(
         }
     }
 
-    // Driver's `get_intermediate` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `get_intermediate` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn get_intermediate_callback(
         ptr: *mut bindings::cpufreq_policy,
         index: u32,
@@ -1219,12 +1221,17 @@ extern "C" fn get_intermediate_callback(
         // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
         // lifetime of `policy`.
         let policy = unsafe { Policy::from_raw_mut(ptr) };
+
+        // SAFETY: The C code guarantees that `index` corresponds to a valid entry in the
+        // frequency table.
+        let index = unsafe { TableIndex::new(index as usize) };
+
         T::get_intermediate(policy, index)
     }
 
-    // Driver's `target_intermediate` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `target_intermediate` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn target_intermediate_callback(
         ptr: *mut bindings::cpufreq_policy,
         index: u32,
@@ -1233,25 +1240,30 @@ extern "C" fn target_intermediate_callback(
             // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
             // lifetime of `policy`.
             let policy = unsafe { Policy::from_raw_mut(ptr) };
+
+            // SAFETY: The C code guarantees that `index` corresponds to a valid entry in the
+            // frequency table.
+            let index = unsafe { TableIndex::new(index as usize) };
+
             T::target_intermediate(policy, index).map(|()| 0)
         })
     }
 
-    // Driver's `get` callback.
+    /// Driver's `get` callback.
     extern "C" fn get_callback(cpu: u32) -> kernel::ffi::c_uint {
         PolicyCpu::from_cpu(cpu).map_or(0, |mut policy| T::get(&mut policy).map_or(0, |f| f))
     }
 
-    // Driver's `update_limit` callback.
+    /// Driver's `update_limit` callback.
     extern "C" fn update_limits_callback(cpu: u32) {
         if let Ok(mut policy) = PolicyCpu::from_cpu(cpu) {
             T::update_limits(&mut policy);
         }
     }
 
-    // Driver's `bios_limit` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `bios_limit` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn bios_limit_callback(cpu: i32, limit: *mut u32) -> kernel::ffi::c_int {
         from_result(|| {
             let mut policy = PolicyCpu::from_cpu(cpu as u32)?;
@@ -1261,9 +1273,9 @@ extern "C" fn bios_limit_callback(cpu: i32, limit: *mut u32) -> kernel::ffi::c_i
         })
     }
 
-    // Driver's `set_boost` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `set_boost` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn set_boost_callback(
         ptr: *mut bindings::cpufreq_policy,
         state: i32,
@@ -1276,9 +1288,9 @@ extern "C" fn set_boost_callback(
         })
     }
 
-    // Driver's `register_em` callback.
-    //
-    // SAFETY: Called from C. Inputs must be valid pointers.
+    /// Driver's `register_em` callback.
+    ///
+    /// SAFETY: Called from C. Inputs must be valid pointers.
     extern "C" fn register_em_callback(ptr: *mut bindings::cpufreq_policy) {
         // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
         // lifetime of `policy`.
@@ -1288,9 +1300,9 @@ extern "C" fn register_em_callback(ptr: *mut bindings::cpufreq_policy) {
 }
 
 impl<T: Driver> Drop for Registration<T> {
-    // Removes the `Registration` from the kernel, if it has initialized successfully earlier.
+    /// Unregisters with the cpufreq core.
     fn drop(&mut self) {
-        // SAFETY: The driver was earlier registered from `new`.
-        unsafe { bindings::cpufreq_unregister_driver(self.0.as_ptr()) };
+        // SAFETY: `self.0` is guaranteed to be valid for the lifetime of `Registration`.
+        unsafe { bindings::cpufreq_unregister_driver(self.0.get_mut()) };
     }
 }

-- 
viresh

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ