Linux中的物理和虚拟存储空间布局

 在支持MMU的32位处理器平台上,Linux系统中的物理存储空间和虚拟存储空间的地址范围分别都是从0x00000000到0xFFFFFFFF,共4GB,但物理存储空间与虚拟存储空间布局完全不同。Linux运行在虚拟存储空间,并负责把系统中实际存在的远小于4GB的物理内存根据不同需求映射到整个4GB的虚拟存储空间中。

物理存储空间布局

Linux的物理存储空间布局与处理器相关,详细情况可以从处理器用户手册的存储空间分布表(memory map)相关章节中查到,我们这里只列出嵌入式处理器平台Linux物理内存空间的一般布局,如图18-4所示。

 

 

                                                                          

图18-4 Linux物理内存空间一般布局示意图说明:

1)最大node号n不能大于MAX_NUMNODES-1。
2)MAX_NUMNODES表示系统支持的最多node数。在ARM系统中,Sharp芯片最多支持16个nodes,其他芯片最多支持4个nodes。
3)numnodes是当前系统中实际的内存node数。
4)在不支持CONFIG_DISCONTIGMEM选项的系统中,只有一个内存node。


5)最大bank号m不能大于NR_BANKS-1。
6)NR_BANKS表示系统中支持的最大内存bank数,一般等于处理器的RAM片选数。在ARM系统中,Sharp芯片最多支持16个banks,其他芯片最多支持8个banks。
7)mem_init()函数会将所有节点的页帧位码表所占空间、孔洞页描述符空间及空闲内存页都释放掉。

虚拟存储空间布局

在支持MMU的系统中,当系统做完硬件初始化后就使能MMU功能,这样整个系统就运行在虚拟存储空间中,实现虚拟存储空间到物理存储空间映射功能的是处理器的MMU,而虚拟存储空间与5路存储空间的映射关系则是由Linux内核来管理的。32位系统中物理存储空间占4GB空间,虚拟存储空间同样占4GB空间,Linux把物理空间中实际存在的远远小于4GB的内存空间映射到整个4GB虚拟存储空间中除映射I/O空间之外的全部空间,所以虚拟内存空间远远大于物理内存空间,这就说同一块物理内存可能映射到多处虚拟内存地址空间上,这正是Linux内存管理职责所在。图18-5列出了Linux内核中虚拟内存空间的一般布局(其实I/O空间也在其中,通常占用高端内存空间,在此未标出)。

虚拟内存空间一般布局示意图

图18-5 Linux系统虚拟内存空间一般布局示意图说明:

1)线性地址空间:是指Linux系统中从0x00000000到0xFFFFFFFF整个4GB虚拟存储空间。
2)内核空间:内核空间表示运行在处理器最高级别的超级用户模式(supervisor mode)下的代码或数据,内核空间占用从0xC0000000到0xFFFFFFFF的1GB线性地址空间,内核线性地址空间由所有进程共享,但只有运行在内核态的进程才能访问,用户进程可以通过系统调用切换到内核态访问内核空间,进程运行在内核态时所产生的地址都属于内核空间。
3)用户空间:用户空间占用从0x00000000到0xBFFFFFFF共3GB的线性地址空间,每个进程都有一个独立的3GB用户空间,所以用户空间由每个进程独有,但是内核线程没有用户空间,因为它不产生用户空间地址。另外子进程共享(继承)父进程的“用户空间”只是使用与父进程相同的用户线性地址到物理内存地址的映射关系,而不是共享父进程用户空间。运行在用户态和内核态的进程都可以访问用户空间。


4)内核逻辑地址空间:是指从PAGE_OFFSET到high_memory之间的线性地址空间,是系统物理内存映射区,它映射了全部或部分(如果系统包含高端内存)物理内存。内核逻辑地址空间与图18-4中的系统RAM内存物理地址空间是一一对应的(包括内存孔洞也是一一对应的),内核逻辑地址空间中的地址与RAM内存物理地址空间中对应的地址只差一个固定偏移量,如果RAM内存物理地址空间从0x00000000地址编址,那么这个偏移量就是PAGE_OFFSET。


