日期:2014-05-16  浏览次数:20755 次

Linux 内存寻址

80x86微处理器下的三种不同的地址:

逻辑地址:16位段选择符+32位offset, 段选择符存放在段寄存器中
线性地址:也称为虚拟地址,32bit 体系结构可以表达4GB的地址空间
物理地址:芯片内存单元寻址

MMU 通过分段单元将 逻辑地址转换为线性地址;
分页单元将线性地址转换为物理地址;

分段的过程:

段选择符有三个字段:
1)Index字段,表示在GDT或者LDT中相应的段描述符的索引
2)TI,两个描述符表的标志,用于区分
3)RPL,特权级

首先从TI字段中决定段描述符保存在哪一个描述符表中,从相应的gdtr或ldtr及寄存器中得到相应的描述符表的基地址
然后将index字段乘以8(一个描述符的大小)加上基地址得到段描述符的地址

段描述符中有一个字段是Base字段,将逻辑地址中的offset与这个Base字段相加就得到了线性地址。这就完成了从逻辑地址到线性地址的转换。
在Linux中,段描述符中的Base字段全部是0x00000000,所以逻辑地址中的offset与线性地址在这个意义上是相等的。
Linux只是象征性地使用了分段机制,目的可能是为了满足可移植性和内存管理的简便。

分页单元把线性地址转换成物理地址:

page:一组线性地址,在内存管理中它是最小的单位,它可以指这组地址中的数据块
page frame:物理页,是RAM的一个区域,表示内存的一部分
page table: 页表存放在主存中,是一种将线性地址隐射到物理地址的数据结构



以上是比较常规的分页,Linux采用三级页表或者四级页表,也就是32为的线性地址多划分两个域出来而已
其中:CR3寄存器存放的是当前活动进程的页目录的物理地址,这是进程上下文的一部分,也就是说当发生进程切换的时候,CR3寄存器的值会被重写,当然,如果两个 进程使用相同的working page set,也就是共享页表结构,那么该寄存器不会被重置(不太确定?有路过的大神求解释下)
线性地址的高10位表示在页目录中的offset,找到页目录项之后,就有了页表的地址,中间10位有是在页表中的offset,这样找到了页表,得到页框的物理地址,最后12位是数据在页框中的offset,12 bit, 4KB大小的页
总共就是1024*1024*4096=2^32

其中页表项中有一个present标志,如果该标志是0,说明这页数据没有在main memory中,产生一个异常page fault
还有一个dirty标志,用于write-back。

Linux中的分页模式一般是3级页表,线性地址被划分为5个域:
Page global directory
Page Upper dir.
Page Middle dir.
Page table 页表
offset

最后提一个TLB缓存,目的是为了加速从虚拟地址到物理地址的隐射,每一个entry会缓存一个VA到一个PA直接的隐射关系。