x86_64/structures/
tss.rs

1//! Provides a type for the task state segment structure.
2
3use crate::VirtAddr;
4use core::mem::size_of;
5
6/// In 64-bit mode the TSS holds information that is not
7/// directly related to the task-switch mechanism,
8/// but is used for stack switching when an interrupt or exception occurs.
9#[derive(Debug, Clone, Copy)]
10#[repr(C, packed(4))]
11pub struct TaskStateSegment {
12    reserved_1: u32,
13    /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
14    /// The stack pointers used when a privilege level change occurs from a lower privilege level to a higher one.
15    pub privilege_stack_table: [VirtAddr; 3],
16    reserved_2: u64,
17    /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
18    /// The stack pointers used when an entry in the Interrupt Descriptor Table has an IST value other than 0.
19    pub interrupt_stack_table: [VirtAddr; 7],
20    reserved_3: u64,
21    reserved_4: u16,
22    /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base.
23    pub iomap_base: u16,
24}
25
26impl TaskStateSegment {
27    /// Creates a new TSS with zeroed privilege and interrupt stack table and an
28    /// empty I/O-Permission Bitmap.
29    ///
30    /// As we always set the TSS segment limit to
31    /// `size_of::<TaskStateSegment>() - 1`, this means that `iomap_base` is
32    /// initialized to `size_of::<TaskStateSegment>()`.
33    #[inline]
34    pub const fn new() -> TaskStateSegment {
35        TaskStateSegment {
36            privilege_stack_table: [VirtAddr::zero(); 3],
37            interrupt_stack_table: [VirtAddr::zero(); 7],
38            iomap_base: size_of::<TaskStateSegment>() as u16,
39            reserved_1: 0,
40            reserved_2: 0,
41            reserved_3: 0,
42            reserved_4: 0,
43        }
44    }
45}
46
47impl Default for TaskStateSegment {
48    #[inline]
49    fn default() -> Self {
50        Self::new()
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    pub fn check_tss_size() {
60        // Per the SDM, the minimum size of a TSS is 0x68 bytes, giving a
61        // minimum limit of 0x67.
62        assert_eq!(size_of::<TaskStateSegment>(), 0x68);
63    }
64}