web-dev-qa-db-ja.com

PCIデバイスにはどのようにアクセスしますか?

PCIバスに関して2つの質問があります。

デバイスドライバーはPCIバス上のデバイスにどのようにアクセスしますか?デバイスに割り当てられたメモリ領域に書き込むだけで十分ですか(mov memory_space_allocated_for_dev, something、デバイスがメモリマップされている場合、またはout io_space_allocated for_dev, somethingそうでない場合)(ハードウェアは、メモリ位置にアクセスするこの試みを、PCIバス上の一連のPCIコマンドなどに変換しますか?)。

すべてのPCIバスにすべてのデバイスをセットアップした後(つまり、メモリスペースの割り当て、バスの列挙など)、デバイスドライバーは、PCIバスが存在するかどうか、またはメモリのデコードが単純なデコーダーで行われるかどうかを知る必要がないというのは正しいですか(古いコンピューターのように) )(つまり、デバイスにアクセスするために、いくつかのメモリ位置から書き込みと読み取りを行うだけです)?

4
maplaz

メモリマップされたPCI(e)デバイスには、デバイスに割り当てられるメモリの量をホストに知らせるBAR(ベースアドレスレジスタ)があります。 BIOS(および後のOS)は、要求されたメモリスペースをターゲットデバイスに割り当てます-メモリではないアドレス、物理ビットは割り当てられていません。さらに、これは通常、仮想メモリアドレスではなく、物理メモリアドレスになります。 Linuxカーネルは、物理メモリの仮想メモリアドレスへのマッピングを可能にするmmap()などの関数を使用して、これらのデバイスへのアクセスを調停します。

たとえば、8個のLEDを制御するPCIeデバイスがあるとします。デバイスの作成者として、1Kのアドレススペースの非常に小さなBARをリクエストできます。 BIOSは、0xE000_0000から0xE000_0400の32ビットシステムで物理アドレスを提供する場合があります(補足:32ビットシステムと大きなVRAMを備えたGPUが一緒にうまく機能しなかった理由をここで確認する必要があります)。

ここで、1バイトの書き込みで0xF0をメモリロケーション0xE000_0000に書き込むと、LED 7〜4がオンになり、3〜0がオフのままになります。それだけです-単純なメモリマップI/Oです。 Linuxでは、抽象化レイヤーを追加して、その優れたPCIサブシステムを利用し、特定のベンダーID +デバイスID文字列に対してロードされるドライバーを記述します。次に、そのカーネルドライバーを呼び出すユーザー空間アプリを作成できます。mmap()呼び出しでメモリをユーザー空間にマップできます。これにより、ユーザー空間アプリケーションは、変換されて終了する仮想メモリアドレスに対してバイト読み取り/書き込みを実行できます。それが属する物理メモリ空間。

x86にはもちろんI/Oスペースがあり、動作は非常に似ていますが、カーネルの低レベル、outb/outw/outl(およびそれらの入力のいとこ)命令がI/Oスペースからの書き込み/読み取りに使用される点が異なります。対メモリの読み取り/書き込み命令。繰り返しますが、カーネルはセキュリティやそのようなメモリへのアクセスを担当しているため、ユーザースペースアプリはioctls()とマップされたメモリセグメントを介して通信している必要があります。

2番目の質問については、上記に少し溶け込んでいますが、Linux用の最新のPCIeドライバーは、多くの低レベルのハウスキーピング関連のものをPCIサブシステムに依存します。ほとんどの場合、担当するベンダー/デバイスIDを定義してから、IRQを取得してデバイスのセットアップを行う.probe()関数を記述します。つまり、メモリが渡されます。

7
Krunal Desai

しばらく経ちましたが、正しく思い出せば、カーネルドライバは/ devにデバイスをセットアップし、BIOSまたはカーネルのいずれかによってPCIデバイスに割り当てられたメモリアドレスにマップします。次に、適切な権限を持つユーザースペースプログラムが、その/ dev /ファイルを開いたり、読み取り/書き込み/シークしたり、閉じたりして、PCIデバイスと対話します。 Linuxデバイスドライバーの第12章を参照してください: https://lwn.net/Kernel/LDD3/

0
Isaac