Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added MTRRs and other missing registers #311

Draft
wants to merge 15 commits into
base: master
Choose a base branch
from
65 changes: 65 additions & 0 deletions src/registers/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@
pub use super::model_specific::{Efer, EferFlags};
use bitflags::bitflags;

/// System software can use the TPR register to temporarily block low-priority interrupts from
/// interrupting a high-priority task. This is accomplished by loading TPR with a value corresponding to
/// the highest-priority interrupt that is to be blocked.
#[derive(Debug)]
pub struct Cr8;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other registers appear in order of their number. We should keep it that way.


bitflags! {
/// Configuration flags of the [`Cr8`] register.
pub struct Cr8Flags: u64 {
/// A value corresponding to the highest-priority interrupt that is to be blocked
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually end all sentences in comments with a dot. This should be fixed in a others comments too.

const TASK_PRIORITY = 0xf;
}
}

Comment on lines +12 to +19
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure bitflags is the right abstraction for this. The register doesn't contain any flags, it contains the task priority as a 4 bit number.

/// Various control flags modifying the basic operation of the CPU.
#[derive(Debug)]
pub struct Cr0;
Expand Down Expand Up @@ -162,6 +176,57 @@ mod x86_64 {
use super::*;
use crate::{instructions::tlb::Pcid, structures::paging::PhysFrame, PhysAddr, VirtAddr};

impl Cr8 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing about the order here.

/// Returns the task priority
#[inline]
pub fn read() -> Cr8Flags {
let value = Self::read_raw();
Cr8Flags::from_bits_truncate(value)
}

/// Read the current raw CR8 value.
#[inline]
pub fn read_raw() -> u64 {
let value: u64;

#[cfg(feature = "inline_asm")]
unsafe {
asm!("mov {}, cr8", out(reg) value, options(nomem, nostack, preserves_flags));
}

value
}

/// Write raw CR8 flags.
///
/// Does _not_ preserve any values, including reserved fields.
///
/// ## Safety
///
/// Could mask important external interrupts
#[inline]
pub unsafe fn write_raw(value: u64) {
#[cfg(feature = "inline_asm")]
asm!("mov cr8, {}", in(reg) value, options(nostack, preserves_flags));
}

/// Write CR8 flags.
///
/// Preserves the value of reserved fields.
///
/// ## Safety
///
/// Could mask important external interrupts
#[inline]
pub unsafe fn write(flags: Cr8Flags) {
let old_value = Self::read_raw();
let reserved = old_value & !(Cr8Flags::all().bits());
let new_value = reserved | flags.bits();

Self::write_raw(new_value);
}
}

impl Cr0 {
/// Read the current set of CR0 flags.
#[inline]
Expand Down
1 change: 1 addition & 0 deletions src/registers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

pub mod control;
pub mod model_specific;
pub mod mtrr;
pub mod rflags;
pub mod segmentation;
pub mod xcontrol;
Expand Down
120 changes: 120 additions & 0 deletions src/registers/model_specific.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ pub struct GsBase;
#[derive(Debug)]
pub struct KernelGsBase;

/// System Configuration Register.
#[derive(Debug)]
pub struct Syscfg;

/// Syscall Register: STAR
#[derive(Debug)]
pub struct Star;
Expand All @@ -51,10 +55,19 @@ pub struct Star;
#[derive(Debug)]
pub struct LStar;

/// Syscall Register: CSTAR
#[derive(Debug)]
pub struct CStar;

/// Syscall Register: SFMASK
#[derive(Debug)]
pub struct SFMask;

impl Syscfg {
/// The underlying model specific register.
pub const MSR: Msr = Msr(0xC001_0010);
}

impl Efer {
/// The underlying model specific register.
pub const MSR: Msr = Msr(0xC000_0080);
Expand Down Expand Up @@ -85,11 +98,38 @@ impl LStar {
pub const MSR: Msr = Msr(0xC000_0082);
}

impl CStar {
/// The underlying model specific register.
pub const MSR: Msr = Msr(0xC000_0083);
}

impl SFMask {
/// The underlying model specific register.
pub const MSR: Msr = Msr(0xC000_0084);
}

bitflags! {
/// Flags of the System Configuration Register.
pub struct SyscfgFlags: u32 {
/// MtrrFixDramEn
const MFDE = 1 << 18;
/// MtrrFixDramModEn
const MFDM = 1 << 19;
/// MtrrVarDramEn
const MVDM = 1 << 20;
/// MtrrTom2En
const TOM2 = 1 << 21;
/// Tom2ForceMemTypeWB
const FWB = 1 << 22;
/// MemEncryptionModeEn
const MEME = 1 << 23;
/// SecureNestPagingEn
const SNPE = 1 << 24;
/// VMPLEn
const VMPLE = 1 << 25;
Comment on lines +131 to +146
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation for these could be improved.

}
}

bitflags! {
/// Flags of the Extended Feature Enable Register.
pub struct EferFlags: u64 {
Expand Down Expand Up @@ -177,6 +217,69 @@ mod x86_64 {
}
}

impl Syscfg {
/// Read the current Syscfg flags.
#[inline]
pub fn read() -> SyscfgFlags {
SyscfgFlags::from_bits_truncate(Self::read_raw())
}

/// Read the current raw Syscfg flags.
#[inline]
pub fn read_raw() -> u32 {
unsafe { Self::MSR.read() as u32 }
}

/// Write the Syscfg flags, preserving reserved values.
///
/// Preserves the value of reserved fields.
///
/// ## Safety
///
/// Unsafe because it's possible to break memory
/// safety with wrong flags, e.g. by disabling long mode.
#[inline]
pub unsafe fn write(flags: SyscfgFlags) {
let old_value = Self::read_raw();
let reserved = old_value & !(SyscfgFlags::all().bits());
let new_value = reserved | flags.bits();

Self::write_raw(new_value);
}

/// Write the Syscfg flags.
///
/// Does not preserve any bits, including reserved fields.
///
/// ## Safety
///
/// Unsafe because it's possible to
/// break memory safety with wrong flags
#[inline]
pub unsafe fn write_raw(flags: u32) {
let mut msr = Self::MSR;
msr.write(flags as u64);
}

/// Update Syscfg flags.
///
/// Preserves the value of reserved fields.
///
/// ## Safety
///
/// Unsafe because it's possible to break memory
/// safety with wrong flags, e.g. by disabling long mode.
#[inline]
pub unsafe fn update<F>(f: F)
where
F: FnOnce(&mut SyscfgFlags),
{
let mut flags = Self::read();
f(&mut flags);
Self::write(flags);
}
}

impl Efer {
/// Read the current EFER flags.
#[inline]
Expand Down Expand Up @@ -416,6 +519,23 @@ mod x86_64 {
}
}

impl CStar {
/// Read the current CStar register.
/// This holds the target RIP of a syscall in compatibily mode.
#[inline]
pub fn read() -> VirtAddr {
VirtAddr::new(unsafe { Self::MSR.read() })
}

/// Write a given virtual address to the CStar register.
/// This holds the target RIP of a syscall in compatibily mode.
#[inline]
pub fn write(address: VirtAddr) {
let mut msr = Self::MSR;
unsafe { msr.write(address.as_u64()) };
}
}

impl SFMask {
/// Read to the SFMask register.
/// The SFMASK register is used to specify which RFLAGS bits
Expand Down
Loading