Skip to content

Add rust_random sample that uses module_misc_device. #220

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion rust/kernel/file_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,12 @@ pub trait FileOpener<T: ?Sized>: FileOperations {
fn open(context: &T) -> KernelResult<Self::Wrapper>;
}

impl<T: FileOperations<Wrapper = Box<T>> + Default> FileOpener<()> for T {
fn open(_: &()) -> KernelResult<Self::Wrapper> {
Ok(Box::try_new(T::default())?)
}
}

/// Corresponds to the kernel's `struct file_operations`.
///
/// You implement this trait whenever you would create a `struct file_operations`.
Expand All @@ -532,7 +538,7 @@ pub trait FileOperations: Send + Sync + Sized {
const TO_USE: ToUse;

/// The pointer type that will be used to hold ourselves.
type Wrapper: PointerWrapper<Self>;
type Wrapper: PointerWrapper<Self> = Box<Self>;

/// Cleans up after the last reference to the file goes away.
///
Expand Down
1 change: 1 addition & 0 deletions rust/kernel/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#![feature(
allocator_api,
alloc_error_handler,
associated_type_defaults,
const_fn,
const_mut_refs,
const_panic,
Expand Down
2 changes: 1 addition & 1 deletion rust/kernel/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

pub use alloc::{borrow::ToOwned, string::String};

pub use module::module;
pub use module::{module, module_misc_device};

pub use super::{pr_alert, pr_cont, pr_crit, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};

Expand Down
81 changes: 80 additions & 1 deletion rust/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ pub fn module(ts: TokenStream) -> TokenStream {
}}

fn __init() -> kernel::c_types::c_int {{
match <{type_} as KernelModule>::init() {{
match <{type_} as kernel::KernelModule>::init() {{
Ok(m) => {{
unsafe {{
__MOD = Some(m);
Expand Down Expand Up @@ -683,3 +683,82 @@ pub fn module(ts: TokenStream) -> TokenStream {
initcall_section = ".initcall6.init"
).parse().expect("Error parsing formatted string into token stream.")
}

/// Declares a kernel module that exposes a single misc device.
///
/// The `type` argument should be a type which implements the [`FileOpener`] trait. Also accepts
/// various forms of kernel metadata.
///
/// [`FileOpener`]: ../kernel/file_operations/trait.FileOpener.html
///
/// # Examples
///
/// ```rust,no_run
/// use kernel::prelude::*;
///
/// module_misc_device! {
/// type: MyFile,
/// name: b"my_miscdev_kernel_module",
/// author: b"Rust for Linux Contributors",
/// description: b"My very own misc device kernel module!",
/// license: b"GPL v2",
/// }
///
/// #[derive(Default)]
/// struct MyFile;
///
/// impl kernel::file_operations::FileOperations for MyFile {
/// kernel::declare_file_operations!();
/// }
/// ```
#[proc_macro]
pub fn module_misc_device(ts: TokenStream) -> TokenStream {
let mut it = ts.into_iter();

let type_ = get_ident(&mut it, "type");
let name = get_byte_string(&mut it, "name");
let author = get_byte_string(&mut it, "author");
let description = get_byte_string(&mut it, "description");
let license = get_byte_string(&mut it, "license");
expect_end(&mut it);

let module = format!("__internal_ModuleFor{}", type_);

format!(
"
#[doc(hidden)]
struct {module} {{
_dev: core::pin::Pin<alloc::boxed::Box<kernel::miscdev::Registration>>,
}}

impl kernel::KernelModule for {module} {{
fn init() -> kernel::KernelResult<Self> {{
Ok(Self {{
_dev: kernel::miscdev::Registration::new_pinned::<{type_}>(
kernel::cstr!(\"{name}\"),
None,
(),
)?,
}})
}}
}}

kernel::prelude::module! {{
type: {module},
name: b\"{name}\",
author: b\"{author}\",
description: b\"{description}\",
license: b\"{license}\",
params: {{}},
}}
",
module = module,
type_ = type_,
name = name,
author = author,
description = description,
license = license
)
.parse()
.expect("Error parsing formatted string into token stream.")
}
10 changes: 10 additions & 0 deletions samples/rust/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,14 @@ config SAMPLE_RUST_SEMAPHORE_C

If unsure, say N.

config SAMPLE_RUST_RANDOM
tristate "Random"
help
This option builds the Rust random sample.

To compile this as a module, choose M here:
the module will be called rust_random.

If unsure, say N.

endif # SAMPLES_RUST
1 change: 1 addition & 0 deletions samples/rust/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ obj-$(CONFIG_SAMPLE_RUST_MISCDEV) += rust_miscdev.o
obj-$(CONFIG_SAMPLE_RUST_STACK_PROBING) += rust_stack_probing.o
obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE) += rust_semaphore.o
obj-$(CONFIG_SAMPLE_RUST_SEMAPHORE_C) += rust_semaphore_c.o
obj-$(CONFIG_SAMPLE_RUST_RANDOM) += rust_random.o
15 changes: 2 additions & 13 deletions samples/rust/rust_chrdev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
use alloc::boxed::Box;
use core::pin::Pin;
use kernel::prelude::*;
use kernel::{
chrdev, cstr,
file_operations::{FileOpener, FileOperations},
};
use kernel::{chrdev, cstr, file_operations::FileOperations};

module! {
type: RustChrdev,
Expand All @@ -23,18 +20,10 @@ module! {
},
}

#[derive(Default)]
struct RustFile;

impl FileOpener<()> for RustFile {
fn open(_ctx: &()) -> KernelResult<Self::Wrapper> {
pr_info!("rust file was opened!\n");
Ok(Box::try_new(Self)?)
}
}

impl FileOperations for RustFile {
type Wrapper = Box<Self>;

kernel::declare_file_operations!();
}

Expand Down
60 changes: 60 additions & 0 deletions samples/rust/rust_random.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: GPL-2.0

//! Rust random device
//!
//! Adapted from Alex Gaynor's original available at
//! <https://github.com/alex/just-use/blob/master/src/lib.rs>.

#![no_std]
#![feature(allocator_api, global_asm)]

use kernel::{
file_operations::{File, FileOperations},
prelude::*,
user_ptr::{UserSlicePtrReader, UserSlicePtrWriter},
};

#[derive(Default)]
struct RandomFile;

impl FileOperations for RandomFile {
kernel::declare_file_operations!(read, write);

fn read(&self, file: &File, buf: &mut UserSlicePtrWriter, _offset: u64) -> KernelResult<usize> {
let total_len = buf.len();
let mut chunkbuf = [0; 256];

while !buf.is_empty() {
let len = chunkbuf.len().min(buf.len());
let chunk = &mut chunkbuf[0..len];

if file.is_blocking() {
kernel::random::getrandom(chunk)?;
} else {
kernel::random::getrandom_nonblock(chunk)?;
}
buf.write_slice(chunk)?;
}
Ok(total_len)
}

fn write(&self, buf: &mut UserSlicePtrReader, _offset: u64) -> KernelResult<usize> {
let total_len = buf.len();
let mut chunkbuf = [0; 256];
while !buf.is_empty() {
let len = chunkbuf.len().min(buf.len());
let chunk = &mut chunkbuf[0..len];
buf.read_slice(chunk)?;
kernel::random::add_randomness(chunk);
}
Ok(total_len)
}
}

module_misc_device! {
type: RandomFile,
name: b"rust_random",
author: b"Rust for Linux Contributors",
description: b"Just use /dev/urandom: Now with early-boot safety",
license: b"GPL v2",
}