Skip to content

Commit

Permalink
feat(hal-x86_64): add bitflags for cr0 and cr4 (#370)
Browse files Browse the repository at this point in the history
This branch adds nice structured bitfield APIs for control registers
`CR0` and `CR4`. These will be useful when starting application
processors.
  • Loading branch information
hawkw authored Nov 6, 2022
1 parent 0910c6d commit a10bdeb
Showing 1 changed file with 216 additions and 1 deletion.
217 changes: 216 additions & 1 deletion hal-x86_64/src/control_regs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use core::arch::asm;
use mycelium_util::bits::bitfield;

pub mod cr3 {
use super::*;
use crate::{mm::size::Size4Kb, PAddr};
use core::arch::asm;
use hal_core::{mem::page::Page, Address};

#[derive(Copy, Clone, Eq, PartialEq)]
Expand Down Expand Up @@ -35,3 +38,215 @@ pub mod cr3 {
}
}
}

bitfield! {
/// Control Register 0
#[derive(Eq, PartialEq)]
pub struct Cr0<u64> {
/// Protected Mode Enable (`PE`)
///
/// Enables protected mode.
pub const PROTECTED_MODE_ENABLE: bool;
/// Monitor Coprocessor (`MP`).
///
/// Enables monitoring of the coprocessor, typically for x87 instructions.
///
/// Controls (together with the [`TASK_SWITCHED`] flag) whether a `WAIT`
/// or `FWAIT` instruction should cause an `#NE` exception.
pub const MONITOR_COPROCESSOR: bool;
/// x87 FPU Emulation (`EM`).
///
/// Force all x87 and MMX instructions to cause an `#NE` exception.
pub const EMULATE_COPROCESSOR: bool;
/// Task Switched (`TS`).
///
/// Set to 1 on hardware task switches. This allows lazily saving x87,
/// MMX, and SSE state on hardware context switches.
pub const TASK_SWITCHED: bool;
/// Extension Type (`ET`).
///
/// Indicates support of 387DX math coprocessor instructions.
///
/// Always set on all recent x86 processors, cannot be cleared.
pub const EXTENSION_TYPE: bool;
/// Numeric Error (`NE`).
///
/// Enables native error reporting for x87 FPU errors.
pub const NUMERIC_ERROR: bool;
const RESERVED_0 = 11;
/// Write Protect (`WP`).
///
/// Enables write protection for ring 0 pages.
pub const WRITE_PROTECT: bool;
const RESERVED_1 = 1;
/// Alignment Mask (`AM`).
///
/// Enables user-mode alignment checking if the `ALIGNMENT_CHECK` bit in
/// `RFLAGS` is also set.
pub const ALIGNMENT_MASK: bool;
const RESERVED_2 = 11;
/// Not Write Through (`NW`).
pub const NOT_WRITE_THROUGH: bool;
/// Cache Disable (`NW`).
pub const CACHE_DISABLE: bool;
/// Paging Enabled (`PG`).
///
/// Enables paging, if [`PROTECTED_MODE_ENABLE`] is also set.
pub const PAGING_ENABLE: bool;
}
}

impl Cr0 {
#[must_use]
pub fn read() -> Self {
let bits: u64;
unsafe {
asm!("mov {0}, cr0", out(reg) bits, options(readonly));
};
Self::from_bits(bits)
}

/// Write a value to `CR0`.
///
/// This function preserves the value of all reserved bits in `CR0`.
///
/// # Safety
///
/// Writing to `CR0` can do stuff.
pub unsafe fn write(value: Self) {
Self::update(|current| {
value
.with(Self::RESERVED_0, current.get(Self::RESERVED_0))
.with(Self::RESERVED_1, current.get(Self::RESERVED_1))
.with(Self::RESERVED_2, current.get(Self::RESERVED_2))
})
}

/// # Safety
///
/// Writing to `CR4` can do stuff.
pub unsafe fn update(f: impl FnOnce(Self) -> Self) {
let curr = Self::read();
let value = f(curr);
tracing::trace!("mov cr0, {value:?}");
asm!("mov cr0, {0}", in(reg) value.bits());
}
}

