Skip to content

Commit 698f04d

Browse files
authoredMay 25, 2021
Merge pull request torvalds#276 from TheSven73/rust-for-linux-pdev-pr2
Simple Rust driver that touches real hardware: PR 2/6
2 parents 1a73789 + c02591f commit 698f04d

File tree

7 files changed

+106
-294
lines changed

7 files changed

+106
-294
lines changed
 

‎arch/arm/boot/dts/bcm2835-rpi-zero-w-rust.dts

-156
This file was deleted.

‎arch/arm/boot/dts/bcm2836-rpi-2-b-rust.dts

-135
This file was deleted.

‎drivers/char/hw_random/bcm2835_rng_rust.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
use alloc::boxed::Box;
99
use core::pin::Pin;
10+
use kernel::of::OfMatchTable;
1011
use kernel::prelude::*;
1112
use kernel::{cstr, platdev};
1213

@@ -24,7 +25,13 @@ struct RngModule {
2425

2526
impl KernelModule for RngModule {
2627
fn init() -> Result<Self> {
27-
let pdev = platdev::Registration::new_pinned(cstr!("bcm2835-rng-rust"), &THIS_MODULE)?;
28+
let of_match_tbl = OfMatchTable::new(&cstr!("brcm,bcm2835-rng"))?;
29+
30+
let pdev = platdev::Registration::new_pinned(
31+
cstr!("bcm2835-rng-rust"),
32+
Some(of_match_tbl),
33+
&THIS_MODULE,
34+
)?;
2835

2936
Ok(RngModule { _pdev: pdev })
3037
}

‎rust/kernel/bindings_helper.h

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/mm.h>
1515
#include <uapi/linux/android/binder.h>
1616
#include <linux/platform_device.h>
17+
#include <linux/of_platform.h>
1718

1819
// `bindgen` gets confused at certain things
1920
const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;

‎rust/kernel/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ pub mod sysctl;
6363

6464
pub mod io_buffer;
6565
pub mod iov_iter;
66+
pub mod of;
6667
pub mod platdev;
6768
mod types;
6869
pub mod user_ptr;

‎rust/kernel/of.rs

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Devicetree and Open Firmware abstractions.
4+
//!
5+
//! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h)
6+
7+
use alloc::boxed::Box;
8+
9+
use crate::{
10+
bindings, c_types,
11+
error::{Error, Result},
12+
types::PointerWrapper,
13+
CStr,
14+
};
15+
16+
use core::mem::transmute;
17+
18+
type InnerTable = Box<[bindings::of_device_id; 2]>;
19+
20+
/// Wraps a kernel Open Firmware / devicetree match table.
21+
///
22+
/// Rust drivers may create this structure to match against devices
23+
/// described in the devicetree.
24+
///
25+
/// The ['PointerWrapper'] trait provides conversion to/from a raw pointer,
26+
/// suitable to be assigned to a `bindings::device_driver::of_match_table`.
27+
///
28+
/// # Invariants
29+
///
30+
/// The final array element is always filled with zeros (the default).
31+
pub struct OfMatchTable(InnerTable);
32+
33+
impl OfMatchTable {
34+
/// Creates a [`OfMatchTable`] from a single `compatible` string.
35+
pub fn new(compatible: &CStr<'static>) -> Result<Self> {
36+
let tbl: InnerTable = Box::try_new([
37+
Self::new_of_device_id(compatible)?,
38+
bindings::of_device_id::default(),
39+
])?;
40+
// INVARIANTS: we allocated an array with `default()` as its final
41+
// element, therefore that final element will be filled with zeros,
42+
// and the invariant above will hold.
43+
Ok(Self(tbl))
44+
}
45+
46+
fn new_of_device_id(compatible: &CStr<'static>) -> Result<bindings::of_device_id> {
47+
let mut buf = [0_u8; 128];
48+
if compatible.len() > buf.len() {
49+
return Err(Error::EINVAL);
50+
}
51+
buf.get_mut(..compatible.len())
52+
.ok_or(Error::EINVAL)?
53+
.copy_from_slice(compatible.as_bytes());
54+
Ok(bindings::of_device_id {
55+
// SAFETY: re-interpretation from [u8] to [c_types::c_char] of same length is always safe.
56+
compatible: unsafe { transmute::<[u8; 128], [c_types::c_char; 128]>(buf) },
57+
..Default::default()
58+
})
59+
}
60+
}
61+
62+
impl PointerWrapper for OfMatchTable {
63+
fn into_pointer(self) -> *const c_types::c_void {
64+
// Per the invariant above, the generated pointer points to an
65+
// array of `bindings::of_device_id`, where the final element is
66+
// filled with zeros (the sentinel). Therefore, it's suitable to
67+
// be assigned to `bindings::device_driver::of_match_table`.
68+
self.0.into_pointer()
69+
}
70+
71+
unsafe fn from_pointer(p: *const c_types::c_void) -> Self {
72+
Self(InnerTable::from_pointer(p))
73+
}
74+
}

‎rust/kernel/platdev.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
use crate::{
1010
bindings, c_types,
1111
error::{Error, Result},
12-
pr_info, CStr,
12+
of::OfMatchTable,
13+
pr_info,
14+
types::PointerWrapper,
15+
CStr,
1316
};
1417
use alloc::boxed::Box;
1518
use core::{marker::PhantomPinned, pin::Pin};
@@ -18,6 +21,7 @@ use core::{marker::PhantomPinned, pin::Pin};
1821
#[derive(Default)]
1922
pub struct Registration {
2023
registered: bool,
24+
of_table: Option<*const c_types::c_void>,
2125
pdrv: bindings::platform_driver,
2226
_pin: PhantomPinned,
2327
}
@@ -40,6 +44,7 @@ impl Registration {
4044
fn register(
4145
self: Pin<&mut Self>,
4246
name: CStr<'static>,
47+
of_match_table: Option<OfMatchTable>,
4348
module: &'static crate::ThisModule,
4449
) -> Result {
4550
// SAFETY: We must ensure that we never move out of `this`.
@@ -49,13 +54,22 @@ impl Registration {
4954
return Err(Error::EINVAL);
5055
}
5156
this.pdrv.driver.name = name.as_ptr() as *const c_types::c_char;
57+
if let Some(tbl) = of_match_table {
58+
let ptr = tbl.into_pointer();
59+
this.of_table = Some(ptr);
60+
this.pdrv.driver.of_match_table = ptr.cast();
61+
}
5262
this.pdrv.probe = Some(probe_callback);
5363
this.pdrv.remove = Some(remove_callback);
5464
// SAFETY:
5565
// - `this.pdrv` lives at least until the call to `platform_driver_unregister()` returns.
5666
// - `name` pointer has static lifetime.
5767
// - `module.0` lives at least as long as the module.
5868
// - `probe()` and `remove()` are static functions.
69+
// - `of_match_table` is either:
70+
// - a raw pointer which lives until after the call to
71+
// `bindings::platform_driver_unregister()`, or
72+
// - null.
5973
let ret = unsafe { bindings::__platform_driver_register(&mut this.pdrv, module.0) };
6074
if ret < 0 {
6175
return Err(Error::from_kernel_errno(ret));
@@ -69,10 +83,11 @@ impl Registration {
6983
/// Returns a pinned heap-allocated representation of the registration.
7084
pub fn new_pinned(
7185
name: CStr<'static>,
86+
of_match_tbl: Option<OfMatchTable>,
7287
module: &'static crate::ThisModule,
7388
) -> Result<Pin<Box<Self>>> {
7489
let mut r = Pin::from(Box::try_new(Self::default())?);
75-
r.as_mut().register(name, module)?;
90+
r.as_mut().register(name, of_match_tbl, module)?;
7691
Ok(r)
7792
}
7893
}
@@ -85,5 +100,10 @@ impl Drop for Registration {
85100
// safe to call.
86101
unsafe { bindings::platform_driver_unregister(&mut self.pdrv) }
87102
}
103+
if let Some(ptr) = self.of_table {
104+
// SAFETY: `ptr` came from an `OfMatchTable`.
105+
let tbl = unsafe { OfMatchTable::from_pointer(ptr) };
106+
drop(tbl);
107+
}
88108
}
89109
}

0 commit comments

Comments
 (0)
Please sign in to comment.