Skip to content

Commit

Permalink
driver, of: Mangle the device ID machinery further to remove const_tr…
Browse files Browse the repository at this point in the history
…ait_impl

This unstable feature is broken/gone in 1.73. To work around this
without breaking the API, turn IdArray::new() into a macro so that it
can use concrete types (which can still have const associated
functions) instead of a trait.

This is quite ugly...

Signed-off-by: Asahi Lina <[email protected]>
(cherry picked from commit 71e6c52)
Signed-off-by: Fabien Parent <[email protected]>
  • Loading branch information
asahilina authored and Fabo committed Nov 27, 2023
1 parent 65ae6a8 commit afd17dc
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 43 deletions.
116 changes: 76 additions & 40 deletions rust/kernel/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ impl<T: DriverOps> Drop for Registration<T> {
/// - [`RawDeviceId::ZERO`] is actually a zeroed-out version of the raw device id.
/// - [`RawDeviceId::to_rawid`] stores `offset` in the context/data field of the raw device id so
/// that buses can recover the pointer to the data.
#[const_trait]
pub unsafe trait RawDeviceId {
/// The raw type that holds the device id.
///
Expand All @@ -131,13 +130,6 @@ pub unsafe trait RawDeviceId {
/// Id tables created from [`Self`] use [`Self::ZERO`] as the sentinel to indicate the end of
/// the table.
const ZERO: Self::RawType;

/// Converts an id into a raw id.
///
/// `offset` is the offset from the memory location where the raw device id is stored to the
/// location where its associated context information is stored. Implementations must store
/// this in the appropriate context/data field of the raw type.
fn to_rawid(&self, offset: isize) -> Self::RawType;
}

/// A zero-terminated device id array.
Expand All @@ -158,35 +150,7 @@ pub struct IdArray<T: RawDeviceId, U, const N: usize> {
}

impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
/// Creates a new instance of the array.
///
/// The contents are derived from the given identifiers and context information.
pub const fn new(ids: [T; N], infos: [Option<U>; N]) -> Self
where
T: ~const RawDeviceId + Copy,
T::RawType: Copy + Clone,
{
let mut array = Self {
ids: IdArrayIds {
ids: [T::ZERO; N],
sentinel: T::ZERO,
},
id_infos: infos,
};
let mut i = 0usize;
while i < N {
// SAFETY: Both pointers are within `array` (or one byte beyond), consequently they are
// derived from the same allocated object. We are using a `u8` pointer, whose size 1,
// so the pointers are necessarily 1-byte aligned.
let offset = unsafe {
(&array.id_infos[i] as *const _ as *const u8)
.offset_from(&array.ids.ids[i] as *const _ as _)
};
array.ids.ids[i] = ids[i].to_rawid(offset);
i += 1;
}
array
}
const U_NONE: Option<U> = None;

/// Returns an `IdTable` backed by `self`.
///
Expand All @@ -206,10 +170,82 @@ impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
/// Returns the inner IdArrayIds array, without the context data.
pub const fn as_ids(&self) -> IdArrayIds<T, N>
where
T: ~const RawDeviceId + Copy,
T: RawDeviceId + Copy,
{
self.ids
}

/// Creates a new instance of the array.
///
/// The contents are derived from the given identifiers and context information.
#[doc(hidden)]
pub const unsafe fn new(raw_ids: [T::RawType; N], infos: [Option<U>; N]) -> Self
where
T: RawDeviceId + Copy,
T::RawType: Copy + Clone,
{
Self {
ids: IdArrayIds {
ids: raw_ids,
sentinel: T::ZERO,
},
id_infos: infos,
}
}

#[doc(hidden)]
pub const fn get_offset(idx: usize) -> isize
where
T: RawDeviceId + Copy,
T::RawType: Copy + Clone,
{
// SAFETY: We are only using this dummy value to get offsets.
let array = unsafe { Self::new([T::ZERO; N], [Self::U_NONE; N]) };
// SAFETY: Both pointers are within `array` (or one byte beyond), consequently they are
// derived from the same allocated object. We are using a `u8` pointer, whose size 1,
// so the pointers are necessarily 1-byte aligned.
let ret = unsafe {
(&array.id_infos[idx] as *const _ as *const u8)
.offset_from(&array.ids.ids[idx] as *const _ as _)
};
core::mem::forget(array);
ret
}
}

// Creates a new ID array. This is a macro so it can take as a parameter the concrete ID type in order
// to call to_rawid() on it, and still remain const. This is necessary until a new const_trait_impl
// implementation lands, since the existing implementation was removed in Rust 1.73.
#[macro_export]
#[doc(hidden)]
macro_rules! _new_id_array {
(($($args:tt)*), $id_type:ty) => {{
/// Creates a new instance of the array.
///
/// The contents are derived from the given identifiers and context information.
const fn new< U, const N: usize>(ids: [$id_type; N], infos: [Option<U>; N])
-> $crate::driver::IdArray<$id_type, U, N>
where
$id_type: $crate::driver::RawDeviceId + Copy,
<$id_type as $crate::driver::RawDeviceId>::RawType: Copy + Clone,
{
let mut raw_ids =
[<$id_type as $crate::driver::RawDeviceId>::ZERO; N];
let mut i = 0usize;
while i < N {
let offset: isize = $crate::driver::IdArray::<$id_type, U, N>::get_offset(i);
raw_ids[i] = ids[i].to_rawid(offset);
i += 1;
}

// SAFETY: We are passing valid arguments computed with the correct offsets.
unsafe {
$crate::driver::IdArray::<$id_type, U, N>::new(raw_ids, infos)
}
}

new($($args)*)
}}
}

/// A device id table.
Expand Down Expand Up @@ -367,8 +403,8 @@ macro_rules! define_id_array {
($table_name:ident, $id_type:ty, $data_type:ty, [ $($t:tt)* ]) => {
const $table_name:
$crate::driver::IdArray<$id_type, $data_type, { $crate::count_paren_items!($($t)*) }> =
$crate::driver::IdArray::new(
$crate::first_item!($id_type, $($t)*), $crate::second_item!($($t)*));
$crate::_new_id_array!((
$crate::first_item!($id_type, $($t)*), $crate::second_item!($($t)*)), $id_type);
};
}

Expand Down
9 changes: 6 additions & 3 deletions rust/kernel/of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//!
//! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h)
use crate::{bindings, driver, str::BStr};
use crate::{bindings, driver::RawDeviceId, str::BStr};

/// An open firmware device id.
#[derive(Clone, Copy)]
Expand Down Expand Up @@ -61,16 +61,19 @@ macro_rules! module_of_id_table {
}

// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `of_device_id::data`.
unsafe impl const driver::RawDeviceId for DeviceId {
unsafe impl RawDeviceId for DeviceId {
type RawType = bindings::of_device_id;
const ZERO: Self::RawType = bindings::of_device_id {
name: [0; 32],
type_: [0; 32],
compatible: [0; 128],
data: core::ptr::null(),
};
}

fn to_rawid(&self, offset: isize) -> Self::RawType {
impl DeviceId {
#[doc(hidden)]
pub const fn to_rawid(&self, offset: isize) -> <Self as RawDeviceId>::RawType {
let DeviceId::Compatible(compatible) = self;
let mut id = Self::ZERO;
let mut i = 0;
Expand Down

0 comments on commit afd17dc

Please sign in to comment.