Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1134891
  • 博文数量: 414
  • 博客积分: 10030
  • 博客等级: 上将
  • 技术积分: 4440
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-05 21:42
文章分类

全部博文(414)

文章存档

2011年(1)

2009年(1)

2008年(412)

我的朋友

分类: LINUX

2008-10-15 09:54:38

§2.2  硬件中的分段

80286 模型开始,Intel 微处理器以两种不同的方式执行地址转换,这两种方式分别称为实模式(real mode)和保护模式(protected mode)。我们将从下一节开始描述保护模式下的地址转换。实模式存在的主要原因是要维持处理器与早期模型兼容,并让操作系统自举(参阅附录一中针对实模式的简短描述)。

 

*段选择符和段寄存器

一个逻辑地址由两部分组成:一个段标识符和一个指定段内相对地址的偏移量。段标识符是一个16 位长的字段,称为段选择符(Segment Selector)如图2-2 所示,而偏移量是一个32 位长的字段。我们将在本章“快速访问段描述符”一节描述段选择符字段。

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

6 个寄存器中3 个有专门的用途:

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

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

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

其他3 个段寄存器作一般用途,可以指向任意的数据段。

cs 寄存器还有一个很重要的功能:它含有一个两位的字段,用以指明CPU 的当前特权级(Current Privilege LevelCPL)。值为0 代表最高优先级,而值为3 代表最低优先级。Linux 只用0 级和3 级,分别称之为内核态和用户态。

 

*段描述符

每个段由一个8 字节的段描述符(Segment Descriptor)表示,它描述了段的特征。段描述符放在全局描述符表(Global Descriptor Table ,GDT)或局部描述符表(Local Descriptor Table LDT)中。

通常只定义一个GDT,而每个进程除了存放在GDT 中的段之外如果还需要创建附加的段,就可以有自己的LDTGDT在主存中的地址和大小存放在gdtr 控制寄存器中,当前正被使用的LDT 地址和大小放在ldtr 控制寄存器中。

2-3 阐明了段描述符的格式;表2-1 解释了图中各个字段的含义

 

2-1:段描述符字段

字段名

描述

Base

包含段的首字节的线性地址

G

粒度标志:如果该位清0,则段大小以字节为单位,否则以4096 字节的倍
数计

Limit

存放段中最后一个内存单元的偏移量,从而决定段的长度。如果G 被置为
0
,则一个段的大小在1 个字节到1MB 之间变化;否则,将在4KB 4GB
之间变化

S

系统标志:如果它被清0,则这是一个系统段,存储诸如LDT 这种关键的
数据结构,否则它是一个普通的代码段或数据段

Type

描述了段的类型特征和它的存取权限(请看表下面的描述)

DPL

描述符特权级(Descriptor Privilege Level)字段:用于限制对这个段的存
取。它表示为访问这个段而要求的CPU 最小的优先级。因此,DPL 设为0
的段只能当CPL 0 时(即在内核态)才是可访问的,而DPL 设为3 的段
对任何CPL 值都是可访问的

P

Segment-Present 标志:等于0 表示段当前不在主存中。Linux 总是把这个
标志(第47 位)设为1,因为它从来不把整个段交换到磁盘上去

D B

称为D B 的标志,取决于是代码段还是数据段。D B 的含义在两种情
况下稍微有所区别,但是如果段偏移量的地址是32 位长,就基本上把它置
1,如果这个偏移量是16 位长,它被清0(更详细的描述参见Intel 使用
手册)

AVL

标志可以由操作系统使用,但是被Linux 忽略

有几种不同类型的段以及和它们对应的的段描述符。下面列出了Linux 中被广泛采用的类型:

代码段描述符:表示这个段描述符代表一个代码段,它可以放在GDTLDT 中。该描述符置S 标志为1(非系统段)。

数据段描述符

表示这个段描述符代表一个数据段,它可以放在GDTLDT 中。该描述符置S 标志为1。栈段是通过一般的数据段实现的。

任务状态段描述符(TSSD

表示这个段描述符代表一个任务状态段(Task State SegmentTSS),也就是说这个段用于保存处理器寄存器的内容(参见第三章中的“任务状态段”一节)。它只能出现在GDT 中。根据相应的进程是否正在CPU 上运行,其Type 字段的值分别为11 9。这个描述符的S 标志置为0

 

 

 

*快速访问段描述符

我们回忆一下:逻辑地址由16 位段选择符和32 位偏移量组成,段寄存器仅仅存放段选择符。

为了加速逻辑地址到线性地址的转换,80x86 处理器提供一种附加的非编程的寄存器(一个不能被程序员所设置的寄存器), 6 个可编程的段寄存器使用。每一个非编程的寄存器含有8 个字节的段描述符(在前一节已讲述),由相应的段寄存器中的段选择符来指定。每当一个段选择符被装入段寄存器时,相应的段描述符就由内存装入到对应的非编程CPU 寄存器。从那时起,针对那个段的逻辑地址转换就可以不访问主存中的GDTLDT,处理器只需直接引用存放段描述符的CPU 寄存器即可。仅当段寄存器的内容改变时,才有必要访问GDT LDT(参见图2-4)。

 

2-2 描述了任意段选择符所包含的3 个字段。

2-2:段选择符字段

字段名

描述

index

指定了放在GDTLDT中的相应段描述符的入口(在下面将作进一步的讲述)

TI

TI((Table Indicator)标志:指明段描述符是在GDT 中(TI=0)或在LDT
中(TI=1

RPL

请求者特权级:当相应的段选择符装入到cs 寄存器中时指示出CPU 当前
的特权级;它还可以用于在访问数据段时有选择地削弱处理器的特权级
(详情请参见Intel 文档)

 

由于一个段描述符是8 字节长,因此它在GDT LDT 内的相对地址是由段选择符的最高13 位的值乘以8 得到的。例如:如果GDT0x00020000(这个值保存在gdtr寄存器中),且由段选择符所指定的索引号为2,那么相应的段描述符地址是0x00020000 + 2 × 8), 0x00020010

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

 

 

*分段单元

2-5详细显示了一个逻辑地址是怎样转换成相应的线性地址的。分段单元(segmentationunit)执行以下操作:

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

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

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

 

请注意,有了与段寄存器相关的不可编程寄存器,只有当段寄存器的内容被改变时才需要执行前两个操作。

 

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