Skip to content

Commit 247b365

Browse files
wedsonafojeda
authored andcommitted
rust: add kernel crate
The `kernel` crate currently includes all the abstractions that wrap kernel features written in C. These abstractions call the C side of the kernel via the generated bindings with the `bindgen` tool. Modules developed in Rust should never call the bindings themselves. In the future, as the abstractions grow in number, we may need to split this crate into several, possibly following a similar subdivision in subsystems as the kernel itself and/or moving the code to the actual subsystems. Reviewed-by: Greg Kroah-Hartman <[email protected]> Co-developed-by: Alex Gaynor <[email protected]> Signed-off-by: Alex Gaynor <[email protected]> Co-developed-by: Geoffrey Thomas <[email protected]> Signed-off-by: Geoffrey Thomas <[email protected]> Co-developed-by: Finn Behrens <[email protected]> Signed-off-by: Finn Behrens <[email protected]> Co-developed-by: Adam Bratschi-Kaye <[email protected]> Signed-off-by: Adam Bratschi-Kaye <[email protected]> Co-developed-by: Sven Van Asbroeck <[email protected]> Signed-off-by: Sven Van Asbroeck <[email protected]> Co-developed-by: Gary Guo <[email protected]> Signed-off-by: Gary Guo <[email protected]> Co-developed-by: Boris-Chengbiao Zhou <[email protected]> Signed-off-by: Boris-Chengbiao Zhou <[email protected]> Co-developed-by: Boqun Feng <[email protected]> Signed-off-by: Boqun Feng <[email protected]> Co-developed-by: Fox Chen <[email protected]> Signed-off-by: Fox Chen <[email protected]> Co-developed-by: Viktor Garske <[email protected]> Signed-off-by: Viktor Garske <[email protected]> Co-developed-by: Dariusz Sosnowski <[email protected]> Signed-off-by: Dariusz Sosnowski <[email protected]> Co-developed-by: Léo Lanteri Thauvin <[email protected]> Signed-off-by: Léo Lanteri Thauvin <[email protected]> Co-developed-by: Niklas Mohrin <[email protected]> Signed-off-by: Niklas Mohrin <[email protected]> Co-developed-by: Milan Landaverde <[email protected]> Signed-off-by: Milan Landaverde <[email protected]> Co-developed-by: Morgan Bartlett <[email protected]> Signed-off-by: Morgan Bartlett <[email protected]> Co-developed-by: Maciej Falkowski <[email protected]> Signed-off-by: Maciej Falkowski <[email protected]> Co-developed-by: Nándor István Krácser <[email protected]> Signed-off-by: Nándor István Krácser <[email protected]> Co-developed-by: David Gow <[email protected]> Signed-off-by: David Gow <[email protected]> Co-developed-by: John Baublitz <[email protected]> Signed-off-by: John Baublitz <[email protected]> Co-developed-by: Björn Roy Baron <[email protected]> Signed-off-by: Björn Roy Baron <[email protected]> Signed-off-by: Wedson Almeida Filho <[email protected]> Co-developed-by: Miguel Ojeda <[email protected]> Signed-off-by: Miguel Ojeda <[email protected]>
1 parent 8326ac0 commit 247b365

File tree

6 files changed

+491
-0
lines changed

6 files changed

+491
-0
lines changed

rust/kernel/allocator.rs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Allocator support.
4+
5+
use core::alloc::{GlobalAlloc, Layout};
6+
use core::ptr;
7+
8+
use crate::bindings;
9+
10+
struct KernelAllocator;
11+
12+
unsafe impl GlobalAlloc for KernelAllocator {
13+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
14+
// `krealloc()` is used instead of `kmalloc()` because the latter is
15+
// an inline function and cannot be bound to as a result.
16+
unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 }
17+
}
18+
19+
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
20+
unsafe {
21+
bindings::kfree(ptr as *const core::ffi::c_void);
22+
}
23+
}
24+
}
25+
26+
#[global_allocator]
27+
static ALLOCATOR: KernelAllocator = KernelAllocator;
28+
29+
// `rustc` only generates these for some crate types. Even then, we would need
30+
// to extract the object file that has them from the archive. For the moment,
31+
// let's generate them ourselves instead.
32+
//
33+
// Note that `#[no_mangle]` implies exported too, nowadays.
34+
#[no_mangle]
35+
fn __rust_alloc(size: usize, _align: usize) -> *mut u8 {
36+
unsafe { bindings::krealloc(core::ptr::null(), size, bindings::GFP_KERNEL) as *mut u8 }
37+
}
38+
39+
#[no_mangle]
40+
fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) {
41+
unsafe { bindings::kfree(ptr as *const core::ffi::c_void) };
42+
}
43+
44+
#[no_mangle]
45+
fn __rust_realloc(ptr: *mut u8, _old_size: usize, _align: usize, new_size: usize) -> *mut u8 {
46+
unsafe {
47+
bindings::krealloc(
48+
ptr as *const core::ffi::c_void,
49+
new_size,
50+
bindings::GFP_KERNEL,
51+
) as *mut u8
52+
}
53+
}
54+
55+
#[no_mangle]
56+
fn __rust_alloc_zeroed(size: usize, _align: usize) -> *mut u8 {
57+
unsafe {
58+
bindings::krealloc(
59+
core::ptr::null(),
60+
size,
61+
bindings::GFP_KERNEL | bindings::__GFP_ZERO,
62+
) as *mut u8
63+
}
64+
}

