Skip to content

Commit 759cb32

Browse files
authored
Merge pull request #273 from rust-osdev/flags
Add flags for CR0, CR4 and XCR0, as well as extra checks for modification of XCR0
2 parents 1a0b149 + d369377 commit 759cb32

File tree

2 files changed

+125
-42
lines changed

2 files changed

+125
-42
lines changed

src/registers/control.rs

+66-34
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Functions to read and write control registers.
22
33
pub use super::model_specific::{Efer, EferFlags};
4+
#[cfg(docsrs)]
5+
use crate::{registers::rflags::RFlags, structures::paging::PageTableFlags};
46

57
use bitflags::bitflags;
68

@@ -9,119 +11,149 @@ use bitflags::bitflags;
911
pub struct Cr0;
1012

1113
bitflags! {
12-
/// Configuration flags of the Cr0 register.
14+
/// Configuration flags of the [`Cr0`] register.
1315
pub struct Cr0Flags: u64 {
1416
/// Enables protected mode.
1517
const PROTECTED_MODE_ENABLE = 1;
1618
/// Enables monitoring of the coprocessor, typical for x87 instructions.
1719
///
18-
/// Controls together with the `TASK_SWITCHED` flag whether a `wait` or `fwait`
19-
/// instruction should cause a device-not-available exception.
20+
/// Controls (together with the [`TASK_SWITCHED`](Cr0Flags::TASK_SWITCHED)
21+
/// flag) whether a `wait` or `fwait` instruction should cause an `#NE` exception.
2022
const MONITOR_COPROCESSOR = 1 << 1;
21-
/// Force all x87 and MMX instructions to cause an exception.
23+
/// Force all x87 and MMX instructions to cause an `#NE` exception.
2224
const EMULATE_COPROCESSOR = 1 << 2;
2325
/// Automatically set to 1 on _hardware_ task switch.
2426
///
2527
/// This flags allows lazily saving x87/MMX/SSE instructions on hardware context switches.
2628
const TASK_SWITCHED = 1 << 3;
27-
/// Enables the native error reporting mechanism for x87 FPU errors.
29+
/// Indicates support of 387DX math coprocessor instructions.
30+
///
31+
/// Always set on all recent x86 processors, cannot be cleared.
32+
const EXTENSION_TYPE = 1 << 4;
33+
/// Enables the native (internal) error reporting mechanism for x87 FPU errors.
2834
const NUMERIC_ERROR = 1 << 5;
2935
/// Controls whether supervisor-level writes to read-only pages are inhibited.
3036
///
3137
/// When set, it is not possible to write to read-only pages from ring 0.
3238
const WRITE_PROTECT = 1 << 16;
33-
/// Enables automatic alignment checking.
39+
/// Enables automatic usermode alignment checking if [`RFlags::ALIGNMENT_CHECK`] is also set.
3440
const ALIGNMENT_MASK = 1 << 18;
35-
/// Ignored. Used to control write-back/write-through cache strategy on older CPUs.
41+
/// Ignored, should always be unset.
42+
///
43+
/// Must be unset if [`CACHE_DISABLE`](Cr0Flags::CACHE_DISABLE) is unset.
44+
/// Older CPUs used this to control write-back/write-through cache strategy.
3645
const NOT_WRITE_THROUGH = 1 << 29;
37-
/// Disables internal caches (only for some cases).
46+
/// Disables some processor caches, specifics are model-dependent.
3847
const CACHE_DISABLE = 1 << 30;
39-
/// Enables page translation.
48+
/// Enables paging.
49+
///
50+
/// If this bit is set, [`PROTECTED_MODE_ENABLE`](Cr0Flags::PROTECTED_MODE_ENABLE) must be set.
4051
const PAGING = 1 << 31;
4152
}
4253
}
4354

4455
/// Contains the Page Fault Linear Address (PFLA).
4556
///
46-
/// When page fault occurs, the CPU sets this register to the accessed address.
57+
/// When a page fault occurs, the CPU sets this register to the faulting virtual address.
4758
#[derive(Debug)]
4859
pub struct Cr2;
4960