5)低端内存:内核逻辑地址空间所映射物理内存就是低端内存,低端内存在Linux线性地址空间中始终有永久的一一对应的内核逻辑地址,系统初始化过程中将低端内存永久映射到了内核逻辑地址空间,为低端内存建立了虚拟映射页表。低端内存内物理内存的物理地址与线性地址之间的转换可以通过__pa(x)和__va(x)两个宏来进行,__pa(x)将内核逻辑地址空间的地址x转换成对应的物理地址,相当于__virt_to_phys((unsigned long)(x)),__va(x)则相反,把低端物理内存空间的地址转换成对应的内核逻辑地址,相当于((void *)__phys_to_virt((unsigned long)(x)))。


6)高端内存:低端内存地址之上的物理内存是高端内存,高端内存在Linux线性地址空间中没有没有固定的一一对应的内核逻辑地址,系统初始化过程中不会为这些内存建立映射页表将其固定映射到Linux线性地址空间,而是需要使用高端内存的时候才为分配的高端物理内存建立映射页表,使其能够被内核使用,否则不能被使用。高端内存的物理地址于现行地址之间的转换不能使用上面的__pa(x)和__va(x)宏。


7)高端内存概念的由来:如上所述,Linux将4GB的线性地址空间划分成两部分,从0x00000000到0xBFFFFFFF共3GB空间作为用户空间由用户进程独占,这部分线性地址空间并没有固定映射到物理内存空间上;从0xC0000000到0xFFFFFFFF的第4GB线性地址空间作为内核空间,在嵌入式系统中,这部分线性地址空间除了映射物理内存空间之外还要映射处理器内部外设寄存器空间等I/O空间。0xC0000000~high_memory之间的内核逻辑地址空间专用来固定映射系统中的物理内存,也就是说0xC0000000~high_memory之间空间大小与系统的物理内存空间大小是相同的(当然在配置了CONFIG_DISCONTIGMEMD选项的非连续内存系统中,内核逻辑地址空间和物理内存空间一样可能存在内存孔洞),如果系统中的物理内存容量远小于1GB,那么内核现行地址空间中内核逻辑地址空间之上的high_memory~0xFFFFFFFF之间还有足够的空间来固定映射一些I/O空间。可是,如果系统中的物理内存容量(包括内存孔洞)大于1GB,那么就没有足够的内核线性地址空间来固定映射系统全部物理内存以及一些I/O空间了,为了解决这个问题,在x86处理器平台设置了一个经验值:896MB,就是说,如果系统中的物理内存(包括内存孔洞)大于896MB,那么将前896MB物理内存(低端内存)固定映射到内核逻辑地址空间0xC0000000~0xC0000000+896MB(=high_memory)上,而896MB之后的物理内存则不建立到内核线性地址空间的固定映射,这部分内存就叫高端物理内存。此时内核线性地址空间high_memory~0xFFFFFFFF之间的128MB空间就称为高端内存线性地址空间,用来映射高端物理内存和I/O空间。896MB是x86处理器平台的经验值,留了128MB线性地址空间来映射高端内存以及I/O地址空间,我们在嵌入式系统中可以根据具体情况修改这个阈值,比如,MIPS中将这个值设置为0x20000000B(512MB),那么只有当系统中的物理内存空间容量大于0x20000000B时,内核才需要配置CONFIG_HIGHMEM选项,使能内核对高端内存的分配和映射功能。什么情况需要划分出高端物理内存以及高端物理内存阈值的设置原则见上面的内存页区(zone)概念说明。


8)高端线性地址空间:从high_memory到0xFFFFFFFF之间的线性地址空间属于高端线性地址空间,其中VMALLOC_START~VMALLOC_END之间线性地址被vmalloc()函数用来分配物理上不连续但线性地址空间连续的高端物理内存,或者被vmap()函数用来映射高端或低端物理内存,或者由ioremap()函数来重新映射I/O物理空间。PKMAP_BASE开始的LAST_PKMAP(一般等于1024)页线性地址空间被kmap()函数用来永久映射高端物理内存。FIXADDR_START开始的KM_TYPE_NR*NR_CPUS页线性地址空间被kmap_atomic()函数用来临时映射高端物理内存,其他未用高端线性地址空间可以用来在系统初始化期间永久映射I/O地址空间。

问题:

