摘要:任务是处理器可以分配、调度、执行和挂起的一个工作单元。用于可执行程序、任务或者进程、操作系统服务、中断或者异常处理过程和内核代码。通过中断、异常、跳转或者调用我们可以执行一个任务。任务描述符表中与任务相关的描述符有任务状态描述符和任务门,当执行权转移到上述任何一种描述符的时候,将会造成任务切换。
任务切换很像过程调用,但是会保存更多的处理器信息。任务切换几乎要保存所有的处理器寄存器信息,同时任务切换是不可重入的,这和过程调用是不同的。任务切换不会把任何信息压入堆栈中,而是把它们保存在TSS中。
任务有两部分,任务执行空间和TSS。任务执行空间包括代码段、数据段和堆栈段。TSS执行了执行空间中的各个段,并且为任务状态信息提供存储空间。任务的结构和状态如下图:
一个任务的使用由执行TSS段的选择符来指定,当一个任务被加载进处理器执行时,那么该任务的段选择符、基地址、段限长和TSS描述符都会被加载到任务寄存器TR之中;如果使用了分页机制,那么页目录基地址会被加载到CR3寄存器。当前任务状态由处理器的以下内容构成:
@@@所有通用寄存器和段寄存器信息
@@@标志寄存器、程序指针EIP、控制寄存器CR3、任务寄存器TR、LDTR寄存器
@@@段寄存器指定的任务当前执行空间
@@@IO映射位图基地址和IO位图信息
@@@特权级0~2的堆栈指针
@@@链接到前一个任务的链指针
以下方式用于执行一个任务:
1)使用call指令明确调用一个任务
2)使用JMP指令明确跳转到一个任务(linux内核使用的方式)
3)(处理器)隐含地调用一个中断句柄处理服务
4)隐含地调用一个异常句柄处理服务
所有上面的方式,都会使用一个指向任务门或者任务TSS段的选择符来确定一个任务。如果A调用了B,那么A的TSS选择符会被保存在B的TSS中。作为任务切换的一部分,处理器会切换到另一个LDT,从而运行每个任务对基于LDT的段具有不同逻辑到物理地址的转换。
处理器定义了以下支持多任务的寄存器和数据结构:任务状态段TSS(注意TSS是一个段)、TSS描述符、任务寄存器TR、任务们描述符、标志寄存器中的NT标志。它们用于完成任务的切换和任务上下文的保存。
TSS中的各个字段分为两类:
1)动态字段:
通用寄存器(EAX~EDX、EBP、ESP、ESI、EDI)/段选择符字段(CS~GS中的内容)/标志寄存器字段/指令指针字段EIP/先前任务链(前一个任务的TSS段选择符)
2)静态字段:
处理器会读取这些字段的内容,但是不会改变他们。这些字段的内容是在任务创建的时候被初始化的。
LDT段选择符
CR3控制寄存器字段
特权级0~2的堆栈指针字段(堆栈选择符SS0~SS2)
调试陷阱T标志字段
其他相应字段和一般段描述符相同
使用调用或者跳转指令,任何可以访问TSS描述符的程序都能够造成任务切换,但是可以访问TSS描述符并不代表用户具有修改描述符的能力。如果想要修改它,可以通过映射到内存相同能位置的数据段描述符来实现——别名操作符。将TSS描述符加载进入任何一个段描述符都将产生一个异常。企图使用TI标志置位的描述符(当前LDT中的选择符)来访问TSS段也将导致异常。
处理器用以下的四种方式来完成任务切换:
1)当前任务对GDT中的TSS描述符执行JMP和CALL指令
2)当前任务对GDT或者LDT中的任务门描述符执行JMP和CALL指令
3)中断或者异常响亮指向IDT表中的任务门描述符
4)当EFLAGS中的NT置位的时候,当前位置执行IRET指令
JMP、CALL、IRET以及中断和异常都是处理器的普通机制,可用于不发生任务切换的环境。对于TSS描述符或者任务门的引用,或者NT标志的状态,确定是否会发生任务切换。IDT中有任务门、陷阱门和中断门,前者才会发生任务切换。
关于中断返回:中断服务过程总是把执行权返回到被中断的过程中,被中断的过程可能在另一个任务中。如果NT标志是复位状态(0),执行一般返回处理;如果NT标志是置位状态返回操作会产生任务切换,切换到的新任务,由中断服务过程TSS中的TSS选择符决定。
任务切换的步骤:
1)从JMP、CALL指令的当前操作数,任务门,当前TSS的前一个任务链字段(IRET引起的任务切换)取得新任务的TSS段选择符
2)检查当前任务是否允许切换到新的任务:jmp和call——CPL、RPL、DPL按照普通数据段访问规则;任务门——无论面目标门或者TSS段描述符的DPL是什么,异常和中断(除了INT n指令产生的中断)和IRET指令都允许任务切换。INT n引起的切换,需要检查DPL。
3)检查新任务的TSS描述符是否标志为存在,并且TSS段长度有效(大于0x67)
4)老任务忙位B:如果任务切换来自JMP和IRET,处理器会把老任务的忙位复位(B=0),表示这个任务已经执行完毕;其他情况,B保持不变。
5)NT标志:如果任务切换来自IRET,NT=0;否则,不改动NT
6)当前任务状态保存到TSS中
7)新任务的NT标志:任务切换来自IRET和JMP,NT不变;其他,NT置位
8)新任务的忙标志B:任务切换来自IRET,B保持不变;其他,B置位
9)用新任务的段选择符和描述符加载到TR,设置CR0的TS标志。
10)将新任务的状态,加载进入处理器
11)开始执行新任务。
执行任务切换时候,新老任务特权级没有任何联系。
TSS的前一任务字段以及EFLAGS中的NT标志用于返回到前一个任务,NT标志指出了当前执行的任务是否嵌套在另外一个任务中执行。
call、中断和陷进都是引发的嵌套任务,表示老的任务还没有结束;jmp引发的是非嵌套任务,意味着老的任务已经结束;IRET用于挂起一个任务,返回到前一个任务。
任务切换引起相关标志变换如下表:(注意,这些命令改变了哪些位)
对比:
新任务的B,基本上都是设置
老任务的B:只有jmp,是清除,表明jmp过后,老任务结束了。
新任务NT:只有call引发的,一定是嵌套
老任务NT:只有IRET是清除,因为这个任务被挂起了,并没有在运行
另外,我们使用忙标志B来防止递归的任务切换:
1)调度一个任务,将新任务置位
2)如果调度任务,当前任务处于嵌套链中,那么它仍然保持置位
3)切换新任务的时候,如果新任务的B置位,那么将产生异常(说明产生了递归);如果任务切换是IRET引起的,那么不会在新任务B=1的时候产生异常——因为IRET是非嵌套的,所以不存在递归任务。
2)每个任务都有自己的线性地址空间
对于映射任务线性地址空间的两种方法,所有任务的TSS段都必须存放在可共享的物理地址空间区域中。
1)通过GDT段描述符
2)工过共享的LDT
3)通过映射到线性地址空间公共区域的不同LDT的段描述符——别名段。
任务切换很像过程调用,但是会保存更多的处理器信息。任务切换几乎要保存所有的处理器寄存器信息,同时任务切换是不可重入的,这和过程调用是不同的。任务切换不会把任何信息压入堆栈中,而是把它们保存在TSS中。
1.任务的结构和状态
任务有两部分,任务执行空间和TSS。任务执行空间包括代码段、数据段和堆栈段。TSS执行了执行空间中的各个段,并且为任务状态信息提供存储空间。任务的结构和状态如下图:
一个任务的使用由执行TSS段的选择符来指定,当一个任务被加载进处理器执行时,那么该任务的段选择符、基地址、段限长和TSS描述符都会被加载到任务寄存器TR之中;如果使用了分页机制,那么页目录基地址会被加载到CR3寄存器。当前任务状态由处理器的以下内容构成:
@@@所有通用寄存器和段寄存器信息
@@@标志寄存器、程序指针EIP、控制寄存器CR3、任务寄存器TR、LDTR寄存器
@@@段寄存器指定的任务当前执行空间
@@@IO映射位图基地址和IO位图信息
@@@特权级0~2的堆栈指针
@@@链接到前一个任务的链指针
2.任务的执行
以下方式用于执行一个任务:
1)使用call指令明确调用一个任务
2)使用JMP指令明确跳转到一个任务(linux内核使用的方式)
3)(处理器)隐含地调用一个中断句柄处理服务
4)隐含地调用一个异常句柄处理服务
所有上面的方式,都会使用一个指向任务门或者任务TSS段的选择符来确定一个任务。如果A调用了B,那么A的TSS选择符会被保存在B的TSS中。作为任务切换的一部分,处理器会切换到另一个LDT,从而运行每个任务对基于LDT的段具有不同逻辑到物理地址的转换。
3.任务管理数据结构
处理器定义了以下支持多任务的寄存器和数据结构:任务状态段TSS(注意TSS是一个段)、TSS描述符、任务寄存器TR、任务们描述符、标志寄存器中的NT标志。它们用于完成任务的切换和任务上下文的保存。
3.1.任务状态段
TSS中的各个字段分为两类:
1)动态字段:
通用寄存器(EAX~EDX、EBP、ESP、ESI、EDI)/段选择符字段(CS~GS中的内容)/标志寄存器字段/指令指针字段EIP/先前任务链(前一个任务的TSS段选择符)
2)静态字段:
处理器会读取这些字段的内容,但是不会改变他们。这些字段的内容是在任务创建的时候被初始化的。
LDT段选择符
CR3控制寄存器字段
特权级0~2的堆栈指针字段(堆栈选择符SS0~SS2)
调试陷阱T标志字段
IO位图基地址
3.2TSS描述符
它只能放在GDT中,结构如下:
其他相应字段和一般段描述符相同
使用调用或者跳转指令,任何可以访问TSS描述符的程序都能够造成任务切换,但是可以访问TSS描述符并不代表用户具有修改描述符的能力。如果想要修改它,可以通过映射到内存相同能位置的数据段描述符来实现——别名操作符。将TSS描述符加载进入任何一个段描述符都将产生一个异常。企图使用TI标志置位的描述符(当前LDT中的选择符)来访问TSS段也将导致异常。
3.3任务寄存器
3.4任务门描述符
任务门描述符提供一个对任务间接、受保护的引用,格式如图:
可以存放在GDT、LDT、IDT表中。任务门描述符中的TSS选择字段指向GDT中的一个TSS段描述符。这个TSS选择符的RPL不用,任务门描述符中的DP刘永余在任务切换的时候控制对TSS段的访问。注意,使用任务门的时候,目标TSS段描述符的DPL忽略不用,因为我们用的是任务门描述符的相关字段。程序可以通过任务门描述符或者TSS段描述符来访问一个任务。
4.任务切换
处理器用以下的四种方式来完成任务切换:
1)当前任务对GDT中的TSS描述符执行JMP和CALL指令
2)当前任务对GDT或者LDT中的任务门描述符执行JMP和CALL指令
3)中断或者异常响亮指向IDT表中的任务门描述符
4)当EFLAGS中的NT置位的时候,当前位置执行IRET指令
JMP、CALL、IRET以及中断和异常都是处理器的普通机制,可用于不发生任务切换的环境。对于TSS描述符或者任务门的引用,或者NT标志的状态,确定是否会发生任务切换。IDT中有任务门、陷阱门和中断门,前者才会发生任务切换。
关于中断返回:中断服务过程总是把执行权返回到被中断的过程中,被中断的过程可能在另一个任务中。如果NT标志是复位状态(0),执行一般返回处理;如果NT标志是置位状态返回操作会产生任务切换,切换到的新任务,由中断服务过程TSS中的TSS选择符决定。
任务切换的步骤:
1)从JMP、CALL指令的当前操作数,任务门,当前TSS的前一个任务链字段(IRET引起的任务切换)取得新任务的TSS段选择符
2)检查当前任务是否允许切换到新的任务:jmp和call——CPL、RPL、DPL按照普通数据段访问规则;任务门——无论面目标门或者TSS段描述符的DPL是什么,异常和中断(除了INT n指令产生的中断)和IRET指令都允许任务切换。INT n引起的切换,需要检查DPL。
3)检查新任务的TSS描述符是否标志为存在,并且TSS段长度有效(大于0x67)
4)老任务忙位B:如果任务切换来自JMP和IRET,处理器会把老任务的忙位复位(B=0),表示这个任务已经执行完毕;其他情况,B保持不变。
5)NT标志:如果任务切换来自IRET,NT=0;否则,不改动NT
6)当前任务状态保存到TSS中
7)新任务的NT标志:任务切换来自IRET和JMP,NT不变;其他,NT置位
8)新任务的忙标志B:任务切换来自IRET,B保持不变;其他,B置位
9)用新任务的段选择符和描述符加载到TR,设置CR0的TS标志。
10)将新任务的状态,加载进入处理器
11)开始执行新任务。
执行任务切换时候,新老任务特权级没有任何联系。
5.任务链
TSS的前一任务字段以及EFLAGS中的NT标志用于返回到前一个任务,NT标志指出了当前执行的任务是否嵌套在另外一个任务中执行。
call、中断和陷进都是引发的嵌套任务,表示老的任务还没有结束;jmp引发的是非嵌套任务,意味着老的任务已经结束;IRET用于挂起一个任务,返回到前一个任务。
任务切换引起相关标志变换如下表:(注意,这些命令改变了哪些位)
标志或字段 | JMP指令的影响 | CALL指令或中断的影响 | IRET指令的影响 |
新任务忙标志B | 设置标志。以前须已被清除 | 设置标志。以前须已被清除 | 不变。必须已被设置 |
老任务忙标志B | 被清除 | 不变。当前处于设置状态 | 设置标志 |
新任务NT标志 | 设置成新任务TSS中的值 | 设置标志 | 设置成新任务TSS中的值 |
老任务NT标志 | 不变 | 不变 | 清除标志 |
新任务链接字段 | 不变 | 存放老任务TSS段选择符 | 不变 |
老任务链接字段 | 不变 | 不变 | 不变 |
CR0中TS标志 | 设置标志 | 设置标志 | 设置标志 |
对比:
新任务的B,基本上都是设置
老任务的B:只有jmp,是清除,表明jmp过后,老任务结束了。
新任务NT:只有call引发的,一定是嵌套
老任务NT:只有IRET是清除,因为这个任务被挂起了,并没有在运行
另外,我们使用忙标志B来防止递归的任务切换:
1)调度一个任务,将新任务置位
2)如果调度任务,当前任务处于嵌套链中,那么它仍然保持置位
3)切换新任务的时候,如果新任务的B置位,那么将产生异常(说明产生了递归);如果任务切换是IRET引起的,那么不会在新任务B=1的时候产生异常——因为IRET是非嵌套的,所以不存在递归任务。
6.任务地址空间
6.1将任务映射到线性和物理地址空间
2)每个任务都有自己的线性地址空间
对于映射任务线性地址空间的两种方法,所有任务的TSS段都必须存放在可共享的物理地址空间区域中。
6.2映射逻辑地址空间
1)通过GDT段描述符
2)工过共享的LDT
3)通过映射到线性地址空间公共区域的不同LDT的段描述符——别名段。