なぜカーネルのビルド・実行を体験したかったのか(ポエム)
- そもそものコンピュータ・アーキテクチャ、ソフトウェア工学的な知識がなく、今後応用が効かないのではないかという危惧
- (個人的に)ブラックボックス化の上に成り立つ仕組みの栄枯盛衰をいくつか見て、無常を感じた
- ブラックボックスなレイヤはほぼ変わっていない
- 10年後に別のものに変わらないとは必ずしも言い切れないけど、ほぼ必ず存在すると思われる
- こんなことを考えていると、低レイヤの仕組みについて知りたい欲が抑えきれない
- 自分の中で完全にブラックボックスになっている部分に手を出したい
- しかし挙動や全体像が不明のままソースを読んでも迷子になって挫折するだけ
- 取っ掛かりとして、実際に手元で動かすことができるカーネル環境を試す
目次
- なぜカーネルのビルド・実行を体験したかったのか(ポエム)
- 目次
- 今回試したカーネルバージョン
- ビルド環境
- 実行環境・ツールなど
- パッケージのインストール
- Linuxカーネル取得
- Linuxカーネルのビルド
- qemuの-initrdオプションに指定するイメージを作成
- ビルドしたカーネルをqemuで起動
- 今後どうしたいのか
- 参考
今回試したカーネルバージョン
- linux-4.19.63
ビルド環境
- [手順作成時] Ubuntu 18.04.3 LTS
- [手順検証時] Ubuntu WSL(https://www.microsoft.com/store/productId/9NBLGGH4MSV6) 4.4.0-17763-Microsoft
実行環境・ツールなど
- QEMU 2.11(apt-get経由)
- BusyBox 1.31.0
パッケージのインストール
$ sudo apt update -y $ sudo apt upgrade -y $ sudo apt install -y git build-essential ncurses-dev bison flex libelf-dev openssl libssl-dev $ sudo apt-get install -y qemu # 下記は必要に応じて $ sudo apt-get install -y bzip2 vim wget
Linuxカーネル取得
# clone完了まで30分~1時間程度 $ git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git $ cd ./linux $ git tag|grep v4.19.63 $ git checkout -b v4.19.63 v4.19.63
Linuxカーネルのビルド
- 今回はx86_64を対象としてビルドする
# x86_64の設定ファイルを配置する $ cp arch/x86/configs/x86_64_defconfig ./.config $ # .configをもとに関連ファイルを設定する $ # 有効にすべき機能の取捨選択を判断できる知見を持っていないので、今回はEnter押しっぱなしにした $ make oldconfig $ make
- arch/x86_64/boot/bzImageが作成されている
qemuの-initrdオプションに指定するイメージを作成
busyboxのソースをダウンロード
$ wget https://busybox.net/downloads/busybox-1.31.0.tar.bz2 $ tar -jxvf ./busybox-1.31.0.tar.bz2 $ cd ./busybox-1.31.0
busyboxのビルド (make menuconfig)
- ポイント
- Setting -> Build static binary (no shared libs)をチェックする
- Networking Utilities -> Enable IPv6 Supportのチェックを外す
$ make menuconfig # Setting -> Build static binary (no shared libs)をチェックする # Networking Utilities -> Enable IPv6 Supportのチェックを外す $ make install
busyboxディレクトリに_installディレクトリが作成されている
dev, dev/null, proc, sys, etc/init.dを作成
$ cd ./_install $ mkdir dev $ sudo mknod dev/null c 1 3 $ mkdir proc $ mkdir sys $ mkdir -p etc/init.d
_install/etc/init.d/rcSを作成
$ vim ./etc/init.d/rcS # 以下の内容を記述 #!/bin/sh mount -t proc none /proc mount -t sysfs none /sys /sbin/mdev -s
_install/etc/inittabを作成
$ vim ./etc/inittab # 以下の内容を記述 ::sysinit:/etc/init.d/rcS ::respawn:-/bin/sh ::respawn:/sbin/getty -L ttyS5 115200 vt100 ::ctrlaltdel:/bin/umount -a -r
初期化プロセスのプログラムを作成(_install/init.c)
- ここではbusyboxの_installディレクトリ直下で作業を実施
/* init.c */ #include <stdio.h> void main() { printf("Hello World!"); while(1); }
- init.cをコンパイル(_install/init)
$ gcc -static -o init ./init.c
パーミッションの変更
$ chmod 755 ./init ./etc/init.d/rcS
_installディレクトリ以下でコマンドを実行し、cpio形式イメージを作成
$ find . | cpio -o --format=newc | gzip > ../initrd.img
ビルドしたカーネルをqemuで起動
$ qemu-system-x86_64 -m 1024 -nographic -kernel ~/linux/arch/x86_64/boot/bzImage -initrd ~/linux/busybox-1.31.0/initrd.img -append "console=ttyS0 root=/dev/mem0 rdinit=/sbin/init"
- 正しくビルド、起動できている!
今後どうしたいのか
- (個人的)ブラックボックスを少しずつ減らしたい
- デバッグしてみたい
参考
busyboxの設定やデバイスファイル生成など、下記のサイト様を参考にしました。