Chinaunix首页 | 论坛 | 博客
  • 博客访问: 821339
  • 博文数量: 97
  • 博客积分: 3042
  • 博客等级: 中校
  • 技术积分: 1610
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-21 11:48
文章存档

2015年(1)

2014年(3)

2013年(4)

2012年(43)

2011年(44)

2010年(2)

分类: LINUX

2011-10-24 14:25:41

linux下逻辑地址转换成线性地址的流程
1.  使用段选择符中的偏移值 在GDT或LDT中定位相应的段描述符。
2.  利用段描述符检验段的方位权限和范围,以便确定该段是可访问的并且偏
     移量位于段的段界限内。
3.  把段的偏移量加到段的基地址上最后形成一个线性地址


1.  使用段选择符中的偏移值,在GDT或LDT中定位相应的段描述符。
      段描述符表是段描述符的一个数组,每个段描述符占8个字节并且段描述符表是可变的。段描述符表可分为全
局描述符表(GDT)和局部描述符表(LDT)。
     虚拟地址空间被分成大小相等的两部分,一部分是由GDT映射到线性地址空间,另一部分是由LDT映射到线性地址空间。当发生任务切换时,LDT会切换到新的任务的LDT,而GDT并不会改变。因此,GDT所映射的一般虚拟地址空间是系统所共有的。
     GDT:Global descriptor table 全局描述符表。所谓全局,是因为它里面有内核所有的段描述符信息。表中并没有直接存放相应的段,而是存放了指向相应段的段描述符。具体的,可以通过段寄存器中的段选择符,也就是索引,即可以在GDT中查找到相应的段描述符。

       GDT本身不是段,它只是线性地址空间的一个数据结构。每个GDT的线性基址和它的大小限制都必须通过lgdt指令加载到GDTR寄存器中。

源码cpu_init中,对于GDT的初始化:

        int ;

        int ;

        /*

         * Initialize the per-CPU GDT with the boot GDT,

         * and set up the GDT descriptor:

         */

        ();

 


/////

/*

* Current gdt points %fs at the "master" per-cpu area: after this,

* it's on the real one.

*/

void (int )这里的cpu变量指的是某个cpu如果系统是多处理器的话,这里会对每个cpu都有相应的gdt初始化。

{

        struct ;

        . = (long)();

        . = - 1;

        (&);

        /* Reload the per-cpu base */

        ();

}

其中,描述GDT的线性基址和大小限制的数据结构即为desc_ptr

/////

struct {

        unsigned short ;

        unsigned long ;

} (()) ;

详细查看load_gdt。也就是加载GDT的宏:

#define () ()

static void (const struct *)

{

        asm volatile("lgdt %0"::"m" (*));

}

详细看下GDT_SIZE:

#define ( * 8)

/*

* The GDT has 32 entries

*/

#define 32

也就是GDT32项。每项占8个字节。其中,包括18个段描述符和14个空的、未使用、保留的项。

详细的布局见图:


 

图中,可以看到段选择符这里就起到了索引的作用。通过它可以在GDT表中查找相应的段描述符的信息。

可以看到图中有LDT的描述项。LDT。也就是local descriptor tableGDT必须包含LDT的项。如果有多个LDT,那么GDT中必须有单独的多个来描述相应的LDT

为什么会有局部描述符表?我的理解是,在纯粹的linux程序的环境下,是可以通过GDT统一管理,而不需要其他的支持就可以了。但是当需要提供对于某些其他非linux环境下的程序,他们在linux环境下运行,可能单单靠GDT是不够的。可能还需要专门的描述符表来针对这类程序提供支持。于是就有了局部描述符表。

 

图中,比较熟悉的还有内核数据段描述符、内核代码段描述符,用户数据段描述符、内核代码段描述符。以及TSS:任务状态段。

2.  利用段描述符检验段的访位权限和范围,以便确定该段是可访问的并且偏移量位于段的段界限内。
      每个段由三个部分组成:
     (1)段基地址: 指定段在线性地址空间中的起始地址。
     (2)段限长: 是虚拟地址空间中段内最大可用偏移位置。
     (3)段属性:指定段的特性。例如该段是否可读可写等。
      以此来判断段的访问权限和范围。
3. 
把段的偏移量加到段的基地址上最后形成一个线性地址

阅读(3670) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~