x86/bits64/task.rs
1//! Helpers to program the task state segment.
2//! See Intel 3a, Chapter 7, Section 7
3
4use crate::Ring;
5
6/// Although hardware task-switching is not supported in 64-bit mode,
7/// a 64-bit task state segment (TSS) must exist.
8///
9/// The TSS holds information important to 64-bit mode and that is not
10/// directly related to the task-switch mechanism. This information includes:
11///
12/// # RSPn
13/// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
14/// RSPx is loaded in whenever an interrupt causes the CPU to change RPL to x.
15/// Note on a syscall entry this field is not used to load a stack, setting the stack there
16/// is the handler's responsibility (however when using the int instruction in user-space,
17/// we load the stack from RSPn).
18///
19/// # ISTn
20/// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
21/// You can set an interrupt vector to use an IST entry in the Interrupt Descriptor
22/// Table by giving it a number from 0 - 7. If 0 is selected, then the IST mechanism
23/// is not used. If any other number is selected then when that interrupt vector is
24/// called the CPU will load RSP from the corresponding IST entry. This is useful for
25/// handling things like double faults, since you don't have to worry about switching
26/// stacks; the CPU will do it for you.
27///
28/// # I/O map base address
29/// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base.
30///
31/// The operating system must create at least one 64-bit TSS after activating IA-32e mode.
32/// It must execute the LTR instruction (in 64-bit mode) to load the TR register with a
33/// pointer to the 64-bit TSS responsible for both 64-bitmode programs and
34/// compatibility-mode programs ([load_tr](crate::task::load_tr)).
35#[derive(Clone, Copy, Debug, Default)]
36#[repr(C, packed)]
37pub struct TaskStateSegment {
38 pub reserved: u32,
39 /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
40 pub rsp: [u64; 3],
41 pub reserved2: u64,
42 /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
43 pub ist: [u64; 7],
44 pub reserved3: u64,
45 pub reserved4: u16,
46 /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base.
47 pub iomap_base: u16,
48}
49
50impl TaskStateSegment {
51 /// Creates a new empty TSS.
52 pub const fn new() -> TaskStateSegment {
53 TaskStateSegment {
54 reserved: 0,
55 rsp: [0; 3],
56 reserved2: 0,
57 ist: [0; 7],
58 reserved3: 0,
59 reserved4: 0,
60 iomap_base: 0,
61 }
62 }
63
64 /// Sets the stack pointer (`stack_ptr`) to be used for when
65 /// an interrupt causes the CPU to change RPL to `pl`.
66 pub fn set_rsp(&mut self, pl: Ring, stack_ptr: u64) {
67 match pl {
68 Ring::Ring0 => self.rsp[0] = stack_ptr,
69 Ring::Ring1 => self.rsp[1] = stack_ptr,
70 Ring::Ring2 => self.rsp[2] = stack_ptr,
71 Ring::Ring3 => unreachable!("Can't set stack for PL3"),
72 }
73 }
74
75 /// Sets the stack pointer (`stack_ptr`) to be used when
76 /// an interrupt with a corresponding IST entry in the Interrupt
77 /// Descriptor table pointing to the given `index` is raised.
78 pub fn set_ist(&mut self, index: usize, stack_ptr: u64) {
79 match index {
80 0 => self.ist[0] = stack_ptr,
81 1 => self.ist[1] = stack_ptr,
82 2 => self.ist[2] = stack_ptr,
83 3 => self.ist[3] = stack_ptr,
84 4 => self.ist[4] = stack_ptr,
85 5 => self.ist[5] = stack_ptr,
86 6 => self.ist[6] = stack_ptr,
87 _ => unreachable!("Can't set IST for this index (out of bounds)."),
88 }
89 }
90}