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
//! Abstractions for cpu flags and control registers
use core::arch::asm;
use bitfield_struct::bitfield;
/// The RFLAGS register.
#[bitfield(u32)]
pub struct Flags {
/// Set by hardware if last arithmetic operation generated a carry out of the
/// most-significant bit of the result.
pub carry: bool,
__: bool,
/// Set by hardware if last result has an even number of 1 bits (only for some operations).
pub parity: bool,
__: bool,
/// Set by hardware if last arithmetic operation generated a carry ouf of bit 3 of the
/// result.
pub auxiliary_carry: bool,
__: bool,
/// Set by hardware if last arithmetic operation resulted in a zero value.
pub zero: bool,
/// Set by hardware if last arithmetic operation resulted in a negative value.
pub sign: bool,
/// Enable single-step mode for debugging.
pub trap: bool,
/// Enable interrupts.
pub interrupt: bool,
/// Determines the order in which strings are processed.
pub direction: bool,
/// Set by hardware to indicate that the sign bit of the result of the last signed integer
/// operation differs from the source operands.
pub overflow: bool,
/// Specifies the privilege level required for executing I/O address-space instructions.
pub iopl_low: bool,
/// Specifies the privilege level required for executing I/O address-space instructions.
pub iopl_high: bool,
/// Used by `iret` in hardware task switch mode to determine if current task is nested.
pub nested_task: bool,
__: bool,
/// Temporarily disables debug exceptions so that an instruction can be restarted after a debug exception
/// without immediately causing another debug exception.
pub resume: bool,
/// Enable the virtual-8086 mode.
pub virtual_8086_mode: bool,
/// Enable automatic alignment checking if CR0.AM is set. Only works if CPL is 3.
pub alignment_check: bool,
/// Virtual interrupt flag.
pub virtual_interrupt: bool,
/// Virtual interrupt pending.
pub virtual_interrupt_pending: bool,
/// Able to use CPUID instruction.
pub id: bool,
#[bits(10)]
__: (),
}
impl Flags {
pub fn read() -> Self {
let value: u32;
unsafe { asm!("pushfd\npop {}", out(reg) value, options(nomem)) };
Self(value)
}
}
/// Contains system control flags that control operating mode and states of the processor.
#[bitfield(u32)]
pub struct Cr0 {
/// Enables protected mode.
pub protected_mode_enable: bool,
/// 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.
pub monitor_coprocessor: bool,
/// Force all x87 and MMX instructions to cause an exception.
pub emulate_coprocessor: bool,
/// Automatically set to 1 on _hardware_ task switch.
///
/// This flags allows lazily saving x87/MMX/SSE instructions on hardware context switches.
pub task_switched: bool,
__: bool,
/// Enables the native error reporting mechanism for x87 FPU errors.
pub numeric_error: bool,
#[bits(10)]
__: (),
/// Controls whether supervisor-level writes to read-only pages are inhibited.
pub write_protect: bool,
__: bool,
/// Enables automatic alignment checking.
pub alignment_mask: bool,
#[bits(10)]
__: (),
/// Ignored. Used to control write-back/write-through cache strategy on older CPUs.
pub not_write_through: bool,
/// Disables internal caches (only for some cases).
pub cache_disable: bool,
/// Enables page translation.
pub paging: bool,
}
impl Cr0 {
pub fn read() -> Self {
let value: u32;
unsafe { asm!("mov {}, cr0", out(reg) value, options(nomem)) };
Self(value)
}
pub fn update(f: impl FnOnce(Self) -> Self) {
unsafe { f(Self::read()).write() }
}
unsafe fn write(self) {
asm!("mov cr0, {}", in(reg) self.0, options(nostack));
}
}
/// Contains the page-fault linear address.
#[repr(transparent)]
pub struct Cr2(pub u32);
impl Cr2 {
pub fn read() -> Self {
let value: u32;
unsafe { asm!("mov {}, cr2", out(reg) value, options(nomem)) };
Self(value)
}
}
/// Contains the physical address of the base of the paging-structure hierarchy
/// and two flags (PCD and PWT). Only the most-significant bits (less the lower
/// 12 bits) of the base address are specified; the lower 12 bits of the
/// address are assumed to be 0. The first paging structure must thus be
/// aligned to a page (4-KByte) boundary. The PCD and PWT flags control caching
/// of that paging structure in the processor’s internal data caches (they do
/// not control TLB caching of page-directory information).
///
/// When using the physical address extension, the CR3 register contains the
/// base address of the page-directory-pointer table. In IA-32e mode, the CR3
/// register contains the base address of the PML4 table.
#[repr(transparent)]
pub struct Cr3(pub u32);
impl Cr3 {
pub fn read() -> Self {
let value: u32;
unsafe { asm!("mov {}, cr3", out(reg) value, options(nomem)) };
Self(value)
}
pub unsafe fn write(self) {
asm!("mov cr3, {}", in(reg) self.0, options(nostack));
}
}