usr - みる会図書館


検索対象: 386BSD カーネルソースコードの秘密
378件見つかりました。

1. 386BSD カーネルソースコードの秘密

第 2 章アセンブリ言語によるエントリとプリミティブ ( i386/locore. s) [ Fi1e : /usr/src/kerne1/kern/i386/10core . s , line : 139 の ] 2 : movl sti $IRNET IIRSCLK, _cpl #define DONET(isr , tmp) / * ネットとソフトクロックをマスク * / / * ソフトウェア割り込みを探す * / \ bsfl btrl incl ca11 testl Jne ISr If tmp If tmp isr ; \ _cnt + V_SOFT ; / *_netintr( , tmp isr ; \ ISr lb ; \ , 4 ) DONET(%ebx, %eax) 9b JIIIP ト割り込みをネストさせることができる。ネットワークソフトウェア割り込みがあるのは、まさにこの ロックされない。こうすれば、割り込みをプロックしてバケットを取り損なうことなく、連続したバケッ と、このソフトウェア割り込みがチェックされてプロトコル処理が行われる。他のバケットの到着はプ トワークバケットドライバによってエンキューされる。割り込みから戻って優先順位 0 のレベルに帰る ネットワークソフトウェア割り込みは、バケットの到着によってトリガされるが、そのバケットはネッ り込みの処理が終わったら、ソフトウェア割り込みのマスクをクリアして、この処理は終了する。 のうち、現在システムが実装しているのは、 IP バケット処理だけである。ネットワークソフトウェア割 ビットがセットされている、すべてのプロトコルサービス要求を、順にチェックする。ただし、これら DONET マクロは、 ( 前に示したコードでサンプルした ) ネットワークソフトウェア割り込みレジスタに ア割り込みを処理しないようにして、必ず今回の割り込みコード自身で処理するためである。 るソフトウェア割り込みレベルをマスクするのは、これ以降のネスト割り込みが、これらのソフトウェ キューイングされている次のバケットをサービスできるようにする。クロックとネットワークに対応す ウンタの値をインクリメントし、プロトコルを処理するネットワーク割り込みハンドラを呼び出して、 タ ( isr) のビットをチェックする。もしビットがあれば、それに対応するソフトウェア割り込み受付カ DONET マクロは、ネットワーク割り込みサービスルーチンに対応する指定の割り込みサービスレジス 98 / * softclock ( ) のハードウェア割り込みをシミュレートする * / 3 : [ Fi1e : /usr/src/kerne1/kern/i386/10core . s , line : 14 効 9 ] ためである。

2. 386BSD カーネルソースコードの秘密

