hal_x86_64/
task.rs

1use crate::{cpu, segment, VAddr};
2use core::mem;
3use mycelium_util::fmt;
4
5/// A 64-bit mode task-state segment (TSS).
6#[derive(Clone, Copy)]
7#[repr(C, packed(4))]
8pub struct StateSegment {
9    _reserved_1: u32,
10    /// The stack pointers for privilege levels 0-2.
11    ///
12    /// These addresses must be in canonical form.
13    pub privilege_stacks: [VAddr; 3],
14    _reserved_2: u64,
15    /// The interrupt stack table.
16    pub interrupt_stacks: [VAddr; 7],
17    _reserved_3: u64,
18    _reserved_4: u16,
19    /// The 16-bit offset from the TSS' base address to the I/O permissions bitmap.
20    pub iomap_offset: u16,
21}
22
23impl StateSegment {
24    /// Returns a new task-state segment with all fields zeroed.
25    pub const fn empty() -> Self {
26        Self {
27            privilege_stacks: [VAddr::zero(); 3],
28            interrupt_stacks: [VAddr::zero(); 7],
29            iomap_offset: mem::size_of::<Self>() as u16,
30            _reserved_1: 0,
31            _reserved_2: 0,
32            _reserved_3: 0,
33            _reserved_4: 0,
34        }
35    }
36
37    /// Returns the virtual address of the I/O permission bitmap.
38    #[inline]
39    pub fn iomap_addr(&self) -> VAddr {
40        VAddr::of(self).offset(self.iomap_offset as isize)
41    }
42
43    /// Loads the provided [`selector`](segment::Selector) into the current task
44    /// register.
45    ///
46    /// Prefer this higher-level wrapper to the [`ltr` CPU intrinsic][ltr].
47    ///
48    /// # Safety
49    ///
50    /// The caller is responsible for ensuring that `selector` selects a valid
51    /// task state segment, and that the selected TSS will not be deallocated as
52    /// long as it's active.
53    ///
54    /// [ltr]: crate::cpu::intrinsics::ltr
55    pub unsafe fn load_tss(selector: segment::Selector) {
56        tracing::trace!(?selector, "setting TSS...");
57        cpu::intrinsics::ltr(selector);
58        tracing::debug!(?selector, "TSS set");
59    }
60}
61
62impl Default for StateSegment {
63    fn default() -> Self {
64        Self::empty()
65    }
66}
67
68impl fmt::Debug for StateSegment {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        let Self {
71            privilege_stacks,
72            interrupt_stacks,
73            iomap_offset,
74            _reserved_1: _,
75            _reserved_2: _,
76            _reserved_3: _,
77            _reserved_4: _,
78        } = *self;
79        f.debug_struct("task::StateSegment")
80            .field("privilege_stacks", &privilege_stacks)
81            .field("interrupt_stacks", &interrupt_stacks)
82            .field("iomap_offset", &fmt::hex(iomap_offset))
83            .field("iomap_addr", &self.iomap_addr())
84            .finish()
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn sizeof_tss() {
94        assert_eq!(mem::size_of::<StateSegment>(), 0x68)
95    }
96}