a minimal Linux kernel module written in rust.
This code uses feature flags, so you'll need to use a nightly version of Rust to compile it.
Create a file config.mk
in the root directory of the repository.
Set RUST_ROOT
in this file to the directory containing bin/rustc
, e.g. RUST_ROOT := /usr
Compile rust.ko
:
$ make
Try it out:
# insmod hello.ko
# rmmod hello
$ dmesg | tail -3
[54024.186997] hello: init
[54024.187000] hello from rust
[54024.191963] hello: exit
make
command-line optionsCurrently there are a few parameters you can pass to make
to affect the build:
V=1
: Enable verbose output
make
and cargo
will be printed to the screenRELEASE=1
: Create a release build
rustc
will compile all code in --release
modeWhen running make
for the first time cargo
will generate a Cargo.lock
file in the project's
root directory. This file contains information about the exact versions of the dependencies of
your project. Since this is an example project it will not ship any Cargo.lock
file, but it's
recommended that you commit it to your source tree if you're actually trying to build a project
based on this code.
(Please don't make any pull requests to this code containing a Cargo.lock
file through.)
Since Linux code can be compiled for a lot of different architectures, we have to be able to generate CPU code that is in line with what the kernel expects. This means specifically:
Currently this source code only ships with a target specification file for the x64_64 architecture. If you get an error similar to the following, you'll have the honor of creating and submitting one for favourite architecture: :wink:
cd "…/rust.ko" && /usr/local/bin/cargo rustc --target="armhf-unknown-none-gnu" -- --emit obj -o "…/rust.ko/build/hello-rust.o"
failed to run `rustc` to learn about target-specific information
Some ideas on how to do this may be found here under the Creating a target file section.
Due to the fact that Linux does not provide any ABI stability (not even for two identical copies of
its source code), we must build kernel modules against its API instead. While this is trivially
done in C, by building the code against the headers of that kernel version, it's not that easy to
do in Rust. Most importantly because Rust cannot read C headers of course, but also because any
extern "C"
function bindings and, more importantly, any #[repr(C)]
structure definitions you
define, will link against the kernel's ABI not the API!
Here is an incomplete list of things that affect the kernel's ABI stability:
gcc
or clang
to compile the kernel's source codeCheck out the kernel documentation for more information on kernel API (in)stability.
Currently rust-bindgen
is invoked at the module's build
time to generate Rust counterparts for all C data structures, enumerations, functions and types
defined by the kernel headers. This addresses most of the issues mentioned above, but is not a
silver bullet: No bindings are generated for C macro definitions and in-line functions. Most
importantly this matters, because, for a C developer it is often irrelevant whether they declare a
bunch of macros for different states of something, or use an enum
definition instead; after all,
the result is the same, right? While this is certainly true from a C programmers perspective, it is
not the same from the compiler's point of view: C macros are expanded during the preprocessor stage,
while enums are expanded during the main compiling/assembling stage. For rust-bindgen
(that
operates on the main compiling stage) this means that all macros have disappeared by the time it
gets to look at the source code's AST. There
is no way to use C macro definitions because of this at the current time.
The first build will be ratter slow as the kernel header bindings are generated by
rust-bindgen
. Also, when you target another kernel or
change the list of headers used (with the KERNEL_INCLUDE
option), you will also experience a delay
while the bindings are regenerated.
Please see the Kernel API and ABI stability section for details on why this is necessary for any serious use of the kernel interfaces.