linux0.12是结合了分段和分页两种机制来完成程序的逻辑地址到物理地址的转换,所以地址转换分为两个阶段,第一阶段使用分段基址把逻辑地址转换为线性地址空间,第二阶段使用分页基址把线性地址转换为物理地址。下面举一个具体的例子来讲述一下linux0.11是如何把这两种机制结合使用的。
首先我们要了解,硬件为存放段选择符提供了6个段寄存器:CS、DS、ES、SS、FS、GS,其中CS专门用于代码段的寻址,DS专门用于数据段的寻址、SS专门用于堆栈段的寻址,其余三个寄存器作辅助用。
我们知道,程序运行都是通过CS寄存器和EIP寄存器来找到下一条要执行的指令的。那么我们就以CS:EIP为例来看一下是从逻辑地址最终查找到物理地址的。CS寄存器中存放的是代码段在GDT(全局描述符表)表中的偏移,而GDT表的基址存放在GDTR寄存器中,那么就可以根据GDTR寄存器和CS寄存器来查找到当前代码段描述符,描述符中就有存放代码段的基址。EIP寄存器存放的是该对象在段内的偏移。那么就根据段基址和段内偏移得到了该对象在线性地址空间中的地址。
在寻址之前,我们要知道32位线性地址的结构:高10位是页表在页目录表中的偏移,中间10位是页面在页表中的偏移,低12位是被寻址对象在页表中的偏移。
linux0.12使用两级页表结构,首先由CR3寄存器得到页目录表的基址,然后根据线性地址的高10位得到页表在页目录表中的偏移,据此可以查找到页表在页目录表中的表项,表项中第12-31位记录了页表的基址,那么现在得到了二级页表的基址,然后根据线性地址的中间10位来得到该页面在二级页表中的偏移,那么就得到了页面在二级页表中的页表项,页表项的第12-31位记录了该页面的基址,线性地址的低12位记录了页面内偏移,那么根据页面基址和页面内偏移就可以得到该对象的地址。至此完成了逻辑地址到线性地址的转换