1、通过演示如何创建一个任务,并使之投入运行来学习任务的概念及组成要素,包括任务的全局空间和局部空间、TSS、LDT、特权级等。
2、必须了解特权级不是指任务的特权级,而是组成任务的各个部分的特权级。比如:任务的全局部分一般是0、1和2特权级别的,任务的私有部分一般是3特权级别的。
3、必须清楚CPL、DPL和RPL的含义,以及不同特权级别之间的控制转移规则。
4、熟悉调用门的用法。
5、掌握一些在Bochs下调试程序的新手段。
6、学习一些新的x86处理器命令,包括lldt、ltr、pushf/pushfd、popf/popfd、ret n/retf n、arpl等。同时了解像jmp和call这样的传统指令是如何被赋予一些新的功能的。
任务:程序是记录在载体上的指令和数据,其正在执行的一个副本,叫做任务(Task)。
LDT:为了有效地在任务之间实施隔离,处理器建议每个任务都应当具有自己的描述符表,称为局部描述符表(Local Description Table)。
TSS:为了保存任务的状态,并在下次重新执行时恢复它们,每个任务应当用一个额外的内存区域保存相关信息,这叫做任务状态段(Task State Segment)。
LDTR:处理器使用局部描述符表寄存器(LDT Register:LDTR)来追踪和访问这些LDT
TR:处理器用TR寄存器来指向当前任务的TSS。
每个任务实际上包括两个部分:全局部分和局部部分。全局部分是所有任务共有的,含有操作系统的软件和库程序,以及可以调用的系统服务和数据;私有部分则是每个任务各自的数据和代码,与任务所要解决的具体任务问题有关,彼此并不相同。
因此,全局地址空间是用全局描述符GDT来指定的,而局部地址空间则是由每个任务私有的局部描述符表LDT来定义的。
DPL:描述符特权级,代表着其所描述的段的特权级别
CPL:当处理器正在一个代码段中取指令和执行指令时,那个代码段的特权级叫做当前特权级(Current Privilege Level,CPL)。正在执行的这个代码段,其选择子位于段寄存器CS
中,其最低两位
就是当前特权级数值
那些只有在当前特权级CPL为0时才能执行的指令,称为特权指令(Privilege Instructions)
典型的特权指令:lgdt、lldt、ltr、mov、停机指令hlt等
将高特权级的代码段定义为依从的
使用门(Gate)
CPL = 目标代码段描述符的DPL
RPL = 目标代码段描述符的DPL
CPL ≥ 目标代码段描述符的DPL
RPL ≥ 目标代码段描述符的DPL
CPL ≤ 目标数据段描述符的DPL
RPL ≤ 目标数据段描述符的DPL
CPL = 目标栈段描述符的DPL
RPL = 目标栈段描述符的DPL
需要两个条件
1、当前特权级CPL和请求特权级RPL高于,或者和调用门描述符特权级DPL相同
CPL ≤ 调用门描述符的DPL
RPL ≤ 调用门描述符的DPL
2、当前特权级低于,或者和目标代码段描述符特权级DPL相同,即数值上
CPL ≥ 目标代码段描述符的DPL
本章继续使用上一章的主引导程序,因此内核加载后的GDT布局和上一章一致。
调用门用于在不同特权级的程序之间进行控制转移。本质上,它只是一个描述符,一个不同于代码段和数据段的描述符,可以安装在GDT或者LDT中。
将内核的描述符表中,各个描述符对应的段基地址,修改为调用门选择子。
按处理器的要求标准,要使一个程序成为“任务”,并且能够参与任务切换和调度,必须要有LDT和TSS。
对于操作系统来说,内核应当为每一个任务创建一个内存区域,来记录任务的信息和状态,称为任务控制块(TCB),可能在不同操作系统中有不同的称呼,但是必定是有一个类似的结构的。
栈的访问有两种
从硬盘中将程序加载到内存中,但现在还要分配LDT,同时将程序在内存中的位置记录到TCB中。即,以下3件事:
流程和创建GDT一样。
和13章的流程一样,不同点在于,传给用户程序的选择子,现在变成了调用门选择子。
安装到LDT,并将栈信息登记到TCB中。
全局描述符表(GDT)是唯一的,整个系统中只有一个,所以只需要用GDTR寄存器存放其线性基地址和段界限即可;但LDT不同,每个任务一个,所以为了追踪它们,处理器要求在GDT中安装每一个LDT描述符。当要使用这些LDT时,可以用它们的选择子来访问GDT,将LDT描述符加载到LDTR寄存器。
和LDT一样,必须在全局描述符表(GDT)中创建每个TSS的描述符。
找到当前任务TSS,并检索I/O许可位
分配内存,以填入TSS的内容。将TSS的基地址和界限登记到任务控制块(TCB)中,将来创建TSS描述符时用得着。
TSS的界限值必须至少为103,任何小于该值的TSS,在执行任务切换时,都会引发处理器异常中断
TSS中,LDT对任务来说并不是必须的,如果没有LDT,这里应该填0
必须在GDT中安装TSS描述符。这样做,一方面是为了对TSS进行段和特权级的检查;另一方面,也是执行任务切换的需要。当call far和jmp far指令的操作数是TSS描述符选择子时,处理器执行任务切换操作。
格式和LDT描述符差不多,除了TYPE字段。
TSS描述符中的B位是Busy位。在任务刚刚创建的时候,它应该为二进制的1001,即B位是0,表明任务不忙。当任务开始执行时,或者处于挂起状态(临时被中断执行)时,有处理器固件把B位置1。
ret imm16/32
ret imm16/32
;都允许16位和32位的立即数作为操作数,不同之处在于,前者是近返回,后者是远返回。
任务寄存器TR总是指向当前任务的任务状态段(TSS),而LDTR也总是指向当前任务的LDT。TSS是任务的主要标志,因此要使TR寄存器指向TR;而使用LDTR的原因是可以在任务执行期间加速段的访问。
ltr r/m16
lldt r/m16
;操纵数是16位通用寄存器或者一个16位单元的内存地址
;ltr和lldt执行时,处理器首先要检查描述符的有效性,包括审查它是不是TSS或者LDT描述符
本章代码因为只有一个任务,而且是个3特权级的任务,不能用任务切换的方法使它开始运行。即,如何从任务的0特权级全局空间转移到它自己的3特权级空间正常执行?
执行一个远返回指令retf,假装从调用门返回,于是控制转移到用户程序的3特权级代码开始执行。