1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
//! Architecture-specific primitives common to 32-bit and 64-bit x86 processors.

use core::arch::asm;
use tartan_bitfield::bitfield;

#[cfg(doc)]
use features::BasicFeatures;
#[cfg(doc)]
use protection::IOPermissionBitmap;

pub mod features;
pub mod interrupt;
pub mod io;
pub mod paging;
pub mod protection;


bitfield! {
    /// `EFLAGS`/`RFLAGS`: General flags, including control, status, and basic system
    /// flags.
    ///
    /// Getters and setters for this structure only access a value in memory, not the
    /// register itself. Use the [`get`](Self::get) and [`set`](Self::set) methods to work
    /// with the actual register.
    pub struct FlagRegister(usize) {
        /// `CF`: Indicates an arithmetic instruction generated a carry/borrow (unsigned
        /// overflow).
        [0] pub carry,
        /// `PF`: Indicates that the least-significant byte of the result has *even*
        /// parity.
        [2] pub parity,
        /// `AF`: Indicates a carry/borrow/overflow out of bit 3 in binary-coded decimal
        /// (BCD) arithmetic.
        [4] pub aux_carry,
        /// `ZF`: Indicates that the result of an instruction is zero.
        [6] pub zero,
        /// `SF`: Indicates that the most-significant bit of a result is 1.
        [7] pub sign,
        /// `TF`: Enable single-step debugging.
        [8] pub trap,
        /// `IF`: Enable non-maskable interrupts. Non-maskable interrupts are always
        /// enabled.
        [9] pub interrupt_enabled,
        /// `DF`: String instructions work on addresses high-to-low when set, low-to-high
        /// when clear.
        [10] pub direction,
        /// `OF`: Indicates that the result overflowed for signed arithmetic (carry/borrow
        /// for the second-most-significant bit).
        [11] pub signed_overflow,
        /// `IOPL`: Sets the privilege threshold for a task to access I/O address space.
        /// Smaller numbers are higher privilege.
        ///
        /// Individual I/O ports may still be accessible at lower privilege levels
        /// (greater numeric values) if allowed by [`IOPermissionBitmap`] for the current
        /// task.
        [12..14] pub io_privilege_level: u8,
        /// `NT`: Indicates that the processor should switch back to a parent task when it
        /// executes an `IRET` instruction.
        ///
        /// Only supported in 32-bit mode. If this is set in 64-bit mode, `IRET` will
        /// trigger an exception.
        [14] pub nested_task,
        /// `RF`: Disable instruction breakpoints.
        [16] pub resume,
        /// `VM`: Enable virtual real mode.
        [17] pub virtual_8086_mode,
        /// `AC`: Enable strict alignment checks for memory accesses in privilege level 3.
        /// In privilege levels 0–2, allow access to pages assigned to lower privilege
        /// levels.
        ///
        /// Alignment checking requires [`ControlRegister0::alignment_check_mask`]. Access
        /// protection requires [`ControlRegister4::supervisor_access_prevention`].
        [18] pub alignment_check_or_access_control,
        /// `VIF`: Virtual counterpart to the `interrupt_enabled` flag, used with
        /// [VME](ControlRegister4::virtual_8086_extensions) or
        /// [PVI](ControlRegister4::protected_virtual_interrupts).
        [19] pub virtual_interrupt_enabled,
        /// `VIP`: Indicates an interrupt is pending for
        /// [VME](ControlRegister4::virtual_8086_extensions) or
        /// [PVI](ControlRegister4::protected_virtual_interrupts).
        [20] pub virtual_interrupt_pending,
        /// `ID`: Indicates `CPUID` support when the flag is modifiable.
        [21] pub identification,
    }
}

impl FlagRegister {
    /// Retrieve the current value of the `EFLAGS` register.
    pub fn get() -> Self {
        let mut value = Self(0);
        unsafe {
            #[cfg(target_arch = "x86")]
            asm!(
                "
                pushfd
                pop {0:e}
                ",
                out(reg) value.0,
            );

            #[cfg(target_arch = "x86_64")]
            asm!(
                "
                pushfq
                pop {0:r}
                ",
                out(reg) value.0,
            );
        }
        value
    }

    /// Update the `EFLAGS` register with the given value, as permission level allows.
    ///
    /// Some flags will be unaffected depending on the processor mode and permission level
    /// flags. See the reference for the POPF instruction in the _Intel 64 and IA-32
    /// Architectures Software Developer's Manual_, volume 2.
    ///
    /// # Safety
    /// Altering certain system flags can have dramatic effects on the execution of this
    /// and other programs, including memory safety. See volume 1 §3.4.3 ("EFLAGS
    /// Register") and volume 3 §2.3 ("System Flags and Fields in the EFLAGS Register") of
    /// the _Intel 64 and IA-32 Architectures Software Developer's Manual_.
    pub unsafe fn set(value: Self) {
        #[cfg(target_arch = "x86")]
        asm!(
            "
            push {0:e}
            popfd
            ",
            in(reg) value.0,
        );

        #[cfg(target_arch = "x86_64")]
        asm!(
            "
            push {0:r}
            popfq
            ",
            in(reg) value.0,
        );
    }
}


