Task State Segment: Difference between revisions

[unchecked revision][unchecked revision]
Content deleted Content added
Redo wikitables and flesh out article information around tables.
Line 1:
TheA '''Task State Segment''' ('''TSS''') is a specialbinary data structure forspecific to the [[IA32_Architecture_Family|IA-32]] and [[X86-64|x86-64]] processorsarchitectures. whichIt holds information about a task. TheIn '''[[Protected Mode]]''' the '''TSS''' is primarily suited for '''[[Context Switching#Hardware Context Switching|hardwareHardware multitaskingTask Switching]]''', where each individual process'''Task''' has its own '''TSS'''. InFor use in [[Context Switching#Software Context Switching|software multitasking]], one or two TSS's are also generally used, as they allow for entering [['''Ring 0''' code after an interrupt. In '''[[Long Mode]]''', codethe '''TSS''' has a separate structure and is used to change the '''Stack Pointer''' after an interrupt or permission level change. You'll have to update the '''TSS''' yourself in the multitasking function, as it apparently does not save your registers automatically.
 
== x86Protected Mode Structure==
 
For its use in hardware task switching, a '''TSS''' contains a program's state, including '''[[CPU Registers x86#General Purpose Registers|General Purpose Registers]]''', '''[[Segment Selector|Segment Selectors]]''', the '''[[CPU Registers x86#General Pointer Registers|Instruction Pointer]]''', the '''[[CPU Registers x86#EFLAGS Register|EFLAGS Register]]''' and '''[[CPU Registers x86#CR3|Control Register 3]]'''. It contains certain other fields described below.
{| {{wikitable}}
 
{|class="wikitable"
|-
!style="width: 20%;"| 0x3
! offset
!style="width: 20%;"| 0x2
! 0 - 15
!style="width: 20%;"| 0x1
! 16 - 31
!style="width: 20%;"| 0x0
!style="width: 20%;"| Offset
|-
|colspan=4 style="text-align: center;"| '''SSP'''
! 0x00
!0x68
| LINK
| style="background: #ffdddd" | reserved
|-
|colspan=2 style="text-align: center;"| '''IOPB'''
! 0x04
| colspan=2 style="text-align: center;"| ESP0Reserved
!0x64
|-
|colspan=2 style="text-align: center;"| Reserved
! 0x08
|colspan=2 style="text-align: center;"| '''LDTR'''
| SS0
!0x60
| style="background: #ffdddd" | reserved
|-
|colspan=2 style="text-align: center;"| Reserved
! 0x0C
| colspan=2 style="text-align: center;"| ESP1'''GS'''
!0x5C
|-
|colspan=2 style="text-align: center;"| Reserved
! 0x10
|colspan=2 style="text-align: center;"| '''FS'''
| SS1
!0x58
| style="background: #ffdddd" | reserved
|-
|colspan=2 style="text-align: center;"| Reserved
! 0x14
| colspan=2 style="text-align: center;"| ESP2'''DS'''
!0x54
|-
|colspan=2 style="text-align: center;"| Reserved
! 0x18
|colspan=2 style="text-align: center;"| '''SS'''
| SS2
!0x50
| style="background: #ffdddd" | reserved
|-
|colspan=2 style="text-align: center;"| Reserved
! 0x1C
| colspan=2 style="text-align: center;"| CR3'''CS'''
!0x4C
|-
|colspan=2 style="text-align: center;"| Reserved
! 0x20
| colspan=2 style="text-align: center;"| EIP'''ES'''
!0x48
|-
|colspan=4 style="text-align: center;"| '''EDI'''
! 0x24
!0x44
| colspan=2 | EFLAGS
|-
|colspan=4 style="text-align: center;"| '''ESI'''
! 0x28
!0x40
| colspan=2 | EAX
|-
|colspan=4 style="text-align: center;"| '''EBP'''
! 0x2C
!0x3C
| colspan=2 | ECX
|-
|colspan=4 style="text-align: center;"| '''ESP'''
! 0x30
!0x38
| colspan=2 | EDX
|-
|colspan=4 style="text-align: center;"| '''EBX'''
! 0x34
!0x34
| colspan=2 | EBX
|-
|colspan=4 style="text-align: center;"| '''EDX'''
! 0x38
!0x30
| colspan=2 | ESP
|-
|colspan=4 style="text-align: center;"| '''ECX'''
! 0x3C
!0x2C
| colspan=2 | EBP
|-
|colspan=4 style="text-align: center;"| '''EAX'''
! 0x40
!0x28
| colspan=2 | ESI
|-
|colspan=4 style="text-align: center;"| '''EFLAGS'''
! 0x44
!0x24
| colspan=2 | EDI
|-
|colspan=4 style="text-align: center;"| '''EIP'''
! 0x48
!0x20
| ES
| style="background: #ffdddd" | reserved
|-
|colspan=4 style="text-align: center;"| '''CR3'''
! 0x4C
!0x1C
| CS
| style="background: #ffdddd" | reserved
|-
|colspan=2 style="text-align: center;"| Reserved
! 0x50
|colspan=2 style="text-align: center;"| '''SS2'''
| SS
!0x18
| style="background: #ffdddd" | reserved
|-
|colspan=4 style="text-align: center;"| '''ESP2'''
! 0x54
!0x14
| DS
| style="background: #ffdddd" | reserved
|-
|colspan=2 style="text-align: center;"| Reserved
! 0x58
|colspan=2 style="text-align: center;"| '''SS1'''
| FS
!0x10
| style="background: #ffdddd" | reserved
|-
|colspan=4 style="text-align: center;"| '''ESP1'''
! 0x5C
!0x0C
| GS
| style="background: #ffdddd" | reserved
|-
|colspan=2 style="text-align: center;"| Reserved
! 0x60
|colspan=2 style="text-align: center;"| '''SS0'''
| LDTR
!0x08
| style="background: #ffdddd" | reserved
|-
|colspan=4 style="text-align: center;"| '''ESP0'''
! 0x64
!0x04
| style="background: #ffdddd" | reserved
| IOPB offset
|-
|colspan=2 style="text-align: center;"| Reserved
|colspan=2 style="text-align: center;"| '''LINK'''
!0x00
|}
 
* '''LINK:''' Previous Task Link Field. Contains the '''Segment Selector''' for the '''TSS''' of the previous task.
==x86_64 Structure==
* '''SS0, SS1, SS2:''' The '''Segment Selectors''' used to load the stack when a privilege level change occurs from a lower privilege level to a higher one.
* '''ESP0, ESP1, ESP2:''' The '''Stack Pointers''' used to load the stack when a privilege level change occurs from a lower privilege level to a higher one.
* '''IOPB:''' I/O Map Base Address Field. Contains a 16-bit offset from the base of the '''TSS''' to the '''I/O Permission Bit Map'''.
* '''SSP:''' Shadow Stack Pointer.
 
== Long Mode ==
{| {{wikitable}}
 
|-
In '''[[Long Mode]]''', the '''TSS''' does not store information on a task's execution state, instead it is used to store the '''Interrupt Stack Table'''.
! offset
 
! 0 - 15
{|class="wikitable"
! 16 - 31
|-
!style="width: 20%;"| 0x3
! 0x00
| colspan=2 !style="backgroundwidth: #ffdddd20%;" | reserved0x2
!style="width: 20%;"| 0x1
!style="width: 20%;"| 0x0
!style="width: 20%;"| Offset
|-
|colspan=2 style="text-align: center;"| '''IOPB'''
! 0x04
| colspan=42 |style="text-align: RSP0center;"| (low)Reserved
!0x64
|-
|colspan=4 style="text-align: center;"| Reserved
! 0x08
!0x60
| colspan=4 | RSP0 (high)
|-
|colspan=4 style="text-align: center;"| Reserved
! 0x0C
!0x5C
| colspan=2 | RSP1 (low)
|-
|colspan=4 style="text-align: center;"| '''IST7''' (High)
! 0x10
!0x58
| colspan=2 | RSP1 (high)
|-
|colspan=4 style="text-align: center;"| '''IST7''' (Low)
! 0x14
!0x54
| colspan=2 | RSP2 (low)
|-
|colspan=4 style="text-align: center;"| '''IST6''' (High)
! 0x18
!0x50
| colspan=2 | RSP2 (high)
|-
|colspan=4 style="text-align: center;"| '''IST6''' (Low)
! 0x1C
!0x4C
| colspan=2 style="background: #ffdddd" | reserved
|-
|colspan=4 style="text-align: center;"| '''IST5''' (High)
! 0x20
!0x48
| colspan=2 style="background: #ffdddd" | reserved
|-
|colspan=4 style="text-align: center;"| '''IST5''' (Low)
! 0x24
!0x44
| colspan=2 | IST1 (low)
|-
|colspan=4 style="text-align: center;"| '''IST4''' (High)
! 0x28
!0x40
| colspan=2 | IST1 (high)
|-
|colspan=4 style="text-align: center;"| '''IST4''' (Low)
! 0x2C
!0x3C
| colspan=2 | IST2 (low)
|-
|colspan=4 style="text-align: center;"| '''IST3''' (High)
! 0x30
!0x38
| colspan=2 | IST2 (high)
|-
|colspan=4 style="text-align: center;"| '''IST3''' (Low)
! 0x34
!0x34
| colspan=2 | IST3 (low)
|-
|colspan=4 style="text-align: center;"| '''IST2''' (High)
! 0x38
!0x30
| colspan=2 | IST3 (high)
|-
|colspan=4 style="text-align: center;"| '''IST2''' (Low)
! 0x3C
!0x2C
| colspan=2 | IST4 (low)
|-
|colspan=4 style="text-align: center;"| '''IST1''' (High)
! 0x40
!0x28
| colspan=2 | IST4 (high)
|-
|colspan=4 style="text-align: center;"| '''IST1''' (Low)
! 0x44
!0x24
| colspan=2 | IST5 (low)
|-
|colspan=4 style="text-align: center;"| Reserved
! 0x48
!0x20
| colspan=2 | IST5 (high)
|-
|colspan=4 style="text-align: center;"| Reserved
! 0x4C
!0x1C
| colspan=2 | IST6 (low)
|-
|colspan=4 style="text-align: center;"| '''RSP2''' (High)
! 0x50
!0x18
| colspan=2 | IST6 (high)
|-
|colspan=4 style="text-align: center;"| '''RSP2''' (Low)
! 0x54
!0x14
| colspan=2 | IST7 (low)
|-
|colspan=4 style="text-align: center;"| '''RSP1''' (High)
! 0x58
!0x10
| colspan=2 | IST7 (high)
|-
|colspan=4 style="text-align: center;"| '''RSP1''' (Low)
! 0x5C
!0x0C
| colspan=2 style="background: #ffdddd" | reserved
|-
|colspan=4 style="text-align: center;"| '''RSP0''' (High)
! 0x60
!0x08
| colspan=2 style="background: #ffdddd" | reserved
|-
|colspan=4 style="text-align: center;"| '''RSP0''' (Low)
! 0x64
!0x04
| style="background: #ffdddd" | reserved
| IOPB offset
|-
|colspan=4 style="text-align: center;"| Reserved
!0x00
|}
 
* '''RSP0, RSP1, RSP2:''' The '''Stack Pointers''' used to load the stack when a privilege level change occurs from a lower privilege level to a higher one.
The x86_64 structure is slightly different. The RSP0, RSP1 and RSP2 fields remain. RSPx is loaded in whenever an interrupt causes the CPU to change PL (privilege level) to x. The TSS in long mode also holds the Interrupt Stack Table, which is a table of 7 known good stack pointers that can be used for handling interrupts. You can set an interrupt vector to use an IST entry in the [[Interrupt Descriptor Table]] by giving it a number from 0 - 7. If 0 is selected, then the IST mechanism is not used. If any other number is selected then when that interrupt vector is called the CPU will load RSP from the corresponding IST entry. This is useful for handling things like double faults, since you don't have to worry about switching stacks; the CPU will do it for you.
* '''IST#:''' Interrupt Stack Table. The '''Stack Pointers''' used to load the stack when an entry in the '''[[Interrupt Descriptor Table#Long Mode|Interrupt Descriptor Table]]''' has an '''IST''' value other than 0.
* '''IOPB:''' I/O Map Base Address Field. Contains a 16-bit offset from the base of the '''TSS''' to the '''I/O Permission Bit Map'''.
 
== TSS in software multitasking ==
Note that in any case, when an interrupt occurs, SS is forced to NULL and the SS selector's RPL field is set to the new CPL.
 
==TSS in software multitasking==
For each CPU which executes processes possibly wanting to do system calls via interrupts, one TSS is required. The only interesting fields are SS0 and ESP0. Whenever a system call occurs, the CPU gets the SS0 and ESP0-value in its TSS and assigns the stack-pointer to it. So one or more kernel-stacks need to be set up for processes doing system calls. Be aware that a thread's/process' time-slice may end during a system call, passing control to another thread/process which may as well perform a system call, ending up in the same stack. Solutions are to create a private kernel-stack for each thread/process and re-assign esp0 at any task-switch or to disable scheduling during a system-call (see also [[Kernel Multitasking]]).