80X86系统寄存器和系统指令
为了协助处理器执行初始化和控制系统操作,80X86提供了一个标志寄存器EFLAGS和几个系统寄存器,除了一些通用状态标志外,EFLAGS中还包含几个系统标志。这些系统标志用于控制任务切换、中断处理、指令跟踪以及访问权限。
系统寄存器用于内存管理和控制处理器操作,含有分段和分页处理机制系统表的基地址、控制处理器操作的比特标志位。
标志寄存器
内存管理寄存器
处理器提供了4个内存管理寄存器(GDTR、LDTR、DTR和TR),用于指定分段内存管理所使用的系统表的基地址,见图4-2所示。处理器为这些寄存器的加载和保存提供了特定的指令。
- 全局描述符表寄存器GDTR
- 中断描述符表寄存器IDTR
- 局部描述符表寄存器LDTR
当进行任务切换时,处理器会把新任务LDT的段选择符和段描述符自动地加载进LDTR中. - 任务寄存器TR
当执行任务切换时,处理器会把新任务TSS的段选择符和段描述符自动地加载进任务寄存器TR中。
控制寄存器
保护模式内存管理
内存寻址
80X86为段部分提供了6个存放段选择符的段寄存器:CS、DS、ES、SS、FS和GS。
其中CS总是用于寻址代码段,而堆栈段则专门使用SS段寄存器。在任何指定时刻由CS寻址的段称为当前代码段。此时EP寄存器中包含了当前代码段内下一条要执行指令的段内偏移地址。因此要执行指令的地址可表示成CS:[EP]。
由段寄存器SS寻址的段称为当前堆栈段。栈顶由ESP寄存器内容指定。因此堆栈顶处地址是SS:[ESP]。另外4个段寄存器是通用段寄存器。当指令中没有指定所操作数据的段时,那么DS将是默认的数据段寄存器。
指令的偏移量由三部分相加组成:基地址寄存器、变址寄存器和一个偏移常量。即:
偏移地址=基地址+(变址ⅹ比例因子)+偏移量
地址变换
KEY: 保护 和 地址变换
80X86在从逻辑地址到物理地址变换过程中使用了分段和分页两种机制,见图4-4所示。
第一阶段使用分段机制把程序的逻辑地址变换成处理器可寻址内存空间(称为线性地址空间)中的地址。
第二阶段使用分页机制把线性地址转换为物理地址。在地址变换过程中,第一阶段的分段变换机制总是使用的,而第二阶段的分页机制则是供选用的。如果没有启用分页机制,那么分段机制产生的线性地址空间就直接映射到处理器的物理地址空间上。物理地址空间定义为处理器在其地址总线上能够产生的地址范围。
分段机制
一个系统中所有使用的段都包含在处理器线性地址空间中。为了定位指定段中的一个字节,程序必须提供一个逻辑地址。逻辑地址包括一个段选择符和一个偏移量。段选择符是一个段的唯一标识。另外,==段选择符提供了段描述符表(例如全局描述符表GDT)中一个数据结构(称为段描述符)的偏移量。==每个段都有一个段描述符。段描述符指明段的大小、访问权限和段的特权级、段类型以及段的第1个字节在线性地址空间中的位置(称为段的基地址)。逻辑地址的偏移量部分加到段的基地址上就可以定位段中某个字节的位置。因此基地址加上偏移量就形成了处理器线性地址空间中的地址。
分页机制
80X86分页机制最适合支持虚拟存储技术。分页机制会使用大小固定的内存块,而分段管理则使用了大小可变的块来管理内存。无论在物理内存中还是在硬盘上,分页使用固定大小的块更为适合管理物理内存。另一方面,分段机制使用大小可变的块更适合处理复杂系统的逻辑分区。可以定义与逻辑块大小适合的内存单元而无需受到固定大小页面的限制。每个段都可以作为一个单元来处理,从而简化了段的保护和共享操作。
分段和分页是两种不同的地址变换机制,它们都对整个地址变换操作提供独立的处理阶段。尽管两种机制都使用存储在内存中的变换表,但所用的表结构不同。实际上,段表存储在线性地址空间,而页表则保存在物理地址空间。因而段变换表可由分页机制重新定位而无需段机制的信息或合作。段变换机制把虚拟地址(逻辑地址)变换成线性地址,并且在线性地址空间中访问自己的表,但是并不知晓分页机制把这些线性地址转换到物理地址的过程。类似地,分页机制也不知道程序产生地址的虚拟地址空间。分页机制只是简单地把线性地址转换成物理地址,并且在物理内存中访问自己的转换表。
保护
任务之间的保护
通过在所有任务中安排具有相同的虚拟到物理地址映射部分,并且把操作系统存储在这个公共的虚拟地址空间部分,操作系统可以被所有任务共享。这个所有任务都具有的相同虚拟地址空间部分被称为全局地址空间(Global address space)。这也正是现代Linux操作系统使用虚拟地址空间的方式。
特权级保护
==每当程序企图访问一个段时,当前特权级就会与段的特权级进行比较,以确定是否有访问许可。==在给定CPL级别上执行的程序允许访问同级别或低级别的数据段。任何对高级别段的引用都是非法的,并且会引发一个异常来通知操作系统。
分段机制
==多段模型能够利用分段机制全部功能提供由硬件增强的代码、数据结构、程序和任务的保护措施。==通常,每个程序(或任务)都使用自己的段描述符表以及自己的段。对程序来说段能够完全是私有的,或者是程序之间共享的。对所有段以及系统上运行程序各自执行环境的访问都由硬件控制。
访问检查不仅能够用来保护对段界限以外地址的引用,而且也能用来在某些段中防止执行不允许的操作。例如,因为代码段被设计成是只读形式的段,因此可以用硬件来防止对代码段执行写操作。段中的访问权限信息也可以用来设置保护环或级别。保护级别可用于保护操作系统程序不受应用程序非法访问。
==1.段基地址(Base address),==指定段在线性地址空间中的开始地址。基地址是线性地址,对应于段中偏移0处。
==2.段限长(1imit),==是虚拟地址空间中段内最大可用偏移位置。它定义了段的长度。
==3.段属性(Attributes),==指定段的特性。例如该段是否可读、可写或可作为一个程序执行;段的特权级等。
段描述符表
整个虚拟地址空间共含有24个段:一半空间(即23个段)是由GDT映射的全局虚拟地址空间,另一半是由LDT映射的局部虚拟地址空间。通过指定一个描述符表(GDT或LDT)以及表中描述符号,我们就可以定位一个描述符。
当发生任务切换时,LDT会更换成新任务的LDT,但是GDT并不会改变。因此,GDT所映射的一半虚拟地址空间是系统中所有任务共有的,但是LDT所映射的另一半则在任务切换时被改变。系统中所有任务共享的段由GDT来映射。这样的段通常包括含有操作系统的段以及所有任务各自的包含LDT的特殊段。LDT段可以想象成属于操作系统的数据。
每个系统必须定义一个GDT,并可用于系统中所有程序或任务。另外,可选定义一个或多个LDT。
GDT本身并不是一个段,而是线性地址空间中的一个数据结构。GDT的基线性地址和长度值必须加载进GDTR寄存器中。GDT的基地址应该进行内存8字节对齐,以得到最佳处理器性能。
LDT表存放在LDT类型的系统段中。此时GDT必须含有LDT的段描述符。如果系统支持多LDT的话,那么每个LDT都必须在GDT中有一个段描述符和段选择符。一个LDT的段描述符可以存放在GDT表的任何地方。
访问LDT需使用其段选择符。为了在访问LDT时减少地址转换次数,LDT的段选择符、基地址、段限长以及访问权限需要存放在LDTR寄存器中。
段描述符
系统描述符类型
分页机制
分页机制是80X86内存管理机制的第二部分。
它在分段机制的基础上完成虚拟(逻辑)地址到物理地址转换的过程。分段机制把逻辑地址转换成线性地址,而分页则把线性地址转换成物理地址。分页可以用于任何一种分段模型。处理器分页机制会把线性地址空间(段已映射到其中)划分成页面,然后这些线性地址空间页面被映射到物理地址空间的页面上。分页机制几种页面级保护措施,可和分段机制保护机制合用或替代分段机制的保护措施。例如,在基于页面的基础上可以加强读/写保护。另外,在页面单元上,分页机制还提供了用户·超级用户两级保护。
为了减少地址转换所要求的总线周期数量,最近访问的页目录和页表会被存放在处理器的缓冲器件中,该缓冲器件被称为转换查找缓冲区TLB(Translation Lookaside Buffer))。
保护
段级保护
- 段界限检查;
- 段类型检查;
- 特权级检查;
- 可寻址范围限制;
- 过程入口点限制;
- 指令集限制。
堆栈切换
每当调用门用于把程序控制转移到一个更高级别的非一致性代码段时,CPU会自动切换到目的代码段特权级的堆栈去。执行栈切换操作的目的是为了防止高特权级程序由于栈空间不足而引起崩溃,同时也为了防止低特权级程序通过共享的堆栈有意或无意地干扰高特权级的程序。
中断 与 异常⭐⭐
中断(Interrupt)和异常(Exception)是指明系统、处理器或当前执行程序(或任务)的某处出现一个事件,该事件需要处理器进行处理。
通常,这种事件会导致执行控制被强迫从当前运行程序转移到被称为==中断处理程序(interrupt handler)或异常处理程序(exception handler)==的特殊软件函数或任务中。
处理器响应中断或异常所采取的行动被称为中断/异常服务(处理)。
对应用程序和操作系统来说,80X86的中断和异常处理机制可以透明地处理发生的中断和异常事件。当收到一个中断或检测到一个异常时,处理器会自动地把当前正在执行的程序或任务挂起,并开始运行中断或异常处理程序。当处理程序执行完毕,处理器就会恢复并继续执行被中断的程序或任务。被中断程序的恢复过程并不会失去程序执行的连贯性,除非从异常中恢复是不可能的或者中断导致当前运行程序被终止。本节描述保护模式中处理器中断和异常的处理机制。
中断 异常向量
为了有助于处理异常和中断,每个需要被处理器进行特殊处理的处理器定义的异常和中断条件都被赋予了一个标识号,称为向量(vector)。处理器把赋予异常或中断的向量用作中断描述符表IDT(InterruptDescriptor Table)中的一个索引号,来定位一个异常或中断的处理程序入口点位置。
中断源与异常源
中断源:
- 外部产生
- 软件产生
外部中断通过处理器芯片上两个引脚(NTR和NMI)接收。当引脚NTR接收到外部发生的中断信号时,处理器就会从系统总线上读取外部中段控制器(例如8259A)提供的中断向量号。
当引脚NMI接收到信号时,就产生一个非屏蔽中断。它使用固定的中断向量号2。任何通过处理器NTR引脚接收的外部中断都被称为可屏蔽硬件中断,包括中断向量号0到255。
标志寄存器EFLAGS中的IF标志可用来屏蔽所有这些硬件中断。通过在指令操作数中提供中断向量号,NT指令可用于从软件中产生中断。
异常源
- 处理器检测到的程序错误异常
- 软件产生的异常
异常分为: 故障、陷阱、中止
-
Faut是一种通常可以被纠正的异常,并且一旦被纠正程序就可以继续运行。当出现一个Fault,处理器会把机器状态恢复到产生Fult的指令之前的状态。此时异常处理程序的返回地址会指向产生Fault的指令,而不是其后面一条指令。因此在返回后产生Fault的指令将被重新执行。
-
Trap是一个引起陷阱的指令被执行后立刻会报告的异常。Trap也能够让程序或任务连贯地执行。Trap处理程序的返回地址指向引起陷阱指令的随后一条指令,因此在返回后会执行下一条指令。
-
Abort是一种不会总是报告导致异常的指令的精确位置的异常,并且不允许导致异常的程序重新继续执行。Abort用于报告严重错误,例如硬件错误以及系统表中存在不一致性或非法值。
为了让程序或任务在一个异常或中断处理完之后能重新恢复执行,除了中止(Abot)之外的所有异常都能报告精确的指令位置,并且所有中断保证是在指令边界上发生。
中断描述符
异常与中断处理
处理器对异常和中断处理过程的调用操作方法与使用CALL指令调用程序过程和任务的方法类似。当响应一个异常或中断时,处理器使用异常或中断的向量作为DT表中的索引。如果索引值指向中断门或陷阱门,则处理器使用与CALL指令操作调用门类似的方法调用异常或中断处理过程。如果索引值指向任务门,则处理器使用与CALL指令操作任务门类似的方法进行任务切换,执行异常或中断的处理任务。
中断处理任务
任务管理⭐⭐
任务结构与状态
一个任务由两部分构成:==任务执行空间和任务状态段TSS(Task-state segment)。==任务执行空间包括代码段、堆栈段和一个或多个数据段,见图4-33所示。如果操作系统使用了处理器的特权级保护机制,那么任务执行空间就需要为每个特权级提供一个独立的堆栈空间。TSS指定了构成任务执行空间的各个段,并且为任务状态信息提供存储空间。在多任务环境中,TSS也为任务之间的链接提供了处理方法。
任务的执行
所有这些调度任务执行的方法都会使用一个指向任务门或任务T$S段的选择符来确定一个任务
任务管理数据结构
任务状态段TSS
TSS描述符
任务门描述符
任务切换
模式切换
切换到保护模式
切换回实地址模式