32
25

More than 5 years have passed since last update.

Linux を(わりと)シンプルな構成でビルドして Qemu で起動する

Posted at

はじめに

  • 唐突に小さいカーネルを何となく作りたくなりました(。>﹏<。)
  • そこで(わりと)シンプルな kernel config で Linux カーネルを作れるか試してみました
  • まったり進行です

前提

  • ビルド環境は Ubuntu 14.04 64 bit を使っています
    • 64 bit 環境で 32 bit のカーネルをビルドする、とか需要あるのかしら。
    • あれば書こうかなぁ。
  • init は自作の Hello, world で代用します
  • ディスクイメージ(qcow2とか)に焼く方法は書いてません。qemu の -kernel オプションと -initrd オプションを使ってビルドしたカーネルを起動します
    • そのうち書くかも

ざっくりとした流れ

  1. qemu をインストールして
  2. カーネルを設定して、ビルドして
  3. initramfs を作って
  4. 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
32
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
25