rom*_*vis 6 kernel mmap linux-device-driver linux-kernel
我有一个内核驱动程序,它在内核空间中分配几个缓冲区(物理上连续,与页面边界对齐,并由整数页组成).接下来,我需要让我的驱动程序能够将一些缓冲区映射到用户空间(当然,每个mmap()调用一个缓冲区).驱动程序为此目的注册单字符设备.用户空间程序必须能够告诉内核它想要mmap的缓冲区(例如,通过指定其索引或唯一ID,或先前通过ioctl()解析的物理地址).
我想通过使用mmap()的offset参数(例如来自用户空间)来实现:
mapped_ptr = mmap(NULL, buf_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (MAGIC + buffer_id) * PAGE_SIZE);
Run Code Online (Sandbox Code Playgroud)
其中"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()
*/
}
Run Code Online (Sandbox Code Playgroud)
但我认为它是某种肮脏的方式,因为mmap()中的"offset"不应该指定索引或标识符,它的作用是从mmap-ed设备的开头提供跳过的字节数(或页数) (或文件)内存(应该是连续的,对吧?).
但是,我已经看到主线中的一些驱动程序使用"offset"来区分mmap-ed缓冲区.
有没有替代解决方案?
PS我需要这一切只是因为我正在处理一些不寻常的SoC'图形控制器,它只能在物理上连续运行,与8字节边界内存缓冲区对齐.所以,我只能在内核空间中分配这样的缓冲区,并通过mmap()将它们传递给用户空间.
控制器编程的大部分(编写指令批并将其推送到内核驱动程序)在用户空间中执行.此外,我不能只分配单个大块的物理连续内存,因为在这种情况下它需要非常大(例如,16 + MiB)并且alloc_pages_exact()将失败.
我不认为使用偏移量将索引从用户空间传递到驱动程序有什么问题。如果它让您感到困扰,那么只需将您的驱动程序视为从单个页面中组装一个大缓冲区,它希望将其呈现给用户空间作为几乎连续的,以便偏移量实际上是该缓冲区的偏移量。但实际上我认为这样做并没有什么错。
如果您可以使用内核 3.5 或更高版本,另一种选择可能是使用“连续内存分配器”(CMA)——查看<linux/dma-contiguous.h>和drivers/base/dma-contiguous.c了解更多信息。还有https://lwn.net/Articles/486301/作为参考,但我不知道该文章与将代码合并到主线之间有多少(如果有的话)变化。
| 归档时间: |
|
| 查看次数: |
1949 次 |
| 最近记录: |