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}