TSS - Waaal/BobaOS GitHub Wiki
A TSS is a struct that lives in memory. It holds information about the kernel stack.
In protected mode TSS is responsible for holding information such as the kernel stack pointer and segment. It also holds the General purpose registers, Segment Selectors, Instruction pointer, EFLAGS register and the Cr3. Important for us are the Kernel stack pointer (ESP0) and the kernel stack segment (SS0).
Whenever a system call in ring3 occurs, the CPU takes the ESP0 and SS0 values from the TSS and populates its stack registers with it. So basically it holds the kernel stack and when we are in ring3 and perform a interrupt and we change our ring level to 0 we know where the kernel stack is.
But important if, if we are currently working on a interrupt for a process and the process time ends and we change to a different process and this process also performs a interrupt we land in the same stack. To solve this problem each process has its own kernel stack. The TSS ESP0 values just needs to be swapped when we change process.
Important: The TSS is only needed in interrupts where a priviledge level change occure. So If we are in ring 0 and a interrupt occurs the TSS is not used and is not filled by the CPU.
| 4 Bytes | Offset |
|---|---|
| SSP | 0x68 |
| IOPB (2byte (high)) | 0x64 |
| LDTR (2byte) | 0x60 |
| GS (2byte) | 0x5C |
| FS (2byte) | 0x58 |
| DS (2byte) | 0x54 |
| SS (2byte) | 0x50 |
| CS (2byte) | 0x4C |
| ES (2byte) | 0x48 |
| EDI | 0x44 |
| ESI | 0x40 |
| EBP | 0x3C |
| ESP | 0x38 |
| EBX | 0x34 |
| EDX | 0x30 |
| ECX | 0x2C |
| EAX | 0x28 |
| EFLAGS | 0x24 |
| EIP | 0x20 |
| CR3 | 0x1C |
| SS2 (2byte) | 0x18 |
| ESP2 | 0x14 |
| SS1 (2byte) | 0x10 |
| ESP1 | 0x0C |
| SS0 (2byte) | 0x08 |
| ESP0 | 0x04 |
| LINK (2byte) | 0x00 |
LINK: The segment selector for the TSS of the previous task
SS0, SS1, SS2: Segment selectors to load stack for priviledge level change from ring 0 - 2
ESP0, ESP1, ESP2: Stack pointer load stack when priviledge level change from ring 0 - 2
IOPB: I/O Map Base address field for I/O port permission map
SSP: Shadow stack pointer
The TSS is also needed for multitasking. Because each CPU core has its own TSS in a multitasking scenario.
The TSS needs to have a entry in the gdt. The TSS entry is special, because the base and limit needs to be set to the start and size of the TSS.
Base = TSS start address.
Limit = TSS Length.
The Access Bytes look like this: 1110 1001 Special about this is that the bit 4 (Descriptor Type) is set to 0 which means this is a system segment and not a code or data segment.
The tss needs to be loaded with the ltr instruction. The ltr instruction taks as argument the TSS GDT entry.
mov ax, 0x28 ;0x28 = 00000000 00101000 = RPL = 0; TL = 0; Selected Index = 5 (At which index is the TSS entry in the GDT);
ltr ax