PDP-11が起動し最初にディスクから読み出されるコードは、ディスクの先頭に書かれているブートプログラムです。そのソースコードは、/usr/mdec/rpuboot.s です。UNIX V6だと、このプログラムがUNIXカーネルをディスクから読み出して実行するのですが、V7では、/bootを読み込んで実行します。そしてbootがUNIXカーネルを読み込んで実行します。bootのソースコードは、/usr/src/cmd/standaloneにあります。
ブートプログラムはアセンブリ言語で書かれています。コードのメインの部分を見ていきます。
/ now start reading the inodes / starting at the root and / going through directories 1: mov $names,r1 mov $2,r0 / ルートディレクトリのinode番号 1: clr bno jsr pc,iget tst (r1) / namesの終端か beq 1f 2: jsr pc,rmblk / br start / rmblkが正常の終了の場合はスキップ mov $buf,r2 / r2 = buf[] 3: mov r1,r3 / r3 = names[] mov r2,r4 / r4 = buf[] add $16.,r2 / r2 = 次のディレクトリエントリ tst (r4)+ / inodeは空か beq 5f 4: cmpb (r3)+,(r4)+ / ファイル名の比較 bne 5f cmp r4,r2 / blo 4b mov -16.(r2),r0 / r0 = inode番号 add $14.,r1 / br 1b 5: cmp r2,$buf+512. / blo 3b / buf[]の最後でない br 2b / buf[]の最後 / read file into core until / a mapping error, (no disk address) 1: clr r1 / r1 = 0 1: jsr pc,rmblk br 1f mov $buf,r2 2: mov (r2)+,(r1)+ cmp r2,$buf+512. blo 2b br 1b 1: clr r1
6−9行で、ルートディレクトリのinodeを読み込んでいます。igetは、r0で指定した番号のinodeをinode[]にコピーします。
13行は、rmblkでルートディレクトリをbuf[]に読み込みます。15行目からは、1エントリごとにファイル名とnames[]を比較します。
一致した場合は、27行でinode番号をr0に読み込みます。r1に14を足して8行目に飛び、igetでファイル名が一致したファイルのinodeを読み込みます。
11行でファイル名が終わっていることを確認し、38行目からinodeのdi_addr[]に沿ってファイルをメモリーに読み込んでいきます。
次のリストは igetです。
/ get the inode specified in r0 iget: add $15.,r0 mov r0,r5 ash $-3.,r0 / r0 = (r0 + 15) / 8 bic $!17777,r0 / r0 &= 0x01fff mov r0,dno clr r0 jsr pc,rblk bic $!7,r5 / r5 &= 0x0007 ash $6,r5 / r5 *= 64 add $buf,r5 / r5 += buf mov $inod,r4 1: mov (r5)+,(r4)+ cmp r4,$inod+64. blo 1b rts pc
3-6行でinode番号をinodeが存在しているブロック番号に変換し、9行でそのブロックをbuf[]に読み込んでいます。
10-12行で目的のinodeのbuf[]内でのオフセットを求め、13ー17行でinode[]にコピーしています。
次のrmblkは、bnoで指定されたブロックを、inode内のdi_addr[]に従ってbuff[]に読み込みます。
/ read a mapped block / offset in file is in bno. / skip if success, no skip if fail / the algorithm only handles a single / indirect block. that means that / files longer than 10+128 blocks cannot / be loaded. rmblk: add $2,(sp) / リターンアドレスを2増やす mov bno,r0 cmp r0,$10. blt 1f mov $10.,r0 / 間接参照 1: mov r0,-(sp) / asl r0 / add (sp)+,r0 / r0 = bno * 3 add $addr+1,r0 / r0 += di_addr + 1 movb (r0)+,dno movb (r0)+,dno+1 / dno = ブロック番号の下位2バイト movb -3(r0),r0 / ブロック番号の上位1バイト bne 1f tst dno beq 2f 1: jsr pc,rblk / ブロック読み込み mov bno,r0 inc bno sub $10.,r0 blt 1f / 直接参照ならリターン ash $2,r0 / r0 *= 4 mov buf+2(r0),dno / dno = ディスク番号の下位2バイト mov buf(r0),r0 / r0 = ディスク番号の上位2バイト bne rblk tst dno bne rblk 2: sub $2,(sp) 1: rts pc
ブロック番号が0から9までは直接参照で10は間接参照になりますが、コメントにあるとおり、2重間接参照には対応していません。
13行でブロック番号10以上は、間接参照に対応するため10に固定しています。
15-18行で、ブロック番号からdi_addr[]内でのディスク番号下位2バイトのオフセットを求めています。
22-24行は、ブロック番号が0だった場合、rmblkを呼び出した直後のアドレスにリターンします。
26-30行で、ブロックを読み込んだ後、直接参照の場合はリターンします。
31行目からは間接参照の処理で、29行で10引かれたディスク番号を4倍しオフセットを求め、先に読み込んだブロックからブロック番号を取り出します。
34-36行で、番号が0でなければブロックを読み出します。
ブロックが正常に読み込まれた場合は、9行でリターンアドレスが+2されているので、rmblkを呼び出した次の命令をスキップします。
これで、UNIXが起動する第一段階を追いかけられました。次は、2段階目の/bootになります。
0 件のコメント:
コメントを投稿