标签:
本文为<x86汇编语言:从实模式到保护模式> 第15章笔记
由两种基本的任务切换方式, 一种是协同式额, 从一个任务切换到另一个任务, 需要当前任务主动地请求暂时放弃执行权, 或者在通过调用门请求操作系统服务时, 由操作系统"趁机"将控制转移到另一个任务. 这种方式依赖于每个任务的"自律"性, 当一个任务失控时, 其他任务可能得不到执行的机会. 另一种是抢占式的, 在这种方式下, 可以安装一个定时器中断, 并在中断服务程序中实施任务切换. 硬件中断信号总会定时出现, 不管处理器当时在做什么, 中断都会适时地发生, 而任务切换也就能够顺利进行. 在这种情况下, 每个任务都能获得平等的执行机会. 而且, 即使一个任务失控, 也不会导致其他任务没有机会执行.
如上图所示( - -画的比较挫), 所有任务共享一个全局空间, 这是内核或者操作系统的, 包括了系统服务程序和数据; 同时, 每个任务还有自己的局部空间, 每个人物的功能都不一样, 所以, 局部空间包含的是一个任务区别于其他任务的私有代码和数据.
任务切换是以任务为单位的, 是指离开一个任务, 转到另一个任务中去执行. 要执行任务切换, 系统中必须至少有两个任务, 而且已经有一个正在执行中.
第一种任务切换的方法是借助中断, 这也是现代抢占式多任务的基础. 原因很简单, 只要中断没有被屏蔽, 它就能随时发生. 特别是定时器中断, 能够以准确的时间间隔发生, 可以用来强制实施任务切换. 毕竟, 没有哪个人物愿意交出处理器控制权, 也没有哪个任务能精确地把握交出控制权的时机.
在实模式下, 内存最低地址端1KB是中断向量表, 保存着256个中断处理程序的段地址和偏移地址. 当中断发生时, 处理器把中断号乘以4, 作为表内索引号访问中断向量表, 从相应的位置取出中断处理过程的段地址和偏移地址, 并转移到那里执行. 在保护模式下, 中断向量表不再使用, 取而代之的是中断描述符表. 它和GDT, LDT是一样的, 用于保存描述符. 唯一不同的地方是, 它保存的是门描述符, 包括中断门, 陷阱门和任务门. 当中断发生时, 处理器用中断号乘以8(因为每个描述符8字节), 作为索引访问中断描述符表, 取出门描述符. 门描述符中有中断处理过程的代码段选择子和段内偏移量, 这和调用门是一样的. 接着, 转移到相应的位置去执行.
一般的中断处理可以使用中断门和陷阱门. 回忆一下调用门的工作原理, 它只是从任务的局部空间转移到更高特权级的全局空间去执行, 本质上是一种任务内的控制转移行为. 与此相同, 中断门和陷阱门允许在任务内实施中断处理, 转到全局空间去执行一些系统级的管理工作, 本质上, 也是任务内的控制转移行为.
但是, 当中断发生时, 如果该中断号对应的门是任务门, 那么, 性质就截然不同了, 必须进行任务切换, 即, 要中断当前任务的执行, 保护当前任务的现场, 并转换到另一个任务去执行.
如上图所示, 这是任务门描述符的格式. 相对与其他描述符, 任务门描述符中的多数区域没有使用.
任务门描述符中的主要成分是任务的TSS选择子. 任务门用于在中断发生时执行任务切换, 而执行任务切换时必须找到新任务的任务状态段(TSS). 所以, 任务门应当指向任务的TSS. 为了指向任务的TSS, 只需要在任务门描述符中给出任务的TSS选择子就可以了.
任务门描述符的P位指示该门是否有效, 当P位为0时, 不允许通过门实施任务切换; DPL是任务门描述符的特权级, 但是对于因中断而发起的任务切换不起作用, 处理器不按特权级是假任何保护. 但是, 这并不意味着DPL字段没有用处, 当以非中断的方式通过任务门实施任务切换时, 它就有用了.
当中断发生时, 处理器用中断号乘以8作为索引访问中断描述符表. 当它发现这是一个任务门(描述符)时, 就知道应当发起任务切换. 于是, 它取出任务门描述符; 再从任务门描述符中取出新任务的TSS选择子; 接着, 再用TSS选择子访问GDT, 取出新任务的TSS描述符. 在转到新任务执行前, 处理器要先把当前任务的状态保存起来. 当前任务的TSS是由任务寄存器TR的当前内容指向的, 所以, 处理器把每个寄存器的"快照"保存到由TR指向的TSS中. 然后, 处理器访问新任务的TSS, 从中恢复各个寄存器的内容, 包括通用寄存器, 标志寄存器, 段寄存器, 指令指针寄存器EIP, 栈指针寄存器ESP, 以及局部描述符表寄存器LDTR等. 最终, 任务寄存器TR指向新任务的TSS, 而处理器随即开始执行新的任务. 一旦新任务开始执行, 处理器固件会自动将其TSS描述符的B位置1, 表示该任务的状态为忙.
中断发生时, 可以执行常规的中断处理过程, 也可以进行任务切换. 尽管性质不同, 但它们都要使用iret指令返回. 前者是返回到同一任务内的不同代码段; 后者是返回到被中断的那个任务. 处理器根据标志寄存器的NT位(位14)来区分, 意思是嵌套任务标志. 每个任务的TSS中都有一个任务链接域(指向前一个人物的指针), 可以填写为前一个任务的TSS描述符选择子. 如果当前任务EFLAGS寄存器的NT位是1, 则表示当前正在执行的任务嵌套与其他任务内, 并且能够通过TSS任务链接域的指针返回到前一个任务.
因中断而引发任务切换时, 取决于当前任务(旧任务)是否嵌套于其他任务内, 其EFLAGS的NT位可能是0, 也可能是1. 不过这无关紧要, 因为处理器不会改变它, 而是和其他寄存器一道, 写入TSS中保护起来. 另外, 当前任务(旧任务)肯定处于"忙"的状态, 其TSS描述符的B位一定是"1", 在任务切换后同样保持不变.
对新任务的处理是, 要把老任务的TSS选择子填写到新任务TSS中的任务链接域, 同时, 将新任务EFLAGS的NT位置1, 以允许返回到前一个任务(老任务)继续执行, 同时, 还要把新任务TSS描述符的B位置1(忙).
可以使用iret指令从当前任务返回到前一个任务, 前提是EFLAGS的NT位为1. 无论任务处理器碰到iret指令, 它都要检查NT位, 如果为0, 表示是一般的中断过程, 按一般的中断返回处理, 即, 中断返回是任务内的(中断处理过程虽然属于操作系统, 但属于任务的全局空间); 如果此位为1, 则表明当前任务之所以能够正在执行, 是因为中断了别的任务. 因此, 应当返回原先被中断的任务继续执行. 此时, 由处理器固件把当前任务EFLAGS的NT位置0, 并把TSS描述符的B位置0(非忙). 在保存了当前任务的状态之后, 接着, 用新任务(被中断的任务)的TSS恢复现场.
除了中断引发的任务切换外, 还可以用远过程调用指令call, 或者远跳转指令jmp直接发起任务切换. 在这两种情况下, call和jmp指令的操作数是任务的TSS描述符选择子或任务门. 以下是两个例子
call 0x0010:0x00000000 jmp 0x0010:0x00000000
当处理器执行这两条指令时, 首先用指令中给出的描述符选择子访问GDT, 分析他的描述符类型, 如果是一般的代码段描述符, 就按普通的段间转移规则执行; 如果是调用门, 按调用门的规则执行; 如果是TSS描述符, 或者任务门, 则执行任务切换. 此时指令中给出的32位偏移被忽略, 原因是执行任务切换时, 所有处理器的状态都可以从TSS中获得. 注意, 任务门描述符可以安装在中断描述符表中, 也可以安装在GDT或者LDT中.
如果用于发起任务切换, call指令和jmp指令也有不同之处. 使用call发起的任务切换类似于因中断发起的任务切换. 这就是, 由call发起的任务切换是嵌套的, 当前任务(旧任务)TSS描述符的B位保持原来的1不变, EFLAGS寄存器的NT位也不发生变化; 新任务TSS描述符的B位置1, EFLAGS的NT位也置1, 表示此任务嵌套与其他任务中. 同时, TSS任务链接域的内容改为旧任务的TSS描述符选择子.
如上图所示(- -画的较挫), 假设任务1是整个系统中的第一个任务. 当任务1开始执行时, 其TSS描述符的B位是1, EFLAGS的NT位是0, 不嵌套于其他任务. 当从任务1转换到任务2后, 任务1任然为忙, eflags的nt位不变(在其TSS中); 任务2也变为忙, eflags的nt位为1, 表示嵌套与任务1中, 同时, 任务1的TSS描述符选择子也被复制到任务2的TSS中(任务链接域). 最后是从任务2转换到任务3执行, 和从前一样, 任务2保持忙状态, eflags的nt位不变(在其TSS中); 任务3成为当前任务, 其TSS描述符的B位变成1, eflags寄存器的nt位也变成1, 同时, 其TSS的任务链接域指向任务2.
用call指令发起的任务切换, 可以通过iret返回前一个任务. 此时, 旧任务(当前任务)TSS描述符的B位, 以及eflags的nt位都被恢复到0, 并保存到它的TSS中.
用jmp指令发起的任务切换, 不会形成任务之间的嵌套关系. 执行任务切换时, 当前任务(旧任务)TSS的B位清0, eflags的nt位不变; 新任务TSS描述符的B位置1, 进入忙的状态, eflags的nt位保持从TSS中加载时的状态不变.
任务是不可重入的. 任务不可重入的本质是, 执行任务切换是, 新任务的状态不能为忙. 这里有两个典型的情形:
处理器是通过TSS描述符的B位来检测重入的. 因中断, iret, call和jmp指令发起任务切换时, 处理器固件会检测新任务TSS描述符的B位, 如果为1, 则不允许执行这样的切换.
处理器用一下4种方法将控制转移到其他任务:
在任务切换是, 处理器执行以下操作:
任务切换时, 当前任务的状态总要保存起来, 在恢复执行时, 处理器从eip寄存器的保存值所指向的那条指令开始执行, 这个寄存器的值是在当初任务切换被挂起时保存的.
任务切换时, 新任务的特权级并不是从那个被挂起的任务继承来的. 新任务的特权级别是由其段寄存器CS的低2位决定的.
任务状态段TSS的任务链接域和eflags的nt位用于返回前一个任务执行, 当前eflags寄存器的nt位是1表明当前任务嵌套与其他任务中. 无论如何, 新任务的TSS描述符的B位都会被置位, 旧任务的B位取决于任务切换的方法, 如下图所示
标签:
原文地址:http://www.cnblogs.com/Acg-Check/p/4269481.html