カーネル空間に複数のバッファーを割り当てるカーネルドライバーがあります (物理的に連続し、ページ境界に整列し、整数のページで構成されます)。次に、ドライバーがこれらのバッファーの一部をユーザー空間に mmap できるようにする必要があります (もちろん、mmap() 呼び出しごとに 1 つのバッファー)。ドライバーは、その目的のために単一文字デバイスを登録します。ユーザー空間プログラムは、mmap したいバッファーをカーネルに伝えることができなければなりません (たとえば、そのインデックスまたは一意の ID、または以前に ioctl() によって解決された物理アドレスを指定することによって)。
たとえば、(ユーザー空間から) mmap() のオフセット パラメータを使用して、これを行いたいと考えています。
mapped_ptr = mmap(NULL, buf_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (MAGIC + buffer_id) * PAGE_SIZE);
「MAGIC」はマジックナンバーで、buffer_idはmmapしたいバッファIDです。次に、カーネル部分には次のようなものがあります。
static int my_dev_mmap(struct file *filp, struct vm_area_struct *vma)
{
int bufferID = vma->vm_pgoff - MAGIC;
/*
* Convert bufferID to PFN by looking through driver's buffer descriptors
* Check length = vma->vm_end - vma->vm_start
* Call remap_pfn_range()
*/
}
mmap() の「オフセット」はインデックスまたは識別子を指定することを想定していないため、その役割は、mmap-ed デバイスの先頭からスキップされたバイト (またはページ) の数を提供することです。 (またはファイル)メモリ(連続していると思われますよね?)。
ただし、メインラインで、「オフセット」を使用して mmap-ed バッファーを区別するドライバーをいくつか見てきました。
これに代わる解決策はありますか?
PS 物理的に隣接し、8 バイトの境界メモリ バッファーに配置されている場合にのみ動作する、いくつかの異常な SoC のグラフィックス コントローラーを扱っているという理由だけで、これらすべてが必要です。そのため、そのようなバッファーはカーネル空間にのみ割り当て、mmap() を介してユーザー空間に渡すことができます。
コントローラーのプログラミング (命令バッチの作成とカーネル ドライバーへのプッシュ) の大部分は、ユーザー空間で実行されます。また、物理的に連続したメモリの単一の大きなチャンクを割り当てることはできません。その場合、非常に大きくする必要があり (たとえば、16 + MiB)、alloc_pages_exact() が失敗するためです。