一、要点常识
1. Linux内存办理机制
Linux 2.6.29内核为每种CPU供给一致的界面,选用四级页面办理构架。来兼容二级、三级、四级办理架构的CPU。经过页式办理机制完结虚拟地址(线性地址)到物理地址的映射。一般每个页巨细为4K。cr3寄存器中保存了创立进程时分配的值。
Linux操作体系选用虚拟内存办理技能,使得每个进程都有独立的进程地址空间,该空间巨细是3G,用户看到和触摸的都是虚拟地址,无法看到实践的物理地址。运用这种虚拟地址不但能起到维护操作体系的效果,并且更重要的是用户程序可运用比实践物理内存更大的地址空间。
Linux将4G的虚拟地址空间划分为两个部分——用户空间与内核空间。用户空间从0到0xbfffffff,内核空间从3G到4G。用户进程一般情况下只能拜访用户空间的虚拟地址,不能拜访内核空间,破例是用户进程经过体系调用拜访内核空间。
每个用户空间是彻底独立的,互不想干的。用户空间对应进程,一切每逢进程切换,用户空间就会跟着改动。
实践的物理内存只有当进程真的去拜访新获取的虚拟地址时,才会由“请页机制”发生“缺页反常”,然后进入分配实践页框程序。
内核空间是由内核担任映射,它并不会跟着进程改动,是固定的。
物理内存896MB以上的部分称之为高端内存。
2. mmap办法
完成mmap办法,驱动程序只需要为该地址规模树立适宜的页表,并将vma->ops替换成一系列的新操作就可以了。
void *mmap(void *addr, size_t len, intprot, int flags, int fd, off_t offset)
内存映射函数,担任把文件内存映射到虚拟内存空间,回来映射地址空间地址。
参数阐明:
addr:指定映射的开端地址,一般设为NULL,由体系指定。
length:映射到内存的文件长度
prot:映射区的维护模式,可所以PROT_EXEC(可执行)、PROT_READ(可读)、PROT_WRITE(可写)。
flag:映射区的特性,可所以
MAP_SHARED:写入映射区的数据会仿制回文件,且答应其他映射该文件的进程同享。
MAP_PRIVATE:对映射区的写入操作会发生一个映射区的仿制,对此区域的修正不会写回原文件。
fd:要映射的文件描绘符
offet:以文件开端出的偏移量,一般为0,从文件头开端映射。
int munmap(void *start, size_t length)
免除映射。
struct vm_area_struct
内核用来描绘虚拟内存区域的结构。
int remap_pfn_range(structvm_area_struct *vma, unsigned long virt_add, unsigned long pfn, unsigned longpfn, unsigned long size, pgprot_t prot)
int io_remap_page_range(structvm_area_struct *vma, unsignde long virt_add, unsigned long phys_add, unsignedlong size, pgprot_t prot)
mmap的中心函数。他们映射了物理地址中从pfn表明的页号开端的size个字节到虚拟地址virt_add上。相关虚拟地址的维护位在port中指定。假如方针地址在I/O地址空间的话,运用io_remap_page_range函数。
二、驱动代码
staticint mem_mmap(struct file *filp, struct vm_area_struct *vma)
{
intret = 0;
structmem_dev *dev;
dev= filp->private_data;
ret = remap_pfn_range(vma,vma->vm_start, virt_to_phys(dev->data)>>PAGE_SHIFT, vma->vm_end- vma->vm_start, vma->vm_page_prot); //树立页表
if(ret)
return-EAGAIN;
returnret;
}
staTIc const struct file_operaTIonsmem_fops = {
.owner= THIS_MODULE,
.open= mem_open,
.write= mem_write,
.read= mem_read,
.release= mem_release,
.llseek= mem_llseek,
.ioctl= mem_ioctl,
.poll= mem_poll,
.mmap= mem_mmap,
};
staticint mem_mmap(struct file *filp, struct vm_area_struct *vma){intret = 0;structmem_dev *dev;dev= filp->private_data;ret = remap_pfn_range(vma,vma->vm_start, virt_to_phys(dev->data)>>PAGE_SHIFT, vma->vm_end- vma->vm_start, vma->vm_page_prot); //树立页表if(ret)return-EAGAIN;returnret;}staTIc const struct file_operaTIonsmem_fops = {.owner= THIS_MODULE,.open= mem_open,.write= mem_write,.read= mem_read,.release= mem_release,.llseek= mem_llseek,.ioctl= mem_ioctl,.poll= mem_poll,.mmap= mem_mmap,};