QEMUでLinuxカーネルを動かす part1

実習Linuxカーネルという本の中で、システムコールを自作する実習があるのですが、その際、いちいちカーネルをビルドして、grubを再設定して、云々というのが面倒だと思い、(それ以上に、何かをしくじってPCが起動しなくなるのが怖いというのが本音なのですが)、QEMUを利用して、カーネルを起動して作業しようと考え、色々やってみたので、それについてメモしておきます。

実習Linuxカーネル―理論と実習 カーネルを効率的に理解するための実習書

実習Linuxカーネル―理論と実習 カーネルを効率的に理解するための実習書

  • 作者: ゲーリーナット,Gary J. Nutt,浜田真理,浜田光之
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2001/12
  • メディア: 単行本
  • クリック: 3回
  • この商品を含むブログ (7件) を見る

QEMU

以下、QEMU(Wikipedia)からの引用です。

QEMU(キューエミュ)は、Fabrice Bellardが中心となって開発しているオープンソースのプロセッサエミュレータである。

QEMUは機械全体をエミュレーションするシステムエミュレーションと呼ばれる環境と、Linuxのユーザーランドをエミュレーションするユーザーエミュレーションと呼ばれる環境がある。

QEMUを利用してLinuxカーネルを動かす

QEMUでは、"-kernel"や"-initrd"といったオプションをしようすることで、ブートローダを迂回して、カーネルramdiskを直接ロードできます。

今回はそれを利用して、カーネルを動作させます。

ちなみに実行環境は、Ubuntu 12.04(32bit)です。

カーネルのビルド

まずは、動作させる対象のカーネルをビルドします。

Linuxカーネルソースコードは、(The Linux Kernel Archives)https://www.kernel.org/からダウンロードすることが出来ます。

今回は、最新の安定版である、3.16.3を使用します。

まずはソースコードのダウンロードです。

# 適当なディレクトリに移動
$ cd /tmp
# ソースコードのダウンロード
$ wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.16.3.tar.xz
# ソースコードの展開
$ tar xvf linux-3.16.3.tar.xz
# 展開したディレクトリに移動
$ cd linux-3.16.3/

次にビルドですが、カーネルをビルドする際には多くの設定項目があります。"make menuconfig"などすると、GUIっぽい画面になり、設定することが出来るのですが、量も多いですし、私にはよくわからない項目ばかりだったので、現在しようしているカーネルの設定を利用してビルドを行います。

また、カーネルソースコード内のREADMEを見るとビルド用のディレクトリを使用した例が紹介されているので、ビルド用のディレクトリを指定してビルドします。

# 適当なビルド用ディレクトリを作成
$ mkdir -p ~/build/kernel
# 現在使用中のカーネルの設定ファイルを使用
$ sudo cp /boot/config-3.8.0-44-generic ~/build/kernel/.config
$ make O=~/build/kernel oldconfig
$ make O=~/build/kernel 

"oldconfig"を指定した部分では、現在のカーネルとこれからビルドしようとしているカーネルの設定項目に差分がある場合に、その設定項目をどうするか対話的に決めていきます。

"make"には非常に長い時間がかかります。要らない機能を外していくように設定すれば、この時間は短くなると思います。"make allnoconfig"とやると最低限の設定のみでビルドされ、"make"の時間はとても短いものでしたがQEMUでうまく動作しませんでした。。

"make"が終わると、ビルド用のディレクトリ内に、カーネルのイメージが作成されています。

$ ls -al ~/build/kernel/arch/x86/boot/bzImage
-rw-rw-r-- 1 twhs twhs 5603200  9月 30 12:11 /home/twhs/build/kernel/arch/x86/boot/bzImage

initrd の作成

initrdとは"initial ramdisk"の略で、カーネルのブート時に使用される一時的なファイルシステムの一種

引用元 : initrd

だそうです。今回はinitrdに"Hello World"を表示するだけのプログラムを使用してみます。

まずは、C言語で"Hello World"と表示するプログラムを作成します。ここでは"~/build/helloworld.c"として作成します。

#include <stdio.h>

void main()
{
    printf("Hello World");
    printf("Hello World");
    printf("Hello World");
    while(1);
}

コンパイルします。

$ cd ~/build
$ gcc -static -o ./helloworld ./helloworld.c

ここでは"-static"を指定して必要なライブラリを静的リンクするようにしています。

次に、"cpio"というコマンドを使用して、initrdを作成します。"cpio"はアーカイブの作成や展開にも利用できます。

$ echo helloworld | cpio -o --format=newc > rootfs

これで必要なものは揃ったので、QEMUカーネルを動作させてみます。

Hello World

$ qemu-system-i386 \
    -kernel ~/build/kernel/arch/x86/boot/bzImage \
    -initrd ~/build/rootfs \
    -append "root=/dev/ram rdinit=/helloworld"

こんな感じで、"Hello World"が表示されます。

f:id:ryouta768:20140930191155p:plain

  • -kernel
  • -initrd
  • -append
    • カーネル起動時のパラメータを指定します
    • rdinit
      • 起動後に実行するプログラムを指定
    • root=/dev/ram

最低限の作業環境を整える

"Hello World"を表示したのは良いですが、このままだと、このカーネルを使用して作業を行うことが出来ません。普段利用している"sh"や"cat"など、ほか多数のコマンドが無いからです。

ここでは、最低限のコマンドが使用出来ればよいので、"BusyBox"と呼ばれるツールを利用します。

BusyBox とは、アプリケーションソフトウェアである。Coreutilsにある主な標準UNIXコマンドの機能を単一の実行ファイルで提供する。なおかつ、その実行ファイルはLinux上で最小の実行ファイルとなるよう設計されており、各コマンドの実行ファイルをインストールするのに比べディスクの使用量を大幅に削減することができる。そのため、特定用途のLinuxディストリビューションや組み込みシステムに最適である。「組み込みLinuxの十徳ナイフ」と呼ばれている。GPLv2 でリリースされているフリーソフトウェアである。

引用元 : BusyBox

少し長くなったので、"BusyBox"のインストールは次回メモしたいと思います。

参考にしたページ