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}