/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 | } |