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
35 changes: 33 additions & 2 deletions src/instructions/tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub unsafe fn lgdt(gdt: &DescriptorTablePointer) {
crate::asm::x86_64_asm_lgdt(gdt as *const _);
}

/// Load an IDT.
/// Load an LIDT.
///
/// Use the
/// [`InterruptDescriptorTable`](crate::structures::idt::InterruptDescriptorTable) struct for a high-level
Expand All @@ -34,7 +34,7 @@ pub unsafe fn lgdt(gdt: &DescriptorTablePointer) {
/// ## Safety
///
/// This function is unsafe because the caller must ensure that the given
/// `DescriptorTablePointer` points to a valid IDT and that loading this
/// `DescriptorTablePointer` points to a valid LIDT and that loading this
Qubasa marked this conversation as resolved.
Show resolved Hide resolved
/// IDT is safe.
#[inline]
pub unsafe fn lidt(idt: &DescriptorTablePointer) {
Expand All @@ -45,6 +45,23 @@ pub unsafe fn lidt(idt: &DescriptorTablePointer) {
crate::asm::x86_64_asm_lidt(idt as *const _);
}

/// Load an LIDT.
///
/// Use the
/// [`InterruptDescriptorTable`](crate::structures::idt::InterruptDescriptorTable) struct for a high-level
/// interface to loading an LIDT.
///
/// ## Safety
///
/// This function is unsafe because the caller must ensure that the given
/// `DescriptorTablePointer` points to a valid LIDT and that loading this
/// LIDT is safe.
#[inline]
pub unsafe fn lldt(lidt: &DescriptorTablePointer) {
#[cfg(feature = "inline_asm")]
asm!("lldt [{}]", in(reg) lidt, options(readonly, nostack, preserves_flags));
}

/// Get the address of the current GDT.
#[inline]
pub fn sgdt() -> DescriptorTablePointer {
Expand Down Expand Up @@ -79,6 +96,20 @@ pub fn sidt() -> DescriptorTablePointer {
idt
}

/// Get the address of the current LIDT.
#[inline]
pub fn sldt() -> DescriptorTablePointer {
let mut sldt: DescriptorTablePointer = DescriptorTablePointer {
limit: 0,
base: VirtAddr::new(0),
};
unsafe {
#[cfg(feature = "inline_asm")]
asm!("sldt [{}]", in(reg) &mut sldt, options(nostack, preserves_flags));
}
sldt
}

Qubasa marked this conversation as resolved.
Show resolved Hide resolved
/// Load the task state register using the `ltr` instruction.
///
/// ## Safety
Expand Down
44 changes: 44 additions & 0 deletions src/registers/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
pub use super::model_specific::{Efer, EferFlags};
use bitflags::bitflags;

/// Various control flags modifying the basic operation of the CPU.
Qubasa marked this conversation as resolved.
Show resolved Hide resolved
#[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.


/// Various control flags modifying the basic operation of the CPU.
#[derive(Debug)]
pub struct Cr0;
Expand Down Expand Up @@ -162,6 +166,46 @@ 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() -> u8 {
Self::read_raw() as u8
}
Qubasa marked this conversation as resolved.
Show resolved Hide resolved

/// 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.
///
#[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.
///
#[inline]
pub unsafe fn write(value: u8) {
Qubasa marked this conversation as resolved.
Show resolved Hide resolved
Self::write_raw(value as u64);
Qubasa marked this conversation as resolved.
Show resolved Hide resolved
}
}

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