x86_64/structures/
tss.rs

1//! Provides a type for the task state segment structure.
2
3use crate::VirtAddr;
4use core::{
5    fmt::{self, Display},
6    mem::size_of,
7};
8
9/// In 64-bit mode the TSS holds information that is not
10/// directly related to the task-switch mechanism,
11/// but is used for stack switching when an interrupt or exception occurs.
12#[derive(Debug, Clone, Copy)]
13#[repr(C, packed(4))]
14pub struct TaskStateSegment {
15    reserved_1: u32,
16    /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
17    /// The stack pointers used when a privilege level change occurs from a lower privilege level to a higher one.
18    pub privilege_stack_table: [VirtAddr; 3],
19    reserved_2: u64,
20    /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
21    /// The stack pointers used when an entry in the Interrupt Descriptor Table has an IST value other than 0.
22    pub interrupt_stack_table: [VirtAddr; 7],
23    reserved_3: u64,
24    reserved_4: u16,
25    /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base. It must not
26    /// exceed `0xDFFF`.
27    pub iomap_base: u16,
28}
29
30impl TaskStateSegment {
31    /// Creates a new TSS with zeroed privilege and interrupt stack table and an
32    /// empty I/O-Permission Bitmap.
33    ///
34    /// As we always set the TSS segment limit to
35    /// `size_of::<TaskStateSegment>() - 1`, this means that `iomap_base` is
36    /// initialized to `size_of::<TaskStateSegment>()`.
37    #[inline]
38    pub const fn new() -> TaskStateSegment {
39        TaskStateSegment {
40            privilege_stack_table: [VirtAddr::zero(); 3],
41            interrupt_stack_table: [VirtAddr::zero(); 7],
42            iomap_base: size_of::<TaskStateSegment>() as u16,
43            reserved_1: 0,
44            reserved_2: 0,
45            reserved_3: 0,
46            reserved_4: 0,
47        }
48    }
49}
50
51impl Default for TaskStateSegment {
52    #[inline]
53    fn default() -> Self {
54        Self::new()
55    }
56}
57
58/// The given IO permissions bitmap is invalid.
59#[derive(Debug, Copy, Clone, PartialEq, Eq)]
60pub enum InvalidIoMap {
61    /// The IO permissions bitmap is before the TSS. It must be located after the TSS.
62    IoMapBeforeTss,
63    /// The IO permissions bitmap is too far from the TSS. It must be within `0xdfff` bytes of the
64    /// start of the TSS. Note that if the IO permissions bitmap is located before the TSS, then
65    /// `IoMapBeforeTss` will be returned instead.
66    TooFarFromTss {
67        /// The distance of the IO permissions bitmap from the beginning of the TSS.
68        distance: usize,
69    },
70    /// The final byte of the IO permissions bitmap was not 0xff
71    InvalidTerminatingByte {
72        /// The byte found at the end of the IO permissions bitmap.
73        byte: u8,
74    },
75    /// The IO permissions bitmap exceeds the maximum length (8193).
76    TooLong {
77        /// The length of the IO permissions bitmap.
78        len: usize,
79    },
80    /// The `iomap_base` in the `TaskStateSegment` struct was not what was expected.
81    InvalidBase {
82        /// The expected `iomap_base` to be set in the `TaskStateSegment` struct.
83        expected: u16,
84        /// The actual `iomap_base` set in the `TaskStateSegment` struct.
85        got: u16,
86    },
87}
88
89impl Display for InvalidIoMap {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        match *self {
92            InvalidIoMap::IoMapBeforeTss => {
93                write!(f, "the IO permissions bitmap is before the TSS")
94            }
95            InvalidIoMap::TooFarFromTss { distance } => write!(
96                f,
97                "the IO permissions bitmap is too far from the TSS (distance {distance})"
98            ),
99            InvalidIoMap::InvalidTerminatingByte { byte } => write!(
100                f,
101                "The final byte of the IO permissions bitmap was not 0xff ({byte}"
102            ),
103            InvalidIoMap::TooLong { len } => {
104                write!(
105                    f,
106                    "The IO permissions bitmap exceeds the maximum length ({len} > 8193)"
107                )
108            }
109            InvalidIoMap::InvalidBase { expected, got } => write!(
110                f,
111                "the `iomap_base` in the `TaskStateSegment` struct was not what was expected (expected {expected}, got {got})"
112            ),
113        }
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    pub fn check_tss_size() {
123        // Per the SDM, the minimum size of a TSS is 0x68 bytes, giving a
124        // minimum limit of 0x67.
125        assert_eq!(size_of::<TaskStateSegment>(), 0x68);
126    }
127}