diff --git a/src/registers/control.rs b/src/registers/control.rs index c09dd0d7e..a8f306e68 100644 --- a/src/registers/control.rs +++ b/src/registers/control.rs @@ -1,6 +1,8 @@ //! Functions to read and write control registers. pub use super::model_specific::{Efer, EferFlags}; +#[cfg(docsrs)] +use crate::{registers::rflags::RFlags, structures::paging::PageTableFlags}; use bitflags::bitflags; @@ -9,119 +11,149 @@ use bitflags::bitflags; pub struct Cr0; bitflags! { - /// Configuration flags of the Cr0 register. + /// Configuration flags of the [`Cr0`] register. pub struct Cr0Flags: u64 { /// Enables protected mode. const PROTECTED_MODE_ENABLE = 1; /// Enables monitoring of the coprocessor, typical for x87 instructions. /// - /// Controls together with the `TASK_SWITCHED` flag whether a `wait` or `fwait` - /// instruction should cause a device-not-available exception. + /// Controls (together with the [`TASK_SWITCHED`](Cr0Flags::TASK_SWITCHED) + /// flag) whether a `wait` or `fwait` instruction should cause an `#NE` exception. const MONITOR_COPROCESSOR = 1 << 1; - /// Force all x87 and MMX instructions to cause an exception. + /// Force all x87 and MMX instructions to cause an `#NE` exception. const EMULATE_COPROCESSOR = 1 << 2; /// Automatically set to 1 on _hardware_ task switch. /// /// This flags allows lazily saving x87/MMX/SSE instructions on hardware context switches. const TASK_SWITCHED = 1 << 3; - /// Enables the native error reporting mechanism for x87 FPU errors. + /// Indicates support of 387DX math coprocessor instructions. + /// + /// Always set on all recent x86 processors, cannot be cleared. + const EXTENSION_TYPE = 1 << 4; + /// Enables the native (internal) error reporting mechanism for x87 FPU errors. const NUMERIC_ERROR = 1 << 5; /// Controls whether supervisor-level writes to read-only pages are inhibited. /// /// When set, it is not possible to write to read-only pages from ring 0. const WRITE_PROTECT = 1 << 16; - /// Enables automatic alignment checking. + /// Enables automatic usermode alignment checking if [`RFlags::ALIGNMENT_CHECK`] is also set. const ALIGNMENT_MASK = 1 << 18; - /// Ignored. Used to control write-back/write-through cache strategy on older CPUs. + /// Ignored, should always be unset. + /// + /// Must be unset if [`CACHE_DISABLE`](Cr0Flags::CACHE_DISABLE) is unset. + /// Older CPUs used this to control write-back/write-through cache strategy. const NOT_WRITE_THROUGH = 1 << 29; - /// Disables internal caches (only for some cases). + /// Disables some processor caches, specifics are model-dependent. const CACHE_DISABLE = 1 << 30; - /// Enables page translation. + /// Enables paging. + /// + /// If this bit is set, [`PROTECTED_MODE_ENABLE`](Cr0Flags::PROTECTED_MODE_ENABLE) must be set. const PAGING = 1 << 31; } } /// Contains the Page Fault Linear Address (PFLA). /// -/// When page fault occurs, the CPU sets this register to the accessed address. +/// When a page fault occurs, the CPU sets this register to the faulting virtual address. #[derive(Debug)] pub struct Cr2; -/// Contains the physical address of the level 4 page table. +/// Contains the physical address of the highest-level page table. #[derive(Debug)] pub struct Cr3; bitflags! { - /// Controls cache settings for the level 4 page table. + /// Controls cache settings for the highest-level page table. + /// + /// Unused if paging is disabled or if [`PCID`](Cr4Flags::PCID) is enabled. pub struct Cr3Flags: u64 { - /// Use a writethrough cache policy for the P4 table (else a writeback policy is used). + /// Use a writethrough cache policy for the table (otherwise a writeback policy is used). const PAGE_LEVEL_WRITETHROUGH = 1 << 3; - /// Disable caching for the P4 table. + /// Disable caching for the table. const PAGE_LEVEL_CACHE_DISABLE = 1 << 4; } } -/// Various control flags modifying the basic operation of the CPU while in protected mode. -/// -/// Note: The documention for the individual fields is taken from the AMD64 and Intel x86_64 -/// manuals. +/// Contains various control flags that enable architectural extensions, and +/// indicate support for specific processor capabilities. #[derive(Debug)] pub struct Cr4; bitflags! { - /// Controls cache settings for the level 4 page table. + /// Configuration flags of the [`Cr4`] register. pub struct Cr4Flags: u64 { /// Enables hardware-supported performance enhancements for software running in /// virtual-8086 mode. const VIRTUAL_8086_MODE_EXTENSIONS = 1; /// Enables support for protected-mode virtual interrupts. const PROTECTED_MODE_VIRTUAL_INTERRUPTS = 1 << 1; - /// When set, only privilege-level 0 can execute the RDTSC or RDTSCP instructions. + /// When set, only privilege-level 0 can execute the `RDTSC` or `RDTSCP` instructions. const TIMESTAMP_DISABLE = 1 << 2; - /// Enables I/O breakpoint capability and enforces treatment of DR4 and DR5 registers + /// Enables I/O breakpoint capability and enforces treatment of `DR4` and `DR5` registers /// as reserved. const DEBUGGING_EXTENSIONS = 1 << 3; - /// Enables the use of 4MB physical frames; ignored in long mode. + /// Enables the use of 4MB physical frames; ignored if + /// [`PHYSICAL_ADDRESS_EXTENSION`](Cr4Flags::PHYSICAL_ADDRESS_EXTENSION) + /// is set (so always ignored in long mode). const PAGE_SIZE_EXTENSION = 1 << 4; - /// Enables physical address extension and 2MB physical frames; required in long mode. + /// Enables physical address extensions and 2MB physical frames. Required in long mode. const PHYSICAL_ADDRESS_EXTENSION = 1 << 5; /// Enables the machine-check exception mechanism. const MACHINE_CHECK_EXCEPTION = 1 << 6; - /// Enables the global-page mechanism, which allows to make page translations global - /// to all processes. + /// Enables the global page feature, allowing some page translations to + /// be marked as global (see [`PageTableFlags::GLOBAL`]). const PAGE_GLOBAL = 1 << 7; - /// Allows software running at any privilege level to use the RDPMC instruction. + /// Allows software running at any privilege level to use the `RDPMC` instruction. const PERFORMANCE_MONITOR_COUNTER = 1 << 8; - /// Enable the use of legacy SSE instructions; allows using FXSAVE/FXRSTOR for saving + /// Enables the use of legacy SSE instructions; allows using `FXSAVE`/`FXRSTOR` for saving /// processor state of 128-bit media instructions. const OSFXSR = 1 << 9; - /// Enables the SIMD floating-point exception (#XF) for handling unmasked 256-bit and + /// Enables the SIMD floating-point exception (`#XF`) for handling unmasked 256-bit and /// 128-bit media floating-point errors. const OSXMMEXCPT_ENABLE = 1 << 10; - /// Prevents the execution of the SGDT, SIDT, SLDT, SMSW, and STR instructions by + /// Prevents the execution of the `SGDT`, `SIDT`, `SLDT`, `SMSW`, and `STR` instructions by /// user-mode software. const USER_MODE_INSTRUCTION_PREVENTION = 1 << 11; - /// Enables 5-level paging on supported CPUs. + /// Enables 5-level paging on supported CPUs (Intel Only). const L5_PAGING = 1 << 12; - /// Enables VMX insturctions. + /// Enables VMX instructions (Intel Only). const VIRTUAL_MACHINE_EXTENSIONS = 1 << 13; - /// Enables SMX instructions. + /// Enables SMX instructions (Intel Only). const SAFER_MODE_EXTENSIONS = 1 << 14; /// Enables software running in 64-bit mode at any privilege level to read and write /// the FS.base and GS.base hidden segment register state. const FSGSBASE = 1 << 16; /// Enables process-context identifiers (PCIDs). const PCID = 1 << 17; - /// Enables extendet processor state management instructions, including XGETBV and XSAVE. + /// Enables extended processor state management instructions, including `XGETBV` and `XSAVE`. const OSXSAVE = 1 << 18; + /// Enables the Key Locker feature (Intel Only). + /// + /// This enables creation and use of opaque AES key handles; see the + /// [Intel Key Locker Specification](https://software.intel.com/content/www/us/en/develop/download/intel-key-locker-specification.html) + /// for more information. + const KEY_LOCKER = 1 << 19; /// Prevents the execution of instructions that reside in pages accessible by user-mode /// software when the processor is in supervisor-mode. const SUPERVISOR_MODE_EXECUTION_PROTECTION = 1 << 20; /// Enables restrictions for supervisor-mode software when reading data from user-mode /// pages. const SUPERVISOR_MODE_ACCESS_PREVENTION = 1 << 21; - /// Enables 4-level paging to associate each linear address with a protection key. + /// Enables protection keys for user-mode pages. + /// + /// Also enables access to the PKRU register (via the `RDPKRU`/`WRPKRU` + /// instructions) to set user-mode protection key access controls. const PROTECTION_KEY = 1 << 22; + /// Enables Control-flow Enforcement Technology (CET) + /// + /// This enables the shadow stack feature, ensuring return addresses read + /// via `RET` and `IRET` have not been corrupted. + const CONTROL_FLOW_ENFORCEMENT = 1 << 23; + /// Enables protection keys for supervisor-mode pages (Intel Only). + /// + /// Also enables the `IA32_PKRS` MSR to set supervisor-mode protection + /// key access controls. + const PROTECTION_KEY_SUPERVISOR = 1 << 24; } } diff --git a/src/registers/xcontrol.rs b/src/registers/xcontrol.rs index 8d2dfb789..8c4cb3cfa 100644 --- a/src/registers/xcontrol.rs +++ b/src/registers/xcontrol.rs @@ -7,19 +7,43 @@ pub struct XCr0; bitflags! { /// Configuration flags of the XCr0 register. + /// + /// For MPX, [`BNDREG`](XCr0Flags::BNDREG) and [`BNDCSR`](XCr0Flags::BNDCSR) must be set/unset simultaneously. + /// For AVX-512, [`OPMASK`](XCr0Flags::OPMASK), [`ZMM_HI256`](XCr0Flags::ZMM_HI256), and [`HI16_ZMM`](XCr0Flags::HI16_ZMM) must be set/unset simultaneously. pub struct XCr0Flags: u64 { - /// Enables x87 FPU + /// Enables using the x87 FPU state + /// with `XSAVE`/`XRSTOR`. + /// + /// Must be set. const X87 = 1; - /// Enables 128-bit (legacy) SSE - /// Must be set to enable AVX and YMM + /// Enables using MXCSR and the XMM registers + /// with `XSAVE`/`XRSTOR`. + /// + /// Must be set if [`YMM`](XCr0Flags::YMM) is set. const SSE = 1<<1; - /// Enables 256-bit SSE - /// Must be set to enable AVX + /// Enables AVX instructions and using the upper halves of the YMM registers + /// with `XSAVE`/`XRSTOR`. const YMM = 1<<2; - /// When set, PKRU state management is supported by - /// ZSAVE/XRSTOR + /// Enables MPX instructions and using the BND0-BND3 bound registers + /// with `XSAVE`/`XRSTOR` (Intel Only). + const BNDREG = 1 << 3; + /// Enables MPX instructions and using the BNDCFGU and BNDSTATUS registers + /// with `XSAVE`/`XRSTOR` (Intel Only). + const BNDCSR = 1 << 4; + /// Enables AVX-512 instructions and using the K0-K7 mask registers + /// with `XSAVE`/`XRSTOR` (Intel Only). + const OPMASK = 1 << 5; + /// Enables AVX-512 instructions and using the upper halves of the lower ZMM registers + /// with `XSAVE`/`XRSTOR` (Intel Only). + const ZMM_HI256 = 1 << 6; + /// Enables AVX-512 instructions and using the upper ZMM registers + /// with `XSAVE`/`XRSTOR` (Intel Only). + const HI16_ZMM = 1 << 7; + /// Enables using the PKRU register + /// with `XSAVE`/`XRSTOR`. const MPK = 1<<9; - /// When set the Lightweight Profiling extensions are enabled + /// Enables Lightweight Profiling extensions and managing LWP state + /// with `XSAVE`/`XRSTOR` (AMD Only). const LWP = 1<<62; } } @@ -58,6 +82,7 @@ mod x86_64 { /// Write XCR0 flags. /// /// Preserves the value of reserved fields. + /// Panics if invalid combinations of [`XCr0Flags`] are set. /// /// ## Safety /// @@ -69,6 +94,32 @@ mod x86_64 { let reserved = old_value & !(XCr0Flags::all().bits()); let new_value = reserved | flags.bits(); + assert!(flags.contains(XCr0Flags::X87), "The X87 flag must be set"); + if flags.contains(XCr0Flags::YMM) { + assert!( + flags.contains(XCr0Flags::SSE), + "AVX/YMM cannot be enabled without enabling SSE" + ); + } + let mpx = XCr0Flags::BNDREG | XCr0Flags::BNDCSR; + if flags.intersects(mpx) { + assert!( + flags.contains(mpx), + "MPX flags XCr0.BNDREG and XCr0.BNDCSR must be set and unset together" + ); + } + let avx512 = XCr0Flags::OPMASK | XCr0Flags::ZMM_HI256 | XCr0Flags::HI16_ZMM; + if flags.intersects(avx512) { + assert!( + flags.contains(XCr0Flags::YMM), + "AVX-512 cannot be enabled without enabling AVX/YMM" + ); + assert!( + flags.contains(avx512), + "AVX-512 flags XCR0.opmask, XCR0.ZMM_Hi256, and XCR0.Hi16_ZMM must be set and unset together" + ); + } + Self::write_raw(new_value); }