4.3 386BSD のコンフィギュレーション : kern/config. c たら、クラッシュダンプのためのデバイスメソッドを呼び出し、その値を返す。その他のすべての場合 は、 ENODEV 工ラーを返す。 4.3.32 devif-config() とは何か devif-config() は、指定された devif ポインタとコンフィギュレーション文字列を使って、デバ イスインターフェイス登録用の配列にインターフェイスを登録することによって、デバイスの構築を試 みる。これを使うのはデバイスドライバだけであり、初期化メッセージを受信したデバイスドライバが、 自分のメソッド関数インターフェイスをカーネル本体に結合させるのに使用する。 devif-config() は、供給されたコンフィギュレーション文字列を見て、デバイスを構成可能か、ま た構成していいかを判定し、デバイスをカーネルにリンクできるような正しいパラメータが含まれてい るかどうかも判断する。デバイスが、適切なコンフィギュレーション文字列とデバイスインターフェイ スポインタを供給できるとしたら、この関数はさらにデバイスのさまざまな名称 ( モジュール名、チャラ クタメジャー番号、プロックメジャー番号 ) を、デバイスインターフェイス構造体に初期化する ( 「 4.3.52 ドライバの名前」参照 ) 。このようにすると、コンフィギュレーションの唯一の情報源 ( コンフィギュレー ション文字列 ) によって、そのドライバの、カーネルに依存するすべてのパラメータが定義される。 [ FiIe : /usr/src/kernel/kern/config. c , line : 779 ] int devif config(char **cfg, struct devif *dif) devif-config() の引数は 2 つ、コンフィギュレーション文字列へのポインタと、デバイスインター フェイスポインタである。戻り値は成功か失敗である。この関数は、このデバイスを構成するうえで衝 突がないかチェックし、もしあればユーザーに警告する。また、提供されたデバイスインターフェイス 構造体の妥当性チェックも行って、正しい関数名を指す完全なエントリが含まれていることを確認する。 ◆ 4.3.32.1 devif_config() の実装 [ Fi1e : /usr/src/kernel/kern/config. c , line if (dif->di-name [ ] if (!config-scan(*cfg, cfg)) return ( の ; : 787 ] memcpy(dif->di-name , arg, sizeof (arg) ) ; デバイスモジュールの名前がなかったら、すべてのデバイス構成を評価する config-scan() 関数を 呼び出して、デバイスモジュールを構成しようと試みる。デバイスを構成して名前を取得することがで 219
第 4 章カーネル内部サービス (kern/config. c 、 kern/malloc. c) [ FiIe : /usr/src/kernel/kern/config. c , line : 1 の 26 ] int ldiscif-config(char **cfg, struct ldiscif *lif) ldiscif-config() の引数は 2 つ、ラインディシプリンに関連しているコンフィギュレーション文 字列へのポインタと、そのラインディシプリンのラインディシプリンインターフェイスへのポインタで ある。この関数は、ディシプリンを正しく構成できたら真を、そうでなければ偽を返す。 ◆ 4.3.43.1 ldiscif_config() の実装 [ Fi1e : /usr/src/kernel/kern/config. c , line : if (Iif->1i-name[Ø] if ( !config-scan(*cfg, cfg)) return ( の ; 1 の 34 ] memcpy(lif—>li-name , arg, sizeof (arg) ) ; / * ラインのインデックスを構成 ? * / if (lif—>li-disc ー 1 & & !cfg-number(cfg, &lif—>li-disc)) return ( の ; このラインディシプリンの名前が初期化されていなければ、 config-scan() 関数を呼び出し、コン フィギュレーション文字列の最初の文字列を構成するモジュールの名前として、ラインディシプリンの モジュールをシステムに組み込む。構成に失敗したら、このルーチンは不成功を返して終了する。そう でなければ、ラインディシプリンの名前を、そのインターフェイス構造体に記入する。 同様に、もしラインディシプリンのインデックス名が初期化されていなければ、コンフィギュレーショ ン文字列を調べて、このラインディシプリンに割り当てられているラインディシプリン番号を取り出し、 その値をインターフェイス構造体に格納する。 [ Fi1e : /usr/src/kernel/kern/config ・ c , line : 1 45 ] if ((line lif—>li-disc) > = の { / * ラインディシプリンを探索する * / for (olif ldisc; olif & & olif—>li_disc ! = lif->li-next) olif / * デバイスはすでに使われている ? * / if (olif) printf ("%s : ldisc %d already used by %s , arg, line , olif—>li—name) ; 232 line not configured. \n"
索引 devif-root() ・ devif_XXX ・ ・・ 28 , 62 , 349 , 442 , 444 , 449 ・ 180 , 258 ・・ 90 , 102 ・ 146 , 167 config ・ config() ・ CONFIG. SYS ・・ config-scan() ・ ConneXlons ・ console-config() ・ console-getchar() ・ console-putchar() ・ COPS ・・ copyin3() ・ copyinoutstr() ・ copyinstr copyout ・・ copyout-l ・ copyout-2 ・ copyout-4 ・ copyout-X ・ copyoutstr ・ coredump() ・ ・・ 49 , 446 , 454 , 460 cpl ・ CPU- CPII CPU— CPU— CPLI CPII cpu- tfork() ・ -texit() ・ cpu-signalreturn() ・ -signal() ・ reset() ・ ptrace reg() ・ -preempt() ・ execsetregs() ・ 576 DDB ・ data ・ DAC ・・ currents ・ current prioroty level ・ curproc ・ curprl ・ CTSS ・・ crXXX() ・ crhold() ・ crget() ・ crfree() ・ credentials ・ crdup() ・ ・・ 557 ・・ 190 ・・ 544 ・・ 235 ・・ 234 ・・ 234 ・・ 545 ・・ 190 , 199 ・・ 37 , 64 , 68 ・・ 68 ・・ 457 ・・ 113 , 134 , 139 ・・ 37 , 68 ・ 68 , 73 ・・ 69 ・・ 69 ・・ 69 ・・ 69 ・・ 12 , 112 , 356 ・・ 359 , 380 ・・ 305 , 356 ・・ 146 , 147 ・・ 146 , 164 ・・ 142 , 146 , 159 ・・ 147 , 168 ・・ 130 , 142 ・ 146 , 158 , 464 ・・ 305 , 340 , 351 ・・ 118 ・・ 548 ・・ 183 ・・ 102 ・・ 81 ・・ 130 ・・ 362 ・・ 358 ・・ 380 ・・ 380 ・・ 146 device not available ・ devif-write() ・ —strategy() devif_select() ・ devif-read() ・ devif-psize() ・ devif- 叩 en() ・ devif-name() ・ -mmap() ・ devif-ioctl() ・ devif-dump() ・ devif_config() ・ devif_close() ・ devif devif execsigs() esym ・ ERESTART ・・ endtsleep() end Of interrupt ・ EJUSTRETURN ・・ EFLAGS ・ effective privilage ・ effective ID ・ dupfdopen() ・ dup2() ・ dup() ・ ds ・ Dr. Dobb's JournaI ・ DOS ・ DONET ・・ DISTANTUSR ・ devifXXX() ・ ・・ 120 ・・ 208 ・・ 219 ・・ 218 ・・ 210 ・・ 215 ・・ 203 ・・ 206 ・・ 217 ・・ 211 ・・ 205 ・・ 213 ・・ 216 ・・ 213 ・・ 474 ・・ 86 ・・ 98 ・・ 83 ・・ 389 ・・ 185 ・・ 190 ・・ 182 ・・ 86 ・・ 141 ・・ 90 ・・ 417 ・・ 90 ・・ 141 ・・ 107 ・・ 365 ・・ 365 ・・ 473 , 528 , 529 ・・ 476 , 517 465 , 538 , 544 ・・ 42 , 85 , 175 , 258 ・ 305 , 349 , 462 ・・ 11 , 44 , 49 , 92 , 175 , 403 , 446 , executable file format emulator ・ execve() ・ execve() システムコール・ exit() ・ expanded memory ・ extended memory ・ ・・ 263 , 282 , 283 , 351 , 522 ・・ 442 ・ 447 ・・ 39 ・・ 39
4.3 386BSD のコンフィギュレーション : kern/config. c console-getchar() は引数を取らず、キャラクタを返す。 ◆ 4.3.45.1 console_getchar() の実装 [ Fi1e : /usr/src/kernel/kern/config. c , line : 11 の 4 ] if (console—devif) { splhigh( ) ; ch = (console-devif—>di-getchar) (makedev (cons01e—devif—>di-cmaJ or , sp1x(S); return (ch) ; return ( の ; } e1se もし構成済みのコンソールデバイスがあれば、割り込みを禁止し、 console_minor) ) ; そのコンソールデバイスのコンソー ルキャラクタ入力メソッドを使って、デバイスドライバからキャラクタを取得する。ドライパ内の適切 なデバイスを選択するために、そのコンソールデバイスのためのデバイス識別子を構築し、引数として getchar() メソッドに渡す。キャラクタを取得したら、デバイス割り込みを復旧し、キャラクタを呼び 出し側に返す。もしコンソールが構成されていなければ、キャラクタを返せないという意味を示す 0 の 値を返す。 4.3.46 console-config() とは何か console-conf ig ( ) は、デバイスドライバモジュールを、コンソールデバイスとして構成する。 console-config() は引数として、コンソールのコンフィギュレーション文字列、ドライバモジュール のコンフィギュレーション文字列、そしてデバイスインターフェイスへのポインタを取り、これをコン ソールとしてシステムで使うように構成していいかを判定する。複数のコンソールを構成することが可 能なので、 console-config() は、このコンソールが既に使えるように構成されているか、また構成 可能なモジュールに割り当てられているかを判定しなければならない。もしそうでなくて、主に使用さ れるコンソールが選択されていない場合、デフォルトで使用されるコンソールを選択する必要がある。 [ Fi1e : /usr/src/kernel/kern/config. c , line : 1115 ] int console—config(char **cons—cfg, char **mod—cfg, struct devif *dif) { console ー config ( ) の引数は 3 つ、コンソールのコンフィギュレーション文字列へのポインタ、モ ジュールのコンフィギュレーション文字列へのポインタ、そしてモジュールのデバイスインターフェイス へのポインタである。戻り値は、コンソール構成に成功したか失敗したかに応じて、真または偽を返す。 235
◆ 4.3.46.1 console-config() の実装 [ Fi1e : /usr/src/kernel/kern/config. c , cfg = *cons-cfg; / * コンソールが定義されているか ? * / if (config—scan(cfg, cons-cfg) return ( の ; 第 4 章カーネル内部サービス (kern/config. c 、 kern/malloc. c) = の = の 1122 ] はじめにコンソールのコンフィギュレーション文字列を評価して、共有コンフィギュレーション文字 列の中にコンソールが存在するかどうか判定する。もしコンソールの割り当てが定義されていなければ、 = の return ( の ; if (config-scan(cfg, mod-cfg) cfg = *mod—cfg; / * 要求されたコンソールモジュールは構成可能か ? * / return ( の ; if (cfg—string(cons—cfg, modnamel , sizeof (modnamel) ) [ Fi1e:/usr/src/kerne1/kern/config. c, line: 1129 ] このルーチンは即座に不成功を返す。 else if (strcmp(modnamel , arg) ! = の / * 同じモジュールか ? * / default_console_devif = dif ; = の if (strcmp(modnamel, "default") [ Fi1e : /usr/src/kernel/kern/config. c, line : 1138 ] 走査して、構成可能かどうか調べる。もしそうなら、このコンソールの構成は失敗に終わる。 システムに組み込んで使えるコンソールモジュールを取り出したら、与えられたモジュール文字列を ジュールを取得する。もしなければ、そのときも不成功を返す。 コンソールのコンフィギュレーション文字列の、その次のトークンから、コンソールとして使うモ return ( の ; コンソールとして構築すべきコンソールと違っていたら、それは正しいコンソールではないことがわか 変数に保存して、デフォルトコンソールが構築されたことを示す。そうでなく、もしそのコンソールが、 コンソールとして構成するモジュールが、デフォルトコンソールであれば、その値は別のグローバル 236 こまでに不成功となる状況にならなければ、構成すべき正しいデバイスを見つけたことになる。こ る。それはシステムの別のモジュールである。そのときは、この関数は不成功を返す。
4.3 386BSD のコンフィギュレーション : kern/config. c 4.3.42 ldiscif-qsize() とは何か デフォルトのキューサイズである 0 を返す。これは、東縛されていないラインディシプリンのキュー長 ディシプリンの qsize ( ) メソッドを呼び出す。もしラインディシプリンが割り当てられていなければ、 もので、キューのキャラクタ数は実装に依存する。 ldiscif-qsize() は、割り当てられているライン イズを返す。この関数は、カーネルのラインディシプリン援助関数が、キューのサイズを知るために使う ldiscif-qsize() は、ラインディシプリンの実装に依存する、キャラクタを要素とするキューのサ return ( の ; return ((lif->li-qsize) (tp, q)) ; if (lif) [ Fi1e:/usr/src/kerne1/kern/config. c, line: 1 の 19 ] ◆ 4.3.42.1 ldiscif_qsize() の実装 不明確なポインタである。戻り値は、ラインディシプリンの qsize ( ) が返した値である。 ldiscif-qsize() の引数は 2 つ、端末構造体へのポインタと、その構造体の中の端末キューを指す ldiscif—qsize(struct tty *tp, void (q) { int [ Fi1e : /usr/src/kernel/kern/config. c , line : 1 の 14 ] は常に 0 ( 空 ) であることを示す。 231 録済みのラインディシプリンインターフェイスとして使えるようにする。 したシンポルによるパラメータを割り当てることを期待する。そして、それをカーネルに挿入して、登 を受け取り ( また、オプションで構成し ) 、指定のラインディシプリンインターフェイスに、引数で指定 プリンは、 ldiscif-config() が、共有コンフィギュレーション文字列を使って、ラインディシプリン れる。この関数は、ラインディシプリンのモジュール初期化工ントリから呼び出される。ラインディシ ldiscif-config() は、カーネルで使用できるようにラインディシプリンを登録するために使用さ 4.3.43 ldiscif-config() とは何か であることを示す 0 の値を返す。 ソッドを呼び出し、その値を返す。もしラインディシプリンが割り当てられていなければ、キューが空 端末構造体にラインディシプリンが割り当てられていたら、そのラインディシプリンの qsize ( ) メ
第 4 章カーネル内部サービス (kern/config. c 、 kern/malloc. c) ldiscif-modem() ldiscif—rint ( ) ldiscif-ioctl() ldiscif-write ( ) ldiscif—read() ldiscif-close() devif-config() ldiscif ldiscif ldiscif ldiscif ldiscif console COIlSOIe C011SOIe -open() -put ( ) -start ( ) -qsize() -config() -getchar() -putchar ( ) -config() これらの関数は 5 つのグループに分類される。 cfg_xxx() 系関数、 isdigit() 、 isalphanum() 、 valdigit ( ) は、コンフィギュレーション文字列処理関数である。モジュール構成機構を扱うのは config-scan() と modscaninit() である。デバイスドライバとラインディシプリンへのカーネル インターフェイスは、 devif_XXX() 系関数、 ldiscif_xxx() 系関数が、それぞれ扱う。そしてコン ソールへのカーネルインターフェイスを扱う関数は、 putchar() 、 getchar() 、 config() である。 devif-XXX 系関数は、 UNIX デバイスドライバインターフェイスオプジェクトへの、一連のオプジェ クトメソッドコールを実装する。カーネルとデバイスドライバの間にレイヤを挟むことにより、デバイス ドライバへの要求にフィルタをかけ、またリダイレクションを行うことも可能である ( リモート、クラス 夕、および論理デバイスマッピング ) 。これを使うと、ディスクドライプの「ストライプ」化を行うことも できる。つまり要求に応じて操作を別のドライプ、サプュニット、コントローラに割り当てるのである。 devif ー xxx 系関数と同じように、 ld 土 sk ー xxx 系関数はラインディシプリンへのアクセスを管理する。 ラインディシプリンは、一時的なクラスによるドライバに似た機構で、シリアル通信ドライバに共通の ターミナル機能およびネットワーク機能を提供する目的で使用される。また、コンソールインターフェ イス関数は、ドライバに埋め込まれているさまざまな、異なったコンソールインターフェイスのひとつ を、カーネルが読み書きできるようにする。 コードの冗長さを減少させるために、これらの関数の多くをマクロを使って組み合わせることも可能 である。しかし、今回のこのファイルでは、わざと行っていない。これらのファイルの一部は、のちの バージョンで変更される可能性があるからだ。そういうわけで、マクロ化の作業は読者への課題として 残されている。 4.3.10 cfg-skipwhite() とは何か cfg-skipwhite() は、コンフィギュレーション文字列に含まれている空白をスキップするための簡 単な関数である。 cfg-skipwhite() に渡された、文字列へのポインタは、空白でない次のキャラクタ 190
4.3 386BSD のコンフィギュレーション : kern/config. c return (any) ; ジュールの構成パラメータを含み、これから解析する必要のある、コンフィギュレーション文字列の残 かを判定する。もしモジュールを構成する必要があれば、この関数は成功を示す真を返すとともに、モ ようなコンフィギュレーション文字列が、共有コンフィギュレーションファイルに入っていないかどう か、また、モジュールに埋め込まれているデフォルトのコンフィギュレーションをオーバーライドする ルトのコンフィギュレーション文字列の、両方を調べて、そのモジュールを構成する必要があるかどう プによってロードされた共有コンフィギュレーションファイルと、モジュールによって供給されるデフォ ルから見ると、コンフィギュレーション文字列の供給元である。この関数は、システムのプートストラッ config-scan() はモジュールのコンフィギュレーション処理を開始するものであり、そのモジュー 4.3.18 config-scan() とは何か namelist 工ントリの状態が返される。 タの位置に置かれるのが普通である。 n elist 名が存在しないときは、ループが終結し、見つかった え、重複している場合さえありえるので、 nameli st は nameli st 文字列の最後、空白でないデリミ そして、次のペアを探し始める。 namelist 工ントリは、どのような順序になっているかわからないう ギュレーション文字列ポインタを進め、 namelist のペアを見つけることができたことを記録する * 訳注 2 トリの解析に成功し値を返すことができたのであれば、 2 つのトークンを処理済みとするためにコンフィ 文字列フィールドを解析しないまま、その場でリターンする。その他の場合、もしこの nameli st 工ン もし型が実装されていない場合は ( 数と文字列の、どちらの型でも解析できなかった場合と同じく ) 、 在は n elist 構造体に文字列長は入っていない。 必要な場合は、同様に文字列を返す。この文字列は適切なサイズにセットされているという前提で、現 の数値を value ポインタに対応したⅡ amelist に格納してリターンする。また、文字列 (STRING) が ンを探す。つまり、その型が数 (NUMBER) であれば、コンフィギュレーション文字列から数を探し、そ 工ントリが見つかったら、そのエントリの型を調べ、そのトークンの種類に適した型の、次のトーク * 訳注 2 any をインクリメントする。 config-scan() の引数は 2 つ、モジュールのデフォルトコンフィギュレーション文字列へのポイン config-scan(char *cfg, char **cfg-sp) { i nt [ Fi1e : /usr/src/kernel/kern/config. c, line : 265 ] りの部分を指すポインタを返す。 199
◆ 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
第 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() はバッフアポインタに埋め込まれて指定されたデバイスに割り当てられている