地址映射 分段分页

来源:互联网 发布:逆战透视源码 编辑:程序博客网 时间:2024/06/04 00:39

linux内核采用页式存储管理。虚拟地址空间划分成固定大小的“页面”,由MMU将虚拟地址映射成某个物理内存页面中的地址。

一、三种不同的地址

1、逻辑地址:程序中所使用的(相当于一个偏移量)即逻辑上的地址

2、线性地址:(虚拟地址) 32位无符号整数,可以用来表示高达4G的地址。线性地址通常用十六进制数字表示,值的范围从 0x0000 0000 到 0xffff ffff。

逻辑地址经分段机制后就成线性地址;如果不启用分页,那么此线性地址和物理地址相同。

3、物理地址:真实的物理内存,物理内存就是CPU的地址线可以直接进行寻址的内存空间大小。比如8086只有20根地址线,那么它的寻址空间就是1MB,我们就说8086能支持1MB的物理内存,及时我们安装了128M的内存条在板子上,我们也只能说8086拥有1MB的物理内存空间。同理我们现在大部分使用的是32位的机子,32位的386以上CPU就可以支持最大4GB的物理内存空间了。

线性地址经分页转换后就成了物理地址。

二、分段

1、段选择符和段寄存器

一个逻辑地址由两部分组成:一个段标识符和一个指定段内相对地址的偏移量。段标识符是一个16位长的字段,称为段选择符(Segment Selector),而偏移量是一个32位长的字段。


index:指定了放在GDT或LDT中的相应段描述符的入口

TI:指明段描述符是在GDT中(T1=0)或在LDT中(T1=1)

RPL:请求者特权级,当相应的段选择符装入到cs寄存器中时指示出CPU当前的特权级;它还可以用于在访问数据段时有选择地削弱处理器的特权级。

为了快速方便地找到段选择符,处理器提供段寄存器,段寄存器的唯一目的是存放段选择符。这些段寄存器称为cs,ss,ds,es,fs和gs.尽管只有 6个段寄存器,但程序可以把同一个段寄存器用于不同的目的,方法是先将其值保存在内存中,用完后再恢复。

cs 代码段寄存器,指向包含程序指令的段

ss 栈段寄存器,指向包含当前程序栈的段

ds 数据段寄存器,指向包含静态数据或者全局数据段

cs含有一个两位的字段,用以指明CPU的当前特权级CPL。值为0代表内核态,值为3代表用户态。(linux只有0级和3级)

2、段描述符

每个段由一个8字节的段描述符表示,它描述了段的特征。段描述符放在全局描述符表GDT或局部描述符表LDT中。通常只定义一个GDT,而每个进程除了存放在GDT中的段之外如果还需要创建附加的段,就可以有自己的LDT。

GDT在主存中的地址和大小存放在gdtr控制寄存器中,当前正在被使用的LDT地址和大小放在ldtr控制寄存器中。


由于一个段描述符是8字节长,因此它在GDT或LDT内的相对地址是段选择符的最高13位的值乘以8得到的。

eg:如果GDT在0X00020000,且由段选择符所指定的索引号为2,那么相应的段描述符地址是0x00020000+(2*8)


GDT的第一项总是设为0。确保空段选择符的逻辑地址会被认为是无效的,因此引起一个处理器异常。能够保存在GDT中的段描述符的最大数目是8191,即2^13-1

3、分段单元(逻辑地址怎样转换成相应的线性地址)

(1)先检查段选择符的TI字段,以决定段描述符保存在哪一个描述符表中。TI字段指明描述符在GDT(分段单元从gdtr寄存器中得到GDT的线性基地址)中还是在激活的LDT中。(分段单元从ldtr寄存器中得到LDT的线性基地址)

(2)从段选择符的Index字段计算段描述符的地址,index字段的值乘以8(一个描述符的大小),这个结果与gdtr或ldtr寄存器中的内容相加。

(3)把逻辑地址的偏移量与段描述符Base字段的值相加就得到了线性地址


三、分页

每当调度一个进程进入运行的时候,内核都要为即将运行的进程设置好控制寄存器CR3,而MMU的硬件则总是从CR3中取得指向当前页面目录的指针。


CPU在执行程序时使用的是虚拟地址,而MMU硬件在进行映射时所用的则是物理地址。这是在inline函数switch_mm()中完成的。

不管什么进程,一旦进入了内核就进了系统空间,都有相同的页面映射。

i386 CPU以线性地址的最高10位为下标去页面目录中找到其目录项。
这个目录项中的高20位指向一个页面表。
每个页面表占一个页面,4K字节边界对齐,其起始地址的低12位一定是0。所以把32位目录项中的低12位挪作它用,其中最低位为P标志位,为1时表示该页面表在内存中。

线性地址的中间10位,CPU以此为下标在已经找到的页面表中找到相应的表项。
页面表项的P标志位为1时表示所映射的页面在内存中。32位的页面表项中的高20位指向一个物理内存页面。

加上线性地址中的最低12位,就得到最终的物理内存地址。


在页面映射过程中,i386 CPU要访问内存三次,第一次是页面目录,第二次是页面表,第三次是访问真正的目标。


总结:

1.CPU将一个虚拟内存空间中的地址转换为物理地址,需要进行两步:首先将给定一个逻辑地址(其实是段内偏移量,这个一定要理解!!!),CPU要利用其段式内存管理单元,先将为个逻辑地址转换成一个线性地址,再利用其页式内存管理单元,转换为最终物理地址。

逻辑地址----段式内存管理单元----线性地址----页式内存管理单元----物理地址

这样做两次转换,的确是非常麻烦而且没有必要的,因为直接可以把线性地址抽像给进程。之所以这样冗余,Intel完全是为了兼容而已。

2.在linux平台下,线性地址=虚拟地址=逻辑地址

阅读全文
0 0
原创粉丝点击