一、LDT的相关知识
为了有效地在任务之间实施隔离,处理器建议每个任务都应当具有自己的描述符表,称为局部描述符表LDT(Local Descriptor Table),并且把专属于自己的那些段放到LDT中。
LDT也是用来存放描述符的。它与GDT的不同之处在于,LDT只属于某个任务。每个任务都有自己的LDT,每个任务私有的段,都应当在LDT中进行描述。LDT的第1个描述符,也就是0号槽位,也是有效的、可以使用的。
GDTR寄存器追踪和访问GDT。LDTR追踪和访问LDT。
在一个多任务的系统中,会有很多任务在轮流执行,正在执行的那个任务,称为当前任务(Current Task)。因为LDTR寄存器只有一个,所以,它只用于指向当前任务的LDT。每当发生任务切换时,LDTR的内容被更新,以指向新任务的LDT。和GDTR一样,LDTR包含了32位线性基地址字段和16位段界限字段,以指示当前LDT的位置和大小。
在访问内存之前需要指定一个段,方法是向段寄存器的选择器传送一个段选择子,这称为“引用一个段”,比如:“mov cx,0x0008”“mov ds,cx”。我们回顾一下段选择子的构成,段选择子总共16位,其中第1、0位是RPL;第2位是TI位,如果TI=0,则表示描述符在GDT中,如果TI=1,则表示描述符在LDT中;第15~3位是描述符的索引号。在这里,“0x0008”是选择子,它的二进制表示形式为:0000_0000_0000_1000,我们可以看到,它的第1、0位RPL=00;它的第2位TI=0,表明描述符在GDT中;它的第15~3位为1,表示描述符的索引号为1(十进制)。处理器将访问GDT,从1号槽位取得描述符,并传送到段寄存器DS的描述符高速缓存器中。再看一个例子:“mov cx,0x005C”“mov ds,cx”。“ 0x005C”的二进制表示形式为:0000_0000_0101_1100,我们可以得知,它的第1、0位RPL=00;它的第2位TI=1;它的第15~3位索引号为11(十进制)。处理器执行这两条指令的时候,必然会访问当前任务的LDT(该LDT在内存中的位置由LDTR指定),从它的11号槽位取出描述符,并传送到段寄存器DS的描述符高速缓存器中去。
段选择子是16位的,而且只有高13位被用作索引号来访问GDT或者LDT,所以,每个LDT所能容纳的的描述符个数为2^13,即8192个。或者换句话说,每个LDT只能定义8192个段。又因为每个描述符的长度是8字节,LDT的长度最大为64KB。
二、TSS的相关知识
在一个多任务的环境中,当任务切换发生时,必须保护旧任务的运行状态,或者说是保护现场,保护的内容包括通用寄存器、段寄存器、栈指针寄存器ESP、指令指针寄存器EIP、状态寄存器EFLAGS,等等。否则的话,等下次该任务又恢复执行时,一切都会变得茫然而毫无头绪。
为了保存任务的状态,并在下次重新执行时恢复它们,每个任务都应当用一个额外的内存区域保存相关信息,这叫做任务状态段(Task State Segment:TSS),如图14-001。任务状态段TSS具有固定的格式,最小尺寸是104字节,图14-001中所标注的偏移量是十进制的。处理器固件能够识别TSS中的每个元素,并在任务切换的时候读取其中的信息。