linux内核源代码学习(2)内存映射模式终于搞清楚了

来源:互联网 发布:饼状图如何显示数据 编辑:程序博客网 时间:2024/05/16 15:47
2009-08-12 00:38我发表于百度空间,今天移过来
linux内核源代码学习(2)内存映射模式终于搞清楚了
                                                                                                                                           ------flyli
今天通过不断的读《linux内核代码情景分析》和在网上查阅资料,终于把内存映射的总得机理高清楚了
下面是我参考的一篇文章(cttnbcj兄弟在csdn上发的一篇帖子,具体地址为http://topic.csdn.net/u/20081011/07/a3d92bd2-19d5-4e25-89c3-bf8f7308bcef.html)
=====================================
段xxxx:偏移yyyyyyyy 
首先,xxxx是无法表示段的基址的,对于这个地址,首先要看xxxx的TI位是否为0(即xxxx的第二位),如果是,则从GDTR中获取GDT的基 址,然后在GDT中以段选择器xxxx的高12位得出索引,根据索引偏移找到相应的段描述符,段描述符包括段的基址,限长,优先级各种属性,这就得到了段 的起始地址,加上yyyyyyyy即是要找的内存的线性地址zzzzzzzz。  如果TI位为1,则表示段描述符放在LDT中,第一步的操作还是从GDTR中获取GDT的基址,然后从LDTR寄存器获得索引(非XXXX的高十二位), 注意,这时根据索引偏移得到得并不是段描述符,而是得到LDT段的位置,然后根据xxxx的高十二位从LDT段中获得段描述。再以这个段描述符信息得到段 基址,再加上偏移yyyyyyyy得到要找的线性地址zzzzzzzz。可以写个简单的模拟程式来表示:
if( xxxx的第二位==1 ) //段描述符的位置在GDTR中
{
A1=(GDTR的前三十二位); //把GDTR的基址给A1
段描述符=A1+(xxxx的高12位);  //可获得段描述符
线性地址 = 段描述符中的基址+yyyyyyyy;
}
else  //TI位为0,表示在段描述符在LDT中
{
A1=(GDTR的前三十二位);
A2=A1+LDTR;  //A2即是LDT描述符表的入口,注:LDTR是16位的 (自己注释:GDTR只有一张表,而且基地址(在内核中)确定的,任务切换时候,也不会改变!每个LDTR又是指向自己任务的,所以任务切换时候,只是改 变LDTR寄存器中的内容(改变在GDT中的索引),找到另一个LDT段的描述符(包含了LDT的开始基地址和界限),然后加上段选择子的索引,找出地址 中的位置!),还要要注意的是LDT表的基地址和界限是在LDT的高速缓存中,任务不切换的话,v高速缓存高速缓存的内容不会变!
段描述符=A2+(xxxx的高十二位) //LDT描述符表入口加上偏移,即是相应的段描述符 自己注释:书上写的A2(应该是表示从LDT的开始基地址吧)LDT的基地址+索引才是局部描述符正确的位置
线性地址 = 段描述符中的基址+yyyyyyyy;
}
========================================

原来GDT和LDT之所以一个叫Global(全局)一个叫Local(局部)是因为其实局部的描述表LDT仅仅是GDT的一个引索而已,
为什么要有一个GDTR,并且GDTR的结构和LDTR不一样呢?

这主要是因为系统只有一个GDT,而GDT的描述符有不能存放在GDT中(LDT的描述符都存放在GDT中),所以就需要一个GDTR来指示GDT在内存中的位置。因为GDTR是直接指示内存地址,而LDTR主要指示LDT描述符在GDT中的位置和属性,所以GDTR和LDTR的结构也不同。
原创粉丝点击