170 likes | 341 Views
Linux カーネル読書会. ● システムの起動 □ Linuxカーネルの起動 ☆ エントリポイントとCPUの初期化 ☆ カーネル資源の初期化 ☆ initプロセスの起動 ●システムの終了 ☆ システムの正常終了 ☆ システムの異常終了. ■ システムの起動 Linux カーネルの起動 - ブートに必要なファイル. LILO ( LInux LOader )を使用して Linux をブートするときに必要になるファイル ●プライマリブートローダ ブートセクタまたはパーティションテーブルのブートセクタにある。 ●カーネルイメージ
E N D
Linuxカーネル読書会 ●システムの起動 □ Linuxカーネルの起動 ☆ エントリポイントとCPUの初期化 ☆ カーネル資源の初期化 ☆ initプロセスの起動 ●システムの終了 ☆ システムの正常終了 ☆ システムの異常終了
■システムの起動 Linuxカーネルの起動 - ブートに必要なファイル LILO(LInuxLOader)を使用してLinuxをブートするときに必要になるファイル ●プライマリブートローダ ブートセクタまたはパーティションテーブルのブートセクタにある。 ●カーネルイメージ 通常はvmlinuzまたはvzImageという名前になっている。 ●マップファイル デフォルトコマンドライン、ディスクリプタテーブル、RAMディスクイメージとカーネ ルイメージ、イニシャルグリーティングメッセージのセクタ情報、キー変換テーブル などの情報が入っている。 ●LILOブートローダー boot.bという名前で、first.Sとsecond.Sのバイナリコード。 カーネルイメージの内容 カーネルの オリジナルブートローダー フロッピィディスクで起動する 場合のみ使用される。 LILOでは、書き込まれている パラメータだけを使用。 512Byte カーネルの セットアップコード カーネル本体
Linuxカーネルの起動 - LILOブートローダーLinuxカーネルの起動 - LILOブートローダー LILOがインストールされている場合、マシンの電源をONにすると「LILO」と表示される。 ロードが失敗した場合、表示されているメッセージでエラーを判断できる。 メッセージなし LILOがまったくロードされていない。LILOがインストールされていないか LILOが入っている領域がアクティブになっていない。 LI ローダの最初のステップにより、第2ステップをロードできたが、第2ステッ プの処理が失敗している。誤ったジオメトリもしくはローダを再インストール せずに、boot.bファイルを移動したことが考えられる。 LIL ローダの第2ステップが開始されたがマップファイルから記述子テーブル が読み取れない。誤ったジオメトリもしくは物理的な欠陥が考えられる。 LIL? ローダーの第2ステップが誤ったアドレスにロードされた。原因はLIの時と 同じ。 LIL- 記述子テーブルに欠陥がある。誤ったジオメトリもしくはローダーを再イン ストールしないでマップファイルを移動したことが考えられる。 LILO ローダー全てが正常にロードされた。
Linuxカーネルの起動 - エントリポイントとCPUの初期化Linuxカーネルの起動 - エントリポイントとCPUの初期化 LILOによってメモリ上にカーネルが展開されると、カーネルの先頭である stextエントリ に制御が渡る。 arch/i386/kernel/head.s ENTRY(stext) ENTRY(_stext) startup_32: 既知の値にセグメントをセット ページテーブルの初期化 ページングを有効 BSS領域をクリア 32ビットシステムの設定 call SYMBOL_NAME (start_kernel) L6: jmp L6 Init/main.c start_kernel() { : : }
Linuxカーネルの起動 - カーネル資源の初期化Linuxカーネルの起動 - カーネル資源の初期化 start_kernel () は、カーネルの様々な機能やデータ構造の初期化を行うルーチンであり、 初期化プロセスのコンテキストで実行される。初期化処理が終了すると init プロセスを生成 し、アイドルプロセスとなる。 ブートから渡されたパラメータの解析を行う。 Linuxカーネル自体が受け付けるパラメタ以外 の解析は、各種ドライバが以下の形式で登録 した関数を呼び出すことで実現する。 これらで解決できないオプションは、/etc/initを 起動する時の引数として渡す。 Setup_baa(char *line) { lineに渡されたオプションの解析 } __setup (“hoge=“, setup_baa); start_kernel () Linux起動メッセージの出力 <各種初期化処理> trap_init (); init_IRQ (); sched_init (); time_init (); : parse_options (); : smp_init (); init プロセス起動 kernel_thread (init) アイドルプロセスになる cpu_idle ()
Linuxカーネルの起動 - initプロセスの起動 即座に /etc/init が動作を開始するわけではなく、以下の関数を実行するカーネルスレッド として実行される。init はファイルシステム上の init コマンドを実行する前に、カーネル初期 化処理の続きである do_basic_setup () を実行する。 init () カーネルの初期化処理 do_basic_setup () 標準入出力用にコンソール /dev/console をオープンする。 if (BOOTでコマンドが指定されている) BOOTで指定されたコマンドをexecする initコマンドのexec if (init コマンドのexecに失敗)シェル /bin/sh をexecする do_basic_setup () (各種初期化処理) バスの初期化(PCIバスなど) ネットワークデータ初期化 sock_init () 各種機能の初期化(各種デバイスドライバの初期化) do_initcalls() 各種ファイルシステムの登録 filesystem_setup () PCカードの初期化 init_pcmcia_ds() rootファイルシステムのマウント mount_root () devfsのマウント mount_devfs_fs() ※devfsはinodeとdentryだけの実態の無いファイルシステム) if (RAMディスクがROOTの場合) スレッドで /linuxrc を実行 本物のrootをマウントし直す
初期化 プロセス idleプロセス IPL /boot/vmlinuz 起動 initプロセス exec /etc/init /etc/inittab rcファイル実行
各種初期化関数を do_initcalls() で呼び出されるようするには、以下のようにする必要が ある。例えば、システムコール起動時に init_foo() という関数が呼び出されるようにするに は、その機能の中で以下のように宣言する。自動的に __initcall_start テーブルに登録され システム起動時に do_initcalls () から呼び出される。 init_foo () { foo 機能の初期化; } __initcall (init_foo); ただし、モージュールとしてコンパイルできるものは、__initcall (init_foo) の代わりに、 module_init (init_foo) と宣言する。 ※Linux カーネルへのスタティックリンクとしてコンパイルする場合には、__initcall (init_foo) として置き換えられる。 ※モジュールとしてコンパイルする場合には、init_module () に置き換えられ、モジュールの ロード時に初期化関数として呼び出される。
初期化 プロセス idleプロセス IPL /boot/vmlinuz 起動 linuxrc initプロセス 起動とexec inirrdマウント exec 本当のroot再マウント /etc/init /etc/inittab rcファイル実行
/etc/inittabの例 id:3:initdefault: si::sysinit:/etc/rc.d/rc.sysinit l0:0:wait:/etc/rc.d/rc 0 l1:1:wait:/etc/rc.d/rc 1 l2:2:wait:/etc/rc.d/rc 2 l3:3:wait:/etc/rc.d/rc 3 l4:4:wait:/etc/rc.d/rc 4 l5:5:wait:/etc/rc.d/rc 5 l6:6:wait:/etc/rc.d/rc 6 ud::once:/sbin/update 1:12345:respawn:/sbin/mingetty tty1 2:2345:respawn:/sbin/mingetty tty2
initコマンド /etc/inittabを参照し、定義された処理を実行 fsck /etc/rc.sysinit mount Level 1 /etc/rc.d/rc1.d/* Level 2 /etc/rc.d/rc2.d/* Level 3 /etc/rc.d/rc3.d/* Level 5 /etc/rc.d/rc5.d/* mingetty /dev/ttyS1 mingetty /dev/ttyS2 mingetty /dev/ttyS3
マルチプロセッサシステムの起動 マルチプロセッサシステムであっても、システムの起動は、シングルプロセッサマシンとして 動作している。2つめ以降のCPUの起動は、1つめのCPUがカーネル初期化関数である start_kernel () の最後に呼び出す smp_init () で行われる。 最初はシングルプロセッサ マシンとして起動する CPU 0 CPU 3 start_kernel() smp_init() CPU 2 CPU 1 CPU起動
smp_init () では、各CPU専用の初期化プロセスを生成する。これらの各CPU専用の初期化 プロセスは、start_secondary () から実行を開始するようにコンテキストを初期化する。 各CPUの初期化プロセスを生成後、ハード的に各CPUの起動を行う。 start_kernel () (各種初期化処理) : : smp_init (); init プロセスを起動(kernel_thread (init,) ) smp_init () 他のCPU初期化処理用にプロセスを生成(task_structを初期化して init_tasksテーブルに登録)し、他CPUをsmp_boot_cpus () で起動する。 2つめのCPUの初期化処理と smp_commence () で同期をとる。 起動された2つめ以降のCPUも、1つめのCPUと同様に、Linuxカーネルテキストの 先頭stextから実行を開始する。 1つめのCPUの場合は、start_kernel () を呼び出すが、2つめ以降のCPUは initialize_secondary () を呼び出す。 initialize_secondary () は、1つめのCPUが、smp_boot_cpus () で生成した初期化 プロセスのコンテキストをロードする。
コンテキストのロードを行った直後、2つめ以降のCPU上では、初期化プロセスがコンテキストのロードを行った直後、2つめ以降のCPU上では、初期化プロセスが start_secondary () から実行を開始する。初期化プロセスの処理が終了すると、そのまま アイドルプロセスへと変化する、その後、スケジューラからプロセスが割り当てられるのを 待ち続ける。 stext () { : if (2つめ以降のCPUの場合) initialize_secondary (); else /* 1つめのCPUの場合 */ start_kernel (); } /* ここには戻ってこない */ start_secondary () { CPUコンテキストの初期化 cpu_init () CPU固有の初期化処理 smp_callin () (ローカルタイマの起動なども、ここで行う) 1つめのCPUの初期化完了と同期をとる(ビジーウェイト) このCPU上で動くアイドルプロセスとなる cpu_idle ()
CPU 0 start_kernel () smp_init () CPU 1 CPU 2 warm start initialize_secondary () initialize_secondary () start_secondary () start_secondary () idle.. idle.. idle..
システムの終了 - システムの正常終了 Linuxシステムは、rebootシステムコール によりシステムを停止させることができる。 システムの停止もしくはリブート処理時には、各種デバイスドライバの終了処理ルー チン notifier_call_chain () が呼び出される。終了処理の必要なデバイスは、デバイスドライバ の初期化時に register_reboot_notifier () を利用してドライバ処理ルーチンを登録しておく。 sys_reboot () switch (コマンド) case システム停止(LINUX_REBOOT_CMD_HALT): ドライバ終了処理 notifier_call_chain () システム停止処理 machine_power_off () case システム電源断(LINUX_REBOOT_CMD_POWER_OFF): ドライバ終了処理 notifier_call_chain () システム停止処理 machine_power_off () case システム再起動処理(LINUX_REBOOT_CMD_RESTART) : ドライバ終了処理 notifier_call_chain () システム再起動処理 machine_restart () ※システム再起動要求では、再起動時に実行するコマンドを指定することも可能 ※CTRL+ALT+DELによるリブートと同様な動作を行う仕組みは ctrl_alt_del () として提供されている。
システムの終了 - システムの異常終了 なんらかの原因により、Linuxカーネルがフリーズ(処理継続不可能)すると、panic () が 呼び出され、システムを停止させる。この場合、ドライバの終了処理は呼び出されない。 panic () パニックメッセージの表示 可能であれば、バッファキャッシュの書き出しを試みる sys_sync () SMPの場合、他CPUを強制終了させる smp_send_stop () if (再起動指定の場合) システム再起動 machine_restart () システム停止