%al , %dh ・ $IO_ICU2 ・ lmp ca11 sti WRPOST outb movb outb movl pu s 1 movb sh11 pushl movl mOVW movw movw pu sh1 pu s 1 outb outb movb outb movb outb movb $ 2 , %al NOP mo Vb %al , %al, $ 工旡工 CUI X62 , %al 2.6 周辺デバイス割り込みとは何か / * ISR を保存 * / \ / * なるべくはやく * / \ / * IRR をセレクト * / \ / * 次に、なるべくはやく EOI を送り * / \ inservice bit をクリアする * / \ $ ( の x6 引 (unit-8) ) , %al ・ / * 同じく、なるべくはやく * / \ %al, $ 工 0 ーエ CUI %al, $ 工 0 ーエ CU2 %ds $ 8 , %edx ; \ %eax ; \ -cpl, %eax ; \ %ax, %es %ax , %ds $KDSEL , %ax %es —imen , %ax %eax,-cpl mask , %ax %edx ; \ $unit , %dl %al , $ 工 0 ーエ CU2 + 1 %al, $ 工 0 ーエ CUI + 1 / * EOI で inservicebit をクリア * / \ / * カーネルのセグメントをロード * / \ / * 現在の DS と ES を保存して * / \ / * 書き込みを強制 (writepost) * / \ —isa—strayintr ; \ common_int_return はカスケード割り込みをリセットするため、第 2 ICU に送るのは、これに対応する「インサービス」ビッ 前のマクロとの、もうひとつの違いは、 EOI 応答を両方の ICU に送る点である。第 1 ICU に送るの れる。 ルーチンに渡される ( 「インサービス」レジスタ用の ) 16 ビットフィールドのうち、高位 8 ビットに置か ICU の ISR を取得する。統一性をとるため、第 21CU の ISR から得られる ISR のビットは、 INTSTRAY2 この INTSTRAY2 マクロは、前のマクロと同じ機能だが、こちらのマクロは第 2 ICU を参照し、第 2 [ Fi1e : /usr/src/kerne1/kern/i386/10core . s , line : 1168 ] トをクリアするためである。 IDTVEC (intrØ) IDTVEC ( intrl) IDTVEC ( intr2) IDTVEC ( intr3) IDTVEC (intr4) IDTVEC (intr5) IDTVEC (intr6) 工 NTRSTRAYI ( の , 工 NTRSTRAYI ( 1 , 工 NTRSTRAY 1 ( 2 , INTRSTRAYI ( 3 , 工 NTRSTRAY 1 ( 4 , INTRSTRAYI ( 5 , INTRSTRAYI ( 6 , -highmask , -highmask , -highmask , -highmask , -highmask , -highmask , -highmask , 1 ) 2 ) 3 ) 4 ) 5 ) 6 ) 91

3. 386BSD カーネルソースコードの秘密

第 2 章アセンブリ言語によるエントリとプリミティブ ( i386/locore. s) い番号。プライマリ ICU の場合、 IRQ7 ) に割り当てられる。この INTSTRAY マクロの目的は、この情 報を捕獲し、より高いレベルのルーチンに、この割り込みが本来このユニットの他の割り込みべクタに 相当するものかどうかを判定してもらうことにある。 次に、 ICU のポートを読む場合のデフォルトである割り込み要求レジスタ (IRR) を、再び選択する。 こうしておけば、いつでも割り込み要求のラインを監視して、たとえマスクされている割り込みでもア クテイプな割り込みを検出することができる * 35 。 次の割り込みを受け付けられるように、 ICU に EOI(endofinterrupt) 応答を送り、その割り込みに 対応する「インサービス」ビットをクリアさせる。データおよび工クストラセレクタ ()s と (s) の内容 をセープし、これらにカーネルのデータセレクタをロードして、割り込みレベルのコードがデータ参照 と文字列命令を実行できるようにする。 現在の割り込み優先度レベルのマスクをスタックに保存し、「インサービス」レジスタの内容と割り込 みべクタ番号を合成した別のワードを、迷い割り込みハンドラのための引数としてストアする。現在の 割り込みマスク ( cpl ) の内容を、この割り込みのための現在のマスクに書き換えて、割り込みハンドラ の処理中に割り込みの再入が起こらないようマスクするため、両方の ICU のレジスタにその値を書き込 む。そして割り込みを許可する前にマスクが必ず更新されるように、ライトボストを行う。これによっ て割り込みのネストが許可される。マスクされていない、より優先順位の高い割り込みは、このマクロ の外の高いレベルのコードで実行されている現在の割り込み処理よりも優先して実行される。 割り込みが自分自身をマスクするので、 16 レベルより多くの割り込みネストを許可しないのは当然で ある。平均的な PC には 8 個以下の周辺デバイスしかないので、この程度のネストでも大抵の用途には 十分である。 割り込みを許可してこのマクロを終了すると、迷い割り込みハンドラ * 36 を呼び出す。そして割り込み リターン共通コードにジャンプすることによって、プロセッサはカーネルモードから出て、割り込みが $ 3 , %al 発生した元の場所に制御を戻す。 [ Fi1e : /usr/src/kerne1/kern/i386/10core . s , ・ 1 の 79 ] line . #define INTRSTRAY2 (unit , mask , pushl pushl pushal NOP movb outb NOP inb $ の $T_ASTFLT ; \ offst) \ 8259 のリカバリ ー待ち * / \ / * ISR を選択 * / \ ( 8259 ユニット # 2 ) * / \ / * 8259 のリカバリー待ち * / \ / * ISR をセレクト * / \ この機能はまだ完全には実装されていない。 %dl , %dl ・ 工 CU2 , %al, $IØ-ICU2 $ 工 0 ー %al * 35 本システムでは、 90 * 36 これは C 言語で書かれている。バスデバイスドライバ、 isa. c を参昭

4. 386BSD カーネルソースコードの秘密

