-
Notifications
You must be signed in to change notification settings - Fork 132
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
base: master
Are you sure you want to change the base?
Changes from 10 commits
9b5d13e
8f1ede6
bb44e2c
f9c28dd
bd9a811
1e0d618
2a370ce
bac30bc
df8104b
ac9fae1
355bd52
d87eeda
c0c929c
b9c8e2a
d93e721
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
||
bitflags! { | ||
/// Configuration flags of the [`Cr8`] register. | ||
pub struct Cr8Flags: u64 { | ||
/// A value corresponding to the highest-priority interrupt that is to be blocked | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
|
@@ -162,6 +176,57 @@ mod x86_64 { | |
use super::*; | ||
use crate::{instructions::tlb::Pcid, structures::paging::PhysFrame, PhysAddr, VirtAddr}; | ||
|
||
impl Cr8 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
@@ -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); | ||
|
@@ -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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 { | ||
|
@@ -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] | ||
|
@@ -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 | ||
|
There was a problem hiding this comment.
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.