Linuxの起動を追ってみる(1)
Linuxカーネルのソースコードを読み始めて、2週間弱経過したのでちょくちょくまとめていこうと思う。
記念すべき第1回は、Linuxがどのように起動されるかを簡単な流れとしてみてみることにする。
詳細な部分の解析をきちんと行っていないため、不満点もあるかもしれないが、参考になれば幸いである。
Linuxのバージョンは2.6.15とし、アーキテクチャはx86_64とする。
簡単な流れとしては以下のようになっている。
- linux/arch/x86_64/boot/bootsect.Sは最初に実行されるプログラム
- linux/arch/x86_64/boot/setup.SでGDTとIDTの設定、プロテクトモードへの移行を行う
- linux/arch/x86_64/kernel/head.Sは64bitモードへの移行、GDTとIDTの再設定を行う
- linux/init/main.cでLinuxの各部分の初期化をする
まずBIOSによって自動的にプログラムが読み込まれる、ブートセクタのプログラムは、linux/arch/x86_64/boot/bootsect.Sにある。
最後に記述されている以下の部分はブートセクタの正当性を示すシグネイチャである。
boot_flag: .word 0xAA55
次に実行されるプログラムstart()は、linux/arch/x86_64/boot/setup.Sに記述されている。
このプログラムではGDTとIDTの設定、プロテクトモードへの移行を行っている。
GDTの設定値は、824行目の以下の部分である。
# Descriptor tables gdt:
プロテクトモードへの移行、GDTとIDTの設定は、rmodeswitch_normalラベルからの一連の処理で行われている。
そのことを示すコメントが540行目にある。
# Now we want to move to protected mode ... cmpw $0, %cs:realmode_switch jz rmodeswitch_normal (中略) rmodeswitch_normal: pushw %cs call default_switch
default_switchを見ていくと、GDTとIDTの読み込みを行っている部分が、end_move_selfラベルの646行目と653行目にある。
end_move_self: lidt idt_48 (中略) lgdt gdt_48
そして最後にプロテクトモードに移行する以下の記述が657行目から書かれている。
A20信号線はイネーブルさせることで、リアルモードからプロテクトモードへと移行する。
# that was painless, now we enable a20 (中略) movb $0xD1, %al outb %al, $0x64 (中略) movb $0xDF, %al outb %al, $0x60
続いて、64bitモードへの移行を行うために、linux/arch/x86_64/kernel/head.Sのstartup_32()プログラムが実行されるが、詳細はよくわかっていない。(というかまだ64bitモードへの移行についてはよくわからない)
また、GDTやIDTの再設定を行っている。
head.Sに書かれたプログラムは最終的に、linux/init/main.cにある、start_kernel()を呼び出す。
ここでスケジューラや割り込み、メモリ管理、ファイルシステムといったほとんどのLinuxの機能を初期化する。
以上、Linuxの起動の流れをブートセクタから初期化まで、簡単ではあるが追ってみた。
Linuxのバージョンもついに3.3となり、今となっては古い情報ではあるが、どのように処理されているかを知る分には重要であると考え、書いてみた。
詳細な解説は、解析が進み次第、紹介していこうと思う。
あと、電車の中でも、人を待っているちょっとした時間でもソースコードを読めるようになったので、LXRはカーネルのソースコードを読む上ではすばらしいサイトであると思う。