できるだけ小さいRISC-VのLinuxのビルド

はじめに

RISC-Vのエミュレータを作っているのですが、そのうえで小さいLinuxを動かしたくなったのでLinuxカーネル(以下カーネル)をビルドしてみました。今回ビルドするカーネルはRV64Iと、できるだけ拡張機能を削ったもの(rv64imafdc_zicsr_zifencei)です。カーネルだけだと寂しいのでBusyBoxを入れただけのinitramfsも作ります。カーネルビルド初心者なので間違ってるところやもっと小さくできるTipsがあれば教えてください。

環境構築

私のメインの環境はx86_64のArchLinuxです。ほぼDockerで作業しますが一応書いときます。$はホストOSで>はDockerの中という意味です。

Dockerfileの作成

上手く動かなかったのでriscv-gnu-toolchainにスクリプトを当てています。-jはCPUに合わせて変更してください。riscv-gnu-toolchain本体や依存関係をインストールする設定です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
FROM ubuntu:latest
RUN apt-get update &&\
    apt-get install -y autoconf automake autotools-dev curl python3 python3-pip python3-tomli libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev ninja-bu      ild git cmake libglib2.0-dev libslirp-dev libncurses-dev vim &&\
     apt-get clean &&\
    rm -rf /var/lib/apt/lists/* &&\
    git clone https://github.com/riscv/riscv-gnu-toolchain
WORKDIR riscv-gnu-toolchain
RUN  git switch -d 2025.01.20 &&\
     sed -i '/shallow = true/d' .gitmodules &&\
     sed -i 's/--depth 1//g' Makefile.in &&\
    ./configure --enable-linux &&\
    make -j6

ツールチェイン等のビルド

結構時間かかりました。多分ネットワーク的な問題なのでビルド自体は体感だとそんなかかってなかった気がします。

1
$ sudo docker build . -t riscv-env

ダウンロード&展開

gitのサーバからもってくるとめちゃくちゃ遅かったので直接ダウンロードしています。チェックサムを確かめたい方は公式ページから確かめてみてください。

1
2
3
4
5
6
$ mkdir tiny-riscv-linux
$ sudo docker run -ti  -v .:/tiny-riscv-linux -ti riscv-env:latest
> curl -O https://git.kernel.org/torvalds/t/linux-6.14-rc1.tar.gz
> tar xvf linux-6.14
> curl -O https://busybox.net/downloads/busybox-1.37.0.tar.bz2
> tar xvf busybox-1.37.0.tar.bz2

カーネルのビルド

Linuxのconfigの調整

tinyconfigを作ってそれをTUIで設定する感じです。

1
2
3
> cd linux-6.14
> CORSS_COMPILE=riscv64-unknown-linux-gnu- make ARCH=riscv tinyconfig
> CORSS_COMPILE=riscv64-unknown-linux-gnu- make ARCH=riscv menuconfig

以下を設定します。依存関係があるのでこの順序で行ってください。/を押すと検索できたり、光っている文字を押すとその文字の項目に飛ぶことができます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
General setup  --> Initial RAM filesystem and RAM disk (initramfs/initrd) support y
               --> Configure standard kernel features (expert users) ---> Enable support for printk y
Platform type  --> Allow configurations that result in non-portable kenels y
               --> FPU support y
Boot options   --> UEFI runtime support n
Device Drivers --> Character devices --> Enable TTY y
                                     --> Serial drivers    --> 8250/16550 and compatiable serial support y
                                                           --> Console on 8250/16550 and compatiable serial port y
                                                           --> Extended 8250/16550 serial driver options y
                                                           --> Support more than 4 legancy serial ports y
                                                           --> Devicetree based probing for 8250 ports y
                                                           --> Early console using RISC-V SBI y
                                    --> RISC-V SBI console support y
Executable file formats --> Kernel support for ELF binaries y
                        --> Kernel support for scripts starting with #! y

ビルド

defconfigのときと比べて信じられないくらい早いです。待ち時間にYoutubeはみれないです。 ちなみに今回はBuxyBoxがF拡張とD拡張を使用するので指定していませんがFPU supportnにし、CFLAGS="-march=rv64imac_zicsr_zifencei -mabi=lp64"と指定することでF拡張とD拡張を使用しないカーネルをビルドすることもできます。

1
2
> CORSS_COMPILE=riscv64-unknown-linux-gnu- make ARCH=riscv -j12
> cd ..

BusyBoxのビルドとinitramfsの作成

カーネル単体でもいいのですが寂しいのでinitramfsを作ります。

BusyBoxの設定&ビルド

こちらはdefconfigを使用します。いつかはBusyBoxの方の設定もちゃんとやってみたいです。

1
2
3
4
5
6
7
> cd busybox-1.37.0
> CROSS_COMPILE=$CCPREFIX make ARCH=riscv defconfig
> vim .config

CONFIG_STATIC=y

> CROSS_COMPILE=$CCPREFIX make ARCH=riscv -j12

initramfsの作成

find ..のコマンドは参考Building a tiny Linux from scratchからほぼお借りしました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ mkdir initramfs
$ cd initramfs
$ mkdir {bin,sbin}
$ cp busybox-1.37.0/busybox bin
$ ln -sf busybox bin/sh
$ nvim sbin/init

#! /bin/busybox sh
busybox --install -s

exec /bin/sh

$ find . -print0 | cpio --null --create --verbose --format=newc | bzip2 -c > ../initrd

QEMUで実行

シェルが出てきたら成功です!!

1
2
$ yay -Syu extra/qemu-system-riscv 
$ qemu-system-riscv64 -kernel linux-6.14/arch/riscv/boot/Image -machine virt -initrd initrd -append "init=/sbin/init earlycon=sbi console=ttyS0" -nographic

ちなみに上のコマンドではqemu側でcpuの色々な拡張機能が有効になっている状態で実行されるので以下のように-cpuを設定することによって使用したい拡張機能を指定することができます。※以下の例では、カーネルのビルドのCFLAGSを設定した状態でビルドしたカーネルを用いています。またF拡張とD拡張は無効になっているのでBusyBoxを実行するときに例外が発生します。

1
$ qemu-system-riscv64 -cpu rv64i,m=true,a=true,c=true,zicsr=true,zifencei=true,u=true,s=true,mmu=on,pmp=on,sv57=true -kernel linux-6.14/arch/riscv/boot/Image -machine virt -initrd initrd -append "init=/sbin/init earlycon=sbi console=ttyS0" -nographic

おわりに

初めてLinuxのビルドオプションを色々いじったのでめちゃくちゃハマりましたが楽しすぎました。 このせいでネスペ勉強できなかった。 いつかは自分だけのinitを書いてディストリ作ってみたいです。次回は自宅サーバ系かOpenSBIで遊んでみた的な記事を書くかもしれないです。

参考

Licensed under CC BY-NC-SA 4.0
Hugo で構築されています。
テーマ StackJimmy によって設計されています。