段(segmentation)是一个主要用在x86体系的概念,大多数的RISC体系是不支持段的,为了更简单的管理内存和拥有更好的可移植性,linux 2.6的内核除了在x86架构里使用了段之外,在其他架构都使用的分页(Paging)来管理内存。也就是说,分段和分页在某种程度上是重复的。
在硬件上,分页单元(Paging Unit)把线性地址转成物理地址,它一个主要的功能就是检查进程是否有权限访问所请求的地址。如果没有权限(或者不存在)的话,它就会产生一个页访问出错(Page Fault exception)。也就是我们常见到的"Unable to handle page request at 0xxxxx, system panic"。不好意思,系统崩溃了。
分页单元把所有的RAM看成是很多具有固定长度的页框(Page Frame)的集合。每一个页框包含一个页。页框是构成内存的单元,是一个存储区域的概念;而页是一块数据区,是一个存储内容的概念,它既可以存放在页框里,也可以存在硬盘上。把线性地址映射成物理地址的数据结构称为页表。
从80386开始,线性地址分成了三部分,最高10位叫分页目录(Page Directory),中间10位叫页表(Page Table),最后12们是页偏移量。再来看一张图,看看分页单元是怎么工作的。一目了然,就不用多说了。
Linux 2.6.10及以前的版本分别对32位和64位系统采用两级和三级的分页机制。从2.6.11开始,linux使用的是四级的分页机制,分别是全局分页目录(Page Global Directory),上层分页目录(Page Upper Directory),中层分页目录(Page Middle Directory)和页表(Page Table)。至上而下,每级分别记录着其下级的每个入口的地址。对于32位非PAE系统,Linux把中间两级当成所有的位都为0而省略了;对于32位PAE系统,Linux使用了三级分页机制,上层分页目录被省略了;64位系统会根据硬件来决定使用三级或四级分页机制。使用分页机制使得Linux可以实现为不同的进程分配不同的物理地址空间,有效的保证不会出现询址错误,并把页和页框的概念分开,从而现在所谓的虚拟内存的机制。
最后来了解一下Linux里面有关分页的主要的C语言宏和函数。
PAGE_SHIFT --- 线性地址里面偏移量(offset)的位数,比如32位非PAE系统就是12
PAGE_SIZE --- 页的大小,有4K, 2M, 4M等
PAGE_MASK --- 页偏移的掩码,比如说0xFFFFF000
pte_t, pmd_t, pud_t和tgd_t是用来分别表示页表,中层分页目录,上层分页目录和全局分页目录的类型。
(引自Understanding the Linux Kernel (Third Edition))
Linux进程的地址空间分为部分,一是0x00000000 - 0xBFFFFFFF,这是当进程运行有用户模式或者内核模式时可以使用的地址空间;二是0xC0000000 - 0xFFFFFFFF,只有当进程运行在内核模式时才可以使用这段地址空间。
阅读(948) | 评论(0) | 转发(0) |