今回はCD/DVDからのLinuxシステムの起動を目指します。
1.4MBの制限が無くなりますので、容量をあまり気にせずkernelの設定やユーザーランドを構築できます。
ローカルHDDのマウントなどは考えません。単純にISOイメージ上に格納されたbzImage(Linuxカーネル)と、kernel-2.6以降で利用出来るようになったcpio形式のInitial RAM Disk(initrd)だけで起動します。ルートファイルシステムはkernelパラメータに "root=/dev/ram0" を指定することで、initrdをそのまま使います。
また、今回は "Buildroot" を使ってuClibc, BusyBoxのビルドとルートファイルシステムの構築を行ってみます。
initrd, initramfsの違いについては "DEBUG HACKS", hack #64 を参照してください。
initrdやInitial RAM Disk関連のカーネルパラメータ、カーネル設定については豊富なWeb資料と共に、カーネルソースツリーの
Documentation/ blockdev/ramdisk.txt devices.txt initrd.txt filesystems/tmpfs.txt
も参考になります。
参考:
Buildrootをダウンロードします。今回は buildroot-2011.02.tar.bz2 を使います。
$ pwd /home/msakamoto/reduced.linux $ ls ... buildroot-2011.02.tar.bz2 ... $ tar jxf buildroot-2011.02.tar.bz2
また、Buildrootのソースコードダウンロード先ディレクトリを作っておきます。Buildrootの設定でダウンロード先を指定することで、ダウンロードファイルを一箇所にまとめて共通化できます。
$ pwd /home/msakamoto/reduced.linux $ mkdir buildroot-dl
環境変数で指定する方法もあります。詳しくはBuildrootのドキュメントを参照してください。
今回のビルドディレクトリを作成します。 "04_cdboot" を親ディレクトリとし、Buildroot用に "br" という子ディレクトリを作成します。
$ pwd /home/msakamoto/reduced.linux $ mkdir -p 04_cdboot/br
一旦 "allnoconfig" でBuildrootの設定を初期化します。
$ pwd /home/msakamoto/reduced.linux $ make -C `pwd`/buildroot-2011.02 O=`pwd`/04_cdboot/br allnoconfig
Buildrootの設定を調整していきます。
$ cd 04_cdboot/br/ $ make menuconfig
以下のようにオプションを調整します。
BR2_DL_DIR="$(TOPDIR)/dl" → BR2_DL_DIR="/home/msakamoto/reduced.linux/buildroot-dl" # BusyBoxをビルドします。 BR2_PACKAGE_BUSYBOX=y # ルートファイルシステムのイメージファイルををcpio形式で作成します。 BR2_TARGET_ROOTFS_CPIO=y
ビルドします。
$ make all
ビルドに成功すると、ビルドディレクトリの下に "images/rootfs.cpio", "images/rootfs.cpio.gz" というファイルが作成されます。これがcpio形式でアーカイブされたルートファイルシステムのイメージファイルになります。
続いてCDブートするための最小構成のカーネルをビルドします。
まず、ビルドディレクトリを作成します。
$ pwd /home/msakamoto/reduced.linux/04_cdboot $ mkdir kernel
カーネルは 技術/Linux/手作りLinuxシステム/01. Boot from Floppy Disk (kernel-2.6.x) で展開したソースツリー(kernel-2.6.38.2)を流用します。Buildroot側ではtoolchainのコンパイルにkernel-2.6.37.2を使ってますが・・・まぁ、今回は目をつぶる方向で。(Buildroot側でLinux Kernelのコンパイルを有効化すると、toolchainで使うヘッダーと同じバージョンのkernelを使うよう設定することも可能です。ただ今回はこれ以上カーネルソースを展開してHDD容量を消費したくなかったので、Buildrootの外側で既に展開していたkernelソースを使ってしまいます)
allnoconfigで設定を初期化します。
$ make -C ../linux-2.6.38.2 O=`pwd`/kernel allnoconfig $ cd kernel $ make menuconfig
以下のオプションを有効化します。モジュール化はせず、カーネルに組み込みます。
CONFIG_BLK_DEV_INITRD CONFIG_BINFMT_ELF
CONFIG_BLK_DEV_INITRDを有効化するときは、"make menuconfig"で
General setup ---> Initial RAM filesystem and RAM disk (initramfs/initrd) support
のチェックをONにすることをお薦めします。圧縮ファイルの展開関連のオプションも自動的に有効化されます。
ビルドします。"bzImage"が生成されればOKです。
$ make bzImage ... BUILD arch/x86/boot/bzImage Root device is (253, 0) Setup is 14008 bytes (padded to 14336 bytes). System is 770 kB CRC 5b2917a6 Kernel: arch/x86/boot/bzImage is ready (#1)
mkisofsと、syslinuxが提供しているisolinuxを使ってブート可能なISOイメージを作成します。
本シリーズで使用している開発マシン、CentOS 5.5 での両パッケージのバージョン:
syslinux-3.11-4 mkisofs-2.01-10.7.el5
ISOLINUX参考:
まずISOイメージに対応するディレクトリを作成します。
$ pwd /home/msakamoto/reduced.linux/04_cdboot $ mkdir cdimage
"cdimage/" 以下のディレクトリツリーがISOイメージに変換されます。
まずカーネルとルートファイルシステムのイメージファイルをコピーしてきます。rootfsについてはファイル名を短くしておきます。
$ cp kernel/arch/x86/boot/bzImage cdimage/ $ cp br/images/rootfs.cpio.gz cdimage/rootfs.gz
続いて "isolinux" というディレクトリを作成し、その中にsyslinuxで提供されている isolinux.bin をコピーします。
$ mkdir -p cdimage/isolinux $ rpm -ql syslinux ... /usr/lib/syslinux/isolinux.bin ... $ cp /usr/lib/syslinux/isolinux.bin cdimage/isolinux/
isolinux.cfgを作成します。改行はCRLFにして編集してください。(vimなら ":set fileformat=dos" で保存)
$ vim cdimage/isolinux/isolinux.cfg
isolinux.cfg:
default linux label linux kernel /bzImage append initrd=/rootfs.gz root=/dev/ram0
"root=/dev/ram0" でinitrd(Initial RAM Disk)をルートファイルシステムとしてそのまま使い続けるようにしています。もちろん、rootfs.gzの中には "/dev/ram0" デバイスノードが作成されていることが条件です。"cpio -t < br/images/rootfs.cpio" などでcpioアーカイブの中身を確認してみてください。
initrdと"root=/dev/ram0"の解説はカーネルソースツリーの Documentation/initrd.txt などを参照してください。
mkisofsでISOイメージを作成します。
$ mkisofs -o output.iso \ -b isolinux/isolinux.bin \ -c isolinux/boot.cat \ -no-emul-boot \ -boot-load-size 4 \ -boot-info-table \ cdimage
output.isoをVMware仮想マシンのCD/DVDイメージファイルに設定し、起動してみます。
無事ログインシェル、およびrootログインまで辿り着きました!(パスワードは空になっています)
→ "Could not find ramdisk..."というメッセージはsyslinux側が表示しています。
などの対処で解決できると思います。
メッセージが表示されるのであれば、kernelソースやsyslinuxのソースをgrepし、どちらが出力しているのか切り分け、その後Web等で検索してみてください。
syslinux側の場合は、isolinux-debug.bin を使ってデバッグメッセージを表示させてみてください(ISOLINUXのドキュメント参照)。
これまでずっと英語キーボード設定のまま話を進めてきました。本シリーズの趣旨としてまずは最低限度動作する環境を構築することを優先したため、キーボードなどユーザー環境については無視してきました。
しかしBuildrootを使うことで、ユーザーランドのアプリケーションもスムーズに導入できるようになりましたので、ここで日本語106キーボードを使えるようにしてみます。
やり方は簡単で、Buildrootの設定で
Package Selection for the target ---> Hardware handling ---> kbd
をチェックして有効化し、"make"しなおします。新しいrootfs.cpio.gzができたら、上記と同様 cdimage/rootfs.gz に上書きコピーしてmkisofsしなおします。
新しいISOイメージで起動したらrootでログインし、
# cd /usr/share/keymaps/i386/qwerty # loadkeys jp106.map.gz
すれば日本語106キーボードが使えるようになります。
Buildrootがビルドしたtoolchain(gcc, binutils)は "出力ディレクトリ/host" 以下に保存されています。これをBuildrootの外部で使うには、単純に "出力ディレクトリ/host/usr/bin" にPATHを通せばOKです。
$ pwd /home/msakamoto/reduced.linux/04_cdboot $ pushd br/host/usr/bin/ $ ls faked* ... fakeroot* ... i386-linux-gcc@ ... $ export PATH=`pwd`:$PATH $ popd $ cat helloworld.c #include <stdio.h> #include <linux/version.h> int main(int argc, char *argv[]) { int i; printf("Hello, World! LINUX_VERSION_CODE=%ld\n", LINUX_VERSION_CODE); for (i = 0; i < argc; i++) { printf("args[%d]=[%s]\n", i, argv[i]); } return 0; } $ which i386-linux-gcc ~/reduced.linux/04_cdboot/br/host/usr/bin/i386-linux-gcc $ i386-linux-gcc -o helloworld helloworld.c ... $ readelf -x .interp helloworld Hex dump of section '.interp': 0x080480f4 732e6362 696c4375 2d646c2f 62696c2f /lib/ld-uClibc.s 0x08048104 00302e6f o.0.
実行ファイル helloworld をルートファイルシステムに組み込みます。ルートファイルシステムをカスタマイズする簡単な方法としては、 "出力ディレクトリ/target/" の下に直接ファイルをコピーし、"make"しなおすだけというのがあります。この方法を使ってみます。
$ cp helloworld br/target/ $ cd br $ make
新しいrootfs.cpio.gzが生成されたので、これまでと同様の手順でISOイメージを再生成します。
ルートファイルシステムをカスタマイズするその他の方法についてはBuildrootのドキュメントを参照してください。
仮想マシンを起動してみます。
無事helloworldが動きました!
以上でCDブートのLinuxシステムの構築記事は終わりです。次回はいよいよPXEを使ったネットワークブートに挑戦します。