操作系统-存储管理(5)IA-32/Linux的地址转换

IA-32/Linux按字节编址;在保护模式下,IA-32采用段页式虚拟存储管理方式,存储地址采用逻辑地址、线性地址和物理地址来进行描述。
逻辑地址由48位组成,包含16位段选择符(高13位为段表项的index)和32位段内偏移量(有效地址=基址寄存器+变址寄存器×比例因子+偏移量),通过段描述符取到段表中的对应段表项的段基址,加上有效地址得到线性地址(位数由虚拟地址空间大小决定)。
PS:逻辑地址和线性地址是虚拟地址的两种不同表示形式,描述的都是4GB虚拟地址空间中的一个存储地址。
最后通过分页方式转换为物理地址(位数由存储器总线的地址线条数决定)
 
逻辑地址向线性地址的转换:
6个16位段寄存器,用于存放段选择符
CS(代码段):程序代码所在段
SS(栈段):栈区所在段
DS(数据段):全局静态数据区所在段
其他3个辅助段寄存器ES、GS和FS可指向任意数据段
TI=0,选择全局描述符表(GDT);TI=1,选择局部描述符表(LDT)
每个段寄存器都有一个RPL字段(Request Privilege Level),说明的是进程对段访问的请求权限。
RPL是当前程序段的特权等级,Linux只用了0级和3级:RPL=00,为第0级,位于最高级的内核态;RPL=11,为第3级,位于最低级的用户态。当前CPL=0的进程要访问一个数据段,它把段选择符中的RPL设为3,这样它对该段仍然只有特权为3的访问权限。
CS寄存器中的RPL字段表示CPU的当前特权级(Current Privilege Level,CPL)
高13位索引用来确定当前使用的段描述符在描述表(段表)中的位置,即段表项的index
段描述符实际就是段表项,分两类:
  • 普通段:用户/内核的代码段和数据段描述符
  • 系统控制段描述符,又分两种:
  1. 特殊系统控制段描述符,包括:局部描述符表(LDT)描述符和任务状态段(TSS,每一个进程的状态描述信息)描述符   
  2. 控制转移类描述符,包括:调用门描述符、任务门描述符、中断门描述符和陷阱门描述符(门:中断服务程序的首地址)
每项段描述符共64位,包括:
B31~B0: 32位基地址; 
L19~L0:20位限界,表示段中最大页号
G:粒度。G=1以页(4KB)为单位;G=0以字节为单位。因为界限为20位,故当G=0时最大的段为1MB;当G=1时,最大段为4KB×2^20 =4GB
D:D=1表示地址和数据(段内偏移量)为32位宽,D=0表示16位宽
AVL:由操作系统定义使用,Linux未使用
P:P=1表示存在于主存,P=0表示不存在。Linux总把P置1,不会以段为单位淘汰
DPL:访问段时对当前特权级CPL的最低等级要求。即,只有CPL为00时才可访问DPL为00的段,任何进程都可访问DPL为11的段
S:S=0系统控制描述符,S=1普通的代码段或数据段描述符
TYPE:段的访问权限或系统控制描述符类型
A:A=1已被访问过,A=0未被访问过。(通常A包含在TYPE字段中,相当于脏位)
 
描述表实际就是段表,有三种类型:
  • 全局描述符表GDT:只有一个,用来存放系统内每个任务共用的描述符,例如,内核代码段、内核数据段、用户代码段、用户数据段以及TSS(任务状态段)等都属于GDT中描述的段
  • 局部描述符表LDT:存放某任务(即用户进程)专用的描述符
  • 中断描述符表IDT:包含256个中断门、陷阱门和任务门描述符
为支持分段机制,CPU中有多个用户不可访问的内部寄存器,操作系统通过特权指令可对寄存器TR、LDTR、GDTR和IDTR进行读写
每次段寄存器装入新选择符时(例如更换进程的时候CS换新段选择符),新描述符装入描述符cache,在逻辑地址到线性地址转换时,MMU直接用描述符cache中的信息,不必访问主存段表
TR(任务寄存器)存放TSS描述符的段选择符;LDTR(LDT寄存器)存放LDT描述符的段选择符 
PS:复习的时候注意段选择符和段描述符的区别。TR和LDTR放的是TSS描述符和LDT描述符的段选择符。TSS描述符和LDT描述符在GDT中。
GDT和IDT首地址、限界放在GDTR和IDTR中
 
