はじめに
- 唐突に小さいカーネルを何となく作りたくなりました(。>﹏<。)
- そこで(わりと)シンプルな kernel config で Linux カーネルを作れるか試してみました
- まったり進行です
前提
- ビルド環境は Ubuntu 14.04 64 bit を使っています
- 64 bit 環境で 32 bit のカーネルをビルドする、とか需要あるのかしら。
- あれば書こうかなぁ。
- init は自作の Hello, world で代用します
- ディスクイメージ(qcow2とか)に焼く方法は書いてません。qemu の
-kernel
オプションと-initrd
オプションを使ってビルドしたカーネルを起動します- そのうち書くかも
ざっくりとした流れ
- qemu をインストールして
- カーネルを設定して、ビルドして
- initramfs を作って
- qemu で起動(∩´∀`)∩
下準備
使うツールのインストール
- qemu と カーネルの設定をする際に使う
make menuconfig
で利用される libcurses 群を入れます
$ sudo apt-get install qemu
$ sudo apt-get install libncurses5 libncurses5-dev
カーネルのダウンロードと解凍
$ wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.4.4.tar.xz
$ tar Jxvf linux-4.4.4.tar.xz
$ cd linux-4.4.4
カーネルの設定
カーネルに必要最低限なコンフィグのみ残す
$ make allnoconfig
- どれくらい行数があるか気になったのでカウントしてみました
$ egrep -v "(^#|^$)" .config | wc -l
234
- 結構ありますね(* ´﹃` *)
qemu で起動するために必要なコンフィグを有効にする
- make menuconfig を使います。
$ make menuconfig
- 下の項目を有効にしていきます。
[*] 64-bit kernel
-> General setup
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
-> General setup
-> Configure standard kernel features
[*] Enable support for printk
-> Executable file formats / Emulations
[*] Kernel support for ELF binaries
-> Device Drivers
-> Character devices
[*] Enable TTY
-> Device Drivers
-> Character devices
-> Serial drivers
[*] 8250/16550 and compatible serial support
[*] Console on 8250/16550 and compatible serial port
設定項目 | 何に使うか |
---|---|
64-bit kernel | 今回は 64 bit kernel をビルドするので必要です |
Initial RAM filesystem and RAM disk (initramfs/initrd) support | initramfs/initrd を有効にします。qemu から -initrd オプションで起動させるためです。これを有効にしないでやるケースってどんなときなんでしょうね。 |
Enable support for printk | printk 出力を有効にします。カーネルの起動ログをコンソールに出すようにするためです。 |
Kernel support for ELF binaries | ELF を読み込めるようにします。initrd に指定するプログラムが ELF binary なためです。 |
Enable TTY | TTY を有効にします。ターミナルに文字を出力させるためです。 |
Console on 8250/16550 and compatible serial port | シリアルポートを有効にします。カーネルの出力を見られるようにするために必要です |
- ここでコンフィグの行数をカウントしてみます。
$ egrep -v "(^#|^$)" .config | wc -l
311
- make allnoconfig が 234 だったので、思ったより増えてますね。
カーネルのビルド
-
-j
オプションはマルチコアの場合に並列ビルドをします。任意で指定してくださいませ。
$ make -j4 bzImage
- ビルドを待ちます。この時にビルド対象のコード一覧を見てみるのも楽しいかもしれません
- bzImage ができていることを確認します。今回は 64 bit kernel なので ./arch/x86/boot/bzImage を使います
$ find ./ -name bzImage
./arch/i386/boot/bzImage
./arch/x86/boot/bzImage
- カーネルができあがったので、次に initramfs を作ります。
initramfs の作成
下準備(作業ディレクトリの作成とか)
$ mkdir ~/work
$ cd ~/work
$ cp ~/linux-4.4.4/arch/x86/boot/bzImage bzImage
init で実行するプログラムの作成
- おもむろに vim を立ち上げて init.c ファイルを作ります
$ vim init.c
- 以下のようなコードを書きます
#include <stdio.h>
int main(void) {
printf("-----------HELLO------------\n");
return 0;
}
- libc をプログラム本体に含めるために static ビルドをします
$ gcc -static -o init init.c
プログラムを gzip 圧縮の initramfs 形式にする
- cpio コマンドがパイプでプログラム名を受け取れるため、以下のようなコマンドを実行して、initramfs を作ります
$ echo init | cpio -o -H newc | gzip > initramfs.cpio.gz
カーネルの起動
- これですべての準備が整いました。以下のコマンドを実行してカーネルを立ち上げてみてください
$ qemu-system-x86_64 -kernel ./bzImage -initrd ./initramfs.cpio.gz -append "console=ttyS0" -nographic
- 以下のような感じでカーネルの起動ログが出て、作成したプログラムの HELLO という文字が出力されていると思います
- panic してますが、とりあえずここまで。
(省略)
mousedev: PS/2 mouse device common for all mice
input: AT Translated Set 2 keyboard as /devices/platform/i8042/serio0/input/input0
Freeing unused kernel memory: 440K (ffffffff81175000 - ffffffff811e3000)
-----------HELLO------------
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
Kernel Offset: disabled
---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000