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モジュールを動作させることができました。