未验证 提交 072e48ba 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!150 Summer OSPP 2022: add the rust-for-linux support of linux driver

Merge Pull Request from: @LHY1999 
 
The Linux kernel plans to accept rust as the second language.
This can help improve the security of the Linux drivers.

However, the current example of drivers in rust-for-linux
is limited. This adds an example for rust-for-linux. 
 
Link:https://gitee.com/openeuler/kernel/pulls/150 
Reviewed-by: Zheng Zengkai <zhengzengkai@huawei.com> 
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com> 
...@@ -438,6 +438,18 @@ config HW_RANDOM_CAVIUM ...@@ -438,6 +438,18 @@ config HW_RANDOM_CAVIUM
If unsure, say Y. If unsure, say Y.
config HW_RANDOM_CAVIUM_RUST
tristate "Rust implementation of Cavium ThunderX Random Number Generator"
depends on RUST && HW_RANDOM && PCI && ARCH_THUNDER
help
This driver provides alternative Rust-based kernel-side support
for the Random Number Generator hardware found on Cavium SoCs.
To compile this driver as a module, choose M here: the
module will be called cavium_rng_rust.
If unsure, say N.
config HW_RANDOM_MTK config HW_RANDOM_MTK
tristate "Mediatek Random Number Generator support" tristate "Mediatek Random Number Generator support"
depends on HW_RANDOM depends on HW_RANDOM
......
...@@ -39,6 +39,7 @@ obj-$(CONFIG_HW_RANDOM_STM32) += stm32-rng.o ...@@ -39,6 +39,7 @@ obj-$(CONFIG_HW_RANDOM_STM32) += stm32-rng.o
obj-$(CONFIG_HW_RANDOM_PIC32) += pic32-rng.o obj-$(CONFIG_HW_RANDOM_PIC32) += pic32-rng.o
obj-$(CONFIG_HW_RANDOM_MESON) += meson-rng.o obj-$(CONFIG_HW_RANDOM_MESON) += meson-rng.o
obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o
obj-$(CONFIG_HW_RANDOM_CAVIUM_RUST) += cavium_rng_rust.o
obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o
obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o
obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o
......
// SPDX-License-Identifier: GPL-2.0
//! Broadcom CAVIUM Random Number Generator support.
use kernel::{
bindings, define_pci_id_table, device, file, file::File, io_buffer::IoBufferWriter,
io_mem::IoMem, miscdev, module_pci_driver, pci, prelude::*, sync::Ref,
};
module_pci_driver! {
type: RngDriver,
name: b"cavium_rng_rust",
author: b"Rust for Linux Contributors",
description: b"Cavium Random Number Generator (RNG) driver",
license: b"GPL v2",
}
const THUNDERX_RNM_ENT_EN: u64 = 0x1;
const THUNDERX_RNM_RNG_EN: u64 = 0x2;
const CAVIUM_SIZE: usize = 0x1000;
struct RngDevice;
impl file::Operations for RngDevice {
kernel::declare_file_operations!();
fn open(_open_data: &(), _file: &File) -> Result {
Ok(())
}
fn read(_: (), _: &File, data: &mut impl IoBufferWriter, offset: u64) -> Result<usize> {
// Succeed if the caller doesn't provide a buffer or if not at the start.
if data.is_empty() || offset != 0 {
return Ok(0);
}
data.write(&0_u32)?;
Ok(4)
}
}
struct CAVIUMResources {
base: IoMem<CAVIUM_SIZE>,
}
struct CAVIUMData {
dev: device::Device,
}
type DeviceData = device::Data<miscdev::Registration<RngDevice>, CAVIUMResources, CAVIUMData>;
struct RngDriver;
impl pci::Driver for RngDriver {
type Data = Ref<DeviceData>;
define_pci_id_table! {u32, [
(pci::DeviceId::new(bindings::PCI_VENDOR_ID_CAVIUM, 0xa018), None),
]}
fn probe(dev: &mut pci::Device, _id_info: Option<&Self::IdInfo>) -> Result<Self::Data> {
let res = dev.take_resource().ok_or(ENXIO)?;
let res = CAVIUMResources {
// SAFETY: This device doesn't support DMA.
base: unsafe { IoMem::try_new(res)? },
};
res.base
.writeq(THUNDERX_RNM_ENT_EN | THUNDERX_RNM_RNG_EN, 0);
let ret = dev.pci_enable_sriov(1);
match ret {
Ok(_o) => (),
Err(_e) => {
dev_err!(dev, "Error initializing RNG virtual function.\n",);
res.base.writeq(0, 0);
return Err(_e);
}
}
let cdata = CAVIUMData {
dev: device::Device::from_dev(dev),
};
let mut data = kernel::new_device_data!(
miscdev::Registration::new(),
res,
cdata,
"CAVIUM::Registrations"
)?;
let data = Ref::<DeviceData>::from(data);
data.registrations()
.ok_or(ENXIO)?
.as_pinned_mut()
.register(fmt!("rust_cavium"), ())?;
Ok(data.into())
}
}
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <linux/security.h> #include <linux/security.h>
...@@ -620,6 +621,18 @@ unsigned int rust_helper_NF_QUEUE_NR(unsigned int n) ...@@ -620,6 +621,18 @@ unsigned int rust_helper_NF_QUEUE_NR(unsigned int n)
} }
EXPORT_SYMBOL_GPL(rust_helper_NF_QUEUE_NR); 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 * 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 * as the Rust `usize` type, so we can use it in contexts where Rust
......
...@@ -133,7 +133,7 @@ unsafe extern "C" fn probe_callback<T: Driver>( ...@@ -133,7 +133,7 @@ unsafe extern "C" fn probe_callback<T: Driver>(
} }
} }
unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device) -> i32 { unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device) {
// SAFETY: `adev` is valid by the contract with the C code. // SAFETY: `adev` is valid by the contract with the C code.
let ptr = unsafe { bindings::amba_get_drvdata(adev) }; let ptr = unsafe { bindings::amba_get_drvdata(adev) };
// SAFETY: The value returned by `amba_get_drvdata` was stored by a previous call to // SAFETY: The value returned by `amba_get_drvdata` was stored by a previous call to
...@@ -142,7 +142,6 @@ unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device ...@@ -142,7 +142,6 @@ unsafe extern "C" fn remove_callback<T: Driver>(adev: *mut bindings::amba_device
let data = unsafe { T::Data::from_pointer(ptr) }; let data = unsafe { T::Data::from_pointer(ptr) };
T::remove(&data); T::remove(&data);
<T::Data as driver::DeviceRemoval>::device_remove(&data); <T::Data as driver::DeviceRemoval>::device_remove(&data);
0
} }
/// An Amba device. /// An Amba device.
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h> #include <linux/netfilter_ipv6.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/random.h> #include <linux/random.h>
......
...@@ -60,6 +60,8 @@ pub mod mm; ...@@ -60,6 +60,8 @@ pub mod mm;
#[cfg(CONFIG_NET)] #[cfg(CONFIG_NET)]
pub mod net; pub mod net;
pub mod pages; pub mod pages;
#[cfg(CONFIG_PCI)]
pub mod pci;
pub mod power; pub mod power;
pub mod revocable; pub mod revocable;
pub mod security; pub mod security;
......
...@@ -107,11 +107,7 @@ unsafe impl AlwaysRefCounted for SkBuff { ...@@ -107,11 +107,7 @@ unsafe impl AlwaysRefCounted for SkBuff {
unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) { unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
// SAFETY: The safety requirements guarantee that the refcount is nonzero. // SAFETY: The safety requirements guarantee that the refcount is nonzero.
unsafe { unsafe { bindings::__kfree_skb(obj.cast().as_ptr()) };
bindings::__kfree_skb(
obj.cast().as_ptr()
)
};
} }
} }
......
// SPDX-License-Identifier: GPL-2.0
//! PCI devices and drivers.
//!
//! C header: [`include/linux/pci.h`](../../../../include/linux/pci.h)
#![allow(dead_code)]
use crate::{
bindings, c_types, device, driver,
error::{from_kernel_result, Result},
io_mem::Resource,
str::CStr,
to_result,
types::PointerWrapper,
ThisModule,
};
/// An adapter for the registration of PCI drivers.
pub struct Adapter<T: Driver>(T);
impl<T: Driver> driver::DriverOps for Adapter<T> {
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_ref();
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<T: Driver> Adapter<T> {
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) };
// SAFETY: `id` is a pointer within the static table, so it's always valid.
let offset = unsafe {(*id).driver_data};
// SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, which
// guarantees that the resulting pointer is within the table.
let info = {
let ptr = unsafe {id.cast::<u8>().offset(offset as _).cast::<Option<T::IdInfo>>()};
unsafe {(&*ptr).as_ref()}
};
let data = T::probe(&mut dev, info)?;
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);
<T::Data as driver::DeviceRemoval>::device_remove(&data);
}
}
/// Abstraction for bindings::pci_device_id.
#[derive(Clone, Copy)]
pub struct DeviceId {
/// Vendor ID
pub vendor: u32,
/// Device ID
pub device: u32,
/// Subsystem vendor ID
pub subvendor: u32,
/// Subsystem device ID
pub subdevice: u32,
/// Device class and subclass
pub class: u32,
/// Limit which sub-fields of the class
pub class_mask: u32,
}
impl DeviceId {
const PCI_ANY_ID: u32 = !0;
/// PCI_DEVICE macro.
pub const fn new(vendor: u32, device: u32) -> Self {
Self {
vendor,
device,
subvendor: DeviceId::PCI_ANY_ID,
subdevice: DeviceId::PCI_ANY_ID,
class: 0,
class_mask: 0,
}
}
/// PCI_DEVICE_CLASS macro.
pub const fn with_class(class: u32, class_mask: u32) -> Self {
Self {
vendor: DeviceId::PCI_ANY_ID,
device: DeviceId::PCI_ANY_ID,
subvendor: DeviceId::PCI_ANY_ID,
subdevice: DeviceId::PCI_ANY_ID,
class,
class_mask,
}
}
}
// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `pci_device_id::driver_data`.
unsafe impl const driver::RawDeviceId for DeviceId {
type RawType = bindings::pci_device_id;
const ZERO: Self::RawType = bindings::pci_device_id {
vendor: 0,
device: 0,
subvendor: 0,
subdevice: 0,
class: 0,
class_mask: 0,
driver_data: 0,
};
fn to_rawid(&self, offset: isize) -> Self::RawType {
bindings::pci_device_id {
vendor: self.vendor,
device: self.device,
subvendor: self.subvendor,
subdevice: self.subdevice,
class: self.class,
class_mask: self.class_mask,
driver_data: offset as _,
}
}
}
/// Define a const pci device id table
///
/// # Examples
///
/// ```ignore
/// # use kernel::{pci, define_pci_id_table};
/// #
/// struct MyDriver;
/// impl pci::Driver for MyDriver {
/// // [...]
/// # fn probe(_dev: &mut pci::Device, _id_info: Option<&Self::IdInfo>) -> Result {
/// # Ok(())
/// # }
/// # define_pci_id_table! {u32, [
/// # (pci::DeviceId::new(0x010800, 0xffffff), None),
/// # (pci::DeviceId::with_class(0x010802, 0xfffff), Some(0x10)),
/// # ]}
/// }
/// ```
#[macro_export]
macro_rules! define_pci_id_table {
($data_type:ty, $($t:tt)*) => {
type IdInfo = $data_type;
const PCI_ID_TABLE: $crate::driver::IdTable<'static, $crate::pci::DeviceId, $data_type> = {
$crate::define_id_array!(ARRAY, $crate::pci::DeviceId, $data_type, $($t)* );
ARRAY.as_table()
};
};
}
/// 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 type holding information about each device id supported by the driver.
type IdInfo: 'static = ();
/// The table of device ids supported by the driver.
const PCI_ID_TABLE: driver::IdTable<'static, DeviceId, Self::IdInfo>;
/// 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, id: Option<&Self::IdInfo>) -> Result<Self::Data>;
/// 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,
res: Option<Resource>,
}
impl Device {
/// Creates a new device from the given pointer.
///
/// # Safety
///
/// `ptr` must be non-null and valid. It must remain valid for the lifetime of the returned
/// instance.
unsafe fn from_ptr(ptr: *mut bindings::pci_dev) -> Self {
// SAFETY: The safety requirements of the function ensure that `ptr` is valid.
let dev = unsafe { &mut *ptr };
// INVARIANT: The safety requirements of the function ensure the lifetime invariant.
Self {
ptr,
res: Resource::new(dev.resource[0].start, dev.resource[0].end),
}
}
/// Returns the io mem resource associated with the device, if there is one.
///
/// Ownership of the resource is transferred to the caller, so subsequent calls to this
/// function will return [`None`].
pub fn take_resource(&mut self) -> Option<Resource> {
self.res.take()
}
pub fn pci_enable_sriov(&self, nr_virtfn: i32) -> Result {
to_result(||
// SAFETY: The existence of the shared references mean `self.0`is valid.
unsafe{bindings::pci_enable_sriov(self.ptr, nr_virtfn)})
}
fn pci_disable_sriov(&self) {
// SAFETY: The existence of the shared references mean `self.0`is valid.
unsafe { bindings::pci_disable_sriov(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 }
}
}
/// Declares a kernel module that exposes a single pci driver.
///
/// # Examples
///
/// ```ignore
/// # use kernel::{pci, define_pci_id_table, module_pci_driver};
/// #
/// struct MyDriver;
/// impl pci::Driver for MyDriver {
/// // [...]
/// # fn probe(_dev: &mut pci::Device, _id_info: Option<&Self::IdInfo>) -> Result {
/// # Ok(())
/// # }
/// # define_pci_id_table! {u32, [
/// # (pci::DeviceId::new(0x177d, 0xa018), None),
/// # ]}
/// }
///
/// module_pci_driver! {
/// type: MyDriver,
/// name: b"module_name",
/// author: b"Author name",
/// license: b"GPL",
/// }
/// ```
#[macro_export]
macro_rules! module_pci_driver {
($($f:tt)*) => {
$crate::module_driver!(<T>, $crate::pci::Adapter<T>, { $($f)* });
};
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册