Skip to content

Commit 4a191ac

Browse files
committed
Add ModuleParam trait and new int params
1 parent 711070f commit 4a191ac

File tree

5 files changed

+122
-12
lines changed

5 files changed

+122
-12
lines changed

rust/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ $(objtree)/rust/bindings_generated.rs: $(srctree)/rust/kernel/bindings_helper.h
4646
quiet_cmd_exports = EXPORTS $@
4747
cmd_exports = \
4848
$(NM) -p --defined-only $< \
49-
| grep -F ' T ' | cut -d ' ' -f 3 | grep -E '^(__rust_|_R)' \
49+
| grep -E '( T | R )' | cut -d ' ' -f 3 | grep -E '^(__rust_|_R)' \
5050
| xargs -n1 -Isymbol \
5151
echo 'EXPORT_SYMBOL$(exports_target_type)(symbol);' > $@
5252

rust/kernel/buffer.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use core::fmt;
2+
3+
pub struct Buffer<'a> {
4+
slice: &'a mut [u8],
5+
pos: usize,
6+
}
7+
8+
impl<'a> Buffer<'a> {
9+
pub fn new(slice: &'a mut [u8]) -> Self {
10+
Buffer {
11+
slice,
12+
pos: 0,
13+
}
14+
}
15+
16+
pub fn bytes_written(&self) -> usize {
17+
self.pos
18+
}
19+
}
20+
21+
impl<'a> fmt::Write for Buffer<'a> {
22+
fn write_str(&mut self, s: &str) -> fmt::Result {
23+
if s.len() > self.slice.len() - self.pos {
24+
Err(fmt::Error)
25+
} else {
26+
self.slice[self.pos..self.pos + s.len()].copy_from_slice(s.as_bytes());
27+
self.pos += s.len();
28+
Ok(())
29+
}
30+
}
31+
}

rust/kernel/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ use core::panic::PanicInfo;
1414

1515
mod allocator;
1616
pub mod bindings;
17+
mod buffer;
1718
pub mod c_types;
1819
pub mod chrdev;
1920
mod error;
2021
pub mod file_operations;
2122
pub mod miscdev;
23+
pub mod module_param;
2224
pub mod prelude;
2325
pub mod printk;
2426
pub mod random;
@@ -32,6 +34,8 @@ pub mod user_ptr;
3234
pub use crate::error::{Error, KernelResult};
3335
pub use crate::types::{CStr, Mode};
3436

37+
pub const PAGE_SIZE: usize = 1 << bindings::PAGE_SHIFT;
38+
3539
/// KernelModule is the top level entrypoint to implementing a kernel module. Your kernel module
3640
/// should implement the `init` method on it, which maps to the `module_init` macro in Linux C API.
3741
/// You can use this method to do whatever setup or registration your module should do. For any

rust/kernel/module_param.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use core::fmt::Write;
2+
3+
/// Types that can be used for module parameters.
4+
/// Note that displaying the type in `sysfs` will fail if `to_string` returns
5+
/// more than 4K bytes (including an additional null terminator).
6+
pub trait ModuleParam : core::fmt::Display + core::marker::Sized {
7+
fn try_from_param_arg(arg: &[u8]) -> Option<Self>;
8+
9+
/// # Safety
10+
///
11+
/// `val` must point to a valid null-terminated string. The `arg` field of
12+
/// `param` must be an instance of `Self`.
13+
unsafe extern "C" fn set_param(val: *const crate::c_types::c_char, param: *const crate::bindings::kernel_param) -> crate::c_types::c_int {
14+
let arg = crate::c_types::c_string_bytes(val);
15+
match Self::try_from_param_arg(arg) {
16+
Some(new_value) => {
17+
let old_value = (*param).__bindgen_anon_1.arg as *mut Self;
18+
let _ = core::ptr::replace(old_value, new_value);
19+
0
20+
}
21+
None => crate::error::Error::EINVAL.to_kernel_errno()
22+
}
23+
}
24+
25+
/// # Safety
26+
///
27+
/// `buf` must be a buffer of length at least `kernel::PAGE_SIZE` that is
28+
/// writeable. The `arg` field of `param` must be an instance of `Self`.
29+
unsafe extern "C" fn get_param(buf: *mut crate::c_types::c_char, param: *const crate::bindings::kernel_param) -> crate::c_types::c_int {
30+
let slice = core::slice::from_raw_parts_mut(buf as *mut u8, crate::PAGE_SIZE);
31+
let mut buf = crate::buffer::Buffer::new(slice);
32+
match write!(buf, "{}\0", *((*param).__bindgen_anon_1.arg as *mut Self)) {
33+
Err(_) => crate::error::Error::EINVAL.to_kernel_errno(),
34+
Ok(()) => buf.bytes_written() as crate::c_types::c_int,
35+
}
36+
}
37+
38+
/// # Safety
39+
///
40+
/// The `arg` field of `param` must be an instance of `Self`.
41+
unsafe extern "C" fn free(arg: *mut crate::c_types::c_void) {
42+
core::ptr::drop_in_place(arg as *mut Self);
43+
}
44+
}
45+
46+
macro_rules! make_param_ops {
47+
($ops:ident, $ty:ident) => {
48+
impl ModuleParam for $ty {
49+
fn try_from_param_arg(arg: &[u8]) -> Option<Self> {
50+
let utf8 = core::str::from_utf8(arg).ok()?;
51+
utf8.parse::<$ty>().ok()
52+
}
53+
}
54+
55+
pub static $ops: crate::bindings::kernel_param_ops = crate::bindings::kernel_param_ops {
56+
flags: 0,
57+
set: Some(<$ty as crate::module_param::ModuleParam>::set_param),
58+
get: Some(<$ty as crate::module_param::ModuleParam>::get_param),
59+
free: Some(<$ty as crate::module_param::ModuleParam>::free),
60+
};
61+
}
62+
}
63+
64+
make_param_ops!(PARAM_OPS_I8, i8);
65+
make_param_ops!(PARAM_OPS_I64, i64);
66+
make_param_ops!(PARAM_OPS_USIZE, usize);
67+
make_param_ops!(PARAM_OPS_ISIZE, isize);

