操作系统——L2-对GDT和LDT的理解

操作系统——L2-对GDT和LDT的理解1 内存寻址 1

欢迎大家来到IT世界,在知识的湖畔探索吧!

1、内存寻址

1.1 实模式下的内存寻址

实模式(也就是 8086 的模式)下的寻址方式如下:

段首地址 x 16 + 偏移量 = 物理地址;即cs<<4+ip

乘以 16 是因为在 8086 CPU中,地址线是20位,但寄存器是16位的(或者说用来寻址的段寄存器只有16位),最高寻址64KB,它无法寻址到1M内存。于是,Intel 设计了这种寻址方式,这也造成了段的首地址必须是16的倍数的限制。

1.2 保护模式下分段机制的内存寻址

保护模式和实模式的寻址方式有着很大的不同。保护模式下内存寻址的方式为:利用段选择子(通常情况下也就是实模式下的段寄存器:cs、ds等)从段描述符表(GDT、LDT都是段描述符表)中找到对应的段描述符,因为段描述符中含有需要寻址的段基地址、段长度,段属性等信息,所以利用通过段选择子找到的段描述符和偏移量就可以寻址到对应的内存地址。在未开启分页机制的情况下,此时保护模式下的寻址方式如下:

段描述符中的基地址 + 偏移量 = 物理地址

这一段话,出现了三个新名词:段选择子、段描述符表、段描述符

可以先简单理解:段描述符表 是一个数组,这个数组中的每一项都是一个 段描述符,段选择子 作为 段描述符表 的索引,其实 段选择子 就是数组的下标。

说人话:

  • 段描述符表:数组
  • 段描述符:数组元素
  • 段选择子:数组下标

我们再看一下实模式下和保护模式下 ,下面两条汇编指令的区别(下面两句代码都来自 Linux0.11 ):

jmpi go, INITSEG ! 该指令在实模式下执行, go是个汇编标号,是偏移地址,INITSEG 是段基地址(在mov指令中段基地址 ! 通常是cs、ds等)。所以该指令要跳转 INITSEG << 4 + go 地址去执行。 jmpi 0, 8 ! 该指令在保护模式下执行,0 为偏移地址,8 为段选择子(在mov指令中段选择子通常是cs、ds等)。 ! 所以该指令利用 8 找到对应的段描述符,在利用段描述符中的段基地址 + 偏移地址找到对应的物理地址。

欢迎大家来到IT世界,在知识的湖畔探索吧!

2、什么是GDT

GDT 就是段描述符表的一种。GDT 全名是(Global Describe Table)全局描述符表,存放在内存中(GDT可以被放在内存的任何位置),只有一张且全局可见。经过上一节的分析,GDT 就是一个段描述符类型的数组。形象点表示的话,如下:

欢迎大家来到IT世界,在知识的湖畔探索吧!// Discriptor就是段描述符,该结构体大小为 64 bit struct Discriptor { elemType Base; // 段物理首地址 elemType Limit; // 段界限 elemType Access; // 段属性 }; // discriptorTable[n] 就是描述符表(GDT) struct Discriptor discriptorTable[n] = {...};

段描述符 有64位,段描述符的实际结构如下(其实段描述符不是上面说的那个结构体,不过内容也没什么区别。另外段描述符为什么会这么奇怪,好像是为了兼容之前的架构):

操作系统——L2-对GDT和LDT的理解



欢迎大家来到IT世界,在知识的湖畔探索吧!

从图中可以看出 段描述符表 中有一个重要的信息——段基地址。关于 段属性 可以简单了解一下:

  1. G:
    1. G=0时,段限长的20位为实际段限长,最大限长为2^20=1MB
    2. G=1时,则实际段限长为20位段限长乘以2^12=4KB,最大限长达到4GB
  1. DPL:特权级,0为最高特权级,3为最低,表示访问该段时CPU所需处于的最低特权级。( 区别一下CPL:CPL是当前进程的权限级别(Current Privilege Level),是当前正在执行的代码所在的段的特权级,存在于cs寄存器的低两位。)

3、什么是LDT

LDT 的全称是局部段描述符表。LDT 的结构与 GDT 类似,也存放在内存中,与GDT不同的是,LDT在系统中可以存在多个(当然LDT也可以没有),并且从LDT的名字可以得知,LDT不是全局可见的,它们只对引用它们的任务可见,每个任务最多可以拥有一个LDT。另外,每一个LDT自身作为一个段存在,它们的段描述符被放在GDT中。

IA-32 为 LDT 的入口地址也提供了一个寄存器 LDTR,因为在任何时刻只能有一个任务(或者说进程)在运行,所以 LDT 寄存器全局也只需要有一个。如果每个任务都拥有自身的 LDT,那么在切换到下一个任务的时候,就要修改 LDTR ,让 LDTR 指向下一个任务的 LDT。修改方式就是通过 LLDT 指令将下一个任务的 LDT 的 段描述符的索引(也就是段选择子)装入此寄存器。

操作系统——L2-对GDT和LDT的理解

