Task State Segment

来自osdev
跳到导航 跳到搜索

任务状态段 (TSS-Task State Segment) 是特定于IA-32X86-64体系结构的二进制数据结构。 它保存有关任务的信息。 在 保护模式 中,TTS; 主要适用于 硬件任务切换,其中每个单独的 任务 都有自己的 TSS。 在软件多任务中使用时,通常也会使用一两个,因为它们允许在中断后进入“Ring 0”代码。 在长模式中,TSS具有独立的结构,用于在中断或权限级别更改后更改堆栈指针(Stack Pointer)。 你必须自己在多任务处理功能中更新 TTS,因为它显然不会自动保存寄存器。

保护模式

对于在硬件任务切换中的使用,TSS包含程序的状态,包括通用寄存器段选择器指令指针EFLAGS寄存器EFLAGS寄存器指令指针EFLAGS寄存器 它包含下面描述的某些其他字段。

0x3 0x2 0x1 0x0 Offset
SSP 0x68
IOPB Reserved 0x64
Reserved LDTR 0x60
Reserved GS 0x5C
Reserved FS 0x58
Reserved DS 0x54
Reserved SS 0x50
Reserved CS 0x4C
Reserved ES 0x48
EDI 0x44
ESI 0x40
EBP 0x3C
ESP 0x38
EBX 0x34
EDX 0x30
ECX 0x2C
EAX 0x28
EFLAGS 0x24
EIP 0x20
CR3 0x1C
Reserved SS2 0x18
ESP2 0x14
Reserved SS1 0x10
ESP1 0x0C
Reserved SS0 0x08
ESP0 0x04
Reserved LINK 0x00
  • LINK: 上一个任务链接字段。 包含前一任务的TSSSegment Selector
  • SS0, SS1, SS2: 当权限级别从较低权限级别更改为较高权限级别时,用于加载堆栈的Segment Selectors
  • ESP0, ESP1, ESP2: Stack Pointers用于在权限级别从较低的权限级别更改为较高的权限级别时加载堆栈。
  • IOPB: I/O映射基址字段。 包含从 TSS 的基地址到I/O Permission Bit Map的16位偏移量。
  • SSP: Shadow Stack Pointer.

长模式

长模式中,TSS不存储有关任务执行状态的信息,而是用于存储中断堆栈表(Interrupt Stack Table)

0x3 0x2 0x1 0x0 Offset
IOPB Reserved 0x64
Reserved 0x60
Reserved 0x5C
IST7 (High) 0x58
IST7 (Low) 0x54
IST6 (High) 0x50
IST6 (Low) 0x4C
IST5 (High) 0x48
IST5 (Low) 0x44
IST4 (High) 0x40
IST4 (Low) 0x3C
IST3 (High) 0x38
IST3 (Low) 0x34
IST2 (High) 0x30
IST2 (Low) 0x2C
IST1 (High) 0x28
IST1 (Low) 0x24
Reserved 0x20
Reserved 0x1C
RSP2 (High) 0x18
RSP2 (Low) 0x14
RSP1 (High) 0x10
RSP1 (Low) 0x0C
RSP0 (High) 0x08
RSP0 (Low) 0x04
Reserved 0x00
  • RSP0, RSP1, RSP2: 当特权级别从较低的特权级别更改为较高的特权级别时,用于加载堆栈的Stack Pointers(栈指针)
  • IST#: 中断堆栈表(Interrupt Stack Table)。 “中断描述符表-Interrupt Descriptor Table”中的一个条目的IST值不是0时,用于加载堆栈的Stack Pointers
  • IOPB: I/O映射基址字段。 包含从TSS的基地址到I/O Permission Bit Map的16位偏移量。

软件多任务中的TSS

对于执行可能想要通过中断进行系统调用的进程的每个CPU,需要一个TSS。 唯一有趣的字段是SS0和esp0。 每当发生系统调用时,CPU都会在其TSS中获取SS0和ESP0值,并将堆栈指针分配给它。 因此,需要为执行系统调用的进程设置一个或多个内核堆栈。 请注意,线程/进程的时间片可能在系统调用期间结束,将控制权传递给另一个线程/进程,该线程/进程也可以执行系统调用,最终在同一堆栈中。 解决方案是为每个线程/进程创建一个私有内核堆栈,并在任何任务切换时重新分配esp0,或者在系统调用期间禁用调度(另请参见[[Kernel Multitasking|内核多任务])。

设置TSS很简单。 需要 全局描述符表 中的条目 (另请参阅 GDT教程),将TSS的地址指定为 “base”,TSS的大小指定为 “limit”,0x89 (Present|Executable|Accessed) 作为 “access byte”,0x40 (Size-bit) 作为 “flags”。 在TSS本身中,要设置成员“SS0”、“ESP0”和“IOPB偏移量”:

  • SS0获取内核数据段描述符(例如,如果GDT中的第三个条目描述了内核数据,则为0x10)
  • ESP0获取堆栈指针在系统调用时应获得的值
  • 如果你不打算进一步使用此io-bitmap,IOPB可能会获得 sizeof(TSS)值(即104)(根据mystran http://forum.osdev.org/viewtopic.php?t=13678)

TSS的实际加载必须在保护模式下进行,并且必须在GDT加载之后进行。 加载过程很简单,如下所示:

mov ax, 0x??  ;GDT中TSS的描述符(例如,如果GDT中的第六个条目描述了你的TSS,则为0x28)
ltr ax        ;实际加载

另见

文章

论坛主题

外部链接

de:Task State Segment