次のページ 前のページ 目次へ

4. 初めに init ありき

次のレッスンの目的は「ユーザランドの構築」です. が,いきなり組み込みボードでここらをやるのはしんどい場合も多いので,まずは x86 環境で練習してみましょう.

4.1 Linux インストールフロッピー

Linux の場合,インストーラ自体が Linux 上で動作しています. というわけで,「小さな Linux イメージ」を見るにはここらが適当かな,というわけで. ここでは,Vine のインストールフロッピーの中身を見ていきましょう. なお,Vine-2.6r1 のイメージを使用しています.

フロッピーイメージの解析

ftp で入手したイメージを調べてみましょう.

# file boot.img
boot.img: x86 boot sector, code offset 0x3c, OEM-ID "SYSLINUX", root entries 224
, sectors 2880 (volumes <=32 MB) , sectors/FAT 9, serial number 0x3b9c1a3a, labe
l: "           ", FAT (12 bit)

ブートセクタが頭に付いた FAT イメージということなので,とりあえず mount して中を覗いてみましょう.

# mount -o loop -r boot.img /mnt/tmp
# ls /mnt/tmp
boot.msg    general.msg  kickit.msg   param.msg   snake.msg     vmlinuz
expert.msg  initrd.img   ldlinux.sys  rescue.msg  syslinux.cfg

ファイルの構成からすると,syslinux というブートローダを使用しているようです. syslinux.cfg というのが設定ファイルなので,中を覗いてみると,initrd を使用しており,intird.img というのがそのイメージのようです.

initrd というのは,本来,モジュールの読み込みを行ってから本番のファイルシステムをマウント,という処理を行うためのものですが,ここでは initrd 環境でそのままメインの処理を行っているようです.

何はともあれ,initrd.img の中を覗いてみましょう. 例によってファイルの素性を調べると

# file /mnt/tmp/initrd.img 
/mnt/tmp/initrd.img: gzip compressed data, was "initrd-boot.img.nogz", from Unix
, max compression
gzip 圧縮されたイメージだそうです.

それでは,と,

# zcat /mnt/tmp/initrd.img > initrd.img 
# mount -o loop -r initrd /mnt/tmp0
# ls /mnt/tmp0
bin  dev  etc  initrd  linuxrc  lost+found  modules  proc  sbin  tmp  var
圧縮をほどいてこいつも mount してみます. これがインストーラ実行時のルートファイルシステムになります.

と,ここまでたどってくれば,initrd イメージの作成方法も自ずとわかりますね. つまり

  1. 適当なファイル (initrd.img) を用意
  2. mke2fs で論理フォーマット
  3. loopback device として,適当なディレクトリに mount
  4. 必要なファイルをコピー・作成
  5. umount
  6. gzip で圧縮
  7. インストールディスクの initrd.img と差し替える
ということになります.

4.2 initrd イメージの作成

それでは,先の手順に従って initrd イメージを作成してみましょう.

まず,0 で埋められた「適当なファイル」を作成します. サイズは元のイントスールディスクの非圧縮の initrd.img と同じにしてみます.

# dd if=/dev/zero of=myinitrd.img bs=3309568 count=1

ちなみに,実際に作成されるファイルの大きさは,「bs= で指定された数」×「count= で指定された数」になります. つまり,ここで,「0 で埋められたファイルを作成する」という場合は,上記 の操作は

# dd if=/dev/zero of=myinitrd.img bs=1 count=3309568 

と(実行速度以外は)等価です. フロッピー以外のブートデバイスで大きな initrd を作成しようとして,メモ リが足りない,などのエラーが出た場合は,参考までに.

あと,「実用の」イメージを作るときは,既存のイメージを mount して修正するより,この作業から開始し,ファイルをコピーし直した方が良いでしょう. というのは,「ファイルの削除」という操作は,インデックスの書き換えを行うのみで,実際のディスクイメージを 0 で埋めるのではないからです. 何度もイメージの書き換えを行うと,これらの「使用していないけど何かが書かれている」領域が gzip 圧縮に響いてきます.

とはいえ,「圧縮率が悪くなる」という程度の問題でもあるので,容量に余裕があるのならば,開発時はイメージをそのまま書き換えても差し支えありません.

次に,このイメージを ext2 で論理フォーマットします.

# mke2fs myinitrd.img 
mke2fs 1.29 (24-Sep-2002)
myinitrd.img is not a block special device.
Proceed anyway? (y,n) y
Filesystem label=
                               .
                               .
                               .

