世界を動かす技術を、日本語で。

ユーザースペースにおけるPCIeデバイスエミュレーションのためのLinuxカーネルフレームワーク

概要

PCIem は、Linuxカーネル上でユーザ空間のみで動作する PCIeデバイスエミュレーションフレームワーク。 実ハードウェア不要で PCIeドライバの開発・テスト を実現。 BAR、DMA、割り込み などのPCIe機能を包括的にサポート。 QEMU などのユーザ空間アプリでプロトタイプ作成が可能。 MIT/GPLv2デュアルライセンス で公開。

PCIemとは何か

  • PCIem は、Linuxカーネル内で 仮想PCIeデバイス を生成するフレームワーク
  • 新規技術 により、合成カードを 正規のPCIデバイス としてホストOSに認識させる
  • 実機ハードウェア不要 でPCIeデバイスドライバの 開発・検証 を可能にする仕組み
  • PCIemフレームワーク を使い、ユーザ空間からデバイス挙動を自在にエミュレート

アーキテクチャ

  • Linuxカーネルユーザ空間 の2層構成
    • /dev/pciem デバイスファイルを介した PCIem Framework の実装
      • PCI Config SpaceBARマッピング のエミュレーション
      • INT/MSI/MSI-X割り込み の動的トリガー
      • DMA (IOMMU対応/非対応)や P2P DMA もサポート
    • Userspace PCI shim によるPCIeデバイスロジックの実装
      • ユーザ空間アプリが PCIem を通じてデバイス制御を実現
  • 既存のPCIeドライバPCIem の存在を意識せず動作可能

主な機能

  • BAR(Base Address Register)管理
    • プログラムによるBAR登録・管理機構
  • ウォッチポイント
    • CPUウォッチポイントによるイベント駆動型アーキテクチャ
  • 割り込みサポート
    • Legacy IRQ/MSI/MSI-X の全サポートと動的トリガー
  • PCI Capabilityフレームワーク
    • モジュール式PCI機能システム(内部はリンクリスト構造)
  • DMAシステム
    • IOMMU対応 DMA操作とアトミックメモリ操作サポート
  • P2P DMA
    • デバイス間ピアツーピアDMA(ホワイトリストベースのアクセス制御)
  • ユーザ空間定義型
    • PCIeプロトタイプを 任意のユーザ空間アプリ で実装可能

利用例

  • ProtoPCIemカード
    • QEMU 上でカード全体をプログラムし、初期化やコマンド処理をユーザ空間で実現
    • DOOM などのソフトウェアレンダリングゲームを動作可能
    • OpenGL 1.X ゲーム(例:tyr-glquake、xash3d)もQEMU内のカスタムOpenGLステートマシンで描画
    • DMA経由でフレームをカードに送信し、QEMUが表示

ライセンス

  • pciem_framework.c および protopciem_driver.cMIT/GPLv2デュアルライセンス
  • その他の部分は MITライセンス

参考リンク

Hackerたちの意見

うーん… Raspberry Piとか、もっとパワフルなデバイスを使ってPCIeカードをエミュレートできるようになるのかな? 1xから16xスロットまで、マシンに差し込むことができるネットワークカードをエミュレートするカードのアイデアが面白いな。VPNとか他のことをカード上で動かして、ホストからオフロードできるし、ストレージとしても使える。ZFSを動かせるだけのパワーがあって、いくつかのディスクをまとめてホストに1つのディスクとして見せることができれば、ZFSがサポートされていないデバイスでも使えるようになる。でも、これは簡単なことじゃないだろうな…

stm32mp2シリーズのMCUみたいなものでLinuxを動かして、MCUのカーネルモジュールから制御できるPCIeエンドポイントとして使えるんだよね。そうすれば、任意のPCIeデバイスをプログラムできるけど、速度記録を更新することはないだろうし、PHYはPCIe 1xに制限されてるかも。

… それともイーサネット経由のPCIe ;)

