Skip to content
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

Parameter support #7

Merged
merged 4 commits into from
Sep 19, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[workspace]
members = [
"rust/shlex",
"rust/module",
ojeda marked this conversation as resolved.
Show resolved Hide resolved
"rust/kernel",
"drivers/char/rust_example",
]
Expand Down
29 changes: 23 additions & 6 deletions drivers/char/rust_example/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@

use kernel::prelude::*;

module!{
typename: RustExample,
name: b"rust_example",
author: b"Rust for Linux Contributors",
description: b"An example kernel module written in Rust",
license: b"GPL v2",
params: {
my_bool: bool {
default_: true,
ojeda marked this conversation as resolved.
Show resolved Hide resolved
permissions: 0,
description: b"Example of bool",
},
my_i32: i32 {
default_: 42,
permissions: 0o644,
description: b"Example of i32",
},
},
}

struct RustExample {
message: String,
}
Expand All @@ -13,6 +33,9 @@ impl KernelModule for RustExample {
fn init() -> KernelResult<Self> {
println!("Rust Example (init)");
println!("Am I built-in? {}", !cfg!(MODULE));
println!("Parameters:");
println!(" my_bool: {}", my_bool.read());
println!(" my_i32: {}", my_i32.read());
Ok(RustExample {
message: "on the heap!".to_owned(),
})
Expand All @@ -26,9 +49,3 @@ impl Drop for RustExample {
}
}

kernel_module!(
RustExample,
author: b"Rust for Linux Contributors",
description: b"An example kernel module written in Rust",
license: b"GPL v2"
);
1 change: 1 addition & 0 deletions rust/kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ publish = false

[dependencies]
bitflags = "1"
module = { path = "../module" }

[build-dependencies]
bindgen = "0.54"
Expand Down
2 changes: 2 additions & 0 deletions rust/kernel/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ const INCLUDED_VARS: &[&str] = &[
"SEEK_CUR",
"SEEK_END",
"O_NONBLOCK",
"param_ops_bool",
"param_ops_int",
];
const OPAQUE_TYPES: &[&str] = &[
// These need to be opaque because they're both packed and aligned, which rustc
Expand Down
125 changes: 0 additions & 125 deletions rust/kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,131 +26,6 @@ pub mod user_ptr;
pub use crate::error::{Error, KernelResult};
pub use crate::types::{CStr, Mode};

/// Declares the entrypoint for a kernel module. The first argument should be a type which
/// implements the [`KernelModule`] trait. Also accepts various forms of kernel metadata.
///
/// Example:
/// ```rust,no_run
/// use kernel::prelude::*;
///
/// struct MyKernelModule;
/// impl KernelModule for MyKernelModule {
/// fn init() -> KernelResult<Self> {
/// Ok(MyKernelModule)
/// }
/// }
///
/// kernel_module!(
/// MyKernelModule,
/// author: b"Rust for Linux Contributors",
/// description: b"My very own kernel module!",
/// license: b"GPL"
/// );
#[macro_export]
macro_rules! kernel_module {
($module:ty, $($name:ident : $value:expr),*) => {
static mut __MOD: Option<$module> = None;

// Built-in modules are initialized through an initcall pointer
//
// TODO: should we compile a C file on the fly to avoid duplication?
#[cfg(not(MODULE))]
#[cfg(not(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS))]
#[link_section = ".initcall6.init"]
#[used]
pub static __initcall: extern "C" fn() -> $crate::c_types::c_int = init_module;

#[cfg(not(MODULE))]
#[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)]
global_asm!(
r#".section ".initcall6.init", "a"
__initcall:
.long init_module - .
.previous
"#
);

// TODO: pass the kernel module name here to generate a unique,
// helpful symbol name (the name would also useful for the `modinfo`
// issue below).
#[no_mangle]
pub extern "C" fn init_module() -> $crate::c_types::c_int {
match <$module as $crate::KernelModule>::init() {
Ok(m) => {
unsafe {
__MOD = Some(m);
}
return 0;
}
Err(e) => {
return e.to_kernel_errno();
}
}
}

#[no_mangle]
pub extern "C" fn cleanup_module() {
unsafe {
// Invokes drop() on __MOD, which should be used for cleanup.
__MOD = None;
}
}

$(
$crate::kernel_module!(@attribute $name, $value);
)*
};

// TODO: The modinfo attributes below depend on the compiler placing
// the variables in order in the .modinfo section, so that you end up
// with b"key=value\0" in order in the section. This is a reasonably
// standard trick in C, but I'm not sure that rustc guarantees it.
//
// Ideally we'd be able to use concat_bytes! + stringify_bytes! +
// some way of turning a string literal (or at least a string
// literal token) into a bytes literal, and get a single static
// [u8; * N] with the whole thing, but those don't really exist yet.
// Most of the alternatives (e.g. .as_bytes() as a const fn) give
// you a pointer, not an array, which isn't right.

// TODO: `modules.builtin.modinfo` etc. is missing the prefix (module name)
(@attribute author, $value:expr) => {
#[link_section = ".modinfo"]
#[used]
pub static AUTHOR_KEY: [u8; 7] = *b"author=";
#[link_section = ".modinfo"]
#[used]
pub static AUTHOR_VALUE: [u8; $value.len()] = *$value;
#[link_section = ".modinfo"]
#[used]
pub static AUTHOR_NUL: [u8; 1] = *b"\0";
};

(@attribute description, $value:expr) => {
#[link_section = ".modinfo"]
#[used]
pub static DESCRIPTION_KEY: [u8; 12] = *b"description=";
#[link_section = ".modinfo"]
#[used]
pub static DESCRIPTION_VALUE: [u8; $value.len()] = *$value;
#[link_section = ".modinfo"]
#[used]
pub static DESCRIPTION_NUL: [u8; 1] = *b"\0";
};

(@attribute license, $value:expr) => {
#[link_section = ".modinfo"]
#[used]
pub static LICENSE_KEY: [u8; 8] = *b"license=";
#[link_section = ".modinfo"]
#[used]
pub static LICENSE_VALUE: [u8; $value.len()] = *$value;
#[link_section = ".modinfo"]
#[used]
pub static LICENSE_NUL: [u8; 1] = *b"\0";
};
}

/// KernelModule is the top level entrypoint to implementing a kernel module. Your kernel module
/// should implement the `init` method on it, which maps to the `module_init` macro in Linux C API.
/// You can use this method to do whatever setup or registration your module should do. For any
Expand Down
3 changes: 2 additions & 1 deletion rust/kernel/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ pub use alloc::{
borrow::ToOwned,
};

pub use module::module;

pub use super::{
kernel_module,
println,
KernelResult,
KernelModule,
Expand Down
12 changes: 12 additions & 0 deletions rust/module/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: GPL-2.0

[package]
name = "module"
version = "0.1.0"
authors = ["Rust for Linux Contributors"]
edition = "2018"
publish = false

[lib]
proc-macro = true

Loading