Open5

『オペレーティングシステム - 設計と実装 (第3版)』 を読む。第8日目。プロセス 5(ブートモニタ)

horie-thorie-t

boot(void)

void boot(void)
/* Load Minix and start it, among other things. */
{

	/* Initialize tables. */
	initialize();

	/* Get environment variables from the parameter sector. */
	get_parameters();

	while (1) {
		/* While there are commands, execute them! */

		while (cmds != nil) execute();

		/* The "monitor" is just a "read one command" thing. */
		monitor();
	}
}

boot()は以下の処理を行う。

  1. initialize()関数を呼び出し初期化をする。
  2. get_parameters()パラメータセクタ(ブートストラップの次のセクタ)からパラメータを読み込む。
  3. パラメータにあるコマンドをexecute()を呼び出して実行(OSの起動も含む)する。
  4. OSが終了したら、monitor()を呼び出し、プロンプト(d0p0s0> 等)を出力してコマンドを読み込む。
horie-thorie-t

initialize(void)

initialize()は以下の処理を行う。

  1. ブートモニタを低メモリ(mem[0])の上端に移動する。低メモリとは通常640KiB未満のメモリのことだ。
  2. カーネルに渡されるメモリマップからブートモニターを削除する。これにより、カーネルはブートモニターが占有するメモリを割り当てることができなくなる。
  3. bootdevを初期化する。

ブートモニタの移動

	/* Copy the boot program to the far end of low memory, this must be
	 * done to get out of the way of Minix, and to put the data area
	 * cleanly inside a 64K chunk if using BIOS I/O (no DMA problems).
	 */
	u32_t oldaddr= caddr;
	u32_t memend= mem[0].base + mem[0].size;
	u32_t newaddr= (memend - runsize) & ~0x0000FL;

(memend - runsize)でコピー先の末尾が640KiBになるように仮の開始アドレスを計算する。~0x0000FL0xFFFFFFF0Lであり、論理積を取ってセグメントの16バイトアライメントを取っている。

#if !DOS
	u32_t dma64k= (memend - 1) & ~0x0FFFFL;


	/* Check if data segment crosses a 64K boundary. */
	if (newaddr + (daddr - caddr) < dma64k) newaddr= dma64k - runsize;
#endif

データセグメントが64KiBバウンダリをまたぐ場合は再調整する。

	/* Set the new caddr for relocate. */
	caddr= newaddr;

	/* Copy code and data. */
	raw_copy(newaddr, oldaddr, runsize);

raw_copy()(アセンブラで定義)を呼び出して、コードを低メモリの上端にコピーする。

	/* Make the copy running. */
	relocate();

relocate()(アセンブラで定義)を呼び出して、コピー先で続きを実行する。

カーネルに渡されるメモリマップからブートモニターを削除

	if (mon_return = (mem[1].size > 512*1024L)) mem[0].size = newaddr;

拡張メモリがある場合、つまり(mem[1].size > 512*1024L)の場合は、mem[0]からブートモニタのメモリの領域を除く。

	mem[0].base += 2048;
	mem[0].size -= 2048;

BIOS割込みベクタや、BIOSのデータ領域、および古いカーネルのヘッダ領域のために、開始アドレスを2KiBずらす。

bootdevを初期化する

	/* Find out what the boot device and partition was. */
	bootdev.name[0]= 0;
	bootdev.device= device;
	bootdev.primary= -1;
	bootdev.secondary= -1;

で初期化しておいて、get_master(master, table, masterpos)の結果を使って値を設定していく。

	raw_copy(mon2abs(&lowsec),
		vec2abs(&rem_part) + offsetof(struct part_entry, lowsec),
		sizeof(lowsec));

他にも、アクティブパーティションの開始セクタをC言語の領域にコピーする。(rem_partはアクティブパーティションのパーティションテーブルのエントリ位置。lowsecはパーティションの開始セクタ)

horie-thorie-t

get_parameters(void)

// 略
	b_setvar(E_SPECIAL|E_VAR|E_DEV, "rootdev", "ram");
// 略
	/* Default hidden menu function: */
	b_setenv(E_RESERVED|E_FUNCTION, null, "=,Start MINIX", "boot");

のように、変数、環境変数を設定し、

	if ((r= readsectors(mon2abs(params), lowsec+PARAMSEC, 1)) != 0) {

アクティブパーティションの2番目のセクタから起動用のコマンド文字列を取得する。

	acmds= tokenize(&cmds, params);
// 略
	(void) tokenize(acmds, ":;leader;main");

コマンド文字列は、tokenize()でトークン化され、cmdsにリンクリストで追加される。

horie-thorie-t

execute(void)

cmdにコマンドがある時はexecute()が呼ばれ、コマンドが実行される。

	name= cmds->token;
	res= reserved(name);

で、tokenが"boot"の場合、R_BOOTがresに代入される。

		switch (res) {
		case R_BOOT:	bootminix();	ok= 1;	break;

R_BOOTの場合にbootminix()(bootimage.cにある方。このファイルにある方ではないので注意)が呼ばれ、MINIXが起動する。