您现在的位置是:首页 > 服务器相关

CPU的保护模式(三)

batsom2020-12-11服务器相关

简介CPU的保护模式(三)

这个理论比较多,而且难以理解,如果是新手建议大致概念和思路,然后跳过,学完后面再来学,因为我也只是大致了解下概念,而且后面更精彩!

1:GDT(全局描述符表)和LDT(局部描述符表)和IDT(中断描述符表)
GDT的由来:
在Protected Mode下,一个重要的必不可少的数据结构就是GDT(Global Descriptor Table)。
为什么要有GDT?我们首先考虑一下在Real Mode下的编程模型:
在Real Mode下,我们对一个内存地址的访问是通过Segment:Offset的方式来进行的,其中Segment是一个段的Base Address,一个Segment的最大长度是64 KB,这是16-bit系统所能表示的最大长度。而Offset则是相对于此Segment Base Address的偏移量。Base Address+Offset就是一个内存绝对地址。由此,我们可以看出,一个段具备两个因素:Base Address和Limit(段的最大长度),而对一个内存地址的访问,则是需要指出:使用哪个段?以及相对于这个段Base Address的Offset,这个Offset应该小于此段的Limit。当然对于16-bit系统,Limit不要指定,默认为最大长度64KB,而 16-bit的Offset也永远不可能大于此Limit。我们在实际编程的时候,使用16-bit段寄存器CS(Code Segment),DS(Data Segment),SS(Stack Segment)来指定Segment,CPU将段积存器中的数值向左偏移4-bit,放到20-bit的地址线上就成为20-bit的Base Address。
到了Protected Mode,内存的管理模式分为两种,段模式和页模式,其中页模式也是基于段模式的。也就是说,Protected Mode的内存管理模式事实上是:纯段模式和段页式。进一步说,段模式是必不可少的,而页模式则是可选的——如果使用页模式,则是段页式;否则这是纯段模式。
既然是这样,我们就先不去考虑页模式。对于段模式来讲,访问一个内存地址仍然使用Segment:Offset的方式,这是很自然的。由于 Protected Mode运行在32-bit系统上,那么Segment的两个因素:Base Address和Limit也都是32位的。IA-32允许将一个段的Base Address设为32-bit所能表示的任何值(Limit则可以被设为32-bit所能表示的,以2^12为倍数的任何指),而不像Real Mode下,一个段的Base Address只能是16的倍数(因为其低4-bit是通过左移运算得来的,只能为0,从而达到使用16-bit段寄存器表示20-bit Base Address的目的),而一个段的Limit只能为固定值64 KB。另外,Protected Mode,顾名思义,又为段模式提供了保护机制,也就说一个段的描述符需要规定对自身的访问权限(Access)。所以,在Protected Mode下,对一个段的描述则包括3方面因素:【Base Address, Limit, Access】,它们加在一起被放在一个64-bit长的数据结构中,被称为段描述符。这种情况下,如果我们直接通过一个64-bit段描述符来引用一个段的时候,就必须使用一个64-bit长的段寄存器装入这个段描述符。但Intel为了保持向后兼容,将段寄存器仍然规定为16-bit(尽管每个段寄存器事实上有一个64-bit长的不可见部分,但对于程序员来说,段寄存器就是16-bit的),那么很明显,我们无法通过16-bit长度的段寄存器来直接引用64-bit的段描述符。
怎么办?解决的方法就是把这些长度为64-bit的段描述符放入一个数组中,而将段寄存器中的值作为下标索引来间接引用(事实上,是将段寄存器中的高13 -bit的内容作为索引)。这个全局的数组就是GDT。事实上,在GDT中存放的不仅仅是段描述符,还有其它描述符,它们都是64-bit长。GDT是Protected Mode所必须的数据结构,也是唯一的。另外,正像它的名字(Global Descriptor Table)所揭示的,它是全局可见的,对任何一个任务而言都是这样。

LDT属于程序,GDT属于系统,同一台计算机上的所有程序共享一个GDT。
LDT描述局部于每个程序的段,包括其代码、数据、堆栈等。GDT描述系统段,包括操作系统本身。

GDT
整个系统中只有GDT(一个处理器对应一个),可以存放在内存的任何位置,那么如何获得GDT的入口地址呢? Intel使用一个48位的寄存器GDTR存储GDT的入口地址。使用LGDT xxx将GDT的入口地址装入GDTR,之后CPU根据GSTR的内容访问GDT表,相应的又LDTR,与GDTR相同的功能,只是它存放的LDT的入口地址。

GDT与LDT都是保护模式中的,之前不明白实模式与保护模式的区别,如何保护,系统级别与特权级别的区别在哪里,到这里稍微有点明白。在保护模式中通过描述符表,选择子加入了特权级别的检验以下是全局描述符表的数据结构:

LDT
LDT局部描述符表可以有若干张,每个任务可以有一张。我们可以这样理解GDT和LDT:GDT为一级描述符表,LDT为二级描述符表。

和GDT一样,中断描述符表在系统最多只能有一个,中断描述符表内可以存放256个描述符,分别对应256个中断.因为每个描述符占用8个字节,所以IDT的长度可达2K.中断描述符表中可以有任务门、中断门、陷阱门三个门描述符,其它的描述符在中断描述符表中无意义。

