driver.rs under Rust-for-Linux

·

10 min read

driver.rs

// SPDX-License-Identifier: GPL-2.0

//! 不同总线(例如PCI、平台、Amba等)的驱动程序的通用支持。
//!
//! 每个总线/子系统都需要实现[`DriverOps`] trait,以允许驱动程序使用[`Registration`]类进行注册。

use crate::{error::code::*, str::CStr, sync::Arc, Result, ThisModule};
use alloc::boxed::Box;
use core::{cell::UnsafeCell, marker::PhantomData, ops::Deref, pin::Pin};

/// 允许编写特定总线的驱动程序的子系统(例如PCI、平台、Amba等)。
pub trait DriverOps {
    /// 保存与注册相关信息的类型。通常是由内核的C部分定义的结构体。
    type RegType: Default;

    /// 注册一个驱动程序。
    ///
    /// # 安全性
    ///
    /// `reg`必须指向有效、已初始化和可写入的内存。该函数可能会修改`reg`以保存注册状态。
    ///
    /// 成功后,`reg`必须保持固定且有效,直到与之匹配的调用[`DriverOps::unregister`]。
    unsafe fn register(
        reg: *mut Self::RegType,
        name: &'static CStr,
        module: &'static ThisModule,
    ) -> Result;

    /// 注销之前使用[`DriverOps::register`]注册的驱动程序。
    ///
    /// # 安全性
    ///
    /// `reg`必须指向有效可写入的内存,由先前成功调用[`DriverOps::register`]进行初始化。
    unsafe fn unregister(reg: *mut Self::RegType);
}

/// 驱动程序的注册信息。
pub struct Registration<T: DriverOps> {
    is_registered: bool,
    concrete_reg: UnsafeCell<T::RegType>,
}

// SAFETY: `Registration`的字段或方法无法通过`&Registration`访问,因此可以安全地与多个线程共享对它的引用,因为无法执行任何操作。
unsafe impl<T: DriverOps> Sync for Registration<T> {}

impl<T: DriverOps> Registration<T> {
    /// 创建注册对象的新实例。
    pub fn new() -> Self {
        Self {
            is_registered: false,
            concrete_reg: UnsafeCell::new(T::RegType::default()),
        }
    }

    /// 分配一个固定的注册对象并进行注册。
    ///
    /// 返回一个固定的堆分配的注册对象。
    pub fn new_pinned(name: &'static CStr, module: &'static ThisModule) -> Result<Pin<Box<Self>>> {
        let mut reg = Pin::from(Box::try_new(Self::new())?);
        reg.as_mut().register(name, module)?;
        Ok(reg)
    }

    /// 使用其子系统注册驱动程序。
    ///
    /// 必须进行固定,因为表示注册的内存块可能自引用。
    pub fn register(
        self: Pin<&mut Self>,
        name: &'static CStr,
        module: &'static ThisModule,
    ) -> Result {
        // SAFETY: 我们不会从`this`中移出任何内容。
        let this = unsafe { self.get_unchecked_mut() };
        if this.is_registered {
            // 已注册。
            return Err(EINVAL);
        }

        // SAFETY: 通过默认构造函数初始化了`concrete_reg`。在调用`Self::drop`之前,它只有在成功调用`T::unregister`之后才会被释放。
        unsafe { T::register(this.concrete_reg.get(), name, module) }?;

        this.is_registered = true;
        Ok(())
    }
}

impl<T: DriverOps> Default for Registration<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T: DriverOps> Drop for Registration<T> {
    fn drop(&mut self) {
        if self.is_registered {
            // SAFETY: 仅当之前对`T::register`的调用成功完成后,才会执行此路径。
            unsafe { T::unregister(self.concrete_reg.get()) };
        }
    }
}

/// 设备ID到原始设备ID的转换。
///
/// 这应该由总线/子系统实现,以便它们可以使用[`IdTable`]来在编译时保证设备ID表的零终止。
///
/// # 安全性
///
/// 实现者必须确保:
///   - [`RawDeviceId::ZERO`]实际上是原始设备ID的零值。
///   - [`RawDeviceId::to_rawid`]将`offset`存储在原始设备ID的上下文/数据字段中,以便总线可以恢复指向数据的指针。
#[const_trait]
pub unsafe trait RawDeviceId {
    /// 保存设备ID的原始类型。
    ///
    /// 由[`Self`]创建的ID表将在其零终止数组中保存此类型。
    type RawType: Copy;

    /// 原始设备ID的零值表示。
    ///
    /// 由[`Self`]创建的ID表使用[`Self::ZERO`]作为标记来表示表的结束。
    const ZERO: Self::RawType;