LLDT 指令与 LGDT 指令不同:

  • LGDT 指令的操作数是一个 32-bit 的内存地址,这个内存地址指向一个48bit的内存空间,这个内存空间里存放了 32-bit GDT 的入口地址,以及 16-bit 的GDT Limit。LGDT 指令会将这48bit内容加载到 GDTR中。
  • LLDT 指令的操作数是一个16-bit的 选择子,这个选择子主要内容是:被装入的 LDT 的段描述符在 GDT 中的索引值。LLDT 指令会将这个16-bit的 选择子加载到 LDTR 中。

4、段选择子

原先实模式下的各个段寄存器作为保护模式下的段选择子(也可以称为段选择器、段选择符),80486中有6个(即CS,SS,DS,ES,FS,GS)16位的段寄存器。段选择子 CS 对应表示的段仍为代码段,SS 对应表示的段仍为堆栈段。当然段选择子也不都是段寄存器,而是根据具体的汇编指令而定,就像第1节中的那个 jmpi 指令,选择子就是一个常数。

段选择子大小为 16bit。段选择子包括三部分:描述符索引(index)、TI、请求特权级(RPL)。

操作系统——L2-对GDT和LDT的理解

(图5.1存在一些错误:段选择子的大小应该是0~15 共 16bit,其中 RPL 为 bit0 – bit1、TI 为 bit2、Index 为 bit3 – bit15)

  • Index(描述符索引)部分表示所需要的段描述符在描述符表的位置(如Index = 1,表示段描述符表的第1项段描述符),由这个位置再根据在 GDTR 中存储的描述符表基址就可以找到相应的描述符。然后用描述符表中的段基址加上逻辑地址(SEL:OFFSET)的OFFSET就可以转换成线性地址。
  • TI 值只有一位0或1,0代表选择子是在 GDT 中索引,1代表选择子是在 LDT 中索引。
  • 请求特权级(RPL)则代表选择子的特权级,共有4个特权级(0级、1级、2级、3级)。

5、关于特权级的说明

任务中的每一个段都有一个特定的级别。每当一个程序试图访问某一个段时,就将该程序所拥有的特权级与要访问的特权级进行比较,以决定能否访问该段。系统约定,CPU只能访问同一特权级或级别较低特权级的段。

Linux0.11中只是用了2个特权级:0级和3级,其中操作系统的内核区为0级,用户区为3级。特权级有3种类型:CPL、DPL和RPL。

  • CPL为当前特权级,表示当前正在执行的程序的特权级,存放在cs和ss寄存器中。int指令可以将 CPL 改为0
  • DPL为描述符特权级,表示要访问的段或门的特权级(目标特权级)。DPL存放在段描述符或门描符中。
  • RPL为请求特权级,存放在段选择子(如ds,cs等段寄存器,不过RPL通常被用在ds中)中。若这个段选择子是 cs,那么此时RPL 就等于 CPL (因为CPL只存放在 cs 中)。

当程序访问一个段时,处理器会检查CPL、DPL和RPL, 只有当 DPL>= CPL 且 DPL>= RPL 时处理器才会允许程序访问该段。例如 CPL = 3,RPL = 3, DPL = 0 时程序访问的请求时不被允许的。

6、再看保护模式下分段机制的内存寻址

6.1 访问GDT

操作系统——L2-对GDT和LDT的理解

TI = 0时表示段描述符在 GDT 中,如上图所示:

  1. 先从 GDTR 寄存器中获得 GDT 基址;
  2. 然后再根据段选择子(段选择器)高13位的位置索引值得到段描述符;
  3. 段描述符符包含段的基址、限长、优先级等各种属性,这就得到了段的起始地址(基址),再以基址加上偏移地址;

6.2 访问LDT

操作系统——L2-对GDT和LDT的理解

当 TI = 1 时表示段描述符在 LDT 中,如上图所示:

  1. 还是先从 GDTR 寄存器中获得 GDT 基址;
  2. 从 LDTR 寄存器中获取 LDT 所在段的位置索引 (LDTR高13位),此时 LDTR 可以看成一个段选择子;
  3. 通过这个位置索引 (LDTR高13位),在 GDT 中得到 LDT 的段描述符从而得到 LDT 段基址;
  4. 利用段选择子(段选择器)高13位位置索引值从 LDT 段中得到需要访问的内存的段描述符;
  5. 段描述符符包含段的基址、限长、优先级等各种属性,这就得到了段的起始地址(基址),再以基址加上偏移地址 yyyyyyyy 得到最后的线性地址;

7、总结

其实GDT只是一个段描述符类型的数组,它主要是用于内存寻找。为了对部分内存区域(存放着核心数据)进行保护,因此将段描述符设计成了三部份。而LDT的结构和GDT类似,我们可以这样理解GDT和LDT:GDT为一级描述符表,LDT为二级描述符表。

LDT不包含在GDT中。GDT中只是包含了LDT描述符(一个指向LDT起始地址的指针)。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/110845.html

(0)
上一篇 23分钟前
下一篇 8分钟前

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信