1. 三种地址:逻辑地址,线性地址,物理地址。
三者的详细解释:
逻辑地址(logical address):由段(segment)(16位)和偏移量(offset或displacement)(32位)组成。
线性地址(linear address)(也称虚拟地址virtual address):是一个32位无符号整数,用来表示高达4GB的地址。
物理地址(physical address):实际地址。
分段目的:把逻辑地址转换为线性地址,如下图所示:
2.1 段标识符和段寄存器
段标识符(段选择符)(存放在段寄存器中)字段如下:
index |
用来得到段描述符在GDT或LDT中的偏移(位置) |
TI |
指明段描述符是在GDT中(TI=0)或在LDT中(TI=1) |
RPL |
请求特权级, |
由于一个段描述符是8字节,因此它的地址=GDT或LDT内的首地址+(index*8)。能够保存在GDT中的段描述符的最大数目是8191(213-1),其中13是index的位数。
不同段的段描述符构成段描述符表,段描述符(8字节)存放在全局描述符表(GDT)或局部描述符表(LDT)中。GDT在主存中的地址和大小存放在gdtr控制寄存器中,当前正被使用的LDT地址和大小存放在ldtr控制寄存器中。
2.2 段描述符
CPL(Current Privilege Level) |
当前特权级 |
DPL(Descriptor Privilege Level) |
描述符特权级 |
RPL ( Require Privilege Level) |
请求特权级, |
Liunx中广泛采用的段描述符类型:代码段描述符、数据段描述符、任务状态段描述符、局部描述符表描述符(代表一个包含LDT的段)。
2.3 快速访问段描述符:(是由逻辑地址得到段的一个流程)
1.4 Linux中的分段
用户代码段 |
__USER_CS |
用户数据段 |
__USER_DS |
内核代码段 |
__KERNEL_CS |
内核数据段 |
__KERNEL_DS |
1.5 Linux GDT
每个处理器中只有一个GDT,所以在多处理器系统中有多个GDT。一般的,每个处理器中的都是GDT的一个副本。除了以下的三种情况:
1.每个处理器都有自己的TSS段,因此其对应的GDT项不同。
2.GDT中只有少数项可能依赖于CPU正在执行的进程。
3.在某些情况下,处理器可能临时修改GDT副本中的某个项。
所有的GDT存放在cpu_gdt_table数组中,而所有的GDT的地址和它们的大小(初始化gdtr时用)存放在cpu_gdt_descr数组中。这些都在arch/i386/kernel/head.s中定义。
如下图所示,一个GDT中包含18个描述符和14个空的、未使用的、或保留的项。
1.6 Linux LDT
大多数用户态程序不使用LDT,这样内核就在GDT中定义了一个缺省的LDT来供大多数进程共享。缺省的LDT存放在default_ldt数组中。它含有5个项,内核只使用了两个项:用于iBCS执行文件的调用门和Solaris/x86可执行文件的调用门。调用门是一种机制:用于在调用预定义函数时改变CPU的特权级。
如果进程需要创建自己的LDT,则使用modify_ldt()系统调用。用户创建的LDT需要自己的段,此时GDT中的LDT表项相应的就要被修改。
2. 分页
目的:把线性地址转换为物理地址。其中的一个关键任务:比较所请求的访问类型与线性地址的访问权限。如果内存访问无效,则产生一个缺页异常。
页:以固定长度为单位的线性地址。页内部的线性地址被映射到连续的物理地址中。(即代表一组数据)
页框:RAM被分成固定长度的页框,每一个页框包含一个页。(即主存中的物理地址)
页表:把线性地址映射到物理地址的数据结构,它存放在主存中,并在启用分页单元之前由内核进行初始化。
所有的80x86都支持分页,它通过设置cr0寄存器的PG标志启用(PG=0)。
3.1 常规分页
32位的线性地址被分为3个域(4KB的页):
重要的概率 |
组成 |
页目录 |
页目录项 |
页表 |
页表项 |
线性地址到物理地址的转换如下图所示:
3.2 扩展分页
3.3 物理地址扩展(PAE)分页
看书p56-57
3.4 硬件保护方案
段有三种存取权限(读、写、执行),页只有两种存取权限(读、写)。
PAE(Physical Address Extension) |
物理地址扩展 |
PSE(Page Size Extension) |
页大小扩展 |
PGE(Page Global Enable) |
页全局启用 |
3.5 硬件高速缓存
原因:CPU和RAM之间速度不匹配。
原理:基于局部性原理,用小而快的内存来存放最近最常使用的代码。以脉冲突发模式(burst mode)在慢速DRAM和快速片上SRAM之间传送行(一种新单位)。
映射关系:直接映射、全相关、N-路相关。
硬件高速缓存单元的组成:一个硬件高速缓存内存、一个高速缓存控制器。Cache hit、cache miss。通写(write-through)、回写(write-back)。
多处理器高速缓存,需要保持高速缓存间的内容同步。就有一种高速缓存侦听(cache snooping)活动来实现同步。
Linux中对所有的页框都启用高速缓存,对于写操作总是采用回写策略。
3. Linux中的分页
4.1 分页概述
Linux从2.6.11开始采用四级分页模型:(为了适用于32位和64位系统)
l PGD(Page Global Directory)
l PUD(Page Upper Directory)
l PMD(Page Middle Directory)
l PT(Page Table)
PGD中包含若干PUD的地址,PUD中包含若干PMD的地址,PMD中又包含若干PT的地址。每一个页表项指向一个页框。线性地址被分为五个部分,如下图所示:(图中没有指明每一部分的大小,因为每一部分的大小与具体的计算机体系结构相关。)
没有启用物理地址扩展的32位系统,两级页表就可以了。Linux通过使PUD和PMD对应的位全为0,使得每个PUD和PMD都只有一个项。此时PGD、PUD、PMD、PT中表项的个数分别是:1024、1、1、1024。
启用物理地址扩展的32位系统使用了三级页表。Linux中的PGD对应于80x86的页目录指针表(PDPT),PUD对应位全为0,PMD对应于80x86的页目录,PT对应于80x86的页表。此时PGD、PUD、PMD、PT中表项的个数分别是:4、1、512、512。
Linux的进程处理依赖于分页:
1. 给每一个进程分配一块不同的物理地址空间,可以有效地防止寻址错误。
2. 区别页和页框之不同。这就允许存放在某个页框中的一个页,然后保存到磁盘上,以后重新装入这同一页时又可以被装在不同的页框中。这是虚拟内存机制的基本要素。
当发生进程切换时,linux把cr3控制寄存器的内容保存在前一个执行进程的描述符中,然后把下一个要执行进程的描述符的值装入cr3寄存器中,因此,当新进程重新开始在CPU上执行时,分页单元指向一组正确的页表。