JF-INDEX (document list of JF Project)

LILO "the Linux Loader" の動作について

佐野武俊 / Taketoshi Sano, (kgh12351@nifty.ne.jp)

$Date: 1999/10/12 08:20:24 $, ($Revision: 1.5 $)


この文書は、LILO "the Linux Loader" の動作について説明するものです。 なお、対象としている LILO は ver.21 および ver.22 です。

1. 起動時の動作

2. /sbin/lilo コマンドを実行した時の動作

3. 補足


1. 起動時の動作

起動時に実行される LILO のコードには、1st boot loader と 2nd boot loader の 2 種類があります。

これらのコードは通常、 /boot/boot.b というファイルの中に保存されており、 このうち 1st boot loader に相当する先頭 446bytes が "lilo" コマンドの実行によって lilo.conf の boot= で 指定された場所のブートセクターにインストールされます。このとき同時に 2nd boot loader やマップ (カーネル位置情報) ファイルなどのディスク上の 位置を示す CHS アドレスが 1st boot loader のコード中のデータ領域に記録されます。

1st boot loader は 2nd boot loader をメモリーにロードするのが役目です。 2nd boot loader はマップファイルをロードしてその情報を解析し、 その結果に従ってカーネルコードをロードします。 また必要な場合には initrd で使用するルートイメージのロードも 2nd boot loader が実行します。

1.1 1st boot loader

LILO によるブートでは、最初にブートセクターの先頭 446 bytes に記録された 1st boot loader が BIOS または MBR に置かれた他のブートローダーによって ロードされます。ロードに成功し、1st boot loader が実行を開始すると 最初の "L" という文字が表示されます。

次に 1st boot loader は "lilo" コマンド実行時に 自分の中に記録された 2nd boot loader のディスク上の位置 (CHS セクターアドレス) を BIOS に提示して、セクター単位で BIOS に 2nd boot loader をロードさせます。 ロードに成功すると、コンソールに "I" という文字を表示して 2nd boot loader に 制御を渡します。

lilo のソースコードで 1st boot loader に相当するのは first.S です。 (なんてわかりやすい名前でしょう!) 上記の "L", "I", の表示を実行しているのは、 それぞれ

go:     cli                     ! no interrupts
        mov     ds,ax           ! AX is already set
        mov     es,ax           ! (ES may be wrong when restarting)
        mov     sp,#STACK       ! set the stack
        mov     ax,#STACKSEG
        mov     ss,ax
        sti                     ! now it is safe

        mov     al,#0x0d        ! gimme a CR ...
        call    display
        mov     al,#0x0a        ! ... an LF ...
        call    display
        mov     al,#0x4c        ! ... an 'L' ...
        call    display

done:   mov     al,#0x49        ! display an 'I'
        call    display
        jmpi    0,SECONDSEG     ! start the second stage loader

の部分です。コメントを読めば、何をしているか想像がつきますね。

1.2 2nd boot loader

2nd boot loader が実行を開始すると、 2 番目の "L" という文字が表示されます。 次に 2nd boot loader は、map ファイルの先頭の部分をロードします。 ここには LILO のブートメニューで選択肢として表示されるラベルの名前や、 パスワードなどの情報が記録されています。

この先頭部分の構造は LILO のソースコードにある common.h 中で 以下のように規定されています。

typedef struct {
    char name[MAX_IMAGE_NAME+1];
    char password[MAX_PW+1];
    unsigned short rd_size[2]; /* RAM disk size in bytes, 0 if none */
    SECTOR_ADDR initrd,start;
    unsigned short start_page; /* page at which the kernel is loaded high, 0
                                  if loading low */
    unsigned short flags,vga_mode;
} IMAGE_DESCR;

(この部分に関しては ver.21, 22 とも同じ記述です。 ただし、後述しますが SECTOR_ADDR の構成が 21 と 22 では違います。)

このマップファイル先頭部分のロードが完了すると "O" という文字を コンソールに表示し、指定された待ち時間のあいだ、キー入力をチェックします。

この後、プロンプト表示やキー入力に対する処理を行い、 これから起動するカーネルに対応したアドレスマップを 上記の SECTOR_ADDR initrd,start によって指定された CHS セクターアドレスから ロードし、このマップファイルに記録されているカーネルや initrd ファイルの セクターアドレスを解読して、それぞれをロードしていきます。

これらのディスクまたはフロッピーからカーネルや initrd ファイルをメモリーに ロードする作業は、すべてセクターアドレスを指定して BIOS に実行させます。

必要なセクターのロードがすべて成功した後、カーネルコードに制御を移行して LILO は動作を完了します。

1.3 Option linear

ときどき勘違いされる方がいますが、lilo.conf のパラメータに "Option linear" を追加しても、LILO のブートローダーが ディスクからファイルをロードする時に INT13 AH=4? な Extended BIOS コールを利用するわけではありません。

