x86 0.52.0

Library to program x86 (amd64) hardware. Contains x86 specific data structure descriptions, data-tables, as well as convenience function to call assembly instructions typically not exposed in higher level languages.
Documentation
//! Helpers to program the task state segment.
//! See Intel 3a, Chapter 7, Section 7

use crate::Ring;

/// Although hardware task-switching is not supported in 64-bit mode,
/// a 64-bit task state segment (TSS) must exist.
///
/// The TSS holds information important to 64-bit mode and that is not
/// directly related to the task-switch mechanism. This information includes:
///
/// # RSPn
/// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
/// RSPx is loaded in whenever an interrupt causes the CPU to change RPL to x.
/// Note on a syscall entry this field is not used to load a stack, setting the stack there
/// is the handler's responsibility (however when using the int instruction in user-space,
/// we load the stack from RSPn).
///
/// # ISTn
/// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
/// You can set an interrupt vector to use an IST entry in the Interrupt Descriptor
/// Table by giving it a number from 0 - 7. If 0 is selected, then the IST mechanism
/// is not used. If any other number is selected then when that interrupt vector is
/// called the CPU will load RSP from the corresponding IST entry. This is useful for
/// handling things like double faults, since you don't have to worry about switching
/// stacks; the CPU will do it for you.
///
/// # I/O map base address
/// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base.
///
/// The operating system must create at least one 64-bit TSS after activating IA-32e mode.
/// It must execute the LTR instruction (in 64-bit mode) to load the TR register with a
/// pointer to the 64-bit TSS responsible for both 64-bitmode programs and
/// compatibility-mode programs ([load_tr](crate::task::load_tr)).
#[derive(Clone, Copy, Debug, Default)]
#[repr(C, packed)]
pub struct TaskStateSegment {
    pub reserved: u32,
    /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2.
    pub rsp: [u64; 3],
    pub reserved2: u64,
    /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers.
    pub ist: [u64; 7],
    pub reserved3: u64,
    pub reserved4: u16,
    /// The 16-bit offset to the I/O permission bit map from the 64-bit TSS base.
    pub iomap_base: u16,
}

impl TaskStateSegment {
    /// Creates a new empty TSS.
    pub const fn new() -> TaskStateSegment {
        TaskStateSegment {
            reserved: 0,
            rsp: [0; 3],
            reserved2: 0,
            ist: [0; 7],
            reserved3: 0,
            reserved4: 0,
            iomap_base: 0,
        }
    }

    /// Sets the stack pointer (`stack_ptr`) to be used for when
    /// an interrupt causes the CPU to change RPL to `pl`.
    pub fn set_rsp(&mut self, pl: Ring, stack_ptr: u64) {
        match pl {
            Ring::Ring0 => self.rsp[0] = stack_ptr,
            Ring::Ring1 => self.rsp[1] = stack_ptr,
            Ring::Ring2 => self.rsp[2] = stack_ptr,
            Ring::Ring3 => unreachable!("Can't set stack for PL3"),
        }
    }

    /// Sets the stack pointer (`stack_ptr`) to be used when
    /// an interrupt with a corresponding IST entry in the Interrupt
    /// Descriptor table pointing to the given `index` is raised.
    pub fn set_ist(&mut self, index: usize, stack_ptr: u64) {
        match index {
            0 => self.ist[0] = stack_ptr,
            1 => self.ist[1] = stack_ptr,
            2 => self.ist[2] = stack_ptr,
            3 => self.ist[3] = stack_ptr,
            4 => self.ist[4] = stack_ptr,
            5 => self.ist[5] = stack_ptr,
            6 => self.ist[6] = stack_ptr,
            _ => unreachable!("Can't set IST for this index (out of bounds)."),
        }
    }
}