x86_64/registers/
segmentation.rs

1//! Abstractions for segment registers.
2
3use super::model_specific::Msr;
4use crate::{PrivilegeLevel, VirtAddr};
5use bit_field::BitField;
6use core::fmt;
7// imports for intra doc links
8#[cfg(doc)]
9use crate::{
10    registers::control::Cr4Flags,
11    structures::gdt::{Descriptor, DescriptorFlags, GlobalDescriptorTable},
12};
13
14/// An x86 segment
15///
16/// Segment registers on x86 are 16-bit [`SegmentSelector`]s, which index into
17/// the [`GlobalDescriptorTable`]. The corresponding GDT entry is used to
18/// configure the segment itself. Note that most segmentation functionality is
19/// disabled in 64-bit mode. See the individual segments for more information.
20pub trait Segment {
21    /// Returns the current value of the segment register.
22    fn get_reg() -> SegmentSelector;
23    /// Reload the segment register. Depending on the segment, this may also
24    /// reconfigure the corresponding segment.
25    ///
26    /// ## Safety
27    ///
28    /// This function is unsafe because the caller must ensure that `sel`
29    /// is a valid segment descriptor, and that reconfiguring the segment will
30    /// not cause undefined behavior.
31    unsafe fn set_reg(sel: SegmentSelector);
32}
33
34/// An x86 segment which is actually used in 64-bit mode
35///
36/// While most segments are unused in 64-bit mode, the FS and GS segments are
37/// still partially used. Only the 64-bit segment base address is used, and this
38/// address can be set via the GDT, or by using the `FSGSBASE` instructions.
39pub trait Segment64: Segment {
40    /// MSR containing the segment base. This MSR can be used to set the base
41    /// when [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is **not** set.
42    const BASE: Msr;
43    /// Reads the segment base address
44    ///
45    /// ## Exceptions
46    ///
47    /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is not set, this instruction will throw a `#UD`.
48    fn read_base() -> VirtAddr;
49    /// Writes the segment base address
50    ///
51    /// ## Exceptions
52    ///
53    /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is not set, this instruction will throw a `#UD`.
54    ///
55    /// ## Safety
56    ///
57    /// The caller must ensure that this write operation has no unsafe side
58    /// effects, as the segment base address might be in use.
59    unsafe fn write_base(base: VirtAddr);
60}
61
62/// Specifies which element to load into a segment from
63/// descriptor tables (i.e., is a index to LDT or GDT table
64/// with some additional flags).
65///
66/// See Intel 3a, Section 3.4.2 "Segment Selectors"
67#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
68#[repr(transparent)]
69pub struct SegmentSelector(pub u16);
70
71impl SegmentSelector {
72    /// Creates a new SegmentSelector
73    ///
74    /// # Arguments
75    ///  * `index`: index in GDT or LDT array (not the offset)
76    ///  * `rpl`: the requested privilege level
77    #[inline]
78    pub const fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector {
79        SegmentSelector(index << 3 | (rpl as u16))
80    }
81
82    /// Can be used as a selector into a non-existent segment and assigned to segment registers,
83    /// e.g. data segment register in ring 0
84    pub const NULL: Self = Self::new(0, PrivilegeLevel::Ring0);
85
86    /// Returns the GDT index.
87    #[inline]
88    pub fn index(self) -> u16 {
89        self.0 >> 3
90    }
91
92    /// Returns the requested privilege level.
93    #[inline]
94    pub fn rpl(self) -> PrivilegeLevel {
95        PrivilegeLevel::from_u16(self.0.get_bits(0..2))
96    }
97
98    /// Set the privilege level for this Segment selector.
99    #[inline]
100    pub fn set_rpl(&mut self, rpl: PrivilegeLevel) {
101        self.0.set_bits(0..2, rpl as u16);
102    }
103}
104
105impl fmt::Debug for SegmentSelector {
106    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107        let mut s = f.debug_struct("SegmentSelector");
108        s.field("index", &self.index());
109        s.field("rpl", &self.rpl());
110        s.finish()
111    }
112}
113
114/// Code Segment
115///
116/// While most fields in the Code-Segment [`Descriptor`] are unused in 64-bit
117/// long mode, some of them must be set to a specific value. The
118/// [`EXECUTABLE`](DescriptorFlags::EXECUTABLE),
119/// [`USER_SEGMENT`](DescriptorFlags::USER_SEGMENT), and
120/// [`LONG_MODE`](DescriptorFlags::LONG_MODE) bits must be set, while the
121/// [`DEFAULT_SIZE`](DescriptorFlags::DEFAULT_SIZE) bit must be unset.
122///
123/// The [`DPL_RING_3`](DescriptorFlags::DPL_RING_3) field can be used to change
124/// privilege level. The [`PRESENT`](DescriptorFlags::PRESENT) bit can be used
125/// to make a segment present or not present.
126///
127/// All other fields (like the segment base and limit) are ignored by the
128/// processor and setting them has no effect.
129#[derive(Debug)]
130pub struct CS;
131
132/// Stack Segment
133///
134/// Entirely unused in 64-bit mode; setting the segment register does nothing.
135/// However, in ring 3, the SS register still has to point to a valid
136/// [`Descriptor`] (it cannot be zero). This
137/// means a user-mode read/write segment descriptor must be present in the GDT.
138///
139/// This register is also set by the `syscall`/`sysret` and
140/// `sysenter`/`sysexit` instructions (even on 64-bit transitions). This is to
141/// maintain symmetry with 32-bit transitions where setting SS actually will
142/// actually have an effect.
143#[derive(Debug)]
144pub struct SS;
145
146/// Data Segment
147///
148/// Entirely unused in 64-bit mode; setting the segment register does nothing.
149#[derive(Debug)]
150pub struct DS;
151
152/// ES Segment
153///
154/// Entirely unused in 64-bit mode; setting the segment register does nothing.
155#[derive(Debug)]
156pub struct ES;
157
158/// FS Segment
159///
160/// Only base is used in 64-bit mode, see [`Segment64`]. This is often used in
161/// user-mode for Thread-Local Storage (TLS).
162#[derive(Debug)]
163pub struct FS;
164
165/// GS Segment
166///
167/// Only base is used in 64-bit mode, see [`Segment64`]. In kernel-mode, the GS
168/// base often points to a per-cpu kernel data structure.
169#[derive(Debug)]
170pub struct GS;