举例:Linux中的全局描述符表(GDT)
如TSS和LDT的段选择符分别为0x88和0x80:
TR放了0x80,RPL=0,说明TR所指段TSS处于第0环;TI=0,其描述符在GDT中;索引值为0x0010,是第16项
LDTR放了0x88,RPL=0,说明LDTR所指段LDT处于第0环;TI=0,其描述符在GDT中;索引值为0x0011,是第17项
 
图中,其实只有第一次需要去GDT表中找段描述符,后来就去Cache中找了。
 
Linux为了移植到RISC处理器,简化了分段机制,在初始化时将所有段描述符的基址设为0来简化,每个段都被初始化在0~4GB的线性地址空间中。线性地址就是有效地址。
P必定为1
GDT的第12-15表项分别是内核代码段、内核数据段、用户代码段、用户数据段。每个段描述符8B。
因此执行内核代码的时候,CS里总是0x60,DS里总是0x68,以及最后三位000
执行用户程序的时候,CS里总是0x73,DS里总是0x7b,以及最后三位011
 
线性地址向物理地址的转换:
控制寄存器保存机器的各种控制和状态信息,它们将影响系统所有任务的运行,操作系统进行任务控制或存储管理时使用这些控制和状态信息。
  • CR0:控制寄存器
① PE:1为保护模式。一旦在保护模式,不能再将PE清0,只能重启系统以回到实模式。
② PG:1为启用分页;0为禁止分页,此时线性地址被直接作为物理地址使用。
若要启用分页机制,则PE和PG都要置1。
③ 任务切换位TS:任务切换时将其置1,切换完毕则清0,可用CLTS指令将其清0。
④ 对齐屏蔽位AM。AM=0则禁止对齐检查;AM=1且EFLSGS的AC=1则进行对其检查
⑤ cache功能控制位NW(Not Write-through)和CD(Cache Disable):只有当NW和CD均为0时,cache才能工作。
  • CR2:页故障(page fault)线性地址寄存器
存放引起页故障的线性地址。只有在CR0中的PG=1时,CR2才有效。 
  • CR3:页目录基址寄存器
保存页目录表(第一级页表)的起始地址。只有当CR0中的PG=1时,CR3才有效。
IA-32采用两级页表方式:
4GB=1K个子空间×1K个页面/子空间×4KB/页
32位线性地址:1K个页目录项,通过10位页目录索引找到;每个页表1K页表项,通过10位页表索引找到;每页4KB,通过12位页内偏移量找到。
P:1表示页表或页在主存中;P=0表示页表或页不在主存,即缺页,此时需将页故障线性地址保存到CR2。
R/W:0表示页表或页只能读不能写;1表示可读可写。
U/S:0表示用户进程不能访问;1表示允许访问。
PWT:控制页表或页的cache写策略是全写(Write Through)还是回写(Write Back)。
PCD:控制页表或页能否被缓存到cache中。
A:1表示指定页表或页被访问过,初始化时OS将其清0。利用该标志,OS可清楚了解哪些页表或页正在使用,一般选择长期未用的页或近来最少使用的页调出主存。由MMU在进行地址转换时将该位置1。
D:脏位dirty bit。第一级页表页目录项中的脏位无意义,只在第二级页表页表项中有意义。初始化时OS将其清0,由MMU在进行写操作的地址转换时将该位置1。
高20位是页表或页在主存中的首地址对应的页框号,即首地址的高20位。每个页表的起始位置都按4KB对齐。
举例:IA-32/Linux中,执行“movl 8(%ebp), %eax”时,源操作数的逻辑地址向线性地址转换的过程如下:
(1)若CPL>DPL则越级,否则计算有效地址EA=R[ebp]+0×0+8
(2)取出段寄存器DS对应的描述符cache中的段基址(Linux中段基址为0)
(3)线性地址LA=段基址+EA=EA,若LA>段限则越界(Linux肯定不会,段限是全1)
(4)将LA转换为主存地址A
-    若访问TLB命中则地址转换得到A;否则处理TLB缺失(硬件/OS)
-    若缺页或越权(R/W不符)则调出OS内核;否则地址转换得到A 
-    根据A先到Cache中找,若命中则取出A在Cache中的副本 
-    若Cache不命中,则再到主存取A所在主存块送对应Cache行
 
Intel Core i7的线性地址转换:
 
页表变为了4级页表,每级虚页号9位。
进程切换时,从mm结构的pgd获得进程对应第一级页表的首地址放入CR3。
虚拟地址VA变为了48位。其中虚页号36位,页内偏移量12位。物理地址可以远大于虚拟地址。
页表项PTE从32位4B变为了64位8B。因此项数从1024变为了512。
显存不需要地址转换。
posted @ 2018-05-24 20:21  扬羽流风  阅读(707)  评论(0编辑  收藏  举报