保护机制(个人理解)
来源:互联网 发布:蒋欣刘涛关系破裂知乎 编辑:程序博客网 时间:2024/05/20 00:12
- 保护机制概述:
- 保护机制是可靠的多任务运行环境所必须的。它可用于保护各个任务免受相互之间的干扰。在软件开发的任何阶段都可以使用段级和页级保护来协助寻找和检测设计问题和错误。当程序对错误内存空间执行一次非期望的引用,保护机制可以阻止这种操作并且报告此类事件。
- 保护机制可以被用于分段和分页机制。处理器寄存器的2个比特位定义了当前执行程序的特权级,称为当前特权级CPL(Current Privilege Level)。分段和分页地址转换过程中,处理器将对CPL进行验证。
- 通过设置控制寄存器CR0 的PE 标志(位 0)可以让处理器工作在保护模式下,从而也就开启了分段保护机制。一旦进入保护模式,处理器中并不存在明确的控制标志来停止或者启用保护机制。不过基于特权级的保护机制部分可以通过把所有段选择符和段描述符的特权级都设置为0级来隐含地关闭。这种呢处理方式可以在段之间禁止特权级保护壁垒,但是其他段长度和段类型等保护机制仍然起作用。
- 设置控制寄存器CR0的PG 标志(位31)可以开启分页机制,同时也开启了分页保护机制。同样,处理器中也没有相关的标志用来分页开启条件下禁止或开启页级别保护机制。但是通过设置每个页目录项和页表现的读/写(R/W)标志和用户/超级用户(U/S)标志,我们可以禁止页级保护机制。设置这两个标志可以使得每个页面都可以被任意读/写,因此实际上也就禁止了页级保护。
- 对于分段保护机制,处理器使用段寄存器中选择符(RPL 和 CPL)和段描述符中各个字段执行保护验证。对于分页机制,则主要利用页目录和页表项中的R/W 和 U/S 标志来实现保护操作。
- 段级别保护
- 在保护模式下,80x86 提供了段级和页级保护机制。这种保护机制根据特权级(4级段保护和 2级页保护)提供了对某些段和页面的访问限制能力。例如,操作系统代码和数据存放在要比普通应用程序具有高特权级的段中。此后处理器的保护机制将会限制应用程序只能按照受控制的和规定的方式访问操作系统的代码和数据。
- 当使用保护机制时,每个内存引用都将受到检查以验证内存引用符合各种保护要求。因为检查操作是与地址变换同时并行操作,所以处理器性能并没有受到影响。所进行的保护检查可分为以下几类:
- 段界限检查;
- 段类型检查;
- 特权级检查;
- 可寻址范围限制;
- 过程入口点限制;
- 指令集限制.
- 所有违反保护的操作都将导致产生一个异常。下面各节描述保护模式下的保护机制。
- 段限长Limit 检查
- 段描述符的段限长(或称段界限)字段用于防止程序或过程寻址到段外内存位置。段限长的有效值依赖于颗粒度G 标志的设置状态。对于数据段,段限长还与标志E (扩展方向)和标志B(默认栈指针大小和/或上界限)有关。E 标志是数据段类型的段描述符中类型字段的一个比特位。
- 当G 标志清零时(字节颗粒度),有效的段长度是20 bit 的段描述符中段限长字段Limit的值。在这种情况下,Limit的范围从 0 到0xfFFFF(2^20 = 1MB)。当G 标志置位时(4KB 页颗粒度),处理器把Limit 字段的值乘上一个因子 4K。在这种情况下,有效的Limit范围是从0xFFF 到 0xffffFFFF(2^32 = 4GB)。请注意,当设置了 G 标志时,段偏移(地址)的低12 bit 不会与Limit 进行对照检查。例如,当段限长Limit 等于 0时,偏移值 0 到 0xFFF 仍然是有效的。
- 除了下扩段意外的所有段类型,有效Limit 的值是段中允许被访问的最后一个地址,它要比段长度小 1个 字节。任何超出段限长字段指定的有效地址范围都将导致产生一个一般保护异常。
- 对于下扩数据段,段限长具有同样的功能,但其含义不同。这里,段限长指定了段中最后一个不允许访问的地址,因此在设置了B 标志的情况下,有效偏移范围是从(有效段偏移+1) 到 0xffff FFFF ; 当B 清零时,有效偏移值范围是从(有效段偏移+1) 到 0xFFFF 。当下扩段的段限长为0 时,段会有最大长度。
- 除了对段限长进行检查,处理器也会检查描述符表的长度。GDTR ,IDTR 和LDTR 寄存器中包含有 16bit 的限长值,处理器用它来防止程序在描述符的外面选择描述符。描述符表的限长值指明了表中最后一个有效字节。因为每个描述符是 8 字节长,因此含有N 个描述符项的表应该具有限长值 8N -1.
- 选择符可以具有 0值。这样的选择符指向GDT 表中的第一个不用的描述符项。尽管这个空选择符可以被加载进一个段寄存器中,但是任何使用这种描述符引用内存的企图都将产生一个一般保护性异常。
- 段类型TYPE 检查
- 除了应用程序代码和数据段有描述符以外,处理器还有系统段和门两种描述符类型。这些数据结构用于管理任务以及异常和中断。 请注意,并非所有的描述符都定义一个段,门描述符中存放有指向一个过程入口点的指针。段描述符在两个地方含有类型信息,即描述符中的S 标志和类型字段 TYPE。 处理器利用这些信息对由于非法使用段或门导致的编程错误进行检测。
- S 标志用于指出一个描述符是系统类型的还是代码或者数据类型的。TYPE 字段另外提供了 4 个 bit 用于定义代码,数据和系统描述符的各种类型。 以前的表给出了代码和数据描述符TYPE 字段的编码; 另一个表给出了系统描述符TYPE 字段的编码。
- 当操作段选择符和段描述符时,处理器会随时检查类型信息。主要在以下两种情况下检查类型信息:
- 当一个描述符的选择符加载进一个段寄存器中。此时某些段寄存器只能存放特定类型的描述符,例如:
- CS 寄存器中只能被加载进一个可执行段的选择符;
- 不可读可执行段的选择符不能被加载进数据段寄存器中;
- 只有可可数据段的选择符才能被加载进SS 寄存器中。
- 当指令访问一个段,而该段的描述符已经加载进段寄存器中。指令只能使用某些预定义的方法来访问某些段。
- 任何指令不能写一个可执行段;
- 任何指令不能写一个可写位没有置位的数据段;
- 任何指令不能读一个可执行段,除非可执行段设置了可读标志。
- 当一个描述符的选择符加载进一个段寄存器中。此时某些段寄存器只能存放特定类型的描述符,例如:
- 特权级
- 处理器的段保护机制可以识别 4 个特权级(或特权层 R0~R3) 0级到3级。数值越大,特权越小。下图示出了这些特权级如何被解释成保护环形式。环中心(保留给最高级的代码,数据和堆栈)用于含有最紧要软件的段,通常用于操作系统核心部分。中间两个环用于较为紧要的软件。只使用 2个特权级的系统应该使用 R0 以及R3.
- 处理器利用特权级来防止运行在较低特权级的程序或任务访问具有较高特权级的一个段,除非是在受控的条件下。当处理器检测到一个违反特权级的操作时候,它就会产生一个一般保护性异常。
- 为了各个代码段和数据段之间进行特权级检测处理,处理器可以识别以下三种类型的特权级:
- 当前特权级CPL(Current Privilege Level)。CPL是当前正在执行程序或任务的特权级。它存放在CS 和SS段寄存器中的位0 和 位1中。通常,CPL等于当前代码段的特权级。当程序把控制转移到另一个具有不同特权级的代码段中时,处理器就会改变CPL。当访问一个一致性(conforming)代码段时,则处理器对CPL的设置有些不同。特权级值高于(即低特权级)或等于一致代码段DPL 的任何段 都可以访问一致代码段。并且当处理器访问一个特权级不同于CPL的一致代码段时,CPL并不会被修改一致代码段的DPL(Descriptor Privilege Level)。
- DPL 是一个段或门的特权级。它存放在段或门描述符的DPL 字段中。在当前执行代码段试图访问一个段或者门时,段或门的DPL 会用来与CPL 以及段 或门选择符中RPL (见下面说明)作比较。根据被访问的段或门的类型不同,DPL也有不同的含义:
- 数据段(Data Segment)。其DPL 指出允许访问本数据段的程序或任务应具有的最大特权级数值。例如,如果数据段的特权级DPL 是1,那么只有运行在CPL 为0 或 1的程序可以访问这个段。
- 非一致代码段(Nonconforming code segment)(不使用调用门)。其DPL 指出程序或任务访问该段必须具有的特权级。例如,如果某个非一致代码段的DPL 是 0,那么只有运行在CPL 为 0的程序能够访问这个段。
- 调用门(Call Gate)。其DPL 指出访问调用门的当前执行程序或任务可处于的最大特权级数值。(这与数据段的访问规则相同)。
- 一致和非一致代码段(通过调用门访问)。其DPL 指出允许访问本代码段的程序或任务应具有的最小特权级数值。例如,如果一致代码段的DPL 是2,那么运行在CPL 为 0的程序就不能访问这个代码段。
- 任务状态段TSS。其DPL 指出访问TSS 的当前执行程序或任务可处于的最大特权级数值。(这与数据段的访问规则相同)。
- 请求特权级RPL (Request Privilege Level).PRL 是一种赋予段选择符的超越特权级,它存放在选择符的位 0 和 位 1中。处理器会同时检查RPL 和CPL,以确定是否允许访问一个段。即使程序或者任务具有足够的特权级(CPL)来访问一个段,但是如果提供的RPL 特权级不足的话访问也将被拒绝。也即如果段选择符的RPL 其数值大于CPL,那么RPL将覆盖CPL(而使用RPL作为检查比较的特权级),反之也然。即始终取RPL 和CPL 中数值最大的特权级作为访问段时的比较对象。因此,,RPL 可以用来确保高特权级的代码不会代表应用程序去访问一个段,除非应用程序自己具有访问这个段的权限。
- 当段描述符的段选择符被加载进一个段寄存器时就会进行特权级检查操作,但用于数据访问的检查方式和那些用于在代码段之间进行程序控制转移的检查方式不一样。因此下面分两种访问情况来考虑。
- 访问数据段时的特权级检查
- 为了访问数据段中的操作数,数据段的段选择符必须被加载进数据段寄存器(DS,ES,FS,GS)或堆栈段寄存器(SS)中。(可以使用指令MOV, POP,LDS,LES,LFS,LGS,LSS来加载段寄存器)。在把一个段选择符加载进段寄存器中之前,处理器会进行特权级检查,见下图所示。它会把当前运行程序或任务的CPL ,段选择符的RPL 和段描述符的DPL进行比较.。只有当段的DPL数值大于或等于CPL 和RPL 两者时候,处理器才会把选择符加载进段寄存器中。否则就会产生一个一般保护异常,并且不加载段选择符。
- 可知一个程序或任务可寻址的区域随着其CPL 改变而变化。
- 当CPL 是 0时,此时所有特权级上的数据段都可被访问;
- 当CPL 是1 时,只有特权级 R1-R3的数据段可被访问;
- 当CPL 是 3时,只有处于特权级3 的数据段可被访问。
- 另外,有可能会把数据保护在代码段中。例如,当代码和数据是在ROM中时。因此,有些时候我们会需要访问代码段中的数据。此时可以使用以下方法来访问代码段中的数据:
- 把非一致可读代码段的选择符加载进一个数据段寄存器中。
- 把一致可读代码段的选择符加载进一个数据段寄存器中。
- 使用代码段覆盖前缀(CS)来读取一个选择符已经在CS 寄存器中的可读代码段。
- 访问数据段的相同规则也适用方法1.方法2则是总是有效的,因为一致代码段的特权级等同于CPL,而不管代码段的DPL。方法3 也总是有效的,因为CS 寄存器选择的代码段的DPL 与CPL 相同。
- 当使用堆栈段选择符加载SS 段寄存器时 也会执行特权级检查。这里与堆栈段相关的所有特权级必须与CPL 匹配。也即,CPL,堆栈段选择符的RPL 以及堆栈段描述符的DPL 都必须相同。如果RPL 或DPL与CPL 不同,处理器就会产生一个一般保护性异常。
- 代码段之间转移控制时的特权级检查
- 对于将程序控制权从一个代码段转移到另一个代码段,目标代码段的段选择符必须加载进代码段寄存器(CS)中。作为这个加载过程的一部分,处理器会检查目标代码段的段描述符并执行各种限长,类型和特权级检查。如果这些检查都通过了,则目标代码段选择符就会加载进CS 寄存器,于是程序的控制权就被转移到新代码段中,程序将从EIP 寄存器指向的指令处开始执行。
- 程序的控制转移使用指令 JMP,RET, INT 和IRET 以及异常和中断机制来实现。异常和中断时一些特殊实现,将在后面描述,本节主要说明 JMP, CALL 和RET 指令的实现方法。 JMP 和CALL 指令可以利用以下四种方法之一来引用另外一个代码段:
- 目标操作数含有目标代码段的段选择符;
- 目标操作数指向一个调用门描述符,而该描述符中含有目标代码段的选择符;
- 目标操作数指向一个TSS ,而该TSS 中含有目标代码段的选择符;
- 目标操作数指向一个任务门,该任务门指向一个TSS,而该TSS中含有目标代码段的选择符;
- 直接调用或跳转到代码段
- JMP,CALL 呵呵RET 指令的近转移形式只是在当前代码段中执行程序控制转移,因此不会执行特权级检查。JMP CALL 或RET 指令的远转移形式会把 控制转移到另外一个代码段中,因此处理器一定会执行特权级检查。
- 当不通过调用门把程序控制权转移到另一个代码段时,处理器会验证4种 特权级和类型信息,见下图所示:
- 当前特权级CPL。(这里,CPL 是执行调用的代码段的特权级,即含有执行调用或跳转程序的代码段的CPL)。
- 含有被调用过程的目的代码段描述符中的描述符特权级DPL。
- 目的代码段的段选择符中的请求特权级RPL。
- 目的代码段描述符中的一致性标志C。它确定了一个代码段是非一致代码段还是一致代码段。处理器检查CPL,RPL和DPL 的规则依赖于一致标志C的设置状态。当访问非一致代码段时(C=0),调用者(程序)的CPL 必须等于目的代码段的DPL,否则将会产生一般保护异常。指向非一致代码段的段选择符的RPL 对检查所起的作用有限。RPL 在数值上必须小于或等于调用者的CPL 才能使得控制转移成功完成。当非一致代码段的段选择符被加载进CS 寄存器中时,特权级字段不会改变,即使】它仍然是调用者的CPL。即使段选择符的RPL 与CPL 不同,这也是正确的。
- 当访问一致代码段时(C=1),调用者的CPL 可以在数值上大于或等于目的代码段的DPL。仅当CPL < DPL 时,处理器才会产生一般保护异常。对于访问一致代码段,处理器忽略对RPL 的检查。对于一致代码段,DPL 表示调用者对代码段进行成功调用可以处于的最低数值特权级。
- 当程序控制被转移到一个一致代码段中,CPL 并不改变,即使目的代码段的DPL 在数值上小于CPL。这是CPL 与 可能与当前代码段DPL 不相同的唯一一种情况。同样,由于CPL 没有改变,因此堆栈也不会切换。
- 大多数代码段都是非一致代码段。对于这些段,程序的控制权只能转移到具有相同特权级的代码段中,除非转移是通过一个调用门进行,见下面说明。
- 门描述符
- 为了对具有不同特权级的代码段提供受控的访问,处理器提供了称为门描述符的特殊描述符集。共有4种门描述符:
- 调用门(Call Gate),类型TYPE =12;
- 陷阱门(Trap Gate),类型TYPE =15;
- 中断门(Interrupt Gate),类型TYPE =14;
- 任务门(Task Gate), 类型TYPE = 5。
- 任务门用于任务切换,将在后面任务管理一节说明。陷阱门和中断门是调用门的特殊类,专门用于调用异常和中断的处理程序,这里仅说明调用门的使用方法。
- 调用门用于在不同特权级之间实现受控的程序控制转移。它们通常仅用于使用特权级保护机制的操作系统中。下图给出了调用门描述符的格式。调用门描述符可以存放在GDT 或 LDT 中,但是不能放在中断描述符IDT 中。一个调用门主要具有以下几个功能:
- 指定要访问的代码段;
- 在指定代码段中定义过程(程序)的一个入口点;
- 指定访问过程的调用者需要具备的特权级;
- 若会发生堆栈切换,它会指定在堆栈之间需要复制的可选参数个数;
- 指明调用门描述符是否有效。
- 调用门中的段选择符字段指定要访问的代码段。偏移值字段指定段中入口点。这个入口点通常是指定过程的第一条指令。DPL 字段指定调用门的特权级,从而指定通过调用门访问特定过程所要求的特权级。标志P 指明调用门描述符是否有效。参数个数字段(param Count)指明在发生堆栈齐辉时从调用者堆栈复制到新堆栈中的参数个数。Linux 内核中并没有用到调用门。这里对调用门进行说明是为了下一节介绍利用中断和异常门进行处理作准备。
- 为了对具有不同特权级的代码段提供受控的访问,处理器提供了称为门描述符的特殊描述符集。共有4种门描述符:
- 通过调用门访问代码段
- 为了访问调用门,我们需要为CALL 或 JMP 指令的操作数提供一个远指针。该指针中的段选择符用于指定调用门,而指针的偏移值虽然需要单CPU 并不会用它。该偏移值可以设置为任意值。见下图所示。
- 当处理器访问调用门时,它会使用调用门中的段选择符来定位目的代码段的段描述符。然后CPU 会把代码段描述符的基地址与调用门中的偏移值进行组合,形成代码段中指定程序入口点的线性地址。
- 通过调用门进行程序控制转移时,CPU 会对 4种不同的特权级进行检查,以确定控制转移的有效性,见下图所示:
- 当前特权级CPL;
- 调用门选择符中的请求特权级RPL;
- 调用门描述符中的描述符特权级DPL;
- 目的代码段描述符中的DPL;
- 另外,目的代码段描述符中的一致性标志C 也会受到检查。
- 使用CALL 指令和JMP 指令分别具有不同的特权级检测规则,见下图所示。调用门描述符的DPL 字段指明了调用程序能够访问调用门的数值最大的特权级(最小特权级),即为了访问调用门,调用者程序的特权级CPL 必须小于 或等于调用门的DPL 。 调用门段选择符的RPL 也需同调用这的CPL 遵守同样的规则,即RPL 也必须小于或等于调用门的DPL。
- 如果调用这与调用门之间的特权级检查成功通过,CPU就会接着把调用者的CPL 与代码段描述符的DPL 进行比较检查。在这方面,CALL 指令和JMP 指令的检查规则就不同了。只有CALL指令可以通过调用门把程序控制转移到特权级更高的非一致性代码段中,即可以转移到DPL 小于CPL 的非一致性代码段中去执行。而JMP 指令只能通过调用门把控制转移到DPL 等于CPL 的非一致性代码段中。但CALL 指令和JMP 指令都可以把控制转移到更高特权级的一致性代码段中,即转移到DPL 小于或等于 CPL 的一致性代码段中。
- 如果一个调用把控制转移到了更高特权级的非一致代码段中,那么CPL 就会被设置为目的代码段的DPL值,并且会引起堆栈切换。但是如果一个调用或跳转把控制转移到更高级别的一致性代码段上,那么CPL 并不会改变,并且也不会引起堆栈切换。
- 调用门可以让一个代码段中的过程被不同特权级的程序访问。例如,位于一个代码段中的操作系统代码可能含有操作系统自身和应用软件都允许访问的代码(比如处理字符I/O的代码)。因此可以为这些过程设置一个所有特权级代码都能访问的调用门。另外可以专门为仅用于操作系统的代码设置一些更高特权级的调用门。
- 堆栈切换
- 每当调用门用于把程序控制转移到一个更高级别的非一致性代码段时,CPU 会自动切换到目的代码段特权级的堆栈去执行栈切换操作的目的是为了防止高特权级程序由于栈空间不足而引起崩溃,同时也为了防止低特权级程序通过共享的堆栈有意或无意地干扰高特权级的程序。
- 每个人物必须定义最多3个栈。一个用于运行在特权级3的应用程序代码,其他分别用于用到的特权级R2 ,R1,和R0.如果一个系统中只使用了R3 和R0 两个特权级,那么每个人物就只需要设置两个栈。每个栈都位于不同的段中,并且使用段选择符和段中偏移值指定。
- 特权级R0,R1,R2的堆栈的初始指针值都存放在当前运行人物的TSS段中。TSS段中这些指针都是只读值。在人物运行时CPU 并不会修改它们。当调用更高特权级程序时,CPU 才用它们来建立新堆栈。当从调用过程返回时,相应栈就不存在了。下一次再调用该过程时,就又会再次使用TSS 中的初始指针值 建立一个新栈。
- 操作系统需要负责为所有用到的特权级建立堆栈和堆栈段描述符,并且在任务的TSS中设置初始指针值。每个栈必须可读可写,并且具有足够的空间来存放以下一些信息:
- 调用过程的SS,ESP,CS和EIP寄存器内存;
- 被调用过程的参数和临时变量所需使用的空间。
- 当隐含调用一个异常或中断过程时标志寄存器EFLAGS 和出错码使用的空间。
- 由于一个过程可调用其它过程,因此每个栈必须有足够大的空间来容纳多帧(多套)上述信息。
- 当通过调用门执行一个过程调用而造成特权级改变时,CPU 就会执行以下步骤切换堆栈并开始在新的特权级上执行被调用过程(见下图所示)
- 使用目的代码段的DPL (即新的CPL)从TSS中选择新栈的指针。从当前TSS中读取新栈的段选择符和栈指针。在读取段选择符,栈指针或栈段描述符过程中,任何违反段界限的错误都将导致产生一个无效TSS异常;
- 检查栈段描述符特权级和类型是否有效,若无效者同样产生一个无效TSS异常。
- 临时保存SS 和ESP 寄存器的当前值,把新栈的 段选择符和栈指针加载到SS 和ESP 中。然后把临时保存的SS 和ESP 内容压入新栈中。
- 把调用门描述符中指定参数个数的参数从调用过程栈复制到新栈中。调用门中参数个数值最大为31,如果个数为0,则表示无参数,不需复制。
- 把返回指令指针(即当前CS 和EIP 内容)压人新栈。把新(目的)代码段选择符加载到CS中,同时把调用门中偏移值(新指令指针)加载到EIP中。最后开始执行被调用过程。
- 从被调用过程返回
- 指令RET 用于执行近返回(near return),同特权级远返回(far return) 和不同特权级的远返回。该指令用于从使用CALL 指令调用的过程中返回。近返回仅在当前代码段中转移程序控制权,因此CPU 仅进行界限检查。对于相同特权级的远返回,CPU 同时从堆栈中弹出返回代码段的选择符和返回指令指针。由于通常情况下这两个指针是CALL 指令压人栈中,因此它们应该是有效的。但是CPU 还是会执行特权级检查以应付当前过程可能修改指针值或 堆栈出现问题时的情况。
- 会发生特权级改变的远返回近允许返回到低特权级程序中,即返回到的代码段DPL 在数值上要大于CPL。CPU 会使用CS 寄存器中选择符的RPL 字段来确定是否要求返回到低特权级。如果RPL 的数值要比CPL 大,就会执行特权级之间的返回操作。当执行远返回到一个调用过程时,CPU 会执行以下步骤:
- 检查保存的CS 寄存器中RPL 字段值,以确定在返回时特权级是否需要改变。
- 弹出并使用被调用过程堆栈上的值加载CS 和EIP 寄存器。在此过程中 会对代码段描述符和代码段选择符的RPL 进行特权级与类型检查。
- 如果RET 指令包含一个参数个数操作数并且返回操作会改变特权级,那么就在弹出栈中CS 和EIP 值之后把参数个数值加到ESP 寄存器值中,以跳过(丢弃)被调用者栈上的参数。此时ESP 寄存器指向原来保存的调用者堆栈的指针 SS 和ESP。
- 把保存的SS 和ESP 值加载到SS 和ESP 寄存器中,从而切换回调用者的堆栈。而此时被调用者堆栈的SS 和ESP值被抛弃。
- 如果RET 指令包含一个参数个数操作数,则把参数个数值加到ESP 寄存器值中,以跳过(丢弃)调用者栈上的参数
- 检查段寄存器DS,ES,FS和GS 的内容。如果其中有指向DPL 小于新CPL 的段(一致代码段除外),那么CPU 就会用NULL 选择符加载这个段寄存器。
- 页级保护
- 页目录和页表表项中的读写标志R/W 和用户/超级用户标志 U/S提供了分段机制保护属性的一个子集。分页机制只识别两级权限。特权级R0 ,R1,R2 被归类为超级用户级。而特权级R3 被作为普通用户级。普通用户级的页面可以被标志成只读/可执行或刻度/可写/可执行。超级用户级的页面对于超级用户来讲总是可读/可写/可执行的,但普通用户不可访问,见下表所示。对于分段机制,在最外层用户级执行的程序只能访问用户级的页面,但是在任何超级用户层(R0,R1,R2)执行的程序不仅可以访问用户层的页面,页可以访问超级用户层的页面。与分段机制不同的是,在内层超级用户级执行的程序对任何页面都具有可读/可写/可执行权限,包括那些在用户级标注为只读/可执行的页面。
- 正如在整个80x86 地址转换机制中分页机制是在分段机制之后实施一样,页级保护也是在分段机制提供的保护措施之后发挥作用。首先,所有段级保护被检查和测试。如果通过检查,就会再进行页级保护检查。例如,仅当一个字节位于R3 执行的程序可访问的段中,并且处于标志位用户级页面中时,这个内存中的字节才能被R3 级别上的程序访问。 仅当分段和分页都允许写时,才能对页面执行写操作。如果一个段是读/写类型的段,但是地址对应的相应页面被标注为只读/可执行,那么还是不能对页面执行写操作。如果段的类型是只读/可执行,那么不管对应页面被赋予任何保护属性,页面始终是没有写权限的。可见分段和分页的保护机制就像电子线路中的串行线路,其中那个开关没有合上线路都不会通。
- 类似地,一个页面的保护属性由页目录和页表中表项的“串行”或“与操作”构成,见下表所示。页表表项中的U/S标志和R/W标志应用于该表项映射的单个页面。页目录项中的U/S和R/W标志则对该目录项所映射的所有页面起作用。页目录和页表的组合保护属性由两者属性的“与”(AND) 操作构成,因此保护措施非常严格。
- 修改页表项的软件问题
- 分页转换缓冲要求所有系统都需遵守以下规则,为了避免每次内存应用都要访问驻留内存的页表,从而加快速度,最近使用的线性到物理地址的转换信息被保存在处理器内的页转换告诉缓冲中。处理器在访问内存中的页表之前会首先利用缓冲中的信息。只有当必要的转换信息不再高速缓冲中时,处理器才会搜寻内存中的页目录和页表。页转换高速缓冲作用类似于前面描述的加速段转换的段寄存器的影子描述符寄存器。页转换高速缓冲的另一个属于称为转换查找缓冲TLB(Translation Lookaside Buffer)。
- 80x86 处理器并没有维护页转换高速缓冲和页表中数据的相关性,但是需要操作系统软件来确保它们一致。即处理器并不知道什么时候页表被软件修改过了。因此操作系统必须在改动过页表之后刷新高速缓冲以确保两者一致。通过简单地重新加载寄存器CR3,我们就可以完成对高速缓冲的刷新操作。
- 有一种特殊情况,在这种情况下修改页表项不需要刷新页转换高速缓冲。页即当不存在页面的表项被修改时,即使把P 标志从 0 改成 1 来标注表项对页转换有效,也不需要刷新高速缓冲。因为无效的表项不糊被存入高速缓冲中。所以在把一个页面从磁盘调入内存以使页面存在时,我们不需要刷新页转换高速缓冲.
- 组合页级和段级保护
- 当启用了分页机制,CPU 会首先执行段级保护,然后再处理页级保护。如果CPU 在任何一级检测到一个保护违规错误,则会放弃内存访问并产生一个异常。如果是段机制产生的异常,那么就不会再产生一个页异常。
- 页级保护不能替代或忽略段级保护。例如,若一个代码段被设定为不可写,那么代码段被分页后,即使页面的R/W标志被设置成可读可写也不会让页面可写。 此时段级保护检查会阻止任何对页面的写操作企图。 页级别保护可被用来增强段级别保护。 例如,如果一个可读可写数据段被分页,那么页级保护机制可用来对个别页面进行写保护。
0 0
- 保护机制(个人理解)
- 分段机制(个人理解)
- 分页机制(个人理解)
- android事件机制个人理解
- JVM加载机制--个人理解
- Qt 销毁机制个人理解~
- Django 的 CSRF 保护机制理解
- android Handler机制(个人理解)
- 消息列队机制(个人理解)
- Linux内核-中断机制个人理解
- 个人对于JAVA反射机制的理解
- java的反射机制(个人理解)
- 保护机制
- 保护个人文档隐私
- Java反射机制的个人理解与总结
- 个人对Android Touch事件机制的理解
- 安卓事件传递机制个人理解版
- 对于JAVA反射机制和CLASS类的个人理解
- FckEditor在Extjs中的使用
- C#文件操作大全
- 互联网经济与实体经济
- 针对Hadoop YARN 的REST API web服务介绍
- ScrollView起始位置不是最顶部的解决办法
- 保护机制(个人理解)
- js格式化字符串
- git强制回滚+IDEA+GIT BASH
- Redis百亿级Key存储方案
- 被知识库收录
- 辅lua
- Android热补丁动态修复技术(一):从Dex分包原理到热补丁
- hdf5和las文件的读写
- IOS中的GCD的简要认识