Coverage Report

Created: 2026-10-28 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/x86-0.47.0/src/bits64/segmentation.rs
Line
Count
Source
1
#[allow(unused_imports)]
2
use crate::segmentation::SegmentSelector;
3
use crate::segmentation::{
4
    BuildDescriptor, Descriptor, DescriptorBuilder, DescriptorType, GateDescriptorBuilder,
5
    LdtDescriptorBuilder, SystemDescriptorTypes64,
6
};
7
8
#[cfg(target_arch = "x86_64")]
9
use core::arch::asm;
10
11
/// Entry for IDT, GDT or LDT.
12
///
13
/// See Intel 3a, Section 3.4.5 "Segment Descriptors", and Section 3.5.2
14
/// "Segment Descriptor Tables in IA-32e Mode", especially Figure 3-8.
15
#[derive(Copy, Clone, Debug, Default)]
16
#[repr(C, packed)]
17
pub struct Descriptor64 {
18
    desc32: Descriptor,
19
    lower: u32,
20
    upper: u32,
21
}
22
23
impl Descriptor64 {
24
    pub const NULL: Descriptor64 = Descriptor64 {
25
        desc32: Descriptor::NULL,
26
        lower: 0,
27
        upper: 0,
28
    };
29
30
0
    pub(crate) fn apply_builder_settings(&mut self, builder: &DescriptorBuilder) {
31
0
        self.desc32.apply_builder_settings(builder);
32
0
        if let Some((base, limit)) = builder.base_limit {
33
0
            self.set_base_limit(base, limit)
34
0
        }
35
0
        if let Some((selector, offset)) = builder.selector_offset {
36
0
            self.set_selector_offset(selector, offset)
37
0
        }
38
0
    }
39
40
    /// Create a new segment, TSS or LDT descriptor
41
    /// by setting the three base and two limit fields.
42
0
    pub fn set_base_limit(&mut self, base: u64, limit: u64) {
43
0
        self.desc32.set_base_limit(base as u32, limit as u32);
44
0
        self.lower = (base >> 32) as u32;
45
0
    }
46
47
    /// Creates a new descriptor with selector and offset (for IDT Gate descriptors,
48
    /// e.g. Trap, Interrupts and Task gates)
49
0
    pub fn set_selector_offset(&mut self, selector: SegmentSelector, offset: u64) {
50
0
        self.desc32.set_selector_offset(selector, offset as u32);
51
0
        self.lower = (offset >> 32) as u32;
52
0
    }
53
54
    /// Sets the interrupt stack table index.
55
    /// The 3-bit IST index field that provides an offset into the IST section of the TSS.
56
    /// Using the IST mechanism, the processor loads the value pointed by an IST pointer into the RSP.
57
0
    pub fn set_ist(&mut self, index: u8) {
58
0
        assert!(index <= 0b111);
59
0
        self.desc32.upper |= index as u32;
60
0
    }
61
}
62
63
impl GateDescriptorBuilder<u64> for DescriptorBuilder {
64
0
    fn tss_descriptor(base: u64, limit: u64, available: bool) -> DescriptorBuilder {
65
0
        let typ = if available {
66
0
            DescriptorType::System64(SystemDescriptorTypes64::TssAvailable)
67
        } else {
68
0
            DescriptorType::System64(SystemDescriptorTypes64::TssBusy)
69
        };
70
71
0
        DescriptorBuilder::with_base_limit(base, limit).set_type(typ)
72
0
    }
73
74
0
    fn call_gate_descriptor(selector: SegmentSelector, offset: u64) -> DescriptorBuilder {
75
0
        DescriptorBuilder::with_selector_offset(selector, offset)
76
0
            .set_type(DescriptorType::System64(SystemDescriptorTypes64::CallGate))
77
0
    }
78
79
0
    fn interrupt_descriptor(selector: SegmentSelector, offset: u64) -> DescriptorBuilder {
80
0
        DescriptorBuilder::with_selector_offset(selector, offset).set_type(
81
0
            DescriptorType::System64(SystemDescriptorTypes64::InterruptGate),
82
        )
83
0
    }
84
85
0
    fn trap_gate_descriptor(selector: SegmentSelector, offset: u64) -> DescriptorBuilder {
86
0
        DescriptorBuilder::with_selector_offset(selector, offset)
87
0
            .set_type(DescriptorType::System64(SystemDescriptorTypes64::TrapGate))
88
0
    }
89
}
90
91
impl LdtDescriptorBuilder<u64> for DescriptorBuilder {
92
0
    fn ldt_descriptor(base: u64, limit: u64) -> DescriptorBuilder {
93
0
        DescriptorBuilder::with_base_limit(base, limit)
94
0
            .set_type(DescriptorType::System64(SystemDescriptorTypes64::LDT))
95
0
    }
96
}
97
98
impl BuildDescriptor<Descriptor64> for DescriptorBuilder {
99
0
    fn finish(&self) -> Descriptor64 {
100
0
        let mut desc: Descriptor64 = Default::default();
101
0
        desc.apply_builder_settings(self);
102
103
0
        let typ = match self.typ {
104
0
            Some(DescriptorType::System64(typ)) => {
105
0
                assert!(!self.l);
106
0
                if typ == SystemDescriptorTypes64::LDT
107
0
                    || typ == SystemDescriptorTypes64::TssAvailable
108
0
                    || typ == SystemDescriptorTypes64::TssBusy
109
                {
110
0
                    assert!(!self.db);
111
0
                }
112
113
0
                if typ == SystemDescriptorTypes64::InterruptGate {
114
0
                    desc.set_ist(self.ist);
115
0
                }
116
117
0
                typ as u8
118
            }
119
0
            Some(DescriptorType::System32(_typ)) => {
120
0
                panic!("Can't build a 64-bit version of this type.")
121
            }
122
0
            Some(DescriptorType::Data(_typ)) => {
123
0
                panic!("Can't build a 64-bit version of this type.")
124
            }
125
0
            Some(DescriptorType::Code(_typ)) => {
126
0
                panic!("Can't build a 64-bit version of this type.")
127
            }
128
0
            None => unreachable!("Type not set, this is a library bug in x86."),
129
        };
130
131
0
        desc.desc32.set_type(typ);
132
0
        desc
133
0
    }
134
}
135
136
/// Reload code segment register.
137
///
138
/// Note this is special since we can not directly move
139
/// to %cs. Instead we push the new segment selector
140
/// and return value on the stack and use lretq
141
/// to reload cs and continue at 1:.
142
///
143
/// # Safety
144
/// Can cause a GP-fault with a bad `sel` value.
145
#[cfg(target_arch = "x86_64")]
146
0
pub unsafe fn load_cs(sel: SegmentSelector) {
147
0
    asm!("pushq {0}; \
148
0
          leaq  1f(%rip), %rax; \
149
0
          pushq %rax; \
150
0
          lretq; \
151
0
          1:", in(reg) sel.bits() as usize, out("rax") _, options(att_syntax));
152
0
}
153
154
/// Write GS Segment Base
155
///
156
/// # Safety
157
/// Needs FSGSBASE-Enable Bit (bit 16 of CR4) set.
158
#[cfg(target_arch = "x86_64")]
159
0
pub unsafe fn wrgsbase(base: u64) {
160
0
    asm!("wrgsbase {0}", in(reg) base, options(att_syntax));
161
0
}
162
163
/// Write FS Segment Base
164
///
165
/// # Safety
166
/// Needs FSGSBASE-Enable Bit (bit 16 of CR4) set.
167
#[cfg(target_arch = "x86_64")]
168
0
pub unsafe fn wrfsbase(base: u64) {
169
0
    asm!("wrfsbase {0}", in(reg) base, options(att_syntax));
170
0
}
171
172
/// Read GS Segment Base
173
///
174
/// # Safety
175
/// Needs FSGSBASE-Enable Bit (bit 16 of CR4) set.
176
#[cfg(target_arch = "x86_64")]
177
0
pub unsafe fn rdgsbase() -> u64 {
178
    let gs_base: u64;
179
0
    asm!("rdgsbase {0}", out(reg) gs_base, options(att_syntax));
180
0
    gs_base
181
0
}
182
183
/// Read FS Segment Base
184
///
185
/// # Safety
186
/// Needs FSGSBASE-Enable Bit (bit 16 of CR4) set.
187
#[cfg(target_arch = "x86_64")]
188
0
pub unsafe fn rdfsbase() -> u64 {
189
    let fs_base: u64;
190
0
    asm!("rdfsbase {0}", out(reg) fs_base, options(att_syntax));
191
0
    fs_base
192
0
}
193
194
/// "Dereferences" the fs register at offset 0.
195
///
196
/// # Safety
197
/// fs needs to point to valid address.
198
#[cfg(target_arch = "x86_64")]
199
0
pub unsafe fn fs_deref() -> u64 {
200
    let fs: u64;
201
0
    asm!("movq %fs:0x0, {0}", out(reg) fs, options(att_syntax));
202
0
    fs
203
0
}
204
205
/// "Dereferences" the gs register at offset 0.
206
///
207
/// # Safety
208
/// gs needs to point to valid address.
209
#[cfg(target_arch = "x86_64")]
210
0
pub unsafe fn gs_deref() -> u64 {
211
    let gs: u64;
212
0
    asm!("movq %gs:0x0, {0}", out(reg) gs, options(att_syntax));
213
0
    gs
214
0
}
215
216
/// Swap the GS register.
217
///
218
/// Exchanges the current GS base register value with the value contained
219
/// in MSR address IA32_KERNEL_GS_BASE.
220
///
221
/// The SWAPGS instruction is available only in 64-bit mode.
222
///
223
/// # Safety
224
/// The SWAPGS instruction is a privileged instruction intended for use by system software.
225
#[cfg(target_arch = "x86_64")]
226
0
pub unsafe fn swapgs() {
227
0
    asm!("swapgs");
228
0
}