* PCIコンフィグレーションに関するページ [#lcc0722f]
-自作OSでPCIデバイスをコントロールしたくなる事はあるでしょう。そのための情報をまとめました。
--今じゃほとんどのデバイスがPCIデバイスですしね・・・。
-それぞれのPCIデバイスは最低でも64バイト、最大では256バイトのコンフィグレーションレジスタを持ちます。ここにデバイスを特定するための情報が書いてあります。また、どのI/Oポートアドレス、どのメモリアドレス、どのIRQを使用してデバイスをコントロールするのかを設定するのもこのレジスタを使います(PnPってやつですね)。

* コンフィグレーションレジスタにアクセスする方法 (AT互換機の場合) [#j7d596a1]
-利用するI/Oポート
--CONFIG_ADDRESSレジスタ(0x0cf8、32bit、Read/Write可)
---bit0-1:0に固定
---bit2-7:レジスタアドレス
---bit8-10:機能番号
---bit11-15:デバイス番号
---bit16-23:バス番号
---bit24-30:リザーブで、0に固定
---bit31:イネーブルビットで、1に固定
--CONFIG_DATAレジスタ(0x0cfc~0x0cff、任意のサイズ、Read/Write可)
---CONFIG_ADDRESSレジスタのイネーブルビットが0の場合は、ここはCONFIG_DATAレジスタにはならない
-PCIのコンフィグレーションレジスタにアクセスしたいときは、CONFIG_ADDRESSレジスタのイネーブルビットを1にします。アクセスが済んだら0に戻しておくといいでしょう。
-0x0cf8へのワードやバイト幅のアクセスは、CONFIG_ADDRESSレジスタのアクセスとは見なされません。必ずOUT(DX, EAX);命令を使い、32bitアクセスしてください。
-bit0-7をレジスタアドレスと考えるといいかもしれません。0x00~0xfcが指定できます。4の倍数しか指定できないことに注意してください。
-機能番号は、0~7の値を取り、一つのデバイスに複数の機能が搭載されている場合に、それらを区別して扱うための番号です。
--デバイスが存在するなら、まず機能番号0に何らかの機能が割り振られます。そして機能番号0のデバイスにマルチファンクションであることを示すビットが1になっています。これを見付けたら機能番号1~7を検索するとよいでしょう。二番目のファンクションの機能番号が1であるとは限りません。
-デバイス番号は0~31です。つまり一つのPCIバスに最大で31個のデバイスを付けられます。もっともうちのM/Bは5個しかPCIスロットがありませんが。
-バス番号は0~255です。0から始まります。システムは最大255本のPCIバスを持てます。
--こう考えてください。まずバス番号0のPCIバスがあり、これがチップセットに直接つながっています。そしてこのPCIバスにPCI-PCIブリッジデバイスがくっついていて、その先にはまた別のPCIバスがあるのです(たとえばAGPバスはそういう第二のPCIバスなのです。・・・ハード的にはどうであるにしろ、PCIデバイスとしてアクセスする範囲においてはそう見えるわけです)。
--したがってブリッジの設定がうまくいっていないと、バス番号1以上にはうまくアクセスできないかもしれません(変な設定をしたことがないので失敗するかどうかも分かりませんが)。

* 全デバイス共通のコンフィグレーションレジスタ [#k5f45a5b]
-ベンダID(0x00のbit0-15、多分リードオンリー)
--[[(PCI)vendor]]にベンダーIDのリストがあります
-デバイスID(0x00のbit16-31、多分リードオンリー)
-コマンドレジスタ(0x04のbit0-15、リードライト可)
--それぞれのbitについて0固定だったりするデバイスがあります。たとえばメモリ空間しか使わないデバイスは、I/O空間イネーブルはリードオンリーで0固定の場合があるでしょう。
--bit0:I/O空間イネーブル  これが0だとI/Oポートへのアクセスは全て無視される
--bit1:メモリ空間イネーブル  これが0だとメモリ空間へのアクセスは全て無視される
--bit2:バスマスター
--bit3:スペシャルサイクル
--bit4:メモリライト&インバリデートイネーブル
--bit5:VGAパレットスヌープ
--bit6:パリティエラー応答  これが0だと仮にパリティーエラーを検出しても報告されない
--bit7:ウェイトサイクル制御
--bit8:SERR#イネーブル
--bit9:高速バックツーバックイネーブル
--bit10-15:リザーブ
-ステータスレジスタ(0x04のbit16-31、リードライト可)
--ステータスなので原則としては読み込みが主になりますが、書き込みもできます。
--これはどういうことなのかというと、ステータスレジスタは自動でフラグが立つだけで、フラグのクリアのタイミングはソフトウェアが指定します。CPUからデータを書き込むと、そのデータで1になっているbitが0クリアされます。
--でも多分bit21-23、25-26はクリアできない読み出し専用だと思います。
--bit16-20:リザーブ
--bit21:66MHz対応可能
--bit22:ユーザ定義機能あり
--bit23:高速バックツーバック可能
--bit24:データパリティエラー検知(バスマスター時のエラー)
--bit25-26:DEVSEL#タイミング  00:高速 01:中速 10:低速 11:リザーブ
--bit27:ターゲットアボート通知
--bit28:ターゲットアボート受信
--bit29:マスタアボート受信
--bit30:システムエラー通知
--bit31:パリティエラー検知
-リビジョンID(0x08のbit0-7、多分リードオンリー)
-クラスコード(0x08のbit8-31、多分リードオンリー)
--プログラムインターフェース(bit8-15)
--サブクラス(bit16-23)
--ベースクラス(bit24-31)
--[[(PCI)class]]にクラスコードのリストがあります
-キャッシュラインサイズ(0x0cのbit0-7)
-マスタレイテンシタイマ(0x0cのbit8-15)
-ヘッダタイプ(0x0cのbit16-23、多分リードオンリー)
--bit16-22:デバイスのタイプ  0:通常のPCIデバイス 1:PCI-PCIブリッジ 2:CardBusブリッジ
--bit23:マルチファンクションデバイス
-BISTレジスタ(0x0cのbit24-31)
-レジスタ0x10以降はデバイスのタイプ(ヘッダタイプ参照)によって構成が異なります

*普通のPCIデバイスの場合のコンフィグレーションレジスタ [#c9c4b9b0]
-(普通のPCIデバイスの場合=ヘッダタイプのデバイスのタイプが0の場合です)
-ベースアドレス0(0x10のbit0-31、リードライト可)
-ベースアドレス1(0x14のbit0-31、リードライト可)
-ベースアドレス2(0x18のbit0-31、リードライト可)
-ベースアドレス3(0x1cのbit0-31、リードライト可)
-ベースアドレス4(0x20のbit0-31、リードライト可)
-ベースアドレス5(0x24のbit0-31、リードライト可)
--I/OポートやメモリマップトI/Oのアドレスを指定します。
--bit0:空間種別(このbitはリードオンリー)  0:メモリ空間 1:I/O空間
---どちらなのかでbit構成が変わります
--メモリ空間の場合:
---bit1-2:タイプ(このbitもリードオンリー)  00:32bit空間の任意の位置 01:1MB以下のメモリ空間 10:64bitアドレスの任意の位置 11:リザーブ
---bit3:プリフィッチ可能(このbitもリードオンリー)
---bit4-31:ベースアドレス(リードオンリーとリードライト可能bitの混在)
---64bitPCIの場合、ベースレジスタは次のやつを上位アドレス用に使うのかな???
--I/O空間の場合:
---bit1:リザーブにつき0固定(このbitはリードオンリー)
---bit2-31:ベースアドレス(リードオンリーとリードライト可能bitの混在)
--ベースアドレスは、要求する空間サイズに応じて下位bitが0に固定されています。これを次のように使います。
---まず、ベースアドレスに0xffffffffを書き込み、そしてこのベースアドレスを読み出します。そうすると0に固定されていない部分のbitが1になって読めます。例えば0xffff0000が読み出されたとしましょう。
---そうなると、これはメモリ空間要求ベースアドレスで、4GBの任意の場所に設定可能で、しかも64KBの空間を要求していると分かります。ということでふさわしい値を設定してやってください。
---このような仕様のため、PCIデバイスでは、メモリマップトI/Oのサイズは16バイト以上、I/O空間の消費ポートサイズは4バイト以上です。
---設定中にアクセス用のアドレスが変わるわけで、これがまずいという場合は、コマンドレジスタでメモリ空間やI/O空間をディゼーブルにしてから行なうといいでしょう。
--例えばベースアドレスを3本使う場合はベースアドレス0~2が使われる、というルールはありません。飛び飛びで使っているデバイスもあります。
-CardBus CIS(0x28のbit0-31)
-サブシステムベンダID(0x2cのbit0-15、多分リードオンリー)
--コードと社名の関係は多分ベンダIDと同じです。
-サブシステムID(0x2cのbit16-31、多分リードオンリー)
-拡張ROMアドレス(0x30のbit0-31)
-新機能ポインタ(0x34のbit0-7)
-リザーブ(0x34のbit8-31と0x38のbit0-31)
-インタラプトライン(0x3cのbit0-7、リードライト可能)
-インタラプトピン(0x3cのbit8-15)
--これが0なら割り込みを使わないデバイス
-最小グラント(0x3cのbit16-23)
-最大レイテンシ(0x3cのbit24-31)
-ベンダ定義(0x40~0xfcのbit0-31)

*PCIデバイスの探し方 [#uac5a005]
-まずPCIデバイスのどのスロットに何が刺さっているのかを把握しないと、設定のしようがありません。次のような方法で探します。
-とりあえず、バス番号0について、デバイス番号を0~31のそれぞれについて、機能番号0のベンダーIDを読み出します。
-PCIのルールで、何も接続されていないデバイス番号を指定したときは、常にCONFIG_DATAから0xffffffff(32bit時)、0xffff(16bit時)、0xff(8bit時)が読み出されることになっています。
-0xffffのベンダIDはないので、ベンダIDが0xffffかどうかでそこにデバイスがあるのかないのかが分かります。
-もし他にもバスがあるなら、そのバスも検索しましょう。
--かつて僕はバスがあるかないかを判定するのが面倒で、0~255の全てのバスの、デバイス番号0~31の全てを検索させましたが、これでもそんなには時間はかかりませんし、同じデバイスが二度検出されるということもありませんでした。おすすめではありませんが、まあこれでもできないことはないよ、ということで。
-機能番号0で読み出してマルチファンクションであると書かれていたら、そのデバイスに関しては機能番号1~7についても検索してください。
--かつての僕はこれもサボって、マルチファンクションであってもなくても、とにかく機能番号0~7の全てを検索させてみたことがあります。たいていのデバイスはこれでもちゃんと判定できるのですが、一部のデバイスは機能番号のデコードをサボっているらしく、シングルファンクションの同じデバイスが8個検出されるなんてことがありました。手抜きは駄目ってことらしいです(笑)。

* PCIデバイスの使いかた(PnPのやりかた?) [#w23c9190]
-まずデバイスを探します。探し方は上記参照。
-見付けたデバイスが何であるかは、ベンダID、デバイスID、サブシステムベンダID、サブシステムID、クラスコード、リビジョンなどをもとに自前でデータベースを持って判定します。
-コマンドレジスタでメモリ空間とI/O空間をディゼーブルにして要求しているリソースを設定し、そののちにメモリ空間とI/O空間をイネーブルにしてやります。
-対応するドライバが用意できていないデバイスについては、メモリ空間とI/O空間をディゼーブルにしたままにしておけばいいでしょう。
-IRQの割り当てはチップセット側の設定も必要のようです。PCI用に使う割り込みはレベルトリガモードに変更しなければいけないからです(PC/ATでは原則として割り込みはエッジトリガで、PICの設定もエッジトリガを指定しなければいけない。これを個別にレベルトリガモードにするための設定がPCI対応のチップセットには存在する)。

* PCI-PCIブリッジ [#h694c818]
-AGPやCardBusは、PCIからすればちょっと特別なPCI-PCIブリッジとして振る舞う・・・とかなんとかを書く予定

* こめんと欄 [#wdfdca71]
-なんかの拍子にこのページが消えてしまったらしいのを復活させました。 -- [[K]] SIZE(10){2004-01-03 (土) 14:06:05}
-デバイス -- [[名無しさん]] SIZE(10){2005-01-28 (金) 21:00:55}

#comment


トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS