近年来,Rust 语言以内存安全、高可靠性、零抽象等能力获得大量开发者关注,而这些特性恰好是内核编程中所需要的,所以我们看下如何用rust来写Linux内核模块。
Rust 与内核模块
Aliware
虽然 Rust 支持已经在 LinuxKernel6.1 版本合并到主线了,所以理论上来说,开发者可以使用 Rust 来为 Linux6.1 写内核模块。
但实际开发工作中,内核版本不是最新的,比如 Debian 11 的内核就是 5.10 版本的,那么在这种情况下,该如何用 Rust 写内核模块呢?
原理
Aliware
Rust 和 C 的互操作性
Rust 和 target 配置
内核模块的二进制约定
一个小例子
Aliware
#![no_std]
// no_std用于表示没有std库,即freestanding环境
extern crate alloc;
use alloc::borrow::ToOwned;
use alloc::string::String;
// 我们以printk为底层,提供了println
use linux_kernel_module::println;
// 这个struct代表内核模块
struct HelloWorldModule {
message: String,
}
// 实现内核模块初始化方法
impl linux_kernel_module::KernelModule for HelloWorldModule {
fn init() -> linux_kernel_module::KernelResult<Self> {
println!("Hello kernel module from rust!");
Ok(HelloWorldModule {
message: "on the heap!".to_owned(),
})
}
}
// 提供内核模块卸载方法
impl Drop for HelloWorldModule {
fn drop(&mut self) {
println!("My message is {}", self.message);
println!("Goodbye kernel module from rust!");
}
}
// 通过kernel_module宏,export了内核模块的相关信息
linux_kernel_module::kernel_module!(
HelloWorldModule,
author: b"Fish in a Barrel Contributors",
description: b"An extremely simple kernel module",
license: b"GPL"
);
$ cd linux-kernel-module-rust/hello-world
$ RUST_TARGET_PATH=$(pwd)/.. cargo +nightly xbuild --target x86_64-linux-kernel-module
$ make
$ insmod helloworld.ko
$ rmmod helloworld
$ dmesg | tail -n 3
[521088.916091] Hello kernel module from rust!
[521174.204889] My message is on the heap!
[521174.204891] Goodbye kernel module from rust!
一些小细节
Aliware
VSCode 支持
由于 rust-analyzer 对于自定义 target,多模块的支持不够,所以我们暂时需要手动配置下 settings.json 才能正常开发:
{
"rust-analyzer.cargo.extraEnv": {
"RUST_TARGET_PATH": "/root/linux-kernel-module-rust"
},
"rust-analyzer.cargo.target": "x86_64-linux-kernel-module",
"rust-analyzer.server.extraEnv": {
"RA_LOG": "lsp_server=debug",
"RUST_TARGET_PATH": "/root/linux-kernel-module-rust"
},
"rust-analyzer.trace.server": "verbose",
"rust-analyzer.linkedProjects": [
"hello-world/Cargo.toml",
"Cargo.toml"
],
}
更多规划
Aliware