他のデバイスを使ってPCIeカードをエミュレートする これに対する他の解決策はFPGAカードだね: https://www.fpgadeveloper.com/list-of-fpga-dev-boards-for-pc... 価格の幅が広いのに注意。FPGAツールも扱わなきゃいけないけど、その分タイミングがずっと良くなるよ。

こんにちは!作者です!実際には、ホストのリアルドライバが行うトランザクションを、どこにでもオフロードできるんですよ。PCIは遅延に強いから、デバイスと交渉することが多いし、効率的にスループットを管理できれば、特に問題はないと思います。PCIemが特別なのは、ドライバが行うアクセスに関してほぼ自由にできることです。完全に自由です。私はシンプルなNVMEコントローラを作ったんですが(1GBのドライブをmallocしただけ)、それがローカルのPCIバスに現れます(通常のLinuxのnvmeブロックドライバもちゃんと接続できます)。フォーマットしたり、マウントしたり、ファイルやフォルダを作ったり…結構面白いです。あと、QEMUの中に作ったシンプルなラスタライザもあって、それにドライバを書きたかったんですが、存在しないので、PCIemを使ってドライバの書き込みをカードをホストしているQEMUインスタンスにリダイレクトしました(そのおかげでソフトウェアレンダリングのDOOMやOpenGL 1.XベースのQuake、Half-Lifeポートが動かせました)。

一部のARMチップはPCIeエンドポイントモードができて、カーネルはnvme SSDのふりをするサポートがありますよ。 https://docs.kernel.org/nvme/nvme-pci-endpoint-target.html

最近、DMAチートカードを買ったんだけど、実はただのFPGA PCIeカードなんだ。まだいじってみてないけど、ソフトウェアで本物のPCIeカードをエミュレートするのは難しそうだね。PCIeはかなり高速だから。

これがDPUの役割だよ。

こういうことは、Plan 9みたいなOSではめちゃくちゃ簡単。単一のプロトコル、9Pを使うだけだから。Ethernetデバイスは抽象化されて、カーネルによってファイルシステムとして提供されるんだ。すべてが9Pだから、サーバーがどこで動いてるかなんて気にしない。ローカルのカーネル内サーバーでも、ユーザースペースのサーバーでも、TCPやIL、PCIeリンク、RS232ポート、SPI、USBなどの任意の双方向リンクを介したリモートサーバーでもOK。これで、他のマシンから個々のハードウェアやネットワークスタック(ip(3)や任意の9Pサーバー)をプロセスのローカル名前空間にマウントできる。プロセスごとの名前空間を使えば、ファイルシステムの見え方をカスタマイズできるし、その子プロセスも同様にカスタマイズできる。9frontをOcteonチップで動かすことに興味がある人もいるよ。これができれば、Octeonカードで好きなものを動かせるようになるし(Plan 9のクロスプラットフォームは一級品だから)、ホストのルートファイルシステムを使ってカードをブートしたり、ホスト上でプログラムを書いてテストしたり、objtype環境変数をmips/armに変更して、Octeon用のバイナリをビルドして、rcpuを使ってOcteonで実行したりできる。必要なのは、Octeon上で動くカーネルとホストのカーネルドライバだけで、あとはすぐに使える状態になるよ。

追加の処理能力や再構成の容易さのために、1つ以上の(再プログラム可能な?)FPGAをそのカードに追加できるかも……なんでこういうFPGA付きのカードがレトロコンピュータのエミュレーションやシミュレーションに使われてないのか、ずっと不思議に思ってたんだよね。

これがDMAカードのやることだよ。

ドライバーや本物のハードウェアを開発しているなら、これは大きな勝利だね。ボタン一つでプロトコルを反復できるから。

確かに、このプロジェクトはいくつかのバージョンを経てきました(最初はAPIを呼び出すためにセカンダリモジュールが必要なモノリシックカーネルモジュールでした)。よりユーザースペースに優しい使い方に進化させたのは、変更をもっと早く繰り返せるようにするためです。合成PCIデバイスを作成するのは、プログラムしたユーザースペースのシムを開くだけで簡単にできます。そうすると、バスに現れます。新しい変更をテストしたいときは、シムを通常通り閉じれば(実質的にバスから取り除くことになります)、このプロセスを必要なだけ繰り返せます。