rust/module.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -221,12 +221,16 @@ fn permissions_are_readonly(perms: &str) -> bool {
221221
/// # Supported Parameter Types
222222
///
223223
/// - `bool` - Corresponds to C `bool` param type.
224+
/// - `i8` - No equivalent C param type.
224225
/// - `u8` - Corresponds to C `char` param type.
225226
/// - `i16` - Corresponds to C `short` param type.
226227
/// - `u16` - Corresponds to C `ushort` param type.
227228
/// - `i32` - Corresponds to C `int` param type.
228229
/// - `u32` - Corresponds to C `uint` param type.
230+
/// - `i64` - No equivalent C param type.
229231
/// - `u64` - Corresponds to C `ullong` param type.
232+
/// - `isize` - No equivalent C param type.
233+
/// - `usize` - No equivalent C param type.
230234
/// - `str` - Corresponds to C `charp` param type.
231235
/// Reading the param returns a `&[u8]`.
232236
///
@@ -277,15 +281,19 @@ pub fn module(ts: TokenStream) -> TokenStream {
277281

278282
// TODO: more primitive types
279283
// TODO: other kinds: arrays, unsafes, etc.
280-
let param_kernel_type = match param_type.as_ref() {
281-
"bool" => "bool",
282-
"u8" => "char",
283-
"i16" => "short",
284-
"u16" => "ushort",
285-
"i32" => "int",
286-
"u32" => "uint",
287-
"u64" => "ullong",
288-
"str" => "charp",
284+
let (param_kernel_type, ops) = match param_type.as_ref() {
285+
"bool" => ("bool", "kernel::bindings::param_ops_bool"),
286+
"i8" => ("i8", "kernel::module_param::PARAM_OPS_I8"),
287+
"u8" => ("u8", "kernel::bindings::param_ops_char"),
288+
"i16" => ("i16", "kernel::bindings::param_ops_short"),
289+
"u16" => ("u16", "kernel::bindings::param_ops_ushort"),
290+
"i32" => ("i32", "kernel::bindings::param_ops_int"),
291+
"u32" => ("u32", "kernel::bindings::param_ops_uint"),
292+
"i64" => ("i64", "kernel::module_param::PARAM_OPS_I64"),
293+
"u64" => ("u64", "kernel::bindings::param_ops_ullong"),
294+
"isize" => ("isize", "kernel::module_param::PARAM_OPS_ISIZE"),
295+
"usize" => ("usize", "kernel::module_param::PARAM_OPS_USIZE"),
296+
"str" => ("charp", "kernel::bindings::param_ops_charp"),
289297
t => panic!("Unrecognized type {}", t),
290298
};
291299

@@ -409,7 +417,7 @@ pub fn module(ts: TokenStream) -> TokenStream {
409417
mod_: unsafe {{ &kernel::bindings::__this_module as *const _ as *mut _ }},
410418
#[cfg(not(MODULE))]
411419
mod_: core::ptr::null_mut(),
412-
ops: unsafe {{ &kernel::bindings::param_ops_{param_kernel_type} }} as *const kernel::bindings::kernel_param_ops,
420+
ops: unsafe {{ &{ops} }} as *const kernel::bindings::kernel_param_ops,
413421
perm: {permissions},
414422
level: -1,
415423
flags: 0,
@@ -419,9 +427,9 @@ pub fn module(ts: TokenStream) -> TokenStream {
419427
name = name,
420428
param_type_internal = param_type_internal,
421429
read_func = read_func,
422-
param_kernel_type = param_kernel_type,
423430
param_default = param_default,
424431
param_name = param_name,
432+
ops = ops,
425433
permissions = param_permissions,
426434
kparam = kparam,
427435
)

0 commit comments

Comments
 (0)