    /// 将ID转换为原始ID。
    ///
    /// `offset`是从存储原始设备ID的内存位置偏移的偏移量。实现必须将其存储在原始类型的适当上下文/数据字段中。
    fn to_rawid(&self, offset: isize) -> Self::RawType;
}

/// 零终止的设备ID数组,后跟上下文数据。
#[repr(C)]
pub struct IdArray<T: RawDeviceId, U, const N: usize> {
    ids: [T::RawType; N],
    sentinel: T::RawType,
    id_infos: [Option<U>; N],
}

impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
    /// 创建数组的新实例。
    ///
    /// 内容源自给定的标识符和上下文信息。
    pub const fn new(ids: [T; N], infos: [Option<U>; N]) -> Self
    where
        T: ~const RawDeviceId + Copy,
    {
        let mut array = Self {
            ids: [T::ZERO; N],
            sentinel: T::ZERO,
            id_infos: infos,
        };
        let mut i = 0usize;
        while i < N {
            // SAFETY: 两个指针都在`array`内(或一个字节之外),因此它们都是从同一分配对象派生的。
            // 我们使用了一个`u8`指针,其大小为1,因此指针必然对齐于1字节。
            let offset = unsafe {
                (&array.id_infos[i] as *const _ as *const u8)
                    .offset_from(&array.ids[i] as *const _ as _)
            };
            array.ids[i] = ids[i].to_rawid(offset);
            i += 1;
        }
        array
    }

    /// 返回由`self`支持的`IdTable`。
    ///
    /// 这用于基本上消除了数组大小。
    pub const fn as_table(&self) -> IdTable<'_, T, U> {
        IdTable {
            first: &self.ids[0],
            _p: PhantomData,
        }
    }
}

/// 设备ID表。
///
/// 保证表以零终止,并后跟类型为`Option<U>`的上下文数据数组。
pub struct IdTable<'a, T: RawDeviceId, U> {
    first: &'a T::RawType,
    _p: PhantomData<&'a U>,
}

impl<T: RawDeviceId, U> const AsRef<T::RawType> for IdTable<'_, T, U> {
    fn as_ref(&self) -> &T::RawType {
        self.first
    }
}

/// 计算括号括起的逗号分隔项的数量。
///
/// # Examples
///
///

/// # use kernel::count_paren_items; /// /// assert_eq!(0, count_paren_items!()); /// assert_eq!(1, count_paren_items!((A))); /// assert_eq!(1, count_paren_items!((A),)); /// assert_eq!(2, count_paren_items!((A), (B))); /// assert_eq!(2, count_paren_items!((A), (B),)); /// assert_eq!(3, count_paren_items!((A), (B), (C))); /// assert_eq!(3, count_paren_items!((A), (B), (C),)); /// ```

#[macro_export] macro_rules! count_paren_items { (($($item:tt)), $($remaining:tt)) => { 1 + $crate::count_paren_items!($($remaining)) }; (($($item:tt))) => { 1 }; () => { 0 }; }

/// 将逗号分隔的键值对转换为只包含第一个元素的数组。也就是,它丢弃了键值对的第二个元素。 /// /// 此外,如果第一个元素包含在花括号中,它会自动引入一个类型,例如,如果是{v: 10},它会变成X { v: 10 };这样可以避免重复类型的问题。 /// /// # Examples /// /// /// # use kernel::first_item; /// /// #[derive(PartialEq, Debug)] /// struct X { /// v: u32, /// } /// /// assert_eq!([] as [X; 0], first_item!(X, )); /// assert_eq!([X { v: 10 }], first_item!(X, {v: 10})); /// assert_eq!([X { v: 10 }], first_item!(X, {v: 10}, )); /// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, {v: 10}, {v: 20})); /// assert_eq!([X { v: 10 }, X { v: 20 }], first_item!(X, {v: 10}, {v: 20}, )); /// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }], first_item!(X, {v: 10}, {v: 20}, {v: 30})); /// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }], first_item!(X, {v: 10}, {v: 20}, {v: 30}, )); ///

#[macro_export] macro_rules! first_item { ($type:ty, $({ $($key:ident: $value:expr), }) $(,) ) => {{ let items: [($type,); $crate::count_paren_items!($($($key: $value),))] = [ $($type $(::$key) { $($key: $value), }), ]; items }}; }

