From 496e6c48e64facffb42c715d72a14b0d46497ea9 Mon Sep 17 00:00:00 2001 From: Li Hongyu <543306408@qq.com> Date: Thu, 29 Sep 2022 11:16:50 +0000 Subject: [PATCH] rust: add initial PCI support maillist inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I5TUIJ CVE: NA Reference: https://github.com/Rust-for-Linux/linux/pull/856 ---------------------------------------------------------------------- Added minimum abstration APIs for PCI. Signed-off-by: FUJITA Tomonori Signed-off-by: Li Hongyu <543306408@qq.com> --- rust/helpers.c | 13 ++++ rust/kernel/bindings_helper.h | 1 + rust/kernel/lib.rs | 2 + rust/kernel/pci.rs | 109 ++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 rust/kernel/pci.rs diff --git a/rust/helpers.c b/rust/helpers.c index ead3a64f700c..cfb54a0207d8 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -620,6 +621,18 @@ unsigned int rust_helper_NF_QUEUE_NR(unsigned int n) } EXPORT_SYMBOL_GPL(rust_helper_NF_QUEUE_NR); +void rust_helper_pci_set_drvdata(struct pci_dev *pdev, void *data) +{ + pci_set_drvdata(pdev, data); +} +EXPORT_SYMBOL_GPL(rust_helper_pci_set_drvdata); + +void *rust_helper_pci_get_drvdata(struct pci_dev *pdev) +{ + return pci_get_drvdata(pdev); +} +EXPORT_SYMBOL_GPL(rust_helper_pci_get_drvdata); + /* * We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type * as the Rust `usize` type, so we can use it in contexts where Rust diff --git a/rust/kernel/bindings_helper.h b/rust/kernel/bindings_helper.h index 73100fa139eb..3bab72c8eced 100644 --- a/rust/kernel/bindings_helper.h +++ b/rust/kernel/bindings_helper.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 3e01c30de670..6c11382a03f7 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -60,6 +60,8 @@ pub mod mm; #[cfg(CONFIG_NET)] pub mod net; pub mod pages; +#[cfg(CONFIG_PCI)] +pub mod pci; pub mod power; pub mod revocable; pub mod security; diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs new file mode 100644 index 000000000000..1dab72181eb1 --- /dev/null +++ b/rust/kernel/pci.rs @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! PCI devices and drivers. +//! +//! C header: [`include/linux/pci.h`](../../../../include/linux/pci.h) + +use crate::{ + bindings, c_types, device, driver, + error::{from_kernel_result, Result}, + str::CStr, + to_result, + types::PointerWrapper, + ThisModule, +}; + +/// An adapter for the registration of PCI drivers. +pub struct Adapter(T); + +impl driver::DriverOps for Adapter { + type RegType = bindings::pci_driver; + + unsafe fn register( + reg: *mut bindings::pci_driver, + name: &'static CStr, + module: &'static ThisModule, + ) -> Result { + let pdrv: &mut bindings::pci_driver = unsafe { &mut *reg }; + + pdrv.name = name.as_char_ptr(); + pdrv.probe = Some(Self::probe_callback); + pdrv.remove = Some(Self::remove_callback); + pdrv.id_table = T::PCI_ID_TABLE.as_ptr(); + to_result(|| unsafe { bindings::__pci_register_driver(reg, module.0, name.as_char_ptr()) }) + } + + unsafe fn unregister(reg: *mut bindings::pci_driver) { + unsafe { bindings::pci_unregister_driver(reg) } + } +} + +impl Adapter { + extern "C" fn probe_callback( + pdev: *mut bindings::pci_dev, + _id: *const bindings::pci_device_id, + ) -> c_types::c_int { + from_kernel_result! { + let mut dev = unsafe { Device::from_ptr(pdev) }; + let data = T::probe(&mut dev)?; + unsafe { bindings::pci_set_drvdata(pdev, data.into_pointer() as _) }; + Ok(0) + } + } + + extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) { + let ptr = unsafe { bindings::pci_get_drvdata(pdev) }; + let data = unsafe { T::Data::from_pointer(ptr) }; + T::remove(&data); + ::device_remove(&data); + } +} + +/// A PCI driver +pub trait Driver { + /// Data stored on device by driver. + /// + /// Corresponds to the data set or retrieved via the kernel's + /// `pci_{set,get}_drvdata()` functions. + /// + /// Require that `Data` implements `PointerWrapper`. We guarantee to + /// never move the underlying wrapped data structure. This allows + type Data: PointerWrapper + Send + Sync + driver::DeviceRemoval = (); + + /// The table of device ids supported by the driver. + const PCI_ID_TABLE: &'static [bindings::pci_device_id]; + + /// PCI driver probe. + /// + /// Called when a new platform device is added or discovered. + /// Implementers should attempt to initialize the device here. + fn probe(dev: &mut Device) -> Result; + + /// PCI driver remove. + /// + /// Called when a platform device is removed. + /// Implementers should prepare the device for complete removal here. + fn remove(_data: &Self::Data); +} + +/// A PCI device. +/// +/// # Invariants +/// +/// The field `ptr` is non-null and valid for the lifetime of the object. +pub struct Device { + ptr: *mut bindings::pci_dev, +} + +impl Device { + unsafe fn from_ptr(ptr: *mut bindings::pci_dev) -> Self { + Self { ptr } + } +} + +unsafe impl device::RawDevice for Device { + fn raw_device(&self) -> *mut bindings::device { + // SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid. + unsafe { &mut (*self.ptr).dev } + } +} -- GitLab