Geoff Chappell, Software Analyst
There is, of course, nothing secret about the Task State Segment (TSS). It is perhaps as well, though, to have Microsoft’s representation handy and to take it as an opportunity to note some architectural detail.
Windows—even the sort that ran on DOS for long after Microsoft said—has never made much use of the processor’s built-in support for multi-tasking. As Intel itself put it, as long ago as the 386 DX Microprocessor Programmer’s Reference Manual,
Use of the multitasking mechanism is optional. In some applications, it may not be the best way to manage program execution.
Taking Intel’s option to “perform task switching in software” does not make the TSS redundant. Even when the TSS is not used to switch tasks, one TSS is still needed because the processor retains the notion of executing a current task and looks to the current TSS for certain properties of this task. This is true even for the amd64 architecture which tends to discard (or at least render trivial) 80386 features that programmers seem not to have wanted. Again from Intel, though now from the Intel 64 and IA-32 Architectures Software Developer’s Manual: “Although hardware task-switching is not supported in 64-bit mode, a 64-bit task state segment must exist.”
Hardware task-switching is not completely ignored by 32-bit Windows, but the use is minimal. One TSS for each processor serves all of that processor’s ordinary execution of Windows code. Switching through task gates is kept just to two difficult interrupts by the kernel: the Non-Maskable Interrupt (0x02) and the Double Fault (0x08). Each of these has its own TSS, which each has a dedicated GDT selector (0x0058 and 0x0050, respectively). The HAL in version 4.0 and higher adds to this for the Machine Check exception (0x12), using yet another dedicated GDT selector (0x00A0). The TSS for ordinary execution also has its own GDT selector (0x0028) but most access to it, notably for editing, is through an address that is kept in the KPCR (as the TSS member at offset 0x40).
Perhaps because the KTSS and KTSS64 structures just model things that are anyway documented by Intel, Microsoft seems never to have got round to documenting them. Microsoft’s name for its representation of the 32-bit TSS is revealed in a C-language type definition in the NTDDK.H from as far back as the Device Driver Kit (DDK) for Windows NT 3.51, but the definition there is only of an opaque type and seems likely to have been provided only for neatness in the C-language definition of the KPCR which, of course, keeps a pointer to a KTSS. The first known publication of a C-language definition is in the NTOSP.H from an Enterprise edition of the Windows Driver Kit (WDK) for Windows 10.
In the tables that follow, names, types and offsets are reconstructed from type information in symbol files that Microsoft publishes for the kernel. As noted above, the 32-bit and 64-bit structures differ so much that the layouts are better presented separately.
Symbol-file type information for the KTSS is first available for Windows 2003 SP3. What’s shown for earlier versions is something of a guess, being inferred by inspecting earlier versions for what use they make of the KTSS and either accounting for differences or assuming continuity For instance, since the kernel from version 3.10 allows only 0x206C bytes for each TSS, with the I/O permission bitmap beginning at offset 0x68, it is inferred that although version 3.10 cannot have the DirectionMap and IntDirectionMap that are known from symbol files for later versions, probably everything else that’s known for later versions persists without change.
| Offset (x86) | Definition | Versions |
|---|---|---|
| 0x00 |
USHORT Backlink; |
all |
| 0x02 |
USHORT Reserved0; |
all |
| 0x04 |
ULONG Esp0; |
all |
| 0x08 |
USHORT Ss0; |
all |
| 0x0A |
USHORT Reserved1; |
all |
| 0x0C |
ULONG NotUsed1 [4]; |
all |
| 0x1C |
ULONG CR3; |
all |
| 0x20 |
ULONG Eip; |
all |
| 0x24 |
ULONG NotUsed2 [9]; |
5.0 only |
ULONG EFlags; |
5.1 and higher | |
| 0x28 |
ULONG Eax; |
5.1 and higher |
| 0x2C |
ULONG Ecx; |
5.1 and higher |
| 0x30 |
ULONG Edx; |
5.1 and higher |
| 0x34 |
ULONG Ebx; |
5.1 and higher |
| 0x38 |
ULONG Esp; |
5.1 and higher |
| 0x3C |
ULONG Ebp; |
5.1 and higher |
| 0x40 |
ULONG Esi; |
5.1 and higher |
| 0x44 |
ULONG Edi; |
5.1 and higher |
| 0x48 |
USHORT Es; |
all |
| 0x4A |
USHORT Reserved2; |
all |
| 0x4C |
USHORT Cs; |
all |
| 0x4E |
USHORT Reserved3; |
all |
| 0x50 |
USHORT Ss; |
all |
| 0x52 |
USHORT Reserved4; |
all |
| 0x54 |
USHORT Ds; |
all |
| 0x56 |
USHORT Reserved5; |
all |
| 0x58 |
USHORT Fs; |
all |
| 0x5A |
USHORT Reserved6; |
all |
| 0x5C |
USHORT Gs; |
all |
| 0x5E |
USHORT Reserved7; |
all |
| 0x60 |
USHORT LDT; |
all |
| 0x62 |
USHORT Reserved8; |
all |
| 0x64 |
USHORT Flags; |
all |
| 0x66 |
USHORT IoMapBase; |
all |
| 0x68 |
KIIO_ACCESS_MAP IoMaps [1]; |
all |
| 0x208C |
UCHAR IntDirectionMap [0x20]; |
3.50 and higher |
Among other things, the C-language definition in NTOSP.H shows that Microsoft has the convenience of a type definition, KINT_DIRECTION_MAP, for a 0x20-byte array that’s used as an interrupt direction map.
The KiIoAccessMap structure
| Offset | Definition | Versions |
|---|---|---|
| 0x00 |
UCHAR DirectionMap [0x20]; |
3.50 and higher |
| 0x20 |
UCHAR IoMap [0x2004]; |
all |
| Offset (x86) | Definition | Versions |
|---|---|---|
| 0x00 |
ULONG Reserved0; |
|
| 0x04 |
ULONG64 Rsp0; |
|
| 0x0C |
ULONG64 Rsp1; |
|
| 0x14 |
ULONG64 Rsp2; |
|
| 0x1C |
ULONG64 Ist [8]; |
|
| 0x5C |
ULONG64 Reserved1; |
|
| 0x64 |
USHORT Reserved2; |
|
| 0x66 |
USHORT IoMapBase; |