1、linux会在初始化的时候把物理内存映射到内核空间。这也让我很奇怪。linux本身维护了一个page的数组来作为物理内存的“仓库”,这个数组的下标实际上就是物理内存的页面号,linux会在初始化的时候初始化这个数组。我的理解是,后期的虚存到物理内存的映射实际上都落实到了对这个page数组的操作,这就够了。为什么还要把物理内存地址映射到内核空间?并且,为什么仅仅是896M,剩下的128M内核地址空间去哪儿了?难道剩下的这128M就是内核本身么?如果是的话,那么内核中的各种系统调用、内核数据结构等就都要挤在这个空间里,这样要对这相对所剩无几的空间进行良好的规划,而不是像普通程序那样,一开始就是8开头的虚存空间地址;如果不是的话,那这128M方的又是什么东西,内核自己又躲到哪儿去了?


linux这样做,只是为了简化内核中虚拟地址和物理地址之间相互转化的工作,__va()、__pa()轻松的就变换过来了,并不是说物理内存映射到内核空间就全部被内核占了。对于内核中非动态数据使用的物理内存是不可以变了,但是动态的部分,是可以释放掉的,而释放掉后这一部分对应的物理内存又可以影射到用户空间。所以,当没有高端内存时,内核空间PAGE_OFFSET到high_memory映射到所有的物理内存空间,但并不是说内核空间一直占用所有的物理内存空间,只是说内核空间这部分虚拟地址始终是映射到所有物理地址空间的,并且从虚拟地址0C000-0000映射到物理地址0开始依次往后。内核空间有些动态数组,也会释放这部分内核地址空间,相应的也会释放一些物理内存。这样,这部分物理内存就可以映射到用户空间。其实,内核空间的其他部分,之所以能映射到地段内存也是这样个道理。

2、实模式和保护模式

一般实地址模式就是不分用户空间和内核空间,用户空间程序可能会修改内核空间程序。具体为实模式下是段选址,但就是简单的段基址+偏移地址的寻址方式。在ARM中可能就是直接的物理寻址方式。而保护模式是借助于MMU的虚拟存储管理。可以起到多道程序互不干扰的保护机制。

3、缺页异常处理

通常情况下,进程代码并不是一次性装入内存的,而是先装入一小部分并执行。在执行过程中,发现将要取的指令或数据不再内存中,具体表现为按指定的线性地址没有与之关联的物理地址。则这时转入缺页异常处理。通过选择空闲页帧,分配一定数量的页帧(也就是物理地址空间)把进程文件存储地,即存储设备的代码或数据复制到物理地址空间里,并将这部分页帧与上述指定的线性地址关联,也就是页(虚拟地址页简称页,物理地址页简称页帧)与页帧关联。等进程部分执行完后全部执行完,则会相应的释放部分或全部页帧。

缺页异常处理如下:

if(数据在物理内存中)

        {        虚拟地址转换成物理地址

                 读数据 }

        else

        {     if(数据在磁盘中)

              {

                     if(物理内存还有空闲)

                     {          把数据从磁盘中读到物理内存

                                 虚拟地址转换成物理地址

                                 读数据

                     }

                     else

                     {         把物理内存中某页的数据存入磁盘

                               把要读的数据从磁盘读到该页的物理内存中

                                 虚拟地址转换成物理地址

                                 读数据

                     }

              }

              else

              {     报错        } }

 

 

4、线性空间到物理空间

在线性空间中,进程1到进程n都有各自的0——3G-1的线性地址,相互间不可见。而内核空间3G——4G是各个进程所共有的。且线性地址3G映射到物理内存空间0处。实际上物理空间0-896M为低端内存,全部映射到内核空间,与内核空间线型映射,这部分线性地址与物理地址只相差一个偏移量C0000000。内核空间其它部分线性地址映射参考上面介绍。当系统要装在某个用户程序时,首先通过父进程生成一个子进程,子进程只是继承了父进程的线性地址与物理地址的映射关系,也就是说子进程并不拥有父进程的内存空间(包括线型空间和物理空间),子进程自己拥有独立的一套用户空间,但内核空间是所有进程共享的。然后会通过缺页机制,将子进程代码和数据从存储设备中复制到相应内存中。注意此时因为继承了父进程的内存映射关系,所以在缺页机制中,优先查找父进程映射的物理内存是否空闲。用户进程要访问内核空间必须通过系统调用或中断等机制,这样用户空间之间不会相互干扰。且内核进程不会产生用户空间地址,所以内核进程不需要用户空间。这样,一般情况下,各个用户进程独立运行,互不干扰,也不会轻易修改内核空间。当需要访问内核空间时,则得通过系统调用或中断等手段进入内核空间。而内核进程不会产生用户地址,所以内核进程只会在内核空间运行。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值