/// 将逗号分隔的键值对转换为只包含第一个元素的数组,并自动为每个元素引入一个类型。 /// /// 此外,如果第一个元素包含在花括号中,它会自动引入一个类型,例如,如果是{v: 10},它会变成X { v: 10 };这样可以避免重复类型的问题。 /// /// # Examples /// /// /// # use kernel::first_item_typed; /// /// #[derive(PartialEq, Debug)] /// struct X { /// v: u32, /// } /// /// assert_eq!([] as [X; 0], first_item_typed!(X, )); /// assert_eq!([X { v: 10 }], first_item_typed!(X, {v: 10})); /// assert_eq!([X { v: 10 }], first_item_typed!(X, {v: 10}, )); /// assert_eq!([X { v: 10 }, X { v: 20 }], first_item_typed!(X, {v: 10}, {v: 20})); /// assert_eq!([X { v: 10 }, X { v: 20 }], first_item_typed!(X, {v: 10}, {v: 20}, )); /// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }], first_item_typed!(X, {v: 10}, {v: 20}, {v: 30})); /// assert_eq!([X { v: 10 }, X { v: 20 }, X { v: 30 }], first_item_typed!(X, {v: 10}, {v: 20}, {v: 30}, )); ///

#[macro_export] macro_rules! first_item_typed { ($type:ty, $({ $($key:ident: $value:expr), }) $(,) ) => {{ let items: [($type,); $crate::count_paren_items!($($($key: $value),))] = [ $($type $(::$key) { $($key: $value), }), ]; items }}; }

/// 根据给定的条件选择第一个元素,并返回其索引。 /// /// # Examples /// /// /// # use kernel::first_index; /// /// assert_eq!(None, first_index!(true => 1, )); /// assert_eq!(Some(0), first_index!(true => 1, false => 2, )); /// assert_eq!(Some(1), first_index!(false => 1, true => 2, )); ///

#[macro_export] macro_rules! first_index { ($($cond:expr => $value:expr,)+) => {{ let mut index = 0; $( if $cond { return Some(index); } index += 1; )+ None }}; }

/// 选择第一个条件为true的元素,并返回该元素。 /// /// # Examples /// /// /// # use kernel::first_match; /// /// assert_eq!(None, first_match!(true => 1, )); /// assert_eq!(Some(1), first_match!(true => 1, false => 2, )); /// assert_eq!(Some(2), first_match!(false => 1, true => 2, )); ///

#[macro_export] macro_rules! first_match { ($($cond:expr => $value:expr,)+) => {{ $( if $cond { return Some($value); } )+ None }}; }

/// 返回一个由逗号分隔的条件数组中第一个条件为true的值。 /// /// # Examples /// /// /// # use kernel::first_value; /// /// assert_eq!(None, first_value!(true, )); /// assert_eq!(Some(1), first_value!(true, false, 1, )); /// assert_eq!(Some(2), first_value!(false, true, 2, )); ///

#[macro_export] macro_rules! first_value { ($($cond:expr, $value:expr,)+) => {{ let mut index = 0; $( if $cond { return Some($value); } index += 1; )+ None }}; }

/// 返回一个由逗号分隔的条件数组中第一个条件为true的索引。 /// /// # Examples /// /// /// # use kernel::first_index_true; /// /// assert_eq!(None, first_index_true!(true, )); /// assert_eq!(Some(0), first_index_true!(true, false, )); /// assert_eq!(Some(1), first_index_true!(false, true, )); ///

#[macro_export] macro_rules! first_index_true { ($($cond:expr,)+) => {{ let mut index = 0; $( if $cond { return Some(index); } index += 1; )+ None }}; }

/// 返回一个由逗号分隔的条件数组中第一个条件为false的索引。 /// /// # Examples /// /// /// # use kernel::first_index_false; /// /// assert_eq!(None, first_index_false!(false, )); /// assert_eq!(Some(0), first_index_false!(false, true, )); /// assert_eq!(Some(1), first_index_false!(true, false, )); ///

#[macro_export] macro_rules! first_index_false { ($($cond:expr,)+) => {{ let mut index = 0; $( if !$cond { return Some(index); } index += 1; )+ None }}; }

/// 返回一个由逗号分隔的条件数组中第一个条件为false的值。 /// /// # Examples /// /// /// # use kernel::first_false; /// /// assert_eq!(None, first_false!(false, )); /// assert_eq!(Some(true), first_false!(false, true, )); /// assert_eq!(Some(false), first_false!(true, false, )); ///

#[macro_export] macro_rules! first_false { ($($cond:expr, $value:expr,)+) => {{ let mut index = 0; $( if !$cond { return Some($value); } index += 1; )+ None }}; }

