x86/bits64/
segmentation.rs1#[allow(unused_imports)]
2use crate::segmentation::SegmentSelector;
3use crate::segmentation::{
4 BuildDescriptor, Descriptor, DescriptorBuilder, DescriptorType, GateDescriptorBuilder,
5 LdtDescriptorBuilder, SystemDescriptorTypes64,
6};
7
8#[cfg(target_arch = "x86_64")]
9use core::arch::asm;
10
11#[derive(Copy, Clone, Debug, Default)]
16#[repr(C, packed)]
17pub struct Descriptor64 {
18 desc32: Descriptor,
19 lower: u32,
20 upper: u32,
21}
22
23impl Descriptor64 {
24 pub const NULL: Descriptor64 = Descriptor64 {
25 desc32: Descriptor::NULL,
26 lower: 0,
27 upper: 0,
28 };
29
30 pub(crate) fn apply_builder_settings(&mut self, builder: &DescriptorBuilder) {
31 self.desc32.apply_builder_settings(builder);
32 if let Some((base, limit)) = builder.base_limit {
33 self.set_base_limit(base, limit)
34 }
35 if let Some((selector, offset)) = builder.selector_offset {
36 self.set_selector_offset(selector, offset)
37 }
38 }
39
40 pub fn set_base_limit(&mut self, base: u64, limit: u64) {
43 self.desc32.set_base_limit(base as u32, limit as u32);
44 self.lower = (base >> 32) as u32;
45 }
46
47 pub fn set_selector_offset(&mut self, selector: SegmentSelector, offset: u64) {
50 self.desc32.set_selector_offset(selector, offset as u32);
51 self.lower = (offset >> 32) as u32;
52 }
53
54 pub fn set_ist(&mut self, index: u8) {
58 assert!(index <= 0b111);
59 self.desc32.upper |= index as u32;
60 }
61}
62
63impl GateDescriptorBuilder<u64> for DescriptorBuilder {
64 fn tss_descriptor(base: u64, limit: u64, available: bool) -> DescriptorBuilder {
65 let typ = if available {
66 DescriptorType::System64(SystemDescriptorTypes64::TssAvailable)
67 } else {
68 DescriptorType::System64(SystemDescriptorTypes64::TssBusy)
69 };
70
71 DescriptorBuilder::with_base_limit(base, limit).set_type(typ)
72 }
73
74 fn call_gate_descriptor(selector: SegmentSelector, offset: u64) -> DescriptorBuilder {
75 DescriptorBuilder::with_selector_offset(selector, offset)
76 .set_type(DescriptorType::System64(SystemDescriptorTypes64::CallGate))
77 }
78
79 fn interrupt_descriptor(selector: SegmentSelector, offset: u64) -> DescriptorBuilder {
80 DescriptorBuilder::with_selector_offset(selector, offset).set_type(
81 DescriptorType::System64(SystemDescriptorTypes64::InterruptGate),
82 )
83 }
84
85 fn trap_gate_descriptor(selector: SegmentSelector, offset: u64) -> DescriptorBuilder {
86 DescriptorBuilder::with_selector_offset(selector, offset)
87 .set_type(DescriptorType::System64(SystemDescriptorTypes64::TrapGate))
88 }
89}
90
91impl LdtDescriptorBuilder<u64> for DescriptorBuilder {
92 fn ldt_descriptor(base: u64, limit: u64) -> DescriptorBuilder {
93 DescriptorBuilder::with_base_limit(base, limit)
94 .set_type(DescriptorType::System64(SystemDescriptorTypes64::LDT))
95 }
96}
97
98impl BuildDescriptor<Descriptor64> for DescriptorBuilder {
99 fn finish(&self) -> Descriptor64 {
100 let mut desc: Descriptor64 = Default::default();
101 desc.apply_builder_settings(self);
102
103 let typ = match self.typ {
104 Some(DescriptorType::System64(typ)) => {
105 assert!(!self.l);
106 if typ == SystemDescriptorTypes64::LDT
107 || typ == SystemDescriptorTypes64::TssAvailable
108 || typ == SystemDescriptorTypes64::TssBusy
109 {
110 assert!(!self.db);
111 }
112
113 if typ == SystemDescriptorTypes64::InterruptGate {
114 desc.set_ist(self.ist);
115 }
116
117 typ as u8
118 }
119 Some(DescriptorType::System32(_typ)) => {
120 panic!("Can't build a 64-bit version of this type.")
121 }
122 Some(DescriptorType::Data(_typ)) => {
123 panic!("Can't build a 64-bit version of this type.")
124 }
125 Some(DescriptorType::Code(_typ)) => {
126 panic!("Can't build a 64-bit version of this type.")
127 }
128 None => unreachable!("Type not set, this is a library bug in x86."),
129 };
130
131 desc.desc32.set_type(typ);
132 desc
133 }
134}
135
136#[cfg(target_arch = "x86_64")]
146pub unsafe fn load_cs(sel: SegmentSelector) {
147 asm!("pushq {0}; \
148 leaq 1f(%rip), %rax; \
149 pushq %rax; \
150 lretq; \
151 1:", in(reg) sel.bits() as usize, out("rax") _, options(att_syntax));
152}
153
154#[cfg(target_arch = "x86_64")]
159pub unsafe fn wrgsbase(base: u64) {
160 asm!("wrgsbase {0}", in(reg) base, options(att_syntax));
161}
162
163#[cfg(target_arch = "x86_64")]
168pub unsafe fn wrfsbase(base: u64) {
169 asm!("wrfsbase {0}", in(reg) base, options(att_syntax));
170}
171
172#[cfg(target_arch = "x86_64")]
177pub unsafe fn rdgsbase() -> u64 {
178 let gs_base: u64;
179 asm!("rdgsbase {0}", out(reg) gs_base, options(att_syntax));
180 gs_base
181}
182
183#[cfg(target_arch = "x86_64")]
188pub unsafe fn rdfsbase() -> u64 {
189 let fs_base: u64;
190 asm!("rdfsbase {0}", out(reg) fs_base, options(att_syntax));
191 fs_base
192}
193
194#[cfg(target_arch = "x86_64")]
200#[macro_export]
201macro_rules! fs_deref {
202 ($offset:expr) => {{
203 let fs: u64;
204 core::arch::asm!("movq %fs:{offset}, {result}",
205 offset = const ($offset),
206 result = out(reg) fs,
207 options(att_syntax)
208 );
209 fs
210 }};
211}
212
213#[cfg(target_arch = "x86_64")]
214pub use fs_deref;
215
216#[cfg(target_arch = "x86_64")]
222#[macro_export]
223macro_rules! gs_deref {
224 ($offset:expr) => {{
225 let gs: u64;
226 core::arch::asm!("movq %gs:{offset}, {result}",
227 offset = const ($offset),
228 result = out(reg) gs,
229 options(att_syntax)
230 );
231 gs
232 }};
233}
234
235#[cfg(target_arch = "x86_64")]
236pub use gs_deref;
237
238#[cfg(target_arch = "x86_64")]
248pub unsafe fn swapgs() {
249 asm!("swapgs");
250}