abyss/x86_64/
mod.rs

1//! x86_64 specific
2
3pub mod interrupt;
4pub mod intrinsics;
5pub mod kernel_gs;
6pub mod msr;
7pub mod pio;
8pub mod power_control;
9pub mod segmentation;
10pub mod table;
11pub mod tss;
12
13use core::arch::asm;
14
15/// Privilege Levels.
16#[derive(Copy, Clone, Debug, Eq, PartialEq)]
17pub enum PrivilegeLevel {
18    Ring0 = 0,
19    Ring1 = 1,
20    Ring2 = 2,
21    Ring3 = 3,
22}
23
24bitflags::bitflags! {
25    /// rflags.
26    #[repr(transparent)]
27    pub struct Rflags: u64 {
28        /// Carry Flag
29        const CF = 1 << 0;
30        /// Must be 1.
31        const _1 = 1 << 1;
32        /// Parity Flag
33        const PF = 1 << 2;
34        /// Adjust Flag
35        const AF = 1 << 4;
36        /// Zero Flag
37        const ZF = 1 << 6;
38        /// Sign Flag
39        const SF = 1 << 7;
40        /// Trap Flag
41        const TF = 1 << 8;
42
43        /// Interrupt enable.
44        ///
45        /// Controls the response of the processor to maskable hardware
46        /// interrupt  requests (see also: Section 6.3.2, "Maskable
47        /// Hardware Interrupts"). The flag is set to respond to maskable
48        /// hardware interrupts; cleared to inhibit maskable hardware
49        /// interrupts. The IF flag does not affect the generation of exceptions
50        /// or nonmaskable interrupts (NMI interrupts). The CPL, IOPL, and the
51        /// state of the VME  flag in control register CR4 determine
52        /// whether the IF flag can be modified by the CLI, STI, POPF, POPFD,
53        /// and IRET.
54        const IF = 1 << 9;
55
56        /// Direction Flag
57        const DF = 1 << 10;
58        /// Overflow Flag
59        const OF = 1 << 11;
60
61        /// I/O privilege level field - bit 0
62        ///
63        /// Indicates the I/O privilege level (IOPL) of the currently
64        /// running program or task. The CPL of the currently running program or
65        /// task must be less than or equal to the IOPL to access the
66        /// I/O address space. The POPF and IRET instructions can modify this
67        /// field only when operating at a CPL of 0.
68        ///
69        /// The IOPL is also one of the mechanisms that controls the
70        /// modification of the IF flag and the handling of interrupts
71        /// in virtual-8086 mode when virtual mode extensions are in effect
72        /// (when CR4.VME = 1).
73        ///
74        /// See also: Chapter 18, "Input/Output," in
75        /// the Intel® 64 and IA-32 Architectures Software Developer’s Manual,
76        /// Volume 1.
77        const IOPL0 = 1 << 12;
78        /// I/O privilege level field - bit 1
79        ///
80        /// Indicates the I/O privilege level (IOPL) of the currently
81        /// running program or task. The CPL of the currently running program or
82        /// task must be less than or equal to the IOPL to access the
83        /// I/O address space. The POPF and IRET instructions can modify this
84        /// field only when operating at a CPL of 0.
85        /// The IOPL is also one of the mechanisms that controls the
86        /// modification of the IF flag and the handling of interrupts
87        /// in virtual-8086 mode when virtual mode extensions are in effect
88        /// (when CR4.VME = 1).
89        ///
90        /// See also: Chapter 18, "Input/Output," in the Intel® 64 and IA-32
91        /// Architectures Software Developer’s Manual, Volume 1.
92        const IOPL1 = 1 << 13;
93        /// Nested task
94        ///
95        /// Controls the chaining of interrupted and called tasks. The processor
96        /// sets this flag on calls to a task initiated with a CALL
97        /// instruction, an interrupt, or an exception. It examines and modifies
98        /// this flag on returns from a task initiated with the IRET
99        /// instruction. The flag can be explicitly set or cleared
100        /// with the POPF/POPFD instructions; however, changing to the state of
101        /// this flag can generate unexpected exceptions in application
102        /// programs.
103        ///
104        /// See also: Section 7.4, "Task Linking."
105        const NT = 1 << 14;
106        /// Resume
107        ///
108        /// Controls the processor’s response to instruction-breakpoint
109        /// conditions. When set, this flag temporarily disables debug
110        /// exceptions (#DB) from being generated for instruction breakpoints
111        /// (although other exception conditions can cause an exception to be
112        /// generated). When clear, instruction breakpoints will
113        /// generate debug exceptions.
114        ///
115        /// The primary function of the RF flag is to allow the restarting of an
116        /// instruction following a debug exception that was caused by
117        /// an instruction breakpoint condition. Here, debug software must set
118        /// this flag in the EFLAGS image on the stack just prior to
119        /// returning to the interrupted program with IRETD (to prevent the
120        /// instruction breakpoint from causing another debug exception). The
121        /// processor then automatically clears this flag after the
122        /// instruction returned to has been successfully executed, enabling
123        /// instruction breakpoint faults again.
124        ///
125        /// See also: Section 17.3.1.1, "Instruction-Breakpoint Exception
126        /// Condition."
127        const RF = 1 << 16;
128        /// Virtual-8086 mode
129        ///
130        /// Set to enable virtual-8086 mode; clear to return to protected mode.
131        ///
132        /// See also: Section 20.2.1, "Enabling Virtual-8086 Mode."
133        const VM = 1 << 17;
134        /// Alignment check or access control
135        ///
136        /// If the AM bit is set in the CR0 register, alignment
137        /// checking of user-mode data accesses is enabled if and only if this flag is 1. An alignment-check exception
138        /// is generated when reference is made to an unaligned operand, such as a word at an odd byte address or a
139        /// doubleword at an address which is not an integral multiple of four. Alignment-check exceptions are generated only in user mode (privilege level 3). Memory references that default to privilege level 0, such as
140        /// segment descriptor loads, do not generate this exception even when caused by instructions executed in
141        /// user-mode.
142        ///
143        /// The alignment-check exception can be used to check alignment of data. This is useful when exchanging
144        /// data with processors which require all data to be aligned. The alignment-check exception can also be used
145        /// by interpreters to flag some pointers as special by misaligning the pointer. This eliminates overhead of
146        /// checking each pointer and only handles the special pointer when used.
147        ///
148        /// If the SMAP bit is set in the CR4 register, explicit supervisor-mode data accesses to user-mode pages are
149        /// allowed if and only if this bit is 1. See Section 4.6, "Access Rights."
150        const AC = 1 << 18;
151        /// Virtual Interrupt
152        ///
153        /// Contains a virtual image of the IF flag. This flag is used in conjunction with
154        /// the VIP flag. The processor only recognizes the VIF flag when either the VME flag or the PVI flag in control
155        /// register CR4 is set and the IOPL is less than 3. (The VME flag enables the virtual-8086 mode extensions;
156        /// the PVI flag enables the protected-mode virtual interrupts.)
157        ///
158        /// See also: Section 20.3.3.5, "Method 6: Software Interrupt Handling," and Section 20.4, "Protected-Mode
159        /// Virtual Interrupts."
160        const VIF = 1 << 19;
161        /// Virtual interrupt pending
162        ///
163        /// Set by software to indicate that an interrupt is pending; cleared to
164        /// indicate that no interrupt is pending. This flag is used in conjunction with the VIF flag. The processor reads
165        /// this flag but never modifies it. The processor only recognizes the VIP flag when either the VME flag or the
166        /// PVI flag in control register CR4 is set and the IOPL is less than 3. The VME flag enables the virtual-8086
167        /// mode extensions; the PVI flag enables the protected-mode virtual interrupts.
168        ///
169        /// See Section 20.3.3.5, "Method 6: Software Interrupt Handling," and Section 20.4, "Protected-Mode Virtual
170        /// Interrupts."
171        const VIP = 1 << 20;
172        /// Identification.
173        ///
174        /// The ability of a program or procedure to set or clear this flag
175        /// indicates support for the CPUID instruction.
176        const ID = 1 << 21;
177    }
178}
179
180impl Rflags {
181    /// Read the current value.
182    #[inline(always)]
183    pub fn read() -> Self {
184        let ret: u64;
185        unsafe {
186            asm!(
187                "pushf",
188                "pop {0}",
189                lateout(reg) ret,
190            );
191            Self::from_bits_truncate(ret)
192        }
193    }
194}
195
196bitflags::bitflags! {
197    /// Cr0 Register.
198    #[repr(transparent)]
199    pub struct Cr0: u64 {
200        /// Protected mode enable.
201        const PE = 1 << 0;
202        /// Monitor co-processor.
203        const MP = 1 << 1;
204        /// Emulation.
205        const EM = 1 << 2;
206        /// Task switched.
207        const TS = 1 << 3;
208        /// Extension type.
209        const ET = 1 << 4;
210        /// Numeric error.
211        const NE = 1 << 5;
212        /// Write protect.
213        const WP = 1 << 16;
214        /// Alignment mask.
215        const AM = 1 << 18;
216        /// Not-write through.
217        const NW = 1 << 29;
218        /// Cache disable.
219        const CD = 1 << 30;
220        /// Paging.
221        const PG = 1 << 31;
222    }
223}
224
225impl Cr0 {
226    /// Read the current value.
227    #[inline(always)]
228    pub fn current() -> Self {
229        let ret: u64;
230        unsafe {
231            asm!("mov {}, cr0", lateout(reg) ret, options(nomem, nostack));
232            Self::from_bits_unchecked(ret)
233        }
234    }
235
236    /// Write the current value.
237    ///
238    /// # Safety
239    /// Write to system register is unsafe.
240    #[inline(always)]
241    pub unsafe fn apply(self) {
242        unsafe {
243            asm!("mov cr0, {}", in(reg) self.bits(), options(nomem, nostack));
244        }
245    }
246}
247
248/// ControlRegister2 Register.
249///
250/// Contains Page-Fault Linear Address.
251#[derive(Debug)]
252pub struct Cr2(u64);
253
254impl Cr2 {
255    /// Read the current value.
256    #[inline(always)]
257    pub fn current() -> Self {
258        let ret: u64;
259        unsafe {
260            asm!("mov {}, cr2", lateout(reg) ret, options(nomem, nostack));
261            Self(ret)
262        }
263    }
264
265    /// Cast into usize.
266    #[inline(always)]
267    pub const fn into_usize(self) -> usize {
268        self.0 as usize
269    }
270}
271
272/// ControlRegister3 Register. Contains Page-Table root.
273#[derive(Debug, PartialEq)]
274pub struct Cr3(pub u64);
275
276impl Cr3 {
277    /// Read the current value.
278    #[inline(always)]
279    pub fn current() -> Self {
280        let ret: u64;
281        unsafe {
282            asm!("mov {}, cr3", lateout(reg) ret, options(nomem, nostack));
283            Self(ret)
284        }
285    }
286
287    /// Cast into usize.
288    #[inline(always)]
289    pub const fn into_usize(self) -> usize {
290        self.0 as usize
291    }
292
293    /// Write the current value.
294    ///
295    /// # Safety
296    /// Write to system register is unsafe.
297    #[inline(always)]
298    pub unsafe fn apply(self) {
299        unsafe {
300            asm!("mov cr3, {}", in(reg) self.0, options(nomem, nostack));
301        }
302    }
303}
304
305bitflags::bitflags! {
306    /// Cr4 Register.
307    #[repr(transparent)]
308    pub struct Cr4: u64 {
309        /// Virtual 8086 mode extensions.
310        const VME = 1 << 0;
311        /// Protected mode virtual interrupts.
312        const PVI = 1 << 1;
313        /// Time stamp disable.
314        const TSD = 1 << 2;
315        /// Debugging extensions.
316        const DE = 1 << 3;
317        /// Page size extension.
318        const PSE = 1 << 4;
319        /// Physical address extension.
320        const PAE = 1 << 5;
321        /// Machine check exception.
322        const MCE = 1 << 6;
323        /// Page global enable.
324        const PGE = 1 << 7;
325        /// Performance monitoring counter enable.
326        const PCE = 1 << 8;
327        /// Os support for fxsave and fxrstor instructions.
328        const OSFXSR = 1 << 9;
329        /// Os support for unmasked simd floating point exceptions.
330        const OSXMMEXCPT = 1 << 10;
331        /// User mode instruction prevention (#GP on SGDT, SIDT, SLDT, SMSW, and STR instructions when CPL > 0).
332        const UMIP = 1 << 11;
333        /// Virtual machine extensions enable.
334        const VMXE = 1 << 13;
335        /// Safer mode extensions enable.
336        const SMXE = 1 << 14;
337        /// Pcid enable.
338        const PCIDE = 1 << 17;
339        /// Xsave and processor extended states enable.
340        const OSXSAVE = 1 << 18;
341        /// Supervisor mode executions protection enable.
342        const SMEP = 1 << 20;
343        /// Supervisor mode access protection enable.
344        const SMAP = 1 << 21;
345        /// Protection keys for user-mode pages enable.
346        const PKE = 1 << 22;
347        /// Control-flow-enforcement enable.
348        const CET = 1 << 23;
349        /// Protection keys for supervisor-mode pages enable.
350        const PKS = 1 << 24;
351    }
352}
353
354impl Cr4 {
355    /// Read the current value.
356    #[inline(always)]
357    pub fn current() -> Self {
358        let ret: u64;
359        unsafe {
360            asm!("mov {}, cr4", lateout(reg) ret, options(nomem, nostack));
361            Self::from_bits_unchecked(ret)
362        }
363    }
364
365    /// Read the current value.
366    ///
367    /// # Safety
368    /// Write to system register is unsafe.
369    #[inline(always)]
370    pub unsafe fn apply(self) {
371        unsafe {
372            asm!("mov cr4, {}", in(reg) self.bits(), options(nomem, nostack));
373        }
374    }
375}