三者的关系:GDT,IDT都是全局的。LDT是局部的(在GDT中有它的描述符),GDT用来存储描述符(门或非门);系统中几个CPU,就有几个GDT,IDT整个系统只有一个,系统启动时候需要初始化GDT和IDT。LDT和进程相关,并不一定必有

相关文章:
http://www.techbulo.com/708.html

2:内存分页机制
当下大部分操作系统的方案是,将一些进程不常用的内存段换出到硬盘中,腾出内存空间供需要的进程使用。虽然硬盘是比内存还低速的设备,在两个速度不匹配的设备之间进行数据交换对内存来说是一种浪费,但使用合理的置换算法可以减少置换次数。
在保护模式下,内存段的各种属性由段描述符保存,CPU在引用一个段时,都要先查看段描述符。段描述符存放在GDT或LDT中,即使段并不在内存中,即CPU允许在段描述表中已注册的段不在内存中存在。如果该描述符中的P位为1,表示该段在内存中存在,访问过该段后,CPU将段描述符中的A位置1,表示近期访问过该内存段。
段描述符的A位由CPU置1,清0则由操作系统来完成。操作系统每发现该位置1后就将该位清0,同时统计一个周期内该位为1的次数,就可以知道该内存段的使用频率,从而在物理内存不足时找出使用频率最低的段将其换出到硬盘以腾出内存空间给需要使用内存的进程。当段被换出到硬盘后,操作系统将该段的段描述符的P位置0,表示该段已不在内存中。
如上所述,计算机的软件和硬件相互配合完成内存的置换工作。虽然这在一定程度上解决了内存不足的问题,但还是有缺陷。比如物理内存特别小,以至于无法容纳任何一个进程的段,这就没法运行进程,更没法做段的置换工作了。而出现这种问题的本质原因是在目前只有分段的情况下,CPU认为线性地址等于物理地址,而线性地址是由编译器编译出来的,它本身是连续的,所以物理地址也必须要连续才行,但我们可用的物理地址并不连续。因此,为解决这个问题,我们需要解除线性地址与物理地址一一对应的关系,让他们之间重新建立映射——即让线性地址连续而物理地址不连续。在操作系统中实现这种映射的策略就是内存分页机制,相关数据结构就是页表。
页目录表与页表 存内存,所以可以一共有 1KB = 2^10个;而物理页存储字节,共存2^12个;因此10-10-12分页就是这么来的。

3:特权级转换
在IA32的分段机制下,特权级总共有4个特权级别,从高到低分别是0、1、2、3。数字越小表示的特权级越大

系统要安全,必须保证内核与用户程序分离开,内核要安全,必须不能被用户来打扰。但是有的时候,用户程序也是需要访问内核中的部分数据,那怎么办?

于是操作系统就将内核中的段分为共享的代码段和非共享的代码段两部分。
其中一致代码段就是操作系统拿出来被共享的代码段,可以被低特权级的用户直接访问的代码。
一致代码段的限制作用:
(1)特权级高的代码段不允许访问特权级低的代码段:即内核态不允许调用用户态下的代码。
(2)特权级低的代码段可以访问特权级高的代码段,但是当前的特权级不发生变化。即:用户态可以访问内核态的代码,但是用户态仍然是用户态。

非一致代码段:为了避免低特权级的访问而被操作系统保护起来的系统代码,也就是非共享代码。
非一致代码段的限制作用:
(1)只允许同特权级间访问
(2)绝对禁止不同级间访问,即:用户态不能访问内核态,内核态也不访问用户态。

1、CPL(Current PrivilegeLevel)是当前执行的程序或任务的特权级。它被存储在CS和SS的第0位和第1位上。通常情况下,CPL等于代码的段的特权级。在遇到一致代码段时,一致代码段可以被相同或者更低特权级的代码访问。当处理器访问一个与CPL特权级不同的一致代码段时,CPL不会被改变。
2、DPL(DescriptorPrivilege Level):DPL表示段或者门的特权级,它被存储在段描述符或者门描述符的DPL字段中。当当前代码段试图访问一个段或者门时,DPL将会和CPL以及段或门选择子的RPL相比较,根据段或者门类型的不同,DPL将会被区别对待,下面介绍一下各种类型的段或者门的情况。
(1)数据段: CPL(RPL)<= DPL才可以访问
(2)非一致代码段(不使用调用门的情况下): CPL(RPL)=DPL才可以访问
(3)调用门:DPL规定了当前执行的程序或任务可以访问此调用门的最低特权级(这与数据段的规则是一致的)。
(4)一致代码段和通过调用门访问的非一致代码段:CPL(RPL)=> DPL
3、RPL(RequestedPrivilege Level):RPL是通过选择子的第0位和第1位表现出来的。处理器通过检查RPL和CPL来确认一个访问请求是否合法。

不同特权级数据段之间的访问规则
CPL(RPL)<=DPL

郑重声明:

本站所有活动均为互联网所得,如有侵权请联系本站删除处理

随便看看

文章排行

本栏推荐

栏目更新