[Ubuntu] RustでLinux kernel モジュールを開発する
Introduction
Linux kernelの6.2からRustでカーネル開発をするための基本的なサポートが導入されましたが、
メジャーなディストリビューションは6.2をデフォルトで搭載していませんでした。
なのでRustカーネルを試そうとした場合、
カーネルのソース持ってきてカーネルビルド関連のソフトウェアやライブラリをインストールし、
Rust関連のオプションつけてビルドしなおして
Rustで書いたカーネルモジュールをビルドして
QEMUとかUTMとかでようやく動作確認ができます。
とりあえずHelloWorldするだけでも、かなり面倒です。
しかし先日、Ubuntu 23.04 Lunar Lobsterがリリースされました。
これは標準でLinux Kernel 6.2を搭載しているので、面倒な手順を踏まなくても
Rust製のLinux kernelが動きます。
また、素晴らしいことにLunar LobsterのEC2のイメージ(Community AMI)の
存在を同僚に教えてもらいました。
(ubuntu/images/hvm-ssd/ubuntu-lunar-23.04-amd64-server-20230425,ami-039bc9bfd44dc9659)
今回はLunar LobsterのAMI Imageをつかって
ここを参考に、
RustでLinux kernelをビルドして動かしてみます。
Try
EC2でUbuntu 23の起動
まずはLunar LobsterをEC2で起動します。
東京リージョンでLunar LobsterのAMIを指定して起動します。
ログインして環境設定
sshログインします。
いつものクセでec2@〜とやらないように。
% ssh -i <pemのパス> ubuntu@<Public IP>
サーバにログインしたらapt updateして必要モジュールのインストールをします。
% sudo apt update % sudo apt install rustc-1.62 rust-1.62-src rustfmt-1.62 \ bindgen-0.56 llvm clang gcc make linux-headers-`uname -r`
必要なのはこれだけ。
もしmake時にエラーがでたら
bisonとかflexとかいれる必要があるかも。
次にRustのカーネルモジュールを作成します。
% mkdir rust_kernel && cd rust_kernel % vi hello_rust.rs
シンプルなHello World。
// SPDX-License-Identifier: GPL-2.0 //! Rust Kernel Module hello world example. use kernel::prelude::*; module! { type: HelloRust, name: "hello_rust", author: "Your Name <your email address>", description: "Rust Kernel Module hello world example", license: "GPL", } struct HelloRust { } impl kernel::Module for HelloRust { fn init(_module: &'static ThisModule) -> Result<Self> { pr_info!("Hello World Kernel Module from Rust\n"); Ok(HelloRust { }) } } impl Drop for HelloRust { fn drop(&mut self) { pr_info!("Goodbye Kernel Module from Rust\n"); } }
Makefileも作成します。
vi Makefile
NAME=hello_rust ifndef KERNELRELEASE ifndef KDIR KDIR:=/lib/modules/`uname -r`/build endif PWD := $(shell pwd) rust_flags=CROSS_COMPILE=x86_64-linux-gnu- HOSTRUSTC=rustc-1.62 RUSTC=rustc-1.62 BINDGEN=bindgen-0.56 RUSTFMT=rustfmt-1.62 RUST_LIB_SRC=/usr/src/rustc-1.62.1/library all: @$(MAKE) $(rust_flags) -C $(KDIR) M=$(PWD) modules install: @$(MAKE) $(rust_flags) -C $(KDIR) M=$(PWD) modules_install clean: @rm -f *.o *.ko *.mod* .*.cmd *.d Module.symvers modules.order @rm -rf .tmp_versions else obj-m := $(NAME).o endif
※ご指摘により修正。ありがとうございます。
準備はこれだけです。簡単ですね。
makeしましょう。
% make make[1]: Entering directory '/usr/src/linux-headers-6.2.0-1003-aws' RUSTC [M] /home/ubuntu/kernel/hello_rust.o MODPOST /home/ubuntu/kernel/Module.symvers CC [M] /home/ubuntu/kernel/hello_rust.mod.o LD [M] /home/ubuntu/kernel/hello_rust.ko BTF [M] /home/ubuntu/kernel/hello_rust.ko Skipping BTF generation for /home/ubuntu/kernel/hello_rust.ko due to unavailability of vmlinux make[1]: Leaving directory '/usr/src/linux-headers-6.2.0-1003-aws'
ファイルが生成されてます。
% ls Makefile hello_rust.ko hello_rust.mod.c hello_rust.o modules.order Module.symvers hello_rust.mod hello_rust.mod.o hello_rust.rs
モジュールをロードした後、lsmodで確認してみましょう。
問題ないようです。
% sudo insmod hello_rust.ko sudo lsmod | grep hello hello_rust 16384 0
dmesgで確認します。ちゃんと実行ログも出てますね。
% sudo dmesg | tail -1 [63004.531176] hello_rust: Hello World Kernel Module from Rust
おわったらrmmodでモジュールを削除しておきます。
% sudo rmmod hello_rust
使い終わったらEC2インスタンスも停止しておきましょう。
Summary
今回はUbuntu 23でRustを使ってカーネルモジュールのビルドと実行を確認してみました。
以前に試したことがある人は、
とても簡単にカーネルの実行まで確認できたことがわかると思います。
このように簡単に試せる環境があると、
Rustでのカーネル開発も少し手が出しやすくなるのではないでしょうか。
ちなみに、最初はM1 MacでUTMつかってubuntu23を起動してやろうとしてましたが、
モジュールビルド後にinsmodするとinvalid formatで動きませんでした。
こっちもなんとか動かしたいところなので、引き続きトライします。
[2023/06/05 追記]
UTM 4.1.5を使用することで、M1 Mac上でも
本稿の手順でRust Kernelモジュールを動作させることができました。