bitfield! {
/// Control Register 4
#[derive(Eq, PartialEq)]
pub struct Cr4<u64> {
/// Virtual 8086 Mode Extensions (`VME`).
pub const VIRTUAL_8086_MODE_EXTENSIONS: bool;
/// Protected-Mode Virtual Interrupts (`PVI`).
pub const PROTECTED_MODE_VIRTUAL_INTERRUPTS: bool;
/// Time Stamp Disable (`TSD`).
pub const TIME_STAMP_DISABLE: bool;
/// Debugging Extensions (`DE`).
pub const DEBUGGING_EXTENSIONS: bool;
/// Page Size Extension (`PSE`).
///
/// This enables the use of 4MB physical pages; always ignored in long mode.
pub const PAGE_SIZE_EXTENSION: bool;
/// Physical Address Extension (`PAE`).
///
/// Enables the use of 2MB physical pages. Required in long mode.
pub const PHYSICAL_ADDRESS_EXTENSION: bool;
/// Machine Check Exception Enable (`MCE`).
pub const MACHINE_CHECK_EXCEPTION: bool;
/// Page Global Enable (`PGE`).
///
/// Allows marking pages as global.
pub const PAGE_GLOBAL_ENABLE: bool;
/// Performance-Monitoring Counter Enable (`PCE`).
///
/// Allows the
pub const PERFORMANCE_MONITOR_COUNTER: bool;
/// Operating System `FXSAVE`/`FXRSTOR` Support
///
/// If enabled, the `FXSAVE` and `FXRSTOR` instructions are
/// available in both 64-bit and compatibility mode.
pub const OSFXSR: bool;
/// Operating System Support for Unmasked Floating-Point Exceptions
pub const OSXMMEXCPT: bool;
/// User-Mode Instruction Prevention (`UMIP`).
///
/// If set, `SGDT`, `SIDT`, `SLDT`, `SMSW`, and `STR`, instructions
/// will result in a general protection fault (`#GP`) when in ring >
/// 0.
pub const USER_MODE_INSTRUCTION_PREVENTION: bool;
/// Virtual Machine Extensions (VMX) Enable
///
/// **Note**: this extension is INTEL ONLY.
pub const VIRTUAL_MACHINE_EXTENSIONS: bool;
/// Safer Mode Extensions (SMX) Enable
///
/// **Note**: this extension is INTEL ONLY.
pub const SAFER_MODE_EXTENSIONS: bool;
/// FSBASE/GSBASE Enable.
///
/// Enables the instructions `RDFSBASE`,`RDGSBASE`, `WRFSBASE`, and `WRGSBASE`.
pub const FSGSBASE: bool;
/// PCID Enable (`PCIDE`).
pub const PCID_ENABLE: bool;
/// OS Support for `XSAVE` and Processor Extended States Enable
pub const OSXSAVE: bool;
/// Supervisor Mode Execution Protection Enable (`SMEP`).
pub const SUPERVISOR_EXECUTION_PROTECTION: bool;
/// Supervisor Mode Access Prevention Enable (`SMAP)
pub const SUPERVISOR_ACCESS_PREVENTION: bool;
/// Protection Key (Used) Enable (`PKE`).
///
/// Enables protection keys for user-mode pages.
pub const PROTECTION_KEY_USER: bool;
/// Control-flow Enforcement Technology Enable (`CET`).
pub const CONTROL_FLOW_ENFORCEMENT: bool;
/// Protection Key (Supervisor) Enable (`PKS`).
///
/// Enables protection keys for user-mode pages.
pub const PROTECTION_KEY_SUPERVISOR: bool;
}
}

impl Cr4 {
#[must_use]
pub fn read() -> Self {
let bits: u64;
unsafe {
asm!("mov {0}, cr4", out(reg) bits, options(readonly));
};
Self::from_bits(bits)
}

/// # Safety
///
/// Writing to `CR4` can do stuff.
pub unsafe fn write(value: Self) {
tracing::trace!("mov cr4, {:?}", value);
asm!("mov cr4, {0}", in(reg) value.bits());
}

/// # Safety
///
/// Writing to `CR4` can do stuff.
pub unsafe fn update(f: impl FnOnce(Self) -> Self) {
let curr = Self::read();
Self::write(f(curr));
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn cr4_valid() {
Cr4::assert_valid();
}

#[test]
fn cr0_valid() {
Cr0::assert_valid();
}
}

0 comments on commit a10bdeb

Please sign in to comment.