PWMドライバを書こうと思っています。ハードウェアドライバーを制御する方法は2つあることを知っています。
一般に(PWMドライバーの場合は考慮しない)、ユーザー空間とカーネル空間のどちらのドライバーを使用するかを決定する必要があります。では、これらとは別に考慮しなければならない要素は何でしょうか。
あなたがリストしたこれらの3つの要因から、最初のものだけが実際に正しいです。残りに関しては、実際にはそうではありません。ユーザー空間コードがDMA=操作を実行することは可能です—問題ありません。この技術を製品に採用しているハードウェアアプライアンス企業は多数あります。また、割り込み駆動型にすることも可能です。すべてのI/Oが完全なカーネルバイパスで行われている場合でも、ユーザー空間アプリケーション。もちろん、_/dev/mem
_でmmap()
を実行するだけでは簡単ではありません。
カーネルにはドライバーの最小限の部分を含める必要があります。これは、ユーザー空間にカーネルから必要な最小限の情報を提供するために必要です(考えれば、_/dev/mem
_もキャラクターデバイスドライバーによってバックアップされます)。
DMAの場合、実際には非常に簡単です。mmap
要求を処理し、DMAバッファーをユーザー空間にマップするだけです。割り込みの場合は、少しトリッキーですが、割り込みは何があってもカーネルによって処理される必要がありますが、カーネルは何もせず、たとえばepoll_wait()
を呼び出すプロセスをウェイクアップするだけです。別のアプローチは、 DOSEMUによって行われるプロセスへのシグナルですが、それは非常に遅く、推奨されません。
あなたの実際の質問に関して、あなたが考慮に入れるべき1つの要素はリソース共有です。複数のアプリケーション間でデバイスを共有する必要がなく、ユーザースペースで実行できないことがない限り、ユーザースペースに移動します。ユーザー空間のコードを書くのは非常に簡単なので、おそらく開発サイクルの時間を大幅に節約できます。ただし、2つ以上のアプリケーションがデバイス(またはそのリソース)を共有する必要がある場合は、非常に多くの時間を費やしてそれを可能にする可能性があります。複数のプロセスが同時にフォーク、クラッシュ、マッピング(同じ?)することを想像してみてください。結局のところ、IPCは一般にカーネルを介して行われるため、アプリケーションが互いに「対話」を開始する必要がある場合、パフォーマンスが大幅に低下する可能性があります。これは実際に行われますただし、特定のパフォーマンスが重要なアプリケーションの場合は、これらの詳細については説明しません。
もう1つの要因は、カーネルインフラストラクチャです。ネットワークデバイスドライバーを作成するとします。ユーザー空間でそれを行うことは問題ではありません。ただし、これを行う場合は、カーネルに存在するLinuxのデフォルトのスタックを使用することができないため、完全なネットワークスタックも作成する必要があります。
可能であれば、ユーザースペースを確保し、物事を機能させるための労力はカーネルドライバーを書くよりも少なく、いつかコードをカーネルに移動する必要があるかもしれないことを覚えておいてください。実際、これは、マクロが定義されているかどうかに応じて、ユーザー空間とカーネル空間の両方に対して同じコードをコンパイルするのが一般的な方法です。ユーザー空間でのテストの方がはるかに楽しいからです。
別の考慮事項:ユーザー空間ドライバーのデバッグははるかに簡単です。 gdb、valgrindなどを使用できます。まあ、Cでドライバーを書く必要すらありません。
ユーザースペースまたはカーネルスペースドライバーだけでなく、3つ目のオプションもあります。カーネルドライバーでは、カーネルスペースのみの処理を実行し、その他のことはすべてユーザースペースで実行できます。 Linux UIOドライバーフレームワークを使用している場合は、カーネルスペースドライバーを作成する必要がない場合もあります( https://www.kernel.org/doc/html/latest/driver-api/uio-howto.htmlを参照)。 )。
私は、ほとんど完全にユーザー空間でDMA対応ドライバーを書くことができました。 UIOはインフラストラクチャを提供するため、ファイルを読み取る/選択する/ポーリングするだけで、割り込みを待つことができます。
DMAディスクリプタをユーザー空間からプログラミングすることのセキュリティへの影響を認識する必要があります。デバイス自体またはIOMMUに何らかの保護がない場合、ユーザー空間ドライバーがデバイスに読み取りを行わせる可能性があります。または、物理メモリ内の任意のアドレスに書き込みます。