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: <DC7AQ7LH1EA0.2BFROWRN54A4@kernel.org>
Date: Wed, 20 Aug 2025 15:40:36 +0200
From: "Danilo Krummrich" <dakr@...nel.org>
To: "Daniel Almeida" <daniel.almeida@...labora.com>
Cc: "Alice Ryhl" <aliceryhl@...gle.com>, <akpm@...ux-foundation.org>,
 <ojeda@...nel.org>, <alex.gaynor@...il.com>, <boqun.feng@...il.com>,
 <gary@...yguo.net>, <bjorn3_gh@...tonmail.com>, <lossin@...nel.org>,
 <a.hindborg@...nel.org>, <tmgross@...ch.edu>, <abdiel.janulgue@...il.com>,
 <acourbot@...dia.com>, <jgg@...pe.ca>, <lyude@...hat.com>,
 <robin.murphy@....com>, <rust-for-linux@...r.kernel.org>,
 <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH 1/4] rust: dma: implement DataDirection

On Wed Aug 20, 2025 at 3:17 PM CEST, Daniel Almeida wrote:
>
>
>> On 18 Aug 2025, at 18:03, Danilo Krummrich <dakr@...nel.org> wrote:
>> 
>> On Mon Aug 18, 2025 at 8:47 PM CEST, Alice Ryhl wrote:
>>> with no warnings and build-failure if out-of-bounds.
>> 
>> +/// DMA data direction.
>> +///
>> +/// Corresponds to the C [`enum dma_data_direction`].
>> +///
>> +/// [`enum dma_data_direction`]: srctree/include/linux/dma-direction.h
>> +#[derive(Copy, Clone, PartialEq, Eq, Debug)]
>> +#[repr(u32)]
>> +pub enum DataDirection {
>> +    /// The DMA mapping is for bidirectional data transfer.
>> +    ///
>> +    /// This is used when the buffer can be both read from and written to by the device.
>> +    /// The cache for the corresponding memory region is both flushed and invalidated.
>> +    Bidirectional = Self::const_cast(bindings::dma_data_direction_DMA_BIDIRECTIONAL),
>> +
>> +    /// The DMA mapping is for data transfer from memory to the device (write).
>> +    ///
>> +    /// The CPU has prepared data in the buffer, and the device will read it.
>> +    /// The cache for the corresponding memory region is flushed.
>> +    ToDevice = Self::const_cast(bindings::dma_data_direction_DMA_TO_DEVICE),
>> +
>> +    /// The DMA mapping is for data transfer from the device to memory (read).
>> +    ///
>> +    /// The device will write data into the buffer for the CPU to read.
>> +    /// The cache for the corresponding memory region is invalidated before CPU access.
>> +    FromDevice = Self::const_cast(bindings::dma_data_direction_DMA_FROM_DEVICE),
>> +
>> +    /// The DMA mapping is not for data transfer.
>> +    ///
>> +    /// This is primarily for debugging purposes. With this direction, the DMA mapping API
>> +    /// will not perform any cache coherency operations.
>> +    None = Self::const_cast(bindings::dma_data_direction_DMA_NONE),
>> +}
>> +
>> +impl DataDirection {
>> +    /// Casts the bindgen-generated enum type to a `u32` at compile time.
>> +    ///
>> +    /// This function will cause a compile-time error if the underlying value of the
>> +    /// C enum is out of bounds for `u32`.
>> +    const fn const_cast(val: bindings::dma_data_direction) -> u32 {
>
> This should be its own generic helper for similar enums, IMHO

In general, I agree, but it may not be exactly straight forward (considering
that it still needs to work from const context).

The function relies on the fact that both the argument and return type are
numeric primitives, which need to fit into an i128. We could probably define a
marker trait for such types, etc.

Yet, I don't know how we could do the casts from one generic type I to another
generic type O. I think we'd need to implement traits for that as well. However,
this would require the unstable const_trait_impl feature.

Hence, working this out (if even possible currently) and improving existing enum
abstractions should be done independent from this series.

>> +        // CAST: The C standard allows compilers to choose different integer types for enums.
>> +        // To safely check the value, we cast it to a wide signed integer type (`i128`)
>> +        // which can hold any standard C integer enum type without truncation.
>> +        let wide_val = val as i128;
>> +
>> +        // Check if the value is outside the valid range for the target type `u32`.
>> +        // CAST: `u32::MAX` is cast to `i128` to match the type of `wide_val` for the comparison.
>> +        if wide_val < 0 || wide_val > u32::MAX as i128 {
>> +            // Trigger a compile-time error in a const context.
>> +            panic!("C enum value is out of bounds for the target type `u32`.");
>> +        }
>> +
>> +        // CAST: This cast is valid because the check above guarantees that `wide_val`
>> +        // is within the representable range of `u32`.
>> +        wide_val as u32
>> +    }
>> +}
>> +
>> +impl From<DataDirection> for bindings::dma_data_direction {
>> +    /// Returns the raw representation of [`enum dma_data_direction`].
>> +    fn from(direction: DataDirection) -> Self {
>> +        // CAST: `direction as u32` gets the underlying representation of our `#[repr(u32)]` enum.
>> +        // The subsequent cast to `Self` (the bindgen type) assumes the C enum is compatible
>> +        // with the enum variants of `DataDirection`, which is a valid assumption given our
>> +        // compile-time checks.
>> +        direction as u32 as Self
>> +    }
>> +}


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