50-
/// Contains the physical address of the level 4 page table.
61+
/// Contains the physical address of the highest-level page table.
5162
#[derive(Debug)]
5263
pub struct Cr3;
5364

5465
bitflags! {
55-
/// Controls cache settings for the level 4 page table.
66+
/// Controls cache settings for the highest-level page table.
67+
///
68+
/// Unused if paging is disabled or if [`PCID`](Cr4Flags::PCID) is enabled.
5669
pub struct Cr3Flags: u64 {
57-
/// Use a writethrough cache policy for the P4 table (else a writeback policy is used).
70+
/// Use a writethrough cache policy for the table (otherwise a writeback policy is used).
5871
const PAGE_LEVEL_WRITETHROUGH = 1 << 3;
59-
/// Disable caching for the P4 table.
72+
/// Disable caching for the table.
6073
const PAGE_LEVEL_CACHE_DISABLE = 1 << 4;
6174
}
6275
}
6376

64-
/// Various control flags modifying the basic operation of the CPU while in protected mode.
65-
///
66-
/// Note: The documention for the individual fields is taken from the AMD64 and Intel x86_64
67-
/// manuals.
77+
/// Contains various control flags that enable architectural extensions, and
78+
/// indicate support for specific processor capabilities.
6879
#[derive(Debug)]
6980
pub struct Cr4;
7081

