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}