x86_64/registers/
control.rs

1//! Functions to read and write control registers.
2
3pub use super::model_specific::{Efer, EferFlags};
4use bitflags::bitflags;
5
6/// Various control flags modifying the basic operation of the CPU.
7#[derive(Debug)]
8pub struct Cr0;
9
10bitflags! {
11    /// Configuration flags of the [`Cr0`] register.
12    #[repr(transparent)]
13    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
14    pub struct Cr0Flags: u64 {
15        /// Enables protected mode.
16        const PROTECTED_MODE_ENABLE = 1;
17        /// Enables monitoring of the coprocessor, typical for x87 instructions.
18        ///
19        /// Controls (together with the [`TASK_SWITCHED`](Cr0Flags::TASK_SWITCHED)
20        /// flag) whether a `wait` or `fwait` instruction should cause an `#NE` exception.
21        const MONITOR_COPROCESSOR = 1 << 1;
22        /// Force all x87 and MMX instructions to cause an `#NE` exception.
23        const EMULATE_COPROCESSOR = 1 << 2;
24        /// Automatically set to 1 on _hardware_ task switch.
25        ///
26        /// This flags allows lazily saving x87/MMX/SSE instructions on hardware context switches.
27        const TASK_SWITCHED = 1 << 3;
28        /// Indicates support of 387DX math coprocessor instructions.
29        ///
30        /// Always set on all recent x86 processors, cannot be cleared.
31        const EXTENSION_TYPE = 1 << 4;
32        /// Enables the native (internal) error reporting mechanism for x87 FPU errors.
33        const NUMERIC_ERROR = 1 << 5;
34        /// Controls whether supervisor-level writes to read-only pages are inhibited.
35        ///
36        /// When set, it is not possible to write to read-only pages from ring 0.
37        const WRITE_PROTECT = 1 << 16;
38        /// Enables automatic usermode alignment checking if [`RFlags::ALIGNMENT_CHECK`] is also set.
39        const ALIGNMENT_MASK = 1 << 18;
40        /// Ignored, should always be unset.
41        ///
42        /// Must be unset if [`CACHE_DISABLE`](Cr0Flags::CACHE_DISABLE) is unset.
43        /// Older CPUs used this to control write-back/write-through cache strategy.
44        const NOT_WRITE_THROUGH = 1 << 29;
45        /// Disables some processor caches, specifics are model-dependent.
46        const CACHE_DISABLE = 1 << 30;
47        /// Enables paging.
48        ///
49        /// If this bit is set, [`PROTECTED_MODE_ENABLE`](Cr0Flags::PROTECTED_MODE_ENABLE) must be set.
50        const PAGING = 1 << 31;
51    }
52}
53
54/// Contains the Page Fault Linear Address (PFLA).
55///
56/// When a page fault occurs, the CPU sets this register to the faulting virtual address.
57#[derive(Debug)]
58pub struct Cr2;
59
60/// Contains the physical address of the highest-level page table.
61#[derive(Debug)]
62pub struct Cr3;
63
64bitflags! {
65    /// Controls cache settings for the highest-level page table.
66    ///
67    /// Unused if paging is disabled or if [`PCID`](Cr4Flags::PCID) is enabled.
68    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
69    pub struct Cr3Flags: u64 {
70        /// Use a writethrough cache policy for the table (otherwise a writeback policy is used).
71        const PAGE_LEVEL_WRITETHROUGH = 1 << 3;
72        /// Disable caching for the table.
73        const PAGE_LEVEL_CACHE_DISABLE = 1 << 4;
74    }
75}
76
77/// Contains various control flags that enable architectural extensions, and
78/// indicate support for specific processor capabilities.
79#[derive(Debug)]
80pub struct Cr4;
81
82bitflags! {
83    /// Configuration flags of the [`Cr4`] register.
84    #[repr(transparent)]
85    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
86    pub struct Cr4Flags: u64 {
87        /// Enables hardware-supported performance enhancements for software running in
88        /// virtual-8086 mode.
89        const VIRTUAL_8086_MODE_EXTENSIONS = 1;
90        /// Enables support for protected-mode virtual interrupts.
91        const PROTECTED_MODE_VIRTUAL_INTERRUPTS = 1 << 1;
92        /// When set, only privilege-level 0 can execute the `RDTSC` or `RDTSCP` instructions.
93        const TIMESTAMP_DISABLE = 1 << 2;
94        /// Enables I/O breakpoint capability and enforces treatment of `DR4` and `DR5` registers
95        /// as reserved.
96        const DEBUGGING_EXTENSIONS = 1 << 3;
97        /// Enables the use of 4MB physical frames; ignored if
98        /// [`PHYSICAL_ADDRESS_EXTENSION`](Cr4Flags::PHYSICAL_ADDRESS_EXTENSION)
99        /// is set (so always ignored in long mode).
100        const PAGE_SIZE_EXTENSION = 1 << 4;
101        /// Enables physical address extensions and 2MB physical frames. Required in long mode.
102        const PHYSICAL_ADDRESS_EXTENSION = 1 << 5;
103        /// Enables the machine-check exception mechanism.
104        const MACHINE_CHECK_EXCEPTION = 1 << 6;
105        /// Enables the global page feature, allowing some page translations to
106        /// be marked as global (see [`PageTableFlags::GLOBAL`]).
107        const PAGE_GLOBAL = 1 << 7;
108        /// Allows software running at any privilege level to use the `RDPMC` instruction.
109        const PERFORMANCE_MONITOR_COUNTER = 1 << 8;
110        /// Enables the use of legacy SSE instructions; allows using `FXSAVE`/`FXRSTOR` for saving
111        /// processor state of 128-bit media instructions.
112        const OSFXSR = 1 << 9;
113        /// Enables the SIMD floating-point exception (`#XF`) for handling unmasked 256-bit and
114        /// 128-bit media floating-point errors.
115        const OSXMMEXCPT_ENABLE = 1 << 10;
116        /// Prevents the execution of the `SGDT`, `SIDT`, `SLDT`, `SMSW`, and `STR` instructions by
117        /// user-mode software.
118        const USER_MODE_INSTRUCTION_PREVENTION = 1 << 11;
119        /// Enables 5-level paging on supported CPUs (Intel Only).
120        const L5_PAGING = 1 << 12;
121        /// Enables VMX instructions (Intel Only).
122        const VIRTUAL_MACHINE_EXTENSIONS = 1 << 13;
123        /// Enables SMX instructions (Intel Only).
124        const SAFER_MODE_EXTENSIONS = 1 << 14;
125        /// Enables software running in 64-bit mode at any privilege level to read and write
126        /// the FS.base and GS.base hidden segment register state.
127        const FSGSBASE = 1 << 16;
128        /// Enables process-context identifiers (PCIDs).
129        const PCID = 1 << 17;
130        /// Enables extended processor state management instructions, including `XGETBV` and `XSAVE`.
131        const OSXSAVE = 1 << 18;
132        /// Enables the Key Locker feature (Intel Only).
133        ///
134        /// This enables creation and use of opaque AES key handles; see the
135        /// [Intel Key Locker Specification](https://software.intel.com/content/www/us/en/develop/download/intel-key-locker-specification.html)
136        /// for more information.
137        const KEY_LOCKER = 1 << 19;
138        /// Prevents the execution of instructions that reside in pages accessible by user-mode
139        /// software when the processor is in supervisor-mode.
140        const SUPERVISOR_MODE_EXECUTION_PROTECTION = 1 << 20;
141        /// Enables restrictions for supervisor-mode software when reading data from user-mode
142        /// pages.
143        const SUPERVISOR_MODE_ACCESS_PREVENTION = 1 << 21;
144        /// Enables protection keys for user-mode pages.
145        ///
146        /// Also enables access to the PKRU register (via the `RDPKRU`/`WRPKRU`
147        /// instructions) to set user-mode protection key access controls.
148        const PROTECTION_KEY_USER = 1 << 22;
149        /// Enables Control-flow Enforcement Technology (CET)
150        ///
151        /// This enables the shadow stack feature, ensuring return addresses read
152        /// via `RET` and `IRET` have not been corrupted.
153        const CONTROL_FLOW_ENFORCEMENT = 1 << 23;
154        /// Enables protection keys for supervisor-mode pages (Intel Only).
155        ///
156        /// Also enables the `IA32_PKRS` MSR to set supervisor-mode protection
157        /// key access controls.
158        const PROTECTION_KEY_SUPERVISOR = 1 << 24;
159    }
160}
161
162/// Contains the task priority.
163#[derive(Debug)]
164pub struct Cr8;
165
166/// A priority class for an interrupt. Loading CR8 with a priority class blocks
167/// all interrupts of that class or lower. Note that 0 is not a priority class,
168/// if CR8 contains 0, all interrupts are enabled regardless of their priority
169/// class.
170#[derive(Debug)]
171pub enum PriorityClass {
172    // 0 is not a valid priority class, 1 is the first valid class
173    /// Priority class 1
174    PriorityClass1 = 1,
175    /// Priority class 2
176    PriorityClass2,
177    /// Priority class 3
178    PriorityClass3,
179    /// Priority class 4
180    PriorityClass4,
181    /// Priority class 5
182    PriorityClass5,
183    /// Priority class 6
184    PriorityClass6,
185    /// Priority class 7
186    PriorityClass7,
187    /// Priority class 8
188    PriorityClass8,
189    /// Priority class 9
190    PriorityClass9,
191    /// Priority class 10
192    PriorityClass10,
193    /// Priority class 11
194    PriorityClass11,
195    /// Priority class 12
196    PriorityClass12,
197    /// Priority class 13
198    PriorityClass13,
199    /// Priority class 14
200    PriorityClass14,
201    /// Priority class 15
202    PriorityClass15,
203}
204
205impl PriorityClass {
206    /// Convert a number into a priority class
207    pub const fn new(priority_class: u8) -> Option<Self> {
208        Some(match priority_class {
209            1 => Self::PriorityClass1,
210            2 => Self::PriorityClass2,
211            3 => Self::PriorityClass3,
212            4 => Self::PriorityClass4,
213            5 => Self::PriorityClass5,
214            6 => Self::PriorityClass6,
215            7 => Self::PriorityClass7,
216            8 => Self::PriorityClass8,
217            9 => Self::PriorityClass9,
218            10 => Self::PriorityClass10,
219            11 => Self::PriorityClass11,
220            12 => Self::PriorityClass12,
221            13 => Self::PriorityClass13,
222            14 => Self::PriorityClass14,
223            15 => Self::PriorityClass15,
224            _ => return None,
225        })
226    }
227}
228
229#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
230mod x86_64 {
231    use super::*;
232    use crate::{
233        addr::VirtAddrNotValid, instructions::tlb::Pcid, structures::paging::PhysFrame, PhysAddr,
234        VirtAddr,
235    };
236    use core::arch::asm;
237
238    impl Cr0 {
239        /// Read the current set of CR0 flags.
240        #[inline]
241        pub fn read() -> Cr0Flags {
242            Cr0Flags::from_bits_truncate(Self::read_raw())
243        }
244
245        /// Read the current raw CR0 value.
246        #[inline]
247        pub fn read_raw() -> u64 {
248            let value: u64;
249
250            unsafe {
251                asm!("mov {}, cr0", out(reg) value, options(nomem, nostack, preserves_flags));
252            }
253
254            value
255        }
256
257        /// Write CR0 flags.
258        ///
259        /// Preserves the value of reserved fields.
260        ///
261        /// ## Safety
262        ///
263        /// This function is unsafe because it's possible to violate memory
264        /// safety through it, e.g. by disabling paging.
265        #[inline]
266        pub unsafe fn write(flags: Cr0Flags) {
267            let old_value = Self::read_raw();
268            let reserved = old_value & !(Cr0Flags::all().bits());
269            let new_value = reserved | flags.bits();
270
271            unsafe {
272                Self::write_raw(new_value);
273            }
274        }
275
276        /// Write raw CR0 flags.
277        ///
278        /// Does _not_ preserve any values, including reserved fields.
279        ///
280        /// ## Safety
281        ///
282        /// This function is unsafe because it's possible to violate memory
283        /// safety through it, e.g. by disabling paging.
284        #[inline]
285        pub unsafe fn write_raw(value: u64) {
286            unsafe {
287                asm!("mov cr0, {}", in(reg) value, options(nostack, preserves_flags));
288            }
289        }
290
291        /// Updates CR0 flags.
292        ///
293        /// Preserves the value of reserved fields.
294        ///
295        /// ## Safety
296        ///
297        /// This function is unsafe because it's possible to violate memory
298        /// safety through it, e.g. by disabling paging.
299        #[inline]
300        pub unsafe fn update<F>(f: F)
301        where
302            F: FnOnce(&mut Cr0Flags),
303        {
304            let mut flags = Self::read();
305            f(&mut flags);
306            unsafe {
307                Self::write(flags);
308            }
309        }
310    }
311
312    impl Cr2 {
313        /// Read the current page fault linear address from the CR2 register.
314        ///
315        /// # Errors
316        ///
317        /// This method returns a [`VirtAddrNotValid`] error if the CR2 register contains a
318        /// non-canonical address. Call [`Cr2::read_raw`] to handle such cases.
319        #[inline]
320        pub fn read() -> Result<VirtAddr, VirtAddrNotValid> {
321            VirtAddr::try_new(Self::read_raw())
322        }
323
324        /// Read the current page fault linear address from the CR2 register as a raw `u64`.
325        #[inline]
326        pub fn read_raw() -> u64 {
327            let value: u64;
328
329            unsafe {
330                asm!("mov {}, cr2", out(reg) value, options(nomem, nostack, preserves_flags));
331            }
332
333            value
334        }
335    }
336
337    impl Cr3 {
338        /// Read the current P4 table address from the CR3 register.
339        #[inline]
340        pub fn read() -> (PhysFrame, Cr3Flags) {
341            let (frame, value) = Cr3::read_raw();
342            let flags = Cr3Flags::from_bits_truncate(value.into());
343            (frame, flags)
344        }
345
346        /// Read the current P4 table address from the CR3 register
347        #[inline]
348        pub fn read_raw() -> (PhysFrame, u16) {
349            let value: u64;
350
351            unsafe {
352                asm!("mov {}, cr3", out(reg) value, options(nomem, nostack, preserves_flags));
353            }
354
355            let addr = PhysAddr::new(value & 0x_000f_ffff_ffff_f000);
356            let frame = PhysFrame::containing_address(addr);
357            (frame, (value & 0xFFF) as u16)
358        }
359
360        /// Read the current P4 table address from the CR3 register along with PCID.
361        /// The correct functioning of this requires CR4.PCIDE = 1.
362        /// See [`Cr4Flags::PCID`]
363        #[inline]
364        pub fn read_pcid() -> (PhysFrame, Pcid) {
365            let (frame, value) = Cr3::read_raw();
366            (frame, Pcid::new(value).unwrap())
367        }
368
369        /// Write a new P4 table address into the CR3 register.
370        ///
371        /// ## Safety
372        ///
373        /// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by
374        /// changing the page mapping.
375        #[inline]
376        pub unsafe fn write(frame: PhysFrame, flags: Cr3Flags) {
377            unsafe {
378                Cr3::write_raw_impl(false, frame, flags.bits() as u16);
379            }
380        }
381
382        /// Write a new P4 table address into the CR3 register.
383        ///
384        /// ## Safety
385        ///
386        /// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by
387        /// changing the page mapping.
388        /// [`Cr4Flags::PCID`] must be set before calling this method.
389        #[inline]
390        pub unsafe fn write_pcid(frame: PhysFrame, pcid: Pcid) {
391            unsafe {
392                Cr3::write_raw_impl(false, frame, pcid.value());
393            }
394        }
395
396        /// Write a new P4 table address into the CR3 register without flushing existing TLB entries for
397        /// the PCID.
398        ///
399        /// ## Safety
400        ///
401        /// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by
402        /// changing the page mapping.
403        /// [`Cr4Flags::PCID`] must be set before calling this method.
404        #[inline]
405        pub unsafe fn write_pcid_no_flush(frame: PhysFrame, pcid: Pcid) {
406            unsafe {
407                Cr3::write_raw_impl(true, frame, pcid.value());
408            }
409        }
410
411        /// Write a new P4 table address into the CR3 register.
412        ///
413        /// ## Safety
414        ///
415        /// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by
416        /// changing the page mapping.
417        #[inline]
418        pub unsafe fn write_raw(frame: PhysFrame, val: u16) {
419            unsafe { Self::write_raw_impl(false, frame, val) }
420        }
421
422        #[inline]
423        unsafe fn write_raw_impl(top_bit: bool, frame: PhysFrame, val: u16) {
424            let addr = frame.start_address();
425            let value = ((top_bit as u64) << 63) | addr.as_u64() | val as u64;
426
427            unsafe {
428                asm!("mov cr3, {}", in(reg) value, options(nostack, preserves_flags));
429            }
430        }
431
432        /// Update the P4 table address in the CR3 register.
433        ///
434        /// ## Safety
435        ///
436        /// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by
437        /// changing the page mapping.
438        #[inline]
439        pub unsafe fn update<F>(f: F)
440        where
441            F: FnOnce(&mut PhysFrame, &mut Cr3Flags),
442        {
443            let (mut frame, mut flags) = Self::read();
444            f(&mut frame, &mut flags);
445            unsafe {
446                Self::write(frame, flags);
447            }
448        }
449
450        /// Updates the P4 table address in the CR3 register.
451        ///
452        /// ## Safety
453        ///
454        /// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by
455        /// changing the page mapping.
456        /// [`Cr4Flags::PCID`] must be set before calling this method.
457        #[inline]
458        pub unsafe fn update_pcid<F>(f: F)
459        where
460            F: FnOnce(&mut PhysFrame, &mut Pcid),
461        {
462            let (mut frame, mut pcid) = Self::read_pcid();
463            f(&mut frame, &mut pcid);
464            unsafe {
465                Self::write_pcid(frame, pcid);
466            }
467        }
468
469        /// Updates the P4 table address in the CR3 register without flushing existing TLB entries for
470        /// the PCID.
471        ///
472        /// ## Safety
473        ///
474        /// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by
475        /// changing the page mapping.
476        /// [`Cr4Flags::PCID`] must be set before calling this method.
477        #[inline]
478        pub unsafe fn update_pcid_no_flush<F>(f: F)
479        where
480            F: FnOnce(&mut PhysFrame, &mut Pcid),
481        {
482            let (mut frame, mut pcid) = Self::read_pcid();
483            f(&mut frame, &mut pcid);
484            unsafe {
485                Self::write_pcid_no_flush(frame, pcid);
486            }
487        }
488    }
489
490    impl Cr4 {
491        /// Read the current set of CR4 flags.
492        #[inline]
493        pub fn read() -> Cr4Flags {
494            Cr4Flags::from_bits_truncate(Self::read_raw())
495        }
496
497        /// Read the current raw CR4 value.
498        #[inline]
499        pub fn read_raw() -> u64 {
500            let value: u64;
501
502            unsafe {
503                asm!("mov {}, cr4", out(reg) value, options(nomem, nostack, preserves_flags));
504            }
505
506            value
507        }
508
509        /// Write CR4 flags.
510        ///
511        /// Preserves the value of reserved fields.
512        ///
513        /// ## Safety
514        ///
515        /// This function is unsafe because it's possible to violate memory
516        /// safety through it, e.g. by overwriting the physical address extension
517        /// flag.
518        #[inline]
519        pub unsafe fn write(flags: Cr4Flags) {
520            let old_value = Self::read_raw();
521            let reserved = old_value & !(Cr4Flags::all().bits());
522            let new_value = reserved | flags.bits();
523
524            unsafe {
525                Self::write_raw(new_value);
526            }
527        }
528
529        /// Write raw CR4 flags.
530        ///
531        /// Does _not_ preserve any values, including reserved fields.
532        ///
533        /// ## Safety
534        ///
535        /// This function is unsafe because it's possible to violate memory
536        /// safety through it, e.g. by overwriting the physical address extension
537        /// flag.
538        #[inline]
539        pub unsafe fn write_raw(value: u64) {
540            unsafe {
541                asm!("mov cr4, {}", in(reg) value, options(nostack, preserves_flags));
542            }
543        }
544
545        /// Updates CR4 flags.
546        ///
547        /// Preserves the value of reserved fields.
548        ///
549        /// ## Safety
550        ///
551        /// This function is unsafe because it's possible to violate memory
552        /// safety through it, e.g. by overwriting the physical address extension
553        /// flag.
554        #[inline]
555        pub unsafe fn update<F>(f: F)
556        where
557            F: FnOnce(&mut Cr4Flags),
558        {
559            let mut flags = Self::read();
560            f(&mut flags);
561            unsafe {
562                Self::write(flags);
563            }
564        }
565    }
566
567    impl Cr8 {
568        /// Read the current priority class in CR8.
569        #[inline]
570        pub fn read() -> Option<PriorityClass> {
571            PriorityClass::new(Self::read_raw() as u8)
572        }
573
574        /// Read the current raw CR8 value.
575        #[inline]
576        pub fn read_raw() -> u64 {
577            let value: u64;
578
579            unsafe {
580                asm!("mov {}, cr8", out(reg) value, options(nomem, nostack, preserves_flags));
581            }
582
583            value
584        }
585
586        /// Write the priority class to CR8.
587        #[inline]
588        pub fn write(priority_class: Option<PriorityClass>) {
589            let value = priority_class.map_or(0, |pc| pc as u64);
590            Self::write_raw(value);
591        }
592
593        /// Write to CR8.
594        #[inline]
595        pub fn write_raw(value: u64) {
596            unsafe {
597                asm!("mov cr8, {}", in(reg) value, options(nomem, nostack, preserves_flags));
598            }
599        }
600
601        /// Updates the priority class in CR8.
602        #[inline]
603        pub fn update<F>(f: F)
604        where
605            F: FnOnce(&mut Option<PriorityClass>),
606        {
607            let mut priority_class = Self::read();
608            f(&mut priority_class);
609            Self::write(priority_class);
610        }
611    }
612}