x86保护模式 任务状态段和控制门
每个任务都有一个任务状态段TSS 用于保存任务的有关信息 在任务内权变和任务切换时 需要用到这些信息
任务内权变的转移和任务切换 一般需要通过控制门进行这些转移。
<一> 系统段描述符
系统段是为了实现存储管理机制所使用的一种特别的段
任务状态段TSS和局部描述符表LDT段 用于描述系统段的描述符成为系统段描述符
1.描述符格式
![](https://images2017.cnblogs.com/blog/1282980/201712/1282980-20171210153540755-1147752123.png)
与存储段描述符类似 区别位属性字节中的描述符类型为DT的值
DT=1为存储段 DT=0为系统段
存储段中的D位在系统描述符中不使用 用符号X表示
TYPE字段用4位表示 含义与存储段描述符的类型完全不同
![](https://images2017.cnblogs.com/blog/1282980/201712/1282980-20171210153546146-1447045635.png)
由图中可知 仅仅只有类型编码为2 1 3 9 和B的描述符才是真正的系统段描述符
用于ldt和任务状态段TSS
其他的都是门描述符
注意系统段描述符的选择子不能用来读写系统段 如果想读写需要用到别名技术
2.LDT段描述符
局部描述符表
此描述符必须位于gdt中才有效
3.任务状态段描述符
TSS用于保存任务的各种状态信息 tss规定任务状态段的基地址和任务状态段的大小等信息
例如 TempTask DESC <104,3456H,12H,89H,,>
仅仅是描述符偏移5的字节一致 也由此字节标识门描述符和系统段描述符 该字节内的p和dpl的意义与其他描述符中的意义相同
此为386任务状态段 基地址为123456h 以字节为单位的界限是104 描述符的特权级是0
装载tr寄存器时 描述符中的基址和界限等信息被装入到tr高速缓冲寄存器中
当任务切换时或执行LTR时 要装载TR寄存器
tss两种状态 忙和可用 当一个任务为当前正在执行,或者是用tss中的链接字段挂起任务链接到当前任务上的任务,那么是忙的任务 否则就是可用的任务
利用jmp和call 直接通过tss描述符或通过任务门来实现任务的切换
二 门描述符
此描述符不描述内存段 而是描述控制转移的入口点
就好象一个代码段通往另一个代码段的门 可以实现任务内权级的变换和任务间的切换 也称控制门
1.门描述符的一般格式
![](https://images2017.cnblogs.com/blog/1282980/201712/1282980-20171210153556302-1958373745.png)
根据上图给出的门描述符的结构,可定义如下的门描述符结构类型:
GATE STRUC ;门结构类型定义 OFFSETL DW 0 ;32位偏移的低16位 SELECTOR DW 0 ;选择子 DCOUNT DB 0 ;双字计数字段 GTYPE DB 0 ;类型 OFFSETH DW 0 ;32位偏移的高16位 GATE ENDS
门描述符可以分为 任务门 调用门 中断门和陷阱门 除了任务门 其他描述符还分成286和386两种
2.调用门
描述某个子程序的入口 选择子必须实现代码段描述符
调用门内的偏移是对应代码段内的偏移 利用段间调用指令call 实现任务内从外层到内层特权级的转移
门描述符中4字节双字计数字段 仅仅在调用门中有效 在其他门中无用
意义:主程序通过堆栈把入口参数传递为子程序 如果在利用调用门时 子程序引起权变 则会引起堆栈的变化 那么就需
要将外层堆栈中的参数复制到内层堆栈中 。该双字计数字段用于说明需要复制的双字参数的数量
3.任务门
此门内的选择子必须指示gdt中的任务状态段TSS描述符 门中的偏移没有意义。任务的入口点保存在TSS中。利用段间转移指令JMP和段间调用指令call 通过任务门可以实现任务切换。
4.中断门和陷阱门
此两个门 描述中断和异常的处理程序的入口点
选择子通调用门相同 需要指向代码段描述符 门内的偏移就是对应代码段的入口点的偏移。
此门只有在IDT中才有效
三 任务状态段
保存一个任务的重要信息的段
tss在任务切换过程中起作用 通过它来实现任务的挂起和恢复
任务切换为挂起当前正在执行的任务,恢复或启动另一任务的执行。
步骤:
1.cpu中的各个寄存器被自动保存到TR所指定的TSS中
2.下一个任务TSS的选择子被装入TR
3.从TR所指定的TSS中各个寄存器的值送到cpu中的各个寄存器中
tss格式如下
![](https://images2017.cnblogs.com/blog/1282980/201712/1282980-20171210153601927-1839372630.png)
1.寄存器保存区
20h到5fh处 用于保存通用 段 指令指针 标志寄存器
当tss对应的任务执行时 此时区域未定义 ;当前任务切换出时 这些寄存器的当前值就保存在该区
当切换回此任务时 再从保存区恢复出这些寄存器的值
通用寄存器 指令指针 标志寄存器各杜英一个32位的双字
段寄存器也对应32位的双字 但是选择子只有16位 存于低16位 高16填0
2.内层堆栈指针区
一个任务有可能有4个堆栈 当发生向内层转移时 不可能转移到3级 所以没有3级的堆栈区
只有0 1 2三个级别的堆栈
三个堆栈指针 都是48位的全指针 16位子和32位的偏移 依次存放到4 12 20开始的位置
发生向内层转移时 把适当的堆栈指针装入ss级esp寄存器 变换到内层堆栈 外层堆栈的指针保存到内层堆栈中
注意:当向外层变换时 不把内层堆栈的指针保存到tss的内层堆栈指针区 cpu从不向该区写入
向内层转移时 总是把内层栈认为是空栈 不允许发生同级别内层转移的递归;如果向内层转移 那么返回到外层的正常途径是相匹配的向外层返回。
3.地址映射寄存器区域
虚拟到线性有GDT和LDT决定 与特定任务相关的有LDT确定 LDTR确定LDT
如果分页机制 则线性到物理的映射由包含页目录表起始物理地址的控制寄存器cr3确定 ,所以与特定任务相关的虚拟到物理的地址映射有LDTR和cr3确定
任务的切换 相应的地址映射关系 函数 表一样要切换
位于偏移1ch处的cr3和偏移60h处的LDTR字段组成 任务切换时 需要cpu自动从要执行的任务中取出这两个字段 ,分别装入到寄存器cr3和ldtr 这样就改变了虚拟到物理地址的映射
注意 任务切换时 ,处理器不把换出任务的寄存器cr3和ldtr的内容保存到tss中的地址映射寄存器区 , 如果程序改变了LDTR和CR3 那么必须把新值人为地保存到tss中的相应字段 且通过别名技术
4.链接字段
链接字段在最开始的位置 其中高16位未用 ;当起链接作用时 低16位保存前一个任务的描述符的选择子
如果当前任务由段间调用指令call或中断和异常而激活,那么链接字段保存被挂起任务(任务链上的前一个任务)的TSS的选择子,并且标志寄存器的NT位被置1,使链接字段有效。在返回时,由于NT标志位为1,返回ret或中断返回指令iret 将使得控制沿着链接字段所指的恢复到前一个任务。
5.其他字段
66h处存放i/o许可位图 实现输入输出的保护
64h处为调试陷阱 最低位用T表示 其他位为0 当任务切换时,如果进入任务的T位为1 那么完成之后 新任务的第一条指令执行之前会产生调试陷阱。
6.用结构类型定义TSS
根据上图给出的任务状态段TSS的结构,可定义如下的TSS结构类型:
;---------------------------------------------------------------------------- ;任务状态段结构类型定义 ;---------------------------------------------------------------------------- TSS STRUC TRLink DW 0 ;链接字段 DW 0 ;不使用,置为0 TRESP0 DD 0 ;0级堆栈指针 TRSS0 DW 0 ;0级堆栈段寄存器 DW 0 ;不使用,置为0 TRESP1 DD 0 ;1级堆栈指针 TRSS1 DW 0 ;1级堆栈段寄存器 DW 0 ;不使用,置为0 TRESP2 DD 0 ;2级堆栈指针 TRSS2 DW 0 ;2级堆栈段寄存器 DW 0 ;不使用,置为0 TRCR3 DD 0 ;CR3 TREIP DD 0 ;EIP TREFlag DD 0 ;EFLAGS TREAX DD 0 ;EAX TRECX DD 0 ;ECX TREDX DD 0 ;EDX TREBX DD 0 ;EBX TRESP DD 0 ;ESP TREBP DD 0 ;EBP TRESI DD 0 ;ESI TREDI DD 0 ;EDI TRES DW 0 ;ES DW 0 ;不使用,置为0 TRCS DW 0 ;CS DW 0 ;不使用,置为0 TRSS DW 0 ;SS DW 0 ;不使用,置为0 TRDS DW 0 ;DS DW 0 ;不使用,置为0 TRFS DW 0 ;FS DW 0 ;不使用,置为0 TRGS DW 0 ;GS DW 0 ;不使用,置为0 TRLDTR DW 0 ;LDTR DW 0 ;不使用,置为0 TRTrip DW 0 ;调试陷阱标志(只用位0) TRIOMap DW $+2 ;指向I/O许可位图区的段内偏移 TSS ENDS