14 mmap
编程指南
- 确定物理地址
- 确定是否使用cache、buffer
- 建立映射关系
1 引入
应用程序与驱动程序之间进行数据传递时常使用read,write
此实现方法本质上是在用户态的buffer与内核态的buffer之间进行了一次copy。此方法本质上没有什么问题,不过在数据量比较大的时候效率就会显的太低。
此时引入mmap可以直接使读去内核态中的buffer,把内核的buffer直接映射到用户态,让应用程序可直接操作。能够极大的提示效率。
使用mmap时需要考虑是否使用cache(高速内存)和buffer(写缓冲寄存器,相当于FIFO)
关于cache和buffer使用机制如下
是否使用cache | 是否使用buffer | 说明 |
---|---|---|
0 | 0 | 读写操作直达硬件(适合操作寄存器、framebuffer、DMA) |
0 | 1 | 读写操作直达硬件 CPU写操作会先写入buffer,借助buffer实现。CPU不会等待写操作完成,而是会立即执行下一条指令。 此操作会存在写合并的情况,即写入多个数据合并为一个数据写入内存 |
1 | 0 | 当cache中存在目标数据时,直接读取。 当cache中没有目标数据时,从内存中读取数据写入cache。 写操作直接写入(适合只读,几乎不用写的设备) |
1 | 1 | 适用于一般内存读写 |
2 API
2.1 mmap
mmap使用的地址最好为连续的,否则就需要多次mmap
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
addr : 指定文件应该被映射到空间的起始地址。一般置为NULL,交给内核完成
len :
prot : 指定访问权限
PROT_READ : 可读
PROT_WRITE : 可写
PROT_EXEC : 可执行
PROT_NONE : 不可访问
flags : 属性
MAP_SHARED : 共享
MAP_PRIVATE : 私有
shared共享内存,大家都可以read、write
private私有内存,使用的机制为copy to write,即在为执行写操作时。内存可以共享大家都能read。当某个应用执行write时,它会先
copy到某个地方在write,而此部分的修改对别人是不可见的
offset : 一般为0
return value 文件映射到进程空间的地址
2.2 munmap
int munmap(void *addr, size_t length);
2.3 virt_to_phys
虚拟地址转化为物理地址
static inline unsigned long virt_to_phys(void *x)
2.4cache buffer设置
parameter 3 觉得cache和buffer的使用
// 不使用cache buffer
#define pgprot_noncached(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
// NonCache,WriteBuffer被使能
#define pgprot_writecombine(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
#define pgprot_stronglyordered(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
#define pgprot_dmacoherent(prot)
...
2.5 remap_pfn_range
int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot)
vma : 添加到的vma结构体指针
addr : 起始地址,首地址
pfn : page frame number页数, 物理地址在内存中存放的页数。
因为内核page一般为4k。所以pfn = phyaddr / 4096 (为了防止不是4K,直接使用PAGE_SHIFT)
pfn = phyaddr >> PAGE_SHIFT
size : size
prot : prot属性