rust/kernel/error.rs

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Kernel errors.
4+
//!
5+
//! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
6+
7+
use alloc::collections::TryReserveError;
8+
9+
/// Contains the C-compatible error codes.
10+
pub mod code {
11+
/// Out of memory.
12+
pub const ENOMEM: super::Error = super::Error(-(crate::bindings::ENOMEM as i32));
13+
}
14+
15+
/// Generic integer kernel error.
16+
///
17+
/// The kernel defines a set of integer generic error codes based on C and
18+
/// POSIX ones. These codes may have a more specific meaning in some contexts.
19+
///
20+
/// # Invariants
21+
///
22+
/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
23+
#[derive(Clone, Copy, PartialEq, Eq)]
24+
pub struct Error(core::ffi::c_int);
25+
26+
impl Error {
27+
/// Returns the kernel error code.
28+
pub fn to_kernel_errno(self) -> core::ffi::c_int {
29+
self.0
30+
}
31+
}
32+
33+
impl From<TryReserveError> for Error {
34+
fn from(_: TryReserveError) -> Error {
35+
code::ENOMEM
36+
}
37+
}
38+
39+
/// A [`Result`] with an [`Error`] error type.
40+
///
41+
/// To be used as the return type for functions that may fail.
42+
///
43+
/// # Error codes in C and Rust
44+
///
45+
/// In C, it is common that functions indicate success or failure through
46+
/// their return value; modifying or returning extra data through non-`const`
47+
/// pointer parameters. In particular, in the kernel, functions that may fail
48+
/// typically return an `int` that represents a generic error code. We model
49+
/// those as [`Error`].
50+
///
51+
/// In Rust, it is idiomatic to model functions that may fail as returning
52+
/// a [`Result`]. Since in the kernel many functions return an error code,
53+
/// [`Result`] is a type alias for a [`core::result::Result`] that uses
54+
/// [`Error`] as its error type.
55+
///
56+
/// Note that even if a function does not return anything when it succeeds,
57+
/// it should still be modeled as returning a `Result` rather than
58+
/// just an [`Error`].
59+
pub type Result<T = ()> = core::result::Result<T, Error>;

rust/kernel/lib.rs

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! The `kernel` crate.
4+
//!
5+
//! This crate contains the kernel APIs that have been ported or wrapped for
6+
//! usage by Rust code in the kernel and is shared by all of them.
7+
//!
8+
//! In other words, all the rest of the Rust code in the kernel (e.g. kernel
9+
//! modules written in Rust) depends on [`core`], [`alloc`] and this crate.
10+
//!
11+
//! If you need a kernel C API that is not ported or wrapped yet here, then
12+
//! do so first instead of bypassing this crate.
13+
14+
#![no_std]
15+
#![feature(core_ffi_c)]
16+
17+
// Ensure conditional compilation based on the kernel configuration works;
18+
// otherwise we may silently break things like initcall handling.
19+
#[cfg(not(CONFIG_RUST))]
20+
compile_error!("Missing kernel configuration for conditional compilation");
21+
22+
#[cfg(not(test))]
23+
#[cfg(not(testlib))]
24+
mod allocator;
25+
pub mod error;
26+
pub mod prelude;
27+
pub mod print;
28+
pub mod str;
29+
30+
#[doc(hidden)]
31+
pub use bindings;
32+
pub use macros;
33+
34+
/// Prefix to appear before log messages printed from within the `kernel` crate.
35+
const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
36+
37+
/// The top level entrypoint to implementing a kernel module.
38+
///
39+
/// For any teardown or cleanup operations, your type may implement [`Drop`].
40+
pub trait Module: Sized + Sync {
41+
/// Called at module initialization time.
42+
///
43+
/// Use this method to perform whatever setup or registration your module
44+
/// should do.
45+
///
46+
/// Equivalent to the `module_init` macro in the C API.
47+
fn init(module: &'static ThisModule) -> error::Result<Self>;
48+
}
49+
50+
/// Equivalent to `THIS_MODULE` in the C API.
51+
///
52+
/// C header: `include/linux/export.h`
53+
pub struct ThisModule(*mut bindings::module);
54+
55+
// SAFETY: `THIS_MODULE` may be used from all threads within a module.
56+
unsafe impl Sync for ThisModule {}
57+
58+
impl ThisModule {
59+
/// Creates a [`ThisModule`] given the `THIS_MODULE` pointer.
60+
///
61+
/// # Safety
62+
///
63+
/// The pointer must be equal to the right `THIS_MODULE`.
64+
pub const unsafe fn from_ptr(ptr: *mut bindings::module) -> ThisModule {
65+
ThisModule(ptr)
66+
}
67+
}
68+
69+
#[cfg(not(any(testlib, test)))]
70+
#[panic_handler]
71+
fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
72+
pr_emerg!("{}\n", info);
73+
// SAFETY: FFI call.
74+
unsafe { bindings::BUG() };
75+
// Bindgen currently does not recognize `__noreturn` so `BUG` returns `()`
76+
// instead of `!`. See <https://github.com/rust-lang/rust-bindgen/issues/2094>.
77+
loop {}
78+
}

rust/kernel/prelude.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! The `kernel` prelude.
4+
//!
5+
//! These are the most common items used by Rust code in the kernel,
6+
//! intended to be imported by all Rust code, for convenience.
7+
//!
8+
//! # Examples
9+
//!
10+
//! ```
11+
//! use kernel::prelude::*;
12+
//! ```
13+
14+
pub use super::{
15+
error::{Error, Result},
16+
pr_emerg, pr_info, ThisModule,
17+
};
18+
pub use alloc::{boxed::Box, vec::Vec};
19+
pub use core::pin::Pin;
20+
pub use macros::module;

0 commit comments

Comments
 (0)