PCIEハードウェアやドライバの開発にどう役立つのか、素人にもわかるように説明してもらえますか?もっと堅牢なユニットテストを書いたり、実際のハードウェアにアクセスする前にベアボーンのドライバを開発することを想像できますが、そこから先はちょっと想像がつかないです。

ちょっと別の質問だけど、PCIeは学ぶ/投資するにはかなり将来性のある技術だよね? 次の5〜10年で廃れる可能性は低いと思うんだけど(USBみたいに)?

来年には光コネクタに置き換わるかもしれないけど、誰が事前に分かるんだろうね。今のところ競争はないし。

どちらも5年後には廃れないよ。リブランドされたり、いろんな拡張が出たりするかもしれないけど、巨大なインストールベースがあるから急激な変化は考えにくい。FirewireもThunderboltもUSBを駆逐できなかったし。

何を学ぶって言ってるの?TLPについて?XDMAみたいなFPGAのDMAエンジンについて?PCIeスイッチやリタイマーについて?それともlspciについて?

PCIeは今のところ、最も将来性のある技術だと思う。ハードウェアレベルで変わっても、ソフトウェアの観点から見ると、デバイスの任意のレジスタをメモリマップされた場所に公開するだけだからね。PCIeデバイスのソフトウェアドライバは、これからも変わらず動くよ。

PCIeの専門知識は、このフォーラムにいる誰よりも長生きするだろうね。

特定のタイミング条件やデバイスからの不正なレスポンスでしか現れないドライバのバグにやられたことがあるので、感謝です。

いつでもどうぞ!あなたのニーズに合って、こういう問題を追跡するのにあまり時間をかけずに済むといいですね。コメントありがとう!

USBのvhci-hcdは、USB開発にめっちゃ役立ってる。特にCIでUSBドライバのコードをテストするのに便利だね。

つまり、これを動かすためには、物理マシンをブートする時にカーネルコマンドライン引数でRAMを予約しなきゃいけないってこと? 予約するRAMの量はBARメモリ用なの? 複数のPCIemデバイスが必要な場合(できるのかな?)は、それぞれのためにRAMを予約する必要があるの?

こんにちは!その通りだよ。仮想BARトリックのために、Linuxが「予約済み」と呼ぶメモリの一部を確保する方法が必要なんだ。現在、PCIemは単一のデバイスしか考えてないけど(まずは動くものが必要だったからね)、動的に「予約済み」メモリプールを共有できる複数のデバイスのサポートが計画されてるから、複数のデバイス用に複数のBARを持つことができるようになるよ。

それって、QEMUでデバイスをエミュレートするのや、libvfio-userみたいなものでやるよりもどういいの?

libfvio-userってクールなプロジェクトだと思うし、ちゃんと動いてるよね。ホストのユーザースペースにデバイスを置いて、VM(この場合はQEMU)に公開したいならだけど。PCIemも似たようなことをするけど、レベルが一つ下がる感じ。要するに、ホストのPCIバスにデバイスをポップするから、実際の未修正ドライバがカードのユーザースペース実装とやり取りできるんだ。QEMUもVMもハイパーバイザもいらない。もちろん、例えば、すべてのアクセスをQEMUに転送するってわけじゃないけど(すでにQEMUにカードを定義してる人や組織もいるから、同じことを何度も定義するのはちょっと無意味だよね?)。だから、ホスト上でドライバを直接試したい場合は、QEMUの機能的エミュレーションを維持しつつ、基本的に自分のQEMUのものをPCIemにくっつけることができる。PCIemは、KVMのクールな人たちがやってることを真似しようとするAPIでアクセスを抽象化してくれるんだ。

これは、2000年代にWindows用にあったデバイスシミュレーションフレームワークのLinux版みたいなもんだね。以下のプレゼンテーションではUSBの機能だけが話されてるけど、PCIデバイスもシミュレートできたんだよ。 https://download.microsoft.com/download/5/b/9/5b97017b-e28a-...

これをmacOSでどうやってやるの?