(注: 以前はここで "option linear" を指定しても LILO の マップファイルにリニアアドレスは格納されない、と書いていたのですが ver 21 と 22 のコードを改めて眺めてみたところ、 ver 21 では 3bytes (=24bits) の領域にリニアセクターアドレスを格納していたことが わかりました。また ver 22 では "option edd" が新設され これを利用すると 4bytes (=32bits) の領域に 32bit のリニアセクター アドレスを格納し、かつ起動時には Extneded BIOS Call を利用する、と いう動作になるようです。)

このオプションは、マザーボードの BIOS が認識するディスクのジオメトリと Linux カーネルの認識するジオメトリが互いに異なる場合、LILO の使う マップファイルにはリニアセクターアドレスを保存しておいて、起動時に 「BIOS が認識するディスクのジオメトリ」を基準とした CHS セクターアドレス に換算し、このアドレスを BIOS に渡してディスクから必要なセクターを ロードするという動作を指定するものです。

このオプションを指定しても、LILO が「1023 シリンダ」を超える領域に アクセスすることは不可能ですので、御注意下さい。

1.4 (New in ver 22) Option edd

このオプションは LILO 22 で新設されたもののようです。CHANGES に よれば Enhanced Disk Drive Support が有効な Extended BIOS の ためのもの、とのこと。

マザーボードもディスクドライブも最近のもので、どうしても 1023 シリンダの壁を超えて起動させたい場合には、試してみると良いかも。

1.5 その他

ちなみに、詳細はまたいつか追加して書くつもりですが Linux カーネルの 先頭 512bytes はカーネルが自前で持っているブートローダーであり、 "make zdisk" で作成したブートフロッピーからの起動ではこれが使われます。

この自前のブートローダーは i386 系の場合 カーネルソースツリーの arch/i386/boot/bootsect.S にあります。

LILO や LOADLIN からの起動では、カーネルのロードが完了するとこの部分 (bootsect) を飛ばして次の setup.S や video.S のコードに制御を移行します。 CPU の動作を 16bit モードから 32bit モードに移行するのは setup.S の中 で実行しています。

これらの実行が終わると次に arch/i386/boot/compressed/head.S が 実行されます。こちらは最初から 32bit モードで実行されることを前提と したコードになっています。この head.S の中にある decompress_kernel() が 圧縮されたカーネル本体を展開します。 head.S の実行は展開されたカーネル 本体に制御を渡して完了します。


2. /sbin/lilo コマンドを実行した時の動作

"lilo" コマンドは別名 map creator (マップ作成ツール) と 呼ばれており、その主な機能は設定ファイル lilo.conf の解読と、その中の指定 およびコマンドライン (オプション) による指定に従って bootloader が起動時に 使用するマップファイルを作成し、その中に必要な Map Descriptor Table を 適切に記録することです。

通常 "lilo" コマンドは lilo.conf を解読して、 使用するカーネルごとに指定された Image ファイル (および、もしあれば initrd ファイル) に対する CHS セクターアドレスを取得し、それを起動時に 使用する Map Descriptor Table のデータ型式にしてマップファイルに保存します。

"lilo" コマンドでファイルからセクターアドレスを 調べる部分は geometry.c の geo_find() にあります。

"lilo" コマンドに -v オプションを複数重ねて起動すると、 マップ作成に使用されたセクターアドレスを観察することができます。

もし Image= で指定したファイルがマウントされていないファイルシステム 上にあると、"lilo" コマンドはそのファイルに対する セクターアドレスを調べることができずにエラーを出します。

なお、起動時に使用する 2nd boot loader のセクターアドレスを 1st boot loader のコード中に書き込むのも "lilo" コマンドの仕事です。


3. 補足

3.1 この文書について

Linux 用のブートローダーとして、この "lilo" を 使う場合が多いのですが、マニュアルでエラーメッセージの意味を確認する 際など、動作を理解しておくときっと役に立つだろうと思ってこの文書を 作成しました。

内容についてはできる限り正確を期したつもりですが、まだまだ間違いや 誤解している個所などあるかもしれません。この文書に対する御意見、 御感想、間違いの指摘などありましたら、著者または JF project まで 御一報頂ければさいわいです。

なお、この文書の配布等については GPL2 に従うものとします。

3.2 MBR 用ブートセレクタについて

個人的な好みですが、"lilo" のインストール先は MBR (Master Boot Record, ハードディスク先頭のブートセクタ) よりも Linux システムのルートパーティションのほうが適していると思います。 ハードディスクの MBR にはより一般的なブートセレクタ、たとえば os-bs, bteasy, extIPL, btsel などをインストールしたほうが トラブルが起きた時の対応などを考慮するとより安心できます。

この中でも特に個人的なお薦めは extIPL です。最近、バージョンアップして拡張領域内の論理領域からも起動可能 になりました。またソース公開であり、かつ Linux 上で make できる (gcc + nasm) 点も見逃せないポイントです。


sgml21html conversion date: Wed Feb 23 10:56:14 JST 2000