7182
bitflags! {
72-
/// Controls cache settings for the level 4 page table.
83+
/// Configuration flags of the [`Cr4`] register.
7384
pub struct Cr4Flags: u64 {
7485
/// Enables hardware-supported performance enhancements for software running in
7586
/// virtual-8086 mode.
7687
const VIRTUAL_8086_MODE_EXTENSIONS = 1;
7788
/// Enables support for protected-mode virtual interrupts.
7889
const PROTECTED_MODE_VIRTUAL_INTERRUPTS = 1 << 1;
79-
/// When set, only privilege-level 0 can execute the RDTSC or RDTSCP instructions.
90+
/// When set, only privilege-level 0 can execute the `RDTSC` or `RDTSCP` instructions.
8091
const TIMESTAMP_DISABLE = 1 << 2;
81-
/// Enables I/O breakpoint capability and enforces treatment of DR4 and DR5 registers
92+
/// Enables I/O breakpoint capability and enforces treatment of `DR4` and `DR5` registers
8293
/// as reserved.
8394
const DEBUGGING_EXTENSIONS = 1 << 3;
84-
/// Enables the use of 4MB physical frames; ignored in long mode.
95+
/// Enables the use of 4MB physical frames; ignored if
96+
/// [`PHYSICAL_ADDRESS_EXTENSION`](Cr4Flags::PHYSICAL_ADDRESS_EXTENSION)
97+
/// is set (so always ignored in long mode).
8598
const PAGE_SIZE_EXTENSION = 1 << 4;
86-
/// Enables physical address extension and 2MB physical frames; required in long mode.
99+
/// Enables physical address extensions and 2MB physical frames. Required in long mode.
87100
const PHYSICAL_ADDRESS_EXTENSION = 1 << 5;
88101
/// Enables the machine-check exception mechanism.
89102
const MACHINE_CHECK_EXCEPTION = 1 << 6;
90-
/// Enables the global-page mechanism, which allows to make page translations global
91-
/// to all processes.
103+
/// Enables the global page feature, allowing some page translations to
104+
/// be marked as global (see [`PageTableFlags::GLOBAL`]).
92105
const PAGE_GLOBAL = 1 << 7;
93-
/// Allows software running at any privilege level to use the RDPMC instruction.
106+
/// Allows software running at any privilege level to use the `RDPMC` instruction.
94107
const PERFORMANCE_MONITOR_COUNTER = 1 << 8;
95-
/// Enable the use of legacy SSE instructions; allows using FXSAVE/FXRSTOR for saving
108+
/// Enables the use of legacy SSE instructions; allows using `FXSAVE`/`FXRSTOR` for saving
96109
/// processor state of 128-bit media instructions.
97110
const OSFXSR = 1 << 9;
98-
/// Enables the SIMD floating-point exception (#XF) for handling unmasked 256-bit and
111+
/// Enables the SIMD floating-point exception (`#XF`) for handling unmasked 256-bit and
99112
/// 128-bit media floating-point errors.
100113
const OSXMMEXCPT_ENABLE = 1 << 10;
101-
/// Prevents the execution of the SGDT, SIDT, SLDT, SMSW, and STR instructions by
114+
/// Prevents the execution of the `SGDT`, `SIDT`, `SLDT`, `SMSW`, and `STR` instructions by
102115
/// user-mode software.
103116
const USER_MODE_INSTRUCTION_PREVENTION = 1 << 11;
104-
/// Enables 5-level paging on supported CPUs.
117+
/// Enables 5-level paging on supported CPUs (Intel Only).
105118
const L5_PAGING = 1 << 12;
106-
/// Enables VMX insturctions.
119+
/// Enables VMX instructions (Intel Only).
107120
const VIRTUAL_MACHINE_EXTENSIONS = 1 << 13;
108-
/// Enables SMX instructions.
121+
/// Enables SMX instructions (Intel Only).
109122
const SAFER_MODE_EXTENSIONS = 1 << 14;
110123
/// Enables software running in 64-bit mode at any privilege level to read and write
111124
/// the FS.base and GS.base hidden segment register state.
112125
const FSGSBASE = 1 << 16;
113126
/// Enables process-context identifiers (PCIDs).
114127
const PCID = 1 << 17;
115-
/// Enables extendet processor state management instructions, including XGETBV and XSAVE.
128+
/// Enables extended processor state management instructions, including `XGETBV` and `XSAVE`.
116129
const OSXSAVE = 1 << 18;
130+
/// Enables the Key Locker feature (Intel Only).
131+
///
132+
/// This enables creation and use of opaque AES key handles; see the
133+
/// [Intel Key Locker Specification](https://software.intel.com/content/www/us/en/develop/download/intel-key-locker-specification.html)
134+
/// for more information.
135+
const KEY_LOCKER = 1 << 19;
117136
/// Prevents the execution of instructions that reside in pages accessible by user-mode
118137
/// software when the processor is in supervisor-mode.
119138
const SUPERVISOR_MODE_EXECUTION_PROTECTION = 1 << 20;
120139
/// Enables restrictions for supervisor-mode software when reading data from user-mode
121140
/// pages.
122141
const SUPERVISOR_MODE_ACCESS_PREVENTION = 1 << 21;
123-
/// Enables 4-level paging to associate each linear address with a protection key.
142+
/// Enables protection keys for user-mode pages.
143+
///
144+
/// Also enables access to the PKRU register (via the `RDPKRU`/`WRPKRU`
145+
/// instructions) to set user-mode protection key access controls.
124146
const PROTECTION_KEY = 1 << 22;
147+
/// Enables Control-flow Enforcement Technology (CET)
148+
///
149+
/// This enables the shadow stack feature, ensuring return addresses read
150+
/// via `RET` and `IRET` have not been corrupted.
151+
const CONTROL_FLOW_ENFORCEMENT = 1 << 23;
152+
/// Enables protection keys for supervisor-mode pages (Intel Only).
153+
///
154+
/// Also enables the `IA32_PKRS` MSR to set supervisor-mode protection
155+
/// key access controls.
156+
const PROTECTION_KEY_SUPERVISOR = 1 << 24;
125157
}
126158
}
127159

src/registers/xcontrol.rs

+59-8
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,43 @@ pub struct XCr0;
77