#[macro_export]
#[doc(hidden)]
macro_rules! simple_register_access {
    [$struct:ident, $register:literal] => {
        impl $struct {
            /// Retrieve the current value of this register
            pub fn get() -> Self {
                let mut value = Self(0);
                unsafe {
                    core::arch::asm!(
                        concat!("mov {0}, ", $register),
                        out(reg) value.0,
                    );
                }
                value
            }

            /// Update the register to the given value.
            ///
            /// # Safety
            /// Altering certain system flags can have dramatic effects on the execution
            /// of this and other programs, including memory safety.
            pub unsafe fn set(value: Self) {
                core::arch::asm!(
                    concat!("mov ", $register, ", {0}"),
                    in(reg) value.0,
                );
            }
        }
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! indexed_register_access {
    [$struct:ident, $index:literal, $read_instr:literal, $write_instr:literal] => {
        impl $struct {
            /// Retrieve the current value of this register
            pub fn get() -> Self {
                let lower: u32;
                let upper: u32;
                unsafe {
                    core::arch::asm!(
                        $read_instr,
                        in("ecx") $index,
                        out("eax") lower,
                        out("edx") upper,
                    );
                }
                let mut value = Self(0);
                value.0 |= u64::from(lower);
                value.0 |= u64::from(upper) << 32;
                value
            }

            /// Update the register to the given value.
            ///
            /// # Safety
            /// Altering certain system flags can have dramatic effects on the execution
            /// of this and other programs, including memory safety.
            pub unsafe fn set(value: Self) {
                #![allow(clippy::cast_possible_truncation)]
                let lower = value.0 as u32;
                let upper = (value.0 >> 32) as u32;
                core::arch::asm!(
                    $write_instr,
                    in("ecx") $index,
                    in("eax") lower,
                    in("edx") upper,
                );
            }
        }
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! extended_register_access {
    [$struct:ident, $index:literal] => {
        $crate::indexed_register_access!($struct, $index, "xgetbv", "xsetbv");
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! model_specific_register_access {
    [$struct:ident, $index:literal] => {
        $crate::indexed_register_access!($struct, $index, "rdmsr", "wrmsr");
    }
}


bitfield! {
    /// `CR0`: System control register with flags affecting protection, paging, and FPU
    /// behavior.
    ///
    /// Getters and setters for this structure only access a value in memory, not the
    /// register itself. Use the [`get`](Self::get) and [`set`](Self::set) methods to
    /// work with the actual register.
    pub struct ControlRegister0(usize) {
        /// `CR0.PG`: Enable paging. Requires [`protected_mode`](Self::protected_mode).
        [31] pub paging,
        /// `CR0.CD`: Disable all memory caching.
        [30] pub cache_disabled,
        /// `CR0.NW`: Disable write-back/write-through caching.
        [29] pub cache_not_write_through,
        /// `CR0.AM`: Enables strict alignment checks for memory access, in combination
        /// with [`FlagRegister::alignment_check_or_access_control`].
        [18] pub alignment_check_mask,
        /// `CR0.WP`: Enforce read-only pages even in privilege levels 0–2. They are
        /// always enforced in level 3.
        [16] pub write_protect,
        /// `CR0.NE`: Use internal error mechanism for FPU errors, rather than DOS-style.
        [ 5] pub native_fpu_error,
        /// `CR0.ET`: On 386/486, 387 FPU instructions are supported if set. Always set
        /// on modern processors.
        [ 4] pub fpu_extension_type,
        /// `CR0.TS`: Set by processor when task was switched but FPU context has not been
        /// saved yet.
        ///
        /// Used to save work when the new task does not alter the FPU state. When an FPU
        /// instruction is executed with this flag set, the processor raises an exception
        /// that allows the OS to save the FPU state. This behavior can be altered by
        /// other flags. See [`monitor_fpu_state`](Self::monitor_fpu_state).
        [ 3] pub task_switched_without_fpu_state,
        /// `CR0.EM`: Trigger an exception on all FPU instructions. Used to support
        /// software emulation.
        [ 2] pub fpu_emulation,
        /// `CR0.MP`: Enable exception behavior described for the `CR0.TS` flag for the
        /// (`F`)`WAIT` instruction.
        [ 1] pub monitor_fpu,
        /// Enable protected mode. Does not enable paging on its own. See
        /// [`paging`](Self::paging).
        [ 0] pub protected_mode,
    }
}

simple_register_access!(ControlRegister0, "cr0");

impl ControlRegister0 {
    /// Directly clear the
    /// [`task_switched_without_fpu_state`](Self::task_switched_without_fpu_state) flag in
    /// this register using a single instruction.
    ///
    /// # Safety
    /// Clearing this flag when inappropriate may clobber FPU state and potentially affect
    /// memory safety.
    pub unsafe fn clear_task_switched_without_fpu_state() {
        asm!("clts");
    }
}


bitfield! {
    /// `CR4`: Miscellaneous system control flags.
    ///
    /// Getters and setters for this structure only access a value in memory, not the
    /// register itself. Use the [`get`](Self::get) and [`set`](Self::set) methods to
    /// work with the actual register.
    pub struct ControlRegister4(usize) {
        /// `CR4.VME`: Enable interrupts and exception handling in [virtual
        /// real-mode](EFLAGS::virtual_8086_mode).
        ///
        /// Requires [`BasicFeatures::virtual_8086_extensions`].
        [0] pub virtual_8086_extensions,

        /// `CR4.PVI`: Enable virtual interrupts in protected mode.
        ///
        /// Requires [`BasicFeatures::virtual_8086_extensions`].
        [1] pub protected_virtual_interrupts,

        /// `CR4.TSD`: Disable access to processor timestamp counter except in privilege
        /// level 0.
        ///
        /// Requires [`BasicFeatures::timestamp_counter`].
        [2] pub timestamp_disabled,

        /// `CR4.DE`: Enable newer debug register scheme where `DR4` and `DR5` are
        /// unavailable.
        ///
        /// When this flag is clear, they are equivalent to `DR6` and `DR7`.
        ///
        /// Requires [`BasicFeatures::debugging_extensions`].
        [3] pub debugging_extensions,

        /// `CR4.PSE`: Support large pages (4MB). Applies to 32-bit mode only.
        ///
        /// When this flag is clear in 32-bit mode, pages are always 4KB. Large pages are
        /// always enabled in 64-bit mode.
        ///
        /// Requires [`BasicFeatures::page_size_extensions`].
        [4] pub page_size_extensions,

        /// `CR4.PAE`: Enable pages to map to physical addresses larger than 32-bits.
        ///
        /// Required for 64-bit mode.
        ///
        /// Requires [`BasicFeatures::physical_address_extension`].
        [5] pub physical_address_extension,

        /// `CR4.MCE`: Enable machine-check exception.
        ///
        /// Requires [`BasicFeatures::machine_check_exception`].
        [6] pub machine_check_exception,

        /// `CR4.PGE`: Enable global pages, which are shared across task contexts.
        ///
        /// Requires [`BasicFeatures::global_pages`].
        [7] pub global_pages,

        /// `CR4.PCE`: Allow access to performance monitoring counter in privilege levels
        /// 1–3 (always accessible in level 0).
        [8] pub performance_counter,

        /// `CR4.OSFXSR`: Enable the `FXSAVE`/`FXRSTOR` and SSE instructions, if present.
        ///
        /// These instructions require special support from the operating system.
        ///
        /// Requires [`BasicFeatures::fpu_save`].
        [9] pub sse_and_fpu_save,

        /// `CR4.OSXMMEXCPT`: Enable unmasked SIMD floating-point exception handling for
        /// SSE instructions.
        ///
        /// This requires special support from the operating system.
        [10] pub simd_exceptions,

        /// `CR4.UMIP`: Prevent access to instructions that allow reads from
        /// descriptor/task registers, except in privilege level 0.
        [11] pub restrict_user_mode_instructions,

        /// `CR4.LA57`: Support 57-bit addresses using 5-level paging in 64-bit mode.
        #[cfg(any(target_arch = "x86_64", doc))]
        #[doc(cfg(target_arch = "x86_64"))]
        [12] pub five_level_paging,

        /// `CR4.VMX` (**Intel-only**): Enable virtual machine extensions.
        ///
        /// Requires [`BasicFeatures::virtual_machine_extensions`].
        [13] pub virtual_machine_extensions,

        /// `CR4.SME` (**Intel-only**): Enable safer-mode extensions.
        ///
        /// Requires [`BasicFeatures::safer_mode_extensions`].
        [14] pub safer_mode_extensions,

        /// `CR4.FSGSBASE`: Enable instructions to load/store the `FS` and `GS` base
        /// registers with 32/64-bit values in 64-bit mode.
        #[cfg(any(target_arch = "x86_64", doc))]
        #[doc(cfg(target_arch = "x86_64"))]
        [16] pub extended_base_registers,

        /// `CR4.PCIDE`: Enable process-context identifiers (PCID) in 64-bit mode.
        ///
        /// Requires [`BasicFeatures::process_context_ids`].
        #[cfg(any(target_arch = "x86_64", doc))]
        #[doc(cfg(target_arch = "x86_64"))]
        [17] pub process_context_ids,

        /// `CR4.OSXSAVE`: Enable instructions for saving and restoring extended processor
        /// state (FPU/MMX/SSE/AVX).
        ///
        /// These instructions require special support from the operating system.
        ///
        /// Requires [`BasicFeatures::extended_state_save`].
        [18] pub extended_state_save,

        /// `CR4.SMEP`: Enable execution prevention in privilege levels 0–2.
        [20] pub supervisor_execution_prevention,

        /// `CR4.SMAP`: Enable access prevention in privilege levels 0–2.
        [21] pub supervisor_access_prevention,

        /// `CR4.PKE`: Use page protection keys in 64-bit mode to control access from
        /// privilege level 3.
        #[cfg(any(target_arch = "x86_64", doc))]
        #[doc(cfg(target_arch = "x86_64"))]
        [22] pub user_protection_keys,

        /// `CR4.CET` (**Intel-only**): Enable control-flow enforcement technology.
        /// Requires [`ControlRegister0::write_protect`].
        [23] pub control_flow_enforcement,

        /// `CR4.PKS` (**Intel-only**): Use page protection keys in 64-bit mode to control
        /// access from privilege levels 0-2.
        #[cfg(any(target_arch = "x86_64", doc))]
        #[doc(cfg(target_arch = "x86_64"))]
        [24] pub supervisor_protection_keys,
    }
}

simple_register_access!(ControlRegister4, "cr4");


bitfield! {
    /// `XCR0`: System control flags that indicate OS support for context management for
    /// various registers with the `XSAVE` feature.
    ///
    /// Getters and setters for this structure only access a value in memory, not the
    /// register itself. Use the [`get`](Self::get) and [`set`](Self::set) methods to
    /// work with the actual register.
    ///
    /// Requires [`BasicFeatures::extended_state_save`].
    pub struct ExtendedControlRegister0(u64) {
        /// `XCR0.X87`: Hardcoded to 1.
        [0] pub fpu,

        /// `XCR0.SSE`: Manage SSE state with `XSAVE`, including the `XMM` registers.
        [1] pub sse,

        /// `XCR0.AVX`: Manage 256-bit AVX state in upper halves of the `YMM` registers
        /// with `XSAVE`.
        ///
        /// Requires [`sse`](Self::sse). The lower halves of these registers are
        /// equivalent to `XMM` and are covered by that flag.
        [2] pub avx_256,

        /// `XCR0.BNDREG`: Manage MPX bounds registers with `XSAVE`.
        ///
        /// Requires [`mpx_bound_config_status`](Self::mpx_bound_config_status).
        [3] pub mpx_bounds,

        /// `XCR0.BNDCSR`: Manage MPX config and status registers with `XSAVE`.
        ///
        /// Requires [`mpx_bounds`](Self::mpx_bounds).
        [4] pub mpx_bound_config_status,

        /// `XCR0.OPMASK`: Manage AVX-512 opmask registers with `XSAVE`.
        ///
        /// Requires the other `avx_512_*` flags.
        [5] pub avx_512_opmask,

        /// `XCR0.ZMM_Hi256`: Manage 512-bit AVX state in the upper halves of the `ZMM`
        /// registers up to `ZMM15` with `XSAVE`.
        ///
        /// Registers `ZMM8`–`ZMM15` are available in 64-bit mode only, so this only
        /// applies up to `ZMM7` in 32-bit mode.
        ///
        /// Requires [`avx_256`](Self::avx_256) and the other `avx_512_*` flags. The lower
        /// halves of these registers are equivalent to `YMM` and are covered by
        /// `avx_256`(Self::avx_256).
        [6] pub avx_512,

        /// `XCR0.Hi16_ZMM`: Manage AVX-512 state in `ZMM16`–`ZMM31` with `XSAVE`.
        ///
        /// These registers are only available in 64-bit mode.
        ///
        /// Requires the other `avx_512_*` flags.
        #[cfg(any(target_arch = "x86_64", doc))]
        #[doc(cfg(target_arch = "x86_64"))]
        [7] pub avx_512_extended,

        /// `XCR0.PKRU`: Manage protection key rights registers with `XSAVE`.
        [8] pub protection_key_rights,
    }
}

extended_register_access!(ExtendedControlRegister0, 0);