Skip to content

Commit

Permalink
Merge pull request #527 from mkroening/xcr0-update
Browse files Browse the repository at this point in the history
feat: add `update()` to `Cr3`, `Dr7`, `SFMask`, `UCet`, `SCet`, `mxcsr`, `rflags`, and `XCr0`
  • Loading branch information
Freax13 authored Dec 24, 2024
2 parents a1ffaad + 87a7aff commit 59ac07c
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 1 deletion.
57 changes: 57 additions & 0 deletions src/registers/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,63 @@ mod x86_64 {
asm!("mov cr3, {}", in(reg) value, options(nostack, preserves_flags));
}
}

/// Update the P4 table address in the CR3 register.
///
/// ## Safety
///
/// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by
/// changing the page mapping.
#[inline]
pub unsafe fn update<F>(f: F)
where
F: FnOnce(&mut PhysFrame, &mut Cr3Flags),
{
let (mut frame, mut flags) = Self::read();
f(&mut frame, &mut flags);
unsafe {
Self::write(frame, flags);
}
}

/// Updates the P4 table address in the CR3 register.
///
/// ## Safety
///
/// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by
/// changing the page mapping.
/// [`Cr4Flags::PCID`] must be set before calling this method.
#[inline]
pub unsafe fn update_pcid<F>(f: F)
where
F: FnOnce(&mut PhysFrame, &mut Pcid),
{
let (mut frame, mut pcid) = Self::read_pcid();
f(&mut frame, &mut pcid);
unsafe {
Self::write_pcid(frame, pcid);
}
}

/// Updates the P4 table address in the CR3 register without flushing existing TLB entries for
/// the PCID.
///
/// ## Safety
///
/// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by
/// changing the page mapping.
/// [`Cr4Flags::PCID`] must be set before calling this method.
#[inline]
pub unsafe fn update_pcid_no_flush<F>(f: F)
where
F: FnOnce(&mut PhysFrame, &mut Pcid),
{
let (mut frame, mut pcid) = Self::read_pcid();
f(&mut frame, &mut pcid);
unsafe {
Self::write_pcid_no_flush(frame, pcid);
}
}
}

impl Cr4 {
Expand Down
13 changes: 13 additions & 0 deletions src/registers/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,5 +499,18 @@ mod x86_64 {
asm!("mov dr7, {}", in(reg) value, options(nomem, nostack, preserves_flags));
}
}

/// Update the DR7 value.
///
/// Preserves the value of reserved fields.
#[inline]
pub fn update<F>(f: F)
where
F: FnOnce(&mut Dr7Value),
{
let mut value = Self::read();
f(&mut value);
Self::write(value);
}
}
}
40 changes: 40 additions & 0 deletions src/registers/model_specific.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,24 @@ mod x86_64 {
let mut msr = Self::MSR;
unsafe { msr.write(value.bits()) };
}

/// Update the SFMask register.
///
/// The SFMASK register is used to specify which RFLAGS bits
/// are cleared during a SYSCALL. In long mode, SFMASK is used
/// to specify which RFLAGS bits are cleared when SYSCALL is
/// executed. If a bit in SFMASK is set to 1, the corresponding
/// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
/// to 0, the corresponding rFLAGS bit is not modified.
#[inline]
pub fn update<F>(f: F)
where
F: FnOnce(&mut RFlags),
{
let mut flags = Self::read();
f(&mut flags);
Self::write(flags);
}
}

impl UCet {
Expand Down Expand Up @@ -560,6 +578,17 @@ mod x86_64 {
pub fn write(flags: CetFlags, legacy_bitmap: Page) {
Self::write_raw(flags.bits() | legacy_bitmap.start_address().as_u64());
}

/// Updates IA32_U_CET.
#[inline]
pub fn update<F>(f: F)
where
F: FnOnce(&mut CetFlags, &mut Page),
{
let (mut flags, mut legacy_bitmap) = Self::read();
f(&mut flags, &mut legacy_bitmap);
Self::write(flags, legacy_bitmap);
}
}

impl SCet {
Expand Down Expand Up @@ -595,5 +624,16 @@ mod x86_64 {
pub fn write(flags: CetFlags, legacy_bitmap: Page) {
Self::write_raw(flags.bits() | legacy_bitmap.start_address().as_u64());
}

/// Updates IA32_S_CET.
#[inline]
pub fn update<F>(f: F)
where
F: FnOnce(&mut CetFlags, &mut Page),
{
let (mut flags, mut legacy_bitmap) = Self::read();
f(&mut flags, &mut legacy_bitmap);
Self::write(flags, legacy_bitmap);
}
}
}
11 changes: 11 additions & 0 deletions src/registers/mxcsr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ mod x86_64 {
}
}

/// Update MXCSR.
#[inline]
pub fn update<F>(f: F)
where
F: FnOnce(&mut MxCsr),
{
let mut mxcsr = self::read();
f(&mut mxcsr);
self::write(mxcsr);
}

#[cfg(test)]
mod test {
use crate::registers::mxcsr::*;
Expand Down
19 changes: 19 additions & 0 deletions src/registers/rflags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,25 @@ mod x86_64 {
}
}

/// Updates the RFLAGS register, preserves reserved bits.
///
/// ## Safety
///
/// Unsafe because undefined becavior can occur if certain flags are modified. For example,
/// the `DF` flag must be unset in all Rust code. Also, modifying `CF`, `PF`, or any other
/// flags also used by Rust/LLVM can result in undefined behavior too.
#[inline]
pub unsafe fn update<F>(f: F)
where
F: FnOnce(&mut RFlags),
{
let mut flags = self::read();
f(&mut flags);
unsafe {
self::write(flags);
}
}

#[cfg(test)]
mod test {
use crate::registers::rflags::read;
Expand Down
23 changes: 22 additions & 1 deletion src/registers/xcontrol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ mod x86_64 {
/// ## Safety
///
/// This function is unsafe because it's possible to
/// enable features that are not supported by the architecture
/// enable features that are not supported by the architecture.
#[inline]
pub unsafe fn write(flags: XCr0Flags) {
let old_value = Self::read_raw();
Expand Down Expand Up @@ -145,5 +145,26 @@ mod x86_64 {
);
}
}

/// Update XCR0 flags.
///
/// Preserves the value of reserved fields.
/// Panics if invalid combinations of [`XCr0Flags`] are set.
///
/// ## Safety
///
/// This function is unsafe because it's possible to
/// enable features that are not supported by the architecture.
#[inline]
pub unsafe fn update<F>(f: F)
where
F: FnOnce(&mut XCr0Flags),
{
let mut flags = Self::read();
f(&mut flags);
unsafe {
Self::write(flags);
}
}
}
}

0 comments on commit 59ac07c

Please sign in to comment.