/// 将逗号分隔的键值对转换为带有第一个键值对的元组。 /// /// # Examples /// /// /// # use kernel::first_tuple; /// /// assert_eq!((), first_tuple!()); /// assert_eq!((1, "hello"), first_tuple!(1 => "hello")); /// assert_eq!((1, "hello"), first_tuple!(1 => "hello",)); /// assert_eq!((1, "hello", 2, "world"), first_tuple!(1 => "hello", 2 => "world")); /// assert_eq!((1, "hello", 2, "world"), first_tuple!(1 => "hello", 2 => "world",)); /// assert_eq!((1, "hello", 2, "world", 3, "foo"), first_tuple!(1 => "hello", 2 => "world", 3 => "foo")); /// assert_eq!((1, "hello", 2, "world", 3, "foo"), first_tuple!(1 => "hello", 2 => "world", 3 => "foo",)); ///

#[macro_export] macro_rules! first_tuple { ($({ $key:expr => $value:expr },)) => {($($key, $value),)}; ($({ $key:expr => $value:expr }),) => {($($key, $value),)}; () => {()}; }

/// 将逗号分隔的表达式转换为第一个表达式的值。 /// /// # Examples /// /// /// # use kernel::first_expr; /// /// assert_eq!((), first_expr!()); /// assert_eq!(1, first_expr!(1)); /// assert_eq!(1, first_expr!(1,)); /// assert_eq!(1, first_expr!(1, 2)); /// assert_eq!(1, first_expr!(1, 2,)); /// assert_eq!(1, first_expr!(1, 2, 3)); /// assert_eq!(1, first_expr!(1, 2, 3,)); ///

#[macro_export] macro_rules! first_expr { ($first:expr $(, $expr:expr)*) => {$first}; }

/// 将逗号分隔的表达式转换为第一个表达式的引用。 /// /// # Examples /// /// /// # use kernel::first_expr_ref; /// /// assert_eq!((), first_expr_ref!()); /// assert_eq!(&1, first_expr_ref!(&1)); /// assert_eq!(&1, first_expr_ref!(&1,)); /// assert_eq!(&1, first_expr_ref!(&1, &2)); /// assert_eq!(&1, first_expr_ref!(&1, &2,)); /// assert_eq!(&1, first_expr_ref!(&1, &2, &3)); /// assert_eq!(&1, first_expr_ref!(&1, &2, &3,)); ///

#[macro_export] macro_rules! first_expr_ref { ($first:expr $(, $expr:expr)*) => {&$first}; }

/// 定义一组可能的错误代码。 /// /// # Examples /// /// /// # use kernel::errno; /// /// errno! { /// pub ERR1 = 1; /// pub ERR2 = 2; /// pub ERR3 = 3; /// } /// /// assert_eq!(1, ERR1); /// assert_eq!(2, ERR2); /// assert_eq!(3, ERR3); ///

#[macro_export] macro_rules! errno { ($($(#[$attr:meta]) pub $name:ident = $value:expr;)+) => { $( $(#[$attr]) pub const $name: $crate::error::code::Errno = $crate::error::code::Errno($value); )+ }; }

/// 定义一组可能的错误代码(通过结构体定义)。 /// /// # Examples /// /// /// # use kernel::errno_struct; /// /// errno_struct! { /// pub struct Errno { /// pub ERR1 = 1; /// pub ERR2 = 2; /// pub ERR3 = 3; /// } /// } /// /// assert_eq!(1, Errno::ERR1); /// assert_eq!(2, Errno::ERR2); /// assert_eq!(3, Errno::ERR3); ///

#[macro_export] macro_rules! errno_struct { ( $(#[$struct_attr:meta]) $vis:vis struct $struct_name:ident { $($($(#[$attr:meta]) $name:ident = $value:expr;)+)+ } ) => { $(#[$struct_attr])*

#[derive(Debug, PartialEq, Eq, Copy, Clone)] $vis struct $struct_name { $($($(#[$attr])* $name = $value),+)+ }

