aboutsummaryrefslogtreecommitdiff
path: root/ja/handbook/internals/chapter.sgml
diff options
context:
space:
mode:
Diffstat (limited to 'ja/handbook/internals/chapter.sgml')
-rw-r--r--ja/handbook/internals/chapter.sgml2046
1 files changed, 0 insertions, 2046 deletions
diff --git a/ja/handbook/internals/chapter.sgml b/ja/handbook/internals/chapter.sgml
deleted file mode 100644
index ddf5079b15..0000000000
--- a/ja/handbook/internals/chapter.sgml
+++ /dev/null
@@ -1,2046 +0,0 @@
-<!--
- The FreeBSD Documentation Project
- The FreeBSD Japanese Documentation Project
-
- Original revision: 1.10
- $Id: chapter.sgml,v 1.2 1999-07-25 06:36:12 kuriyama Exp $
--->
-
-<chapter id="internals">
- <title>FreeBSD の内部</title>
-
- <sect1 id="booting">
- <title>FreeBSDのブート処理の流れ</title>
-
- <para><emphasis>原作: &a.phk;. v1.1, April 26th.</emphasis></para>
-
- <para><emphasis>訳: &a.jp.nakai;. September 6 1996.</emphasis></para>
-
- <para>FreeBSDのブートには基本的に3つの段階があります:
- カーネルの読み込み, ルートのファイルシステムの決定, そして
- ユーザ領域にあるものの初期化です. このことは下に述べる
- いくつかの興味深い可能性につながっています.</para>
-
- <sect2>
- <title>カーネルの読み込み</title>
-
- <para>現在, カーネルの読み込みには基本的に下に挙げる3つの方法が
- あります:
- これらはカーネルが次に何をしたらいいのかという情報をカーネルに
- 与えます.</para>
-
- <variablelist>
- <varlistentry><term>Biosboot</term>
- <listitem>
- <para>Biosboot は &ldquo;ブートブロック&rdquo;
- に相当するもので, 2つのファイル から構成されており,
- フロッピーディスクやハードディスクのブートを
- 開始する側の 8K
- バイトにインストールされています.</para>
-
- <para>Biosboot は FreeBSD のファイルシステムからカーネルを
- 読み込むことができます.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>Dosboot</term>
- <listitem>
- <para>Dosbootは DI. Christian
- Gusenbauerによって書かれましたが,
- 不幸にしてこの場合には, コードのある一部分が
- マイクロソフトの
- コンパイラ向けに書かれているため, FreeBSD
- 単体ではコンパイル することはできません.</para>
-
- <para>Dosboot は MS-DOS のファイルから, またはディスクの
- FreeBSD ファイルシステムのパーティションから
- カーネルをブートします. これは MS-DOS
- システムのハイメモリ領域に潜んでいる
- メモリマネージャ等の
- さまざまな怪しい代物とメモリの取り合いをして,
- なんとかブートしています.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>Netboot</term>
- <listitem>
- <para>Netboot
- はサポートされているイーサネットカードを検出し, BOOTP
- や TFTP, NFS
- を使ってブートするカーネルを探そうとします.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </sect2>
-
- <sect2>
- <title>ルートファイルシステムの決定</title>
-
- <para>カーネルが読み込まれ,
- ブートプログラムがカーネルに移行したら,
- カーネルは自身の初期化をし,
- どんなハードウェアが組み込まれいるか を決定し,
- それからルートファイルシステムを探さなくてはなりません.</para>
-
- <para>現在サポートされているルートファイルシステムは
- 次の通りです :</para>
-
- <variablelist>
- <varlistentry><term>UFS</term>
- <listitem>
- <para>UFS は, もっとも一般的なタイプのルートシステムです.
- フロッピーディスクやハードディスク上に存在します.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>MSDOS</term>
- <listitem>
- <para>技術的に可能ですが, あまり有用ではありません.
- なぜならば, <acronym>FAT</acronym>
- ファイルシステムではリンクやデバイスノードなどの
- &ldquo;UNIX 主義&rdquo; を実現できないからです.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>MFS</term>
- <listitem>
- <para>MFS はカーネル内部に組み込みになっている UFS
- ファイルシステムです. つまり MFS を機能させるのに
- ディスクやフロッピーディスクなどのハードウェアは
- 必要ではありません.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>CD9660</term>
- <listitem>
- <para>CD9660 は CD-ROM
- をルートファイルシステムに使用したものです.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>NFS</term>
- <listitem>
- <para>これはルートシステムにファイルサーバを使用していて,
- 基本的に ディスクレスのマシンのためにあります.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </sect2>
-
- <sect2>
- <title>ユーザ領域にあるものの初期化</title>
-
- <para>ユーザ領域で動作させるようにするために,
- カーネルが初期化を終えると, カーネルは <literal>pid ==
- 1</literal>のプロセスを生成し, ルートファイルシステム
- 上のプログラムを実行します. このプログラムは通常
- <command>/sbin/init</command> です.</para>
-
- <para><filename>/sbin/init</filename>
- を別なプログラム置き換えてしまうことは可能ですが, そのプロセス
- には以下のような制約があります:</para>
-
- <para>pid が 1 のプロセスには stdin/stdout/stderr
- は割り当てられていませんので,
- プログラムは自分でこれらをオープンしないとなりません.
- このプロセスが終了するとカーネルはパニックメッセージを表示して
- 停止します.
- また, このプロセスに対するシグナル処理は特殊です.</para>
-
- <para>この例として, インストール用のフロッピーディスクにある
- <command>/stand/sysinstall</command>があります.</para>
- </sect2>
-
- <sect2>
- <title>興味深い連係</title>
-
- <para>カーネルを MFS でブートするのには次のような特別の
- <filename>/sbin/init</filename> を使います.</para>
-
- <variablelist>
- <varlistentry><term>A &mdash; DOS を使う場合</term>
- <listitem>
- <itemizedlist>
- <listitem>
- <para><filename>C:</filename> を
- <filename>/C:</filename> にマウントします.</para>
- </listitem>
-
- <listitem>
- <para><filename>C:/freebsd.fs</filename> を
- <filename>/dev/vn0</filename>
- にアタッチします.</para>
- </listitem>
-
- <listitem>
- <para><filename>/dev/vn0</filename> を
- <filename>/rootfs</filename>
- にマウントします.</para>
- </listitem>
-
- <listitem>
- <para>シンボリックリンクを作ります.<!-- <br> -->
- <filename>/rootfs/bin</filename> -&gt;
- <filename>/bin</filename><!-- <br> -->
- <filename>/rootfs/etc</filename> -&gt;
- <filename>/etc</filename><!-- <br> -->
- <filename>/rootfs/sbin</filename> -&gt;
- <filename>/sbin</filename><!-- <br> --> (etc...)<!--
- <br> --></para>
- </listitem>
- </itemizedlist>
-
- <para>これでハードディスクのパーティションを切り直さずに
- FreeBSD を 使うことができます.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>B &mdash; NFS を使う場合</term>
- <listitem>
- <para>NFS は<filename>サーバ:~you/FreeBSD</filename> を
- <filename>/nfs</filename> にマウントし,
- ルートディレクトリを <filename>/nfs</filename>
- に変更して, そこで <filename>/sbin/init</filename>
- を実行します.</para>
-
- <para>これで FreeBSD をディスクレスで実行できますが, NFS
- サーバを コントロールできないままです...</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>C &mdash; X-server を起動する場合</term>
- <listitem>
- <para>これで X ターミナルが手に入りました. これは,
- これでハードウェア に費用を割いたりするよりはいい,
- と上司が主張した, Windows で
- 動作する遅くて何がおこなわれているのか
- 見ることができるような すすけた X Window
- エミュレータなんかよりよいものです.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>D &mdash; テープを使う場合</term>
- <listitem>
- <para><filename>/dev/rwd0</filename>
- のコピーを取って, リモートにあるテープ
- ステーションやファイルサーバに書き込んでください.</para>
-
- <para>これで一年前に取っておくべきだった
- バックアップをやっと 取ることができました.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>E &mdash; ファイアウォール/Web
- サーバとして動作させる場合
- (私の知っている範囲で...)</term>
-
- <listitem>
- <para>これは特に面白いもので,
- 書き込み禁止のフロッピーディスクから ブートができて,
- ルートのファイルシステムに書き込むことができる
- というものです.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </sect2>
- </sect1>
-
- <sect1 id="memoryuse">
- <title>PC におけるメモリの利用</title>
-
- <para><emphasis>原作: &a.joerg;.<!-- <br> -->
- 16 Apr 1995.</emphasis></para>
-
- <para><emphasis>訳: &a.jp.tomo;. <!-- <br> -->
- 29 Oct 1996.</emphasis></para>
-
- <para><emphasis>FreeBSD が i386
- プラットフォーム上でどのようにメモリを使うかに
- ついての説明です. </emphasis></para>
-
- <para>ブート部分は<literal>0:0x7c00</literal>にロードされ,
- すぐに自分自身を <literal>0x7c0:0</literal>に移します.
- (これは手品ではなく, 単なる<literal>%cs</literal>
- セレクタのための調節であり,
- <literal>ljmp</literal>により行われます. )</para>
-
- <para>それから最初の 15 セクタを <literal>0x10000</literal>
- (biosboot の Makefile のなかの
- <makevar>BOOTSEG</makevar>部分)にロードし, 作業領域のスタックを
- <literal>0x1fff0</literal>以下に セットします. このあと, boot2
- に飛びます. つまり, boot1 自身と (ダミーの) DOS
- パーティションテーブルを飛び越えて, %csセレクタを 調節します
- &mdash; この時点ではまだ16ビットモードです.</para>
-
- <para>boot2 はブートファイルを要求し,
- <filename>a.out</filename>ヘッダを調べます.
- <literal>0x00ffffff</literal>によってファイルエントリポイントを
- (通常は<literal>0xf0100000</literal>に)マスクし, ロードします.
- このため, 通常のロードポイントは 1MB
- (<literal>0x00100000</literal>) になります. ロードしている間,
- リアルモードでBIOSを使うため, ブートコードは,
- リアルモードとプロテクトモードの間を行ったり来たりします (訳注:
- これは, BIOSがリアルモード用に書かれていて,
- ロードすべき領域がリアルモードではアクセスできない1MBより上位の
- アドレスであることから, ブートコードがリアルモードと
- プロテクトモードを切り替えながら動作するためです).</para>
-
- <para>ブートコード自身はプロテクトモードで
- <literal>%cs</literal>と<literal>%ds/%es</literal> 用に
- セグメントセレクタ <literal>0x18</literal> と
- <literal>0x20</literal> を使い,
- リアルモードに戻るのに<literal>0x28</literal>を使います.
- 最終的にカーネルはアドレス空間全体をカバーできるようなダミーの
- ディスクリプタを参照して<literal>%cs</literal>
- <literal>0x08</literal>と <literal>%ds/%es/%ss</literal>
- <literal>0x10</literal>でスタートします.</para>
-
- <para>カーネルはそのロードポイントで起動されます.
- 別の(高位)アドレスにリンクされるので,
- ページテーブルやページディレクトリなどが適切に設定され,
- ページングが有効になり, カーネルがリンクされたアドレスで
- 動作するようになるまでは, カーネルはロードアドレスからの
- 相対アドレス (PIC: position independent code) を用いて
- 実行されなければなりません.</para>
-
- <para><emphasis>寄贈: &a.dg;.<!-- <br> -->
- 16 Apr 1995.</emphasis></para>
-
- <para>カーネルの BSS セグメントの直後の物理ページ (実メモリ) に
- proc0 (訳注: プロセス番号 0, swapper) のページディレクトリや
- ページテーブル, Uページが配置されます.
- 仮想記憶機構が初期化された少しあと,
- <literal>0x1000-0x9ffff</literal>の実メモリとカーネル (text +
- data + bss + 上記の proc0 に関わるもの + その他)
- の後ろの実メモリは, 通常の仮想記憶ページの形で利用可能となり,
- グローバルな空きページリストに追加されます.</para>
- </sect1>
-
- <sect1 id="dma">
- <title>DMAとはどういったものでどういう働きをするのか</title>
-
- <para><emphasis>原作: &a.uhclem;<!-- <br> --><!-- <br> -->
- 訳: &a.jp.yasu;<!-- <br> -->
- 10 December 1996. 最終更新日 8 October 1997.</emphasis></para>
-
- <para>Direct Memory Access (DMA)は, 中央演算処理装置
- (CPU)からの干渉なく
- データを計算機中である場所から別の場所に動かすための手法です.
- </para>
-
- <para>DMA 機能の実装の方法はそれぞれの
- 計算機アーキテクチャ間で異なるもので あるため,
- ここでの議論はIBMパーソナルコンピュータ(PC), PC/AT
- とその互換機における DMA
- サブシステムの実装と働きに限定します.</para>
-
- <para>PCの DMAサブシステムは, Intelの 8237
- DMAコントローラをベースにして います.
- 8237はそれぞれ独立にプログラムできる4つのDMAチャネルを持ち,
- それぞれどのチャネルもいつでもアクティブにできます.
- これらのチャネルは順に 0, 1, 2, 3となっています. PC/ATからは,
- セカンド 8237 チップが追加され,それらは 4, 5, 6, 7と
- なっています.</para>
-
- <para>オリジナルの DMAコントローラ(0, 1, 2, 3)は,
- 1回の転送で1バイト 転送します. セカンドDMAコントローラ(4, 5, 6,
- 7)は1回で 隣接する2つのメモリ番地から 16ビット転送します.
- ここで, 最初のバイトは通常偶数のアドレスになります.
- 2つのコントローラは全く同じものであり, 転送量が異なるのは
- セカンドコントローラがシステムに直結しているためです.</para>
-
- <para>8237 は個々のチャネルについて,
- DRQと-DACKという2つの電気信号を 持っています. その他に, HRQ
- (Hold Request), HLDA (Hold Acknowledge), -EOP (End of
- Process)があり, バス制御信号として -MEMR (Memory Read), -MEMW
- (Memory Write), -IOR (I/O Read), and -IOW (I/O
- Write)があります.</para>
-
- <para>8237 DMACは, いわゆる&ldquo;fly-by&rdquo;
- DMAコントローラです. これは, データの移動を行う際に, データは
- DMACチップを通過せず, DMACチップに格納されないことを意味します.
- また, DMACはI/Oポートとメモリアドレス間でのみデータを
- 転送することができますが,
- 2つのI/Oポートもしくは2つのメモリアドレス
- 間ではできません.</para>
-
- <note>
- <para>8237 は, 非 &ldquo;fly-by&rdquo;モードでは,
- 互いに接続された
- 2つのチャネルでのメモリ-メモリ間でのDMA操作を許可します.
- しかし, PC メーカは,
- ただでさえ乏しいこのリソースをこんなふうに 使ったりしません.
- なぜなら,
- CPUを使用してメモリ間のデータを動かす方が早いからです.</para>
- </note>
-
- <para>PC アーキテクチャでは, それぞれのDMAチャネルは, 通常
- 与えられた DMA
- チャネルを使用するハードウェアがそのチャネルについて
- DRQ線を使って転送を要求した時のみ動作します.</para>
-
- <sect2>
- <title>DMA転送の例</title>
-
- <para>DMA転送の発生と処理の手順の例をあげてみましょう.
- この例では, フロッピーディスクコントローラ (FDC)が
- ディスケットから1バイト読み込んで,
- DMAを使って,メモリの0x00123456番地に 格納したいとします.
- 処理は, FDCが, DRQ2信号(DMAチャンネル2に
- 対するDRQ線)を有効にして
- DMAコントローラに要求を伝えることで開始されます.</para>
-
- <para>DMAコントローラは DRQ2
- シグナルが有効になったことを記録します.
- するとDMAコントローラはDMAチャネル2がプログラムされ, マスクが
- かかっていない(有効になっている)ことを確認します. 同様に,
- DMAコントローラは, 他のDMAチャネルがアクティブまたは
- アクティブになろうとしていないこと,
- そしてより高い優先度を持って いないことを確認します.
- 一旦これらのチェックが完了すると, DMACはDMACがバスを使うために
- バスを開放するようにCPUに要求します.
- DMACはCPUにHRQ信号を送ってバスを要求します.</para>
-
- <para>CPUはHRQ信号を検出し, 現在の指示の実行を完了します.
- 一旦プロセッサがバスを開放することができる状態になると, 解放を
- 行います. 通常は CPU により駆動される信号 (-MEMR, -MEMW,
- -IOR, -IOW, その他)を すべてハイインピーダンス
- (ハイともローとも指定しない)状態にした後, CPUは
- HLDA信号を有効にして DMAコントローラにバスを明け渡したことを
- 伝えます.</para>
-
- <para>プロセッサによっては, CPUはバスを使用しないいくつかの
- 命令を追加して実行することもできますが,
- しかし,プロセッサの内部キャッシュや
- パイプライン以外のメモリから
- 何か読み出すといった指示に到達したら結局 CPU
- は待たなくてはなりません.</para>
-
- <para>ここで,DMACが バスを&ldquo;託される&rdquo;と, DMACはその
- -MEMR, -MEMW, -IOR, -IOW 出力信号をアクティブにし,
- DMACから出力されるアドレスは 0x3456にセットされます.これは
- 転送しようとする特定のメモリ番地をバイトで
- 指示するのに使われます.</para>
-
- <para>すると DMAC は DMA
- 転送をリクエストしたデバイスに転送が始まることを
- 知らせます.これは -DACK
- 信号をアクティブにすることで行われます.
- フロッピーディスクコントローラの場合は, -DACK2を
- アクティブにすることで行われます.</para>
-
- <para>バスのデータ線に転送されるバイトにを出力することについては
- フロッピーディスクコントローラが責任をもつことになります.
- もし,フロッピーディスクコントローラがバス上にバイトデータを
- 出力するのに余計な時間を必要としなければ
- (もし周辺装置がもっと時間を必要とする場合には, READY信号を
- 経由してDMACに通知します), DMAは 1 DMAクロック待ち,
- メモリにバス上のバイトデータを格納するために -MEMW および -IOR
- 信号を解除します. そして
- FDCはバイトデータが転送されたことを認識します.</para>
-
- <para>DMAサイクルは1度に1バイトしか転送しないので,
- FDCはDRQ2信号を止めて, DMACに転送が終了したことを知らせます.
- DMACは-DACK2信号を解除して, FDCはバス上へのデータ出力を
- 停止しなくてはならないことを知らせます.</para>
-
- <para>次にDMACは他のDMAチャネルのいずれかに要求がきていないか
- チェックを行います.
- もしどのチャネルのDRQも有効になっていなければ,
- DMAコントローラは処理を完了して, -MEMR, -MEMW, -IOR, -IOW
- および アドレス信号をハイインピーダンス状態にします.</para>
-
- <para>最後に, DMAはHRQ信号を解除します.
- CPUはこれを見ると,HOLDA信号を 解除します. そしてCPUは自らの
- -MEMR, -MEMW, -IOR, -IOW 信号および アドレス線を有効にし,
- 命令の実行やメインメモリや周辺機器へのアクセスを
- 再開します.</para>
-
- <para>典型的なフロッピーディスクの1セクタについては,
- 上記のプロセスが それぞれのバイトについて1回行われ,
- 全部で512回繰り返されます. 1 バイト転送される毎に, DMAC
- 内のアドレスレジスタはインクリメントされ, 同じくDMAC内にある,
- 何バイト転送すればよいかを示すカウンタが
- デクリメントされます.</para>
-
- <para>カウンタが0になると, DMAはEOP信号を送ります. この信号は
- カウンタが0であり, DMAコントローラがCPUによって再び
- プログラムされるまで, これ以上データは転送されないことを
- 示すものです.</para>
-
- <para>このイベントはターミナルカウント(TC)とも呼ばれます.
- EOP信号は1本しかありません. そして, 一度にアクティブにできる
- DMAチャネルは一本だけなので,
- 現在アクティブであるDMAチャネルこそが,
- たった今処理を終了したDMAチャネルだと言うことができます.</para>
-
- <para>もし,
- バッファの転送が完了した時に周辺機器から割り込みを発生させたい
- とき, 周辺機器は
- -DACKn信号およびEOP信号の両方が同時に発信されたか
- どうかをテストします. その場合, DMACはCPUの介在がなければ
- これ以上はその周辺機器についての情報を転送しません. その後で,
- 周辺機器はプロセッサに割り込みを生じさせるために,
- 何らかの割り込み信号を発生させることができます.
- PCアーキテクチャ においては,
- DMAチップ自身が割り込みを生じさせることはできません.
- 周辺機器とそれに関連するハードウェアが割り込みを生成する責任を
- 持ちます. また, DMAを使用する周辺機器が割り込みを使用しない
- 可能性もあります.</para>
-
- <para>DMAC が要求を出したときには CPU は常にバスを DMAC
- に開放しますが, この動作は, DMAC
- がアクティブになった時にプロセッサが命令を実行するのに
- かかる時間がわずかに変化することを除いては, アプリケーション,
- オペレーティングシステムの両方からはわからないということを
- 理解することが重要です. そのため,
- プロセッサが確かにDMA転送が完了したことを知るためには,
- 周辺装置や DMA
- チップ中のレジスタを調べたり,周辺装置からの割り込みを
- 受け取る必要があります.</para>
- </sect2>
-
- <sect2>
- <title>DMA ページレジスタ および 16メガ アドレス空間制限</title>
-
- <para>これまで述べたのとは異なり, DMACはアドレス線を 0x0123456
- にセットする 代わりに 0x3456
- だけをセットすることにあなたは気づいたかも しれません.
- この理由について少し説明します.</para>
-
- <para>オリジナルのIBM PCがデザインされた時, IBMは,
- DMACと割込み制御チップの 両方を, 8085(8ビットプロセッサで,
- 16ビットのアドレス空間(64k)を持つ)と
- 組み合わせて使うように設計されたチップを使うことを選びました.
- IBM PCが64k以上のメモリをサポートしていたため,
- DMACが64kを越えるメモリ番地に読み込み又は書き込みを行うために
- 変更を行う必要が生じました.
- この問題を解決するためにIBMが行ったのは,
- それぞれのDMAチャネルに,
- 読み込み元または書き込み先のアドレスの
- 上位ビットを保持するための 外部的なラッチを追加することでした.
- DMAチャネルがアクティブな時はいつでも,
- このラッチの内容はアドレスバスに書かれて,
- そのチャネルのDMA操作が 終了するまでそこに保持されます. IBM
- はこれらのラッチを &ldquo;ページレジスタ&rdquo;
- と呼んでいます.</para>
-
- <para>そのため上記に示した例では,
- DMACはアドレスの0x3456の部分をバス上に 置き,
- DMAチャネル2に対するページレジスタは, 0x0012xxxxをバス上に
- 置きます.
- これらの2つの値が組み合わされてアクセスされるメモリ中の完全な
- アドレスを形成します.</para>
-
- <para>ページレジスタのラッチはDMAチップとは独立であるので,
- 読み込まれる又は書き込まれるメモリ領域は, 64kの物理的境界を
- またいではなりません. 例えば, もし
- DMACがメモリの0xffff番地をアクセスした場合, データの転送後,
- DMACはアドレスレジスタをインクリメントし,
- 0x0000番地にある次のバイトを アクセスします.
- 0x10000番地ではありません.
- これはおそらく意図されたものとは異なっているでしょう.</para>
-
- <note>
- <para>&ldquo;物理的な&rdquo; 64Kの境界を 8086モードの
- 64k&ldquo;セグメント&rdquo;と混同してはいけません.
- セグメントは, セグメント
- レジスタに数学的にオフセットレジスタを
- 加算して作られるものです.
- ページレジスタにはアドレスのオーバーラップも無く, 数学的に
- OR を取られることもありません.</para>
- </note>
-
- <para>さらに複雑なことには, PC/ATでは外部のDMAアドレスのラッチは
- 8ビットしか保持しません. よって8+16で24ビットになり, これは
- DMAが0から16メガの間のメモリ番地しか指し示せないことを
- 意味します.
- 16メガ以上のメモリを持ったより新しいマシンにおいても,
- 標準的なPCコンパチブルなDMAでは16メガ以上のメモリ番地には
- アクセスできません.</para>
-
- <para>この制限を避けるために, オペレーティングシステムは 16
- メガ以下にある物理的な 64k の境界をまたがない領域に RAM
- バッファを 予約します. そして,
- DMACはデータを周辺機器からそのバッファに
- 転送するようにプログラムされます. 一旦DMACがこのバッファに
- データを動かすと, オペレーティングシステムは本当にデータを
- 格納したいアドレスにバッファからデータをコピーします.</para>
-
- <para>16メガを越えるアドレスからDMAベースの周辺機器にデータを
- 書き込む際には, データは16メガ以下に位置したバッファから最初に
- コピーされなくてはならず, その後,
- DMACはバッファからハードウェアに
- データをコピーすることができます. FreeBSDでは,
- これらの予約バッファは
- &ldquo;バウンスバッファ&rdquo;と呼ばれます. MS-DOSの世界では,
- これらは&ldquo;スマートバッファ&rdquo;などと呼ばれます.</para>
-
- <note>
- <para>82374と呼ばれる8237の新しい実装においては,
- ページレジスタを16ビットで指定して,
- バウンスバッファを使用しなくても, 32
- ビットのアドレス空間全体にアクセスすることが可能です.</para>
- </note>
- </sect2>
-
- <sect2>
- <title>DMA操作モードとその設定</title>
-
- <para>8237 DMA はいくつかのモードで動作します. 主なモードは,
- 以下のとおりです.</para>
-
- <variablelist>
- <varlistentry><term>シングル転送モード</term>
- <listitem>
- <para>シングルバイト(もしくはワード)が転送されます.
- DMAは1バイト毎にバスを開放し,
- 再び要求しなくてはなくてはなりません. これは一般に,
- すぐにはデータのブロック全てを転送できないデバイスに
- よって使用されます.
- 周辺装置は次の転送の準備ができる毎にDMAを要求します.
- </para>
-
- <para>標準的な PC
- コンパチブルなフロッピーディスクコントローラ(NEC 765)は
- 1バイトのバッファしか持たないので,
- このモードを使用します.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>ブロック/デマンド転送モード</term>
- <listitem>
- <para>一旦 DMAC がシステムバスを取得すると,
- 最大64kまでのデータブロック 全体が転送されます.
- もし周辺装置が余分に時間を必要とするときは,
- 転送を一時中断するためにREADY信号を有効にします.
- READY信号は過度に使われるべきではなく,
- 遅い周辺装置の転送の場合は
- シングル転送モードを代わりに使うべきです.</para>
-
- <para>ブロック転送モードとデマンド転送モードの違いは,
- 一旦ブロック転送が 始まると, 転送カウンタか 0
- になるまでそれが行われるところです. DRQ は -DACK
- が有効になるまでの間は有効でなければなりません.
- デマンドモードは DRQ が有効な間転送が続けられます.
- DRQが有効でなくなった場合, DMA はその時点で転送を中断し,
- バスを解放して CPU に返します.
- その後, DRQが有効になると,
- 転送は中断したところから再開されます.</para>
-
- <para>データの転送,
- 特に転送に使われるメモリ番地が16Mを越える場合に, CPU
- を使った方が効率がよくなるまで CPU
- の速度が向上する以前の
- 古いハードディスクコントローラはデマンドモードを
- 使っていました.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>カスケード転送モード</term>
- <listitem>
- <para>このメカニズムは DMA
- チャネルがバスを要求することを許可する ものですが,
- 接続されたデバイスはバス上のアドレス情報の配置に
- ついてDMACに代わって責任を持ちます.
- これは&ldquo;バスマスタ&rdquo;
- と呼ばれる技術の実装に利用されます.</para>
-
- <para>カスケードモードの DMA
- チャネルがバスのコントロールを受け取ると, DMA
- は通常行われるようなバス上のアドレスと I/O
- コントロール信号の 出力を行いません. 代わりに,
- DMAはアクティブなチャネルの -DACK信号を
- 有効にします.</para>
-
- <para>この時点で, アドレスとバスコントロール信号の供給は
- DMAチャネルに接続された周辺機器が担当します.
- 周辺機器はシステムバスの完全なコントロールを行い, 16
- メガ以下の任意のアドレスの読み込みおよび書き込みを
- 行うことが できます. 周辺機器はバスの使用を終えると DRQ
- 線を無効にするので, DMA コントローラは CPU
- もしくは他のDMAチャネルに制御を返すことが
- できます.</para>
-
- <para>カスケードモードは複数の DMA
- コントローラを相互接続するのに 使われます.
- PC内ではDMAチャネル4がまさにこの用途に使われています.
- 周辺機器がDMAチャネル0, 1, 2, 3でバスを要求すると,
- スレーブDMAコントローラは HLDREQ を有効にしますが,
- この線はCPUではなく,
- 実際にはプライマリDMAコントローラのDRQ4に
- 接続されています. その後,
- チャンネル4になにか仕事があるものと見なしたプライマリの
- DMAコントローラは HLDREQ を使ってCPUにバスを 要求します.
- バスが与えられると, -DACK4が有効になりますが,
- この線は実際にはスレーブDMAコントローラの HLDA信号に
- 接続されています.
- スレーブDMAコントローラはその後要求したDMAチャネル (0,
- 1, 2, 3) に対してデータを転送するか,
- SCSIコントローラのような
- バスマスタリングを要求する周辺機器にバスを許可します.
- </para>
-
- <para>このような配線がおこなわれているため,
- PC/ATシステムの 周辺機器ではDMAチャネルは 0, 1, 2, 3, 5,
- 6, 7のみが使用できます.</para>
-
- <note>
- <para>初期のIBM PCコンピュータでは, DMAチャネル0は操作の
- リフレッシュのために予約されていますが,
- 最近のシステムでは通常,
- 周辺機器によって使用することができます.</para>
- </note>
-
- <para>周辺機器がバスマスタリングを行っている時は,
- システムバスを保持している間絶えずメモリに
- もしくはメモリから データを転送することが重要です.もし,
- 周辺機器がこのように できないときは,
- システムがメインメモリのリフレッシュを
- 行なえるようにしばしばバスを開放しなくては
- なりません.</para>
-
- <para>全ての PC でメインメモリとして使われるダイナミック
- RAM は, 中身が &ldquo;満たされている&rdquo;
- ビットを保持するため
- 頻繁にアクセスされなくてはなりません. ダイナミック RAM
- は, それぞれが 1 ビットのデータを記憶するコンデンサが
- たくさん集まって構成されています.
- これらのコンデンサは充電された 状態で
- <literal>1</literal>, 充電されていない状態で
- <literal>0</literal> を表します.
- 全てのコンデンサは放電するため, <literal>1</literal>
- の値を保持するために,
- 一定の間隔で電力を加える必要があります. 実際に RAM
- チップは RAM の適切な場所に電力を送る作業を行ないますが,
- メモリのリフレッシュ作業が RAM を普通にアクセスする時と
- 衝突しないように, それをいつ行なうかを
- コンピュータが休止状態の時に知らせなくてはなりません.
- もしコンピュータがメモリのリフレッシュを
- 行なえない場合は,
- メモリの中身はわずか数ミリ秒で壊れてしまいます.</para>
-
- <para>メモリの読み込みと書き込みのサイクルは
- リフレッシュサイクルとして カウントされる(ダイナミック
- RAM のリフレッシュサイクルは
- 実際には不完全なメモリ読み込みサイクルになります)ので,
- 周辺機器のコントローラが連続するメモリ番地から
- データの読み込み または書き込みを行う間は,
- メモリの全てがリフレッシュされます.</para>
-
- <para>バスマスタリングはいくつかの SCSI
- ホストインターフェースやその他の
- ハイパフォーマンスな周辺機器コントローラに
- 見られます.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry><term>自動初期化転送モード</term>
- <listitem>
- <para>このモードにおいてDMAはバイト, ブロック,
- デマンド転送を行いますが, DMA転送カウンタが0になると,
- カウンタとアドレスはDMAチャネルが
- もともとプログラムされた時のものに戻されます. これは,
- 周辺機器が転送を要求している間は転送が続けられることを
- 意味します.
- 転送領域としてDMACにプログラムされた固定バッファの中で,
- 出力操作でDMACがデータを読み出す前もって新しいデータを
- 書き込んだり入力操作でDMACが書き込んだあとに,
- そこから新しいデータを読み出す作業は CPU
- が受け持ちます.</para>
-
- <para>このテクニックは, &ldquo;サンプリング&rdquo;
- 用のバッファが小さいもしくは
- それを持たないオーディオデバイスによく使われます.
- この&ldquo;環状&rdquo; バッファの管理は更なる CPU
- オーバーヘッドになりますが, DMAカウンタが0になり,
- 再プログラムされるまでDMAが停止してしまう
- ことによって起きる遅延は,
- この方法でしかなくす事ができない 場合もあります.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </sect2>
-
- <sect2>
- <title>DMAのプログラミング</title>
-
- <para>プログラムされるDMAチャネルは, 通常, 設定を行う前に
- &ldquo;マスクする&rdquo;べきです.
- これはハードウェアが予期せずそのチャンネルに対してDRQを有効に
- した場合, たとえ全てのパラメータが
- 満たされてない場合や更新されていない場合でも, DMACは
- それに応答してしまう可能性があるからです.</para>
-
- <para>マスクを行ってから,ホストは転送の方向(メモリからI/O,
- もしくはI/Oからメモリ)と, 転送に使用するDMA操作のモード
- (シングル, ブロック, デマンド, カスケードなど)を設定し, 最後に
- アドレスや転送の長さを設定します.
- 設定される長さはDMACに転送させたい量よりも1少なくなります.
- アドレスや転送長のLSBとMSBは同じ8ビットI/O
- ポートに書き込まれます. そのためDMACが最初のバイトをLSBとして,
- 2番目のバイトをMSBとして 受け取ることを保証するために,
- 最初に別のポートに書き込みを行なって LSBとMSB
- の判別を行なうフリップフロップをクリアしておく必要があります.
- </para>
-
- <para>そして,DMAのページレジスタを更新します.
- これはDMACの外部にあり I/O
- ポートの別のセットを通してアクセスされます.</para>
-
- <para>すべての設定ができると,
- DMAチャネルはマスクを解除することができます.
- そのDMAチャネルは&ldquo;準備ができた&rdquo;とみなされ,
- そのチャンネルのDRQが 有効になると応答します.</para>
-
- <para>8237のプログラミングの正確な詳細については,
- ハードウェアデータブックを参照してください. PCシステムにおける
- I/O マップについても参照する必要があるでしょう. このマップには
- DMA およびページレジスタのポートがどこに位置するのかを
- 書いてあります.
- 以下に完全なポートのマップテーブルを示します.</para>
- </sect2>
-
- <sect2>
- <title>DMAポートのマップ</title>
-
- <para>IBM-PCとPC/ATに基づくすべてのシステムでは,
- 同じI/Oポートに配置された DMAハードウェアを持っています.
- その完全なリストを以下に示します.
- DMAコントローラ2に割り当てられたポートは, AT以外のデザインでは
- 未定義になっています.</para>
-
- <sect3>
- <title>0x00 &ndash; 0x1f DMA コントローラ #1 (Channels 0, 1, 2
- and 3)</title>
-
- <para>DMA アドレス および カウントレジスタ</para>
-
- <informaltable frame="none">
- <tgroup cols="3">
- <tbody>
- <row>
- <entry>0x00</entry>
- <entry>write</entry>
- <entry>Channel 0 starting address</entry>
- </row>
-
- <row>
- <entry>0x00</entry>
- <entry>read</entry>
- <entry>Channel 0 current address</entry>
- </row>
-
- <row>
- <entry>0x01</entry>
- <entry>write</entry>
- <entry>Channel 0 starting word count</entry>
- </row>
-
- <row>
- <entry>0x01</entry>
- <entry>read</entry>
- <entry>Channel 0 remaining word count</entry>
- </row>
-
- <row>
- <entry>0x02</entry>
- <entry>write</entry>
- <entry>Channel 1 starting address</entry>
- </row>
-
- <row>
- <entry>0x02</entry>
- <entry>read</entry>
- <entry>Channel 1 current address</entry>
- </row>
-
- <row>
- <entry>0x03</entry>
- <entry>write</entry>
- <entry>Channel 1 starting word count</entry>
- </row>
-
- <row>
- <entry>0x03</entry>
- <entry>read</entry>
- <entry>Channel 1 remaining word count</entry>
- </row>
-
- <row>
- <entry>0x04</entry>
- <entry>write</entry>
- <entry>Channel 2 starting address</entry>
- </row>
-
- <row>
- <entry>0x04</entry>
- <entry>read</entry>
- <entry>Channel 2 current address</entry>
- </row>
-
- <row>
- <entry>0x05</entry>
- <entry>write</entry>
- <entry>Channel 2 starting word count</entry>
- </row>
-
- <row>
- <entry>0x05</entry>
- <entry>read</entry>
- <entry>Channel 2 remaining word count</entry>
- </row>
-
- <row>
- <entry>0x06</entry>
- <entry>write</entry>
- <entry>Channel 3 starting address</entry>
- </row>
-
- <row>
- <entry>0x06</entry>
- <entry>read</entry>
- <entry>Channel 3 current address</entry>
- </row>
-
- <row>
- <entry>0x07</entry>
- <entry>write</entry>
- <entry>Channel 3 starting word count</entry>
- </row>
-
- <row>
- <entry>0x07</entry>
- <entry>read</entry>
- <entry>Channel 3 remaining word count</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
-
- <para>DMA コマンドレジスタ</para>
-
- <informaltable frame="none">
- <tgroup cols="3">
- <tbody>
- <row>
- <entry>0x08</entry>
- <entry>write</entry>
- <entry>Command Register</entry>
- </row>
-
- <row>
- <entry>0x08</entry>
- <entry>read</entry>
- <entry>Status Register</entry>
- </row>
-
- <row>
- <entry>0x09</entry>
- <entry>write</entry>
- <entry>Request Register</entry>
- </row>
-
- <row>
- <entry>0x09</entry>
- <entry>read</entry>
- <entry>-</entry>
- </row>
-
- <row>
- <entry>0x0a</entry>
- <entry>write</entry>
- <entry>Single Mask Register Bit</entry>
- </row>
-
- <row>
- <entry>0x0a</entry>
- <entry>read</entry>
- <entry>-</entry>
- </row>
-
- <row>
- <entry>0x0b</entry>
- <entry>write</entry>
- <entry>Mode Register</entry>
- </row>
-
- <row>
- <entry>0x0b</entry>
- <entry>read</entry>
- <entry>-</entry>
- </row>
-
- <row>
- <entry>0x0c</entry>
- <entry>write</entry>
- <entry>Clear LSB/MSB Flip-Flop</entry>
- </row>
-
- <row>
- <entry>0x0c</entry>
- <entry>read</entry>
- <entry>-</entry>
- </row>
-
- <row>
- <entry>0x0d</entry>
- <entry>write</entry>
- <entry>Master Clear/Reset</entry>
- </row>
-
- <row>
- <entry>0x0d</entry>
- <entry>read</entry>
- <!-- kuriyama - nik typo -->
- <entry>Temporary Register
- (新しいバージョンでは利用不可)</entry>
- </row>
-
- <row>
- <entry>0x0e</entry>
- <entry>write</entry>
- <entry>Clear Mask Register</entry>
- </row>
-
- <row>
- <entry>0x0e</entry>
- <entry>read</entry>
- <entry>-</entry>
- </row>
-
- <row>
- <entry>0x0f</entry>
- <entry>write</entry>
- <entry>Write All Mask Register Bits</entry>
- </row>
-
- <row>
- <entry>0x0f</entry>
- <entry>read</entry>
- <entry>Read All Mask Register Bits (Intel
- 82374にのみ存在する)</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </sect3>
-
- <sect3>
- <title>0xc0 &ndash; 0xdf DMA コントローラ #2 (Channels 4, 5, 6
- and 7)</title>
-
- <para>DMA アドレス および カウントレジスタ</para>
-
- <informaltable frame="none">
- <tgroup cols="3">
- <tbody>
- <row>
- <entry>0xc0</entry>
- <entry>write</entry>
- <entry>Channel 4 starting address</entry>
- </row>
-
- <row>
- <entry>0xc0</entry>
- <entry>read</entry>
- <entry>Channel 4 current address</entry>
- </row>
-
- <row>
- <entry>0xc2</entry>
- <entry>write</entry>
- <entry>Channel 4 starting word count</entry>
- </row>
-
- <row>
- <entry>0xc2</entry>
- <entry>read</entry>
- <entry>Channel 4 remaining word count</entry>
- </row>
-
- <row>
- <entry>0xc4</entry>
- <entry>write</entry>
- <entry>Channel 5 starting address</entry>
- </row>
-
- <row>
- <entry>0xc4</entry>
- <entry>read</entry>
- <entry>Channel 5 current address</entry>
- </row>
-
- <row>
- <entry>0xc6</entry>
- <entry>write</entry>
- <entry>Channel 5 starting word count</entry>
- </row>
-
- <row>
- <entry>0xc6</entry>
- <entry>read</entry>
- <entry>Channel 5 remaining word count</entry>
- </row>
-
- <row>
- <entry>0xc8</entry>
- <entry>write</entry>
- <entry>Channel 6 starting address</entry>
- </row>
-
- <row>
- <entry>0xc8</entry>
- <entry>read</entry>
- <entry>Channel 6 current address</entry>
- </row>
-
- <row>
- <entry>0xca</entry>
- <entry>write</entry>
- <entry>Channel 6 starting word count</entry>
- </row>
-
- <row>
- <entry>0xca</entry>
- <entry>read</entry>
- <entry>Channel 6 remaining word count</entry>
- </row>
-
- <row>
- <entry>0xcc</entry>
- <entry>write</entry>
- <entry>Channel 7 starting address</entry>
- </row>
-
- <row>
- <entry>0xcc</entry>
- <entry>read</entry>
- <entry>Channel 7 current address</entry>
- </row>
-
- <row>
- <entry>0xce</entry>
- <entry>write</entry>
- <entry>Channel 7 starting word count</entry>
- </row>
-
- <row>
- <entry>0xce</entry>
- <entry>read</entry>
- <entry>Channel 7 remaining word count</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
-
- <para>DMA コマンドレジスタ</para>
-
- <informaltable frame="none">
- <tgroup cols="3">
- <tbody>
- <row>
- <entry>0xd0</entry>
- <entry>write</entry>
- <entry>Command Register</entry>
- </row>
-
- <row>
- <entry>0xd0</entry>
- <entry>read</entry>
- <entry>Status Register</entry>
- </row>
-
- <row>
- <entry>0xd2</entry>
- <entry>write</entry>
- <entry>Request Register</entry>
- </row>
-
- <row>
- <entry>0xd2</entry>
- <entry>read</entry>
- <entry>-</entry>
- </row>
-
- <row>
- <entry>0xd4</entry>
- <entry>write</entry>
- <entry>Single Mask Register Bit</entry>
- </row>
-
- <row>
- <entry>0xd4</entry>
- <entry>read</entry>
- <entry>-</entry>
- </row>
-
- <row>
- <entry>0xd6</entry>
- <entry>write</entry>
- <entry>Mode Register</entry>
- </row>
-
- <row>
- <entry>0xd6</entry>
- <entry>read</entry>
- <entry>-</entry>
- </row>
-
- <row>
- <entry>0xd8</entry>
- <entry>write</entry>
- <entry>Clear LSB/MSB Flip-Flop</entry>
- </row>
-
- <row>
- <entry>0xd8</entry>
- <entry>read</entry>
- <entry>-</entry>
- </row>
-
- <row>
- <entry>0xda</entry>
- <entry>write</entry>
- <entry>Master Clear/Reset</entry>
- </row>
-
- <row>
- <entry>0xda</entry>
- <entry>read</entry>
- <!-- kuriyama - nik typo -->
- <entry>Temporary Register (Intel 82374には存在しない)</entry>
- </row>
-
- <row>
- <entry>0xdc</entry>
- <entry>write</entry>
- <entry>Clear Mask Register</entry>
- </row>
-
- <row>
- <entry>0xdc</entry>
- <entry>read</entry>
- <entry>-</entry>
- </row>
-
- <row>
- <entry>0xde</entry>
- <entry>write</entry>
- <entry>Write All Mask Register Bits</entry>
- </row>
-
- <row>
- <entry>0xdf</entry>
- <entry>read</entry>
- <entry>Read All Mask Register Bits (Intel
- 82374にのみ存在する)</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </sect3>
-
- <sect3>
- <title>0x80 &ndash; 0x9f DMA ページレジスタ</title>
-
- <informaltable frame="none">
- <tgroup cols="3">
- <tbody>
- <row>
- <entry>0x87</entry>
- <entry>r/w</entry>
- <entry>Channel 0 Low byte (23-16) page Register</entry>
- </row>
-
- <row>
- <entry>0x83</entry>
- <entry>r/w</entry>
- <entry>Channel 1 Low byte (23-16) page Register</entry>
- </row>
-
- <row>
- <entry>0x81</entry>
- <entry>r/w</entry>
- <entry>Channel 2 Low byte (23-16) page Register</entry>
- </row>
-
- <row>
- <entry>0x82</entry>
- <entry>r/w</entry>
- <entry>Channel 3 Low byte (23-16) page Register</entry>
- </row>
-
- <row>
- <entry>0x8b</entry>
- <entry>r/w</entry>
- <entry>Channel 5 Low byte (23-16) page Register</entry>
- </row>
-
- <row>
- <entry>0x89</entry>
- <entry>r/w</entry>
- <entry>Channel 6 Low byte (23-16) page Register</entry>
- </row>
-
- <row>
- <entry>0x8a</entry>
- <entry>r/w</entry>
- <entry>Channel 7 Low byte (23-16) page Register</entry>
- </row>
-
- <row>
- <entry>0x8f</entry>
- <entry>r/w</entry>
- <entry>Low byte page Refresh</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </sect3>
-
- <sect3>
- <title>0x400 &ndash; 0x4ff 82374 Enhanced DMA Registers</title>
-
- <para>Intel 82374 EISA System Component
- (ESC)は1996年の初めに発表されました. この中
- には機能的には8237のスーパーセットであり,
- 1つのパッケージの中にその他の PC
- 互換機のコアとなる周辺コンポーネントをも含んだ DMA
- コントローラも含まれています. このチップはEISAとPCI
- 両方のプラットホームをターゲットにしたものであり,
- scatter-gather I/O やリングバッファを始めとして,
- システムDMAをして32ビットの
- アドレス空間全体に直接アクセスする能力も提供しています.
- </para>
-
- <para>これらの機能を使用する場合でも,
- 過去16年間のPC互換機で利用されてきた
- 同等機能を提供するコードも含めておく必要があります.
- 互換性の問題から, 82374の レジスタの一部は,
- 従来の8237のレジスタをプログラムした <emphasis>後</emphasis>
- に, 転送の度にプログラムされる必要があります.
- 8237のレジスタに書き込みを行うとき,
- ソフトウェアの下位互換性のために,
- 82374で追加された一部のレジスタの内容が
- 強制的に0にクリアされるからです.</para>
-
- <informaltable frame="none">
- <tgroup cols="3">
- <tbody>
- <row>
- <entry>0x401</entry>
- <entry>r/w</entry>
- <entry>Channel 0 High byte (bits 23-16) word count</entry>
- </row>
-
- <row>
- <entry>0x403</entry>
- <entry>r/w</entry>
- <entry>Channel 1 High byte (bits 23-16) word count</entry>
- </row>
-
- <row>
- <entry>0x405</entry>
- <entry>r/w</entry>
- <entry>Channel 2 High byte (bits 23-16) word count</entry>
- </row>
-
- <row>
- <entry>0x407</entry>
- <entry>r/w</entry>
- <entry>Channel 3 High byte (bits 23-16) word count</entry>
- </row>
-
- <row>
- <entry>0x4c6</entry>
- <entry>r/w</entry>
- <entry>Channel 5 High byte (bits 23-16) word count</entry>
- </row>
-
- <row>
- <entry>0x4ca</entry>
- <entry>r/w</entry>
- <entry>Channel 6 High byte (bits 23-16) word count</entry>
- </row>
-
- <row>
- <entry>0x4ce</entry>
- <entry>r/w</entry>
- <entry>Channel 7 High byte (bits 23-16) word count</entry>
- </row>
-
- <row>
- <entry>0x487</entry>
- <entry>r/w</entry>
- <entry>Channel 0 High byte (bits 31-24) page
- Register</entry>
- </row>
-
- <row>
- <entry>0x483</entry>
- <entry>r/w</entry>
- <entry>Channel 1 High byte (bits 31-24) page
- Register</entry>
- </row>
-
- <row>
- <entry>0x481</entry>
- <entry>r/w</entry>
- <entry>Channel 2 High byte (bits 31-24) page
- Register</entry>
- </row>
-
- <row>
- <entry>0x482</entry>
- <entry>r/w</entry>
- <entry>Channel 3 High byte (bits 31-24) page
- Register</entry>
- </row>
-
- <row>
- <entry>0x48b</entry>
- <entry>r/w</entry>
- <entry>Channel 5 High byte (bits 31-24) page
- Register</entry>
- </row>
-
- <row>
- <entry>0x489</entry>
- <entry>r/w</entry>
- <entry>Channel 6 High byte (bits 31-24) page
- Register</entry>
- </row>
-
- <row>
- <entry>0x48a</entry>
- <entry>r/w</entry>
- <entry>Channel 6 High byte (bits 31-24) page
- Register</entry>
- </row>
-
- <row>
- <entry>0x48f</entry>
- <entry>r/w</entry>
- <entry>High byte page Refresh</entry>
- </row>
-
- <row>
- <entry>0x4e0</entry>
- <entry>r/w</entry>
- <entry>Channel 0 Stop Register (bits 7-2)</entry>
- </row>
-
- <row>
- <entry>0x4e1</entry>
- <entry>r/w</entry>
- <entry>Channel 0 Stop Register (bits 15-8)</entry>
- </row>
-
- <row>
- <entry>0x4e2</entry>
- <entry>r/w</entry>
- <entry>Channel 0 Stop Register (bits 23-16)</entry>
- </row>
-
- <row>
- <entry>0x4e4</entry>
- <entry>r/w</entry>
- <entry>Channel 1 Stop Register (bits 7-2)</entry>
- </row>
-
- <row>
- <entry>0x4e5</entry>
- <entry>r/w</entry>
- <entry>Channel 1 Stop Register (bits 15-8)</entry>
- </row>
-
- <row>
- <entry>0x4e6</entry>
- <entry>r/w</entry>
- <entry>Channel 1 Stop Register (bits 23-16)</entry>
- </row>
-
- <row>
- <entry>0x4e8</entry>
- <entry>r/w</entry>
- <entry>Channel 2 Stop Register (bits 7-2)</entry>
- </row>
-
- <row>
- <entry>0x4e9</entry>
- <entry>r/w</entry>
- <entry>Channel 2 Stop Register (bits 15-8)</entry>
- </row>
-
- <row>
- <entry>0x4ea</entry>
- <entry>r/w</entry>
- <entry>Channel 2 Stop Register (bits 23-16)</entry>
- </row>
-
- <row>
- <entry>0x4ec</entry>
- <entry>r/w</entry>
- <entry>Channel 3 Stop Register (bits 7-2)</entry>
- </row>
-
- <row>
- <entry>0x4ed</entry>
- <entry>r/w</entry>
- <entry>Channel 3 Stop Register (bits 15-8)</entry>
- </row>
-
- <row>
- <entry>0x4ee</entry>
- <entry>r/w</entry>
- <entry>Channel 3 Stop Register (bits 23-16)</entry>
- </row>
-
- <row>
- <entry>0x4f4</entry>
- <entry>r/w</entry>
- <entry>Channel 5 Stop Register (bits 7-2)</entry>
- </row>
-
- <row>
- <entry>0x4f5</entry>
- <entry>r/w</entry>
- <entry>Channel 5 Stop Register (bits 15-8)</entry>
- </row>
-
- <row>
- <entry>0x4f6</entry>
- <entry>r/w</entry>
- <entry>Channel 5 Stop Register (bits 23-16)</entry>
- </row>
-
- <row>
- <entry>0x4f8</entry>
- <entry>r/w</entry>
- <entry>Channel 6 Stop Register (bits 7-2)</entry>
- </row>
-
- <row>
- <entry>0x4f9</entry>
- <entry>r/w</entry>
- <entry>Channel 6 Stop Register (bits 15-8)</entry>
- </row>
-
- <row>
- <entry>0x4fa</entry>
- <entry>r/w</entry>
- <entry>Channel 6 Stop Register (bits 23-16)</entry>
- </row>
-
- <row>
- <entry>0x4fc</entry>
- <entry>r/w</entry>
- <entry>Channel 7 Stop Register (bits 7-2)</entry>
- </row>
-
- <row>
- <entry>0x4fd</entry>
- <entry>r/w</entry>
- <entry>Channel 7 Stop Register (bits 15-8)</entry>
- </row>
-
- <row>
- <entry>0x4fe</entry>
- <entry>r/w</entry>
- <entry>Channel 7 Stop Register (bits 23-16)</entry>
- </row>
-
- <row>
- <entry>0x40a</entry>
- <entry>write</entry>
- <entry>Channels 0-3 Chaining Mode Register</entry>
- </row>
-
- <row>
- <entry>0x40a</entry>
- <entry>read</entry>
- <entry>Channel Interrupt Status Register</entry>
- </row>
-
- <row>
- <entry>0x4d4</entry>
- <entry>write</entry>
- <entry>Channels 4-7 Chaining Mode Register</entry>
- </row>
-
- <row>
- <entry>0x4d4</entry>
- <entry>read</entry>
- <entry>Chaining Mode Status</entry>
- </row>
-
- <row>
- <entry>0x40c</entry>
- <entry>read</entry>
- <entry>Chain Buffer Expiration Control Register</entry>
- </row>
-
- <row>
- <entry>0x410</entry>
- <entry>write</entry>
- <entry>Channel 0 Scatter-Gather Command Register</entry>
- </row>
-
- <row>
- <entry>0x411</entry>
- <entry>write</entry>
- <entry>Channel 1 Scatter-Gather Command Register</entry>
- </row>
-
- <row>
- <entry>0x412</entry>
- <entry>write</entry>
- <entry>Channel 2 Scatter-Gather Command Register</entry>
- </row>
-
- <row>
- <entry>0x413</entry>
- <entry>write</entry>
- <entry>Channel 3 Scatter-Gather Command Register</entry>
- </row>
-
- <row>
- <entry>0x415</entry>
- <entry>write</entry>
- <entry>Channel 5 Scatter-Gather Command Register</entry>
- </row>
-
- <row>
- <entry>0x416</entry>
- <entry>write</entry>
- <entry>Channel 6 Scatter-Gather Command Register</entry>
- </row>
-
- <row>
- <entry>0x417</entry>
- <entry>write</entry>
- <entry>Channel 7 Scatter-Gather Command Register</entry>
- </row>
-
- <row>
- <entry>0x418</entry>
- <entry>read</entry>
- <entry>Channel 0 Scatter-Gather Status Register</entry>
- </row>
-
- <row>
- <entry>0x419</entry>
- <entry>read</entry>
- <entry>Channel 1 Scatter-Gather Status Register</entry>
- </row>
-
- <row>
- <entry>0x41a</entry>
- <entry>read</entry>
- <entry>Channel 2 Scatter-Gather Status Register</entry>
- </row>
-
- <row>
- <entry>0x41b</entry>
- <entry>read</entry>
- <entry>Channel 3 Scatter-Gather Status Register</entry>
- </row>
-
- <row>
- <entry>0x41d</entry>
- <entry>read</entry>
- <entry>Channel 5 Scatter-Gather Status Register</entry>
- </row>
-
- <row>
- <entry>0x41e</entry>
- <entry>read</entry>
- <entry>Channel 5 Scatter-Gather Status Register</entry>
- </row>
-
- <row>
- <entry>0x41f</entry>
- <entry>read</entry>
- <entry>Channel 7 Scatter-Gather Status Register</entry>
- </row>
-
- <row>
- <entry>0x420-0x423</entry>
- <entry>r/w</entry>
- <entry>Channel 0 Scatter-Gather Descriptor Table Pointer
- Register</entry>
- </row>
-
- <row>
- <entry>0x424-0x427</entry>
- <entry>r/w</entry>
- <entry>Channel 1 Scatter-Gather Descriptor Table Pointer
- Register</entry>
- </row>
-
- <row>
- <entry>0x428-0x42b</entry>
- <entry>r/w</entry>
- <entry>Channel 2 Scatter-Gather Descriptor Table Pointer
- Register</entry>
- </row>
-
- <row>
- <entry>0x42c-0x42f</entry>
- <entry>r/w</entry>
- <entry>Channel 3 Scatter-Gather Descriptor Table Pointer
- Register</entry>
- </row>
-
- <row>
- <entry>0x434-0x437</entry>
- <entry>r/w</entry>
- <entry>Channel 5 Scatter-Gather Descriptor Table Pointer
- Register</entry>
- </row>
-
- <row>
- <entry>0x438-0x43b</entry>
- <entry>r/w</entry>
- <entry>Channel 6 Scatter-Gather Descriptor Table Pointer
- Register</entry>
- </row>
-
- <row>
- <entry>0x43c-0x43f</entry>
- <entry>r/w</entry>
- <entry>Channel 7 Scatter-Gather Descriptor Table Pointer
- Register</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </sect3>
- </sect2>
- </sect1>
-
- <sect1 id="internals-vm">
- <title>FreeBSD VM システム</title>
-
- <para><emphasis>原作: &a.dillon;. 6 Feb 1999</emphasis></para>
-
- <sect2>
- <title>物理メモリ管理 &mdash; <literal>vm_page_t</literal></title>
-
- <para>物理メモリはページ単位に,
- <literal>vm_page_t</literal>構造体を用いて管理されます.
- 物理メモリのページは, ページキューの一つに存在する,
- それぞれの <literal>vm_page_t</literal>
- 構造体の配置によって分類されます.</para>
-
- <para>ページは, wired(ワイヤード), active(活性状態),
- inactive(非活性状態), cache(キャッシュ状態),
- free(使われていない状態)の 各状態をとります. wired
- 状態を除いて, ページは通常
- その状態を示す二重連結リストのキューに置かれます. wired
- 状態のページがキューに置かれることはありません.</para>
-
- <para>FreeBSD は, ページカラーリング(page
- coloring)を実装するため, cache 状態, free
- 状態にあるページ用に,
- さらに複雑なページキューを実装しています. その各々の状態は,
- プロセッサの L1, L2 キャッシュサイズに応じて最適化された
- 多重キューを利用します. FreeBSD は,
- 新たなページを確保(allocate)することが
- 必要になった場合に確保される VM オブジェクトのために, L1, L2
- キャッシュに対して合理的にアライン(align)されたページを
- 得ようと試みます.</para>
-
- <para>加えて, ページは参照カウントとともに保持され,
- ビジーカウントとともにロックされます. VM システムは,
- ページフラグとして PG_BUSY を使う &ldquo;完全ロック状態&rdquo;
- も実装しています.
- </para>
-
- <para>一般的には, 各々のページキューは最長不使用 (LRU)
- 方式で動作します. ページは普通, 最初に wired, もしくは active
- 状態に置かれます. wired 状態の場合,
- そのページはどこかにあるページテーブルに 関連づけられています.
- VM システムはアクティブなキュー内のページをスキャンし, wired
- 状態のページにエイジング (訳注:
- ページ参照頻度を量る手法の一つ; aging) を施します. そして,
- そのページはあまりアクティブでないキューへ
- 移動することになります. cache キューに移動させられたページは,
- 再利用の候補になっている VM
- オブジェクトに割り付けられています. free
- キューにあるページは, 完全に自由の状態にあります. FreeBSD は,
- free キューにあるページ数を最小限にとどめようと 試みますが,
- 割り込み発生時のページ確保を融通するため,
- 完全に自由なページをいくつか持っていなければなりません.
- </para>
-
- <para>プロセスがページテーブルに存在しない,
- ページキューの一つ(例えば, inactive, cache キュー等)に
- 存在するページをアクセスしようとしたとき,
- 比較的負荷の小さなページ再活性化フォールトが起こります.
- システムメモリに全く存在していないページの場合は,
- ディスクからページを読み出す間,
- そのプロセスはブロック(block)されます.</para>
-
- <para>FreeBSD は, ページキューを動的に調節し,
- 同期済(clean)のページ, 同期していない(dirty)ページの分類を
- 合理的に保つのと同様に, それぞれのキューにあるページが合理的な
- 比率に保つように試みます. 再バランス化処理が起こる量は,
- システムのメモリ負荷に依存します. この再バランス化処理は
- ページアウトデーモンによって実装されていて,
- (補助記憶とページを同期して)同期していないページの
- クリーニングすることや, (LRU
- キュー内でのページ位置を再配置したり,
- ページをキューの間を移動することで)ページが頻繁に
- 参照状態にあることに注目すること, キューを均等にするための
- キュー間ページ移動等を伴います.
- ページが実際にどれだけ使われているかを決定するために, FreeBSD
- の VM システムは, ページの再活性化フォールトを 自発的に,
- 合理的な数だけ発生します. これは,
- ページをスワップアウトしたり, クリーニングする時期を
- より良く決めることに繋がります.</para>
- </sect2>
-
- <sect2>
- <title>統合バッファキャッシュ &mdash;
- <literal>vm_object_t</literal></title>
-
- <para>FreeBSD は, 一般化した &ldquo;VM オブジェクト&rdquo;
- という考え方を実装しています. VM オブジェクトは,
- 様々な種類の補助記憶(backing store) &mdash; 補助記憶なし,
- スワップ, 物理デバイス, ファイル, に割り付けられます.
- ファイルシステムは
- ファイルと関連するインコアデータを管理するのに, 同じ VM
- オブジェクトを利用するため,
- 統合バッファキャッシュと呼ばれます.</para>
-
- <para>VM オブジェクトは, <emphasis>シャドウ化</emphasis>
- することができます. シャドウ化とは,
- オブジェクトがそれぞれ互いの上に
- スタック(stack)されるということです. 例えば, MAP_PRIVATE
- mmap() の 動作を実装するために, ファイルに割り付けられた VM
- オブジェクトの上にスタックされた, スワップに割り付けられた VM
- オブジェクトが存在しているでしょう. このスタッキングは, fork
- されたアドレス空間のための 様々な共有属性,
- コピーオンライト(訳注: ページ共有のための 手法の一つ;
- cow,copy-on-write) を実装するのにも利用されています.</para>
-
- <para><literal>vm_page_t</literal> は, 同時に一つの VM
- オブジェクトしか割り付けられることが
- できないことに注意しなければなりません. VM
- オブジェクトのシャドウ化は, 複数のインスタンスが同じページに
- 共有できるように実装されています.</para>
- </sect2>
-
- <sect2>
- <title>ファイルシステム I/O &mdash; <literal>struct
- buf</literal>
- </title>
-
- <para>補助記憶にファイルを使う VM オブジェクトのように, v
- ノードを使う VM オブジェクトは通常,
- 処理されているかどうかという情報を,
- VMシステムが管理する処理情報から独立して
- 管理される必要があります. 例えば, VM
- システムが物理ページと補助記憶を同期させようとしたとき, VM
- システムは, 実際に書き戻す前に,
- ページがクリーニング済であるという
- マークを付ける必要があるわけです. さらに, ファイルシステムは,
- KVM 内で操作できるように, ファイルや,
- ファイルメタデータの一部分を KVM にマッピングすることが
- できなくてはなりません.</para>
-
- <para>これを管理するために使われる実体は,
- ファイルシステムバッファ, <literal>struct buf</literal>,
- <literal>bp</literal> として知られています.
- ファイルシステムに VM オブジェクトの一部を操作することが
- 必要となるときは通常, オブジェクトの部分が struct buf に
- マッピングされ, KVM に struct buf
- 内のページがマッピングされます. 同じ方法で, ディスク I/O
- はオブジェクトの部分を バッファ構造体内にマッピングし,
- その時バッファ構造体上の I/O を 発行することで発行されます.
- 基礎となっている vm_page_t は, I/O 処理の間
- ビジー(busy)状態になります. ファイルシステムにも
- 独立したビジー状態があり, それはハードウェア上の VM
- ページの代わりに ファイルシステムバッファで動作する
- ファイルシステムドライバのコードに とって有用です.</para>
-
- <para>FreeBSD は, マッピングを保持するためにある量に制限された
- KVM を 予約していますが, KVM
- がマッピングを保持するためだけに使われ,
- キャッシュデータの能力を制限しないということは
- 明確にされるべきでしょう.
- 物理データキャッシュを行うことは厳密に
- <literal>vm_page_t</literal> の機能になっており,
- ファイルシステムバッファの機能ではありません. しかし,
- ファイルシステムバッファは placehold I/O に使われるため,
- それは実質的に同時処理可能な I/O 処理量を制限します.
- 通常は二, 三千のファイルバッファが利用可能ですから,
- このことは問題にならないでしょう.</para>
- </sect2>
-
- <sect2>
- <title>マッピングページテーブル &mdash;
- <literal>vm_map_t</literal>,
- <literal>vm_entry_t</literal></title>
- <!-- kuriyama - Eng should use literal and mdash -->
-
- <para>FreeBSD は, 物理ページテーブルの形態を VM
- システムと分離しています.
- ハードウェア上にある全てのプロセス毎のページテーブルは,
- その場その場で再構成され, 通常, 使い捨てだとみなされています.
- KVM を管理するような特殊なページテーブルは,
- 最初に永続的な確保が 行われ,
- これらのページテーブルが破棄されることはありません.
- </para>
-
- <para>FreeBSD は, vm_objects の部分を,
- 仮想メモリのアドレス範囲に <literal>vm_map_t</literal> と
- <literal>vm_entry_t</literal> 構造体を通して割り付けます.
- ページテーブルは, <literal>vm_map_t</literal>
- /<literal>vm_entry_t</literal>/<literal>vm_object_t</literal>
- という階層から 直接つくられます. &ldquo;物理ページは,
- 直接一つの <literal>vm_object</literal> に
- 割り付けられる&rdquo; と私が述べたことを思い出して下さい.
- ええと, そうですね, しかしそれはいつでも完全に当てはまる,
- というわけでもないのです. <literal>vm_page_t</literal> のは,
- 実際に割り付けられた ページテーブルにもリンクされています.
- 一つの <literal>vm_page_t</literal> は
- ページテーブルが呼ばれた時, いくつかの
- <emphasis>pmaps</emphasis> と リンクされることがあります.
- しかし, そのような階層的な割り付けは, 同じ
- <literal>vm_page_t</literal> を参照するオブジェクト内の,
- 同じページへの参照全てを保持しているため, その結果,
- 常にバッファキャッシュの統合を得ることができるわけです.
- </para>
- </sect2>
-
- <sect2>
- <title>KVM メモリマッピング</title>
-
- <para>FreeBSD は, 様々なカーネル構造体を保持するため, KVM
- を利用します. ファイルシステムバッファキャッシュは, KVM
- 内で最も大きなものです. それはつまり, <literal>struct
- buf</literal> の実体に対するマッピングに他なりません.</para>
-
- <para>Linux と異なり, FreeBSD は全ての物理メモリを KVM
- にマッピングしません. これは, FreeBSD が 32
- ビットプラットフォームで 4G バイトまでの メモリを扱える,
- ということを意味します. 実際, MMU
- がそれを可能にしているならば, 理論上, FreeBSD は 32
- ビットプラットフォームで 8TB
- までのメモリを扱うことができることになります. しかし,
- 大部分の 32 ビットプラットフォームは 4G バイトの RAM しか
- マッピングできないようになっている,
- ということには議論の余地があるでしょう.
- </para>
- <!-- kuriyama - This translate is difficult to understand -->
-
- <para>KVM は, いくつかのメカニズムによって管理されています.
- 中心となっているのは, <emphasis>ゾーンアロケータ(zone
- allocator)</emphasis>です. ゾーンアロケータは,
- 特定の構造体型を確保するために KVM の部分(chunk)を得て,
- 一定の大きさのメモリブロックに分割します. <command>vmstat
- -m</command> コマンドで, ゾーンによって 分割された, 現在の
- KVM 利用状況一覧を得ることができます.
- </para>
- </sect2>
-
- <sect2>
- <title>FreeBSD VM システムのチューニング</title>
-
- <para>FreeBSD カーネルでは,
- 動的に自分自身をチューニングするために,
- 協調的な努力が行なわれています. 普通は,
- <literal>maxusers</literal> と <literal>NMBCLUSTERS</literal>
- という カーネルオプション, つまり,
- <filename>/usr/src/sys/i386/conf/<replaceable>CONFIG_FILE</replaceable></filename> で 指定されるもの以外, 変更する必要はありません. 可能なカーネルオプションの一覧は, <filename>/usr/src/sys/i386/conf/LINT</filename> に 記載されています.</para>
-
- <para>大きなシステムに対しては, <literal>maxusers</literal>
- を増やしたいと思うかも知れませんね. この値は普通, 10 から 128
- の間の値にします.
- <literal>maxusers</literal> を増やしすぎるとシステムの利用可能な
- KVM がオーバフローしてしまい,
- 予測できない動作に陥ってしまうことに注意して下さい.
- <literal>maxusers</literal> はある適度な値にとどめておいて,
- 特定のリソースを制御する <literal>NMBCLUSTERS</literal>
- のような, 他のオプションを増加させる方が良いでしょう.
- </para>
-
- <para>もし, システムが負荷の高いネットワーク用途に使われるなら,
- <literal>NMBCLUSTERS</literal> を増やしたいと望むことでしょう.
- この値は普通, 1024 から 4096 の間です.
- </para>
-
- <para><literal>NBUF</literal> パラメータも,
- 伝統的にシステムの規模を決めるのに使われます. これは,
- システムがファイルシステムバッファを I/O のために
- マッピングするのに使われる, KVA
- の大きさを決めるのに使われます. このパラメータは,
- 統合バッファキャッシュには何の影響も与えません. これは
- 3.0-RELEASE 以降のカーネルでは動的にチューニングされるため,
- 普通は手作業で調整されるべきものではありません.
- <literal>NBUF</literal> パラメータは,
- 指定しようとしないことを推奨します.
- システムに選択させれば良いのです.
- 小さすぎる値は極端に非効率的なファイルシステム動作を招き,
- 一方で, 大きすぎる値は wired 状態のページを数多くつくりだし,
- ページキューを枯渇させてしまうでしょう.</para>
-
- <para>デフォルトでは, FreeBSD カーネルは最適化されていません.
- カーネルコンフィグにある <literal>makeoption</literal>
- ディレクティブを使って
- 最適化とデバッグフラグをセットすることができます. ただし,
- それによって得られる大きな (7MB
- 超の)カーネルを相手にするのが嫌なら, <option>-g</option>
- オプションは使ってはいけません.</para>
-
- <programlisting>makeoptions DEBUG="-g"
-makeoptions COPTFLAGS="-O2 -pipe"</programlisting>
-
- <para>sysctl は, 実行時にカーネルパラメータをチューニングする
- 手段を提供しています. しかし, 普通は sysctl 変数, 特に VM
- に関連したものを変更する必要が
- 生じるようなことはありません.</para>
-
- <para>実行時の VM とシステムのチューニングは, 比較的単純です.
- まず, 可能ならば UFS/FFS ファイルシステムで softupdates
- を使いましょう.
- <filename>/usr/src/contrib/sys/softupdates/README</filename>
- のファイルに,
- 設定方法に関する手順(と制限)について書かれています.
- </para>
-
- <para>次に, 十分なスワップを設定します. &ldquo;作業&rdquo;
- ディスクを含む 各物理ディスク装置毎に一つずつ
- (最大四つまで)のスワップパーティションを 設定すべきです.
- 少なくとも, メインメモリの 2 倍の スワップ空間が望ましく,
- メモリがあまりない場合には,
- おそらくそれより多く必要になります. また,
- スワップパーティションのサイズは,
- 後でパーティションをつくり直しする必要がないように
- マシンに設定したいメモリ設定の最大値を基準に
- 決めるべきでしょう. もし, クラッシュダンプをとりたい場合,
- スワップパーティションは最低限メインメモリと同じの大きさで,
- <filename>/var/crash</filename> にはダンプを保持するのに十分な
- 空きがなければなければなりません.</para>
-
- <para>NFS 経由のスワップは, -4.x
- 以降のシステムで完全に動作しますが, NFS サーバ側では,
- ページングがその負荷の主な原因になることに
- 注意しなければなりません.</para>
- </sect2>
- </sect1>
-</chapter>
-
-<!--
- Local Variables:
- mode: sgml
- sgml-declaration: "../chapter.decl"
- sgml-indent-data: t
- sgml-omittag: nil
- sgml-always-quote-attributes: t
- sgml-parent-document: ("../handbook.sgml" "part" "chapter")
- End:
--->