This filesystem will be automatically checked every 26 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.
#

このイメージを mount します.

# mount -o loop myinitrd.img /mnt/tmp0
# cd /mnt/tmp0
# ls
lost+found

とりあえず,init として,先ほどの hello,world を x86 ターゲットでコンパイルしたものを用意しましょう. もちろん,ライブラリはスタティックリンクしておきます.

# cd /mnt/tmp0
# mkdir sbin
# cd sbin
# cp (どこか)/hello init

あと,最低限,コンソールデバイスが必要のようなので,これも作成しておきましょう.

# cd /mnt/tmp0
# mkdir dev
# mknod console c 5 1
# chmod 777 console

以上でファイルのコピーはおしまい. というわけで,unmount します. そして,Vine のインストールディスクイメージ中の initrd.img と,今作成したイメージとをすり替えます.

# cd
# umount /mnt/tmp0
# mount -o loop boot.img /mnt/tmp
# gzip -9 < myinitrd.img > /mnt/tmp/initrd.img
# umount /mnt/tmp
gzip の行で圧縮と差し替えを一度に行っています.

最後に,このイメージをフロッピーに書き込みます.

# fdformat /dev/fd0H1440
# dd if=boot.img of=/dev/fd0H1440

これで改造版のインストールディスクのできあがり.

4.3 実行

それでは起動してみましょう. 最初にド派手な VineLinux のバナーが出ますが,これは syslinux ブートローダ(の設定)による仕業です. 無視して,[Enter] キーを押して進みましょう.

おなじみの Linux の起動メッセージがズラズラと出た後,kernel panic で停止します.

Partition check:
 hda: unknown partition table
Floppy drive(s): fd0 is 1.44M, fd1 is 1.44M
FDC 0 is an 8272A
RAMDISK driver initialized: 16 RAM disks of 7168K size 1024 blocksize
loop: loaded (max 8 devices)
usb.c: registered new driver usbdevfs
usb.c: registered new driver hub
usb.c: registered new driver hiddev
usb.c: registered new driver hid
hid-core.c: v1.8.1 Andreas Gal, Vojtech Pavlik <vojtech@suse.cz>
hid-core.c: USB HID support drivers
mice: PS/2 mouse device common for all mice
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 2048 bind 2048)
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
RAMDISK: Compressed image found at block 0
Freeing initrd memory: 458k freed
VFS: Mounted root (ext2 filesystem) readonly.
Freeing unused kernel memory: 104k freed
hello,world
Kernel panic: Attempted to kill init!
普通の init プロセスは,Linux 動作中は決して終了することがないのですが,今回のエセ init は,exit してしまっているので,このようなことになります.

が,よく見ると「hello,world」が表示されていますね. 今組み込んだ hello,world 版 init がしっかりと動作していることがわかります.

「init は全てのプロセスの始祖である」「UNIX カーネルは init プロセスを起動した後は受動的に動作する」とかいうことは耳学問しては知っている人も多いとは思います. が,このように実際に体感してみるというのも興味深いのではないかと思いますが,どうでしょう.

4.4 実際の組み込みボードでは

x86 では,initrd イメージは,カーネルイメージと別れていることが普通ですが,MIPS などの場合,initrd イメージをカーネルイメージと一緒にリンクすることもできます. また,root デバイスも,ハードディスクではなく,flash ROM ディスク(MTD デバイス)であることも多々あります.

が,これらのイメージの作成は,基本的には今回と同様の手順で行うことができます.

また,flash ROM ディスクを使用する場合は,論理フォーマットとして ext2 ではなく,jffs2 を使用するのが普通です. というのは,ext2 の場合,特定のセクタ(ディレクトリエントリなど)の書き換えが頻発するので,書き換え回数が有限の flash ROM ではこのセクタの部分だけ寿命が短くなります.

jffs2 では,このような偏った書き換えが起こらないように考慮されているそうです. また,圧縮された格納形式を採用しているので,より多くのプログラム・データを詰め込むことができます.

が,jffs2 は「特殊な」ファイルシステムで,単なる ramdisk やループバックデバイスのファイルシステムとしては使用できないようです. イメージの作成には,ディレクトリツリーを準備し,専用コマンドでイメージを作成することになります. 作成は iso9660 ファイルシステムのような感覚ですね.


次のページ 前のページ 目次へ