RustでHello, World!
環境構築
実験用のOSはUbuntu 20.10、x86_64を想定します。
まず、Rustの環境を整えます。Rustの環境はrustupで構築できるので簡単です。Rustには大きく分けてstableとnightlyがあるのですが、今回はnightlyを利用します。具体的には以下のようにコマンドを入力するとインストールできます。
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ sh -s -- --default-toolchain nightly-2021-03-06 \ --component clippy rust-src llvm-tools-preview rustfmt rls rust-analysis rustdoc -y
インストール後はenvファイルを読み込んで環境変数を設定します。
$ source $HOME/.cargo/env
次に、必要なソフトウェアをaptからインストールします。
$ sudo apt update $ sudo apt upgrade $ sudo apt install build-essential zsh git curl libncurses5-dev libtinfo5 clang lld fakeroot xz-utils libssl-dev bc flex libelf-dev bison llvm cpio qemu-system
Linuxカーネルコンパイル
次に、Linuxカーネルソースコードを取得します。今回は、linux-nextという次世代Linux向けの実験的なソースコードを使います。
$ git clone --depth 1 git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
$ cd linux-next $ make menuconfig
設定項目は、以下の通りです。General setup ---> Rust support ---> yesと、Device Drivers ---> Character devices ---> Rust Example ---> yesは必ずオンにしておきましょう。他の項目は、以下にチェックがあれば問題ないと思います。様々なオプションをオンにしたままだと、コンパイルに時間がかかるので最小オプションにしておきましょう。
64-bit kernel ---> yes General setup ---> Rust support ---> yes General setup ---> Initial RAM filesystem and RAM disk (initramfs/initrd) support ---> yes General setup ---> Configure standard kernel features ---> Enable support for printk ---> yes Executable file formats / Emulations ---> Kernel support for ELF binaries ---> yes Executable file formats / Emulations ---> Kernel support for scripts starting with #! ---> yes Device Drivers ---> Generic Driver Options ---> Maintain a devtmpfs filesystem to mount at /dev ---> yes Device Drivers ---> Generic Driver Options ---> Automount devtmpfs at /dev, after the kernel mounted the rootfs ---> yes Device Drivers ---> Character devices ---> Rust Example ---> yes Device Drivers ---> Character devices ---> Enable TTY ---> yes Device Drivers ---> Character devices ---> Serial drivers ---> 8250/16550 and compatible serial support ---> yes Device Drivers ---> Character devices ---> Serial drivers ---> Console on 8250/16550 and compatible serial port ---> yes File systems ---> Pseudo filesystems ---> /proc file system support ---> yes File systems ---> Pseudo filesystems ---> sysfs file system support ---> yes
つづいて、Hello Worldを出力するようにします。
./drivers/char/rust_example.rsを修正して、Hello Worldを出力するように修正します。
$ cat ./drivers/char/rust_example.rs
修正箇所は、FileOperationsの実装にTO_USEを設定し、read関数を追加します。read関数内でHello, World!を出力するようにします。具体的な修正箇所は以下の通りです。そのほかの部分は修正しなくても大丈夫です。
use kernel::{ chrdev, condvar_init, cstr, file_operations::{FileOperations, File, ToUse}, user_ptr::UserSlicePtrWriter, miscdev, mutex_init, spinlock_init, sync::{CondVar, Mutex, SpinLock}, }; impl FileOperations for RustFile { type Wrapper = Box<Self>; const TO_USE: ToUse = ToUse { read: true, // read関数を有効化 write: false, seek: false, ioctl: false, compat_ioctl: false, fsync: false, }; fn read(&self, file: &File, data: &mut UserSlicePtrWriter, _offset: u64) -> KernelResult { // read関数を定義 println!("rust file: read, pos = {}", file.pos()); if file.pos() == 0 { let hello = b"Hello, World!\n"; data.write_slice(hello)?; Ok(()) } else { Ok(()) } } fn open() -> KernelResult<Self::Wrapper> { println!("rust file was opened!"); Ok(Box::try_new(Self)?) } }
コンパイルします。
$ make -j 8
busyboxコンパイル
$ git clone git://busybox.net/busybox.git
設定します。
$ cd busybox $ make defconfig $ make menuconfig
設定では以下のように静的リンクのオプションをチェックします。他の設定は触らなくて大丈夫です。
Settings ---> Build Options ---> Build static binary (no shared libs) ---> yes
コンパイルしinitial RAMディスクを作成します。initial RAMディスクはlinux-nextにおいておきましょう。
$ make -j 8 $ make install $ cd _install $ mkdir dev proc sys $ find . | cpio --quiet -H newc -o | gzip > ../../linux-next/initrd.img
Qemuで実行
最後に仕上げとして、Qemuで実行します。
$ cd linux-next $ qemu-system-x86_64 -m 128M -kernel arch/x86_64/boot/bzImage -append "console=ttyS0 rdinit=/bin/sh root=/dev/ram0" -initrd initrd.img -nographic
QemuでLinux起動後は、devtmpfsをマウントします。
# mount -t devtmpfs devtmpfs /dev
最後に、/dev/rust_miscdevファイルをcatして、Hello, World!を出力します。
# cat /dev/rust_miscdev [ 4362.809581] rust file was opened! [ 4362.809787] rust file: read, pos = 0 Hello, World! [ 4362.810056] rust file: read, pos = 14
素晴らしい!Rustで無事にHello, World!を出力することが出来ました。