loadfile関数

loadfile関数では、Kernel imageのロードを行ないます。loadfile関数では、複数形式のロードをサポートしていて、"#ifdef"によって切り替えられるようになっています。

#define BOOT_ELF    /* ELF形式  imageのロードをサポート */
#define BOOT_AOUT   /* AOUT形式 imageのロードをサポート */
#define BOOT_ECOFFE /* COFF形式 imageのロードをサポート */

i386アーキテクチャではOpenBSD 3.4より、ELF formatがサポートされたので、"#ifdef"の定義にBOOT_ELFが定義されています。ここでは、ELFに限定して解析して行く事にします。

elf形式のkernelをロードするときの主な処理は次のようになります。

  1. 引数から渡されたkernel名のファイルをopenします。
  2. ファイルからELFヘッダ部分を読込みhdr構造体に格納します
  3. ヘッダをチェックしてELF形式ならばelf_exec関数をcallします。ここでKernelのloadが行われます。
  4. 正常に読込まれたらfile descriptorの値を、異常であったなら"-1"を返します。

loadfile関数

ファイルヘッダのhdr構造体定義

最初に、ファイルヘッダの定義を行ないます。定義されるヘッダは次のようになり、hdrはこれらの共有体となります。

BOOT_ECOFFが定義されていればECOFF形式のヘッダ定義
BOOT_ELFが定義されていればELF形式ヘッダ定義
BOOT_AOUTが定義されていればAOUT形式ヘッダ定義

ELFのヘッダ類は64bit用と32bit用の2種類あり、アーキテクチャ毎に切り替えが可能です。これを切り替えるのはELFSIZEの値に依存します。i386の場合、ELFSIZEは32と定義されているので、32bit用ELF定義が有効になります。

Kernelのload

Kernel File Open

boot関数から渡された(第一引数)である、fname(最初のHDDからbootされたなら"/dev/rhd0a:/bsd"が渡されるだろう。)をOpenする。

Kernel Headerの読込み

Kernelのヘッダ部分だけを読込み、変数hdrにセットします。

elf_exec関数をcall

ELF Headerのチェック

関数をcallする前に、Headerが正しいかチェックを行います。チェックするのはELF Header内の配列e_identで定義されるelf ID部分であり、この配列は次のような意味を持ちます。

配列e_identの詳細
変数詳細
e_ident[EI_NIDENT]indexdefine内容
0EI_MAG0マジックNO.0byte目 '\177'
1EI_MAG1マジックNO.1byte目 'E'
2EI_MAG2マジックNO.2byte目 'L'
3EI_MAG3マジックNO.3byte目 'F'
4EI_CLASSバイナリファイルのアーキテクチャ
定義意味
ELFCLASSNONE不正なクラス
ELFCLASS3232bit アーキテクチャを定義
ファイル空間と仮想アドレス空間が 4 ギガバイトまでのマシンに対応します。
ELFCLASS6464bit アーキテクチャを定義
5EI_DATAプロセッサ固有のバイトオーダー指定
定義意味
ELFDATANONE未知のデータフォーマット
ELFDATA2LSBリトルエンディアン
ELFDATA2MSBビッグエンディアン
6EI_VERSIONELF 仕様書のバージョンナンバ
定義意味
EV_NONE不当なバージョン
EV_CURRENT現在のバージョン
7EI_OSABIオペレーティングシステムとABIを識別
8EI_ABIVERSIONABIのバージョンを識別
9EI_PADパディングの始め。これらのバイトは、予約されており、0 にセットされます。
10-15---未定義(0 パディング)

ここでチェックするのは、上の図で背景が赤くなっている部分で、下記のチェックが正常の場合関数が呼ばれます。

  1. e_index[0-3](マジックナンバー)がELFMAG("\177ELF")と一致するか。
  2. e_ident[EI_CLASS](バイナリファイルのアーキテクチャ)が正しいか。
    ( 32bitアーキテクチャーの場合、ELFCLASS32と定義されいます。)
elf_exec関数をcall

チェックが正常ならばelf_exec関数をcallし、ヘッダ以外の部分の読込みを行なう。

elf_exec関数の引数一覧
/* boot 関数からの引数 */
marks[MARK_START] = DEFAULT_KERNEL_ADDRESS;  /* Kernelの最下位アドレス (IN) */
marks[MARK_ENTRY];                           /* プロセスを開始する仮想アドレスを示す(OUT) */
marks[MARK_NSYM];                            /* 1固定(OUT) */
marks[MARK_SYM];                             /* シンボルテーブルの最初(OUT) */
marks[MARK_END];                             /* Kernelの最上位アドレス(OUT) */
marks[MARK_MAX];                             /* */
flags=LOAD_ALL;                              /* 全てのsectionをロード */

fd;                                          /* KernelのFile Descriptor */
hdr.elf;                                     /* ELFのヘッダ */
elf_exec(fd, &hdr.elf, marks, flags);

終了処理

正常終了の場合

読込んだkernelのサイズを表示し、ファイルディスクリプタを戻値として、boot関数に戻ります。

reading boot ....
Probing:pc0 com1 com2 apm pci mem[639K 253M a20=on] disk:fd0 hd0
>>OpenBSD/i386 BOOT 2.02
boot>
booting hd0a:/bsd: 4059136+838332 [58+204340+181750] = 0x56cfd0
	  
異常終了の場合

openしているファイルをcloseして、(-1)を戻値として、boot関数に戻ります。

Last modified: Sat Jan 26 00:43:02 2008 JST