14 mmap

发布时间 2023-03-26 17:54:06作者: 人民广场的二道贩子

代码

编程指南

  • 确定物理地址
  • 确定是否使用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属性