Linux Kernel Rust Modules
You can use any editor you want, but remember that vi vi vi is the text editor of the beast.
– Richard Stallman
This post is the second part of the series about Rust in the Linux Kernel. If you haven’t read the part I, please do it before continuing.
My objective here is to show how to build a Linux Kernel module in Rust and general recommendations about the process.
In-Tree Rust Modules
Currently, the Linux Kernel has a few in-tree Rust modules samples in the
samples/rust
directory. So, you can add a new module directly there.
First, we need to modify the kernel samples/rust/Kconfig
file to add a new
menu entry for our module. In this example, we will add a new module called
hello_rust
.
config SAMPLE_HELLO_RUST
tristate "Rust Hello World module"
help
This option builds the Rust Hello World module.
To compile this as a module, choose M here:
the module will be called rust_vdev.
If unsure, say N.
Also, we need to add a new entry in the samples/rust/Makefile
file:
obj-$(CONFIG_SAMPLE_HELLO_RUST) += hello_rust.o
Now, add the module code in the samples/rust/hello_rust.rs
file:
// SPDX-License-Identifier: GPL-2.0
//! Rust LKM Template
mod module {
use kernel::prelude::*;
pub(crate) fn test() {
pr_info!("Rust LKM Template (test)\n");
}
}
use module::test;
use kernel::prelude::*;
module! {
type: RustLkmTemplate,
name: "rust_lkm_template",
author: "Pablo Alessando Santos Hugen",
description: "Rust KLM Template",
license: "GPL",
}
struct RustLkmTemplate(&'static str);
impl kernel::Module for RustLkmTemplate {
fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
let message: &'static str = "Hello World!";
test();
pr_info!("Rust LKM Template (init)\n");
pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
Ok(RustLkmTemplate(message))
}
}
impl Drop for RustLkmTemplate {
fn drop(&mut self) {
pr_info!("My message is: {}\n", self.0);
pr_info!("Rust LKM Template (exit)\n");
}
}
Finally, we can enable the module using the make LLVM=1 CLIPPY=1 menuconfig
command, and set the CONFIG_SAMPLE_HELLO_RUST
option:
After, build the kernel with the make LLVM=1 CLIPPY=1 -j$(nproc)
command, and
fire up the VM as shown in [part I]({% post_url
2023-04-02-linux-kernel-rust-dev-environment %}).
In the VM, we can see the module in the dmesg
output:
Whilst this approach is simple and ok if you are a core kernel maintainer, it has some drawbacks otherwise:
- The module is built in-tree, so it will be built every time we build the kernel.
- You have to open a huge codebase like the Linux Kernel to add a new module. It can slow down some editors and make the development process harder.
Out-of-Tree Rust Modules
A better approach is to build the module out-of-tree. This way, we can build the module separately from the kernel, having a faster and smooth development process.
For building modules in this way, we use the Kbuild system. The Kbuild system is a set of tools that are used to build the Linux Kernel, and we could use it to build external modules too.
The Kbuild config for a external module is very straightforward, we just need to
point the objects in the Kbuild
file and use a simple Makefile
to build the
module. You can refer to the
Kbuild external modules docs
for more info.
For example, in my simple external module template, one can find a complete example of a Kbuild config for a external module ith additional features like hot-reload in a Virtual Machine:
Ok, but what about the Rust part?
Rust for Linux folks have done an amazing job to make the Rust integration with the Kbuild system seamless.
In the same way that we configure an Kbuild
file for a C module, we can do the
same for a Rust module. The only difference is that objects are compiled from
Rust sources!!! How cool is that?
We can find an example of a external module in the Rust for Linux GitHub Organization. This is a simple template for a external module in Rust.
Also, I’ve created a
Rust LKM template based on the
Rust for Linux
one, with some additional features like hot-reload in a Virtual
Machine. In the next session we’re gonna explore it a little bit an see some
examples of what we can do with It.
Building and running a Rust LKM
The Rust LKM template is a simple template for a smooth development process of a external module in Rust.
Remember from [part I]({% post_url 2023-04-02-linux-kernel-rust-dev-environment %}) that we have a VM running with the kernel built from the Rust for Linux fork. We can use this VM to develop and test Rust modules smoothly.
The template has a Makefile
and a Kbuild
file, which are used to build the
module and some helper scripts in the assets/
folder:
The goal of this template is to incrementally add features to it and copy the
generated .ko
in the VM for testing And not panicking your own kernel.
./scrips/setup
This script basically setups the environment for the VM (refer to [part I]({% post_url 2023-04-02-linux-kernel-rust-dev-environment %}) for more info)../scripts/build
,./scripts/build -t clean
,./scripts/build -t rust-analyzer
This script “forwards” targets to the Makefile (build, clean, etc):./scripts/run
This script copies the generated.ko
file to the busybox dir, generate an updatedinitramfs
and boot the VM:./scripts/hot-reload
This script builds the module and run every time a change is detected in the source code:
The hot-reload feature is very useful for kernel development, for it allows us to test our changes in the VM without the need to rebuild the kernel every time.
Further Tests
Now that you have a basic understanding of how to build and run a Rust LKM, let’s see some basic examples of what we can do with it:
- Parrot Module: A silly
example of how one can use the
procfs
subsystem to create a simple file in/proc
that returns a string when read. - Scull Module: Another
example of how to use the
procfs
subsystem to create a simple file in/proc
that returns a persistent string when read.
Also, I strongly recommend you to check out the Rust for Linux documentation, which has a lot of useful information about the Rust integration with the Linux Kernel, for it could help you to learn more about rust abstractions and how to use them in the kernel.