由GDTR访问全局描述符表是通过段选择子(实模式下的寄存器)来完成 。段选择子是一个16位的寄存器(同实模式下的段寄存器相同) 段选择子包括三部分:描述符索引(index)、TI、请求级特权(RPL).
在Linux内核中基本不使用局部段描述表LDT,LDT只是在VM86模式中运行wine以及其它在Linux上模拟运行Windows软件或DOS软件的程序中才使用。
全局描述符表GDT只有一张(一个处理器对应一个GDT),GDT可以被放在内存的任何一个位置,但CPU必须知道GDT的入口,也就是基地址放在哪里,Intel的设计者提供了一个寄存器GDTR用来存放GDT的入口地址,程序员将GDT设定在内存中某个位置之后,可以通过LGDT指令将LDT的入口地址装入此寄存器,从此以后,CPU就根据此寄存器中的内容作为GDT的入口来访问GDT了。GDTR中存放的是GDT在内存中的基地址和其表长界限。LDT和GDT从本质上说是相同的,只是LDT嵌套在GDT中
虚拟地址到线性地址的映射保持原值不变,因此讨论或理解Linux页映射时,可以直接将线性地址当做虚拟地址 两者完全一致。
如下图虚拟地址到物理地址的转换(《程序员的自我修养》)
页式映射的过程,每个进程都有其自身的页面目录PGD,指向这个目录的指针保持在每个进程的mm_struct数据结构中。
在页面映射的过程中,i386CPU要访问内存三次。第一次是页面目录,第二次是页面表,第三次才是访问真正的目标。所以虚存的高效实现有赖于高速缓存(cache)的实现。有了高速缓存,虽然在第一次用到具体的页面目录和页面表时要到内存中读取,但一旦装入了高速缓存以后,一般都可以在高速缓存中找到,而不需要再到内存中读取了。另一方面,这整个过程是由硬件实现的,所以速度很快。
i386CPU的页式存管的基本思路是:通过页面目录和页面表分为两个层次实现从线性地址到物理地址的映射,这种映射模式在大多数情况下可以节省页面表所占用的空间。因为大多数进程不会用到整个虚存空间,在虚存空间中通常都留有很大的“空洞”。采用两层的方式,只要一个目录项所对应的那部分空间是个空洞,就可以把该目录项设置成“空”,从而省下了与之对应的页面表(1024个页面描述项)。当地址的宽度为32位时,两层映射机制比较有效也比较合理。但是,当地址的宽度大于32位时,两层映射就显得不尽合理,不够有效了。
Linux内核的设计要考虑到在各种不同CPU上的实现,还要考虑到在64位CPU (如Alpha),上的实现,所以不能仅仅针对i386结构来设计它的映射机制,而要以一种假想的、虚拟的CPU和MMU(内存管理单元)为基础,设计出一种通用的模型,再把它分别落实到各种具体的CPU上。因此,Linux内核的映射机制设计成三层,在页面目录和页面表中间增设了一-层“中间目录”。在代码中,页面目录称为PGD,中间目录称为PMD,而页面表则称为PT.PT中的表项则称为PTE,PTE是PageTableEntry”的缩写。PGD、PMD和PT三者均为数组。相应地,在逻辑上也把线性地址从高位到低位划分成4个位段,各占若干位,分别用作在目录PGD中的下标、中间目录PMD中的下标、页面表中的下标以及物理页面内的位移。这样,对线性地址的映射就分成如图所示的四步。
具体一点说,对于CPU发出的线性地址,虚拟的Linux内存管理单元分如下四步完成从线性地址到物理地址的映射:
(1)用线性地址中最高的那一个位段作为下标在PGD中找到相应的表项,该表项指向相应的中间目录PMD。
(2)用线性地址中的第 二个位段作为下标在此PMD中找到相应的表项, 该表项指向相应页面表
(3)用线性地址中 的第三个位段作为下标在页面表中找到相应的表项 PTE,该表项中存放的就是指向物理页面的指针。
(4)线性地址中的最后位段为物理页面内的相对位移量,将此位移量与目标物理页面的起始地址相加便得到相应的物理地址
但是,这个虚拟的映射模型必须落实到具体CPU和MMU的物理映射机制。就以i386来说,CPU实际上不是按三层而是按两层的模型进行地址映射的。这就需要将虚拟的三层映射落实到具体的两层映射,跳过中间的PMD层次。
事实上,每个进程只有一个mm_struct 结构,在每个进程的“进程控制块",即task_struct 结构中,有一个指针指向该进程的mm_struct 结构。可以说,mm_struct 数据结构是进程整个用户空间的抽象,也是总的控制结构。结构中的头三个指针都是关于虚存区间的。第一个mmap用来建立一个虚存区间结构的单链线性队列。第二个mmap_av1用来建立一个虚存区间结构的AVL树。第三个指针mmnap cache, 用来指向最近一次用到的那个虚存区间结构;这是因为程序中用到的地址常常带有局部性,最近一次用到的区间很可能就是下一次要用到的区间,这样就可以提高效率。
页式映射的过程,每个进程都有其自身的页面目录PGD,指向这个目录的指针保持在每个进程的mm_struct数据结构中。每当调度一个进程进入运行的时候,内核都要为即将运行的进程设置好控制寄存器CR3,而MMU的硬件则总是从CR3中取得指向当前页面目录的指针。不过,CPU在执行程序时使用的是虚拟地址,而MMU硬件在进行映射时所用的则是物理地址。