$( $(#[$struct_attr]) impl $struct_name { $( $(#[$attr]) pub const $name: Self = Self { $name: $value }; )+ } )+ }; }

/// 定义一组错误代码。 /// /// # Examples /// /// /// # use kernel::error_codes; /// /// error_codes! { /// pub ERR1 => 1, /// pub ERR2 => 2, /// pub ERR3 => 3, /// } /// /// assert_eq!(1, ERR1); /// assert_eq!(2, ERR2); /// assert_eq!(3, ERR3); ///

#[macro_export] macro_rules! error_codes { ($($(#[$attr:meta]) pub $name:ident => $value:expr,)+) => { $( $(#[$attr]) pub const $name: i32 = $value; )+ }; }

/// 定义一组错误代码(通过结构体定义)。 /// /// # Examples /// /// /// # use kernel::error_codes_struct; /// /// error_codes_struct! { /// pub struct ErrorCodes { /// pub ERR1 => 1, /// pub ERR2 => 2, /// pub ERR3 => 3, /// } /// } /// /// assert_eq!(1, ErrorCodes::ERR1); /// assert_eq!(2, ErrorCodes::ERR2); /// assert_eq!(3, ErrorCodes::ERR3); ///

#[macro_export] macro_rules! error_codes_struct { ( $(#[$struct_attr:meta]) $vis:vis struct $struct_name:ident { $($($(#[$attr:meta]) $name:ident => $value:expr,)+)+ } ) => { $(#[$struct_attr])*

#[derive(Debug, PartialEq, Eq, Copy, Clone)] $vis struct $struct_name { $($($(#[$attr])* $name = $value),+)+ }

$( $(#[$struct_attr]) impl $struct_name { $( $(#[$attr]) pub const $name: Self = Self { $name: $value }; )+ } )+ }; }

/// 定义一个从C常量到Rust常量的映射。 /// /// # Examples /// /// /// # use kernel::c_to_rust; /// /// c_to_rust! { /// CONSTANT1, /// CONSTANT2, /// CONSTANT3, /// } /// /// assert_eq!(CONSTANT1, "constant1"); /// assert_eq!(CONSTANT2, "constant2"); /// assert_eq!(CONSTANT3, "constant3"); ///

#[macro_export] macro_rules! c_to_rust { ($($name:ident),+ $(,)?) => { $(const $name: &str = stringify!($name);)+ }; }

/// 定义一个从Rust常量到C常量的映射。 /// /// # Examples /// /// /// # use kernel::rust_to_c; /// /// rust_to_c! { /// "constant1" => CONSTANT1, /// "constant2" => CONSTANT2, /// "constant3" => CONSTANT3, /// } /// /// assert_eq!(rust_to_c!("constant1"), Some(CONSTANT1)); /// assert_eq!(rust_to_c!("constant2"), Some(CONSTANT2)); /// assert_eq!(rust_to_c!("constant3"), Some(CONSTANT3)); /// assert_eq!(rust_to_c!("constant4"), None); ///

#[macro_export] macro_rules! rust_to_c { ($($name:expr => $constant:ident),+ $(,)?) => { fn rust_toc(name: &str) -> Option<&'static str> { match name { $($name => Some(stringify!($constant)),)+ => None, } } }; }

/// 将一个值转换为对齐到指定对齐方式的最接近的大于等于它的值。 /// /// # Examples /// /// /// # use kernel::align_up; /// /// assert_eq!(align_up!(5, 4), 8); /// assert_eq!(align_up!(7, 4), 8); /// assert_eq!(align_up!(9, 4), 12); /// assert_eq!(align_up!(13, 8), 16); ///

#[macro_export] macro_rules! align_up { ($value:expr, $alignment:expr) => { (($value + $alignment - 1) / $alignment) * $alignment }; }

/// 将一个值转换为对齐到指定对齐方式的最接近的小于等于它的值。 /// /// # Examples /// /// /// # use kernel::align_down; /// /// assert_eq!(align_down!(5, 4), 4); /// assert_eq!(align_down!(7, 4), 4); /// assert_eq!(align_down!(9, 4), 8); /// assert_eq!(align_down!(13, 8), 8); ///

#[macro_export] macro_rules! align_down { ($value:expr, $alignment:expr) => { ($value / $alignment) * $alignment }; }

/// 定义一个简单的包装结构体,该结构体将值存储在堆上,并在析构时释放该值。 /// /// # Examples /// /// /// # use kernel::HeapAlloc; /// # /// # let value = vec![1, 2, 3]; /// # /// # fn main() { /// let heap_alloc = HeapAlloc::new(value); /// // 使用heap_alloc... /// # } /// pub struct HeapAlloc(Box);

impl HeapAlloc { /// 创建一个新的HeapAlloc实例。 /// /// 参数value是要存储在堆上的值。 pub fn new(value: T) -> Self { Self(Box::new(value)) } }

impl Deref for HeapAlloc { type Target = T;

fn deref(&self) -> &Self::Target { &self.0 } }

impl Drop for HeapAlloc { fn drop(&mut self) { // 在析构时释放存储在堆上的值。 } } ```