7.1 プロセス保護機構 . kern/cred. c [ Fi1e : /usr/src/kernel/kern/cred. c , line : 292 ] if ( (ngrp = uap->gidsetsize) > NGROUPS-MAX) return (EINVAL) ; サポートされる補助グループの数は固定の数に限られている。 もしこのグル の数が、その値を超えていたら、エラー (EINVAL) を返す。 [ FiIe : /usr/src/kernel/kern/cred. c , line : 296 ] ープ集合の補助グループ if (error = copyin(), (caddr-t)uap->gidset , (caddr-t)groups , に置く。この処理でエラーが発生したら (EFAULT) 、 ューザープログラムからグループ集合を取得して、この関数のフレーム上に確保した一時的なバッファ return (error) ; ngrp * sizeof (groups [ の ] ) ) ) システムコ [ Fi1e : /usr/src/kernel/kern/cred. c, line : 3 の 1 ] pc = modpcred(p) ; pc—>pc—ucred—>cr-ngroups = ngrp ; / * int 型からⅵ d ー t 型に変換 * / for ()p = pc—>pc—ucred¯>cr-groups , 1p *gp 十十 return ( の ; groups ; ールは終了する。 ngrp- 新しいグループ集合を入手したら、 modpcred() 関数によってプロセス証明の共有をなくし、新しい 補助グループ集合によってユーザー証明を更新 * 24 して、リターンする。 7.1.18 groupmember() とは何か groupmember(gid—t gid, const struct ucred *cred) int [ Fi1e : /usr/src/kernel/kern/cred. c , line : 312 ] である。 groupmember() は指定のグループ ID について、指定のユーザー証明を調べ、真か偽を返す。 groupmember() は、グループが特定のユーザー証明のメンバかどうかを判定する、カーネル内部関数 * 24 BSD の整数配列から POSIX 補助グループ型への変換。 379

5. 386BSD カーネルソースコードの秘密

第 4 章カーネル内部サービス (kern/config. c 、 kern/malloc. c) [ Fi1e : /usr/src/kernel/kern/config. c , line : 714 ] panic ("devif-mmap") ; / * 未実装の型 * / 4.3.29 devif-strategy() とは何か キャラクタデバイス型が見つからなければ、パニックを起こし、未実装の型に遭遇したことを示す。 216 if (dif = blkmajtodevif [major] ) major く sizeof blkmajtodevif / sizeof blkmajtodevif [ ) { if (typ = = BLKDEV & & [ Fi1e : /usr/src/kernel/kern/config ・ c , line : 733 ] を返す。 ら、バッフアポインタについて strategy ( ) メソッドを呼び出す。そうでなければ、エラ—(ENODEV) デバイスの型が BSD UNIX のキャラクタデバイスで、デバイスインターフェイスが割り当てられていた return (ENODEV) ; return ( (dif->di-strategy) (bp) ) ; chrmaj todevif [maj or] ) if (dif major く sizeof chrmajtodevif / sizeof chrmajtodevif [ ] ) { if (typ = = CHRDEV & & [ Fi1e : /usr/src/kernel/kern/config. c , line : 724 ] ◆ 4.3.29.1 devif_strategy() の実装 ないことを示す工ラー (ENODEV) である。そうでなければ成功を示す値を返す。 が返す工ラーは、 strategy() ルーチンからのエラー値か、あるいは対応するデバイスが実装されてい devif-strategy() の引数は 2 つ、デバイス型と、バッファ構造体へのポインタである。この関数 devif—strategy (devif—type—t typ , struct buf *bp) { i nt [ FiIe : /usr/src/kernel/kern/config ・ c , line : 718 ] インタを見つけ、そのデバイスの strategy() メソッドを呼び出す。 埋め込まれているデバイスフィールドを参照することによって適切なデバイスインターフェイスへのポ デバイスドライバ strategy() ルーチンを探して呼び出す。 devif_strategy() は、バッファ引数に devif-strategy() はバッフアポインタに埋め込まれて指定されたデバイスに割り当てられている

6. 386BSD カーネルソースコードの秘密

第 3 章 CPU 固有のプリミティブ (i386/trap. c 、 i386/cpu. c) ◆ 3.1 .3.1 trapexcept() の実装 [ FiIe : /usr/src/kerne1/kern/i386/trap. c , eip = tf—>tf-eip; eflags = tf—>tf—eflags ; これ : 467 ] 的な変数に保存する ( これらは上書きされるので ) 。 あとでフレームの再構成に使えるように、プログラムカウンタとプロセッサステータスワードを一時 [ Fi1e : /usr/src/kerne1/kern/i386/trap. c , line : 471 ] tf—>tf—eip = *sp + + ; tf—>tf_cs *SP 十十 ; (eip (int)&iret) tf—>tf—eflags tf->tf-esp = *SP + + ; tf—>tf_ss *sp; if *sp 十十 ; 現在発生しているトラップフレームを、カーネルモードフォールトから抽出したプログラムカンタお よび、それに対応するコードセグメントレジスタの値で上書きする。フォールトが発生したアドレスの 命令が、割り込みからのリターン命令 ( iret ) だった場合、プロセッサステータスの値も書きかえる。そ うでなければ、エラーは lret 命令によって起きたものである。スタックポインタとセタックセグメン トセレクタも、同じくリロードされる。これでスタックフレームは整形され、このフォールトを発生さ せたプロセスにシグナルを送信できるようになった。 [ Fi1e :/usr/src/kerne1/kern/i386/trap ・ c , line : 479 ] p—>p—md. md—flags ー = MDP—SIGPROC; trapsignal(), SIGSEGV, の ) ; プロセスにセグメンテーション違反のシグナルを強制する。シグナル生成処理のすべてのエントリと 同じく、マシン依存フラグ P ー S 工 GPROC を立てて、数値演算コプロセッサとの競合を防いだ状態で関 [ Fi1e : /usr/src/kerne1/kern/i386/trap. c , line : 483 ] 数を呼び出す。 ードは trap ( ) のものとまったく同じである。 さらに、上述した trap() と同じようにシグナルのチェックを行う。求める効果が同じなので、 cpu-preempt (p) ; cpu-signals (p) ; 132 らのコ

7. 386BSD カーネルソースコードの秘密

5.3 プロセス終了の構造 : kern/exit. c return (error) ; もしステータスあるいは資源利用統計が求められていたら、それらをプロセスの死体から回収して返 す。どちらの場合も、もし工ラーが発生したら、ゾンビは子プロセスのリストの中で、変更されないま p->p-nxt->p-prev = p->p-prev ; if (*p->p-prev = p->p-nxt) [ Fi1e : /usr/src/kernel/kern/exit . c , line : 276 ] スフィールド (p-cru) に格納する。 要求された利用情報の回収に成功したら、プロセスの利用統計の合計を、親プロセスの合算子プロセ FREE (p—>p-stats , M_ZOMBIE) ; ruadd (&q—>p-stats—>p—cru , &ru) ; [ Fi1e : /usr/src/kernel/kern/exit . c , line : 272 ] まとなる点に注意してほしい。 [ Fi1e : /usr/src/kernel/kern/exit . c , line : 283 ] れを再利用に回し、ユーザープログラムにリターンする。 統計情報とステータスを引き出したプロセスは、もうゾンビキュー ( 加 mbpr 。 c ) から外していい。 return ( の ; reclaimproc (p) ; (p->p-flag & STRC Ⅱ uap->options & WUNTRACED) ) { = SSTOP & & (p->p_flag & SWTED) = = の & & if (p->p-stat [ Fi1e : /usr/src/kernel/kern/exit . c , line : 287 ] のケースにより、ジョブコントロールは新たに停止したプロセスを知ることができる * 56 。 ロセスすべてを対象に指定されていたら、そのプロセスも wait4 ( ) によってサンプルされる。この第 2 のプロセスが ptrace() されているか ( STRC ) 、あるいは WUNTRACED フラグによって停止しているプ ただし、子プロセスが停止させられていて、まだ wait によって発見されていない場合でも、もしそ p¯>p—stats—p—status W_STOPCODE(p->p-sigacts->ps-stopsig) ; * 56 コマンドシェルの csh は、 これを使って、ユーザーにプロセスの停止を通知する。 293

8. 386BSD カーネルソースコードの秘密

9.3 ファイル記述子機構 : kern/descrip. c : 1294 ] [ Fi1e : /usr/src/kernel/kern/descrip. c , int closef (struct file *fp, struct proc *p) line closef ( ) の引数は 2 つ、ファイルインスタンスへのポインタと、そのファイルをオープンしたプロ セスへのポインタである。もしファイルのクローズに成功したら 0 を返し、失敗したらエラーを返す。 この関数の副作用としてファイル記述子がクローズされることがあり、下位のファイルオプジェクトが 非アクテイプ化され、ときには再利用に回される。 ◆ 9.3.26.1 closef() の実装 [ Fi1e : /usr/src/kernel/kern/descrip. c , if ()p = = NULL) return ( の ; . 13 の 1 ] ファイルインスタンスが既にクローズされていたら、この関数は即座に成功を返す。 もしプロセスが推奨ロック (advisorylock) を使っていて、その下位のレベルのファイル的オプジェク return ( の ; if (--fp->f-count > の (void) VOP-ADVLOCK(vp, (caddr-t)p, vp = (struct vnode *)fp—>f-data; If . l—type = F—UNLCK; If . 1 ー le Ⅱ = ; If . l-start = 殤 If . l_whence = SEEK_SET ; if ( (p->p-flag & SADVLCK) & & fp->ftype [ Fi1e : /usr/src/kernel/kern/descrip. c, line = DTYPEVNODE) { : 13 の 9 ] F_UNLCK , &lf , F_POSIX) ; トが vnode だったら、その vnode に対してアンロック要求を発行するため、 VOP-ADVLOCK メソッドに よって、そのファイルの内容に対するすべてのロックを解除させる。これが認識されるのは POSIX の ロック ( F_POSIX) だけであり、 BSD のファイルロックは無視される。次に、このファイルの参照カウ ントをデクリメントする。もしファイルがまだ誰かに参照されていたら、この関数はリターンし、最後 の参照が取り除かれたときに初めて、このクローズの残りの処理が行われるようにする。 [ Fi1e : /usr/src/kernel/kern/descrip. c , line : 1324 ] = DTYPE_VNODE) { if ( (fp->f-flag & FHASLOCK) & & fp->f-type SEEK_SET ; If . l_whence 525

9. 386BSD カーネルソースコードの秘密

9.3 ファイル記述子機構 . kern/descrip. c によってファイルインスタンスをクローズする。 [ Fi1e : /usr/src/kernel/kern/descrip. c , line : 1254 ] if (fdp—>fd—nfiles > NDFILE) FREE(fdp—>fd-ofi1es , M_FILEDESC) ; ファイル記述子のインスタンスに実装できるファイル数よりも多くのファイルがある場合は、拡張さ れたファイル記述子のセグメントを解放する。インクリメンタルなクローズとは違って、 fdfree ( ) は ファイル記述子の空間を、まとめて一挙に解放する。 [ Fi1e : /usr/src/kernel/kern/descrip. c , line : 1257 ] vrele(fdp->fd—cdir) ; if (fdp—>fd—rdir) vrele (fdp—>fd—rdir) ; カレントディレクトリの vnode への参照、またルートディレクトリの vnode が参照されている場合 は、その参照を解放する。ルートディレクトリはオプションであり、そのプロセスが chr 。。 t ( ) システ ムコール (fs/fs-sys. c) を行ったプロセスの子孫である場合のみ存在する。 [ Fi1e : /usr/src/kernel/kern/descrip. c, line : 1261 ] 9.3.25 fdcloseexec() とは何か FREE(fdp, M_FILEDESC) ; すべての参照と下部構造体を削除したあと、最後にファイル記述子構造体そのものを解放する。 523 戻り値はない。この関数の副作用は、マークのあるファイルをクローズすることである。 fdcloseexec ( ) の引数は 1 つ、走査してファイルをクローズすべきプロセスへのポインタである。 fdcloseexec (struct proc *p) VOid [ Fi1e : /usr/src/kernel/kern/descrip. c , line : 1265 ] しないか調べる。そして新しいプログラムを実行する前に、それらのファイルをクローズする。 ファイル記述子を見て、 close-on-execute フラグ (UF_EXCLOSE) でマークされているファイルが存在 cve . c) を実行中に、クローズすべきファイルがないか調べるために使われるカーネル内部関数である。 POSIX 1003.1 仕様で定義されている fdcloseexec() は、 execve() システムコール (kern/exe

10. 386BSD カーネルソースコードの秘密

◆ 4.3.12.1 isalphanum() の実装 [ Fi1e : /usr/src/kernel/kern/config. c , く = く = return ( の ; return ( 1 ) ; return ( 1 ) ; return ( 1 ) ; line 4.3 386BSD のコンフィギュレーション : kern/config. c : 119 ] キャラクタが大文字または小文字のアルファベットまたは数字かどうかをチェックする。どれかに該 当すれば真を、該当しなければ偽を返す。 4.3.13 valdigit() とは何か valdigit() は、数字の適切な基数による値を返す、簡単な内部関数である。 valdigit ( ) は、 ASCII 文字の値を、 10 進数または 16 進数の値にして返す。 [ Fi1e : /usr/src/kernel/kern/config. c , line : 13 の ] static int valdigit (char c) { valdigit() の引数は、調査すべきキャラクタである。戻り値は、そのキャラクタの数としての値で ある。 ◆ 4.3.13.1 valdigit() の実装 [ Fi1e : /usr/src/kernel/kern/config. c, line : 133 ] return (C return (C return (C return ( の ; , a , + 1 の ; , A ) + 1 の ; 10 進の数字の場合、その数の値を返す。 16 進数の 6 種類のアルファベットについては、それらに対応 する数値を返す。この関数が、以上のキャラクタ以外に対して用いられることはないが、もし範囲外の 値を渡されたら、デフォルトとして偽 ( 0 ) を返す。 193