一、内存映射基础知识
1、内核地址映射模型
例如:X8686CPU采用段页式地址映射模型,进程代码地址为逻辑地址,经过段页式地址映射以后linux内核原理与分析,才才能真正访问数学显存。32位Linux内核地址空间界定:0GB--3GB为用户空间,3GB--4GB为内核空间。32位和64位内核地址空间界定是不同的。具体空间表示如下:
2、内核高档显存
例如:当内核模块代码或络访问显存时,代码中的地址为逻辑地址,并且对应到真正的数学显存地址,须要地址和它一对一的映射,假定:逻辑地址0xcxc0000003对应的数学地址为0x3。内核逻辑地址空间访问为0xc0000000--0xFFFFFFFF,这么对应的数学显存范围为0x0--0x40000000。即只能访问1GB化学显存。假定我们的笔记本8GB化学显存,这么内核就只能访问后面1GB化学显存,剩下7GB化学显存它难以访问,由于内核的地址空间早已全部映射到化学显存地址范围0x--0x40000000。
Linux将内核地址空间界定为三部份:ZONE_DMA/ZONE_NORMAL/ZONE_HIGHMEM。高档显存HIGH_MEM地址空间范围为0xF8000000--0xFFFFFFFF(896MB-1024MB)。针对低端显存的最基本思想:借一段地址空间,完善临时地址映射,用完后释放,达到此段地址空间可以循环使用,访问所有数学显存。
3、内存映射
显存映射是在进程的虚拟地址空间中创建一个映射,可分为两种:
A、文件映射(文件支持的显存映射,把文件的一个区间映射到进程的虚拟地址空间,数据源是储存设备上文件);
B、匿名映射(没有文件支持的显存映射,把数学显存映射到进程的虚拟地址空间,没有数据源)。一般把文件映射的数学页称为文件页linux内核原理与分析,把匿名映射的数学页称为匿名页。
4、根据更改是否对其他进程可见和是否传递到底层文件,显存映射分为共享映射和私有映射。
A、共享映射:更改数据时映射相同区域的其他进程可以看到,倘若是文件支持的映射,更改会传递到底层文件。
B、私有映射:第一次更改数据时会从数据源复制一个副本,之后更改副本,其他进程看不见,不影响我们的数据源。
两个进程可以使用共享的文件映射实现共享显存。匿名映射一般为私有映射,共享的匿名映射只可能出现在父进程和子进程之间。在进程的虚拟地址空间中,代码段和数据段是私有的文件映射,未初始化数据段、堆栈是私有的匿名映射。
5、内存映射原理机制:
1、创建显存映射的时,在进程的用户虚拟地址空间中分配一个虚拟显存区域(vm_area_struct);
2、Linux内核采用延后分配化学显存的策略linux系统下载官网,在进程第一次访问虚拟页的时侯,形成缺页异常,倘若是文件映射,这么分配化学页,把文件指定区间的数据读到化学页中,之后在页表中把虚拟页映射到化学页;假如你是匿名映射,这么分配化学页,之后在页表中把虚拟页映射到化学页。
二、应用层API系统调用
Linux内核当中显存管理子系统提供给我们用户层的系统调用API函数,具体如下:
头文件:#include1、用来创建显存映射
void*mmap(void*addr,size_tlength,intprot,intflags,intfd,off_toffset);
2、用来删掉显存映射
intmunmap(void*addr,size_tlength);
3、专用拿来扩大或缩小早已存在的显存映射,可能同时联通
#define_GNU_SOURCE/*Seefeature_test_macros(7)*/#includevoid*mremap(void*old_address,size_told_size,size_tnew_size,intflags,.../*void*new_address*/);
4、用来设置堆的下界
#include
intbrk(void*addr);
5、用来创建非线性的文件映射,即文件区域和虚拟地址空间之间的映射不是线性关系如何安装linux,现今已不用
#define_GNU_SOURCE/*Seefeature_test_macros(7)*/#include
intremap_file_pages(void*addr,size_tsize,intprot,size_tpgoff,intflags);
6、用来设置虚拟显存区域的访问权限
#include
intmprotect(void*addr,size_tlen,intprot);
在Linux空间中可以使用如下函数:
1、把显存的化学页映射到进程的虚拟地址空间,这个函数好处是:实现进程和内核共享显存。
intremap_pfn_range(structvm_area_struct*vma,unsignedlongaddr,unsignedlongpfn,unsignedlongsize,pgprot_tprot);
2、把外设寄存器的化学地址映射到进程的虚拟地址空间,进程可能直接访问外设寄存器。
intio_remap_page_range(structvm_area_struct*vma,unsignedlongvirt_addr,unsignedlongphys_addr,unsignedlongsize,pgprot_tprot);
应用层当中应用程序通过使用C标准库提供的函数malloc()申请显存。glibc库的显存分配器ptmalloc使用brk或mmap向内核以页为单位申请虚拟显存,之后把页界定成小显存块分配给应用程序。默认的阀值为128KB,倘若应用程序申请的显存宽度大于阀值,ptmalloc分配器使用brk向内核申请虚拟显存,否则ptmalloc分配器使用mmap内内核申请虚拟显存。应用程序可以直接使用mmap向内核申请虚拟显存。
三、Linux内核常用数据结构
1、进程描述符
2、内存描述符
3、虚拟显存区域
4、mmap系统调用
a.进程创建匿名的显存映射,把显存的数学页映射到进程的虚拟地址空间;
b.进程把文件映射到进程的虚拟地址空间,可以像访问显存一样访问文件,不须要调用系统调用read()/write()访问文件,从面防止用户模式和内核模式之间的切换,提升读写文件的速率。
c.两个进程针对同一个文件创建共享的显存映射,实现共享会败在。
函数原型:
#includevoid*mmap(void*addr,size_tlength,intprot,intflags,intfd,off_toffset);
参数如下:
addr:起始虚拟地址,假如addr为0,内核选择虚拟地址。假如addr为非0,内核把这个参数作为提示,在附近选择虚拟地址。
length:映射的宽度,单位是字节。
prot:保护位,具体参数如下:
PROT_EXEC:页可执行PROT_READ:页可读PROT_WRITE:页可写PROT_NONE:面不可访问
flags:标志,具体参数如下:
MAP_SHARED:共享映射
MAP_PRIVATE:私有映射
MAP_ANONYMOUS:匿名映射
MAP_FIXED:固定映射
MAP_HUGETLB:使用巨型页
MAP_LOCKED:把页锁在显存中
fd:文件描述符
offset:偏斜,单位是字节,必须是页宽度的整数倍。
返回值:
返回起始虚拟地址,否则返回负的错误号。
四、创建/删掉显存映射
1、创建显存映射
C标准库封装函数mmap()拿来创建显存映射,内核印花POSIX标准定义的系统调用mmap,内核系统调用sys_mmap(),具体操作流程如下:
函数sys_mmap_pgoff执行流程视图如下:
a.假如是创建文件映射,按照文件描述符在进程的打开文件表中找到file实例;
b.假如是创建匿名巨型页映射,在hugetlbfs文件系统中创建文件“anon_hugepage",但是创建此文件的一个打开实例file;
c.调用vm_mmap_pgoff进行处理。