88
bitflags! {
99
/// Configuration flags of the XCr0 register.
10+
///
11+
/// For MPX, [`BNDREG`](XCr0Flags::BNDREG) and [`BNDCSR`](XCr0Flags::BNDCSR) must be set/unset simultaneously.
12+
/// For AVX-512, [`OPMASK`](XCr0Flags::OPMASK), [`ZMM_HI256`](XCr0Flags::ZMM_HI256), and [`HI16_ZMM`](XCr0Flags::HI16_ZMM) must be set/unset simultaneously.
1013
pub struct XCr0Flags: u64 {
11-
/// Enables x87 FPU
14+
/// Enables using the x87 FPU state
15+
/// with `XSAVE`/`XRSTOR`.
16+
///
17+
/// Must be set.
1218
const X87 = 1;
13-
/// Enables 128-bit (legacy) SSE
14-
/// Must be set to enable AVX and YMM
19+
/// Enables using MXCSR and the XMM registers
20+
/// with `XSAVE`/`XRSTOR`.
21+
///
22+
/// Must be set if [`YMM`](XCr0Flags::YMM) is set.
1523
const SSE = 1<<1;
16-
/// Enables 256-bit SSE
17-
/// Must be set to enable AVX
24+
/// Enables AVX instructions and using the upper halves of the YMM registers
25+
/// with `XSAVE`/`XRSTOR`.
1826
const YMM = 1<<2;
19-
/// When set, PKRU state management is supported by
20-
/// ZSAVE/XRSTOR
27+
/// Enables MPX instructions and using the BND0-BND3 bound registers
28+
/// with `XSAVE`/`XRSTOR` (Intel Only).
29+
const BNDREG = 1 << 3;
30+
/// Enables MPX instructions and using the BNDCFGU and BNDSTATUS registers
31+
/// with `XSAVE`/`XRSTOR` (Intel Only).
32+
const BNDCSR = 1 << 4;
33+
/// Enables AVX-512 instructions and using the K0-K7 mask registers
34+
/// with `XSAVE`/`XRSTOR` (Intel Only).
35+
const OPMASK = 1 << 5;
36+
/// Enables AVX-512 instructions and using the upper halves of the lower ZMM registers
37+
/// with `XSAVE`/`XRSTOR` (Intel Only).
38+
const ZMM_HI256 = 1 << 6;
39+
/// Enables AVX-512 instructions and using the upper ZMM registers
40+
/// with `XSAVE`/`XRSTOR` (Intel Only).
41+
const HI16_ZMM = 1 << 7;
42+
/// Enables using the PKRU register
43+
/// with `XSAVE`/`XRSTOR`.
2144
const MPK = 1<<9;
22-
/// When set the Lightweight Profiling extensions are enabled
45+
/// Enables Lightweight Profiling extensions and managing LWP state
46+
/// with `XSAVE`/`XRSTOR` (AMD Only).
2347
const LWP = 1<<62;
2448
}
2549
}
@@ -58,6 +82,7 @@ mod x86_64 {
5882
/// Write XCR0 flags.
5983
///
6084
/// Preserves the value of reserved fields.
85+
/// Panics if invalid combinations of [`XCr0Flags`] are set.
6186
///
6287
/// ## Safety
6388
///
@@ -69,6 +94,32 @@ mod x86_64 {
6994
let reserved = old_value & !(XCr0Flags::all().bits());
7095
let new_value = reserved | flags.bits();
7196

97+
assert!(flags.contains(XCr0Flags::X87), "The X87 flag must be set");
98+
if flags.contains(XCr0Flags::YMM) {
99+
assert!(
100+
flags.contains(XCr0Flags::SSE),
101+
"AVX/YMM cannot be enabled without enabling SSE"
102+
);
103+
}
104+
let mpx = XCr0Flags::BNDREG | XCr0Flags::BNDCSR;
105+
if flags.intersects(mpx) {
106+
assert!(
107+
flags.contains(mpx),
108+
"MPX flags XCr0.BNDREG and XCr0.BNDCSR must be set and unset together"
109+
);
110+
}
111+
let avx512 = XCr0Flags::OPMASK | XCr0Flags::ZMM_HI256 | XCr0Flags::HI16_ZMM;
112+
if flags.intersects(avx512) {
113+
assert!(
114+
flags.contains(XCr0Flags::YMM),
115+
"AVX-512 cannot be enabled without enabling AVX/YMM"
116+
);
117+
assert!(
118+
flags.contains(avx512),
119+
"AVX-512 flags XCR0.opmask, XCR0.ZMM_Hi256, and XCR0.Hi16_ZMM must be set and unset together"
120+
);
121+
}
122+
72123
Self::write_raw(new_value);
73124
}
74125

0 commit comments

Comments
 (0)